hercules-3.12/0000775000175000017500000000000012625667404010270 500000000000000hercules-3.12/autoconf/0000775000175000017500000000000012625667404012106 500000000000000hercules-3.12/autoconf/hercules.m40000664000175000017500000002774212564723224014111 00000000000000############################################################################## # # H E R C U L E S . M 4 # # Hercules M4 macros for auto-configure # ############################################################################## # $Id$ # # $Log$ #----------------------------------------------------------------------------- # # Macro: HC_C99_FLEXIBLE_ARRAYS() # # Checks whether or not the compiler supports C99 flexible arrays # # Parms: None # Input: Nothing # Output: $hc_cv_c99_flexible_array, # AC_DEFINE() for 'C99_FLEXIBLE_ARRAYS' if yes. # Note: Since AC_DEFINE() might be issued, a corresponding # AH_TEMPLATE() for 'C99_FLEXIBLE_ARRAYS' is of course # also needed somewhere in configure.ac # # Credit: Modeled after 'AC_C99_FLEXIBLE_ARRAY' macro copyright # by Erik de Castro Lopo : # # "Permission to use, copy, modify, distribute, # and sell this file for any purpose is hereby # granted without fee, provided that the above # copyright and this permission notice appear # in all copies. No representations are made # about the suitability of this software for any # purpose. It is provided "as is" without express # or implied warranty." # #----------------------------------------------------------------------------- AC_DEFUN([HC_C99_FLEXIBLE_ARRAYS], [ AC_CACHE_CHECK( C99 struct flexible arrays support, [hc_cv_c99_flexible_array], [ # Initialize to unknown hc_cv_c99_flexible_array=no AC_TRY_LINK( [ #include typedef struct { int foo; char bar[]; } FOOBAR; ], [ int main(int argc, char *argv[]) { FOOBAR* p = calloc( 1, sizeof(FOOBAR) + 16 ); return 0; } ], [hc_cv_c99_flexible_array=yes], [hc_cv_c99_flexible_array=no] ) ] ) if test "$hc_cv_c99_flexible_array" = "yes"; then AC_DEFINE([C99_FLEXIBLE_ARRAYS]) fi ]) #----------------------------------------------------------------------------- # # Macro: HC_PROG_CC() ((((( DEPRECATED ))))) # # Prevents undesired CFLAGS settings set by default AC_PROG_CC macro. # # Parms: none # Input: $ac_env_CFLAGS_value # Output: CFLAGS initialized to our desired starting value # Note: use instead of the default AC_PROG_CC macro # # AC_PROG_CC (actually _AC_PROC_CC_G) takes it upon itself to put "-g -O2" # in CFLAGS. While this may be good for most packages using autoconf, we # have our own "optimize" function that this interferes with. Thus this macro. # # AC_BEFORE emits a warning if AC_PROG_CC was expanded prior to this macro # in case something gets put in configure.ac before us. AC_REQUIRE expands # AC_PROG_CC for us since we need it. # #----------------------------------------------------------------------------- AC_DEFUN([HC_PROG_CC], [ AC_BEFORE( [HC_PROG_CC], [AC_PROG_CC] ) AC_REQUIRE( [AC_PROG_CC] ) # (set CFLAGS to their initial value) CFLAGS=$ac_env_CFLAGS_value ]) #----------------------------------------------------------------------------- # # Macro: HC_LD_DISALLOWDUPS() # # Adds linker options to LDFLAGS variable to warn about duplicate symbols # # Parms: none # Input: $lt_cv_prog_gnu_ld # Output: LDFLAGS variable modified as needed # #----------------------------------------------------------------------------- AC_DEFUN([HC_LD_DISALLOWDUPS], [ AC_REQUIRE([AC_PROG_LIBTOOL]) AC_REQUIRE([AC_PROG_LD_GNU]) if test "$lt_cv_prog_gnu_ld" = "yes"; then LDFLAGS="$LDFLAGS -Wl,--warn-common" fi ]) #----------------------------------------------------------------------------- # # Macro: HC_ARG_ENABLE_GETOPTWRAPPER() # # Handles "--enable-getoptwrapper" configure option # # Parms: none # Input: nothing # Output: $hc_cv_opt_getoptwrapper = "yes", "no" or "auto", as well as # other indirect side effects of _HC_CHECK_NEED_GETOPT_WRAPPER # helper macro being called # Note: calls _HC_CHECK_NEED_GETOPT_WRAPPER internal helper macro which # has its own requirements and side effects # # Ultimately determines whether the 'getopt' wrapper kludge is necessary or # specifically requested. Issues AC_DEFINE for "NEED_GETOPT_WRAPPER" if true. # Refer to _HC_CHECK_NEED_GETOPT_WRAPPER helper macro for details. # #----------------------------------------------------------------------------- AC_DEFUN([HC_ARG_ENABLE_GETOPTWRAPPER], [ AC_ARG_ENABLE( getoptwrapper, AC_HELP_STRING([--enable-getoptwrapper], [force use of the getopt wrapper kludge] ), [ case "${enableval}" in yes) hc_cv_opt_getoptwrapper=yes ;; no) hc_cv_opt_getoptwrapper=no ;; auto) hc_cv_opt_getoptwrapper=auto ;; *) hc_cv_opt_getoptwrapper=auto ;; esac ], [hc_cv_opt_getoptwrapper=auto] ) _HC_CHECK_NEED_GETOPT_WRAPPER($hc_cv_opt_getoptwrapper) ]) #----------------------------------------------------------------------------- # # Macro: _HC_CHECK_NEED_GETOPT_WRAPPER( [opt = "auto"] ) # # Determines whether the 'getopt' wrapper kludge is necessary or requested # # Parms: no they specifically requested NOT to use the wrapper # yes they specifically requested TO use the wrapper # auto we should determine ourselves if wrapper is needed # # Input: nothing # Output: $hc_cv_need_getopt_wrapper = "yes" or "no", # AC_DEFINE for "NEED_GETOPT_WRAPPER" if yes. # # Note: this macro is logically an internal subroutine of # the HC_ARG_ENABLE_GETOPTWRAPPER macro further above # # If the passed value is "yes" or "no", we simply set the output variable # value to whatever value was passed. If the passed value is "auto" however, # then we determine for ourselves whether the wrapper is needed. We do this # by performing a test link of two small programs that each use getopt but # where one calls the other (thereby producing an interdependency between # the two) and then seeing if the link caused any duplicate symbol error. # # If it is determined that the wrapper is needed (or if it was specifically # requested), an AC_DEFINE for "NEED_GETOPT_WRAPPER" is issued so Herc knows # to build/use its getopt wrapper kludge. Note that all AC_DEFINE's require # a corresponding AH_TEMPLATE statement somewhere in configure.ac. # #----------------------------------------------------------------------------- AC_DEFUN([_HC_CHECK_NEED_GETOPT_WRAPPER], [ AC_REQUIRE([AC_PROG_LIBTOOL]) AC_MSG_CHECKING([whether getopt wrapper kludge is necessary]) if test "$1" != "auto"; then hc_cv_need_getopt_wrapper="$1" hc_cv_need_getopt_wrapper_result_msg="$1 (forced)" else if test $(./libtool --features | fgrep "enable shared libraries" | wc -l) -ne 1; then # Libtool doesn't support shared libraries, # and thus our wrapper kludge is not needed. hc_cv_need_getopt_wrapper=no hc_cv_need_getopt_wrapper_result_msg=no else rm -f libconftest* rm -f .libs/libconftest* cat > conftest1.c << DUPGETOPT1 /* Test program that needs getopt, called by another program which itself needs getopt. Will the linker complain about duplicate symbols for getopt? We'll soon find out! */ extern char *optarg; extern int optind; int test1() { int i; char *c; i=optind; c=optarg; getopt(0,0,0); return 0; } DUPGETOPT1 cat > conftest2.c << DUPGETOPT2 /* Test program that not only needs getopt, but also calls another program which also needs getopt. Will linker complain about duplicate symbols for getopt? Let's see. */ extern char *optarg; extern int optind; extern int test2(); int test2() { int i; char *c; i=optind; c=optarg; getopt(0,0,0); test1(); return 0; } DUPGETOPT2 ./libtool --mode=compile ${CC-cc} conftest1.c -c -o conftest1.lo > /dev/null 2>&1 ./libtool --mode=compile ${CC-cc} conftest2.c -c -o conftest2.lo > /dev/null 2>&1 ./libtool --mode=link ${CC-cc} -shared -rpath /lib -no-undefined conftest1.lo -o libconftest1.la > /dev/null 2>&1 ./libtool --mode=link ${CC-cc} -shared -rpath /lib -no-undefined conftest2.lo libconftest1.la -o libconftest2.la > /dev/null 2>&1 if test $? = 0; then hc_cv_need_getopt_wrapper=no hc_cv_need_getopt_wrapper_result_msg=no else hc_cv_need_getopt_wrapper=yes hc_cv_need_getopt_wrapper_result_msg=yes fi rm -f *conftest* rm -f .libs/*conftest* fi fi AC_MSG_RESULT($hc_cv_need_getopt_wrapper_result_msg) if test "$hc_cv_need_getopt_wrapper" = "yes"; then AC_DEFINE([NEED_GETOPT_WRAPPER]) fi ]) #----------------------------------------------------------------------------- # # Macro: HC_CHECK_NEED_GETOPT_OPTRESET() # # Checks whether or not 'optreset' needed for 'getopt' use # # Parms: none # Input: nothing # Output: $hc_cv_need_getopt_optreset, # AC_DEFINE() for 'NEED_GETOPT_OPTRESET' if yes. # Note: since AC_DEFINE() might be issued, a corresponding AH_TEMPLATE() # for 'NEED_GETOPT_OPTRESET' is needed somewhere in configure.ac # #----------------------------------------------------------------------------- AC_DEFUN([HC_CHECK_NEED_GETOPT_OPTRESET], [ AC_CACHE_CHECK( [whether 'optreset' needed for 'getopt' use], [hc_cv_need_getopt_optreset], [ AC_TRY_LINK( [], [ extern int optreset; optreset=1; getopt(0,0,0); ], [hc_cv_need_getopt_optreset=yes], [hc_cv_need_getopt_optreset=no] ) ] ) if test "$hc_cv_need_getopt_optreset" = "yes"; then AC_DEFINE([NEED_GETOPT_OPTRESET]) fi ]) #----------------------------------------------------------------------------- # # Macro: HC_ADD_TO_CFLAGS_IF_SUPPORTED() # # Checks whether the compiler supports 'option', adds to CFLAGS if yes # # Parms: 1. 'option' to be added # 2. 'symbol' to be set # Input: nothing # Output: 'option' is appended to CFLAGS if the compiler supports it; # 'symbol' is set to "yes" or "no" # #----------------------------------------------------------------------------- AC_DEFUN([HC_ADD_TO_CFLAGS_IF_SUPPORTED], [ AC_CACHE_CHECK( [whether compiler supports $1], [$2], [ hc_temp="$CFLAGS" CFLAGS="$CFLAGS -Werror $1" AC_TRY_COMPILE([], [return(0);], $2="yes", $2="no") CFLAGS="$hc_temp" ]) if test "${$2}" = "yes"; then CFLAGS="$CFLAGS $1" fi ]) ############################################################################### # (end-of-file) ############################################################################### hercules-3.12/autoconf/libtool.m40000664000175000017500000063070112564723224013736 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- ## Copyright 1996, 1997, 1998, 1999, 2000, 2001 ## Free Software Foundation, Inc. ## Originally by Gordon Matzigkeit , 1996 ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## ## As a special exception to the GNU General Public License, if you ## distribute this file as part of a program that contains a ## configuration script generated by Autoconf, you may include it under ## the same distribution terms that you use for the rest of that program. # serial 47 AC_PROG_LIBTOOL # AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) # ----------------------------------------------------------- # If this macro is not defined by Autoconf, define it here. m4_ifdef([AC_PROVIDE_IFELSE], [], [m4_define([AC_PROVIDE_IFELSE], [m4_ifdef([AC_PROVIDE_$1], [$2], [$3])])]) # AC_PROG_LIBTOOL # --------------- AC_DEFUN([AC_PROG_LIBTOOL], [AC_REQUIRE([_AC_PROG_LIBTOOL])dnl dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. AC_PROVIDE_IFELSE([AC_PROG_CXX], [AC_LIBTOOL_CXX], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX ])]) dnl And a similar setup for Fortran 77 support AC_PROVIDE_IFELSE([AC_PROG_F77], [AC_LIBTOOL_F77], [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 ])]) dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [AC_LIBTOOL_GCJ], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [AC_LIBTOOL_GCJ], [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], [AC_LIBTOOL_GCJ], [ifdef([AC_PROG_GCJ], [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) ifdef([A][M_PROG_GCJ], [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) ifdef([LT_AC_PROG_GCJ], [define([LT_AC_PROG_GCJ], defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) ])])# AC_PROG_LIBTOOL # _AC_PROG_LIBTOOL # ---------------- AC_DEFUN([_AC_PROG_LIBTOOL], [AC_REQUIRE([AC_LIBTOOL_SETUP])dnl AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl # Prevent multiple expansion define([AC_PROG_LIBTOOL], []) ])# _AC_PROG_LIBTOOL # AC_LIBTOOL_SETUP # ---------------- AC_DEFUN([AC_LIBTOOL_SETUP], [AC_PREREQ(2.50)dnl AC_REQUIRE([AC_ENABLE_SHARED])dnl AC_REQUIRE([AC_ENABLE_STATIC])dnl AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_LD])dnl AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl AC_REQUIRE([AC_PROG_NM])dnl AC_REQUIRE([AC_PROG_LN_S])dnl AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl # Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! AC_REQUIRE([AC_OBJEXT])dnl AC_REQUIRE([AC_EXEEXT])dnl dnl AC_LIBTOOL_SYS_MAX_CMD_LEN AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE AC_LIBTOOL_OBJDIR AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl _LT_AC_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e s/^X//' [sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] # Same as above, but do not quote variable references. [double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Constants: rm="rm -f" # Global variables: default_ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except M$VC, # which needs '.lib'). libext=a ltmain="$ac_aux_dir/ltmain.sh" ofile="$default_ofile" with_gnu_ld="$lt_cv_prog_gnu_ld" AC_CHECK_TOOL(AR, ar, false) AC_CHECK_TOOL(RANLIB, ranlib, :) AC_CHECK_TOOL(STRIP, strip, :) old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru test -z "$AS" && AS=as test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$LD" && LD=ld test -z "$LN_S" && LN_S="ln -s" test -z "$MAGIC_CMD" && MAGIC_CMD=file test -z "$NM" && NM=nm test -z "$SED" && SED=sed test -z "$OBJDUMP" && OBJDUMP=objdump test -z "$RANLIB" && RANLIB=: test -z "$STRIP" && STRIP=: test -z "$ac_objext" && ac_objext=o # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" ;; *) old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi # Only perform the check for file, if the check method requires it case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then AC_PATH_MAGIC fi ;; esac AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], enable_win32_dll=yes, enable_win32_dll=no) AC_ARG_ENABLE([libtool-lock], [AC_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes AC_ARG_WITH([pic], [AC_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=default # Use C for the default configuration in the libtool script tagname= AC_LIBTOOL_LANG_C_CONFIG _LT_AC_TAGCONFIG ])# AC_LIBTOOL_SETUP # _LT_AC_SYS_COMPILER # ------------------- AC_DEFUN([_LT_AC_SYS_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_AC_SYS_COMPILER # _LT_AC_SYS_LIBPATH_AIX # ---------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], [AC_LINK_IFELSE(AC_LANG_PROGRAM,[ aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_AC_SYS_LIBPATH_AIX # _LT_AC_SHELL_INIT(ARG) # ---------------------- AC_DEFUN([_LT_AC_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_AC_SHELL_INIT # _LT_AC_PROG_ECHO_BACKSLASH # -------------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], [_LT_AC_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac echo=${ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then # Yippee, $echo works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null && echo_test_string="`eval $cmd`" && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null then break fi done fi if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. echo='printf %s\n' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. ECHO=$echo if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(ECHO) ])])# _LT_AC_PROG_ECHO_BACKSLASH # _LT_AC_LOCK # ----------- AC_DEFUN([_LT_AC_LOCK], [AC_ARG_ENABLE([libtool-lock], [AC_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case "`/usr/bin/file conftest.o`" in *32-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], [*-*-cygwin* | *-*-mingw* | *-*-pw32*) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; ]) esac need_locks="$enable_libtool_lock" ])# _LT_AC_LOCK # AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [AC_REQUIRE([LT_AC_PROG_SED]) AC_CACHE_CHECK([$1], [$2], [$2=no ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then $2=yes fi fi $rm conftest* ]) if test x"[$]$2" = xyes; then ifelse([$5], , :, [$5]) else ifelse([$6], , :, [$6]) fi ])# AC_LIBTOOL_COMPILER_OPTION # AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ------------------------------------------------------------ # Check whether the given compiler option works AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD else $2=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then ifelse([$4], , :, [$4]) else ifelse([$5], , :, [$5]) fi ])# AC_LIBTOOL_LINKER_OPTION # AC_LIBTOOL_SYS_MAX_CMD_LEN # -------------------------- AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [# find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 testring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; *) # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$testring" 2>/dev/null` \ = "XX$testring") >/dev/null 2>&1 && new_result=`expr "X$testring" : ".*" 2>&1` && lt_cv_sys_max_cmd_len=$new_result && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` testring=$testring$testring done testring= # Add a significant safety factor because C++ compilers can tack on massive # amounts of additional arguments before passing them to the linker. # It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi ])# AC_LIBTOOL_SYS_MAX_CMD_LEN # _LT_AC_CHECK_DLFCN # -------------------- AC_DEFUN([_LT_AC_CHECK_DLFCN], [AC_CHECK_HEADERS(dlfcn.h)dnl ])# _LT_AC_CHECK_DLFCN # _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ------------------------------------------------------------------ AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); }] EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_unknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_AC_TRY_DLOPEN_SELF # AC_LIBTOOL_DLOPEN_SELF # ------------------- AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_AC_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_AC_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi ])# AC_LIBTOOL_DLOPEN_SELF # AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) # --------------------------------- # Check to see if options -c and -o are simultaneously supported by compiler AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], [AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext # According to Tom Tromey, Ian Lance Taylor reported there are C compilers # that will create temporary files in the current directory regardless of # the output directory. Thus, making CWD read-only will cause this test # to fail, enabling locking or at least warning the user not to do parallel # builds. chmod -w . lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* ]) ])# AC_LIBTOOL_PROG_CC_C_O # AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) # ----------------------------------------- # Check to see if we can do hard links to lock some files if needed AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_REQUIRE([_LT_AC_LOCK])dnl hard_links="nottested" if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi ])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS # AC_LIBTOOL_OBJDIR # ----------------- AC_DEFUN([AC_LIBTOOL_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir ])# AC_LIBTOOL_OBJDIR # AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) # ---------------------------------------------- # Check hardcoding attributes. AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_AC_TAGVAR(hardcode_action, $1)= if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then # We can hardcode non-existant directories. if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_AC_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_AC_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_AC_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi ])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH # AC_LIBTOOL_SYS_LIB_STRIP # ------------------------ AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], [striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" # # # The following section is a PATCH to overcome the # stripped import library issues under cygwin case $host_os in cygwin*) striplib= AC_MSG_RESULT([no]) ;; *) AC_MSG_RESULT([yes]) ;; esac # # # AC_MSG_RESULT([yes]) # # else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi ])# AC_LIBTOOL_SYS_LIB_STRIP # AC_LIBTOOL_SYS_DYNAMIC_LINKER # ----------------------------- # PORTME Fill in your ld.so characteristics AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_MSG_CHECKING([dynamic linker characteristics]) library_names_spec= libname_spec='lib$name' soname_spec= shrext=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no ])# AC_LIBTOOL_SYS_DYNAMIC_LINKER # _LT_AC_TAGCONFIG # ---------------- AC_DEFUN([_LT_AC_TAGCONFIG], [AC_ARG_WITH([tags], [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], [include additional configurations @<:@automatic@:>@])], [tagnames="$withval"]) if test -f "$ltmain" && test -n "$tagnames"; then if test ! -f "${ofile}"; then AC_MSG_WARN([output file `$ofile' does not exist]) fi if test -z "$LTCC"; then eval "`$SHELL ${ofile} --config | grep '^LTCC='`" if test -z "$LTCC"; then AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) else AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) fi fi # Extract list of available tagged configurations in $ofile. # Note that this assumes the entire list is on one line. available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for tagname in $tagnames; do IFS="$lt_save_ifs" # Check whether tagname contains only valid characters case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in "") ;; *) AC_MSG_ERROR([invalid tag name: $tagname]) ;; esac if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null then AC_MSG_ERROR([tag name \"$tagname\" already exists]) fi # Update the list of available tags. if test -n "$tagname"; then echo appending configuration tag \"$tagname\" to $ofile case $tagname in CXX) if test -n "$CXX" && test "X$CXX" != "Xno"; then AC_LIBTOOL_LANG_CXX_CONFIG else tagname="" fi ;; F77) if test -n "$F77" && test "X$F77" != "Xno"; then AC_LIBTOOL_LANG_F77_CONFIG else tagname="" fi ;; GCJ) if test -n "$GCJ" && test "X$GCJ" != "Xno"; then AC_LIBTOOL_LANG_GCJ_CONFIG else tagname="" fi ;; RC) AC_LIBTOOL_LANG_RC_CONFIG ;; *) AC_MSG_ERROR([Unsupported tag name: $tagname]) ;; esac # Append the new tag name to the list of available tags. if test -n "$tagname" ; then available_tags="$available_tags $tagname" fi fi done IFS="$lt_save_ifs" # Now substitute the updated list of available tags. if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then mv "${ofile}T" "$ofile" chmod +x "$ofile" else rm -f "${ofile}T" AC_MSG_ERROR([unable to update list of available tagged configurations.]) fi fi ])# _LT_AC_TAGCONFIG # AC_LIBTOOL_DLOPEN # ----------------- # enable checks for dlopen support AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) ])# AC_LIBTOOL_DLOPEN # AC_LIBTOOL_WIN32_DLL # -------------------- # declare package support for building win32 dll's AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) ])# AC_LIBTOOL_WIN32_DLL # AC_ENABLE_SHARED([DEFAULT]) # --------------------------- # implement the --enable-shared flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_SHARED], [define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([shared], [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]AC_ENABLE_SHARED_DEFAULT) ])# AC_ENABLE_SHARED # AC_DISABLE_SHARED # ----------------- #- set the default shared flag to --disable-shared AC_DEFUN([AC_DISABLE_SHARED], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_SHARED(no) ])# AC_DISABLE_SHARED # AC_ENABLE_STATIC([DEFAULT]) # --------------------------- # implement the --enable-static flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_STATIC], [define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([static], [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]AC_ENABLE_STATIC_DEFAULT) ])# AC_ENABLE_STATIC # AC_DISABLE_STATIC # ----------------- # set the default static flag to --disable-static AC_DEFUN([AC_DISABLE_STATIC], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_STATIC(no) ])# AC_DISABLE_STATIC # AC_ENABLE_FAST_INSTALL([DEFAULT]) # --------------------------------- # implement the --enable-fast-install flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_FAST_INSTALL], [define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([fast-install], [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) ])# AC_ENABLE_FAST_INSTALL # AC_DISABLE_FAST_INSTALL # ----------------------- # set the default to --disable-fast-install AC_DEFUN([AC_DISABLE_FAST_INSTALL], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_FAST_INSTALL(no) ])# AC_DISABLE_FAST_INSTALL # AC_LIBTOOL_PICMODE([MODE]) # -------------------------- # implement the --with-pic flag # MODE is either `yes' or `no'. If omitted, it defaults to `both'. AC_DEFUN([AC_LIBTOOL_PICMODE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl pic_mode=ifelse($#,1,$1,default) ])# AC_LIBTOOL_PICMODE # AC_PROG_EGREP # ------------- # This is predefined starting with Autoconf 2.54, so this conditional # definition can be removed once we require Autoconf 2.54 or later. m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], [AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi]) EGREP=$ac_cv_prog_egrep AC_SUBST([EGREP]) ])]) # AC_PATH_TOOL_PREFIX # ------------------- # find a file program which can recognise shared library AC_DEFUN([AC_PATH_TOOL_PREFIX], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="ifelse([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi ])# AC_PATH_TOOL_PREFIX # AC_PATH_MAGIC # ------------- # find a file program which can recognise a shared library AC_DEFUN([AC_PATH_MAGIC], [AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# AC_PATH_MAGIC # AC_PROG_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([AC_PROG_LD], [AC_ARG_WITH([gnu-ld], [AC_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no]) AC_REQUIRE([LT_AC_PROG_SED])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case "$host_cpu" in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; irix5* | irix6* | nonstopux*) case $host_os in irix5* | nonstopux*) # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" ;; *) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" ;; esac lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux*) case $host_cpu in alpha* | hppa* | i*86 | ia64* | m68* | mips* | powerpc* | sparc* | s390* | sh* | x86_64) lt_cv_deplibs_check_method=pass_all ;; *) # glibc up to 2.1.1 does not perform some relocations on ARM lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; esac lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; nto-qnx*) lt_cv_deplibs_check_method=unknown ;; openbsd*) lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' else lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' fi ;; osf3* | osf4* | osf5*) # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' lt_cv_file_magic_test_file=/shlib/libc.so lt_cv_deplibs_check_method=pass_all ;; sco3.2v5*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all lt_cv_file_magic_test_file=/lib/libc.so ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown ])# AC_DEPLIBS_CHECK_METHOD # AC_PROG_NM # ---------- # find the pathname to a BSD-compatible name lister AC_DEFUN([AC_PROG_NM], [AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/${ac_tool_prefix}nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac esac fi done IFS="$lt_save_ifs" test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm fi]) NM="$lt_cv_path_NM" ])# AC_PROG_NM # AC_CHECK_LIBM # ------------- # check for math library AC_DEFUN([AC_CHECK_LIBM], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac ])# AC_CHECK_LIBM # AC_LIBLTDL_CONVENIENCE([DIRECTORY]) # ----------------------------------- # sets LIBLTDL to the link flags for the libltdl convenience library and # LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL # and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If # DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will # be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with # '${top_srcdir}/' (note the single quotes!). If your package is not # flat and you're not using automake, define top_builddir and # top_srcdir appropriately in the Makefiles. AC_DEFUN([AC_LIBLTDL_CONVENIENCE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl case $enable_ltdl_convenience in no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" ])# AC_LIBLTDL_CONVENIENCE # AC_LIBLTDL_INSTALLABLE([DIRECTORY]) # ----------------------------------- # sets LIBLTDL to the link flags for the libltdl installable library and # LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-install to the configure arguments. Note that LIBLTDL # and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If # DIRECTORY is not provided and an installed libltdl is not found, it is # assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' # and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single # quotes!). If your package is not flat and you're not using automake, # define top_builddir and top_srcdir appropriately in the Makefiles. # In the future, this macro may have to be called after AC_PROG_LIBTOOL. AC_DEFUN([AC_LIBLTDL_INSTALLABLE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_CHECK_LIB(ltdl, lt_dlinit, [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], [if test x"$enable_ltdl_install" = xno; then AC_MSG_WARN([libltdl not installed, but installation disabled]) else enable_ltdl_install=yes fi ]) if test x"$enable_ltdl_install" = x"yes"; then ac_configure_args="$ac_configure_args --enable-ltdl-install" LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) else ac_configure_args="$ac_configure_args --enable-ltdl-install=no" LIBLTDL="-lltdl" LTDLINCL= fi # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" ])# AC_LIBLTDL_INSTALLABLE # AC_LIBTOOL_CXX # -------------- # enable support for C++ libraries AC_DEFUN([AC_LIBTOOL_CXX], [AC_REQUIRE([_LT_AC_LANG_CXX]) ])# AC_LIBTOOL_CXX # _LT_AC_LANG_CXX # --------------- AC_DEFUN([_LT_AC_LANG_CXX], [AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([AC_PROG_CXXCPP]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) ])# _LT_AC_LANG_CXX # AC_LIBTOOL_F77 # -------------- # enable support for Fortran 77 libraries AC_DEFUN([AC_LIBTOOL_F77], [AC_REQUIRE([_LT_AC_LANG_F77]) ])# AC_LIBTOOL_F77 # _LT_AC_LANG_F77 # --------------- AC_DEFUN([_LT_AC_LANG_F77], [AC_REQUIRE([AC_PROG_F77]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) ])# _LT_AC_LANG_F77 # AC_LIBTOOL_GCJ # -------------- # enable support for GCJ libraries AC_DEFUN([AC_LIBTOOL_GCJ], [AC_REQUIRE([_LT_AC_LANG_GCJ]) ])# AC_LIBTOOL_GCJ # _LT_AC_LANG_GCJ # --------------- AC_DEFUN([_LT_AC_LANG_GCJ], [AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) ])# _LT_AC_LANG_GCJ # AC_LIBTOOL_RC # -------------- # enable support for Windows resource files AC_DEFUN([AC_LIBTOOL_RC], [AC_REQUIRE([LT_AC_PROG_RC]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) ])# AC_LIBTOOL_RC # AC_LIBTOOL_LANG_C_CONFIG # ------------------------ # Ensure that the configuration vars for the C compiler are # suitably defined. Those variables are subsequently used by # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) AC_DEFUN([_LT_AC_LANG_C_CONFIG], [lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_AC_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}\n' _LT_AC_SYS_COMPILER # # Check for any special shared library compilation flags. # _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= if test "$GCC" = no; then case $host_os in sco3.2v5*) _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' ;; esac fi if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$]_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[[ ]]" >/dev/null; then : else AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no fi fi # # Check to make sure the static flag actually works. # AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), [], [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) AC_LIBTOOL_PROG_COMPILER_PIC($1) AC_LIBTOOL_PROG_CC_C_O($1) AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) AC_LIBTOOL_PROG_LD_SHLIBS($1) AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) AC_LIBTOOL_SYS_LIB_STRIP AC_LIBTOOL_DLOPEN_SELF($1) # Report which librarie types wil actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; darwin* | rhapsody*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case "$host_os" in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' ;; esac fi ;; esac output_verbose_link_cmd='echo' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) AC_LIBTOOL_CONFIG($1) AC_LANG_POP CC="$lt_save_CC" ])# AC_LIBTOOL_LANG_C_CONFIG # AC_LIBTOOL_LANG_CXX_CONFIG # -------------------------- # Ensure that the configuration vars for the C compiler are # suitably defined. Those variables are subsequently used by # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], [AC_LANG_PUSH(C++) AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([AC_PROG_CXXCPP]) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(allow_undefined_flag, $1)= _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(archive_expsym_cmds, $1)= _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=no _LT_AC_TAGVAR(module_cmds, $1)= _LT_AC_TAGVAR(module_expsym_cmds, $1)= _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown _LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_AC_TAGVAR(no_undefined_flag, $1)= _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Dependencies to place before and after the object being linked: _LT_AC_TAGVAR(predep_objects, $1)= _LT_AC_TAGVAR(postdep_objects, $1)= _LT_AC_TAGVAR(predeps, $1)= _LT_AC_TAGVAR(postdeps, $1)= _LT_AC_TAGVAR(compiler_lib_search_path, $1)= # Source file extension for C++ test sources. ac_ext=cc # Object file extension for compiled C++ test sources. objext=o _LT_AC_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_AC_SYS_COMPILER # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_AC_TAGVAR(compiler, $1)=$CC cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` # We don't want -fno-exception wen compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration AC_PROG_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ grep 'no-whole-archive' > /dev/null; then _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_AC_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_AC_TAGVAR(archive_cmds, $1)='' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=yes else # We have old collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_AC_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) _LT_AC_TAGVAR(always_export_symbols, $1)=yes # Exported symbols can be pulled into shared objects from archives _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds it's shared libraries. _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) if test "$GXX" = yes; then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case "$host_os" in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; dgux*) case $cc_basename in ec++) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; ghcx) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[12]*) # C++ shared libraries reported to be fairly broken before switch to ELF _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | kfreebsd*-gnu) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_AC_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aCC) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then case "$host_cpu" in hppa*64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; ia64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; *) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case "$host_cpu" in hppa*64*) _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; ia64*) _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; *) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aCC) case "$host_cpu" in hppa*64*|ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case "$host_cpu" in ia64*|hppa*64*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; irix5* | irix6*) case $cc_basename in CC) # SGI C++ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' fi fi _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; linux*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc) # Intel C++ with_gnu_ld=yes _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; cxx) # Compaq C++ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; osf3*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; cxx) _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; osf4* | osf5*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; cxx) _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ $rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; sco*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case $cc_basename in CC) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; lcc) # Lucid # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The C++ compiler is used as linker so we must use $wl # flag to pass the commands to the underlying system # linker. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac _LT_AC_TAGVAR(link_all_deplibs, $1)=yes # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx) # Green Hills C++ Compiler _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | grep -v '^2\.7' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' fi ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_AC_TAGVAR(GCC, $1)="$GXX" _LT_AC_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... AC_LIBTOOL_POSTDEP_PREDEP($1) AC_LIBTOOL_PROG_COMPILER_PIC($1) AC_LIBTOOL_PROG_CC_C_O($1) AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) AC_LIBTOOL_PROG_LD_SHLIBS($1) AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) AC_LIBTOOL_SYS_LIB_STRIP AC_LIBTOOL_DLOPEN_SELF($1) AC_LIBTOOL_CONFIG($1) AC_LANG_POP CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ldcxx=$with_gnu_ld with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld ])# AC_LIBTOOL_LANG_CXX_CONFIG # AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) # ------------------------ # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" ifelse([$1], [], [#! $SHELL # `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # # This file is part of GNU Libtool: # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="$SED -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi # The names of the tagged configurations supported by this script. available_tags= # ### BEGIN LIBTOOL CONFIG], [# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) # Is the compiler the GNU C compiler? with_gcc=$_LT_AC_TAGVAR(GCC, $1) # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_[]_LT_AC_TAGVAR(LD, $1) # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext='$shrext' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) # Commands used to build and install a shared archive. archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) # Flag that forces no undefined symbols. no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" # Set to yes if exported symbols are required. always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) # The commands to list exported symbols. export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) # Symbols that must always be exported. include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) ifelse([$1],[], [# ### END LIBTOOL CONFIG], [# ### END LIBTOOL TAG CONFIG: $tagname]) __EOF__ ifelse([$1],[], [ case $host_os in aix3*) cat <<\EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || \ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ]) else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. test -f Makefile && make "$ltmain" fi ])# AC_LIBTOOL_CONFIG # AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------------------- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi ])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE # --------------------------------- AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_NM]) AC_REQUIRE([AC_OBJEXT]) # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Transform the above into a raw symbol and a C symbol. symxfrm='\1 \2\3 \3' # Transform an extracted symbol line into a proper C declaration lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32*) symcode='[[ABCDGISTW]]' ;; hpux*) # Its linker distinguishes data from code symbols if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris* | sysv5*) symcode='[[BDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGISTW]]' ;; esac # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Write the raw and C identifiers. lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if grep ' nm_test_var$' "$nlist" >/dev/null; then if grep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' cat <> conftest.$ac_ext #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[[]] = { EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext cat <<\EOF >> conftest.$ac_ext {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -f conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi ]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE # AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) # --------------------------------------- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], [_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) ifelse([$1],[CXX],[ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | os2* | pw32*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix4* | aix5*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68) # Green Hills C++ Compiler # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx) # Green Hills C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | kfreebsd*-gnu) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" if test "$host_cpu" != ia64; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux*) case $cc_basename in KCC) # KAI C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; icpc) # Intel C++ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; cxx) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; osf3* | osf4* | osf5*) case $cc_basename in KCC) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC) # Rational C++ 2.4.1 _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx) # Digital/Compaq C++ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; sco*) case $cc_basename in CC) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; *) ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx) # Green Hills C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc) # Lucid _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; unixware*) ;; vxworks*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; newsos6) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; linux*) case $CC in icc* | ecc*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; ccc*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; sco3.2v5*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' ;; solaris*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sunos4*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; uts4*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" ;; esac ]) # AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) # ------------------------------------ # See if the linker supports building shared libraries. AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) ifelse([$1],[CXX],[ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix4* | aix5*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' else _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw*) _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' ;; *) _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ],[ runpath_var= _LT_AC_TAGVAR(allow_undefined_flag, $1)= _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_AC_TAGVAR(archive_cmds, $1)= _LT_AC_TAGVAR(archive_expsym_cmds, $1)= _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown _LT_AC_TAGVAR(hardcode_automatic, $1)=no _LT_AC_TAGVAR(module_cmds, $1)= _LT_AC_TAGVAR(module_expsym_cmds, $1)= _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_AC_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac _LT_AC_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_AC_TAGVAR(ld_shlibs, $1)=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then _LT_AC_TAGVAR(ld_shlibs, $1)=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; sunos4*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then runpath_var=LD_RUN_PATH _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=yes _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' else _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_AC_TAGVAR(archive_cmds, $1)='' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=yes else # We have old collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_AC_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) _LT_AC_TAGVAR(always_export_symbols, $1)=yes # Exported symbols can be pulled into shared objects from archives _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds it's shared libraries. _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # see comment about different semantics on the GNU ld section _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; bsdi4*) _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext=".dll" # FIXME: Setting linknames here is a bad hack. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no case "$host_os" in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; dgux*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; ia64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes ;; *) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; openbsd*) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi ;; os2*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; sco3.2v5*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_AC_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_AC_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4.2uw2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv5*) _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' ;; uts4*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac fi ]) AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_AC_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) _LT_AC_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac ])# AC_LIBTOOL_PROG_LD_SHLIBS # _LT_AC_FILE_LTDLL_C # ------------------- # Be careful that the start marker always follows a newline. AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ # /* ltdll.c starts here */ # #define WIN32_LEAN_AND_MEAN # #include # #undef WIN32_LEAN_AND_MEAN # #include # # #ifndef __CYGWIN__ # # ifdef __CYGWIN32__ # # define __CYGWIN__ __CYGWIN32__ # # endif # #endif # # #ifdef __cplusplus # extern "C" { # #endif # BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); # #ifdef __cplusplus # } # #endif # # #ifdef __CYGWIN__ # #include # DECLARE_CYGWIN_DLL( DllMain ); # #endif # HINSTANCE __hDllInstance_base; # # BOOL APIENTRY # DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) # { # __hDllInstance_base = hInst; # return TRUE; # } # /* ltdll.c ends here */ ])# _LT_AC_FILE_LTDLL_C # _LT_AC_TAGVAR(VARNAME, [TAGNAME]) # --------------------------------- AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) # old names AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) # This is just to silence aclocal about the macro not being used ifelse([AC_DISABLE_FAST_INSTALL]) AC_DEFUN([LT_AC_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj, no) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS) ]) AC_DEFUN([LT_AC_PROG_RC], [AC_CHECK_TOOL(RC, windres, no) ]) ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ # LT_AC_PROG_SED # -------------- # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. AC_DEFUN([LT_AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && break cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done SED=$lt_cv_path_SED ]) AC_MSG_RESULT([$SED]) ]) hercules-3.12/autoconf/ltdl.m40000664000175000017500000003303012564723224013221 00000000000000## ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- ## Copyright (C) 1999-2000 Free Software Foundation, Inc. ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## ## As a special exception to the GNU General Public License, if you ## distribute this file as part of a program that contains a ## configuration script generated by Autoconf, you may include it under ## the same distribution terms that you use for the rest of that program. # serial 6 AC_LIB_LTDL # AC_WITH_LTDL # ------------ # Clients of libltdl can use this macro to allow the installer to # choose between a shipped copy of the ltdl sources or a preinstalled # version of the library. AC_DEFUN([AC_WITH_LTDL], [AC_REQUIRE([AC_LIB_LTDL]) AC_SUBST([LIBLTDL]) AC_SUBST([INCLTDL]) # Unless the user asks us to check, assume no installed ltdl exists. use_installed_libltdl=no AC_ARG_WITH([included_ltdl], [ --with-included-ltdl use the GNU ltdl sources included here]) if test "x$with_included_ltdl" != xyes; then # We are not being forced to use the included libltdl sources, so # decide whether there is a useful installed version we can use. AC_CHECK_HEADER([ltdl.h], [AC_CHECK_LIB([ltdl], [lt_dlcaller_register], [with_included_ltdl=no], [with_included_ltdl=yes]) ]) fi if test "x$enable_ltdl_install" != xyes; then # If the user did not specify an installable libltdl, then default # to a convenience lib. AC_LIBLTDL_CONVENIENCE fi if test "x$with_included_ltdl" = xno; then # If the included ltdl is not to be used. then Use the # preinstalled libltdl we found. AC_DEFINE([HAVE_LTDL], 1, [Define this if a modern libltdl is already installed]) LIBLTDL=-lltdl fi # Report our decision... AC_MSG_CHECKING([whether to use included libltdl]) AC_MSG_RESULT([$with_included_ltdl]) AC_CONFIG_SUBDIRS([libltdl]) ])# AC_WITH_LTDL # AC_LIB_LTDL # ----------- # Perform all the checks necessary for compilation of the ltdl objects # -- including compiler checks and header checks. AC_DEFUN([AC_LIB_LTDL], [AC_PREREQ(2.50) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_C_CONST]) AC_REQUIRE([AC_HEADER_STDC]) AC_REQUIRE([AC_HEADER_DIRENT]) AC_REQUIRE([_LT_AC_CHECK_DLFCN]) AC_REQUIRE([AC_LTDL_ENABLE_INSTALL]) AC_REQUIRE([AC_LTDL_SHLIBEXT]) AC_REQUIRE([AC_LTDL_SHLIBPATH]) AC_REQUIRE([AC_LTDL_SYSSEARCHPATH]) AC_REQUIRE([AC_LTDL_OBJDIR]) AC_REQUIRE([AC_LTDL_DLPREOPEN]) AC_REQUIRE([AC_LTDL_DLLIB]) AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) AC_REQUIRE([AC_LTDL_DLSYM_USCORE]) AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS]) AC_REQUIRE([AC_LTDL_FUNC_ARGZ]) AC_CHECK_HEADERS([assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ stdio.h unistd.h]) AC_CHECK_HEADERS([dl.h sys/dl.h dld.h mach-o/dyld.h]) AC_CHECK_HEADERS([string.h strings.h], [break]) AC_CHECK_FUNCS([strchr index], [break]) AC_CHECK_FUNCS([strrchr rindex], [break]) AC_CHECK_FUNCS([memcpy bcopy], [break]) AC_CHECK_FUNCS([memmove strcmp]) AC_CHECK_FUNCS([closedir opendir readdir]) ])# AC_LIB_LTDL # AC_LTDL_ENABLE_INSTALL # ---------------------- AC_DEFUN([AC_LTDL_ENABLE_INSTALL], [AC_ARG_ENABLE([ltdl-install], [AC_HELP_STRING([--enable-ltdl-install], [install libltdl])]) AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno) ])])# AC_LTDL_ENABLE_INSTALL # AC_LTDL_SYS_DLOPEN_DEPLIBS # -------------------------- AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], [AC_REQUIRE([AC_CANONICAL_HOST]) AC_CACHE_CHECK([whether deplibs are loaded by dlopen], [libltdl_cv_sys_dlopen_deplibs], [# PORTME does your system automatically load deplibs for dlopen? # or its logical equivalent (e.g. shl_load for HP-UX < 11) # For now, we just catch OSes we know something about -- in the # future, we'll try test this programmatically. libltdl_cv_sys_dlopen_deplibs=unknown case "$host_os" in aix3*|aix4.1.*|aix4.2.*) # Unknown whether this is true for these versions of AIX, but # we want this `case' here to explicitly catch those versions. libltdl_cv_sys_dlopen_deplibs=unknown ;; aix[[45]]*) libltdl_cv_sys_dlopen_deplibs=yes ;; darwin*) # Assuming the user has installed a libdl from somewhere, this is true # If you are looking for one http://www.opendarwin.org/projects/dlcompat libltdl_cv_sys_dlopen_deplibs=yes ;; kfreebsd*-gnu) libltdl_cv_sys_dlopen_deplibs=yes ;; gnu*) libltdl_cv_sys_dlopen_deplibs=yes ;; hpux10*|hpux11*) libltdl_cv_sys_dlopen_deplibs=yes ;; irix[[12345]]*|irix6.[[01]]*) # Catch all versions of IRIX before 6.2, and indicate that we don't # know how it worked for any of those versions. libltdl_cv_sys_dlopen_deplibs=unknown ;; irix*) # The case above catches anything before 6.2, and it's known that # at 6.2 and later dlopen does load deplibs. libltdl_cv_sys_dlopen_deplibs=yes ;; linux*) libltdl_cv_sys_dlopen_deplibs=yes ;; netbsd*) libltdl_cv_sys_dlopen_deplibs=yes ;; openbsd*) libltdl_cv_sys_dlopen_deplibs=yes ;; osf[[1234]]*) # dlopen did load deplibs (at least at 4.x), but until the 5.x series, # it did *not* use an RPATH in a shared library to find objects the # library depends on, so we explictly say `no'. libltdl_cv_sys_dlopen_deplibs=no ;; osf5.0|osf5.0a|osf5.1) # dlopen *does* load deplibs and with the right loader patch applied # it even uses RPATH in a shared library to search for shared objects # that the library depends on, but there's no easy way to know if that # patch is installed. Since this is the case, all we can really # say is unknown -- it depends on the patch being installed. If # it is, this changes to `yes'. Without it, it would be `no'. libltdl_cv_sys_dlopen_deplibs=unknown ;; osf*) # the two cases above should catch all versions of osf <= 5.1. Read # the comments above for what we know about them. # At > 5.1, deplibs are loaded *and* any RPATH in a shared library # is used to find them so we can finally say `yes'. libltdl_cv_sys_dlopen_deplibs=yes ;; solaris*) libltdl_cv_sys_dlopen_deplibs=yes ;; esac ]) if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], [Define if the OS needs help to load dependent libraries for dlopen().]) fi ])# AC_LTDL_SYS_DLOPEN_DEPLIBS # AC_LTDL_SHLIBEXT # ---------------- AC_DEFUN([AC_LTDL_SHLIBEXT], [AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) AC_CACHE_CHECK([which extension is used for loadable modules], [libltdl_cv_shlibext], [ module=yes eval libltdl_cv_shlibext=$shrext_cmds ]) if test -n "$libltdl_cv_shlibext"; then AC_DEFINE_UNQUOTED(LTDL_SHLIB_EXT, "$libltdl_cv_shlibext", [Define to the extension used for shared libraries, say, ".so".]) fi ])# AC_LTDL_SHLIBEXT # AC_LTDL_SHLIBPATH # ----------------- AC_DEFUN([AC_LTDL_SHLIBPATH], [AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) AC_CACHE_CHECK([which variable specifies run-time library path], [libltdl_cv_shlibpath_var], [libltdl_cv_shlibpath_var="$shlibpath_var"]) if test -n "$libltdl_cv_shlibpath_var"; then AC_DEFINE_UNQUOTED(LTDL_SHLIBPATH_VAR, "$libltdl_cv_shlibpath_var", [Define to the name of the environment variable that determines the dynamic library search path.]) fi ])# AC_LTDL_SHLIBPATH # AC_LTDL_SYSSEARCHPATH # --------------------- AC_DEFUN([AC_LTDL_SYSSEARCHPATH], [AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) AC_CACHE_CHECK([for the default library search path], [libltdl_cv_sys_search_path], [libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec"]) if test -n "$libltdl_cv_sys_search_path"; then sys_search_path= for dir in $libltdl_cv_sys_search_path; do if test -z "$sys_search_path"; then sys_search_path="$dir" else sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" fi done AC_DEFINE_UNQUOTED(LTDL_SYSSEARCHPATH, "$sys_search_path", [Define to the system default library search path.]) fi ])# AC_LTDL_SYSSEARCHPATH # AC_LTDL_OBJDIR # -------------- AC_DEFUN([AC_LTDL_OBJDIR], [AC_CACHE_CHECK([for objdir], [libltdl_cv_objdir], [libltdl_cv_objdir="$objdir" if test -n "$objdir"; then : else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then libltdl_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. libltdl_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi ]) AC_DEFINE_UNQUOTED(LTDL_OBJDIR, "$libltdl_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# AC_LTDL_OBJDIR # AC_LTDL_DLPREOPEN # ----------------- AC_DEFUN([AC_LTDL_DLPREOPEN], [AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], [libltdl_cv_preloaded_symbols], [if test -n "$lt_cv_sys_global_symbol_pipe"; then libltdl_cv_preloaded_symbols=yes else libltdl_cv_preloaded_symbols=no fi ]) if test x"$libltdl_cv_preloaded_symbols" = xyes; then AC_DEFINE(HAVE_PRELOADED_SYMBOLS, 1, [Define if libtool can extract symbol lists from object files.]) fi ])# AC_LTDL_DLPREOPEN # AC_LTDL_DLLIB # ------------- AC_DEFUN([AC_LTDL_DLLIB], [LIBADD_DL= AC_SUBST(LIBADD_DL) AC_LANG_PUSH([C]) AC_CHECK_FUNC([shl_load], [AC_DEFINE([HAVE_SHL_LOAD], [1], [Define if you have the shl_load function.])], [AC_CHECK_LIB([dld], [shl_load], [AC_DEFINE([HAVE_SHL_LOAD], [1], [Define if you have the shl_load function.]) LIBADD_DL="$LIBADD_DL -ldld"], [AC_CHECK_LIB([dl], [dlopen], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes"], [AC_TRY_LINK([#if HAVE_DLFCN_H # include #endif ], [dlopen(0, 0);], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen="yes"], [AC_CHECK_LIB([svld], [dlopen], [AC_DEFINE([HAVE_LIBDL], [1], [Define if you have the libdl library or equivalent.]) LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes"], [AC_CHECK_LIB([dld], [dld_link], [AC_DEFINE([HAVE_DLD], [1], [Define if you have the GNU dld library.]) LIBADD_DL="$LIBADD_DL -ldld"], [AC_CHECK_FUNC([_dyld_func_lookup], [AC_DEFINE([HAVE_DYLD], [1], [Define if you have the _dyld_func_lookup function.])]) ]) ]) ]) ]) ]) ]) if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes then lt_save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DL" AC_CHECK_FUNCS([dlerror]) LIBS="$lt_save_LIBS" fi AC_LANG_POP ])# AC_LTDL_DLLIB # AC_LTDL_SYMBOL_USCORE # --------------------- # does the compiler prefix global symbols with an underscore? AC_DEFUN([AC_LTDL_SYMBOL_USCORE], [AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) AC_CACHE_CHECK([for _ prefix in compiled symbols], [ac_cv_sys_symbol_underscore], [ac_cv_sys_symbol_underscore=no cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then # See whether the symbols have a leading underscore. if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then ac_cv_sys_symbol_underscore=yes else if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then : else echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC fi fi else echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC fi else echo "configure: failed program was:" >&AC_FD_CC cat conftest.c >&AC_FD_CC fi rm -rf conftest* ]) ])# AC_LTDL_SYMBOL_USCORE # AC_LTDL_DLSYM_USCORE # -------------------- AC_DEFUN([AC_LTDL_DLSYM_USCORE], [AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) if test x"$ac_cv_sys_symbol_underscore" = xyes; then if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then AC_CACHE_CHECK([whether we have to add an underscore for dlsym], [libltdl_cv_need_uscore], [libltdl_cv_need_uscore=unknown save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DL" _LT_AC_TRY_DLOPEN_SELF( [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], [], [libltdl_cv_need_uscore=cross]) LIBS="$save_LIBS" ]) fi fi if test x"$libltdl_cv_need_uscore" = xyes; then AC_DEFINE(NEED_USCORE, 1, [Define if dlsym() requires a leading underscore in symbol names.]) fi ])# AC_LTDL_DLSYM_USCORE # AC_LTDL_FUNC_ARGZ # ----------------- AC_DEFUN([AC_LTDL_FUNC_ARGZ], [AC_CHECK_HEADERS([argz.h]) AC_CHECK_TYPES([error_t], [], [AC_DEFINE([error_t], [int], [Define to a type to use for `error_t' if it is not otherwise available.])], [#if HAVE_ARGZ_H # include #endif]) AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify]) ])# AC_LTDL_FUNC_ARGZ hercules-3.12/autoconf/mkinstalldirs0000775000175000017500000000342112564723224014627 00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id$ errstatus=0 dirmode="" usage="\ Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." # process command line arguments while test $# -gt 0 ; do case "${1}" in -h | --help | --h* ) # -h for help echo "${usage}" 1>&2; exit 0 ;; -m ) # -m PERM arg shift test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } dirmode="${1}" shift ;; -- ) shift; break ;; # stop option processing -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option * ) break ;; # first non-opt arg esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac case $dirmode in '') if mkdir -p -- . 2>/dev/null; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" fi ;; *) if mkdir -m "$dirmode" -p -- . 2>/dev/null; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" fi ;; esac for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr="" chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp="$pathcomp/" done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 3 # End: # mkinstalldirs ends here hercules-3.12/autoconf/depcomp0000775000175000017500000002752512564723224013411 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects # Copyright 1999, 2000 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # `libtool' can also be set to `yes' or `no'. depfile=${depfile-`echo "$object" | sed 's,\([^/]*\)$,.deps/\1,;s/\.\([^.]*\)$/.P\1/'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. This file always lives in the current directory. # Also, the AIX compiler puts `$object:' at the start of each line; # $object doesn't have directory information. stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" outname="$stripped.o" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; tru64) # The Tru64 AIX compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. tmpdepfile1="$object.d" tmpdepfile2=`echo "$object" | sed -e 's/.o$/.d/'` if test "$libtool" = yes; then "$@" -Wc,-MD else "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi if test -f "$tmpdepfile1"; then tmpdepfile="$tmpdepfile1" else tmpdepfile="$tmpdepfile2" fi if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a space and a tab in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the proprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. test -z "$dashmflag" && dashmflag=-M ( IFS=" " case " $* " in *" --mode=compile "*) # this is libtool, let us make it quiet for arg do # cycle over the arguments case "$arg" in "--mode=compile") # insert --quiet before "--mode=compile" set fnord "$@" --quiet shift # fnord ;; esac set fnord "$@" "$arg" shift # fnord shift # "$arg" done ;; esac "$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) # X makedepend ( shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift;; -*) ;; *) set fnord "$@" "$arg"; shift;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tail +3 "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the proprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. ( IFS=" " case " $* " in *" --mode=compile "*) for arg do # cycle over the arguments case $arg in "--mode=compile") # insert --quiet before "--mode=compile" set fnord "$@" --quiet shift # fnord ;; esac set fnord "$@" "$arg" shift # fnord shift # "$arg" done ;; esac "$@" -E | sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the proprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. ( IFS=" " case " $* " in *" --mode=compile "*) for arg do # cycle over the arguments case $arg in "--mode=compile") # insert --quiet before "--mode=compile" set fnord "$@" --quiet shift # fnord ;; esac set fnord "$@" "$arg" shift # fnord shift # "$arg" done ;; esac "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" ) & proc=$! "$@" stat=$? wait "$proc" if test "$stat" != 0; then exit $stat; fi rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 hercules-3.12/autoconf/ltmain.sh0000664000175000017500000054140312564723224013650 00000000000000# ltmain.sh - Provide generalized library-building support services. # NOTE: Changing this file will not affect anything until you rerun configure. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 # Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Check that we have a working $echo. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell, and then maybe $echo will work. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat <&2 $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 fi # Global variables. mode=$default_mode nonopt= prev= prevopt= run= show="$echo" show_help= execute_dlfiles= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" ##################################### # Shell function definitions: # This seems to be the best place for them # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. win32_libid () { win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ grep -E 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | \ sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` if test "X$win32_nmres" = "Ximport" ; then win32_libid_type="x86 archive import" else win32_libid_type="x86 archive static" fi fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $echo $win32_libid_type } # End of Shell function definitions ##################################### # Parse our command line options once, thoroughly. while test "$#" -gt 0 do arg="$1" shift case $arg in -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in execute_dlfiles) execute_dlfiles="$execute_dlfiles $arg" ;; tag) tagname="$arg" # Check whether tagname contains only valid characters case $tagname in *[!-_A-Za-z0-9,/]*) $echo "$progname: invalid tag name: $tagname" 1>&2 exit 1 ;; esac case $tagname in CC) # Don't test for the "default" C tag, as we know, it's there, but # not specially marked. ;; *) if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$0" > /dev/null; then taglist="$taglist $tagname" # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $0`" else $echo "$progname: ignoring unknown tag $tagname" 1>&2 fi ;; esac ;; *) eval "$prev=\$arg" ;; esac prev= prevopt= continue fi # Have we seen a non-optional argument yet? case $arg in --help) show_help=yes ;; --version) $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" $echo $echo "Copyright (C) 2003 Free Software Foundation, Inc." $echo "This is free software; see the source for copying conditions. There is NO" $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." exit 0 ;; --config) ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0 # Now print the configurations for the tags. for tagname in $taglist; do ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$0" done exit 0 ;; --debug) $echo "$progname: enabling shell trace mode" set -x ;; --dry-run | -n) run=: ;; --features) $echo "host: $host" if test "$build_libtool_libs" = yes; then $echo "enable shared libraries" else $echo "disable shared libraries" fi if test "$build_old_libs" = yes; then $echo "enable static libraries" else $echo "disable static libraries" fi exit 0 ;; --finish) mode="finish" ;; --mode) prevopt="--mode" prev=mode ;; --mode=*) mode="$optarg" ;; --preserve-dup-deps) duplicate_deps="yes" ;; --quiet | --silent) show=: ;; --tag) prevopt="--tag" prev=tag ;; --tag=*) set tag "$optarg" ${1+"$@"} shift prev=tag ;; -dlopen) prevopt="-dlopen" prev=execute_dlfiles ;; -*) $echo "$modename: unrecognized option \`$arg'" 1>&2 $echo "$help" 1>&2 exit 1 ;; *) nonopt="$arg" break ;; esac done if test -n "$prevopt"; then $echo "$modename: option \`$prevopt' requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= if test -z "$show_help"; then # Infer the operation mode. if test -z "$mode"; then $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2 case $nonopt in *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) mode=link for arg do case $arg in -c) mode=compile break ;; esac done ;; *db | *dbx | *strace | *truss) mode=execute ;; *install*|cp|mv) mode=install ;; *rm) mode=uninstall ;; *) # If we have no mode, but dlfiles were specified, then do execute mode. test -n "$execute_dlfiles" && mode=execute # Just use the default operation mode. if test -z "$mode"; then if test -n "$nonopt"; then $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 else $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 fi fi ;; esac fi # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then $echo "$modename: unrecognized option \`-dlopen'" 1>&2 $echo "$help" 1>&2 exit 1 fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$modename --help --mode=$mode' for more information." # These modes are in order of execution frequency so that they run quickly. case $mode in # libtool compile mode compile) modename="$modename: compile" # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_output= arg_mode=normal libobj= for arg do case "$arg_mode" in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) if test -n "$libobj" ; then $echo "$modename: you cannot specify \`-o' more than once" 1>&2 exit 1 fi arg_mode=target continue ;; -static) build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac lastarg="$lastarg $arg" done IFS="$save_ifs" lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` # Add the arguments to base_compile. base_compile="$base_compile $lastarg" continue ;; * ) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` case $lastarg in # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") lastarg="\"$lastarg\"" ;; esac base_compile="$base_compile $lastarg" done # for arg case $arg_mode in arg) $echo "$modename: you must specify an argument for -Xcompile" exit 1 ;; target) $echo "$modename: you must specify a target with \`-o'" 1>&2 exit 1 ;; *) # Get the name of the library object. [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo xform='[cCFSifmso]' case $libobj in *.ada) xform=ada ;; *.adb) xform=adb ;; *.ads) xform=ads ;; *.asm) xform=asm ;; *.c++) xform=c++ ;; *.cc) xform=cc ;; *.ii) xform=ii ;; *.class) xform=class ;; *.cpp) xform=cpp ;; *.cxx) xform=cxx ;; *.f90) xform=f90 ;; *.for) xform=for ;; *.java) xform=java ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` case $libobj in *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; *) $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 exit 1 ;; esac # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. if test -n "$available_tags" && test -z "$tagname"; then case $base_compile in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`" case "$base_compile " in "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then $echo "$modename: unable to infer tagged configuration" $echo "$modename: specify a tag with \`--tag'" 1>&2 exit 1 # else # $echo "$modename: using $tagname tagged configuration" fi ;; esac fi objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then xdir= else xdir=$xdir/ fi lobj=${xdir}$objdir/$objname if test -z "$base_compile"; then $echo "$modename: you must specify a compilation command" 1>&2 $echo "$help" 1>&2 exit 1 fi # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi $run $rm $removelist trap "$run $rm $removelist; exit 1" 1 2 15 # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" removelist="$removelist $output_obj $lockfile" trap "$run $rm $removelist; exit 1" 1 2 15 else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $run ln "$0" "$lockfile" 2>/dev/null; do $show "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $echo "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi $echo $srcfile > "$lockfile" fi if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi $run $rm "$libobj" "${libobj}T" # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then $echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then $show "$mv $output_obj $lobj" if $run $mv $output_obj $lobj; then : else error=$? $run $rm $removelist exit $error fi fi # Append the name of the PIC object to the libtool object file. test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then $echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then $show "$mv $output_obj $obj" if $run $mv $output_obj $obj; then : else error=$? $run $rm $removelist exit $error fi fi # Append the name of the non-PIC object the libtool object file. # Only append if the libtool object file exists. test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi else if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi fi build_libtool_libs=no build_old_libs=yes prefer_static_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" base_compile="$base_compile $arg" shift case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test ;; *) qarg=$arg ;; esac libtool_args="$libtool_args $qarg" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) compile_command="$compile_command @OUTPUT@" finalize_command="$finalize_command @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. compile_command="$compile_command @SYMFILE@" finalize_command="$finalize_command @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" if test ! -f "$arg"; then $echo "$modename: symbol file \`$arg' does not exist" exit 1 fi prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat $save_arg` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then pic_object= non_pic_object= # Read the .lo file # If there is no directory component, then add one. case $arg in */* | *\\*) . $arg ;; *) . ./$arg ;; esac if test -z "$pic_object" || \ test -z "$non_pic_object" || test "$pic_object" = none && \ test "$non_pic_object" = none; then $echo "$modename: cannot find name of object for \`$arg'" 1>&2 exit 1 fi # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. libobjs="$libobjs $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object non_pic_objects="$non_pic_objects $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi fi else # Only an error if not doing a dry-run. if test -z "$run"; then $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 exit 1 else # Dry-run case. # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` libobjs="$libobjs $pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi fi done else $echo "$modename: link input file \`$save_arg' does not exist" exit 1 fi arg=$save_arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit 1 ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= compile_command="$compile_command $qarg" finalize_command="$finalize_command $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= compile_command="$compile_command $wl$qarg" finalize_command="$finalize_command $wl$qarg" continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= compile_command="$compile_command $qarg" finalize_command="$finalize_command $qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 continue ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: more than one -exported-symbols argument is not allowed" exit 1 fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" ;; esac continue ;; -L*) dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 exit 1 fi dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) case :$dllsearchpath: in *":$dir:"*) ;; *) dllsearchpath="$dllsearchpath:$dir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-pw32* | *-*-beos*) # These systems don't actually have a C or math library (as such) continue ;; *-*-mingw* | *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs -framework System" continue esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; # gcc -m* arguments should be passed to the linker via $compiler_flags # in order to pass architecture information to the linker # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo # but this is not reliable with gcc because gcc may use -mfoo to # select a different linker, different libraries, etc, while # -Wl,-mfoo simply passes -mfoo to the linker. -m*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" if test "$with_gcc" = "yes" ; then compiler_flags="$compiler_flags $arg" fi continue ;; -shrext) prev=shrext continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) # The PATH hackery in wrapper scripts is required on Windows # in order for the loader to find any dlls it needs. $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit 1 ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -static) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -Wc,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Wl,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $wl$flag" linker_flags="$linker_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # Some other compiler flag. -* | +*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then pic_object= non_pic_object= # Read the .lo file # If there is no directory component, then add one. case $arg in */* | *\\*) . $arg ;; *) . ./$arg ;; esac if test -z "$pic_object" || \ test -z "$non_pic_object" || test "$pic_object" = none && \ test "$non_pic_object" = none; then $echo "$modename: cannot find name of object for \`$arg'" 1>&2 exit 1 fi # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. libobjs="$libobjs $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object non_pic_objects="$non_pic_objects $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi fi else # Only an error if not doing a dry-run. if test -z "$run"; then $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 exit 1 else # Dry-run case. # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` libobjs="$libobjs $pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi done # argument parsing loop if test -n "$prev"; then $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base link # command doesn't match the default compiler. if test -n "$available_tags" && test -z "$tagname"; then case $base_compile in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`" case $base_compile in "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) # The compiler in $compile_command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then $echo "$modename: unable to infer tagged configuration" $echo "$modename: specify a tag with \`--tag'" 1>&2 exit 1 # else # $echo "$modename: using $tagname tagged configuration" fi ;; esac fi if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi oldlibs= # calculate the name of the file, without its directory outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi # Create the object directory. if test ! -d "$output_objdir"; then $show "$mkdir $output_objdir" $run $mkdir $output_objdir status=$? if test "$status" -ne 0 && test ! -d "$output_objdir"; then exit $status fi fi # Determine the type of output case $output in "") $echo "$modename: you must specify an output file" 1>&2 $echo "$help" 1>&2 exit 1 ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac case $host in *cygwin* | *mingw* | *pw32*) # don't eliminate duplcations in $postdeps and $predeps duplicate_compiler_generated_deps=yes ;; *) duplicate_compiler_generated_deps=$duplicate_deps ;; esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if test "X$duplicate_deps" = "Xyes" ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 exit 1 ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 continue fi if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do for search_ext in .la $shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then library_names= old_library= case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` test "X$ladir" = "X$lib" && ladir="." lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi ;; *) $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) if test "$deplibs_check_method" != pass_all; then $echo $echo "*** Warning: Trying to link with static lib archive $deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because the file extensions .$libext of this argument makes me believe" $echo "*** that it is just a static archive that I should not used here." else $echo $echo "*** Warning: Linking the shared library $output against the" $echo "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else $echo "$modename: cannot find the library \`$lib'" 1>&2 exit 1 fi # Check to see that this really is a libtool archive. if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit 1 fi ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` test "X$ladir" = "X$lib" && ladir="." dlname= dlopen= dlpreopen= libdir= library_names= old_library= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no # Read the .la file case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit 1 fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then $echo "$modename: \`$lib' is not a convenience library" 1>&2 exit 1 fi continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit 1 fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 exit 1 fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 abs_ladir="$ladir" fi ;; esac laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then $echo "$modename: warning: library \`$lib' was moved." 1>&2 dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi # $installed = yes name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 exit 1 fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { test "$prefer_static_libs" = no || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var"; then # Make sure the rpath contains only unique directories. case "$temp_rpath " in *" $dir "*) ;; *" $absdir "*) ;; *) temp_rpath="$temp_rpath $dir" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically if test -n "$library_names" && { test "$prefer_static_libs" = no || test -z "$old_library"; }; then if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi # This is a shared library # Warn about portability, can't link against -module's on some systems (darwin) if test "$shouldnotlink" = yes && test "$pass" = link ; then $echo if test "$linkmode" = prog; then $echo "*** Warning: Linking the executable $output against the loadable module" else $echo "*** Warning: Linking the shared library $output against the loadable module" fi $echo "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names realname="$2" shift; shift libname=`eval \\$echo \"$libname_spec\"` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw*) major=`expr $current - $age` versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" soname=`$echo $soroot | ${SED} -e 's/^.*\///'` newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else $show "extracting exported symbol list from \`$soname'" save_ifs="$IFS"; IFS='~' eval cmds=\"$extract_expsyms_cmds\" for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else $show "generating import library for \`$soname'" save_ifs="$IFS"; IFS='~' eval cmds=\"$old_archive_from_expsyms_cmds\" for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5* ) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a module then we can not link against it, someone # is ignoring the new warnings I added if /usr/bin/file -L $add 2> /dev/null | grep "bundle" >/dev/null ; then $echo "** Warning, lib $linklib is a module, not a shared library" if test -z "$old_library" ; then $echo $echo "** And there doesn't seem to be a static archive available" $echo "** The link will probably fail, sorry" else add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case "$libdir" in [\\/]*) add_dir="-L$inst_prefix_dir$libdir $add_dir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then $echo "$modename: configuration error: unsupported hardcode properties" exit 1 fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && \ test "$hardcode_minus_L" != yes && \ test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case "$libdir" in [\\/]*) add_dir="-L$inst_prefix_dir$libdir $add_dir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. $echo $echo "*** Warning: This system can not link to static lib archive $lib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then $echo "*** But as you try to build a module library, libtool will still create " $echo "*** a static module, that should work as long as the dlopening application" $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then $echo $echo "*** However, this would only work if libtool was able to extract symbol" $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" $echo "*** not find such a program. So, this module is probably useless." $echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else convenience="$convenience $dir/$old_library" old_convenience="$old_convenience $dir/$old_library" deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do case $deplib in -L*) path="$deplib" ;; *.la) dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$deplib" && dir="." # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 absdir="$dir" fi ;; esac if grep "^installed=no" $deplib > /dev/null; then path="$absdir/$objdir" else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit 1 fi if test "$absdir" != "$libdir"; then $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 fi path="$absdir" fi depdepl= case $host in *-*-darwin*) # we do not want to link against static libs, but need to link against shared eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$path/$depdepl" ; then depdepl="$path/$depdepl" fi # do not add paths which are already there case " $newlib_search_path " in *" $path "*) ;; *) newlib_search_path="$newlib_search_path $path";; esac path="" fi ;; *) path="-L$path" ;; esac ;; -l*) case $host in *-*-darwin*) # Again, we only want to link against shared libraries eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` for tmp in $newlib_search_path ; do if test -f "$tmp/lib$tmp_libs.dylib" ; then eval depdepl="$tmp/lib$tmp_libs.dylib" break fi done path="" ;; *) continue ;; esac ;; *) continue ;; esac case " $deplibs " in *" $depdepl "*) ;; *) deplibs="$deplibs $depdepl" ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$deplibs $path" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 fi if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 fi # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` eval shared_ext=\"$shrext\" eval libname=\"$libname_spec\" ;; *) if test "$module" = no; then $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 $echo "$help" 1>&2 exit 1 fi if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` eval shared_ext=\"$shrext\" eval libname=\"$libname_spec\" else libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 exit 1 else $echo $echo "*** Warning: Linking the shared library $output against the non-libtool" $echo "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi if test "$dlself" != no; then $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 fi set dummy $rpath if test "$#" -gt 2; then $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 fi install_libdir="$2" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 fi else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 IFS="$save_ifs" if test -n "$8"; then $echo "$modename: too many parameters to \`-version-info'" 1>&2 $echo "$help" 1>&2 exit 1 fi # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$2" number_minor="$3" number_revision="$4" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows) current=`expr $number_major + $number_minor` age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) current=`expr $number_major + $number_minor - 1` age="$number_minor" revision="$number_minor" ;; esac ;; no) current="$2" revision="$3" age="$4" ;; esac # Check that each of the things are valid numbers. case $current in 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; *) $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case $revision in 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; *) $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case $age in 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; *) $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac if test "$age" -gt "$current"; then $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header major=.`expr $current - $age` versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... minor_current=`expr $current + 1` verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current"; ;; irix | nonstopux) major=`expr $current - $age + 1` case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do iface=`expr $revision - $loop` loop=`expr $loop - 1` verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) major=.`expr $current - $age` versuffix="$major.$age.$revision" ;; osf) major=.`expr $current - $age` versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do iface=`expr $current - $loop` loop=`expr $loop - 1` verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. major=`expr $current - $age` versuffix="-$major" ;; *) $echo "$modename: unknown library version type \`$version_type'" 1>&2 $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$echo "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) removelist="$removelist $p" ;; *) ;; esac done if test -n "$removelist"; then $show "${rm}r $removelist" $run ${rm}r $removelist fi fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. for path in $notinst_path; do lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'` deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'` dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs -framework System" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $rm conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null \ | grep " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ | ${SED} 10q \ | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $echo $echo "*** Warning: linker path does not have real file for library $a_deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $echo "*** with $libname but no candidates were found. (...for file magic test)" else $echo "*** with $libname and none of the candidates passed a file format test" $echo "*** using a file magic. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` for a_deplib in $deplibs; do name="`expr $a_deplib : '-l\(.*\)'`" # If $name is empty we are operating on a -L argument. if test -n "$name" && test "$name" != "0"; then if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval \\$echo \"$libname_spec\"` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval $echo \"$potent_lib\" 2>/dev/null \ | ${SED} 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $echo $echo "*** Warning: linker path does not have real file for library $a_deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $echo "*** with $libname but no candidates were found. (...for regex pattern test)" else $echo "*** with $libname and none of the candidates passed a file format test" $echo "*** using a regex pattern. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ -e 's/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` done fi if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ | grep . >/dev/null; then $echo if test "X$deplibs_check_method" = "Xnone"; then $echo "*** Warning: inter-library dependencies are not supported in this platform." else $echo "*** Warning: inter-library dependencies are not known to be supported." fi $echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then $echo $echo "*** Warning: libtool could not satisfy all declared inter-library" $echo "*** dependencies of module $libname. Therefore, libtool will create" $echo "*** a static module, that should work as long as the dlopening" $echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then $echo $echo "*** However, this would only work if libtool was able to extract symbol" $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" $echo "*** not find such a program. So, this module is probably useless." $echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else $echo "*** The inter-library dependencies that have been dropped here will be" $echo "*** automatically added whenever a program is linked with this library" $echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then $echo $echo "*** Since this library must not contain undefined symbols," $echo "*** because either the platform does not support them or" $echo "*** it was explicitly requested with -no-undefined," $echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext\" eval library_names=\"$library_names_spec\" set dummy $library_names realname="$2" shift; shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols eval cmds=\"$export_symbols_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" if len=`expr "X$cmd" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then $show "$cmd" $run eval "$cmd" || exit $? skipped_export=false else # The command line is too long to execute in one step. $show "using reloadable object file for export list..." skipped_export=: fi done IFS="$save_ifs" if test -n "$export_symbols_regex"; then $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' $show "$mv \"${export_symbols}T\" \"$export_symbols\"" $run eval '$mv "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" else gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "$mkdir $gentop" $run $mkdir "$gentop" status=$? if test "$status" -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "$mkdir $xdir" $run $mkdir "$xdir" status=$? if test "$status" -ne 0 && test ! -d "$xdir"; then exit $status fi # We will extract separately just the conflicting names and we will no # longer touch any unique names. It is faster to leave these extract # automatically by $AR in one run. $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 $AR t "$xabs" | sort | uniq -cd | while read -r count name do i=1 while test "$i" -le "$count" do # Put our $i before any first dot (extension) # Never overwrite any file name_to="$name" while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" do name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` done $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? i=`expr $i + 1` done done fi libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval cmds=\"$module_expsym_cmds\" else eval cmds=\"$module_cmds\" fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval cmds=\"$archive_expsym_cmds\" else eval cmds=\"$archive_cmds\" fi fi if test "X$skipped_export" != "X:" && len=`expr "X$cmds" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise. $echo "creating reloadable object files..." # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= delfiles= last_robj= k=1 output=$output_objdir/$save_output-${k}.$objext # Loop over the list of objects to be linked. for obj in $save_libobjs do eval test_cmds=\"$reload_cmds $objlist $last_robj\" if test "X$objlist" = X || { len=`expr "X$test_cmds" : ".*"` && test "$len" -le "$max_cmd_len"; }; then objlist="$objlist $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. eval concat_cmds=\"$reload_cmds $objlist $last_robj\" else # All subsequent reloadable object files will link in # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" fi last_robj=$output_objdir/$save_output-${k}.$objext k=`expr $k + 1` output=$output_objdir/$save_output-${k}.$objext objlist=$obj len=1 fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if ${skipped_export-false}; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols libobjs=$output # Append the command to create the export file. eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" fi # Set up a command to remove the reloadale object files # after they are used. i=0 while test "$i" -lt "$k" do i=`expr $i + 1` delfiles="$delfiles $output_objdir/$save_output-${i}.$objext" done $echo "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval cmds=\"$archive_expsym_cmds\" else eval cmds=\"$archive_cmds\" fi # Append the command to remove the reloadable object files # to the just-reset $cmds. eval cmds=\"\$cmds~$rm $delfiles\" fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? exit 0 fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 fi case $output in *.lo) if test -n "$objs$old_deplibs"; then $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 exit 1 fi libobj="$output" obj=`$echo "X$output" | $Xsed -e "$lo2o"` ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $run $rm $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" else gentop="$output_objdir/${obj}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "$mkdir $gentop" $run $mkdir "$gentop" status=$? if test "$status" -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "$mkdir $xdir" $run $mkdir "$xdir" status=$? if test "$status" -ne 0 && test ! -d "$xdir"; then exit $status fi # We will extract separately just the conflicting names and we will no # longer touch any unique names. It is faster to leave these extract # automatically by $AR in one run. $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 $AR t "$xabs" | sort | uniq -cd | while read -r count name do i=1 while test "$i" -le "$count" do # Put our $i before any first dot (extension) # Never overwrite any file name_to="$name" while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" do name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` done $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? i=`expr $i + 1` done done fi reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" eval cmds=\"$reload_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit 0 fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $run eval "echo timestamp > $libobj" || exit $? exit 0 fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" eval cmds=\"$reload_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit 0 ;; prog) case $host in *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; esac if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 fi if test "$preload" = yes; then if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && test "$dlopen_self_static" = unknown; then $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." fi fi case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` ;; esac case $host in *darwin*) # Don't allow lazy linking, it breaks C++ global constructors if test "$tagname" = CXX ; then compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" fi ;; esac compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) case :$dllsearchpath: in *":$libdir:"*) ;; *) dllsearchpath="$dllsearchpath:$libdir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then dlsyms="${outputname}S.c" else $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 fi fi if test -n "$dlsyms"; then case $dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${outputname}.nm" $show "$rm $nlist ${nlist}S ${nlist}T" $run $rm "$nlist" "${nlist}S" "${nlist}T" # Parse the name list into a source file. $show "creating $output_objdir/$dlsyms" test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ /* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ /* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ #ifdef __cplusplus extern \"C\" { #endif /* Prevent the only kind of declaration conflicts we can make. */ #define lt_preloaded_symbols some_other_symbol /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then $show "generating symbol list for \`$output'" test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for arg in $progfiles; do $show "extracting global C symbols from \`$arg'" $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi if test -n "$export_symbols_regex"; then $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$output.exp" $run $rm $export_symbols $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' else $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' $run eval 'mv "$nlist"T "$nlist"' fi fi for arg in $dlprefiles; do $show "extracting global C symbols from \`$arg'" name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` $run eval '$echo ": $name " >> "$nlist"' $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -z "$run"; then # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $mv "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if grep -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else grep -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' else $echo '/* NONE */' >> "$output_objdir/$dlsyms" fi $echo >> "$output_objdir/$dlsyms" "\ #undef lt_preloaded_symbols #if defined (__STDC__) && __STDC__ # define lt_ptr void * #else # define lt_ptr char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr address; } lt_preloaded_symbols[] = {\ " eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" $echo >> "$output_objdir/$dlsyms" "\ {0, (lt_ptr) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " fi pic_flag_for_symtable= case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; esac;; *-*-hpux*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag";; esac esac # Now compile the dynamic symbol file. $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? # Clean up the generated files. $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" # Transform the symbol file into the correct name. compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` ;; *) $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 exit 1 ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi if test "$need_relink" = no || test "$build_libtool_libs" != yes; then # Replace the output file specification. compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. $show "$link_command" $run eval "$link_command" status=$? # Delete the generated files. if test -n "$dlsyms"; then $show "$rm $output_objdir/${outputname}S.${objext}" $run $rm "$output_objdir/${outputname}S.${objext}" fi exit $status fi if test -n "$shlibpath_var"; then # We should set the shlibpath_var rpath= for dir in $temp_rpath; do case $dir in [\\/]* | [A-Za-z]:[\\/]*) # Absolute path. rpath="$rpath$dir:" ;; *) # Relative path: add a thisdir entry. rpath="$rpath\$thisdir/$dir:" ;; esac done temp_rpath="$rpath" fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $run $rm $output # Link the executable and exit $show "$link_command" $run eval "$link_command" || exit $? exit 0 fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 $echo "$modename: \`$output' will be relinked during installation" 1>&2 else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname $show "$link_command" $run eval "$link_command" || exit $? # Now create the wrapper script. $show "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $echo for shipping. if test "X$echo" = "X$SHELL $0 --fallback-echo"; then case $0 in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; *) qecho="$SHELL `pwd`/$0 --fallback-echo";; esac qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if our run command is non-null. if test -z "$run"; then # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) cwrappersource=`$echo ${objdir}/lt-${output}.c` cwrapper=`$echo ${output}.exe` $rm $cwrappersource $cwrapper trap "$rm $cwrappersource $cwrapper; exit 1" 1 2 15 cat > $cwrappersource <> $cwrappersource<<"EOF" #include #include #include #include #include #include #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef DIR_SEPARATOR #define DIR_SEPARATOR '/' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) #define HAVE_DOS_BASED_FILE_SYSTEM #ifndef DIR_SEPARATOR_2 #define DIR_SEPARATOR_2 '\\' #endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) const char *program_name = NULL; void * xmalloc (size_t num); char * xstrdup (const char *string); char * basename (const char *name); char * fnqualify(const char *path); char * strendzap(char *str, const char *pat); void lt_fatal (const char *message, ...); int main (int argc, char *argv[]) { char **newargz; int i; program_name = (char *) xstrdup ((char *) basename (argv[0])); newargz = XMALLOC(char *, argc+2); EOF cat >> $cwrappersource <> $cwrappersource <<"EOF" newargz[1] = fnqualify(argv[0]); /* we know the script has the same name, without the .exe */ /* so make sure newargz[1] doesn't end in .exe */ strendzap(newargz[1],".exe"); for (i = 1; i < argc; i++) newargz[i+1] = xstrdup(argv[i]); newargz[argc+1] = NULL; EOF cat >> $cwrappersource <> $cwrappersource <<"EOF" } void * xmalloc (size_t num) { void * p = (void *) malloc (num); if (!p) lt_fatal ("Memory exhausted"); return p; } char * xstrdup (const char *string) { return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL ; } char * basename (const char *name) { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (isalpha (name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) if (IS_DIR_SEPARATOR (*name)) base = name + 1; return (char *) base; } char * fnqualify(const char *path) { size_t size; char *p; char tmp[LT_PATHMAX + 1]; assert(path != NULL); /* Is it qualified already? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha (path[0]) && path[1] == ':') return xstrdup (path); #endif if (IS_DIR_SEPARATOR (path[0])) return xstrdup (path); /* prepend the current directory */ /* doesn't handle '~' */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */ p = XMALLOC(char, size); sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path); return p; } char * strendzap(char *str, const char *pat) { size_t len, patlen; assert(str != NULL); assert(pat != NULL); len = strlen(str); patlen = strlen(pat); if (patlen <= len) { str += len - patlen; if (strcmp(str, pat) == 0) *str = '\0'; } return str; } static void lt_error_core (int exit_status, const char * mode, const char * message, va_list ap) { fprintf (stderr, "%s: %s: ", program_name, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, "FATAL", message, ap); va_end (ap); } EOF # we should really use a build-platform specific compiler # here, but OTOH, the wrappers (shell script and this C one) # are only useful if you want to execute the "real" binary. # Since the "real" binary is built for $host, then this # wrapper might as well be built for $host, too. $run $LTCC -s -o $cwrapper $cwrappersource ;; esac $rm $output trap "$rm $output; exit 1" 1 2 15 $echo > $output "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variable: notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$echo are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then echo=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then # Yippee, \$echo works! : else # Restart under the correct shell, and then maybe \$echo will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $echo >> $output "\ # Find the directory that this script lives in. thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $echo >> $output "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || \\ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $mkdir \"\$progdir\" else $rm \"\$progdir/\$file\" fi" $echo >> $output "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $echo \"\$relink_command_output\" >&2 $rm \"\$progdir/\$file\" exit 1 fi fi $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $rm \"\$progdir/\$program\"; $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } $rm \"\$progdir/\$file\" fi" else $echo >> $output "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $echo >> $output "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $echo >> $output "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $echo >> $output "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $echo >> $output "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2*) $echo >> $output "\ exec \$progdir\\\\\$program \${1+\"\$@\"} " ;; *) $echo >> $output "\ exec \$progdir/\$program \${1+\"\$@\"} " ;; esac $echo >> $output "\ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" exit 1 fi else # The program doesn't exist. \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 \$echo \"This script is just a wrapper for \$program.\" 1>&2 $echo \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " chmod +x $output fi exit 0 ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "$mkdir $gentop" $run $mkdir "$gentop" status=$? if test "$status" -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" # Add in members from convenience archives. for xlib in $addlibs; do # Extract the objects. case $xlib in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "$mkdir $xdir" $run $mkdir "$xdir" status=$? if test "$status" -ne 0 && test ! -d "$xdir"; then exit $status fi # We will extract separately just the conflicting names and we will no # longer touch any unique names. It is faster to leave these extract # automatically by $AR in one run. $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 $AR t "$xabs" | sort | uniq -cd | while read -r count name do i=1 while test "$i" -le "$count" do # Put our $i before any first dot (extension) # Never overwrite any file name_to="$name" while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" do name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` done $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? i=`expr $i + 1` done done fi oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` done fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then eval cmds=\"$old_archive_from_new_cmds\" else eval cmds=\"$old_archive_cmds\" if len=`expr "X$cmds" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # the command line is too long to link in one step, link in parts $echo "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs # GNU ar 2.10+ was changed to match POSIX; thus no paths are # encoded into archives. This makes 'ar r' malfunction in # this piecewise linking case whenever conflicting object # names appear in distinct ar calls; check, warn and compensate. if (for obj in $save_oldobjs do $echo "X$obj" | $Xsed -e 's%^.*/%%' done | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2 $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2 AR_FLAGS=cq fi # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done for obj in $save_oldobjs do oldobjs="$objlist $obj" objlist="$objlist $obj" eval test_cmds=\"$old_archive_cmds\" if len=`expr "X$test_cmds" : ".*"` && test "$len" -le "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~$old_archive_cmds\" fi fi fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$generated"; then $show "${rm}r$generated" $run ${rm}r$generated fi # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" $show "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $0 --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. if test -z "$run"; then for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit 1 fi newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit 1 fi newdlfiles="$newdlfiles $libdir/$name" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit 1 fi newdlprefiles="$newdlprefiles $libdir/$name" done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $rm $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $echo > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $echo >> $output "\ relink_command=\"$relink_command\"" fi done fi # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? ;; esac exit 0 ;; # libtool install mode install) modename="$modename: install" # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then # Aesthetically quote it. arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$arg " arg="$1" shift else install_prog= arg="$nonopt" fi # The real first argument should be the name of the installation program. # Aesthetically quote it. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog$arg" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest="$arg" continue fi case $arg in -d) isdir=yes ;; -f) prev="-f" ;; -g) prev="-g" ;; -m) prev="-m" ;; -o) prev="-o" ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest="$arg" continue fi ;; esac # Aesthetically quote the argument. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog $arg" done if test -z "$install_prog"; then $echo "$modename: you must specify an install program" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -n "$prev"; then $echo "$modename: the \`$prev' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -z "$files"; then if test -z "$dest"; then $echo "$modename: no file or destination specified" 1>&2 else $echo "$modename: you must specify a destination" 1>&2 fi $echo "$help" 1>&2 exit 1 fi # Strip any trailing slash from the destination. dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` test "X$destdir" = "X$dest" && destdir=. destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` # Not a directory, so check to see that there is only one file specified. set dummy $files if test "$#" -gt 2; then $echo "$modename: \`$dest' is not a directory" 1>&2 $echo "$help" 1>&2 exit 1 fi fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi library_names= old_library= relink_command= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ test "X$dir" = "X$file/" && dir= dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. if test "$inst_prefix_dir" = "$destdir"; then $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 exit 1 fi if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi $echo "$modename: warning: relinking \`$file'" 1>&2 $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 exit 1 fi fi # See the names of the shared library. set dummy $library_names if test -n "$2"; then realname="$2" shift shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. $show "$install_prog $dir/$srcname $destdir/$realname" $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? if test -n "$stripme" && test -n "$striplib"; then $show "$striplib $destdir/$realname" $run eval "$striplib $destdir/$realname" || exit $? fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. for linkname do if test "$linkname" != "$realname"; then $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" fi done fi # Do each command in the postinstall commands. lib="$destdir/$realname" eval cmds=\"$postinstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Install the pseudo-library for information purposes. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` instname="$dir/$name"i $show "$install_prog $instname $destdir/$name" $run eval "$install_prog $instname $destdir/$name" || exit $? # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` ;; *.$objext) staticdest="$destfile" destfile= ;; *) $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac # Install the libtool object if requested. if test -n "$destfile"; then $show "$install_prog $file $destfile" $run eval "$install_prog $file $destfile" || exit $? fi # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` $show "$install_prog $staticobj $staticdest" $run eval "$install_prog \$staticobj \$staticdest" || exit $? fi exit 0 ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then file=`$echo $file|${SED} 's,.exe$,,'` stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin*|*mingw*) wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` ;; *) wrapper=$file ;; esac if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then notinst_deplibs= relink_command= # To insure that "foo" is sourced, and not "foo.exe", # finese the cygwin/MSYS system by explicitly sourcing "foo." # which disallows the automatic-append-.exe behavior. case $build in *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; *) wrapperdot=${wrapper} ;; esac # If there is no directory component, then add one. case $file in */* | *\\*) . ${wrapperdot} ;; *) . ./${wrapperdot} ;; esac # Check the variables that should have been set. if test -z "$notinst_deplibs"; then $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 exit 1 fi finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then # If there is no directory component, then add one. case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac fi libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 finalize=no fi done relink_command= # To insure that "foo" is sourced, and not "foo.exe", # finese the cygwin/MSYS system by explicitly sourcing "foo." # which disallows the automatic-append-.exe behavior. case $build in *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; *) wrapperdot=${wrapper} ;; esac # If there is no directory component, then add one. case $file in */* | *\\*) . ${wrapperdot} ;; *) . ./${wrapperdot} ;; esac outputname= if test "$fast_install" = no && test -n "$relink_command"; then if test "$finalize" = yes && test -z "$run"; then tmpdir="/tmp" test -n "$TMPDIR" && tmpdir="$TMPDIR" tmpdir="$tmpdir/libtool-$$" if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : else $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 continue fi file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 ${rm}r "$tmpdir" continue fi file="$outputname" else $echo "$modename: warning: cannot relink \`$file'" 1>&2 fi else # Install the binary that we compiled earlier. file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyways case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` ;; esac ;; esac $show "$install_prog$stripme $file $destfile" $run eval "$install_prog\$stripme \$file \$destfile" || exit $? test -n "$outputname" && ${rm}r "$tmpdir" ;; esac done for file in $staticlibs; do name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` # Set up the ranlib parameters. oldlib="$destdir/$name" $show "$install_prog $file $oldlib" $run eval "$install_prog \$file \$oldlib" || exit $? if test -n "$stripme" && test -n "$striplib"; then $show "$old_striplib $oldlib" $run eval "$old_striplib $oldlib" || exit $? fi # Do each command in the postinstall commands. eval cmds=\"$old_postinstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$future_libdirs"; then $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 fi if test -n "$current_libdirs"; then # Maybe just do a dry run. test -n "$run" && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $0 --finish$current_libdirs' else exit 0 fi ;; # libtool finish mode finish) modename="$modename: finish" libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. eval cmds=\"$finish_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || admincmds="$admincmds $cmd" done IFS="$save_ifs" fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $run eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. test "$show" = : && exit 0 $echo "----------------------------------------------------------------------" $echo "Libraries have been installed in:" for libdir in $libdirs; do $echo " $libdir" done $echo $echo "If you ever happen to want to link against installed libraries" $echo "in a given directory, LIBDIR, you must either use libtool, and" $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" $echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" $echo " during execution" fi if test -n "$runpath_var"; then $echo " - add LIBDIR to the \`$runpath_var' environment variable" $echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $echo " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $echo " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi $echo $echo "See any operating system documentation about shared libraries for" $echo "more information, such as the ld(1) and ld.so(8) manual pages." $echo "----------------------------------------------------------------------" exit 0 ;; # libtool execute mode execute) modename="$modename: execute" # The first argument is the command name. cmd="$nonopt" if test -z "$cmd"; then $echo "$modename: you must specify a COMMAND" 1>&2 $echo "$help" exit 1 fi # Handle -dlopen flags immediately. for file in $execute_dlfiles; do if test ! -f "$file"; then $echo "$modename: \`$file' is not a file" 1>&2 $echo "$help" 1>&2 exit 1 fi dir= case $file in *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi # Read the libtool library. dlname= library_names= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" continue fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 exit 1 fi ;; *.lo) # Just add the directory containing the .lo file. dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. ;; *) $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` args="$args \"$file\"" done if test -z "$run"; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables if test "${save_LC_ALL+set}" = set; then LC_ALL="$save_LC_ALL"; export LC_ALL fi if test "${save_LANG+set}" = set; then LANG="$save_LANG"; export LANG fi # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" $echo "export $shlibpath_var" fi $echo "$cmd$args" exit 0 fi ;; # libtool clean and uninstall mode clean | uninstall) modename="$modename: $mode" rm="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) rm="$rm $arg"; rmforce=yes ;; -*) rm="$rm $arg" ;; *) files="$files $arg" ;; esac done if test -z "$rm"; then $echo "$modename: you must specify an RM program" 1>&2 $echo "$help" 1>&2 exit 1 fi rmdirs= origobjdir="$objdir" for file in $files; do dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$file"; then dir=. objdir="$origobjdir" else objdir="$dir/$origobjdir" fi name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if (test -L "$file") >/dev/null 2>&1 \ || (test -h "$file") >/dev/null 2>&1 \ || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then . $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" if test "$mode" = uninstall; then if test -n "$library_names"; then # Do each command in the postuninstall commands. eval cmds=\"$postuninstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" if test "$?" -ne 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. eval cmds=\"$old_postuninstall_cmds\" save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" if test "$?" -ne 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi # FIXME: should reinstall the best remaining shared library. fi fi ;; *.lo) # Possibly a libtool object, so verify it. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # Read the .lo file . $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" \ && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" \ && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) file=`$echo $file|${SED} 's,.exe$,,'` noexename=`$echo $name|${SED} 's,.exe$,,'` # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then relink_command= . $dir/$noexename # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac $show "$rm $rmfiles" $run $rm $rmfiles || exit_status=1 done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then $show "rmdir $dir" $run rmdir $dir >/dev/null 2>&1 fi done exit $exit_status ;; "") $echo "$modename: you must specify a MODE" 1>&2 $echo "$generic_help" 1>&2 exit 1 ;; esac if test -z "$exec_cmd"; then $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$generic_help" 1>&2 exit 1 fi fi # test -z "$show_help" if test -n "$exec_cmd"; then eval exec $exec_cmd exit 1 fi # We need to display help for each of the modes. case $mode in "") $echo \ "Usage: $modename [OPTION]... [MODE-ARG]... Provide generalized library-building support services. --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --finish same as \`--mode=finish' --help display this help message and exit --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] --quiet same as \`--silent' --silent don't print informational messages --tag=TAG use configuration variables from tag TAG --version print version information MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for a more detailed description of MODE. Report bugs to ." exit 0 ;; clean) $echo \ "Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $echo \ "Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -static always build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $echo \ "Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $echo \ "Usage: $modename [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $echo \ "Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $echo \ "Usage: $modename [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -static do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $echo \ "Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac $echo $echo "Try \`$modename --help' for more information about other modes." exit 0 # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: hercules-3.12/autoconf/config.guess0000775000175000017500000012216612564723224014351 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-07-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha*:OpenVMS:*:*) echo alpha-hp-vms exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*|*:GNU/FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` # GNU/FreeBSD systems have a "k" prefix to indicate we are using # FreeBSD's kernel, but not the complete OS. case ${LIBC} in gnu) kernel_only='k' ;; esac echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) case `uname -p` in *86) UNAME_PROCESSOR=i686 ;; powerpc) UNAME_PROCESSOR=powerpc ;; esac case $MACHTYPE in x86_64*) UNAME_PROCESSOR=x86_64 ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: hercules-3.12/autoconf/config.sub0000775000175000017500000007314112564723224014012 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-07-04' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: hercules-3.12/autoconf/README0000664000175000017500000000010612564723224012676 00000000000000This is where autoconf and automake will place their auxiliary files. hercules-3.12/autoconf/compile0000775000175000017500000001624512564723224013407 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: hercules-3.12/autoconf/config.rpath0000664000175000017500000003343412564723224014335 00000000000000#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2002 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # All known linkers require a `.a' archive for static linking (except M$VC, # which needs '.lib'). libext=a shlibext= host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix3* | aix4* | aix5*) wl='-Wl,' ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6*) wl='-Wl,' ;; linux*) echo '__INTEL_COMPILER' > conftest.$ac_ext if $CC -E conftest.$ac_ext >/dev/null | grep __INTEL_COMPILER >/dev/null then : else # Intel icc wl='-Qoption,ld,' fi ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) if test "x$host_vendor" = xsni; then wl='-LD' else wl='-Wl,' fi ;; esac fi hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then case "$host_os" in aix3* | aix4* | aix5*) # On AIX, the GNU linker is very broken ld_shlibs=no ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' ;; solaris* | sysv5*) if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi esac fi if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=yes ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9* | hpux10* | hpux11*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_minus_L=yes # Not in the search PATH, but as the default # location of the library. ;; irix5* | irix6*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; sco3.2v5*) ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) if test "x$host_vendor" = xsno; then hardcode_direct=yes # is this really true??? else hardcode_direct=no # Motorola manual says yes, but my tests say they lie fi ;; sysv4.3*) ;; sysv5*) hardcode_libdir_flag_spec= ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4.2uw2*) hardcode_direct=yes hardcode_minus_L=no ;; sysv5uw7* | unixware7*) ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics libname_spec='lib$name' sys_lib_dlsearch_path_spec="/lib /usr/lib" sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" case "$host_os" in aix3*) shlibext=so ;; aix4* | aix5*) shlibext=so ;; amigaos*) shlibext=ixlibrary ;; beos*) shlibext=so ;; bsdi4*) shlibext=so sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" ;; cygwin* | mingw* | pw32*) case $GCC,$host_os in yes,cygwin*) shlibext=dll.a ;; yes,mingw*) shlibext=dll sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` ;; yes,pw32*) shlibext=dll ;; *) shlibext=dll ;; esac ;; darwin* | rhapsody*) shlibext=dylib ;; freebsd1*) ;; freebsd*) shlibext=so ;; gnu*) shlibext=so ;; hpux9* | hpux10* | hpux11*) shlibext=sl ;; irix5* | irix6*) shlibext=so case "$host_os" in irix5*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 ") libsuff= shlibsuff= ;; *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" ;; linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) ;; linux-gnu*) shlibext=so ;; netbsd*) shlibext=so ;; newsos6) shlibext=so ;; openbsd*) shlibext=so ;; os2*) libname_spec='$name' shlibext=dll ;; osf3* | osf4* | osf5*) shlibext=so sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) shlibext=so ;; solaris*) shlibext=so ;; sunos4*) shlibext=so ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) shlibext=so case "$host_vendor" in motorola) sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; uts4*) shlibext=so ;; dgux*) shlibext=so ;; sysv4*MP*) if test -d /usr/nec; then shlibext=so fi ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_sys_lib_search_path_spec=`echo "X$sys_lib_search_path_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_sys_lib_dlsearch_path_spec=`echo "X$sys_lib_dlsearch_path_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <, 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch]" ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing 0.3 - GNU automake" ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; aclocal) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then # We have makeinfo, but it failed. exit 1 fi echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; tar) shift if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 fi # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar ${1+"$@"} && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar ${1+"$@"} && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" ${1+"$@"} && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" ${1+"$@"} && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and you do not seem to have it handy on your system. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequirements for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 hercules-3.12/msvc.makefile.includes/0000775000175000017500000000000012625667404014621 500000000000000hercules-3.12/msvc.makefile.includes/BZIP2_DIR.msvc0000664000175000017500000000506512564723224016760 00000000000000# *************************************************************************** # BZIP2_DIR.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Handles support for BZIP2 compression # # *************************************************************************** # --------------------------------------------------------------------- # To enable BZIP2 compression, first make sure you have the libbz2.dll # installed on your system (from: http://sources.redhat.com/bzip2/), # and then define an environment variable called "BZIP2_DIR" that # specifies the full path to the directory where it is installed. # (via the "Advanced" tab of the Control Panel 'System' applet). # # Note that the directory you specify should contain the libbz2.dll as # well as the 'bzlib.h' header file and the 'libbz2.lib' link library. # # Note: if the path contains blanks, do NOT surround it with quotes! # The makefile will do that if it needs to. Just define the variable # with the path as-is. E.g.: # # BZIP2_DIR = E:\MyProjects\bzip2 # --------------------------------------------------------------------- !IFNDEF BZIP2_DIR # Undefined: use default value, if it exists. # BZIP2_DIR defaults to winbuild\bzip2 relative to current directory !IF "$(CPU)" == "i386" && EXIST(winbuild\bzip2) BZIP2_DIR = winbuild\bzip2 !ELSEIF "$(CPU)" == "AMD64" && EXIST(winbuild\bzip2\x64) BZIP2_DIR = winbuild\bzip2\x64 !ELSEIF "$(CPU)" == "IA64" && EXIST(winbuild\bzip2\ia64) BZIP2_DIR = winbuild\bzip2\ia64 !ENDIF !ELSE # Defined: use explicit directory or subdirectory # unless "NONE" is specified or it doesn't exist. !IF "$(BZIP2_DIR)" == "NONE" !UNDEF BZIP2_DIR !ELSE !IF "$(CPU)" == "i386" !IF !EXIST($(BZIP2_DIR)) !UNDEF BZIP2_DIR !ENDIF !ELSEIF "$(CPU)" == "AMD64" !IF EXIST($(BZIP2_DIR)\x64) BZIP2_DIR = $(BZIP2_DIR)\x64 !ENDIF !ELSEIF "$(CPU)" == "IA64" !IF EXIST($(BZIP2_DIR)\ia64) BZIP2_DIR = $(BZIP2_DIR)\ia64 !ENDIF !ENDIF !ENDIF !ENDIF !IFDEF BZIP2_DIR !IF !EXIST("$(BZIP2_DIR)\bzlib.h") !ERROR BZIP2_DIR "$(BZIP2_DIR)\bzlib.h" does not exist. Check BZIP2_DIR !ELSEIF !EXIST("$(BZIP2_DIR)\libbz2.lib") !ERROR BZIP2_DIR "$(BZIP2_DIR)\libbz2.lib" does not exist. Check BZIP2_DIR !ELSEIF !EXIST("$(BZIP2_DIR)\libbz2.dll") !ERROR BZIP2_DIR "$(BZIP2_DIR)\libbz2.dll" does not exist. Check BZIP2_DIR !ENDIF !MESSAGE BZIP2 support will be included from "$(BZIP2_DIR)" !ELSE !MESSAGE BZIP2 support will not be generated !ENDIF hercules-3.12/msvc.makefile.includes/BZIP2_FLAGS.msvc0000664000175000017500000000154312564723224017173 00000000000000# *************************************************************************** # BZIP2_FLAGS.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Sets BZIP2-compression-related compiler/linker flags & #defines... # # # CHANGE HISTORY # $Log$ # # DD/MM/YY Description # # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** !IFDEF BZIP2_DIR BZIP2_DLL = $(BZIP2_DIR)\libbz2.dll BZIP2_LIB = $(BZIP2_DIR)/libbz2.lib BZIP2_INC = $(BZIP2_DIR) LIBS = $(LIBS) "$(BZIP2_LIB)" cflags = $(cflags) /D HAVE_BZLIB_H /I"$(BZIP2_INC)" !ENDIF hercules-3.12/msvc.makefile.includes/BZIP2_RULES.msvc0000664000175000017500000000202612564723224017226 00000000000000# *************************************************************************** # BZIP2_RULES.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2010 # -------------------------------------------------------------------------- # $Id$ # # BZIP2 build rules # # *************************************************************************** !IFDEF BZIP2_DIR $(X)libbz2.dll: XCOPY "$(BZIP2_DLL)" $(X) /V /C /F /H /R /K /Y alllibbz2: allHercules \ $(X)libbz2.dll !ELSE alllibbz2: allHercules !ENDIF # NOTE: to be safe, since this member contains build rules, we need to # make sure there's always a blank line following the last build rule # in the member so that nmake doesn't complain or otherwise treat the # statements immediately following the original !INCLUDE statement as # part of the build rule actions. Thus the purpose of the comments you # are now reading as the very last few lines in every build rule member. hercules-3.12/msvc.makefile.includes/CONFIG.msvc0000664000175000017500000000371112564723224016375 00000000000000# *************************************************************************** # CONFIG.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Set NODEBUG flag appropriately before !INCLUDEing # and attempt to determine the Visual Studio compiler version # # *************************************************************************** # Use environment variables to determine the Visual Studio compiler level !IFDEF VS120COMNTOOLS !MESSAGE Makefile will assume VS12 or VS2013 Express (MSVC version 18) vsversion=12 !ELSEIFDEF VS110COMNTOOLS !MESSAGE Makefile will assume VS11 or VS2012 Express (MSVC version 17) vsversion=11 !ELSEIFDEF VS100COMNTOOLS !MESSAGE Makefile will assume VS10 or VS2010 Express (MSVC version 16) vsversion=10 !ELSEIFDEF VS90COMNTOOLS !MESSAGE Makefile will assume VS9 or VS2008 Express (MSVC version 15) vsversion=9 !ELSEIFDEF VS80COMNTOOLS !MESSAGE Makefile will assume VS8 or VS2005 Express (MSVC version 14) vsversion=8 !ELSE !ERROR This build requires Visual Studio 8 (or VS2005 Express) or later !ENDIF # Use environment variables to determine the target processor type !IF !DEFINED(CPU) || "$(CPU)" == "" CPU=$(PROCESSOR_ARCHITECTURE) !ENDIF !IF "$(CPU)" == "IA64" !MESSAGE Target processor type is IA64 _WIN64=1 !ELSEIF "$(CPU)" == "AMD64" !MESSAGE Target processor type is AMD64 _WIN64=1 !ELSE !MESSAGE Target processor type is i386 CPU=i386 !UNDEF _WIN64 !ENDIF !MESSAGE # ------------------------------------------------- # NOTE! must set the 'NODEBUG' variable properly # BEFORE calling win32.mak since it uses it. # ------------------------------------------------- !IFNDEF CFG NODEBUG = 1 !ELSEIF "$(CFG)" == "DEBUG" !UNDEF NODEBUG !ELSEIF "$(CFG)" == "RETAIL" NODEBUG = 1 !ELSE !ERROR Invalid build configuration! !ENDIF hercules-3.12/msvc.makefile.includes/DEBUG_RETAIL.msvc0000664000175000017500000000353512564723224017322 00000000000000# *************************************************************************** # DEBUG_RETAIL.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Sets appropriate compiler/linker flags (cdebug & ldebug) depending on # whether a normal retail release or debugging version of the product is # being built... (also sets preprocessor #defines too, as appropriate) # # *************************************************************************** # ------------------------------------------------- # NOTE! must set our prefered 'cdebug' value(s) # AFTER calling win32.mak since it sets it. # ------------------------------------------------- !IF $(vsversion) < 8 MAPFILE = /map:$(MAPDIR)\$(@B).map /mapinfo:lines !ELSE MAPFILE = /map:$(MAPDIR)\$(@B).map !ENDIF !IFDEF NODEBUG # ------------------------------- # RETAIL: full optimization # ------------------------------- # PROGRAMMING NOTE: we're purposely discarding win32.mak's $(cdebug) settings # and replacing them with our own by leaving "$(cdebug)" out of the statement cdebug = /O2 /GL /D NDEBUG ldebug = $(ldebug) /LTCG # Create .PDB (Program Database) files for debugging for 'Release' builds too! # (so we can easily analyze "MiniDump" crash dumps should Herc ever crash) cdebug = $(cdebug) /Zi /Gm ldebug = $(ldebug) /DEBUG /PDB:$(PDBDIR)\$(@B).pdb !ELSE # ------------------------------- # DEBUG: no optimizations at all # ------------------------------- # PROGRAMMING NOTE: we're purposely discarding win32.mak's $(cdebug) settings # and replacing them with our own by leaving "$(cdebug)" out of the statement cdebug = -Zi -Od -D DEBUG -D _DEBUG -Gm ldebug = /DEBUG /PDB:$(PDBDIR)\$(@B).pdb !ENDIF hercules-3.12/msvc.makefile.includes/HERC_FLAGS.msvc0000664000175000017500000000607312564723224017071 00000000000000# *************************************************************************** # HERC_FLAGS.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Sets additional Hercules-related compiler/linker flags & #defines... # # *************************************************************************** # Set some additional flags... ldebug = $(ldebug) $(MAPFILE) # user32.lib for the MessageBeep and MessageBox functions LIBS = $(LIBS) user32.lib # The following line makes all warnings into errors cflags = $(cflags) /WX !IFDEF ASSEMBLY_LISTINGS # /FAcs = source code, assembly code, and machine code cflags = $(cflags) /FAcs /Fa$(ASMDIR)\$(NULL) !ENDIF # PRERELEASE Flag support !IFDEF PRERELEASE rcflags = $(rcflags) -D PRERELEASE=1 !ENDIF !IFDEF _WIN64 rcflags = $(rcflags) -D _WIN64 !ENDIF !IFNDEF MAX_CPU_ENGINES MAX_CPU_ENGINES = 8 !ENDIF rcflags = $(rcflags) -D _MSVC_ -D VERSION=$(VERSION) -D V1=$(V1) -D V2=$(V2) -D V3=$(V3) -D V4=$(V4) cflags = $(cflags) /D _MSVC_ /D VERSION=$(VERSION) /D MAX_CPU_ENGINES=$(MAX_CPU_ENGINES) !IF DEFINED(CUSTOM_BUILD_STRING) cflags = $(cflags) /D CUSTOM_BUILD_STRING=\"$(CUSTOM_BUILD_STRING)\" !ENDIF # Allow version.c to display the name of the host CPU architecture cflags = $(cflags) /D HOST_ARCH=$(CPU) # The following instructs the declaration of DLL export symbols cflags = $(cflags) /D HDL_BUILD_SHARED /D OPTION_DYNAMIC_LOAD # Suppress some deprecation warnings that aren't really deprecation warnings cflags = $(cflags) -D _CRT_SECURE_NO_DEPRECATE cflags = $(cflags) -D _CRT_NONSTDC_NO_DEPRECATE ldebug = $(ldebug) /MANIFEST # Override win32.mak options for WIN64 to eliminate the following warnings # C4200: nonstandard extension used : zero-sized array in struct/union # C4127: conditional expression is constant cflags = $(cflags:-W4=-W3) cflags = $(cflags:/W4=/W3) # Suppress warning 4267 conversion from size_t to int possible loss of data cflags = $(cflags) /wd4267 # D9035: option 'Wp64' has been deprecated and will be removed in a future release. cflags = $(cflags:-Wp64=) cflags = $(cflags:/Wp64=) # Enable "/MP (Build with Multiple Processes)" option # if the building host has more than one processor... !IF $(vsversion) >= 9 && $(NUMBER_OF_PROCESSORS) > 1 cflags = $(cflags) /MP !ENDIF # Note: the "/Gm (Enable Minimal Rebuild)" option is incompatible # with the "/MP (Build with Multiple Processes)" option (and besides # that it's still somewhat buggy) so remove it if it's present... cdebug = $(cdebug:-Gm=) cdebug = $(cdebug:/Gm=) # Specify module base address directly via linker option # so we don't have to rely on user having rebase utility. ldebug = $(ldebug) /base:0x400000 # Optimize for AMD64 CPU architecture !IF "$(CPU)" == "AMD64" cflags = $(cflags) /favor:AMD64 !ENDIF # Increase the sockets set size limit/default to be the # same value as used on most non-Windows platforms (1024) cflags = $(cflags) /D FD_SETSIZE=1024 hercules-3.12/msvc.makefile.includes/MOD_RULES1.msvc0000664000175000017500000000536612564723224017112 00000000000000# *************************************************************************** # MOD_RULES1.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Prerequisite hercules build rules... (precompiled header, etc...) # # # CHANGE HISTORY # $Log$ # DD/MM/YY Description # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** $(O)hercver.res: hercver.rc $(rc) $(rcflags) $(rcvars) -fo $(O)hercver.res hercver.rc $(O)build_pch.pch: build_pch.c $(cc) $(cdebug) $(cflags) /Fp"$(OBJDIR)\\build_pch.pch" /Yc"hstdinc.h" $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" $** !IFNDEF NOCRYPTO {crypto}.c{$(OBJDIR)}.obj:: $(cc) $(cdebug) $(cflags) /Icrypto /I. /Fp"$(OBJDIR)\\build_pch.pch" /Yu"hstdinc.h" $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" $< !ENDIF {decNumber}.c{$(OBJDIR)}.obj:: $(cc) $(cdebug) $(cflags) /IdecNumber /I. $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" $< $(O)dfp.obj: dfp.c $(cc) $(cdebug) $(cflags) /IdecNumber /I. /Fp"$(OBJDIR)\\build_pch.pch" /Yu"hstdinc.h" $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" dfp.c $(O)pfpo.obj: pfpo.c $(cc) $(cdebug) $(cflags) /IdecNumber /I. /Fp"$(OBJDIR)\\build_pch.pch" /Yu"hstdinc.h" $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" pfpo.c $(O)decNumber.res: decNumber\decNumber.rc $(rc) $(rcflags) $(rcvars) -i decNumber -fo $(O)decNumber.res decNumber\decNumber.rc {softfloat}.c{$(OBJDIR)}.obj:: $(cc) $(cdebug) $(cflags) /Isoftfloat /I. $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" $< $(O)ieee.obj: ieee.c $(cc) $(cdebug) $(cflags) /Isoftfloat /I. /Fp"$(OBJDIR)\\build_pch.pch" /Yu"hstdinc.h" $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" ieee.c $(O)softfloat.res: softfloat\softfloat.rc $(rc) $(rcflags) $(rcvars) -i softfloat -fo $(O)softfloat.res softfloat\softfloat.rc # # No precompiled headers for these ones.. Sorry! # $(O)getopt.obj: getopt.c $(cc) $(cdebug) $(cflags) $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" getopt.c $(O)herclin.obj: herclin.c $(cc) $(cdebug) $(cflags) $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" herclin.c # NOTE: to be safe, since this member contains build rules, we need to # make sure there's always a blank line following the last build rule # in the member so that nmake doesn't complain or otherwise treat the # statements immediately following the original !INCLUDE statement as # part of the build rule actions. Thus the purpose of the comments you # are now reading as the very last few lines in every build rule member. hercules-3.12/msvc.makefile.includes/MOD_RULES2.msvc0000664000175000017500000001625212564723224017107 00000000000000# *************************************************************************** # MOD_RULES2.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Individual hercules modules build rules... # # # CHANGE HISTORY # $Log$ # Revision 1.2 2008/03/25 11:41:32 fish # SCSI TAPE MODS part 1: groundwork: non-functional changes: # rename some functions, comments, general restructuring, etc. # New source modules awstape.c, omatape.c, hettape.c and # tapeccws.c added, but not yet used (all will be used in a future # commit though when tapedev.c code is eventually split) # # # DD/MM/YY Description # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** # ------------------------------------------------------------- # DLL export libraries are dependent on themselves existing $(O)decNumber.lib: $(X)decNumber.dll $(O)softfloat.lib: $(X)softfloat.dll $(O)hdasd.lib: $(X)hdasd.dll $(O)htape.lib: $(X)htape.dll $(O)hutil.lib: $(X)hutil.dll $(O)hengine.lib: $(X)hengine.dll $(O)hsys.lib: $(X)hsys.dll # ------------------------------------------------------------- # Individual DLLs are dependent their own code as well as the # export libraries from other DLLs that they're dependent on.. $(X)hsys.dll: $(hsys_OBJ) $(O)hercver.res $(linkdll) $(X)hutil.dll: $(hutil_OBJ) $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)htape.dll: $(htape_OBJ) $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(linkdll) $(X)hdasd.dll: $(hdasd_OBJ) $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(linkdll) $(X)hengine.dll: $(hengine_OBJ) $(O)hsys.lib $(O)hdasd.lib $(O)hutil.lib \ $(O)htape.lib $(O)decNumber.lib $(O)softfloat.lib $(O)hercver.res $(linkdll) # ------------------------------------------------------------- # Device modules $(X)hdt2703.dll: $(O)commadpt.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt3705.dll: $(O)comm3705.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt3088.dll: $(O)ctc_lcs.obj $(O)ctc_ctci.obj $(O)ctcadpt.obj $(O)w32ctca.obj $(O)tuntap.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt3420.dll: $(hdt3420_OBJ) $(O)hengine.lib $(O)htape.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt1403.dll: $(O)printer.obj $(O)sockdev.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt3505.dll: $(O)cardrdr.obj $(O)sockdev.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt3525.dll: $(O)cardpch.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt3270.dll: $(O)console.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdt1052c.dll: $(O)con1052c.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)hdtqeth.dll: $(O)qeth.obj $(O)hengine.lib $(O)hutil.lib $(O)hercver.res $(linkdll) $(X)hdteq.dll: $(O)hdteq.obj $(O)hengine.lib $(O)hutil.lib $(O)hercver.res $(linkdll) $(X)dyngui.dll: $(O)dyngui.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) $(X)dyninst.dll: $(O)dyninst.obj $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) !IFNDEF NOCRYPTO crypto: $(X)dyncrypt.dll $(X)dyncrypt.dll: $(dyncrypt_OBJ) $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(O)hercver.res $(linkdll) !ENDIF $(X)decNumber.dll: $(decNumber_OBJ) $(O)decNumber.res $(link) -nologo $(ldebug) $(dlllflags) $** $(LIBS) /def:decNumber\decNumber.def -out:$@ -implib:$(O)$(@B).lib $(conlibsdll) $(MAPFILE) && $(MT_DLL_CMD) $(X)softfloat.dll: $(softfloat_OBJ) $(O)softfloat.res $(link) -nologo $(ldebug) $(dlllflags) $** $(LIBS) /def:softfloat\softfloat.def -out:$@ -implib:$(O)$(@B).lib $(conlibsdll) $(MAPFILE) && $(MT_DLL_CMD) # ------------------------------------------------------------- # Main product executables $(X)hercules.exe: $(O)bootstrap.obj $(O)hdlmain.obj $(O)hengine.lib $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(linkexe) $(X)herclin.exe: $(O)herclin.obj $(O)hdlmain.obj $(O)hengine.lib $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(linkexe) # ------------------------------------------------------------- # System utilities $(X)conspawn.exe: $(O)$(@B).obj $(O)hercver.res $(X)dmap2hrc.exe: $(O)$(@B).obj $(O)hsys.lib $(O)hutil.lib $(O)hercver.res # ------------------------------------------------------------- # Dasd utilities $(X)cckdcdsk.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)cckdcomp.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)cckddiag.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)cckdswap.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdinit.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdisup.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdload.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdconv.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdcopy.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdls.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdcat.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdpdsu.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)dasdseq.exe: $(O)$(@B).obj $(O)hdasd.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res # ------------------------------------------------------------- # Tape utilities $(X)hetget.exe: $(O)$(@B).obj $(O)htape.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)hetinit.exe: $(O)$(@B).obj $(O)htape.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)hetmap.exe: $(O)$(@B).obj $(O)htape.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)hetupd.exe: $(O)$(@B).obj $(O)htape.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)tapecopy.exe: $(O)$(@B).obj $(O)htape.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)tapemap.exe: $(O)$(@B).obj $(O)htape.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res $(X)tapesplt.exe: $(O)$(@B).obj $(O)htape.lib $(O)hsys.lib $(O)hutil.lib $(O)hercver.res # NOTE: to be safe, since this member contains build rules, we need to # make sure there's always a blank line following the last build rule # in the member so that nmake doesn't complain or otherwise treat the # statements immediately following the original !INCLUDE statement as # part of the build rule actions. Thus the purpose of the comments you # are now reading as the very last few lines in every build rule member. hercules-3.12/msvc.makefile.includes/MODULES.msvc0000664000175000017500000000314412564723224016540 00000000000000# *************************************************************************** # MODULES.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # The MODULES to be built... # # # CHANGE HISTORY # $Log$ # # DD/MM/YY Description # # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** !IFNDEF NOCRYPTO DYNCRYPT_DLL = $(X)dyncrypt.dll !ELSE DYNCRYPT_DLL = !ENDIF MODULES = \ $(X)dyngui.dll \ $(X)hdt1052c.dll \ $(X)hdt1403.dll \ $(X)hdt2703.dll \ $(X)hdt3705.dll \ $(X)hdt3088.dll \ $(X)hdt3270.dll \ $(X)hdt3420.dll \ $(X)hdt3505.dll \ $(X)hdt3525.dll \ $(X)hdteq.dll \ $(X)hdtqeth.dll \ $(X)dyninst.dll \ $(X)decNumber.dll \ $(X)softfloat.dll \ $(DYNCRYPT_DLL) EXECUTABLES = \ $(X)cckdcdsk.exe \ $(X)cckdcomp.exe \ $(X)cckddiag.exe \ $(X)cckdswap.exe \ $(X)conspawn.exe \ $(X)dasdcat.exe \ $(X)dasdconv.exe \ $(X)dasdcopy.exe \ $(X)dasdinit.exe \ $(X)dasdisup.exe \ $(X)dasdload.exe \ $(X)dasdls.exe \ $(X)dasdpdsu.exe \ $(X)dasdseq.exe \ $(X)dmap2hrc.exe \ $(X)herclin.exe \ $(X)hercules.exe \ $(X)hetget.exe \ $(X)hetinit.exe \ $(X)hetmap.exe \ $(X)hetupd.exe \ $(X)tapecopy.exe \ $(X)tapemap.exe \ $(X)tapesplt.exe hercules-3.12/msvc.makefile.includes/OBJ_CODE.msvc0000664000175000017500000001016612564723224016636 00000000000000# *************************************************************************** # OBJ_CODE.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # What object code goes in what module... # # # CHANGE HISTORY # $Log$ # Revision 1.7 2008/12/29 11:03:11 jj # Move HMC disk I/O functions to scedasd.c # # Revision 1.6 2008/12/01 20:28:21 rbowler # Add new module losc.c in build process # # Revision 1.5 2008/05/22 19:25:58 fish # Flex FakeTape support # # Revision 1.4 2008/03/25 11:41:32 fish # SCSI TAPE MODS part 1: groundwork: non-functional changes: # rename some functions, comments, general restructuring, etc. # New source modules awstape.c, omatape.c, hettape.c and # tapeccws.c added, but not yet used (all will be used in a future # commit though when tapedev.c code is eventually split) # # Revision 1.3 2008/03/03 22:33:44 rbowler # Add new module general3.c for general-instructions-extension facility # # Revision 1.2 2007/06/02 13:46:42 rbowler # PFPO framework # # DD/MM/YY Description # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** hsys_OBJ = \ $(O)hsys.obj hdasd_OBJ = \ $(O)cache.obj \ $(O)cckddasd.obj \ $(O)cckdutil.obj \ $(O)ckddasd.obj \ $(O)dasdtab.obj \ $(O)dasdutil.obj \ $(O)fbadasd.obj \ $(O)shared.obj htape_OBJ = \ $(O)hetlib.obj \ $(O)sllib.obj \ $(O)w32stape.obj hutil_OBJ = \ $(O)codepage.obj \ $(O)fthreads.obj \ $(O)getopt.obj \ $(O)hdl.obj \ $(O)hostinfo.obj \ $(O)hscutl.obj \ $(O)hscutl2.obj \ $(O)logger.obj \ $(O)logmsg.obj \ $(O)memrchr.obj \ $(O)parser.obj \ $(O)pttrace.obj \ $(O)version.obj \ $(O)hsocket.obj \ $(O)w32util.obj !IFNDEF NOCRYPTO dyncrypt_OBJ = \ $(O)dyncrypt.obj \ $(O)sha1.obj \ $(O)sha256.obj \ $(O)des.obj \ $(O)aes.obj !ENDIF decNumber_OBJ = \ $(O)decContext.obj \ $(O)decimal128.obj \ $(O)decimal32.obj \ $(O)decimal64.obj \ $(O)decNumber.obj \ $(O)decPacked.obj softfloat_OBJ = \ $(O)softfloat.obj hengine_OBJ = \ $(O)assist.obj \ $(O)bldcfg.obj \ $(O)cgibin.obj \ $(O)channel.obj \ $(O)chsc.obj \ $(O)clock.obj \ $(O)cmdtab.obj \ $(O)cmpsc.obj \ $(O)config.obj \ $(O)control.obj \ $(O)cpu.obj \ $(O)crypto.obj \ $(O)dat.obj \ $(O)decimal.obj \ $(O)dfp.obj \ $(O)diagmssf.obj \ $(O)diagnose.obj \ $(O)ecpsvm.obj \ $(O)esame.obj \ $(O)external.obj \ $(O)fillfnam.obj \ $(O)float.obj \ $(O)general1.obj \ $(O)general2.obj \ $(O)general3.obj \ $(O)hconsole.obj \ $(O)history.obj \ $(O)hsccmd.obj \ $(O)hao.obj \ $(O)hscmisc.obj \ $(O)httpserv.obj \ $(O)ieee.obj \ $(O)impl.obj \ $(O)io.obj \ $(O)ipl.obj \ $(O)loadparm.obj \ $(O)losc.obj \ $(O)machchk.obj \ $(O)opcode.obj \ $(O)panel.obj \ $(O)pfpo.obj \ $(O)plo.obj \ $(O)qdio.obj \ $(O)service.obj \ $(O)scedasd.obj \ $(O)sie.obj \ $(O)sr.obj \ $(O)stack.obj \ $(O)timer.obj \ $(O)trace.obj \ $(O)vector.obj \ $(O)vm.obj \ $(O)vmd250.obj \ $(O)vstore.obj \ $(O)w32chan.obj \ $(O)xstore.obj hmodule_OBJ = \ $(O)cardpch.obj \ $(O)cardrdr.obj \ $(O)comm3705.obj \ $(O)commadpt.obj \ $(O)console.obj \ $(O)ctc_ctci.obj \ $(O)ctc_lcs.obj \ $(O)ctcadpt.obj \ $(O)printer.obj \ $(O)qeth.obj \ $(O)sockdev.obj \ $(O)tuntap.obj \ $(O)w32ctca.obj hdt3420_OBJ = \ $(O)tapedev.obj \ $(O)tapeccws.obj \ $(O)awstape.obj \ $(O)faketape.obj \ $(O)hettape.obj \ $(O)omatape.obj \ $(O)scsitape.obj hercules-3.12/msvc.makefile.includes/OUTDIR_RULES.msvc0000664000175000017500000000261112564723224017406 00000000000000# *************************************************************************** # OUTDIR_RULES.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Build rules for creating o/p directories... # # # CHANGE HISTORY # $Log$ # # DD/MM/YY Description # # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** $(OBJDIR): if not exist "$(OBJDIR)\$(NULL)" mkdir $(OBJDIR) $(EXEDIR): if not exist "$(EXEDIR)\$(NULL)" mkdir $(EXEDIR) $(PDBDIR): if not exist "$(PDBDIR)\$(NULL)" mkdir $(PDBDIR) $(MAPDIR): if not exist "$(MAPDIR)\$(NULL)" mkdir $(MAPDIR) !IFDEF ASSEMBLY_LISTINGS $(ASMDIR): if not exist "$(ASMDIR)\$(NULL)" mkdir $(ASMDIR) !ENDIF # NOTE: to be safe, since this member contains build rules, we need to # make sure there's always a blank line following the last build rule # in the member so that nmake doesn't complain or otherwise treat the # statements immediately following the original !INCLUDE statement as # part of the build rule actions. Thus the purpose of the comments you # are now reading as the very last few lines in every build rule member. hercules-3.12/msvc.makefile.includes/OUTPUT_DIRS.msvc0000664000175000017500000000324712564723224017315 00000000000000# *************************************************************************** # OUTPUT_DIRS.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2009 # -------------------------------------------------------------------------- # $Id$ # # Define the build output directories... # # # CHANGE HISTORY # $Log$ # Revision 1.2 2008/10/11 23:46:01 fish # Add CVS "Id" and "Log" # # # DD/MM/YY Description # # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # SET PREFIX=NONE to generate output directories named bin,obj,pdb,map,cod # (this is for nmake version 6 which barfs if the command line is too long) # Otherwise the output directories are named: # msvc.[debug.]yyy.bin/obj/pdb/map/cod # where yyy is "dllmod" (for i386), or "AMD64" or "IA64" # (this naming convention is to avoid breaking existing build procedures) # *************************************************************************** !IFDEF NODEBUG DEBUG_PREFIX = !ELSE DEBUG_PREFIX = debug. !ENDIF !IF ("$(CPU)" == "i386") ARCH_PREFIX = dllmod. !ELSE ARCH_PREFIX = $(CPU). !ENDIF !IF ("$(PREFIX)" == "NONE") || ("$(PREFIX)" == "none") PREFIX = !ELSE PREFIX = msvc.$(DEBUG_PREFIX)$(ARCH_PREFIX) !ENDIF !IF ("$(EXEDIR)" == "") || ("$(OBJDIR)" == "") || ("$(PDBDIR)" == "") || ("$(MAPDIR)" == "") EXEDIR = $(PREFIX)bin OBJDIR = $(PREFIX)obj PDBDIR = $(PREFIX)pdb MAPDIR = $(PREFIX)map !ENDIF !IFNDEF ASSEMBLY_LISTINGS !UNDEF ASMDIR !ELSEIF ("$(ASMDIR)" == "") ASMDIR = $(PREFIX)cod !ENDIF # (shorter names are easier to use) X = $(EXEDIR)\$(NULL) O = $(OBJDIR)\$(NULL) hercules-3.12/msvc.makefile.includes/PCRE_DIR.msvc0000664000175000017500000000720712564723224016663 00000000000000# *************************************************************************** # PCRE_DIR.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Handles support for PCRE (Perl Compatible Regular Expressions), # for MSVC, needed by HAO (Hercules Automatic Operator) facility # # *************************************************************************** # --------------------------------------------------------------------- # To enable PCRE (Perl-Compatible Regular Expressions) support, first # download "32 and 64-bit PCRE for Windows" from www.airesoft.co.uk/pcre # File name: http://www.airesoft.co.uk/files/pcre/pcre-8.20.zip # Then create a permanent directory somewhere called whatever you want # and unzip pcre-8.20.zip into that directory. Finally define an # environment variable called "PCRE_DIR" pointing to that directory. # --------------------------------------------------------------------- !IFNDEF PCRE_DIR # Undefined: use default value, if it exists. # PCRE_DIR defaults to winbuild\pcre relative to current directory !IF "$(CPU)" == "i386" && EXIST(winbuild\pcre) PCRE_DIR = winbuild\pcre !ELSEIF "$(CPU)" == "AMD64" && EXIST(winbuild\pcre\x64) PCRE_DIR = winbuild\pcre\x64 !ELSEIF "$(CPU)" == "IA64" && EXIST(winbuild\pcre\ia64) PCRE_DIR = winbuild\pcre\ia64 !ELSEIF EXIST(winbuild\pcre) PCRE_DIR = winbuild\pcre !ENDIF !ELSE # Defined: use explicit directory or subdirectory # unless "NONE" is specified or it doesn't exist. !IF "$(PCRE_DIR)" == "NONE" !UNDEF PCRE_DIR !ELSE !IF "$(CPU)" == "i386" !IF !EXIST($(PCRE_DIR)) !UNDEF PCRE_DIR !ENDIF !ELSEIF "$(CPU)" == "AMD64" !IF EXIST($(PCRE_DIR)\x64) PCRE_DIR = $(PCRE_DIR)\x64 !ENDIF !ELSEIF "$(CPU)" == "IA64" !IF EXIST($(PCRE_DIR)\ia64) PCRE_DIR = $(PCRE_DIR)\ia64 !ENDIF !ENDIF !ENDIF !ENDIF !IFDEF PCRE_DIR PCRE_INCNAME = pcreposix.h PCRE_LIBNAME1 = pcre.lib PCRE_LIBNAME2 = pcreposix.lib PCRE_DLLNAME1 = pcre3.dll PCRE_DLLNAME2 = pcreposix3.dll !IF EXIST("$(PCRE_DIR)\include") PCRE_INCDIR = $(PCRE_DIR)\include !ELSEIF EXIST("$(PCRE_DIR)\inc") PCRE_INCDIR = $(PCRE_DIR)\inc !ELSE PCRE_INCDIR = $(PCRE_DIR) !ENDIF PCRE_LIBDIR = $(PCRE_DIR)\lib !IF "$(CPU)" == "AMD64" && EXIST($(PCRE_LIBDIR)\x64) PCRE_LIBDIR = $(PCRE_LIBDIR)\x64 !ELSEIF "$(CPU)" == "IA64" && EXIST($(PCRE_LIBDIR)\ia64) PCRE_LIBDIR = $(PCRE_LIBDIR)\ia64 !ENDIF !IF !EXIST("$(PCRE_LIBDIR)\$(PCRE_LIBNAME1)") PCRE_LIBNAME1 = pcre3.lib PCRE_LIBNAME2 = pcreposix3.lib !ENDIF PCRE_DLLDIR = $(PCRE_DIR)\bin !IF "$(CPU)" == "AMD64" && EXIST($(PCRE_DLLDIR)\x64) PCRE_DLLDIR = $(PCRE_DLLDIR)\x64 !ELSEIF "$(CPU)" == "IA64" && EXIST($(PCRE_DLLDIR)\ia64) PCRE_DLLDIR = $(PCRE_DLLDIR)\ia64 !ENDIF PCRE_INCPATH = $(PCRE_INCDIR)\$(PCRE_INCNAME) PCRE_LIBPATH1 = $(PCRE_LIBDIR)\$(PCRE_LIBNAME1) PCRE_LIBPATH2 = $(PCRE_LIBDIR)\$(PCRE_LIBNAME2) PCRE_DLLPATH1 = $(PCRE_DLLDIR)\$(PCRE_DLLNAME1) PCRE_DLLPATH2 = $(PCRE_DLLDIR)\$(PCRE_DLLNAME2) !IF !EXIST("$(PCRE_INCPATH)") !ERROR PCRE_DIR "$(PCRE_INCPATH)" does not exist. Check PCRE_DIR !ELSEIF !EXIST("$(PCRE_LIBPATH1)") !ERROR PCRE_DIR "$(PCRE_LIBPATH1)" does not exist. Check PCRE_DIR !ELSEIF !EXIST("$(PCRE_LIBPATH2)") !ERROR PCRE_DIR "$(PCRE_LIBPATH2)" does not exist. Check PCRE_DIR !ELSEIF !EXIST("$(PCRE_DLLPATH1)") !ERROR PCRE_DIR "$(PCRE_DLLPATH1)" does not exist. Check PCRE_DIR !ELSEIF !EXIST("$(PCRE_DLLPATH2)") !ERROR PCRE_DIR "$(PCRE_DLLPATH2)" does not exist. Check PCRE_DIR !ENDIF !MESSAGE PCRE support will be included from "$(PCRE_DIR)" !ELSE !MESSAGE PCRE support will not be generated !ENDIF hercules-3.12/msvc.makefile.includes/PCRE_FLAGS.msvc0000664000175000017500000000147012564723224017075 00000000000000# *************************************************************************** # PCRE_FLAGS.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Sets PCRE-related compiler/linker flags & #defines... # # # CHANGE HISTORY # $Log$ # # DD/MM/YY Description # # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** !IFDEF PCRE_DIR LIBS = $(LIBS) "$(PCRE_LIBPATH1)" LIBS = $(LIBS) "$(PCRE_LIBPATH2)" cflags = $(cflags) /D HAVE_PCRE /I"$(PCRE_INCDIR)" /D PCRE_INCNAME=\"$(PCRE_INCNAME)\" !ENDIF hercules-3.12/msvc.makefile.includes/PCRE_RULES.msvc0000664000175000017500000000221012564723224017124 00000000000000# *************************************************************************** # PCRE_RULES.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2010 # -------------------------------------------------------------------------- # $Id$ # # PCRE build rules # # *************************************************************************** !IFDEF PCRE_DIR $(X)$(PCRE_DLLNAME1): XCOPY "$(PCRE_DLLPATH1)" $(X) /V /C /F /H /R /K /Y $(X)$(PCRE_DLLNAME2): XCOPY "$(PCRE_DLLPATH2)" $(X) /V /C /F /H /R /K /Y allpcre: allHercules \ $(X)$(PCRE_DLLNAME1) \ $(X)$(PCRE_DLLNAME2) !ELSE allpcre: allHercules !ENDIF # NOTE: to be safe, since this member contains build rules, we need to # make sure there's always a blank line following the last build rule # in the member so that nmake doesn't complain or otherwise treat the # statements immediately following the original !INCLUDE statement as # part of the build rule actions. Thus the purpose of the comments you # are now reading as the very last few lines in every build rule member. hercules-3.12/msvc.makefile.includes/PRIM_RULES.msvc0000664000175000017500000000613412564723224017153 00000000000000# *************************************************************************** # PRIM_RULES.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Primary generic build rules... ('all', 'clean', etc...) # # # CHANGE HISTORY # $Log$ # Revision 1.2 2008/10/11 23:47:05 fish # Fix MSVC build failure when 'rebase' utility doesn't exist # Add CVS "Id" and "Log" # # # DD/MM/YY Description # # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # 07/02/10 Fish: allHercules, rmdir DYNDIR, del fna # # *************************************************************************** # --------------------------------------------------------------------- # Primary build rules... # --------------------------------------------------------------------- all: allzlib alllibbz2 allpcre allHercules for %I in (rebase.exe) do if exist %~$$PATH:I rebase -b 0x400000 $(X)*.dll if exist $(EXEDIR)\*.manifest del /f /q $(EXEDIR)\*.manifest allHercules: $(OBJDIR) $(EXEDIR) $(PDBDIR) $(MAPDIR) $(ASMDIR) \ $(O)build_pch.pch \ $(MODULES) \ $(EXECUTABLES) clean: $(OBJDIR) $(EXEDIR) $(PDBDIR) $(MAPDIR) $(ASMDIR) if exist $(OBJDIR)\*.* rmdir /s /q $(OBJDIR) if exist $(EXEDIR)\*.* rmdir /s /q $(EXEDIR) if exist $(PDBDIR)\*.* rmdir /s /q $(PDBDIR) if exist $(MAPDIR)\*.* rmdir /s /q $(MAPDIR) !IFDEF ASSEMBLY_LISTINGS if exist $(ASMDIR)\*.* rmdir /s /q $(ASMDIR) !ENDIF !IFDEF DYNDIR if exist $(DYNDIR)\*.* rmdir /s /q $(DYNDIR) !ENDIF !IFDEF fna if exist $(fna) del /f /q $(fna) !ENDIF MT_EXE_CMD=if exist $@.manifest mt.exe -nologo -outputresource:$@;1 -manifest $@.manifest MT_DLL_CMD=if exist $@.manifest mt.exe -nologo -outputresource:$@;2 -manifest $@.manifest linkexe = $(link) -nologo $(ldebug) $(conlflags) $(O)build_pch.obj $** $(LIBS) -out:$@ -implib:$(O)$(@B).lib $(conlibsdll) $(MAPFILE) && $(MT_EXE_CMD) linkdll = $(link) -nologo $(ldebug) $(dlllflags) $(O)build_pch.obj $** $(LIBS) -out:$@ -implib:$(O)$(@B).lib $(conlibsdll) $(MAPFILE) && $(MT_DLL_CMD) {$(OBJDIR)}.obj{$(EXEDIR)}.exe: $(linkexe) {$(OBJDIR)}.obj{$(EXEDIR)}.dll: $(linkdll) # Dummy target entry: Since the primary target is .DLL # and .LIB is generated in the same step.. And .LIB # are used as input, the following generates an effective # rule, with no side effect {$(EXEDIR)}.dll{$(OBJDIR)}.lib: echo $* $@ .c{$(OBJDIR)}.obj:: $(cc) $(cdebug) $(cflags) /Fp"$(OBJDIR)\\build_pch.pch" /Yu"hstdinc.h" $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" $< # NOTE: to be safe, since this member contains build rules, we need to # make sure there's always a blank line following the last build rule # in the member so that nmake doesn't complain or otherwise treat the # statements immediately following the original !INCLUDE statement as # part of the build rule actions. Thus the purpose of the comments you # are now reading as the very last few lines in every build rule member. hercules-3.12/msvc.makefile.includes/VERSION.msvc0000664000175000017500000000654112564723224016561 00000000000000# *************************************************************************** # VERSION.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2012 # -------------------------------------------------------------------------- # $Id$ # # Handles defining the product VERSION strings # # *************************************************************************** !UNDEF fna !IF !DEFINED(VERSION) || !DEFINED(V1) || !DEFINED(V2) || !DEFINED(V3) || !DEFINED(V4) # The following logic determines the Hercules version number, attempts # to construct a pseudo-revision number using the git commit history, # and sets variables V1,V2,V3,V4 and VERSION # First extract the Hercules version number from the configure.ac file. # We scan the file looking for AM_INIT_AUTOMAKE=(hercules,x.y[.z]) # # and we create a temporary file containing statements V1=x V2=y # Finally we include the temporary file to set the variables V1,V2 opt = "tokens=1-5 delims=(),. " fna = $(TEMP)\hercver$(BUILD_TYPE).txt cmd = @echo V1=%c >$(fna) && @echo V2=%d >>$(fna) !IF ["for /f $(opt) %a in (configure.ac) do @if %a==AM_INIT_AUTOMAKE $(cmd)"] == 0 !INCLUDE $(fna) !ELSE V1 = 0 V2 = 0 !ENDIF # If git.exe exists in the path, use the 'git log' command to count the # number of commits (nnnn), and write V3=nnnn to the temporary file. # Then include the temporary file to set the variable V3 opt="tokens=1 usebackq" cmd = for /f $(opt) %a in (`"git log --oneline | wc -l"`) do @echo V3=%a>$(fna) !IF ["for %I in (git.exe) do @if exist %~$$PATH:I $(cmd)"] == 0 !INCLUDE $(fna) !ENDIF # If V3 is still not set, then set it to zero !IF !DEFINED(V3) || "$(V3)" == "" V3 = 0 !ENDIF # If date.exe exists in the path, write V4=yyddd to the temporary file. # Then include the temporary file to set the variable V4 opt="tokens=1 usebackq" cmd = for /f $(opt) %a in (`"%~$$PATH:I" +%y%j`) do @echo V4=%a>$(fna) !IF ["for %I in (date.exe) do @if exist %~$$PATH:I $(cmd)"] == 0 !INCLUDE $(fna) !ENDIF # If V4 is still not set, then set it to zero !IF !DEFINED(V4) || "$(V4)" == "" V4 = 0 !ENDIF # Set the version string VERSION = $(V1).$(V2)-spinhawk # Append the revision number to the version string !IF "$(V3)" != "0" VERSION = $(VERSION)-$(V3) !ENDIF !IF DEFINED(HERCVER) VERSION = $(HERCVER) !ENDIF !MESSAGE Hercules version number is $(VERSION) ($(V1).$(V2).$(V3).$(V4)) VERSION = \"$(VERSION)\" !ELSE !MESSAGE VERSION = $(VERSION) ($(V1).$(V2).$(V3).$(V4)) !ENDIF !IF DEFINED(CUSTOM_BUILD_STRING) !MESSAGE CUSTOM_BUILD_STRING = $(CUSTOM_BUILD_STRING) !ENDIF !MESSAGE # The following logic determines the minimum version of Windows on which # the application can run. The minimum version depends on both the target # architecture and the version of Visual Studio used for the build. The # APPVER and TARGETOS variables are set as required by Win32.Mak (SDK) # # 32 bit : # VS < 9 : Win NT 4 & Win 9X (APPVER 4.0, TARGETOS BOTH) # VS >= 9 : Win 2K (APPVER 5.0, TARGETOS WINNT) # 64 bit : # Win 2K3 (APPVER 5.02, TARGETOS WINNT) # !IF (("$(CPU)" == "AMD64") || ("$(CPU)" == "IA64")) APPVER = 5.02 TARGETOS = WINNT !ELSE # 32 bit build !IF $(vsversion) < 9 APPVER = 4.0 TARGETOS = BOTH !ELSE # $(vsversion) >= 9 APPVER = 5.0 TARGETOS = WINNT !ENDIF # vsversion test !ENDIF # 32/64 bit test hercules-3.12/msvc.makefile.includes/ZLIB_DIR.msvc0000664000175000017500000000550012564723224016664 00000000000000# *************************************************************************** # ZLIB_DIR.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Handles support for ZLIB compression # # *************************************************************************** # --------------------------------------------------------------------- # To enable ZLIB compression, first make sure you have the ZLIB dll # installed on your system (downloadable from http://www.zlib.net), # and then define an environment variable called "ZLIB_DIR" that # specifies the full path to the directory where it is installed. # (via the "Advanced" tab of the Control Panel 'System' applet). # # Note that the directory you specify should: a) hold the zlib1.dll # itself, b) contain two sub-directories called 'include' and 'lib' # where the 'zlib.h', zconf.h' and 'zdll.lib', etc, files reside. # # Note: if the path contains blanks, do NOT surround it with quotes! # The makefile will do that if it needs to. Just define the variable # with the path as-is. E.g.: # # ZLIB_DIR = E:\MyProjects\zlib and bzip2 dlls\zlib latest\zlib122-dll # ZLIB_DIR = C:\winbuild\zlib\win32_32 # --------------------------------------------------------------------- !IFNDEF ZLIB_DIR # Undefined: use default value, if it exists. # ZLIB_DIR defaults to winbuild\zlib relative to current directory !IF "$(CPU)" == "i386" && EXIST(winbuild\zlib\win32_32) # Avoid breaking existing builds, use win32_32 subdir if it exists ZLIB_DIR = winbuild\zlib\win32_32 !ELSEIF "$(CPU)" == "i386" && EXIST(winbuild\zlib) ZLIB_DIR = winbuild\zlib !ELSEIF "$(CPU)" == "AMD64" && EXIST(winbuild\zlib\x64) ZLIB_DIR = winbuild\zlib\x64 !ELSEIF "$(CPU)" == "IA64" && EXIST(winbuild\zlib\ia64) ZLIB_DIR = winbuild\zlib\ia64 !ENDIF !ELSE # Defined: use explicit directory or subdirectory # unless "NONE" is specified or it doesn't exist. !IF "$(ZLIB_DIR)" == "NONE" !UNDEF ZLIB_DIR !ELSE !IF "$(CPU)" == "i386" !IF !EXIST($(ZLIB_DIR)) !UNDEF ZLIB_DIR !ENDIF !ELSEIF "$(CPU)" == "AMD64" !IF EXIST($(ZLIB_DIR)\x64) ZLIB_DIR = $(ZLIB_DIR)\x64 !ENDIF !ELSEIF "$(CPU)" == "IA64" !IF EXIST($(ZLIB_DIR)\ia64) ZLIB_DIR = $(ZLIB_DIR)\ia64 !ENDIF !ENDIF !ENDIF !ENDIF !IFDEF ZLIB_DIR !IF !EXIST("$(ZLIB_DIR)\include\zlib.h") !ERROR ZLIB_DIR "$(ZLIB_DIR)\include\zlib.h" does not exist. Check ZLIB_DIR !ELSEIF !EXIST("$(ZLIB_DIR)\lib\zdll.lib") !ERROR ZLIB_DIR "$(ZLIB_DIR)\lib\zdll.lib" does not exist. Check ZLIB_DIR !ELSEIF !EXIST("$(ZLIB_DIR)\zlib1.dll") !ERROR ZLIB_DIR "$(ZLIB_DIR)\zlib1.dll" does not exist. Check ZLIB_DIR !ENDIF !MESSAGE ZLIB support will be included from "$(ZLIB_DIR)" !ELSE !MESSAGE ZLIB support will not be generated !ENDIF hercules-3.12/msvc.makefile.includes/ZLIB_FLAGS.msvc0000664000175000017500000000155312564723224017106 00000000000000# *************************************************************************** # ZLIB_FLAGS.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2007 # -------------------------------------------------------------------------- # $Id$ # # Sets ZLIB-compression-related compiler/linker flags & #defines... # # # CHANGE HISTORY # $Log$ # # DD/MM/YY Description # # 26/12/06 Fish: created by extraction from existing makefile-dllmod.msvc # # *************************************************************************** !IFDEF ZLIB_DIR ZLIB_DLL = $(ZLIB_DIR)\zlib1.dll ZLIB_LIB = $(ZLIB_DIR)/lib/zdll.lib ZLIB_INC = $(ZLIB_DIR)/include LIBS = $(LIBS) "$(ZLIB_LIB)" cflags = $(cflags) /D HAVE_LIBZ /D HAVE_ZLIB_H /I"$(ZLIB_INC)" !ENDIF hercules-3.12/msvc.makefile.includes/ZLIB_RULES.msvc0000664000175000017500000000201412564723224017135 00000000000000# *************************************************************************** # ZLIB_RULES.msvc (!INCLUDE ed by "makefile-dllmod.msvc") # -------------------------------------------------------------------------- # (c) Copyright Roger Bowler, 2005-2010 # -------------------------------------------------------------------------- # $Id$ # # ZLIB build rules # # *************************************************************************** !IFDEF ZLIB_DIR $(X)zlib1.dll: XCOPY "$(ZLIB_DLL)" $(X) /V /C /F /H /R /K /Y allzlib: allHercules \ $(X)zlib1.dll !ELSE allzlib: allHercules !ENDIF # NOTE: to be safe, since this member contains build rules, we need to # make sure there's always a blank line following the last build rule # in the member so that nmake doesn't complain or otherwise treat the # statements immediately following the original !INCLUDE statement as # part of the build rule actions. Thus the purpose of the comments you # are now reading as the very last few lines in every build rule member. hercules-3.12/Makefile.in0000664000175000017500000030202312625667166012262 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # *************************************************************************** # Makefile for Hercules S/370, ESA/390 and z/Architecture emulator # Process this file with 'automake' to produce Makefile.in # *************************************************************************** VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = hercules$(EXEEXT) dasdinit$(EXEEXT) dasdisup$(EXEEXT) \ dasdload$(EXEEXT) dasdconv$(EXEEXT) dasdls$(EXEEXT) \ dasdcat$(EXEEXT) dasdpdsu$(EXEEXT) dasdseq$(EXEEXT) \ tapecopy$(EXEEXT) tapemap$(EXEEXT) tapesplt$(EXEEXT) \ cckdcdsk$(EXEEXT) cckdcomp$(EXEEXT) cckddiag$(EXEEXT) \ cckdswap$(EXEEXT) dasdcopy$(EXEEXT) hetget$(EXEEXT) \ hetinit$(EXEEXT) hetmap$(EXEEXT) hetupd$(EXEEXT) \ dmap2hrc$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) EXTRA_PROGRAMS = hercifc$(EXEEXT) subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in $(top_srcdir)/autoconf/mkinstalldirs \ $(top_srcdir)/autoconf/depcomp \ $(top_srcdir)/autoconf/ltmain.sh \ $(top_srcdir)/autoconf/config.guess \ $(top_srcdir)/autoconf/config.sub $(noinst_HEADERS) INSTALL \ autoconf/README autoconf/compile autoconf/config.guess \ autoconf/config.rpath autoconf/config.sub autoconf/depcomp \ autoconf/install-sh autoconf/missing autoconf/mkinstalldirs \ autoconf/ltmain.sh $(top_srcdir)/autoconf/install-sh \ $(top_srcdir)/autoconf/missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(modexecdir)" \ "$(DESTDIR)$(bindir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(modexec_LTLIBRARIES) \ $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = @OPTION_DYNAMIC_LOAD_TRUE@am__DEPENDENCIES_2 = libherc.la libhercs.la \ @OPTION_DYNAMIC_LOAD_TRUE@ libhercu.la $(am__DEPENDENCIES_1) @OPTION_DYNAMIC_LOAD_TRUE@dyngui_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__dyngui_la_SOURCES_DIST = dyngui.c @OPTION_DYNAMIC_LOAD_TRUE@am_dyngui_la_OBJECTS = dyngui.lo dyngui_la_OBJECTS = $(am_dyngui_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = dyngui_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dyngui_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_dyngui_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@dyninst_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__dyninst_la_SOURCES_DIST = dyninst.c @OPTION_DYNAMIC_LOAD_TRUE@am_dyninst_la_OBJECTS = dyninst.lo dyninst_la_OBJECTS = $(am_dyninst_la_OBJECTS) dyninst_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dyninst_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_dyninst_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt1052c_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt1052c_la_SOURCES_DIST = con1052c.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt1052c_la_OBJECTS = con1052c.lo hdt1052c_la_OBJECTS = $(am_hdt1052c_la_OBJECTS) hdt1052c_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt1052c_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt1052c_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt1403_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt1403_la_SOURCES_DIST = printer.c sockdev.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt1403_la_OBJECTS = printer.lo \ @OPTION_DYNAMIC_LOAD_TRUE@ sockdev.lo hdt1403_la_OBJECTS = $(am_hdt1403_la_OBJECTS) hdt1403_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt1403_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt1403_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt2703_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt2703_la_SOURCES_DIST = commadpt.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt2703_la_OBJECTS = commadpt.lo hdt2703_la_OBJECTS = $(am_hdt2703_la_OBJECTS) hdt2703_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt2703_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt2703_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt2880_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt2880_la_SOURCES_DIST = hchan.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt2880_la_OBJECTS = hchan.lo hdt2880_la_OBJECTS = $(am_hdt2880_la_OBJECTS) hdt2880_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt2880_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt2880_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt3088_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt3088_la_SOURCES_DIST = ctc_lcs.c ctc_ctci.c ctcadpt.c w32ctca.c \ tuntap.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3088_la_OBJECTS = ctc_lcs.lo \ @OPTION_DYNAMIC_LOAD_TRUE@ ctc_ctci.lo ctcadpt.lo w32ctca.lo \ @OPTION_DYNAMIC_LOAD_TRUE@ tuntap.lo hdt3088_la_OBJECTS = $(am_hdt3088_la_OBJECTS) hdt3088_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt3088_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3088_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt3270_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt3270_la_SOURCES_DIST = console.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3270_la_OBJECTS = console.lo hdt3270_la_OBJECTS = $(am_hdt3270_la_OBJECTS) hdt3270_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt3270_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3270_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt3420_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) libherct.la am__hdt3420_la_SOURCES_DIST = tapedev.c tapeccws.c awstape.c \ faketape.c hettape.c omatape.c scsitape.c w32stape.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3420_la_OBJECTS = tapedev.lo \ @OPTION_DYNAMIC_LOAD_TRUE@ tapeccws.lo awstape.lo faketape.lo \ @OPTION_DYNAMIC_LOAD_TRUE@ hettape.lo omatape.lo scsitape.lo \ @OPTION_DYNAMIC_LOAD_TRUE@ w32stape.lo hdt3420_la_OBJECTS = $(am_hdt3420_la_OBJECTS) hdt3420_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt3420_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3420_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt3505_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt3505_la_SOURCES_DIST = cardrdr.c sockdev.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3505_la_OBJECTS = cardrdr.lo \ @OPTION_DYNAMIC_LOAD_TRUE@ sockdev.lo hdt3505_la_OBJECTS = $(am_hdt3505_la_OBJECTS) hdt3505_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt3505_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3505_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt3525_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt3525_la_SOURCES_DIST = cardpch.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3525_la_OBJECTS = cardpch.lo hdt3525_la_OBJECTS = $(am_hdt3525_la_OBJECTS) hdt3525_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt3525_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3525_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdt3705_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdt3705_la_SOURCES_DIST = comm3705.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3705_la_OBJECTS = comm3705.lo hdt3705_la_OBJECTS = $(am_hdt3705_la_OBJECTS) hdt3705_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdt3705_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdt3705_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdteq_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdteq_la_SOURCES_DIST = hdteq.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdteq_la_OBJECTS = hdteq.lo hdteq_la_OBJECTS = $(am_hdteq_la_OBJECTS) hdteq_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdteq_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdteq_la_rpath = -rpath $(modexecdir) @OPTION_DYNAMIC_LOAD_TRUE@hdtqeth_la_DEPENDENCIES = \ @OPTION_DYNAMIC_LOAD_TRUE@ $(am__DEPENDENCIES_2) am__hdtqeth_la_SOURCES_DIST = qeth.c @OPTION_DYNAMIC_LOAD_TRUE@am_hdtqeth_la_OBJECTS = qeth.lo hdtqeth_la_OBJECTS = $(am_hdtqeth_la_OBJECTS) hdtqeth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hdtqeth_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_hdtqeth_la_rpath = -rpath $(modexecdir) libherc_la_DEPENDENCIES = libhercs.la libhercu.la libherct.la \ libhercd.la decNumber/libdecNumber.la \ softfloat/libsoftfloat.la $(am__DEPENDENCIES_1) am__libherc_la_SOURCES_DIST = hconsole.c w32util.c strsignal.c impl.c \ config.c bldcfg.c panel.c history.c fillfnam.c ipl.c assist.c \ dat.c stack.c cpu.c vstore.c general1.c general2.c general3.c \ pfpo.c plo.c control.c crypto.c io.c decimal.c service.c \ scedasd.c losc.c chsc.c opcode.c diagnose.c diagmssf.c vm.c \ vmd250.c channel.c external.c float.c trace.c machchk.c \ vector.c xstore.c cmpsc.c sie.c qdio.c clock.c timer.c esame.c \ ieee.c dfp.c machdep.h httpserv.c cgibin.c loadparm.c hsccmd.c \ cmdtab.c hao.c hscmisc.c sr.c w32chan.c commadpt.c comm3705.c \ console.c cardpch.c cardrdr.c sockdev.c printer.c tapedev.c \ tapeccws.c sllib.c hetlib.c awstape.c faketape.c hettape.c \ omatape.c scsitape.c w32stape.c ctc_lcs.c ctc_ctci.c ctcadpt.c \ w32ctca.c hchan.c tuntap.c qeth.c con1052c.c ecpsvm.c am__objects_1 = w32chan.lo @BUILD_FTHREADS_TRUE@am__objects_2 = $(am__objects_1) am__objects_3 = commadpt.lo comm3705.lo console.lo cardpch.lo \ cardrdr.lo sockdev.lo printer.lo tapedev.lo tapeccws.lo \ sllib.lo hetlib.lo awstape.lo faketape.lo hettape.lo \ omatape.lo scsitape.lo w32stape.lo ctc_lcs.lo ctc_ctci.lo \ ctcadpt.lo w32ctca.lo hchan.lo tuntap.lo qeth.lo con1052c.lo @OPTION_DYNAMIC_LOAD_FALSE@am__objects_4 = $(am__objects_3) am_libherc_la_OBJECTS = hconsole.lo w32util.lo strsignal.lo impl.lo \ config.lo bldcfg.lo panel.lo history.lo fillfnam.lo ipl.lo \ assist.lo dat.lo stack.lo cpu.lo vstore.lo general1.lo \ general2.lo general3.lo pfpo.lo plo.lo control.lo crypto.lo \ io.lo decimal.lo service.lo scedasd.lo losc.lo chsc.lo \ opcode.lo diagnose.lo diagmssf.lo vm.lo vmd250.lo channel.lo \ external.lo float.lo trace.lo machchk.lo vector.lo xstore.lo \ cmpsc.lo sie.lo qdio.lo clock.lo timer.lo esame.lo ieee.lo \ dfp.lo httpserv.lo cgibin.lo loadparm.lo hsccmd.lo cmdtab.lo \ hao.lo hscmisc.lo sr.lo $(am__objects_2) $(am__objects_4) \ ecpsvm.lo libherc_la_OBJECTS = $(am_libherc_la_OBJECTS) libherc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libherc_la_LDFLAGS) $(LDFLAGS) -o $@ libhercd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libhercs.la \ libhercu.la am_libhercd_la_OBJECTS = ckddasd.lo fbadasd.lo cckddasd.lo cckdutil.lo \ dasdtab.lo cache.lo dasdutil.lo shared.lo libhercd_la_OBJECTS = $(am_libhercd_la_OBJECTS) libhercd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libhercd_la_LDFLAGS) $(LDFLAGS) -o $@ libhercs_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am_libhercs_la_OBJECTS = hsys.lo libhercs_la_OBJECTS = $(am_libhercs_la_OBJECTS) libhercs_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libhercs_la_LDFLAGS) $(LDFLAGS) -o $@ libherct_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libhercs.la \ libhercu.la am_libherct_la_OBJECTS = sllib.lo hetlib.lo libherct_la_OBJECTS = $(am_libherct_la_OBJECTS) libherct_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libherct_la_LDFLAGS) $(LDFLAGS) -o $@ libhercu_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libhercs.la am__libhercu_la_SOURCES_DIST = version.c hscutl.c hscutl2.c codepage.c \ logger.c logmsg.c hdl.c hostinfo.c hsocket.c memrchr.c \ parser.c pttrace.c fthreads.c ltdl.c am__objects_5 = fthreads.lo @BUILD_FTHREADS_TRUE@am__objects_6 = $(am__objects_5) @OPTION_DYNAMIC_LOAD_TRUE@am__objects_7 = ltdl.lo am_libhercu_la_OBJECTS = version.lo hscutl.lo hscutl2.lo codepage.lo \ logger.lo logmsg.lo hdl.lo hostinfo.lo hsocket.lo memrchr.lo \ parser.lo pttrace.lo $(am__objects_6) $(am__objects_7) libhercu_la_OBJECTS = $(am_libhercu_la_OBJECTS) libhercu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libhercu_la_LDFLAGS) $(LDFLAGS) -o $@ @BUILD_HERCIFC_TRUE@am__EXEEXT_1 = hercifc$(EXEEXT) @BUILD_SHARED_TRUE@am__EXEEXT_2 = herclin$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) am_cckdcdsk_OBJECTS = cckdcdsk.$(OBJEXT) cckdcdsk_OBJECTS = $(am_cckdcdsk_OBJECTS) am__DEPENDENCIES_3 = $(HERCLIBS2) $(am__DEPENDENCIES_1) cckdcdsk_DEPENDENCIES = $(am__DEPENDENCIES_3) cckdcdsk_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(cckdcdsk_LDFLAGS) $(LDFLAGS) -o $@ am_cckdcomp_OBJECTS = cckdcomp.$(OBJEXT) cckdcomp_OBJECTS = $(am_cckdcomp_OBJECTS) cckdcomp_DEPENDENCIES = $(am__DEPENDENCIES_3) cckdcomp_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(cckdcomp_LDFLAGS) $(LDFLAGS) -o $@ am_cckddiag_OBJECTS = cckddiag.$(OBJEXT) cckddiag_OBJECTS = $(am_cckddiag_OBJECTS) cckddiag_DEPENDENCIES = $(am__DEPENDENCIES_3) cckddiag_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(cckddiag_LDFLAGS) $(LDFLAGS) -o $@ am_cckdswap_OBJECTS = cckdswap.$(OBJEXT) cckdswap_OBJECTS = $(am_cckdswap_OBJECTS) cckdswap_DEPENDENCIES = $(am__DEPENDENCIES_3) cckdswap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(cckdswap_LDFLAGS) $(LDFLAGS) -o $@ am_dasdcat_OBJECTS = dasdcat.$(OBJEXT) dasdcat_OBJECTS = $(am_dasdcat_OBJECTS) dasdcat_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdcat_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdcat_LDFLAGS) $(LDFLAGS) -o $@ am_dasdconv_OBJECTS = dasdconv.$(OBJEXT) dasdconv_OBJECTS = $(am_dasdconv_OBJECTS) dasdconv_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdconv_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdconv_LDFLAGS) $(LDFLAGS) -o $@ am_dasdcopy_OBJECTS = dasdcopy.$(OBJEXT) dasdcopy_OBJECTS = $(am_dasdcopy_OBJECTS) dasdcopy_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdcopy_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdcopy_LDFLAGS) $(LDFLAGS) -o $@ am_dasdinit_OBJECTS = dasdinit.$(OBJEXT) dasdinit_OBJECTS = $(am_dasdinit_OBJECTS) dasdinit_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdinit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdinit_LDFLAGS) $(LDFLAGS) -o $@ am_dasdisup_OBJECTS = dasdisup.$(OBJEXT) dasdisup_OBJECTS = $(am_dasdisup_OBJECTS) dasdisup_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdisup_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdisup_LDFLAGS) $(LDFLAGS) -o $@ am_dasdload_OBJECTS = dasdload.$(OBJEXT) dasdload_OBJECTS = $(am_dasdload_OBJECTS) dasdload_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdload_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdload_LDFLAGS) $(LDFLAGS) -o $@ am_dasdls_OBJECTS = dasdls.$(OBJEXT) dasdls_OBJECTS = $(am_dasdls_OBJECTS) dasdls_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdls_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdls_LDFLAGS) $(LDFLAGS) -o $@ am_dasdpdsu_OBJECTS = dasdpdsu.$(OBJEXT) dasdpdsu_OBJECTS = $(am_dasdpdsu_OBJECTS) dasdpdsu_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdpdsu_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdpdsu_LDFLAGS) $(LDFLAGS) -o $@ am_dasdseq_OBJECTS = dasdseq.$(OBJEXT) dasdseq_OBJECTS = $(am_dasdseq_OBJECTS) dasdseq_DEPENDENCIES = $(am__DEPENDENCIES_3) dasdseq_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dasdseq_LDFLAGS) $(LDFLAGS) -o $@ am_dmap2hrc_OBJECTS = dmap2hrc.$(OBJEXT) dmap2hrc_OBJECTS = $(am_dmap2hrc_OBJECTS) dmap2hrc_DEPENDENCIES = $(am__DEPENDENCIES_3) dmap2hrc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dmap2hrc_LDFLAGS) $(LDFLAGS) -o $@ am__hercifc_SOURCES_DIST = hercifc.c @BUILD_HERCIFC_TRUE@am_hercifc_OBJECTS = hercifc.$(OBJEXT) hercifc_OBJECTS = $(am_hercifc_OBJECTS) @BUILD_HERCIFC_TRUE@hercifc_DEPENDENCIES = $(am__DEPENDENCIES_3) hercifc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hercifc_LDFLAGS) $(LDFLAGS) -o $@ am__herclin_SOURCES_DIST = herclin.c hdlmain.c @BUILD_SHARED_TRUE@am_herclin_OBJECTS = herclin.$(OBJEXT) \ @BUILD_SHARED_TRUE@ hdlmain.$(OBJEXT) herclin_OBJECTS = $(am_herclin_OBJECTS) herclin_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(herclin_LDFLAGS) $(LDFLAGS) -o $@ am_hercules_OBJECTS = bootstrap.$(OBJEXT) hdlmain.$(OBJEXT) hercules_OBJECTS = $(am_hercules_OBJECTS) hercules_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hercules_LDFLAGS) $(LDFLAGS) -o $@ am_hetget_OBJECTS = hetget.$(OBJEXT) hetget_OBJECTS = $(am_hetget_OBJECTS) hetget_DEPENDENCIES = $(am__DEPENDENCIES_3) hetget_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hetget_LDFLAGS) $(LDFLAGS) -o $@ am_hetinit_OBJECTS = hetinit.$(OBJEXT) hetinit_OBJECTS = $(am_hetinit_OBJECTS) hetinit_DEPENDENCIES = $(am__DEPENDENCIES_3) hetinit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hetinit_LDFLAGS) $(LDFLAGS) -o $@ am_hetmap_OBJECTS = hetmap.$(OBJEXT) hetmap_OBJECTS = $(am_hetmap_OBJECTS) hetmap_DEPENDENCIES = $(am__DEPENDENCIES_3) hetmap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hetmap_LDFLAGS) $(LDFLAGS) -o $@ am_hetupd_OBJECTS = hetupd.$(OBJEXT) hetupd_OBJECTS = $(am_hetupd_OBJECTS) hetupd_DEPENDENCIES = $(am__DEPENDENCIES_3) hetupd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(hetupd_LDFLAGS) $(LDFLAGS) -o $@ am_tapecopy_OBJECTS = tapecopy.$(OBJEXT) tapecopy_OBJECTS = $(am_tapecopy_OBJECTS) tapecopy_DEPENDENCIES = $(am__DEPENDENCIES_3) tapecopy_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(tapecopy_LDFLAGS) $(LDFLAGS) -o $@ am_tapemap_OBJECTS = tapemap.$(OBJEXT) tapemap_OBJECTS = $(am_tapemap_OBJECTS) tapemap_DEPENDENCIES = $(am__DEPENDENCIES_3) tapemap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(tapemap_LDFLAGS) $(LDFLAGS) -o $@ am_tapesplt_OBJECTS = tapesplt.$(OBJEXT) tapesplt_OBJECTS = $(am_tapesplt_OBJECTS) tapesplt_DEPENDENCIES = $(am__DEPENDENCIES_3) tapesplt_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(tapesplt_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/autoconf/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(dyngui_la_SOURCES) $(dyninst_la_SOURCES) \ $(hdt1052c_la_SOURCES) $(hdt1403_la_SOURCES) \ $(hdt2703_la_SOURCES) $(hdt2880_la_SOURCES) \ $(hdt3088_la_SOURCES) $(hdt3270_la_SOURCES) \ $(hdt3420_la_SOURCES) $(hdt3505_la_SOURCES) \ $(hdt3525_la_SOURCES) $(hdt3705_la_SOURCES) \ $(hdteq_la_SOURCES) $(hdtqeth_la_SOURCES) \ $(libherc_la_SOURCES) $(EXTRA_libherc_la_SOURCES) \ $(libhercd_la_SOURCES) $(libhercs_la_SOURCES) \ $(libherct_la_SOURCES) $(libhercu_la_SOURCES) \ $(cckdcdsk_SOURCES) $(cckdcomp_SOURCES) $(cckddiag_SOURCES) \ $(cckdswap_SOURCES) $(dasdcat_SOURCES) $(dasdconv_SOURCES) \ $(dasdcopy_SOURCES) $(dasdinit_SOURCES) $(dasdisup_SOURCES) \ $(dasdload_SOURCES) $(dasdls_SOURCES) $(dasdpdsu_SOURCES) \ $(dasdseq_SOURCES) $(dmap2hrc_SOURCES) $(hercifc_SOURCES) \ $(herclin_SOURCES) $(hercules_SOURCES) $(hetget_SOURCES) \ $(hetinit_SOURCES) $(hetmap_SOURCES) $(hetupd_SOURCES) \ $(tapecopy_SOURCES) $(tapemap_SOURCES) $(tapesplt_SOURCES) DIST_SOURCES = $(am__dyngui_la_SOURCES_DIST) \ $(am__dyninst_la_SOURCES_DIST) $(am__hdt1052c_la_SOURCES_DIST) \ $(am__hdt1403_la_SOURCES_DIST) $(am__hdt2703_la_SOURCES_DIST) \ $(am__hdt2880_la_SOURCES_DIST) $(am__hdt3088_la_SOURCES_DIST) \ $(am__hdt3270_la_SOURCES_DIST) $(am__hdt3420_la_SOURCES_DIST) \ $(am__hdt3505_la_SOURCES_DIST) $(am__hdt3525_la_SOURCES_DIST) \ $(am__hdt3705_la_SOURCES_DIST) $(am__hdteq_la_SOURCES_DIST) \ $(am__hdtqeth_la_SOURCES_DIST) $(am__libherc_la_SOURCES_DIST) \ $(EXTRA_libherc_la_SOURCES) $(libhercd_la_SOURCES) \ $(libhercs_la_SOURCES) $(libherct_la_SOURCES) \ $(am__libhercu_la_SOURCES_DIST) $(cckdcdsk_SOURCES) \ $(cckdcomp_SOURCES) $(cckddiag_SOURCES) $(cckdswap_SOURCES) \ $(dasdcat_SOURCES) $(dasdconv_SOURCES) $(dasdcopy_SOURCES) \ $(dasdinit_SOURCES) $(dasdisup_SOURCES) $(dasdload_SOURCES) \ $(dasdls_SOURCES) $(dasdpdsu_SOURCES) $(dasdseq_SOURCES) \ $(dmap2hrc_SOURCES) $(am__hercifc_SOURCES_DIST) \ $(am__herclin_SOURCES_DIST) $(hercules_SOURCES) \ $(hetget_SOURCES) $(hetinit_SOURCES) $(hetmap_SOURCES) \ $(hetupd_SOURCES) $(tapecopy_SOURCES) $(tapemap_SOURCES) \ $(tapesplt_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign 1.5 ACLOCAL_AMFLAGS = -I m4 -I autoconf lns = @LN_S@ SUBDIRS = decNumber softfloat m4 util html man . crypto LDADD = @LIBS@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/decNumber -I$(top_srcdir)/softfloat @BUILD_HERCIFC_FALSE@HERCIFC = @BUILD_HERCIFC_TRUE@HERCIFC = hercifc @BUILD_SHARED_FALSE@HERCLIN = @BUILD_SHARED_TRUE@HERCLIN = herclin fthreads_SRC = fthreads.c fishio_SRC = w32chan.c @BUILD_FTHREADS_FALSE@FTHREADS = @BUILD_FTHREADS_TRUE@FTHREADS = $(fthreads_SRC) @BUILD_FTHREADS_FALSE@FISHIO = @BUILD_FTHREADS_TRUE@FISHIO = $(fishio_SRC) # We need to still include the source for the dynamic modules # in with the distribution regardless of whether or not the dyanmic # modules themselves are to be built so if dynamic load not possible, # then we need to include the source on the EXTRA_hercules_SOURCES # statement so even though they won't/don't actually get built, they # still nonetheless get included into distribution tarball. This is # *similar* to (bit not identical to) the way the fthreads sources # are handled. With the fthreads sources though, they can at least always # be built (even though they may not always generate any actual code # whenever they do) whereas the dynamic module source CANNOT (MUST not) # even be *attempted* to be "built" if support for building dynamic modules # doesn't even exist on the system doing the building. dynamic_SRC = dyngui.c \ dyninst.c \ hdteq.c dyndev_SRC = commadpt.c \ comm3705.c \ console.c \ cardpch.c \ cardrdr.c \ sockdev.c \ printer.c \ tapedev.c \ tapeccws.c \ sllib.c \ hetlib.c \ awstape.c \ faketape.c \ hettape.c \ omatape.c \ scsitape.c \ w32stape.c \ ctc_lcs.c \ ctc_ctci.c \ ctcadpt.c \ w32ctca.c \ hchan.c \ tuntap.c \ qeth.c \ con1052c.c @BUILD_SHARED_FALSE@XSTATIC = -static # -module : create a dlopen'able module # -no-undefined : required on all platform that do not allow shared modules # to have undefined symbols # $(LDADD) : Misc Linker flags set by autoconf # -export-dynamic : so dlsym works (to be verified - not sure it is necessary) # -avoid-version : needed.. Otherwise libtool gives crazy names to Windows # DLLs # @BUILD_SHARED_TRUE@XSTATIC = @OPTION_DYNAMIC_LOAD_FALSE@DYNSRC = $(dyndev_SRC) @OPTION_DYNAMIC_LOAD_TRUE@DYNSRC = @OPTION_DYNAMIC_LOAD_FALSE@LTDL = @OPTION_DYNAMIC_LOAD_TRUE@LTDL = ltdl.c @OPTION_DYNAMIC_LOAD_FALSE@DYNMOD_LD_FLAGS = @OPTION_DYNAMIC_LOAD_TRUE@DYNMOD_LD_FLAGS = -module \ @OPTION_DYNAMIC_LOAD_TRUE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_TRUE@ $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_TRUE@ -export-dynamic \ @OPTION_DYNAMIC_LOAD_TRUE@ -avoid-version @OPTION_DYNAMIC_LOAD_FALSE@DYNMOD_LD_ADD = @OPTION_DYNAMIC_LOAD_TRUE@DYNMOD_LD_ADD = libherc.la \ @OPTION_DYNAMIC_LOAD_TRUE@ libhercs.la \ @OPTION_DYNAMIC_LOAD_TRUE@ libhercu.la \ @OPTION_DYNAMIC_LOAD_TRUE@ $(LDADD) @OPTION_DYNAMIC_LOAD_FALSE@LIB_LD_FLAGS = $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_FALSE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_FALSE@ -avoid-version @OPTION_DYNAMIC_LOAD_TRUE@LIB_LD_FLAGS = -export-dynamic \ @OPTION_DYNAMIC_LOAD_TRUE@ $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_TRUE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_TRUE@ -avoid-version # # List of Libtool shared libraries & loadable modules # HERCLIBS = HERCLIBS2 = libhercs.la \ libhercu.la \ libherct.la \ libhercd.la \ libherc.la HERCMODS = dyngui.la \ dyninst.la \ hdteq.la \ hdt1403.la \ hdt2703.la \ hdt3705.la \ hdt3088.la \ hdt3270.la \ hdt3420.la \ hdt3505.la \ hdt2880.la \ hdt3525.la \ hdtqeth.la \ hdt1052c.la @OPTION_DYNAMIC_LOAD_TRUE@modexec_LTLIBRARIES = $(HERCMODS) noinst_LTLIBRARIES = $(HERCLIBS) lib_LTLIBRARIES = $(HERCLIBS2) # # For each module: # # ModuleName_la_SOURCES = # ModuleName_la_LDFLAGS = $(DYNMOD_LD_FLAGS) (see above) # ModuleName_la_LIBADD = libherc.la (the Core Hercules Shared Library) # ModuleName_la_DEPENDENCIES = libherc.la (may not be necessary) # @OPTION_DYNAMIC_LOAD_TRUE@dyngui_la_SOURCES = dyngui.c @OPTION_DYNAMIC_LOAD_TRUE@dyngui_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@dyngui_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@dyninst_la_SOURCES = dyninst.c @OPTION_DYNAMIC_LOAD_TRUE@dyninst_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@dyninst_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdteq_la_SOURCES = hdteq.c @OPTION_DYNAMIC_LOAD_TRUE@hdteq_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdteq_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt1403_la_SOURCES = printer.c sockdev.c @OPTION_DYNAMIC_LOAD_TRUE@hdt1403_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt1403_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt2880_la_SOURCES = hchan.c @OPTION_DYNAMIC_LOAD_TRUE@hdt2880_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt2880_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt2703_la_SOURCES = commadpt.c @OPTION_DYNAMIC_LOAD_TRUE@hdt2703_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt2703_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt3705_la_SOURCES = comm3705.c @OPTION_DYNAMIC_LOAD_TRUE@hdt3705_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt3705_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt3088_la_SOURCES = ctc_lcs.c ctc_ctci.c ctcadpt.c w32ctca.c tuntap.c @OPTION_DYNAMIC_LOAD_TRUE@hdt3088_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt3088_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt3270_la_SOURCES = console.c @OPTION_DYNAMIC_LOAD_TRUE@hdt3270_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt3270_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt3420_la_SOURCES = tapedev.c tapeccws.c awstape.c faketape.c hettape.c omatape.c scsitape.c w32stape.c @OPTION_DYNAMIC_LOAD_TRUE@hdt3420_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt3420_la_LIBADD = $(DYNMOD_LD_ADD) libherct.la @OPTION_DYNAMIC_LOAD_TRUE@hdt3505_la_SOURCES = cardrdr.c sockdev.c @OPTION_DYNAMIC_LOAD_TRUE@hdt3505_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt3505_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt3525_la_SOURCES = cardpch.c @OPTION_DYNAMIC_LOAD_TRUE@hdt3525_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt3525_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdtqeth_la_SOURCES = qeth.c @OPTION_DYNAMIC_LOAD_TRUE@hdtqeth_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdtqeth_la_LIBADD = $(DYNMOD_LD_ADD) @OPTION_DYNAMIC_LOAD_TRUE@hdt1052c_la_SOURCES = con1052c.c @OPTION_DYNAMIC_LOAD_TRUE@hdt1052c_la_LDFLAGS = $(DYNMOD_LD_FLAGS) @OPTION_DYNAMIC_LOAD_TRUE@hdt1052c_la_LIBADD = $(DYNMOD_LD_ADD) # # Common data areas (shared) library # libhercs_la_SOURCES = hsys.c libhercs_la_LDFLAGS = $(LIB_LD_FLAGS) libhercs_la_LIBADD = $(LDADD) # # Tape utility subroutines (shared) library # libherct_la_SOURCES = sllib.c \ hetlib.c libherct_la_LDFLAGS = $(LIB_LD_FLAGS) libherct_la_LIBADD = $(LDADD) libhercs.la libhercu.la # # DASD utility subroutines (shared) library # libhercd_la_SOURCES = ckddasd.c \ fbadasd.c \ cckddasd.c \ cckdutil.c \ dasdtab.c \ cache.c \ dasdutil.c \ shared.c libhercd_la_LDFLAGS = $(LIB_LD_FLAGS) libhercd_la_LIBADD = $(LDADD) libhercs.la libhercu.la # # libhercu_la_SOURCES = version.c \ hscutl.c \ hscutl2.c \ codepage.c \ logger.c \ logmsg.c \ hdl.c \ hostinfo.c \ hsocket.c \ memrchr.c \ parser.c \ pttrace.c \ $(FTHREADS) \ $(LTDL) libhercu_la_LDFLAGS = $(LIB_LD_FLAGS) libhercu_la_LIBADD = $(LDADD) libhercs.la # # Core Hercules (shared) library # libherc_la_SOURCES = hconsole.c \ w32util.c \ strsignal.c \ impl.c \ config.c \ bldcfg.c \ panel.c \ history.c \ fillfnam.c \ ipl.c \ assist.c \ dat.c \ stack.c \ cpu.c \ vstore.c \ general1.c \ general2.c \ general3.c \ pfpo.c \ plo.c \ control.c \ crypto.c \ io.c \ decimal.c \ service.c \ scedasd.c \ losc.c \ chsc.c \ opcode.c \ diagnose.c \ diagmssf.c \ vm.c \ vmd250.c \ channel.c \ external.c \ float.c \ trace.c \ machchk.c \ vector.c \ xstore.c \ cmpsc.c \ sie.c \ qdio.c \ clock.c \ timer.c \ esame.c \ ieee.c \ dfp.c \ machdep.h \ httpserv.c \ cgibin.c \ loadparm.c \ hsccmd.c \ cmdtab.c \ hao.c \ hscmisc.c \ sr.c \ $(FISHIO) \ $(DYNSRC) \ ecpsvm.c EXTRA_libherc_la_SOURCES = $(fthreads_SRC) \ $(fishio_SRC) \ memrchr.c \ $(dynamic_SRC) \ $(extra_SRC) \ $(dyndev_SRC) \ ltdl.c libherc_la_LDFLAGS = $(LIB_LD_FLAGS) libherc_la_LIBADD = libhercs.la \ libhercu.la \ libherct.la \ libhercd.la \ decNumber/libdecNumber.la \ softfloat/libsoftfloat.la \ $(LDADD) @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@HLDFLAGS = -dlopen self \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen dyngui.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen dyninst.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdteq.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt1403.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt3420.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt2703.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt3705.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt3088.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt3270.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt3505.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt3525.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdtqeth.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ -dlopen hdt1052c.la # # THIS is the hercules executable. # hdlmain.c is requires so that dlopen(self) retrieves # the 'main' hdl symbols # @BUILD_SHARED_TRUE@@OPTION_DYNAMIC_LOAD_TRUE@HLDFLAGS = -dlopen self @OPTION_DYNAMIC_LOAD_FALSE@HLDFLAGS = @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@HDEPS = dyngui.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ dyninst.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdteq.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt1403.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt3420.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt2703.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt3705.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt3088.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt3270.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt3505.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt3525.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdtqeth.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ hdt1052c.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ libherc.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ libherct.la \ @BUILD_SHARED_FALSE@@OPTION_DYNAMIC_LOAD_TRUE@ libhercd.la @BUILD_SHARED_TRUE@@OPTION_DYNAMIC_LOAD_TRUE@HDEPS = @OPTION_DYNAMIC_LOAD_FALSE@HDEPS = hercules_SOURCES = bootstrap.c \ hdlmain.c hercules_LDADD = libherc.la libhercs.la $(LDADD) hercules_LDFLAGS = $(HLDFLAGS) hercules_DEPENDENCIES = libherc.la libhercs.la $(HDEPS) @BUILD_SHARED_TRUE@herclin_SOURCES = herclin.c hdlmain.c @BUILD_SHARED_TRUE@herclin_LDADD = libherc.la libhercs.la $(LDADD) @BUILD_SHARED_TRUE@herclin_LDFLAGS = $(HLDFLAGS) @BUILD_SHARED_TRUE@herclin_DEPENDENCIES = libherc.la libhercs.la $(HDEPS) # # side binaries # tools_LD_FLAGS = tools_ADDLIBS = $(HERCLIBS2) $(LDADD) @BUILD_HERCIFC_TRUE@hercifc_SOURCES = hercifc.c @BUILD_HERCIFC_TRUE@hercifc_LDADD = $(tools_ADDLIBS) @BUILD_HERCIFC_TRUE@hercifc_LDFLAGS = $(tools_LD_FLAGS) dasdinit_SOURCES = dasdinit.c dasdinit_LDADD = $(tools_ADDLIBS) dasdinit_LDFLAGS = $(tools_LD_FLAGS) dasdisup_SOURCES = dasdisup.c dasdisup_LDADD = $(tools_ADDLIBS) dasdisup_LDFLAGS = $(tools_LD_FLAGS) dasdload_SOURCES = dasdload.c dasdload_LDADD = $(tools_ADDLIBS) dasdload_LDFLAGS = $(tools_LD_FLAGS) dasdconv_SOURCES = dasdconv.c dasdconv_LDADD = $(tools_ADDLIBS) dasdconv_LDFLAGS = $(tools_LD_FLAGS) dasdls_SOURCES = dasdls.c dasdls_LDADD = $(tools_ADDLIBS) dasdls_LDFLAGS = $(tools_LD_FLAGS) dasdcat_SOURCES = dasdcat.c dasdcat_LDADD = $(tools_ADDLIBS) dasdcat_LDFLAGS = $(tools_LD_FLAGS) dasdpdsu_SOURCES = dasdpdsu.c dasdpdsu_LDADD = $(tools_ADDLIBS) dasdpdsu_LDFLAGS = $(tools_LD_FLAGS) dasdseq_SOURCES = dasdseq.c dasdseq_LDADD = $(tools_ADDLIBS) dasdseq_LDFLAGS = $(tools_LD_FLAGS) tapecopy_SOURCES = tapecopy.c tapecopy_LDADD = $(tools_ADDLIBS) tapecopy_LDFLAGS = $(tools_LD_FLAGS) tapemap_SOURCES = tapemap.c tapemap_LDADD = $(tools_ADDLIBS) tapemap_LDFLAGS = $(tools_LD_FLAGS) tapesplt_SOURCES = tapesplt.c tapesplt_LDADD = $(tools_ADDLIBS) tapesplt_LDFLAGS = $(tools_LD_FLAGS) cckdcdsk_SOURCES = cckdcdsk.c cckdcdsk_LDADD = $(tools_ADDLIBS) cckdcdsk_LDFLAGS = $(tools_LD_FLAGS) cckdcomp_SOURCES = cckdcomp.c cckdcomp_LDADD = $(tools_ADDLIBS) cckdcomp_LDFLAGS = $(tools_LD_FLAGS) cckddiag_SOURCES = cckddiag.c cckddiag_LDADD = $(tools_ADDLIBS) cckddiag_LDFLAGS = $(tools_LD_FLAGS) dasdcopy_SOURCES = dasdcopy.c dasdcopy_LDADD = $(tools_ADDLIBS) dasdcopy_LDFLAGS = $(tools_LD_FLAGS) cckdswap_SOURCES = cckdswap.c cckdswap_LDADD = $(tools_ADDLIBS) cckdswap_LDFLAGS = $(tools_LD_FLAGS) hetget_SOURCES = hetget.c hetget_LDADD = $(tools_ADDLIBS) hetget_LDFLAGS = $(tools_LD_FLAGS) hetinit_SOURCES = hetinit.c hetinit_LDADD = $(tools_ADDLIBS) hetinit_LDFLAGS = $(tools_LD_FLAGS) hetmap_SOURCES = hetmap.c hetmap_LDADD = $(tools_ADDLIBS) hetmap_LDFLAGS = $(tools_LD_FLAGS) hetupd_SOURCES = hetupd.c hetupd_LDADD = $(tools_ADDLIBS) hetupd_LDFLAGS = $(tools_LD_FLAGS) dmap2hrc_SOURCES = dmap2hrc.c dmap2hrc_LDADD = $(tools_ADDLIBS) dmap2hrc_LDFLAGS = $(tools_LD_FLAGS) # # files that are not 'built' per-se # # # Also contains some WIN32 only source files # EXTRA_DIST = autoconf/config.rpath \ autoconf/mkinstalldirs \ COPYRIGHT \ hercules.cnf \ cckdfix.c \ README.COMMADPT \ README.DYNMOD \ README.ECPSVM \ README.HDL \ README.NETWORKING \ README.OSX \ README.TAPE \ README.HERCLOGO \ RELEASE.NOTES \ README.WIN32 \ README.WIN64 \ README.SUN \ makefile.msvc \ makefile-dllmod.msvc \ msvc.makefile.includes/BZIP2_DIR.msvc \ msvc.makefile.includes/BZIP2_FLAGS.msvc \ msvc.makefile.includes/BZIP2_RULES.msvc \ msvc.makefile.includes/CONFIG.msvc \ msvc.makefile.includes/DEBUG_RETAIL.msvc \ msvc.makefile.includes/HERC_FLAGS.msvc \ msvc.makefile.includes/MOD_RULES1.msvc \ msvc.makefile.includes/MOD_RULES2.msvc \ msvc.makefile.includes/MODULES.msvc \ msvc.makefile.includes/OBJ_CODE.msvc \ msvc.makefile.includes/OUTDIR_RULES.msvc \ msvc.makefile.includes/OUTPUT_DIRS.msvc \ msvc.makefile.includes/PCRE_DIR.msvc \ msvc.makefile.includes/PCRE_FLAGS.msvc \ msvc.makefile.includes/PCRE_RULES.msvc \ msvc.makefile.includes/PRIM_RULES.msvc \ msvc.makefile.includes/VERSION.msvc \ msvc.makefile.includes/ZLIB_DIR.msvc \ msvc.makefile.includes/ZLIB_FLAGS.msvc \ msvc.makefile.includes/ZLIB_RULES.msvc \ hercver.rc \ build_pch.c \ conspawn.c \ getopt.c \ herclogo.txt \ hercules.ico # # Source Header files. No 'build' for those # noinst_HEADERS = hostinfo.h \ cpuint.h \ feat370.h \ feat390.h \ feat900.h \ featall.h \ featchk.h \ feature.h \ esa390.h \ opcode.h \ clock.h \ hercules.h \ inline.h \ dat.h \ vstore.h \ hbyteswp.h \ dasdblks.h \ hetlib.h \ version.h \ parser.h \ dasdtab.h \ sllib.h \ htypes.h \ fthreads.h \ w32chan.h \ w32ctca.h \ tt32api.h \ linklist.h \ httpmisc.h \ devtype.h \ codepage.h \ ctcadpt.h \ hercifc.h \ tuntap.h \ tapedev.h \ scsitape.h \ logger.h \ commadpt.h \ comm3705.h \ cache.h \ ecpsvm.h \ memrchr.h \ shared.h \ hscutl.h \ cmdtab.h \ hdl.h \ crypto.h \ sockdev.h \ ltdl.h \ herc_getopt.h \ service.h \ chsc.h \ pttrace.h \ history.h \ sr.h \ hchan.h \ fillfnam.h \ hthreads.h \ hostopts.h \ w32util.h \ hconsts.h \ hmacros.h \ hstructs.h \ hexterns.h \ hconsole.h \ hextapi.h \ hstdinc.h \ hstdint.h \ hsocket.h \ w32stape.h \ w32dl.h \ hercwind.h \ getopt.h \ w32mtio.h \ vmd250.h \ $(extra_dynamic_SRC) all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } install-modexecLTLIBRARIES: $(modexec_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(modexec_LTLIBRARIES)'; test -n "$(modexecdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(modexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(modexecdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(modexecdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(modexecdir)"; \ } uninstall-modexecLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(modexec_LTLIBRARIES)'; test -n "$(modexecdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(modexecdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(modexecdir)/$$f"; \ done clean-modexecLTLIBRARIES: -test -z "$(modexec_LTLIBRARIES)" || rm -f $(modexec_LTLIBRARIES) @list='$(modexec_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } dyngui.la: $(dyngui_la_OBJECTS) $(dyngui_la_DEPENDENCIES) $(EXTRA_dyngui_la_DEPENDENCIES) $(AM_V_CCLD)$(dyngui_la_LINK) $(am_dyngui_la_rpath) $(dyngui_la_OBJECTS) $(dyngui_la_LIBADD) $(LIBS) dyninst.la: $(dyninst_la_OBJECTS) $(dyninst_la_DEPENDENCIES) $(EXTRA_dyninst_la_DEPENDENCIES) $(AM_V_CCLD)$(dyninst_la_LINK) $(am_dyninst_la_rpath) $(dyninst_la_OBJECTS) $(dyninst_la_LIBADD) $(LIBS) hdt1052c.la: $(hdt1052c_la_OBJECTS) $(hdt1052c_la_DEPENDENCIES) $(EXTRA_hdt1052c_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt1052c_la_LINK) $(am_hdt1052c_la_rpath) $(hdt1052c_la_OBJECTS) $(hdt1052c_la_LIBADD) $(LIBS) hdt1403.la: $(hdt1403_la_OBJECTS) $(hdt1403_la_DEPENDENCIES) $(EXTRA_hdt1403_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt1403_la_LINK) $(am_hdt1403_la_rpath) $(hdt1403_la_OBJECTS) $(hdt1403_la_LIBADD) $(LIBS) hdt2703.la: $(hdt2703_la_OBJECTS) $(hdt2703_la_DEPENDENCIES) $(EXTRA_hdt2703_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt2703_la_LINK) $(am_hdt2703_la_rpath) $(hdt2703_la_OBJECTS) $(hdt2703_la_LIBADD) $(LIBS) hdt2880.la: $(hdt2880_la_OBJECTS) $(hdt2880_la_DEPENDENCIES) $(EXTRA_hdt2880_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt2880_la_LINK) $(am_hdt2880_la_rpath) $(hdt2880_la_OBJECTS) $(hdt2880_la_LIBADD) $(LIBS) hdt3088.la: $(hdt3088_la_OBJECTS) $(hdt3088_la_DEPENDENCIES) $(EXTRA_hdt3088_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt3088_la_LINK) $(am_hdt3088_la_rpath) $(hdt3088_la_OBJECTS) $(hdt3088_la_LIBADD) $(LIBS) hdt3270.la: $(hdt3270_la_OBJECTS) $(hdt3270_la_DEPENDENCIES) $(EXTRA_hdt3270_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt3270_la_LINK) $(am_hdt3270_la_rpath) $(hdt3270_la_OBJECTS) $(hdt3270_la_LIBADD) $(LIBS) hdt3420.la: $(hdt3420_la_OBJECTS) $(hdt3420_la_DEPENDENCIES) $(EXTRA_hdt3420_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt3420_la_LINK) $(am_hdt3420_la_rpath) $(hdt3420_la_OBJECTS) $(hdt3420_la_LIBADD) $(LIBS) hdt3505.la: $(hdt3505_la_OBJECTS) $(hdt3505_la_DEPENDENCIES) $(EXTRA_hdt3505_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt3505_la_LINK) $(am_hdt3505_la_rpath) $(hdt3505_la_OBJECTS) $(hdt3505_la_LIBADD) $(LIBS) hdt3525.la: $(hdt3525_la_OBJECTS) $(hdt3525_la_DEPENDENCIES) $(EXTRA_hdt3525_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt3525_la_LINK) $(am_hdt3525_la_rpath) $(hdt3525_la_OBJECTS) $(hdt3525_la_LIBADD) $(LIBS) hdt3705.la: $(hdt3705_la_OBJECTS) $(hdt3705_la_DEPENDENCIES) $(EXTRA_hdt3705_la_DEPENDENCIES) $(AM_V_CCLD)$(hdt3705_la_LINK) $(am_hdt3705_la_rpath) $(hdt3705_la_OBJECTS) $(hdt3705_la_LIBADD) $(LIBS) hdteq.la: $(hdteq_la_OBJECTS) $(hdteq_la_DEPENDENCIES) $(EXTRA_hdteq_la_DEPENDENCIES) $(AM_V_CCLD)$(hdteq_la_LINK) $(am_hdteq_la_rpath) $(hdteq_la_OBJECTS) $(hdteq_la_LIBADD) $(LIBS) hdtqeth.la: $(hdtqeth_la_OBJECTS) $(hdtqeth_la_DEPENDENCIES) $(EXTRA_hdtqeth_la_DEPENDENCIES) $(AM_V_CCLD)$(hdtqeth_la_LINK) $(am_hdtqeth_la_rpath) $(hdtqeth_la_OBJECTS) $(hdtqeth_la_LIBADD) $(LIBS) libherc.la: $(libherc_la_OBJECTS) $(libherc_la_DEPENDENCIES) $(EXTRA_libherc_la_DEPENDENCIES) $(AM_V_CCLD)$(libherc_la_LINK) -rpath $(libdir) $(libherc_la_OBJECTS) $(libherc_la_LIBADD) $(LIBS) libhercd.la: $(libhercd_la_OBJECTS) $(libhercd_la_DEPENDENCIES) $(EXTRA_libhercd_la_DEPENDENCIES) $(AM_V_CCLD)$(libhercd_la_LINK) -rpath $(libdir) $(libhercd_la_OBJECTS) $(libhercd_la_LIBADD) $(LIBS) libhercs.la: $(libhercs_la_OBJECTS) $(libhercs_la_DEPENDENCIES) $(EXTRA_libhercs_la_DEPENDENCIES) $(AM_V_CCLD)$(libhercs_la_LINK) -rpath $(libdir) $(libhercs_la_OBJECTS) $(libhercs_la_LIBADD) $(LIBS) libherct.la: $(libherct_la_OBJECTS) $(libherct_la_DEPENDENCIES) $(EXTRA_libherct_la_DEPENDENCIES) $(AM_V_CCLD)$(libherct_la_LINK) -rpath $(libdir) $(libherct_la_OBJECTS) $(libherct_la_LIBADD) $(LIBS) libhercu.la: $(libhercu_la_OBJECTS) $(libhercu_la_DEPENDENCIES) $(EXTRA_libhercu_la_DEPENDENCIES) $(AM_V_CCLD)$(libhercu_la_LINK) -rpath $(libdir) $(libhercu_la_OBJECTS) $(libhercu_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list cckdcdsk$(EXEEXT): $(cckdcdsk_OBJECTS) $(cckdcdsk_DEPENDENCIES) $(EXTRA_cckdcdsk_DEPENDENCIES) @rm -f cckdcdsk$(EXEEXT) $(AM_V_CCLD)$(cckdcdsk_LINK) $(cckdcdsk_OBJECTS) $(cckdcdsk_LDADD) $(LIBS) cckdcomp$(EXEEXT): $(cckdcomp_OBJECTS) $(cckdcomp_DEPENDENCIES) $(EXTRA_cckdcomp_DEPENDENCIES) @rm -f cckdcomp$(EXEEXT) $(AM_V_CCLD)$(cckdcomp_LINK) $(cckdcomp_OBJECTS) $(cckdcomp_LDADD) $(LIBS) cckddiag$(EXEEXT): $(cckddiag_OBJECTS) $(cckddiag_DEPENDENCIES) $(EXTRA_cckddiag_DEPENDENCIES) @rm -f cckddiag$(EXEEXT) $(AM_V_CCLD)$(cckddiag_LINK) $(cckddiag_OBJECTS) $(cckddiag_LDADD) $(LIBS) cckdswap$(EXEEXT): $(cckdswap_OBJECTS) $(cckdswap_DEPENDENCIES) $(EXTRA_cckdswap_DEPENDENCIES) @rm -f cckdswap$(EXEEXT) $(AM_V_CCLD)$(cckdswap_LINK) $(cckdswap_OBJECTS) $(cckdswap_LDADD) $(LIBS) dasdcat$(EXEEXT): $(dasdcat_OBJECTS) $(dasdcat_DEPENDENCIES) $(EXTRA_dasdcat_DEPENDENCIES) @rm -f dasdcat$(EXEEXT) $(AM_V_CCLD)$(dasdcat_LINK) $(dasdcat_OBJECTS) $(dasdcat_LDADD) $(LIBS) dasdconv$(EXEEXT): $(dasdconv_OBJECTS) $(dasdconv_DEPENDENCIES) $(EXTRA_dasdconv_DEPENDENCIES) @rm -f dasdconv$(EXEEXT) $(AM_V_CCLD)$(dasdconv_LINK) $(dasdconv_OBJECTS) $(dasdconv_LDADD) $(LIBS) dasdcopy$(EXEEXT): $(dasdcopy_OBJECTS) $(dasdcopy_DEPENDENCIES) $(EXTRA_dasdcopy_DEPENDENCIES) @rm -f dasdcopy$(EXEEXT) $(AM_V_CCLD)$(dasdcopy_LINK) $(dasdcopy_OBJECTS) $(dasdcopy_LDADD) $(LIBS) dasdinit$(EXEEXT): $(dasdinit_OBJECTS) $(dasdinit_DEPENDENCIES) $(EXTRA_dasdinit_DEPENDENCIES) @rm -f dasdinit$(EXEEXT) $(AM_V_CCLD)$(dasdinit_LINK) $(dasdinit_OBJECTS) $(dasdinit_LDADD) $(LIBS) dasdisup$(EXEEXT): $(dasdisup_OBJECTS) $(dasdisup_DEPENDENCIES) $(EXTRA_dasdisup_DEPENDENCIES) @rm -f dasdisup$(EXEEXT) $(AM_V_CCLD)$(dasdisup_LINK) $(dasdisup_OBJECTS) $(dasdisup_LDADD) $(LIBS) dasdload$(EXEEXT): $(dasdload_OBJECTS) $(dasdload_DEPENDENCIES) $(EXTRA_dasdload_DEPENDENCIES) @rm -f dasdload$(EXEEXT) $(AM_V_CCLD)$(dasdload_LINK) $(dasdload_OBJECTS) $(dasdload_LDADD) $(LIBS) dasdls$(EXEEXT): $(dasdls_OBJECTS) $(dasdls_DEPENDENCIES) $(EXTRA_dasdls_DEPENDENCIES) @rm -f dasdls$(EXEEXT) $(AM_V_CCLD)$(dasdls_LINK) $(dasdls_OBJECTS) $(dasdls_LDADD) $(LIBS) dasdpdsu$(EXEEXT): $(dasdpdsu_OBJECTS) $(dasdpdsu_DEPENDENCIES) $(EXTRA_dasdpdsu_DEPENDENCIES) @rm -f dasdpdsu$(EXEEXT) $(AM_V_CCLD)$(dasdpdsu_LINK) $(dasdpdsu_OBJECTS) $(dasdpdsu_LDADD) $(LIBS) dasdseq$(EXEEXT): $(dasdseq_OBJECTS) $(dasdseq_DEPENDENCIES) $(EXTRA_dasdseq_DEPENDENCIES) @rm -f dasdseq$(EXEEXT) $(AM_V_CCLD)$(dasdseq_LINK) $(dasdseq_OBJECTS) $(dasdseq_LDADD) $(LIBS) dmap2hrc$(EXEEXT): $(dmap2hrc_OBJECTS) $(dmap2hrc_DEPENDENCIES) $(EXTRA_dmap2hrc_DEPENDENCIES) @rm -f dmap2hrc$(EXEEXT) $(AM_V_CCLD)$(dmap2hrc_LINK) $(dmap2hrc_OBJECTS) $(dmap2hrc_LDADD) $(LIBS) hercifc$(EXEEXT): $(hercifc_OBJECTS) $(hercifc_DEPENDENCIES) $(EXTRA_hercifc_DEPENDENCIES) @rm -f hercifc$(EXEEXT) $(AM_V_CCLD)$(hercifc_LINK) $(hercifc_OBJECTS) $(hercifc_LDADD) $(LIBS) herclin$(EXEEXT): $(herclin_OBJECTS) $(herclin_DEPENDENCIES) $(EXTRA_herclin_DEPENDENCIES) @rm -f herclin$(EXEEXT) $(AM_V_CCLD)$(herclin_LINK) $(herclin_OBJECTS) $(herclin_LDADD) $(LIBS) hercules$(EXEEXT): $(hercules_OBJECTS) $(hercules_DEPENDENCIES) $(EXTRA_hercules_DEPENDENCIES) @rm -f hercules$(EXEEXT) $(AM_V_CCLD)$(hercules_LINK) $(hercules_OBJECTS) $(hercules_LDADD) $(LIBS) hetget$(EXEEXT): $(hetget_OBJECTS) $(hetget_DEPENDENCIES) $(EXTRA_hetget_DEPENDENCIES) @rm -f hetget$(EXEEXT) $(AM_V_CCLD)$(hetget_LINK) $(hetget_OBJECTS) $(hetget_LDADD) $(LIBS) hetinit$(EXEEXT): $(hetinit_OBJECTS) $(hetinit_DEPENDENCIES) $(EXTRA_hetinit_DEPENDENCIES) @rm -f hetinit$(EXEEXT) $(AM_V_CCLD)$(hetinit_LINK) $(hetinit_OBJECTS) $(hetinit_LDADD) $(LIBS) hetmap$(EXEEXT): $(hetmap_OBJECTS) $(hetmap_DEPENDENCIES) $(EXTRA_hetmap_DEPENDENCIES) @rm -f hetmap$(EXEEXT) $(AM_V_CCLD)$(hetmap_LINK) $(hetmap_OBJECTS) $(hetmap_LDADD) $(LIBS) hetupd$(EXEEXT): $(hetupd_OBJECTS) $(hetupd_DEPENDENCIES) $(EXTRA_hetupd_DEPENDENCIES) @rm -f hetupd$(EXEEXT) $(AM_V_CCLD)$(hetupd_LINK) $(hetupd_OBJECTS) $(hetupd_LDADD) $(LIBS) tapecopy$(EXEEXT): $(tapecopy_OBJECTS) $(tapecopy_DEPENDENCIES) $(EXTRA_tapecopy_DEPENDENCIES) @rm -f tapecopy$(EXEEXT) $(AM_V_CCLD)$(tapecopy_LINK) $(tapecopy_OBJECTS) $(tapecopy_LDADD) $(LIBS) tapemap$(EXEEXT): $(tapemap_OBJECTS) $(tapemap_DEPENDENCIES) $(EXTRA_tapemap_DEPENDENCIES) @rm -f tapemap$(EXEEXT) $(AM_V_CCLD)$(tapemap_LINK) $(tapemap_OBJECTS) $(tapemap_LDADD) $(LIBS) tapesplt$(EXEEXT): $(tapesplt_OBJECTS) $(tapesplt_DEPENDENCIES) $(EXTRA_tapesplt_DEPENDENCIES) @rm -f tapesplt$(EXEEXT) $(AM_V_CCLD)$(tapesplt_LINK) $(tapesplt_OBJECTS) $(tapesplt_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/assist.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awstape.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bldcfg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bootstrap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cardpch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cardrdr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cckdcdsk.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cckdcomp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cckddasd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cckddiag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cckdswap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cckdutil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgibin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chsc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ckddasd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmdtab.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmpsc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/codepage.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/comm3705.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commadpt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/con1052c.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/console.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctc_ctci.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctc_lcs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctcadpt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdcat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdconv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdcopy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdinit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdisup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdls.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdpdsu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdseq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdtab.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasdutil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dat.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decimal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diagmssf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diagnose.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmap2hrc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dyngui.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dyninst.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecpsvm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esame.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/external.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/faketape.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fbadasd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fillfnam.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/float.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fthreads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/general1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/general2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/general3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hao.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hchan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hconsole.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdlmain.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdteq.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hercifc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/herclin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hetget.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hetinit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hetlib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hetmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hettape.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hetupd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/history.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostinfo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hsccmd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hscmisc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hscutl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hscutl2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hsocket.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hsys.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpserv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ieee.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/impl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loadparm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logmsg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/losc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ltdl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/machchk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memrchr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omatape.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opcode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfpo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pttrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qdio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qeth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scedasd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scsitape.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/service.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shared.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sie.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sllib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockdev.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strsignal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapeccws.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapecopy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapedev.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapesplt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tuntap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmd250.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vstore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32chan.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32ctca.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32stape.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xstore.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) config.h install-binPROGRAMS: install-libLTLIBRARIES installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(modexecdir)" "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-modexecLTLIBRARIES clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-exec-local \ install-libLTLIBRARIES install-modexecLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-local uninstall-modexecLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: $(am__recursive_targets) all install-am install-exec-am \ install-strip uninstall-am .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-binPROGRAMS \ clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \ clean-modexecLTLIBRARIES clean-noinstLTLIBRARIES cscope \ cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags distcleancheck \ distdir distuninstallcheck dvi dvi-am html html-am info \ info-am install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-exec-hook install-exec-local \ install-html install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-modexecLTLIBRARIES \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-hook \ uninstall-libLTLIBRARIES uninstall-local \ uninstall-modexecLTLIBRARIES cckd: cckd2ckd$(EXEEXT) \ cckdcdsk$(EXEEXT) \ cckddiag$(EXEEXT) \ cckdcomp$(EXEEXT) \ cckdswap$(EXEEXT) \ dasdcopy$(EXEEXT) ######################################################### # B U I L D R U L E S . . . ######################################################### # # *** PROGRAMMING NOTE! *** # # The tabs in the below statements ARE significant! # Not all make programs accept (handle correctly) # make files that use blanks instead of tabs in their # build rules. Thus in order to remain compatible # with older make programs the below build rules # MUST use *tabs* and NOT BLANKS! # ######################################################### tar: dist install-exec-local: install-exec-hook: @BUILD_SHARED_TRUE@ rm -f $(DESTDIR)$(libdir)/libherc*.a @BUILD_SHARED_TRUE@ rm -f $(DESTDIR)$(modexecdir)/dyn*.a @BUILD_SHARED_TRUE@ rm -f $(DESTDIR)$(modexecdir)/hdt*.a @BUILD_SHARED_FALSE@ rm -f $(DESTDIR)$(libdir)/libherc* # # NOTE : symbolic links point to FINAL destination (not to staged install) # rm -f $(DESTDIR)$(bindir)/fba2cfba$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) fba2cfba$(EXEEXT)) rm -f $(DESTDIR)$(bindir)/ckd2cckd$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) ckd2cckd$(EXEEXT)) rm -f $(DESTDIR)$(bindir)/cfba2fba$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) cfba2fba$(EXEEXT)) rm -f $(DESTDIR)$(bindir)/cckd2ckd$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) cckd2ckd$(EXEEXT)) @SETUID_HERCIFC_TRUE@ chown root $(DESTDIR)$(bindir)/hercifc @HERCIFC_GROUPSET_TRUE@@SETUID_HERCIFC_TRUE@ chgrp $(HERCIFC_GROUPNAME) $(DESTDIR)$(bindir)/hercifc @SETUID_HERCIFC_TRUE@ chmod 0750 $(DESTDIR)$(bindir)/hercifc @SETUID_HERCIFC_TRUE@ chmod +s $(DESTDIR)$(bindir)/hercifc @SETUID_HERCIFC_TRUE@ rm hercifc uninstall-local: uninstall-hook: rm -f $(DESTDIR)$(bindir)/fba2cfba$(EXEEXT) rm -f $(DESTDIR)$(bindir)/ckd2cckd$(EXEEXT) rm -f $(DESTDIR)$(bindir)/cfba2fba$(EXEEXT) rm -f $(DESTDIR)$(bindir)/cckd2ckd$(EXEEXT) %.s: %.c $(COMPILE) -S $< # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/Makefile.am0000664000175000017500000005432612564723224012251 00000000000000# *************************************************************************** # Makefile for Hercules S/370, ESA/390 and z/Architecture emulator # Process this file with 'automake' to produce Makefile.in # *************************************************************************** AUTOMAKE_OPTIONS = foreign 1.5 ACLOCAL_AMFLAGS = -I m4 -I autoconf lns=@LN_S@ SUBDIRS = decNumber softfloat m4 util html man . crypto LDADD = @LIBS@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/decNumber -I$(top_srcdir)/softfloat if BUILD_HERCIFC HERCIFC = hercifc else HERCIFC= endif if BUILD_SHARED HERCLIN=herclin else HERCLIN= endif fthreads_SRC = fthreads.c fishio_SRC = w32chan.c if BUILD_FTHREADS FTHREADS = $(fthreads_SRC) FISHIO = $(fishio_SRC) else FTHREADS = FISHIO = endif # We need to still include the source for the dynamic modules # in with the distribution regardless of whether or not the dyanmic # modules themselves are to be built so if dynamic load not possible, # then we need to include the source on the EXTRA_hercules_SOURCES # statement so even though they won't/don't actually get built, they # still nonetheless get included into distribution tarball. This is # *similar* to (bit not identical to) the way the fthreads sources # are handled. With the fthreads sources though, they can at least always # be built (even though they may not always generate any actual code # whenever they do) whereas the dynamic module source CANNOT (MUST not) # even be *attempted* to be "built" if support for building dynamic modules # doesn't even exist on the system doing the building. dynamic_SRC = dyngui.c \ dyninst.c \ hdteq.c dyndev_SRC = commadpt.c \ comm3705.c \ console.c \ cardpch.c \ cardrdr.c \ sockdev.c \ printer.c \ tapedev.c \ tapeccws.c \ sllib.c \ hetlib.c \ awstape.c \ faketape.c \ hettape.c \ omatape.c \ scsitape.c \ w32stape.c \ ctc_lcs.c \ ctc_ctci.c \ ctcadpt.c \ w32ctca.c \ hchan.c \ tuntap.c \ qeth.c \ con1052c.c # -module : create a dlopen'able module # -no-undefined : required on all platform that do not allow shared modules # to have undefined symbols # $(LDADD) : Misc Linker flags set by autoconf # -export-dynamic : so dlsym works (to be verified - not sure it is necessary) # -avoid-version : needed.. Otherwise libtool gives crazy names to Windows # DLLs # if BUILD_SHARED XSTATIC = else XSTATIC = -static endif if OPTION_DYNAMIC_LOAD DYNSRC = LTDL = ltdl.c DYNMOD_LD_FLAGS = -module \ -no-undefined \ $(XSTATIC) \ -export-dynamic \ -avoid-version DYNMOD_LD_ADD = libherc.la \ libhercs.la \ libhercu.la \ $(LDADD) LIB_LD_FLAGS = -export-dynamic \ $(XSTATIC) \ -no-undefined \ -avoid-version else DYNSRC = $(dyndev_SRC) LTDL = DYNMOD_LD_FLAGS = DYNMOD_LD_ADD = LIB_LD_FLAGS = $(XSTATIC) \ -no-undefined \ -avoid-version endif # # List of Libtool shared libraries & loadable modules # HERCLIBS = HERCLIBS2 = libhercs.la \ libhercu.la \ libherct.la \ libhercd.la \ libherc.la HERCMODS = dyngui.la \ dyninst.la \ hdteq.la \ hdt1403.la \ hdt2703.la \ hdt3705.la \ hdt3088.la \ hdt3270.la \ hdt3420.la \ hdt3505.la \ hdt2880.la \ hdt3525.la \ hdtqeth.la \ hdt1052c.la if OPTION_DYNAMIC_LOAD modexec_LTLIBRARIES = $(HERCMODS) endif noinst_LTLIBRARIES = $(HERCLIBS) lib_LTLIBRARIES = $(HERCLIBS2) # The following causes the dyanmic modules to not even get built # unless support for building dynamic modules exists on the build system bin_PROGRAMS = hercules \ dasdinit dasdisup dasdload dasdconv dasdls dasdcat dasdpdsu dasdseq \ tapecopy tapemap tapesplt \ cckdcdsk cckdcomp cckddiag cckdswap \ dasdcopy \ hetget hetinit hetmap hetupd \ dmap2hrc \ $(HERCIFC) \ $(HERCLIN) EXTRA_PROGRAMS = hercifc if OPTION_DYNAMIC_LOAD # # For each module: # # ModuleName_la_SOURCES = # ModuleName_la_LDFLAGS = $(DYNMOD_LD_FLAGS) (see above) # ModuleName_la_LIBADD = libherc.la (the Core Hercules Shared Library) # ModuleName_la_DEPENDENCIES = libherc.la (may not be necessary) # dyngui_la_SOURCES = dyngui.c dyngui_la_LDFLAGS = $(DYNMOD_LD_FLAGS) dyngui_la_LIBADD = $(DYNMOD_LD_ADD) dyninst_la_SOURCES = dyninst.c dyninst_la_LDFLAGS = $(DYNMOD_LD_FLAGS) dyninst_la_LIBADD = $(DYNMOD_LD_ADD) hdteq_la_SOURCES = hdteq.c hdteq_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdteq_la_LIBADD = $(DYNMOD_LD_ADD) hdt1403_la_SOURCES = printer.c sockdev.c hdt1403_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt1403_la_LIBADD = $(DYNMOD_LD_ADD) hdt2880_la_SOURCES = hchan.c hdt2880_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt2880_la_LIBADD = $(DYNMOD_LD_ADD) hdt2703_la_SOURCES = commadpt.c hdt2703_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt2703_la_LIBADD = $(DYNMOD_LD_ADD) hdt3705_la_SOURCES = comm3705.c hdt3705_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt3705_la_LIBADD = $(DYNMOD_LD_ADD) hdt3088_la_SOURCES = ctc_lcs.c ctc_ctci.c ctcadpt.c w32ctca.c tuntap.c hdt3088_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt3088_la_LIBADD = $(DYNMOD_LD_ADD) hdt3270_la_SOURCES = console.c hdt3270_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt3270_la_LIBADD = $(DYNMOD_LD_ADD) hdt3420_la_SOURCES = tapedev.c tapeccws.c awstape.c faketape.c hettape.c omatape.c scsitape.c w32stape.c hdt3420_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt3420_la_LIBADD = $(DYNMOD_LD_ADD) libherct.la hdt3505_la_SOURCES = cardrdr.c sockdev.c hdt3505_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt3505_la_LIBADD = $(DYNMOD_LD_ADD) hdt3525_la_SOURCES = cardpch.c hdt3525_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt3525_la_LIBADD = $(DYNMOD_LD_ADD) hdtqeth_la_SOURCES = qeth.c hdtqeth_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdtqeth_la_LIBADD = $(DYNMOD_LD_ADD) hdt1052c_la_SOURCES = con1052c.c hdt1052c_la_LDFLAGS = $(DYNMOD_LD_FLAGS) hdt1052c_la_LIBADD = $(DYNMOD_LD_ADD) endif # # Common data areas (shared) library # libhercs_la_SOURCES = hsys.c libhercs_la_LDFLAGS = $(LIB_LD_FLAGS) libhercs_la_LIBADD = $(LDADD) # # Tape utility subroutines (shared) library # libherct_la_SOURCES = sllib.c \ hetlib.c libherct_la_LDFLAGS = $(LIB_LD_FLAGS) libherct_la_LIBADD = $(LDADD) libhercs.la libhercu.la # # DASD utility subroutines (shared) library # libhercd_la_SOURCES = ckddasd.c \ fbadasd.c \ cckddasd.c \ cckdutil.c \ dasdtab.c \ cache.c \ dasdutil.c \ shared.c libhercd_la_LDFLAGS = $(LIB_LD_FLAGS) libhercd_la_LIBADD = $(LDADD) libhercs.la libhercu.la # ## Pure Utility functions # libhercu_la_SOURCES = version.c \ hscutl.c \ hscutl2.c \ codepage.c \ logger.c \ logmsg.c \ hdl.c \ hostinfo.c \ hsocket.c \ memrchr.c \ parser.c \ pttrace.c \ $(FTHREADS) \ $(LTDL) libhercu_la_LDFLAGS = $(LIB_LD_FLAGS) libhercu_la_LIBADD = $(LDADD) libhercs.la # # Core Hercules (shared) library # libherc_la_SOURCES = hconsole.c \ w32util.c \ strsignal.c \ impl.c \ config.c \ bldcfg.c \ panel.c \ history.c \ fillfnam.c \ ipl.c \ assist.c \ dat.c \ stack.c \ cpu.c \ vstore.c \ general1.c \ general2.c \ general3.c \ pfpo.c \ plo.c \ control.c \ crypto.c \ io.c \ decimal.c \ service.c \ scedasd.c \ losc.c \ chsc.c \ opcode.c \ diagnose.c \ diagmssf.c \ vm.c \ vmd250.c \ channel.c \ external.c \ float.c \ trace.c \ machchk.c \ vector.c \ xstore.c \ cmpsc.c \ sie.c \ qdio.c \ clock.c \ timer.c \ esame.c \ ieee.c \ dfp.c \ machdep.h \ httpserv.c \ cgibin.c \ loadparm.c \ hsccmd.c \ cmdtab.c \ hao.c \ hscmisc.c \ sr.c \ $(FISHIO) \ $(DYNSRC) \ ecpsvm.c EXTRA_libherc_la_SOURCES = $(fthreads_SRC) \ $(fishio_SRC) \ memrchr.c \ $(dynamic_SRC) \ $(extra_SRC) \ $(dyndev_SRC) \ ltdl.c libherc_la_LDFLAGS = $(LIB_LD_FLAGS) libherc_la_LIBADD = libhercs.la \ libhercu.la \ libherct.la \ libhercd.la \ decNumber/libdecNumber.la \ softfloat/libsoftfloat.la \ $(LDADD) # # THIS is the hercules executable. # hdlmain.c is requires so that dlopen(self) retrieves # the 'main' hdl symbols # if OPTION_DYNAMIC_LOAD if BUILD_SHARED HLDFLAGS = -dlopen self HDEPS = else HLDFLAGS = -dlopen self \ -dlopen dyngui.la \ -dlopen dyninst.la \ -dlopen hdteq.la \ -dlopen hdt1403.la \ -dlopen hdt3420.la \ -dlopen hdt2703.la \ -dlopen hdt3705.la \ -dlopen hdt3088.la \ -dlopen hdt3270.la \ -dlopen hdt3505.la \ -dlopen hdt3525.la \ -dlopen hdtqeth.la \ -dlopen hdt1052c.la HDEPS = dyngui.la \ dyninst.la \ hdteq.la \ hdt1403.la \ hdt3420.la \ hdt2703.la \ hdt3705.la \ hdt3088.la \ hdt3270.la \ hdt3505.la \ hdt3525.la \ hdtqeth.la \ hdt1052c.la \ libherc.la \ libherct.la \ libhercd.la endif else HLDFLAGS = HDEPS = endif hercules_SOURCES = bootstrap.c \ hdlmain.c hercules_LDADD = libherc.la libhercs.la $(LDADD) hercules_LDFLAGS = $(HLDFLAGS) hercules_DEPENDENCIES = libherc.la libhercs.la $(HDEPS) if BUILD_SHARED herclin_SOURCES = herclin.c hdlmain.c herclin_LDADD = libherc.la libhercs.la $(LDADD) herclin_LDFLAGS = $(HLDFLAGS) herclin_DEPENDENCIES = libherc.la libhercs.la $(HDEPS) endif # # side binaries # tools_LD_FLAGS = tools_ADDLIBS = $(HERCLIBS2) $(LDADD) if BUILD_HERCIFC hercifc_SOURCES = hercifc.c hercifc_LDADD = $(tools_ADDLIBS) hercifc_LDFLAGS = $(tools_LD_FLAGS) endif dasdinit_SOURCES = dasdinit.c dasdinit_LDADD = $(tools_ADDLIBS) dasdinit_LDFLAGS = $(tools_LD_FLAGS) dasdisup_SOURCES = dasdisup.c dasdisup_LDADD = $(tools_ADDLIBS) dasdisup_LDFLAGS = $(tools_LD_FLAGS) dasdload_SOURCES = dasdload.c dasdload_LDADD = $(tools_ADDLIBS) dasdload_LDFLAGS = $(tools_LD_FLAGS) dasdconv_SOURCES = dasdconv.c dasdconv_LDADD = $(tools_ADDLIBS) dasdconv_LDFLAGS = $(tools_LD_FLAGS) dasdls_SOURCES = dasdls.c dasdls_LDADD = $(tools_ADDLIBS) dasdls_LDFLAGS = $(tools_LD_FLAGS) dasdcat_SOURCES = dasdcat.c dasdcat_LDADD = $(tools_ADDLIBS) dasdcat_LDFLAGS = $(tools_LD_FLAGS) dasdpdsu_SOURCES = dasdpdsu.c dasdpdsu_LDADD = $(tools_ADDLIBS) dasdpdsu_LDFLAGS = $(tools_LD_FLAGS) dasdseq_SOURCES = dasdseq.c dasdseq_LDADD = $(tools_ADDLIBS) dasdseq_LDFLAGS = $(tools_LD_FLAGS) tapecopy_SOURCES = tapecopy.c tapecopy_LDADD = $(tools_ADDLIBS) tapecopy_LDFLAGS = $(tools_LD_FLAGS) tapemap_SOURCES = tapemap.c tapemap_LDADD = $(tools_ADDLIBS) tapemap_LDFLAGS = $(tools_LD_FLAGS) tapesplt_SOURCES = tapesplt.c tapesplt_LDADD = $(tools_ADDLIBS) tapesplt_LDFLAGS = $(tools_LD_FLAGS) cckdcdsk_SOURCES = cckdcdsk.c cckdcdsk_LDADD = $(tools_ADDLIBS) cckdcdsk_LDFLAGS = $(tools_LD_FLAGS) cckdcomp_SOURCES = cckdcomp.c cckdcomp_LDADD = $(tools_ADDLIBS) cckdcomp_LDFLAGS = $(tools_LD_FLAGS) cckddiag_SOURCES = cckddiag.c cckddiag_LDADD = $(tools_ADDLIBS) cckddiag_LDFLAGS = $(tools_LD_FLAGS) dasdcopy_SOURCES = dasdcopy.c dasdcopy_LDADD = $(tools_ADDLIBS) dasdcopy_LDFLAGS = $(tools_LD_FLAGS) cckdswap_SOURCES = cckdswap.c cckdswap_LDADD = $(tools_ADDLIBS) cckdswap_LDFLAGS = $(tools_LD_FLAGS) hetget_SOURCES = hetget.c hetget_LDADD = $(tools_ADDLIBS) hetget_LDFLAGS = $(tools_LD_FLAGS) hetinit_SOURCES = hetinit.c hetinit_LDADD = $(tools_ADDLIBS) hetinit_LDFLAGS = $(tools_LD_FLAGS) hetmap_SOURCES = hetmap.c hetmap_LDADD = $(tools_ADDLIBS) hetmap_LDFLAGS = $(tools_LD_FLAGS) hetupd_SOURCES = hetupd.c hetupd_LDADD = $(tools_ADDLIBS) hetupd_LDFLAGS = $(tools_LD_FLAGS) dmap2hrc_SOURCES = dmap2hrc.c dmap2hrc_LDADD = $(tools_ADDLIBS) dmap2hrc_LDFLAGS = $(tools_LD_FLAGS) # # files that are not 'built' per-se # # # Also contains some WIN32 only source files # EXTRA_DIST = autoconf/config.rpath \ autoconf/mkinstalldirs \ COPYRIGHT \ hercules.cnf \ cckdfix.c \ README.COMMADPT \ README.DYNMOD \ README.ECPSVM \ README.HDL \ README.NETWORKING \ README.OSX \ README.TAPE \ README.HERCLOGO \ RELEASE.NOTES \ README.WIN32 \ README.WIN64 \ README.SUN \ makefile.msvc \ makefile-dllmod.msvc \ msvc.makefile.includes/BZIP2_DIR.msvc \ msvc.makefile.includes/BZIP2_FLAGS.msvc \ msvc.makefile.includes/BZIP2_RULES.msvc \ msvc.makefile.includes/CONFIG.msvc \ msvc.makefile.includes/DEBUG_RETAIL.msvc \ msvc.makefile.includes/HERC_FLAGS.msvc \ msvc.makefile.includes/MOD_RULES1.msvc \ msvc.makefile.includes/MOD_RULES2.msvc \ msvc.makefile.includes/MODULES.msvc \ msvc.makefile.includes/OBJ_CODE.msvc \ msvc.makefile.includes/OUTDIR_RULES.msvc \ msvc.makefile.includes/OUTPUT_DIRS.msvc \ msvc.makefile.includes/PCRE_DIR.msvc \ msvc.makefile.includes/PCRE_FLAGS.msvc \ msvc.makefile.includes/PCRE_RULES.msvc \ msvc.makefile.includes/PRIM_RULES.msvc \ msvc.makefile.includes/VERSION.msvc \ msvc.makefile.includes/ZLIB_DIR.msvc \ msvc.makefile.includes/ZLIB_FLAGS.msvc \ msvc.makefile.includes/ZLIB_RULES.msvc \ hercver.rc \ build_pch.c \ conspawn.c \ getopt.c \ herclogo.txt \ hercules.ico # # Source Header files. No 'build' for those # noinst_HEADERS = hostinfo.h \ cpuint.h \ feat370.h \ feat390.h \ feat900.h \ featall.h \ featchk.h \ feature.h \ esa390.h \ opcode.h \ clock.h \ hercules.h \ inline.h \ dat.h \ vstore.h \ hbyteswp.h \ dasdblks.h \ hetlib.h \ version.h \ parser.h \ dasdtab.h \ sllib.h \ htypes.h \ fthreads.h \ w32chan.h \ w32ctca.h \ tt32api.h \ linklist.h \ httpmisc.h \ devtype.h \ codepage.h \ ctcadpt.h \ hercifc.h \ tuntap.h \ tapedev.h \ scsitape.h \ logger.h \ commadpt.h \ comm3705.h \ cache.h \ ecpsvm.h \ memrchr.h \ shared.h \ hscutl.h \ cmdtab.h \ hdl.h \ crypto.h \ sockdev.h \ ltdl.h \ herc_getopt.h \ service.h \ chsc.h \ pttrace.h \ history.h \ sr.h \ hchan.h \ fillfnam.h \ hthreads.h \ hostopts.h \ w32util.h \ hconsts.h \ hmacros.h \ hstructs.h \ hexterns.h \ hconsole.h \ hextapi.h \ hstdinc.h \ hstdint.h \ hsocket.h \ w32stape.h \ w32dl.h \ hercwind.h \ getopt.h \ w32mtio.h \ vmd250.h \ $(extra_dynamic_SRC) cckd: cckd2ckd$(EXEEXT) \ cckdcdsk$(EXEEXT) \ cckddiag$(EXEEXT) \ cckdcomp$(EXEEXT) \ cckdswap$(EXEEXT) \ dasdcopy$(EXEEXT) ######################################################### # B U I L D R U L E S . . . ######################################################### # # *** PROGRAMMING NOTE! *** # # The tabs in the below statements ARE significant! # Not all make programs accept (handle correctly) # make files that use blanks instead of tabs in their # build rules. Thus in order to remain compatible # with older make programs the below build rules # MUST use *tabs* and NOT BLANKS! # ######################################################### tar: dist install-exec-local: install-exec-hook: if BUILD_SHARED rm -f $(DESTDIR)$(libdir)/libherc*.a rm -f $(DESTDIR)$(modexecdir)/dyn*.a rm -f $(DESTDIR)$(modexecdir)/hdt*.a else rm -f $(DESTDIR)$(libdir)/libherc* endif # # NOTE : symbolic links point to FINAL destination (not to staged install) # rm -f $(DESTDIR)$(bindir)/fba2cfba$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) fba2cfba$(EXEEXT)) rm -f $(DESTDIR)$(bindir)/ckd2cckd$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) ckd2cckd$(EXEEXT)) rm -f $(DESTDIR)$(bindir)/cfba2fba$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) cfba2fba$(EXEEXT)) rm -f $(DESTDIR)$(bindir)/cckd2ckd$(EXEEXT) (cd $(DESTDIR)$(bindir); @LN_S@ ./dasdcopy$(EXEEXT) cckd2ckd$(EXEEXT)) if SETUID_HERCIFC chown root $(DESTDIR)$(bindir)/hercifc if HERCIFC_GROUPSET chgrp $(HERCIFC_GROUPNAME) $(DESTDIR)$(bindir)/hercifc endif chmod 0750 $(DESTDIR)$(bindir)/hercifc chmod +s $(DESTDIR)$(bindir)/hercifc rm hercifc endif uninstall-local: uninstall-hook: rm -f $(DESTDIR)$(bindir)/fba2cfba$(EXEEXT) rm -f $(DESTDIR)$(bindir)/ckd2cckd$(EXEEXT) rm -f $(DESTDIR)$(bindir)/cfba2fba$(EXEEXT) rm -f $(DESTDIR)$(bindir)/cckd2ckd$(EXEEXT) %.s: %.c $(COMPILE) -S $< hercules-3.12/configure0000775000175000017500000327122212622170275012120 00000000000000#! /bin/sh # From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` ;; esac echo=${ECHO-echo} if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then # Yippee, $echo works! : else # Restart under the correct shell. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null && echo_test_string="`eval $cmd`" && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null then break fi done fi if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} else # Try using printf. echo='printf %s\n' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL $0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$CONFIG_SHELL $0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "$0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. ECHO=$echo if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" fi tagnames=${tagnames+${tagnames},}CXX tagnames=${tagnames+${tagnames},}F77 test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="hercules.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS USE_DLLTOOL_FALSE USE_DLLTOOL_TRUE BUILD_SHARED_FALSE BUILD_SHARED_TRUE HERCIFC_GROUPNAME HERCIFC_GROUPSET_FALSE HERCIFC_GROUPSET_TRUE SETUID_HERCIFC_FALSE SETUID_HERCIFC_TRUE BUILD_HERCIFC_FALSE BUILD_HERCIFC_TRUE BUILD_FTHREADS_FALSE BUILD_FTHREADS_TRUE OPTION_DYNAMIC_LOAD_FALSE OPTION_DYNAMIC_LOAD_TRUE LIBTOOL_DEPS LIBADD_DL CONVENIENCE_LTDL_FALSE CONVENIENCE_LTDL_TRUE INSTALL_LTDL_FALSE INSTALL_LTDL_TRUE LIBTOOL ac_ct_F77 FFLAGS F77 CXXCPP am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX CPP OBJDUMP AS DLLTOOL RANLIB AR ECHO LN_S EGREP GREP modexecdir am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_maintainer_mode enable_dependency_tracking enable_static enable_shared enable_fast_install with_gnu_ld enable_libtool_lock with_pic with_tags enable_ltdl_install enable_largefile enable_dynamic_load enable_cckd_bzip2 enable_het_bzip2 enable_debug enable_optimization enable_configsymbols enable_enhanced_configsymbols enable_enhanced_configincludes enable_automatic_operator enable_external_gui enable_fthreads enable_multi_cpu enable_capabilities enable_custom enable_setuid_hercifc enable_getoptwrapper ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP CXX CXXFLAGS CCC CXXCPP F77 FFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-static[=PKGS] build static libraries [default=no] --enable-shared[=PKGS] build shared libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --enable-ltdl-install install libltdl --disable-largefile omit support for large files --disable-dynamic-load disable dynamic loader option --enable-cckd-bzip2 enable bzip2 compression for emulated dasd --enable-het-bzip2 enable bzip2 compression for emulated tapes --enable-debug enable debugging (TRACE/VERIFY/ASSERT macros) --enable-optimization=yes|no|FLAGS enable automatic optimization, or specify flags --disable-configsymbols disable symbolic substitutions in configuration file --disable-enhanced-configsymbols disable enhanced-mode symbolic substitutions in configuration file --disable-enhanced-configincludes disable enhanced-mode 'include' file support in configuration file --disable-automatic-operator disable Hercules Automatic Operator feature --disable-external-gui disable external GUI interface --disable-fthreads disable use of fish threads instead of posix threads --enable-multi-cpu=yes|no|NUMBER enable/disable multi-cpu support (1-128, default 8) --disable-capabilities disable fine grained privileges --enable-custom=STRING provide a custom description for this build --enable-setuid-hercifc=yes|no|GROUPNAME install hercifc as setuid root, and allow execution by users in group GROUPNAME --enable-getoptwrapper force use of the getopt wrapper kludge Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-pic try to use only PIC/non-PIC objects [default=use both] --with-tags[=TAGS] include additional configurations [automatic] Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor F77 Fortran 77 compiler command FFLAGS Fortran 77 compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_cxx_check_func LINENO FUNC VAR # ------------------------------------ # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_cxx_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_func # ac_fn_f77_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_f77_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_f77_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_f77_try_compile # ac_fn_f77_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_f77_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_f77_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_f77_try_link # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES # --------------------------------------------- # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # (package, version, bugreport email, etc) # (the version of this configure.ac) ac_aux_dir= for ac_dir in autoconf "$srcdir"/autoconf; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in autoconf \"$srcdir\"/autoconf" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # (directory containing auxillary build tools) am__api_version='1.13' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=hercules VERSION=3.12 cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # (the version of our software package) ac_config_headers="$ac_config_headers config.h" # (the file the resulting configure script will produce) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 $as_echo "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # (sets $host_cpu, $host_vendor, and $host_os) # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=0;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' ############################################################################### # Programs section... ############################################################################### # Set CFLAGS first to override the AC_PROG_CC default setting CFLAGS="$CFLAGS -W -Wall" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # (set CC to the name of the compiler) # ----------------------------------------------------------------------------- # PROGRAMMING NOTE: The below 'AC_SUBST' macro causes AC_OUTPUT to replace # all instances of "@xxxxxx@" in input files with the value that the shell # variable "xxxxxx" has when AC_OUTPUT is called. However, we setup a define # for source files (MODULESDIR) and a variable for make ($(modexecdir)). Any # other usage should be avoided. # ----------------------------------------------------------------------------- modexecdir='$(libdir)/$(PACKAGE)' # ----------------------------------------------------------------------------- # # AC_LIBTOOL_DLOPEN # # Enable checking for dlopen support. This macro should be used if the # package makes use of the '-dlopen' and '-dlpreopen' flags, otherwise # libtool will assume that the system does not support dlopening. The # macro must be called before AC_PROG_LIBTOOL. # # ----------------------------------------------------------------------------- # (we need libtool's dlopen support) # ----------------------------------------------------------------------------- # # AC_LIBTOOL_WIN32_DLL # # This macro should be used if the package has been ported to build # clean dlls on win32 platforms. Usually this means that any library # data items are exported with __declspec(dllexport) and imported with # __declspec(dllimport). If this macro is not used, libtool will assume # that the package libraries are not dll clean and will build only static # libraries on win32 hosts. # # This macro must be called before AC_PROG_LIBTOOL, and provision must # be made to pass '-no-undefined' to libtool in link mode from the package # Makefile. Naturally, if you pass '-no-undefined', you must ensure that # all the library symbols really are defined at link time! # # ----------------------------------------------------------------------------- # (we need Win32 support in libtool) # ----------------------------------------------------------------------------- # See: 'AC_PROG_LIBTOOL' below. # ----------------------------------------------------------------------------- # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=no fi # (forces libtool to build shared # libraries instead of static ones) # ----------------------------------------------------------------------------- # AC_PROG_LIBTOOL # # Add support for the '--enable-shared' and '--disable-shared' # configure flags. By default, this macro turns on shared libraries # if they are available, and also enables static libraries if they # don't conflict with the shared libraries. You can modify these # defaults by calling either the AC_DISABLE_SHARED or AC_DISABLE_STATIC # macros. # # Hercules REQUIRES shared libraries (i.e. DLLs), so we do indeed use # the AC_DISABLE_STATIC macro above. # # ----------------------------------------------------------------------------- # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${lt_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else # Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && break cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done SED=$lt_cv_path_SED fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD-compatible nm" >&5 $as_echo_n "checking for BSD-compatible nm... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/${ac_tool_prefix}nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac esac fi done IFS="$lt_save_ifs" test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } NM="$lt_cv_path_NM" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognise dependent libraries" >&5 $as_echo_n "checking how to recognise dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix4* | aix5*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi4*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin* | mingw* | pw32*) # win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='win32_libid' ;; darwin* | rhapsody*) # this will be overwritten by pass_all, but leave it in just in case lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' lt_cv_file_magic_cmd='/usr/bin/file -L' case "$host_os" in rhapsody* | darwin1.[012]) lt_cv_file_magic_test_file=`/System/Library/Frameworks/System.framework/System` ;; *) # Darwin 1.3 on lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' ;; esac lt_cv_deplibs_check_method=pass_all ;; freebsd* | kfreebsd*-gnu) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case "$host_cpu" in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; irix5* | irix6* | nonstopux*) case $host_os in irix5* | nonstopux*) # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" ;; *) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" ;; esac lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux*) case $host_cpu in alpha* | hppa* | i*86 | ia64* | m68* | mips* | powerpc* | sparc* | s390* | sh* | x86_64) lt_cv_deplibs_check_method=pass_all ;; *) # glibc up to 2.1.1 does not perform some relocations on ARM lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; esac lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; nto-qnx*) lt_cv_deplibs_check_method=unknown ;; openbsd*) lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' else lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' fi ;; osf3* | osf4* | osf5*) # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' lt_cv_file_magic_test_file=/shlib/libc.so lt_cv_deplibs_check_method=pass_all ;; sco3.2v5*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all lt_cv_file_magic_test_file=/lib/libc.so ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 5484 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case "`/usr/bin/file conftest.o`" in *32-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*-cygwin* | *-*-mingw* | *-*-pw32*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AS"; then ac_cv_prog_AS="$AS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AS="${ac_tool_prefix}as" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AS=$ac_cv_prog_AS if test -n "$AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 $as_echo "$AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AS"; then ac_ct_AS=$AS # Extract the first word of "as", so it can be a program name with args. set dummy as; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AS"; then ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AS="as" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AS=$ac_cv_prog_ac_ct_AS if test -n "$ac_ct_AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 $as_echo "$ac_ct_AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AS" = x; then AS="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AS=$ac_ct_AS fi else AS="$ac_cv_prog_AS" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi ;; esac need_locks="$enable_libtool_lock" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_F77+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$F77"; then ac_cv_prog_F77="$F77" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_F77="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi F77=$ac_cv_prog_F77 if test -n "$F77"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $F77" >&5 $as_echo "$F77" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$F77" && break done fi if test -z "$F77"; then ac_ct_F77=$F77 for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_F77+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_F77"; then ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_F77="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_F77=$ac_cv_prog_ac_ct_F77 if test -n "$ac_ct_F77"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_F77" >&5 $as_echo "$ac_ct_F77" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_F77" && break done if test "x$ac_ct_F77" = x; then F77="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac F77=$ac_ct_F77 fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for Fortran 77 compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done rm -f a.out # If we don't use `.F' as extension, the preprocessor is not run on the # input file. (Note that this only needs to work for GNU compilers.) ac_save_ext=$ac_ext ac_ext=F { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Fortran 77 compiler" >&5 $as_echo_n "checking whether we are using the GNU Fortran 77 compiler... " >&6; } if ${ac_cv_f77_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat > conftest.$ac_ext <<_ACEOF program main #ifndef __GNUC__ choke me #endif end _ACEOF if ac_fn_f77_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_f77_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_f77_compiler_gnu" >&5 $as_echo "$ac_cv_f77_compiler_gnu" >&6; } ac_ext=$ac_save_ext ac_test_FFLAGS=${FFLAGS+set} ac_save_FFLAGS=$FFLAGS FFLAGS= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $F77 accepts -g" >&5 $as_echo_n "checking whether $F77 accepts -g... " >&6; } if ${ac_cv_prog_f77_g+:} false; then : $as_echo_n "(cached) " >&6 else FFLAGS=-g cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF if ac_fn_f77_try_compile "$LINENO"; then : ac_cv_prog_f77_g=yes else ac_cv_prog_f77_g=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_f77_g" >&5 $as_echo "$ac_cv_prog_f77_g" >&6; } if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then if test "x$ac_cv_f77_compiler_gnu" = xyes; then FFLAGS="-g -O2" else FFLAGS="-g" fi else if test "x$ac_cv_f77_compiler_gnu" = xyes; then FFLAGS="-O2" else FFLAGS= fi fi if test $ac_compiler_gnu = yes; then G77=yes else G77= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 testring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; *) # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while (test "X"`$CONFIG_SHELL $0 --fallback-echo "X$testring" 2>/dev/null` \ = "XX$testring") >/dev/null 2>&1 && new_result=`expr "X$testring" : ".*" 2>&1` && lt_cv_sys_max_cmd_len=$new_result && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` testring=$testring$testring done testring= # Add a significant safety factor because C++ compilers can tack on massive # amounts of additional arguments before passing them to the linker. # It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Transform the above into a raw symbol and a C symbol. symxfrm='\1 \2\3 \3' # Transform an extracted symbol line into a proper C declaration lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32*) symcode='[ABCDGISTW]' ;; hpux*) # Its linker distinguishes data from code symbols if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris* | sysv5*) symcode='[BDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGISTW]' ;; esac # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Write the raw and C identifiers. lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if grep ' nm_test_var$' "$nlist" >/dev/null; then if grep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' cat <> conftest.$ac_ext #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[] = { EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext cat <<\EOF >> conftest.$ac_ext {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e s/^X//' sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Constants: rm="rm -f" # Global variables: default_ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except M$VC, # which needs '.lib'). libext=a ltmain="$ac_aux_dir/ltmain.sh" ofile="$default_ofile" with_gnu_ld="$lt_cv_prog_gnu_ld" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru test -z "$AS" && AS=as test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$LD" && LD=ld test -z "$LN_S" && LN_S="ln -s" test -z "$MAGIC_CMD" && MAGIC_CMD=file test -z "$NM" && NM=nm test -z "$SED" && SED=sed test -z "$OBJDUMP" && OBJDUMP=objdump test -z "$RANLIB" && RANLIB=: test -z "$STRIP" && STRIP=: test -z "$ac_objext" && ac_objext=o # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" ;; *) old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi # Only perform the check for file, if the check method requires it case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac enable_dlopen=yes enable_win32_dll=yes # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; pic_mode="$withval" else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Use C for the default configuration in the libtool script tagname= lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}\n' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # # Check for any special shared library compilation flags. # lt_prog_cc_shlib= if test "$GCC" = no; then case $host_os in sco3.2v5*) lt_prog_cc_shlib='-belf' ;; esac fi if test -n "$lt_prog_cc_shlib"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&5 $as_echo "$as_me: WARNING: \`$CC' requires \`$lt_prog_cc_shlib' to build shared libraries" >&2;} if echo "$old_CC $old_CFLAGS " | grep "[ ]$lt_prog_cc_shlib[ ]" >/dev/null; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5 $as_echo "$as_me: WARNING: add \`$lt_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;} lt_cv_prog_cc_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_prog_compiler_static works" >&5 $as_echo_n "checking if $compiler static flag $lt_prog_compiler_static works... " >&6; } if ${lt_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_prog_compiler_static" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 else lt_prog_compiler_static_works=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works" >&5 $as_echo "$lt_prog_compiler_static_works" >&6; } if test x"$lt_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag=' -fno-builtin' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7835: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7839: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; *) lt_prog_compiler_pic='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; linux*) case $CC in icc* | ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; sco3.2v5*) lt_prog_compiler_pic='-Kpic' lt_prog_compiler_static='-dn' ;; solaris*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 $as_echo "$lt_prog_compiler_pic" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:8068: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:8072: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works" >&5 $as_echo "$lt_prog_compiler_pic_works" >&6; } if test x"$lt_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext # According to Tom Tromey, Ian Lance Taylor reported there are C compilers # that will create temporary files in the current directory regardless of # the output directory. Thus, making CWD read-only will cause this test # to fail, enabling locking or at least warning the user not to do parallel # builds. chmod -w . lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:8135: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:8139: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= enable_shared_with_static_runtimes=no archive_cmds= archive_expsym_cmds= old_archive_From_new_cmds= old_archive_from_expsyms_cmds= export_dynamic_flag_spec= whole_archive_flag_spec= thread_safe_flag_spec= hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=unsupported link_all_deplibs=unknown hardcode_automatic=no module_cmds= module_expsym_cmds= always_export_symbols=no export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_libdir_separator=':' link_all_deplibs=yes if test "$GCC" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec=' ' archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi4*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then archive_cmds_need_lc=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported whole_archive_flag_spec='-all_load $convenience' link_all_deplibs=yes else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; freebsd1*) ld_shlibs=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) archive_cmds='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_libdir_separator=: hardcode_direct=no hardcode_shlibpath_var=no ;; ia64*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=no hardcode_shlibpath_var=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; *) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld='-rpath $libdir' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: link_all_deplibs=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; openbsd*) hardcode_direct=yes hardcode_shlibpath_var=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; sco3.2v5*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) no_undefined_flag=' -z text' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4.2uw2*) archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=no hardcode_shlibpath_var=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) no_undefined_flag='${wl}-z ${wl}text' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv5*) no_undefined_flag=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' hardcode_libdir_flag_spec= hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc=no else archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 $as_echo "$archive_cmds_need_lc" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || \ test -n "$runpath_var " || \ test "X$hardcode_automatic"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" # # # The following section is a PATCH to overcome the # stripped import library issues under cygwin case $host_os in cygwin*) striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ;; esac # # # AC_MSG_RESULT([yes]) # # else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # Report which librarie types wil actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; darwin* | rhapsody*) if test "$GCC" = yes; then archive_cmds_need_lc=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag='-undefined dynamic_lookup' ;; esac fi ;; esac output_verbose_link_cmd='echo' archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring' module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs$compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported whole_archive_flag_spec='-all_load $convenience' link_all_deplibs=yes else ld_shlibs=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM SED SHELL \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler \ CC \ LD \ lt_prog_compiler_wl \ lt_prog_compiler_pic \ lt_prog_compiler_static \ lt_prog_compiler_no_builtin_flag \ export_dynamic_flag_spec \ thread_safe_flag_spec \ whole_archive_flag_spec \ enable_shared_with_static_runtimes \ old_archive_cmds \ old_archive_from_new_cmds \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ archive_cmds \ archive_expsym_cmds \ postinstall_cmds \ postuninstall_cmds \ old_archive_from_expsyms_cmds \ allow_undefined_flag \ no_undefined_flag \ export_symbols_cmds \ hardcode_libdir_flag_spec \ hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ hardcode_automatic \ module_cmds \ module_expsym_cmds \ lt_cv_prog_compiler_c_o \ exclude_expsyms \ include_expsyms; do case $var in old_archive_cmds | \ old_archive_from_new_cmds | \ archive_cmds | \ archive_expsym_cmds | \ module_cmds | \ module_expsym_cmds | \ old_archive_from_expsyms_cmds | \ export_symbols_cmds | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="${ofile}T" trap "$rm \"$cfgfile\"; exit 1" 1 2 15 $rm -f "$cfgfile" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ofile" >&5 $as_echo "$as_me: creating $ofile" >&6;} cat <<__EOF__ >> "$cfgfile" #! $SHELL # `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # # This file is part of GNU Libtool: # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="$SED -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi # The names of the tagged configurations supported by this script. available_tags= # ### BEGIN LIBTOOL CONFIG # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler # Is the compiler the GNU C compiler? with_gcc=$GCC # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext='$shrext' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # ### END LIBTOOL CONFIG __EOF__ case $host_os in aix3*) cat <<\EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || \ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. test -f Makefile && make "$ltmain" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" # Check whether --with-tags was given. if test "${with_tags+set}" = set; then : withval=$with_tags; tagnames="$withval" fi if test -f "$ltmain" && test -n "$tagnames"; then if test ! -f "${ofile}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: output file \`$ofile' does not exist" >&5 $as_echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} fi if test -z "$LTCC"; then eval "`$SHELL ${ofile} --config | grep '^LTCC='`" if test -z "$LTCC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: output file \`$ofile' does not look like a libtool script" >&5 $as_echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 $as_echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} fi fi # Extract list of available tagged configurations in $ofile. # Note that this assumes the entire list is on one line. available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for tagname in $tagnames; do IFS="$lt_save_ifs" # Check whether tagname contains only valid characters case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in "") ;; *) as_fn_error $? "invalid tag name: $tagname" "$LINENO" 5 ;; esac if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null then as_fn_error $? "tag name \"$tagname\" already exists" "$LINENO" 5 fi # Update the list of available tags. if test -n "$tagname"; then echo appending configuration tag \"$tagname\" to $ofile case $tagname in CXX) if test -n "$CXX" && test "X$CXX" != "Xno"; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_flag_spec_ld_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_automatic_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= # Source file extension for C++ test sources. ac_ext=cc # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *) { return(0); }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC compiler_CXX=$CC cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` # We don't want -fno-exception wen compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes if test "$GXX" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_CXX=yes else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols_CXX=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX=' ' archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs_CXX=no fi ;; darwin* | rhapsody*) if test "$GXX" = yes; then archive_cmds_need_lc_CXX=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag_CXX='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_CXX='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_CXX='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag_CXX='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds_CXX='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds_CXX='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported whole_archive_flag_spec_CXX='-all_load $convenience' link_all_deplibs_CXX=yes else ld_shlibs_CXX=no fi ;; dgux*) case $cc_basename in ec++) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd12*) # C++ shared libraries reported to be fairly broken before switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | kfreebsd*-gnu) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; gnu*) ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC) archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld_CXX='+b $libdir' hardcode_libdir_separator_CXX=: ;; ia64*) hardcode_libdir_flag_spec_CXX='-L$libdir' ;; *) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case "$host_cpu" in hppa*64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; *) hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC) case "$host_cpu" in hppa*64*|ia64*) archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case "$host_cpu" in ia64*|hppa*64*) archive_cmds_CXX='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' ;; *) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; irix5* | irix6*) case $cc_basename in CC) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: ;; linux*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc) # Intel C++ with_gnu_ld=yes archive_cmds_need_lc_CXX=no archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; cxx) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; osf3*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; osf4* | osf5*) case $cc_basename in KCC) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; RCC) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ $rm $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sco*) archive_cmds_need_lc_CXX=no case $cc_basename in CC) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.0-5 | solaris2.0-5.*) ;; *) # The C++ compiler is used as linker so we must use $wl # flag to pass the commands to the underlying system # linker. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac link_all_deplibs_CXX=yes # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[LR]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | grep -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' fi ;; esac ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) archive_cmds_need_lc_CXX=no ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... cat > conftest.$ac_ext <&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no # The `*' in the case matches for architectures that use `case' in # $output_verbose_cmd can trigger glob expansion during the loop # eval without this substitution. output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`" for p in `eval $output_verbose_link_cmd`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" \ || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $rm -f confest.$objext case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | os2* | pw32*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix4* | aix5*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68) # Green Hills C++ Compiler # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | kfreebsd*-gnu) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux*) case $cc_basename in KCC) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; icpc) # Intel C++ lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; cxx) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; osf3* | osf4* | osf5*) case $cc_basename in KCC) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; sco*) case $cc_basename in CC) lt_prog_compiler_pic_CXX='-fPIC' ;; *) ;; esac ;; solaris*) case $cc_basename in CC) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; tandem*) case $cc_basename in NCC) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; unixware*) ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 $as_echo "$lt_prog_compiler_pic_CXX" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if ${lt_prog_compiler_pic_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:12132: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:12136: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works_CXX=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_CXX" >&5 $as_echo "$lt_prog_compiler_pic_works_CXX" >&6; } if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext # According to Tom Tromey, Ian Lance Taylor reported there are C compilers # that will create temporary files in the current directory regardless of # the output directory. Thus, making CWD read-only will cause this test # to fail, enabling locking or at least warning the user not to do parallel # builds. chmod -w . lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:12199: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:12203: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix4* | aix5*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw*) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc_CXX=no else archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_CXX" >&5 $as_echo "$archive_cmds_need_lc_CXX" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || \ test -n "$runpath_var CXX" || \ test "X$hardcode_automatic_CXX"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 $as_echo "$hardcode_action_CXX" >&6; } if test "$hardcode_action_CXX" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" # # # The following section is a PATCH to overcome the # stripped import library issues under cygwin case $host_os in cygwin*) striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ;; esac # # # AC_MSG_RESULT([yes]) # # else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_cxx_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" else ac_fn_cxx_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM SED SHELL \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_CXX \ CC_CXX \ LD_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_static_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ export_dynamic_flag_spec_CXX \ thread_safe_flag_spec_CXX \ whole_archive_flag_spec_CXX \ enable_shared_with_static_runtimes_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ postinstall_cmds_CXX \ postuninstall_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ export_symbols_cmds_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_flag_spec_ld_CXX \ hardcode_libdir_separator_CXX \ hardcode_automatic_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ lt_cv_prog_compiler_c_o_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX; do case $var in old_archive_cmds_CXX | \ old_archive_from_new_cmds_CXX | \ archive_cmds_CXX | \ archive_expsym_cmds_CXX | \ module_cmds_CXX | \ module_expsym_cmds_CXX | \ old_archive_from_expsyms_cmds_CXX | \ export_symbols_cmds_CXX | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU C compiler? with_gcc=$GCC_CXX # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_CXX # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext='$shrext' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_CXX old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_CXX # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_CXX # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_CXX # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_CXX # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_CXX # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_CXX" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. test -f Makefile && make "$ltmain" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ldcxx=$with_gnu_ld with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld else tagname="" fi ;; F77) if test -n "$F77" && test "X$F77" != "Xno"; then ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu archive_cmds_need_lc_F77=no allow_undefined_flag_F77= always_export_symbols_F77=no archive_expsym_cmds_F77= export_dynamic_flag_spec_F77= hardcode_direct_F77=no hardcode_libdir_flag_spec_F77= hardcode_libdir_flag_spec_ld_F77= hardcode_libdir_separator_F77= hardcode_minus_L_F77=no hardcode_automatic_F77=no module_cmds_F77= module_expsym_cmds_F77= link_all_deplibs_F77=unknown old_archive_cmds_F77=$old_archive_cmds no_undefined_flag_F77= whole_archive_flag_spec_F77= enable_shared_with_static_runtimes_F77=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o objext_F77=$objext # Code to be used in simple compile tests lt_simple_compile_test_code=" subroutine t\n return\n end\n" # Code to be used in simple link tests lt_simple_link_test_code=" program t\n end\n" # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${F77-"f77"} compiler=$CC compiler_F77=$CC cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4*) test "$enable_shared" = yes && enable_static=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } test "$ld_shlibs_F77" = no && can_build_shared=no GCC_F77="$G77" LD_F77="$LD" lt_prog_compiler_wl_F77= lt_prog_compiler_pic_F77= lt_prog_compiler_static_F77= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_static_F77='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_F77='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_F77='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_F77='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared_F77=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_F77=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_F77='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_F77='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl_F77='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_F77='-Bstatic' else lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_F77='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl_F77='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_F77='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static_F77='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl_F77='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static_F77='-non_shared' ;; newsos6) lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; linux*) case $CC in icc* | ecc*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-static' ;; ccc*) lt_prog_compiler_wl_F77='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static_F77='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl_F77='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static_F77='-non_shared' ;; sco3.2v5*) lt_prog_compiler_pic_F77='-Kpic' lt_prog_compiler_static_F77='-dn' ;; solaris*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; sunos4*) lt_prog_compiler_wl_F77='-Qoption ld ' lt_prog_compiler_pic_F77='-PIC' lt_prog_compiler_static_F77='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic_F77='-Kconform_pic' lt_prog_compiler_static_F77='-Bstatic' fi ;; uts4*) lt_prog_compiler_pic_F77='-pic' lt_prog_compiler_static_F77='-Bstatic' ;; *) lt_prog_compiler_can_build_shared_F77=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_F77" >&5 $as_echo "$lt_prog_compiler_pic_F77" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_F77"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... " >&6; } if ${lt_prog_compiler_pic_works_F77+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works_F77=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_F77" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:14164: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:14168: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works_F77=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_F77" >&5 $as_echo "$lt_prog_compiler_pic_works_F77" >&6; } if test x"$lt_prog_compiler_pic_works_F77" = xyes; then case $lt_prog_compiler_pic_F77 in "" | " "*) ;; *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; esac else lt_prog_compiler_pic_F77= lt_prog_compiler_can_build_shared_F77=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_F77= ;; *) lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_F77+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_F77=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext # According to Tom Tromey, Ian Lance Taylor reported there are C compilers # that will create temporary files in the current directory regardless of # the output directory. Thus, making CWD read-only will cause this test # to fail, enabling locking or at least warning the user not to do parallel # builds. chmod -w . lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:14231: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:14235: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o_F77=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_F77" >&5 $as_echo "$lt_cv_prog_compiler_c_o_F77" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag_F77= enable_shared_with_static_runtimes_F77=no archive_cmds_F77= archive_expsym_cmds_F77= old_archive_From_new_cmds_F77= old_archive_from_expsyms_cmds_F77= export_dynamic_flag_spec_F77= whole_archive_flag_spec_F77= thread_safe_flag_spec_F77= hardcode_libdir_flag_spec_F77= hardcode_libdir_flag_spec_ld_F77= hardcode_libdir_separator_F77= hardcode_direct_F77=no hardcode_minus_L_F77=no hardcode_shlibpath_var_F77=unsupported link_all_deplibs_F77=unknown hardcode_automatic_F77=no module_cmds_F77= module_expsym_cmds_F77= always_export_symbols_F77=no export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms_F77= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs_F77=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs_F77=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs_F77=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_F77=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_F77=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_F77='-L$libdir' allow_undefined_flag_F77=unsupported always_export_symbols_F77=no enable_shared_with_static_runtimes_F77=yes export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs_F77=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_F77=no fi ;; sunos4*) archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_F77=no fi ;; esac if test "$ld_shlibs_F77" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_F77='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_F77= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag_F77=unsupported always_export_symbols_F77=yes archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L_F77=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct_F77=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_F77='' hardcode_direct_F77=yes hardcode_libdir_separator_F77=':' link_all_deplibs_F77=yes if test "$GCC" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_F77=yes else # We have old collect2 hardcode_direct_F77=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_F77=yes hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_libdir_separator_F77= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_F77=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_F77='-berok' # Determine the default libpath from the value encoded in an empty executable. cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF if ac_fn_f77_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_F77="-z nodefs" archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF if ac_fn_f77_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_F77=' ${wl}-bernotok' allow_undefined_flag_F77=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols_F77=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_F77=' ' archive_cmds_need_lc_F77=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes # see comment about different semantics on the GNU ld section ld_shlibs_F77=no ;; bsdi4*) export_dynamic_flag_spec_F77=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_F77=' ' allow_undefined_flag_F77=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds_F77='true' # FIXME: Should let the user specify the lib program. old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes_F77=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then archive_cmds_need_lc_F77=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag_F77='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_F77='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_F77='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag_F77='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds_F77='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds_F77='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds_F77='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct_F77=no hardcode_automatic_F77=yes hardcode_shlibpath_var_F77=unsupported whole_archive_flag_spec_F77='-all_load $convenience' link_all_deplibs_F77=yes else ld_shlibs_F77=no fi ;; dgux*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_shlibpath_var_F77=no ;; freebsd1*) ld_shlibs_F77=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_minus_L_F77=yes hardcode_shlibpath_var_F77=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes export_dynamic_flag_spec_F77='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) archive_cmds_F77='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld_F77='+b $libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=no hardcode_shlibpath_var_F77=no ;; ia64*) hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_direct_F77=no hardcode_shlibpath_var_F77=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes ;; *) hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=yes export_dynamic_flag_spec_F77='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' fi hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: link_all_deplibs_F77=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; newsos6) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_shlibpath_var_F77=no ;; openbsd*) hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' export_dynamic_flag_spec_F77='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-R$libdir' ;; *) archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes allow_undefined_flag_F77=unsupported archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag_F77=' -expect_unresolved \*' archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' else allow_undefined_flag_F77=' -expect_unresolved \*' archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec_F77='-rpath $libdir' fi hardcode_libdir_separator_F77=: ;; sco3.2v5*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no export_dynamic_flag_spec_F77='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) no_undefined_flag_F77=' -z text' if test "$GCC" = yes; then archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_shlibpath_var_F77=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_F77=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_direct_F77=yes hardcode_minus_L_F77=yes hardcode_shlibpath_var_F77=no ;; sysv4) case $host_vendor in sni) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds_F77='$CC -r -o $output$reload_objs' hardcode_direct_F77=no ;; motorola) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_F77=no ;; sysv4.3*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no export_dynamic_flag_spec_F77='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs_F77=yes fi ;; sysv4.2uw2*) archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_minus_L_F77=no hardcode_shlibpath_var_F77=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) no_undefined_flag_F77='${wl}-z ${wl}text' if test "$GCC" = yes; then archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_F77=no ;; sysv5*) no_undefined_flag_F77=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' hardcode_libdir_flag_spec_F77= hardcode_shlibpath_var_F77=no runpath_var='LD_RUN_PATH' ;; uts4*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_shlibpath_var_F77=no ;; *) ld_shlibs_F77=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_F77" >&5 $as_echo "$ld_shlibs_F77" >&6; } test "$ld_shlibs_F77" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_F77" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_F77=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_F77 in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_F77 compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_F77 allow_undefined_flag_F77= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc_F77=no else archive_cmds_need_lc_F77=yes fi allow_undefined_flag_F77=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_F77" >&5 $as_echo "$archive_cmds_need_lc_F77" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_F77= if test -n "$hardcode_libdir_flag_spec_F77" || \ test -n "$runpath_var F77" || \ test "X$hardcode_automatic_F77"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_F77" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && test "$hardcode_minus_L_F77" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_F77=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_F77=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_F77=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_F77" >&5 $as_echo "$hardcode_action_F77" >&6; } if test "$hardcode_action_F77" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" # # # The following section is a PATCH to overcome the # stripped import library issues under cygwin case $host_os in cygwin*) striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ;; esac # # # AC_MSG_RESULT([yes]) # # else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM SED SHELL \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_F77 \ CC_F77 \ LD_F77 \ lt_prog_compiler_wl_F77 \ lt_prog_compiler_pic_F77 \ lt_prog_compiler_static_F77 \ lt_prog_compiler_no_builtin_flag_F77 \ export_dynamic_flag_spec_F77 \ thread_safe_flag_spec_F77 \ whole_archive_flag_spec_F77 \ enable_shared_with_static_runtimes_F77 \ old_archive_cmds_F77 \ old_archive_from_new_cmds_F77 \ predep_objects_F77 \ postdep_objects_F77 \ predeps_F77 \ postdeps_F77 \ compiler_lib_search_path_F77 \ archive_cmds_F77 \ archive_expsym_cmds_F77 \ postinstall_cmds_F77 \ postuninstall_cmds_F77 \ old_archive_from_expsyms_cmds_F77 \ allow_undefined_flag_F77 \ no_undefined_flag_F77 \ export_symbols_cmds_F77 \ hardcode_libdir_flag_spec_F77 \ hardcode_libdir_flag_spec_ld_F77 \ hardcode_libdir_separator_F77 \ hardcode_automatic_F77 \ module_cmds_F77 \ module_expsym_cmds_F77 \ lt_cv_prog_compiler_c_o_F77 \ exclude_expsyms_F77 \ include_expsyms_F77; do case $var in old_archive_cmds_F77 | \ old_archive_from_new_cmds_F77 | \ archive_cmds_F77 | \ archive_expsym_cmds_F77 | \ module_cmds_F77 | \ module_expsym_cmds_F77 | \ old_archive_from_expsyms_cmds_F77 | \ export_symbols_cmds_F77 | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_F77 # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_F77 # Is the compiler the GNU C compiler? with_gcc=$GCC_F77 # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_F77 # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_F77 # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext='$shrext' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_F77 pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_F77 # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_F77 old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_F77 archive_expsym_cmds=$lt_archive_expsym_cmds_F77 postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_F77 module_expsym_cmds=$lt_module_expsym_cmds_F77 # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_F77 # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_F77 # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_F77 # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_F77 # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_F77 # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_F77 # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_F77 # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_F77 # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_F77 # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_F77 # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_F77 # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_F77 # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_F77" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_F77 # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_F77 # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_F77 # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_F77 # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. test -f Makefile && make "$ltmain" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" else tagname="" fi ;; GCJ) if test -n "$GCJ" && test "X$GCJ" != "Xno"; then # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o objext_GCJ=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}\n" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String argv) {}; }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${GCJ-"gcj"} compiler=$CC compiler_GCJ=$CC # GCJ did not exist at the time GCC didn't implicitly link libc in. archive_cmds_need_lc_GCJ=no ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... lt_prog_compiler_no_builtin_flag_GCJ= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:16190: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:16194: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl_GCJ= lt_prog_compiler_pic_GCJ= lt_prog_compiler_static_GCJ= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_static_GCJ='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_GCJ='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_GCJ='-fno-common' ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared_GCJ=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_GCJ=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_GCJ='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_GCJ='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl_GCJ='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_GCJ='-Bstatic' else lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl_GCJ='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case "$host_cpu" in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_GCJ='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl_GCJ='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static_GCJ='-non_shared' ;; newsos6) lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; linux*) case $CC in icc* | ecc*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-static' ;; ccc*) lt_prog_compiler_wl_GCJ='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static_GCJ='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl_GCJ='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static_GCJ='-non_shared' ;; sco3.2v5*) lt_prog_compiler_pic_GCJ='-Kpic' lt_prog_compiler_static_GCJ='-dn' ;; solaris*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sunos4*) lt_prog_compiler_wl_GCJ='-Qoption ld ' lt_prog_compiler_pic_GCJ='-PIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic_GCJ='-Kconform_pic' lt_prog_compiler_static_GCJ='-Bstatic' fi ;; uts4*) lt_prog_compiler_pic_GCJ='-pic' lt_prog_compiler_static_GCJ='-Bstatic' ;; *) lt_prog_compiler_can_build_shared_GCJ=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_GCJ" >&5 $as_echo "$lt_prog_compiler_pic_GCJ" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_GCJ"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... " >&6; } if ${lt_prog_compiler_pic_works_GCJ+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works_GCJ=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_GCJ" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:16423: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:16427: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s conftest.err; then lt_prog_compiler_pic_works_GCJ=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_GCJ" >&5 $as_echo "$lt_prog_compiler_pic_works_GCJ" >&6; } if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then case $lt_prog_compiler_pic_GCJ in "" | " "*) ;; *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; esac else lt_prog_compiler_pic_GCJ= lt_prog_compiler_can_build_shared_GCJ=no fi fi case "$host_os" in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_GCJ= ;; *) lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_GCJ+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_GCJ=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext # According to Tom Tromey, Ian Lance Taylor reported there are C compilers # that will create temporary files in the current directory regardless of # the output directory. Thus, making CWD read-only will cause this test # to fail, enabling locking or at least warning the user not to do parallel # builds. chmod -w . lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:16490: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:16494: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test ! -s out/conftest.err; then lt_cv_prog_compiler_c_o_GCJ=yes fi fi chmod u+w . $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 $as_echo "$lt_cv_prog_compiler_c_o_GCJ" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag_GCJ= enable_shared_with_static_runtimes_GCJ=no archive_cmds_GCJ= archive_expsym_cmds_GCJ= old_archive_From_new_cmds_GCJ= old_archive_from_expsyms_cmds_GCJ= export_dynamic_flag_spec_GCJ= whole_archive_flag_spec_GCJ= thread_safe_flag_spec_GCJ= hardcode_libdir_flag_spec_GCJ= hardcode_libdir_flag_spec_ld_GCJ= hardcode_libdir_separator_GCJ= hardcode_direct_GCJ=no hardcode_minus_L_GCJ=no hardcode_shlibpath_var_GCJ=unsupported link_all_deplibs_GCJ=unknown hardcode_automatic_GCJ=no module_cmds_GCJ= module_expsym_cmds_GCJ= always_export_symbols_GCJ=no export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms_GCJ= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs_GCJ=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs_GCJ=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs_GCJ=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_GCJ=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_GCJ=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_GCJ='-L$libdir' allow_undefined_flag_GCJ=unsupported always_export_symbols_GCJ=no enable_shared_with_static_runtimes_GCJ=yes export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris* | sysv5*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs_GCJ=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_GCJ=no fi ;; sunos4*) archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_GCJ=no fi ;; esac if test "$ld_shlibs_GCJ" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_GCJ= fi fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag_GCJ=unsupported always_export_symbols_GCJ=yes archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L_GCJ=yes if test "$GCC" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct_GCJ=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_GCJ='' hardcode_direct_GCJ=yes hardcode_libdir_separator_GCJ=':' link_all_deplibs_GCJ=yes if test "$GCC" = yes; then case $host_os in aix4.012|aix4.012.*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_GCJ=yes else # We have old collect2 hardcode_direct_GCJ=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_GCJ=yes hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_libdir_separator_GCJ= fi esac shared_flag='-shared' else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_GCJ=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_GCJ='-berok' # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_GCJ="-z nodefs" archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_GCJ=' ${wl}-bernotok' allow_undefined_flag_GCJ=' ${wl}-berok' # -bexpall does not export symbols beginning with underscore (_) always_export_symbols_GCJ=yes # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_GCJ=' ' archive_cmds_need_lc_GCJ=yes # This is similar to how AIX traditionally builds it's shared libraries. archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes # see comment about different semantics on the GNU ld section ld_shlibs_GCJ=no ;; bsdi4*) export_dynamic_flag_spec_GCJ=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_GCJ=' ' allow_undefined_flag_GCJ=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds_GCJ='true' # FIXME: Should let the user specify the lib program. old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes_GCJ=yes ;; darwin* | rhapsody*) if test "$GXX" = yes ; then archive_cmds_need_lc_GCJ=no case "$host_os" in rhapsody* | darwin1.[012]) allow_undefined_flag_GCJ='-undefined suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_GCJ='-flat_namespace -undefined suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_GCJ='-flat_namespace -undefined suppress' ;; 10.*) allow_undefined_flag_GCJ='-undefined dynamic_lookup' ;; esac fi ;; esac lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds_GCJ='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds_GCJ='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds_GCJ='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' hardcode_direct_GCJ=no hardcode_automatic_GCJ=yes hardcode_shlibpath_var_GCJ=unsupported whole_archive_flag_spec_GCJ='-all_load $convenience' link_all_deplibs_GCJ=yes else ld_shlibs_GCJ=no fi ;; dgux*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_shlibpath_var_GCJ=no ;; freebsd1*) ld_shlibs_GCJ=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu) archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-E' ;; hpux10* | hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*|ia64*) archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case "$host_cpu" in hppa*64*|ia64*) archive_cmds_GCJ='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' ;; *) archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; esac fi if test "$with_gnu_ld" = no; then case "$host_cpu" in hppa*64*) hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=no hardcode_shlibpath_var_GCJ=no ;; ia64*) hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_direct_GCJ=no hardcode_shlibpath_var_GCJ=no # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes ;; *) hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' fi hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: link_all_deplibs_GCJ=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; newsos6) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_shlibpath_var_GCJ=no ;; openbsd*) hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' export_dynamic_flag_spec_GCJ='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-R$libdir' ;; *) archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes allow_undefined_flag_GCJ=unsupported archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag_GCJ=' -expect_unresolved \*' archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' else allow_undefined_flag_GCJ=' -expect_unresolved \*' archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec_GCJ='-rpath $libdir' fi hardcode_libdir_separator_GCJ=: ;; sco3.2v5*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no export_dynamic_flag_spec_GCJ='${wl}-Bexport' runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) no_undefined_flag_GCJ=' -z text' if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_shlibpath_var_GCJ=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;; esac link_all_deplibs_GCJ=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; sysv4) case $host_vendor in sni) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds_GCJ='$CC -r -o $output$reload_objs' hardcode_direct_GCJ=no ;; motorola) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_GCJ=no ;; sysv4.3*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no export_dynamic_flag_spec_GCJ='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs_GCJ=yes fi ;; sysv4.2uw2*) archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=no hardcode_shlibpath_var_GCJ=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[78]* | unixware7*) no_undefined_flag_GCJ='${wl}-z ${wl}text' if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' fi runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_GCJ=no ;; sysv5*) no_undefined_flag_GCJ=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' hardcode_libdir_flag_spec_GCJ= hardcode_shlibpath_var_GCJ=no runpath_var='LD_RUN_PATH' ;; uts4*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_shlibpath_var_GCJ=no ;; *) ld_shlibs_GCJ=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_GCJ" >&5 $as_echo "$ld_shlibs_GCJ" >&6; } test "$ld_shlibs_GCJ" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_GCJ" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_GCJ=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_GCJ in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_GCJ compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ allow_undefined_flag_GCJ= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc_GCJ=no else archive_cmds_need_lc_GCJ=yes fi allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_GCJ" >&5 $as_echo "$archive_cmds_need_lc_GCJ" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/./-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext='$(test .$module = .yes && echo .so || echo .dylib)' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.01* | freebsdelf3.01*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case "$host_cpu" in ia64*) shrext='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_GCJ= if test -n "$hardcode_libdir_flag_spec_GCJ" || \ test -n "$runpath_var GCJ" || \ test "X$hardcode_automatic_GCJ"="Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_GCJ" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && test "$hardcode_minus_L_GCJ" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_GCJ=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_GCJ=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_GCJ=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_GCJ" >&5 $as_echo "$hardcode_action_GCJ" >&6; } if test "$hardcode_action_GCJ" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" # # # The following section is a PATCH to overcome the # stripped import library issues under cygwin case $host_os in cygwin*) striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ;; esac # # # AC_MSG_RESULT([yes]) # # else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then LDFLAGS="$LDFLAGS $link_static_flag" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM SED SHELL \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_GCJ \ CC_GCJ \ LD_GCJ \ lt_prog_compiler_wl_GCJ \ lt_prog_compiler_pic_GCJ \ lt_prog_compiler_static_GCJ \ lt_prog_compiler_no_builtin_flag_GCJ \ export_dynamic_flag_spec_GCJ \ thread_safe_flag_spec_GCJ \ whole_archive_flag_spec_GCJ \ enable_shared_with_static_runtimes_GCJ \ old_archive_cmds_GCJ \ old_archive_from_new_cmds_GCJ \ predep_objects_GCJ \ postdep_objects_GCJ \ predeps_GCJ \ postdeps_GCJ \ compiler_lib_search_path_GCJ \ archive_cmds_GCJ \ archive_expsym_cmds_GCJ \ postinstall_cmds_GCJ \ postuninstall_cmds_GCJ \ old_archive_from_expsyms_cmds_GCJ \ allow_undefined_flag_GCJ \ no_undefined_flag_GCJ \ export_symbols_cmds_GCJ \ hardcode_libdir_flag_spec_GCJ \ hardcode_libdir_flag_spec_ld_GCJ \ hardcode_libdir_separator_GCJ \ hardcode_automatic_GCJ \ module_cmds_GCJ \ module_expsym_cmds_GCJ \ lt_cv_prog_compiler_c_o_GCJ \ exclude_expsyms_GCJ \ include_expsyms_GCJ; do case $var in old_archive_cmds_GCJ | \ old_archive_from_new_cmds_GCJ | \ archive_cmds_GCJ | \ archive_expsym_cmds_GCJ | \ module_cmds_GCJ | \ module_expsym_cmds_GCJ | \ old_archive_from_expsyms_cmds_GCJ | \ export_symbols_cmds_GCJ | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_GCJ # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_GCJ # Is the compiler the GNU C compiler? with_gcc=$GCC_GCJ # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_GCJ # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_GCJ # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext='$shrext' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_GCJ pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_GCJ # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_GCJ old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_GCJ archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_GCJ module_expsym_cmds=$lt_module_expsym_cmds_GCJ # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_GCJ # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_GCJ # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_GCJ # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_GCJ # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_GCJ # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_GCJ # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_GCJ # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_GCJ # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_GCJ # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_GCJ # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_GCJ # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_GCJ" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_GCJ # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_GCJ # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_GCJ # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_GCJ # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. test -f Makefile && make "$ltmain" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" else tagname="" fi ;; RC) # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o objext_RC=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # Allow CC to be a program name with arguments. compiler=$CC # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${RC-"windres"} compiler=$CC compiler_RC=$CC lt_cv_prog_compiler_c_o_RC=yes # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC NM SED SHELL \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_RC \ CC_RC \ LD_RC \ lt_prog_compiler_wl_RC \ lt_prog_compiler_pic_RC \ lt_prog_compiler_static_RC \ lt_prog_compiler_no_builtin_flag_RC \ export_dynamic_flag_spec_RC \ thread_safe_flag_spec_RC \ whole_archive_flag_spec_RC \ enable_shared_with_static_runtimes_RC \ old_archive_cmds_RC \ old_archive_from_new_cmds_RC \ predep_objects_RC \ postdep_objects_RC \ predeps_RC \ postdeps_RC \ compiler_lib_search_path_RC \ archive_cmds_RC \ archive_expsym_cmds_RC \ postinstall_cmds_RC \ postuninstall_cmds_RC \ old_archive_from_expsyms_cmds_RC \ allow_undefined_flag_RC \ no_undefined_flag_RC \ export_symbols_cmds_RC \ hardcode_libdir_flag_spec_RC \ hardcode_libdir_flag_spec_ld_RC \ hardcode_libdir_separator_RC \ hardcode_automatic_RC \ module_cmds_RC \ module_expsym_cmds_RC \ lt_cv_prog_compiler_c_o_RC \ exclude_expsyms_RC \ include_expsyms_RC; do case $var in old_archive_cmds_RC | \ old_archive_from_new_cmds_RC | \ archive_cmds_RC | \ archive_expsym_cmds_RC | \ module_cmds_RC | \ module_expsym_cmds_RC | \ old_archive_from_expsyms_cmds_RC | \ export_symbols_cmds_RC | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_RC # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # A language-specific compiler. CC=$lt_compiler_RC # Is the compiler the GNU C compiler? with_gcc=$GCC_RC # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_RC # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_RC # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext='$shrext' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_RC pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC # Must we lock files when doing compilation ? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_RC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_RC old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_RC archive_expsym_cmds=$lt_archive_expsym_cmds_RC postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_RC module_expsym_cmds=$lt_module_expsym_cmds_RC # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=$lt_predep_objects_RC # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=$lt_postdep_objects_RC # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_RC # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_RC # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=$lt_compiler_lib_search_path_RC # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_RC # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_RC # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_RC # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_RC # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_RC # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_RC # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_RC # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_RC # Compile-time system search path for libraries sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_RC" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_RC # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_RC # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_RC # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_RC # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. test -f Makefile && make "$ltmain" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ;; *) as_fn_error $? "Unsupported tag name: $tagname" "$LINENO" 5 ;; esac # Append the new tag name to the list of available tags. if test -n "$tagname" ; then available_tags="$available_tags $tagname" fi fi done IFS="$lt_save_ifs" # Now substitute the updated list of available tags. if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then mv "${ofile}T" "$ofile" chmod +x "$ofile" else rm -f "${ofile}T" as_fn_error $? "unable to update list of available tagged configurations." "$LINENO" 5 fi fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' # Prevent multiple expansion # (we build libtool for ourselves) # ----------------------------------------------------------------------------- # # AC_LIB_LTDL # # Even though libltdl is installed together with libtool, you may wish # to include libltdl in the distribution of your package, for the convenience # of users of your package that don't have libtool or libltdl installed. # # The most simplistic way to add libltdl to your package is to copy the # source files, 'ltdl.c' and 'ltdl.h', to a source directory withing your # package and to build and link them along with the rest of your sources. # # To do this, you must add a call to the 'AC_LIB_LTDL' macro to your package's # 'configure.in' to perform the required configure time checks in order that # 'ltdl.o' is built correctly. # # This method does have its problems though: if you try to link the package # binaries with an installed libltdl, or a library which depends on libltdl, # you may have problems with duplicate symbol definitions. # # In order to enable this flavor of libltdl, you should add the line # 'AC_LIBLTDL_CONVENIENCE' to your `configure.in', before 'AC_PROG_LIBTOOL'. # # In order to select the installable version of libltdl, you should add a # call of the macro 'AC_LIBLTDL_INSTALLABLE' to your 'configure.in' before # 'AC_PROG_LIBTOOL'. This macro will check whether libltdl is already # installed and, if not, request the libltdl embedded in your package to be # built and installed. # # Whatever macro you use, it is up to you to ensure that your 'configure.in' # will configure libltdl, using 'AC_CONFIG_SUBDIRS', and that your 'Makefile's # will start sub-makes within libltdl's directory, using automake's SUBDIRS, # for example. Both macros define the shell variables LIBLTDL, to the link flag # that you should use to link with libltdl, and LTDLINCL, to the preprocessor # flag that you should use to compile with programs that include 'ltdl.h'. It # is up to you to use 'AC_SUBST' to ensure that this variable will be available # in 'Makefile's, or add them to variables that are 'AC_SUBST'ed by default, # such as LIBS and CPPFLAGS. # # So, when you want to link a program with libltdl, be it a convenience, # installed or installable library, just compile with '$(LTDLINCL)' and link # it with '$(LIBLTDL)', using libtool. # # You should probably also add 'AC_LIBTOOL_DLOPEN' to your 'configure.in' before # 'AC_PROG_LIBTOOL', otherwise libtool will assume no dlopening mechanism is # supported, and revert to dlpreopening, which is probably not what you want. # # The following example shows you how to embed the convenience libltdl # in your package. In order to use the installable variant just replace # 'AC_LIBLTDL_CONVENIENCE' with 'AC_LIBLTDL_INSTALLABLE'. We assume that libltdl # was embedded using 'libtoolize --ltdl': # # configure.in: # # ... # dnl Enable building of the convenience library # dnl and set LIBLTDL accordingly # AC_LIBLTDL_CONVENIENCE # dnl Substitute LTDLINCL and LIBLTDL in the Makefiles # AC_SUBST(LTDLINCL) # AC_SUBST(LIBLTDL) # dnl Check for dlopen support # AC_LIBTOOL_DLOPEN # dnl Configure libtool # AC_PROG_LIBTOOL # dnl Configure libltdl # AC_CONFIG_SUBDIRS(libltdl) # ... # # Makefile.am: # # ... # SUBDIRS = libltdl # # INCLUDES = $(LTDLINCL) # # myprog_LDFLAGS = -export-dynamic # # The quotes around -dlopen below fool automake <= 1.4 into accepting it # myprog_LDADD = $(LIBLTDL) "-dlopen" self "-dlopen" foo1.la # myprog_DEPENDENCIES = $(LIBLTDL) foo1.la # ... # # ----------------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi # Check whether --enable-ltdl-install was given. if test "${enable_ltdl_install+set}" = set; then : enableval=$enable_ltdl_install; fi if test x"${enable_ltdl_install-no}" != xno; then INSTALL_LTDL_TRUE= INSTALL_LTDL_FALSE='#' else INSTALL_LTDL_TRUE='#' INSTALL_LTDL_FALSE= fi if test x"${enable_ltdl_convenience-no}" != xno; then CONVENIENCE_LTDL_TRUE= CONVENIENCE_LTDL_FALSE='#' else CONVENIENCE_LTDL_TRUE='#' CONVENIENCE_LTDL_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking which extension is used for loadable modules" >&5 $as_echo_n "checking which extension is used for loadable modules... " >&6; } if ${libltdl_cv_shlibext+:} false; then : $as_echo_n "(cached) " >&6 else module=yes eval libltdl_cv_shlibext=$shrext_cmds fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_shlibext" >&5 $as_echo "$libltdl_cv_shlibext" >&6; } if test -n "$libltdl_cv_shlibext"; then cat >>confdefs.h <<_ACEOF #define LTDL_SHLIB_EXT "$libltdl_cv_shlibext" _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variable specifies run-time library path" >&5 $as_echo_n "checking which variable specifies run-time library path... " >&6; } if ${libltdl_cv_shlibpath_var+:} false; then : $as_echo_n "(cached) " >&6 else libltdl_cv_shlibpath_var="$shlibpath_var" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_shlibpath_var" >&5 $as_echo "$libltdl_cv_shlibpath_var" >&6; } if test -n "$libltdl_cv_shlibpath_var"; then cat >>confdefs.h <<_ACEOF #define LTDL_SHLIBPATH_VAR "$libltdl_cv_shlibpath_var" _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the default library search path" >&5 $as_echo_n "checking for the default library search path... " >&6; } if ${libltdl_cv_sys_search_path+:} false; then : $as_echo_n "(cached) " >&6 else libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_sys_search_path" >&5 $as_echo "$libltdl_cv_sys_search_path" >&6; } if test -n "$libltdl_cv_sys_search_path"; then sys_search_path= for dir in $libltdl_cv_sys_search_path; do if test -z "$sys_search_path"; then sys_search_path="$dir" else sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" fi done cat >>confdefs.h <<_ACEOF #define LTDL_SYSSEARCHPATH "$sys_search_path" _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${libltdl_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else libltdl_cv_objdir="$objdir" if test -n "$objdir"; then : else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then libltdl_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. libltdl_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_objdir" >&5 $as_echo "$libltdl_cv_objdir" >&6; } cat >>confdefs.h <<_ACEOF #define LTDL_OBJDIR "$libltdl_cv_objdir/" _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libtool supports -dlopen/-dlpreopen" >&5 $as_echo_n "checking whether libtool supports -dlopen/-dlpreopen... " >&6; } if ${libltdl_cv_preloaded_symbols+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$lt_cv_sys_global_symbol_pipe"; then libltdl_cv_preloaded_symbols=yes else libltdl_cv_preloaded_symbols=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_preloaded_symbols" >&5 $as_echo "$libltdl_cv_preloaded_symbols" >&6; } if test x"$libltdl_cv_preloaded_symbols" = xyes; then $as_echo "#define HAVE_PRELOADED_SYMBOLS 1" >>confdefs.h fi LIBADD_DL= ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : $as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : $as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h LIBADD_DL="$LIBADD_DL -ldld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : $as_echo "#define HAVE_LIBDL 1" >>confdefs.h LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_DLFCN_H # include #endif int main () { dlopen(0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : $as_echo "#define HAVE_LIBDL 1" >>confdefs.h libltdl_cv_func_dlopen="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : $as_echo "#define HAVE_LIBDL 1" >>confdefs.h LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : $as_echo "#define HAVE_DLD 1" >>confdefs.h LIBADD_DL="$LIBADD_DL -ldld" else ac_fn_c_check_func "$LINENO" "_dyld_func_lookup" "ac_cv_func__dyld_func_lookup" if test "x$ac_cv_func__dyld_func_lookup" = xyes; then : $as_echo "#define HAVE_DYLD 1" >>confdefs.h fi fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi fi fi if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes then lt_save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DL" for ac_func in dlerror do : ac_fn_c_check_func "$LINENO" "dlerror" "ac_cv_func_dlerror" if test "x$ac_cv_func_dlerror" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLERROR 1 _ACEOF fi done LIBS="$lt_save_LIBS" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ prefix in compiled symbols" >&5 $as_echo_n "checking for _ prefix in compiled symbols... " >&6; } if ${ac_cv_sys_symbol_underscore+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_symbol_underscore=no cat > conftest.$ac_ext <&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. ac_nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$ac_nlist"; then # See whether the symbols have a leading underscore. if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then ac_cv_sys_symbol_underscore=yes else if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then : else echo "configure: cannot find nm_test_func in $ac_nlist" >&5 fi fi else echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "configure: failed program was:" >&5 cat conftest.c >&5 fi rm -rf conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_symbol_underscore" >&5 $as_echo "$ac_cv_sys_symbol_underscore" >&6; } if test x"$ac_cv_sys_symbol_underscore" = xyes; then if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we have to add an underscore for dlsym" >&5 $as_echo_n "checking whether we have to add an underscore for dlsym... " >&6; } if ${libltdl_cv_need_uscore+:} false; then : $as_echo_n "(cached) " >&6 else libltdl_cv_need_uscore=unknown save_LIBS="$LIBS" LIBS="$LIBS $LIBADD_DL" if test "$cross_compiling" = yes; then : libltdl_cv_need_uscore=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) libltdl_cv_need_uscore=no ;; x$lt_dlneed_uscore) libltdl_cv_need_uscore=yes ;; x$lt_unknown|x*) ;; esac else : # compilation failed fi fi rm -fr conftest* LIBS="$save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_need_uscore" >&5 $as_echo "$libltdl_cv_need_uscore" >&6; } fi fi if test x"$libltdl_cv_need_uscore" = xyes; then $as_echo "#define NEED_USCORE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether deplibs are loaded by dlopen" >&5 $as_echo_n "checking whether deplibs are loaded by dlopen... " >&6; } if ${libltdl_cv_sys_dlopen_deplibs+:} false; then : $as_echo_n "(cached) " >&6 else # PORTME does your system automatically load deplibs for dlopen? # or its logical equivalent (e.g. shl_load for HP-UX < 11) # For now, we just catch OSes we know something about -- in the # future, we'll try test this programmatically. libltdl_cv_sys_dlopen_deplibs=unknown case "$host_os" in aix3*|aix4.1.*|aix4.2.*) # Unknown whether this is true for these versions of AIX, but # we want this `case' here to explicitly catch those versions. libltdl_cv_sys_dlopen_deplibs=unknown ;; aix[45]*) libltdl_cv_sys_dlopen_deplibs=yes ;; darwin*) # Assuming the user has installed a libdl from somewhere, this is true # If you are looking for one http://www.opendarwin.org/projects/dlcompat libltdl_cv_sys_dlopen_deplibs=yes ;; kfreebsd*-gnu) libltdl_cv_sys_dlopen_deplibs=yes ;; gnu*) libltdl_cv_sys_dlopen_deplibs=yes ;; hpux10*|hpux11*) libltdl_cv_sys_dlopen_deplibs=yes ;; irix[12345]*|irix6.[01]*) # Catch all versions of IRIX before 6.2, and indicate that we don't # know how it worked for any of those versions. libltdl_cv_sys_dlopen_deplibs=unknown ;; irix*) # The case above catches anything before 6.2, and it's known that # at 6.2 and later dlopen does load deplibs. libltdl_cv_sys_dlopen_deplibs=yes ;; linux*) libltdl_cv_sys_dlopen_deplibs=yes ;; netbsd*) libltdl_cv_sys_dlopen_deplibs=yes ;; openbsd*) libltdl_cv_sys_dlopen_deplibs=yes ;; osf[1234]*) # dlopen did load deplibs (at least at 4.x), but until the 5.x series, # it did *not* use an RPATH in a shared library to find objects the # library depends on, so we explictly say `no'. libltdl_cv_sys_dlopen_deplibs=no ;; osf5.0|osf5.0a|osf5.1) # dlopen *does* load deplibs and with the right loader patch applied # it even uses RPATH in a shared library to search for shared objects # that the library depends on, but there's no easy way to know if that # patch is installed. Since this is the case, all we can really # say is unknown -- it depends on the patch being installed. If # it is, this changes to `yes'. Without it, it would be `no'. libltdl_cv_sys_dlopen_deplibs=unknown ;; osf*) # the two cases above should catch all versions of osf <= 5.1. Read # the comments above for what we know about them. # At > 5.1, deplibs are loaded *and* any RPATH in a shared library # is used to find them so we can finally say `yes'. libltdl_cv_sys_dlopen_deplibs=yes ;; solaris*) libltdl_cv_sys_dlopen_deplibs=yes ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libltdl_cv_sys_dlopen_deplibs" >&5 $as_echo "$libltdl_cv_sys_dlopen_deplibs" >&6; } if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then $as_echo "#define LTDL_DLOPEN_DEPLIBS 1" >>confdefs.h fi for ac_header in argz.h do : ac_fn_c_check_header_mongrel "$LINENO" "argz.h" "ac_cv_header_argz_h" "$ac_includes_default" if test "x$ac_cv_header_argz_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ARGZ_H 1 _ACEOF fi done ac_fn_c_check_type "$LINENO" "error_t" "ac_cv_type_error_t" "#if HAVE_ARGZ_H # include #endif " if test "x$ac_cv_type_error_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ERROR_T 1 _ACEOF else $as_echo "#define error_t int" >>confdefs.h fi for ac_func in argz_append argz_create_sep argz_insert argz_next argz_stringify do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ stdio.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dl.h sys/dl.h dld.h mach-o/dyld.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in string.h strings.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF break fi done for ac_func in strchr index do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF break fi done for ac_func in strrchr rindex do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF break fi done for ac_func in memcpy bcopy do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF break fi done for ac_func in memmove strcmp do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in closedir opendir readdir do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # (we need the ltdl libtool library) # (see PROGRAMMING NOTE above) # ----------------------------------------------------------------------------- # (See comments in the 'AC_CHECK_LIB' Libraries section further below) # ----------------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: (use of lt_dlopen forced by Hercules Dynamic Loader requirement) " >&5 $as_echo "$as_me: (use of lt_dlopen forced by Hercules Dynamic Loader requirement) " >&6;} if test "x${with_included_ltdl}" = "xno"; then : hc_cv_have_lt_dlopen=no else hc_cv_have_lt_dlopen=yes fi if test "x${ac_cv_func_dlopen}" = "xyes" -o "x${ac_cv_lib_dl_dlopen}" = "xyes"; then : hc_cv_have_dlopen=yes else hc_cv_have_dlopen=no fi if test "$lt_cv_prog_gnu_ld" = "yes"; then LDFLAGS="$LDFLAGS -Wl,--warn-common" fi # (add duplicate symbols option to LDFLAGS) # ----------------------------------------------------------------------------- # The following is a "global error" flag used to defer aborting configure # until after ALL errors have been detected/reported. # ----------------------------------------------------------------------------- hc_error=no ############################################################################### # Autoheader templates ############################################################################### # All AC_DEFINE() macros used within autoconf (to define pre-processor vars # used during the actual build process) must have corresponding AH_TEMPLATE # statements coded somewhere. We place them all here simply for convenience. ############################################################################### # OS-specific settings that we can't figure out any other way (yet) ############################################################################### # # Determine what type of host we're building on... # case "$host_os" in linux*) hc_cv_is_nix=yes hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no ;; mingw*) hc_cv_is_nix=no hc_cv_is_windows=yes hc_cv_is_mingw32=yes hc_cv_is_apple=no ;; cygwin*) hc_cv_is_nix=no hc_cv_is_windows=yes hc_cv_is_mingw32=no hc_cv_is_apple=no ;; darwin*) if test $host_vendor = apple; then hc_cv_is_nix=no hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=yes else hc_cv_is_nix=no hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no fi ;; *bsd*) hc_cv_is_nix=yes hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no ;; *) hc_cv_is_nix=no hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no ;; esac #------------------------------------------------------# # Hard-coded host-operating-system-specific settings # # that we have no other/easy way to figure out... # #------------------------------------------------------# if test "$hc_cv_is_nix" = "yes"; then hc_cv_build_hercifc=yes hc_cv_non_unique_gettimeofday=no elif test "$hc_cv_is_windows" = "yes"; then hc_cv_build_hercifc=no hc_cv_non_unique_gettimeofday=yes elif test "$hc_cv_is_apple" = "yes"; then hc_cv_build_hercifc=yes hc_cv_non_unique_gettimeofday=no else hc_cv_build_hercifc=no hc_cv_non_unique_gettimeofday=no fi ############################################################################### # Checks for REQUIRED (non-optional) header files... ############################################################################### # PROGRAMMING NOTE: We use 'AC_CHECK_HEADER' here (singular) since we don't # care whether 'HAVE_XXX' gets #defined or not since, because these are re- # quired headers, if any of them are not found, we abort and thus we don't # need to have any 'HAVE_XXX' pre-processor #defined entered into config.h # (because we can't build Herc at all if any of them don't happen to exist) ac_fn_c_check_header_mongrel "$LINENO" "ctype.h" "ac_cv_header_ctype_h" "$ac_includes_default" if test "x$ac_cv_header_ctype_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'ctype.h' not found " >&5 $as_echo "ERROR: Required header 'ctype.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'errno.h' not found " >&5 $as_echo "ERROR: Required header 'errno.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" if test "x$ac_cv_header_fcntl_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'fcntl.h' not found " >&5 $as_echo "ERROR: Required header 'fcntl.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'limits.h' not found " >&5 $as_echo "ERROR: Required header 'limits.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" "$ac_includes_default" if test "x$ac_cv_header_setjmp_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'setjmp.h' not found " >&5 $as_echo "ERROR: Required header 'setjmp.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "stdarg.h" "ac_cv_header_stdarg_h" "$ac_includes_default" if test "x$ac_cv_header_stdarg_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'stdarg.h' not found " >&5 $as_echo "ERROR: Required header 'stdarg.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "stdio.h" "ac_cv_header_stdio_h" "$ac_includes_default" if test "x$ac_cv_header_stdio_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'stdio.h' not found " >&5 $as_echo "ERROR: Required header 'stdio.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'stdlib.h' not found " >&5 $as_echo "ERROR: Required header 'stdlib.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'string.h' not found " >&5 $as_echo "ERROR: Required header 'string.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "time.h" "ac_cv_header_time_h" "$ac_includes_default" if test "x$ac_cv_header_time_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'time.h' not found " >&5 $as_echo "ERROR: Required header 'time.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'unistd.h' not found " >&5 $as_echo "ERROR: Required header 'unistd.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default" if test "x$ac_cv_header_sys_stat_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'sys/stat.h' not found " >&5 $as_echo "ERROR: Required header 'sys/stat.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'sys/time.h' not found " >&5 $as_echo "ERROR: Required header 'sys/time.h' not found " >&6; }; hc_error=yes fi ac_fn_c_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" if test "x$ac_cv_header_sys_types_h" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'sys/types.h' not found " >&5 $as_echo "ERROR: Required header 'sys/types.h' not found " >&6; }; hc_error=yes fi # PROGRAMMING NOTE: the pthread.h header only required if this is not # an fthreads build. Thus we delay aborting until later once we know # (if this is a windows build; otherwise we abort right away) ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : hc_cv_have_pthread_h=yes else if test "$hc_cv_is_windows" = "yes"; then hc_cv_alt_pthread_location=/usr/Pthreads { $as_echo "$as_me:${as_lineno-$LINENO}: looking for pthread.h in ${hc_cv_alt_pthread_location} " >&5 $as_echo "$as_me: looking for pthread.h in ${hc_cv_alt_pthread_location} " >&6;} hc_temp=$CFLAGS CFLAGS="$CFLAGS -I${hc_cv_alt_pthread_location}" ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : hc_cv_have_pthread_h=yes else hc_cv_have_pthread_h=no fi CFLAGS=$hc_temp else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'pthread.h' not found " >&5 $as_echo "ERROR: Required header 'pthread.h' not found " >&6; } hc_error=yes fi fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for optional (non-required) header files... ############################################################################### # PROGRAMMING NOTE: We use 'AC_CHECK_HEADERS' here (plural) to cause autoconf # to automatically add a #define/#undef 'HAVE_XXX' statement into config.h to # let us know whether the header exists on this system or not (since, because # these are optional headers, we are still able to successfully build Herc if # they don't happen to exist). The 'hc_cv_have_xxx' variables are only defined # in case other parts of configure.ac need to know whether the header exists # or not without having to do their own AC_CHECK_HEADERS (since we've already # done it). #------------------------------------------------------------------------------ # PROGRAMMING NOTE: on Darwin sys/socket.h must be included before # net/if.h, net/route.h, or netinet/in.h can be #included, and on OS X 10.3 # (but not 10.4) sys/types.h must be #included before sys/socket.h. Thus # the below four header checks are treated specially. If we ever drop support # for OS X 10.3, a lot of this cruft can be removed, not just here but # anywhere we find ourselves manually including sys/types.h. # PROGRAMMING NOTE: on *BSD sys/socket.h must be included before net/if.h, # net/route.h, or netinet/in.h can be #included. for ac_header in sys/socket.h do : ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" " #include " if test "x$ac_cv_header_sys_socket_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_SOCKET_H 1 _ACEOF hc_cv_have_sys_socket_h=yes else hc_cv_have_sys_socket_h=no fi done for ac_header in net/if.h do : ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_header_net_if_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_IF_H 1 _ACEOF hc_cv_have_net_if_h=yes else hc_cv_have_net_if_h=no fi done for ac_header in netinet/in.h do : ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_header_netinet_in_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NETINET_IN_H 1 _ACEOF hc_cv_have_netinet_in_h=yes else hc_cv_have_netinet_in_h=no fi done for ac_header in netinet/tcp.h do : ac_fn_c_check_header_compile "$LINENO" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_header_netinet_tcp_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NETINET_TCP_H 1 _ACEOF hc_cv_have_netinet_tcp_h=yes else hc_cv_have_netinet_tcp_h=no fi done for ac_header in net/route.h do : ac_fn_c_check_header_compile "$LINENO" "net/route.h" "ac_cv_header_net_route_h" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_header_net_route_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_ROUTE_H 1 _ACEOF hc_cv_have_net_route_h=yes else hc_cv_have_net_route_h=no fi done #------------------------------------------------------------------------------ for ac_header in arpa/inet.h do : ac_fn_c_check_header_mongrel "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" if test "x$ac_cv_header_arpa_inet_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ARPA_INET_H 1 _ACEOF hc_cv_have_arpa_inet_h=yes else hc_cv_have_arpa_inet_h=no fi done for ac_header in linux/if_tun.h do : ac_fn_c_check_header_mongrel "$LINENO" "linux/if_tun.h" "ac_cv_header_linux_if_tun_h" "$ac_includes_default" if test "x$ac_cv_header_linux_if_tun_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_IF_TUN_H 1 _ACEOF hc_cv_have_linux_if_tun_h=yes else hc_cv_have_linux_if_tun_h=no fi done for ac_header in sys/ioctl.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_IOCTL_H 1 _ACEOF hc_cv_have_sys_ioctl_h=yes else hc_cv_have_sys_ioctl_h=no fi done for ac_header in sys/mman.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mman_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_MMAN_H 1 _ACEOF hc_cv_have_sys_mman_h=yes else hc_cv_have_sys_mman_h=no fi done #------------------------------------------------------------------------------ # PROGRAMMING NOTE: on *BSD systems sys/param.h must be #included before # sys/mount.h as it contains the #define of NGROUPS. for ac_header in sys/param.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PARAM_H 1 _ACEOF hc_cv_have_sys_param_h=yes else hc_cv_have_sys_param_h=no fi done for ac_header in sys/mount.h do : ac_fn_c_check_header_compile "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" " #if HAVE_SYS_PARAM_H #include #endif " if test "x$ac_cv_header_sys_mount_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_MOUNT_H 1 _ACEOF hc_cv_have_sys_mount_h=yes else hc_cv_have_sys_mount_h=no fi done #------------------------------------------------------------------------------ for ac_header in sys/mtio.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/mtio.h" "ac_cv_header_sys_mtio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mtio_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_MTIO_H 1 _ACEOF hc_cv_have_sys_mtio_h=yes else hc_cv_have_sys_mtio_h=no fi done for ac_header in sys/resource.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default" if test "x$ac_cv_header_sys_resource_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_RESOURCE_H 1 _ACEOF hc_cv_have_sys_resource_h=yes else hc_cv_have_sys_resource_h=no fi done for ac_header in sys/uio.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/uio.h" "ac_cv_header_sys_uio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_uio_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_UIO_H 1 _ACEOF hc_cv_have_sys_uio_h=yes else hc_cv_have_sys_uio_h=no fi done for ac_header in sys/utsname.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/utsname.h" "ac_cv_header_sys_utsname_h" "$ac_includes_default" if test "x$ac_cv_header_sys_utsname_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_UTSNAME_H 1 _ACEOF hc_cv_have_sys_utsname_h=yes else hc_cv_have_sys_utsname_h=no fi done for ac_header in sys/wait.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" if test "x$ac_cv_header_sys_wait_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_WAIT_H 1 _ACEOF hc_cv_have_sys_wait_h=yes else hc_cv_have_sys_wait_h=no fi done for ac_header in sys/un.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default" if test "x$ac_cv_header_sys_un_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_UN_H 1 _ACEOF hc_cv_have_sys_un_h=yes else hc_cv_have_sys_un_h=no fi done for ac_header in byteswap.h do : ac_fn_c_check_header_mongrel "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default" if test "x$ac_cv_header_byteswap_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_BYTESWAP_H 1 _ACEOF hc_cv_have_byteswap_h=yes else hc_cv_have_byteswap_h=no fi done for ac_header in bzlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "bzlib.h" "ac_cv_header_bzlib_h" "$ac_includes_default" if test "x$ac_cv_header_bzlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_BZLIB_H 1 _ACEOF hc_cv_have_bzlib_h=yes else hc_cv_have_bzlib_h=no fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF hc_cv_have_dlfcn_h=yes else hc_cv_have_dlfcn_h=no fi done for ac_header in inttypes.h do : ac_fn_c_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default" if test "x$ac_cv_header_inttypes_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INTTYPES_H 1 _ACEOF hc_cv_have_inttypes_h=yes else hc_cv_have_inttypes_h=no fi done for ac_header in iconv.h do : ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default" if test "x$ac_cv_header_iconv_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ICONV_H 1 _ACEOF hc_cv_have_iconv_h=yes else hc_cv_have_iconv_h=no fi done for ac_header in ltdl.h do : ac_fn_c_check_header_mongrel "$LINENO" "ltdl.h" "ac_cv_header_ltdl_h" "$ac_includes_default" if test "x$ac_cv_header_ltdl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LTDL_H 1 _ACEOF hc_cv_have_ltdl_h=yes else hc_cv_have_ltdl_h=no fi done for ac_header in malloc.h do : ac_fn_c_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default" if test "x$ac_cv_header_malloc_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MALLOC_H 1 _ACEOF hc_cv_have_malloc_h=yes else hc_cv_have_malloc_h=no fi done for ac_header in math.h do : ac_fn_c_check_header_mongrel "$LINENO" "math.h" "ac_cv_header_math_h" "$ac_includes_default" if test "x$ac_cv_header_math_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MATH_H 1 _ACEOF hc_cv_have_math_h=yes else hc_cv_have_math_h=no fi done for ac_header in netdb.h do : ac_fn_c_check_header_mongrel "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" if test "x$ac_cv_header_netdb_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NETDB_H 1 _ACEOF hc_cv_have_netdb_h=yes else hc_cv_have_netdb_h=no fi done for ac_header in pwd.h do : ac_fn_c_check_header_mongrel "$LINENO" "pwd.h" "ac_cv_header_pwd_h" "$ac_includes_default" if test "x$ac_cv_header_pwd_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PWD_H 1 _ACEOF hc_cv_have_pwd_h=yes else hc_cv_have_pwd_h=no fi done for ac_header in regex.h do : ac_fn_c_check_header_mongrel "$LINENO" "regex.h" "ac_cv_header_regex_h" "$ac_includes_default" if test "x$ac_cv_header_regex_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_REGEX_H 1 _ACEOF hc_cv_have_regex_h=yes else hc_cv_have_regex_h=no fi done for ac_header in sched.h do : ac_fn_c_check_header_mongrel "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" if test "x$ac_cv_header_sched_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SCHED_H 1 _ACEOF hc_cv_have_sched_h=yes else hc_cv_have_sched_h=no fi done for ac_header in signal.h do : ac_fn_c_check_header_mongrel "$LINENO" "signal.h" "ac_cv_header_signal_h" "$ac_includes_default" if test "x$ac_cv_header_signal_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SIGNAL_H 1 _ACEOF hc_cv_have_signal_h=yes else hc_cv_have_signal_h=no fi done for ac_header in termios.h do : ac_fn_c_check_header_mongrel "$LINENO" "termios.h" "ac_cv_header_termios_h" "$ac_includes_default" if test "x$ac_cv_header_termios_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_TERMIOS_H 1 _ACEOF hc_cv_have_termios_h=yes else hc_cv_have_termios_h=no fi done for ac_header in time.h do : ac_fn_c_check_header_mongrel "$LINENO" "time.h" "ac_cv_header_time_h" "$ac_includes_default" if test "x$ac_cv_header_time_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_TIME_H 1 _ACEOF hc_cv_have_time_h=yes else hc_cv_have_time_h=no fi done for ac_header in zlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ZLIB_H 1 _ACEOF hc_cv_have_zlib_h=yes else hc_cv_have_zlib_h=no fi done for ac_header in sys/capability.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default" if test "x$ac_cv_header_sys_capability_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_CAPABILITY_H 1 _ACEOF hc_cv_have_sys_capa_h=yes else hc_cv_have_sys_capa_h=no fi done for ac_header in sys/prctl.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_prctl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PRCTL_H 1 _ACEOF hc_cv_have_sys_prctl_h=yes else hc_cv_have_sys_prctl_h=no fi done cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for declarations... ############################################################################### # PROGRAMMING NOTE: For declaration checks, you need to be careful to use the # following test in your program: # # #if defined(HAVE_DECL_XXXX) && !HAVE_DECL_XXXXX # ...code to handle not declared case... # #endif # # This is because UNLIKE other 'AC_CHECK' macros, when a SYMBOL isn't DECLared, # "HAVE_DECL_XXXX" is #defined to '0' instead of leaving "HAVE_DECL_XXXX" #undefined. # (e.g. #defined to 1 if you have the declaration and #defined to 0 if you don't) ac_fn_c_check_decl "$LINENO" "SIGUSR1" "ac_cv_have_decl_SIGUSR1" "#include " if test "x$ac_cv_have_decl_SIGUSR1" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIGUSR1 $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_sigusr1=yes else hc_cv_have_sigusr1=no fi ac_fn_c_check_decl "$LINENO" "SIGUSR2" "ac_cv_have_decl_SIGUSR2" "#include " if test "x$ac_cv_have_decl_SIGUSR2" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIGUSR2 $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_sigusr2=yes else hc_cv_have_sigusr2=no fi ac_fn_c_check_decl "$LINENO" "SIGPIPE" "ac_cv_have_decl_SIGPIPE" "#include " if test "x$ac_cv_have_decl_SIGPIPE" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIGPIPE $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_sigpipe=yes else hc_cv_have_sigpipe=no fi ac_fn_c_check_decl "$LINENO" "SIGBUS" "ac_cv_have_decl_SIGBUS" "#include " if test "x$ac_cv_have_decl_SIGBUS" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIGBUS $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_sigbus=yes else hc_cv_have_sigbus=no fi ac_fn_c_check_decl "$LINENO" "IFNAMSIZ" "ac_cv_have_decl_IFNAMSIZ" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_have_decl_IFNAMSIZ" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_IFNAMSIZ $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_ifnamsiz=yes else hc_cv_have_ifnamsiz=no fi ac_fn_c_check_decl "$LINENO" "LOGIN_NAME_MAX" "ac_cv_have_decl_LOGIN_NAME_MAX" "#include " if test "x$ac_cv_have_decl_LOGIN_NAME_MAX" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_LOGIN_NAME_MAX $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_login_name_max=yes else hc_cv_have_login_name_max=no fi ac_fn_c_check_decl "$LINENO" "_SC_NPROCESSORS_CONF" "ac_cv_have_decl__SC_NPROCESSORS_CONF" "#include " if test "x$ac_cv_have_decl__SC_NPROCESSORS_CONF" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL__SC_NPROCESSORS_CONF $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_sc_nprocessors_conf=yes else hc_cv_have_sc_nprocessors_conf=no fi ac_fn_c_check_decl "$LINENO" "_SC_NPROCESSORS_ONLN" "ac_cv_have_decl__SC_NPROCESSORS_ONLN" "#include " if test "x$ac_cv_have_decl__SC_NPROCESSORS_ONLN" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL__SC_NPROCESSORS_ONLN $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_sc_nprocessors_onln=yes else hc_cv_have_sc_nprocessors_onln=no fi ac_fn_c_check_decl "$LINENO" "SIOCSIFNETMASK" "ac_cv_have_decl_SIOCSIFNETMASK" "#include " if test "x$ac_cv_have_decl_SIOCSIFNETMASK" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIOCSIFNETMASK $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_siocsifnetmask=yes else hc_cv_have_siocsifnetmask=no fi ac_fn_c_check_decl "$LINENO" "SIOCSIFHWADDR" "ac_cv_have_decl_SIOCSIFHWADDR" "#include " if test "x$ac_cv_have_decl_SIOCSIFHWADDR" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIOCSIFHWADDR $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_siocsifhwaddr=yes else hc_cv_have_siocsifhwaddr=no fi ac_fn_c_check_decl "$LINENO" "SIOCADDRT" "ac_cv_have_decl_SIOCADDRT" "#include " if test "x$ac_cv_have_decl_SIOCADDRT" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIOCADDRT $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_siocaddrt=yes else hc_cv_have_siocaddrt=no fi ac_fn_c_check_decl "$LINENO" "SIOCDELRT" "ac_cv_have_decl_SIOCDELRT" "#include " if test "x$ac_cv_have_decl_SIOCDELRT" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIOCDELRT $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_siocdelrt=yes else hc_cv_have_siocdelrt=no fi ac_fn_c_check_decl "$LINENO" "SIOCDIFADDR" "ac_cv_have_decl_SIOCDIFADDR" "#include " if test "x$ac_cv_have_decl_SIOCDIFADDR" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SIOCDIFADDR $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_siocdifaddr=yes else hc_cv_have_siocdifaddr=no fi if test "$hc_cv_have_sys_mtio_h" == "yes"; then ac_fn_c_check_decl "$LINENO" "MTEWARN" "ac_cv_have_decl_MTEWARN" "#include " if test "x$ac_cv_have_decl_MTEWARN" = xyes; then : ac_have_decl=1 else ac_have_decl=0 fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_MTEWARN $ac_have_decl _ACEOF if test $ac_have_decl = 1; then : hc_cv_have_mtewarn=yes else hc_cv_have_mtewarn=no fi else hc_cv_have_mtewarn=no fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for types... ############################################################################### ac_fn_c_check_type "$LINENO" "u_int8_t" "ac_cv_type_u_int8_t" "$ac_includes_default" if test "x$ac_cv_type_u_int8_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_U_INT8_T 1 _ACEOF hc_cv_have_u_int8_t=yes else hc_cv_have_u_int8_t=no fi ac_fn_c_check_type "$LINENO" "useconds_t" "ac_cv_type_useconds_t" "$ac_includes_default" if test "x$ac_cv_type_useconds_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_USECONDS_T 1 _ACEOF hc_cv_have_useconds_t=yes else hc_cv_have_useconds_t=no fi ac_fn_c_check_type "$LINENO" "id_t" "ac_cv_type_id_t" "$ac_includes_default" if test "x$ac_cv_type_id_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ID_T 1 _ACEOF hc_cv_have_id_t=yes else hc_cv_have_id_t=no fi ac_fn_c_check_type "$LINENO" "u_char" "ac_cv_type_u_char" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_type_u_char" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_U_CHAR 1 _ACEOF hc_cv_have_u_char=yes else hc_cv_have_u_char=no fi ac_fn_c_check_type "$LINENO" "u_short" "ac_cv_type_u_short" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_type_u_short" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_U_SHORT 1 _ACEOF hc_cv_have_u_short=yes else hc_cv_have_u_short=no fi ac_fn_c_check_type "$LINENO" "u_int" "ac_cv_type_u_int" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_type_u_int" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_U_INT 1 _ACEOF hc_cv_have_u_int=yes else hc_cv_have_u_int=no fi ac_fn_c_check_type "$LINENO" "u_long" "ac_cv_type_u_long" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_type_u_long" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_U_LONG 1 _ACEOF hc_cv_have_u_long=yes else hc_cv_have_u_long=no fi ac_fn_c_check_type "$LINENO" "in_addr_t" "ac_cv_type_in_addr_t" " #include #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif " if test "x$ac_cv_type_in_addr_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_IN_ADDR_T 1 _ACEOF hc_cv_have_in_addr_t=yes else hc_cv_have_in_addr_t=no fi ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" " #include #if HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_type_socklen_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SOCKLEN_T 1 _ACEOF hc_cv_have_socklen_t=yes else hc_cv_have_socklen_t=no fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for libraries... ############################################################################### # PROGRAMMING NOTE: we require libtool (or, optionally, dlltool (a less power- # ful (flexible) libtool-like tool for Windows platforms) in order to support # OPTION_DYNAMIC_LOAD. This is a relatively safe requirement since we provide # a version of libtool with Hercules (and build it as part of the preliminary # autoconf processing; see the 'Programs' section above). However, we need to # keep the below check for 'dlopen' anyway since we prefer that libtool use it # instead of its own equivalent (lt_dlopen) if it's available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _pipe in -lmsvcrt" >&5 $as_echo_n "checking for _pipe in -lmsvcrt... " >&6; } if ${ac_cv_lib_msvcrt__pipe__________+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmsvcrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char _pipe (); int main () { return _pipe (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_msvcrt__pipe__________=yes else ac_cv_lib_msvcrt__pipe__________=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_msvcrt__pipe__________" >&5 $as_echo "$ac_cv_lib_msvcrt__pipe__________" >&6; } if test "x$ac_cv_lib_msvcrt__pipe__________" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBMSVCRT 1 _ACEOF LIBS="-lmsvcrt $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen_________+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen_________=yes else ac_cv_lib_dl_dlopen_________=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen_________" >&5 $as_echo "$ac_cv_lib_dl_dlopen_________" >&6; } if test "x$ac_cv_lib_dl_dlopen_________" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF LIBS="-ldl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 $as_echo_n "checking for sqrt in -lm... " >&6; } if ${ac_cv_lib_m_sqrt___________+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sqrt (); int main () { return sqrt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_sqrt___________=yes else ac_cv_lib_m_sqrt___________=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt___________" >&5 $as_echo "$ac_cv_lib_m_sqrt___________" >&6; } if test "x$ac_cv_lib_m_sqrt___________" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if ${ac_cv_lib_socket_connect________+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect________=yes else ac_cv_lib_socket_connect________=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect________" >&5 $as_echo "$ac_cv_lib_socket_connect________" >&6; } if test "x$ac_cv_lib_socket_connect________" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname__+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname__=yes else ac_cv_lib_nsl_gethostbyname__=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname__" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname__" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname__" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 $as_echo_n "checking for inet_aton in -lresolv... " >&6; } if ${ac_cv_lib_resolv_inet_aton______+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_aton (); int main () { return inet_aton (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_resolv_inet_aton______=yes else ac_cv_lib_resolv_inet_aton______=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton______" >&5 $as_echo "$ac_cv_lib_resolv_inet_aton______" >&6; } if test "x$ac_cv_lib_resolv_inet_aton______" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF LIBS="-lresolv $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uncompress in -lz" >&5 $as_echo_n "checking for uncompress in -lz... " >&6; } if ${ac_cv_lib_z_uncompress_____+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char uncompress (); int main () { return uncompress (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_uncompress_____=yes else ac_cv_lib_z_uncompress_____=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_uncompress_____" >&5 $as_echo "$ac_cv_lib_z_uncompress_____" >&6; } if test "x$ac_cv_lib_z_uncompress_____" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBZ 1 _ACEOF LIBS="-lz $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BZ2_bzBuffToBuffDecompress in -lbz2" >&5 $as_echo_n "checking for BZ2_bzBuffToBuffDecompress in -lbz2... " >&6; } if ${ac_cv_lib_bz2_BZ2_bzBuffToBuffDecompress+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbz2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char BZ2_bzBuffToBuffDecompress (); int main () { return BZ2_bzBuffToBuffDecompress (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bz2_BZ2_bzBuffToBuffDecompress=yes else ac_cv_lib_bz2_BZ2_bzBuffToBuffDecompress=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bz2_BZ2_bzBuffToBuffDecompress" >&5 $as_echo "$ac_cv_lib_bz2_BZ2_bzBuffToBuffDecompress" >&6; } if test "x$ac_cv_lib_bz2_BZ2_bzBuffToBuffDecompress" = xyes; then : hc_cv_have_libbz2=yes else hc_cv_have_libbz2=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv in -liconv" >&5 $as_echo_n "checking for iconv in -liconv... " >&6; } if ${ac_cv_lib_iconv_iconv__________+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-liconv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char iconv (); int main () { return iconv (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_iconv_iconv__________=yes else ac_cv_lib_iconv_iconv__________=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iconv_iconv__________" >&5 $as_echo "$ac_cv_lib_iconv_iconv__________" >&6; } if test "x$ac_cv_lib_iconv_iconv__________" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBICONV 1 _ACEOF LIBS="-liconv $LIBS" fi # jbs 10/15/2003 Solaris requires -lrt for sched_yield() and fdatasync() { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 $as_echo_n "checking for sched_yield in -lrt... " >&6; } if ${ac_cv_lib_rt_sched_yield____+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sched_yield (); int main () { return sched_yield (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_sched_yield____=yes else ac_cv_lib_rt_sched_yield____=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield____" >&5 $as_echo "$ac_cv_lib_rt_sched_yield____" >&6; } if test "x$ac_cv_lib_rt_sched_yield____" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRT 1 _ACEOF LIBS="-lrt $LIBS" fi # rbowler 2008/03/10 rev 1.196 Solaris 2.9 requires -lpthread { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create_+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create_=yes else ac_cv_lib_pthread_pthread_create_=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create_" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create_" >&6; } if test "x$ac_cv_lib_pthread_pthread_create_" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for library functions... ############################################################################### # PROGRAMMING NOTE: AC_CHECK_LIB should be called first for the below # library function checks to ensure the library where the function is # defined gets added to the LIBS library search variable... ############################################################################### for ac_func in iconv do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in memrchr do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getopt_long do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in sqrtl ldexpl fabsl fmodl frexpl do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in ldexpf frexpf fabsf rint do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in strlcpy strlcat do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in strerror_r do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in strsignal do : ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal" if test "x$ac_cv_func_strsignal" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRSIGNAL 1 _ACEOF hc_cv_have_strsignal=yes else hc_cv_have_strsignal=no fi done for ac_func in sys_siglist do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in InitializeCriticalSectionAndSpinCount do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in sleep usleep nanosleep do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in sched_yield do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in strtok_r do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in pipe do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in gettimeofday do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getpgrp do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in scandir alphasort do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getlogin getlogin_r do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in realpath do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in fdatasync fsync ftruncate do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in inet_aton do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in fork socketpair do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in sysconf do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in vsscanf do : ac_fn_c_check_func "$LINENO" "vsscanf" "ac_cv_func_vsscanf" if test "x$ac_cv_func_vsscanf" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VSSCANF 1 _ACEOF hc_cv_have_vsscanf=yes else hc_cv_have_vsscanf=no fi done for ac_func in setresuid getresuid do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF hc_cv_have_getset_uid=yes else hc_cv_have_getset_uid=no; break fi done if test "$hc_cv_have_getset_uid" != "yes"; then for ac_func in setreuid geteuid getuid do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF hc_cv_have_getset_uid=yes else hc_cv_have_getset_uid=no; break fi done fi # FIXME: Disabled because some builtin ffs seem to be causing a problem. # (gcc 3.4 barfs on certain 'march=' settings?) #AC_CHECK_FUNCS( ffs ) # For OS X 10.6 autoconf defines HAVE_FDATASYNC even though there is # no function prototype declared for fdatasync() and unistd.h contains # define _POSIX_SYNCHRONIZED_IO (-1) which indicates that fdatasync is # not supported. So to decide whether fdatasync really can be used, we # create a new symbol HAVE_FDATASYNC_SUPPORTED which is defined only if # HAVE_FDATASYNC is defined and _POSIX_SYNCHRONIZED_IO is not negative. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fdatasync is supported" >&5 $as_echo_n "checking whether fdatasync is supported... " >&6; } if ${ac_cv_func_fdatasync_supported+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if !defined(HAVE_FDATASYNC) #error fdatasync is not defined on this platform #endif #if defined(_POSIX_SYNCHRONIZED_IO) && (_POSIX_SYNCHRONIZED_IO+0 < 0) #error fdatasync is not supported on this platform #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_fdatasync_supported=yes else ac_cv_func_fdatasync_supported=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fdatasync_supported" >&5 $as_echo "$ac_cv_func_fdatasync_supported" >&6; } if test "x${ac_cv_func_fdatasync_supported}" = "xyes"; then : $as_echo "#define HAVE_FDATASYNC_SUPPORTED 1" >>confdefs.h fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for structures and structure members... ############################################################################### ac_fn_c_check_member "$LINENO" "struct sockaddr_in" "sin_len" "ac_cv_member_struct_sockaddr_in_sin_len" " #include #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_in_sin_len" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1 _ACEOF hc_cv_have_sockaddr_in_sin_len=yes else hc_cv_have_sockaddr_in_sin_len=no fi ac_fn_c_check_member "$LINENO" "struct in_addr" "s_addr" "ac_cv_member_struct_in_addr_s_addr" " #include #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif " if test "x$ac_cv_member_struct_in_addr_s_addr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_IN_ADDR_S_ADDR 1 _ACEOF hc_cv_have_in_addr_s_addr=yes else hc_cv_have_in_addr_s_addr=no fi ac_fn_c_check_member "$LINENO" "struct sigaction" "sa_sigaction" "ac_cv_member_struct_sigaction_sa_sigaction" "#include " if test "x$ac_cv_member_struct_sigaction_sa_sigaction" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SIGACTION_SA_SIGACTION 1 _ACEOF hc_cv_have_sa_sigaction=yes else hc_cv_have_sa_sigaction=no fi ac_fn_c_check_member "$LINENO" "struct timespec" "tv_nsec" "ac_cv_member_struct_timespec_tv_nsec" "#include " if test "x$ac_cv_member_struct_timespec_tv_nsec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TIMESPEC_TV_NSEC 1 _ACEOF hc_cv_timespec_in_sys_types_h=yes hc_cv_timespec_in_time_h=no else ac_fn_c_check_member "$LINENO" "struct timespec" "tv_nsec" "ac_cv_member_struct_timespec_tv_nsec" "#include " if test "x$ac_cv_member_struct_timespec_tv_nsec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TIMESPEC_TV_NSEC 1 _ACEOF hc_cv_timespec_in_sys_types_h=no hc_cv_timespec_in_time_h=yes else hc_cv_timespec_in_sys_types_h=no hc_cv_timespec_in_time_h=no fi fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for compiler characteristics... ############################################################################### { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac # PROGRAMMING NOTE: Okay, this is stupid. If there are any trailing spaces # following the type we're checking the size of, then they're converted to # underscores in the 'SIZEOF_XXXX' that gets #defined! For example, doing a # AC_CHECK_SIZEOF( int ) yields: #define SIZEOF_INT____ 4 !!!!!!!!!!!!! # So... the below AC_CHECK_SIZEOF macros must NOT have any spaces in them!! # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } if ${ac_cv_sizeof_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : else if test "$ac_cv_type_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 $as_echo "$ac_cv_sizeof_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT $ac_cv_sizeof_int _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 $as_echo "$ac_cv_sizeof_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } if ${ac_cv_sizeof_size_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : else if test "$ac_cv_type_size_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (size_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 $as_echo "$ac_cv_sizeof_size_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SIZE_T $ac_cv_sizeof_size_t _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int *" >&5 $as_echo_n "checking size of int *... " >&6; } if ${ac_cv_sizeof_int_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int *))" "ac_cv_sizeof_int_p" "$ac_includes_default"; then : else if test "$ac_cv_type_int_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int *) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int_p=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int_p" >&5 $as_echo "$ac_cv_sizeof_int_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT_P $ac_cv_sizeof_int_p _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } if ${ac_cv_sizeof_off_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default"; then : else if test "$ac_cv_type_off_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off_t=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 $as_echo "$ac_cv_sizeof_off_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_OFF_T $ac_cv_sizeof_off_t _ACEOF #----------------------------------# # Structure alignment/size test # #----------------------------------# { $as_echo "$as_me:${as_lineno-$LINENO}: begin check: whether byte structs are aligned/rounded by default... " >&5 $as_echo "$as_me: begin check: whether byte structs are aligned/rounded by default... " >&6;} cat > conftest.h << __EOF #include struct bytestruct { unsigned char a; }; __EOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of struct bytestruct" >&5 $as_echo_n "checking size of struct bytestruct... " >&6; } if ${ac_cv_sizeof_struct_bytestruct+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (struct bytestruct))" "ac_cv_sizeof_struct_bytestruct" "#include \"conftest.h\" "; then : else if test "$ac_cv_type_struct_bytestruct" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (struct bytestruct) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_struct_bytestruct=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_struct_bytestruct" >&5 $as_echo "$ac_cv_sizeof_struct_bytestruct" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_STRUCT_BYTESTRUCT $ac_cv_sizeof_struct_bytestruct _ACEOF if test "$ac_cv_sizeof_struct_bytestruct" = "1"; then hc_cv_byte_structs_aligned_and_rounded_by_default=no hc_cv_byte_structs_always_aligned_and_rounded=no else # The sizeof our test structure is not '1'. # The compiler is rounding the size of the # structure upward to some predefined value. hc_cv_byte_structs_aligned_and_rounded_by_default=yes # If there's no way to request the compiler # to not do that, then we can't build Herc. case "$host_cpu-$GCC" in arm*-yes|xscale*-yes|sh*-yes|pxa*-yes) hc_cv_byte_structs_always_aligned_and_rounded=no ;; *) hc_cv_byte_structs_always_aligned_and_rounded=yes ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: results: byte structs are aligned/rounded by default... ${hc_cv_byte_structs_aligned_and_rounded_by_default} " >&5 $as_echo "$as_me: results: byte structs are aligned/rounded by default... ${hc_cv_byte_structs_aligned_and_rounded_by_default} " >&6;} if test "$hc_cv_byte_structs_always_aligned_and_rounded" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Size of structures are aligned/rounded and we don't know how to tell the compiler otherwise " >&5 $as_echo "ERROR: Size of structures are aligned/rounded and we don't know how to tell the compiler otherwise " >&6; } hc_error=yes fi #------------------------------# # Check if this is GCC 2.96 # #------------------------------# { $as_echo "$as_me:${as_lineno-$LINENO}: checking if this is the broken 2.96 version of GCC" >&5 $as_echo_n "checking if this is the broken 2.96 version of GCC... " >&6; } if ${hc_cv_is_gcc_2_96+:} false; then : $as_echo_n "(cached) " >&6 else if test "$GCC" = "yes"; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if __GNUC__ == 2 && __GNUC_MINOR__ == 96 yes; #else int no; #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : hc_cv_is_gcc_2_96=no else hc_cv_is_gcc_2_96=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else hc_cv_is_gcc_2_96=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_is_gcc_2_96" >&5 $as_echo "$hc_cv_is_gcc_2_96" >&6; } #----------------------------------------------# # Check C99 if flexible arrays are supported # #----------------------------------------------# # The logic to test whether C99 flexible # # arrays are supported is defined in the # # 'HC_C99_FLEXIBLE_ARRAYS' macro in the # # 'hercules.m4' file in the 'autoconf' sub- # # directory, and issues the AC_DEFINE for # # 'C99_FLEXIBLE_ARRAYS' if it's supported # # and also sets '$hc_cv_c99_flexible_array'. # #----------------------------------------------# { $as_echo "$as_me:${as_lineno-$LINENO}: checking C99 struct flexible arrays support" >&5 $as_echo_n "checking C99 struct flexible arrays support... " >&6; } if ${hc_cv_c99_flexible_array+:} false; then : $as_echo_n "(cached) " >&6 else # Initialize to unknown hc_cv_c99_flexible_array=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include typedef struct { int foo; char bar[]; } FOOBAR; int main () { int main(int argc, char *argv[]) { FOOBAR* p = calloc( 1, sizeof(FOOBAR) + 16 ); return 0; } ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : hc_cv_c99_flexible_array=yes else hc_cv_c99_flexible_array=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_c99_flexible_array" >&5 $as_echo "$hc_cv_c99_flexible_array" >&6; } if test "$hc_cv_c99_flexible_array" = "yes"; then $as_echo "#define C99_FLEXIBLE_ARRAYS 1" >>confdefs.h fi #--------------------------------------------------------# # Check if GCC supports '__attribute__ ((regparm(n)))' # #--------------------------------------------------------# # Note: even though at the moment GCC only supports regparm # on i386 or greater machines, that could change at any time # in the future so we don't bother checking for it. if test "$GCC" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether '__attribute__ ((regparm(n)))' is supported" >&5 $as_echo_n "checking whether '__attribute__ ((regparm(n)))' is supported... " >&6; } if ${hc_cv_regparm_attr_supported+:} false; then : $as_echo_n "(cached) " >&6 else hc_temp="$CFLAGS" CFLAGS="-Wall -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void conftest() __attribute__ ((regparm(1))); _ACEOF if ac_fn_c_try_compile "$LINENO"; then : hc_cv_regparm_attr_supported=yes else hc_cv_regparm_attr_supported=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$hc_temp" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_regparm_attr_supported" >&5 $as_echo "$hc_cv_regparm_attr_supported" >&6; } else hc_cv_regparm_attr_supported=no fi #---------------------------------------------------# # Test for GCC '__attribute__ ((regparm(3)))' bug # #---------------------------------------------------# if test "$GCC" = "yes" && test "$hc_cv_regparm_attr_supported" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether '__attribute__ ((regparm(3)))' is broken" >&5 $as_echo_n "checking whether '__attribute__ ((regparm(3)))' is broken... " >&6; } if ${hc_cv_regparm_attr_broke+:} false; then : $as_echo_n "(cached) " >&6 else hc_temp="$CFLAGS" CFLAGS="-O3 -fomit-frame-pointer" if test "$cross_compiling" = yes; then : hc_cv_regparm_attr_broke=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Fish: Test for reparms bug caused by alloca bug# 8750 Ref: */ struct REGS { int a, b, c, d; char e[50000]; }; typedef struct REGS REGS; #define ATTR_REGPARM __attribute__ (( regparm(3) )) int func1 ( int a, int b, int c, REGS *regs ) ATTR_REGPARM; int func2 ( int a, int b, int c, REGS *regs ) ATTR_REGPARM; REGS global_regs; int main() { return func1( 1, 2, 3, &global_regs ); } int ATTR_REGPARM func1 ( int a, int b, int c, REGS *regs ) { REGS stack_regs; regs=regs; /* (quiet compiler warning) */ if ( func2( a, b, c, &stack_regs ) == 0 ) return 0; /* pass */ return 1; /* fail */ } int ATTR_REGPARM func2 ( int a, int b, int c, REGS *regs ) { regs=regs; /* (quiet compiler warning) */ if ( 1==a && 2==b && 3==c ) return 0; /* pass */ return 1; /* fail */ } _ACEOF if ac_fn_c_try_run "$LINENO"; then : hc_cv_regparm_attr_broke=no else hc_cv_regparm_attr_broke=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$hc_temp" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_regparm_attr_broke" >&5 $as_echo "$hc_cv_regparm_attr_broke" >&6; } else hc_cv_regparm_attr_broke=no fi #------------------------------------------------------# # Test for GCC builtin alloca bug# 8750 # # # #------------------------------------------------------# if test "$GCC" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether '__builtin_alloca' is broken" >&5 $as_echo_n "checking whether '__builtin_alloca' is broken... " >&6; } if ${hc_cv_builtin_alloca_broke+:} false; then : $as_echo_n "(cached) " >&6 else hc_temp=$CFLAGS CFLAGS="-g -O2 -fomit-frame-pointer" if test "$cross_compiling" = yes; then : hc_cv_builtin_alloca_broke=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Fish: Test for gcc builtin alloca bug# 8750 Required(?!) (not sure) compiler options: -g -O2 -fomit-frame-pointer */ int foo () { char a[50000+16]; memset(a,0xCD,50000); a[50000]=0; return strlen(a); } int main() { return ( foo() != 50000 ); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : hc_cv_builtin_alloca_broke=no else hc_cv_builtin_alloca_broke=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS=$hc_temp fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_builtin_alloca_broke" >&5 $as_echo "$hc_cv_builtin_alloca_broke" >&6; } else hc_cv_builtin_alloca_broke=no fi #------------------------------------------------------------# # Check for OS X gcc preprocessor macro argument count bug # #------------------------------------------------------------# if test "$GCC" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether preprocessor macro argument counting broken" >&5 $as_echo_n "checking whether preprocessor macro argument counting broken... " >&6; } if ${hc_cv_pp_macro_arg_counting_broke+:} false; then : $as_echo_n "(cached) " >&6 else hc_temp="$CFLAGS" CFLAGS="-Wall -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #define MACRO(_x,_args...) printf(_x, ## _args) int main( int argc, char **argv, char **arge ) { MACRO( "bare printf\n" ); return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : hc_cv_pp_macro_arg_counting_broke=no else hc_cv_pp_macro_arg_counting_broke=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$hc_temp" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_pp_macro_arg_counting_broke" >&5 $as_echo "$hc_cv_pp_macro_arg_counting_broke" >&6; } else hc_cv_pp_macro_arg_counting_broke=no fi #------------------------------------------------------------# # Check if traditional preprocessor is the K&R C type... # #------------------------------------------------------------# # # Apple's latest GCC documentation reveals: # # ... the -traditional-cpp option has changed. # In Apple GCC 3.1 and earlier Apple GCC compilers, # -traditional-cpp was used to toggle between the # standard GNU GCC preprocessor and Apple's own # preprocessor, "cpp-precomp". The GNU GCC compiler # interpreted -traditional-cpp differently on all # other platforms. Since cpp-precomp has been removed # for Apple's GCC 3.3 compiler, the standard GNU # meaning of -traditional-cpp has been restored. By # default, the GCC 3.3 preprocessor conforms to the # ISO C standard. Using the -tradtional-cpp option # means the C preprocessor should instead try to # emulate the old "K&R C". # #------------------------------------------------------------# if test "$GCC" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether '-traditional-cpp' is K&R C preprocessor" >&5 $as_echo_n "checking whether '-traditional-cpp' is K&R C preprocessor... " >&6; } if ${hc_cv_traditional_cpp_is_K_AND_R_C_type+:} false; then : $as_echo_n "(cached) " >&6 else hc_temp="$CFLAGS" CFLAGS="-Wall -Werror -traditional-cpp" # Note: The test program MUST start in column 1! Otherwise, the compilation # will fail when it's not supposed to. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* If the following gets an error, then the "traditional" preprocessor is K&R C type. Otherwise if it compiles WITHOUT error the the "traditional" preprocessor is NOT the K&R C type. */ #if 1 #include // comment/etc... #endif int main( int, char**, char** ) { return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : hc_cv_traditional_cpp_is_K_AND_R_C_type=no else hc_cv_traditional_cpp_is_K_AND_R_C_type=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$hc_temp" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_traditional_cpp_is_K_AND_R_C_type" >&5 $as_echo "$hc_cv_traditional_cpp_is_K_AND_R_C_type" >&6; } else hc_cv_traditional_cpp_is_K_AND_R_C_type=no fi #-----------------------------------------------------------# # Check whether byte-swapping can be done using assembler # #-----------------------------------------------------------# { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte-swapping can be done using assembler " >&5 $as_echo_n "checking whether byte-swapping can be done using assembler ... " >&6; } # (use our own byteswap assembler routines are i486+ only) # use system's byteswap routines if present... case "$host_cpu" in i486|i586|i686|i786|x86_64) hc_cv_asm_byteswap=yes ;; *) hc_cv_asm_byteswap=$hc_cv_have_byteswap_h ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_asm_byteswap " >&5 $as_echo "$hc_cv_asm_byteswap " >&6; } #----------------------------------------------# # Check whether -pthread needed for pthreads # #----------------------------------------------# { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -pthread " >&5 $as_echo_n "checking whether ${CC-cc} accepts -pthread ... " >&6; } echo 'void f(){}' >conftest.c if test -z "`${CC-cc} -pthread -c conftest.c 2>&1`"; then hc_cv_dash_pthread_needed=yes else hc_cv_dash_pthread_needed=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_dash_pthread_needed " >&5 $as_echo "$hc_cv_dash_pthread_needed " >&6; } #------------------------------------------------------------------ # The logic to test whether optreset is needed for getopt use is # defined in the 'HC_CHECK_NEED_GETOPT_OPTRESET' macro in the # 'hercules.m4' file in the autoconf directory, and issues the # AC_DEFINE for 'NEED_GETOPT_OPTRESET' if it's needed (and also # sets the '$hc_cv_need_getopt_optreset' variable appropriately). #------------------------------------------------------------------ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether 'optreset' needed for 'getopt' use" >&5 $as_echo_n "checking whether 'optreset' needed for 'getopt' use... " >&6; } if ${hc_cv_need_getopt_optreset+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { extern int optreset; optreset=1; getopt(0,0,0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : hc_cv_need_getopt_optreset=yes else hc_cv_need_getopt_optreset=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_need_getopt_optreset" >&5 $as_echo "$hc_cv_need_getopt_optreset" >&6; } if test "$hc_cv_need_getopt_optreset" = "yes"; then $as_echo "#define NEED_GETOPT_OPTRESET 1" >>confdefs.h fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Checks for system services... ############################################################################### # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 $as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } if ${ac_cv_sys_largefile_source+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=no; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE 1 #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=1; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_cv_sys_largefile_source=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 $as_echo "$ac_cv_sys_largefile_source" >&6; } case $ac_cv_sys_largefile_source in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source _ACEOF ;; esac rm -rf conftest* # We used to try defining _XOPEN_SOURCE=500 too, to work around a bug # in glibc 2.1.3, but that breaks too many other things. # If you want fseeko and ftello with glibc, upgrade to a fixed glibc. if test $ac_cv_sys_largefile_source != unknown; then $as_echo "#define HAVE_FSEEKO 1" >>confdefs.h fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # AC_CONFIG_FILES( [file...] )... ############################################################################### cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Set flags according to user-specified --enable-xxxxx build options ############################################################################### # PROGRAMMING NOTE: some of these values default to previously determined # values (e.g. cckd-bzip2 for example defaults to whether libbz2 exists), # so this section MUST [unfortunately] come AFTER the above sections. This # does have the unfortunate side effect of not detecting invalid options # right away like one would normally expect/want. The only way around that # would be to perform two checks (one at the beginning and then one again # later on), but that approach was rejected since it would tend to make our # configure.ac script less clean (simple and straightforward). # Check whether --enable-dynamic-load was given. if test "${enable_dynamic_load+set}" = set; then : enableval=$enable_dynamic_load; case "${enableval}" in yes) hc_cv_opt_dynamic_load=yes ;; no) hc_cv_opt_dynamic_load=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'dynamic-load' option " >&5 $as_echo "ERROR: invalid 'dynamic-load' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_dynamic_load=yes fi # Check whether --enable-cckd-bzip2 was given. if test "${enable_cckd_bzip2+set}" = set; then : enableval=$enable_cckd_bzip2; case "${enableval}" in yes) hc_cv_opt_cckd_bzip2=yes ;; no) hc_cv_opt_cckd_bzip2=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'cckd-bzip2' option " >&5 $as_echo "ERROR: invalid 'cckd-bzip2' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_cckd_bzip2=$hc_cv_have_libbz2 fi # Check whether --enable-het-bzip2 was given. if test "${enable_het_bzip2+set}" = set; then : enableval=$enable_het_bzip2; case "${enableval}" in yes) hc_cv_opt_het_bzip2=yes ;; no) hc_cv_opt_het_bzip2=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'het-bzip2' option " >&5 $as_echo "ERROR: invalid 'het-bzip2' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_het_bzip2=$hc_cv_have_libbz2 fi # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; case "${enableval}" in yes) hc_cv_opt_debug=yes ;; no) hc_cv_opt_debug=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'debug' option " >&5 $as_echo "ERROR: invalid 'debug' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_debug=no fi # Check whether --enable-optimization was given. if test "${enable_optimization+set}" = set; then : enableval=$enable_optimization; hc_cv_opt_optimization=${enableval} else hc_cv_opt_optimization=yes fi # Check whether --enable-configsymbols was given. if test "${enable_configsymbols+set}" = set; then : enableval=$enable_configsymbols; case "${enableval}" in yes) hc_cv_opt_configsymbols=yes ;; no) hc_cv_opt_configsymbols=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'configsymbols' option " >&5 $as_echo "ERROR: invalid 'configsymbols' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_configsymbols=yes fi # Check whether --enable-enhanced-configsymbols was given. if test "${enable_enhanced_configsymbols+set}" = set; then : enableval=$enable_enhanced_configsymbols; case "${enableval}" in yes) hc_cv_opt_enhanced_configsymbols=yes ;; no) hc_cv_opt_enhanced_configsymbols=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'enhanced-configsymbols' option " >&5 $as_echo "ERROR: invalid 'enhanced-configsymbols' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_enhanced_configsymbols=yes fi # Check whether --enable-enhanced-configincludes was given. if test "${enable_enhanced_configincludes+set}" = set; then : enableval=$enable_enhanced_configincludes; case "${enableval}" in yes) hc_cv_opt_enhanced_configincludes=yes ;; no) hc_cv_opt_enhanced_configincludes=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'enhanced-configincludes' option " >&5 $as_echo "ERROR: invalid 'enhanced-configincludes' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_enhanced_configincludes=yes fi # Check whether --enable-automatic-operator was given. if test "${enable_automatic_operator+set}" = set; then : enableval=$enable_automatic_operator; case "${enableval}" in yes) hc_cv_opt_auto_oper=yes ;; no) hc_cv_opt_auto_oper=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'automatic-operator' option " >&5 $as_echo "ERROR: invalid 'automatic-operator' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_auto_oper=$hc_cv_have_regex_h fi # Check whether --enable-external-gui was given. if test "${enable_external_gui+set}" = set; then : enableval=$enable_external_gui; case "${enableval}" in yes) hc_cv_opt_external_gui=yes ;; no) hc_cv_opt_external_gui=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'external-gui' option " >&5 $as_echo "ERROR: invalid 'external-gui' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_external_gui=yes fi # Check whether --enable-fthreads was given. if test "${enable_fthreads+set}" = set; then : enableval=$enable_fthreads; case "${enableval}" in yes) hc_cv_opt_fthreads=yes ;; no) hc_cv_opt_fthreads=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'fthreads' option " >&5 $as_echo "ERROR: invalid 'fthreads' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_fthreads=$hc_cv_is_windows fi # Check whether --enable-multi-cpu was given. if test "${enable_multi_cpu+set}" = set; then : enableval=$enable_multi_cpu; case "${enableval}" in yes) hc_cv_opt_num_cpu_engines=8 ;; no) hc_cv_opt_num_cpu_engines=1 ;; *) if test 0 -lt "${enableval}" -a 128 -ge "${enableval}" then hc_cv_opt_num_cpu_engines=${enableval} else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'multi-cpu' option " >&5 $as_echo "ERROR: invalid 'multi-cpu' option " >&6; } hc_error=yes fi ;; esac else hc_cv_opt_num_cpu_engines=8 fi # Check whether --enable-capabilities was given. if test "${enable_capabilities+set}" = set; then : enableval=$enable_capabilities; case "${enableval}" in yes) hc_cv_opt_capabilities=yes ;; no) hc_cv_opt_capabilities=no ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: invalid 'capabilities' option " >&5 $as_echo "ERROR: invalid 'capabilities' option " >&6; } hc_error=yes ;; esac else hc_cv_opt_capabilities=hc_cv_have_sys_capability fi # only include libcap if needed if test "$hc_cv_opt_capabilities" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_set_proc in -lcap" >&5 $as_echo_n "checking for cap_set_proc in -lcap... " >&6; } if ${ac_cv_lib_cap_cap_set_proc+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcap $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char cap_set_proc (); int main () { return cap_set_proc (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_cap_cap_set_proc=yes else ac_cv_lib_cap_cap_set_proc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_set_proc" >&5 $as_echo "$ac_cv_lib_cap_cap_set_proc" >&6; } if test "x$ac_cv_lib_cap_cap_set_proc" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCAP 1 _ACEOF LIBS="-lcap $LIBS" fi fi # Force disable capabilities support if library is missing if test "$ac_cv_lib_cap_cap_set_proc" = "no"; then hc_cv_opt_capabilities="no" fi # Force disable capabilities support if sys/capability.h header is missing if test "$hc_cv_have_sys_capa_h" = "no"; then hc_cv_opt_capabilities="no" fi # Force disable capabilities support if sys/prctl.h header is missing if test "$hc_cv_have_sys_prctl_h" = "no"; then hc_cv_opt_capabilities="no" fi # Check whether --enable-custom was given. if test "${enable_custom+set}" = set; then : enableval=$enable_custom; hc_cv_opt_custom_build_str=${enableval} fi if test "$hc_cv_build_hercifc" = "yes"; then # Check whether --enable-setuid-hercifc was given. if test "${enable_setuid_hercifc+set}" = set; then : enableval=$enable_setuid_hercifc; case "${enableval}" in yes) hc_cv_opt_setuid_hercifc=yes ;; no) hc_cv_opt_setuid_hercifc=no ;; *) hc_cv_opt_setuid_hercifc=yes hc_cv_hercifc_groupname=${enableval} ;; esac else hc_cv_opt_setuid_hercifc=no fi hc_cv_setuid_hercifc=$hc_cv_opt_setuid_hercifc else hc_cv_setuid_hercifc=no fi #----------------------------------------------------------------- # The handling of AC_ARG_ENABLE for "--enable-getoptwrapper" # is defined within the 'HC_ARG_ENABLE_GETOPTWRAPPER' macro # coded in the 'hercules.m4' file in the autoconf directory # and issues the AC_DEFINE for NEED_GETOPT_WRAPPER if needed # (and sets the '$hc_cv_need_getopt_wrapper' variable too). #----------------------------------------------------------------- # Check whether --enable-getoptwrapper was given. if test "${enable_getoptwrapper+set}" = set; then : enableval=$enable_getoptwrapper; case "${enableval}" in yes) hc_cv_opt_getoptwrapper=yes ;; no) hc_cv_opt_getoptwrapper=no ;; auto) hc_cv_opt_getoptwrapper=auto ;; *) hc_cv_opt_getoptwrapper=auto ;; esac else hc_cv_opt_getoptwrapper=auto fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getopt wrapper kludge is necessary" >&5 $as_echo_n "checking whether getopt wrapper kludge is necessary... " >&6; } if test "$hc_cv_opt_getoptwrapper" != "auto"; then hc_cv_need_getopt_wrapper="$hc_cv_opt_getoptwrapper" hc_cv_need_getopt_wrapper_result_msg="$hc_cv_opt_getoptwrapper (forced)" else if test $(./libtool --features | fgrep "enable shared libraries" | wc -l) -ne 1; then # Libtool doesn't support shared libraries, # and thus our wrapper kludge is not needed. hc_cv_need_getopt_wrapper=no hc_cv_need_getopt_wrapper_result_msg=no else rm -f libconftest* rm -f .libs/libconftest* cat > conftest1.c << DUPGETOPT1 /* Test program that needs getopt, called by another program which itself needs getopt. Will the linker complain about duplicate symbols for getopt? We'll soon find out! */ extern char *optarg; extern int optind; int test1() { int i; char *c; i=optind; c=optarg; getopt(0,0,0); return 0; } DUPGETOPT1 cat > conftest2.c << DUPGETOPT2 /* Test program that not only needs getopt, but also calls another program which also needs getopt. Will linker complain about duplicate symbols for getopt? Let's see. */ extern char *optarg; extern int optind; extern int test2(); int test2() { int i; char *c; i=optind; c=optarg; getopt(0,0,0); test1(); return 0; } DUPGETOPT2 ./libtool --mode=compile ${CC-cc} conftest1.c -c -o conftest1.lo > /dev/null 2>&1 ./libtool --mode=compile ${CC-cc} conftest2.c -c -o conftest2.lo > /dev/null 2>&1 ./libtool --mode=link ${CC-cc} -shared -rpath /lib -no-undefined conftest1.lo -o libconftest1.la > /dev/null 2>&1 ./libtool --mode=link ${CC-cc} -shared -rpath /lib -no-undefined conftest2.lo libconftest1.la -o libconftest2.la > /dev/null 2>&1 if test $? = 0; then hc_cv_need_getopt_wrapper=no hc_cv_need_getopt_wrapper_result_msg=no else hc_cv_need_getopt_wrapper=yes hc_cv_need_getopt_wrapper_result_msg=yes fi rm -f *conftest* rm -f .libs/*conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_need_getopt_wrapper_result_msg" >&5 $as_echo "$hc_cv_need_getopt_wrapper_result_msg" >&6; } if test "$hc_cv_need_getopt_wrapper" = "yes"; then $as_echo "#define NEED_GETOPT_WRAPPER 1" >>confdefs.h fi #---------------------------------------------------------------- # Note: '$enable_shared' is automatically set by LIBTOOL, # unless the user overrides it via --disable-shared. #---------------------------------------------------------------- hc_cv_hdl_build_shared=$enable_shared cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Final default settings, final sanity / error checks... ############################################################################### if test "$hc_cv_build_hercifc" = "yes"; then if test "$hc_cv_have_linux_if_tun_h" != "yes"; then if test "$hc_cv_have_net_if_h" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required headers 'linux/if_tun.h' or 'net/if.h' not found " >&5 $as_echo "ERROR: Required headers 'linux/if_tun.h' or 'net/if.h' not found " >&6; } hc_error=yes fi fi if test "$hc_cv_have_net_route_h" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'net/route_h' not found " >&5 $as_echo "ERROR: Required header 'net/route_h' not found " >&6; } hc_error=yes fi fi #------------------------------------------------------------------------------ # signal.h is only required if strsignal function isn't available since if # the strsignal function isn't available, we use our builtin which needs it. # The presumption that if the strsignal function is found, then the signal.h # header will also be found seems to be a fairly safe assumption to make IMO. if test "$hc_cv_have_strsignal" != "yes" && test "$hc_cv_have_signal_h" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required header 'signal.h' not found " >&5 $as_echo "ERROR: Required header 'signal.h' not found " >&6; } hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_have_vsscanf" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: Required function 'vsscanf' not found " >&5 $as_echo "ERROR: Required function 'vsscanf' not found " >&6; } hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_have_inttypes_h" != "yes" && test "$hc_cv_have_u_int8_t" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: unable to find fixed-size data types " >&5 $as_echo "ERROR: unable to find fixed-size data types " >&6; } hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_cckd_bzip2" = "yes" || test "$hc_cv_opt_het_bzip2" = "yes"; then if test "$hc_cv_have_libbz2" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: bzip2 compression requested but libbz2 library not found " >&5 $as_echo "ERROR: bzip2 compression requested but libbz2 library not found " >&6; } hc_error=yes fi if test "$hc_cv_have_bzlib_h" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: bzip2 compression requested but 'bzlib.h' header not found " >&5 $as_echo "ERROR: bzip2 compression requested but 'bzlib.h' header not found " >&6; } hc_error=yes fi fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_dynamic_load" = "yes"; then if test "$hc_cv_have_lt_dlopen" != "yes" && test "$hc_cv_have_dlopen" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: dynamic-load requires libtool or dlltool " >&5 $as_echo "ERROR: dynamic-load requires libtool or dlltool " >&6; } hc_error=yes fi fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_auto_oper" = "yes" && test "$hc_cv_have_regex_h" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: automatic-operator requested but 'regex.h' header not found " >&5 $as_echo "ERROR: automatic-operator requested but 'regex.h' header not found " >&6; } hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_external_gui" = "yes" && test "$hc_cv_opt_dynamic_load" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: external-gui requires dynamic-load " >&5 $as_echo "ERROR: external-gui requires dynamic-load " >&6; } hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_fthreads" = "yes" && test "$hc_cv_is_windows" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: fthreads is only for Windows platforms " >&5 $as_echo "ERROR: fthreads is only for Windows platforms " >&6; } hc_error=yes fi if test "$hc_cv_have_pthread_h" != "yes" && test "$hc_cv_opt_fthreads" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: unable to find pthread.h " >&5 $as_echo "ERROR: unable to find pthread.h " >&6; } hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_is_apple" = "yes" && test "$hc_cv_pp_macro_arg_counting_broke" = "yes" && test "$hc_cv_traditional_cpp_is_K_AND_R_C_type" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ERROR: macro argument counting broken and cannot use -traditional-cpp option to work around it " >&5 $as_echo "ERROR: macro argument counting broken and cannot use -traditional-cpp option to work around it " >&6; } hc_error=yes fi #------------------------------------------------------------------------------ # If any errors have been detected, then abort the configure at this time #------------------------------------------------------------------------------ if test "$hc_error" != "no"; then as_fn_error $? "Please correct the above error(s) and try again " "$LINENO" 5 fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Act on the results of all of the above... ############################################################################### # AUTOMATIC DETERMINATION OF OPTIMIZATION FLAGS # # If they specified 'no' then don't optimize. # If they specified 'yes' then determine what flags we should use. # If they didn't specify, then optimize only if this is NOT a debug build. # Otherwise use whatever flags they specified as-is. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for what optimization flags to use " >&5 $as_echo_n "checking for what optimization flags to use ... " >&6; } case "$hc_cv_opt_optimization" in no) hc_cv_auto_optimize=no ;; yes) hc_cv_auto_optimize=yes ;; *) if test "x$hc_cv_opt_optimization" = "x"; then if test "$hc_cv_opt_debug" = "yes"; then hc_cv_auto_optimize=no else hc_cv_auto_optimize=yes fi else hc_cv_auto_optimize=no hc_cv_optimization_flags="$hc_cv_opt_optimization" fi ;; esac if test "$hc_cv_auto_optimize" = "yes"; then if test "$hc_cv_builtin_alloca_broke" != "yes" && test "$hc_cv_opt_debug" != "yes"; then hc_cv_optimization_flags="-O3" fi hc_cv_is_intel_x86_arch=no case "$host_cpu-$GCC" in x86_64-yes) hc_cv_is_intel_x86_arch=yes hc_cv_intel_cpu_type=k8 ;; i386-yes|i486-yes|i586-yes|i686-yes|i786-yes) hc_cv_is_intel_x86_arch=yes if test $host_cpu = i786; then hc_cv_intel_cpu_type=pentium4 else if test $host_cpu = i686 && test "hc_cv_is_gcc_2_96" = "yes"; then hc_cv_intel_cpu_type=i586 else hc_cv_intel_cpu_type=$host_cpu fi fi ;; arm-yes) hc_cv_is_intel_x86_arch=no hc_cv_optimization_flags="$hc_cv_optimization_flags -frename-registers" ;; xscale-yes|arm*-yes) hc_cv_is_intel_x86_arch=no hc_cv_optimization_flags="$hc_cv_optimization_flags -mcpu=$host_cpu -mtune=$host_cpu -frename-registers" ;; esac if test "$hc_cv_is_intel_x86_arch" = "yes"; then hc_cv_optimization_flags="$hc_cv_optimization_flags -march=$hc_cv_intel_cpu_type" if test "$hc_cv_builtin_alloca_broke" != "yes" && test "$hc_cv_opt_debug" != "yes"; then hc_cv_optimization_flags="$hc_cv_optimization_flags -fomit-frame-pointer" else hc_cv_optimization_flags="$hc_cv_optimization_flags -fno-omit-frame-pointer" fi fi hc_cv_optimization_flags="$hc_cv_optimization_flags -fno-strict-aliasing" fi if test "x$hc_cv_optimization_flags" = "x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: (none) " >&5 $as_echo "(none) " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_cv_optimization_flags " >&5 $as_echo "$hc_cv_optimization_flags " >&6; } fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # Set additional Warning options for the compiler ############################################################################### # Avoid warnings when the instruction decoders load unused register numbers # from the instruction, and also to avoid modifying decNumber and softfloat { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wno-unused-but-set-variable" >&5 $as_echo_n "checking whether compiler supports -Wno-unused-but-set-variable... " >&6; } if ${hc_have_unused_set_variable+:} false; then : $as_echo_n "(cached) " >&6 else hc_temp="$CFLAGS" CFLAGS="$CFLAGS -Werror -Wno-unused-but-set-variable" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : hc_have_unused_set_variable="yes" else hc_have_unused_set_variable="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$hc_temp" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_have_unused_set_variable" >&5 $as_echo "$hc_have_unused_set_variable" >&6; } if test "${hc_have_unused_set_variable}" = "yes"; then CFLAGS="$CFLAGS -Wno-unused-but-set-variable" fi # MSVC requires all declarations to be at the start of a block, whereas gcc # only issues a warning. This makes gcc flag mixed declarations as an error { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Werror=declaration-after-statement" >&5 $as_echo_n "checking whether compiler supports -Werror=declaration-after-statement... " >&6; } if ${hc_have_decl_after_stmt+:} false; then : $as_echo_n "(cached) " >&6 else hc_temp="$CFLAGS" CFLAGS="$CFLAGS -Werror -Werror=declaration-after-statement" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return(0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : hc_have_decl_after_stmt="yes" else hc_have_decl_after_stmt="no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$hc_temp" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hc_have_decl_after_stmt" >&5 $as_echo "$hc_have_decl_after_stmt" >&6; } if test "${hc_have_decl_after_stmt}" = "yes"; then CFLAGS="$CFLAGS -Werror=declaration-after-statement" fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ############################################################################### # DONE! -- Define our OUTPUT values and then exit... ############################################################################### #--------------------------------------------------------------# # (place only AC_DEFINE_UNQUOTED here; place AC_DEFINE below) # #--------------------------------------------------------------# if test "x$hc_cv_opt_custom_build_str" != "x"; then cat >>confdefs.h <<_ACEOF #define CUSTOM_BUILD_STRING "${hc_cv_opt_custom_build_str}" _ACEOF fi cat >>confdefs.h <<_ACEOF #define MAX_CPU_ENGINES ${hc_cv_opt_num_cpu_engines} _ACEOF cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache { $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 $as_echo "$as_me: " >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Package destination directory prefixes: " >&5 $as_echo "$as_me: Package destination directory prefixes: " >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 $as_echo "$as_me: " >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Libraries: ${modexecdir} " >&5 $as_echo "$as_me: Libraries: ${modexecdir} " >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Data: \$(datadir)/hercules " >&5 $as_echo "$as_me: Data: \$(datadir)/hercules " >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 $as_echo "$as_me: " >&6;} CPPFLAGS="$CPPFLAGS"' -DPKGDATADIR=\"$(pkgdatadir)\" -DMODULESDIR=\"$(modexecdir)\"' #---------------------------------------------------------------# # (place only AC_DEFINE here; place AC_DEFINE_UNQUOTED above) # #---------------------------------------------------------------# test "$hc_cv_opt_debug" = "yes" && $as_echo "#define DEBUG 1" >>confdefs.h test "$hc_cv_have_inttypes_h" = "yes" && $as_echo "#define HAVE_INTTYPES_H 1" >>confdefs.h test "$hc_cv_have_u_int8_t" = "yes" && $as_echo "#define HAVE_U_INT 1" >>confdefs.h test "$hc_cv_opt_configsymbols" = "yes" && $as_echo "#define OPTION_CONFIG_SYMBOLS 1" >>confdefs.h test "$hc_cv_opt_enhanced_configsymbols" = "yes" && $as_echo "#define OPTION_ENHANCED_CONFIG_SYMBOLS 1" >>confdefs.h test "$hc_cv_opt_enhanced_configincludes" = "yes" && $as_echo "#define OPTION_ENHANCED_CONFIG_INCLUDE 1" >>confdefs.h test "$hc_cv_opt_auto_oper" = "yes" && $as_echo "#define OPTION_HAO 1" >>confdefs.h test "$hc_cv_opt_dynamic_load" = "yes" && $as_echo "#define OPTION_DYNAMIC_LOAD 1" >>confdefs.h test "$hc_cv_opt_fthreads" = "yes" && $as_echo "#define OPTION_FTHREADS 1" >>confdefs.h test "$hc_cv_hdl_build_shared" = "yes" && $as_echo "#define HDL_BUILD_SHARED 1" >>confdefs.h test "$hc_cv_have_lt_dlopen" = "yes" && $as_echo "#define HDL_USE_LIBTOOL 1" >>confdefs.h test "$hc_cv_is_windows" = "yes" && $as_echo "#define WIN32 1" >>confdefs.h test "$hc_cv_opt_external_gui" = "yes" && $as_echo "#define EXTERNALGUI 1" >>confdefs.h test "$hc_cv_opt_cckd_bzip2" = "yes" && $as_echo "#define CCKD_BZIP2 1" >>confdefs.h test "$hc_cv_opt_het_bzip2" = "yes" && $as_echo "#define HET_BZIP2 1" >>confdefs.h test "$hc_cv_timespec_in_sys_types_h" = "yes" && $as_echo "#define TIMESPEC_IN_SYS_TYPES_H 1" >>confdefs.h test "$hc_cv_timespec_in_time_h" = "yes" && $as_echo "#define TIMESPEC_IN_TIME_H 1" >>confdefs.h test "$hc_cv_have_getset_uid" != "yes" && $as_echo "#define NO_SETUID 1" >>confdefs.h test "$hc_cv_asm_byteswap" != "yes" && $as_echo "#define NO_ASM_BYTESWAP 1" >>confdefs.h test "$hc_cv_non_unique_gettimeofday" = "yes" && $as_echo "#define NON_UNIQUE_GETTIMEOFDAY 1" >>confdefs.h test "$hc_cv_build_hercifc" = "yes" && $as_echo "#define BUILD_HERCIFC 1" >>confdefs.h test "$hc_cv_opt_capabilities" = "yes" && $as_echo "#define OPTION_CAPABILITIES 1" >>confdefs.h if test $hc_cv_have_sa_sigaction != yes || test $hc_cv_have_sigusr1 != yes || test $hc_cv_have_sigusr2 != yes || test $hc_cv_have_sigpipe != yes || test $hc_cv_have_sigbus != yes; then $as_echo "#define NO_SIGABEND_HANDLER 1" >>confdefs.h fi if test "$hc_cv_regparm_attr_supported" = "yes" && test "$hc_cv_regparm_attr_broke" != "yes"; then $as_echo "#define HAVE_ATTR_REGPARM 1" >>confdefs.h fi if test "$hc_cv_is_apple" = "yes"; then : # # TODO?? # # Do whatever is necessary to get the following symbol defined # so the included libltdl will be built and used... # ## AC_PROVIDE_AC_LIBTOOL_DLOPEN() fi #--------------------------------------------------# # CPPFLAGS (pre-processor flags) # #--------------------------------------------------# if test "$hc_cv_is_apple" = "yes" && test "$hc_cv_pp_macro_arg_counting_broke" = "yes"; then CPPFLAGS="${CPPFLAGS} -traditional-cpp -Wno-endif-labels" fi #--------------------------------------------------# # CFLAGS (compiler flags) # #--------------------------------------------------# if test "$hc_cv_is_windows" = "yes"; then if test "$hc_cv_have_pthread_h" = "yes" && test "x$hc_cv_alt_pthread_location" != "x"; then CFLAGS="$CFLAGS -I${hc_cv_alt_pthread_location}" fi CFLAGS="$CFLAGS -Wno-format" fi if test "$hc_cv_byte_structs_aligned_and_rounded_by_default" = "yes"; then #=============================================================== # the following requests 8-bit (byte) struct boundary alignment #=============================================================== CFLAGS="$CFLAGS -mstructure-size-boundary=8" fi test "x$hc_cv_optimization_flags" != "x" && CFLAGS="$CFLAGS $hc_cv_optimization_flags" #--------------------------------------------------# # LIBS (linker flags) # #--------------------------------------------------# test "$hc_cv_dash_pthread_needed" = "yes" && LIBS="$LIBS -pthread" test "$hc_cv_have_libbz2" = "yes" && LIBS="$LIBS -lbz2" # ---------------------- MINGW32 ---------------------- test "$hc_cv_is_mingw32" = "yes" && LIBS="$LIBS -lmsvcrt" test "$hc_cv_is_mingw32" = "yes" && LIBS="$LIBS -lws2_32" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache #--------------------------------------------------------------------------------# # Pass certain values/settings as makefile variables to automake (makefile.am) # #--------------------------------------------------------------------------------# if test "$hc_cv_opt_dynamic_load" = "yes" ; then OPTION_DYNAMIC_LOAD_TRUE= OPTION_DYNAMIC_LOAD_FALSE='#' else OPTION_DYNAMIC_LOAD_TRUE='#' OPTION_DYNAMIC_LOAD_FALSE= fi if test "$hc_cv_opt_fthreads" = "yes" ; then BUILD_FTHREADS_TRUE= BUILD_FTHREADS_FALSE='#' else BUILD_FTHREADS_TRUE='#' BUILD_FTHREADS_FALSE= fi if test "$hc_cv_build_hercifc" = "yes" ; then BUILD_HERCIFC_TRUE= BUILD_HERCIFC_FALSE='#' else BUILD_HERCIFC_TRUE='#' BUILD_HERCIFC_FALSE= fi if test "$hc_cv_setuid_hercifc" = "yes" ; then SETUID_HERCIFC_TRUE= SETUID_HERCIFC_FALSE='#' else SETUID_HERCIFC_TRUE='#' SETUID_HERCIFC_FALSE= fi if test "x$hc_cv_hercifc_groupname" != "x" ; then HERCIFC_GROUPSET_TRUE= HERCIFC_GROUPSET_FALSE='#' else HERCIFC_GROUPSET_TRUE='#' HERCIFC_GROUPSET_FALSE= fi if test "x$hc_cv_hercifc_groupname" != "x"; then HERCIFC_GROUPNAME=${hc_cv_hercifc_groupname} fi # Building of shared libraries is forced, and we force use of libtool too. if test "$hc_cv_hdl_build_shared" = "yes" ; then BUILD_SHARED_TRUE= BUILD_SHARED_FALSE='#' else BUILD_SHARED_TRUE='#' BUILD_SHARED_FALSE= fi if test "$hc_cv_is_windows" = "yes" ; then USE_DLLTOOL_TRUE= USE_DLLTOOL_FALSE='#' else USE_DLLTOOL_TRUE='#' USE_DLLTOOL_FALSE= fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache ac_config_files="$ac_config_files Makefile util/Makefile html/Makefile crypto/Makefile man/Makefile m4/Makefile decNumber/Makefile softfloat/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${INSTALL_LTDL_TRUE}" && test -z "${INSTALL_LTDL_FALSE}"; then as_fn_error $? "conditional \"INSTALL_LTDL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CONVENIENCE_LTDL_TRUE}" && test -z "${CONVENIENCE_LTDL_FALSE}"; then as_fn_error $? "conditional \"CONVENIENCE_LTDL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OPTION_DYNAMIC_LOAD_TRUE}" && test -z "${OPTION_DYNAMIC_LOAD_FALSE}"; then as_fn_error $? "conditional \"OPTION_DYNAMIC_LOAD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_FTHREADS_TRUE}" && test -z "${BUILD_FTHREADS_FALSE}"; then as_fn_error $? "conditional \"BUILD_FTHREADS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_HERCIFC_TRUE}" && test -z "${BUILD_HERCIFC_FALSE}"; then as_fn_error $? "conditional \"BUILD_HERCIFC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SETUID_HERCIFC_TRUE}" && test -z "${SETUID_HERCIFC_FALSE}"; then as_fn_error $? "conditional \"SETUID_HERCIFC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HERCIFC_GROUPSET_TRUE}" && test -z "${HERCIFC_GROUPSET_FALSE}"; then as_fn_error $? "conditional \"HERCIFC_GROUPSET\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_SHARED_TRUE}" && test -z "${BUILD_SHARED_FALSE}"; then as_fn_error $? "conditional \"BUILD_SHARED\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_DLLTOOL_TRUE}" && test -z "${USE_DLLTOOL_FALSE}"; then as_fn_error $? "conditional \"USE_DLLTOOL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;; "html/Makefile") CONFIG_FILES="$CONFIG_FILES html/Makefile" ;; "crypto/Makefile") CONFIG_FILES="$CONFIG_FILES crypto/Makefile" ;; "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; "m4/Makefile") CONFIG_FILES="$CONFIG_FILES m4/Makefile" ;; "decNumber/Makefile") CONFIG_FILES="$CONFIG_FILES decNumber/Makefile" ;; "softfloat/Makefile") CONFIG_FILES="$CONFIG_FILES softfloat/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ############################################################################### # (end-of-file) ############################################################################### hercules-3.12/configure.ac0000664000175000017500000021372112622153562012474 00000000000000############################################################################### # CONFIGURE.AC: Process this file with AutoConf to produce a configure script. ############################################################################### # $Id$ # AC is AutoConfigure, AM is AutoMake, and AH is AutoHeader. The # 'HC_XXXX..' macros are custom Hercules autoconf macros defined # in the 'hercules.m4' file in the 'autoconf' subdirectory. AC_INIT(hercules.h) # (package, version, bugreport email, etc) AC_REVISION($Revision$) # (the version of this configure.ac) AC_CONFIG_AUX_DIR(autoconf) # (directory containing auxillary build tools) AM_INIT_AUTOMAKE(hercules,3.12) # (the version of our software package) AM_CONFIG_HEADER(config.h) # (the file the resulting configure script will produce) AM_MAINTAINER_MODE() AC_CANONICAL_HOST() # (sets $host_cpu, $host_vendor, and $host_os) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) ############################################################################### # Programs section... ############################################################################### # Set CFLAGS first to override the AC_PROG_CC default setting CFLAGS="$CFLAGS -W -Wall" AC_PROG_CC() # (set CC to the name of the compiler) # ----------------------------------------------------------------------------- # PROGRAMMING NOTE: The below 'AC_SUBST' macro causes AC_OUTPUT to replace # all instances of "@xxxxxx@" in input files with the value that the shell # variable "xxxxxx" has when AC_OUTPUT is called. However, we setup a define # for source files (MODULESDIR) and a variable for make ($(modexecdir)). Any # other usage should be avoided. # ----------------------------------------------------------------------------- modexecdir='$(libdir)/$(PACKAGE)' AC_SUBST(modexecdir) # ----------------------------------------------------------------------------- # # AC_LIBTOOL_DLOPEN # # Enable checking for dlopen support. This macro should be used if the # package makes use of the '-dlopen' and '-dlpreopen' flags, otherwise # libtool will assume that the system does not support dlopening. The # macro must be called before AC_PROG_LIBTOOL. # # ----------------------------------------------------------------------------- AC_LIBTOOL_DLOPEN() # (we need libtool's dlopen support) # ----------------------------------------------------------------------------- # # AC_LIBTOOL_WIN32_DLL # # This macro should be used if the package has been ported to build # clean dlls on win32 platforms. Usually this means that any library # data items are exported with __declspec(dllexport) and imported with # __declspec(dllimport). If this macro is not used, libtool will assume # that the package libraries are not dll clean and will build only static # libraries on win32 hosts. # # This macro must be called before AC_PROG_LIBTOOL, and provision must # be made to pass '-no-undefined' to libtool in link mode from the package # Makefile. Naturally, if you pass '-no-undefined', you must ensure that # all the library symbols really are defined at link time! # # ----------------------------------------------------------------------------- AC_LIBTOOL_WIN32_DLL() # (we need Win32 support in libtool) # ----------------------------------------------------------------------------- # See: 'AC_PROG_LIBTOOL' below. # ----------------------------------------------------------------------------- AC_DISABLE_STATIC() # (forces libtool to build shared # libraries instead of static ones) # ----------------------------------------------------------------------------- # AC_PROG_LIBTOOL # # Add support for the '--enable-shared' and '--disable-shared' # configure flags. By default, this macro turns on shared libraries # if they are available, and also enables static libraries if they # don't conflict with the shared libraries. You can modify these # defaults by calling either the AC_DISABLE_SHARED or AC_DISABLE_STATIC # macros. # # Hercules REQUIRES shared libraries (i.e. DLLs), so we do indeed use # the AC_DISABLE_STATIC macro above. # # ----------------------------------------------------------------------------- AC_PROG_LIBTOOL() # (we build libtool for ourselves) # ----------------------------------------------------------------------------- # # AC_LIB_LTDL # # Even though libltdl is installed together with libtool, you may wish # to include libltdl in the distribution of your package, for the convenience # of users of your package that don't have libtool or libltdl installed. # # The most simplistic way to add libltdl to your package is to copy the # source files, 'ltdl.c' and 'ltdl.h', to a source directory withing your # package and to build and link them along with the rest of your sources. # # To do this, you must add a call to the 'AC_LIB_LTDL' macro to your package's # 'configure.in' to perform the required configure time checks in order that # 'ltdl.o' is built correctly. # # This method does have its problems though: if you try to link the package # binaries with an installed libltdl, or a library which depends on libltdl, # you may have problems with duplicate symbol definitions. # # In order to enable this flavor of libltdl, you should add the line # 'AC_LIBLTDL_CONVENIENCE' to your `configure.in', before 'AC_PROG_LIBTOOL'. # # In order to select the installable version of libltdl, you should add a # call of the macro 'AC_LIBLTDL_INSTALLABLE' to your 'configure.in' before # 'AC_PROG_LIBTOOL'. This macro will check whether libltdl is already # installed and, if not, request the libltdl embedded in your package to be # built and installed. # # Whatever macro you use, it is up to you to ensure that your 'configure.in' # will configure libltdl, using 'AC_CONFIG_SUBDIRS', and that your 'Makefile's # will start sub-makes within libltdl's directory, using automake's SUBDIRS, # for example. Both macros define the shell variables LIBLTDL, to the link flag # that you should use to link with libltdl, and LTDLINCL, to the preprocessor # flag that you should use to compile with programs that include 'ltdl.h'. It # is up to you to use 'AC_SUBST' to ensure that this variable will be available # in 'Makefile's, or add them to variables that are 'AC_SUBST'ed by default, # such as LIBS and CPPFLAGS. # # So, when you want to link a program with libltdl, be it a convenience, # installed or installable library, just compile with '$(LTDLINCL)' and link # it with '$(LIBLTDL)', using libtool. # # You should probably also add 'AC_LIBTOOL_DLOPEN' to your 'configure.in' before # 'AC_PROG_LIBTOOL', otherwise libtool will assume no dlopening mechanism is # supported, and revert to dlpreopening, which is probably not what you want. # # The following example shows you how to embed the convenience libltdl # in your package. In order to use the installable variant just replace # 'AC_LIBLTDL_CONVENIENCE' with 'AC_LIBLTDL_INSTALLABLE'. We assume that libltdl # was embedded using 'libtoolize --ltdl': # # configure.in: # # ... # dnl Enable building of the convenience library # dnl and set LIBLTDL accordingly # AC_LIBLTDL_CONVENIENCE # dnl Substitute LTDLINCL and LIBLTDL in the Makefiles # AC_SUBST(LTDLINCL) # AC_SUBST(LIBLTDL) # dnl Check for dlopen support # AC_LIBTOOL_DLOPEN # dnl Configure libtool # AC_PROG_LIBTOOL # dnl Configure libltdl # AC_CONFIG_SUBDIRS(libltdl) # ... # # Makefile.am: # # ... # SUBDIRS = libltdl # # INCLUDES = $(LTDLINCL) # # myprog_LDFLAGS = -export-dynamic # # The quotes around -dlopen below fool automake <= 1.4 into accepting it # myprog_LDADD = $(LIBLTDL) "-dlopen" self "-dlopen" foo1.la # myprog_DEPENDENCIES = $(LIBLTDL) foo1.la # ... # # ----------------------------------------------------------------------------- AC_LIB_LTDL() # (we need the ltdl libtool library) AC_SUBST([LIBTOOL_DEPS]) # (see PROGRAMMING NOTE above) # ----------------------------------------------------------------------------- # (See comments in the 'AC_CHECK_LIB' Libraries section further below) # ----------------------------------------------------------------------------- AC_MSG_NOTICE( [(use of lt_dlopen forced by Hercules Dynamic Loader requirement)] ) AS_IF([test "x${with_included_ltdl}" = "xno"], [hc_cv_have_lt_dlopen=no], [hc_cv_have_lt_dlopen=yes]) AS_IF([test "x${ac_cv_func_dlopen}" = "xyes" -o "x${ac_cv_lib_dl_dlopen}" = "xyes"], [hc_cv_have_dlopen=yes], [hc_cv_have_dlopen=no]) HC_LD_DISALLOWDUPS() # (add duplicate symbols option to LDFLAGS) # ----------------------------------------------------------------------------- # The following is a "global error" flag used to defer aborting configure # until after ALL errors have been detected/reported. # ----------------------------------------------------------------------------- hc_error=no ############################################################################### # Autoheader templates ############################################################################### # All AC_DEFINE() macros used within autoconf (to define pre-processor vars # used during the actual build process) must have corresponding AH_TEMPLATE # statements coded somewhere. We place them all here simply for convenience. AH_TEMPLATE( [CUSTOM_BUILD_STRING], [Define to provide additional information about this build] ) AH_TEMPLATE( [MAX_CPU_ENGINES], [Defines the maximum number of emulated CPU engines] ) AH_TEMPLATE( [DEBUG], [Define to enable extra debugging code (TRACE/VERIFY/ASSERT macros)] ) AH_TEMPLATE( [C99_FLEXIBLE_ARRAYS], [Define if your gcc properly supports C99 flexible arrays] ) AH_TEMPLATE( [HAVE_ATTR_REGPARM], [Define if your gcc properly supports __attribute__((regparm(n)))] ) AH_TEMPLATE( [NO_ASM_BYTESWAP], [Define to disable assembler routines for byte swapping] ) AH_TEMPLATE( [NO_SETUID], [Define to disable setuid operation] ) AH_TEMPLATE( [NO_SIGABEND_HANDLER], [Define to disable sigabend_handler (please describe this better)] ) AH_TEMPLATE( [NON_UNIQUE_GETTIMEOFDAY], [Define if 'gettimeofday' returns non-unique values] ) AH_TEMPLATE( [NEED_GETOPT_WRAPPER], [Define to indicate a wrapper for getopt is needed] ) AH_TEMPLATE( [NEED_GETOPT_OPTRESET], [Define to indicate optreset exists] ) AH_TEMPLATE( [HAVE_INTTYPES_H], [Define if inttypes.h header file is present on your system] ) AH_TEMPLATE( [HAVE_U_INT], [Define if your system uses u_int8_t, etc, instead of uint8_t] ) AH_TEMPLATE( [OPTION_CONFIG_SYMBOLS], [Define to enable symbolic substitutions in configuration file] ) AH_TEMPLATE( [OPTION_ENHANCED_CONFIG_SYMBOLS], [Define to enable enhanced-mode symbolic substitutions in configuration file] ) AH_TEMPLATE( [OPTION_ENHANCED_CONFIG_INCLUDE], [Define to enable enhanced-mode 'include' file support in configuration file] ) AH_TEMPLATE( [OPTION_HAO], [Define to enable Hercules Automatic Operator feature] ) AH_TEMPLATE( [OPTION_DYNAMIC_LOAD], [Define to enable Hercules Dynamic Loader feature] ) AH_TEMPLATE( [HDL_BUILD_SHARED], [Define to indicate shared libraries are being used] ) AH_TEMPLATE( [HDL_USE_LIBTOOL], [Define to cause dynamic loader to use libtool instead of dlopen] ) AH_TEMPLATE( [BUILD_HERCIFC], [Define if hercifc program is to be built] ) AH_TEMPLATE( [WIN32], [Define when building under Win32 (MinGW or Cygwin)] ) AH_TEMPLATE( [EXTERNALGUI], [Define to build interface to external Windows GUI] ) AH_TEMPLATE( [OPTION_FTHREADS], [Define to use included threads implementation (fthreads)] ) AH_TEMPLATE( [TIMESPEC_IN_TIME_H], [Define if 'struct timespec' defined in ] ) AH_TEMPLATE( [TIMESPEC_IN_SYS_TYPES_H], [Define if 'struct timespec' defined in ] ) AH_TEMPLATE( [_BSD_SOCKLEN_T_], [Define missing macro on apple darwin (osx) platform] ) AH_TEMPLATE( [CCKD_BZIP2], [Define to enable bzip2 compression in emulated DASDs] ) AH_TEMPLATE( [HET_BZIP2], [Define to enable bzip2 compression in emulated tapes] ) AH_TEMPLATE( [OPTION_CAPABILITIES], [Define to enable posix draft 1003.1e capabilities] ) ############################################################################### # OS-specific settings that we can't figure out any other way (yet) ############################################################################### # # Determine what type of host we're building on... # case "$host_os" in linux*) hc_cv_is_nix=yes hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no ;; mingw*) hc_cv_is_nix=no hc_cv_is_windows=yes hc_cv_is_mingw32=yes hc_cv_is_apple=no ;; cygwin*) hc_cv_is_nix=no hc_cv_is_windows=yes hc_cv_is_mingw32=no hc_cv_is_apple=no ;; darwin*) if test $host_vendor = apple; then hc_cv_is_nix=no hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=yes else hc_cv_is_nix=no hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no fi ;; *bsd*) hc_cv_is_nix=yes hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no ;; *) hc_cv_is_nix=no hc_cv_is_windows=no hc_cv_is_mingw32=no hc_cv_is_apple=no ;; esac #------------------------------------------------------# # Hard-coded host-operating-system-specific settings # # that we have no other/easy way to figure out... # #------------------------------------------------------# if test "$hc_cv_is_nix" = "yes"; then hc_cv_build_hercifc=yes hc_cv_non_unique_gettimeofday=no elif test "$hc_cv_is_windows" = "yes"; then hc_cv_build_hercifc=no hc_cv_non_unique_gettimeofday=yes elif test "$hc_cv_is_apple" = "yes"; then hc_cv_build_hercifc=yes hc_cv_non_unique_gettimeofday=no else hc_cv_build_hercifc=no hc_cv_non_unique_gettimeofday=no fi ############################################################################### # Checks for REQUIRED (non-optional) header files... ############################################################################### # PROGRAMMING NOTE: We use 'AC_CHECK_HEADER' here (singular) since we don't # care whether 'HAVE_XXX' gets #defined or not since, because these are re- # quired headers, if any of them are not found, we abort and thus we don't # need to have any 'HAVE_XXX' pre-processor #defined entered into config.h # (because we can't build Herc at all if any of them don't happen to exist) AC_CHECK_HEADER( ctype.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'ctype.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( errno.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'errno.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( fcntl.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'fcntl.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( limits.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'limits.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( setjmp.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'setjmp.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( stdarg.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'stdarg.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( stdio.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'stdio.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( stdlib.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'stdlib.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( string.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'string.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( time.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'time.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( unistd.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'unistd.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( sys/stat.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'sys/stat.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( sys/time.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'sys/time.h' not found] ); hc_error=yes ] ) AC_CHECK_HEADER( sys/types.h, [], [ AC_MSG_RESULT( [ERROR: Required header 'sys/types.h' not found] ); hc_error=yes ] ) # PROGRAMMING NOTE: the pthread.h header only required if this is not # an fthreads build. Thus we delay aborting until later once we know # (if this is a windows build; otherwise we abort right away) AC_CHECK_HEADER( pthread.h, [hc_cv_have_pthread_h=yes], [ if test "$hc_cv_is_windows" = "yes"; then hc_cv_alt_pthread_location=/usr/Pthreads AC_MSG_NOTICE( [looking for pthread.h in ${hc_cv_alt_pthread_location}] ) hc_temp=$CFLAGS CFLAGS="$CFLAGS -I${hc_cv_alt_pthread_location}" AC_CHECK_HEADER( pthread.h, [hc_cv_have_pthread_h=yes], [hc_cv_have_pthread_h=no] ) CFLAGS=$hc_temp else AC_MSG_RESULT( [ERROR: Required header 'pthread.h' not found] ) hc_error=yes fi ] ) AC_CACHE_SAVE() ############################################################################### # Checks for optional (non-required) header files... ############################################################################### # PROGRAMMING NOTE: We use 'AC_CHECK_HEADERS' here (plural) to cause autoconf # to automatically add a #define/#undef 'HAVE_XXX' statement into config.h to # let us know whether the header exists on this system or not (since, because # these are optional headers, we are still able to successfully build Herc if # they don't happen to exist). The 'hc_cv_have_xxx' variables are only defined # in case other parts of configure.ac need to know whether the header exists # or not without having to do their own AC_CHECK_HEADERS (since we've already # done it). #------------------------------------------------------------------------------ # PROGRAMMING NOTE: on Darwin sys/socket.h must be included before # net/if.h, net/route.h, or netinet/in.h can be #included, and on OS X 10.3 # (but not 10.4) sys/types.h must be #included before sys/socket.h. Thus # the below four header checks are treated specially. If we ever drop support # for OS X 10.3, a lot of this cruft can be removed, not just here but # anywhere we find ourselves manually including sys/types.h. # PROGRAMMING NOTE: on *BSD sys/socket.h must be included before net/if.h, # net/route.h, or netinet/in.h can be #included. AC_CHECK_HEADERS( sys/socket.h, [hc_cv_have_sys_socket_h=yes], [hc_cv_have_sys_socket_h=no], [ #include ] ) AC_CHECK_HEADERS( net/if.h, [hc_cv_have_net_if_h=yes], [hc_cv_have_net_if_h=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_HEADERS( netinet/in.h, [hc_cv_have_netinet_in_h=yes], [hc_cv_have_netinet_in_h=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_HEADERS( netinet/tcp.h, [hc_cv_have_netinet_tcp_h=yes], [hc_cv_have_netinet_tcp_h=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_HEADERS( net/route.h, [hc_cv_have_net_route_h=yes], [hc_cv_have_net_route_h=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) #------------------------------------------------------------------------------ AC_CHECK_HEADERS( arpa/inet.h, [hc_cv_have_arpa_inet_h=yes], [hc_cv_have_arpa_inet_h=no] ) AC_CHECK_HEADERS( linux/if_tun.h, [hc_cv_have_linux_if_tun_h=yes], [hc_cv_have_linux_if_tun_h=no] ) AC_CHECK_HEADERS( sys/ioctl.h, [hc_cv_have_sys_ioctl_h=yes], [hc_cv_have_sys_ioctl_h=no] ) AC_CHECK_HEADERS( sys/mman.h, [hc_cv_have_sys_mman_h=yes], [hc_cv_have_sys_mman_h=no] ) #------------------------------------------------------------------------------ # PROGRAMMING NOTE: on *BSD systems sys/param.h must be #included before # sys/mount.h as it contains the #define of NGROUPS. AC_CHECK_HEADERS( sys/param.h, [hc_cv_have_sys_param_h=yes], [hc_cv_have_sys_param_h=no] ) AC_CHECK_HEADERS( sys/mount.h, [hc_cv_have_sys_mount_h=yes], [hc_cv_have_sys_mount_h=no], [ #if HAVE_SYS_PARAM_H #include #endif ] ) #------------------------------------------------------------------------------ AC_CHECK_HEADERS( sys/mtio.h, [hc_cv_have_sys_mtio_h=yes], [hc_cv_have_sys_mtio_h=no] ) AC_CHECK_HEADERS( sys/resource.h, [hc_cv_have_sys_resource_h=yes], [hc_cv_have_sys_resource_h=no] ) AC_CHECK_HEADERS( sys/uio.h, [hc_cv_have_sys_uio_h=yes], [hc_cv_have_sys_uio_h=no] ) AC_CHECK_HEADERS( sys/utsname.h, [hc_cv_have_sys_utsname_h=yes], [hc_cv_have_sys_utsname_h=no] ) AC_CHECK_HEADERS( sys/wait.h, [hc_cv_have_sys_wait_h=yes], [hc_cv_have_sys_wait_h=no] ) AC_CHECK_HEADERS( sys/un.h, [hc_cv_have_sys_un_h=yes], [hc_cv_have_sys_un_h=no] ) AC_CHECK_HEADERS( byteswap.h, [hc_cv_have_byteswap_h=yes], [hc_cv_have_byteswap_h=no] ) AC_CHECK_HEADERS( bzlib.h, [hc_cv_have_bzlib_h=yes], [hc_cv_have_bzlib_h=no] ) AC_CHECK_HEADERS( dlfcn.h, [hc_cv_have_dlfcn_h=yes], [hc_cv_have_dlfcn_h=no] ) AC_CHECK_HEADERS( inttypes.h, [hc_cv_have_inttypes_h=yes], [hc_cv_have_inttypes_h=no] ) AC_CHECK_HEADERS( iconv.h, [hc_cv_have_iconv_h=yes], [hc_cv_have_iconv_h=no] ) AC_CHECK_HEADERS( ltdl.h, [hc_cv_have_ltdl_h=yes], [hc_cv_have_ltdl_h=no] ) AC_CHECK_HEADERS( malloc.h, [hc_cv_have_malloc_h=yes], [hc_cv_have_malloc_h=no] ) AC_CHECK_HEADERS( math.h, [hc_cv_have_math_h=yes], [hc_cv_have_math_h=no] ) AC_CHECK_HEADERS( netdb.h, [hc_cv_have_netdb_h=yes], [hc_cv_have_netdb_h=no] ) AC_CHECK_HEADERS( pwd.h, [hc_cv_have_pwd_h=yes], [hc_cv_have_pwd_h=no] ) AC_CHECK_HEADERS( regex.h, [hc_cv_have_regex_h=yes], [hc_cv_have_regex_h=no] ) AC_CHECK_HEADERS( sched.h, [hc_cv_have_sched_h=yes], [hc_cv_have_sched_h=no] ) AC_CHECK_HEADERS( signal.h, [hc_cv_have_signal_h=yes], [hc_cv_have_signal_h=no] ) AC_CHECK_HEADERS( termios.h, [hc_cv_have_termios_h=yes], [hc_cv_have_termios_h=no] ) AC_CHECK_HEADERS( time.h, [hc_cv_have_time_h=yes], [hc_cv_have_time_h=no] ) AC_CHECK_HEADERS( zlib.h, [hc_cv_have_zlib_h=yes], [hc_cv_have_zlib_h=no] ) AC_CHECK_HEADERS( sys/capability.h, [hc_cv_have_sys_capa_h=yes], [hc_cv_have_sys_capa_h=no] ) AC_CHECK_HEADERS( sys/prctl.h, [hc_cv_have_sys_prctl_h=yes], [hc_cv_have_sys_prctl_h=no] ) AC_CACHE_SAVE() ############################################################################### # Checks for declarations... ############################################################################### # PROGRAMMING NOTE: For declaration checks, you need to be careful to use the # following test in your program: # # #if defined(HAVE_DECL_XXXX) && !HAVE_DECL_XXXXX # ...code to handle not declared case... # #endif # # This is because UNLIKE other 'AC_CHECK' macros, when a SYMBOL isn't DECLared, # "HAVE_DECL_XXXX" is #defined to '0' instead of leaving "HAVE_DECL_XXXX" #undefined. # (e.g. #defined to 1 if you have the declaration and #defined to 0 if you don't) AC_CHECK_DECLS( SIGUSR1, [hc_cv_have_sigusr1=yes], [hc_cv_have_sigusr1=no], [#include ] ) AC_CHECK_DECLS( SIGUSR2, [hc_cv_have_sigusr2=yes], [hc_cv_have_sigusr2=no], [#include ] ) AC_CHECK_DECLS( SIGPIPE, [hc_cv_have_sigpipe=yes], [hc_cv_have_sigpipe=no], [#include ] ) AC_CHECK_DECLS( SIGBUS, [hc_cv_have_sigbus=yes], [hc_cv_have_sigbus=no], [#include ] ) AC_CHECK_DECLS( IFNAMSIZ, [hc_cv_have_ifnamsiz=yes], [hc_cv_have_ifnamsiz=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_DECLS( LOGIN_NAME_MAX, [hc_cv_have_login_name_max=yes], [hc_cv_have_login_name_max=no], [#include ] ) AC_CHECK_DECLS( _SC_NPROCESSORS_CONF, [hc_cv_have_sc_nprocessors_conf=yes], [hc_cv_have_sc_nprocessors_conf=no], [#include ] ) AC_CHECK_DECLS( _SC_NPROCESSORS_ONLN, [hc_cv_have_sc_nprocessors_onln=yes], [hc_cv_have_sc_nprocessors_onln=no], [#include ] ) AC_CHECK_DECLS( SIOCSIFNETMASK, [hc_cv_have_siocsifnetmask=yes], [hc_cv_have_siocsifnetmask=no], [#include ] ) AC_CHECK_DECLS( SIOCSIFHWADDR, [hc_cv_have_siocsifhwaddr=yes], [hc_cv_have_siocsifhwaddr=no], [#include ] ) AC_CHECK_DECLS( SIOCADDRT, [hc_cv_have_siocaddrt=yes], [hc_cv_have_siocaddrt=no], [#include ] ) AC_CHECK_DECLS( SIOCDELRT, [hc_cv_have_siocdelrt=yes], [hc_cv_have_siocdelrt=no], [#include ] ) AC_CHECK_DECLS( SIOCDIFADDR, [hc_cv_have_siocdifaddr=yes], [hc_cv_have_siocdifaddr=no], [#include ] ) if test "$hc_cv_have_sys_mtio_h" == "yes"; then AC_CHECK_DECLS( MTEWARN, [hc_cv_have_mtewarn=yes], [hc_cv_have_mtewarn=no], [#include ] ) else hc_cv_have_mtewarn=no fi AC_CACHE_SAVE() ############################################################################### # Checks for types... ############################################################################### AC_CHECK_TYPES( u_int8_t, [hc_cv_have_u_int8_t=yes], [hc_cv_have_u_int8_t=no] ) AC_CHECK_TYPES( useconds_t, [hc_cv_have_useconds_t=yes], [hc_cv_have_useconds_t=no] ) AC_CHECK_TYPES( id_t, [hc_cv_have_id_t=yes], [hc_cv_have_id_t=no] ) AC_CHECK_TYPES( u_char, [hc_cv_have_u_char=yes], [hc_cv_have_u_char=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_TYPES( u_short, [hc_cv_have_u_short=yes], [hc_cv_have_u_short=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_TYPES( u_int, [hc_cv_have_u_int=yes], [hc_cv_have_u_int=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_TYPES( u_long, [hc_cv_have_u_long=yes], [hc_cv_have_u_long=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CHECK_TYPES( in_addr_t, [hc_cv_have_in_addr_t=yes], [hc_cv_have_in_addr_t=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif ] ) AC_CHECK_TYPES( socklen_t, [hc_cv_have_socklen_t=yes], [hc_cv_have_socklen_t=no], [ #include #if HAVE_SYS_SOCKET_H #include #endif ] ) AC_CACHE_SAVE() ############################################################################### # Checks for libraries... ############################################################################### # PROGRAMMING NOTE: we require libtool (or, optionally, dlltool (a less power- # ful (flexible) libtool-like tool for Windows platforms) in order to support # OPTION_DYNAMIC_LOAD. This is a relatively safe requirement since we provide # a version of libtool with Hercules (and build it as part of the preliminary # autoconf processing; see the 'Programs' section above). However, we need to # keep the below check for 'dlopen' anyway since we prefer that libtool use it # instead of its own equivalent (lt_dlopen) if it's available. AC_CHECK_LIB( msvcrt, _pipe ) AC_CHECK_LIB( dl, dlopen ) AC_CHECK_LIB( m, sqrt ) AC_CHECK_LIB( socket, connect ) AC_CHECK_LIB( nsl, gethostbyname ) AC_CHECK_LIB( resolv, inet_aton ) AC_CHECK_LIB( z, uncompress ) AC_CHECK_LIB( bz2, BZ2_bzBuffToBuffDecompress, [ hc_cv_have_libbz2=yes ], [ hc_cv_have_libbz2=no ] ) AC_CHECK_LIB( iconv, iconv ) # jbs 10/15/2003 Solaris requires -lrt for sched_yield() and fdatasync() AC_CHECK_LIB( rt, sched_yield ) # rbowler 2008/03/10 rev 1.196 Solaris 2.9 requires -lpthread AC_CHECK_LIB( pthread,pthread_create ) AC_CACHE_SAVE() ############################################################################### # Checks for library functions... ############################################################################### # PROGRAMMING NOTE: AC_CHECK_LIB should be called first for the below # library function checks to ensure the library where the function is # defined gets added to the LIBS library search variable... ############################################################################### AC_CHECK_FUNCS( iconv ) AC_CHECK_FUNCS( memrchr ) AC_CHECK_FUNCS( getopt_long ) AC_CHECK_FUNCS( sqrtl ldexpl fabsl fmodl frexpl ) AC_CHECK_FUNCS( ldexpf frexpf fabsf rint ) AC_CHECK_FUNCS( strlcpy strlcat ) AC_CHECK_FUNCS( strerror_r ) AC_CHECK_FUNCS( strsignal, [hc_cv_have_strsignal=yes], [hc_cv_have_strsignal=no] ) AC_CHECK_FUNCS( sys_siglist ) AC_CHECK_FUNCS( InitializeCriticalSectionAndSpinCount ) AC_CHECK_FUNCS( sleep usleep nanosleep ) AC_CHECK_FUNCS( sched_yield ) AC_CHECK_FUNCS( strtok_r ) AC_CHECK_FUNCS( pipe ) AC_CHECK_FUNCS( gettimeofday ) AC_CHECK_FUNCS( getpgrp ) AC_CHECK_FUNCS( scandir alphasort ) AC_CHECK_FUNCS( getlogin getlogin_r ) AC_CHECK_FUNCS( realpath ) AC_CHECK_FUNCS( fdatasync fsync ftruncate ) AC_CHECK_FUNCS( inet_aton ) AC_CHECK_FUNCS( fork socketpair ) AC_CHECK_FUNCS( sysconf ) AC_CHECK_FUNCS( vsscanf, [hc_cv_have_vsscanf=yes], [hc_cv_have_vsscanf=no] ) AC_CHECK_FUNCS( setresuid getresuid, [hc_cv_have_getset_uid=yes], [hc_cv_have_getset_uid=no; break] ) if test "$hc_cv_have_getset_uid" != "yes"; then AC_CHECK_FUNCS( setreuid geteuid getuid, [hc_cv_have_getset_uid=yes], [hc_cv_have_getset_uid=no; break] ) fi # FIXME: Disabled because some builtin ffs seem to be causing a problem. # (gcc 3.4 barfs on certain 'march=' settings?) #AC_CHECK_FUNCS( ffs ) # For OS X 10.6 autoconf defines HAVE_FDATASYNC even though there is # no function prototype declared for fdatasync() and unistd.h contains # define _POSIX_SYNCHRONIZED_IO (-1) which indicates that fdatasync is # not supported. So to decide whether fdatasync really can be used, we # create a new symbol HAVE_FDATASYNC_SUPPORTED which is defined only if # HAVE_FDATASYNC is defined and _POSIX_SYNCHRONIZED_IO is not negative. AC_CACHE_CHECK([whether fdatasync is supported],[ac_cv_func_fdatasync_supported],[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]],[[ #if !defined(HAVE_FDATASYNC) #error fdatasync is not defined on this platform #endif #if defined(_POSIX_SYNCHRONIZED_IO) && (_POSIX_SYNCHRONIZED_IO+0 < 0) #error fdatasync is not supported on this platform #endif ]])], [ac_cv_func_fdatasync_supported=yes], [ac_cv_func_fdatasync_supported=no]) ]) AS_IF([test "x${ac_cv_func_fdatasync_supported}" = "xyes"], [AC_DEFINE([HAVE_FDATASYNC_SUPPORTED],[1],[Define to 1 if the fdatasync function is supported.])]) AC_CACHE_SAVE() ############################################################################### # Checks for structures and structure members... ############################################################################### AC_CHECK_MEMBERS( [struct sockaddr_in.sin_len], [hc_cv_have_sockaddr_in_sin_len=yes ], [hc_cv_have_sockaddr_in_sin_len=no ], [ #include #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif ] ) AC_CHECK_MEMBERS( [struct in_addr.s_addr], [hc_cv_have_in_addr_s_addr=yes ], [hc_cv_have_in_addr_s_addr=no ], [ #include #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif ] ) AC_CHECK_MEMBERS( [struct sigaction.sa_sigaction], [hc_cv_have_sa_sigaction=yes ], [hc_cv_have_sa_sigaction=no ], [#include ] ) AC_CHECK_MEMBERS( [struct timespec.tv_nsec], [ hc_cv_timespec_in_sys_types_h=yes hc_cv_timespec_in_time_h=no ], [ AC_CHECK_MEMBERS( [struct timespec.tv_nsec], [ hc_cv_timespec_in_sys_types_h=no hc_cv_timespec_in_time_h=yes ], [ hc_cv_timespec_in_sys_types_h=no hc_cv_timespec_in_time_h=no ], [#include ] ) ], [#include ] ) AC_CACHE_SAVE() ############################################################################### # Checks for compiler characteristics... ############################################################################### AC_C_BIGENDIAN() # PROGRAMMING NOTE: Okay, this is stupid. If there are any trailing spaces # following the type we're checking the size of, then they're converted to # underscores in the 'SIZEOF_XXXX' that gets #defined! For example, doing a # AC_CHECK_SIZEOF( int ) yields: #define SIZEOF_INT____ 4 !!!!!!!!!!!!! # So... the below AC_CHECK_SIZEOF macros must NOT have any spaces in them!! AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(int *) AC_CHECK_SIZEOF(off_t) #----------------------------------# # Structure alignment/size test # #----------------------------------# AC_MSG_NOTICE( [begin check: whether byte structs are aligned/rounded by default...] ) cat > conftest.h << __EOF #include struct bytestruct { unsigned char a; }; __EOF AC_CHECK_SIZEOF( struct bytestruct, [], [#include "conftest.h"] ) if test "$ac_cv_sizeof_struct_bytestruct" = "1"; then hc_cv_byte_structs_aligned_and_rounded_by_default=no hc_cv_byte_structs_always_aligned_and_rounded=no else # The sizeof our test structure is not '1'. # The compiler is rounding the size of the # structure upward to some predefined value. hc_cv_byte_structs_aligned_and_rounded_by_default=yes # If there's no way to request the compiler # to not do that, then we can't build Herc. case "$host_cpu-$GCC" in arm*-yes|xscale*-yes|sh*-yes|pxa*-yes) hc_cv_byte_structs_always_aligned_and_rounded=no ;; *) hc_cv_byte_structs_always_aligned_and_rounded=yes ;; esac fi AC_MSG_NOTICE( [results: byte structs are aligned/rounded by default... ${hc_cv_byte_structs_aligned_and_rounded_by_default}] ) if test "$hc_cv_byte_structs_always_aligned_and_rounded" = "yes"; then AC_MSG_RESULT( [ERROR: Size of structures are aligned/rounded and we don't know how to tell the compiler otherwise] ) hc_error=yes fi #------------------------------# # Check if this is GCC 2.96 # #------------------------------# AC_CACHE_CHECK( [if this is the broken 2.96 version of GCC], [hc_cv_is_gcc_2_96], [ if test "$GCC" = "yes"; then AC_COMPILE_IFELSE( [ #if __GNUC__ == 2 && __GNUC_MINOR__ == 96 yes; #else int no; #endif ], [hc_cv_is_gcc_2_96=no], [hc_cv_is_gcc_2_96=yes] ) else hc_cv_is_gcc_2_96=no fi ] ) #----------------------------------------------# # Check C99 if flexible arrays are supported # #----------------------------------------------# # The logic to test whether C99 flexible # # arrays are supported is defined in the # # 'HC_C99_FLEXIBLE_ARRAYS' macro in the # # 'hercules.m4' file in the 'autoconf' sub- # # directory, and issues the AC_DEFINE for # # 'C99_FLEXIBLE_ARRAYS' if it's supported # # and also sets '$hc_cv_c99_flexible_array'. # #----------------------------------------------# HC_C99_FLEXIBLE_ARRAYS() #--------------------------------------------------------# # Check if GCC supports '__attribute__ ((regparm(n)))' # #--------------------------------------------------------# # Note: even though at the moment GCC only supports regparm # on i386 or greater machines, that could change at any time # in the future so we don't bother checking for it. if test "$GCC" = "yes"; then AC_CACHE_CHECK( [whether '__attribute__ ((regparm(n)))' is supported], [hc_cv_regparm_attr_supported], [ hc_temp="$CFLAGS" CFLAGS="-Wall -Werror" AC_COMPILE_IFELSE( [ void conftest() __attribute__ ((regparm(1))); ], [hc_cv_regparm_attr_supported=yes], [hc_cv_regparm_attr_supported=no] ) CFLAGS="$hc_temp" ] ) else hc_cv_regparm_attr_supported=no fi #---------------------------------------------------# # Test for GCC '__attribute__ ((regparm(3)))' bug # #---------------------------------------------------# if test "$GCC" = "yes" && test "$hc_cv_regparm_attr_supported" = "yes"; then AC_CACHE_CHECK( [whether '__attribute__ ((regparm(3)))' is broken], [hc_cv_regparm_attr_broke], [ hc_temp="$CFLAGS" CFLAGS="-O3 -fomit-frame-pointer" AC_TRY_RUN( [ /* Fish: Test for reparms bug caused by alloca bug# 8750 Ref: */ struct REGS { int a, b, c, d; char e[50000]; }; typedef struct REGS REGS; #define ATTR_REGPARM __attribute__ (( regparm(3) )) int func1 ( int a, int b, int c, REGS *regs ) ATTR_REGPARM; int func2 ( int a, int b, int c, REGS *regs ) ATTR_REGPARM; REGS global_regs; int main() { return func1( 1, 2, 3, &global_regs ); } int ATTR_REGPARM func1 ( int a, int b, int c, REGS *regs ) { REGS stack_regs; regs=regs; /* (quiet compiler warning) */ if ( func2( a, b, c, &stack_regs ) == 0 ) return 0; /* pass */ return 1; /* fail */ } int ATTR_REGPARM func2 ( int a, int b, int c, REGS *regs ) { regs=regs; /* (quiet compiler warning) */ if ( 1==a && 2==b && 3==c ) return 0; /* pass */ return 1; /* fail */ } ], [hc_cv_regparm_attr_broke=no], [hc_cv_regparm_attr_broke=yes], [hc_cv_regparm_attr_broke=yes] ) CFLAGS="$hc_temp" ] ) else hc_cv_regparm_attr_broke=no fi #------------------------------------------------------# # Test for GCC builtin alloca bug# 8750 # # # #------------------------------------------------------# if test "$GCC" = "yes"; then AC_CACHE_CHECK( [whether '__builtin_alloca' is broken], [hc_cv_builtin_alloca_broke], [ hc_temp=$CFLAGS CFLAGS="-g -O2 -fomit-frame-pointer" AC_TRY_RUN( [ /* Fish: Test for gcc builtin alloca bug# 8750 Required(?!) (not sure) compiler options: -g -O2 -fomit-frame-pointer */ int foo () { char a[50000+16]; memset(a,0xCD,50000); a[50000]=0; return strlen(a); } int main() { return ( foo() != 50000 ); } ], [hc_cv_builtin_alloca_broke=no], [hc_cv_builtin_alloca_broke=yes], [hc_cv_builtin_alloca_broke=yes] ) CFLAGS=$hc_temp ] ) else hc_cv_builtin_alloca_broke=no fi #------------------------------------------------------------# # Check for OS X gcc preprocessor macro argument count bug # #------------------------------------------------------------# if test "$GCC" = "yes"; then AC_CACHE_CHECK( [whether preprocessor macro argument counting broken], [hc_cv_pp_macro_arg_counting_broke], [ hc_temp="$CFLAGS" CFLAGS="-Wall -Werror" AC_COMPILE_IFELSE( [ #include #define MACRO(_x,_args...) printf(_x, ## _args) int main( int argc, char **argv, char **arge ) { MACRO( "bare printf\n" ); return 0; } ], [hc_cv_pp_macro_arg_counting_broke=no], [hc_cv_pp_macro_arg_counting_broke=yes] ) CFLAGS="$hc_temp" ] ) else hc_cv_pp_macro_arg_counting_broke=no fi #------------------------------------------------------------# # Check if traditional preprocessor is the K&R C type... # #------------------------------------------------------------# # # Apple's latest GCC documentation reveals: # # ... the -traditional-cpp option has changed. # In Apple GCC 3.1 and earlier Apple GCC compilers, # -traditional-cpp was used to toggle between the # standard GNU GCC preprocessor and Apple's own # preprocessor, "cpp-precomp". The GNU GCC compiler # interpreted -traditional-cpp differently on all # other platforms. Since cpp-precomp has been removed # for Apple's GCC 3.3 compiler, the standard GNU # meaning of -traditional-cpp has been restored. By # default, the GCC 3.3 preprocessor conforms to the # ISO C standard. Using the -tradtional-cpp option # means the C preprocessor should instead try to # emulate the old "K&R C". # #------------------------------------------------------------# if test "$GCC" = "yes"; then AC_CACHE_CHECK( [whether '-traditional-cpp' is K&R C preprocessor], [hc_cv_traditional_cpp_is_K_AND_R_C_type], [ hc_temp="$CFLAGS" CFLAGS="-Wall -Werror -traditional-cpp" # Note: The test program MUST start in column 1! Otherwise, the compilation # will fail when it's not supposed to. AC_COMPILE_IFELSE( [ /* If the following gets an error, then the "traditional" preprocessor is K&R C type. Otherwise if it compiles WITHOUT error the the "traditional" preprocessor is NOT the K&R C type. */ #if 1 #include // comment/etc... #endif int main( int, char**, char** ) { return 0; } ], [hc_cv_traditional_cpp_is_K_AND_R_C_type=no], [hc_cv_traditional_cpp_is_K_AND_R_C_type=yes] ) CFLAGS="$hc_temp" ] ) else hc_cv_traditional_cpp_is_K_AND_R_C_type=no fi #-----------------------------------------------------------# # Check whether byte-swapping can be done using assembler # #-----------------------------------------------------------# AC_MSG_CHECKING( [whether byte-swapping can be done using assembler] ) # (use our own byteswap assembler routines are i486+ only) # use system's byteswap routines if present... case "$host_cpu" in i486|i586|i686|i786|x86_64) hc_cv_asm_byteswap=yes ;; *) hc_cv_asm_byteswap=$hc_cv_have_byteswap_h ;; esac AC_MSG_RESULT( [$hc_cv_asm_byteswap] ) #----------------------------------------------# # Check whether -pthread needed for pthreads # #----------------------------------------------# AC_MSG_CHECKING( [whether ${CC-cc} accepts -pthread] ) echo 'void f(){}' >conftest.c if test -z "`${CC-cc} -pthread -c conftest.c 2>&1`"; then hc_cv_dash_pthread_needed=yes else hc_cv_dash_pthread_needed=no fi AC_MSG_RESULT( [$hc_cv_dash_pthread_needed] ) #------------------------------------------------------------------ # The logic to test whether optreset is needed for getopt use is # defined in the 'HC_CHECK_NEED_GETOPT_OPTRESET' macro in the # 'hercules.m4' file in the autoconf directory, and issues the # AC_DEFINE for 'NEED_GETOPT_OPTRESET' if it's needed (and also # sets the '$hc_cv_need_getopt_optreset' variable appropriately). #------------------------------------------------------------------ HC_CHECK_NEED_GETOPT_OPTRESET() AC_CACHE_SAVE() ############################################################################### # Checks for system services... ############################################################################### AC_SYS_LARGEFILE() AC_TYPE_OFF_T() AC_FUNC_FSEEKO() AC_CACHE_SAVE() ############################################################################### # AC_CONFIG_FILES( [file...] )... ############################################################################### AC_CACHE_SAVE() ############################################################################### # Set flags according to user-specified --enable-xxxxx build options ############################################################################### # PROGRAMMING NOTE: some of these values default to previously determined # values (e.g. cckd-bzip2 for example defaults to whether libbz2 exists), # so this section MUST [unfortunately] come AFTER the above sections. This # does have the unfortunate side effect of not detecting invalid options # right away like one would normally expect/want. The only way around that # would be to perform two checks (one at the beginning and then one again # later on), but that approach was rejected since it would tend to make our # configure.ac script less clean (simple and straightforward). AC_ARG_ENABLE( dynamic-load, AC_HELP_STRING([--disable-dynamic-load], [disable dynamic loader option] ), [ case "${enableval}" in yes) hc_cv_opt_dynamic_load=yes ;; no) hc_cv_opt_dynamic_load=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'dynamic-load' option] ) hc_error=yes ;; esac ], [hc_cv_opt_dynamic_load=yes] ) AC_ARG_ENABLE( cckd-bzip2, AC_HELP_STRING( [--enable-cckd-bzip2], [enable bzip2 compression for emulated dasd] ), [ case "${enableval}" in yes) hc_cv_opt_cckd_bzip2=yes ;; no) hc_cv_opt_cckd_bzip2=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'cckd-bzip2' option] ) hc_error=yes ;; esac ], [hc_cv_opt_cckd_bzip2=$hc_cv_have_libbz2] ) AC_ARG_ENABLE( het-bzip2, AC_HELP_STRING( [--enable-het-bzip2], [enable bzip2 compression for emulated tapes] ), [ case "${enableval}" in yes) hc_cv_opt_het_bzip2=yes ;; no) hc_cv_opt_het_bzip2=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'het-bzip2' option] ) hc_error=yes ;; esac ], [hc_cv_opt_het_bzip2=$hc_cv_have_libbz2] ) AC_ARG_ENABLE( debug, AC_HELP_STRING( [--enable-debug], [enable debugging (TRACE/VERIFY/ASSERT macros)] ), [ case "${enableval}" in yes) hc_cv_opt_debug=yes ;; no) hc_cv_opt_debug=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'debug' option] ) hc_error=yes ;; esac ], [hc_cv_opt_debug=no] ) AC_ARG_ENABLE( optimization, AC_HELP_STRING( [--enable-optimization=yes|no|FLAGS], [enable automatic optimization, or specify flags] ), [ hc_cv_opt_optimization=${enableval} ], [hc_cv_opt_optimization=yes] ) AC_ARG_ENABLE( configsymbols, AC_HELP_STRING( [--disable-configsymbols], [disable symbolic substitutions in configuration file] ), [ case "${enableval}" in yes) hc_cv_opt_configsymbols=yes ;; no) hc_cv_opt_configsymbols=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'configsymbols' option] ) hc_error=yes ;; esac ], [hc_cv_opt_configsymbols=yes] ) AC_ARG_ENABLE( enhanced-configsymbols, AC_HELP_STRING( [--disable-enhanced-configsymbols], [disable enhanced-mode symbolic substitutions in configuration file] ), [ case "${enableval}" in yes) hc_cv_opt_enhanced_configsymbols=yes ;; no) hc_cv_opt_enhanced_configsymbols=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'enhanced-configsymbols' option] ) hc_error=yes ;; esac ], [hc_cv_opt_enhanced_configsymbols=yes] ) AC_ARG_ENABLE( enhanced-configincludes, AC_HELP_STRING( [--disable-enhanced-configincludes], [disable enhanced-mode 'include' file support in configuration file] ), [ case "${enableval}" in yes) hc_cv_opt_enhanced_configincludes=yes ;; no) hc_cv_opt_enhanced_configincludes=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'enhanced-configincludes' option] ) hc_error=yes ;; esac ], [hc_cv_opt_enhanced_configincludes=yes] ) AC_ARG_ENABLE( automatic-operator, AC_HELP_STRING( [--disable-automatic-operator], [disable Hercules Automatic Operator feature] ), [ case "${enableval}" in yes) hc_cv_opt_auto_oper=yes ;; no) hc_cv_opt_auto_oper=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'automatic-operator' option] ) hc_error=yes ;; esac ], [hc_cv_opt_auto_oper=$hc_cv_have_regex_h] ) AC_ARG_ENABLE( external-gui, AC_HELP_STRING( [--disable-external-gui], [disable external GUI interface] ), [ case "${enableval}" in yes) hc_cv_opt_external_gui=yes ;; no) hc_cv_opt_external_gui=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'external-gui' option] ) hc_error=yes ;; esac ], [hc_cv_opt_external_gui=yes] ) AC_ARG_ENABLE( fthreads, AC_HELP_STRING( [--disable-fthreads], [disable use of fish threads instead of posix threads] ), [ case "${enableval}" in yes) hc_cv_opt_fthreads=yes ;; no) hc_cv_opt_fthreads=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'fthreads' option] ) hc_error=yes ;; esac ], [hc_cv_opt_fthreads=$hc_cv_is_windows] ) AC_ARG_ENABLE( multi-cpu, AC_HELP_STRING( [--enable-multi-cpu=yes|no|NUMBER], [enable/disable multi-cpu support (1-128, default 8)] ), [ case "${enableval}" in yes) hc_cv_opt_num_cpu_engines=8 ;; no) hc_cv_opt_num_cpu_engines=1 ;; *) if test 0 -lt "${enableval}" -a 128 -ge "${enableval}" then hc_cv_opt_num_cpu_engines=${enableval} else AC_MSG_RESULT( [ERROR: invalid 'multi-cpu' option] ) hc_error=yes fi ;; esac ], [hc_cv_opt_num_cpu_engines=8] ) AC_ARG_ENABLE( capabilities, AC_HELP_STRING([--disable-capabilities], [disable fine grained privileges] ), [ case "${enableval}" in yes) hc_cv_opt_capabilities=yes ;; no) hc_cv_opt_capabilities=no ;; *) AC_MSG_RESULT( [ERROR: invalid 'capabilities' option] ) hc_error=yes ;; esac ], [hc_cv_opt_capabilities=hc_cv_have_sys_capability] ) # only include libcap if needed if test "$hc_cv_opt_capabilities" = "yes"; then AC_CHECK_LIB(cap,cap_set_proc) fi # Force disable capabilities support if library is missing if test "$ac_cv_lib_cap_cap_set_proc" = "no"; then hc_cv_opt_capabilities="no" fi # Force disable capabilities support if sys/capability.h header is missing if test "$hc_cv_have_sys_capa_h" = "no"; then hc_cv_opt_capabilities="no" fi # Force disable capabilities support if sys/prctl.h header is missing if test "$hc_cv_have_sys_prctl_h" = "no"; then hc_cv_opt_capabilities="no" fi AC_ARG_ENABLE( custom, AC_HELP_STRING( [--enable-custom=STRING], [provide a custom description for this build] ), [ hc_cv_opt_custom_build_str=${enableval} ] ) if test "$hc_cv_build_hercifc" = "yes"; then AC_ARG_ENABLE( setuid-hercifc, AC_HELP_STRING( [--enable-setuid-hercifc=yes|no|GROUPNAME], [install hercifc as setuid root, and allow execution by users in group GROUPNAME] ), [ case "${enableval}" in yes) hc_cv_opt_setuid_hercifc=yes ;; no) hc_cv_opt_setuid_hercifc=no ;; *) hc_cv_opt_setuid_hercifc=yes hc_cv_hercifc_groupname=${enableval} ;; esac ], [hc_cv_opt_setuid_hercifc=no] ) hc_cv_setuid_hercifc=$hc_cv_opt_setuid_hercifc else hc_cv_setuid_hercifc=no fi #----------------------------------------------------------------- # The handling of AC_ARG_ENABLE for "--enable-getoptwrapper" # is defined within the 'HC_ARG_ENABLE_GETOPTWRAPPER' macro # coded in the 'hercules.m4' file in the autoconf directory # and issues the AC_DEFINE for NEED_GETOPT_WRAPPER if needed # (and sets the '$hc_cv_need_getopt_wrapper' variable too). #----------------------------------------------------------------- HC_ARG_ENABLE_GETOPTWRAPPER() #---------------------------------------------------------------- # Note: '$enable_shared' is automatically set by LIBTOOL, # unless the user overrides it via --disable-shared. #---------------------------------------------------------------- hc_cv_hdl_build_shared=$enable_shared AC_CACHE_SAVE() ############################################################################### # Final default settings, final sanity / error checks... ############################################################################### if test "$hc_cv_build_hercifc" = "yes"; then if test "$hc_cv_have_linux_if_tun_h" != "yes"; then if test "$hc_cv_have_net_if_h" != "yes"; then AC_MSG_RESULT( [ERROR: Required headers 'linux/if_tun.h' or 'net/if.h' not found] ) hc_error=yes fi fi if test "$hc_cv_have_net_route_h" != "yes"; then AC_MSG_RESULT( [ERROR: Required header 'net/route_h' not found] ) hc_error=yes fi fi #------------------------------------------------------------------------------ # signal.h is only required if strsignal function isn't available since if # the strsignal function isn't available, we use our builtin which needs it. # The presumption that if the strsignal function is found, then the signal.h # header will also be found seems to be a fairly safe assumption to make IMO. if test "$hc_cv_have_strsignal" != "yes" && test "$hc_cv_have_signal_h" != "yes"; then AC_MSG_RESULT( [ERROR: Required header 'signal.h' not found] ) hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_have_vsscanf" != "yes"; then AC_MSG_RESULT( [ERROR: Required function 'vsscanf' not found] ) hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_have_inttypes_h" != "yes" && test "$hc_cv_have_u_int8_t" != "yes"; then AC_MSG_RESULT( [ERROR: unable to find fixed-size data types] ) hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_cckd_bzip2" = "yes" || test "$hc_cv_opt_het_bzip2" = "yes"; then if test "$hc_cv_have_libbz2" != "yes"; then AC_MSG_RESULT( [ERROR: bzip2 compression requested but libbz2 library not found] ) hc_error=yes fi if test "$hc_cv_have_bzlib_h" != "yes"; then AC_MSG_RESULT( [ERROR: bzip2 compression requested but 'bzlib.h' header not found] ) hc_error=yes fi fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_dynamic_load" = "yes"; then if test "$hc_cv_have_lt_dlopen" != "yes" && test "$hc_cv_have_dlopen" != "yes"; then AC_MSG_RESULT( [ERROR: dynamic-load requires libtool or dlltool] ) hc_error=yes fi fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_auto_oper" = "yes" && test "$hc_cv_have_regex_h" != "yes"; then AC_MSG_RESULT( [ERROR: automatic-operator requested but 'regex.h' header not found] ) hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_external_gui" = "yes" && test "$hc_cv_opt_dynamic_load" != "yes"; then AC_MSG_RESULT( [ERROR: external-gui requires dynamic-load] ) hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_opt_fthreads" = "yes" && test "$hc_cv_is_windows" != "yes"; then AC_MSG_RESULT( [ERROR: fthreads is only for Windows platforms] ) hc_error=yes fi if test "$hc_cv_have_pthread_h" != "yes" && test "$hc_cv_opt_fthreads" != "yes"; then AC_MSG_RESULT( [ERROR: unable to find pthread.h] ) hc_error=yes fi #------------------------------------------------------------------------------ if test "$hc_cv_is_apple" = "yes" && test "$hc_cv_pp_macro_arg_counting_broke" = "yes" && test "$hc_cv_traditional_cpp_is_K_AND_R_C_type" = "yes"; then AC_MSG_RESULT( [ERROR: macro argument counting broken and cannot use -traditional-cpp option to work around it] ) hc_error=yes fi #------------------------------------------------------------------------------ # If any errors have been detected, then abort the configure at this time #------------------------------------------------------------------------------ if test "$hc_error" != "no"; then AC_MSG_ERROR( [Please correct the above error(s) and try again] ) fi AC_CACHE_SAVE() ############################################################################### # Act on the results of all of the above... ############################################################################### # AUTOMATIC DETERMINATION OF OPTIMIZATION FLAGS # # If they specified 'no' then don't optimize. # If they specified 'yes' then determine what flags we should use. # If they didn't specify, then optimize only if this is NOT a debug build. # Otherwise use whatever flags they specified as-is. AC_MSG_CHECKING( [for what optimization flags to use] ) case "$hc_cv_opt_optimization" in no) hc_cv_auto_optimize=no ;; yes) hc_cv_auto_optimize=yes ;; *) if test "x$hc_cv_opt_optimization" = "x"; then if test "$hc_cv_opt_debug" = "yes"; then hc_cv_auto_optimize=no else hc_cv_auto_optimize=yes fi else hc_cv_auto_optimize=no hc_cv_optimization_flags="$hc_cv_opt_optimization" fi ;; esac if test "$hc_cv_auto_optimize" = "yes"; then if test "$hc_cv_builtin_alloca_broke" != "yes" && test "$hc_cv_opt_debug" != "yes"; then hc_cv_optimization_flags="-O3" fi hc_cv_is_intel_x86_arch=no case "$host_cpu-$GCC" in x86_64-yes) hc_cv_is_intel_x86_arch=yes hc_cv_intel_cpu_type=k8 ;; i386-yes|i486-yes|i586-yes|i686-yes|i786-yes) hc_cv_is_intel_x86_arch=yes if test $host_cpu = i786; then hc_cv_intel_cpu_type=pentium4 else if test $host_cpu = i686 && test "hc_cv_is_gcc_2_96" = "yes"; then hc_cv_intel_cpu_type=i586 else hc_cv_intel_cpu_type=$host_cpu fi fi ;; arm-yes) hc_cv_is_intel_x86_arch=no hc_cv_optimization_flags="$hc_cv_optimization_flags -frename-registers" ;; xscale-yes|arm*-yes) hc_cv_is_intel_x86_arch=no hc_cv_optimization_flags="$hc_cv_optimization_flags -mcpu=$host_cpu -mtune=$host_cpu -frename-registers" ;; esac if test "$hc_cv_is_intel_x86_arch" = "yes"; then hc_cv_optimization_flags="$hc_cv_optimization_flags -march=$hc_cv_intel_cpu_type" if test "$hc_cv_builtin_alloca_broke" != "yes" && test "$hc_cv_opt_debug" != "yes"; then hc_cv_optimization_flags="$hc_cv_optimization_flags -fomit-frame-pointer" else hc_cv_optimization_flags="$hc_cv_optimization_flags -fno-omit-frame-pointer" fi fi hc_cv_optimization_flags="$hc_cv_optimization_flags -fno-strict-aliasing" fi if test "x$hc_cv_optimization_flags" = "x"; then AC_MSG_RESULT( [(none)] ) else AC_MSG_RESULT( [$hc_cv_optimization_flags] ) fi AC_CACHE_SAVE() ############################################################################### # Set additional Warning options for the compiler ############################################################################### # Avoid warnings when the instruction decoders load unused register numbers # from the instruction, and also to avoid modifying decNumber and softfloat HC_ADD_TO_CFLAGS_IF_SUPPORTED([-Wno-unused-but-set-variable], hc_have_unused_set_variable) # MSVC requires all declarations to be at the start of a block, whereas gcc # only issues a warning. This makes gcc flag mixed declarations as an error HC_ADD_TO_CFLAGS_IF_SUPPORTED([-Werror=declaration-after-statement], hc_have_decl_after_stmt) AC_CACHE_SAVE() ############################################################################### # DONE! -- Define our OUTPUT values and then exit... ############################################################################### #--------------------------------------------------------------# # (place only AC_DEFINE_UNQUOTED here; place AC_DEFINE below) # #--------------------------------------------------------------# if test "x$hc_cv_opt_custom_build_str" != "x"; then AC_DEFINE_UNQUOTED( [CUSTOM_BUILD_STRING], "${hc_cv_opt_custom_build_str}" ) fi AC_DEFINE_UNQUOTED( [MAX_CPU_ENGINES], ${hc_cv_opt_num_cpu_engines} ) AC_CACHE_SAVE() AC_MSG_NOTICE( [ ] ) AC_MSG_NOTICE( [ Package destination directory prefixes: ] ) AC_MSG_NOTICE( [ ] ) AC_MSG_NOTICE( [ Libraries: ${modexecdir} ] ) AC_MSG_NOTICE( [ Data: \$(datadir)/hercules ] ) AC_MSG_NOTICE( [ ] ) CPPFLAGS="$CPPFLAGS"' -DPKGDATADIR=\"$(pkgdatadir)\" -DMODULESDIR=\"$(modexecdir)\"' #---------------------------------------------------------------# # (place only AC_DEFINE here; place AC_DEFINE_UNQUOTED above) # #---------------------------------------------------------------# test "$hc_cv_opt_debug" = "yes" && AC_DEFINE(DEBUG) test "$hc_cv_have_inttypes_h" = "yes" && AC_DEFINE(HAVE_INTTYPES_H) test "$hc_cv_have_u_int8_t" = "yes" && AC_DEFINE(HAVE_U_INT) test "$hc_cv_opt_configsymbols" = "yes" && AC_DEFINE(OPTION_CONFIG_SYMBOLS) test "$hc_cv_opt_enhanced_configsymbols" = "yes" && AC_DEFINE(OPTION_ENHANCED_CONFIG_SYMBOLS) test "$hc_cv_opt_enhanced_configincludes" = "yes" && AC_DEFINE(OPTION_ENHANCED_CONFIG_INCLUDE) test "$hc_cv_opt_auto_oper" = "yes" && AC_DEFINE(OPTION_HAO) test "$hc_cv_opt_dynamic_load" = "yes" && AC_DEFINE(OPTION_DYNAMIC_LOAD) test "$hc_cv_opt_fthreads" = "yes" && AC_DEFINE(OPTION_FTHREADS) test "$hc_cv_hdl_build_shared" = "yes" && AC_DEFINE(HDL_BUILD_SHARED) test "$hc_cv_have_lt_dlopen" = "yes" && AC_DEFINE(HDL_USE_LIBTOOL) test "$hc_cv_is_windows" = "yes" && AC_DEFINE(WIN32) test "$hc_cv_opt_external_gui" = "yes" && AC_DEFINE(EXTERNALGUI) test "$hc_cv_opt_cckd_bzip2" = "yes" && AC_DEFINE(CCKD_BZIP2) test "$hc_cv_opt_het_bzip2" = "yes" && AC_DEFINE(HET_BZIP2) test "$hc_cv_timespec_in_sys_types_h" = "yes" && AC_DEFINE(TIMESPEC_IN_SYS_TYPES_H) test "$hc_cv_timespec_in_time_h" = "yes" && AC_DEFINE(TIMESPEC_IN_TIME_H) test "$hc_cv_have_getset_uid" != "yes" && AC_DEFINE(NO_SETUID) test "$hc_cv_asm_byteswap" != "yes" && AC_DEFINE(NO_ASM_BYTESWAP) test "$hc_cv_non_unique_gettimeofday" = "yes" && AC_DEFINE(NON_UNIQUE_GETTIMEOFDAY) test "$hc_cv_build_hercifc" = "yes" && AC_DEFINE(BUILD_HERCIFC) test "$hc_cv_opt_capabilities" = "yes" && AC_DEFINE(OPTION_CAPABILITIES) if test $hc_cv_have_sa_sigaction != yes || test $hc_cv_have_sigusr1 != yes || test $hc_cv_have_sigusr2 != yes || test $hc_cv_have_sigpipe != yes || test $hc_cv_have_sigbus != yes; then AC_DEFINE(NO_SIGABEND_HANDLER) fi if test "$hc_cv_regparm_attr_supported" = "yes" && test "$hc_cv_regparm_attr_broke" != "yes"; then AC_DEFINE(HAVE_ATTR_REGPARM) fi if test "$hc_cv_is_apple" = "yes"; then : # # TODO?? # # Do whatever is necessary to get the following symbol defined # so the included libltdl will be built and used... # ## AC_PROVIDE_AC_LIBTOOL_DLOPEN() fi #--------------------------------------------------# # CPPFLAGS (pre-processor flags) # #--------------------------------------------------# if test "$hc_cv_is_apple" = "yes" && test "$hc_cv_pp_macro_arg_counting_broke" = "yes"; then CPPFLAGS="${CPPFLAGS} -traditional-cpp -Wno-endif-labels" fi #--------------------------------------------------# # CFLAGS (compiler flags) # #--------------------------------------------------# if test "$hc_cv_is_windows" = "yes"; then if test "$hc_cv_have_pthread_h" = "yes" && test "x$hc_cv_alt_pthread_location" != "x"; then CFLAGS="$CFLAGS -I${hc_cv_alt_pthread_location}" fi CFLAGS="$CFLAGS -Wno-format" fi if test "$hc_cv_byte_structs_aligned_and_rounded_by_default" = "yes"; then #=============================================================== # the following requests 8-bit (byte) struct boundary alignment #=============================================================== CFLAGS="$CFLAGS -mstructure-size-boundary=8" fi test "x$hc_cv_optimization_flags" != "x" && CFLAGS="$CFLAGS $hc_cv_optimization_flags" #--------------------------------------------------# # LIBS (linker flags) # #--------------------------------------------------# test "$hc_cv_dash_pthread_needed" = "yes" && LIBS="$LIBS -pthread" test "$hc_cv_have_libbz2" = "yes" && LIBS="$LIBS -lbz2" # ---------------------- MINGW32 ---------------------- test "$hc_cv_is_mingw32" = "yes" && LIBS="$LIBS -lmsvcrt" test "$hc_cv_is_mingw32" = "yes" && LIBS="$LIBS -lws2_32" AC_CACHE_SAVE() #--------------------------------------------------------------------------------# # Pass certain values/settings as makefile variables to automake (makefile.am) # #--------------------------------------------------------------------------------# AM_CONDITIONAL( OPTION_DYNAMIC_LOAD, [ test "$hc_cv_opt_dynamic_load" = "yes" ] ) AM_CONDITIONAL( BUILD_FTHREADS, [ test "$hc_cv_opt_fthreads" = "yes" ] ) AM_CONDITIONAL( BUILD_HERCIFC, [ test "$hc_cv_build_hercifc" = "yes" ] ) AM_CONDITIONAL( SETUID_HERCIFC, [ test "$hc_cv_setuid_hercifc" = "yes" ] ) AM_CONDITIONAL( HERCIFC_GROUPSET, [ test "x$hc_cv_hercifc_groupname" != "x"] ) if test "x$hc_cv_hercifc_groupname" != "x"; then HERCIFC_GROUPNAME=${hc_cv_hercifc_groupname} AC_SUBST(HERCIFC_GROUPNAME) fi # Building of shared libraries is forced, and we force use of libtool too. AM_CONDITIONAL( BUILD_SHARED, [ test "$hc_cv_hdl_build_shared" = "yes" ] ) AM_CONDITIONAL( USE_DLLTOOL, [ test "$hc_cv_is_windows" = "yes" ] ) AC_CACHE_SAVE() AC_OUTPUT( [ Makefile util/Makefile html/Makefile crypto/Makefile man/Makefile m4/Makefile decNumber/Makefile softfloat/Makefile] ) ############################################################################### # (end-of-file) ############################################################################### hercules-3.12/aclocal.m40000664000175000017500000011716012622170274012045 00000000000000# generated automatically by aclocal 1.13.4 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.13.4], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.13.4])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless 'enable' is passed literally. # For symmetry, 'disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], am_maintainer_other[ make rules and dependencies not useful (and sometimes confusing) to the casual installer])], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # -*- Autoconf -*- # Obsolete and "removed" macros, that must however still report explicit # error messages when used, to smooth transition. # # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. AC_DEFUN([AM_CONFIG_HEADER], [AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl AC_CONFIG_HEADERS($@)]) AC_DEFUN([AM_PROG_CC_STDC], [AC_PROG_CC am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should simply use the 'AC][_PROG_CC' macro instead. Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', but upon 'ac_cv_prog_cc_stdc'.])]) AC_DEFUN([AM_C_PROTOTYPES], [AC_FATAL([automatic de-ANSI-fication support has been removed])]) AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([autoconf/hercules.m4]) m4_include([autoconf/libtool.m4]) m4_include([autoconf/ltdl.m4]) hercules-3.12/config.h.in0000664000175000017500000004463312564723541012242 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Define if hercifc program is to be built */ #undef BUILD_HERCIFC /* Define if your gcc properly supports C99 flexible arrays */ #undef C99_FLEXIBLE_ARRAYS /* Define to enable bzip2 compression in emulated DASDs */ #undef CCKD_BZIP2 /* Define to provide additional information about this build */ #undef CUSTOM_BUILD_STRING /* Define to enable extra debugging code (TRACE/VERIFY/ASSERT macros) */ #undef DEBUG /* Define to build interface to external Windows GUI */ #undef EXTERNALGUI /* Define to 1 if you have the `alphasort' function. */ #undef HAVE_ALPHASORT /* Define to 1 if you have the `argz_append' function. */ #undef HAVE_ARGZ_APPEND /* Define to 1 if you have the `argz_create_sep' function. */ #undef HAVE_ARGZ_CREATE_SEP /* Define to 1 if you have the header file. */ #undef HAVE_ARGZ_H /* Define to 1 if you have the `argz_insert' function. */ #undef HAVE_ARGZ_INSERT /* Define to 1 if you have the `argz_next' function. */ #undef HAVE_ARGZ_NEXT /* Define to 1 if you have the `argz_stringify' function. */ #undef HAVE_ARGZ_STRINGIFY /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ASSERT_H /* Define if your gcc properly supports __attribute__((regparm(n))) */ #undef HAVE_ATTR_REGPARM /* Define to 1 if you have the `bcopy' function. */ #undef HAVE_BCOPY /* Define to 1 if you have the header file. */ #undef HAVE_BYTESWAP_H /* Define to 1 if you have the header file. */ #undef HAVE_BZLIB_H /* Define to 1 if you have the `closedir' function. */ #undef HAVE_CLOSEDIR /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H /* Define to 1 if you have the declaration of `IFNAMSIZ', and to 0 if you don't. */ #undef HAVE_DECL_IFNAMSIZ /* Define to 1 if you have the declaration of `LOGIN_NAME_MAX', and to 0 if you don't. */ #undef HAVE_DECL_LOGIN_NAME_MAX /* Define to 1 if you have the declaration of `MTEWARN', and to 0 if you don't. */ #undef HAVE_DECL_MTEWARN /* Define to 1 if you have the declaration of `SIGBUS', and to 0 if you don't. */ #undef HAVE_DECL_SIGBUS /* Define to 1 if you have the declaration of `SIGPIPE', and to 0 if you don't. */ #undef HAVE_DECL_SIGPIPE /* Define to 1 if you have the declaration of `SIGUSR1', and to 0 if you don't. */ #undef HAVE_DECL_SIGUSR1 /* Define to 1 if you have the declaration of `SIGUSR2', and to 0 if you don't. */ #undef HAVE_DECL_SIGUSR2 /* Define to 1 if you have the declaration of `SIOCADDRT', and to 0 if you don't. */ #undef HAVE_DECL_SIOCADDRT /* Define to 1 if you have the declaration of `SIOCDELRT', and to 0 if you don't. */ #undef HAVE_DECL_SIOCDELRT /* Define to 1 if you have the declaration of `SIOCDIFADDR', and to 0 if you don't. */ #undef HAVE_DECL_SIOCDIFADDR /* Define to 1 if you have the declaration of `SIOCSIFHWADDR', and to 0 if you don't. */ #undef HAVE_DECL_SIOCSIFHWADDR /* Define to 1 if you have the declaration of `SIOCSIFNETMASK', and to 0 if you don't. */ #undef HAVE_DECL_SIOCSIFNETMASK /* Define to 1 if you have the declaration of `_SC_NPROCESSORS_CONF', and to 0 if you don't. */ #undef HAVE_DECL__SC_NPROCESSORS_CONF /* Define to 1 if you have the declaration of `_SC_NPROCESSORS_ONLN', and to 0 if you don't. */ #undef HAVE_DECL__SC_NPROCESSORS_ONLN /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define if you have the GNU dld library. */ #undef HAVE_DLD /* Define to 1 if you have the header file. */ #undef HAVE_DLD_H /* Define to 1 if you have the `dlerror' function. */ #undef HAVE_DLERROR /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_DL_H /* Define if you have the _dyld_func_lookup function. */ #undef HAVE_DYLD /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if the system has the type `error_t'. */ #undef HAVE_ERROR_T /* Define to 1 if you have the `fabsf' function. */ #undef HAVE_FABSF /* Define to 1 if you have the `fabsl' function. */ #undef HAVE_FABSL /* Define to 1 if you have the `fdatasync' function. */ #undef HAVE_FDATASYNC /* Define to 1 if the fdatasync function is supported. */ #undef HAVE_FDATASYNC_SUPPORTED /* Define to 1 if you have the `fmodl' function. */ #undef HAVE_FMODL /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `frexpf' function. */ #undef HAVE_FREXPF /* Define to 1 if you have the `frexpl' function. */ #undef HAVE_FREXPL /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ #undef HAVE_FSEEKO /* Define to 1 if you have the `fsync' function. */ #undef HAVE_FSYNC /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE /* Define to 1 if you have the `geteuid' function. */ #undef HAVE_GETEUID /* Define to 1 if you have the `getlogin' function. */ #undef HAVE_GETLOGIN /* Define to 1 if you have the `getlogin_r' function. */ #undef HAVE_GETLOGIN_R /* Define to 1 if you have the `getopt_long' function. */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the `getpgrp' function. */ #undef HAVE_GETPGRP /* Define to 1 if you have the `getresuid' function. */ #undef HAVE_GETRESUID /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the `getuid' function. */ #undef HAVE_GETUID /* Define to 1 if you have the `iconv' function. */ #undef HAVE_ICONV /* Define to 1 if you have the header file. */ #undef HAVE_ICONV_H /* Define to 1 if the system has the type `id_t'. */ #undef HAVE_ID_T /* Define to 1 if you have the `index' function. */ #undef HAVE_INDEX /* Define to 1 if you have the `inet_aton' function. */ #undef HAVE_INET_ATON /* Define to 1 if you have the `InitializeCriticalSectionAndSpinCount' function. */ #undef HAVE_INITIALIZECRITICALSECTIONANDSPINCOUNT /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if the system has the type `in_addr_t'. */ #undef HAVE_IN_ADDR_T /* Define to 1 if you have the `ldexpf' function. */ #undef HAVE_LDEXPF /* Define to 1 if you have the `ldexpl' function. */ #undef HAVE_LDEXPL /* Define to 1 if you have the `cap' library (-lcap). */ #undef HAVE_LIBCAP /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `iconv' library (-liconv). */ #undef HAVE_LIBICONV /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the `msvcrt' library (-lmsvcrt). */ #undef HAVE_LIBMSVCRT /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define to 1 if you have the `rt' library (-lrt). */ #undef HAVE_LIBRT /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the `z' library (-lz). */ #undef HAVE_LIBZ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_IF_TUN_H /* Define to 1 if you have the header file. */ #undef HAVE_LTDL_H /* Define to 1 if you have the header file. */ #undef HAVE_MACH_O_DYLD_H /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MATH_H /* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memrchr' function. */ #undef HAVE_MEMRCHR /* Define to 1 if you have the `nanosleep' function. */ #undef HAVE_NANOSLEEP /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_ROUTE_H /* Define to 1 if you have the `opendir' function. */ #undef HAVE_OPENDIR /* Define to 1 if you have the `pipe' function. */ #undef HAVE_PIPE /* Define if libtool can extract symbol lists from object files. */ #undef HAVE_PRELOADED_SYMBOLS /* Define to 1 if you have the header file. */ #undef HAVE_PWD_H /* Define to 1 if you have the `readdir' function. */ #undef HAVE_READDIR /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the header file. */ #undef HAVE_REGEX_H /* Define to 1 if you have the `rindex' function. */ #undef HAVE_RINDEX /* Define to 1 if you have the `rint' function. */ #undef HAVE_RINT /* Define to 1 if you have the `scandir' function. */ #undef HAVE_SCANDIR /* Define to 1 if you have the header file. */ #undef HAVE_SCHED_H /* Define to 1 if you have the `sched_yield' function. */ #undef HAVE_SCHED_YIELD /* Define to 1 if you have the `setresuid' function. */ #undef HAVE_SETRESUID /* Define to 1 if you have the `setreuid' function. */ #undef HAVE_SETREUID /* Define if you have the shl_load function. */ #undef HAVE_SHL_LOAD /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `sleep' function. */ #undef HAVE_SLEEP /* Define to 1 if you have the `socketpair' function. */ #undef HAVE_SOCKETPAIR /* Define to 1 if the system has the type `socklen_t'. */ #undef HAVE_SOCKLEN_T /* Define to 1 if you have the `sqrtl' function. */ #undef HAVE_SQRTL /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strcmp' function. */ #undef HAVE_STRCMP /* Define to 1 if you have the `strerror_r' function. */ #undef HAVE_STRERROR_R /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the `strsignal' function. */ #undef HAVE_STRSIGNAL /* Define to 1 if you have the `strtok_r' function. */ #undef HAVE_STRTOK_R /* Define to 1 if `s_addr' is a member of `struct in_addr'. */ #undef HAVE_STRUCT_IN_ADDR_S_ADDR /* Define to 1 if `sa_sigaction' is a member of `struct sigaction'. */ #undef HAVE_STRUCT_SIGACTION_SA_SIGACTION /* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */ #undef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN /* Define to 1 if `tv_nsec' is a member of `struct timespec'. */ #undef HAVE_STRUCT_TIMESPEC_TV_NSEC /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file. */ #undef HAVE_SYS_CAPABILITY_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_DL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MTIO_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PRCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the `sys_siglist' function. */ #undef HAVE_SYS_SIGLIST /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UTSNAME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if the system has the type `useconds_t'. */ #undef HAVE_USECONDS_T /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP /* Define to 1 if the system has the type `u_char'. */ #undef HAVE_U_CHAR /* Define to 1 if the system has the type `u_int'. */ #undef HAVE_U_INT /* Define to 1 if the system has the type `u_int8_t'. */ #undef HAVE_U_INT8_T /* Define to 1 if the system has the type `u_long'. */ #undef HAVE_U_LONG /* Define to 1 if the system has the type `u_short'. */ #undef HAVE_U_SHORT /* Define to 1 if you have the `vsscanf' function. */ #undef HAVE_VSSCANF /* Define to 1 if you have the header file. */ #undef HAVE_ZLIB_H /* Define to indicate shared libraries are being used */ #undef HDL_BUILD_SHARED /* Define to cause dynamic loader to use libtool instead of dlopen */ #undef HDL_USE_LIBTOOL /* Define to enable bzip2 compression in emulated tapes */ #undef HET_BZIP2 /* Define if the OS needs help to load dependent libraries for dlopen(). */ #undef LTDL_DLOPEN_DEPLIBS /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LTDL_OBJDIR /* Define to the name of the environment variable that determines the dynamic library search path. */ #undef LTDL_SHLIBPATH_VAR /* Define to the extension used for shared libraries, say, ".so". */ #undef LTDL_SHLIB_EXT /* Define to the system default library search path. */ #undef LTDL_SYSSEARCHPATH /* Defines the maximum number of emulated CPU engines */ #undef MAX_CPU_ENGINES /* Define to indicate optreset exists */ #undef NEED_GETOPT_OPTRESET /* Define to indicate a wrapper for getopt is needed */ #undef NEED_GETOPT_WRAPPER /* Define if dlsym() requires a leading underscore in symbol names. */ #undef NEED_USCORE /* Define if 'gettimeofday' returns non-unique values */ #undef NON_UNIQUE_GETTIMEOFDAY /* Define to disable assembler routines for byte swapping */ #undef NO_ASM_BYTESWAP /* Define to disable setuid operation */ #undef NO_SETUID /* Define to disable sigabend_handler (please describe this better) */ #undef NO_SIGABEND_HANDLER /* Define to enable posix draft 1003.1e capabilities */ #undef OPTION_CAPABILITIES /* Define to enable symbolic substitutions in configuration file */ #undef OPTION_CONFIG_SYMBOLS /* Define to enable Hercules Dynamic Loader feature */ #undef OPTION_DYNAMIC_LOAD /* Define to enable enhanced-mode 'include' file support in configuration file */ #undef OPTION_ENHANCED_CONFIG_INCLUDE /* Define to enable enhanced-mode symbolic substitutions in configuration file */ #undef OPTION_ENHANCED_CONFIG_SYMBOLS /* Define to use included threads implementation (fthreads) */ #undef OPTION_FTHREADS /* Define to enable Hercules Automatic Operator feature */ #undef OPTION_HAO /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT /* The size of `int *', as computed by sizeof. */ #undef SIZEOF_INT_P /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG /* The size of `off_t', as computed by sizeof. */ #undef SIZEOF_OFF_T /* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T /* The size of `struct bytestruct', as computed by sizeof. */ #undef SIZEOF_STRUCT_BYTESTRUCT /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if 'struct timespec' defined in */ #undef TIMESPEC_IN_SYS_TYPES_H /* Define if 'struct timespec' defined in */ #undef TIMESPEC_IN_TIME_H /* Version number of package */ #undef VERSION /* Define when building under Win32 (MinGW or Cygwin) */ #undef WIN32 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Define missing macro on apple darwin (osx) platform */ #undef _BSD_SOCKLEN_T_ /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ #undef _LARGEFILE_SOURCE /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to a type to use for `error_t' if it is not otherwise available. */ #undef error_t /* Define to `long int' if does not define. */ #undef off_t hercules-3.12/hostinfo.h0000664000175000017500000000314212564723224012205 00000000000000/* HOSTINFO.H (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* Host system information header file */ /* Released under the Q Public License */ /* (http://www.hercules-390.org/herclic.html) */ /* as modifications to Hercules. */ /*-------------------------------------------------------------------*/ /* Header file contains host system information */ /*-------------------------------------------------------------------*/ #ifndef _HOSTINFO_H_ #define _HOSTINFO_H_ #include "hercules.h" #ifndef _HOSTINFO_C_ #ifndef _HUTIL_DLL_ #define HI_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define HI_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define HI_DLL_IMPORT DLL_EXPORT #endif typedef struct HOST_INFO { char sysname[20]; char nodename[20]; char release[20]; char version[50]; char machine[20]; int trycritsec_avail; /* 1=TryEnterCriticalSection */ int num_procs; /* #of processors */ } HOST_INFO; HI_DLL_IMPORT HOST_INFO hostinfo; HI_DLL_IMPORT void init_hostinfo ( HOST_INFO* pHostInfo ); HI_DLL_IMPORT void display_hostinfo ( HOST_INFO* pHostInfo, FILE *f,int httpfd ); HI_DLL_IMPORT char* get_hostinfo_str ( HOST_INFO* pHostInfo, char* pszHostInfoStrBuff, size_t nHostInfoStrBuffSiz ); /* Hercules Host Information structure (similar to utsname struct) */ #endif // _HOSTINFO_H_ hercules-3.12/cpuint.h0000664000175000017500000006255012564723224011666 00000000000000/* CPUINT.H (c) Copyright Jan Jaeger, 2001-2009 */ /* Hercules Interrupt State and Mask Definitions */ /********************************************************************** Interrupts_State & Interrupts_Mask bits definition (Initial_Mask=800E) Machine check, PER and external interrupt subclass bit positions are fixed by the architecture and cannot be changed Floating interrupts are made pending to all CPUs, and are recorded in the sysblk structure, CPU specific interrupts are recorded in the regs structure. hi0m mmmm pppp p00p xxxx xxxx xxxx h0hs : type U32 || | |||| |||| |--| |||| |||| |||| |-|| h:mask is always '1' || | |||| |||| | | |||| |||| |||| | || s:state is always '1' || | |||| |||| | | |||| |||| |||| | |+--> '1' : PSW_WAIT || | |||| |||| | | |||| |||| |||| | +---> '1' : RESTART || | |||| |||| | | |||| |||| |||| | (available) || | |||| |||| | | |||| |||| |||| +-----> '1' : STORSTAT || | |||| |||| | | |||| |||| |||| || | |||| |||| | | |||| |||| |||+-------> '1' : ETR || | |||| |||| | | |||| |||| ||+--------> '1' : EXTSIG || | |||| |||| | | |||| |||| |+---------> '1' : INTKEY || | |||| |||| | | |||| |||| +----------> '1' : ITIMER || | |||| |||| | | |||| |||| || | |||| |||| | | |||| |||+------------> '1' : ECPS VTIMER || | |||| |||| | | |||| ||+-------------> '1' : SERVSIG || | |||| |||| | | |||| |+--------------> '1' : PTIMER || | |||| |||| | | |||| +---------------> '1' : CLKC || | |||| |||| | | |||| || | |||| |||| | | |||+-----------------> '1' : TODSYNC || | |||| |||| | | ||+------------------> '1' : EXTCALL || | |||| |||| | | |+-------------------> '1' : EMERSIG || | |||| |||| | | +--------------------> '1' : MALFALT || | |||| |||| | | || | |||| |||| | +----------------------> '1' : PER IFNUL || | |||| |||| | || | |||| |||| | || | |||| |||| +-------------------------> '1' : PER STURA || | |||| |||| || | |||| |||+---------------------------> '1' : PER GRA || | |||| ||+----------------------------> '1' : PER SA || | |||| |+-----------------------------> '1' : PER IF || | |||| +------------------------------> '1' : PER SB || | |||| || | |||+--------------------------------> '1' : WARNING || | ||+---------------------------------> '1' : XDMGRPT || | |+----------------------------------> '1' : DGRDRPT || | +-----------------------------------> '1' : RCVYRPT || | || +-------------------------------------> '1' : CHANRPT || |+---------------------------------------> '1' : IO +----------------------------------------> '1' : INTERRUPT possible **********************************************************************/ // Hercules internal bit# macro: bit numbers are referenced counting // from the RIGHT to left (i.e. 31 <-- 0) and thus the numerical value // of a set bit is equal to two raised to the power of the bit position. // While this is the COMPLETE OPPOSITE from the way bit numbers are // numbered in IBM architectural reference manuals, we do it this way // anyway since that's the way Intel numbers their bits, thus allowing // us to easily replace bit referencing statements with corresponding // Intel assembler bit manipulation instructions (since Intel is still // the predominant host architecture platform for Hercules) /* The BIT() macro should only be used for bit numbers strictly less than 32 */ #ifndef BIT #define BIT(nr) ( 1 << (nr) ) // (bit# counting from the right) #endif /* The CPU_BIT macro is solely for manipulating the CPU number as a CPU bit in a CPU_BITMAP */ #ifndef CPU_BIT #define CPU_BIT(nr) ( (( CPU_BITMAP ) ( 1 ) ) << ( nr ) ) #endif /* Interrupt bit numbers */ #define IC_INTERRUPT 31 /* 0x80000000 */ #define IC_IO 30 /* 0x40000000 */ #define IC_UNUSED_29 29 /* 0x20000000 */ #define IC_CHANRPT 28 /* 0x10000000 - Architecture dependent (CR14) */ #define IC_RCVYRPT 27 /* 0x08000000 - Architecture dependent (CR14) */ #define IC_DGRDRPT 26 /* 0x04000000 - Architecture dependent (CR14) */ #define IC_XDMGRPT 25 /* 0x02000000 - Architecture dependent (CR14) */ #define IC_WARNING 24 /* 0x01000000 - Architecture dependent (CR14) */ #define IC_PER_SB 23 /* 0x00800000 - Architecture dependent (CR9 >> 8) */ #define IC_PER_IF 22 /* 0x00400000 - Architecture dependent (CR9 >> 8) */ #define IC_PER_SA 21 /* 0x00200000 - Architecture dependent (CR9 >> 8) */ #define IC_PER_GRA 20 /* 0x00100000 - Architecture dependent (CR9 >> 8) */ #define IC_PER_STURA 19 /* 0x00080000 - Architecture dependent (CR9 >> 8) */ #define IC_UNUSED_18 18 /* 0x00040000 */ #define IC_UNUSED_17 17 /* 0x00020000 */ #define IC_PER_IFNUL 16 /* 0x00010000 - Architecture dependent (CR9 >> 8) */ #define IC_MALFALT 15 /* 0x00008000 - Architecture dependent (CR0) */ #define IC_EMERSIG 14 /* 0x00004000 - Architecture dependent (CR0) */ #define IC_EXTCALL 13 /* 0x00002000 - Architecture dependent (CR0) */ #define IC_TODSYNC 12 /* 0x00001000 - Architecture dependent (CR0) */ #define IC_CLKC 11 /* 0x00000800 - Architecture dependent (CR0) */ #define IC_PTIMER 10 /* 0x00000400 - Architecture dependent (CR0) */ #define IC_SERVSIG 9 /* 0x00000200 - Architecture dependent (CR0) */ #define IC_ECPSVTIMER 8 /* 0x00000100 - Not Architecture dependent */ #define IC_ITIMER 7 /* 0x00000080 - Architecture dependent (CR0) */ #define IC_INTKEY 6 /* 0x00000040 - Architecture dependent (CR0) */ #define IC_EXTSIG 5 /* 0x00000020 - Architecture dependent (CR0) */ #define IC_ETR 4 /* 0x00000010 - Architecture dependent (CR0) */ #define IC_STORSTAT 3 /* 0x00000008 */ #define IC_UNUSED_2 2 /* 0x00000004 */ #define IC_RESTART 1 /* 0x00000002 */ #define IC_PSW_WAIT 0 /* 0x00000001 */ /* Initial values */ #define IC_INITIAL_STATE BIT(IC_PSW_WAIT) #define IC_INITIAL_MASK ( BIT(IC_INTERRUPT) \ | BIT(IC_RESTART) \ | BIT(IC_STORSTAT) \ ) #define SET_IC_INITIAL_MASK(_regs) (_regs)->ints_mask = IC_INITIAL_MASK #define SET_IC_INITIAL_STATE(_regs) (_regs)->ints_state = IC_INITIAL_STATE /* I/O interrupt subclasses */ #define IC_IOPENDING ( BIT(IC_IO) ) /* External interrupt subclasses in CR 0 */ #define IC_EXT_SCM_CR0 ( BIT(IC_MALFALT) \ | BIT(IC_EMERSIG) \ | BIT(IC_EXTCALL) \ | BIT(IC_TODSYNC) \ | BIT(IC_CLKC) \ | BIT(IC_PTIMER) \ | BIT(IC_SERVSIG) \ | BIT(IC_ITIMER) \ | BIT(IC_INTKEY) \ | BIT(IC_EXTSIG) \ | BIT(IC_ETR) \ ) /* External interrupt subclasses */ /* * Adds ECPS:VM Vtimer which has no individual * subclass mask in CR0 */ #define IC_EXTPENDING ( BIT(IC_MALFALT) \ | BIT(IC_EMERSIG) \ | BIT(IC_EXTCALL) \ | BIT(IC_TODSYNC) \ | BIT(IC_CLKC) \ | BIT(IC_PTIMER) \ | BIT(IC_SERVSIG) \ | BIT(IC_ECPSVTIMER) \ | BIT(IC_ITIMER) \ | BIT(IC_INTKEY) \ | BIT(IC_EXTSIG) \ | BIT(IC_ETR) \ ) /* Machine check subclasses */ #define IC_MCKPENDING ( BIT(IC_CHANRPT) \ | BIT(IC_RCVYRPT) \ | BIT(IC_DGRDRPT) \ | BIT(IC_XDMGRPT) \ | BIT(IC_WARNING) \ ) /* Not disabled mask */ #define IC_OPEN_MASK ( IC_MCKPENDING \ | IC_EXTPENDING \ | IC_IOPENDING \ ) #define IC_PER_MASK ( BIT(IC_PER_SB) \ | BIT(IC_PER_IF) \ | BIT(IC_PER_SA) \ | BIT(IC_PER_GRA) \ | BIT(IC_PER_STURA) \ | BIT(IC_PER_IFNUL) \ ) /* SIE & Assist supported events */ #define IC_SIE_INT ( BIT(IC_IO) \ | BIT(IC_CLKC) \ | BIT(IC_PTIMER) \ | BIT(IC_ITIMER) \ ) #define IC_CR9_SHIFT 8 /* Mask bits are ONLY set by the associated cpu thread and * therefore don't have to be serialized. The mask bits * indicate which interrupts the CPU is willing to take at * this time. We set the mask bits below in one fell swoop * to avoid multiple updates to `ints_mask'. */ #undef IC_CR0_TO_INTMASK #if defined(FEATURE_ECPSVM) #define IC_CR0_TO_INTMASK(_regs) \ ( ( (_regs)->CR(0) & IC_EXT_SCM_CR0) \ | (((_regs)->CR(0) & BIT(IC_ITIMER)) ? BIT(IC_ECPSVTIMER) : 0) ) #else #define IC_CR0_TO_INTMASK(_regs) \ ( (_regs)->CR(0) & IC_EXT_SCM_CR0) #endif /* FEATURE_ECPSVM */ #define IC_MASK(_regs) \ ( ( IC_INITIAL_MASK ) \ | ( ECMODE(&(_regs)->psw) \ ? ( ((_regs)->psw.sysmask & PSW_IOMASK) ? BIT(IC_IO) : 0 ) \ : ( ((_regs)->psw.sysmask & 0xFE) ? BIT(IC_IO) : 0 ) \ ) \ | ( MACHMASK(&(_regs)->psw) ? ((_regs)->CR(14) & IC_MCKPENDING) : 0 ) \ | ( PER_MODE((_regs)) ? ((_regs)->ints_mask & IC_PER_MASK) : 0 ) \ | ( ((_regs)->psw.sysmask & PSW_EXTMASK) ? (IC_CR0_TO_INTMASK((_regs))) : 0 ) \ | ( WAITSTATE(&(_regs)->psw) ? BIT(IC_PSW_WAIT) : 0 ) \ ) #define IC_ECMODE_MASK(_regs) \ ( ( IC_INITIAL_MASK ) \ | ( ((_regs)->psw.sysmask & PSW_IOMASK) ? BIT(IC_IO) : 0 ) \ | ( MACHMASK(&(_regs)->psw) ? ((_regs)->CR(14) & IC_MCKPENDING) : 0 ) \ | ( PER_MODE((_regs)) ? ((_regs)->ints_mask & IC_PER_MASK) : 0 ) \ | ( ((_regs)->psw.sysmask & PSW_EXTMASK) ? (IC_CR0_TO_INTMASK((_regs))) : 0 ) \ | ( WAITSTATE(&(_regs)->psw) ? BIT(IC_PSW_WAIT) : 0 ) \ ) #define IC_BCMODE_MASK(_regs) \ ( ( IC_INITIAL_MASK ) \ | ( ((_regs)->psw.sysmask & 0xFE) ? BIT(IC_IO) : 0 ) \ | ( MACHMASK(&(_regs)->psw) ? ((_regs)->CR(14) & IC_MCKPENDING) : 0 ) \ | ( PER_MODE((_regs)) ? ((_regs)->ints_mask & IC_PER_MASK) : 0 ) \ | ( ((_regs)->psw.sysmask & PSW_EXTMASK) ? (IC_CR0_TO_INTMASK((_regs))) : 0 ) \ | ( WAITSTATE(&(_regs)->psw) ? BIT(IC_PSW_WAIT) : 0 ) \ ) /* Note: if PER mode, invalidate the AIA to force instfetch to be called */ #define SET_IC_ECMODE_MASK(_regs) \ do { \ (_regs)->ints_mask = IC_ECMODE_MASK((_regs)); \ if ( ( (_regs)->permode = PER_MODE((_regs)) ) ) \ INVALIDATE_AIA((_regs)); \ } while (0) #define SET_IC_BCMODE_MASK(_regs) \ do { \ (_regs)->ints_mask = IC_BCMODE_MASK((_regs)); \ if ( ( (_regs)->permode = PER_MODE((_regs)) ) ) \ INVALIDATE_AIA((_regs)); \ } while (0) #undef SET_IC_MASK #ifdef FEATURE_BCMODE #define SET_IC_MASK(_regs) \ do { \ (_regs)->ints_mask = IC_MASK((_regs)); \ if ( ( (_regs)->permode = PER_MODE((_regs)) ) ) \ INVALIDATE_AIA((_regs)); \ } while (0) #else #define SET_IC_MASK(_regs) SET_IC_ECMODE_MASK(_regs) #endif /* * State bits indicate what interrupts are possibly pending * for a CPU. These bits can be set by any thread and therefore * are serialized by the `intlock'. * For PER, the state bits are set when CR9 is loaded and the mask * bits are set when a PER event occurs */ #define SET_IC_TRACE \ do { \ int i; \ CPU_BITMAP mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) \ sysblk.regs[i]->ints_state |= BIT(IC_INTERRUPT); \ mask >>= 1; \ } \ } while (0) #define SET_IC_PER(_regs) \ do { \ (_regs)->ints_state &= (~IC_PER_MASK); \ (_regs)->ints_state |= (((_regs)->CR(9) >> IC_CR9_SHIFT) & IC_PER_MASK); \ (_regs)->ints_mask &= (~IC_PER_MASK | (_regs)->ints_state); \ } while (0) /* * * * * * * * * * * * * * * Set state bit to '1' * * * * * * * * * * * * * * */ #define ON_IC_INTERRUPT(_regs) \ do { \ (_regs)->ints_state |= BIT(IC_INTERRUPT); \ } while (0) #define ON_IC_RESTART(_regs) \ do { \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_RESTART); \ } while (0) #define ON_IC_STORSTAT(_regs) \ do { \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_STORSTAT); \ } while (0) #define ON_IC_IOPENDING \ do { \ int i; CPU_BITMAP mask; \ if ( !(sysblk.ints_state & BIT(IC_IO)) ) { \ sysblk.ints_state |= BIT(IC_IO); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) { \ if ( sysblk.regs[i]->ints_mask & BIT(IC_IO) ) \ sysblk.regs[i]->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_IO); \ else \ sysblk.regs[i]->ints_state |= BIT(IC_IO); \ } \ mask >>= 1; \ } \ } \ } while (0) #define ON_IC_CHANRPT \ do { \ int i; CPU_BITMAP mask; \ if ( !(sysblk.ints_state & BIT(IC_CHANRPT)) ) { \ sysblk.ints_state |= BIT(IC_CHANRPT); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) { \ if ( sysblk.regs[i]->ints_mask & BIT(IC_CHANRPT) ) \ sysblk.regs[i]->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_CHANRPT); \ else \ sysblk.regs[i]->ints_state |= BIT(IC_CHANRPT); \ } \ mask >>= 1; \ } \ } \ } while (0) #define ON_IC_INTKEY \ do { \ int i; CPU_BITMAP mask; \ if ( !(sysblk.ints_state & BIT(IC_INTKEY)) ) { \ sysblk.ints_state |= BIT(IC_INTKEY); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) { \ if ( sysblk.regs[i]->ints_mask & BIT(IC_INTKEY) ) \ sysblk.regs[i]->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_INTKEY); \ else \ sysblk.regs[i]->ints_state |= BIT(IC_INTKEY); \ } \ mask >>= 1; \ } \ } \ } while (0) #define ON_IC_SERVSIG \ do { \ int i; CPU_BITMAP mask; \ if ( !(sysblk.ints_state & BIT(IC_SERVSIG)) ) { \ sysblk.ints_state |= BIT(IC_SERVSIG); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) { \ if ( sysblk.regs[i]->ints_mask & BIT(IC_SERVSIG) ) \ sysblk.regs[i]->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_SERVSIG); \ else \ sysblk.regs[i]->ints_state |= BIT(IC_SERVSIG); \ } \ mask >>= 1; \ } \ } \ } while (0) #define ON_IC_ITIMER(_regs) \ do { \ if ( (_regs)->ints_mask & BIT(IC_ITIMER) ) \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_ITIMER); \ else \ (_regs)->ints_state |= BIT(IC_ITIMER); \ } while (0) #define ON_IC_PTIMER(_regs) \ do { \ if ( (_regs)->ints_mask & BIT(IC_PTIMER) ) \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_PTIMER); \ else \ (_regs)->ints_state |= BIT(IC_PTIMER); \ } while (0) #define ON_IC_ECPSVTIMER(_regs) \ do { \ if ( (_regs)->ints_mask & BIT(IC_ECPSVTIMER) ) \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_ECPSVTIMER); \ else \ (_regs)->ints_state |= BIT(IC_ECPSVTIMER); \ } while (0) #define ON_IC_CLKC(_regs) \ do { \ if ( (_regs)->ints_mask & BIT(IC_CLKC) ) \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_CLKC); \ else \ (_regs)->ints_state |= BIT(IC_CLKC); \ } while (0) #define ON_IC_EXTCALL(_regs) \ do { \ if ( (_regs)->ints_mask & BIT(IC_EXTCALL) ) \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_EXTCALL); \ else \ (_regs)->ints_state |= BIT(IC_EXTCALL); \ } while (0) #define ON_IC_MALFALT(_regs) \ do { \ if ( (_regs)->ints_mask & BIT(IC_MALFALT) ) \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_MALFALT); \ else \ (_regs)->ints_state |= BIT(IC_MALFALT); \ } while (0) #define ON_IC_EMERSIG(_regs) \ do { \ if ( (_regs)->ints_mask & BIT(IC_EMERSIG) ) \ (_regs)->ints_state |= BIT(IC_INTERRUPT) | BIT(IC_EMERSIG); \ else \ (_regs)->ints_state |= BIT(IC_EMERSIG); \ } while (0) /* * When a PER event occurs we set the bit in ints_mask instead of * ints_state; therefore intlock does not need to be held. * The ints_state bits are set when CR9 is loaded. */ #define ON_IC_PER_SB(_regs) \ do { \ (_regs)->ints_mask |= BIT(IC_PER_SB); \ } while (0) #define ON_IC_PER_IF(_regs) \ do { \ (_regs)->ints_mask |= BIT(IC_PER_IF); \ } while (0) #define ON_IC_PER_SA(_regs) \ do { \ (_regs)->ints_mask |= BIT(IC_PER_SA); \ } while (0) #define ON_IC_PER_GRA(_regs) \ do { \ (_regs)->ints_mask |= BIT(IC_PER_GRA); \ } while (0) #define ON_IC_PER_STURA(_regs) \ do { \ (_regs)->ints_mask |= BIT(IC_PER_STURA); \ } while (0) #define ON_IC_PER_IFNUL(_regs) \ do { \ (_regs)->ints_mask |= BIT(IC_PER_IFNUL); \ } while (0) /* * * * * * * * * * * * * * * Set state bit to '0' * * * * * * * * * * * * * * */ #define OFF_IC_INTERRUPT(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_INTERRUPT); \ } while (0) #define OFF_IC_RESTART(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_RESTART); \ } while (0) #define OFF_IC_STORSTAT(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_STORSTAT); \ } while (0) #define OFF_IC_IOPENDING \ do { \ int i; CPU_BITMAP mask; \ if ( sysblk.ints_state & BIT(IC_IO) ) { \ sysblk.ints_state &= ~BIT(IC_IO); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) \ sysblk.regs[i]->ints_state &= ~BIT(IC_IO); \ mask >>= 1; \ } \ } \ } while (0) #define OFF_IC_CHANRPT \ do { \ int i; CPU_BITMAP mask; \ if ( sysblk.ints_state & BIT(IC_CHANRPT) ) { \ sysblk.ints_state &= ~BIT(IC_CHANRPT); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) \ sysblk.regs[i]->ints_state &= ~BIT(IC_CHANRPT); \ mask >>= 1; \ } \ } \ } while (0) #define OFF_IC_INTKEY \ do { \ int i; CPU_BITMAP mask; \ if ( sysblk.ints_state & BIT(IC_INTKEY) ) { \ sysblk.ints_state &= ~BIT(IC_INTKEY); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) \ sysblk.regs[i]->ints_state &= ~BIT(IC_INTKEY); \ mask >>= 1; \ } \ } \ } while (0) #define OFF_IC_SERVSIG \ do { \ int i; CPU_BITMAP mask; \ if ( sysblk.ints_state & BIT(IC_SERVSIG) ) { \ sysblk.ints_state &= ~BIT(IC_SERVSIG); \ mask = sysblk.started_mask; \ for (i = 0; mask; i++) { \ if (mask & 1) \ sysblk.regs[i]->ints_state &= ~BIT(IC_SERVSIG); \ mask >>= 1; \ } \ } \ } while (0) #define OFF_IC_ITIMER(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_ITIMER); \ } while (0) #define OFF_IC_PTIMER(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_PTIMER); \ } while (0) #define OFF_IC_ECPSVTIMER(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_ECPSVTIMER); \ } while (0) #define OFF_IC_CLKC(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_CLKC); \ } while (0) #define OFF_IC_EXTCALL(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_EXTCALL); \ } while (0) #define OFF_IC_MALFALT(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_MALFALT); \ } while (0) #define OFF_IC_EMERSIG(_regs) \ do { \ (_regs)->ints_state &= ~BIT(IC_EMERSIG); \ } while (0) #define OFF_IC_PER(_regs) \ do { \ (_regs)->ints_mask &= ~IC_PER_MASK; \ } while (0) #define OFF_IC_PER_SB(_regs) \ do { \ (_regs)->ints_mask &= ~BIT(IC_PER_SB); \ } while (0) #define OFF_IC_PER_IF(_regs) \ do { \ (_regs)->ints_mask &= ~BIT(IC_PER_IF); \ } while (0) #define OFF_IC_PER_SA(_regs) \ do { \ (_regs)->ints_mask &= ~BIT(IC_PER_SA); \ } while (0) #define OFF_IC_PER_GRA(_regs) \ do { \ (_regs)->ints_mask &= ~BIT(IC_PER_GRA); \ } while (0) #define OFF_IC_PER_STURA(_regs) \ do { \ (_regs)->ints_mask &= ~BIT(IC_PER_STURA); \ } while (0) #define OFF_IC_PER_IFNUL(_regs) \ do { \ (_regs)->ints_mask &= ~BIT(IC_PER_IFNUL); \ } while (0) /* * * * * * * * * * * * * * * Test interrupt state * * * * * * * * * * * * * * */ #define IS_IC_INTERRUPT(_regs) ( (_regs)->ints_state & BIT(IC_INTERRUPT) ) #define IS_IC_RESTART(_regs) ( (_regs)->ints_state & BIT(IC_RESTART) ) #define IS_IC_STORSTAT(_regs) ( (_regs)->ints_state & BIT(IC_STORSTAT) ) #define IS_IC_IOPENDING ( sysblk.ints_state & BIT(IC_IO) ) #define IS_IC_MCKPENDING(_regs) ( (_regs)->ints_state & IC_MCKPENDING ) #define IS_IC_CHANRPT ( sysblk.ints_state & BIT(IC_CHANRPT) ) #define IS_IC_INTKEY ( sysblk.ints_state & BIT(IC_INTKEY) ) #define IS_IC_SERVSIG ( sysblk.ints_state & BIT(IC_SERVSIG) ) #define IS_IC_ITIMER(_regs) ( (_regs)->ints_state & BIT(IC_ITIMER) ) #define IS_IC_PTIMER(_regs) ( (_regs)->ints_state & BIT(IC_PTIMER) ) #define IS_IC_ECPSVTIMER(_regs) ( (_regs)->ints_state & BIT(IC_ECPSVTIMER)) #define IS_IC_CLKC(_regs) ( (_regs)->ints_state & BIT(IC_CLKC) ) #define IS_IC_EXTCALL(_regs) ( (_regs)->ints_state & BIT(IC_EXTCALL) ) #define IS_IC_MALFALT(_regs) ( (_regs)->ints_state & BIT(IC_MALFALT) ) #define IS_IC_EMERSIG(_regs) ( (_regs)->ints_state & BIT(IC_EMERSIG) ) #define IS_IC_PER(_regs) ( (_regs)->ints_mask & IC_PER_MASK ) #define IS_IC_PER_SB(_regs) ( (_regs)->ints_mask & BIT(IC_PER_SB) ) #define IS_IC_PER_IF(_regs) ( (_regs)->ints_mask & BIT(IC_PER_IF) ) #define IS_IC_PER_SA(_regs) ( (_regs)->ints_mask & BIT(IC_PER_SA) ) #define IS_IC_PER_GRA(_regs) ( (_regs)->ints_mask & BIT(IC_PER_GRA) ) #define IS_IC_PER_STURA(_regs) ( (_regs)->ints_mask & BIT(IC_PER_STURA) ) #define IS_IC_PER_IFNUL(_regs) ( (_regs)->ints_mask & BIT(IC_PER_IFNUL) ) /* * * * * * * * * * * * * * * Disabled wait check * * * * * * * * * * * * * * */ #define IS_IC_DISABLED_WAIT_PSW(_regs) \ ( ((_regs)->ints_mask & IC_OPEN_MASK) == 0 ) /* * * * * * * * * * * * * * * Test PER mask bits * * * * * * * * * * * * * * */ #define EN_IC_PER(_regs) unlikely( (_regs)->permode ) #define EN_IC_PER_SB(_regs) ( EN_IC_PER(_regs) && ((_regs)->ints_state & BIT(IC_PER_SB)) ) #define EN_IC_PER_IF(_regs) ( EN_IC_PER(_regs) && ((_regs)->ints_state & BIT(IC_PER_IF)) ) #define EN_IC_PER_SA(_regs) ( EN_IC_PER(_regs) && ((_regs)->ints_state & BIT(IC_PER_SA)) ) #define EN_IC_PER_GRA(_regs) ( EN_IC_PER(_regs) && ((_regs)->ints_state & BIT(IC_PER_GRA)) ) #define EN_IC_PER_STURA(_regs) ( EN_IC_PER(_regs) && ((_regs)->ints_state & BIT(IC_PER_STURA)) ) #define EN_IC_PER_IFNUL(_regs) ( EN_IC_PER(_regs) && ((_regs)->ints_state & BIT(IC_PER_IFNUL)) ) /* * * * * * * * * * * * * * * * * * * * * * * * * * Check for specific enabled pending interrupt * * * * * * * * * * * * * * * * * * * * * * * * * */ #define OPEN_IC_MCKPENDING(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & IC_MCKPENDING ) #define OPEN_IC_IOPENDING(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & IC_IOPENDING ) #define OPEN_IC_CHANRPT(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_CHANRPT) ) #define OPEN_IC_EXTPENDING(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & IC_EXTPENDING ) #define OPEN_IC_ITIMER(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_ITIMER) ) #define OPEN_IC_PTIMER(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_PTIMER) ) #define OPEN_IC_ECPSVTIMER(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_ECPSVTIMER) ) #define OPEN_IC_CLKC(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_CLKC) ) #define OPEN_IC_INTKEY(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_INTKEY) ) #define OPEN_IC_SERVSIG(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_SERVSIG) ) #define OPEN_IC_EXTCALL(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_EXTCALL) ) #define OPEN_IC_MALFALT(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_MALFALT) ) #define OPEN_IC_EMERSIG(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_EMERSIG) ) #define OPEN_IC_PER(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & IC_PER_MASK ) #define OPEN_IC_PER_SB(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_PER_SB) ) #define OPEN_IC_PER_IF(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_PER_IF) ) #define OPEN_IC_PER_SA(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_PER_SA) ) #define OPEN_IC_PER_GRA(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_PER_GRA) ) #define OPEN_IC_PER_STURA(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_PER_STURA) ) #define OPEN_IC_PER_IFNUL(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask & BIT(IC_PER_IFNUL) ) /* * * * * * * * * * * * * * * * * * * * * * * * * * Check for general enabled pending interrupt * * * * * * * * * * * * * * * * * * * * * * * * * */ #define IC_INTERRUPT_CPU(_regs) \ ( (_regs)->ints_state & (_regs)->ints_mask ) #define INTERRUPT_PENDING(_regs) IC_INTERRUPT_CPU((_regs)) #define SIE_IC_INTERRUPT_CPU(_regs) \ (((_regs)->ints_state|((_regs)->hostregs->ints_state&IC_SIE_INT)) & (_regs)->ints_mask) #define SIE_INTERRUPT_PENDING(_regs) SIE_IC_INTERRUPT_CPU((_regs)) hercules-3.12/feat370.h0000664000175000017500000000524612564723224011534 00000000000000/* FEAT370.H (c) Copyright Jan Jaeger, 2000-2009 */ /* S/370 feature definitions */ /*-------------------------------------------------------------------*/ /* This file defines the architectural features which are included */ /* at compilation time for S/370 mode */ /*-------------------------------------------------------------------*/ #if defined(OPTION_370_MODE) #define _ARCH_370_NAME "S/370" /* This file MUST NOT contain #undef statements */ #define FEATURE_2K_STORAGE_KEYS #define FEATURE_BASIC_STORAGE_KEYS #define FEATURE_EXTENDED_STORAGE_KEYS #define FEATURE_BCMODE #define FEATURE_DUAL_ADDRESS_SPACE #define FEATURE_EMULATE_VM #define FEATURE_HERCULES_DIAGCALLS #define FEATURE_HEXADECIMAL_FLOATING_POINT #define FEATURE_PER #define FEATURE_INTERVAL_TIMER #define FEATURE_SEGMENT_PROTECTION #define FEATURE_S370_CHANNEL #define FEATURE_CHANNEL_SWITCHING #define FEATURE_S370E_EXTENDED_ADDRESSING #define FEATURE_TEST_BLOCK #define FEATURE_ECPSVM #define FEATURE_VM_BLOCKIO /* The following ESA/390 features can be retrofitted to S/370 and may be activated if desired by uncommenting the appropriate define statements below and performing a complete rebuild */ //#define FEATURE_BASIC_FP_EXTENSIONS //#define FEATURE_BINARY_FLOATING_POINT //#define FEATURE_CHECKSUM_INSTRUCTION //#define FEATURE_COMPARE_AND_MOVE_EXTENDED //#define FEATURE_COMPRESSION //#define FEATURE_EXTENDED_TRANSLATION //#define FEATURE_EXTENDED_TRANSLATION_FACILITY_2 //#define FEATURE_HFP_EXTENSIONS //#define FEATURE_HFP_MULTIPLY_ADD_SUBTRACT //#define FEATURE_HFP_UNNORMALIZED_EXTENSION //#define FEATURE_IMMEDIATE_AND_RELATIVE //#define FEATURE_SQUARE_ROOT //#define FEATURE_STRING_INSTRUCTION /* The following ESAME features can be retrofitted to S/370 and may be activated if desired by uncommenting the appropriate define statements below and performing a complete rebuild */ //#define FEATURE_ESAME_N3_ESA390 //#define FEATURE_ETF2_ENHANCEMENT //#define FEATURE_ETF3_ENHANCEMENT //#define FEATURE_EXECUTE_EXTENSIONS_FACILITY //#define FEATURE_EXTENDED_IMMEDIATE //#define FEATURE_EXTENDED_TRANSLATION_FACILITY_3 //#define FEATURE_FLOATING_POINT_EXTENSION_FACILITY //#define FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY //#define FEATURE_LONG_DISPLACEMENT //#define FEATURE_MESSAGE_SECURITY_ASSIST //#define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 //#define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 //#define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 //#define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 //#define FEATURE_PARSING_ENHANCEMENT_FACILITY #endif /*defined(OPTION_370_MODE)*/ /* end of FEAT370.H */ hercules-3.12/feat390.h0000664000175000017500000000720512564723224011533 00000000000000/* FEAT390.H (c) Copyright Jan Jaeger, 2000-2009 */ /* ESA/390 feature definitions */ /*-------------------------------------------------------------------*/ /* This file defines the architectural features which are included */ /* at compilation time for ESA/390 mode */ /*-------------------------------------------------------------------*/ /* This file MUST NOT contain #undef statements */ #if defined(OPTION_390_MODE) #define _ARCH_390_NAME "ESA/390" #define FEATURE_4K_STORAGE_KEYS #define FEATURE_ACCESS_REGISTERS #define FEATURE_ADDRESS_LIMIT_CHECKING #define FEATURE_BASIC_FP_EXTENSIONS #define FEATURE_BIMODAL_ADDRESSING #define FEATURE_BINARY_FLOATING_POINT #define FEATURE_BRANCH_AND_SET_AUTHORITY #define FEATURE_BROADCASTED_PURGING #define FEATURE_CANCEL_IO_FACILITY #define FEATURE_CALLED_SPACE_IDENTIFICATION #define FEATURE_CHANNEL_SUBSYSTEM #define FEATURE_CHECKSUM_INSTRUCTION #define FEATURE_CHSC #define FEATURE_COMPARE_AND_MOVE_EXTENDED #define FEATURE_COMPRESSION #define FEATURE_CPU_RECONFIG #define FEATURE_DUAL_ADDRESS_SPACE #define FEATURE_EMULATE_VM #define FEATURE_ETF2_ENHANCEMENT /*@ZA*/ #define FEATURE_ETF3_ENHANCEMENT /*@ZA*/ #define FEATURE_EXPANDED_STORAGE #define FEATURE_EXPEDITED_SIE_SUBSET #define FEATURE_EXTENDED_STORAGE_KEYS #define FEATURE_EXTENDED_TOD_CLOCK #define FEATURE_EXTENDED_TRANSLATION #define FEATURE_EXTENDED_TRANSLATION_FACILITY_2 #define FEATURE_EXTENDED_TRANSLATION_FACILITY_3 /*@ZA*/ #define FEATURE_EXTERNAL_INTERRUPT_ASSIST #define FEATURE_FAST_SYNC_DATA_MOVER #define FEATURE_FETCH_PROTECTION_OVERRIDE #define FEATURE_FPS_ENHANCEMENT /*DFP*/ #define FEATURE_FPS_EXTENSIONS #define FEATURE_HERCULES_DIAGCALLS #define FEATURE_HEXADECIMAL_FLOATING_POINT #define FEATURE_HFP_EXTENSIONS #define FEATURE_HFP_MULTIPLY_ADD_SUBTRACT #define FEATURE_HYPERVISOR #define FEATURE_IMMEDIATE_AND_RELATIVE #define FEATURE_INCORRECT_LENGTH_INDICATION_SUPPRESSION #define FEATURE_INTEGRATED_3270_CONSOLE //#define FEATURE_INTEGRATED_ASCII_CONSOLE #define FEATURE_INTERPRETIVE_EXECUTION #define FEATURE_IO_ASSIST #define FEATURE_LOCK_PAGE #define FEATURE_LINKAGE_STACK #define FEATURE_MESSAGE_SECURITY_ASSIST #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 #define FEATURE_MOVE_PAGE_FACILITY_2 #define FEATURE_MPF_INFO #define FEATURE_MSSF_CALL #define FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE #define FEATURE_MVS_ASSIST #define FEATURE_PAGE_PROTECTION #define FEATURE_PERFORM_LOCKED_OPERATION #define FEATURE_PER #define FEATURE_PER2 #define FEATURE_PRIVATE_SPACE #define FEATURE_PROTECTION_INTERCEPTION_CONTROL #define FEATURE_QUEUED_DIRECT_IO #define FEATURE_REGION_RELOCATE #define FEATURE_RESUME_PROGRAM #define FEATURE_S390_DAT #define FEATURE_SCEDIO #define FEATURE_SERVICE_PROCESSOR #define FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST #define FEATURE_SQUARE_ROOT #define FEATURE_STORAGE_KEY_ASSIST #define FEATURE_STORAGE_PROTECTION_OVERRIDE #define FEATURE_STORE_SYSTEM_INFORMATION #define FEATURE_STRING_INSTRUCTION #define FEATURE_SUBSPACE_GROUP #define FEATURE_SUPPRESSION_ON_PROTECTION #define FEATURE_SYSTEM_CONSOLE #define FEATURE_TEST_BLOCK #define FEATURE_TRACING #define FEATURE_WAITSTATE_ASSIST #define FEATURE_STORE_FACILITY_LIST #define FEATURE_STORE_FACILITY_LIST_EXTENDED #define FEATURE_VM_BLOCKIO // #define FEATURE_VECTOR_FACILITY #endif /*defined(OPTION_390_MODE)*/ /* end of FEAT390.H */ hercules-3.12/feat900.h0000664000175000017500000001626712564723224011540 00000000000000/* FEAT900.H (c) Copyright Jan Jaeger, 2000-2009 */ /* ESAME feature definitions */ /*-------------------------------------------------------------------*/ /* This file defines the architectural features which are included */ /* at compilation time for ESAME (z/Architecture) mode */ /*-------------------------------------------------------------------*/ #if defined(OPTION_900_MODE) #define _ARCH_900_NAME "z/Arch" /* also: "ESAME" */ /* This file MUST NOT contain #undef statements */ #define FEATURE_4K_STORAGE_KEYS #define FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION /*810*/ #define FEATURE_ACCESS_REGISTERS #define FEATURE_ADDRESS_LIMIT_CHECKING #define FEATURE_ASN_AND_LX_REUSE #define FEATURE_BASIC_FP_EXTENSIONS #define FEATURE_BIMODAL_ADDRESSING #define FEATURE_BINARY_FLOATING_POINT #define FEATURE_BRANCH_AND_SET_AUTHORITY #define FEATURE_BROADCASTED_PURGING #define FEATURE_CANCEL_IO_FACILITY #define FEATURE_CALLED_SPACE_IDENTIFICATION #define FEATURE_CHANNEL_SUBSYSTEM #define FEATURE_CHECKSUM_INSTRUCTION #define FEATURE_CHSC #define FEATURE_COMPARE_AND_MOVE_EXTENDED #define FEATURE_COMPARE_AND_SWAP_AND_STORE /*407*/ #define FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2 /*ISW*/ #define FEATURE_COMPRESSION #define FEATURE_CONDITIONAL_SSKE /*407*/ #define FEATURE_CONFIGURATION_TOPOLOGY_FACILITY /*208*/ //#define FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY //#define FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY #define FEATURE_CPU_RECONFIG #define FEATURE_DAT_ENHANCEMENT #define FEATURE_DAT_ENHANCEMENT_FACILITY_2 /*@Z9*/ #define FEATURE_DECIMAL_FLOATING_POINT /*DFP*/ #define FEATURE_DFP_ZONED_CONVERSION_FACILITY /*912*/ #define FEATURE_DISTINCT_OPERANDS_FACILITY /*810*/ #define FEATURE_DUAL_ADDRESS_SPACE #define FEATURE_EMULATE_VM #define FEATURE_ENHANCED_DAT_FACILITY /*208*/ //#define FEATURE_ENHANCED_DAT_FACILITY_2 /*912*/ #define FEATURE_ENHANCED_MONITOR_FACILITY /*810*/ #define FEATURE_ENHANCED_SUPPRESSION_ON_PROTECTION /*208*/ #define FEATURE_ESAME #define FEATURE_ETF2_ENHANCEMENT /*@Z9*/ #define FEATURE_ETF3_ENHANCEMENT /*@Z9*/ #define FEATURE_EXECUTE_EXTENSIONS_FACILITY /*208*/ #define FEATURE_EXECUTION_HINT_FACILITY /*912*/ #define FEATURE_EXPANDED_STORAGE #define FEATURE_EXPEDITED_SIE_SUBSET #define FEATURE_EXTENDED_DIAG204 #define FEATURE_EXTENDED_IMMEDIATE /*@Z9*/ #define FEATURE_EXTENDED_STORAGE_KEYS #define FEATURE_EXTENDED_TOD_CLOCK #define FEATURE_EXTENDED_TRANSLATION #define FEATURE_EXTENDED_TRANSLATION_FACILITY_2 #define FEATURE_EXTENDED_TRANSLATION_FACILITY_3 #define FEATURE_EXTERNAL_INTERRUPT_ASSIST #define FEATURE_EXTRACT_CPU_TIME /*407*/ #define FEATURE_FETCH_PROTECTION_OVERRIDE #define FEATURE_FAST_BCR_SERIALIZATION_FACILITY /*810*/ #define FEATURE_FLOATING_POINT_EXTENSION_FACILITY /*810*/ #define FEATURE_FPS_ENHANCEMENT /*DFP*/ #define FEATURE_FPS_EXTENSIONS #define FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY /*208*/ #define FEATURE_HERCULES_DIAGCALLS #define FEATURE_HEXADECIMAL_FLOATING_POINT #define FEATURE_HFP_EXTENSIONS #define FEATURE_HFP_MULTIPLY_ADD_SUBTRACT #define FEATURE_HFP_UNNORMALIZED_EXTENSION /*@Z9*/ #define FEATURE_HIGH_WORD_FACILITY /*810*/ #define FEATURE_HYPERVISOR #define FEATURE_IEEE_EXCEPTION_SIMULATION /*407*/ #define FEATURE_IMMEDIATE_AND_RELATIVE #define FEATURE_INCORRECT_LENGTH_INDICATION_SUPPRESSION #define FEATURE_INTEGRATED_3270_CONSOLE //#define FEATURE_INTEGRATED_ASCII_CONSOLE #define FEATURE_INTERLOCKED_ACCESS_FACILITY /*810*/ //#define FEATURE_INTERLOCKED_ACCESS_FACILITY_2 /*912*/ #define FEATURE_INTERPRETIVE_EXECUTION #define FEATURE_IO_ASSIST #define FEATURE_IPTE_RANGE_FACILITY /*810*/ #define FEATURE_LINKAGE_STACK #define FEATURE_LOAD_AND_TRAP_FACILITY /*912*/ #define FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY /*810*/ #define FEATURE_LOAD_REVERSED #define FEATURE_LOAD_STORE_ON_CONDITION_FACILITY /*810*/ //#define FEATURE_LOCAL_TLB_CLEARING_FACILITY /*912*/ #define FEATURE_LOCK_PAGE #define FEATURE_LONG_DISPLACEMENT #define FEATURE_MESSAGE_SECURITY_ASSIST #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 /*@Z9*/ #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /*810*/ #define FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*810*/ #define FEATURE_MIDAW /*@Z9*/ #define FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY /*912*/ #define FEATURE_MOVE_PAGE_FACILITY_2 #define FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS /*208*/ #define FEATURE_MPF_INFO #define FEATURE_MVS_ASSIST //#define FEATURE_NONQUIESCING_KEY_SETTING_FACILITY /*810*/ #define FEATURE_PAGE_PROTECTION #define FEATURE_PARSING_ENHANCEMENT_FACILITY /*208*/ #define FEATURE_PERFORM_LOCKED_OPERATION #define FEATURE_PER #define FEATURE_PER2 #define FEATURE_PER3 /*@Z9*/ //#define FEATURE_PER_ZERO_ADDRESS_DETECTION_FACILITY /*912*/ #define FEATURE_PFPO /*407*/ #define FEATURE_POPULATION_COUNT_FACILITY /*810*/ #define FEATURE_PRIVATE_SPACE //#define FEATURE_PROCESSOR_ASSIST_FACILITY /*912*/ //#define FEATURE_PROGRAM_DIRECTED_REIPL /*DIAG308 incomplete*/ /*@Z9*/ #define FEATURE_PROTECTION_INTERCEPTION_CONTROL #define FEATURE_QUEUED_DIRECT_IO #define FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY /*810*/ //#define FEATURE_RESTORE_SUBCHANNEL_FACILITY /*208*/ #define FEATURE_RESUME_PROGRAM #define FEATURE_REGION_RELOCATE #define FEATURE_SCEDIO #define FEATURE_SENSE_RUNNING_STATUS /*@Z9*/ #define FEATURE_SERVICE_PROCESSOR #define FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST #define FEATURE_SQUARE_ROOT #define FEATURE_STORAGE_KEY_ASSIST #define FEATURE_STORAGE_PROTECTION_OVERRIDE #define FEATURE_STORE_CLOCK_FAST #define FEATURE_STORE_FACILITY_LIST #define FEATURE_STORE_FACILITY_LIST_EXTENDED /*@Z9*/ #define FEATURE_STORE_SYSTEM_INFORMATION #define FEATURE_STRING_INSTRUCTION #define FEATURE_SUBSPACE_GROUP #define FEATURE_SUPPRESSION_ON_PROTECTION #define FEATURE_SYSTEM_CONSOLE #define FEATURE_TEST_BLOCK #define FEATURE_TOD_CLOCK_STEERING /*@Z9*/ #define FEATURE_TRACING //#define FEATURE_TRANSACTIONAL_EXECUTION_FACILITY /*912*/ #define FEATURE_WAITSTATE_ASSIST #define FEATURE_VM_BLOCKIO //#define FEATURE_WARNING_TRACK_INTERRUPTION_FACILITY /*912*/ #endif /*defined(OPTION_900_MODE)*/ /* end of FEAT900.H */ hercules-3.12/featall.h0000664000175000017500000003006212564723224011765 00000000000000/* FEATALL.H (c) Copyright Jan Jaeger, 2000-2009 */ /* Architecture-dependent macro definitions */ /*-------------------------------------------------------------------*/ /* Default features */ /* All existing features MUST be #undef-ed here. */ /*-------------------------------------------------------------------*/ #define OPTION_370_MODE /* Generate S/370 support */ #define OPTION_390_MODE /* Generate ESA/390 support */ #define OPTION_900_MODE /* Generate ESAME support */ #define OPTION_LPP_RESTRICT /* Disable Licensed Software */ #define OPTION_SMP /* Enable SMP support */ #define VECTOR_SECTION_SIZE 128 /* Vector section size */ #define VECTOR_PARTIAL_SUM_NUMBER 1 /* Vector partial sum number */ #define CKD_MAXFILES 27 /* Max files per CKD volume */ #define OPTION_MIPS_COUNTING /* Display MIPS on ctl panel */ #define PANEL_REFRESH_RATE /* Enable panrate feature */ #define PANEL_REFRESH_RATE_FAST 50 /* Fast refresh rate */ #define PANEL_REFRESH_RATE_SLOW 500 /* Slow refresh rate */ #define DEFAULT_TIMER_REFRESH_USECS 50 /* Default timer refresh int */ #define MAX_DEVICE_THREAD_IDLE_SECS 300 /* 5 Minute thread timeout */ #undef OPTION_NO_INLINE_DAT /* Performance option */ #undef OPTION_NO_INLINE_LOGICAL /* Performance option */ #undef OPTION_NO_INLINE_VSTORE /* Performance option */ #undef OPTION_NO_INLINE_IFETCH /* Performance option */ #define OPTION_MULTI_BYTE_ASSIST /* Performance option */ #define OPTION_SINGLE_CPU_DW /* Performance option (ia32) */ #define OPTION_FAST_DEVLOOKUP /* Fast devnum/subchan lookup*/ #define OPTION_IODELAY_KLUDGE /* IODELAY kludge for linux */ #undef OPTION_FOOTPRINT_BUFFER /* 2048 ** Size must be a power of 2 */ #undef OPTION_INSTRUCTION_COUNTING /* First use trace and count */ #define OPTION_CKD_KEY_TRACING /* Trace CKD search keys */ #undef OPTION_CMPSC_DEBUGLVL /* 3 ** 1=Exp 2=Comp 3=Both debug */ #undef MODEL_DEPENDENT_STCM /* STCM, STCMH always store */ #define OPTION_NOP_MODEL158_DIAGNOSE /* NOP mod 158 specific diags*/ #define FEATURE_ALD_FORMAT 0 /* Use fmt0 Access-lists */ #define FEATURE_SIE_MAXZONES 8 /* Maximum SIE Zones */ #define FEATURE_LCSS_MAX 4 /* Number of supported lcss's*/ // #define SIE_DEBUG_PERFMON /* SIE performance monitor */ #define OPTION_LPARNAME /* DIAG 204 lparname */ #define OPTION_HTTP_SERVER /* HTTP server support */ #define OPTION_WAKEUP_SELECT_VIA_PIPE /* Use communication pipes to interrupt selects instead of inter-thread signaling */ #define OPTION_TIMESTAMP_LOGFILE /* Hardcopy logfile HH:MM:SS */ #define OPTION_IPLPARM /* IPL PARM a la VM */ #define OPTION_PTTRACE /* Pthreads tracing */ //#define OPTION_DEBUG_MESSAGES /* Prefix msgs with filename // and line# if DEBUG build */ #define OPTION_SET_STSI_INFO /* Set STSI info in cfg file */ #define OPTION_TAPE_AUTOMOUNT /* "Automount" CCWs support */ #define OPTION_CMDTGT /* the cmdtgt command */ #define OPTION_MSGCLR /* Colored messages */ #define OPTION_MSGHLD /* Sticky messages */ #if defined(OPTION_MSGHLD) && !defined(OPTION_MSGCLR) #error OPTION_MSGHLD requires OPTION_MSGCLR #endif // defined(OPTION_MSGHLD) && !defined(OPTION_MSGCLR) #if (CKD_MAXFILES > 35) #error CKD_MAXFILES can not exceed design limit of 35 #endif /*********************************************************************\ ********************************************************************* ** ** ** *** NOTE! *** ** ** ** ** All HOST-operating-system-specific FEATUREs and OPTIONs ** ** should be #defined in the below header (and ONLY in the ** ** below header!) Please read the comments there! ** ** ** ********************************************************************* \*********************************************************************/ #include "hostopts.h" // (HOST-specific options/feature settings) // (allow for compiler command-line overrides...) #if defined(OPTION_370_MODE) && defined(NO_370_MODE) #undef OPTION_370_MODE #endif #if defined(OPTION_390_MODE) && defined(NO_390_MODE) #undef OPTION_390_MODE #endif #if defined(OPTION_900_MODE) && defined(NO_900_MODE) #undef OPTION_900_MODE #endif #undef FEATURE_4K_STORAGE_KEYS #undef FEATURE_2K_STORAGE_KEYS #undef FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION /*810*/ #undef FEATURE_ACCESS_REGISTERS #undef FEATURE_ADDRESS_LIMIT_CHECKING #undef FEATURE_ASN_AND_LX_REUSE #undef FEATURE_BASIC_FP_EXTENSIONS #undef FEATURE_BASIC_STORAGE_KEYS #undef FEATURE_BCMODE #undef FEATURE_BIMODAL_ADDRESSING #undef FEATURE_BINARY_FLOATING_POINT #undef FEATURE_BRANCH_AND_SET_AUTHORITY #undef FEATURE_BROADCASTED_PURGING #undef FEATURE_CALLED_SPACE_IDENTIFICATION #undef FEATURE_CANCEL_IO_FACILITY #undef FEATURE_CHANNEL_SUBSYSTEM #undef FEATURE_CHANNEL_SWITCHING #undef FEATURE_CHECKSUM_INSTRUCTION #undef FEATURE_CHSC #undef FEATURE_COMPARE_AND_MOVE_EXTENDED #undef FEATURE_COMPARE_AND_SWAP_AND_STORE /*407*/ #undef FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2 /*208*/ #undef FEATURE_COMPRESSION #undef FEATURE_CONDITIONAL_SSKE /*407*/ #undef FEATURE_CONFIGURATION_TOPOLOGY_FACILITY /*208*/ #undef FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY #undef FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY #undef FEATURE_CPU_RECONFIG #undef FEATURE_DAT_ENHANCEMENT #undef FEATURE_DAT_ENHANCEMENT_FACILITY_2 /*@Z9*/ #undef FEATURE_DECIMAL_FLOATING_POINT /*DFP*/ #undef FEATURE_DFP_ZONED_CONVERSION_FACILITY /*912*/ #undef FEATURE_DISTINCT_OPERANDS_FACILITY /*810*/ #undef FEATURE_DUAL_ADDRESS_SPACE #undef FEATURE_ECPSVM #undef FEATURE_EMULATE_VM #undef FEATURE_ENHANCED_DAT_FACILITY /*208*/ #undef FEATURE_ENHANCED_DAT_FACILITY_2 /*912*/ #undef FEATURE_ENHANCED_MONITOR_FACILITY /*810*/ #undef FEATURE_ENHANCED_SUPPRESSION_ON_PROTECTION /*208*/ #undef FEATURE_ESAME #undef FEATURE_ESAME_N3_ESA390 #undef FEATURE_ETF2_ENHANCEMENT /*@Z9*/ #undef FEATURE_ETF3_ENHANCEMENT /*@Z9*/ #undef FEATURE_EXECUTE_EXTENSIONS_FACILITY /*208*/ #undef FEATURE_EXECUTION_HINT_FACILITY /*912*/ #undef FEATURE_EXPANDED_STORAGE #undef FEATURE_EXPEDITED_SIE_SUBSET #undef FEATURE_EXTENDED_DIAG204 #undef FEATURE_EXTENDED_IMMEDIATE /*@Z9*/ #undef FEATURE_EXTENDED_STORAGE_KEYS #undef FEATURE_EXTENDED_TOD_CLOCK #undef FEATURE_EXTENDED_TRANSLATION #undef FEATURE_EXTENDED_TRANSLATION_FACILITY_2 #undef FEATURE_EXTENDED_TRANSLATION_FACILITY_3 #undef FEATURE_EXTERNAL_INTERRUPT_ASSIST #undef FEATURE_EXTRACT_CPU_TIME /*407*/ #undef FEATURE_FAST_BCR_SERIALIZATION_FACILITY /*810*/ #undef FEATURE_FAST_SYNC_DATA_MOVER #undef FEATURE_FETCH_PROTECTION_OVERRIDE #undef FEATURE_FLOATING_POINT_EXTENSION_FACILITY /*810*/ #undef FEATURE_FPS_ENHANCEMENT /*DFP*/ #undef FEATURE_FPS_EXTENSIONS #undef FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY #undef FEATURE_HERCULES_DIAGCALLS #undef FEATURE_HEXADECIMAL_FLOATING_POINT #undef FEATURE_HFP_EXTENSIONS #undef FEATURE_HFP_MULTIPLY_ADD_SUBTRACT #undef FEATURE_HFP_UNNORMALIZED_EXTENSION /*@Z9*/ #undef FEATURE_HIGH_WORD_FACILITY /*810*/ #undef FEATURE_HYPERVISOR #undef FEATURE_IEEE_EXCEPTION_SIMULATION /*407*/ #undef FEATURE_IMMEDIATE_AND_RELATIVE #undef FEATURE_INCORRECT_LENGTH_INDICATION_SUPPRESSION #undef FEATURE_INTEGRATED_3270_CONSOLE #undef FEATURE_INTEGRATED_ASCII_CONSOLE #undef FEATURE_INTERLOCKED_ACCESS_FACILITY /*810*/ #undef FEATURE_INTERLOCKED_ACCESS_FACILITY_2 /*912*/ #undef FEATURE_INTERPRETIVE_EXECUTION #undef FEATURE_INTERVAL_TIMER #undef FEATURE_IPTE_RANGE_FACILITY /*810*/ #undef FEATURE_IO_ASSIST #undef FEATURE_LINKAGE_STACK #undef FEATURE_LOAD_AND_TRAP_FACILITY /*912*/ #undef FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY #undef FEATURE_LOAD_REVERSED #undef FEATURE_LOAD_STORE_ON_CONDITION_FACILITY /*810*/ #undef FEATURE_LOCAL_TLB_CLEARING_FACILITY /*912*/ #undef FEATURE_LOCK_PAGE #undef FEATURE_LONG_DISPLACEMENT #undef FEATURE_MESSAGE_SECURITY_ASSIST #undef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 /*@Z9*/ #undef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #undef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /*810*/ #undef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*810*/ #undef FEATURE_MIDAW /*@Z9*/ #undef FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY /*912*/ #undef FEATURE_MOVE_PAGE_FACILITY_2 #undef FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS /*208*/ #undef FEATURE_MPF_INFO #undef FEATURE_MSSF_CALL #undef FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE #undef FEATURE_MVS_ASSIST #undef FEATURE_NONQUIESCING_KEY_SETTING_FACILITY /*810*/ #undef FEATURE_PAGE_PROTECTION #undef FEATURE_PARSING_ENHANCEMENT_FACILITY /*208*/ #undef FEATURE_PERFORM_LOCKED_OPERATION #undef FEATURE_PER #undef FEATURE_PER2 #undef FEATURE_PER3 /*@Z9*/ #undef FEATURE_PER_ZERO_ADDRESS_DETECTION_FACILITY /*912*/ #undef FEATURE_PFPO /*407*/ #undef FEATURE_POPULATION_COUNT_FACILITY /*810*/ #undef FEATURE_PRIVATE_SPACE #undef FEATURE_PROCESSOR_ASSIST_FACILITY /*912*/ #undef FEATURE_PROGRAM_DIRECTED_REIPL /*@Z9*/ #undef FEATURE_PROTECTION_INTERCEPTION_CONTROL #undef FEATURE_QUEUED_DIRECT_IO #undef FEATURE_REGION_RELOCATE #undef FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY /*810*/ #undef FEATURE_RESTORE_SUBCHANNEL_FACILITY /*208*/ #undef FEATURE_RESUME_PROGRAM #undef FEATURE_SCEDIO #undef FEATURE_S370_CHANNEL #undef FEATURE_S390_DAT #undef FEATURE_S370E_EXTENDED_ADDRESSING #undef FEATURE_SEGMENT_PROTECTION #undef FEATURE_SENSE_RUNNING_STATUS /*@Z9*/ #undef FEATURE_SERVICE_PROCESSOR #undef FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST #undef FEATURE_SQUARE_ROOT #undef FEATURE_STORAGE_KEY_ASSIST #undef FEATURE_STORAGE_PROTECTION_OVERRIDE #undef FEATURE_STORE_CLOCK_FAST /*@Z9*/ #undef FEATURE_STORE_FACILITY_LIST #undef FEATURE_STORE_FACILITY_LIST_EXTENDED /*@Z9*/ #undef FEATURE_STORE_SYSTEM_INFORMATION #undef FEATURE_STRING_INSTRUCTION #undef FEATURE_SUBSPACE_GROUP #undef FEATURE_SUPPRESSION_ON_PROTECTION #undef FEATURE_SYSTEM_CONSOLE #undef FEATURE_TEST_BLOCK #undef FEATURE_TOD_CLOCK_STEERING /*@Z9*/ #undef FEATURE_TRACING #undef FEATURE_TRANSACTIONAL_EXECUTION_FACILITY /*912*/ #undef FEATURE_VECTOR_FACILITY #undef FEATURE_VM_BLOCKIO #undef FEATURE_WAITSTATE_ASSIST #undef FEATURE_WARNING_TRACK_INTERRUPTION_FACILITY /*912*/ /* end of FEATALL.H */ hercules-3.12/featchk.h0000664000175000017500000004106212564723224011764 00000000000000/* FEATCHK.H (c) Copyright Jan Jaeger, 2000-2009 */ /* Feature definition consistency checks */ /*-------------------------------------------------------------------*/ /* Perform various checks on feature combinations, and set */ /* additional flags to percolate certain features such as */ /* SIE down to lower architecture levels such that these */ /* can include emulation support */ /* */ /* FEATURE_XXXX is defined per architecture mode, and */ /* _FEATURE_XXXX is defined across all architectures */ /* if FEATURE_ XXXX is defined for any architecture mode. */ /* */ /*-------------------------------------------------------------------*/ #if defined(FEATCHK_CHECK_ALL) /* FEATURE_INTERPRETIVE_EXECUTION is related to host related issues _FEATURE_SIE is related to guest (emulation) related issues. This because if FEATURE_INTERPRETIVE_EXECUTION is defined for say 390 mode, then _FEATURE_SIE will also need to be in 370 in order to support 370 mode SIE emulation */ #if defined(FEATURE_INTERPRETIVE_EXECUTION) #define _FEATURE_SIE #if defined(FEATURE_ESAME) #define _FEATURE_ZSIE #endif #if defined(FEATURE_PROTECTION_INTERCEPTION_CONTROL) #define _FEATURE_PROTECTION_INTERCEPTION_CONTROL #endif #endif /* _FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE is used for host related processing issues, FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE is defined only in ESA/390 mode. MCDS is an ESA/390 feature that is supported under z/Architecture SIE */ #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) #define _FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE #endif #if defined(FEATURE_2K_STORAGE_KEYS) #define _FEATURE_2K_STORAGE_KEYS #endif #if defined(FEATURE_INTERVAL_TIMER) #define _FEATURE_INTERVAL_TIMER #endif #if defined(FEATURE_ECPSVM) #define _FEATURE_ECPSVM #endif #if defined(FEATURE_VECTOR_FACILITY) #define _FEATURE_VECTOR_FACILITY #endif #if defined(FEATURE_CHANNEL_SUBSYSTEM) #define _FEATURE_CHANNEL_SUBSYSTEM #endif #if defined(FEATURE_SYSTEM_CONSOLE) #define _FEATURE_SYSTEM_CONSOLE #endif #if defined(FEATURE_EXPANDED_STORAGE) #define _FEATURE_EXPANDED_STORAGE #endif #if defined(FEATURE_ECPSVM) #define _FEATURE_ECPSVM #endif #if defined(_FEATURE_SIE) && defined(FEATURE_STORAGE_KEY_ASSIST) #define _FEATURE_STORAGE_KEY_ASSIST #endif #if defined(FEATURE_CPU_RECONFIG) #define _FEATURE_CPU_RECONFIG #endif #if defined(FEATURE_PER) #define _FEATURE_PER #endif #if defined(FEATURE_PER2) #define _FEATURE_PER2 #endif #if defined(FEATURE_EXPEDITED_SIE_SUBSET) #define _FEATURE_EXPEDITED_SIE_SUBSET #endif #if defined(FEATURE_REGION_RELOCATE) #define _FEATURE_REGION_RELOCATE #endif #if defined(FEATURE_IO_ASSIST) #define _FEATURE_IO_ASSIST #endif #if defined(FEATURE_WAITSTATE_ASSIST) #define _FEATURE_WAITSTATE_ASSIST #endif #if defined(FEATURE_EXTERNAL_INTERRUPT_ASSIST) #define _FEATURE_EXTERNAL_INTERRUPT_ASSIST #endif #if defined(FEATURE_MESSAGE_SECURITY_ASSIST) #define _FEATURE_MESSAGE_SECURITY_ASSIST #endif #if defined(FEATURE_ASN_AND_LX_REUSE) #define _FEATURE_ASN_AND_LX_REUSE #endif #if defined(FEATURE_INTEGRATED_3270_CONSOLE) #define _FEATURE_INTEGRATED_3270_CONSOLE #endif #if defined(FEATURE_INTEGRATED_ASCII_CONSOLE) #define _FEATURE_INTEGRATED_ASCII_CONSOLE #endif #if defined(FEATURE_ESAME) #define _FEATURE_ESAME #endif #if defined(FEATURE_ESAME_N3_ESA390) #define _FEATURE_ESAME_N3_ESA390 #endif #if defined(FEATURE_DAT_ENHANCEMENT) #define _FEATURE_DAT_ENHANCEMENT #endif #if defined(FEATURE_STORE_FACILITY_LIST_EXTENDED) #define _FEATURE_STORE_FACILITY_LIST_EXTENDED #endif #if defined(FEATURE_ENHANCED_DAT_FACILITY) #define _FEATURE_ENHANCED_DAT_FACILITY #endif #if defined(FEATURE_ENHANCED_DAT_FACILITY_2) #define _FEATURE_ENHANCED_DAT_FACILITY_2 #endif #if defined(FEATURE_SENSE_RUNNING_STATUS) #define _FEATURE_SENSE_RUNNING_STATUS #endif #if defined(FEATURE_CONDITIONAL_SSKE) #define _FEATURE_CONDITIONAL_SSKE #endif #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) #define _FEATURE_CONFIGURATION_TOPOLOGY_FACILITY #endif #if defined(FEATURE_IPTE_RANGE_FACILITY) #define _FEATURE_IPTE_RANGE_FACILITY #endif #if defined(FEATURE_NONQUIESCING_KEY_SETTING_FACILITY) #define _FEATURE_NONQUIESCING_KEY_SETTING_FACILITY #endif #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) #define _FEATURE_EXTENDED_TRANSLATION_FACILITY_2 #endif #if defined(FEATURE_MESSAGE_SECURITY_ASSIST) #define _FEATURE_MESSAGE_SECURITY_ASSIST #endif #if defined(FEATURE_LONG_DISPLACEMENT) #define _FEATURE_LONG_DISPLACEMENT #endif #if defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT) #define _FEATURE_HFP_MULTIPLY_ADD_SUBTRACT #endif #if defined(FEATURE_EXTENDED_IMMEDIATE) #define _FEATURE_EXTENDED_IMMEDIATE #endif #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_3) #define _FEATURE_EXTENDED_TRANSLATION_FACILITY_3 #endif #if defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) #define _FEATURE_HFP_UNNORMALIZED_EXTENSION #endif #if defined(FEATURE_ETF2_ENHANCEMENT) #define _FEATURE_ETF2_ENHANCEMENT #endif #if defined(FEATURE_STORE_CLOCK_FAST) #define _FEATURE_STORE_CLOCK_FAST #endif #if defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS) #define _FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS #endif #if defined(FEATURE_TOD_CLOCK_STEERING) #define _FEATURE_TOD_CLOCK_STEERING #endif #if defined(FEATURE_ETF3_ENHANCEMENT) #define _FEATURE_ETF3_ENHANCEMENT #endif #if defined(FEATURE_EXTRACT_CPU_TIME) #define _FEATURE_EXTRACT_CPU_TIME #endif #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE) #define _FEATURE_COMPARE_AND_SWAP_AND_STORE #endif #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) #define _FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2 #endif #if defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY) #define _FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY #endif #if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) #define _FEATURE_EXECUTE_EXTENSIONS_FACILITY #endif #if defined(FEATURE_ENHANCED_MONITOR_FACILITY) #define _FEATURE_ENHANCED_MONITOR_FACILITY #endif #if defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY) #define _FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY #endif #if defined(FEATURE_FPS_ENHANCEMENT) #define _FEATURE_FPS_ENHANCEMENT #endif #if defined(FEATURE_DECIMAL_FLOATING_POINT) #define _FEATURE_DECIMAL_FLOATING_POINT #endif #if defined(FEATURE_PFPO) #define _FEATURE_PFPO #endif #if defined(FEATURE_FAST_BCR_SERIALIZATION_FACILITY) #define _FEATURE_FAST_BCR_SERIALIZATION_FACILITY #endif #if defined(FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY) #define _FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY #endif #if defined(FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY) #define _FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY #endif #if defined(FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY) #define _FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY #endif #if defined(FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION) #define _FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION #endif #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) #define _FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 #endif #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) #define _FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 #endif #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1) #define _FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 #endif #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2) #define _FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #endif #if defined(FEATURE_HERCULES_DIAGCALLS) #define _FEATURE_HERCULES_DIAGCALLS #endif #undef _VSTORE_C_STATIC #if !defined(OPTION_NO_INLINE_VSTORE) #define _VSTORE_C_STATIC static inline #define _VSTORE_FULL_C_STATIC static #else #define _VSTORE_C_STATIC #define _VSTORE_FULL_C_STATIC #endif #undef _VFETCH_C_STATIC #if !defined(OPTION_NO_INLINE_IFETCH) #define _VFETCH_C_STATIC static inline #else #define _VFETCH_C_STATIC #endif #undef _DAT_C_STATIC #if !defined(OPTION_NO_INLINE_DAT) #define _DAT_C_STATIC static inline #else #define _DAT_C_STATIC #endif #undef _LOGICAL_C_STATIC #if !defined(OPTION_NO_INLINE_LOGICAL) #define _LOGICAL_C_STATIC static inline #else #define _LOGICAL_C_STATIC #endif #if !defined(OPTION_370_MODE) \ && !defined(OPTION_390_MODE) \ && !defined(OPTION_900_MODE) #error No Architecture mode #endif #if defined(OPTION_370_MODE) #define _370 #define _ARCHMODE1 370 #define ARCH_370 0 #endif #if defined(OPTION_390_MODE) #define _390 #if !defined(_ARCHMODE1) #define _ARCHMODE1 390 #define ARCH_390 0 #else #define _ARCHMODE2 390 #define ARCH_390 1 #endif #endif #if defined(OPTION_900_MODE) #define _900 #if !defined(_ARCHMODE2) #define _ARCHMODE2 900 #define ARCH_900 1 #else #define _ARCHMODE3 900 #define ARCH_900 2 #endif #endif #if !defined(ARCH_370) #define ARCH_370 -1 #endif #if !defined(ARCH_390) #define ARCH_390 -1 #endif #if !defined(ARCH_900) #define ARCH_900 -1 #endif #if defined(_ARCHMODE3) #define GEN_MAXARCH 3+2 #elif defined(_ARCHMODE2) #define GEN_MAXARCH 2+2 #else #define GEN_MAXARCH 1+2 #endif #if defined(_900) && !defined(_390) #error OPTION_390_MODE must be enabled for OPTION_900_MODE #endif #else /*!defined(FEATCHK_CHECK_ALL)*/ /* When ESAME is installed then all instructions marked N3 in the reference are also available in ESA/390 mode */ #if defined(_900) && (__GEN_ARCH == 390) #define FEATURE_ESAME_N3_ESA390 #endif #if !defined(FEATURE_2K_STORAGE_KEYS) \ && !defined(FEATURE_4K_STORAGE_KEYS) #error Storage keys must be 2K or 4K #endif #if defined(FEATURE_EXTENDED_STORAGE_KEYS) #if !defined(FEATURE_S370E_EXTENDED_ADDRESSING) #define FEATURE_S370E_EXTENDED_ADDRESSING #endif #endif #if defined(FEATURE_EXPANDED_STORAGE) \ && !defined(FEATURE_4K_STORAGE_KEYS) #error Expanded storage cannot be defined with 2K storage keys #endif #if defined(_900) && defined(FEATURE_VECTOR_FACILITY) #error Vector Facility not supported on ESAME capable processors #endif #if !defined(FEATURE_S370_CHANNEL) && !defined(FEATURE_CHANNEL_SUBSYSTEM) #error Either S/370 Channel or Channel Subsystem must be defined #endif #if defined(FEATURE_S370_CHANNEL) && defined(FEATURE_CHANNEL_SUBSYSTEM) #error S/370 Channel and Channel Subsystem cannot both be defined #endif #if defined(FEATURE_CANCEL_IO_FACILITY) \ && !defined(FEATURE_CHANNEL_SUBSYSTEM) #error Cancel I/O facility requires Channel Subsystem #endif #if defined(FEATURE_MOVE_PAGE_FACILITY_2) \ && !defined(FEATURE_4K_STORAGE_KEYS) #error Move page facility cannot be defined with 2K storage keys #endif #if defined(FEATURE_FAST_SYNC_DATA_MOVER) \ && !defined(FEATURE_MOVE_PAGE_FACILITY_2) #error Fast sync data mover facility requires Move page facility #endif #if defined(FEATURE_ESAME) \ && defined(FEATURE_INTERPRETIVE_EXECUTION) \ && !defined(_FEATURE_SIE) #error ESA/390 SIE must be defined when defining ESAME SIE #endif #if defined(FEATURE_ENHANCED_DAT_FACILITY_2) \ && !defined(FEATURE_ENHANCED_DAT_FACILITY) #error Enhanced DAT facility 2 requires enhanced DAT facility #endif #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) \ && !defined(FEATURE_INTERPRETIVE_EXECUTION) #error MCDS only supported with SIE #endif #if defined(FEATURE_PROTECTION_INTERCEPTION_CONTROL) \ && !defined(FEATURE_INTERPRETIVE_EXECUTION) #error Protection Interception Control only supported with SIE #endif #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) \ && !defined(FEATURE_STORAGE_KEY_ASSIST) #error MCDS requires storage key assist #endif #if defined(FEATURE_SIE) && defined(FEATURE_ESAME) \ && !defined(FEATURE_STORAGE_KEY_ASSIST) #error ESAME SIE requires storage key assist #endif #if defined(FEATURE_STORAGE_KEY_ASSIST) \ && !defined(FEATURE_INTERPRETIVE_EXECUTION) #error Storage Key assist only supported with SIE #endif #if defined(FEATURE_REGION_RELOCATE) \ && !defined(FEATURE_INTERPRETIVE_EXECUTION) #error Region Relocate Facility only supported with SIE #endif #if defined(FEATURE_IO_ASSIST) \ && !defined(_FEATURE_SIE) #error I/O Assist Feature only supported with SIE #endif #if defined(FEATURE_IO_ASSIST) \ && !defined(_FEATURE_REGION_RELOCATE) #error Region Relocate Facility required for IO Assist #endif #if defined(FEATURE_EXTERNAL_INTERRUPT_ASSIST) \ && !defined(_FEATURE_SIE) #error External Interruption assist only supported with SIE #endif #if defined(FEATURE_EXPEDITED_SIE_SUBSET) \ && !defined(_FEATURE_SIE) #error Expedited SIE Subset only supported with SIE #endif #if defined(FEATURE_ASN_AND_LX_REUSE) #if !defined(FEATURE_DUAL_ADDRESS_SPACE) #error ASN-and-LX-Reuse requires Dual Address-Space feature #endif #if !defined(FEATURE_ESAME) #error ASN-and-LX-Reuse is only supported with ESAME #endif #endif #if defined(FEATURE_ESAME) \ && defined(FEATURE_VECTOR_FACILITY) #error Vector Facility not supported in ESAME mode #endif #if defined(FEATURE_BINARY_FLOATING_POINT) \ && !defined(FEATURE_BASIC_FP_EXTENSIONS) #error Binary floating point requires basic FP extensions #endif #if defined(FEATURE_DECIMAL_FLOATING_POINT) \ && !defined(FEATURE_BASIC_FP_EXTENSIONS) #error Decimal floating point requires basic FP extensions #endif #if defined(FEATURE_BASIC_FP_EXTENSIONS) \ && !defined(FEATURE_HEXADECIMAL_FLOATING_POINT) #error Basic FP extensions requires hexadecimal floating point #endif #if !defined(FEATURE_BASIC_FP_EXTENSIONS) #if defined(FEATURE_HFP_EXTENSIONS) \ || defined(FEATURE_FPS_EXTENSIONS) #error Floating point extensions require basic FP extensions #endif #endif #if defined(FEATURE_FPS_EXTENSIONS) \ && !defined(FEATURE_BINARY_FLOATING_POINT) #error FP support extensions requires binary floating point #endif #if defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT) \ && !defined(FEATURE_HEXADECIMAL_FLOATING_POINT) #error HFP multiply add/subtract requires hexadecimal floating point #endif #if defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) \ && !defined(FEATURE_HEXADECIMAL_FLOATING_POINT) #error HFP unnormalized extension requires hexadecimal floating point #endif #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) \ && !defined(FEATURE_BINARY_FLOATING_POINT) #error Floating point extension facility requires binary floating point #endif #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) \ && !defined(FEATURE_DECIMAL_FLOATING_POINT) #error Floating point extension facility requires decimal floating point #endif #if defined(FEATURE_PER2) && !defined(FEATURE_PER) #error FEATURE_PER must be defined when using FEATURE_PER2 #endif #if defined(FEATURE_PER3) && !defined(FEATURE_PER) #error FEATURE_PER must be defined when using FEATURE_PER3 #endif #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) && !defined(FEATURE_COMPARE_AND_SWAP_AND_STORE) #error FEATURE_COMPARE_AND_SWAP_AND_STORE must be defined when using FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2 #endif #if defined(FEATURE_INTEGRATED_3270_CONSOLE) && !defined(FEATURE_SYSTEM_CONSOLE) #error Integrated 3270 console requires FEATURE_SYSTEM_CONSOLE #endif #if defined(FEATURE_INTEGRATED_ASCII_CONSOLE) && !defined(FEATURE_SYSTEM_CONSOLE) #error Integrated ASCII console requires FEATURE_SYSTEM_CONSOLE #endif #if defined(FEATURE_VM_BLOCKIO) && !defined(FEATURE_EMULATE_VM) #error VM Standard Block I/O DIAGNOSE 0x250 requires FEATURE_EMULATE_VM #endif #if defined(FEATURE_MESSAGE_SECURITY_ASSIST) #if defined(_370) #define _370_FEATURE_MESSAGE_SECURITY_ASSIST #endif #if defined(_390) #define _390_FEATURE_MESSAGE_SECURITY_ASSIST #endif #if defined(_900) #define _900_FEATURE_MESSAGE_SECURITY_ASSIST #endif #endif /*defined(FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(FEATURE_STORE_FACILITY_LIST_EXTENDED) #if !defined(FEATURE_STORE_FACILITY_LIST) #error STFLE requires STFL (FEATURE_STORE_FACILITY_LIST_EXTENDED requires FEATURE_STORE_FACILITY_LIST) #endif #endif #if defined(FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION) /*810*/ #if !defined(FEATURE_ENHANCED_SUPPRESSION_ON_PROTECTION) #error Access-Exception Fetch/Store Indication facility requires Enhanced Suppression on Protection #endif #endif #if defined(FEATURE_ENHANCED_SUPPRESSION_ON_PROTECTION) /*208*/ #if !defined(FEATURE_SUPPRESSION_ON_PROTECTION) #error Enhanced Suppression on Protection facility requires Suppression on Protection #endif #endif #if defined(FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY)\ || defined(FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY) #if !defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY) #error CPU Measurement facilities requires Load Program Parameter facility #endif #endif #endif /*!defined(FEATALL_CHECKALL)*/ /* end of FEATCHK.H */ hercules-3.12/feature.h0000664000175000017500000005377112564723224012024 00000000000000/* FEATURE.H (c) Copyright Jan Jaeger, 2000-2009 */ /* Architecture-dependent macro definitions */ #ifdef HAVE_CONFIG_H #include // Hercules build configuration options/settings #endif #if !defined(FEATCHK_CHECK_DONE) #include "featall.h" #include "feat370.h" #include "feat390.h" #include "feat900.h" #define FEATCHK_CHECK_ALL #include "featchk.h" #undef FEATCHK_CHECK_ALL #define FEATCHK_CHECK_DONE #endif /*!defined(FEATCHK_CHECK_DONE)*/ #undef __GEN_ARCH #if defined(_GEN_ARCH) #define __GEN_ARCH _GEN_ARCH #else #define __GEN_ARCH _ARCHMODE1 #endif #include "featall.h" #if __GEN_ARCH == 370 #include "feat370.h" #elif __GEN_ARCH == 390 #include "feat390.h" #elif __GEN_ARCH == 900 #include "feat900.h" #else #error Unable to determine Architecture Mode #endif #include "featchk.h" #undef ARCH_MODE #undef APPLY_PREFIXING #undef AMASK #undef ADDRESS_MAXWRAP #undef ADDRESS_MAXWRAP_E #undef REAL_MODE #undef PER_MODE #undef ASF_ENABLED #undef ASN_AND_LX_REUSE_ENABLED #undef ASTE_AS_DESIGNATOR #undef ASTE_LT_DESIGNATOR #undef SAEVENT_BIT #undef SSEVENT_BIT #undef SSGROUP_BIT #undef LSED_UET_HDR #undef LSED_UET_TLR #undef LSED_UET_BAKR #undef LSED_UET_PC #undef CR12_BRTRACE #undef CR12_TRACEEA #undef CHM_GPR2_RESV #undef DEF_INST #undef ARCH_DEP #undef PSA #undef PSA_SIZE #undef IA #undef PX #undef CR #undef GR #undef GR_A #undef SET_GR_A #undef MONCODE #undef TEA #undef DXC #undef ET #undef PX_MASK #undef RSTOLD #undef RSTNEW #undef RADR #undef F_RADR #undef VADR #undef VADR_L #undef F_VADR #undef GREG #undef F_GREG #undef CREG #undef F_CREG #undef AREG #undef F_AREG #undef STORE_W #undef FETCH_W #undef AIV #undef AIE #undef VIE #undef SIEBK #undef ZPB #undef TLB_REAL_ASD #undef TLB_ASD #undef TLB_VADDR #undef TLB_PTE #undef TLB_PAGEMASK #undef TLB_BYTEMASK #undef TLB_PAGESHIFT #undef TLBID_PAGEMASK #undef TLBID_BYTEMASK #undef ASD_PRIVATE #undef PER_SB #if __GEN_ARCH == 370 #define ARCH_MODE ARCH_370 #define DEF_INST(_name) \ void (ATTR_REGPARM(2) s370_ ## _name) (BYTE inst[], REGS *regs) #define ARCH_DEP(_name) \ s370_ ## _name #define APPLY_PREFIXING(addr,pfx) \ ( ((U32)(addr) & 0x7FFFF000) == 0 || ((U32)(addr) & 0x7FFFF000) == (pfx) \ ? (U32)(addr) ^ (pfx) \ : (addr) \ ) #define AMASK AMASK_L #define ADDRESS_MAXWRAP(_register_context) \ (AMASK24) #define ADDRESS_MAXWRAP_E(_register_context) \ (AMASK31) #define REAL_MODE(p) \ (!ECMODE(p) || ((p)->sysmask & PSW_DATMODE)==0) #if defined(_FEATURE_SIE) #define PER_MODE(_regs) \ ( (ECMODE(&(_regs)->psw) && ((_regs)->psw.sysmask & PSW_PERMODE)) \ || (SIE_MODE((_regs)) && ((_regs)->siebk->m & SIE_M_GPE)) ) #else #define PER_MODE(_regs) \ (ECMODE(&(_regs)->psw) && ((_regs)->psw.sysmask & PSW_PERMODE)) #endif #define ASF_ENABLED(_regs) 0 /* ASF is never enabled for S/370 */ #define ASN_AND_LX_REUSE_ENABLED(_regs) 0 /* never enabled for S/370 */ #define ASTE_AS_DESIGNATOR(_aste) \ ((_aste)[2]) #define ASTE_LT_DESIGNATOR(_aste) \ ((_aste)[3]) #define SAEVENT_BIT STD_SAEVENT #define SSEVENT_BIT STD_SSEVENT #define SSGROUP_BIT STD_GROUP #define PSA PSA_3XX #define PSA_SIZE 4096 #define IA IA_L #define PX PX_L #define CR(_r) CR_L(_r) #define GR(_r) GR_L(_r) #define GR_A(_r, _regs) ((_regs)->GR_L((_r))) #define SET_GR_A(_r, _regs,_v) ((_regs)->GR_L((_r))=(_v)) #define MONCODE MC_L #define TEA EA_L #define DXC tea #define ET ET_L #define PX_MASK 0x7FFFF000 #define RSTOLD iplccw1 #define RSTNEW iplpsw #if !defined(_FEATURE_ZSIE) #define RADR U32 #define F_RADR "%8.8"I32_FMT"X" #else #define RADR U64 #define F_RADR "%8.8"I64_FMT"X" #endif #define VADR U32 #define VADR_L VADR #define F_VADR "%8.8"I32_FMT"X" #define GREG U32 #define F_GREG "%8.8"I32_FMT"X" #define CREG U32 #define F_CREG "%8.8"I32_FMT"X" #define AREG U32 #define F_AREG "%8.8"I32_FMT"X" #define STORE_W STORE_FW #define FETCH_W FETCH_FW #define AIV AIV_L #define AIE AIE_L #define SIEBK SIE1BK #define ZPB ZPB1 #define TLB_REAL_ASD TLB_REAL_ASD_L #define TLB_ASD(_n) TLB_ASD_L(_n) #define TLB_VADDR(_n) TLB_VADDR_L(_n) #define TLB_PTE(_n) TLB_PTE_L(_n) #define TLB_PAGEMASK 0x00FFF800 #define TLB_BYTEMASK 0x000007FF #define TLB_PAGESHIFT 11 #define TLBID_PAGEMASK 0x00E00000 #define TLBID_BYTEMASK 0x001FFFFF #define ASD_PRIVATE SEGTAB_370_CMN #elif __GEN_ARCH == 390 #define ARCH_MODE ARCH_390 #define DEF_INST(_name) \ void (ATTR_REGPARM(2) s390_ ## _name) (BYTE inst[], REGS *regs) #define ARCH_DEP(_name) \ s390_ ## _name #define APPLY_PREFIXING(addr,pfx) \ ( ((U32)(addr) & 0x7FFFF000) == 0 || ((U32)(addr) & 0x7FFFF000) == (pfx) \ ? (U32)(addr) ^ (pfx) \ : (addr) \ ) #define AMASK AMASK_L #define ADDRESS_MAXWRAP(_register_context) \ ((_register_context)->psw.AMASK) #define ADDRESS_MAXWRAP_E(_register_context) \ ((_register_context)->psw.AMASK) #define REAL_MODE(p) \ (((p)->sysmask & PSW_DATMODE)==0) #if defined(_FEATURE_SIE) #define PER_MODE(_regs) \ ( ((_regs)->psw.sysmask & PSW_PERMODE) \ || (SIE_MODE((_regs)) && ((_regs)->siebk->m & SIE_M_GPE)) ) #else #define PER_MODE(_regs) \ ((_regs)->psw.sysmask & PSW_PERMODE) #endif #define ASF_ENABLED(_regs) ((_regs)->CR(0) & CR0_ASF) #define ASN_AND_LX_REUSE_ENABLED(_regs) 0 /* never enabled in ESA/390 */ #define ASTE_AS_DESIGNATOR(_aste) \ ((_aste)[2]) #define ASTE_LT_DESIGNATOR(_aste) \ ((_aste)[3]) #define SAEVENT_BIT STD_SAEVENT #define SSEVENT_BIT STD_SSEVENT #define SSGROUP_BIT STD_GROUP #define LSED_UET_HDR S_LSED_UET_HDR #define LSED_UET_TLR S_LSED_UET_TLR #define LSED_UET_BAKR S_LSED_UET_BAKR #define LSED_UET_PC S_LSED_UET_PC #define CR12_BRTRACE S_CR12_BRTRACE #define CR12_TRACEEA S_CR12_TRACEEA #define CHM_GPR2_RESV S_CHM_GPR2_RESV #define PSA PSA_3XX #define PSA_SIZE 4096 #define IA IA_L #define PX PX_L #define CR(_r) CR_L(_r) #define GR(_r) GR_L(_r) #define GR_A(_r, _regs) ((_regs)->GR_L((_r))) #define SET_GR_A(_r, _regs,_v) ((_regs)->GR_L((_r))=(_v)) #define MONCODE MC_L #define TEA EA_L #define DXC tea #define ET ET_L #define PX_MASK 0x7FFFF000 #define RSTNEW iplpsw #define RSTOLD iplccw1 #if !defined(_FEATURE_ZSIE) #define RADR U32 #define F_RADR "%8.8"I32_FMT"X" #else #define RADR U64 #define F_RADR "%8.8"I64_FMT"X" #endif #define VADR U32 #define VADR_L VADR #define F_VADR "%8.8"I32_FMT"X" #define GREG U32 #define F_GREG "%8.8"I32_FMT"X" #define CREG U32 #define F_CREG "%8.8"I32_FMT"X" #define AREG U32 #define F_AREG "%8.8"I32_FMT"X" #define STORE_W STORE_FW #define FETCH_W FETCH_FW #define AIV AIV_L #define AIE AIE_L #define SIEBK SIE1BK #define ZPB ZPB1 #define TLB_REAL_ASD TLB_REAL_ASD_L #define TLB_ASD(_n) TLB_ASD_L(_n) #define TLB_VADDR(_n) TLB_VADDR_L(_n) #define TLB_PTE(_n) TLB_PTE_L(_n) #define TLB_PAGEMASK 0x7FFFF000 #define TLB_BYTEMASK 0x00000FFF #define TLB_PAGESHIFT 12 #define TLBID_PAGEMASK 0x7FC00000 #define TLBID_BYTEMASK 0x003FFFFF #define ASD_PRIVATE STD_PRIVATE #elif __GEN_ARCH == 900 #define ARCH_MODE ARCH_900 #define APPLY_PREFIXING(addr,pfx) \ ( (U64)((addr) & 0xFFFFFFFFFFFFE000ULL) == (U64)0 || (U64)((addr) & 0xFFFFFFFFFFFFE000ULL) == (pfx) \ ? (addr) ^ (pfx) \ : (addr) \ ) #define AMASK AMASK_G #define ADDRESS_MAXWRAP(_register_context) \ ((_register_context)->psw.AMASK) #define ADDRESS_MAXWRAP_E(_register_context) \ ((_register_context)->psw.AMASK) #define REAL_MODE(p) \ (((p)->sysmask & PSW_DATMODE)==0) #if defined(_FEATURE_SIE) #define PER_MODE(_regs) \ ( ((_regs)->psw.sysmask & PSW_PERMODE) \ || (SIE_MODE((_regs)) && ((_regs)->siebk->m & SIE_M_GPE)) ) #else #define PER_MODE(_regs) \ ((_regs)->psw.sysmask & PSW_PERMODE) #endif #define ASF_ENABLED(_regs) 1 /* ASF is always enabled for ESAME */ /* ASN-and-LX-reuse is enabled if the ASN-and-LX-reuse facility is installed and CR0 bit 44 is 1 */ #if defined(FEATURE_ASN_AND_LX_REUSE) #define ASN_AND_LX_REUSE_ENABLED(_regs) \ (sysblk.asnandlxreuse && ((_regs)->CR_L(0) & CR0_ASN_LX_REUS)) #else /* !defined(FEATURE_ASN_AND_LX_REUSE) */ #define ASN_AND_LX_REUSE_ENABLED(_regs) 0 #endif /* !defined(FEATURE_ASN_AND_LX_REUSE) */ #define ASTE_AS_DESIGNATOR(_aste) \ (((U64)((_aste)[2])<<32)|(U64)((_aste)[3])) #define ASTE_LT_DESIGNATOR(_aste) \ ((_aste)[6]) #define SAEVENT_BIT ASCE_S #define SSEVENT_BIT ASCE_X #define SSGROUP_BIT ASCE_G #define LSED_UET_HDR Z_LSED_UET_HDR #define LSED_UET_TLR Z_LSED_UET_TLR #define LSED_UET_BAKR Z_LSED_UET_BAKR #define LSED_UET_PC Z_LSED_UET_PC #define CR12_BRTRACE Z_CR12_BRTRACE #define CR12_TRACEEA Z_CR12_TRACEEA #define CHM_GPR2_RESV Z_CHM_GPR2_RESV #define DEF_INST(_name) \ void (ATTR_REGPARM(2) z900_ ## _name) (BYTE inst[], REGS *regs) #define ARCH_DEP(_name) \ z900_ ## _name #define PSA PSA_900 #define PSA_SIZE 8192 #define IA IA_G #define PX PX_L #define CR(_r) CR_G(_r) #define GR(_r) GR_G(_r) #define GR_A(_r, _regs) ((_regs)->psw.amode64 ? (_regs)->GR_G((_r)) : (_regs)->GR_L((_r))) #define SET_GR_A(_r, _regs,_v) \ do { \ if((_regs)->psw.amode64) { \ ((_regs)->GR_G((_r))=(_v)); \ } else { \ ((_regs)->GR_L((_r))=(_v)); \ } \ } while(0) #define MONCODE MC_G #define TEA EA_G #define DXC dataexc #define ET ET_G #define PX_MASK 0x7FFFE000 #define RSTOLD rstold #define RSTNEW rstnew #if 0 #define RADR U32 #else #define RADR U64 #endif #define F_RADR "%16.16"I64_FMT"X" #define VADR U64 #if SIZEOF_INT == 4 #define VADR_L U32 #else #define VADR_L VADR #endif #define F_VADR "%16.16"I64_FMT"X" #define GREG U64 #define F_GREG "%16.16"I64_FMT"X" #define CREG U64 #define F_CREG "%16.16"I64_FMT"X" #define AREG U32 #define F_AREG "%8.8"I32_FMT"X" #define STORE_W STORE_DW #define FETCH_W FETCH_DW #define AIV AIV_G #define AIE AIE_G #define SIEBK SIE2BK #define ZPB ZPB2 #define TLB_REAL_ASD TLB_REAL_ASD_G #define TLB_ASD(_n) TLB_ASD_G(_n) #define TLB_VADDR(_n) TLB_VADDR_G(_n) #define TLB_PTE(_n) TLB_PTE_G(_n) #define TLB_PAGEMASK 0xFFFFFFFFFFFFF000ULL #define TLB_BYTEMASK 0x0000000000000FFFULL #define TLB_PAGESHIFT 12 #define TLBID_PAGEMASK 0xFFFFFFFFFFC00000ULL #define TLBID_BYTEMASK 0x00000000003FFFFFULL #define ASD_PRIVATE (ASCE_P|ASCE_R) #else #warning __GEN_ARCH must be 370, 390, 900 or undefined #endif #undef PAGEFRAME_PAGESIZE #undef PAGEFRAME_PAGESHIFT #undef PAGEFRAME_BYTEMASK #undef PAGEFRAME_PAGEMASK #undef MAXADDRESS #if defined(FEATURE_ESAME) #define PAGEFRAME_PAGESIZE 4096 #define PAGEFRAME_PAGESHIFT 12 #define PAGEFRAME_BYTEMASK 0x00000FFF #define PAGEFRAME_PAGEMASK 0xFFFFFFFFFFFFF000ULL #define MAXADDRESS 0xFFFFFFFFFFFFFFFFULL #elif defined(FEATURE_S390_DAT) #define PAGEFRAME_PAGESIZE 4096 #define PAGEFRAME_PAGESHIFT 12 #define PAGEFRAME_BYTEMASK 0x00000FFF #define PAGEFRAME_PAGEMASK 0x7FFFF000 #define MAXADDRESS 0x7FFFFFFF #else /* S/370 */ #define PAGEFRAME_PAGESIZE 2048 #define PAGEFRAME_PAGESHIFT 11 #define PAGEFRAME_BYTEMASK 0x000007FF #define PAGEFRAME_PAGEMASK 0x7FFFF800 #if defined(FEATURE_370E_EXTENDED_ADDRESSING) #define MAXADDRESS 0x03FFFFFF #else #define MAXADDRESS 0x00FFFFFF #endif #endif #undef ITIMER_UPDATE #undef ITIMER_SYNC #if defined(FEATURE_INTERVAL_TIMER) #define ITIMER_UPDATE(_addr, _len, _regs) \ do { \ if( ITIMER_ACCESS((_addr), (_len)) ) \ ARCH_DEP(fetch_int_timer) ((_regs)); \ } while(0) #define ITIMER_SYNC(_addr, _len, _regs) \ do { \ if( ITIMER_ACCESS((_addr), (_len)) ) \ ARCH_DEP(store_int_timer) ((_regs)); \ } while (0) #else #define ITIMER_UPDATE(_addr, _len, _regs) #define ITIMER_SYNC(_addr, _len, _regs) #endif #if !defined(_FEATURE_2K_STORAGE_KEYS) #define STORAGE_KEY_UNITSIZE 4096 #else #define STORAGE_KEY_UNITSIZE 2048 #endif #undef STORAGE_KEY #undef STORAGE_KEY_PAGESHIFT #undef STORAGE_KEY_PAGESIZE #undef STORAGE_KEY_PAGEMASK #undef STORAGE_KEY_BYTEMASK #ifdef FEATURE_4K_STORAGE_KEYS #if defined(_FEATURE_2K_STORAGE_KEYS) #define STORAGE_KEY_PAGESHIFT 11 #else #define STORAGE_KEY_PAGESHIFT 12 #endif #define STORAGE_KEY_PAGESIZE 4096 #if defined(FEATURE_ESAME) #define STORAGE_KEY_PAGEMASK 0xFFFFFFFFFFFFF000ULL #else #define STORAGE_KEY_PAGEMASK 0x7FFFF000 #endif #define STORAGE_KEY_BYTEMASK 0x00000FFF #else #define STORAGE_KEY_PAGESHIFT 11 #define STORAGE_KEY_PAGESIZE 2048 #define STORAGE_KEY_PAGEMASK 0x7FFFF800 #define STORAGE_KEY_BYTEMASK 0x000007FF #endif #define STORAGE_KEY(_addr, _pointer) \ (_pointer)->storkeys[(_addr)>>STORAGE_KEY_PAGESHIFT] #if defined(_FEATURE_2K_STORAGE_KEYS) #define STORAGE_KEY1(_addr, _pointer) \ (_pointer)->storkeys[((_addr)>>STORAGE_KEY_PAGESHIFT)&~1] #define STORAGE_KEY2(_addr, _pointer) \ (_pointer)->storkeys[((_addr)>>STORAGE_KEY_PAGESHIFT)|1] #endif #define XSTORE_INCREMENT_SIZE 0x00100000 #define XSTORE_PAGESHIFT 12 #define XSTORE_PAGESIZE 4096 #undef XSTORE_PAGEMASK #if defined(FEATURE_ESAME) || defined(_FEATURE_ZSIE) #define XSTORE_PAGEMASK 0xFFFFFFFFFFFFF000ULL #else #define XSTORE_PAGEMASK 0x7FFFF000 #endif /*-------------------------------------------------------------------*/ /* Macros use by Compare and Form Codeword (CFC (B21A)) instruction */ /*-------------------------------------------------------------------*/ #undef CFC_A64_OPSIZE #undef CFC_DEF_OPSIZE #undef CFC_MAX_OPSIZE #undef CFC_OPSIZE #undef CFC_GR2_SHIFT #undef CFC_HIGH_BIT #undef AR1 #define AR1 ( 1 ) /* Access Register 1 */ #define CFC_A64_OPSIZE ( 6 ) /* amode-64 operand size */ #define CFC_DEF_OPSIZE ( 2 ) /* non-amode-64 operand size */ #define CFC_MAX_OPSIZE ( CFC_A64_OPSIZE > CFC_DEF_OPSIZE ? CFC_A64_OPSIZE : CFC_DEF_OPSIZE ) #if defined(FEATURE_ESAME) #define CFC_OPSIZE ( a64 ? CFC_A64_OPSIZE : CFC_DEF_OPSIZE ) #define CFC_GR2_SHIFT ( a64 ? ( CFC_A64_OPSIZE * 8 ) : ( CFC_DEF_OPSIZE * 8 ) ) #define CFC_HIGH_BIT ( a64 ? 0x8000000000000000ULL : 0x0000000080000000ULL ) #else #define CFC_OPSIZE ( CFC_DEF_OPSIZE ) #define CFC_GR2_SHIFT ( CFC_DEF_OPSIZE * 8 ) #define CFC_HIGH_BIT ( 0x80000000UL ) #endif /*-------------------------------------------------------------------*/ /* Macros use by Update Tree (CFC (0102)) instruction */ /*-------------------------------------------------------------------*/ #undef UPT_ALIGN_MASK #undef UPT_SHIFT_MASK #undef UPT_HIGH_BIT #undef AR4 #define AR4 (4) /* Access Register 4 */ #if defined(FEATURE_ESAME) #define UPT_ALIGN_MASK ( a64 ? 0x000000000000000FULL : 0x0000000000000007ULL ) #define UPT_SHIFT_MASK ( a64 ? 0xFFFFFFFFFFFFFFF0ULL : 0xFFFFFFFFFFFFFFF8ULL ) #define UPT_HIGH_BIT ( a64 ? 0x8000000000000000ULL : 0x0000000080000000ULL ) #else #define UPT_ALIGN_MASK ( 0x00000007 ) #define UPT_SHIFT_MASK ( 0xFFFFFFF8 ) #define UPT_HIGH_BIT ( 0x80000000 ) #endif /* Macros for accelerated lookup */ #undef SPACE_BIT #undef AR_BIT #undef PRIMARY_SPACE_MODE #undef SECONDARY_SPACE_MODE #undef ACCESS_REGISTER_MODE #undef HOME_SPACE_MODE #undef AEA_MODE #undef SET_AEA_COMMON #undef SET_AEA_MODE #undef _CASE_AR_SET_AEA_MODE #undef _CASE_DAS_SET_AEA_MODE #undef _CASE_HOME_SET_AEA_MODE #undef TEST_SET_AEA_MODE #undef SET_AEA_AR #undef MADDR #if defined(FEATURE_DUAL_ADDRESS_SPACE) && defined(FEATURE_LINKAGE_STACK) #define SET_AEA_COMMON(_regs) \ do { \ (_regs)->aea_common[1] = ((_regs)->CR(1) & ASD_PRIVATE) == 0; \ (_regs)->aea_common[7] = ((_regs)->CR(7) & ASD_PRIVATE) == 0; \ (_regs)->aea_common[13] = ((_regs)->CR(13) & ASD_PRIVATE) == 0; \ } while (0) #elif defined(FEATURE_DUAL_ADDRESS_SPACE) #define SET_AEA_COMMON(_regs) \ do { \ (_regs)->aea_common[1] = ((_regs)->CR(1) & ASD_PRIVATE) == 0; \ (_regs)->aea_common[7] = ((_regs)->CR(7) & ASD_PRIVATE) == 0; \ } while (0) #else #define SET_AEA_COMMON(_regs) \ do { \ (_regs)->aea_common[1] = ((_regs)->CR(1) & ASD_PRIVATE) == 0; \ } while (0) #endif #if defined(FEATURE_DUAL_ADDRESS_SPACE) || defined(FEATURE_LINKAGE_STACK) #define SPACE_BIT(p) \ (((p)->asc & BIT(PSW_SPACE_BIT)) != 0) #define AR_BIT(p) \ (((p)->asc & BIT(PSW_AR_BIT)) != 0) #define PRIMARY_SPACE_MODE(p) \ ((p)->asc == PSW_PRIMARY_SPACE_MODE) #define SECONDARY_SPACE_MODE(p) \ ((p)->asc == PSW_SECONDARY_SPACE_MODE) #define ACCESS_REGISTER_MODE(p) \ ((p)->asc == PSW_ACCESS_REGISTER_MODE) #define HOME_SPACE_MODE(p) \ ((p)->asc == PSW_HOME_SPACE_MODE) #define AEA_MODE(_regs) \ ( ( REAL_MODE(&(_regs)->psw) ? (SIE_STATB((_regs), MX, XC) && AR_BIT(&(_regs)->psw) ? 2 : 0) : (((_regs)->psw.asc >> 6) + 1) ) \ | ( PER_MODE((_regs)) ? 0x40 : 0 ) \ ) #else #define SPACE_BIT(p) (0) #define AR_BIT(p) (0) #define PRIMARY_SPACE_MODE(p) (1) #define SECONDARY_SPACE_MODE(p) (0) #define ACCESS_REGISTER_MODE(p) (0) #define HOME_SPACE_MODE(p) (0) #define AEA_MODE(_regs) \ ( (REAL_MODE(&(_regs)->psw) ? 0 : 1 ) | (PER_MODE((_regs)) ? 0x40 : 0 ) ) #endif #if defined(FEATURE_ACCESS_REGISTERS) /* * Update the aea_ar vector whenever an access register * is changed and in armode */ #define SET_AEA_AR(_regs, _arn) \ do \ { \ if (ACCESS_REGISTER_MODE(&(_regs)->psw) && (_arn) > 0 && (_arn) < 16) { \ if ((_regs)->AR((_arn)) == ALET_PRIMARY) \ (_regs)->aea_ar[(_arn)] = 1; \ else if ((_regs)->AR((_arn)) == ALET_SECONDARY) \ (_regs)->aea_ar[(_arn)] = 7; \ else \ (_regs)->aea_ar[(_arn)] = 0; \ } \ } while (0) #else #define SET_AEA_AR(_regs, _arn) #endif /* * Conditionally reset the aea_ar vector */ #define TEST_SET_AEA_MODE(_regs) \ do \ { \ if ((_regs)->aea_mode != AEA_MODE((_regs))) { \ SET_AEA_MODE((_regs)); \ } \ } while (0) /* * Reset aea_ar vector to indicate the appropriate * control register: * 0 - unresolvable (armode and alet is not 0 or 1) * 1 - primary space * 7 - secondary space * 13 - home space * 16 - real */ #if defined(FEATURE_ACCESS_REGISTERS) #define _CASE_AR_SET_AEA_MODE(_regs) \ case 2: /* AR */ \ (_regs)->aea_ar[USE_INST_SPACE] = 1; \ for(i = 0; i < 16; i++) \ (_regs)->aea_ar[i] = 1; \ for (i = 1; i < 16; i++) { \ if ((_regs)->AR(i) == ALET_SECONDARY) (_regs)->aea_ar[i] = 7; \ else if ((_regs)->AR(i) != ALET_PRIMARY) (_regs)->aea_ar[i] = 0; \ } \ break; #else #define _CASE_AR_SET_AEA_MODE(_regs) #endif #if defined(FEATURE_DUAL_ADDRESS_SPACE) #define _CASE_DAS_SET_AEA_MODE(_regs) \ case 3: /* SEC */ \ (_regs)->aea_ar[USE_INST_SPACE] = 1; \ for(i = 0; i < 16; i++) \ (_regs)->aea_ar[i] = 7; \ break; #else #define _CASE_DAS_SET_AEA_MODE(_regs) #endif #if defined(FEATURE_LINKAGE_STACK) #define _CASE_HOME_SET_AEA_MODE(_regs) \ case 4: /* HOME */ \ (_regs)->aea_ar[USE_INST_SPACE] = 13; \ for(i = 0; i < 16; i++) \ (_regs)->aea_ar[i] = 13; \ break; #else #define _CASE_HOME_SET_AEA_MODE(_regs) #endif #define SET_AEA_MODE(_regs) \ do { \ int i; \ int inst_cr = (_regs)->aea_ar[USE_INST_SPACE]; \ BYTE oldmode = (_regs)->aea_mode; \ (_regs)->aea_mode = AEA_MODE((_regs)); \ switch ((_regs)->aea_mode & 0x0F) { \ case 1: /* PRIM */ \ (_regs)->aea_ar[USE_INST_SPACE] = 1; \ for(i = 0; i < 16; i++) \ (_regs)->aea_ar[i] = 1; \ break; \ _CASE_AR_SET_AEA_MODE((_regs)) \ _CASE_DAS_SET_AEA_MODE((_regs)) \ _CASE_HOME_SET_AEA_MODE((_regs)) \ default: /* case 0: REAL */ \ (_regs)->aea_ar[USE_INST_SPACE] = CR_ASD_REAL; \ for(i = 0; i < 16; i++) \ (_regs)->aea_ar[i] = CR_ASD_REAL; \ } \ if (inst_cr != (_regs)->aea_ar[USE_INST_SPACE]) \ INVALIDATE_AIA((_regs)); \ if ((oldmode & PSW_PERMODE) == 0 && ((_regs)->aea_mode & PSW_PERMODE) != 0) { \ INVALIDATE_AIA((_regs)); \ if (EN_IC_PER_SA((_regs))) \ ARCH_DEP(invalidate_tlb)((_regs),~(ACC_WRITE|ACC_CHECK)); \ } \ } while (0) /* * Accelerated lookup */ #define MADDRL(_addr, _len, _arn, _regs, _acctype, _akey) \ ( \ likely((_regs)->aea_ar[(_arn)]) \ && likely( \ ((_regs)->CR((_regs)->aea_ar[(_arn)]) == (_regs)->tlb.TLB_ASD(TLBIX(_addr))) \ || ((_regs)->aea_common[(_regs)->aea_ar[(_arn)]] & (_regs)->tlb.common[TLBIX(_addr)]) \ ) \ && likely((_akey) == 0 || (_akey) == (_regs)->tlb.skey[TLBIX(_addr)]) \ && likely((((_addr) & TLBID_PAGEMASK) | (_regs)->tlbID) == (_regs)->tlb.TLB_VADDR(TLBIX(_addr))) \ && likely((_acctype) & (_regs)->tlb.acc[TLBIX(_addr)]) \ ? ( \ ((_acctype) & ACC_CHECK) ? \ (_regs)->dat.storkey = (_regs)->tlb.storkey[TLBIX(_addr)], \ MAINADDR((_regs)->tlb.main[TLBIX(_addr)], (_addr)) : \ MAINADDR((_regs)->tlb.main[TLBIX(_addr)], (_addr)) \ ) \ : ( \ ARCH_DEP(logical_to_main_l) ((_addr), (_arn), (_regs), (_acctype), (_akey), (_len)) \ ) \ ) /* Old style accelerated lookup (without length) */ #define MADDR(_addr, _arn, _regs, _acctype, _akey) \ MADDRL( (_addr), 1, (_arn), (_regs), (_acctype), (_akey)) /* * PER Successful Branch */ #if defined(FEATURE_PER) #if defined(FEATURE_PER2) #define PER_SB(_regs, _addr) \ do { \ if (unlikely(EN_IC_PER_SB((_regs))) \ && (!((_regs)->CR(9) & CR9_BAC) \ || PER_RANGE_CHECK((_addr) & ADDRESS_MAXWRAP((_regs)), \ (_regs)->CR(10), (_regs)->CR(11)) \ ) \ ) \ ON_IC_PER_SB((_regs)); \ } while (0) #else /*!defined(FEATURE_PER2)*/ #define PER_SB(_regs, _addr) \ do { \ if (unlikely(EN_IC_PER_SB((_regs)))) \ ON_IC_PER_SB((_regs)); \ } while (0) #endif /*!defined(FEATURE_PER2)*/ #else /*!defined(FEATURE_PER)*/ #define PER_SB(_regs,_addr) #endif /*!defined(FEATURE_PER)*/ /* end of FEATURES.H */ hercules-3.12/esa390.h0000664000175000017500000040347312564723224011373 00000000000000/* ESA390.H (c) Copyright Roger Bowler, 1994-2010 */ /* ESA/390 Data Areas */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #ifndef _ESA390_H #define _ESA390_H /* Platform-independent storage operand definitions */ #include "htypes.h" #if defined(WORDS_BIGENDIAN) typedef union { U16 H; struct { BYTE H; BYTE L; } B; } HW; typedef union { U32 F; struct { HW H; HW L; } H; struct { BYTE B; U32 A:24; } A; } FW; typedef union { U64 D; struct { FW H; FW L; } F; } DW; typedef union { struct { DW H; DW L; } D; struct { FW HH; FW HL; FW LH; FW LL; } F; } QW; #else // !defined(WORDS_BIGENDIAN) typedef union { U16 H; struct { BYTE L; BYTE H; } B; } HW; typedef union { U32 F; struct { HW L; HW H; } H; struct { U32 A:24, B:8; } A; } FW; typedef union { U64 D; struct { FW L; FW H; } F; } DW; typedef union { struct { DW L; DW H; } D; struct { FW LL; FW LH; FW HL; FW HH; } F; } QW; #endif // defined(WORDS_BIGENDIAN) typedef union { HWORD H; struct { BYTE H; BYTE L; } B; } HWORD_U; typedef union { FWORD F; struct { HWORD_U H; HWORD_U L; } H; } FWORD_U; typedef union { DBLWRD D; struct { FWORD_U H; FWORD_U L; } F; } DWORD_U; /* Internal-format PSW structure definition */ typedef struct _PSW { BYTE sysmask; /* System mask (0 - 7) */ BYTE pkey; /* PSW Key (8 - 11) */ BYTE states; /* EC,M,W,P bits (12 - 15) */ BYTE asc; /* Address space control */ /* (16 - 17) */ BYTE cc; /* Condition code (18 - 19) */ BYTE progmask; /* Program mask (20 - 23) */ BYTE zerobyte; /* Zeroes (24 - 31) */ /* or (esame) (24 - 30) */ u_int /* Addressing mode (31 - 32) */ amode64:1, /* 64-bit addressing (31) */ amode:1, /* 31-bit addressing (32) */ zeroilc:1; /* 1=Zero ILC */ U32 zeroword; /* esame only (33 - 63) */ DW ia; /* Instruction addrress */ /* (33 - 63) */ /* or (esame) (64 -127) */ DW amask; /* Address wraparound mask */ U16 intcode; /* Interruption code */ BYTE ilc; /* Instruction length count */ BYTE unused; } PSW; #define IA_G ia.D #define IA_H ia.F.H.F #define IA_L ia.F.L.F #define IA_LA24 ia.F.L.A.A #define AMASK_G amask.D #define AMASK_L amask.F.L.F #define AMASK_H amask.F.H.F #define AMASK24 0x00FFFFFF #define AMASK31 0x7FFFFFFF #define AMASK64 0xFFFFFFFFFFFFFFFFULL /* System mask (0 - 7) */ #define PSW_PERMODE 0x40 /* Program event recording */ #define PSW_DATMODE 0x04 /* Dynamic addr translation */ #define PSW_IOMASK 0x02 /* I/O interrupt mask */ #define PSW_EXTMASK 0x01 /* External interrupt mask */ /* PSW key mask (8 - 11) */ #define PSW_KEYMASK 0xF0 /* PSW key mask */ /* (12 - 15) */ #define PSW_EC_BIT 3 /* 0x08 ECMODE */ #define PSW_MACH_BIT 2 /* 0x04 Machine check mask */ #define PSW_WAIT_BIT 1 /* 0x02 Wait state */ #define PSW_PROB_BIT 0 /* 0x01 Problem state */ #define PSW_NOTESAME_BIT PSW_EC_BIT /* Address space control (16 - 17) */ #define PSW_ASCMASK 0xC0 /* Address space control mask*/ #define PSW_SPACE_BIT 7 /* 0x80 Space mode bit */ #define PSW_AR_BIT 6 /* 0x40 Access register mode bit */ #define PSW_PRIMARY_SPACE_MODE 0x00 /* Primary-space mode */ #define PSW_SECONDARY_SPACE_MODE 0x80 /* Secondary-space mode */ #define PSW_ACCESS_REGISTER_MODE 0x40 /* Access-register mode */ #define PSW_HOME_SPACE_MODE 0xC0 /* Home-space mode */ /* Condition code (18 - 19) */ #define PSW_CCMASK 0x30 /* Condition code mask */ /* Program mask (20 - 23) */ #define PSW_PROGMASK 0x0F /* Program-mask bits */ #define PSW_FOBIT 3 /* 0x08 Fixed-point overflow bit */ #define PSW_DOBIT 2 /* 0x04 Decimal overflow bit */ #define PSW_EUBIT 1 /* 0x02 Exponent underflow bit */ #define PSW_SGBIT 0 /* 0x01 Significance bit */ /* Address mode (31 - 32) */ #define PSW_AMODE64_BIT 0 /* Extended addressing (31) */ #define PSW_AMODE31_BIT 7 /* Basic addressing (32) */ /* Macros for testing states (EC, M, W, P bits) */ #define ECMODE(p) (((p)->states & BIT(PSW_EC_BIT)) != 0) #define NOTESAME(p) (((p)->states & BIT(PSW_NOTESAME_BIT)) != 0) #define MACHMASK(p) (((p)->states & BIT(PSW_MACH_BIT)) != 0) #define WAITSTATE(p) (((p)->states & BIT(PSW_WAIT_BIT)) != 0) #define PROBSTATE(p) (((p)->states & BIT(PSW_PROB_BIT)) != 0) /* Macros for testing program mask */ #define FOMASK(p) ( (p)->progmask & BIT(PSW_FOBIT) ) #define DOMASK(p) ( (p)->progmask & BIT(PSW_DOBIT) ) #define EUMASK(p) ( (p)->progmask & BIT(PSW_EUBIT) ) #define SGMASK(p) ( (p)->progmask & BIT(PSW_SGBIT) ) /* Structure definition for translation-lookaside buffer entry */ #define TLBN 1024 /* Number TLB entries */ #define TLB_MASK 0x3FF /* Mask for 1024 entries */ #define TLB_REAL_ASD_L 0xFFFFFFFF /* ASD values for real mode */ #define TLB_REAL_ASD_G 0xFFFFFFFFFFFFFFFFULL #define TLB_HOST_ASD 0x800 /* Host entry for XC guest */ typedef struct _TLB { DW asd[TLBN]; /* Address space designator */ #define TLB_ASD_G(_n) asd[(_n)].D #define TLB_ASD_L(_n) asd[(_n)].F.L.F DW vaddr[TLBN]; /* Virtual page address */ #define TLB_VADDR_G(_n) vaddr[(_n)].D #define TLB_VADDR_L(_n) vaddr[(_n)].F.L.F DW pte[TLBN]; /* Copy of page table entry */ #define TLB_PTE_G(_n) pte[(_n)].D #define TLB_PTE_L(_n) pte[(_n)].F.L.F BYTE *main[TLBN]; /* Mainstor address */ BYTE *storkey[TLBN]; /* -> Storage key */ BYTE skey[TLBN]; /* Storage key key-value */ BYTE common[TLBN]; /* 1=Page in common segment */ BYTE protect[TLBN]; /* 1=Page in protected segmnt*/ BYTE acc[TLBN]; /* Access type flags */ } TLB; /* TLB Notes - * Fields set by translate_addr() are asd, vaddr, pte, id, common and * protect. * Fields set by logical_to_main() are main, storkey, skey, read and * write and are used for accelerated address lookup (formerly AEA). */ /* Structure for Dynamic Address Translation */ typedef struct _DAT { RADR raddr; /* Real address */ RADR aaddr; /* Absolute address */ RADR rpfra; /* Real page frame address */ RADR asd; /* Address space designator: */ /* STD or ASCE */ int stid; /* Address space indicator */ BYTE *storkey; /* ->Storage key */ U16 xcode; /* Translation exception code*/ u_int private:1, /* 1=Private address space */ protect:2; /* 1=Page prot, 2=ALE prot */ } DAT; /* Bit definitions for control register 0 */ #define CR0_MCX_AUTH 0x0001000000000000 /* Measurement Counter Extraction Authority */ #define CR0_BMPX 0x80000000 /* Block multiplex ctl S/370*/ #define CR0_SSM_SUPP 0x40000000 /* SSM suppression control */ #define CR0_TOD_SYNC 0x20000000 /* TOD clock sync control */ #define CR0_LOW_PROT 0x10000000 /* Low-address protection */ #define CR0_EXT_AUTH 0x08000000 /* Extraction auth control */ #define CR0_SEC_SPACE 0x04000000 /* Secondary space control */ #define CR0_FETCH_OVRD 0x02000000 /* Fetch protection override */ #define CR0_STORE_OVRD 0x01000000 /* Store protection override */ #define CR0_STORKEY_4K 0x01000000 /* Storkey exception control */ #define CR0_TRAN_FMT 0x00F80000 /* Translation format bits...*/ #define CR0_TRAN_ESA390 0x00B00000 /* ...1M/4K ESA/390 format */ #define CR0_PAGE_SIZE 0x00C00000 /* Page size for S/370... */ #define CR0_PAGE_SZ_2K 0x00400000 /* ...2K pages */ #define CR0_PAGE_SZ_4K 0x00800000 /* ...4K pages */ #define CR0_ED 0x00800000 /* Enhanced DAT enable ESAME*/ #define CR0_SEG_SIZE 0x00380000 /* Segment size for S/370... */ #define CR0_SEG_SZ_64K 0x00000000 /* ...64K segments */ #define CR0_SEG_SZ_1M 0x00100000 /* ...1M segments */ #define CR0_ASN_LX_REUS 0x00080000 /* ASN-and-LX-reuse control */ #define CR0_AFP 0x00040000 /* AFP register control */ #define CR0_VOP 0x00020000 /* Vector control 390*/ #define CR0_ASF 0x00010000 /* AS function control 390*/ #define CR0_XM_MALFALT 0x00008000 /* Malfunction alert mask */ #define CR0_XM_EMERSIG 0x00004000 /* Emergency signal mask */ #define CR0_XM_EXTCALL 0x00002000 /* External call mask */ #define CR0_XM_TODSYNC 0x00001000 /* TOD clock sync mask */ #define CR0_XM_CLKC 0x00000800 /* Clock comparator mask */ #define CR0_XM_PTIMER 0x00000400 /* CPU timer mask */ #define CR0_XM_SERVSIG 0x00000200 /* Service signal mask */ #define CR0_XM_ITIMER 0x00000080 /* Interval timer mask S/370*/ #define CR0_XM_INTKEY 0x00000040 /* Interrupt key mask */ #define CR0_XM_EXTSIG 0x00000020 /* External signal mask S/370*/ #define CR0_XM_MALERT 0x00000020 /* Measurement alert mask */ #define CR0_XM_ETR 0x00000010 /* External timer mask */ #define CR0_PC_FAST 0x00000008 /* PC fast control 390*/ #define CR0_CRYPTO 0x00000004 /* Crypto control ESAME*/ #define CR0_IUCV 0x00000002 /* IUCV interrupt mask */ #define SERVSIG_PEND 0x00000001 /* Event buffer pending */ #define SERVSIG_ADDR 0xFFFFFFF8 /* Parameter address */ /* Bit definitions for control register 1 */ /* CR1 is the primary segment table descriptor or primary ASCE */ /* Bit definitions for control register 2 */ #define CR2_DUCTO 0x7FFFFFC0 /* DUCT origin */ /* For S/370, CR2 contains channel masks for channels 0-31 */ /* Bit definitions for control register 3 */ #define CR3_SASTEIN 0xFFFFFFFF00000000ULL /* SASN STE instance# */ #define CR3_KEYMASK 0xFFFF0000 /* PSW key mask */ #define CR3_SASN 0x0000FFFF /* Secondary ASN */ /* Bit definitions for control register 4 */ #define CR4_PASTEIN 0xFFFFFFFF00000000ULL /* PASN STE instance# */ #define CR4_AX 0xFFFF0000 /* Authorization index */ #define CR4_PASN 0x0000FFFF /* Primary ASN */ /* Bit definitions for control register 5 */ /* When CR0_ASF=0 (ESA/390): */ #define CR5_SSLINK 0x80000000 /* Subsystem-Linkage control */ #define CR5_LTO 0x7FFFFF80 /* Linkage-Table origin */ #define CR5_LTL 0x0000007F /* Linkage-Table length */ /* When CR0_ASF=1 or ESAME: */ #define CR5_PASTEO 0x7FFFFFC0 /* Primary-ASTE origin */ /* Bit definitions for control register 6 */ /* CR6 is the I/O interruption subclass mask */ /* Bit definitions for control register 7 */ /* CR7 is the secondary segment table descriptor or secondary ASCE */ /* Bit definitions for control register 8 */ #define CR8_ENHMCMASK 0x0000FFFF00000000ULL /* Enh Monitor masks */ #define CR8_EAX 0xFFFF0000 /* Extended auth index */ #define CR8_MCMASK 0x0000FFFF /* Monitor masks */ /* Bit definitions for PER */ #define CR9_SB 0x80000000 /* Successful Branching */ #define CR9_IF 0x40000000 /* Instruction Fetch */ #define CR9_SA 0x20000000 /* Storage Alteration */ #define CR9_GRA 0x10000000 /* General Register Alt. */ #define CR9_STURA 0x08000000 /* Store using real addr */ #define CR9_IFNUL 0x01000000 /* IF nullification @PER3*/ #define CR9_GRMASK 0x0000FFFF /* GR mask bits */ #define CR9_BAC 0x00800000 /* Br addr control PER2 only */ #define CR9_SAC 0x00200000 /* Stor. alter. c. PER2 only */ /* Bit definitions for control register 12 */ #define S_CR12_BRTRACE 0x80000000 /* Branch trace control */ #define Z_CR12_BRTRACE 0x8000000000000000ULL /* Branch trace control*/ #define CR12_MTRACE 0x4000000000000000ULL /* Mode trace control */ #define S_CR12_TRACEEA 0x7FFFFFFC /* Trace entry address */ #define Z_CR12_TRACEEA 0x3FFFFFFFFFFFFFFCULL /* Trace entry address */ #define CR12_ASNTRACE 0x00000002 /* ASN trace control */ #define CR12_EXTRACE 0x00000001 /* Explicit trace control */ /* Bit definitions for control register 13 */ /* CR13 is the home segment table descriptor or home ASCE */ /* Bit definitions for control register 14 */ #define CR14_CHKSTOP 0x80000000 /* Check-stop control S/370*/ #define CR14_SYNCMCEL 0x40000000 /* Synchronous MCEL S/370*/ #define CR14_IOEXTLOG 0x20000000 /* I/O extended logout S/370*/ #define CR14_CHANRPT 0x10000000 /* Channel report mask */ #define CR14_RCVYRPT 0x08000000 /* Recovery report mask */ #define CR14_DGRDRPT 0x04000000 /* Degradation report mask */ #define CR14_XDMGRPT 0x02000000 /* External damage mask */ #define CR14_WARNING 0x01000000 /* Warning mask */ #define CR14_ASYNMCEL 0x00800000 /* Asynchronous MCEL S/370*/ #define CR14_ASYNFIXL 0x00400000 /* Asynch fixed log S/370*/ #define CR14_TODCTLOV 0x00200000 /* TOD clock control override*/ #define CR14_ASN_TRAN 0x00080000 /* ASN translation control */ #define CR14_AFTO 0x0007FFFF /* ASN first table origin */ /* Bit definitions for control register 15 */ #define CR15_LSEA_390 0x7FFFFFF8 /* Linkage stack address 390*/ #define CR15_LSEA_900 0xFFFFFFFFFFFFFFF8ULL /* Linkage stack ESAME*/ #define CR15_MCEL 0x00FFFFF8 /* MCEL address S/370*/ /* Linkage table designation bit definitions */ #define LTD_SSLINK 0x80000000 /* Subsystem-Linkage control */ #define LTD_LTO 0x7FFFFF80 /* Linkage-Table origin */ #define LTD_LTL 0x0000007F /* Linkage-Table length */ /* Linkage first table designation bit definitions (ASN-and-LX-reuse)*/ #define LFTD_SSLINK 0x80000000 /* Subsystem-Linkage control */ #define LFTD_LFTO 0x7FFFFF00 /* Linkage-First-Table origin*/ #define LFTD_LFTL 0x000000FF /* Linkage-First-Table length*/ /* Values for designation type and table type (ESAME mode) */ #define TT_R1TABL 0xC /* Region first table */ #define TT_R2TABL 0x8 /* Region second table */ #define TT_R3TABL 0x4 /* Region third table */ #define TT_SEGTAB 0x0 /* Segment table */ /* Address space control element bit definitions (ESAME mode) */ #define ASCE_TO 0xFFFFFFFFFFFFF000ULL /* Table origin */ #define ASCE_G 0x200 /* Subspace group indicator */ #define ASCE_P 0x100 /* Private space indicator */ #define ASCE_S 0x080 /* Storage alteration event */ #define ASCE_X 0x040 /* Space switch event */ #define ASCE_R 0x020 /* Real space */ #define ASCE_DT 0x00C /* Designation type */ #define ASCE_TL 0x003 /* Table length */ #define ASCE_RESV 0xC10 /* Reserved bits - ignored */ /* Region table entry bit definitions (ESAME mode) */ #define REGTAB_TO 0xFFFFFFFFFFFFF000ULL /* Table origin */ #define REGTAB_RFAA 0xFFFFFFFF80000000ULL /* Region addr EDAT2*/ #define REGTAB_AV 0x10000 /* ACCF validity bit EDAT2*/ #define REGTAB_ACC 0xF000 /* Access control bits EDAT2*/ #define REGTAB_F 0x800 /* Fetch protect bit EDAT2*/ #define REGTAB_FC 0x400 /* Format control bit EDAT2*/ #define REGTAB_P 0x200 /* DAT Protection bit EDAT*/ #define REGTAB_CO 0x100 /* Change override bit EDAT2*/ #define REGTAB_TF 0x0C0 /* Table offset */ #define REGTAB_I 0x020 /* Region invalid */ #define REGTAB_CR 0x010 /* Common region bit EDAT2*/ #define REGTAB_TT 0x00C /* Table type */ #define REGTAB_TL 0x003 /* Table length */ #define REGTAB_RESV 0xD10 /* Reserved bits - ignored */ /* Segment table entry bit definitions (ESAME mode) */ #define ZSEGTAB_PTO 0xFFFFFFFFFFFFF800ULL /* Page table origin */ #define ZSEGTAB_SFAA 0xFFFFFFFFFFF00000ULL /* Seg Fr Abs Addr EDAT*/ #define ZSEGTAB_AV 0x10000 /* ACCF Validity Control EDAT*/ #define ZSEGTAB_ACC 0x0F000 /* Access Control Bits EDAT*/ #define ZSEGTAB_F 0x800 /* Fetch Protection EDAT*/ #define ZSEGTAB_FC 0x400 /* Format control EDAT*/ #define ZSEGTAB_P 0x200 /* Page protection bit */ #define ZSEGTAB_CO 0x100 /* Change-rec override EDAT*/ #define ZSEGTAB_I 0x020 /* Invalid segment */ #define ZSEGTAB_C 0x010 /* Common segment */ #define ZSEGTAB_TT 0x00C /* Table type */ #define ZSEGTAB_RESV 0x0C3 /* Reserved bits - ignored */ /* Page table entry bit definitions (ESAME mode) */ #define ZPGETAB_PFRA 0xFFFFFFFFFFFFF000ULL /* Page frame real addr*/ #define ZPGETAB_I 0x400 /* Invalid page */ #define ZPGETAB_P 0x200 /* Protected page */ #define ZPGETAB_ESVALID 0x100 /* Valid in expanded storage */ #define ZPGETAB_CO 0x100 /* Change-rec override EDAT*/ #define ZPGETAB_ESREF 0x080 /* ES Referenced */ #define ZPGETAB_ESCHA 0x040 /* ES Changed */ #define ZPGETAB_ESLCK 0x020 /* ES Locked */ #define ZPGETAB_RESV 0x800 /* Reserved bits - must be 0 */ /* Segment table designation bit definitions (ESA/390 mode) */ #define STD_SSEVENT 0x80000000 /* Space switch event */ #define STD_STO 0x7FFFF000 /* Segment table origin */ #define STD_RESV 0x00000C00 /* Reserved bits - must be 0 */ #define STD_GROUP 0x00000200 /* Subspace group indicator */ #define STD_PRIVATE 0x00000100 /* Private space indicator */ #define STD_SAEVENT 0x00000080 /* Storage alteration event */ #define STD_STL 0x0000007F /* Segment table length */ /* Segment table entry bit definitions (ESA/390 mode) */ #define SEGTAB_PTO 0x7FFFFFC0 /* Page table origin */ #define SEGTAB_INVALID 0x00000020 /* Invalid segment */ #define SEGTAB_COMMON 0x00000010 /* Common segment */ #define SEGTAB_PTL 0x0000000F /* Page table length */ #define SEGTAB_RESV 0x80000000 /* Reserved bits - must be 0 */ /* Page table entry bit definitions (ESA/390 mode) */ #define PAGETAB_PFRA 0x7FFFF000 /* Page frame real address */ #define PAGETAB_ESNK 0x00000800 /* ES NK bit */ #define PAGETAB_INVALID 0x00000400 /* Invalid page */ #define PAGETAB_PROT 0x00000200 /* Protected page */ #define PAGETAB_ESVALID 0x00000100 /* Valid in expanded storage */ #define PAGETAB_ESREF 0x00000004 /* ES Referenced */ #define PAGETAB_ESCHA 0x00000002 /* ES Changed */ #define PAGETAB_PGLOCK 0x00000001 /* Page lock (LKPG) */ #define PAGETAB_RESV 0x80000900 /* Reserved bits - must be 0 */ /* Segment table designation bit definitions (S/370 mode) */ #define STD_370_STL 0xFF000000 /* 370 segment table length */ #define STD_370_STO 0x00FFFFC0 /* 370 segment table origin */ #define STD_370_SSEVENT 0x00000001 /* 370 space switch event */ /* Segment table entry bit definitions (S/370 mode) */ #define SEGTAB_370_PTL 0xF0000000 /* Page table length */ #define SEGTAB_370_PTO 0x00FFFFF8 /* Page table origin */ #define SEGTAB_370_PROT 0x00000004 /* Protected segment */ #define SEGTAB_370_CMN 0x00000002 /* Common segment */ #define SEGTAB_370_INVL 0x00000001 /* Invalid segment */ #define SEGTAB_370_RSV 0x0F000000 /* Reserved bits - must be 0 */ /* Page table entry bit definitions (S/370 mode) */ #define PAGETAB_PFRA_4K 0xFFF0 /* Page frame real address */ #define PAGETAB_INV_4K 0x0008 /* Invalid page */ #define PAGETAB_EA_4K 0x0006 /* Extended physical address */ #define PAGETAB_PFRA_2K 0xFFF8 /* Page frame real address */ #define PAGETAB_INV_2K 0x0004 /* Invalid page */ #define PAGETAB_RSV_2K 0x0002 /* Reserved bit - must be 0 */ /* Access-list entry token special value definitions */ #define ALET_PRIMARY 0 /* Primary address-space */ #define ALET_SECONDARY 1 /* Secondary address-space */ #define ALET_HOME 2 /* Home address-space */ /* Access-list entry token bit definitions */ #define ALET_RESV 0xFE000000 /* Reserved bits - must be 0 */ #define ALET_PRI_LIST 0x01000000 /* Primary space access-list */ #define ALET_ALESN 0x00FF0000 /* ALE sequence number */ #define ALET_ALEN 0x0000FFFF /* Access-list entry number */ /* Access-list designation bit definitions */ #if FEATURE_ALD_FORMAT == 0 || defined(_900) #define ALD_ALO 0x7FFFFF80 /* Access-list origin (fmt0) */ #define ALD_ALL 0x0000007F /* Access-list length (fmt0) */ #define ALD_ALL_SHIFT 3 /* Length units are 2**3 */ #else #define ALD_ALO 0x7FFFFF00 /* Access-list origin (fmt1) */ #define ALD_ALL 0x000000FF /* Access-list length (fmt1) */ #define ALD_ALL_SHIFT 4 /* Length units are 2**4 */ #endif /* Access-list entry bit definitions */ #define ALE0_INVALID 0x80000000 /* ALEN invalid */ #define ALE0_FETCHONLY 0x02000000 /* Fetch only address space */ #define ALE0_PRIVATE 0x01000000 /* Private address space */ #define ALE0_ALESN 0x00FF0000 /* ALE sequence number */ #define ALE0_ALEAX 0x0000FFFF /* ALE authorization index */ #define ALE2_ASTE 0x7FFFFFC0 /* ASTE address */ #define ALE3_ASTESN 0xFFFFFFFF /* ASTE sequence number */ /* Address-space number (ASN) bit definitions */ #define ASN_AFX 0xFFC0 /* ASN first table index */ #define ASN_ASX 0x003F /* ASN second table index */ /* ASN first table entry bit definitions */ #define AFTE_INVALID 0x80000000 /* ASN invalid */ #define AFTE_ASTO_0 0x7FFFFFF0 /* ASTE origin (CR0_ASF=0) */ #define AFTE_RESV_0 0x0000000F /* Reserved bits (CR0_ASF=0) */ #define AFTE_ASTO_1 0x7FFFFFC0 /* ASTE origin (CR0_ASF=1) */ #define AFTE_RESV_1 0x0000003F /* Reserved bits (CR0_ASF=1) */ /* ASN second table entry bit definitions */ #define ASTE0_INVALID 0x80000000 /* ASX invalid */ #define ASTE0_ATO 0x7FFFFFFC /* Authority-table origin */ #define ASTE0_RESV 0x00000002 /* Must be 0 for ESA/390 */ #define ASTE0_BASE 0x00000001 /* Base space of group */ #define ASTE1_AX 0xFFFF0000 /* Authorization index */ #define ASTE1_ATL 0x0000FFF0 /* Authority-table length */ #define ASTE1_RESV 0x0000000F /* Must be 0 for ESA/390 */ #define ASTE1_CA 0x00000002 /* Controlled ASN */ #define ASTE1_RA 0x00000001 /* Reusable ASN */ /* ASTE word 2 is the segment table designation for ESA/390 */ /* ASTE word 3 is the linkage-table designation for ESA/390 */ /* ASTE words 2 and 3 are the ASCE (RTD, STD, or RSD) for ESAME */ /* ASTE word 4 is the access-list designation */ #define ASTE5_ASTESN 0xFFFFFFFF /* ASTE sequence number */ #define ASTE6_RESV 0xFFFFFFFF /* Must be zero for ESA/390 */ /* ASTE word 6 is the LTD or LFTD for ESAME */ /* ASTE words 7-9 are reserved for control program use */ /* ASTE word 10 is unused */ #define ASTE11_ASTEIN 0xFFFFFFFF /* ASTE instance number */ /* ASTE words 12-15 are unused */ /* Authority table entry bit definitions */ #define ATE_PRIMARY 0x80 /* Primary authority bit */ #define ATE_SECONDARY 0x40 /* Secondary authority bit */ /* Dispatchable unit control table bit definitions */ #define DUCT0_BASTEO 0x7FFFFFC0 /* Base ASTE origin */ #define DUCT1_SA 0x80000000 /* Subspace active */ #define DUCT1_SSASTEO 0x7FFFFFC0 /* Subspace ASTE origin */ /* DUCT word 2 is unused */ #define DUCT3_SSASTESN 0xFFFFFFFF /* Subspace ASTE seq number */ /* DUCT word 4 is the access-list designation */ /* DUCT word 5 is unused for ESA/390 */ /* DUCT word 5 contains PKM/KEY/RA/PROB for ESAME */ /* DUCT word 6 is unused */ /* DUCT word 7 is for control program use */ /* DUCT words 8 and 9 are the return address for ESAME. In 24-bit and 31-bit mode, word 8 contains zero and word 9 contains AM31/IA31 */ /* DUCT word 8 contains AM31/IA31 for ESA/390 */ /* DUCT word 9 contains PKM/KEY/RA/PROB for ESA/390 */ /* DUCT word 10 is unused */ #define DUCT11_TCBA 0x7FFFFFF8 /* Trap control block address*/ #define DUCT11_TE 0x00000001 /* Trap enabled */ /* DUCT word 12 is unused */ /* DUCT word 13 is unused */ /* DUCT word 14 is unused */ /* DUCT word 15 is unused */ /* Bit definitions for DUCT word 5 (ESAME) or word 9 (ESA/390) */ #define DUCT_PKM 0xFFFF0000 /* PSW key mask */ #define DUCT_KEY 0x000000F0 /* PSW key */ #define DUCT_RA 0x00000008 /* Reduced authority state */ #define DUCT_PROB 0x00000001 /* Problem state */ /* Bit definitions for DUCT word 9 (ESAME) or word 8 (ESA/390) */ #define DUCT_AM31 0x80000000 /* 1=31-bit, 0=24-bit address*/ #define DUCT_IA31 0x7FFFFFFF /* 24/31 return address */ #define TCB0_P 0x00040000 /* Bit 13 PSW Control (P) */ #define TCB0_R 0x00020000 /* Bit 14 GR Control (R) */ #define TRAP0_EXECUTE 0x80000000 /* TRAP is target of execute */ #define TRAP0_TRAP4 0x40000000 /* TRAP is TRAP4 */ /* Linkage stack entry descriptor structure definition */ typedef struct _LSED { BYTE uet; /* U-bit and entry type */ BYTE si; /* Section identification */ HWORD rfs; /* Remaining free space */ HWORD nes; /* Next entry size */ HWORD resv; /* Reserved bits - must be 0 */ } LSED; /* Stack type definitions */ #define LSED_UET_U 0x80 /* Unstack suppression bit */ #define LSED_UET_ET 0x7F /* Entry type... */ #define S_LSED_UET_HDR 0x01 /* ...header entry */ #define S_LSED_UET_TLR 0x02 /* ...trailer entry */ #define S_LSED_UET_BAKR 0x04 /* ...branch state entry */ #define S_LSED_UET_PC 0x05 /* ...call state entry */ #define Z_LSED_UET_HDR 0x09 /* ...header entry */ #define Z_LSED_UET_TLR 0x0A /* ...trailer entry */ #define Z_LSED_UET_BAKR 0x0C /* ...branch state entry */ #define Z_LSED_UET_PC 0x0D /* ...call state entry */ /* Program call number bit definitions */ #define PC_LFX1 0xFFF00000 /* Linkage first index (high)*/ #define PC_BIT44 0x00080000 /* 1=LFX1 is significant */ #define PC_LFX2 0x0007E000 /* Linkage first index (low) */ #define PC_LSX 0x00001F00 /* Linkage second index */ #define PC_LX 0x000FFF00 /* Linkage index */ #define PC_EX 0x000000FF /* Entry index */ /* Linkage table entry bit definitions */ #define LTE_INVALID 0x80000000 /* LX invalid */ #define LTE_ETO 0x7FFFFFC0 /* Entry table origin */ #define LTE_ETL 0x0000003F /* Entry table length */ /* Linkage first table entry bit definitions (ASN-and-LX-reuse) */ #define LFTE_INVALID 0x80000000 /* LFX invalid */ #define LFTE_LSTO 0x7FFFFF00 /* Linkage second table orig */ /* Linkage second table entry bit definitions (ASN-and-LX-reuse) */ #define LSTE0_INVALID 0x80000000 /* LSX invalid */ #define LSTE0_ETO 0x7FFFFFC0 /* Entry table origin */ #define LSTE0_ETL 0x0000003F /* Entry table length */ #define LSTE1_LSTESN 0xFFFFFFFF /* LSTE sequence number */ /* Entry table bit entry definitions */ /* ETE word 0 is the left half of the EIA for ESAME if ETE4_G is set */ #define ETE0_AKM 0xFFFF0000 /* Authorization key mask 390*/ #define ETE0_ASN 0x0000FFFF /* Address space number 390*/ #define ETE1_AMODE 0x80000000 /* Addressing mode */ #define ETE1_EIA 0x7FFFFFFE /* Instruction address */ #define ETE1_PROB 0x00000001 /* Problem state bit */ /* ETE word 2 is the entry parameter for ESA/390 */ #define ETE2_AKM 0xFFFF0000 /* Auth.key mask ESAME*/ #define ETE2_ASN 0x0000FFFF /* Address space number ESAME*/ #define ETE3_EKM 0xFFFF0000 /* Entry key mask */ #define ETE4_T 0x80000000 /* 0=Basic PC, 1=Stacking PC */ #define ETE4_G 0x40000000 /* 1=64-bit EIA/EPARM ESAME*/ #define ETE4_K 0x10000000 /* 1=Replace PSW key by EK */ #define ETE4_M 0x08000000 /* 1=Replace PKM by EKM, 0=or*/ #define ETE4_E 0x04000000 /* 1=Replace EAX by EEAX */ #define ETE4_C 0x02000000 /* 0=Primary mode, 1=AR mode */ #define ETE4_S 0x01000000 /* SASN:0=old PASN,1=new PASN*/ #define ETE4_EK 0x00F00000 /* Entry key */ #define ETE4_EEAX 0x0000FFFF /* Entry extended AX */ #define ETE5_ASTE 0x7FFFFFC0 /* ASTE address */ /* ETE words 6 and 7 are unused for ESA/390 */ /* ETE words 6 and 7 are the entry parameter for ESAME */ /* Clock states */ #define CC_CLOCK_SET 0 /* Clock in set state */ #define CC_CLOCK_NOTSET 1 /* Clock in not-set state */ #define CC_CLOCK_ERROR 2 /* Clock in error state */ #define CC_CLOCK_STOP 3 /* Clock in stopped state or not-operational state */ /* SIGP order codes */ #define SIGP_SENSE 0x01 /* Sense */ #define SIGP_EXTCALL 0x02 /* External call */ #define SIGP_EMERGENCY 0x03 /* Emergency signal */ #define SIGP_START 0x04 /* Start */ #define SIGP_STOP 0x05 /* Stop */ #define SIGP_RESTART 0x06 /* Restart */ #define SIGP_IPR 0x07 /* Initial program reset 370*/ #define SIGP_PR 0x08 /* Program reset 370*/ #define SIGP_STOPSTORE 0x09 /* Stop and store status */ #define SIGP_IMPL 0x0A /* Initial uprogram load 370*/ #define SIGP_INITRESET 0x0B /* Initial CPU reset */ #define SIGP_RESET 0x0C /* CPU reset */ #define SIGP_SETPREFIX 0x0D /* Set prefix */ #define SIGP_STORE 0x0E /* Store status at address */ #define SIGP_STOREX 0x11 /* Store ext stat at addr 390*/ #define SIGP_SETARCH 0x12 /* Set architecture mode */ #define SIGP_COND_EMERGENCY 0x13 /* Conditional Emergency */ #define SIGP_SENSE_RUNNING_STATE 0x15 /* Sense Running State */ #define MAX_SIGPORDER 0x15 /* Maximum SIGP order value */ #define LOG_SIGPORDER 0x03 /* Log any SIGP > this value */ /* SIGP status codes */ #define SIGP_STATUS_EQUIPMENT_CHECK 0x80000000 #define SIGP_STATUS_NOT_RUNNING 0x00000400 #define SIGP_STATUS_INCORRECT_STATE 0x00000200 #define SIGP_STATUS_INVALID_PARAMETER 0x00000100 #define SIGP_STATUS_EXTERNAL_CALL_PENDING 0x00000080 #define SIGP_STATUS_STOPPED 0x00000040 #define SIGP_STATUS_OPERATOR_INTERVENING 0x00000020 #define SIGP_STATUS_CHECK_STOP 0x00000010 #define SIGP_STATUS_INOPERATIVE 0x00000004 #define SIGP_STATUS_INVALID_ORDER 0x00000002 #define SIGP_STATUS_RECEIVER_CHECK 0x00000001 /* Storage key bit definitions */ #define STORKEY_KEY 0xF0 /* Storage key */ #define STORKEY_FETCH 0x08 /* Fetch protect bit */ #define STORKEY_REF 0x04 /* Reference bit */ #define STORKEY_CHANGE 0x02 /* Change bit */ #define STORKEY_BADFRM 0x01 /* Unusable frame */ /* Prefixed storage area structure definition */ typedef struct _PSA_3XX { /* Prefixed storage area */ /*000*/ DBLWRD iplpsw; /* IPL PSW, Restart new PSW */ /*008*/ DBLWRD iplccw1; /* IPL CCW1, Restart old PSW */ /*010*/ DBLWRD iplccw2; /* IPL CCW2 */ /*018*/ DBLWRD extold; /* External old PSW */ /*020*/ DBLWRD svcold; /* SVC old PSW */ /*028*/ DBLWRD pgmold; /* Program check old PSW */ /*030*/ DBLWRD mckold; /* Machine check old PSW */ /*038*/ DBLWRD iopold; /* I/O old PSW */ /*040*/ DBLWRD csw; /* Channel status word (S370)*/ /*048*/ FWORD caw; /* Channel address word(S370)*/ /*04C*/ FWORD resv04C; /* Reserved */ /*050*/ FWORD inttimer; /* Interval timer */ /*054*/ FWORD resv054; /* Reserved */ /*058*/ DBLWRD extnew; /* External new PSW */ /*060*/ DBLWRD svcnew; /* SVC new PSW */ /*068*/ DBLWRD pgmnew; /* Program check new PSW */ /*070*/ DBLWRD mcknew; /* Machine check new PSW */ /*078*/ DBLWRD iopnew; /* I/O new PSW */ /*080*/ FWORD extparm; /* External interrupt param */ /*084*/ HWORD extcpad; /* External interrupt CPU# */ /*086*/ HWORD extint; /* External interrupt code */ /*088*/ FWORD svcint; /* SVC interrupt code */ /*08C*/ FWORD pgmint; /* Program interrupt code */ /*090*/ FWORD tea; /* Translation exception addr*/ /*094*/ HWORD monclass; /* Monitor class */ /*096*/ HWORD perint; /* PER interrupt code */ /*098*/ FWORD peradr; /* PER address */ /*09C*/ FWORD moncode; /* Monitor code */ /*0A0*/ BYTE excarid; /* Exception access id */ /*0A1*/ BYTE perarid; /* PER access id */ /*0A2*/ BYTE opndrid; /* Operand access id */ /*0A3*/ BYTE arch; /* Architecture mode ID */ /*0A4*/ FWORD resv0A4; /* Reserved */ /*0A8*/ FWORD chanid; /* Channel id (S370) */ /*0AC*/ FWORD ioelptr; /* I/O extended logout (S370)*/ /*0B0*/ FWORD lcl; /* Limited chan logout (S370)*/ /*0B4*/ FWORD resv0B0; /* Reserved */ /*0B8*/ FWORD ioid; /* I/O interrupt device id */ /*0BC*/ FWORD ioparm; /* I/O interrupt parameter */ /*0C0*/ FWORD iointid; /* I/O interrupt ID */ /*0C4*/ FWORD resv0C4; /* Reserved */ /*0C8*/ FWORD stfl; /* Facilities list (STFL) */ /*0CC*/ FWORD resv0CC; /* Reserved */ /*0D0*/ DBLWRD resv0D0; /* Reserved */ /*0D8*/ DBLWRD storeptmr; /* CPU timer save area */ /*0E0*/ DBLWRD storeclkc; /* Clock comparator save area*/ /*0E8*/ DBLWRD mckint; /* Machine check int code */ /*0F0*/ FWORD resv0F0; /* Reserved */ /*0F4*/ FWORD xdmgcode; /* External damage code */ /*0F8*/ FWORD mcstorad; /* Failing storage address */ /*0FC*/ FWORD resv0FC; /* Reserved */ /*100*/ DBLWRD storepsw; /* Store status PSW save area*/ /*108*/ FWORD storepfx; /* Prefix register save area */ /*10C*/ FWORD resv10C; /* Reserved */ /*110*/ DBLWRD resv110; /* Reserved */ /*118*/ DBLWRD resv118; /* Reserved */ /*120*/ FWORD storear[16]; /* Access register save area */ /*160*/ FWORD storefpr[8]; /* FP register save area */ /*180*/ FWORD storegpr[16]; /* General register save area*/ /*1C0*/ FWORD storecr[16]; /* Control register save area*/ } PSA_3XX; /* ESAME Prefixed storage area structure definition */ typedef struct _PSA_900 { /* Prefixed storage area */ /*0000*/ DBLWRD iplpsw; /* IPL PSW */ /*0008*/ DBLWRD iplccw1; /* IPL CCW1 */ /*0010*/ DBLWRD iplccw2; /* IPL CCW2 */ /*0018*/ BYTE resv0018[104]; /* Reserved */ /*0080*/ FWORD extparm; /* External interrupt param */ /*0084*/ HWORD extcpad; /* External interrupt CPU# */ /*0086*/ HWORD extint; /* External interrupt code */ /*0088*/ FWORD svcint; /* SVC interrupt code */ /*008C*/ FWORD pgmint; /* Program interrupt code */ /*0090*/ FWORD dataexc; /* Data exception code */ /*0094*/ HWORD monclass; /* Monitor class */ /*0096*/ HWORD perint; /* PER interrupt code */ /*0098*/ DBLWRD peradr; /* PER address */ /*00A0*/ BYTE excarid; /* Exception access id */ /*00A1*/ BYTE perarid; /* PER access id */ /*00A2*/ BYTE opndrid; /* Operand access id */ /*00A3*/ BYTE arch; /* Architecture mode ID */ /*00A4*/ FWORD mpladdr; /* MPL addr */ /*00A8*/ DWORD_U tea; /* Translation exception addr*/ #define TEA_G tea.D #define TEA_L tea.F.L.F #define TEA_H tea.F.H.F /*00B0*/ DBLWRD moncode; /* Monitor code */ /*00B8*/ FWORD ioid; /* I/O interrupt subsys id */ /*00BC*/ FWORD ioparm; /* I/O interrupt parameter */ /*00C0*/ FWORD iointid; /* I/O interrupt ID */ /*00C4*/ FWORD resv00C0; /* Reserved */ /*00C8*/ FWORD stfl; /* Facilities list (STFL) */ /*00CC*/ FWORD resv00CC; /* Reserved */ /*00D0*/ DBLWRD resv00D0; /* Reserved */ /*00D8*/ DBLWRD resv00D8; /* Reserved */ /*00E0*/ DBLWRD resv00E0; /* Reserved */ /*00E8*/ DBLWRD mckint; /* Machine check int code */ /*00F0*/ FWORD mckext; /* Machine check int code ext*/ /*00F4*/ FWORD xdmgcode; /* External damage code */ /*00F8*/ DBLWRD mcstorad; /* Failing storage address */ /*0100*/ DBLWRD cao; /* Enh Mon Counter Array Orig*/ /*0108*/ FWORD cal; /* Enh Mon Counter Array Len */ /*010C*/ FWORD ec; /* Enh Mon Exception Count */ /*0110*/ DBLWRD bea; /* Breaking event address @Z9*/ /*0118*/ DBLWRD resv0118; /* Reserved */ /*0120*/ QWORD rstold; /* Restart old PSW */ /*0130*/ QWORD extold; /* External old PSW */ /*0140*/ QWORD svcold; /* SVC old PSW */ /*0150*/ QWORD pgmold; /* Program check old PSW */ /*0160*/ QWORD mckold; /* Machine check old PSW */ /*0170*/ QWORD iopold; /* I/O old PSW */ /*0180*/ BYTE resv0180[32]; /* Reserved */ /*01A0*/ QWORD rstnew; /* Restart new PSW */ /*01B0*/ QWORD extnew; /* External new PSW */ /*01C0*/ QWORD svcnew; /* SVC new PSW */ /*01D0*/ QWORD pgmnew; /* Program check new PSW */ /*01E0*/ QWORD mcknew; /* Machine check new PSW */ /*01F0*/ QWORD iopnew; /* I/O new PSW */ /*0200*/ BYTE resv0200[4096]; /* Reserved */ /*1200*/ FWORD storefpr[32]; /* FP register save area */ /*1280*/ DBLWRD storegpr[16]; /* General register save area*/ /*1300*/ QWORD storepsw; /* Store status PSW save area*/ /*1310*/ DBLWRD resv1310; /* Reserved */ /*1318*/ FWORD storepfx; /* Prefix register save area */ /*131C*/ FWORD storefpc; /* FP control save area */ /*1320*/ FWORD resv1320; /* Reserved */ /*1324*/ FWORD storetpr; /* TOD prog reg save area */ /*1328*/ DBLWRD storeptmr; /* CPU timer save area */ /*1330*/ DBLWRD storeclkc; /* Clock comparator save area*/ /*1338*/ DBLWRD resv1338; /* Reserved */ /*1340*/ FWORD storear[16]; /* Access register save area */ /*1380*/ DBLWRD storecr[16]; /* Control register save area*/ } PSA_900; /* Bit settings for translation exception address */ #define TEA_SECADDR 0x80000000 /* Secondary addr (370,390) */ #define TEA_FETCH 0x800 /* Fetch exception 810*/ #define TEA_STORE 0x400 /* Store exception 810*/ #define TEA_PROT_A 0x008 /* Access-list prot (ESAME) */ #define TEA_PROT_AP 0x004 /* Access-list/page protected*/ #define TEA_MVPG 0x004 /* MVPG exception (ESAME) */ #define TEA_ST 0x003 /* Address space indication..*/ #define TEA_ST_PRIMARY 0x000 /* ..primary STO/ASCE used */ #define TEA_ST_ARMODE 0x001 /* ..access register mode */ #define TEA_ST_SECNDRY 0x002 /* ..secondary STO/ASCE used */ #define TEA_ST_HOME 0x003 /* ..home STO/ASCE used */ #define TEA_SSEVENT 0x80000000 /* Space switch event bit */ #define TEA_ASN 0x0000FFFF /* Address space number */ #define TEA_PCN 0x000FFFFF /* Program call number */ /* Bit settings for machine check interruption code */ #define MCIC_SD 0x8000000000000000ULL /* System damage */ #define MCIC_P 0x4000000000000000ULL /* Instruction proc damage */ #define MCIC_SR 0x2000000000000000ULL /* System recovery */ #define MCIC_CD 0x0800000000000000ULL /* Timing facility damage */ #define MCIC_ED 0x0400000000000000ULL /* External damage */ #define MCIC_VF 0x0200000000000000ULL /* Vector facility failure */ #define MCIC_DG 0x0100000000000000ULL /* Degradation */ #define MCIC_W 0x0080000000000000ULL /* Warning */ #define MCIC_CP 0x0040000000000000ULL /* Channel report pending */ #define MCIC_SP 0x0020000000000000ULL /* Service processor damage */ #define MCIC_CK 0x0010000000000000ULL /* Channel subsystem damage */ #define MCIC_VS 0x0004000000000000ULL /* Vector facility source */ #define MCIC_B 0x0002000000000000ULL /* Backed up */ #define MCIC_SE 0x0000800000000000ULL /* Storage error uncorrected */ #define MCIC_SC 0x0000400000000000ULL /* Storage error corrected */ #define MCIC_KE 0x0000200000000000ULL /* Storkey error uncorrected */ #define MCIC_DS 0x0000100000000000ULL /* Storage degradation */ #define MCIC_WP 0x0000080000000000ULL /* PSW-MWP validity */ #define MCIC_MS 0x0000040000000000ULL /* PSW mask and key validity */ #define MCIC_PM 0x0000020000000000ULL /* PSW pm and cc validity */ #define MCIC_IA 0x0000010000000000ULL /* PSW ia validity */ #define MCIC_FA 0x0000008000000000ULL /* Failing stor addr validity*/ #define MCIC_EC 0x0000002000000000ULL /* External damage code val. */ #define MCIC_FP 0x0000001000000000ULL /* Floating point reg val. */ #define MCIC_GR 0x0000000800000000ULL /* General register validity */ #define MCIC_CR 0x0000000400000000ULL /* Control register validity */ #define MCIC_ST 0x0000000100000000ULL /* Storage logical validity */ #define MCIC_IE 0x0000000080000000ULL /* Indirect storage error */ #define MCIC_AR 0x0000000040000000ULL /* Access register validity */ #define MCIC_DA 0x0000000020000000ULL /* Delayed access exeption */ #define MCIC_PR 0x0000000000200000ULL /* TOD prog. reg. validity */ #define MCIC_XF 0x0000000000100000ULL /* Extended float reg val. */ #define MCIC_AP 0x0000000000080000ULL /* Ancillary report */ #define MCIC_CT 0x0000000000020000ULL /* CPU timer validity */ #define MCIC_CC 0x0000000000010000ULL /* Clock comparator validity */ /* Channel Report Word definitions */ #define CRW_SOL 0x40000000 /* Solicited CRW */ #define CRW_OVER 0x20000000 /* Overflow, CRW's lost */ #define CRW_CHAIN 0x10000000 /* More CRW's describe event */ #define CRW_RSC 0x0F000000 /* Reporting resource mask */ #define CRW_MONIT 0x02000000 /* Channel monitor is source */ #define CRW_SUBCH 0x03000000 /* Subchannel is source */ #define CRW_CHPID 0x04000000 /* Channel path is source */ #define CRW_CAF 0x09000000 /* Configuration alert */ #define CRW_CSS 0x0B000000 /* Channel subsys is source */ #define CRW_AR 0x00800000 /* Ancillary report indicator*/ #define CRW_ERC 0x003F0000 /* Error recovery code */ #define CRW_AVAIL 0x00010000 /* Available */ #define CRW_INIT 0x00020000 /* Initialized no parm. chg. */ #define CRW_TEMP 0x00030000 /* Temporary error */ #define CRW_ALERT 0x00040000 /* Installed, subch changed */ #define CRW_TERM 0x00050000 /* Terminal */ #define CRW_PERM 0x00060000 /* Permanent error / not init*/ #define CRW_PERMI 0x00070000 /* Permanent, initialized */ #define CRW_IPM 0x00080000 /* PIM / PAM / CHPIDs changed*/ #define CRW_RSID 0x0000FFFF /* Resource identifier */ /* Bit settings for channel id */ #define CHANNEL_TYPE 0xF0000000 /* Bits 0-3=Channel type... */ #define CHANNEL_SEL 0x00000000 /* ...selector channel */ #define CHANNEL_MPX 0x10000000 /* ...byte multiplexor */ #define CHANNEL_BMX 0x20000000 /* ...block multiplexor */ #define CHANNEL_MODEL 0x0FFF0000 /* Bits 4-15=Channel model */ #define CHANNEL_MAXIOEL 0x0000FFFF /* Bits 16-31=Max.IOEL length*/ /* Program interruption codes */ #define PGM_OPERATION_EXCEPTION 0x0001 #define PGM_PRIVILEGED_OPERATION_EXCEPTION 0x0002 #define PGM_EXECUTE_EXCEPTION 0x0003 #define PGM_PROTECTION_EXCEPTION 0x0004 #define PGM_ADDRESSING_EXCEPTION 0x0005 #define PGM_SPECIFICATION_EXCEPTION 0x0006 #define PGM_DATA_EXCEPTION 0x0007 #define PGM_FIXED_POINT_OVERFLOW_EXCEPTION 0x0008 #define PGM_FIXED_POINT_DIVIDE_EXCEPTION 0x0009 #define PGM_DECIMAL_OVERFLOW_EXCEPTION 0x000A #define PGM_DECIMAL_DIVIDE_EXCEPTION 0x000B #define PGM_EXPONENT_OVERFLOW_EXCEPTION 0x000C #define PGM_EXPONENT_UNDERFLOW_EXCEPTION 0x000D #define PGM_SIGNIFICANCE_EXCEPTION 0x000E #define PGM_FLOATING_POINT_DIVIDE_EXCEPTION 0x000F #define PGM_SEGMENT_TRANSLATION_EXCEPTION 0x0010 #define PGM_PAGE_TRANSLATION_EXCEPTION 0x0011 #define PGM_TRANSLATION_SPECIFICATION_EXCEPTION 0x0012 #define PGM_SPECIAL_OPERATION_EXCEPTION 0x0013 #define PGM_OPERAND_EXCEPTION 0x0015 #define PGM_TRACE_TABLE_EXCEPTION 0x0016 #define PGM_ASN_TRANSLATION_SPECIFICATION_EXCEPTION 0x0017 #define PGM_VECTOR_OPERATION_EXCEPTION 0x0019 #define PGM_SPACE_SWITCH_EVENT 0x001C #define PGM_SQUARE_ROOT_EXCEPTION 0x001D #define PGM_UNNORMALIZED_OPERAND_EXCEPTION 0x001E #define PGM_PC_TRANSLATION_SPECIFICATION_EXCEPTION 0x001F #define PGM_AFX_TRANSLATION_EXCEPTION 0x0020 #define PGM_ASX_TRANSLATION_EXCEPTION 0x0021 #define PGM_LX_TRANSLATION_EXCEPTION 0x0022 #define PGM_EX_TRANSLATION_EXCEPTION 0x0023 #define PGM_PRIMARY_AUTHORITY_EXCEPTION 0x0024 #define PGM_SECONDARY_AUTHORITY_EXCEPTION 0x0025 #define PGM_LFX_TRANSLATION_EXCEPTION 0x0026 #define PGM_LSX_TRANSLATION_EXCEPTION 0x0027 #define PGM_ALET_SPECIFICATION_EXCEPTION 0x0028 #define PGM_ALEN_TRANSLATION_EXCEPTION 0x0029 #define PGM_ALE_SEQUENCE_EXCEPTION 0x002A #define PGM_ASTE_VALIDITY_EXCEPTION 0x002B #define PGM_ASTE_SEQUENCE_EXCEPTION 0x002C #define PGM_EXTENDED_AUTHORITY_EXCEPTION 0x002D #define PGM_LSTE_SEQUENCE_EXCEPTION 0x002E #define PGM_ASTE_INSTANCE_EXCEPTION 0x002F #define PGM_STACK_FULL_EXCEPTION 0x0030 #define PGM_STACK_EMPTY_EXCEPTION 0x0031 #define PGM_STACK_SPECIFICATION_EXCEPTION 0x0032 #define PGM_STACK_TYPE_EXCEPTION 0x0033 #define PGM_STACK_OPERATION_EXCEPTION 0x0034 #define PGM_ASCE_TYPE_EXCEPTION 0x0038 #define PGM_REGION_FIRST_TRANSLATION_EXCEPTION 0x0039 #define PGM_REGION_SECOND_TRANSLATION_EXCEPTION 0x003A #define PGM_REGION_THIRD_TRANSLATION_EXCEPTION 0x003B #define PGM_MONITOR_EVENT 0x0040 #define PGM_PER_EVENT 0x0080 #define PGM_CRYPTO_OPERATION_EXCEPTION 0x0119 /* External interrupt codes */ #define EXT_INTERRUPT_KEY_INTERRUPT 0x0040 #define EXT_INTERVAL_TIMER_INTERRUPT 0x0080 #define EXT_TOD_CLOCK_SYNC_CHECK_INTERRUPT 0x1003 #define EXT_CLOCK_COMPARATOR_INTERRUPT 0x1004 #define EXT_CPU_TIMER_INTERRUPT 0x1005 #define EXT_MALFUNCTION_ALERT_INTERRUPT 0x1200 #define EXT_EMERGENCY_SIGNAL_INTERRUPT 0x1201 #define EXT_EXTERNAL_CALL_INTERRUPT 0x1202 #define EXT_ETR_INTERRUPT 0x1406 #define EXT_MEASUREMENT_ALERT_INTERRUPT 0x1407 #define EXT_SERVICE_SIGNAL_INTERRUPT 0x2401 #define EXT_IUCV_INTERRUPT 0x4000 #if defined(FEATURE_ECPSVM) #define EXT_VINTERVAL_TIMER_INTERRUPT 0x0100 #endif #if defined(FEATURE_VM_BLOCKIO) #define EXT_BLOCKIO_INTERRUPT 0x2603 #endif /* Macros for classifying CCW operation codes */ #define IS_CCW_WRITE(c) (((c)&0x03)==0x01) #define IS_CCW_READ(c) (((c)&0x03)==0x02) #define IS_CCW_CONTROL(c) (((c)&0x03)==0x03) #define IS_CCW_NOP(c) ((c)==0x03) #define IS_CCW_SENSE(c) (((c)&0x0F)==0x04) #define IS_CCW_TIC(c) (((c)&0x0F)==0x08) #define IS_CCW_RDBACK(c) (((c)&0x0F)==0x0C) /* Operation request block structure definition */ typedef struct _ORB { FWORD intparm; /* Interruption parameter */ BYTE flag4; /* Flag byte 4 */ BYTE flag5; /* Flag byte 5 */ BYTE lpm; /* Logical path mask */ BYTE flag7; /* Flag byte 7 */ FWORD ccwaddr; /* CCW address */ } ORB; /* Bit definitions for ORB flag byte 4 */ #define ORB4_KEY 0xF0 /* Subchannel protection key */ #define ORB4_S 0x08 /* Suspend control */ #define ORB4_C 0x04 /* Streaming mode (FICON) */ #define ORB4_M 0x02 /* Modification (FICON) */ #define ORB4_Y 0x01 /* Synchronization (FICON) */ /* Bit definitions for ORB flag byte 5 */ #define ORB5_F 0x80 /* CCW format */ #define ORB5_P 0x40 /* Prefetch */ #define ORB5_I 0x20 /* Initial status interrupt */ #define ORB5_A 0x10 /* Address limit checking */ #define ORB5_U 0x08 /* Suppress susp interrupt */ #define ORB5_RESV 0x04 /* Reserved bit - must be 0 */ #define ORB5_H 0x02 /* Format-2 IDAW control */ #define ORB5_T 0x01 /* 2K format-2 IDAW control */ /* Bit definitions for ORB flag byte 7 */ #define ORB7_L 0x80 /* Suppress incorrect length */ #define ORB7_D 0x40 /* MIDAW control @MW*/ #define ORB7_RESV 0x3E /* Reserved - must be 0 @MW*/ #define ORB7_X 0x01 /* ORB extension control */ /* Path management control word structure definition */ typedef struct _PMCW { FWORD intparm; /* Interruption parameter */ BYTE flag4; /* Flag byte 4 */ BYTE flag5; /* Flag byte 5 */ HWORD devnum; /* Device number */ BYTE lpm; /* Logical path mask */ BYTE pnom; /* Path not operational mask */ BYTE lpum; /* Last path used mask */ BYTE pim; /* Path installed mask */ HWORD mbi; /* Measurement block index */ BYTE pom; /* Path operational mask */ BYTE pam; /* Path available mask */ BYTE chpid[8]; /* Channel path identifiers */ BYTE zone; /* SIE zone */ BYTE flag25; /* Flag byte 25 */ BYTE flag26; /* Reserved byte - must be 0 */ BYTE flag27; /* Flag byte 27 */ } PMCW; /* Bit definitions for PMCW flag byte 4 */ #define PMCW4_Q 0x80 /* QDIO available */ #define PMCW4_ISC 0x38 /* Interruption subclass */ #define PMCW4_A 0x01 /* Alternate Block Control */ #define PMCW4_RESV 0x46 /* Reserved bits - must be 0 */ /* Bit definitions for PMCW flag byte 5 */ #define PMCW5_E 0x80 /* Subchannel enabled */ #define PMCW5_LM 0x60 /* Limit mode... */ #define PMCW5_LM_NONE 0x00 /* ...no limit checking */ #define PMCW5_LM_LOW 0x20 /* ...lower limit specified */ #define PMCW5_LM_HIGH 0x40 /* ...upper limit specified */ #define PMCW5_LM_RESV 0x60 /* ...reserved value */ #define PMCW5_MM 0x18 /* Measurement mode enable...*/ #define PMCW5_MM_MBU 0x10 /* ...meas.block.upd enabled */ #define PMCW5_MM_DCTM 0x08 /* Dev.conn.time.meas enabled*/ #define PMCW5_D 0x04 /* Multipath mode enabled */ #define PMCW5_T 0x02 /* Timing facility available */ #define PMCW5_V 0x01 /* Subchannel valid */ /* Bit definitions for PMCW flag byte 25 */ #define PMCW25_VISC 0x07 /* Guest ISC */ #define PMCW25_TYPE 0xE0 /* Subchannel Type */ #define PMCW25_TYPE_0 0x00 /* I/O Subchannel */ #define PMCW25_TYPE_1 0x20 /* CHSC subchannel */ #define PMCW25_TYPE_2 0x40 /* Message subchannel */ #define PMCW25_TYPE_3 0x60 /* ADM subchannel */ #define PMCW25_RESV 0x18 /* Reserved bits */ /* Bit definitions for PMCW flag byte 27 */ #define PMCW27_I 0x80 /* Interrupt Interlock Cntl */ #define PMCW27_S 0x01 /* Concurrent sense mode */ #define PMCW27_RESV 0x7E /* Reserved bits - must be 0 */ /* Extended status word structure definition */ typedef struct _ESW { BYTE scl0; /* Subchannel logout byte 0 */ BYTE lpum; /* Last path used mask */ BYTE scl2; /* Subchannel logout byte 2 */ BYTE scl3; /* Subchannel logout byte 3 */ BYTE erw0; /* Extended report word byte0*/ BYTE erw1; /* Extended report word byte1*/ BYTE erw2; /* Extended report word byte2*/ BYTE erw3; /* Extended report word byte3*/ FWORD failaddr; /* Failing storage address */ FWORD resv2; /* Reserved word - must be 0 */ FWORD resv3; /* Reserved word - must be 0 */ } ESW; /* Bit definitions for subchannel logout byte 0 */ #define SCL0_ESF 0x7F /* Extended status flags... */ #define SCL0_ESF_KEY 0x40 /* ...key check */ #define SCL0_ESF_MBPGK 0x20 /* ...meas.block prog.check */ #define SCL0_ESF_MBDCK 0x10 /* ...meas.block data check */ #define SCL0_ESF_MBPTK 0x08 /* ...meas.block prot.check */ #define SCL0_ESF_CCWCK 0x04 /* ...CCW check */ #define SCL0_ESF_IDACK 0x02 /* ...IDAW check */ /* Bit definitions for subchannel logout byte 2 */ #define SCL2_R 0x80 /* Ancillary report bit */ #define SCL2_FVF 0x7C /* Field validity flags... */ #define SCL2_FVF_LPUM 0x40 /* ...LPUM valid */ #define SCL2_FVF_TC 0x20 /* ...termination code valid */ #define SCL2_FVF_SC 0x10 /* ...sequence code valid */ #define SCL2_FVF_USTAT 0x08 /* ...device status valid */ #define SCL2_FVF_CCWAD 0x04 /* ...CCW address valid */ #define SCL2_SA 0x03 /* Storage access code... */ #define SCL2_SA_UNK 0x00 /* ...access type unknown */ #define SCL2_SA_RD 0x01 /* ...read */ #define SCL2_SA_WRT 0x02 /* ...write */ #define SCL2_SA_RDBK 0x03 /* ...read backward */ /* Bit definitions for subchannel logout byte 3 */ #define SCL3_TC 0xC0 /* Termination code... */ #define SCL3_TC_HALT 0x00 /* ...halt signal issued */ #define SCL3_TC_NORM 0x40 /* ...stop, stack, or normal */ #define SCL3_TC_CLEAR 0x80 /* ...clear signal issued */ #define SCL3_TC_RESV 0xC0 /* ...reserved */ #define SCL3_D 0x20 /* Device status check */ #define SCL3_E 0x10 /* Secondary error */ #define SCL3_A 0x08 /* I/O error alert */ #define SCL3_SC 0x07 /* Sequence code */ /* Bit definitions for extended report word byte 0 */ #define ERW0_A 0x10 /* Authorization check */ #define ERW0_P 0x08 /* Path verification required*/ #define ERW0_T 0x04 /* Channel path timeout */ #define ERW0_F 0x02 /* Failing storage addr valid*/ #define ERW0_S 0x01 /* Concurrent sense */ /* Bit definitions for extended report word byte 1 */ #define ERW1_SCNT 0x3F /* Concurrent sense count */ /* Subchannel status word structure definition */ typedef struct _SCSW { BYTE flag0; /* Flag byte 0 */ BYTE flag1; /* Flag byte 1 */ BYTE flag2; /* Flag byte 2 */ BYTE flag3; /* Flag byte 3 */ FWORD ccwaddr; /* CCW address */ BYTE unitstat; /* Device status */ BYTE chanstat; /* Subchannel status */ HWORD count; /* Residual byte count */ } SCSW; /* Bit definitions for SCSW flag byte 0 */ #define SCSW0_KEY 0xF0 /* Subchannel protection key */ #define SCSW0_S 0x08 /* Suspend control */ #define SCSW0_L 0x04 /* ESW format (logout stored)*/ #define SCSW0_CC 0x03 /* Deferred condition code...*/ #define SCSW0_CC_0 0x00 /* ...condition code 0 */ #define SCSW0_CC_1 0x01 /* ...condition code 1 */ #define SCSW0_CC_3 0x03 /* ...condition code 3 */ /* Bit definitions for SCSW flag byte 1 */ #define SCSW1_F 0x80 /* CCW format */ #define SCSW1_P 0x40 /* Prefetch */ #define SCSW1_I 0x20 /* Initial status interrupt */ #define SCSW1_A 0x10 /* Address limit checking */ #define SCSW1_U 0x08 /* Suppress susp interrupt */ #define SCSW1_Z 0x04 /* Zero condition code */ #define SCSW1_E 0x02 /* Extended control */ #define SCSW1_N 0x01 /* Path not operational */ /* Bit definitions for SCSW flag byte 2 */ #define SCSW2_Q 0x80 /* QDIO active */ #define SCSW2_FC 0x70 /* Function control bits... */ #define SCSW2_FC_START 0x40 /* ...start function */ #define SCSW2_FC_HALT 0x20 /* ...halt function */ #define SCSW2_FC_CLEAR 0x10 /* ...clear function */ #define SCSW2_AC 0x0F /* Activity control bits... */ #define SCSW2_AC_RESUM 0x08 /* ...resume pending */ #define SCSW2_AC_START 0x04 /* ...start pending */ #define SCSW2_AC_HALT 0x02 /* ...halt pending */ #define SCSW2_AC_CLEAR 0x01 /* ...clear pending */ /* Bit definitions for SCSW flag byte 3 */ #define SCSW3_AC 0xE0 /* Activity control bits... */ #define SCSW3_AC_SCHAC 0x80 /* ...subchannel active */ #define SCSW3_AC_DEVAC 0x40 /* ...device active */ #define SCSW3_AC_SUSP 0x20 /* ...suspended */ #define SCSW3_SC 0x1F /* Status control bits... */ #define SCSW3_SC_ALERT 0x10 /* ...alert status */ #define SCSW3_SC_INTER 0x08 /* ...intermediate status */ #define SCSW3_SC_PRI 0x04 /* ...primary status */ #define SCSW3_SC_SEC 0x02 /* ...secondary status */ #define SCSW3_SC_PEND 0x01 /* ...status pending */ /* CSW unit status flags */ #define CSW_ATTN 0x80 /* Attention */ #define CSW_SM 0x40 /* Status modifier */ #define CSW_CUE 0x20 /* Control unit end */ #define CSW_BUSY 0x10 /* Busy */ #define CSW_CE 0x08 /* Channel end */ #define CSW_DE 0x04 /* Device end */ #define CSW_UC 0x02 /* Unit check */ #define CSW_UX 0x01 /* Unit exception */ /* CSW channel status flags */ #define CSW_PCI 0x80 /* Program control interrupt */ #define CSW_IL 0x40 /* Incorrect length */ #define CSW_PROGC 0x20 /* Program check */ #define CSW_PROTC 0x10 /* Protection check */ #define CSW_CDC 0x08 /* Channel data check */ #define CSW_CCC 0x04 /* Channel control check */ #define CSW_ICC 0x02 /* Interface control check */ #define CSW_CHC 0x01 /* Chaining check */ /* CCW flags */ #define CCW_FLAGS_CD 0x80 /* Chain data flag */ #define CCW_FLAGS_CC 0x40 /* Chain command flag */ #define CCW_FLAGS_SLI 0x20 /* Suppress incorrect length indication flag */ #define CCW_FLAGS_SKIP 0x10 /* Skip flag */ #define CCW_FLAGS_PCI 0x08 /* Program controlled interrupt flag */ #define CCW_FLAGS_IDA 0x04 /* Indirect data address flag*/ #define CCW_FLAGS_SUSP 0x02 /* Suspend flag */ #define CCW_FLAGS_MIDAW 0x01 /* Modified IDAW flag @MW*/ /* MIDAW flags (bits 40-47) @MW*/ #define MIDAW_LAST 0x80 /* Last MIDAW flag @MW*/ #define MIDAW_SKIP 0x40 /* Skip flag @MW*/ #define MIDAW_DTI 0x20 /* Data transfer interrupt@MW*/ #define MIDAW_RESV 0x1F /* Reserved bits @MW*/ /* Device independent bit settings for sense byte 0 */ #define SENSE_CR 0x80 /* Command reject */ #define SENSE_IR 0x40 /* Intervention required */ #define SENSE_BOC 0x20 /* Bus-out check */ #define SENSE_EC 0x10 /* Equipment check */ #define SENSE_DC 0x08 /* Data check */ #define SENSE_OR 0x04 /* Overrun */ #define SENSE_US 0x04 /* Unit specify */ #define SENSE_CC 0x02 /* Control check */ #define SENSE_OC 0x01 /* Operation check */ /* Device dependent bit settings for sense byte 1 */ #define SENSE1_PER 0x80 /* Permanent Error */ #define SENSE1_ITF 0x40 /* Invalid Track Format */ #define SENSE1_EOC 0x20 /* End of Cylinder */ #define SENSE1_MTO 0x10 /* Message to Operator */ #define SENSE1_NRF 0x08 /* No Record Found */ #define SENSE1_FP 0x04 /* File Protected */ #define SENSE1_WRI 0x02 /* Write Inhibited */ #define SENSE1_IE 0x01 /* Imprecise Ending */ /* Subchannel information block structure definition */ typedef struct _SCHIB { PMCW pmcw; /* Path management ctl word */ SCSW scsw; /* Subchannel status word */ BYTE moddep[12]; /* Model dependent area */ } SCHIB; /* Interruption response block structure definition */ typedef struct _IRB { SCSW scsw; /* Subchannel status word */ ESW esw; /* Extended status word */ BYTE ecw[32]; /* Extended control word */ } IRB; /* Measurement Block */ typedef struct _MBK { HWORD srcount; /* SSCH + RSCH count */ HWORD samplecnt; /* Sample count */ FWORD dct; /* Device connect time */ FWORD fpt; /* Function pending time */ FWORD ddt; /* Device disconnect time */ FWORD cuqt; /* Control unit queueing time*/ FWORD resv[3]; /* Reserved */ } MBK; /* Bit definitions for SCHM instruction */ #define CHM_GPR1_MBK 0xF0000000 /* Measurement Block Key */ #define CHM_GPR1_M 0x00000002 /* Measurement mode control */ #define CHM_GPR1_D 0x00000001 /* Block update Mode */ #define CHM_GPR1_A 0x01000000 /* Alternate mode */ #define CHM_GPR1_ZONE 0x00FF0000 /* Zone */ #define CHM_GPR1_RESV 0x0E00FFFC /* Reserved, must be zero */ /* Measurement Block Origin */ #define S_CHM_GPR2_RESV 0x8000001F /* Reserved, must be zero */ #define Z_CHM_GPR2_RESV 0x0000001F /* Reserved, must be zero */ /* Definitions for PLO instruction */ #define PLO_GPR0_FC 0x000000FF /* Function code mask */ #define PLO_GPR0_T 0x00000100 /* Function test mask */ #define PLO_GPR0_RESV 0xFFFFFE00 /* Reserved bits */ #define PLO_CL 0 /* Compare and load */ #define PLO_CLG 1 /* Compare and load */ #define PLO_CLGR 2 /* Compare and load ESAME */ #define PLO_CLX 3 /* Compare and load ESAME */ #define PLO_CS 4 /* Compare and swap */ #define PLO_CSG 5 /* Compare and swap */ #define PLO_CSGR 6 /* Compare and swap ESAME */ #define PLO_CSX 7 /* Compare and swap ESAME */ #define PLO_DCS 8 /* Double compare and swap */ #define PLO_DCSG 9 /* Double compare and swap */ #define PLO_DCSGR 10 /* Double c and s ESAME */ #define PLO_DCSX 11 /* Double c and s ESAME */ #define PLO_CSST 12 /* Compare and swap and store*/ #define PLO_CSSTG 13 /* Compare and swap and store*/ #define PLO_CSSTGR 14 /* C/S/S ESAME */ #define PLO_CSSTX 15 /* C/S/S ESAME */ #define PLO_CSDST 16 /* C/S and double store */ #define PLO_CSDSTG 17 /* C/S and double store */ #define PLO_CSDSTGR 18 /* C/S/DS ESAME */ #define PLO_CSDSTX 19 /* C/S/DS ESAME */ #define PLO_CSTST 20 /* C/S and triple store */ #define PLO_CSTSTG 21 /* C/S and triple store */ #define PLO_CSTSTGR 22 /* C/S/TS ESAME */ #define PLO_CSTSTX 23 /* C/S/TS ESAME */ /* Perform Frame Management Function definitions */ #define PFMF_FMFI 0x000f0000 /* Frame mgmt function indic */ #define PFMF_FMFI_RESV 0x000c0000 /* Reserved must be zero */ #define PFMF_FMFI_SK 0x00020000 /* Set-Key Control */ #define PFMF_FMFI_CF 0x00010000 /* Clear-Frame Control */ #define PFMF_UI 0x00008000 /* Usage Indication */ #define PFMF_FSC 0x00007000 /* Frame-Size Code */ #define PFMF_FSC_4K 0x00000000 /* 4K */ #define PFMF_FSC_1M 0x00001000 /* 1M */ #define PFMF_FSC_2G 0x00002000 /* 2G */ #define PFMF_NQ 0x00000800 /* Quiesce (SK must be one) */ #define PFMF_MR 0x00000400 /* Reference Bit Update Mask */ #define PFMF_MC 0x00000200 /* Change Bit Update Mask */ #define PFMF_KEY 0x000000F7 /* Storage Key */ #define PFMF_RESERVED 0xFFF00101 /* Reserved */ /* Bit definitions for Store Facilities List instruction */ /* Byte STFL_0: STFL/STFLE bits 0-7 */ #define STFL_0_N3 0x80 /* Instructions marked N3 in the reference summary are available in ESA/390 mode */ #define STFL_0_ESAME_INSTALLED 0x40 /* ESAME mode is available on this processor */ #define STFL_0_ESAME_ACTIVE 0x20 /* ESAME mode is active on this processor */ #define STFL_0_IDTE_INSTALLED 0x10 /* IDTE installed ESAME mode */ #define STFL_0_IDTE_SC_SEGTAB 0x08 /* IDTE selective clearing when segtab invalidated */ #define STFL_0_IDTE_SC_REGTAB 0x04 /* IDTE selective clearing when regtab invalidated */ #define STFL_0_ASN_LX_REUSE 0x02 /* ASN-and-LX-reuse facility is installed */ #define STFL_0_STFL_EXTENDED 0x01 /* Store facility list @Z9 extended is installed @Z9*/ /* Byte STFL_1: STFL/STFLE bits 8-15 */ #define STFL_1_ENHANCED_DAT 0x80 /* Enhanced-DAT facility 208 is installed 208*/ #define STFL_1_SENSE_RUN_STATUS 0x40 /* Sense running status @Z9 facility is installed @Z9*/ #define STFL_1_CONDITIONAL_SSKE 0x20 /* Conditional SSKE facility is installed 407*/ #define STFL_1_CONFIG_TOPOLOGY 0x10 /* STSI-enhancement for configuration topology */ #define STFL_1_IPTE_RANGE 0x04 /* IPTE-Range facility 810 installed 810*/ #define STFL_1_NONQ_KEY_SET 0x02 /* Nonquiescing Key-Setting 810 Facility installed 810*/ /* Byte STFL_2: STFL/STFLE bits 16-23 */ #define STFL_2_TRAN_FAC2 0x80 /* Extended translation facility 2 is installed */ #define STFL_2_MSG_SECURITY 0x40 /* Message security assist feature is installed */ #define STFL_2_LONG_DISPL_INST 0x20 /* Long displacement facility is installed */ #define STFL_2_LONG_DISPL_HPERF 0x10 /* Long displacement facility has high performance */ #define STFL_2_HFP_MULT_ADD_SUB 0x08 /* HFP multiply-add/subtract facility is installed */ #define STFL_2_EXTENDED_IMMED 0x04 /* Extended immediate @Z9 facility is installed @Z9*/ #define STFL_2_TRAN_FAC3 0x02 /* Extended translation facility 3 is installed */ #define STFL_2_HFP_UNNORM_EXT 0x01 /* HFP unnormalized extension facility is installed @Z9*/ /* Byte STFL_3: STFL/STFLE bits 24-31 */ #define STFL_3_ETF2_ENHANCEMENT 0x80 /* Extended translation @Z9 facility 2 enhancement @Z9*/ #define STFL_3_STORE_CLOCK_FAST 0x40 /* Store clock fast @Z9 enhancement installed @Z9*/ #define STFL_3_PARSING_ENHANCE 0x20 /* Parsing-Enhancement 208 facility is installed 208*/ #define STFL_3_MVCOS 0x10 /* MVCOS instruction is installed 407*/ #define STFL_3_TOD_CLOCK_STEER 0x08 /* TOD clock steering @Z9 facility is installed @Z9*/ #define STFL_3_ETF3_ENHANCEMENT 0x02 /* Extended translation @Z9 facility 3 enhancement @Z9*/ #define STFL_3_EXTRACT_CPU_TIME 0x01 /* Extract CPU time facility is installed 407*/ /* Byte STFL_4: STFLE bits 32-39 */ #define STFL_4_CSSF 0x80 /* Compare-and-Swap-and-Store facility is installed */ #define STFL_4_CSSF2 0x40 /* Compare-and-Swap-and-Store facility 2 is installed */ #define STFL_4_GEN_INST_EXTN 0x20 /* General-Instr-Extn 208 facility is installed 208*/ #define STFL_4_EXECUTE_EXTN 0x10 /* Execute-Extensions 208 facility is installed 208*/ #define STFL_4_ENH_MONITOR 0x08 /* Enhanced-Monitor facility installed 810*/ #define STFL_4_FP_EXTENSION 0x04 /* Floating-point extension facility installed 810*/ /* Byte STFL_5: STFLE bits 40-47 */ #define STFL_5_LOAD_PROG_PARAM 0x80 /* Load-Program-Parameter facility installed (ESAME)*/ #define STFL_5_FPS_ENHANCEMENT 0x40 /* Floating point support enhancements (FPR-GR-loading FPS-sign-handling, and DFP-rounding) installed */ #define STFL_5_DECIMAL_FLOAT 0x20 /* Decimal floating point (DFP) facility */ #define STFL_5_DFP_HPERF 0x10 /* DFP has high performance */ #define STFL_5_PFPO 0x08 /* PFPO instruction installed*/ #define STFL_5_FAST_BCR_SERIAL 0x04 /* Fast-BCR-serialization Facility installed 810*/ #define STFL_5_CMPSC_ENH 0x01 /* CMPSC-enhancement Facility installed 810*/ /* Byte STFL_6: STFLE bits 48-55 */ #define STFL_6_DFP_ZONED_CONV 0x80 /* DFP zoned-conversion facility is installed 912*/ #define STFL_6_MISC_INST_EXT 0x40 /* Execution-hint,load-and-trap misc-inst-ext,processor-asst facilities installed 912*/ #define STFL_6_CONSTRAINED_TEF 0x20 /* Constrained-transactn-execn facility is installed 912*/ #define STFL_6_LOCAL_TLB_CLEAR 0x10 /* Local-TLB-clearing facility is installed 912*/ #define STFL_6_INTERLOCK_ACC_2 0x08 /* Interlocked-access facility 2 installed 912*/ /* Byte STFL_7: STFLE bits 56-63 */ /* Byte STFL_8: STFLE bits 64-71 */ #define STFL_8_RES_REF_BITS_MUL 0x20 /* Reset-Reference-Bits-Multiple Facility installed 810*/ #define STFL_8_CPU_MEAS_COUNTER 0x10 /* CPU-measurement counter facility installed (ESAME)*/ #define STFL_8_CPU_MEAS_SAMPLNG 0x08 /* CPU-measurement sampling facility installed (ESAME)*/ /* Byte STFL_9: STFLE bits 72-79 */ #define STFL_9_TRANSACT_EXEC 0x40 /* Transactional execution facility is installed 912*/ #define STFL_9_ACC_EX_FS_INDIC 0x10 /* Access-exception fetch/store indication facility 810*/ #define STFL_9_MSA_EXTENSION_3 0x08 /* Message Security Assist Extension 3 installed 810*/ #define STFL_9_MSA_EXTENSION_4 0x04 /* Message Security Assist Extension 4 installed 810*/ #define STFL_9_ENHANCED_DAT_2 0x02 /* Enhanced-DAT facility 2 is installed 912*/ /* Bit definitions for the Vector Facility */ #define VSR_M 0x0001000000000000ULL /* Vector mask mode bit */ #define VSR_VCT 0x0000FFFF00000000ULL /* Vector count */ #define VSR_VIX 0x00000000FFFF0000ULL /* Vector interruption index */ #define VSR_VIU 0x000000000000FF00ULL /* Vector in-use bits */ #define VSR_VIU0 0x0000000000008000ULL /* Vector in-use bit vr0 */ #define VSR_VCH 0x00000000000000FFULL /* Vector change bits */ #define VSR_VCH0 0x0000000000000080ULL /* Vector change bit vr0 */ #define VSR_RESV 0xFFFE000000000000ULL /* Reserved bits */ #define VAC_MASK 0x00FFFFFFFFFFFFFFULL /* Vector Activity Count mask*/ /* SIE Format 1 State Descriptor Block */ typedef struct _SIE1BK { /* SIE State Descriptor */ /*000*/ BYTE v; /* Intervention requests */ #define SIE_V v #define SIE_V_WAIT 0x10 /* Wait/Run bit */ #define SIE_V_EXTCALL 0x08 /* External call pending */ #define SIE_V_STOP 0x04 /* SIE Stop control */ #define SIE_V_IO 0x02 /* I/O Interrupt pending */ #define SIE_V_EXT 0x01 /* EXT Interrupt pending */ /*001*/ BYTE s; /* State controls */ #define SIE_S s #define SIE_S_T 0x80 /* Interval timer irpt pend */ #define SIE_S_RETENTION 0x40 /* SIE State retained */ #define SIE_S_EXP_TIMER 0x02 /* Expedite timer enabled */ #define SIE_S_EXP_RUN 0x01 /* Expedite run enabled */ /*002*/ BYTE mx; /* Machine mode control */ #define SIE_MX mx #define SIE_MX_RRF 0x80 /* Region Relocate Installed */ #define SIE_MX_XC 0x01 /* XC mode guest */ /*003*/ BYTE m; /* Mode controls */ #define SIE_M m #define SIE_M_VCC 0x40 /* Vector change control */ #define SIE_M_XA 0x20 /* XA mode guest */ #define SIE_M_370 0x10 /* 370 mode guest */ #define SIE_M_VR 0x08 /* V=R mode guest */ #define SIE_M_ITMOF 0x04 /* Guest ival timer disabled */ #define SIE_M_GPE 0x01 /* Guest per enhancement */ /*004*/ FWORD prefix; /* Guest prefix register */ /*008*/ HWORD mso; /* Main Storage Origin */ /*00A*/ HWORD mse; /* Main Storage Extent */ /*00C*/ FWORD resv0cf; /*010*/ FWORD gr14; /* Guest gr 14 */ /*014*/ FWORD gr15; /* Guest gr 15 */ /*018*/ DBLWRD psw; /* Guest PSW */ /*020*/ FWORD resv20f; /*024*/ FWORD residue; /* Residue counter */ /*028*/ DBLWRD cputimer; /* CPU timer */ /*030*/ DBLWRD clockcomp; /* Clock comparator */ /*038*/ DBLWRD epoch; /* Guest/Host epoch diff. */ /*040*/ FWORD svc_ctl; /* SVC Controls */ #define SIE_SVC0 svc_ctl[0] #define SIE_SVC0_ALL 0x80 /* Intercept all SVCs */ #define SIE_SVC0_1N 0x40 /* Intercept SVC 1n */ #define SIE_SVC0_2N 0x20 /* Intercept SVC 2n */ #define SIE_SVC0_3N 0x10 /* Intercept SVC 3n */ /*044*/ HWORD lctl_ctl; /* LCTL Control */ #define SIE_LCTL0 lctl_ctl[0] #define SIE_LCTL0_CR0 0x80 /* Intercept LCTL 0 */ #define SIE_LCTL0_CR1 0x40 /* Intercept LCTL 1 */ #define SIE_LCTL0_CR2 0x20 /* Intercept LCTL 2 */ #define SIE_LCTL0_CR3 0x10 /* Intercept LCTL 3 */ #define SIE_LCTL0_CR4 0x08 /* Intercept LCTL 4 */ #define SIE_LCTL0_CR5 0x04 /* Intercept LCTL 5 */ #define SIE_LCTL0_CR6 0x02 /* Intercept LCTL 6 */ #define SIE_LCTL0_CR7 0x01 /* Intercept LCTL 7 */ #define SIE_LCTL1 lctl_ctl[1] #define SIE_LCTL1_CR8 0x80 /* Intercept LCTL 8 */ #define SIE_LCTL1_CR9 0x40 /* Intercept LCTL 9 */ #define SIE_LCTL1_CR10 0x20 /* Intercept LCTL 10 */ #define SIE_LCTL1_CR11 0x10 /* Intercept LCTL 11 */ #define SIE_LCTL1_CR12 0x08 /* Intercept LCTL 12 */ #define SIE_LCTL1_CR13 0x04 /* Intercept LCTL 13 */ #define SIE_LCTL1_CR14 0x02 /* Intercept LCTL 14 */ #define SIE_LCTL1_CR15 0x01 /* Intercept LCTL 15 */ /*046*/ HWORD cpuad; /* Virtual CPU address */ /*048*/ FWORD ic; /* Interception Controls */ #define SIE_IC0 ic[0] #define SIE_IC0_OPEREX 0x80 /* Intercept operation exc. */ #define SIE_IC0_PRIVOP 0x40 /* Intercept priv. op. exc. */ #define SIE_IC0_PGMALL 0x20 /* Intercept program ints */ #define SIE_IC0_STFL 0x10 /* Intercept STFL/STFLE */ #define SIE_IC0_TS1 0x08 /* Intercept TS cc1 */ #define SIE_IC0_CS1 0x04 /* Intercept CS cc1 */ #define SIE_IC0_CDS1 0x02 /* Intercept CDS cc1 */ #define SIE_IC0_IPTECSP 0x01 /* Intercept IPTE or CSP */ #define SIE_IC1 ic[1] #define SIE_IC1_LPSW 0x40 /* Intercept LPSW */ #define SIE_IC1_PXLB 0x20 /* Intercept PTLB or PALB */ #define SIE_IC1_SSM 0x10 /* Intercept SSM */ #define SIE_IC1_BSA 0x08 /* Intercept BSA */ #define SIE_IC1_STCTL 0x04 /* Intercept STCTL */ #define SIE_IC1_STNSM 0x02 /* Intercept STNSM */ #define SIE_IC1_STOSM 0x01 /* Intercept STOSM */ #define SIE_IC2 ic[2] #define SIE_IC2_STCK 0x80 /* Intercept STCK */ #define SIE_IC2_ISKE 0x40 /* Intercept ISK/ISKE */ #define SIE_IC2_SSKE 0x20 /* Intercept SSK/SSKE */ #define SIE_IC2_RRBE 0x10 /* Intercept RRB/RRBE */ #define SIE_IC2_PC 0x08 /* Intercept PC */ #define SIE_IC2_PT 0x04 /* Intercept PT */ #define SIE_IC2_TPROT 0x02 /* Intercept TPROT */ #define SIE_IC2_LASP 0x01 /* Intercept LASP */ #define SIE_IC3 ic[3] #define SIE_IC3_VACSV 0x80 /* Intercept VACSV */ #define SIE_IC3_SPT 0x40 /* Intercept SPT and STPT */ #define SIE_IC3_SCKC 0x20 /* Intercept SCKC and STCKC */ #define SIE_IC3_VACRS 0x10 /* Intercept VACRS */ #define SIE_IC3_PR 0x08 /* Intercept PR */ #define SIE_IC3_BAKR 0x04 /* Intercept BAKR */ #define SIE_IC3_PGX 0x02 /* Intercept PGIN/PGOUT */ /*04C*/ FWORD ec; /* Execution Controls */ #define SIE_EC0 ec[0] #define SIE_EC0_EXTA 0x80 /* External Interrupt Assist */ #define SIE_EC0_INTA 0x40 /* Intervention Bypass Assist*/ #define SIE_EC0_WAIA 0x20 /* Wait State Assist */ #define SIE_EC0_SIGPA 0x10 /* SIGP Assist */ #define SIE_EC0_ALERT 0x08 /* Alert Monitoring */ #define SIE_EC0_IOA 0x04 /* I/O Assist */ #define SIE_EC0_MVPG 0x01 /* Interpret MVPG and IESBE */ #define SIE_EC1 ec[1] #define SIE_EC1_EC370 0x20 /* 370 I/O Assist */ #define SIE_EC1_VFONL 0x04 /* Virtual VF online */ #define SIE_EC2 ec[2] #define SIE_EC2_PROTEX 0x20 /* Intercept prot exception */ #define SIE_EC3 ec[3] #define SIE_EC3_SIGAA 0x04 /* SIGA Assist */ /*050*/ BYTE c; /* Interception Code */ #define SIE_C_INST 4 /* Instruction interception */ #define SIE_C_PGMINT 8 /* Program interruption */ #define SIE_C_PGMINST 12 /* Program/instruction int */ #define SIE_C_EXTREQ 16 /* External request */ #define SIE_C_EXTINT 20 /* External interruption */ #define SIE_C_IOREQ 24 /* I/O request */ #define SIE_C_WAIT 28 /* Wait state */ #define SIE_C_VALIDITY 32 /* Validity */ #define SIE_C_STOPREQ 40 /* Stop request */ #define SIE_C_OPEREXC 44 /* Operation Exception */ #define SIE_C_IOINT 60 /* I/O Interruption */ #define SIE_C_IOINST 64 /* I/O Instruction */ #define SIE_C_EXP_RUN 68 /* Expedited Run Intercept */ #define SIE_C_EXP_TIMER 72 /* Expedited Timer Intercept */ /*051*/ BYTE f; /* Interception Status */ #define SIE_F f #define SIE_F_IN 0x80 /* Intercept format 2 */ #define SIE_F_IF 0x02 /* Instruction fetch PER */ #define SIE_F_EX 0x01 /* Icept for target of EX */ /*052*/ HWORD lhcpu; /* Last Host CPU addr */ /*054*/ HWORD todpf; /* TOD programmable field */ /*056*/ HWORD ipa; /* Instruction parameter A */ /*058*/ FWORD ipb; /* Instruction parameter B */ /*05C*/ FWORD ipc; /* Instruction parameter C */ /*060*/ FWORD rcpo; /* RCP area origin */ #define SIE_RCPO0 rcpo[0] #define SIE_RCPO0_SKA 0x80 /* Storage Key Assist */ #define SIE_RCPO0_SKAIP 0x40 /* SKA in progress */ #define SIE_RCPO2 rcpo[2] #define SIE_RCPO2_RCPBY 0x10 /* RCP Bypass */ /*064*/ FWORD scao; /* SCA area origin */ /*068*/ FWORD subchtabo; /* Subchannel table origin */ /*06C*/ FWORD resv6Cf; /*070*/ HWORD tch_ctl; /* Test Channel control */ /*072*/ HWORD resv72h; /*074*/ BYTE zone; /* Zone Number */ /*075*/ BYTE resv075; /*076*/ BYTE tschds; /* TSCH device status */ /*077*/ BYTE tschsc; /* TSCH subchannel status */ /*078*/ BYTE xslim[3]; /* Extended stor upper lim */ /*07B*/ BYTE resv7Bb; /*07C*/ FWORD resv7Cf; /*080*/ FWORD cr[16]; /* Guest Control registers */ /*0C0*/ BYTE ip[34]; /* Interruption parameters */ #define SIE_IP_PSA_OFFSET 0x40 /* Offset of the IP field relative to the ipfields in the PSA */ #define SIE_II_PSA_OFFSET 0x30 /* Offset of the IP field relative to the I/O fields in the PSA for ESAME guest*/ /*0E2*/ BYTE xso[3]; /* Expanded storage origin */ /*0E5*/ BYTE xsl[3]; /* Expanded storage limit */ /*0E8*/ BYTE resvE8b[24]; } SIE1BK; /* SIE Format 2 State Descriptor Block */ typedef struct _SIE2BK { /* SIE State Descriptor */ /*000*/ BYTE v; /* Intervention requests */ #define SIE_V v #define SIE_V_WAIT 0x10 /* Wait/Run bit */ #define SIE_V_EXTCALL 0x08 /* External call pending */ #define SIE_V_STOP 0x04 /* SIE Stop control */ #define SIE_V_IO 0x02 /* I/O Interrupt pending */ #define SIE_V_EXT 0x01 /* EXT Interrupt pending */ /*001*/ BYTE s; /* State controls */ #define SIE_S s #define SIE_S_T 0x80 /* Interval timer irpt pend */ #define SIE_S_RETENTION 0x40 /* SIE State retained */ #define SIE_S_EXP_TIMER 0x02 /* Expedite timer enabled */ #define SIE_S_EXP_RUN 0x01 /* Expedite run enabled */ /*002*/ BYTE mx; /* Machine mode control */ #define SIE_MX mx #define SIE_MX_RRF 0x80 /* Region Relocate Installed */ #define SIE_MX_XC 0x01 /* XC mode guest */ #define SIE_MX_ESAME 0x08 /* ESAME mode guest */ /*003*/ BYTE m; /* Mode controls */ #define SIE_M m #define SIE_M_VCC 0x40 /* Vector change control */ #define SIE_M_XA 0x20 /* XA mode guest */ #define SIE_M_370 0x10 /* 370 mode guest */ #define SIE_M_VR 0x08 /* V=R mode guest */ #define SIE_M_ITMOF 0x04 /* Guest ival timer disabled */ #define SIE_M_GPE 0x01 /* Guest per enhancement */ /*004*/ FWORD prefix; /* Guest prefix register */ /*008*/ FWORD resv008f; /*00C*/ FWORD resv00cf; /*010*/ DBLWRD resv010d; /*018*/ DBLWRD resv018d; /*020*/ DBLWRD resv020d; /*028*/ DBLWRD cputimer; /* CPU timer */ /*030*/ DBLWRD clockcomp; /* Clock comparator */ /*038*/ DBLWRD epoch; /* Guest/Host epoch diff. */ /*040*/ FWORD svc_ctl; /* SVC Controls */ #define SIE_SVC0 svc_ctl[0] #define SIE_SVC0_ALL 0x80 /* Intercept all SVCs */ #define SIE_SVC0_1N 0x40 /* Intercept SVC 1n */ #define SIE_SVC0_2N 0x20 /* Intercept SVC 2n */ #define SIE_SVC0_3N 0x10 /* Intercept SVC 3n */ /*044*/ HWORD lctl_ctl; /* LCTL Control */ #define SIE_LCTL0 lctl_ctl[0] #define SIE_LCTL0_CR0 0x80 /* Intercept LCTL 0 */ #define SIE_LCTL0_CR1 0x40 /* Intercept LCTL 1 */ #define SIE_LCTL0_CR2 0x20 /* Intercept LCTL 2 */ #define SIE_LCTL0_CR3 0x10 /* Intercept LCTL 3 */ #define SIE_LCTL0_CR4 0x08 /* Intercept LCTL 4 */ #define SIE_LCTL0_CR5 0x04 /* Intercept LCTL 5 */ #define SIE_LCTL0_CR6 0x02 /* Intercept LCTL 6 */ #define SIE_LCTL0_CR7 0x01 /* Intercept LCTL 7 */ #define SIE_LCTL1 lctl_ctl[1] #define SIE_LCTL1_CR8 0x80 /* Intercept LCTL 8 */ #define SIE_LCTL1_CR9 0x40 /* Intercept LCTL 9 */ #define SIE_LCTL1_CR10 0x20 /* Intercept LCTL 10 */ #define SIE_LCTL1_CR11 0x10 /* Intercept LCTL 11 */ #define SIE_LCTL1_CR12 0x08 /* Intercept LCTL 12 */ #define SIE_LCTL1_CR13 0x04 /* Intercept LCTL 13 */ #define SIE_LCTL1_CR14 0x02 /* Intercept LCTL 14 */ #define SIE_LCTL1_CR15 0x01 /* Intercept LCTL 15 */ /*046*/ HWORD cpuad; /* Virtual CPU address */ /*048*/ FWORD ic; /* Interception Controls */ #define SIE_IC0 ic[0] #define SIE_IC0_OPEREX 0x80 /* Intercept operation exc. */ #define SIE_IC0_PRIVOP 0x40 /* Intercept priv. op. exc. */ #define SIE_IC0_PGMALL 0x20 /* Intercept program ints */ #define SIE_IC0_TS1 0x08 /* Intercept TS cc1 */ #define SIE_IC0_CS1 0x04 /* Intercept CS cc1 */ #define SIE_IC0_CDS1 0x02 /* Intercept CDS cc1 */ #define SIE_IC0_IPTECSP 0x01 /* Intercept IPTE or CSP */ #define SIE_IC1 ic[1] #define SIE_IC1_LPSW 0x40 /* Intercept LPSW/LPSWE */ #define SIE_IC1_PXLB 0x20 /* Intercept PTLB or PALB */ #define SIE_IC1_SSM 0x10 /* Intercept SSM */ #define SIE_IC1_BSA 0x08 /* Intercept BSA */ #define SIE_IC1_STCTL 0x04 /* Intercept STCTL */ #define SIE_IC1_STNSM 0x02 /* Intercept STNSM */ #define SIE_IC1_STOSM 0x01 /* Intercept STOSM */ #define SIE_IC2 ic[2] #define SIE_IC2_STCK 0x80 /* Intercept STCK */ #define SIE_IC2_ISKE 0x40 /* Intercept ISK/ISKE */ #define SIE_IC2_SSKE 0x20 /* Intercept SSK/SSKE */ #define SIE_IC2_RRBE 0x10 /* Intercept RRB/RRBE */ #define SIE_IC2_PC 0x08 /* Intercept PC */ #define SIE_IC2_PT 0x04 /* Intercept PT */ #define SIE_IC2_TPROT 0x02 /* Intercept TPROT */ #define SIE_IC2_LASP 0x01 /* Intercept LASP */ #define SIE_IC3 ic[3] #define SIE_IC3_VACSV 0x80 /* Intercept VACSV */ #define SIE_IC3_SPT 0x40 /* Intercept SPT and STPT */ #define SIE_IC3_SCKC 0x20 /* Intercept SCKC and STCKC */ #define SIE_IC3_VACRS 0x10 /* Intercept VACRS */ #define SIE_IC3_PR 0x08 /* Intercept PR */ #define SIE_IC3_BAKR 0x04 /* Intercept BAKR */ #define SIE_IC3_PGX 0x02 /* Intercept PGIN/PGOUT */ /*04C*/ FWORD ec; /* Execution Controls */ #define SIE_EC0 ec[0] #define SIE_EC0_EXTA 0x80 /* External Interrupt Assist */ #define SIE_EC0_INTA 0x40 /* Intervention Bypass Assist*/ #define SIE_EC0_WAIA 0x20 /* Wait State Assist */ #define SIE_EC0_SIGPA 0x10 /* SIGP Assist */ #define SIE_EC0_ALERT 0x08 /* Alert Monitoring */ #define SIE_EC0_IOA 0x04 /* I/O Assist */ #define SIE_EC0_MVPG 0x01 /* Interpret MVPG and IESBE */ #define SIE_EC1 ec[1] #define SIE_EC1_EC370 0x20 /* 370 I/O Assist */ #define SIE_EC1_VFONL 0x04 /* Virtual VF online */ #define SIE_EC2 ec[2] #define SIE_EC2_PROTEX 0x20 /* Intercept prot exception */ #define SIE_EC3 ec[3] #define SIE_EC3_SIGAA 0x04 /* SIGA Assist */ /*050*/ BYTE c; /* Interception Code */ #define SIE_C_INST 4 /* Instruction interception */ #define SIE_C_PGMINT 8 /* Program interruption */ #define SIE_C_PGMINST 12 /* Program/instruction int */ #define SIE_C_EXTREQ 16 /* External request */ #define SIE_C_EXTINT 20 /* External interruption */ #define SIE_C_IOREQ 24 /* I/O request */ #define SIE_C_WAIT 28 /* Wait state */ #define SIE_C_VALIDITY 32 /* Validity */ #define SIE_C_STOPREQ 40 /* Stop request */ #define SIE_C_OPEREXC 44 /* Operation Exception */ #define SIE_C_EXP_RUN 68 /* Expedited Run Intercept */ #define SIE_C_EXP_TIMER 72 /* Expedited Timer Intercept */ /*051*/ BYTE f; /* Interception Status */ #define SIE_F f #define SIE_F_IN 0x80 /* Intercept format 2 */ #define SIE_F_IF 0x02 /* Instruction fetch PER */ #define SIE_F_EX 0x01 /* Icept for target of EX */ /*052*/ HWORD lhcpu; /* Last Host CPU addr */ /*054*/ HWORD resv054h; /*056*/ HWORD ipa; /* Instruction parameter A */ #define vi_who ipa[0] #define vi_when ipa[1] #define vi_why ipb #define vi_zero ipb+2 /*058*/ FWORD ipb; /* Instruction parameter B */ /*05C*/ FWORD ipc; /* Instruction parameter C */ /*060*/ FWORD rcpo; /* RCP area origin */ #define SIE_RCPO0 rcpo[0] #define SIE_RCPO0_SKA 0x80 /* Storage Key Assist */ #define SIE_RCPO0_SKAIP 0x40 /* SKA in progress */ #define SIE_RCPO2 rcpo[2] #define SIE_RCPO2_RCPBY 0x10 /* RCP Bypass */ /*064*/ FWORD scao; /* SCA area origin */ /*068*/ FWORD resv068f; /*06C*/ HWORD todpfh; /* TOD pf high half */ /*06E*/ HWORD todpf; /* TOD programmable field */ /*070*/ FWORD resv070f; /*074*/ BYTE zone; /* Zone Number */ /*075*/ BYTE resv075; /*076*/ BYTE tschds; /* TSCH device status */ /*077*/ BYTE tschsc; /* TSCH subchannel status */ /*078*/ FWORD resv078f; /*07C*/ FWORD resv07cf; /*080*/ DBLWRD mso; /* Main Storage Origin */ /*088*/ DBLWRD mse; /* Main Storage Extend The actual guest machine size is (mse+1)-mso */ #define SIE2_MS_MASK 0xFFFFFFFFFFF00000ULL /*090*/ QWORD psw; /* Guest PSW */ /*0A0*/ DBLWRD gr14; /* Guest gr 14 */ /*0A8*/ DBLWRD gr15; /* Guest gr 15 */ /*0B0*/ DBLWRD recv0b0d; /*0B8*/ HWORD recv0b8d; /*0BA*/ BYTE xso[3]; /* Expanded storage origin */ /*0BD*/ BYTE xsl[3]; /* Expanded storage limit */ /*0C0*/ BYTE ip[52]; /* Interruption parameters */ #define SIE_IP_PSA_OFFSET 0x40 /* Offset of the IP field relative to the ipfields in the PSA for ESAME guest*/ #define SIE_II_PSA_OFFSET 0x30 /* Offset of the IP field relative to the I/O fields in the PSA for ESAME guest*/ /*0F4*/ BYTE resv0f4b[6]; /*0FA*/ HWORD ief; /* Migration Emulation cnlt */ /*0FC*/ FWORD resv0fcf; /*100*/ DBLWRD cr[16]; /* Control registers */ /*180*/ BYTE resv180b[128]; } SIE2BK; #define SIE_VI_WHO_LVLM 0xF0 /* Mask for "source level" field: If non-zero, this is the inter- pretive-execution depth at which the problem was originally detected. It is set to 1 (or 2 for Interpreted SIE) by the entity (hardware or vSIE software) that reports the problem, and is incremented (to a max of 15) by every level of vSIE that passes the interception along. */ #define SIE_VI_WHO_LVL1 0x10 /* Condition recognized one level down in interpretive execution */ #define SIE_VI_WHO_LVLMX 0xF0 /* Maximum source level reported */ #define SIE_VI_WHO_INITM 0x0F /* Mask for "initiator" field, identifying the type of entity that detected the problem. */ #define SIE_VI_WHO_CPU 0x01 /* Initiator was a CPU */ #define SIE_VI_WHO_VSIE 0x08 /* Initiator was vSIE software */ #define SIE_VI_WHEN_RECPM 0xF0 /* Mask for "recognition point" field the normal processing that recognized the condition necessitating the validity interception. */ #define SIE_VI_WHEN_SIENT 0x10 /* Condition recognized during SIE entry */ #define SIE_VI_WHEN_INST 0x20 /* Condition recognized during instruction interpretation */ #define SIE_VI_WHEN_IRPT 0x30 /* Condition recognized during interruption interpretation */ #define SIE_VI_WHEN_SIEXT 0x40 /* Condition recognized during SIE exit */ #define SIE_VI_WHY_MODE 0x0001 /* Invalid guest mode or invalid combination of modes */ #define SIE_VI_WHY_ARCHM 0x0002 /* Invalid architecture mode specified (neither or both S/370 and ESA/390) */ #define SIE_VI_WHY_370NI 0x0003 /* S/370 interpretation requested but not installed */ #define SIE_VI_WHY_PRMCS 0x0004 /* Preferred and MCDS modes specified together */ #define SIE_VI_WHY_MCS37 0x0005 /* MCDS and S/370 modes specified together */ #define SIE_VI_WHY_RRFNI 0x0006 /* RRF requested but not installed */ #define SIE_VI_WHY_ISINI 0x0007 /* iSIE requested but not installed */ #define SIE_VI_WHY_PFOUT 0x0010 /* Guest prefix outside guest extent */ #define SIE_VI_WHY_SCHPF 0x0011 /* SCA origin nonzero and its frame address matches host prefix reg */ #define SIE_VI_WHY_SDOVL 0x0030 /* State description overlaps guest storage */ #define SIE_VI_WHY_SCOVL 0x0031 /* SCA overlaps guest storage */ #define SIE_VI_WHY_APOVL 0x0032 /* APCB overlaps guest storage */ #define SIE_VI_WHY_SCADR 0x0034 /* SCA at invalid host address */ #define SIE_VI_WHY_APADR 0x0035 /* APCB at invalid host address */ #define SIE_VI_WHY_PFACC 0x0037 /* Access exception on guest prefix area */ #define SIE_VI_WHY_SCZER 0x0038 /* SCA origin nonzero but under 4K (8K for ESAME host) */ #define SIE_VI_WHY_APZER 0x0039 /* APCB origin is zero when an APCB is needed */ #define SIE_VI_WHY_PSADR 0x003A /* PGSTE at invalid host address */ #define SIE_VI_WHY_SCBDY 0x003B /* SCA crosses 4KB boundary */ #define SIE_VI_WHY_APBDY 0x003C /* APCB crosses 4KB boundary */ #define SIE_VI_WHY_MSLEX 0x003D /* MSL exceeds maximum host address supported for guest storage (ESAME SIE only) */ #define SIE_VI_WHY_MSDEF 0x0041 /* MSO exceeds MSL (ESAME SIE only) */ #define SIE_VI_WHY_MSDF2 0x0042 /* Alternate for MSDEF detected during guest prefix access */ #define SIE_VI_WHY_RRHPF 0x0046 /* RRF guest extent (zone) includes host prefix area */ #define SIE_VI_WHY_PRHPF 0x0050 /* Preferred guest extent includes host prefix area */ #define SIE_VI_WHY_MSONZ 0x0051 /* MSO not zero for preferred guest */ #define SIE_VI_WHY_CDXNI 0x0070 /* Crypto Domain Index not installed */ #define SIE_VI_WHY_DRFNI 0x1001 /* DRF requested but not installed */ #define SIE_VI_WHY_PRALE 0x1002 /* Alerting enabled for preferred non-DRF guest */ #define SIE_VI_WHY_AZNNI 0x1005 /* Zone identified by AZN is not installed */ #define SIE_VI_WHY_AZNNZ 0x1006 /* Nonzero AZN for non-RRF/DRF guest (or level-1 DSC nonzero for pageable guest) */ /* The following occur only under ESA/390 SIE: */ #define SIE_VI_WHY_MSSTL 0x0043 /* Guest extent exceeds host STL */ #define SIE_VI_WHY_HOSTF 0x0060 /* Invalid host translation format (CR0.8-12) */ #define SIE_VI_WHY_MSOFL 0x0061 /* Pageable guest extent exceeds 2G-1 */ #define SIE_VI_WHY_RCOFL 0x0062 /* RCP area extends beyond 2G-1 in host virtual */ #define SIE_VI_WHY_RCSTL 0x0063 /* RCP area exceeds host STL */ #define SIE_VI_WHY_SCOFL 0x0064 /* SCA extends beyond 2G-1 */ #define SIE_VI_WHY_APOFL 0x0065 /* APCB extends beyond 2G-1 */ #define SIE_VI_WHY_RCZER 0x0067 /* RCP area origin is zero */ #define SIE_VI_WHY_PFSTL 0x0068 /* Guest prefix exceeds host STL */ #define SIE_VI_WHY_PTBDY 0x0069 /* PTO/PGST not on 2K boundary */ #define SIE_VI_WHY_MSODS 0x006A /* MSO nonzero for MCDS guest */ #define SIE_VI_WHY_SNOVL 0x1009 /* SNT overlaps guest storage */ #define SIE_VI_WHY_SNHPF 0x100C /* SNT overlaps host prefix area */ /* The following occur only in virtual machines under VM/ESA: */ #define SIE_VI_WHY_PFRDO 0xF000 /* Guest prefix maps to read-only storage (e.g. in a DCSS) */ #define SIE_VI_WHY_SCRDO 0xF001 /* SCA in read-only storage */ #define SIE_VI_WHY_OBMSB 0xF003 /* MSO/MSE not multiple of 1Meg... ..not supported in ESAME gen */ /* Zone Parameter Block */ typedef struct _ZPB1 { FWORD mso; /* Main Storage Origin bits 0-15 must be 0 */ FWORD msl; /* Main Storage Limit bits 0-15 must be 0 */ FWORD eso; /* Expanded Storage Origin bits 0-7 must be 0 */ FWORD esl; /* Expanded Storage Limit bits 0-7 must be 0 */ FWORD res[4]; /* Reserved bits - must be 0 */ } ZPB1; typedef struct _ZPB2 { DBLWRD mso; /* Main Storage Origin bits 0-19 must be 0 */ DBLWRD msl; /* Main Storage Limit bits 0-19 must be 0 */ #define ZPB2_MS_VALID 0x00000FFFFFFFFFFFULL DBLWRD eso; /* Expanded Storage Origin bits 0-7 must be 0 */ DBLWRD esl; /* Expanded Storage Limit bits 0-7 must be 0 */ #define ZPB2_ES_VALID 0x00FFFFFFFFFFFFFFULL } ZPB2; typedef struct _SCAENT { FWORD scn; FWORD resv1; DBLWRD sda; /* Address of SIEBK */ DBLWRD resv2[2]; } SCAENT; typedef struct _SCABLK { DBLWRD ipte_control; DBLWRD resv1[5]; DBLWRD mcn; /* Bitmap of VCPUs config */ DBLWRD resv2; SCAENT vcpu[64]; } SCABLK; #define LKPG_GPR0_LOCKBIT 0x00000200 #define LKPG_GPR0_RESV 0x0000FD00 #define STSI_GPR0_FC_MASK 0xF0000000 #define STSI_GPR0_FC_CURRNUM 0x00000000 #define STSI_GPR0_FC_BASIC 0x10000000 #define STSI_GPR0_FC_LPAR 0x20000000 #define STSI_GPR0_FC_VM 0x30000000 #define STSI_GPR0_FC_CURRINFO 0xF0000000 #define STSI_GPR0_SEL1_MASK 0x000000FF #define STSI_GPR0_RESERVED 0x0FFFFF00 #define STSI_GPR1_SEL2_MASK 0x0000FFFF #define STSI_GPR1_RESERVED 0xFFFF0000 typedef struct _SYSIB111 { /* Basic Machine Config */ BYTE flag1; /* 1.1.1 SYSIB Flag */ #define SYSIB111_PFLAG 0x80 /* Type percentage present */ BYTE resv1[3]; /* Reserved */ FWORD resv2[7]; /* Reserved */ BYTE manufact[16]; /* Manufacturer */ BYTE type[4]; /* Type */ FWORD resv3[3]; /* Reserved */ BYTE modcapaid[16]; /* Model capacity identifier */ BYTE seqc[16]; /* Sequence Code */ BYTE plant[4]; /* Plant of manufacture */ BYTE model[16]; /* System Model */ BYTE mpci[16]; /* Model Perm Capacity ID */ BYTE mtci[16]; /* Model Temp Capacity ID */ FWORD mcaprating; /* Model Capacity Rating */ FWORD mpcaprating; /* Model Perm Capacity Rating*/ FWORD mtcaprating; /* Model temp Capacity Rating*/ BYTE typepct[5]; /* Secondary CPU types pct */ } SYSIB111; typedef struct _SYSIB121 { /* Basic Machine CPU */ FWORD resv1[20]; /* Reserved */ BYTE seqc[16]; /* Sequence Code */ BYTE plant[4]; /* Plant of manufacture */ HWORD resv2; /* Reserved */ HWORD cpuad; /* CPU address */ } SYSIB121; typedef struct _SYSIB122 { /* Basic Machine CPUs */ BYTE format; /* Format 0 or 1 */ BYTE resv1; /* Reserved */ HWORD accoff; /* Offset to accap field */ FWORD resv2[6]; /* Reserved */ FWORD sccap; /* Secondary CPU Capability */ FWORD cap; /* CPU capability */ HWORD totcpu; /* Total CPU count */ HWORD confcpu; /* Configured CPU count */ HWORD sbcpu; /* Standby CPU count */ HWORD resvcpu; /* Reserved CPU count */ HWORD mpfact[MAX_CPU_ENGINES-1]; /* MP factors */ #if ((MAX_CPU_ENGINES-1) % 2) /* if prev is odd #of HWORDs */ HWORD resv3; /* then need some alignment */ #endif FWORD accap; /* Alternate CPU Capability */ HWORD ampfact[MAX_CPU_ENGINES-1]; /* Alternate MP factors */ #if ((MAX_CPU_ENGINES-1) % 2) /* if prev is odd #of HWORDs */ HWORD resv4; /* then need some alignment */ #endif } SYSIB122; typedef struct _SYSIB221 { /* Logical partition CPU */ FWORD resv1[20]; /* Reserved */ BYTE seqc[16]; /* Logical CPU Sequence Code */ BYTE plant[4]; /* Plant of manufacture */ HWORD lcpuid; /* Logical CPU ID */ HWORD cpuad; /* CPU address */ } SYSIB221; typedef struct _SYSIB222 { /* Logical partition CPUs */ FWORD resv1[8]; /* Reserved */ HWORD lparnum; /* LPAR number */ BYTE resv2; /* Reserved */ BYTE lcpuc; /* Logical CPU characteristic*/ #define SYSIB222_LCPUC_DEDICATED 0x80 #define SYSIB222_LCPUC_SHARED 0x40 #define SYSIB222_LCPUC_CAPPED 0x20 HWORD totcpu; /* Total CPU count */ HWORD confcpu; /* Configured CPU count */ HWORD sbcpu; /* Standby CPU count */ HWORD resvcpu; /* Reserved CPU count */ BYTE lparname[8]; /* LPAR name */ FWORD lparcaf; /* LPAR capability adjustment*/ FWORD mdep[2]; /* Model Dependent */ FWORD resv3[2]; /* Reserved */ HWORD dedcpu; /* Dedicated CPU count */ HWORD shrcpu; /* Shared CPU count */ } SYSIB222; typedef struct _SYSIB322 { /* Virtual Machines CPUs */ BYTE resv1[4*7]; /* Reserved */ BYTE resv2[3*1]; /* Reserved */ BYTE dbct; /* Four bit desc block count */ BYTE vmdb[4*16]; /* Virtual Machine desc block*/ } SYSIB322; typedef struct _SYSIB1512 { /* Configuration Topology */ HWORD resv1; /* Reserved */ HWORD len; /* Length */ BYTE mag[6]; /* Magnitudes 6, 5, ... 1 */ BYTE resv2; /* Reserved */ BYTE mnest; /* Nesting Level */ FWORD resv3; /* Reserved */ BYTE tles[FLEXIBLE_ARRAY]; /* Topology List Entries */ } SYSIB1512; typedef struct _TLECNTNR { /* Container TLE */ BYTE nl; /* Nesting Level */ BYTE resv1[3]; /* Reserved */ BYTE resv2; /* Reserved */ BYTE resv3[2]; /* Reserved */ BYTE cntnrid; /* Container Id */ } TLECNTNR; typedef struct _TLECPU { /* CPU TLE */ BYTE nl; /* Nesting Level */ BYTE resv1[3]; /* Reserved */ BYTE flags; /* Flags */ BYTE cputype; /* CPU Type */ U16 cpuadorg; /* CPU Address Origin */ DW cpumask; /* CPU Mask */ } TLECPU; /* Bit definitions for TLECPU flag byte */ #define CPUTLE_FLAG_DEDICATED 0x04 /* Dedicated CPU */ #define CPUTLE_FLAG_HORIZ 0x00 /* Horizontally polarized */ #define CPUTLE_FLAG_VERTLOW 0x01 /* Vertical low entitlement */ #define CPUTLE_FLAG_VERTMED 0x02 /* Vertical med entitlement */ #define CPUTLE_FLAG_VERTHIGH 0x03 /* Vertical high entitlement */ typedef struct _SYSIBVMDB { /* Virtual Machine Desc Block*/ BYTE resv1[4*1]; /* Reserved */ HWORD totcpu; /* Total CPU count */ HWORD confcpu; /* Configured CPU count */ HWORD sbcpu; /* Standby CPU count */ HWORD resvcpu; /* Reserved CPU count */ BYTE vmname[8]; /* VM userid */ FWORD vmcaf; /* VM capability adjustment */ BYTE cpid[4*4]; /* Control Program ID */ } SYSIBVMDB; #define PTFF_GPR0_RESV 0x00000080 #define PTFF_GPR0_FC_MASK 0x0000007F #define PTFF_GPR0_FC_QAF 0x00 #define PTFF_GPR0_FC_QTO 0x01 #define PTFF_GPR0_FC_QSI 0x02 #define PTFF_GPR0_FC_QPT 0x03 #define PTFF_GPR0_FC_ATO 0x40 #define PTFF_GPR0_FC_STO 0x41 #define PTFF_GPR0_FC_SFS 0x42 #define PTFF_GPR0_FC_SGS 0x43 typedef struct _PTFFQAF { /* Query Available Functions */ FWORD sb[4]; /* Status Bits words */ } PTFFQAF; typedef struct _PTFFQTO { /* Query TOD Offset */ DBLWRD physclk; /* Physical Clock */ DBLWRD todoff; /* TOD Offset */ DBLWRD ltodoff; /* Logical TOD Offset */ DBLWRD todepoch; /* TOD Epoch Difference */ } PTFFQTO; typedef struct _PTFFQSI { /* Query Steering Information*/ DBLWRD physclk; /* Physical Clock */ DBLWRD oldestart; /* Old Episode Start Time */ DBLWRD oldebase; /* Old Episode Base Offset */ FWORD oldfsr; /* Old Episode Fine St. Rate */ FWORD oldgsr; /* Old Episode Gross St. Rate*/ DBLWRD newestart; /* New Episode Start Time */ DBLWRD newebase; /* New Episode Base Offset */ FWORD newfsr; /* New Episode Fine St. Rate */ FWORD newgsr; /* New Episode Gross St. Rate*/ } PTFFQSI; #define SIGA_FC_W 0 /* Initiate Output */ #define SIGA_FC_R 1 /* Initiate Input */ #define SIGA_FC_S 2 /* Synchronize */ #define SIGA_FC_MAX SIGA_FC_S /* Bit definitions for floating-point-control register */ #define FPC_MASK 0xFC000000 /*810*/ #define FPC_MASK_IMI 0x80000000 #define FPC_MASK_IMZ 0x40000000 #define FPC_MASK_IMO 0x20000000 #define FPC_MASK_IMU 0x10000000 #define FPC_MASK_IMX 0x08000000 #define FPC_MASK_IMQ 0x04000000 /*810*/ #define FPC_FLAG 0x00FC0000 /*810*/ #define FPC_FLAG_SFI 0x00800000 #define FPC_FLAG_SFZ 0x00400000 #define FPC_FLAG_SFO 0x00200000 #define FPC_FLAG_SFU 0x00100000 #define FPC_FLAG_SFX 0x00080000 #define FPC_FLAG_SFQ 0x00040000 /*810*/ #define FPC_DXC 0x0000FF00 #define FPC_DXC_I 0x00008000 #define FPC_DXC_Z 0x00004000 #define FPC_DXC_O 0x00002000 #define FPC_DXC_U 0x00001000 #define FPC_DXC_X 0x00000800 #define FPC_DXC_Y 0x00000400 #define FPC_DRM 0x00000070 #define FPC_BRM_3BIT 0x00000007 /*810*/ #define FPC_BIT29 0x00000004 /*810*/ #define FPC_BRM_2BIT 0x00000003 /*810*/ #define FPC_RESV_FPX 0x03030088 /*810*/ #define FPC_RESERVED 0x0707008C /* Shift counts to allow alignment of each field in the FPC register */ #define FPC_MASK_SHIFT 24 /*810*/ #define FPC_FLAG_SHIFT 16 /*810*/ #define FPC_DXC_SHIFT 8 #define FPC_DRM_SHIFT 4 #define FPC_BRM_SHIFT 0 /* Data exception codes */ #define DXC_DECIMAL 0x00 /* Decimal operand exception */ #define DXC_AFP_REGISTER 0x01 /* AFP register exception */ #define DXC_BFP_INSTRUCTION 0x02 /* BFP instruction exception */ #define DXC_DFP_INSTRUCTION 0x03 /* DFP instruction exception */ #define DXC_QUANTUM 0x04 /* Quantum exception 810*/ #define DXC_QUANTUM_IISE 0x07 /* Quantum simulated 810*/ #define DXC_IEEE_INEXACT_TRUNC 0x08 /* IEEE inexact, truncated */ #define DXC_IEEE_INEXACT_IISE 0x0B /* IEEE inexact (IISE) DFP*/ #define DXC_IEEE_INEXACT_INCR 0x0C /* IEEE inexact, incremented */ #define DXC_IEEE_UF_EXACT 0x10 /* IEEE underflow. exact */ #define DXC_IEEE_UF_EXACT_IISE 0x13 /* IEEE u/flow,exact(IISE)DFP*/ #define DXC_IEEE_UF_INEX_TRUNC 0x18 /* IEEE u/flow,inexact,trunc */ #define DXC_IEEE_UF_INEX_IISE 0x1B /* IEEE u/flow,inex(IISE) DFP*/ #define DXC_IEEE_UF_INEX_INCR 0x1C /* IEEE u/flow,inexact,incr */ #define DXC_IEEE_OF_EXACT 0x20 /* IEEE overflow. exact */ #define DXC_IEEE_OF_EXACT_IISE 0x23 /* IEEE o/flow,exact(IISE)DFP*/ #define DXC_IEEE_OF_INEX_TRUNC 0x28 /* IEEE o/flow,inexact,trunc */ #define DXC_IEEE_OF_INEX_IISE 0x2B /* IEEE o/flow,inex(IISE) DFP*/ #define DXC_IEEE_OF_INEX_INCR 0x2C /* IEEE o/flow,inexact,incr */ #define DXC_IEEE_DIV_ZERO 0x40 /* IEEE division by zero */ #define DXC_IEEE_DIV_ZERO_IISE 0x43 /* IEEE div by zero(IISE) DFP*/ #define DXC_IEEE_INVALID_OP 0x80 /* IEEE invalid operation */ #define DXC_IEEE_INV_OP_IISE 0x83 /* IEEE invalid op (IISE) DFP*/ #define DXC_COMPARE_AND_TRAP 0xFF /* Compare-and-trap exception*/ /* Note: IISE = IEEE-interruption-simulation event */ /* Decimal rounding modes */ #define DRM_RNE 0 /* Round to nearest tie even */ #define DRM_RTZ 1 /* Round toward zero */ #define DRM_RTPI 2 /* Round toward +infinity */ #define DRM_RTMI 3 /* Round toward -infinity */ #define DRM_RNAZ 4 /* Round nearest tie away 0 */ #define DRM_RNTZ 5 /* Round nearest tie toward 0*/ #define DRM_RAFZ 6 /* Round away from zero */ #define DRM_RFSP 7 /* Prepare shorter precision */ /* Binary rounding modes */ #define BRM_RNE 0 /* Round to nearest tie even */ #define BRM_RTZ 1 /* Round toward zero */ #define BRM_RTPI 2 /* Round toward +infinity */ #define BRM_RTMI 3 /* Round toward -infinity */ #define BRM_RESV4 4 /* Reserved (invalid) 810*/ #define BRM_RESV5 5 /* Reserved (invalid) 810*/ #define BRM_RESV6 6 /* Reserved (invalid) 810*/ #define BRM_RFSP 7 /* Prep shorter precision 810*/ /* Mask bits for conditional SSKE facility */ #define SSKE_MASK_NQ 0x08 /* NonQuiesce */ #define SSKE_MASK_MR 0x04 /* Reference bit update mask */ #define SSKE_MASK_MC 0x02 /* Change bit update mask */ #define SSKE_MASK_MB 0x01 /* Multiple Block */ /* Measurement alert external interruption parameter */ #define MAEIP_IEA 0x80000000 /* Invalid Entry Address */ #define MAEIP_ISDBTE 0x80000000 /* Incorrect sample-data-block- table entry */ #define MAEIP_PRA 0x20000000 /* Program request alert */ #define MAEIP_SACA 0x00800000 /* Sampling authorisation change alert */ #define MAEIP_LSDA 0x00400000 /* Loss of sample data alert */ #define MAEIP_CACA 0x00000080 /* Counter Authorisation change alert */ #define MAEIP_LCDA 0x00000040 /* Loss of counter data alert */ #endif // _ESA390_H hercules-3.12/opcode.h0000664000175000017500000046072412564723224011642 00000000000000/* OPCODE.H (c) Copyright Jan Jaeger, 2000-2009 */ /* Instruction decoding macros and prototypes */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #ifndef _OPCODE_H #define _OPCODE_H #include "hercules.h" #ifndef _CPU_C_ #ifndef _HENGINE_DLL_ #define CPU_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define CPU_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else /* _CPU_C_ */ #define CPU_DLL_IMPORT DLL_EXPORT #endif /* _CPU_C_ */ #ifndef _OPCODE_C_ #ifndef _HENGINE_DLL_ #define OPC_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define OPC_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else /* _OPCODE_C_ */ #define OPC_DLL_IMPORT DLL_EXPORT #endif /* _OPCODE_C_ */ #if defined(_370) #define _GEN370(_name) &s370_ ## _name, #else #define _GEN370(_name) #endif #if defined(_390) #define _GEN390(_name) &s390_ ## _name, #else #define _GEN390(_name) #endif #if defined(_900) #define _GEN900(_name) &z900_ ## _name, #else #define _GEN900(_name) #endif #define GENx___x___x___ \ { \ _GEN370(operation_exception) \ _GEN390(operation_exception) \ _GEN900(operation_exception) \ (void*)&disasm_none, \ (void*)&"?????" "\0" "?" \ } #define GENx370x___x___(_name,_format,_mnemonic) \ { \ _GEN370(_name) \ _GEN390(operation_exception) \ _GEN900(operation_exception) \ (void*)&disasm_ ## _format, \ (void*)& _mnemonic "\0" #_name \ } #define GENx___x390x___(_name,_format,_mnemonic) \ { \ _GEN370(operation_exception) \ _GEN390(_name) \ _GEN900(operation_exception) \ (void*)&disasm_ ## _format, \ (void*)& _mnemonic "\0" #_name \ } #define GENx370x390x___(_name,_format,_mnemonic) \ { \ _GEN370(_name) \ _GEN390(_name) \ _GEN900(operation_exception) \ (void*)&disasm_ ## _format, \ (void*)& _mnemonic "\0" #_name \ } #define GENx___x___x900(_name,_format,_mnemonic) \ { \ _GEN370(operation_exception) \ _GEN390(operation_exception) \ _GEN900(_name) \ (void*)&disasm_ ## _format, \ (void*)& _mnemonic "\0" #_name \ } #define GENx370x___x900(_name,_format,_mnemonic) \ { \ _GEN370(_name) \ _GEN390(operation_exception) \ _GEN900(_name) \ (void*)&disasm_ ## _format, \ (void*)& _mnemonic "\0" #_name \ } #define GENx___x390x900(_name,_format,_mnemonic) \ { \ _GEN370(operation_exception) \ _GEN390(_name) \ _GEN900(_name) \ (void*)&disasm_ ## _format, \ (void*)& _mnemonic "\0" #_name \ } #define GENx370x390x900(_name,_format,_mnemonic) \ { \ _GEN370(_name) \ _GEN390(_name) \ _GEN900(_name) \ (void*)&disasm_ ## _format, \ (void*)& _mnemonic "\0" #_name \ } /* The following variants of the opcode table definition macros specify 37X (370 EXTENSIONS) instead of 370 to indicate that they are ESA/390 and ESAME instructions back-ported to S/370 */ #define GENx37Xx390x___ GENx370x390x___ #define GENx37Xx___x900 GENx370x___x900 #define GENx37Xx390x900 GENx370x390x900 typedef void (ATTR_REGPARM(2) *zz_func) (BYTE inst[], REGS *regs); #define ILC(_b) ((_b) < 0x40 ? 2 : (_b) < 0xc0 ? 4 : 6) #define REAL_ILC(_regs) \ (likely(!(_regs)->execflag) ? (_regs)->psw.ilc : (_regs)->exrl ? 6 : 4) /* Gabor Hoffer (performance option) */ OPC_DLL_IMPORT zz_func s370_opcode_table[]; OPC_DLL_IMPORT zz_func s390_opcode_table[]; OPC_DLL_IMPORT zz_func z900_opcode_table[]; OPC_DLL_IMPORT zz_func opcode_table[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_01xx[][GEN_MAXARCH]; extern zz_func v_opcode_a4xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_a5xx[][GEN_MAXARCH]; extern zz_func v_opcode_a5xx[][GEN_MAXARCH]; extern zz_func v_opcode_a6xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_a7xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_b2xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_b3xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_b9xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_c0xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_c2xx[][GEN_MAXARCH]; /*@Z9*/ OPC_DLL_IMPORT zz_func opcode_c4xx[][GEN_MAXARCH]; /*208*/ OPC_DLL_IMPORT zz_func opcode_c6xx[][GEN_MAXARCH]; /*208*/ OPC_DLL_IMPORT zz_func opcode_c8xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_ccxx[][GEN_MAXARCH]; /*810*/ OPC_DLL_IMPORT zz_func opcode_e3xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_e4xx[256][GEN_MAXARCH]; extern zz_func v_opcode_e4xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_e5xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_e6xx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_ebxx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_ecxx[][GEN_MAXARCH]; OPC_DLL_IMPORT zz_func opcode_edxx[][GEN_MAXARCH]; #define DISASM_INSTRUCTION(_inst, p) \ disasm_table((_inst), 0, p) typedef int (*func) (); extern int disasm_table (BYTE inst[], char mnemonic[], char *p); #if defined(OPTION_INSTRUCTION_COUNTING) #define COUNT_INST(_inst, _regs) \ do { \ int used; \ switch((_inst)[0]) { \ case 0x01: \ used = sysblk.imap01[(_inst)[1]]++; \ break; \ case 0xA4: \ used = sysblk.imapa4[(_inst)[1]]++; \ break; \ case 0xA5: \ used = sysblk.imapa5[(_inst)[1] & 0x0F]++; \ break; \ case 0xA6: \ used = sysblk.imapa6[(_inst)[1]]++; \ break; \ case 0xA7: \ used = sysblk.imapa7[(_inst)[1] & 0x0F]++; \ break; \ case 0xB2: \ used = sysblk.imapb2[(_inst)[1]]++; \ break; \ case 0xB3: \ used = sysblk.imapb3[(_inst)[1]]++; \ break; \ case 0xB9: \ used = sysblk.imapb9[(_inst)[1]]++; \ break; \ case 0xC0: \ used = sysblk.imapc0[(_inst)[1] & 0x0F]++; \ break; \ case 0xC2: /*@Z9*/ \ used = sysblk.imapc2[(_inst)[1] & 0x0F]++; /*@Z9*/ \ break; /*@Z9*/ \ case 0xC4: /*208*/ \ used = sysblk.imapc4[(_inst)[1] & 0x0F]++; /*208*/ \ break; /*208*/ \ case 0xC6: /*208*/ \ used = sysblk.imapc6[(_inst)[1] & 0x0F]++; /*208*/ \ break; /*208*/ \ case 0xC8: \ used = sysblk.imapc8[(_inst)[1] & 0x0F]++; \ break; \ case 0xE3: \ used = sysblk.imape3[(_inst)[5]]++; \ break; \ case 0xE4: \ used = sysblk.imape4[(_inst)[1]]++; \ break; \ case 0xE5: \ used = sysblk.imape5[(_inst)[1]]++; \ break; \ case 0xEB: \ used = sysblk.imapeb[(_inst)[5]]++; \ break; \ case 0xEC: \ used = sysblk.imapec[(_inst)[5]]++; \ break; \ case 0xED: \ used = sysblk.imaped[(_inst)[5]]++; \ break; \ default: \ used = sysblk.imapxx[(_inst)[0]]++; \ } \ if(!used) \ { \ obtain_lock( &sysblk.icount_lock ); \ logmsg("First use: "); \ ARCH_DEP(display_inst) ((_regs), (_inst)); \ release_lock( &sysblk.icount_lock ); \ } \ } while(0) #else #define COUNT_INST(_inst, _regs) #endif #if defined(_FEATURE_SIE) #define SIE_MODE(_register_context) \ unlikely((_register_context)->sie_mode) #define SIE_STATE(_register_context) \ ((_register_context)->sie_state) #define SIE_FEATB(_regs, _feat_byte, _feat_name) \ (((_regs)->siebk->SIE_ ## _feat_byte) & (SIE_ ## _feat_byte ## _ ## _feat_name)) #define SIE_STATB(_regs, _feat_byte, _feat_name) \ (SIE_MODE((_regs)) && SIE_FEATB((_regs), _feat_byte, _feat_name) ) #define SIE_STATNB(_regs, _feat_byte, _feat_name) \ (SIE_MODE((_regs)) && !SIE_FEATB((_regs), _feat_byte, _feat_name) ) #else #define SIE_MODE(_register_context) (0) #define SIE_STATE(_register_context) (0) #define SIE_FEATB(_register_context, _feat_byte, _feat_name) (0) #define SIE_STATB(_register_context, _feat_byte, _feat_name) (0) #endif /* The footprint_buffer option saves a copy of the register context every time an instruction is executed. This is for problem determination only, as it severely impacts performance. *JJ */ #if defined(OPTION_FOOTPRINT_BUFFER) #define FOOTPRINT(_ip, _regs) \ do { \ sysblk.footprregs[(_regs)->cpuad][sysblk.footprptr[(_regs)->cpuad]] = *(_regs); \ memcpy(&sysblk.footprregs[(_regs)->cpuad][sysblk.footprptr[(_regs)->cpuad]++].inst,(_ip),6); \ sysblk.footprptr[(_regs)->cpuad] &= OPTION_FOOTPRINT_BUFFER - 1; \ } while(0) #endif #if !defined(FOOTPRINT) #define FOOTPRINT(_ip, _regs) #endif /* PSW Instruction Address manipulation */ #define _PSW_IA(_regs, _n) \ (VADR)((_regs)->AIV + ((intptr_t)(_regs)->ip - (intptr_t)(_regs)->aip) + (_n)) #define PSW_IA(_regs, _n) \ (_PSW_IA((_regs), (_n)) & ADDRESS_MAXWRAP((_regs))) #define SET_PSW_IA(_regs) \ do { \ if ((_regs)->aie) (_regs)->psw.IA = PSW_IA((_regs), 0); \ } while (0) #define UPD_PSW_IA(_regs, _addr) \ do { \ (_regs)->psw.IA = (_addr) & ADDRESS_MAXWRAP(_regs); \ if (likely((_regs)->aie != NULL)) { \ if (likely((_regs)->AIV == ((_regs)->psw.IA & (PAGEFRAME_PAGEMASK|1)))) \ (_regs)->ip = _PSW_IA_MAIN((_regs), (_regs)->psw.IA); \ else \ (_regs)->aie = NULL; \ } \ } while (0) /* * The next three macros are used by branch-and-link type instructions * where the addressing mode is known. * Note that wrap is not performed for PSW_IA64 and for PSW_IA31. * For the latter, we expect branch-and-link code to `or' the hi bit * on so there is no need to `and' it off. */ #define PSW_IA64(_regs, _n) \ ((_regs)->AIV \ + (((uintptr_t)(_regs)->ip + (unsigned int)(_n)) - (uintptr_t)(_regs)->aip)) #define PSW_IA31(_regs, _n) \ ((_regs)->AIV_L + ((uintptr_t)(_regs)->ip + (unsigned int)(_n)) \ - (uintptr_t)(_regs)->aip) #define PSW_IA24(_regs, _n) \ (((_regs)->AIV_L + ((uintptr_t)(_regs)->ip + (unsigned int)(_n)) \ - (uintptr_t)(_regs)->aip) & AMASK24) /* Accelerator for instruction addresses */ #define INVALIDATE_AIA(_regs) \ do { \ if ((_regs)->aie) { \ (_regs)->psw.IA = PSW_IA((_regs), 0); \ (_regs)->aie = NULL; \ } \ } while (0) #define INVALIDATE_AIA_MAIN(_regs, _main) \ do { \ if ((_main) == (_regs)->aip && (_regs)->aie) { \ (_regs)->psw.IA = PSW_IA((_regs), 0); \ (_regs)->aie = NULL; \ } \ } while (0) #if 1 #define _PSW_IA_MAIN(_regs, _addr) \ ((BYTE *)((uintptr_t)(_regs)->aip | (uintptr_t)((_addr) & PAGEFRAME_BYTEMASK))) #else #define _PSW_IA_MAIN(_regs, _addr) \ ((BYTE *)((_regs)->aim ^ (uintptr_t)(_addr))) #endif #define _VALID_IP(_regs, _exec) \ ( \ ( !(_exec) && (_regs)->ip < (_regs)->aie ) \ || \ ( (_exec) && ((_regs)->ET & (PAGEFRAME_PAGEMASK|0x01)) == (_regs)->AIV \ && _PSW_IA_MAIN((_regs), (_regs)->ET) < (_regs)->aie \ ) \ ) /* Instruction fetching */ #define INSTRUCTION_FETCH(_regs, _exec) \ likely(_VALID_IP((_regs),(_exec))) \ ? ((_exec) ? _PSW_IA_MAIN((_regs), (_regs)->ET) : (_regs)->ip) \ : ARCH_DEP(instfetch) ((_regs), (_exec)) /* Instruction execution */ #define EXECUTE_INSTRUCTION(_ip, _regs) \ do { \ FOOTPRINT ((_ip), (_regs)); \ COUNT_INST ((_ip), (_regs)); \ (_regs)->ARCH_DEP(opcode_table)[_ip[0]]((_ip), (_regs)); \ } while(0) #define UNROLLED_EXECUTE(_regs) \ if ((_regs)->ip >= (_regs)->aie) break; \ EXECUTE_INSTRUCTION((_regs)->ip, (_regs)) /* Branching */ #define SUCCESSFUL_BRANCH(_regs, _addr, _len) \ do { \ VADR _newia; \ UPDATE_BEAR((_regs), 0); \ _newia = (_addr) & ADDRESS_MAXWRAP((_regs)); \ if (likely(!(_regs)->permode && !(_regs)->execflag) \ && likely((_newia & (PAGEFRAME_PAGEMASK|0x01)) == (_regs)->AIV)) { \ (_regs)->ip = (BYTE *)((uintptr_t)(_regs)->aim ^ (uintptr_t)_newia); \ return; \ } else { \ if (unlikely((_regs)->execflag)) \ UPDATE_BEAR((_regs), (_len) - ((_regs)->exrl ? 6 : 4)); \ (_regs)->psw.IA = _newia; \ (_regs)->aie = NULL; \ PER_SB((_regs), (_regs)->psw.IA); \ } \ } while (0) #define SUCCESSFUL_RELATIVE_BRANCH(_regs, _offset, _len) \ do { \ UPDATE_BEAR((_regs), 0); \ if (likely(!(_regs)->permode && !(_regs)->execflag) \ && likely((_regs)->ip + (_offset) >= (_regs)->aip) \ && likely((_regs)->ip + (_offset) < (_regs)->aie)) { \ (_regs)->ip += (_offset); \ return; \ } else { \ if (likely(!(_regs)->execflag)) \ (_regs)->psw.IA = PSW_IA((_regs), (_offset)); \ else { \ UPDATE_BEAR((_regs), (_len) - ((_regs)->exrl ? 6 : 4)); \ (_regs)->psw.IA = (_regs)->ET + (_offset); \ (_regs)->psw.IA &= ADDRESS_MAXWRAP((_regs)); \ } \ (_regs)->aie = NULL; \ PER_SB((_regs), (_regs)->psw.IA); \ } \ } while (0) /* BRCL, BRASL can branch +/- 4G. This is problematic on a 32 bit host */ #define SUCCESSFUL_RELATIVE_BRANCH_LONG(_regs, _offset) \ do { \ UPDATE_BEAR((_regs), 0); \ if (likely(!(_regs)->permode && !(_regs)->execflag) \ && likely((_offset) > -4096) \ && likely((_offset) < 4096) \ && likely((_regs)->ip + (_offset) >= (_regs)->aip) \ && likely((_regs)->ip + (_offset) < (_regs)->aie)) { \ (_regs)->ip += (_offset); \ return; \ } else { \ if (likely(!(_regs)->execflag)) \ (_regs)->psw.IA = PSW_IA((_regs), (_offset)); \ else { \ UPDATE_BEAR((_regs), 6 - ((_regs)->exrl ? 6 : 4)); \ (_regs)->psw.IA = (_regs)->ET + (_offset); \ (_regs)->psw.IA &= ADDRESS_MAXWRAP((_regs)); \ } \ (_regs)->aie = NULL; \ PER_SB((_regs), (_regs)->psw.IA); \ } \ } while (0) /* CPU Stepping or Tracing */ #define CPU_STEPPING(_regs, _ilc) \ ( \ sysblk.inststep \ && ( \ (sysblk.stepaddr[0] == 0 && sysblk.stepaddr[1] == 0) \ || (sysblk.stepaddr[0] <= sysblk.stepaddr[1] \ && PSW_IA((_regs), -(_ilc)) >= sysblk.stepaddr[0] \ && PSW_IA((_regs), -(_ilc)) <= sysblk.stepaddr[1] \ ) \ || (sysblk.stepaddr[0] > sysblk.stepaddr[1] \ && PSW_IA((_regs), -(_ilc)) >= sysblk.stepaddr[1] \ && PSW_IA((_regs), -(_ilc)) <= sysblk.stepaddr[0] \ ) \ ) \ ) #define CPU_TRACING(_regs, _ilc) \ ( \ sysblk.insttrace \ && ( \ (sysblk.traceaddr[0] == 0 && sysblk.traceaddr[1] == 0) \ || (sysblk.traceaddr[0] <= sysblk.traceaddr[1] \ && PSW_IA((_regs), -(_ilc)) >= sysblk.traceaddr[0] \ && PSW_IA((_regs), -(_ilc)) <= sysblk.traceaddr[1] \ ) \ || (sysblk.traceaddr[0] > sysblk.traceaddr[1] \ && PSW_IA((_regs), -(_ilc)) >= sysblk.traceaddr[1] \ && PSW_IA((_regs), -(_ilc)) <= sysblk.traceaddr[0] \ ) \ ) \ ) #define CPU_STEPPING_OR_TRACING(_regs, _ilc) \ ( unlikely((_regs)->tracing) && \ (CPU_STEPPING((_regs), (_ilc)) || CPU_TRACING((_regs), (_ilc))) \ ) #define CPU_TRACING_ALL \ (sysblk.insttrace && sysblk.traceaddr[0] == 0 && sysblk.traceaddr[1] == 0) #define CPU_STEPPING_ALL \ (sysblk.inststep && sysblk.stepaddr[0] == 0 && sysblk.stepaddr[1] == 0) #define CPU_STEPPING_OR_TRACING_ALL \ ( CPU_TRACING_ALL || CPU_STEPPING_ALL ) #define RETURN_INTCHECK(_regs) \ longjmp((_regs)->progjmp, SIE_NO_INTERCEPT) #define ODD_CHECK(_r, _regs) \ if( (_r) & 1 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #define ODD2_CHECK(_r1, _r2, _regs) \ if( ((_r1) & 1) || ((_r2) & 1) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #define HW_CHECK(_value, _regs) \ if( (_value) & 1 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #define FW_CHECK(_value, _regs) \ if( (_value) & 3 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #define DW_CHECK(_value, _regs) \ if( (_value) & 7 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #define QW_CHECK(_value, _regs) \ if( (_value) & 15 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if m is not 0, 1, or 4 to 7 */ #define HFPM_CHECK(_m, _regs) \ if (((_m) == 2) || ((_m) == 3) || ((_m) & 8)) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #define PRIV_CHECK(_regs) \ if( PROBSTATE(&(_regs)->psw) ) \ (_regs)->program_interrupt( (_regs), PGM_PRIVILEGED_OPERATION_EXCEPTION) /* Program check if r is not 0,1,4,5,8,9,12, or 13 (designating the lower-numbered register of a floating-point register pair) */ #define BFPREGPAIR_CHECK(_r, _regs) \ if( ((_r) & 2) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if r1 and r2 are not both 0,1,4,5,8,9,12, or 13 (lower-numbered register of a floating-point register pair) */ #define BFPREGPAIR2_CHECK(_r1, _r2, _regs) \ if( ((_r1) & 2) || ((_r2) & 2) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if r is not 0,1,4,5,8,9,12, or 13 (designating the lower-numbered register of a floating-point register pair) */ #define DFPREGPAIR_CHECK(_r, _regs) \ if( ((_r) & 2) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if r1 and r2 are not both 0,1,4,5,8,9,12, or 13 (lower-numbered register of a floating-point register pair) */ #define DFPREGPAIR2_CHECK(_r1, _r2, _regs) \ if( ((_r1) & 2) || ((_r2) & 2) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if r1, r2, r3 are not all 0,1,4,5,8,9,12, or 13 (lower-numbered register of a floating-point register pair) */ #define DFPREGPAIR3_CHECK(_r1, _r2, _r3, _regs) \ if( ((_r1) & 2) || ((_r2) & 2) || ((_r3) & 2) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if fpc is not valid contents for FPC register */ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ #define FPC_BRM FPC_BRM_3BIT #define FPC_CHECK(_fpc, _regs) \ if(((_fpc) & FPC_RESV_FPX) \ || ((_fpc) & FPC_BRM_3BIT) == BRM_RESV4 \ || ((_fpc) & FPC_BRM_3BIT) == BRM_RESV5 \ || ((_fpc) & FPC_BRM_3BIT) == BRM_RESV6) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #else /*!defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ #define FPC_BRM FPC_BRM_2BIT #define FPC_CHECK(_fpc, _regs) \ if((_fpc) & FPC_RESERVED) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) #endif /*!defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ #define SSID_CHECK(_regs) \ if((!((_regs)->GR_LHH(1) & 0x0001)) \ || (_regs)->GR_LHH(1) > (0x0001|((FEATURE_LCSS_MAX-1) << 1))) \ (_regs)->program_interrupt( (_regs), PGM_OPERAND_EXCEPTION) #define IOID_TO_SSID(_ioid) \ ((_ioid) >> 16) #define IOID_TO_LCSS(_ioid) \ ((_ioid) >> 17) #define SSID_TO_LCSS(_ssid) \ ((_ssid) >> 1) #define LCSS_TO_SSID(_lcss) \ (((_lcss) << 1) | 1) #define PER_RANGE_CHECK(_addr, _low, _high) \ ( (((_high) & MAXADDRESS) >= ((_low) & MAXADDRESS)) ? \ (((_addr) >= ((_low) & MAXADDRESS)) && (_addr) <= ((_high) & MAXADDRESS)) : \ (((_addr) >= ((_low) & MAXADDRESS)) || (_addr) <= ((_high) & MAXADDRESS)) ) #define PER_RANGE_CHECK2(_addr1, _addr2, _low, _high) \ ( (((_high) & MAXADDRESS) >= ((_low) & MAXADDRESS)) ? \ (((_addr1) >= ((_low) & MAXADDRESS)) && (_addr1) <= ((_high) & MAXADDRESS)) || \ (((_addr2) >= ((_low) & MAXADDRESS)) && (_addr2) <= ((_high) & MAXADDRESS)) || \ (((_addr1) <= ((_low) & MAXADDRESS)) && (_addr2) >= ((_high) & MAXADDRESS)) : \ (((_addr2) >= ((_low) & MAXADDRESS)) || (_addr1) <= ((_high) & MAXADDRESS)) ) #ifdef WORDS_BIGENDIAN #define CSWAP16(_x) (_x) #define CSWAP32(_x) (_x) #define CSWAP64(_x) (_x) #else #define CSWAP16(_x) bswap_16(_x) #define CSWAP32(_x) bswap_32(_x) #define CSWAP64(_x) bswap_64(_x) #endif #define FETCH_HW(_value, _storage) (_value) = fetch_hw(_storage) #define FETCH_FW(_value, _storage) (_value) = fetch_fw(_storage) #define FETCH_DW(_value, _storage) (_value) = fetch_dw(_storage) #define STORE_HW(_storage, _value) store_hw(_storage, _value) #define STORE_FW(_storage, _value) store_fw(_storage, _value) #define STORE_DW(_storage, _value) store_dw(_storage, _value) #include "machdep.h" #endif /*!defined(_OPCODE_H)*/ #undef SIE_ACTIVE #if defined(FEATURE_INTERPRETIVE_EXECUTION) #define SIE_ACTIVE(_regs) ((_regs)->sie_active) #else #define SIE_ACTIVE(_regs) (0) #endif #undef MULTIPLE_CONTROLLED_DATA_SPACE #if defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) #define MULTIPLE_CONTROLLED_DATA_SPACE(_regs) \ ( SIE_FEATB((_regs), MX, XC) && AR_BIT(&(_regs)->psw) ) #else #define MULTIPLE_CONTROLLED_DATA_SPACE(_regs) (0) #endif /* PER3 Breaking Event Address Recording (BEAR) */ #undef UPDATE_BEAR #undef SET_BEAR_REG #if defined(FEATURE_PER3) #define UPDATE_BEAR(_regs, _n) (_regs)->bear_ip = (_regs)->ip + (_n) #define SET_BEAR_REG(_regs, _ip) \ do { \ if ((_ip)) { \ (_regs)->bear = (_regs)->AIV \ + (intptr_t)((_ip) - (_regs)->aip); \ (_regs)->bear &= ADDRESS_MAXWRAP((_regs)); \ regs->bear_ip = NULL; \ } \ } while (0) #else #define UPDATE_BEAR(_regs, _n) while (0) #define SET_BEAR_REG(_regs, _ip) while (0) #endif /* Set addressing mode (BASSM, BSM) */ #undef SET_ADDRESSING_MODE #if defined(FEATURE_ESAME) #define SET_ADDRESSING_MODE(_regs, _addr) \ do { \ if ((_addr) & 1) { \ (_regs)->psw.amode64 = regs->psw.amode = 1; \ (_regs)->psw.AMASK = AMASK64; \ (_addr) ^= 1; \ } else if ((_addr) & 0x80000000) { \ (_regs)->psw.amode64 = 0; \ (_regs)->psw.amode = 1; \ (_regs)->psw.AMASK = AMASK31; \ } else { \ (_regs)->psw.amode64 = (_regs)->psw.amode = 0; \ (_regs)->psw.AMASK = AMASK24; \ } \ } while (0) #else /* !defined(FEATURE_ESAME) */ #define SET_ADDRESSING_MODE(_regs, _addr) \ do { \ if ((_addr) & 0x80000000) { \ (_regs)->psw.amode = 1; \ (_regs)->psw.AMASK = AMASK31; \ } else { \ (_regs)->psw.amode = 0; \ (_regs)->psw.AMASK = AMASK24; \ } \ } while (0) #endif #undef HFPREG_CHECK #undef HFPREG2_CHECK #undef HFPODD_CHECK #undef HFPODD2_CHECK #undef FPR2I #undef FPREX #if defined(FEATURE_BASIC_FP_EXTENSIONS) #if defined(_FEATURE_SIE) /* Program check if BFP instruction is executed when AFP control is zero */ #define BFPINST_CHECK(_regs) \ if( !((_regs)->CR(0) & CR0_AFP) \ || (SIE_MODE((_regs)) && !((_regs)->hostregs->CR(0) & CR0_AFP)) ) { \ (_regs)->dxc = DXC_BFP_INSTRUCTION; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } /* Program check if DFP instruction is executed when AFP control is zero */ #define DFPINST_CHECK(_regs) \ if( !((_regs)->CR(0) & CR0_AFP) \ || (SIE_MODE((_regs)) && !((_regs)->hostregs->CR(0) & CR0_AFP)) ) { \ (_regs)->dxc = DXC_DFP_INSTRUCTION; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } /* Program check if r1 is not 0, 2, 4, or 6 */ #define HFPREG_CHECK(_r, _regs) \ if( !((_regs)->CR(0) & CR0_AFP) \ || (SIE_MODE((_regs)) && !((_regs)->hostregs->CR(0) & CR0_AFP)) ) { \ if( (_r) & 9 ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } /* Program check if r1 and r2 are not 0, 2, 4, or 6 */ #define HFPREG2_CHECK(_r1, _r2, _regs) \ if( !((_regs)->CR(0) & CR0_AFP) \ || (SIE_MODE((_regs)) && !((_regs)->hostregs->CR(0) & CR0_AFP)) ) { \ if( ((_r1) & 9) || ((_r2) & 9) ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } /* Program check if r1 is not 0 or 4 */ #define HFPODD_CHECK(_r, _regs) \ if( (_r) & 2 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION); \ else if( !((_regs)->CR(0) & CR0_AFP) \ || (SIE_MODE((_regs)) && !((_regs)->hostregs->CR(0) & CR0_AFP)) ) { \ if( (_r) & 9 ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } /* Program check if r1 and r2 are not 0 or 4 */ #define HFPODD2_CHECK(_r1, _r2, _regs) \ if( ((_r1) & 2) || ((_r2) & 2) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION); \ else if( !((_regs)->CR(0) & CR0_AFP) \ || (SIE_MODE((_regs)) && !((_regs)->hostregs->CR(0) & CR0_AFP)) ) { \ if( ((_r1) & 9) || ((_r2) & 9) ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } #else /*!defined(_FEATURE_SIE)*/ /* Program check if BFP instruction is executed when AFP control is zero */ #define BFPINST_CHECK(_regs) \ if( !((_regs)->CR(0) & CR0_AFP) ) { \ (_regs)->dxc = DXC_BFP_INSTRUCTION; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } /* Program check if DFP instruction is executed when AFP control is zero */ #define DFPINST_CHECK(_regs) \ if( !((_regs)->CR(0) & CR0_AFP) ) { \ (_regs)->dxc = DXC_DFP_INSTRUCTION; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } /* Program check if r1 is not 0, 2, 4, or 6 */ #define HFPREG_CHECK(_r, _regs) \ if( !((_regs)->CR(0) & CR0_AFP) ) { \ if( (_r) & 9 ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } /* Program check if r1 and r2 are not 0, 2, 4, or 6 */ #define HFPREG2_CHECK(_r1, _r2, _regs) \ if( !((_regs)->CR(0) & CR0_AFP) ) { \ if( ((_r1) & 9) || ((_r2) & 9) ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } /* Program check if r1 is not 0 or 4 */ #define HFPODD_CHECK(_r, _regs) \ if( (_r) & 2 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION); \ else if( !((_regs)->CR(0) & CR0_AFP) ) { \ if( (_r) & 9 ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } /* Program check if r1 and r2 are not 0 or 4 */ #define HFPODD2_CHECK(_r1, _r2, _regs) \ if( ((_r1) & 2) || ((_r2) & 2) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION); \ else if( !((_regs)->CR(0) & CR0_AFP) ) { \ if( ((_r1) & 9) || ((_r2) & 9) ) { \ (_regs)->dxc = DXC_AFP_REGISTER; \ (_regs)->program_interrupt( (_regs), PGM_DATA_EXCEPTION); \ } \ } #endif /*!defined(_FEATURE_SIE)*/ /* Convert fpr to index */ #define FPR2I(_r) \ ((_r) << 1) /* Offset of extended register */ #define FPREX 4 #else /*!defined(FEATURE_BASIC_FP_EXTENSIONS)*/ /* Program check if r1 is not 0, 2, 4, or 6 */ #define HFPREG_CHECK(_r, _regs) \ if( (_r) & 9 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if r1 and r2 are not 0, 2, 4, or 6 */ #define HFPREG2_CHECK(_r1, _r2, _regs) \ if( ((_r1) & 9) || ((_r2) & 9) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if r1 is not 0 or 4 */ #define HFPODD_CHECK(_r, _regs) \ if( (_r) & 11 ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Program check if r1 and r2 are not 0 or 4 */ #define HFPODD2_CHECK(_r1, _r2, _regs) \ if( ((_r1) & 11) || ((_r2) & 11) ) \ (_regs)->program_interrupt( (_regs), PGM_SPECIFICATION_EXCEPTION) /* Convert fpr to index */ #define FPR2I(_r) \ (_r) /* Offset of extended register */ #define FPREX 2 #endif /*!defined(FEATURE_BASIC_FP_EXTENSIONS)*/ #define TLBIX(_addr) (((VADR_L)(_addr) >> TLB_PAGESHIFT) & TLB_MASK) #define MAINADDR(_main, _addr) \ (BYTE*)((uintptr_t)(_main) ^ (uintptr_t)(_addr)) #define NEW_MAINADDR(_regs, _addr, _aaddr) \ (BYTE*)((uintptr_t)((_regs)->mainstor \ + (uintptr_t)(_aaddr)) \ ^ (uintptr_t)((_addr) & TLB_PAGEMASK)) /* Perform invalidation after storage key update. * If the REF or CHANGE bit is turned off for an absolute * address then we need to invalidate any cached entries * for that address on *all* CPUs. * FIXME: Synchronization, esp for the CHANGE bit, should * be tighter than what is provided here. */ #define STORKEY_INVALIDATE(_regs, _n) \ do { \ BYTE *mn; \ mn = (_regs)->mainstor + ((_n) & PAGEFRAME_PAGEMASK); \ ARCH_DEP(invalidate_tlbe)((_regs), mn); \ if (sysblk.cpus > 1) { \ int i; \ OBTAIN_INTLOCK ((_regs)); \ for (i = 0; i < HI_CPU; i++) { \ if (IS_CPU_ONLINE(i) && i != (_regs)->cpuad) { \ if ( sysblk.waiting_mask & CPU_BIT(i) ) \ ARCH_DEP(invalidate_tlbe)(sysblk.regs[i], mn); \ else { \ ON_IC_INTERRUPT(sysblk.regs[i]); \ if (!sysblk.regs[i]->invalidate) { \ sysblk.regs[i]->invalidate = 1; \ sysblk.regs[i]->invalidate_main = mn; \ } else \ sysblk.regs[i]->invalidate_main = NULL; \ } \ } \ } \ RELEASE_INTLOCK((_regs)); \ } \ } while (0) #if defined(INLINE_STORE_FETCH_ADDR_CHECK) #define FETCH_MAIN_ABSOLUTE(_addr, _regs, _len) \ ARCH_DEP(fetch_main_absolute)((_addr), (_regs), (_len)) #else #define FETCH_MAIN_ABSOLUTE(_addr, _regs, _len) \ ARCH_DEP(fetch_main_absolute)((_addr), (_regs)) #endif #define INST_UPDATE_PSW(_regs, _len, _ilc) \ do { \ if (_len) (_regs)->ip += (_len); \ if (_ilc) (_regs)->psw.ilc = (_ilc); \ } while(0) /* Instruction decoders */ /* * A decoder is placed at the start of each instruction. The purpose * of a decoder is to extract the operand fields according to the * instruction format; to increment the instruction address (IA) field * of the PSW by 2, 4, or 6 bytes; and to set the instruction length * code (ILC) field of the PSW in case a program check occurs. * * Certain decoders have additional forms with 0 and _B suffixes. * - the 0 suffix version does not update the PSW ILC. * - the _B suffix version updates neither the PSW ILC nor the PSW IA. * * The "0" versions of the decoders are chosen whenever we know * that past this point, no program interrupt will be generated * (like most general instructions when no storage access is needed) * therefore needing simpler prologue code. * The "_B" versions for some of the decoders are intended for * "branch" type operations where updating the PSW IA to IA+ILC * should only be done after the branch is deemed impossible. */ #undef DECODER_TEST_RRE #define DECODER_TEST_RRF_R #define DECODER_TEST_RRF_M #define DECODER_TEST_RRF_M4 #define DECODER_TEST_RRF_RM #define DECODER_TEST_RRF_MM #define DECODER_TEST_RRR #undef DECODER_TEST_RX #define DECODER_TEST_RXE #define DECODER_TEST_RXF #define DECODER_TEST_RXY #undef DECODER_TEST_RS #define DECODER_TEST_RSY #undef DECODER_TEST_RSL #undef DECODER_TEST_RSI #undef DECODER_TEST_RI #define DECODER_TEST_RIL #define DECODER_TEST_RIL_A #undef DECODER_TEST_RIS #undef DECODER_TEST_RRS #undef DECODER_TEST_SI #define DECODER_TEST_SIY #undef DECODER_TEST_SIL #undef DECODER_TEST_S #define DECODER_TEST_SS #define DECODER_TEST_SS_L #define DECODER_TEST_SSE #define DECODER_TEST_SSF /* E implied operands and extended op code */ #undef E #define E(_inst,_regs) E_DECODER((_inst), (_regs), 2, 2) #define E_DECODER(_inst, _regs, _len, _ilc) \ { \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ UNREFERENCED(_inst); \ } /* IE extended op code with two 4-bit immediate fields */ /*912*/ #undef IE #undef IE0 #define IE(_inst, _regs, _i1, _i2) \ IE_DECODER(_inst, _regs, _i1, _i2, 4, 4) #define IE0(_inst, _regs, _i1, _i2) \ IE_DECODER(_inst, _regs, _i1, _i2, 4, 0) #define IE_DECODER(_inst, _regs, _i1, _i2, _len, _ilc) \ { \ int i = (_inst)[3]; \ (_i1) = i >> 4; \ (_i2) = i & 0x0F; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* MII mask with 12-bit and 24-bit relative address fields */ /*912*/ #undef MII_A #undef MII_A0 #define MII_A(_inst, _regs, _m1, _addr2, _addr3) \ MII_A_DECODER(_inst, _regs, _m1, _addr2, _addr3, 6, 6) #define MII_A0(_inst, _regs, _m1, _addr2, _addr3) \ MII_A_DECODER(_inst, _regs, _m1, _addr2, _addr3, 6, 0) #define MII_A_DECODER(_inst, _regs, _m1, _addr2, _addr3, _len, _ilc) \ { \ U32 ri2, ri3; S64 offset; \ U32 temp = fetch_fw(&(_inst)[2]); \ int i = (_inst)[1]; \ (_m1) = (i >> 4) & 0x0F; \ ri2 = (i << 4) | (temp >> 24); \ ri3 = temp & 0xFFFFFF; \ offset = 2LL*(S32)ri2; \ (_addr2) = (likely(!(_regs)->execflag)) ? \ PSW_IA((_regs), offset) : \ ((_regs)->ET + offset) & ADDRESS_MAXWRAP((_regs)); \ offset = 2LL*(S32)ri3; \ (_addr3) = (likely(!(_regs)->execflag)) ? \ PSW_IA((_regs), offset) : \ ((_regs)->ET + offset) & ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RR register to register */ #undef RR #undef RR0 #undef RR_B #define RR(_inst, _regs, _r1, _r2) \ RR_DECODER(_inst, _regs, _r1, _r2, 2, 2) #define RR0(_inst, _regs, _r1, _r2) \ RR_DECODER(_inst, _regs, _r1, _r2, 2, 0) #define RR_B(_inst, _regs, _r1, _r2) \ RR_DECODER(_inst, _regs, _r1, _r2, 0, 0) #define RR_DECODER(_inst, _regs, _r1, _r2, _len, _ilc) \ { \ int i = (_inst)[1]; \ (_r1) = i >> 4; \ (_r2) = i & 0x0F; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RR special format for SVC instruction */ #undef RR_SVC #define RR_SVC(_inst, _regs, _svc) \ RR_SVC_DECODER(_inst, _regs, _svc, 2, 2) #define RR_SVC_DECODER(_inst, _regs, _svc, _ilc, _len) \ { \ (_svc) = (_inst)[1]; \ INST_UPDATE_PSW((_regs), (_ilc), (_len)); \ } /* RRE register to register with extended op code */ #undef RRE #undef RRE0 #undef RRE_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRE) #define RRE(_inst, _regs, _r1, _r2) \ RRE_DECODER(_inst, _regs, _r1, _r2, 4, 4) #define RRE0(_inst, _regs, _r1, _r2) \ RRE_DECODER(_inst, _regs, _r1, _r2, 4, 0) #define RRE_B(_inst, _regs, _r1, _r2) \ RRE_DECODER(_inst, _regs, _r1, _r2, 0, 0) #else #define RRE(_inst, _regs, _r1, _r2) \ RRE_DECODER_TEST(_inst, _regs, _r1, _r2, 4, 4) #define RRE0(_inst, _regs, _r1, _r2) \ RRE_DECODER_TEST(_inst, _regs, _r1, _r2, 4, 0) #define RRE_B(_inst, _regs, _r1, _r2) \ RRE_DECODER_TEST(_inst, _regs, _r1, _r2, 0, 0) #endif #define RRE_DECODER(_inst, _regs, _r1, _r2, _len, _ilc) \ { \ int i = (_inst)[3]; \ (_r1) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRE_DECODER_TEST(_inst, _regs, _r1, _r2, _len, _ilc) \ { \ int i = (_inst)[3]; \ (_r2) = i & 0xf; \ (_r1) = i >> 4; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRF register to register with additional R3 field */ #undef RRF_R #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRF_R) #define RRF_R(_inst, _regs, _r1, _r2, _r3) \ RRF_R_DECODER(_inst, _regs, _r1, _r2, _r3, 4, 4) #else #define RRF_R(_inst, _regs, _r1, _r2, _r3) \ RRF_R_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, 4, 4) #endif #define RRF_R_DECODER(_inst, _regs, _r1, _r2, _r3, _len, _ilc) \ { \ int i = (_inst)[2]; \ (_r1) = i >> 4; \ i = (_inst)[3]; \ (_r3) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRF_R_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r2) = (temp ) & 0xf; \ (_r3) = (temp >> 4) & 0xf; \ (_r1) = (temp >> 12) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRF register to register with additional M3 field */ #undef RRF_M #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRF_M) #define RRF_M(_inst, _regs, _r1, _r2, _m3) \ RRF_M_DECODER(_inst, _regs, _r1, _r2, _m3, 4, 4) #else #define RRF_M(_inst, _regs, _r1, _r2, _m3) \ RRF_M_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, 4, 4) #endif #define RRF_M_DECODER(_inst, _regs, _r1, _r2, _m3, _len, _ilc) \ { \ int i = (_inst)[2]; \ (_m3) = i >> 4; \ i = (_inst)[3]; \ (_r1) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRF_M_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_m3) = (temp >> 12) & 0xf; \ (_r2) = (temp ) & 0xf; \ (_r1) = (temp >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRF register to register with additional M4 field */ #undef RRF_M4 #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRF_M4) #define RRF_M4(_inst, _regs, _r1, _r2, _m4) \ RRF_M4_DECODER(_inst, _regs, _r1, _r2, _m4, 4, 4) #else #define RRF_M4(_inst, _regs, _r1, _r2, _m4) \ RRF_M4_DECODER_TEST(_inst, _regs, _r1, _r2, _m4, 4, 4) #endif #define RRF_M4_DECODER(_inst, _regs, _r1, _r2, _m4, _len, _ilc) \ { \ int i = (_inst)[2]; \ (_m4) = i & 0xf; \ i = (_inst)[3]; \ (_r1) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRF_M4_DECODER_TEST(_inst, _regs, _r1, _r2, _m4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_m4) = (temp >> 8) & 0xf; \ (_r2) = (temp ) & 0xf; \ (_r1) = (temp >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRF register to register with additional R3 and M4 fields */ #undef RRF_RM #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRF_RM) #define RRF_RM(_inst, _regs, _r1, _r2, _r3, _m4) \ RRF_RM_DECODER(_inst, _regs, _r1, _r2, _r3, _m4, 4, 4) #else #define RRF_RM(_inst, _regs, _r1, _r2, _r3, _m4) \ RRF_RM_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, _m4, 4, 4) #endif #define RRF_RM_DECODER(_inst, _regs, _r1, _r2, _r3, _m4, _len, _ilc) \ { \ int i = (_inst)[2]; \ (_r3) = i >> 4; \ (_m4) = i & 0xf; \ i = (_inst)[3]; \ (_r1) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRF_RM_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, _m4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r3) = (temp >> 12) & 0xf; \ (_m4) = (temp >> 8) & 0xf; \ (_r2) = (temp ) & 0xf; \ (_r1) = (temp >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRF register to register with additional M3 and M4 fields */ #undef RRF_MM #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRF_MM) #define RRF_MM(_inst, _regs, _r1, _r2, _m3, _m4) \ RRF_MM_DECODER(_inst, _regs, _r1, _r2, _m3, _m4, 4, 4) #else #define RRF_MM(_inst, _regs, _r1, _r2, _m3, _m4) \ RRF_MM_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, _m4, 4, 4) #endif #define RRF_MM_DECODER(_inst, _regs, _r1, _r2, _m3, _m4, _len, _ilc) \ { \ int i = (_inst)[2]; \ (_m3) = i >> 4; \ (_m4) = i & 0xf; \ i = (_inst)[3]; \ (_r1) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRF_MM_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, _m4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_m3) = (temp >> 12) & 0xf; \ (_m4) = (temp >> 8) & 0xf; \ (_r2) = (temp ) & 0xf; \ (_r1) = (temp >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRE_MMA instructions are RRE format instructions which are treated as RRF_MM when the floating-point extension facility is installed */ #undef RRE_MMA #if defined(FLOATING_POINT_EXTENSION_FACILITY) #define RRE_MMA(_inst, _regs, _r1, _r2, _m3, _m4) \ RRF_MM(_inst, _regs, _r1, _r2, _m3, _m4) #else #define RRE_MMA(_inst, _regs, _r1, _r2, _m3, _m4) \ { RRE(_inst, _regs, _r1, _r2); m3 = m4 = 0; } #endif /* RRF_MMA instructions are RRF_M format instructions which are treated as RRF_MM when the floating-point extension facility is installed */ #undef RRF_MMA #if defined(FLOATING_POINT_EXTENSION_FACILITY) #define RRF_MMA(_inst, _regs, _r1, _r2, _m3, _m4) \ RRF_MM(_inst, _regs, _r1, _r2, _m3, _m4) #else #define RRF_MMA(_inst, _regs, _r1, _r2, _m3, _m4) \ { RRF_M(_inst, _regs, _r1, _r2, _m3); m4 = 0; } #endif /* RRR register to register with register */ #undef RRR #undef RRR0 #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRR) #define RRR(_inst, _regs, _r1, _r2, _r3) \ RRR_DECODER(_inst, _regs, _r1, _r2, _r3, 4, 4) #define RRR0(_inst, _regs, _r1, _r2, _r3) \ RRR_DECODER(_inst, _regs, _r1, _r2, _r3, 4, 0) #else #define RRR(_inst, _regs, _r1, _r2, _r3) \ RRR_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, 4, 4) #define RRR0(_inst, _regs, _r1, _r2, _r3) \ RRR_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, 4, 0) #endif #define RRR_DECODER(_inst, _regs, _r1, _r2, _r3, _len, _ilc) \ { \ int i = (_inst)[2]; \ (_r3) = i >> 4; \ i = (_inst)[3]; \ (_r1) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRR_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r3) = (temp >> 12) & 0xf; \ (_r2) = (temp ) & 0xf; \ (_r1) = (temp >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRR_M register to register with register with additional M4 field */ #undef RRR_M #undef RRR_M0 #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRR_M) #define RRR_M(_inst, _regs, _r1, _r2, _r3, _m4) \ RRR_M_DECODER(_inst, _regs, _r1, _r2, _r3, _m4, 4, 4) #define RRR_M0(_inst, _regs, _r1, _r2, _r3, _m4) \ RRR_M_DECODER(_inst, _regs, _r1, _r2, _r3, _m4, 4, 0) #else #define RRR_M(_inst, _regs, _r1, _r2, _r3, _m4) \ RRR_M_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, _m4, 4, 4) #define RRR_M0(_inst, _regs, _r1, _r2, _r3, _m4) \ RRR_M_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, _m4, 4, 0) #endif #define RRR_M_DECODER(_inst, _regs, _r1, _r2, _r3, _m4, _len, _ilc) \ { \ int i = (_inst)[2]; \ (_r3) = i >> 4; \ (_m4) = i & 0xf; \ i = (_inst)[3]; \ (_r1) = i >> 4; \ (_r2) = i & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRR_M_DECODER_TEST(_inst, _regs, _r1, _r2, _r3, _m4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_m4) = (temp >> 8) & 0xf; \ (_r3) = (temp >> 12) & 0xf; \ (_r2) = (temp ) & 0xf; \ (_r1) = (temp >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRR_MA instructions are RRR format instructions which are treated as RRR_M when the floating-point extension facility is installed */ #undef RRR_MA #if defined(FLOATING_POINT_EXTENSION_FACILITY) #define RRR_MA(_inst, _regs, _r1, _r2, _r3, _m4) \ RRR_M(_inst, _regs, _r1, _r2, _r3, _m4) #else #define RRR_MA(_inst, _regs, _r1, _r2, _r3, _m4) \ { RRR(_inst, _regs, _r1, _r2, _r3); m4 = 0; } #endif /* RX register and indexed storage */ #undef RX #undef RX0 #undef RX_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RX) #define RX(_inst, _regs, _r1, _b2, _effective_addr2) \ RX_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, 4, 4) #define RX0(_inst, _regs, _r1, _b2, _effective_addr2) \ RX_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, 4, 0) #define RX_B(_inst, _regs, _r1, _b2, _effective_addr2) \ RX_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, 0, 0) #else #define RX(_inst, _regs, _r1, _b2, _effective_addr2) \ RX_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 4, 4) #define RX0(_inst, _regs, _r1, _b2, _effective_addr2) \ RX_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 4, 0) #define RX_B(_inst, _regs, _r1, _b2, _effective_addr2) \ RX_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 0, 0) #endif #define RX_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_b2) = (temp >> 16) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RX_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 16) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RX_BC register and indexed storage - optimized for BC */ #undef RX_BC #define RX_BC(_inst, _regs, _b2, _effective_addr2) \ RX_BC_DECODER(_inst, _regs, _b2, _effective_addr2, 0, 0) #define RX_BC_DECODER(_inst, _regs, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 16) & 0xf; \ if(unlikely((_b2))) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_b2) = (temp >> 12) & 0xf; \ if(likely((_b2))) \ (_effective_addr2) += (_regs)->GR((_b2)); \ } /* RXE register and indexed storage with extended op code */ #undef RXE #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RXE) #define RXE(_inst, _regs, _r1, _b2, _effective_addr2) \ RXE_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, 6, 6) #else #define RXE(_inst, _regs, _r1, _b2, _effective_addr2) \ RXE_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 6, 6) #endif #define RXE_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_b2) = (temp >> 16) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RXE_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 16) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RXF register and indexed storage with ext.opcode and additional R3 */ #undef RXF #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RXF) #define RXF(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RXF_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 6) #else #define RXF(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RXF_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 6) #endif #define RXF_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp; \ (_r1) = (_inst)[4] >> 4; \ memcpy (&temp, (_inst), 4); \ temp = CSWAP32(temp); \ (_r3) = (temp >> 20) & 0xf; \ (_b2) = (temp >> 16) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RXF_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 16) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ (_r3) = (temp >> 20) & 0xf; \ (_r1) = (_inst)[4] >> 4; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RXY register and indexed storage with extended op code and long displacement */ #undef RXY #undef RXY0 #undef RXY_B #if defined(FEATURE_LONG_DISPLACEMENT) #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RXY) #define RXY(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_LD(_inst, _regs, _r1, _b2, _effective_addr2, 6, 6) #define RXY0(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_LD(_inst, _regs, _r1, _b2, _effective_addr2, 6, 0) #define RXY_B(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_LD(_inst, _regs, _r1, _b2, _effective_addr2, 0, 0) #else #define RXY(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_LD_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 6, 6) #define RXY0(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_LD_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 6, 0) #define RXY_B(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_LD_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 0, 0) #endif #else /* !defined(FEATURE_LONG_DISPLACEMENT) */ #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RXY) #define RXY(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, 6, 6) #define RXY0(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, 6, 0) #define RXY_B(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, 0, 0) #else #define RXY(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 6, 6) #define RXY0(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 6, 0) #define RXY_B(_inst, _regs, _r1, _b2, _effective_addr2) \ RXY_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, 0, 0) #endif #endif #define RXY_DECODER_LD(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp; S32 temp2; int tempx; \ temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ tempx = (temp >> 16) & 0xf; \ (_b2) = (temp >> 12) & 0xf; \ temp2 = (_inst[4] << 12) | (temp & 0xfff); \ if (temp2 & 0x80000) temp2 |= 0xfff00000; \ (_effective_addr2) = \ (tempx ? (_regs)->GR(tempx) : (GREG)0) + \ ((_b2) ? (_regs)->GR((_b2)) : (GREG)0) + \ temp2; \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RXY_DECODER_LD_TEST(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp; S32 disp2; \ temp = fetch_fw(_inst); \ (_effective_addr2) = 0; \ (_b2) = (temp >> 16) & 0xf; \ if ((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_b2) = (temp >> 12) & 0xf; \ if ((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ disp2 = temp & 0xfff; \ if (unlikely((_inst)[4])) { \ disp2 |= (_inst[4] << 12); \ if (disp2 & 0x80000) disp2 |= 0xfff00000; \ } \ (_effective_addr2) += disp2; \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RXY_DECODER(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_b2) = (temp >> 16) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RXY_DECODER_TEST(_inst, _regs, _r1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 16) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RS register and storage with additional R3 or M3 field */ #undef RS #undef RS0 #undef RS_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RS) #define RS(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RS_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 4, 4) #define RS0(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RS_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 4, 0) #define RS_B(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RS_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 0, 0) #else #define RS(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RS_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 4, 4) #define RS0(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RS_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 4, 0) #define RS_B(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RS_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 0, 0) #endif #define RS_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_r3) = (temp >> 16) & 0xf; \ (_b2) = (temp >> 12) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RS_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_r3) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #if 0 /* RSE register and storage with extended op code and additional R3 or M3 field (note, this is NOT the ESA/390 vector RSE format) */ /* Note: Effective June 2003, RSE is retired and replaced by RSY */ #undef RSE #define RSE(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ { U32 temp; \ memcpy (&temp, (_inst), 4); \ temp = CSWAP32(temp); \ (_r1) = (temp >> 20) & 0xf; \ (_r3) = (temp >> 16) & 0xf; \ (_b2) = (temp >> 12) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), 6, 6); \ } #endif /* RSY register and storage with extended op code, long displacement, and additional R3 or M3 field */ #undef RSY #undef RSY0 #undef RSY_B #if defined(FEATURE_LONG_DISPLACEMENT) #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RSY) #define RSY(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_LD(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 6) #define RSY0(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_LD(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 0) #define RSY_B(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_LD(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 0, 0) #else #define RSY(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_LD_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 6) #define RSY0(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_LD_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 0) #define RSY_B(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_LD_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 0, 0) #endif #else #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RSY) #define RSY(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 6) #define RSY0(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 0) #define RSY_B(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 0, 0) #else #define RSY(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 6) #define RSY0(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 6, 0) #define RSY_B(_inst, _regs, _r1, _r3, _b2, _effective_addr2) \ RSY_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, 0, 0) #endif #endif #define RSY_DECODER_LD(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp; S32 temp2; \ temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_r3) = (temp >> 16) & 0xf; \ (_b2) = (temp >> 12) & 0xf; \ temp2 = (_inst[4] << 12) | (temp & 0xfff); \ if (temp2 & 0x80000) temp2 |= 0xfff00000; \ (_effective_addr2) = \ ((_b2) ? (_regs)->GR((_b2)) : (GREG)0) + \ temp2; \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RSY_DECODER_LD_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp; S32 disp2; \ temp = fetch_fw(_inst); \ (_effective_addr2) = 0; \ (_b2) = (temp >> 12) & 0xf; \ if ((_b2)) \ _effective_addr2 += (_regs)->GR((_b2)); \ disp2 = temp & 0xfff; \ if (unlikely((_inst)[4])) { \ disp2 |= (_inst[4] << 12); \ if (disp2 & 0x80000) disp2 |= 0xfff00000; \ } \ (_effective_addr2) += disp2; \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ (_r3) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RSY_DECODER(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_r3) = (temp >> 16) & 0xf; \ (_b2) = (temp >> 12) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RSY_DECODER_TEST(_inst, _regs, _r1, _r3, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 12) & 0xf; \ if((_b2)) \ (_effective_addr2) += (_regs)->GR((_b2)); \ if ((_len)) \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ (_r3) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RSL storage operand with extended op code and 4-bit L field */ #undef RSL #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RSL) #define RSL(_inst, _regs, _l1, _b1, _effective_addr1) \ RSL_DECODER(_inst, _regs, _l1, _b1, _effective_addr1, 6, 6) #else #define RSL(_inst, _regs, _l1, _b1, _effective_addr1) \ RSL_DECODER_TEST(_inst, _regs, _l1, _b1, _effective_addr1, 6, 6) #endif #define RSL_DECODER(_inst, _regs, _l1, _b1, _effective_addr1, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_l1) = (temp >> 20) & 0xf; \ (_b1) = (temp >> 12) & 0xf; \ (_effective_addr1) = temp & 0xfff; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RSL_DECODER_TEST(_inst, _regs, _l1, _b1, _effective_addr1, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr1) = temp & 0xfff; \ (_b1) = (temp >> 12) & 0xf; \ if((_b1)) { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_l1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RSL register and storage with extended op code, 8-bit L field, and mask */ #undef RSL_RM #define RSL_RM(_inst, _regs, _r1, _l2, _b2, _effective_addr2, _m3) \ RSL_RM_DECODER(_inst, _regs, _r1, _l2, _b2, _effective_addr2, _m3, 6, 6) #define RSL_RM_DECODER(_inst, _regs, _r1, _l2, _b2, _effective_addr2, _m3, _len, _ilc) \ { U32 temp = fetch_fw(&(_inst)[1]); \ (_m3) = temp & 0xf; \ (_r1) = (temp >> 4) & 0xf; \ (_effective_addr2) = (temp >> 8) & 0xfff; \ (_b2) = (temp >> 20) & 0xf; \ (_l2) = (temp >> 24) & 0xff; \ if((_b2)) { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RSI register and immediate with additional R3 field */ #undef RSI #undef RSI0 #undef RSI_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RSI) #define RSI(_inst, _regs, _r1, _r3, _i2) \ RSI_DECODER(_inst, _regs, _r1, _r3, _i2, 4, 4) #define RSI0(_inst, _regs, _r1, _r3, _i2) \ RSI_DECODER(_inst, _regs, _r1, _r3, _i2, 4, 0) #define RSI_B(_inst, _regs, _r1, _r3, _i2) \ RSI_DECODER(_inst, _regs, _r1, _r3, _i2, 0, 0) #else #define RSI(_inst, _regs, _r1, _r3, _i2) \ RSI_DECODER_TEST(_inst, _regs, _r1, _r3, _i2, 4, 4) #define RSI0(_inst, _regs, _r1, _r3, _i2) \ RSI_DECODER_TEST(_inst, _regs, _r1, _r3, _i2, 4, 0) #define RSI_B(_inst, _regs, _r1, _r3, _i2) \ RSI_DECODER_TEST(_inst, _regs, _r1, _r3, _i2, 0, 0) #endif #define RSI_DECODER(_inst, _regs, _r1, _r3, _i2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_r3) = (temp >> 16) & 0xf; \ (_i2) = temp & 0xffff; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RSI_DECODER_TEST(_inst, _regs, _r1, _r3, _i2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_i2) = temp & 0xffff; \ (_r3) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RI register and immediate with extended 4-bit op code */ #undef RI #undef RI0 #undef RI_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RI) #define RI(_inst, _regs, _r1, _i2) \ RI_DECODER(_inst, _regs, _r1, _i2, 4, 4) #define RI0(_inst, _regs, _r1, _i2) \ RI_DECODER(_inst, _regs, _r1, _i2, 4, 0) #define RI_B(_inst, _regs, _r1, _i2) \ RI_DECODER(_inst, _regs, _r1, _i2, 0, 0) #else #define RI(_inst, _regs, _r1, _i2) \ RI_DECODER_TEST(_inst, _regs, _r1, _i2, 4, 4) #define RI0(_inst, _regs, _r1, _i2) \ RI_DECODER_TEST(_inst, _regs, _r1, _i2, 4, 0) #define RI_B(_inst, _regs, _r1, _i2) \ RI_DECODER_TEST(_inst, _regs, _r1, _i2, 0, 0) #endif #define RI_DECODER(_inst, _regs, _r1, _i2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_i2) = temp & 0xffff; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RI_DECODER_TEST(_inst, _regs, _r1, _i2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_i2) = temp & 0xffff; \ (_r1) = (temp >> 20) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIE register and immediate with ext.opcode and additional R3 */ #undef RIE #undef RIE0 #undef RIE_B #define RIE(_inst, _regs, _r1, _r3, _i2) \ RIE_DECODER(_inst, _regs, _r1, _r3, _i2, 6, 6) #define RIE0(_inst, _regs, _r1, _r3, _i2) \ RIE_DECODER(_inst, _regs, _r1, _r3, _i2, 6, 0) #define RIE_B(_inst, _regs, _r1, _r3, _i2) \ RIE_DECODER(_inst, _regs, _r1, _r3, _i2, 0, 0) #define RIE_DECODER(_inst, _regs, _r1, _r3, _i2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_r3) = (temp >> 16) & 0xf; \ (_i2) = temp & 0xffff; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIE register and immediate with mask */ /*208*/ #undef RIE_RIM #define RIE_RIM(_inst, _regs, _r1, _i2, _m3) \ RIE_RIM_DECODER(_inst, _regs, _r1, _i2, _m3, 6, 6) #define RIE_RIM_DECODER(_inst, _regs, _r1, _i2, _m3, _len, _ilc) \ { U32 temp = fetch_fw(&(_inst)[1]); \ (_m3) = (temp >> 4) & 0xf; \ (_i2) = (temp >> 8) & 0xffff; \ (_r1) = (temp >> 28) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIE register to register with immediate and mask */ /*208*/ #undef RIE_RRIM #undef RIE_RRIM0 #undef RIE_RRIM_B #define RIE_RRIM(_inst, _regs, _r1, _r2, _i4, _m3) \ RIE_RRIM_DECODER(_inst, _regs, _r1, _r2, _i4, _m3, 6, 6) #define RIE_RRIM0(_inst, _regs, _r1, _r2, _i4, _m3) \ RIE_RRIM_DECODER(_inst, _regs, _r1, _r2, _i4, _m3, 6, 0) #define RIE_RRIM_B(_inst, _regs, _r1, _r2, _i4, _m3) \ RIE_RRIM_DECODER(_inst, _regs, _r1, _r2, _i4, _m3, 0, 0) #define RIE_RRIM_DECODER(_inst, _regs, _r1, _r2, _i4, _m3, _len, _ilc) \ { U32 temp = fetch_fw(&(_inst)[1]); \ (_m3) = (temp >> 4) & 0xf; \ (_i4) = (temp >> 8) & 0xffff; \ (_r2) = (temp >> 24) & 0xf; \ (_r1) = (temp >> 28) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIE register and mask with longer immediate and immediate */ /*208*/ #undef RIE_RMII #undef RIE_RMII0 #undef RIE_RMII_B #define RIE_RMII(_inst, _regs, _r1, _i2, _m3, _i4) \ RIE_RMII_DECODER(_inst, _regs, _r1, _i2, _m3, _i4, 6, 6) #define RIE_RMII0(_inst, _regs, _r1, _i2, _m3, _i4) \ RIE_RMII_DECODER(_inst, _regs, _r1, _i2, _m3, _i4, 6, 0) #define RIE_RMII_B(_inst, _regs, _r1, _i2, _m3, _i4) \ RIE_RMII_DECODER(_inst, _regs, _r1, _i2, _m3, _i4, 0, 0) #define RIE_RMII_DECODER(_inst, _regs, _r1, _i2, _m3, _i4, _len, _ilc) \ { U32 temp = fetch_fw(&(_inst)[1]); \ (_i2) = temp & 0xff; \ (_i4) = (temp >> 8) & 0xffff; \ (_m3) = (temp >> 24) & 0xf; \ (_r1) = (temp >> 28) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIE register to register with three immediate fields */ /*208*/ #undef RIE_RRIII #define RIE_RRIII(_inst, _regs, _r1, _r2, _i3, _i4, _i5) \ RIE_RRIII_DECODER(_inst, _regs, _r1, _r2, _i3, _i4, _i5, 6, 6) #define RIE_RRIII_DECODER(_inst, _regs, _r1, _r2, _i3, _i4, _i5, _len, _ilc) \ { U32 temp = fetch_fw(&(_inst)[1]); \ (_i5) = temp & 0xff; \ (_i4) = (temp >> 8) & 0xff; \ (_i3) = (temp >> 16) & 0xff; \ (_r2) = (temp >> 24) & 0xf; \ (_r1) = (temp >> 28) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIL register and longer immediate with extended 4 bit op code */ #undef RIL #undef RIL0 #undef RIL_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RIL) #define RIL(_inst, _regs, _r1, _op, _i2) \ RIL_DECODER(_inst, _regs, _r1, _op, _i2, 6, 6) #define RIL0(_inst, _regs, _r1, _op, _i2) \ RIL_DECODER(_inst, _regs, _r1, _op, _i2, 6, 0) #define RIL_B(_inst, _regs, _r1, _op, _i2) \ RIL_DECODER(_inst, _regs, _r1, _op, _i2, 0, 0) #else #define RIL(_inst, _regs, _r1, _op, _i2) \ RIL_DECODER_TEST(_inst, _regs, _r1, _op, _i2, 6, 6) #define RIL0(_inst, _regs, _r1, _op, _i2) \ RIL_DECODER_TEST(_inst, _regs, _r1, _op, _i2, 6, 0) #define RIL_B(_inst, _regs, _r1, _op, _i2) \ RIL_DECODER_TEST(_inst, _regs, _r1, _op, _i2, 0, 0) #endif #define RIL_DECODER(_inst, _regs, _r1, _op, _i2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_op) = (temp >> 16) & 0xf; \ (_i2) = ((temp & 0xffff) << 16) \ | ((_inst)[4] << 8) \ | (_inst)[5]; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RIL_DECODER_TEST(_inst, _regs, _r1, _op, _i2, _len, _ilc) \ { \ (_i2) = fetch_fw(&(_inst)[2]); \ (_op) = ((_inst)[1] ) & 0xf; \ (_r1) = ((_inst)[1] >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIL register and longer immediate relative address */ #undef RIL_A #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RIL_A) #define RIL_A(_inst, _regs, _r1, _addr2) \ RIL_A_DECODER(_inst, _regs, _r1, _addr2, 6, 6) #else #define RIL_A(_inst, _regs, _r1, _addr2) \ RIL_A_DECODER_TEST(_inst, _regs, _r1, _addr2, 6, 6) #endif #define RIL_A_DECODER(_inst, _regs, _r1, _addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ S64 offset; \ (_r1) = (temp >> 20) & 0xf; \ offset = 2LL*(S32)(((temp & 0xffff) << 16) \ | ((_inst)[4] << 8) \ | (_inst)[5]); \ (_addr2) = (likely(!(_regs)->execflag)) ? \ PSW_IA((_regs), offset) : \ ((_regs)->ET + offset) & ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RIL_A_DECODER_TEST(_inst, _regs, _r1, _addr2, _len, _ilc) \ { \ S64 offset = 2LL*(S32)(fetch_fw(&(_inst)[2])); \ (_r1) = ((_inst)[1] >> 4) & 0xf; \ (_addr2) = (likely(!(_regs)->execflag)) ? \ PSW_IA((_regs), offset) : \ ((_regs)->ET + offset) & ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RIS register, immediate, mask, and storage */ /*208*/ #undef RIS #undef RIS0 #undef RIS_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RIS) #define RIS(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4) \ RIS_DECODER(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, 6, 6) #define RIS0(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4) \ RIS_DECODER(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, 6, 0) #define RIS_B(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4) \ RIS_DECODER(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, 0, 0) #else #define RIS(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4) \ RIS_DECODER_TEST(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, 6, 6) #define RISO(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4) \ RIS_DECODER_TEST(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, 6, 0) #define RIS_B(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4) \ RIS_DECODER_TEST(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, 0, 0) #endif #define RIS_DECODER(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr4) = temp & 0xfff; \ (_b4) = (temp >> 12) & 0xf; \ if((_b4) != 0) \ { \ (_effective_addr4) += (_regs)->GR((_b4)); \ (_effective_addr4) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_m3) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ (_i2) = (_inst)[4]; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RIS_DECODER_TEST(_inst, _regs, _r1, _i2, _m3, _b4, _effective_addr4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr4) = temp & 0xfff; \ (_b4) = (temp >> 12) & 0xf; \ if((_b4)) { \ (_effective_addr4) += (_regs)->GR((_b4)); \ (_effective_addr4) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_m3) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ (_i2) = (_inst)[4]; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* RRS register, immediate, mask, and storage */ /*208*/ #undef RRS #undef RRS0 #undef RRS_B #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_RRS) #define RRS(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4) \ RRS_DECODER(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, 6, 6) #define RRS0(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4) \ RRS_DECODER(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, 6, 0) #define RRS_B(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4) \ RRS_DECODER(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, 0, 0) #else #define RRS(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4) \ RRS_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, 6, 6) #define RRS0(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4) \ RRS_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, 6, 0) #define RRS_B(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4) \ RRS_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, 0, 0) #endif #define RRS_DECODER(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr4) = temp & 0xfff; \ (_b4) = (temp >> 12) & 0xf; \ if((_b4) != 0) \ { \ (_effective_addr4) += (_regs)->GR((_b4)); \ (_effective_addr4) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_r2) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ (_m3) = ((_inst)[4] >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define RRS_DECODER_TEST(_inst, _regs, _r1, _r2, _m3, _b4, _effective_addr4, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr4) = temp & 0xfff; \ (_b4) = (temp >> 12) & 0xf; \ if((_b4)) { \ (_effective_addr4) += (_regs)->GR((_b4)); \ (_effective_addr4) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_r2) = (temp >> 16) & 0xf; \ (_r1) = (temp >> 20) & 0xf; \ (_m3) = ((_inst)[4] >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* SI storage and immediate */ #undef SI #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_SI) #define SI(_inst, _regs, _i2, _b1, _effective_addr1) \ SI_DECODER(_inst, _regs, _i2, _b1, _effective_addr1, 4, 4) #else #define SI(_inst, _regs, _i2, _b1, _effective_addr1) \ SI_DECODER_TEST(_inst, _regs, _i2, _b1, _effective_addr1, 4, 4) #endif #define SI_DECODER(_inst, _regs, _i2, _b1, _effective_addr1, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_i2) = (temp >> 16) & 0xff; \ (_b1) = (temp >> 12) & 0xf; \ (_effective_addr1) = temp & 0xfff; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define SI_DECODER_TEST(_inst, _regs, _i2, _b1, _effective_addr1, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr1) = temp & 0xfff; \ (_b1) = (temp >> 12) & 0xf; \ if((_b1)) { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_i2) = (temp >> 16) & 0xff; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* SIY storage and immediate with long displacement */ #undef SIY #if defined(FEATURE_LONG_DISPLACEMENT) #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_SIY) #define SIY(_inst, _regs, _i2, _b1, _effective_addr1) \ SIY_DECODER_LD(_inst, _regs, _i2, _b1, _effective_addr1, 6, 6) #else #define SIY(_inst, _regs, _i2, _b1, _effective_addr1) \ SIY_DECODER_LD_TEST(_inst, _regs, _i2, _b1, _effective_addr1, 6, 6) #endif #endif /* defined(FEATURE_LONG_DISPLACEMENT) */ #define SIY_DECODER_LD(_inst, _regs, _i2, _b1, _effective_addr1, _len, _ilc) \ { U32 temp; S32 temp1; \ temp = fetch_fw(_inst); \ (_i2) = (temp >> 16) & 0xff; \ (_b1) = (temp >> 12) & 0xf; \ temp1 = (_inst[4] << 12) | (temp & 0xfff); \ if (temp1 & 0x80000) temp1 |= 0xfff00000; \ (_effective_addr1) = \ ((_b1) ? (_regs)->GR((_b1)) : (GREG)0) + \ temp1; \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define SIY_DECODER_LD_TEST(_inst, _regs, _i2, _b1, _effective_addr1, _len, _ilc) \ { U32 temp; S32 disp; \ temp = fetch_fw(_inst); \ (_effective_addr1) = 0; \ (_b1) = (temp >> 12) & 0xf; \ if ((_b1)) \ (_effective_addr1) += (_regs)->GR((_b1)); \ disp = temp & 0xfff; \ if (unlikely((_inst)[4])) { \ disp |= (_inst[4] << 12); \ if (disp & 0x80000) disp |= 0xfff00000; \ } \ (_effective_addr1) += disp; \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ (_i2) = (temp >> 16) & 0xff; \ } /* SIL storage and longer immediate */ /*208*/ #undef SIL #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_SIL) #define SIL(_inst, _regs, _i2, _b1, _effective_addr1) \ SIL_DECODER(_inst, _regs, _i2, _b1, _effective_addr1, 6, 6) #else #define SIL(_inst, _regs, _i2, _b1, _effective_addr1) \ SIL_DECODER_TEST(_inst, _regs, _i2, _b1, _effective_addr1, 6, 6) #endif #define SIL_DECODER(_inst, _regs, _i2, _b1, _effective_addr1, _len, _ilc) \ { U32 temp = fetch_fw(&(_inst)[2]); \ (_i2) = temp & 0xffff; \ (_effective_addr1) = (temp >> 16) & 0xfff; \ (_b1) = (temp >> 28) & 0xf; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define SIL_DECODER_TEST(_inst, _regs, _i2, _b1, _effective_addr1, _len, _ilc) \ { U32 temp = fetch_fw(&(_inst)[2]); \ (_i2) = temp & 0xffff; \ (_effective_addr1) = (temp >> 16) & 0xfff; \ (_b1) = (temp >> 28) & 0xf; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* SMI storage with mask and 16-bit relative address */ /*912*/ #undef SMI_A #undef SMI_A0 #define SMI_A(_inst, _regs, _m1, _addr2, _b3, _addr3) \ SMI_A_DECODER(_inst, _regs, _m1, _addr2, _b3, _addr3, 6, 6) #define SMI_A0(_inst, _regs, _m1, _addr2, _b3, _addr3) \ SMI_A_DECODER(_inst, _regs, _m1, _addr2, _b3, _addr3, 6, 0) #define SMI_A_DECODER(_inst, _regs, _m1, _addr2, _b3, _addr3, _len, _ilc) \ { \ U32 ri2; S64 offset; \ U32 temp = fetch_fw(&(_inst)[2]); \ int i = (_inst)[1]; \ (_m1) = (i >> 4) & 0x0F; \ ri2 = temp & 0xFFFF; \ (_addr3) = (temp >> 16) & 0xFFF; \ (_b3) = (temp >> 28) & 0x0F; \ if((_b3)) \ { \ (_addr3) += (_regs)->GR((_b3)); \ (_addr3) &= ADDRESS_MAXWRAP((_regs)); \ } \ offset = 2LL*(S32)ri2; \ (_addr2) = (likely(!(_regs)->execflag)) ? \ PSW_IA((_regs), offset) : \ ((_regs)->ET + offset) & ADDRESS_MAXWRAP((_regs)); \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* S storage operand only */ #undef S #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_S) #define S(_inst, _regs, _b2, _effective_addr2) \ S_DECODER(_inst, _regs, _b2, _effective_addr2, 4, 4) #else #define S(_inst, _regs, _b2, _effective_addr2) \ S_DECODER_TEST(_inst, _regs, _b2, _effective_addr2, 4, 4) #endif #define S_DECODER(_inst, _regs, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_b2) = (temp >> 12) & 0xf; \ (_effective_addr2) = temp & 0xfff; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define S_DECODER_TEST(_inst, _regs, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 12) & 0xf; \ if((_b2) != 0) { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* SS storage to storage with two 4-bit L or R fields */ #undef SS #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_SS) #define SS(_inst, _regs, _r1, _r3, \ _b1, _effective_addr1, _b2, _effective_addr2) \ SS_DECODER(_inst, _regs, _r1, _r3, \ _b1, _effective_addr1, _b2, _effective_addr2, 6, 6) #else #define SS(_inst, _regs, _r1, _r3, \ _b1, _effective_addr1, _b2, _effective_addr2) \ SS_DECODER_TEST(_inst, _regs, _r1, _r3, \ _b1, _effective_addr1, _b2, _effective_addr2, 6, 6) #endif #define SS_DECODER(_inst, _regs, _r1, _r3, \ _b1, _effective_addr1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r1) = (temp >> 20) & 0xf; \ (_r3) = (temp >> 16) & 0xf; \ (_b1) = (temp >> 12) & 0xf; \ (_effective_addr1) = temp & 0xfff; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b2) = (_inst)[4] >> 4; \ (_effective_addr2) = (((_inst)[4] & 0x0F) << 8) | (_inst)[5]; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define SS_DECODER_TEST(_inst, _regs, _r1, _r3, \ _b1, _effective_addr1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp; \ temp = fetch_fw((_inst)+2); \ (_effective_addr1) = (temp >> 16) & 0xfff; \ (_b1) = (temp >> 28); \ if ((_b1)) { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 12) & 0xf; \ if ((_b2)) { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_r3) = ((_inst)[1] ) & 0xf; \ (_r1) = ((_inst)[1] >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* SS storage to storage with one 8-bit L field */ #undef SS_L #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_SS_L) #define SS_L(_inst, _regs, _l, \ _b1, _effective_addr1, _b2, _effective_addr2) \ SS_L_DECODER(_inst, _regs, _l, \ _b1, _effective_addr1, _b2, _effective_addr2, 6, 6) #else #define SS_L(_inst, _regs, _l, \ _b1, _effective_addr1, _b2, _effective_addr2) \ SS_L_DECODER_TEST(_inst, _regs, _l, \ _b1, _effective_addr1, _b2, _effective_addr2, 6, 6) #endif #define SS_L_DECODER(_inst, _regs, _l, \ _b1, _effective_addr1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_l) = (temp >> 16) & 0xff; \ (_b1) = (temp >> 12) & 0xf; \ (_effective_addr1) = temp & 0xfff; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b2) = (_inst)[4] >> 4; \ (_effective_addr2) = (((_inst)[4] & 0x0F) << 8) | (_inst)[5]; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define SS_L_DECODER_TEST(_inst, _regs, _l, \ _b1, _effective_addr1, _b2, _effective_addr2, _len, _ilc) \ { U32 temp; \ temp = fetch_fw((_inst)+2); \ (_effective_addr1) = (temp >> 16) & 0xfff; \ (_b1) = (temp >> 28); \ if((_b1)) { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 12) & 0xf; \ if ((_b2)) { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_l) = (_inst)[1]; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* SSE storage to storage with extended op code */ #undef SSE #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_SSE) #define SSE(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2) \ SSE_DECODER(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, 6, 6) #else #define SSE(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2) \ SSE_DECODER_TEST(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, 6, 6) #endif #define SSE_DECODER(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_b1) = (temp >> 12) & 0xf; \ (_effective_addr1) = temp & 0xfff; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b2) = (_inst)[4] >> 4; \ (_effective_addr2) = (((_inst)[4] & 0x0F) << 8) | (_inst)[5]; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define SSE_DECODER_TEST(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _len, _ilc) \ { U32 temp = fetch_fw((_inst)+2); \ (_effective_addr1) = (temp >> 16) & 0xfff; \ (_b1) = (temp >> 28); \ if((_b1)) { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 12) & 0xf; \ if ((_b2)) { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } /* SSF storage to storage with additional register */ #undef SSF #if !defined(DECODER_TEST)&&!defined(DECODER_TEST_SSF) #define SSF(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _r3) \ SSF_DECODER(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _r3, 6, 6) #else #define SSF(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _r3) \ SSF_DECODER_TEST(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _r3, 6, 6) #endif #define SSF_DECODER(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _r3, _len, _ilc) \ { U32 temp = fetch_fw(_inst); \ (_r3) = (temp >> 20) & 0xf; \ (_b1) = (temp >> 12) & 0xf; \ (_effective_addr1) = temp & 0xfff; \ if((_b1) != 0) \ { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b2) = (_inst)[4] >> 4; \ (_effective_addr2) = (((_inst)[4] & 0x0F) << 8) | (_inst)[5]; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #define SSF_DECODER_TEST(_inst, _regs, _b1, _effective_addr1, \ _b2, _effective_addr2, _r3, _len, _ilc) \ { U32 temp; \ temp = fetch_fw((_inst)+2); \ (_effective_addr1) = (temp >> 16) & 0xfff; \ (_b1) = (temp >> 28); \ if((_b1)) { \ (_effective_addr1) += (_regs)->GR((_b1)); \ (_effective_addr1) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_effective_addr2) = temp & 0xfff; \ (_b2) = (temp >> 12) & 0xf; \ if ((_b2)) { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ (_b1) = ((_inst)[1] ) & 0xf;\ (_r3) = ((_inst)[1] >> 4) & 0xf; \ INST_UPDATE_PSW((_regs), (_len), (_ilc)); \ } #undef SIE_TRANSLATE_ADDR #undef SIE_LOGICAL_TO_ABS #undef SIE_INTERCEPT #undef SIE_TRANSLATE #if defined(_FEATURE_SIE) #define SIE_SET_VI(_who, _when, _why, _regs) \ { \ (_regs)->siebk->vi_who = (_who); \ (_regs)->siebk->vi_when = (_when); \ STORE_HW((_regs)->siebk->vi_why, (_why)); \ memset((_regs)->siebk->vi_zero, 0, 6); \ } #if __GEN_ARCH == 900 || (__GEN_ARCH == 390 && !defined(_FEATURE_ZSIE)) #define SIE_TRANSLATE_ADDR(_addr, _arn, _regs, _acctype) \ ARCH_DEP(translate_addr)((_addr), (_arn), (_regs), (_acctype)) #define SIE_LOGICAL_TO_ABS(_addr, _arn, _regs, _acctype, _akey) \ ( \ ARCH_DEP(logical_to_main)((_addr), (_arn), (_regs), (_acctype), (_akey)), \ (_regs)->dat.aaddr \ ) #elif __GEN_ARCH == 370 && defined(_FEATURE_SIE) #define SIE_TRANSLATE_ADDR(_addr, _arn, _regs, _acctype) \ s390_translate_addr((_addr), (_arn), (_regs), (_acctype)) #define SIE_LOGICAL_TO_ABS(_addr, _arn, _regs, _acctype, _akey) \ ( \ s390_logical_to_main((_addr), (_arn), (_regs), (_acctype), (_akey)), \ (_regs)->dat.aaddr \ ) #else /*__GEN_ARCH == 390 && defined(_FEATURE_ZSIE)*/ #define SIE_TRANSLATE_ADDR(_addr, _arn, _regs, _acctype) \ ( ((_regs)->arch_mode == ARCH_390) ? \ s390_translate_addr((_addr), (_arn), (_regs), (_acctype)) : \ z900_translate_addr((_addr), (_arn), (_regs), (_acctype)) ) #define SIE_LOGICAL_TO_ABS(_addr, _arn, _regs, _acctype, _akey) \ ( \ (((_regs)->arch_mode == ARCH_390) \ ? s390_logical_to_main((_addr), (_arn), (_regs), (_acctype), (_akey)) \ : z900_logical_to_main((_addr), (_arn), (_regs), (_acctype), (_akey))), \ (_regs)->dat.aaddr \ ) #endif #define SIE_INTERCEPT(_regs) \ do { \ if(SIE_MODE((_regs))) \ longjmp((_regs)->progjmp, SIE_INTERCEPT_INST); \ } while(0) #define SIE_TRANSLATE(_addr, _acctype, _regs) \ do { \ if(SIE_MODE((_regs)) && !(_regs)->sie_pref) \ *(_addr) = SIE_LOGICAL_TO_ABS ((_regs)->sie_mso + *(_addr), \ USE_PRIMARY_SPACE, (_regs)->hostregs, (_acctype), 0); \ } while(0) #else /*!defined(_FEATURE_SIE)*/ #define SIE_TRANSLATE_ADDR(_addr, _arn, _regs, _acctype) #define SIE_LOGICAL_TO_ABS(_addr, _arn, _regs, _acctype, _akey) #define SIE_INTERCEPT(_regs) #define SIE_TRANSLATE(_addr, _acctype, _regs) #endif /*!defined(_FEATURE_SIE)*/ #undef SIE_XC_INTERCEPT #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) #define SIE_XC_INTERCEPT(_regs) \ if(SIE_STATB((_regs), MX, XC)) \ SIE_INTERCEPT((_regs)) #else /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ #define SIE_XC_INTERCEPT(_regs) #endif /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ #if defined(FEATURE_VECTOR_FACILITY) #if !defined(_VFDEFS) #define _VFDEFS #define VOP_CHECK(_regs) \ if(!((_regs)->CR(0) & CR0_VOP) || !(_regs)->vf->online) \ (_regs)->program_interrupt((_regs), PGM_VECTOR_OPERATION_EXCEPTION) #define VR_INUSE(_vr, _regs) \ ((_regs)->vf->vsr & (VSR_VIU0 >> ((_vr) >> 1))) #define VR_CHANGED(_vr, _regs) \ ((_regs)->vf->vsr & (VSR_VCH0 >> ((_vr) >> 1))) #define SET_VR_INUSE(_vr, _regs) \ (_regs)->vf->vsr |= (VSR_VIU0 >> ((_vr) >> 1)) #define SET_VR_CHANGED(_vr, _regs) \ (_regs)->vf->vsr |= (VSR_VCH0 >> ((_vr) >> 1)) #define RESET_VR_INUSE(_vr, _regs) \ (_regs)->vf->vsr &= ~(VSR_VIU0 >> ((_vr) >> 1)) #define RESET_VR_CHANGED(_vr, _regs) \ (_regs)->vf->vsr &= ~(VSR_VCH0 >> ((_vr) >> 1)) #define VMR_SET(_section, _regs) \ ((_regs)->vf->vmr[(_section) >> 3] & (0x80 >> ((_section) & 7))) #define MASK_MODE(_regs) \ ((_regs)->vf->vsr & VSR_M) #define VECTOR_COUNT(_regs) \ (((_regs)->vf->vsr & VSR_VCT) >> 32) #define VECTOR_IX(_regs) \ (((_regs)->vf->vsr & VSR_VIX) >> 16) #endif /*!defined(_VFDEFS)*/ /* VST and QST formats are the same */ #undef VST #define VST(_inst, _regs, _vr3, _rt2, _vr1, _rs2) \ { \ (_qr3) = (_inst)[2] >> 4; \ (_rt2) = (_inst)[2] & 0x0F; \ (_vr1) = (_inst)[3] >> 4; \ (_rs2) = (_inst)[3] & 0x0F; \ INST_UPDATE_PSW((_regs), 4, 4); \ } /* VR, VV and QV formats are the same */ #undef VR #define VR(_inst, _regs, _qr3, _vr1, _vr2) \ { \ (_qr3) = (_inst)[2] >> 4; \ (_vr1) = (_inst)[3] >> 4; \ (_vr2) = (_inst)[3] & 0x0F; \ INST_UPDATE_PSW((_regs), 4, 4); \ } #undef VS #define VS(_inst, _regs, _rs2) \ { \ (_rs2) = (_inst)[3] & 0x0F; \ INST_UPDATE_PSW((_regs), 4, 4); \ } /* The RSE vector instruction format of ESA/390 is referred to as VRSE to avoid conflict with the ESAME RSE instruction format */ #undef VRSE #define VRSE(_inst, _regs, _r3, _vr1, \ _b2, _effective_addr2) \ { \ (_r3) = (_inst)[2] >> 4; \ (_vr1) = (_inst)[3] >> 4; \ (_b2) = (_inst)[4] >> 4; \ (_effective_addr2) = (((_inst)[4] & 0x0F) << 8) | (_inst)[5]; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ (_effective_addr2) &= ADDRESS_MAXWRAP((_regs)); \ } \ INST_UPDATE_PSW((_regs), 6, 6); \ } /* S format instructions where the effective address does not wrap */ #undef S_NW #define S_NW(_inst, _regs, _b2, _effective_addr2) \ { \ (_b2) = (_inst)[2] >> 4; \ (_effective_addr2) = (((_inst)[2] & 0x0F) << 8) | (_inst)[3]; \ if((_b2) != 0) \ { \ (_effective_addr2) += (_regs)->GR((_b2)); \ } \ INST_UPDATE_PSW((_regs), 4, 4); \ } #endif /*defined(FEATURE_VECTOR_FACILITY)*/ #define PERFORM_SERIALIZATION(_regs) do { } while (0) #define PERFORM_CHKPT_SYNC(_regs) do { } while (0) /* Functions in module channel.c */ int ARCH_DEP(startio) (REGS *regs, DEVBLK *dev, ORB *orb); void *s370_execute_ccw_chain (DEVBLK *dev); void *s390_execute_ccw_chain (DEVBLK *dev); void *z900_execute_ccw_chain (DEVBLK *dev); int stchan_id (REGS *regs, U16 chan); int testch (REGS *regs, U16 chan); int testio (REGS *regs, DEVBLK *dev, BYTE ibyte); int test_subchan (REGS *regs, DEVBLK *dev, IRB *irb); int cancel_subchan (REGS *regs, DEVBLK *dev); void clear_subchan (REGS *regs, DEVBLK *dev); int halt_subchan (REGS *regs, DEVBLK *dev); int haltio (REGS *regs, DEVBLK *dev, BYTE ibyte); int resume_subchan (REGS *regs, DEVBLK *dev); int ARCH_DEP(present_io_interrupt) (REGS *regs, U32 *ioid, U32 *ioparm, U32 *iointid, BYTE *csw); int ARCH_DEP(present_zone_io_interrupt) (U32 *ioid, U32 *ioparm, U32 *iointid, BYTE zone); void io_reset (void); int chp_reset(REGS *, BYTE chpid); void channelset_reset(REGS *regs); DLL_EXPORT int device_attention (DEVBLK *dev, BYTE unitstat); DLL_EXPORT int ARCH_DEP(device_attention) (DEVBLK *dev, BYTE unitstat); /* Functions in module cpu.c */ /* define all arch_load|store_psw */ /* regardless of current architecture (if any) */ #if defined(_370) void s370_store_psw (REGS *regs, BYTE *addr); int s370_load_psw (REGS *regs, BYTE *addr); void s370_process_trace (REGS *regs); #endif #if defined(_390) int s390_load_psw (REGS *regs, BYTE *addr); void s390_store_psw (REGS *regs, BYTE *addr); void s390_process_trace (REGS *regs); #endif /*defined(_FEATURE_ZSIE)*/ #if defined(_900) int z900_load_psw (REGS *regs, BYTE *addr); void z900_store_psw (REGS *regs, BYTE *addr); void z900_process_trace (REGS *regs); #endif int cpu_init (int cpu, REGS *regs, REGS *hostregs); void ARCH_DEP(perform_io_interrupt) (REGS *regs); void ARCH_DEP(checkstop_config)(void); #if defined(_FEATURE_SIE) CPU_DLL_IMPORT void (ATTR_REGPARM(2) s370_program_interrupt) (REGS *regs, int code); #endif /*!defined(_FEATURE_SIE)*/ #if defined(_FEATURE_ZSIE) CPU_DLL_IMPORT void (ATTR_REGPARM(2) s390_program_interrupt) (REGS *regs, int code); #endif /*!defined(_FEATURE_ZSIE)*/ CPU_DLL_IMPORT void (ATTR_REGPARM(2) ARCH_DEP(program_interrupt)) (REGS *regs, int code); void *cpu_thread (int *cpu); DLL_EXPORT void copy_psw (REGS *regs, BYTE *addr); void display_psw (REGS *regs); /* Functions in module vm.c */ int ARCH_DEP(diag_devtype) (int r1, int r2, REGS *regs); int ARCH_DEP(syncblk_io) (int r1, int r2, REGS *regs); int ARCH_DEP(syncgen_io) (int r1, int r2, REGS *regs); void ARCH_DEP(extid_call) (int r1, int r2, REGS *regs); int ARCH_DEP(cpcmd_call) (int r1, int r2, REGS *regs); void ARCH_DEP(pseudo_timer) (U32 code, int r1, int r2, REGS *regs); void ARCH_DEP(access_reipl_data) (int r1, int r2, REGS *regs); int ARCH_DEP(diag_ppagerel) (int r1, int r2, REGS *regs); void ARCH_DEP(vm_info) (int r1, int r2, REGS *regs); int ARCH_DEP(device_info) (int r1, int r2, REGS *regs); /* Functions in module vmd250.c */ int ARCH_DEP(vm_blockio) (int r1, int r2, REGS *regs); /* Functions in module control.c */ void ARCH_DEP(load_real_address_proc) (REGS *regs, int r1, int b2, VADR effective_addr2); /* Functions in module decimal.c */ void packed_to_binary (BYTE *dec, int len, U64 *result, int *ovf, int *dxf); void binary_to_packed (S64 bin, BYTE *result); /* Functions in module diagnose.c */ void ARCH_DEP(diagnose_call) (VADR effective_addr2, int b2, int r1, int r3, REGS *regs); /* Functions in module diagmssf.c */ void ARCH_DEP(scpend_call) (void); int ARCH_DEP(mssf_call) (int r1, int r2, REGS *regs); void ARCH_DEP(diag204_call) (int r1, int r2, REGS *regs); void ARCH_DEP(diag224_call) (int r1, int r2, REGS *regs); /* Functions in module external.c */ void ARCH_DEP(perform_external_interrupt) (REGS *regs); void ARCH_DEP(store_status) (REGS *ssreg, RADR aaddr); void store_status (REGS *ssreg, U64 aaddr); /* Functions in module ipl.c */ int load_ipl (U16 lcss, U16 devnum, int cpu, int clear); int ARCH_DEP(load_ipl) (U16 lcss, U16 devnum, int cpu, int clear); int system_reset (int cpu, int clear); int ARCH_DEP(system_reset) (int cpu, int clear); int cpu_reset (REGS *regs); int ARCH_DEP(cpu_reset) (REGS *regs); int initial_cpu_reset (REGS *regs); int ARCH_DEP(initial_cpu_reset) (REGS *regs); int ARCH_DEP(common_load_begin) (int cpu, int clear); int ARCH_DEP(common_load_finish) (REGS *regs); void storage_clear(void); void xstorage_clear(void); /* Functions in module scedasd.c */ void set_sce_dir (char *path); char *get_sce_dir (); int load_main (char *fname, RADR startloc); int ARCH_DEP(load_main) (char *fname, RADR startloc); int load_hmc (char *fname, int cpu, int clear); int ARCH_DEP(load_hmc) (char *fname, int cpu, int clear); void ARCH_DEP(sclp_scedio_request) (SCCB_HEADER *); void ARCH_DEP(sclp_scedio_event) (SCCB_HEADER *); /* Functions in module machchk.c */ int ARCH_DEP(present_mck_interrupt) (REGS *regs, U64 *mcic, U32 *xdmg, RADR *fsta); U32 channel_report (REGS *); void machine_check_crwpend (void); void ARCH_DEP(sync_mck_interrupt) (REGS *regs); void sigabend_handler (int signo); /* Functions in module opcode.c */ OPC_DLL_IMPORT void copy_opcode_tables (); void set_opcode_pointers (REGS *regs); /* Functions in module panel.c */ void ARCH_DEP(display_inst) (REGS *regs, BYTE *inst); void display_inst (REGS *regs, BYTE *inst); /* Functions in module sie.c */ void ARCH_DEP(sie_exit) (REGS *regs, int code); void ARCH_DEP(diagnose_002) (REGS *regs, int r1, int r3); /* Functions in module stack.c */ void ARCH_DEP(trap_x) (int trap_is_trap4, REGS *regs, U32 trap_operand); void ARCH_DEP(form_stack_entry) (BYTE etype, VADR retna, VADR calla, U32 csi, U32 pcnum, REGS *regs); VADR ARCH_DEP(locate_stack_entry) (int prinst, LSED *lsedptr, REGS *regs); void ARCH_DEP(stack_modify) (VADR lsea, U32 m1, U32 m2, REGS *regs); void ARCH_DEP(stack_extract) (VADR lsea, int r1, int code, REGS *regs); void ARCH_DEP(unstack_registers) (int gtype, VADR lsea, int r1, int r2, REGS *regs); int ARCH_DEP(program_return_unstack) (REGS *regs, RADR *lsedap, int *rc); /* Functions in module trace.c */ CREG ARCH_DEP(trace_br) (int amode, VADR ia, REGS *regs); #if defined(_FEATURE_ZSIE) U32 s390_trace_br (int amode, U32 ia, REGS *regs); #endif /*!defined(_FEATURE_ZSIE)*/ CREG ARCH_DEP(trace_bsg) (U32 alet, VADR ia, REGS *regs); CREG ARCH_DEP(trace_ssar) (int ssair, U16 sasn, REGS *regs); CREG ARCH_DEP(trace_pc) (U32 pcea, REGS *regs); CREG ARCH_DEP(trace_pr) (REGS *newregs, REGS *regs); CREG ARCH_DEP(trace_pt) (int pti, U16 pasn, GREG gpr2, REGS *regs); CREG ARCH_DEP(trace_tr) (int r1, int r3, U32 op, REGS *regs); CREG ARCH_DEP(trace_tg) (int r1, int r3, U32 op, REGS *regs); CREG ARCH_DEP(trace_ms) (int br_ind, VADR ia, REGS *regs); /* Functions in module plo.c */ int ARCH_DEP(plo_cl) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_clg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_clgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_clx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_cs) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_dcs) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_dcsg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_dcsgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_dcsx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csst) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csstg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csstgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csstx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csdst) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csdstg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csdstgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_csdstx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_cstst) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_cststg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_cststgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); int ARCH_DEP(plo_cststx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs); /* Instruction functions in opcode.c */ DEF_INST(execute_01xx); DEF_INST(execute_a4xx); DEF_INST(execute_a5xx); DEF_INST(execute_a6xx); DEF_INST(execute_a7xx); DEF_INST(execute_b2xx); DEF_INST(execute_b3xx); DEF_INST(execute_b9xx); DEF_INST(execute_c0xx); DEF_INST(execute_e3xx); DEF_INST(execute_e4xx); DEF_INST(execute_e5xx); DEF_INST(execute_ebxx); DEF_INST(execute_ecxx); DEF_INST(execute_edxx); DEF_INST(operation_exception); DEF_INST(dummy_instruction); /* Instructions in assist.c */ DEF_INST(fix_page); DEF_INST(svc_assist); DEF_INST(obtain_local_lock); DEF_INST(release_local_lock); DEF_INST(obtain_cms_lock); DEF_INST(release_cms_lock); DEF_INST(trace_svc_interruption); DEF_INST(trace_program_interruption); DEF_INST(trace_initial_srb_dispatch); DEF_INST(trace_io_interruption); DEF_INST(trace_task_dispatch); DEF_INST(trace_svc_return); /* Instructions in cmpsc.c */ DEF_INST(compression_call); /* Instructions in crypto.c */ DEF_INST(cipher_message_r); DEF_INST(cipher_message_with_chaining_r); DEF_INST(compute_intermediate_message_digest_r); DEF_INST(compute_last_message_digest_r); DEF_INST(compute_message_authentication_code_r); DEF_INST(perform_cryptographic_key_management_operation_r); DEF_INST(cipher_message_with_cipher_feedback_r); DEF_INST(cipher_message_with_counter_r); DEF_INST(cipher_message_with_output_feedback_r); DEF_INST(perform_cryptographic_computation_r); /* Instructions in control.c */ DEF_INST(branch_and_set_authority); DEF_INST(branch_in_subspace_group); DEF_INST(branch_and_stack); DEF_INST(compare_and_swap_and_purge); DEF_INST(diagnose); DEF_INST(extract_primary_asn); DEF_INST(extract_primary_asn_and_instance); DEF_INST(extract_secondary_asn); DEF_INST(extract_secondary_asn_and_instance); DEF_INST(extract_stacked_registers); DEF_INST(extract_stacked_state); DEF_INST(insert_address_space_control); DEF_INST(insert_psw_key); DEF_INST(insert_storage_key); DEF_INST(insert_storage_key_extended); DEF_INST(insert_virtual_storage_key); DEF_INST(invalidate_page_table_entry); DEF_INST(load_address_space_parameters); DEF_INST(load_control); DEF_INST(load_program_status_word); DEF_INST(load_real_address); DEF_INST(load_using_real_address); DEF_INST(lock_page); DEF_INST(modify_stacked_state); DEF_INST(move_to_primary); DEF_INST(move_to_secondary); DEF_INST(move_with_destination_key); DEF_INST(move_with_key); DEF_INST(move_with_optional_specifications); /*208*/ DEF_INST(move_with_source_key); DEF_INST(program_call); DEF_INST(program_return); DEF_INST(program_transfer); DEF_INST(program_transfer_with_instance); DEF_INST(purge_accesslist_lookaside_buffer); DEF_INST(purge_translation_lookaside_buffer); DEF_INST(reset_reference_bit); DEF_INST(reset_reference_bit_extended); DEF_INST(set_address_space_control); DEF_INST(set_address_space_control_fast); DEF_INST(set_clock); DEF_INST(set_clock_comparator); DEF_INST(set_clock_programmable_field); DEF_INST(set_cpu_timer); DEF_INST(set_prefix); DEF_INST(set_psw_key_from_address); DEF_INST(set_secondary_asn); DEF_INST(set_secondary_asn_with_instance); DEF_INST(set_storage_key); DEF_INST(set_storage_key_extended); DEF_INST(set_system_mask); DEF_INST(signal_processor); DEF_INST(store_clock_comparator); DEF_INST(store_control); DEF_INST(store_cpu_address); DEF_INST(store_cpu_id); DEF_INST(store_cpu_timer); DEF_INST(store_prefix); DEF_INST(store_system_information); DEF_INST(store_then_and_system_mask); DEF_INST(store_then_or_system_mask); DEF_INST(store_using_real_address); DEF_INST(test_access); DEF_INST(test_block); DEF_INST(test_protection); DEF_INST(trace); /* Instructions in decimal.c */ DEF_INST(add_decimal); DEF_INST(compare_decimal); DEF_INST(divide_decimal); DEF_INST(edit_x_edit_and_mark); DEF_INST(multiply_decimal); DEF_INST(shift_and_round_decimal); DEF_INST(subtract_decimal); DEF_INST(zero_and_add); DEF_INST(test_decimal); /* Instructions in vm.c */ DEF_INST(inter_user_communication_vehicle); /* Instructions in sie.c */ DEF_INST(start_interpretive_execution); DEF_INST(store_zone_parameter); DEF_INST(set_zone_parameter); DEF_INST(test_pending_zone_interrupt); /* Instructions in qdio.c */ DEF_INST(signal_adapter); /* Instructions in float.c */ DEF_INST(load_positive_float_long_reg); DEF_INST(load_negative_float_long_reg); DEF_INST(load_and_test_float_long_reg); DEF_INST(load_complement_float_long_reg); DEF_INST(halve_float_long_reg); DEF_INST(load_rounded_float_long_reg); DEF_INST(multiply_float_ext_reg); DEF_INST(multiply_float_long_to_ext_reg); DEF_INST(load_float_long_reg); DEF_INST(compare_float_long_reg); DEF_INST(add_float_long_reg); DEF_INST(subtract_float_long_reg); DEF_INST(multiply_float_long_reg); DEF_INST(divide_float_long_reg); DEF_INST(add_unnormal_float_long_reg); DEF_INST(subtract_unnormal_float_long_reg); DEF_INST(load_positive_float_short_reg); DEF_INST(load_negative_float_short_reg); DEF_INST(load_and_test_float_short_reg); DEF_INST(load_complement_float_short_reg); DEF_INST(halve_float_short_reg); DEF_INST(load_rounded_float_short_reg); DEF_INST(add_float_ext_reg); DEF_INST(subtract_float_ext_reg); DEF_INST(load_float_short_reg); DEF_INST(compare_float_short_reg); DEF_INST(add_float_short_reg); DEF_INST(subtract_float_short_reg); DEF_INST(multiply_float_short_to_long_reg); DEF_INST(divide_float_short_reg); DEF_INST(add_unnormal_float_short_reg); DEF_INST(subtract_unnormal_float_short_reg); DEF_INST(store_float_long); DEF_INST(multiply_float_long_to_ext); DEF_INST(load_float_long); DEF_INST(compare_float_long); DEF_INST(add_float_long); DEF_INST(subtract_float_long); DEF_INST(multiply_float_long); DEF_INST(divide_float_long); DEF_INST(add_unnormal_float_long); DEF_INST(subtract_unnormal_float_long); DEF_INST(store_float_short); DEF_INST(load_float_short); DEF_INST(compare_float_short); DEF_INST(add_float_short); DEF_INST(subtract_float_short); DEF_INST(multiply_float_short_to_long); DEF_INST(divide_float_short); DEF_INST(add_unnormal_float_short); DEF_INST(subtract_unnormal_float_short); DEF_INST(divide_float_ext_reg); DEF_INST(squareroot_float_long_reg); DEF_INST(squareroot_float_short_reg); DEF_INST(load_lengthened_float_short_to_long_reg); DEF_INST(load_lengthened_float_long_to_ext_reg); DEF_INST(load_lengthened_float_short_to_ext_reg); DEF_INST(squareroot_float_ext_reg); DEF_INST(multiply_float_short_reg); DEF_INST(load_positive_float_ext_reg); DEF_INST(load_negative_float_ext_reg); DEF_INST(load_and_test_float_ext_reg); DEF_INST(load_complement_float_ext_reg); DEF_INST(load_rounded_float_ext_to_short_reg); DEF_INST(load_fp_int_float_ext_reg); DEF_INST(compare_float_ext_reg); DEF_INST(load_fp_int_float_short_reg); DEF_INST(load_fp_int_float_long_reg); DEF_INST(convert_fixed_to_float_short_reg); DEF_INST(convert_fixed_to_float_long_reg); DEF_INST(convert_fixed_to_float_ext_reg); DEF_INST(convert_fix64_to_float_short_reg); DEF_INST(convert_fix64_to_float_long_reg); DEF_INST(convert_fix64_to_float_ext_reg); DEF_INST(convert_float_short_to_fixed_reg); DEF_INST(convert_float_long_to_fixed_reg); DEF_INST(convert_float_ext_to_fixed_reg); DEF_INST(convert_float_short_to_fix64_reg); /* under construction! Bernard van der Helm */ DEF_INST(convert_float_long_to_fix64_reg); /* under construction! Bernard van der Helm */ DEF_INST(convert_float_ext_to_fix64_reg); /* under construction! Bernard van der Helm */ DEF_INST(load_lengthened_float_short_to_long); DEF_INST(load_lengthened_float_long_to_ext); DEF_INST(load_lengthened_float_short_to_ext); DEF_INST(squareroot_float_short); DEF_INST(squareroot_float_long); DEF_INST(multiply_float_short); DEF_INST(load_float_ext_reg); DEF_INST(load_zero_float_short_reg); DEF_INST(load_zero_float_long_reg); DEF_INST(load_zero_float_ext_reg); DEF_INST(multiply_add_float_short_reg); DEF_INST(multiply_add_float_long_reg); DEF_INST(multiply_add_float_short); DEF_INST(multiply_add_float_long); DEF_INST(multiply_subtract_float_short_reg); DEF_INST(multiply_subtract_float_long_reg); DEF_INST(multiply_subtract_float_short); DEF_INST(multiply_subtract_float_long); DEF_INST(multiply_unnormal_float_long_to_ext_reg); /*@Z9*/ DEF_INST(multiply_unnormal_float_long_to_ext_low_reg); /*@Z9*/ DEF_INST(multiply_unnormal_float_long_to_ext_high_reg); /*@Z9*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_reg); /*@Z9*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_low_reg); /*@Z9*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_high_reg); /*@Z9*/ DEF_INST(multiply_unnormal_float_long_to_ext); /*@Z9*/ DEF_INST(multiply_unnormal_float_long_to_ext_low); /*@Z9*/ DEF_INST(multiply_unnormal_float_long_to_ext_high); /*@Z9*/ DEF_INST(multiply_add_unnormal_float_long_to_ext); /*@Z9*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_low); /*@Z9*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_high); /*@Z9*/ DEF_INST(load_float_long_y); DEF_INST(load_float_short_y); DEF_INST(store_float_long_y); DEF_INST(store_float_short_y); /* Instructions in general1.c */ DEF_INST(add_register); DEF_INST(add); DEF_INST(add_halfword); DEF_INST(add_halfword_immediate); DEF_INST(add_logical_register); DEF_INST(add_logical); DEF_INST(and_register); DEF_INST(and); DEF_INST(and_immediate); DEF_INST(and_character); DEF_INST(branch_and_link_register); DEF_INST(branch_and_link); DEF_INST(branch_and_save_register); DEF_INST(branch_and_save); DEF_INST(branch_and_save_and_set_mode); DEF_INST(branch_and_set_mode); DEF_INST(branch_on_condition_register); DEF_INST(branch_on_condition); DEF_INST(branch_on_count_register); DEF_INST(branch_on_count); DEF_INST(branch_on_index_high); DEF_INST(branch_on_index_low_or_equal); DEF_INST(branch_relative_on_condition); DEF_INST(branch_relative_and_save); DEF_INST(branch_relative_on_count); DEF_INST(branch_relative_on_index_high); DEF_INST(branch_relative_on_index_low_or_equal); DEF_INST(checksum); DEF_INST(compare_register); DEF_INST(compare); DEF_INST(compare_and_form_codeword); DEF_INST(compare_and_swap); DEF_INST(compare_double_and_swap); DEF_INST(compare_and_swap_and_store); DEF_INST(compare_halfword); DEF_INST(compare_halfword_immediate); DEF_INST(compare_logical_register); DEF_INST(compare_logical); DEF_INST(compare_logical_immediate); DEF_INST(compare_logical_character); DEF_INST(compare_logical_characters_under_mask); DEF_INST(compare_logical_character_long); DEF_INST(compare_logical_long_extended); DEF_INST(compare_logical_string); DEF_INST(compare_until_substring_equal); DEF_INST(convert_utf16_to_utf8); DEF_INST(convert_utf16_to_utf32); DEF_INST(convert_utf32_to_utf16); DEF_INST(convert_utf32_to_utf8); DEF_INST(convert_utf8_to_utf16); DEF_INST(convert_utf8_to_utf32); DEF_INST(convert_to_binary); DEF_INST(convert_to_decimal); DEF_INST(copy_access); DEF_INST(divide_register); DEF_INST(divide); DEF_INST(exclusive_or_register); DEF_INST(exclusive_or); DEF_INST(exclusive_or_immediate); DEF_INST(exclusive_or_character); DEF_INST(execute); DEF_INST(execute_relative_long); /*208*/ DEF_INST(extract_access_register); DEF_INST(insert_character); DEF_INST(insert_characters_under_mask); DEF_INST(insert_program_mask); DEF_INST(load); DEF_INST(load_register); DEF_INST(load_access_multiple); DEF_INST(load_address); DEF_INST(load_address_extended); DEF_INST(load_and_test_register); DEF_INST(load_complement_register); DEF_INST(load_halfword); DEF_INST(load_halfword_immediate); DEF_INST(load_multiple); DEF_INST(load_negative_register); DEF_INST(load_positive_register); DEF_INST(monitor_call); DEF_INST(move_immediate); DEF_INST(move_character); DEF_INST(move_inverse); DEF_INST(move_long); DEF_INST(move_long_extended); DEF_INST(move_numerics); DEF_INST(move_string); DEF_INST(move_with_offset); DEF_INST(move_zones); DEF_INST(multiply_register); DEF_INST(multiply); DEF_INST(multiply_halfword); DEF_INST(multiply_halfword_immediate); DEF_INST(multiply_single_register); DEF_INST(multiply_single); /* Instructions in general2.c */ DEF_INST(or_register); DEF_INST(or); DEF_INST(or_immediate); DEF_INST(or_character); DEF_INST(perform_locked_operation); DEF_INST(pack); DEF_INST(search_string); DEF_INST(search_string_unicode); DEF_INST(set_access_register); DEF_INST(set_program_mask); DEF_INST(shift_left_double); DEF_INST(shift_left_double_logical); DEF_INST(shift_left_single); DEF_INST(shift_left_single_logical); DEF_INST(shift_right_double); DEF_INST(shift_right_double_logical); DEF_INST(shift_right_single); DEF_INST(shift_right_single_logical); DEF_INST(store); DEF_INST(store_access_multiple); DEF_INST(store_character); DEF_INST(store_characters_under_mask); DEF_INST(store_clock); DEF_INST(store_clock_extended); DEF_INST(store_clock_fast); /*@Z9*/ DEF_INST(store_halfword); DEF_INST(store_multiple); DEF_INST(subtract_register); DEF_INST(subtract); DEF_INST(subtract_halfword); DEF_INST(subtract_logical_register); DEF_INST(subtract_logical); DEF_INST(supervisor_call); DEF_INST(test_and_set); DEF_INST(test_under_mask); DEF_INST(test_under_mask_high); DEF_INST(test_under_mask_low); DEF_INST(translate); DEF_INST(translate_and_test); DEF_INST(translate_and_test_reverse); DEF_INST(translate_and_test_extended); /*208*/ DEF_INST(translate_and_test_reverse_extended); /*208*/ DEF_INST(translate_extended); DEF_INST(unpack); DEF_INST(update_tree); /* Instructions in general3.c */ DEF_INST(add_immediate_long_storage); /*208*/ DEF_INST(add_immediate_storage); /*208*/ DEF_INST(add_logical_with_signed_immediate); /*208*/ DEF_INST(add_logical_with_signed_immediate_long); /*208*/ DEF_INST(compare_and_branch_register); /*208*/ DEF_INST(compare_and_branch_long_register); /*208*/ DEF_INST(compare_and_branch_relative_register); /*208*/ DEF_INST(compare_and_branch_relative_long_register); /*208*/ DEF_INST(compare_and_trap_long_register); /*208*/ DEF_INST(compare_and_trap_register); /*208*/ DEF_INST(compare_halfword_immediate_halfword_storage); /*208*/ DEF_INST(compare_halfword_immediate_long_storage); /*208*/ DEF_INST(compare_halfword_immediate_storage); /*208*/ DEF_INST(compare_halfword_long); /*208*/ DEF_INST(compare_halfword_relative_long); /*208*/ DEF_INST(compare_halfword_relative_long_long); /*208*/ DEF_INST(compare_immediate_and_branch); /*208*/ DEF_INST(compare_immediate_and_branch_long); /*208*/ DEF_INST(compare_immediate_and_branch_relative); /*208*/ DEF_INST(compare_immediate_and_branch_relative_long); /*208*/ DEF_INST(compare_immediate_and_trap); /*208*/ DEF_INST(compare_immediate_and_trap_long); /*208*/ DEF_INST(compare_logical_and_branch_long_register); /*208*/ DEF_INST(compare_logical_and_branch_register); /*208*/ DEF_INST(compare_logical_and_branch_relative_long_register); /*208*/ DEF_INST(compare_logical_and_branch_relative_register); /*208*/ DEF_INST(compare_logical_and_trap_long_register); /*208*/ DEF_INST(compare_logical_and_trap_register); /*208*/ DEF_INST(compare_logical_immediate_and_branch); /*208*/ DEF_INST(compare_logical_immediate_and_branch_long); /*208*/ DEF_INST(compare_logical_immediate_and_branch_relative); /*208*/ DEF_INST(compare_logical_immediate_and_branch_relative_long); /*208*/ DEF_INST(compare_logical_immediate_and_trap_fullword); /*208*/ DEF_INST(compare_logical_immediate_and_trap_long); /*208*/ DEF_INST(compare_logical_immediate_fullword_storage); /*208*/ DEF_INST(compare_logical_immediate_halfword_storage); /*208*/ DEF_INST(compare_logical_immediate_long_storage); /*208*/ DEF_INST(compare_logical_relative_long); /*208*/ DEF_INST(compare_logical_relative_long_halfword); /*208*/ DEF_INST(compare_logical_relative_long_long); /*208*/ DEF_INST(compare_logical_relative_long_long_fullword); /*208*/ DEF_INST(compare_logical_relative_long_long_halfword); /*208*/ DEF_INST(compare_relative_long); /*208*/ DEF_INST(compare_relative_long_long); /*208*/ DEF_INST(compare_relative_long_long_fullword); /*208*/ DEF_INST(extract_cache_attribute); /*208*/ DEF_INST(load_address_extended_y); /*208*/ DEF_INST(load_and_test_long_fullword); /*208*/ DEF_INST(load_halfword_relative_long); /*208*/ DEF_INST(load_halfword_relative_long_long); /*208*/ DEF_INST(load_logical_halfword_relative_long); /*208*/ DEF_INST(load_logical_halfword_relative_long_long); /*208*/ DEF_INST(load_logical_relative_long_long_fullword); /*208*/ DEF_INST(load_relative_long); /*208*/ DEF_INST(load_relative_long_long); /*208*/ DEF_INST(load_relative_long_long_fullword); /*208*/ DEF_INST(move_fullword_from_halfword_immediate); /*208*/ DEF_INST(move_halfword_from_halfword_immediate); /*208*/ DEF_INST(move_long_from_halfword_immediate); /*208*/ DEF_INST(multiply_halfword_y); /*208*/ DEF_INST(multiply_single_immediate_fullword); /*208*/ DEF_INST(multiply_single_immediate_long_fullword); /*208*/ DEF_INST(multiply_y); /*208*/ DEF_INST(prefetch_data); /*208*/ DEF_INST(prefetch_data_relative_long); /*208*/ DEF_INST(rotate_then_and_selected_bits_long_reg); /*208*/ DEF_INST(rotate_then_exclusive_or_selected_bits_long_reg); /*208*/ DEF_INST(rotate_then_insert_selected_bits_long_reg); /*208*/ DEF_INST(rotate_then_or_selected_bits_long_reg); /*208*/ DEF_INST(store_halfword_relative_long); /*208*/ DEF_INST(store_relative_long); /*208*/ DEF_INST(store_relative_long_long); /*208*/ DEF_INST(add_high_high_high_register); /*810*/ DEF_INST(add_high_high_low_register); /*810*/ DEF_INST(add_high_immediate); /*810*/ DEF_INST(add_logical_high_high_high_register); /*810*/ DEF_INST(add_logical_high_high_low_register); /*810*/ DEF_INST(add_logical_with_signed_immediate_high); /*810*/ DEF_INST(add_logical_with_signed_immediate_high_n); /*810*/ DEF_INST(branch_relative_on_count_high); /*810*/ DEF_INST(compare_high_high_register); /*810*/ DEF_INST(compare_high_low_register); /*810*/ DEF_INST(compare_high_fullword); /*810*/ DEF_INST(compare_high_immediate); /*810*/ DEF_INST(compare_logical_high_high_register); /*810*/ DEF_INST(compare_logical_high_low_register); /*810*/ DEF_INST(compare_logical_high_fullword); /*810*/ DEF_INST(compare_logical_high_immediate); /*810*/ DEF_INST(load_byte_high); /*810*/ DEF_INST(load_fullword_high); /*810*/ DEF_INST(load_halfword_high); /*810*/ DEF_INST(load_logical_character_high); /*810*/ DEF_INST(load_logical_halfword_high); /*810*/ DEF_INST(rotate_then_insert_selected_bits_high_long_reg); /*810*/ DEF_INST(rotate_then_insert_selected_bits_low_long_reg); /*810*/ DEF_INST(store_character_high); /*810*/ DEF_INST(store_fullword_high); /*810*/ DEF_INST(store_halfword_high); /*810*/ DEF_INST(subtract_high_high_high_register); /*810*/ DEF_INST(subtract_high_high_low_register); /*810*/ DEF_INST(subtract_logical_high_high_high_register); /*810*/ DEF_INST(subtract_logical_high_high_low_register); /*810*/ DEF_INST(load_and_add); /*810*/ DEF_INST(load_and_add_long); /*810*/ DEF_INST(load_and_add_logical); /*810*/ DEF_INST(load_and_add_logical_long); /*810*/ DEF_INST(load_and_and); /*810*/ DEF_INST(load_and_and_long); /*810*/ DEF_INST(load_and_exclusive_or); /*810*/ DEF_INST(load_and_exclusive_or_long); /*810*/ DEF_INST(load_and_or); /*810*/ DEF_INST(load_and_or_long); /*810*/ DEF_INST(load_pair_disjoint); /*810*/ DEF_INST(load_pair_disjoint_long); /*810*/ DEF_INST(load_on_condition_register); /*810*/ DEF_INST(load_on_condition_long_register); /*810*/ DEF_INST(load_on_condition); /*810*/ DEF_INST(load_on_condition_long); /*810*/ DEF_INST(store_on_condition); /*810*/ DEF_INST(store_on_condition_long); /*810*/ DEF_INST(add_distinct_register); /*810*/ DEF_INST(add_distinct_long_register); /*810*/ DEF_INST(add_distinct_halfword_immediate); /*810*/ DEF_INST(add_distinct_long_halfword_immediate); /*810*/ DEF_INST(add_logical_distinct_register); /*810*/ DEF_INST(add_logical_distinct_long_register); /*810*/ DEF_INST(add_logical_distinct_signed_halfword_immediate); /*810*/ DEF_INST(add_logical_distinct_long_signed_halfword_immediate); /*810*/ DEF_INST(and_distinct_register); /*810*/ DEF_INST(and_distinct_long_register); /*810*/ DEF_INST(exclusive_or_distinct_register); /*810*/ DEF_INST(exclusive_or_distinct_long_register); /*810*/ DEF_INST(or_distinct_register); /*810*/ DEF_INST(or_distinct_long_register); /*810*/ DEF_INST(shift_right_single_distinct); /*810*/ DEF_INST(shift_left_single_distinct); /*810*/ DEF_INST(shift_right_single_logical_distinct); /*810*/ DEF_INST(shift_left_single_logical_distinct); /*810*/ DEF_INST(subtract_distinct_register); /*810*/ DEF_INST(subtract_distinct_long_register); /*810*/ DEF_INST(subtract_logical_distinct_register); /*810*/ DEF_INST(subtract_logical_distinct_long_register); /*810*/ DEF_INST(population_count); /*810*/ DEF_INST(load_and_trap); /*912*/ DEF_INST(load_long_and_trap); /*912*/ DEF_INST(load_fullword_high_and_trap); /*912*/ DEF_INST(load_logical_long_fullword_and_trap); /*912*/ DEF_INST(load_logical_long_thirtyone_and_trap); /*912*/ DEF_INST(compare_logical_and_trap); /*912*/ DEF_INST(compare_logical_and_trap_long); /*912*/ DEF_INST(rotate_then_insert_selected_bits_long_reg_n); /*912*/ DEF_INST(branch_prediction_preload); /*912*/ DEF_INST(branch_prediction_relative_preload); /*912*/ DEF_INST(next_instruction_access_intent); /*912*/ /* Instructions in io.c */ DEF_INST(clear_subchannel); DEF_INST(halt_subchannel); DEF_INST(modify_subchannel); DEF_INST(resume_subchannel); DEF_INST(set_address_limit); DEF_INST(set_channel_monitor); DEF_INST(reset_channel_path); DEF_INST(start_subchannel); DEF_INST(cancel_subchannel); DEF_INST(store_channel_path_status); DEF_INST(store_channel_report_word); DEF_INST(store_subchannel); DEF_INST(test_pending_interruption); DEF_INST(test_subchannel); DEF_INST(start_io); DEF_INST(test_io); DEF_INST(halt_io); DEF_INST(test_channel); DEF_INST(store_channel_id); DEF_INST(connect_channel_set); DEF_INST(disconnect_channel_set); /* Instructions in service.c */ DEF_INST(service_call); /* Instructions in chsc.c */ DEF_INST(channel_subsystem_call); /* Instructions in xstore.c */ DEF_INST(page_in); DEF_INST(page_out); DEF_INST(move_page); DEF_INST(invalidate_expanded_storage_block_entry); /* Instructions in vector.c */ DEF_INST(v_test_vmr); DEF_INST(v_complement_vmr); DEF_INST(v_count_left_zeros_in_vmr); DEF_INST(v_count_ones_in_vmr); DEF_INST(v_extract_vct); DEF_INST(v_extract_vector_modes); DEF_INST(v_restore_vr); DEF_INST(v_save_changed_vr); DEF_INST(v_save_vr); DEF_INST(v_load_vmr); DEF_INST(v_load_vmr_complement); DEF_INST(v_store_vmr); DEF_INST(v_and_to_vmr); DEF_INST(v_or_to_vmr); DEF_INST(v_exclusive_or_to_vmr); DEF_INST(v_save_vsr); DEF_INST(v_save_vmr); DEF_INST(v_restore_vsr); DEF_INST(v_restore_vmr); DEF_INST(v_load_vct_from_address); DEF_INST(v_clear_vr); DEF_INST(v_set_vector_mask_mode); DEF_INST(v_load_vix_from_address); DEF_INST(v_store_vector_parameters); DEF_INST(v_save_vac); DEF_INST(v_restore_vac); /* Instructions in esame.c */ DEF_INST(store_fpc); DEF_INST(load_fpc); DEF_INST(set_fpc); DEF_INST(extract_fpc); DEF_INST(set_bfp_rounding_mode_2bit); DEF_INST(set_bfp_rounding_mode_3bit); /*810*/ DEF_INST(trap2); DEF_INST(trap4); DEF_INST(resume_program); DEF_INST(trace_long); DEF_INST(convert_to_binary_long); DEF_INST(convert_to_decimal_long); DEF_INST(multiply_logical); DEF_INST(multiply_logical_long); DEF_INST(multiply_logical_register); DEF_INST(multiply_logical_long_register); DEF_INST(divide_logical); DEF_INST(divide_logical_long); DEF_INST(divide_logical_register); DEF_INST(divide_logical_long_register); DEF_INST(add_logical_carry_long_register); DEF_INST(subtract_logical_borrow_long_register); DEF_INST(add_logical_carry_long); DEF_INST(subtract_logical_borrow_long); DEF_INST(add_logical_carry_register); DEF_INST(subtract_logical_borrow_register); DEF_INST(add_logical_carry); DEF_INST(subtract_logical_borrow); DEF_INST(divide_single_long); DEF_INST(divide_single_long_fullword); DEF_INST(divide_single_long_register); DEF_INST(divide_single_long_fullword_register); DEF_INST(load_logical_long_character); DEF_INST(load_logical_long_halfword); DEF_INST(store_pair_to_quadword); DEF_INST(load_pair_from_quadword); DEF_INST(extract_stacked_registers_long); DEF_INST(extract_psw); DEF_INST(extract_and_set_extended_authority); DEF_INST(load_address_relative_long); DEF_INST(perform_frame_management_function); /*208*/ DEF_INST(perform_timing_facility_function); /*@Z9*/ DEF_INST(perform_topology_function); /*208*/ DEF_INST(reset_reference_bits_multiple); /*810*/ DEF_INST(store_facility_list); DEF_INST(store_facility_list_extended); /*@Z9*/ DEF_INST(load_long_halfword_immediate); DEF_INST(add_long_halfword_immediate); DEF_INST(multiply_long_halfword_immediate); DEF_INST(compare_long_halfword_immediate); DEF_INST(and_long); DEF_INST(or_long); DEF_INST(exclusive_or_long); DEF_INST(and_long_register); DEF_INST(or_long_register); DEF_INST(exclusive_or_long_register); DEF_INST(load_long_register); DEF_INST(add_logical_long_register); DEF_INST(add_logical_long_fullword_register); DEF_INST(subtract_logical_long_register); DEF_INST(subtract_logical_long_fullword_register); DEF_INST(load_control_long); DEF_INST(store_control_long); DEF_INST(load_multiple_disjoint); DEF_INST(load_multiple_high); DEF_INST(load_multiple_long); DEF_INST(store_multiple_high); DEF_INST(store_multiple_long); DEF_INST(load_using_real_address_long); DEF_INST(store_using_real_address_long); DEF_INST(test_addressing_mode); DEF_INST(set_addressing_mode_24); DEF_INST(set_addressing_mode_31); DEF_INST(set_addressing_mode_64); DEF_INST(load_program_status_word_extended); DEF_INST(store_long); DEF_INST(store_real_address); DEF_INST(load_long); DEF_INST(multiply_single_long_register); DEF_INST(multiply_single_long_fullword_register); DEF_INST(multiply_single_long); DEF_INST(multiply_single_long_fullword); DEF_INST(rotate_left_single_logical_long); DEF_INST(rotate_left_single_logical); DEF_INST(shift_right_single_long); DEF_INST(shift_left_single_long); DEF_INST(shift_right_single_logical_long); DEF_INST(shift_left_single_logical_long); DEF_INST(compare_logical_long); DEF_INST(compare_logical_long_fullword); DEF_INST(compare_logical_long_fullword_register); DEF_INST(load_logical_long_thirtyone_register); DEF_INST(compare_logical_long_register); DEF_INST(test_under_mask_high_high); DEF_INST(test_under_mask_high_low); DEF_INST(branch_relative_on_count_long); DEF_INST(load_positive_long_register); DEF_INST(load_negative_long_register); DEF_INST(load_and_test_long_register); DEF_INST(load_complement_long_register); DEF_INST(load_real_address_long); DEF_INST(load_long_fullword_register); DEF_INST(add_long_register); DEF_INST(add_long_fullword_register); DEF_INST(subtract_long_register); DEF_INST(subtract_long_fullword_register); DEF_INST(add_logical_long); DEF_INST(add_logical_long_fullword); DEF_INST(add_long); DEF_INST(add_long_fullword); DEF_INST(subtract_logical_long); DEF_INST(subtract_logical_long_fullword); DEF_INST(subtract_long); DEF_INST(subtract_long_fullword); DEF_INST(compare_long_register); DEF_INST(compare_long); DEF_INST(branch_on_count_long_register); DEF_INST(branch_on_count_long); DEF_INST(compare_and_swap_long); DEF_INST(compare_double_and_swap_long); DEF_INST(branch_on_index_high_long); DEF_INST(branch_on_index_low_or_equal_long); DEF_INST(branch_relative_on_index_high_long); DEF_INST(branch_relative_on_index_low_or_equal_long); DEF_INST(compare_logical_characters_under_mask_high); DEF_INST(store_characters_under_mask_high); DEF_INST(insert_characters_under_mask_high); DEF_INST(branch_relative_on_condition_long); DEF_INST(branch_relative_and_save_long); DEF_INST(compare_long_fullword_register); DEF_INST(load_positive_long_fullword_register); DEF_INST(load_negative_long_fullword_register); DEF_INST(load_and_test_long_fullword_register); DEF_INST(load_complement_long_fullword_register); DEF_INST(load_long_fullword); DEF_INST(load_long_halfword); DEF_INST(compare_long_fullword); DEF_INST(load_logical_long_fullword_register); DEF_INST(load_logical_long_fullword); DEF_INST(load_logical_long_thirtyone); DEF_INST(insert_immediate_high_high); DEF_INST(insert_immediate_high_low); DEF_INST(insert_immediate_low_high); DEF_INST(insert_immediate_low_low); DEF_INST(and_immediate_high_high); DEF_INST(and_immediate_high_low); DEF_INST(and_immediate_low_high); DEF_INST(and_immediate_low_low); DEF_INST(or_immediate_high_high); DEF_INST(or_immediate_high_low); DEF_INST(or_immediate_low_high); DEF_INST(or_immediate_low_low); DEF_INST(load_logical_immediate_high_high); DEF_INST(load_logical_immediate_high_low); DEF_INST(load_logical_immediate_low_high); DEF_INST(load_logical_immediate_low_low); DEF_INST(load_reversed_long_register); DEF_INST(load_reversed_register); DEF_INST(load_reversed_long); DEF_INST(load_reversed); DEF_INST(load_reversed_half); DEF_INST(store_reversed_long); DEF_INST(store_reversed); DEF_INST(store_reversed_half); DEF_INST(pack_ascii); DEF_INST(pack_unicode); DEF_INST(unpack_ascii); DEF_INST(unpack_unicode); DEF_INST(translate_two_to_two); DEF_INST(translate_two_to_one); DEF_INST(translate_one_to_two); DEF_INST(translate_one_to_one); DEF_INST(move_long_unicode); DEF_INST(compare_logical_long_unicode); DEF_INST(add_y); DEF_INST(add_halfword_y); DEF_INST(add_logical_y); DEF_INST(and_immediate_y); DEF_INST(and_y); DEF_INST(compare_y); DEF_INST(compare_and_swap_y); DEF_INST(compare_double_and_swap_y); DEF_INST(compare_halfword_y); DEF_INST(compare_logical_y); DEF_INST(compare_logical_immediate_y); DEF_INST(compare_logical_characters_under_mask_y); DEF_INST(convert_to_binary_y); DEF_INST(convert_to_decimal_y); DEF_INST(exclusive_or_immediate_y); DEF_INST(exclusive_or_y); DEF_INST(insert_character_y); DEF_INST(insert_characters_under_mask_y); DEF_INST(load_y); DEF_INST(load_access_multiple_y); DEF_INST(load_address_y); DEF_INST(load_byte); DEF_INST(load_byte_long); DEF_INST(load_halfword_y); DEF_INST(load_multiple_y); DEF_INST(load_real_address_y); DEF_INST(move_immediate_y); DEF_INST(multiply_single_y); DEF_INST(or_immediate_y); DEF_INST(or_y); DEF_INST(store_y); DEF_INST(store_access_multiple_y); DEF_INST(store_character_y); DEF_INST(store_characters_under_mask_y); DEF_INST(store_halfword_y); DEF_INST(store_multiple_y); DEF_INST(subtract_y); DEF_INST(subtract_halfword_y); DEF_INST(subtract_logical_y); DEF_INST(test_under_mask_y); DEF_INST(compare_and_swap_and_purge_long); DEF_INST(invalidate_dat_table_entry); DEF_INST(compare_and_replace_dat_table_entry); /*912*/ DEF_INST(load_page_table_entry_address); /*@Z9*/ DEF_INST(add_fullword_immediate); /*@Z9*/ DEF_INST(add_long_fullword_immediate); /*@Z9*/ DEF_INST(add_logical_fullword_immediate); /*@Z9*/ DEF_INST(add_logical_long_fullword_immediate); /*@Z9*/ DEF_INST(and_immediate_high_fullword); /*@Z9*/ DEF_INST(and_immediate_low_fullword); /*@Z9*/ DEF_INST(compare_fullword_immediate); /*@Z9*/ DEF_INST(compare_long_fullword_immediate); /*@Z9*/ DEF_INST(compare_logical_fullword_immediate); /*@Z9*/ DEF_INST(compare_logical_long_fullword_immediate); /*@Z9*/ DEF_INST(exclusive_or_immediate_high_fullword); /*@Z9*/ DEF_INST(exclusive_or_immediate_low_fullword); /*@Z9*/ DEF_INST(insert_immediate_high_fullword); /*@Z9*/ DEF_INST(insert_immediate_low_fullword); /*@Z9*/ DEF_INST(load_long_fullword_immediate); /*@Z9*/ DEF_INST(load_logical_immediate_high_fullword); /*@Z9*/ DEF_INST(load_logical_immediate_low_fullword); /*@Z9*/ DEF_INST(or_immediate_high_fullword); /*@Z9*/ DEF_INST(or_immediate_low_fullword); /*@Z9*/ DEF_INST(subtract_logical_fullword_immediate); /*@Z9*/ DEF_INST(subtract_logical_long_fullword_immediate); /*@Z9*/ DEF_INST(load_and_test); /*@Z9*/ DEF_INST(load_and_test_long); /*@Z9*/ DEF_INST(load_byte_register); /*@Z9*/ DEF_INST(load_long_byte_register); /*@Z9*/ DEF_INST(load_halfword_register); /*@Z9*/ DEF_INST(load_long_halfword_register); /*@Z9*/ DEF_INST(load_logical_character); /*@Z9*/ DEF_INST(load_logical_character_register); /*@Z9*/ DEF_INST(load_logical_long_character_register); /*@Z9*/ DEF_INST(load_logical_halfword); /*@Z9*/ DEF_INST(load_logical_halfword_register); /*@Z9*/ DEF_INST(load_logical_long_halfword_register); /*@Z9*/ DEF_INST(find_leftmost_one_long_register); /*@Z9*/ DEF_INST(extract_cpu_time); DEF_INST(load_program_parameter); /*810*/ /* Instructions in ecpsvm.c */ DEF_INST(ecpsvm_basic_freex); DEF_INST(ecpsvm_basic_fretx); DEF_INST(ecpsvm_lock_page); DEF_INST(ecpsvm_unlock_page); DEF_INST(ecpsvm_decode_next_ccw); DEF_INST(ecpsvm_free_ccwstor); DEF_INST(ecpsvm_locate_vblock); DEF_INST(ecpsvm_disp1); DEF_INST(ecpsvm_tpage); DEF_INST(ecpsvm_tpage_lock); DEF_INST(ecpsvm_inval_segtab); DEF_INST(ecpsvm_inval_ptable); DEF_INST(ecpsvm_decode_first_ccw); DEF_INST(ecpsvm_dispatch_main); DEF_INST(ecpsvm_locate_rblock); DEF_INST(ecpsvm_comm_ccwproc); DEF_INST(ecpsvm_unxlate_ccw); DEF_INST(ecpsvm_disp2); DEF_INST(ecpsvm_store_level); DEF_INST(ecpsvm_loc_chgshrpg); DEF_INST(ecpsvm_extended_freex); DEF_INST(ecpsvm_extended_fretx); DEF_INST(ecpsvm_prefmach_assist); /* Instructions in ieee.c */ DEF_INST(convert_bfp_long_to_float_long_reg); DEF_INST(convert_bfp_short_to_float_long_reg); DEF_INST(convert_float_long_to_bfp_long_reg); DEF_INST(convert_float_long_to_bfp_short_reg); DEF_INST(add_bfp_ext_reg); DEF_INST(add_bfp_long_reg); DEF_INST(add_bfp_long); DEF_INST(add_bfp_short_reg); DEF_INST(add_bfp_short); DEF_INST(compare_bfp_ext_reg); DEF_INST(compare_bfp_long_reg); DEF_INST(compare_bfp_long); DEF_INST(compare_bfp_short_reg); DEF_INST(compare_bfp_short); DEF_INST(compare_and_signal_bfp_ext_reg); DEF_INST(compare_and_signal_bfp_long_reg); DEF_INST(compare_and_signal_bfp_long); DEF_INST(compare_and_signal_bfp_short_reg); DEF_INST(compare_and_signal_bfp_short); DEF_INST(convert_fix32_to_bfp_ext_reg); DEF_INST(convert_fix32_to_bfp_long_reg); DEF_INST(convert_fix32_to_bfp_short_reg); DEF_INST(convert_u32_to_bfp_ext_reg); /*810*/ DEF_INST(convert_u32_to_bfp_long_reg); /*810*/ DEF_INST(convert_u32_to_bfp_short_reg); /*810*/ DEF_INST(convert_fix64_to_bfp_ext_reg); DEF_INST(convert_fix64_to_bfp_long_reg); DEF_INST(convert_fix64_to_bfp_short_reg); DEF_INST(convert_u64_to_bfp_ext_reg); /*810*/ DEF_INST(convert_u64_to_bfp_long_reg); /*810*/ DEF_INST(convert_u64_to_bfp_short_reg); /*810*/ DEF_INST(convert_bfp_ext_to_fix32_reg); DEF_INST(convert_bfp_long_to_fix32_reg); DEF_INST(convert_bfp_short_to_fix32_reg); DEF_INST(convert_bfp_ext_to_u32_reg); /*810*/ DEF_INST(convert_bfp_long_to_u32_reg); /*810*/ DEF_INST(convert_bfp_short_to_u32_reg); /*810*/ DEF_INST(convert_bfp_ext_to_fix64_reg); DEF_INST(convert_bfp_long_to_fix64_reg); DEF_INST(convert_bfp_short_to_fix64_reg); DEF_INST(convert_bfp_ext_to_u64_reg); /*810*/ DEF_INST(convert_bfp_long_to_u64_reg); /*810*/ DEF_INST(convert_bfp_short_to_u64_reg); /*810*/ DEF_INST(divide_bfp_ext_reg); DEF_INST(divide_bfp_long_reg); DEF_INST(divide_bfp_long); DEF_INST(divide_bfp_short_reg); DEF_INST(divide_bfp_short); DEF_INST(divide_integer_bfp_long_reg); DEF_INST(divide_integer_bfp_short_reg); DEF_INST(load_and_test_bfp_ext_reg); DEF_INST(load_and_test_bfp_long_reg); DEF_INST(load_and_test_bfp_short_reg); DEF_INST(load_fp_int_bfp_ext_reg); DEF_INST(load_fp_int_bfp_long_reg); DEF_INST(load_fp_int_bfp_short_reg); DEF_INST(load_lengthened_bfp_short_to_long_reg); DEF_INST(load_lengthened_bfp_short_to_long); DEF_INST(load_lengthened_bfp_long_to_ext_reg); DEF_INST(load_lengthened_bfp_long_to_ext); DEF_INST(load_lengthened_bfp_short_to_ext_reg); DEF_INST(load_lengthened_bfp_short_to_ext); DEF_INST(load_negative_bfp_ext_reg); DEF_INST(load_negative_bfp_long_reg); DEF_INST(load_negative_bfp_short_reg); DEF_INST(load_complement_bfp_ext_reg); DEF_INST(load_complement_bfp_long_reg); DEF_INST(load_complement_bfp_short_reg); DEF_INST(load_positive_bfp_ext_reg); DEF_INST(load_positive_bfp_long_reg); DEF_INST(load_positive_bfp_short_reg); DEF_INST(load_rounded_bfp_long_to_short_reg); DEF_INST(load_rounded_bfp_ext_to_long_reg); DEF_INST(load_rounded_bfp_ext_to_short_reg); DEF_INST(multiply_bfp_ext_reg); DEF_INST(multiply_bfp_long_to_ext_reg); DEF_INST(multiply_bfp_long_to_ext); DEF_INST(multiply_bfp_long_reg); DEF_INST(multiply_bfp_long); DEF_INST(multiply_bfp_short_to_long_reg); DEF_INST(multiply_bfp_short_to_long); DEF_INST(multiply_bfp_short_reg); DEF_INST(multiply_bfp_short); DEF_INST(multiply_add_bfp_long_reg); DEF_INST(multiply_add_bfp_long); DEF_INST(multiply_add_bfp_short_reg); DEF_INST(multiply_add_bfp_short); DEF_INST(multiply_subtract_bfp_long_reg); DEF_INST(multiply_subtract_bfp_long); DEF_INST(multiply_subtract_bfp_short_reg); DEF_INST(multiply_subtract_bfp_short); DEF_INST(squareroot_bfp_ext_reg); DEF_INST(squareroot_bfp_long_reg); DEF_INST(squareroot_bfp_long); DEF_INST(squareroot_bfp_short_reg); DEF_INST(squareroot_bfp_short); DEF_INST(subtract_bfp_ext_reg); DEF_INST(subtract_bfp_long_reg); DEF_INST(subtract_bfp_long); DEF_INST(subtract_bfp_short_reg); DEF_INST(subtract_bfp_short); DEF_INST(test_data_class_bfp_short); DEF_INST(test_data_class_bfp_long); DEF_INST(test_data_class_bfp_ext); /* Instructions in dfp.c */ DEF_INST(copy_sign_fpr_long_reg); DEF_INST(load_complement_fpr_long_reg); DEF_INST(load_fpr_from_gr_long_reg); DEF_INST(load_gr_from_fpr_long_reg); DEF_INST(load_negative_fpr_long_reg); DEF_INST(load_positive_fpr_long_reg); DEF_INST(set_dfp_rounding_mode); DEF_INST(load_fpc_and_signal); DEF_INST(set_fpc_and_signal); DEF_INST(add_dfp_ext_reg); DEF_INST(add_dfp_long_reg); DEF_INST(compare_dfp_ext_reg); DEF_INST(compare_dfp_long_reg); DEF_INST(compare_and_signal_dfp_ext_reg); DEF_INST(compare_and_signal_dfp_long_reg); DEF_INST(compare_exponent_dfp_ext_reg); DEF_INST(compare_exponent_dfp_long_reg); DEF_INST(convert_fix32_to_dfp_ext_reg); /*810*/ DEF_INST(convert_fix32_to_dfp_long_reg); /*810*/ DEF_INST(convert_u32_to_dfp_ext_reg); /*810*/ DEF_INST(convert_u32_to_dfp_long_reg); /*810*/ DEF_INST(convert_fix64_to_dfp_ext_reg); DEF_INST(convert_fix64_to_dfp_long_reg); DEF_INST(convert_u64_to_dfp_ext_reg); /*810*/ DEF_INST(convert_u64_to_dfp_long_reg); /*810*/ DEF_INST(convert_sbcd128_to_dfp_ext_reg); DEF_INST(convert_sbcd64_to_dfp_long_reg); DEF_INST(convert_ubcd128_to_dfp_ext_reg); DEF_INST(convert_ubcd64_to_dfp_long_reg); DEF_INST(convert_zoned_to_dfp_ext); /*912*/ DEF_INST(convert_zoned_to_dfp_long); /*912*/ DEF_INST(convert_dfp_ext_to_fix32_reg); /*810*/ DEF_INST(convert_dfp_long_to_fix32_reg); /*810*/ DEF_INST(convert_dfp_ext_to_u32_reg); /*810*/ DEF_INST(convert_dfp_long_to_u32_reg); /*810*/ DEF_INST(convert_dfp_ext_to_fix64_reg); DEF_INST(convert_dfp_long_to_fix64_reg); DEF_INST(convert_dfp_ext_to_u64_reg); /*810*/ DEF_INST(convert_dfp_long_to_u64_reg); /*810*/ DEF_INST(convert_dfp_ext_to_sbcd128_reg); DEF_INST(convert_dfp_long_to_sbcd64_reg); DEF_INST(convert_dfp_ext_to_ubcd128_reg); DEF_INST(convert_dfp_long_to_ubcd64_reg); DEF_INST(convert_dfp_ext_to_zoned); /*912*/ DEF_INST(convert_dfp_long_to_zoned); /*912*/ DEF_INST(divide_dfp_ext_reg); DEF_INST(divide_dfp_long_reg); DEF_INST(extract_biased_exponent_dfp_ext_to_fix64_reg); DEF_INST(extract_biased_exponent_dfp_long_to_fix64_reg); DEF_INST(extract_significance_dfp_ext_reg); DEF_INST(extract_significance_dfp_long_reg); DEF_INST(insert_biased_exponent_fix64_to_dfp_ext_reg); DEF_INST(insert_biased_exponent_fix64_to_dfp_long_reg); DEF_INST(load_and_test_dfp_ext_reg); DEF_INST(load_and_test_dfp_long_reg); DEF_INST(load_fp_int_dfp_ext_reg); DEF_INST(load_fp_int_dfp_long_reg); DEF_INST(load_lengthened_dfp_long_to_ext_reg); DEF_INST(load_lengthened_dfp_short_to_long_reg); DEF_INST(load_rounded_dfp_ext_to_long_reg); DEF_INST(load_rounded_dfp_long_to_short_reg); DEF_INST(multiply_dfp_ext_reg); DEF_INST(multiply_dfp_long_reg); DEF_INST(quantize_dfp_ext_reg); DEF_INST(quantize_dfp_long_reg); DEF_INST(reround_dfp_ext_reg); DEF_INST(reround_dfp_long_reg); DEF_INST(shift_coefficient_left_dfp_ext); DEF_INST(shift_coefficient_left_dfp_long); DEF_INST(shift_coefficient_right_dfp_ext); DEF_INST(shift_coefficient_right_dfp_long); DEF_INST(subtract_dfp_ext_reg); DEF_INST(subtract_dfp_long_reg); DEF_INST(test_data_class_dfp_ext); DEF_INST(test_data_class_dfp_long); DEF_INST(test_data_class_dfp_short); DEF_INST(test_data_group_dfp_ext); DEF_INST(test_data_group_dfp_long); DEF_INST(test_data_group_dfp_short); /* Instructions in pfpo.c */ DEF_INST(perform_floating_point_operation); /* Instructions in transact.c */ DEF_INST(perform_processor_assist); /*912*/ DEF_INST(extract_transaction_nesting_depth); /*912*/ DEF_INST(nontransactional_store_long); /*912*/ DEF_INST(transaction_abort); /*912*/ DEF_INST(transaction_begin); /*912*/ DEF_INST(transaction_begin_constrained); /*912*/ DEF_INST(transaction_end); /*912*/ /* end of OPCODE.H */ hercules-3.12/clock.h0000664000175000017500000001016712564723224011454 00000000000000/* CLOCK.H (c) Copyright Jan Jaeger, 2000-2009 */ /* TOD Clock functions */ #if !defined(_CLOCK_C_) #define _CLOCK_EXTERN extern #else #undef _CLOCK_EXTERN #define _CLOCK_EXTERN #endif #if !defined(_CLOCK_H_) #define _CLOCK_H_ /* Clock Steering Registers */ typedef struct _CSR { U64 start_time; S64 base_offset; S32 fine_s_rate; S32 gross_s_rate; } CSR; void csr_reset(void); /* Reset cs registers */ void set_tod_steering(double); /* Set steering rate */ double get_tod_steering(void); /* Get steering rate */ U64 update_tod_clock(void); /* Update the TOD clock */ void update_cpu_timer(void); /* Update the CPU timer */ void set_tod_epoch(S64); /* Set TOD epoch */ void adjust_tod_epoch(S64); /* Adjust TOD epoch */ S64 get_tod_epoch(void); /* Get TOD epoch */ U64 hw_clock(void); /* Get hardware clock */ S64 cpu_timer(REGS *); /* Retrieve CPU timer */ void set_cpu_timer(REGS *, S64); /* Set CPU timer */ S32 int_timer(REGS *); /* Get interval timer */ void set_int_timer(REGS *, S32); /* Set interval timer */ U64 tod_clock(REGS *); /* Get TOD clock */ void set_tod_clock(U64); /* Set TOD clock */ int chk_int_timer(REGS *); /* Check int_timer pending */ int clock_hsuspend(void *file); /* Hercules suspend */ int clock_hresume(void *file); /* Hercules resume */ static __inline__ U64 host_tod(void) { struct timeval tv; gettimeofday (&tv, NULL); return (U64)tv.tv_sec*1000000 + tv.tv_usec; } #endif DLL_EXPORT void ARCH_DEP(store_int_timer) (REGS *); void ARCH_DEP(store_int_timer_nolock) (REGS *); DLL_EXPORT void ARCH_DEP(fetch_int_timer) (REGS *); void ARCH_DEP(set_gross_s_rate) (REGS *); void ARCH_DEP(set_fine_s_rate) (REGS *); void ARCH_DEP(set_tod_offset) (REGS *); void ARCH_DEP(adjust_tod_offset) (REGS *); void ARCH_DEP(query_physical_clock) (REGS *); void ARCH_DEP(query_steering_information) (REGS *); void ARCH_DEP(query_tod_offset) (REGS *); void ARCH_DEP(query_available_functions) (REGS *); _CLOCK_EXTERN U64 tod_value; /* Bits 0-7 TOD clock epoch */ /* Bits b-63 TOD bits 0-55 */ _CLOCK_EXTERN S64 tod_epoch; /* Bits 0-7 TOD clock epoch */ /* Bits 8-63 offset bits 0-55*/ _CLOCK_EXTERN U64 hw_tod; /* Hardware clock */ #define SECONDS_IN_SEVENTY_YEARS ((70*365 + 17) * 86400ULL) #define TOD_4YEARS (1461*24*60*60*16000000LL) #define TOD_LYEAR (366*24*60*60*16000000LL) #define TOD_YEAR (365*24*60*60*16000000LL) #define TOD_DAY (24*60*60*16000000LL) #define TOD_HOUR (60*60*16000000LL) #define TOD_MIN (60*16000000LL) #define TOD_SEC (16000000LL) #define TOD_USEC (16LL) #define ITIMER_TO_TOD(_units) \ ((S64)(625*((S64)(_units))/3)) #define TOD_TO_ITIMER(_units) \ ((S32)(3*(_units)/625)) #define TOD_CLOCK(_regs) \ (tod_value + (_regs)->tod_epoch) #define CPU_TIMER(_regs) \ ((S64)((_regs)->cpu_timer - hw_tod)) #define INT_TIMER(_regs) \ ((S32)TOD_TO_ITIMER((S64)((_regs)->int_timer - hw_tod))) #define ITIMER_ACCESS(_addr, _len) \ (unlikely(unlikely((_addr) < 84) && (((_addr) + (_len)) >= 80))) #undef ITIMER_UPDATE #undef ITIMER_SYNC #if defined(FEATURE_INTERVAL_TIMER) #define ITIMER_UPDATE(_addr, _len, _regs) \ do { \ if( ITIMER_ACCESS((_addr), (_len)) ) \ ARCH_DEP(fetch_int_timer) ((_regs)); \ } while(0) #define ITIMER_SYNC(_addr, _len, _regs) \ do { \ if( ITIMER_ACCESS((_addr), (_len)) ) \ ARCH_DEP(store_int_timer) ((_regs)); \ } while (0) #else #define ITIMER_UPDATE(_addr, _len, _regs) #define ITIMER_SYNC(_addr, _len, _regs) #endif hercules-3.12/hercules.h0000664000175000017500000001015412564723224012167 00000000000000/* HERCULES.H (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Header Files */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #ifdef HAVE_CONFIG_H #include // Hercules build configuration options/settings #endif /*-------------------------------------------------------------------*/ /* Performance attribute: use registers to pass function parameters */ /* (must be #defined BEFORE "feature,h" since it uses it) */ /*-------------------------------------------------------------------*/ #if defined(HAVE_ATTR_REGPARM) #ifdef _MSVC_ #define ATTR_REGPARM(n) __fastcall #else /* GCC presumed */ #define ATTR_REGPARM(n) __attribute__ (( regparm(n) )) #endif #else #define ATTR_REGPARM(n) /* nothing */ #endif // ------------------------------------------------------------------- // // PROGRAMMING NOTE // // The "feature.h" header MUST be #included AFTER *AND* // BEFORE the _HERCULES_H pre-processor variable gets #defined. This // is to enure that it is ALWAYS #included regardless of whether the // "hercules.h" header has already been #included or not. This is so // the various architecture dependent source modules compile properly // since they #include themselves several times so as to cause them // to be compiled multiple times, each time with a new architecture // mode #defined (e.g. 370/390/900). See the very end of the source // member "general2.c" for a typical example of this very technique. // // ------------------------------------------------------------------- // // // Include standard system headers (if not already done) // #include "feature.h" // Hercules [manually maintained] features; // auto-includes featall.h and hostopts.h // ALWAYS include cpuint.h after feature.h // and also assure it is re-included for // each archs. #include "cpuint.h" #ifndef _HERCULES_H // MUST come AFTER "feature.h" is #included #define _HERCULES_H // MUST come AFTER "feature.h" is #included #include "hstdinc.h" // Precompilation-eligible header files #ifdef _MSVC_ #include "getopt.h" #else #if defined(HAVE_GETOPT_LONG) && !defined(__GETOPT_H__) #include #endif #endif #ifdef OPTION_DYNAMIC_LOAD #ifdef HDL_USE_LIBTOOL #include #else #if defined(__MINGW__) || defined(_MSVC_) #include "w32dl.h" #else #include #endif #endif #endif /////////////////////////////////////////////////////////////////////// // Private Hercules-specific headers..... /////////////////////////////////////////////////////////////////////// #include "linklist.h" // (Hercules-wide linked-list macros) #include "hconsts.h" // (Hercules-wide #define constants) #include "hthreads.h" // (Hercules-wide threading macros) #include "hmacros.h" // (Hercules-wide #define macros) #if !defined(HAVE_BYTESWAP_H) || defined(NO_ASM_BYTESWAP) #include "hbyteswp.h" // (Hercules equivalent of ) #endif #if !defined(HAVE_MEMRCHR) #include "memrchr.h" #endif #if defined(HAVE_ASSERT_H) #include #endif #include "hostinfo.h" #include "version.h" #include "esa390.h" // (ESA/390 structure definitions) #include "hscutl.h" // (utility functions) #include "w32util.h" // (win32 porting functions) #include "clock.h" // (TOD definitions) #include "codepage.h" #include "logger.h" // (logmsg, etc) #include "hdl.h" // (Hercules Dynamic Loader) #include "cache.h" #include "devtype.h" #include "dasdtab.h" #include "shared.h" #include "hetlib.h" #include "sockdev.h" #include "w32ctca.h" #include "service.h" #include "hsocket.h" #ifdef _MSVC_ #include "w32mtio.h" // 'mtio.h' needed by hstructs.h #endif // _MSVC_ #include "hstructs.h" // (Hercules-wide structures) #include "hexterns.h" // (Hercules-wide extern function prototypes) #endif // _HERCULES_H hercules-3.12/inline.h0000664000175000017500000007532412564723224011645 00000000000000/* INLINE.H (c) Copyright Jan Jaeger, 2000-2009 */ /* Inline function definitions */ /* Original author Roger Bowler, 1999 */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /* Storage protection override fix Jan Jaeger 31/08/00 */ /* ESAME low-address protection v208d Roger Bowler 20/01/01 */ /* ESAME subspace replacement v208e Roger Bowler 27/01/01 */ /* Multiply/Divide Logical instructions Vic Cross 13/02/2001 */ // #define INLINE_STORE_FETCH_ADDR_CHECK #if defined(FEATURE_DUAL_ADDRESS_SPACE) _DAT_C_STATIC U16 ARCH_DEP(translate_asn) (U16 asn, REGS *regs, U32 *asteo, U32 aste[]); _DAT_C_STATIC int ARCH_DEP(authorize_asn) (U16 ax, U32 aste[], int atemask, REGS *regs); #endif #if defined(FEATURE_ACCESS_REGISTERS) _DAT_C_STATIC U16 ARCH_DEP(translate_alet) (U32 alet, U16 eax, int acctype, REGS *regs, U32 *asteo, U32 aste[]); _DAT_C_STATIC void ARCH_DEP(purge_alb_all) (); _DAT_C_STATIC void ARCH_DEP(purge_alb) (REGS *regs); #endif _DAT_C_STATIC int ARCH_DEP(translate_addr) (VADR vaddr, int arn, REGS *regs, int acctype); _DAT_C_STATIC void ARCH_DEP(purge_tlb_all) (); _DAT_C_STATIC void ARCH_DEP(purge_tlb) (REGS *regs); _DAT_C_STATIC void ARCH_DEP(purge_tlbe_all) (RADR pfra); _DAT_C_STATIC void ARCH_DEP(purge_tlbe) (REGS *regs, RADR pfra); _DAT_C_STATIC void ARCH_DEP(invalidate_tlb) (REGS *regs, BYTE mask); #if ARCH_MODE == ARCH_390 && defined(_900) _DAT_C_STATIC void z900_invalidate_tlb (REGS *regs, BYTE mask); #endif _DAT_C_STATIC void ARCH_DEP(invalidate_tlbe) (REGS *regs, BYTE *main); _DAT_C_STATIC void ARCH_DEP(invalidate_pte) (BYTE ibyte, RADR op1, U32 op2, REGS *regs); _LOGICAL_C_STATIC BYTE *ARCH_DEP(logical_to_main) (VADR addr, int arn, REGS *regs, int acctype, BYTE akey); #if defined(_FEATURE_SIE) && ARCH_MODE != ARCH_900 _LOGICAL_C_STATIC BYTE *s390_logical_to_main (U32 addr, int arn, REGS *regs, int acctype, BYTE akey); _DAT_C_STATIC int s390_translate_addr (U32 vaddr, int arn, REGS *regs, int acctype); #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_ZSIE) _LOGICAL_C_STATIC BYTE *z900_logical_to_main (U64 addr, int arn, REGS *regs, int acctype, BYTE akey); _DAT_C_STATIC int z900_translate_addr (U64 vaddr, int arn, REGS *regs, int acctype); #endif /*defined(_FEATURE_ZSIE)*/ _VSTORE_C_STATIC void ARCH_DEP(vstorec) (void *src, BYTE len, VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC void ARCH_DEP(vstoreb) (BYTE value, VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC void ARCH_DEP(vstore2) (U16 value, VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC void ARCH_DEP(vstore4) (U32 value, VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC void ARCH_DEP(vstore8) (U64 value, VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC void ARCH_DEP(vfetchc) (void *dest, BYTE len, VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC BYTE ARCH_DEP(vfetchb) (VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC U16 ARCH_DEP(vfetch2) (VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC U32 ARCH_DEP(vfetch4) (VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC U64 ARCH_DEP(vfetch8) (VADR addr, int arn, REGS *regs); _VSTORE_C_STATIC void ARCH_DEP(move_chars) (VADR addr1, int arn1, BYTE key1, VADR addr2, int arn2, BYTE key2, int len, REGS *regs); _VSTORE_C_STATIC void ARCH_DEP(validate_operand) (VADR addr, int arn, int len, int acctype, REGS *regs); _VFETCH_C_STATIC BYTE * ARCH_DEP(instfetch) (REGS *regs, int exec); #if defined(_FEATURE_SIE) && defined(_370) && !defined(_IEEE_C_) _VFETCH_C_STATIC BYTE * s370_instfetch (REGS *regs, int exec); #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_ZSIE) && defined(_900) _VFETCH_C_STATIC BYTE * s390_instfetch (REGS *regs, int exec); #endif /*defined(_FEATURE_ZSIE)*/ #if !defined(_INLINE_H) #define _INLINE_H /*-------------------------------------------------------------------*/ /* Add two unsigned fullwords giving an unsigned fullword result */ /* and return the condition code for the AL or ALR instruction */ /*-------------------------------------------------------------------*/ static inline int add_logical(U32 *result, U32 op1, U32 op2) { *result = op1 + op2; return (*result == 0 ? 0 : 1) | (op1 > *result ? 2 : 0); } /* end function add_logical */ /*-------------------------------------------------------------------*/ /* Subtract two unsigned fullwords giving unsigned fullword result */ /* and return the condition code for the SL or SLR instruction */ /*-------------------------------------------------------------------*/ static inline int sub_logical(U32 *result, U32 op1, U32 op2) { *result = op1 - op2; return (*result == 0 ? 0 : 1) | (op1 < *result ? 0 : 2); } /* end function sub_logical */ /*-------------------------------------------------------------------*/ /* Add two signed fullwords giving a signed fullword result */ /* and return the condition code for the A or AR instruction */ /*-------------------------------------------------------------------*/ static inline int add_signed(U32 *result, U32 op1, U32 op2) { *result = (S32)op1 + (S32)op2; return ((S32)*result > 0) ? ((S32)op1 < 0 && (S32)op2 < 0) ? 3 : 2 : ((S32)*result < 0) ? ((S32)op1 >= 0 && (S32)op2 >= 0) ? 3 : 1 : ((S32)op1 < 0 && (S32)op2 < 0) ? 3 : 0; /* return (((S32)op1 < 0 && (S32)op2 < 0 && (S32)*result >= 0) || ((S32)op1 >= 0 && (S32)op2 >= 0 && (S32)*result < 0)) ? 3 : (S32)*result < 0 ? 1 : (S32)*result > 0 ? 2 : 0; */ } /* end function add_signed */ /*-------------------------------------------------------------------*/ /* Subtract two signed fullwords giving a signed fullword result */ /* and return the condition code for the S or SR instruction */ /*-------------------------------------------------------------------*/ static inline int sub_signed(U32 *result, U32 op1, U32 op2) { *result = (S32)op1 - (S32)op2; return ((S32)*result > 0) ? ((S32)op1 < 0 && (S32)op2 >= 0) ? 3 : 2 : ((S32)*result < 0) ? ((S32)op1 >= 0 && (S32)op2 < 0) ? 3 : 1 : ((S32)op1 < 0 && (S32)op2 >= 0) ? 3 : 0; /* return (((S32)op1 < 0 && (S32)op2 >= 0 && (S32)*result >= 0) || ((S32)op1 >= 0 && (S32)op2 < 0 && (S32)*result < 0)) ? 3 : (S32)*result < 0 ? 1 : (S32)*result > 0 ? 2 : 0; */ } /* end function sub_signed */ /*-------------------------------------------------------------------*/ /* Multiply two signed fullwords giving a signed doubleword result */ /*-------------------------------------------------------------------*/ static inline void mul_signed ( U32 *resulthi, U32 *resultlo, U32 op1, U32 op2 ) { S64 r; r = (S64)(S32)op1 * (S32)op2; *resulthi = (U32)((U64)r >> 32); *resultlo = (U32)((U64)r & 0xFFFFFFFF); } /* end function mul_signed */ /*-------------------------------------------------------------------*/ /* Divide a signed doubleword dividend by a signed fullword divisor */ /* giving a signed fullword remainder and a signed fullword quotient.*/ /* Returns 0 if successful, 1 if divide overflow. */ /*-------------------------------------------------------------------*/ static inline int div_signed ( U32 *remainder, U32 *quotient, U32 dividendhi, U32 dividendlo, U32 divisor ) { U64 dividend; S64 quot, rem; if (divisor == 0) return 1; dividend = (U64)dividendhi << 32 | dividendlo; quot = (S64)dividend / (S32)divisor; rem = (S64)dividend % (S32)divisor; if (quot < -2147483648LL || quot > 2147483647LL) return 1; *quotient = (U32)quot; *remainder = (U32)rem; return 0; } /* end function div_signed */ /* * The following routines were moved from esame.c rev 1.139 21oct2005 */ /*-------------------------------------------------------------------*/ /* Add two unsigned doublewords giving an unsigned doubleword result */ /* and return the condition code for the ALG or ALGR instruction */ /*-------------------------------------------------------------------*/ static inline int add_logical_long(U64 *result, U64 op1, U64 op2) { *result = op1 + op2; return (*result == 0 ? 0 : 1) | (op1 > *result ? 2 : 0); } /* end function add_logical_long */ /*-------------------------------------------------------------------*/ /* Subtract unsigned doublewords giving unsigned doubleword result */ /* and return the condition code for the SLG or SLGR instruction */ /*-------------------------------------------------------------------*/ static inline int sub_logical_long(U64 *result, U64 op1, U64 op2) { *result = op1 - op2; return (*result == 0 ? 0 : 1) | (op1 < *result ? 0 : 2); } /* end function sub_logical_long */ /*-------------------------------------------------------------------*/ /* Add two signed doublewords giving a signed doubleword result */ /* and return the condition code for the AG or AGR instruction */ /*-------------------------------------------------------------------*/ static inline int add_signed_long(U64 *result, U64 op1, U64 op2) { *result = (S64)op1 + (S64)op2; return (((S64)op1 < 0 && (S64)op2 < 0 && (S64)*result >= 0) || ((S64)op1 >= 0 && (S64)op2 >= 0 && (S64)*result < 0)) ? 3 : (S64)*result < 0 ? 1 : (S64)*result > 0 ? 2 : 0; } /* end function add_signed_long */ /*-------------------------------------------------------------------*/ /* Subtract two signed doublewords giving signed doubleword result */ /* and return the condition code for the SG or SGR instruction */ /*-------------------------------------------------------------------*/ static inline int sub_signed_long(U64 *result, U64 op1, U64 op2) { *result = (S64)op1 - (S64)op2; return (((S64)op1 < 0 && (S64)op2 >= 0 && (S64)*result >= 0) || ((S64)op1 >= 0 && (S64)op2 < 0 && (S64)*result < 0)) ? 3 : (S64)*result < 0 ? 1 : (S64)*result > 0 ? 2 : 0; } /* end function sub_signed_long */ /*-------------------------------------------------------------------*/ /* Divide an unsigned 128-bit dividend by an unsigned 64-bit divisor */ /* giving unsigned 64-bit remainder and unsigned 64-bit quotient. */ /* Returns 0 if successful, 1 if divide overflow. */ /*-------------------------------------------------------------------*/ static inline int div_logical_long (U64 *rem, U64 *quot, U64 high, U64 lo, U64 d) { int i; *quot = 0; if (high >= d) return 1; for (i = 0; i < 64; i++) { int ovf; ovf = high >> 63; high = (high << 1) | (lo >> 63); lo <<= 1; *quot <<= 1; if (high >= d || ovf) { *quot += 1; high -= d; } } *rem = high; return 0; } /* end function div_logical_long */ /*-------------------------------------------------------------------*/ /* Multiply two unsigned doublewords giving unsigned 128-bit result */ /*-------------------------------------------------------------------*/ static inline int mult_logical_long (U64 *high, U64 *lo, U64 md, U64 mr) { int i; *high = 0; *lo = 0; for (i = 0; i < 64; i++) { U64 ovf; ovf = *high; if (md & 1) *high += mr; md >>= 1; *lo = (*lo >> 1) | (*high << 63); if(ovf > *high) *high = (*high >> 1) | 0x8000000000000000ULL; else *high >>= 1; } return 0; } /* end function mult_logical_long */ #endif /*!defined(_INLINE_H)*/ /*-------------------------------------------------------------------*/ /* Test for fetch protected storage location. */ /* */ /* Input: */ /* addr Logical address of storage location */ /* skey Storage key with fetch, reference, and change bits */ /* and one low-order zero appended */ /* akey Access key with 4 low-order zeroes appended */ /* regs Pointer to the CPU register context */ /* regs->dat.private 1=Location is in a private address space */ /* Return value: */ /* 1=Fetch protected, 0=Not fetch protected */ /*-------------------------------------------------------------------*/ static inline int ARCH_DEP(is_fetch_protected) (VADR addr, BYTE skey, BYTE akey, REGS *regs) { UNREFERENCED_370(addr); UNREFERENCED_370(regs); /* [3.4.1] Fetch is allowed if access key is zero, regardless of the storage key and fetch protection bit */ /* [3.4.1] Fetch protection prohibits fetch if storage key fetch protect bit is on and access key does not match storage key */ if (likely(akey == 0 || akey == (skey & STORKEY_KEY) || !(skey & STORKEY_FETCH))) return 0; #ifdef FEATURE_FETCH_PROTECTION_OVERRIDE /* [3.4.1.2] Fetch protection override allows fetch from first 2K of non-private address spaces if CR0 bit 6 is set */ if (addr < 2048 && (regs->CR(0) & CR0_FETCH_OVRD) && regs->dat.private == 0) return 0; #endif /*FEATURE_FETCH_PROTECTION_OVERRIDE*/ #ifdef FEATURE_STORAGE_PROTECTION_OVERRIDE /* [3.4.1.1] Storage protection override allows access to locations with storage key 9, regardless of the access key, provided that CR0 bit 7 is set */ if ((skey & STORKEY_KEY) == 0x90 && (regs->CR(0) & CR0_STORE_OVRD)) return 0; #endif /*FEATURE_STORAGE_PROTECTION_OVERRIDE*/ /* Return one if location is fetch protected */ return 1; } /* end function is_fetch_protected */ /*-------------------------------------------------------------------*/ /* Test for low-address protection. */ /* */ /* Input: */ /* addr Logical address of storage location */ /* regs Pointer to the CPU register context */ /* regs->dat.private 1=Location is in a private address space */ /* Return value: */ /* 1=Low-address protected, 0=Not low-address protected */ /*-------------------------------------------------------------------*/ static inline int ARCH_DEP(is_low_address_protected) (VADR addr, REGS *regs) { #if defined (FEATURE_ESAME) /* For ESAME, low-address protection applies to locations 0-511 (0000-01FF) and 4096-4607 (1000-11FF) */ if (addr & 0xFFFFFFFFFFFFEE00ULL) #else /*!defined(FEATURE_ESAME)*/ /* For S/370 and ESA/390, low-address protection applies to locations 0-511 only */ if (addr > 511) #endif /*!defined(FEATURE_ESAME)*/ return 0; /* Low-address protection applies only if the low-address protection control bit in control register 0 is set */ if ((regs->CR(0) & CR0_LOW_PROT) == 0) return 0; #if defined(_FEATURE_SIE) /* Host low-address protection is not applied to guest references to guest storage */ if (regs->sie_active) return 0; #endif /*defined(_FEATURE_SIE)*/ /* Low-address protection does not apply to private address spaces */ if (regs->dat.private) return 0; /* Return one if location is low-address protected */ return 1; } /* end function is_low_address_protected */ /*-------------------------------------------------------------------*/ /* Test for store protected storage location. */ /* */ /* Input: */ /* addr Logical address of storage location */ /* skey Storage key with fetch, reference, and change bits */ /* and one low-order zero appended */ /* akey Access key with 4 low-order zeroes appended */ /* regs Pointer to the CPU register context */ /* regs->dat.private 1=Location is in a private address space */ /* regs->dat.protect 1=Access list protected or page protected */ /* Return value: */ /* 1=Store protected, 0=Not store protected */ /*-------------------------------------------------------------------*/ static inline int ARCH_DEP(is_store_protected) (VADR addr, BYTE skey, BYTE akey, REGS *regs) { /* [3.4.4] Low-address protection prohibits stores into certain locations in the prefixed storage area of non-private address address spaces, if the low-address control bit in CR0 is set, regardless of the access key and storage key */ if (ARCH_DEP(is_low_address_protected) (addr, regs)) return 1; /* Access-list controlled protection prohibits all stores into the address space, and page protection prohibits all stores into the page, regardless of the access key and storage key */ if (regs->dat.protect) return 1; #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && regs->hostregs->dat.protect) return 1; #endif /* [3.4.1] Store is allowed if access key is zero, regardless of the storage key */ if (akey == 0) return 0; #ifdef FEATURE_STORAGE_PROTECTION_OVERRIDE /* [3.4.1.1] Storage protection override allows access to locations with storage key 9, regardless of the access key, provided that CR0 bit 7 is set */ if ((skey & STORKEY_KEY) == 0x90 && (regs->CR(0) & CR0_STORE_OVRD)) return 0; #endif /*FEATURE_STORAGE_PROTECTION_OVERRIDE*/ /* [3.4.1] Store protection prohibits stores if the access key does not match the storage key */ if (akey != (skey & STORKEY_KEY)) return 1; /* Return zero if location is not store protected */ return 0; } /* end function is_store_protected */ /*-------------------------------------------------------------------*/ /* Return mainstor address of absolute address. */ /* The caller is assumed to have already checked that the absolute */ /* address is within the limit of main storage. */ /*-------------------------------------------------------------------*/ #if defined(INLINE_STORE_FETCH_ADDR_CHECK) static inline BYTE *ARCH_DEP(fetch_main_absolute) (RADR addr, REGS *regs, int len) #else static inline BYTE *ARCH_DEP(fetch_main_absolute) (RADR addr, REGS *regs) #endif { #if defined(INLINE_STORE_FETCH_ADDR_CHECK) if(addr > regs->mainlim - len) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); #endif /*defined(INLINE_STORE_FETCH_ADDR_CHECK)*/ SIE_TRANSLATE(&addr, ACCTYPE_READ, regs); /* Set the main storage reference bit */ STORAGE_KEY(addr, regs) |= STORKEY_REF; /* Return absolute storage mainstor address */ return (regs->mainstor + addr); } /* end function fetch_main_absolute */ /*-------------------------------------------------------------------*/ /* Fetch a doubleword from absolute storage. */ /* The caller is assumed to have already checked that the absolute */ /* address is within the limit of main storage. */ /* All bytes of the word are fetched concurrently as observed by */ /* other CPUs. The doubleword is first fetched as an integer, then */ /* the bytes are reversed into host byte order if necessary. */ /*-------------------------------------------------------------------*/ static inline U64 ARCH_DEP(fetch_doubleword_absolute) (RADR addr, REGS *regs) { // The change below affects 32 bit hosts that use something like // cmpxchg8b to fetch the doubleword concurrently. // This routine is mainly called by DAT in 64 bit guest mode // to access DAT-related values. In most `well-behaved' OS's, // other CPUs should not be interfering with these values #if !defined(OPTION_STRICT_ALIGNMENT) return CSWAP64(*(U64 *)FETCH_MAIN_ABSOLUTE(addr, regs, 8)); #else return fetch_dw(FETCH_MAIN_ABSOLUTE(addr, regs, 8)); #endif } /* end function fetch_doubleword_absolute */ /*-------------------------------------------------------------------*/ /* Fetch a fullword from absolute storage. */ /* The caller is assumed to have already checked that the absolute */ /* address is within the limit of main storage. */ /* All bytes of the word are fetched concurrently as observed by */ /* other CPUs. The fullword is first fetched as an integer, then */ /* the bytes are reversed into host byte order if necessary. */ /*-------------------------------------------------------------------*/ static inline U32 ARCH_DEP(fetch_fullword_absolute) (RADR addr, REGS *regs) { return fetch_fw(FETCH_MAIN_ABSOLUTE(addr, regs, 4)); } /* end function fetch_fullword_absolute */ /*-------------------------------------------------------------------*/ /* Fetch a halfword from absolute storage. */ /* The caller is assumed to have already checked that the absolute */ /* address is within the limit of main storage. */ /* All bytes of the halfword are fetched concurrently as observed by */ /* other CPUs. The halfword is first fetched as an integer, then */ /* the bytes are reversed into host byte order if necessary. */ /*-------------------------------------------------------------------*/ static inline U16 ARCH_DEP(fetch_halfword_absolute) (RADR addr, REGS *regs) { return fetch_hw(FETCH_MAIN_ABSOLUTE(addr, regs, 2)); } /* end function fetch_halfword_absolute */ /*-------------------------------------------------------------------*/ /* Store doubleword into absolute storage. */ /* All bytes of the word are stored concurrently as observed by */ /* other CPUs. The bytes of the word are reversed if necessary */ /* and the word is then stored as an integer in absolute storage. */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(store_doubleword_absolute) (U64 value, RADR addr, REGS *regs) { #if defined(INLINE_STORE_FETCH_ADDR_CHECK) if(addr > regs->mainlim - 8) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); #endif /*defined(INLINE_STORE_FETCH_ADDR_CHECK)*/ SIE_TRANSLATE(&addr, ACCTYPE_WRITE, regs); /* Set the main storage reference and change bits */ STORAGE_KEY(addr, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Store the doubleword into absolute storage */ store_dw(regs->mainstor + addr, value); } /* end function store_doubleword_absolute */ /*-------------------------------------------------------------------*/ /* Store a fullword into absolute storage. */ /* All bytes of the word are stored concurrently as observed by */ /* other CPUs. The bytes of the word are reversed if necessary */ /* and the word is then stored as an integer in absolute storage. */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(store_fullword_absolute) (U32 value, RADR addr, REGS *regs) { #if defined(INLINE_STORE_FETCH_ADDR_CHECK) if(addr > regs->mainlim - 4) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); #endif /*defined(INLINE_STORE_FETCH_ADDR_CHECK)*/ SIE_TRANSLATE(&addr, ACCTYPE_WRITE, regs); /* Set the main storage reference and change bits */ STORAGE_KEY(addr, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Store the fullword into absolute storage */ store_fw(regs->mainstor + addr, value); } /* end function store_fullword_absolute */ /*-------------------------------------------------------------------*/ /* Perform subspace replacement */ /* */ /* Input: */ /* std Original segment table designation (STD) or ASCE */ /* asteo ASTE origin obtained by ASN translation */ /* xcode Pointer to field to receive exception code, or NULL */ /* regs Pointer to the CPU register context */ /* */ /* Output: */ /* xcode Exception code or zero (if xcode is not NULL) */ /* */ /* Return value: */ /* On successful completion, the exception code field (if not */ /* NULL) is set to zero, and the function return value is the */ /* STD resulting from subspace replacement, or is the original */ /* STD if subspace replacement is not applicable. */ /* */ /* Operation: */ /* If the ASF control is enabled, and the STD or ASCE is a */ /* member of a subspace-group (bit 22 is one), and the */ /* dispatchable unit is subspace active (DUCT word 1 bit 0 is */ /* one), and the ASTE obtained by ASN translation is the ASTE */ /* for the base space of the dispatchable unit, then the STD */ /* or ASCE is replaced (except for the event control bits) by */ /* the STD or ASCE from the ASTE for the subspace in which the */ /* dispatchable unit last had control; otherwise the STD or */ /* ASCE remains unchanged. */ /* */ /* Error conditions: */ /* If an ASTE validity exception or ASTE sequence exception */ /* occurs, and the xcode parameter is a non-NULL pointer, */ /* then the exception code is returned in the xcode field */ /* and the function return value is zero. */ /* For all other error conditions a program check is generated */ /* and the function does not return. */ /* */ /*-------------------------------------------------------------------*/ static inline RADR ARCH_DEP(subspace_replace) (RADR std, U32 asteo, U16 *xcode, REGS *regs) { U32 ducto; /* DUCT origin */ U32 duct0; /* DUCT word 0 */ U32 duct1; /* DUCT word 1 */ U32 duct3; /* DUCT word 3 */ U32 ssasteo; /* Subspace ASTE origin */ U32 ssaste[16]; /* Subspace ASTE */ BYTE *p; /* Mainstor pointer */ /* Clear the exception code field, if provided */ if (xcode != NULL) *xcode = 0; /* Return the original STD unchanged if the address-space function control (CR0 bit 15) is zero, or if the subspace-group control (bit 22 of the STD) is zero */ if (!ASF_ENABLED(regs) || (std & SSGROUP_BIT) == 0) return std; /* Load the DUCT origin address */ ducto = regs->CR(2) & CR2_DUCTO; ducto = APPLY_PREFIXING (ducto, regs->PX); /* Program check if DUCT origin address is invalid */ if (ducto > regs->mainlim) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch DUCT words 0, 1, and 3 from absolute storage (note: the DUCT cannot cross a page boundary) */ p = FETCH_MAIN_ABSOLUTE(ducto, regs, 16); duct0 = fetch_fw(p); duct1 = fetch_fw(p+4); duct3 = fetch_fw(p+12); /* Return the original STD unchanged if the dispatchable unit is not subspace active or if the ASTE obtained by ASN translation is not the same as the base ASTE for the dispatchable unit */ if ((duct1 & DUCT1_SA) == 0 || asteo != (duct0 & DUCT0_BASTEO)) return std; /* Load the subspace ASTE origin from the DUCT */ ssasteo = duct1 & DUCT1_SSASTEO; ssasteo = APPLY_PREFIXING (ssasteo, regs->PX); /* Program check if ASTE origin address is invalid */ if (ssasteo > regs->mainlim) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch subspace ASTE words 0, 2, 3, and 5 from absolute storage (note: the ASTE cannot cross a page boundary) */ p = FETCH_MAIN_ABSOLUTE(ssasteo, regs, 24); ssaste[0] = fetch_fw(p); ssaste[2] = fetch_fw(p+8); #if defined(FEATURE_ESAME) ssaste[3] = fetch_fw(p+12); #endif /*defined(FEATURE_ESAME)*/ ssaste[5] = fetch_fw(p+20); /* ASTE validity exception if subspace ASTE invalid bit is one */ if (ssaste[0] & ASTE0_INVALID) { regs->excarid = 0; if (xcode == NULL) regs->program_interrupt (regs, PGM_ASTE_VALIDITY_EXCEPTION); else *xcode = PGM_ASTE_VALIDITY_EXCEPTION; return 0; } /* ASTE sequence exception if the subspace ASTE sequence number does not match the sequence number in the DUCT */ if ((ssaste[5] & ASTE5_ASTESN) != (duct3 & DUCT3_SSASTESN)) { regs->excarid = 0; if (xcode == NULL) regs->program_interrupt (regs, PGM_ASTE_SEQUENCE_EXCEPTION); else *xcode = PGM_ASTE_SEQUENCE_EXCEPTION; return 0; } /* Replace the STD or ASCE with the subspace ASTE STD or ASCE, except for the space switch event bit and the storage alteration event bit, which remain unchanged */ std &= (SSEVENT_BIT | SAEVENT_BIT); std |= (ASTE_AS_DESIGNATOR(ssaste) & ~((RADR)(SSEVENT_BIT | SAEVENT_BIT))); /* Return the STD resulting from subspace replacement */ return std; } /* end function subspace_replace */ #include "dat.h" #include "vstore.h" /* end of INLINE.H */ hercules-3.12/dat.h0000664000175000017500000030640012564723224011127 00000000000000/* DAT.H (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Dynamic Address Translation */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements the DAT, ALET, and ASN translation */ /* functions of the ESA/390 architecture, described in the manual */ /* SA22-7201-04 ESA/390 Principles of Operation. The numbers in */ /* square brackets in the comments refer to sections in the manual. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* S/370 DAT support by Jay Maynard (as described in */ /* GA22-7000 System/370 Principles of Operation) */ /* Clear remainder of ASTE when ASF=0 - Jan Jaeger */ /* S/370 DAT support when running under SIE - Jan Jaeger */ /* ESAME DAT support by Roger Bowler (SA22-7832) */ /* ESAME ASN authorization and ALET translation - Roger Bowler */ /*-------------------------------------------------------------------*/ #if !defined(OPTION_NO_INLINE_DAT) || defined(_DAT_C) #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* Translate ASN to produce address-space control parameters */ /* */ /* Input: */ /* asn Address space number to be translated */ /* regs Pointer to the CPU register context */ /* asteo Pointer to a word to receive real address of ASTE */ /* aste Pointer to 16-word area to receive a copy of the */ /* ASN second table entry associated with the ASN */ /* */ /* Output: */ /* If successful, the ASTE corresponding to the ASN value will */ /* be stored into the 16-word area pointed to by aste, and the */ /* return value is zero. Either 4 or 16 words will be stored */ /* depending on the value of the ASF control bit (CR0 bit 15). */ /* The real address of the ASTE will be stored into the word */ /* pointed to by asteo. */ /* */ /* If unsuccessful, the return value is a non-zero exception */ /* code indicating AFX-translation or ASX-translation error */ /* (this is to allow the LASP instruction to handle these */ /* exceptions by setting the condition code). */ /* */ /* A program check may be generated for addressing and ASN */ /* translation specification exceptions, in which case the */ /* function does not return. */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC U16 ARCH_DEP(translate_asn) (U16 asn, REGS *regs, U32 *asteo, U32 aste[]) { U32 afte_addr; /* Address of AFTE */ U32 afte; /* ASN first table entry */ U32 aste_addr; /* Address of ASTE */ BYTE *aste_main; /* ASTE mainstor address */ int code; /* Exception code */ int numwords; /* ASTE size (4 or 16 words) */ int i; /* Array subscript */ /* [3.9.3.1] Use the AFX to obtain the real address of the AFTE */ afte_addr = (regs->CR(14) & CR14_AFTO) << 12; afte_addr += (asn & ASN_AFX) >> 4; /* Addressing exception if AFTE is outside main storage */ if (afte_addr > regs->mainlim) goto asn_addr_excp; /* Load the AFTE from main storage. All four bytes must be fetched concurrently as observed by other CPUs */ afte_addr = APPLY_PREFIXING (afte_addr, regs->PX); afte = ARCH_DEP(fetch_fullword_absolute) (afte_addr, regs); /* AFX translation exception if AFTE invalid bit is set */ if (afte & AFTE_INVALID) goto asn_afx_tran_excp; #if !defined(FEATURE_ESAME) /* ASN translation specification exception if reserved bits set */ if (!ASF_ENABLED(regs)) { if (afte & AFTE_RESV_0) goto asn_asn_tran_spec_excp; } else { if (afte & AFTE_RESV_1) goto asn_asn_tran_spec_excp; } #endif /*!defined(FEATURE_ESAME)*/ /* [3.9.3.2] Use AFTE and ASX to obtain real address of ASTE */ if (!ASF_ENABLED(regs)) { aste_addr = afte & AFTE_ASTO_0; aste_addr += (asn & ASN_ASX) << 4; numwords = 4; } else { aste_addr = afte & AFTE_ASTO_1; aste_addr += (asn & ASN_ASX) << 6; numwords = 16; } /* Ignore carry into bit position 0 of ASTO */ aste_addr &= 0x7FFFFFFF; /* Addressing exception if ASTE is outside main storage */ if (aste_addr > regs->mainlim) goto asn_addr_excp; /* Return the real address of the ASTE */ *asteo = aste_addr; /* Fetch the 16- or 64-byte ASN second table entry from real storage. Each fullword of the ASTE must be fetched concurrently as observed by other CPUs */ aste_addr = APPLY_PREFIXING (aste_addr, regs->PX); aste_main = FETCH_MAIN_ABSOLUTE(aste_addr, regs, numwords * 4); for (i = 0; i < numwords; i++) { aste[i] = fetch_fw(aste_main); aste_main += 4; } /* Clear remaining words if fewer than 16 words were loaded */ while (i < 16) aste[i++] = 0; /* Check the ASX invalid bit in the ASTE */ if (aste[0] & ASTE0_INVALID) goto asn_asx_tran_excp; #if !defined(FEATURE_ESAME) /* Check the reserved bits in first two words of ASTE */ if ((aste[0] & ASTE0_RESV) || (aste[1] & ASTE1_RESV) || ((aste[0] & ASTE0_BASE) #ifdef FEATURE_SUBSPACE_GROUP && !ASF_ENABLED(regs) #endif /*FEATURE_SUBSPACE_GROUP*/ )) goto asn_asn_tran_spec_excp; #endif /*!defined(FEATURE_ESAME)*/ return 0; /* Conditions which always cause program check */ asn_addr_excp: code = PGM_ADDRESSING_EXCEPTION; goto asn_prog_check; #if !defined(FEATURE_ESAME) asn_asn_tran_spec_excp: code = PGM_ASN_TRANSLATION_SPECIFICATION_EXCEPTION; goto asn_prog_check; #endif /*!defined(FEATURE_ESAME)*/ asn_prog_check: regs->program_interrupt (regs, code); /* Conditions which the caller may or may not program check */ asn_afx_tran_excp: regs->TEA = asn; code = PGM_AFX_TRANSLATION_EXCEPTION; return code; asn_asx_tran_excp: regs->TEA = asn; code = PGM_ASX_TRANSLATION_EXCEPTION; return code; } /* end function translate_asn */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* Perform ASN authorization process */ /* */ /* Input: */ /* ax Authorization index */ /* aste Pointer to 16-word area containing a copy of the */ /* ASN second table entry associated with the ASN */ /* atemask Specifies which authority bit to test in the ATE: */ /* ATE_PRIMARY (for PT instruction) */ /* ATE_SECONDARY (for PR, SSAR, and LASP instructions, */ /* and all access register translations) */ /* regs Pointer to the CPU register context */ /* */ /* Operation: */ /* The AX is used to select an entry in the authority table */ /* pointed to by the ASTE, and an authorization bit in the ATE */ /* is tested. For ATE_PRIMARY (X'80'), the P bit is tested. */ /* For ATE_SECONDARY (X'40'), the S bit is tested. */ /* Authorization is successful if the ATE falls within the */ /* authority table limit and the tested bit value is 1. */ /* */ /* Output: */ /* If authorization is successful, the return value is zero. */ /* If authorization is unsuccessful, the return value is 1. */ /* */ /* A program check may be generated for addressing exception */ /* if the authority table entry address is invalid, and in */ /* this case the function does not return. */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC int ARCH_DEP(authorize_asn) (U16 ax, U32 aste[], int atemask, REGS *regs) { RADR ato; /* Authority table origin */ int atl; /* Authority table length */ BYTE ate; /* Authority table entry */ /* [3.10.3.1] Authority table lookup */ /* Isolate the authority table origin and length */ ato = aste[0] & ASTE0_ATO; atl = aste[1] & ASTE1_ATL; /* Authorization fails if AX is outside table */ if ((ax & 0xFFF0) > atl) return 1; /* Calculate the address of the byte in the authority table which contains the 2 bit entry for this AX */ ato += (ax >> 2); /* Ignore carry into bit position 0 */ ato &= 0x7FFFFFFF; /* Addressing exception if ATE is outside main storage */ if (ato > regs->mainlim) goto auth_addr_excp; /* Load the byte containing the authority table entry and shift the entry into the leftmost 2 bits */ ato = APPLY_PREFIXING (ato, regs->PX); SIE_TRANSLATE(&ato, ACCTYPE_SIE, regs); ate = regs->mainstor[ato]; ate <<= ((ax & 0x03)*2); /* Set the main storage reference bit */ STORAGE_KEY(ato, regs) |= STORKEY_REF; /* Authorization fails if the specified bit (either X'80' or X'40' of the 2 bit authority table entry) is zero */ if ((ate & atemask) == 0) return 1; /* Exit with successful return code */ return 0; /* Conditions which always cause program check */ auth_addr_excp: regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); return 1; } /* end function authorize_asn */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* Translate an ALET to produce the corresponding ASTE */ /* */ /* This routine performs both ordinary ART (as used by DAT when */ /* operating in access register mode, and by the TAR instruction), */ /* and special ART (as used by the BSG instruction). The caller */ /* is assumed to have already eliminated the special cases of ALET */ /* values 0 and 1 (which have different meanings depending on */ /* whether the caller is DAT, TAR, or BSG). */ /* */ /* Input: */ /* alet ALET value */ /* eax The authorization index (normally obtained from */ /* CR8; obtained from R2 for TAR; not used for BSG) */ /* acctype Type of access requested: READ, WRITE, instfetch, */ /* TAR, LRA, TPROT, or BSG */ /* regs Pointer to the CPU register context */ /* asteo Pointer to word to receive ASTE origin address */ /* aste Pointer to 16-word area to receive a copy of the */ /* ASN second table entry associated with the ALET */ /* */ /* Output: */ /* If successful, the ASTE is copied into the 16-word area, */ /* the real address of the ASTE is stored into the word pointed */ /* word pointed to by asteop, and the return value is zero; */ /* regs->dat.protect is set to 2 if the fetch-only bit */ /* in the ALE is set, otherwise it is set to zero. */ /* */ /* If unsuccessful, the return value is a non-zero exception */ /* code in the range X'0028' through X'002D' (this is to allow */ /* the TAR, LRA, and TPROT instructions to handle these */ /* exceptions by setting the condition code). */ /* regs->dat.xcode is also set to the exception code. */ /* */ /* A program check may be generated for addressing and ASN */ /* translation specification exceptions, in which case the */ /* function does not return. */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC U16 ARCH_DEP(translate_alet) (U32 alet, U16 eax, int acctype, REGS *regs, U32 *asteo, U32 aste[]) { U32 cb; /* DUCT or PASTE address */ U32 ald; /* Access-list designation */ U32 alo; /* Access-list origin */ U32 all; /* Access-list length */ U32 ale[4]; /* Access-list entry */ U32 aste_addr; /* Real address of ASTE */ U32 abs; /* Absolute address */ BYTE *mn; /* Mainstor address */ int i; /* Array subscript */ regs->dat.protect = 0; /* [5.8.4.3] Check the reserved bits in the ALET */ if ( alet & ALET_RESV ) goto alet_spec_excp; /* [5.8.4.4] Obtain the effective access-list designation */ /* Obtain the real address of the control block containing the effective access-list designation. This is either the Primary ASTE or the DUCT */ cb = (alet & ALET_PRI_LIST) ? regs->CR(5) & CR5_PASTEO : regs->CR(2) & CR2_DUCTO; /* Addressing exception if outside main storage */ if (cb > regs->mainlim) goto alet_addr_excp; /* Load the effective access-list designation (ALD) from offset 16 in the control block. All four bytes must be fetched concurrently as observed by other CPUs. Note that the DUCT and the PASTE cannot cross a page boundary */ cb = APPLY_PREFIXING (cb, regs->PX); ald = ARCH_DEP(fetch_fullword_absolute) (cb+16, regs); /* [5.8.4.5] Access-list lookup */ /* Isolate the access-list origin and access-list length */ alo = ald & ALD_ALO; all = ald & ALD_ALL; /* Check that the ALEN does not exceed the ALL */ if (((alet & ALET_ALEN) >> ALD_ALL_SHIFT) > all) goto alen_tran_excp; /* Add the ALEN x 16 to the access list origin */ alo += (alet & ALET_ALEN) << 4; /* Addressing exception if outside main storage */ if (alo > regs->mainlim) goto alet_addr_excp; /* Fetch the 16-byte access list entry from absolute storage. Each fullword of the ALE must be fetched concurrently as observed by other CPUs */ alo = APPLY_PREFIXING (alo, regs->PX); mn = FETCH_MAIN_ABSOLUTE(alo, regs, 16); for (i = 0; i < 4; i++) { ale[i] = fetch_fw (mn); mn += 4; } /* Check the ALEN invalid bit in the ALE */ if (ale[0] & ALE0_INVALID) goto alen_tran_excp; /* For ordinary ART (but not for special ART), compare the ALE sequence number with the ALET */ if (!(acctype & ACC_SPECIAL_ART) && (ale[0] & ALE0_ALESN) != (alet & ALET_ALESN)) goto ale_seq_excp; /* [5.8.4.6] Locate the ASN-second-table entry */ aste_addr = ale[2] & ALE2_ASTE; /* Addressing exception if ASTE is outside main storage */ abs = APPLY_PREFIXING (aste_addr, regs->PX); if (abs > regs->mainlim) goto alet_addr_excp; mn = FETCH_MAIN_ABSOLUTE(abs, regs, 64); /* Fetch the 64-byte ASN second table entry from real storage. Each fullword of the ASTE must be fetched concurrently as observed by other CPUs. ASTE cannot cross a page boundary */ for (i = 0; i < 16; i++) { aste[i] = fetch_fw(mn); mn += 4; } /* Check the ASX invalid bit in the ASTE */ if (aste[0] & ASTE0_INVALID) goto aste_vald_excp; /* Compare the ASTE sequence number with the ALE */ if ((aste[5] & ASTE5_ASTESN) != (ale[3] & ALE3_ASTESN)) goto aste_seq_excp; /* [5.8.4.7] For ordinary ART (but not for special ART), authorize the use of the access-list entry */ if (!(acctype & ACC_SPECIAL_ART)) { /* If ALE private bit is zero, or the ALE AX equals the EAX, then authorization succeeds. Otherwise perform the extended authorization process. */ if ((ale[0] & ALE0_PRIVATE) && (ale[0] & ALE0_ALEAX) != eax) { #if !defined(FEATURE_ESAME) /* Check the reserved bits in first two words of ASTE */ if ((aste[0] & ASTE0_RESV) || (aste[1] & ASTE1_RESV) || ((aste[0] & ASTE0_BASE) #ifdef FEATURE_SUBSPACE_GROUP && !ASF_ENABLED(regs) #endif /*FEATURE_SUBSPACE_GROUP*/ )) goto alet_asn_tran_spec_excp; #endif /*!defined(FEATURE_ESAME)*/ /* Perform extended authorization */ if (ARCH_DEP(authorize_asn)(eax, aste, ATE_SECONDARY, regs) != 0) goto ext_auth_excp; } } /* end if(!ACCTYPE_BSG) */ /* [5.8.4.8] Check for access-list controlled protection */ if (ale[0] & ALE0_FETCHONLY) regs->dat.protect = 2; /* Return the ASTE origin address */ *asteo = aste_addr; return 0; /* Conditions which always cause program check, except when performing translation for the control panel */ alet_addr_excp: regs->dat.xcode = PGM_ADDRESSING_EXCEPTION; goto alet_prog_check; #if !defined(FEATURE_ESAME) alet_asn_tran_spec_excp: regs->dat.xcode = PGM_ASN_TRANSLATION_SPECIFICATION_EXCEPTION; goto alet_prog_check; #endif /*!defined(FEATURE_ESAME)*/ alet_prog_check: regs->program_interrupt (regs, regs->dat.xcode); /* Conditions which the caller may or may not program check */ alet_spec_excp: regs->dat.xcode = PGM_ALET_SPECIFICATION_EXCEPTION; return regs->dat.xcode; alen_tran_excp: regs->dat.xcode = PGM_ALEN_TRANSLATION_EXCEPTION; return regs->dat.xcode; ale_seq_excp: regs->dat.xcode = PGM_ALE_SEQUENCE_EXCEPTION; return regs->dat.xcode; aste_vald_excp: regs->dat.xcode = PGM_ASTE_VALIDITY_EXCEPTION; return regs->dat.xcode; aste_seq_excp: regs->dat.xcode = PGM_ASTE_SEQUENCE_EXCEPTION; return regs->dat.xcode; ext_auth_excp: regs->dat.xcode = PGM_EXTENDED_AUTHORITY_EXCEPTION; return regs->dat.xcode; } /* end function translate_alet */ #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* Purge the ART lookaside buffer */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(purge_alb) (REGS *regs) { int i; for(i = 1; i < 16; i++) if(regs->aea_ar[i] >= CR_ALB_OFFSET && regs->aea_ar[i] != CR_ASD_REAL) regs->aea_ar[i] = 0; if(regs->host && regs->guestregs) for(i = 1; i < 16; i++) if(regs->guestregs->aea_ar[i] >= CR_ALB_OFFSET && regs->guestregs->aea_ar[i] != CR_ASD_REAL) regs->guestregs->aea_ar[i] = 0; } /* end function purge_alb */ /*-------------------------------------------------------------------*/ /* Purge the ART lookaside buffer for all CPUs */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(purge_alb_all) () { int i; for (i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i) && (sysblk.regs[i]->cpubit & sysblk.started_mask)) ARCH_DEP(purge_alb) (sysblk.regs[i]); } /* end function purge_alb_all */ #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* Determine effective ASCE or STD */ /* */ /* This routine returns either an address-space control element */ /* (for ESAME) or a segment table descriptor (for S/370 and ESA/390) */ /* loaded from control register 1, 7, or 13, or computed from the */ /* contents of an address register, together with an indication of */ /* the addressing mode (home, primary, secondary, or AR mode) */ /* which was used to determine the source of the ASCE or STD. */ /* */ /* Input: */ /* arn Access register number (0-15) to be used if the */ /* address-space control (PSW bits 16-17) indicates */ /* that ARMODE is the current translation mode. */ /* An access register number ORed with the special */ /* value USE_ARMODE forces this routine to use ARMODE */ /* regardless of the PSW address-space control setting. */ /* Access register 0 is treated as if it contained 0 */ /* and its actual contents are not examined. */ /* Alternatively the arn parameter may contain one */ /* of these special values (defined in hconsts.h): */ /* USE_PRIMARY_SPACE, USE_SECONDARY_SPACE, */ /* USE_HOME_SPACE, USE_REAL_ADDR to force the use of */ /* a specific translation mode instead of the mode */ /* indicated by the address-space control in the PSW. */ /* regs Pointer to the CPU register context */ /* acctype Type of access requested: READ, WRITE, INSTFETCH, */ /* LRA, IVSK, TPROT, STACK, PTE, LPTEA */ /* */ /* Output: */ /* regs->dat.asd = the selected ASCE or STD */ /* regs->dat.stid = TEA_ST_PRIMARY, TEA_ST_SECNDRY, */ /* TEA_ST_HOME, or TEA_ST_ARMODE indicates which */ /* address space was used to select the ASCE or STD. */ /* regs->dat.protect = 2 if in AR mode and access-list */ /* controlled protection is indicated by the ALE */ /* fetch-only bit; otherwise it remains unchanged. */ /* */ /* If an ALET translation error occurs, the return value */ /* is the exception code; otherwise the return value is zero, */ /* regs->dat.asd field contains the ASCE or STD, and */ /* regs->dat.stid is set to TEA_ST_PRIMARY, TEA_ST_SECNDRY, */ /* TEA_ST_HOME, or TEA_ST_ARMODE. */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC U16 ARCH_DEP(load_address_space_designator) (int arn, REGS *regs, int acctype) { #if defined(FEATURE_ACCESS_REGISTERS) U32 alet; /* Access list entry token */ U32 asteo; /* Real address of ASTE */ U32 aste[16]; /* ASN second table entry */ U16 eax; /* Authorization index */ #else UNREFERENCED(acctype); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ switch(arn) { case USE_PRIMARY_SPACE: regs->dat.stid = TEA_ST_PRIMARY; regs->dat.asd = regs->CR(1); break; case USE_SECONDARY_SPACE: regs->dat.stid = TEA_ST_SECNDRY; regs->dat.asd = regs->CR(7); break; case USE_HOME_SPACE: regs->dat.stid = TEA_ST_HOME; regs->dat.asd = regs->CR(13); break; case USE_REAL_ADDR: regs->dat.stid = 0; regs->dat.asd = TLB_REAL_ASD; break; case USE_INST_SPACE: switch(regs->aea_ar[USE_INST_SPACE]) { case 1: regs->dat.stid = TEA_ST_PRIMARY; break; #if defined(FEATURE_LINKAGE_STACK) case 13: regs->dat.stid = TEA_ST_HOME; break; #endif default: regs->dat.stid = 0; } /* end switch(regs->aea_ar[USE_INST_SPACE]) */ regs->dat.asd = regs->CR(regs->aea_ar[USE_INST_SPACE]); break; default: #if defined(FEATURE_ACCESS_REGISTERS) if (ACCESS_REGISTER_MODE(®s->psw) || (SIE_ACTIVE(regs) && MULTIPLE_CONTROLLED_DATA_SPACE(regs->guestregs)) || (arn & USE_ARMODE) ) { /* Remove flags giving access register number 0-15 */ arn &= 0xF; /* [5.8.4.1] Select the access-list-entry token */ alet = (arn == 0) ? 0 : /* Guest ALET if XC guest in AR mode */ (SIE_ACTIVE(regs) && MULTIPLE_CONTROLLED_DATA_SPACE(regs->guestregs)) ? regs->guestregs->AR(arn) : /* If SIE host but not XC guest in AR mode then alet is 0 */ SIE_ACTIVE(regs) ? 0 : /* Otherwise alet is in the access register */ regs->AR(arn); /* Use the ALET to determine the segment table origin */ switch (alet) { case ALET_PRIMARY: /* [5.8.4.2] Obtain primary segment table designation */ regs->dat.stid = TEA_ST_PRIMARY; regs->dat.asd = regs->CR(1); break; case ALET_SECONDARY: /* [5.8.4.2] Obtain secondary segment table designation */ regs->dat.stid = TEA_ST_SECNDRY; regs->dat.asd = regs->CR(7); break; default: /* ALB Lookup */ if(regs->aea_ar[arn] >= CR_ALB_OFFSET && regs->aea_ar[arn] != CR_ASD_REAL) { regs->dat.asd = regs->CR(regs->aea_ar[arn]); regs->dat.protect = regs->aea_aleprot[arn]; regs->dat.stid = TEA_ST_ARMODE; } else { /* Extract the extended AX from CR8 bits 0-15 (32-47) */ eax = regs->CR_LHH(8); /* [5.8.4.3] Perform ALET translation to obtain ASTE */ if (ARCH_DEP(translate_alet) (alet, eax, acctype, regs, &asteo, aste)) /* Exit if ALET translation error */ return regs->dat.xcode; /* [5.8.4.9] Obtain the STD or ASCE from the ASTE */ regs->dat.asd = ASTE_AS_DESIGNATOR(aste); regs->dat.stid = TEA_ST_ARMODE; if(regs->dat.protect & 2) { #if defined(FEATURE_ESAME) regs->dat.asd ^= ASCE_RESV; regs->dat.asd |= ASCE_P; #else regs->dat.asd ^= STD_RESV; regs->dat.asd |= STD_PRIVATE; #endif } /* Update ALB */ regs->CR(CR_ALB_OFFSET + arn) = regs->dat.asd; regs->aea_ar[arn] = CR_ALB_OFFSET + arn; regs->aea_common[CR_ALB_OFFSET + arn] = (regs->dat.asd & ASD_PRIVATE) == 0; regs->aea_aleprot[arn] = regs->dat.protect & 2; } } /* end switch(alet) */ break; } /* end if(ACCESS_REGISTER_MODE) */ #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) if (SECONDARY_SPACE_MODE(®s->psw)) { regs->dat.stid = TEA_ST_SECNDRY; regs->dat.asd = regs->CR(7); break; } #endif /* defined(FEATURE_DUAL_ADDRESS_SPACE) */ #if defined(FEATURE_LINKAGE_STACK) if (HOME_SPACE_MODE(®s->psw)) { regs->dat.stid = TEA_ST_HOME; regs->dat.asd = regs->CR(13); break; } #endif /* defined(FEATURE_LINKAGE_STACK) */ /* Primary space mode */ regs->dat.stid = TEA_ST_PRIMARY; regs->dat.asd = regs->CR(1); break; } /* switch(arn) */ return 0; } /* end function load_address_space_designator */ /*-------------------------------------------------------------------*/ /* Translate a virtual address to a real address */ /* */ /* Input: */ /* vaddr virtual address to be translated */ /* arn Access register number or special value (see */ /* load_address_space_designator function for a */ /* complete description of this parameter) */ /* regs Pointer to the CPU register context */ /* acctype Type of access requested: READ, WRITE, INSTFETCH, */ /* LRA, IVSK, TPROT, STACK, PTE, LPTEA */ /* */ /* Output: */ /* The return value is set to facilitate the setting of the */ /* condition code by the LRA instruction: */ /* 0 = Translation successful; real address field contains */ /* the real address corresponding to the virtual address */ /* supplied by the caller; exception code set to zero. */ /* 1 = Segment table entry invalid; real address field */ /* contains real address of segment table entry; */ /* exception code is set to X'0010'. */ /* 2 = Page table entry invalid; real address field contains */ /* real address of page table entry; exception code */ /* is set to X'0011'. */ /* 3 = Segment or page table length exceeded; real address */ /* field contains the real address of the entry that */ /* would have been fetched if length violation had not */ /* occurred; exception code is set to X'0010' or X'0011'. */ /* 4 = ALET translation error: real address field is not */ /* set; exception code is set to X'0028' through X'002D'. */ /* ASCE-type or region-translation error: real address */ /* is not set; exception code is X'0038' through X'003B'. */ /* The LRA instruction converts this to condition code 3. */ /* 5 = For ACCTYPE_EMC (Enhanced MC access only): */ /* A translation specification exception occured */ /* */ /* For ACCTYPE_LPTEA, the return value is set to facilitate */ /* setting the condition code by the LPTEA instruction: */ /* 0 = Page table entry found, and page protection bit in the */ /* segment table entry is zero; the real address field */ /* contains the real address of the page table entry; */ /* exception code is set to zero. */ /* 1 = Page table entry found, and page protection bit in the */ /* segment table entry is one; the real address field */ /* contains the real address of the page table entry; */ /* exception code is set to zero. */ /* 2 = Region table or segment table entry invalid bit is set; */ /* the real address field contains the real address of the */ /* region table entry or segment table entry, with the */ /* entry type in the low-order two bits of the address. */ /* 3 = Region table or segment table length exceeded; real */ /* address field is not set; exception code is set to */ /* X'0010' or X'0039' through X'003B'. */ /* ALET translation error: real address field is not */ /* set; exception code is set to X'0028' through X'002D'. */ /* ASCE-type error: real address is not set; exception */ /* exception code is X'0038'. */ /* */ /* regs->dat.raddr is set to the real address if translation */ /* was successful; otherwise it may contain the address of */ /* a page or segment table entry as described above. */ /* For ACCTYPE_PTE or ACCTYPE_LPTEA it contains the address of */ /* the page table entry if translation was successful. */ /* */ /* regs->dat.xcode is set to the exception code if translation */ /* was unsuccessful; otherwise it is set to zero. */ /* */ /* regs->dat.private is set to 1 if translation was */ /* successful and the STD indicates a private address space; */ /* otherwise it is set to zero. */ /* */ /* regs->dat.protect is set to 1 if translation was */ /* successful and page protection, segment protection, or */ /* segment controlled page protection is in effect; it is */ /* set to 2 if translation was successful and ALE controlled */ /* protection (but not page protection) is in effect; */ /* otherwise it is set to zero. */ /* */ /* regs->dat.stid is set to one of the following */ /* values TEA_ST_PRIMARY, TEA_ST_SECNDRY, TEA_ST_HOME, or */ /* TEA_ST_ARMODE if the translation was successful. This */ /* indication is used to set bits 30-31 of the translation */ /* exception address in the event of a protection exception */ /* when the suppression on protection facility is used. */ /* */ /* A program check may be generated for addressing and */ /* translation specification exceptions, in which case the */ /* function does not return. */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC int ARCH_DEP(translate_addr) (VADR vaddr, int arn, REGS *regs, int acctype) { RADR sto = 0; /* Segment table origin */ RADR pto = 0; /* Page table origin */ int cc; /* Condition code */ int tlbix = TLBIX(vaddr); /* TLB entry index */ #if !defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME) /*-----------------------------------*/ /* S/370 Dynamic Address Translation */ /*-----------------------------------*/ U32 stl; /* Segment table length */ RADR ste; /* Segment table entry */ U16 pte; /* Page table entry */ U32 ptl; /* Page table length */ regs->dat.private = regs->dat.protect = 0; /* Load the effective segment table descriptor */ if (ARCH_DEP(load_address_space_designator) (arn, regs, acctype)) goto tran_alet_excp; /* Check the translation format bits in CR0 */ if ((((regs->CR(0) & CR0_PAGE_SIZE) != CR0_PAGE_SZ_2K) && ((regs->CR(0) & CR0_PAGE_SIZE) != CR0_PAGE_SZ_4K)) || (((regs->CR(0) & CR0_SEG_SIZE) != CR0_SEG_SZ_64K) && ((regs->CR(0) & CR0_SEG_SIZE) != CR0_SEG_SZ_1M))) goto tran_spec_excp; /* Look up the address in the TLB */ if ( ((vaddr & TLBID_PAGEMASK) | regs->tlbID) == regs->tlb.TLB_VADDR(tlbix) && (regs->tlb.common[tlbix] || regs->dat.asd == regs->tlb.TLB_ASD(tlbix)) && !(regs->tlb.common[tlbix] && regs->dat.private) && !(acctype & ACC_NOTLB) ) { pte = regs->tlb.TLB_PTE(tlbix); #ifdef FEATURE_SEGMENT_PROTECTION /* Set the protection indicator if segment is protected */ if (regs->tlb.protect[tlbix]) regs->dat.protect = regs->tlb.protect[tlbix]; #endif /*FEATURE_SEGMENT_PROTECTION*/ } else { /* S/370 segment table lookup */ /* Calculate the real address of the segment table entry */ sto = regs->dat.asd & STD_370_STO; stl = regs->dat.asd & STD_370_STL; sto += ((regs->CR(0) & CR0_SEG_SIZE) == CR0_SEG_SZ_1M) ? ((vaddr & 0x00F00000) >> 18) : ((vaddr & 0x00FF0000) >> 14); /* Check that virtual address is within the segment table */ if (((regs->CR(0) & CR0_SEG_SIZE) == CR0_SEG_SZ_64K) && ((vaddr << 4) & STD_370_STL) > stl) goto seg_tran_length; /* Generate addressing exception if outside real storage */ if (sto > regs->mainlim) goto address_excp; /* Fetch segment table entry from real storage. All bytes must be fetched concurrently as observed by other CPUs */ sto = APPLY_PREFIXING (sto, regs->PX); ste = ARCH_DEP(fetch_fullword_absolute) (sto, regs); /* Generate segment translation exception if segment invalid */ if (ste & SEGTAB_370_INVL) goto seg_tran_invalid; /* Check that all the reserved bits in the STE are zero */ if (ste & SEGTAB_370_RSV) goto tran_spec_excp; /* Isolate page table origin and length */ pto = ste & SEGTAB_370_PTO; ptl = ste & SEGTAB_370_PTL; /* S/370 page table lookup */ /* Calculate the real address of the page table entry */ pto += ((regs->CR(0) & CR0_SEG_SIZE) == CR0_SEG_SZ_1M) ? (((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) ? ((vaddr & 0x000FF000) >> 11) : ((vaddr & 0x000FF800) >> 10)) : (((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) ? ((vaddr & 0x0000F000) >> 11) : ((vaddr & 0x0000F800) >> 10)); /* Generate addressing exception if outside real storage */ if (pto > regs->mainlim) goto address_excp; /* Check that the virtual address is within the page table */ if ((((regs->CR(0) & CR0_SEG_SIZE) == CR0_SEG_SZ_1M) && (((vaddr & 0x000F0000) >> 16) > ptl)) || (((regs->CR(0) & CR0_SEG_SIZE) == CR0_SEG_SZ_64K) && (((vaddr & 0x0000F000) >> 12) > ptl))) goto page_tran_length; /* Fetch the page table entry from real storage. All bytes must be fetched concurrently as observed by other CPUs */ pto = APPLY_PREFIXING (pto, regs->PX); pte = ARCH_DEP(fetch_halfword_absolute) (pto, regs); /* Generate page translation exception if page invalid */ if ((((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) && (pte & PAGETAB_INV_4K)) || (((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_2K) && (pte & PAGETAB_INV_2K))) goto page_tran_invalid; /* Check that all the reserved bits in the PTE are zero */ if (((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_2K) && (pte & PAGETAB_RSV_2K)) goto tran_spec_excp; #ifdef FEATURE_SEGMENT_PROTECTION /* Set the protection indicator if segment is protected */ if (ste & SEGTAB_370_PROT) regs->dat.protect |= 1; #endif /*FEATURE_SEGMENT_PROTECTION*/ /* Place the translated address in the TLB */ if (!(acctype & ACC_NOTLB)) { regs->tlb.TLB_ASD(tlbix) = regs->dat.asd; regs->tlb.TLB_VADDR(tlbix) = (vaddr & TLBID_PAGEMASK) | regs->tlbID; regs->tlb.TLB_PTE(tlbix) = pte; regs->tlb.common[tlbix] = (ste & SEGTAB_370_CMN) ? 1 : 0; regs->tlb.protect[tlbix] = regs->dat.protect; regs->tlb.acc[tlbix] = 0; regs->tlb.main[tlbix] = NULL; /* Set adjacent TLB entry if 4K page sizes */ if ((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) { regs->tlb.TLB_ASD(tlbix^1) = regs->tlb.TLB_ASD(tlbix); regs->tlb.TLB_VADDR(tlbix^1) = (vaddr & TLBID_PAGEMASK) | regs->tlbID; regs->tlb.TLB_PTE(tlbix^1) = regs->tlb.TLB_PTE(tlbix); regs->tlb.common[tlbix^1] = regs->tlb.common[tlbix]; regs->tlb.protect[tlbix^1] = regs->tlb.protect[tlbix]; regs->tlb.acc[tlbix^1] = 0; regs->tlb.main[tlbix^1] = NULL; } } } /* end if(!TLB) */ /* Combine the page frame real address with the byte index of the virtual address to form the real address */ regs->dat.raddr = ((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) ? #if defined(FEATURE_S370E_EXTENDED_ADDRESSING) (((U32)pte & PAGETAB_EA_4K) << 23) | #endif (((U32)pte & PAGETAB_PFRA_4K) << 8) | (vaddr & 0xFFF) : (((U32)pte & PAGETAB_PFRA_2K) << 8) | (vaddr & 0x7FF); regs->dat.rpfra = regs->dat.raddr & PAGEFRAME_PAGEMASK; #endif /*!defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME)*/ #if defined(FEATURE_S390_DAT) /*-----------------------------------*/ /* S/390 Dynamic Address Translation */ /*-----------------------------------*/ U32 stl; /* Segment table length */ RADR ste; /* Segment table entry */ RADR pte; /* Page table entry */ U32 ptl; /* Page table length */ regs->dat.private = regs->dat.protect = 0; /* [3.11.3.1] Load the effective segment table descriptor */ if (ARCH_DEP(load_address_space_designator) (arn, regs, acctype)) goto tran_alet_excp; /* [3.11.3.2] Check the translation format bits in CR0 */ if ((regs->CR(0) & CR0_TRAN_FMT) != CR0_TRAN_ESA390) goto tran_spec_excp; /* Extract the private space bit from segment table descriptor */ regs->dat.private = ((regs->dat.asd & STD_PRIVATE) != 0); /* [3.11.4] Look up the address in the TLB */ if ( ((vaddr & TLBID_PAGEMASK) | regs->tlbID) == regs->tlb.TLB_VADDR(tlbix) && (regs->tlb.common[tlbix] || regs->dat.asd == regs->tlb.TLB_ASD(tlbix)) && !(regs->tlb.common[tlbix] && regs->dat.private) && !(acctype & ACC_NOTLB) ) { pte = regs->tlb.TLB_PTE(tlbix); if (regs->tlb.protect[tlbix]) regs->dat.protect = regs->tlb.protect[tlbix]; } else { /* [3.11.3.3] Segment table lookup */ /* Calculate the real address of the segment table entry */ sto = regs->dat.asd & STD_STO; stl = regs->dat.asd & STD_STL; sto += (vaddr & 0x7FF00000) >> 18; /* Check that virtual address is within the segment table */ if ((vaddr >> 24) > stl) goto seg_tran_length; /* Generate addressing exception if outside real storage */ if (sto > regs->mainlim) goto address_excp; /* Fetch segment table entry from real storage. All bytes must be fetched concurrently as observed by other CPUs */ sto = APPLY_PREFIXING (sto, regs->PX); ste = ARCH_DEP(fetch_fullword_absolute) (sto, regs); /* Generate segment translation exception if segment invalid */ if (ste & SEGTAB_INVALID) goto seg_tran_invalid; /* Check that all the reserved bits in the STE are zero */ if (ste & SEGTAB_RESV) goto tran_spec_excp; /* If the segment table origin register indicates a private address space then STE must not indicate a common segment */ if (regs->dat.private && (ste & (SEGTAB_COMMON))) goto tran_spec_excp; /* Isolate page table origin and length */ pto = ste & SEGTAB_PTO; ptl = ste & SEGTAB_PTL; /* [3.11.3.4] Page table lookup */ /* Calculate the real address of the page table entry */ pto += (vaddr & 0x000FF000) >> 10; /* Check that the virtual address is within the page table */ if (((vaddr & 0x000FF000) >> 16) > ptl) goto page_tran_length; /* Generate addressing exception if outside real storage */ if (pto > regs->mainlim) goto address_excp; /* Fetch the page table entry from real storage. All bytes must be fetched concurrently as observed by other CPUs */ pto = APPLY_PREFIXING (pto, regs->PX); pte = ARCH_DEP(fetch_fullword_absolute) (pto, regs); /* Generate page translation exception if page invalid */ if (pte & PAGETAB_INVALID) goto page_tran_invalid; /* Check that all the reserved bits in the PTE are zero */ if (pte & PAGETAB_RESV) goto tran_spec_excp; /* Set the protection indicator if page protection is active */ if (pte & PAGETAB_PROT) regs->dat.protect |= 1; /* [3.11.4.2] Place the translated address in the TLB */ if (!(acctype & ACC_NOTLB)) { regs->tlb.TLB_ASD(tlbix) = regs->dat.asd; regs->tlb.TLB_VADDR(tlbix) = (vaddr & TLBID_PAGEMASK) | regs->tlbID; regs->tlb.TLB_PTE(tlbix) = pte; regs->tlb.common[tlbix] = (ste & SEGTAB_COMMON) ? 1 : 0; regs->tlb.acc[tlbix] = 0; regs->tlb.protect[tlbix] = regs->dat.protect; regs->tlb.main[tlbix] = NULL; } } /* end if(!TLB) */ if(!(acctype & ACC_PTE)) { /* [3.11.3.5] Combine the page frame real address with the byte index of the virtual address to form the real address */ regs->dat.raddr = (pte & PAGETAB_PFRA) | (vaddr & 0xFFF); regs->dat.rpfra = (pte & PAGETAB_PFRA); } else /* In the case of lock page, return the address of the pagetable entry */ regs->dat.raddr = pto; #endif /*defined(FEATURE_S390_DAT)*/ #if defined(FEATURE_ESAME) /*-----------------------------------*/ /* ESAME Dynamic Address Translation */ /*-----------------------------------*/ RADR rte; /* Region table entry */ #define rto sto /* Region/seg table origin */ RADR ste = 0; /* Segment table entry */ RADR pte = 0; /* Page table entry */ BYTE tt; /* Table type */ BYTE tl; /* Table length */ BYTE tf; /* Table offset */ U16 rfx, rsx, rtx; /* Region first/second/third index + 3 low-order zeros */ U16 sx, px; /* Segment and page index, + 3 low-order zero bits */ regs->dat.private = regs->dat.protect = 0; /* Load the address space control element */ if (ARCH_DEP(load_address_space_designator) (arn, regs, acctype)) goto tran_alet_excp; /* Extract the private space bit from the ASCE */ regs->dat.private = ((regs->dat.asd & (ASCE_P|ASCE_R)) != 0); // logmsg("asce=%16.16" I64_FMT "X\n",regs->dat.asd); /* [3.11.4] Look up the address in the TLB */ if ( ((vaddr & TLBID_PAGEMASK) | regs->tlbID) == regs->tlb.TLB_VADDR(tlbix) && (regs->tlb.common[tlbix] || regs->dat.asd == regs->tlb.TLB_ASD(tlbix)) && !(regs->tlb.common[tlbix] && regs->dat.private) && !(acctype & ACC_NOTLB) ) { pte = regs->tlb.TLB_PTE(tlbix); if (regs->tlb.protect[tlbix]) regs->dat.protect = regs->tlb.protect[tlbix]; } else { /* If ASCE indicates a real-space then real addr = virtual addr */ if (regs->dat.asd & ASCE_R) { // logmsg("asce type = real\n"); /* Translation specification exception if LKPG for a real-space */ if(acctype & ACC_PTE) goto tran_spec_excp; /* Special operation exception if LPTEA for a real-space */ if(acctype & ACC_LPTEA) goto spec_oper_excp; /* Construct a fake page table entry for real = virtual */ pte = vaddr & 0xFFFFFFFFFFFFF000ULL; } else { /* Extract the table origin, type, and length from the ASCE, and set the table offset to zero */ rto = regs->dat.asd & ASCE_TO; tf = 0; tt = regs->dat.asd & ASCE_DT; tl = regs->dat.asd & ASCE_TL; /* Extract the 11-bit region first index, region second index, and region third index from the virtual address, and shift each index into bits 2-12 of a 16-bit integer, ready for addition to the appropriate region table origin */ rfx = (vaddr >> 50) & 0x3FF8; rsx = (vaddr >> 39) & 0x3FF8; rtx = (vaddr >> 28) & 0x3FF8; /* Extract the 11-bit segment index from the virtual address, and shift it into bits 2-12 of a 16-bit integer, ready for addition to the segment table origin */ sx = (vaddr >> 17) & 0x3FF8; /* Extract the 8-bit page index from the virtual address, and shift it into bits 2-12 of a 16-bit integer, ready for addition to the page table origin */ px = (vaddr >> 9) & 0x07F8; /* ASCE-type exception if the virtual address is too large for the table type designated by the ASCE */ if ((rfx != 0 && tt < TT_R1TABL) || (rsx != 0 && tt < TT_R2TABL) || (rtx != 0 && tt < TT_R3TABL)) goto asce_type_excp; /* Perform region translation */ switch (tt) { /* Perform region-first translation */ case TT_R1TABL: /* Region-first translation exception if table length is less than high-order 2 bits of region-first index */ if (tl < (rfx >> 12)) goto reg_first_excp; /* Add the region-first index (with three low-order zeroes) to the region-first table origin, giving the address of the region-first table entry */ rto += rfx; /* Addressing exception if outside main storage */ if (rto > regs->mainlim) goto address_excp; /* Fetch region-first table entry from absolute storage. All bytes must be fetched concurrently as observed by other CPUs */ rte = ARCH_DEP(fetch_doubleword_absolute) (rto, regs); // logmsg("r1te:%16.16" I64_FMT "X=>%16.16" I64_FMT "X\n",rto,rte); /* Region-first translation exception if the bit 58 of the region-first table entry is set (region invalid) */ if (rte & REGTAB_I) goto reg_first_invalid; /* Translation specification exception if bits 60-61 of the region-first table entry do not indicate the correct type of region table */ if ((rte & REGTAB_TT) != TT_R1TABL) goto tran_spec_excp; #if defined(FEATURE_ENHANCED_DAT_FACILITY) if ((regs->CR_L(0) & CR0_ED) && (rte & REGTAB_P)) regs->dat.protect |= 1; #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ /* Extract the region-second table origin, offset, and length from the region-first table entry */ rto = rte & REGTAB_TO; tf = (rte & REGTAB_TF) >> 6; tl = rte & REGTAB_TL; /* Fall through to perform region-second translation */ /* Perform region-second translation */ case TT_R2TABL: /* Region-second translation exception if table offset is greater than high-order 2 bits of region-second index */ if (tf > (rsx >> 12)) goto reg_second_excp; /* Region-second translation exception if table length is less than high-order 2 bits of region-second index */ if (tl < (rsx >> 12)) goto reg_second_excp; /* Add the region-second index (with three low-order zeroes) to the region-second table origin, giving the address of the region-second table entry */ rto += rsx; /* Addressing exception if outside main storage */ if (rto > regs->mainlim) goto address_excp; /* Fetch region-second table entry from absolute storage. All bytes must be fetched concurrently as observed by other CPUs */ rte = ARCH_DEP(fetch_doubleword_absolute) (rto, regs); // logmsg("r2te:%16.16" I64_FMT "X=>%16.16" I64_FMT "X\n",rto,rte); /* Region-second translation exception if the bit 58 of the region-second table entry is set (region invalid) */ if (rte & REGTAB_I) goto reg_second_invalid; /* Translation specification exception if bits 60-61 of the region-second table entry do not indicate the correct type of region table */ if ((rte & REGTAB_TT) != TT_R2TABL) goto tran_spec_excp; #if defined(FEATURE_ENHANCED_DAT_FACILITY) if ((regs->CR_L(0) & CR0_ED) && (rte & REGTAB_P)) regs->dat.protect |= 1; #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ /* Extract the region-third table origin, offset, and length from the region-second table entry */ rto = rte & REGTAB_TO; tf = (rte & REGTAB_TF) >> 6; tl = rte & REGTAB_TL; /* Fall through to perform region-third translation */ /* Perform region-third translation */ case TT_R3TABL: /* Region-third translation exception if table offset is greater than high-order 2 bits of region-third index */ if (tf > (rtx >> 12)) goto reg_third_excp; /* Region-third translation exception if table length is less than high-order 2 bits of region-third index */ if (tl < (rtx >> 12)) goto reg_third_excp; /* Add the region-third index (with three low-order zeroes) to the region-third table origin, giving the address of the region-third table entry */ rto += rtx; /* Addressing exception if outside main storage */ if (rto > regs->mainlim) goto address_excp; /* Fetch region-third table entry from absolute storage. All bytes must be fetched concurrently as observed by other CPUs */ rte = ARCH_DEP(fetch_doubleword_absolute) (rto, regs); // logmsg("r3te:%16.16" I64_FMT "X=>%16.16" I64_FMT "X\n",rto,rte); /* Region-third translation exception if the bit 58 of the region-third table entry is set (region invalid) */ if (rte & REGTAB_I) goto reg_third_invalid; /* Translation specification exception if bits 60-61 of the region-third table entry do not indicate the correct type of region table */ if ((rte & REGTAB_TT) != TT_R3TABL) goto tran_spec_excp; #if defined(FEATURE_ENHANCED_DAT_FACILITY_2) if ((regs->CR_L(0) & CR0_ED)) { /* Translation specification exception if the ASCE indicates a private space, and the region third table entry indicates a common region */ if (regs->dat.private && (rte & REGTAB_CR)) goto tran_spec_excp; } #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY_2)*/ #if defined(FEATURE_ENHANCED_DAT_FACILITY) if ((regs->CR_L(0) & CR0_ED) && (rte & REGTAB_P)) regs->dat.protect |= 1; #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ #if defined(FEATURE_ENHANCED_DAT_FACILITY_2) if ((regs->CR_L(0) & CR0_ED) && (rte & REGTAB_FC)) { /* For LPTEA instruction, return the address of the RTTE */ if (unlikely(acctype & ACC_LPTEA)) { regs->dat.raddr = rto | (regs->dat.protect ? 0x04 : 0); // logmsg("raddr:%16.16" I64_FMT "X cc=2\n",regs->dat.raddr); regs->dat.xcode = 0; cc = 2; return cc; } /* end if(ACCTYPE_LPTEA) */ /* Combine the region frame absolute address with the byte index of the virtual address to form the absolute address */ regs->dat.raddr = (rte & REGTAB_RFAA) | (vaddr & ~REGTAB_RFAA); /* Fake 4K PFRA for TLB purposes */ regs->dat.rpfra = ((rte & REGTAB_RFAA) | (vaddr & ~REGTAB_RFAA)) & PAGEFRAME_PAGEMASK; // logmsg("raddr:%16.16" I64_FMT "X cc=0\n",regs->dat.raddr); /* [3.11.4.2] Place the translated address in the TLB */ if (!(acctype & ACC_NOTLB)) { regs->tlb.TLB_ASD(tlbix) = regs->dat.asd; regs->tlb.TLB_VADDR(tlbix) = (vaddr & TLBID_PAGEMASK) | regs->tlbID; /* Fake 4K PTE for TLB purposes */ regs->tlb.TLB_PTE(tlbix) = ((rte & REGTAB_RFAA) | (vaddr & ~REGTAB_RFAA)) & PAGEFRAME_PAGEMASK; regs->tlb.common[tlbix] = (rte & REGTAB_CR) ? 1 : 0; regs->tlb.protect[tlbix] = regs->dat.protect; regs->tlb.acc[tlbix] = 0; regs->tlb.main[tlbix] = NULL; } /* Clear exception code and return with zero return code */ regs->dat.xcode = 0; return 0; } #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY_2)*/ /* Extract the segment table origin, offset, and length from the region-third table entry */ sto = rte & REGTAB_TO; tf = (rte & REGTAB_TF) >> 6; tl = rte & REGTAB_TL; /* Fall through to perform segment translation */ } /* end switch(tt) */ /* Perform ESAME segment translation */ /* Add the segment index (with three low-order zeroes) to the segment table origin, giving the address of the segment table entry */ sto += sx; /* Segment translation exception if table offset is greater than high-order 2 bits of segment index */ if (tf > (sx >> 12)) goto seg_tran_length; /* Segment translation exception if table length is less than high-order 2 bits of segment index */ if (tl < (sx >> 12)) goto seg_tran_length; /* Addressing exception if outside real storage */ if (sto > regs->mainlim) goto address_excp; /* Fetch segment table entry from absolute storage. All bytes must be fetched concurrently as observed by other CPUs */ ste = ARCH_DEP(fetch_doubleword_absolute) (sto, regs); // logmsg("ste:%16.16" I64_FMT "X=>%16.16" I64_FMT "X\n",sto,ste); /* Segment translation exception if segment invalid */ if (ste & ZSEGTAB_I) goto seg_tran_invalid; /* Translation specification exception if bits 60-61 of the segment table entry do not indicate segment table */ if ((ste & ZSEGTAB_TT) != TT_SEGTAB) goto tran_spec_excp; /* Translation specification exception if the ASCE indicates a private space, and the segment table entry indicates a common segment */ if (regs->dat.private && (ste & ZSEGTAB_C)) goto tran_spec_excp; #if defined(FEATURE_ENHANCED_DAT_FACILITY) if ((regs->CR_L(0) & CR0_ED) && (ste & ZSEGTAB_FC)) { /* Set protection indicator if page protection is indicated */ if (ste & ZSEGTAB_P) regs->dat.protect |= 1; /* For LPTEA instruction, return the address of the STE */ if (unlikely(acctype & ACC_LPTEA)) { regs->dat.raddr = sto | (regs->dat.protect ? 0x04 : 0); // logmsg("raddr:%16.16" I64_FMT "X cc=2\n",regs->dat.raddr); regs->dat.xcode = 0; cc = 2; return cc; } /* end if(ACCTYPE_LPTEA) */ /* Combine the page frame real address with the byte index of the virtual address to form the real address */ regs->dat.raddr = (ste & ZSEGTAB_SFAA) | (vaddr & ~ZSEGTAB_SFAA); /* Fake 4K PFRA for TLB purposes */ regs->dat.rpfra = ((ste & ZSEGTAB_SFAA) | (vaddr & ~ZSEGTAB_SFAA)) & PAGEFRAME_PAGEMASK; // logmsg("raddr:%16.16" I64_FMT "X cc=0\n",regs->dat.raddr); /* [3.11.4.2] Place the translated address in the TLB */ if (!(acctype & ACC_NOTLB)) { regs->tlb.TLB_ASD(tlbix) = regs->dat.asd; regs->tlb.TLB_VADDR(tlbix) = (vaddr & TLBID_PAGEMASK) | regs->tlbID; /* Fake 4K PTE for TLB purposes */ regs->tlb.TLB_PTE(tlbix) = ((ste & ZSEGTAB_SFAA) | (vaddr & ~ZSEGTAB_SFAA)) & PAGEFRAME_PAGEMASK; regs->tlb.common[tlbix] = (ste & SEGTAB_COMMON) ? 1 : 0; regs->tlb.protect[tlbix] = regs->dat.protect; regs->tlb.acc[tlbix] = 0; regs->tlb.main[tlbix] = NULL; } /* Clear exception code and return with zero return code */ regs->dat.xcode = 0; return 0; } #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ /* Extract the page table origin from segment table entry */ pto = ste & ZSEGTAB_PTO; /* Perform ESAME page translation */ /* Add the page index (with three low-order zeroes) to the page table origin, giving address of page table entry */ pto += px; /* For LPTEA instruction, return the address of the PTE */ if (acctype & ACC_LPTEA) { regs->dat.raddr = pto; regs->dat.xcode = 0; cc = (ste & ZSEGTAB_P) ? 1 : 0; #if defined(FEATURE_ENHANCED_DAT_FACILITY) if ((regs->CR_L(0) & CR0_ED) && regs->dat.protect) cc = 1; #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ return cc; } /* end if(ACCTYPE_LPTEA) */ /* Addressing exception if outside real storage */ if (pto > regs->mainlim) goto address_excp; /* Fetch the page table entry from absolute storage. All bytes must be fetched concurrently as observed by other CPUs */ pte = ARCH_DEP(fetch_doubleword_absolute) (pto, regs); // logmsg("pte:%16.16" I64_FMT "X=>%16.16" I64_FMT "X\n",pto,pte); /* Page translation exception if page invalid */ if (pte & ZPGETAB_I) goto page_tran_invalid; /* Check that all the reserved bits in the PTE are zero */ if (pte & ZPGETAB_RESV) goto tran_spec_excp; } /* end else(ASCE_R) */ /* Set protection indicator if page protection is indicated in either the segment table or the page table */ if ((ste & ZSEGTAB_P) || (pte & ZPGETAB_P)) regs->dat.protect |= 1; /* [3.11.4.2] Place the translated address in the TLB */ if (!(acctype & ACC_NOTLB)) { regs->tlb.TLB_ASD(tlbix) = regs->dat.asd; regs->tlb.TLB_VADDR(tlbix) = (vaddr & TLBID_PAGEMASK) | regs->tlbID; regs->tlb.TLB_PTE(tlbix) = pte; regs->tlb.common[tlbix] = (ste & SEGTAB_COMMON) ? 1 : 0; regs->tlb.protect[tlbix] = regs->dat.protect; regs->tlb.acc[tlbix] = 0; regs->tlb.main[tlbix] = NULL; } } if(!(acctype & ACC_PTE)) { /* Combine the page frame real address with the byte index of the virtual address to form the real address */ regs->dat.raddr = (pte & ZPGETAB_PFRA) | (vaddr & 0xFFF); regs->dat.rpfra = (pte & ZPGETAB_PFRA); } else regs->dat.raddr = pto; #endif /*defined(FEATURE_ESAME)*/ /* The following code is common to S/370, ESA/390, and ESAME */ /* Clear exception code and return with zero return code */ regs->dat.xcode = 0; return 0; /* Conditions which always cause program check, except when performing translation for the control panel */ address_excp: // logmsg("dat.c: addressing exception: %8.8X %8.8X %4.4X %8.8X\n", // regs->CR(0),regs->dat.asd,pte,vaddr); regs->dat.xcode = PGM_ADDRESSING_EXCEPTION; goto tran_prog_check; tran_spec_excp: #if defined(FEATURE_ESAME) // logmsg("dat.c: translation specification exception...\n"); // logmsg(" pte = %16.16" I64_FMT "X, ste = %16.16" I64_FMT "X, rte=%16.16" I64_FMT "X\n", // pte, ste, rte); #else // logmsg("dat.c: translation specification exception...\n"); // logmsg(" cr0=%8.8X ste=%8.8X pte=%4.4X vaddr=%8.8X\n", // regs->CR(0),ste,pte,vaddr); #endif regs->dat.xcode = PGM_TRANSLATION_SPECIFICATION_EXCEPTION; goto tran_prog_check; #if defined(FEATURE_ESAME) spec_oper_excp: regs->dat.xcode = PGM_SPECIAL_OPERATION_EXCEPTION; goto tran_prog_check; #endif /*defined(FEATURE_ESAME)*/ tran_prog_check: #if defined(FEATURE_ENHANCED_MONITOR_FACILITY) /* No program interrupt for enhanced MC */ if(acctype & ACC_ENH_MC) { cc = 5; return cc; } #endif /*defined(FEATURE_ENHANCED_MONITOR_FACILITY)*/ regs->program_interrupt (regs, regs->dat.xcode); /* Conditions which the caller may or may not program check */ seg_tran_invalid: /* For LPTEA, return segment table entry address with cc 2 */ if (acctype & ACC_LPTEA) { regs->dat.raddr = sto; cc = 2; return cc; } /* end if(ACCTYPE_LPTEA) */ /* Otherwise set translation exception code */ regs->dat.xcode = PGM_SEGMENT_TRANSLATION_EXCEPTION; regs->dat.raddr = sto; cc = 1; goto tran_excp_addr; page_tran_invalid: regs->dat.xcode = PGM_PAGE_TRANSLATION_EXCEPTION; regs->dat.raddr = pto; if(acctype & ACC_PTE) return 0; cc = 2; goto tran_excp_addr; #if !defined(FEATURE_ESAME) page_tran_length: regs->dat.xcode = PGM_PAGE_TRANSLATION_EXCEPTION; regs->dat.raddr = pto; cc = 3; goto tran_excp_addr; #endif /*!defined(FEATURE_ESAME)*/ seg_tran_length: // logmsg("dat.c: segment translation exception due to segment length\n"); // logmsg(" cr0=" F_RADR " sto=" F_RADR "\n",regs->CR(0),sto); regs->dat.xcode = PGM_SEGMENT_TRANSLATION_EXCEPTION; regs->dat.raddr = sto; cc = 3; goto tran_excp_addr; tran_alet_excp: regs->excarid = arn; cc = (acctype & ACC_LPTEA) ? 3 : 4; return cc; #if defined(FEATURE_ESAME) reg_first_invalid: /* For LPTEA, return region table entry address with cc 2 */ if (acctype & ACC_LPTEA) { regs->dat.raddr = rto | (TT_R1TABL >> 2); cc = 2; return cc; } /* end if(ACCTYPE_LPTEA) */ /* Otherwise set translation exception code */ goto reg_first_excp; reg_second_invalid: /* For LPTEA, return region table entry address with cc 2 */ if (acctype & ACC_LPTEA) { regs->dat.raddr = rto | (TT_R2TABL >> 2); cc = 2; return cc; } /* end if(ACCTYPE_LPTEA) */ /* Otherwise set translation exception code */ goto reg_second_excp; reg_third_invalid: /* For LPTEA, return region table entry address with cc 2 */ if (acctype & ACC_LPTEA) { regs->dat.raddr = rto | (TT_R3TABL >> 2); cc = 2; return cc; } /* end if(ACCTYPE_LPTEA) */ /* Otherwise set translation exception code */ goto reg_third_excp; asce_type_excp: // logmsg("rfx = %4.4X, rsx %4.4X, rtx = %4.4X, tt = %1.1X\n", // rfx, rsx, rtx, tt); regs->dat.xcode = PGM_ASCE_TYPE_EXCEPTION; cc = 4; goto tran_excp_addr; reg_first_excp: regs->dat.xcode = PGM_REGION_FIRST_TRANSLATION_EXCEPTION; cc = 4; goto tran_excp_addr; reg_second_excp: regs->dat.xcode = PGM_REGION_SECOND_TRANSLATION_EXCEPTION; cc = 4; goto tran_excp_addr; reg_third_excp: regs->dat.xcode = PGM_REGION_THIRD_TRANSLATION_EXCEPTION; cc = 4; goto tran_excp_addr; #endif /*defined(FEATURE_ESAME)*/ tran_excp_addr: /* For LPTEA instruction, return xcode with cc = 3 */ if (acctype & ACC_LPTEA) return 3; /* Set the translation exception address */ regs->TEA = vaddr & PAGEFRAME_PAGEMASK; /* Set the address space indication in the exception address */ #if defined(FEATURE_ESAME) if(regs->dat.stid == TEA_ST_ARMODE) { if ((regs->dat.asd & ASCE_TO) == (regs->CR(1) & ASCE_TO)) regs->TEA |= TEA_ST_PRIMARY; else if ((regs->dat.asd & ASCE_TO) == (regs->CR(7) & ASCE_TO)) regs->TEA |= TEA_ST_SECNDRY; else if ((regs->dat.asd & ASCE_TO) == (regs->CR(13) & ASCE_TO)) regs->TEA |= TEA_ST_HOME; else regs->TEA |= TEA_ST_ARMODE; } else regs->TEA |= regs->dat.stid; #else /*!defined(FEATURE_ESAME)*/ if(regs->dat.stid == TEA_ST_ARMODE) { if ((regs->dat.asd & STD_STO) == (regs->CR(1) & STD_STO)) regs->TEA |= TEA_ST_PRIMARY; else if ((regs->dat.asd & STD_STO) == (regs->CR(7) & STD_STO)) regs->TEA |= TEA_ST_SECNDRY; else if ((regs->dat.asd & STD_STO) == (regs->CR(13) & STD_STO)) regs->TEA |= TEA_ST_HOME; else regs->TEA |= TEA_ST_ARMODE; } else if((regs->dat.stid == TEA_ST_SECNDRY) && (PRIMARY_SPACE_MODE(®s->psw) || SECONDARY_SPACE_MODE(®s->psw))) regs->TEA |= TEA_ST_SECNDRY | TEA_SECADDR; else regs->TEA |= regs->dat.stid; #endif /*!defined(FEATURE_ESAME)*/ #if defined(FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION) /*810*/ /* Set the fetch/store indication bits 52-53 in the TEA */ if (acctype & ACC_READ) { regs->TEA |= TEA_FETCH; } else if (acctype & (ACC_WRITE|ACC_CHECK)) { regs->TEA |= TEA_STORE; } #endif /*defined(FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION)*/ /*810*/ /* Set the exception access identification */ if (ACCESS_REGISTER_MODE(®s->psw) || (SIE_ACTIVE(regs) && MULTIPLE_CONTROLLED_DATA_SPACE(regs->guestregs)) ) regs->excarid = arn > 15 ? 0 : arn; /* Return condition code */ return cc; } /* end function translate_addr */ /*-------------------------------------------------------------------*/ /* Purge the translation lookaside buffer */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(purge_tlb) (REGS *regs) { INVALIDATE_AIA(regs); if (((++regs->tlbID) & TLBID_BYTEMASK) == 0) { memset (®s->tlb.vaddr, 0, TLBN * sizeof(DW)); regs->tlbID = 1; } #if defined(_FEATURE_SIE) /* Also clear the guest registers in the SIE copy */ if(regs->host && regs->guestregs) { INVALIDATE_AIA(regs->guestregs); if (((++regs->guestregs->tlbID) & TLBID_BYTEMASK) == 0) { memset (®s->guestregs->tlb.vaddr, 0, TLBN * sizeof(DW)); regs->guestregs->tlbID = 1; } } #endif /*defined(_FEATURE_SIE)*/ } /* end function purge_tlb */ /*-------------------------------------------------------------------*/ /* Purge the translation lookaside buffer for all CPUs */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(purge_tlb_all) () { int i; for (i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i) && (sysblk.regs[i]->cpubit & sysblk.started_mask)) ARCH_DEP(purge_tlb) (sysblk.regs[i]); } /* end function purge_tlb_all */ /*-------------------------------------------------------------------*/ /* Purge translation lookaside buffer entries */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(purge_tlbe) (REGS *regs, RADR pfra) { int i; RADR pte; RADR ptemask; #if !defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME) ptemask = ((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) ? PAGETAB_PFRA_4K : PAGETAB_PFRA_2K; pte = ((pfra & 0xFFFFFF) >> 8) & ptemask; #endif #if defined(FEATURE_S390_DAT) ptemask = PAGETAB_PFRA; pte = pfra & ptemask; #endif /* defined(FEATURE_S390_DAT) */ #if defined(FEATURE_ESAME) ptemask = (RADR)ZPGETAB_PFRA; pte = pfra & ptemask; #endif /* defined(FEATURE_ESAME) */ INVALIDATE_AIA(regs); for (i = 0; i < TLBN; i++) if ((regs->tlb.TLB_PTE(i) & ptemask) == pte) regs->tlb.TLB_VADDR(i) &= TLBID_PAGEMASK; #if defined(_FEATURE_SIE) /* Also clear the guest registers in the SIE copy */ if (regs->host && regs->guestregs) { INVALIDATE_AIA(regs->guestregs); for (i = 0; i < TLBN; i++) if ((regs->guestregs->tlb.TLB_PTE(i) & ptemask) == pte) regs->guestregs->tlb.TLB_VADDR(i) &= TLBID_PAGEMASK; } else /* For guests, clear any host entries */ if (regs->guest) { INVALIDATE_AIA(regs->hostregs); for (i = 0; i < TLBN; i++) if ((regs->hostregs->tlb.TLB_PTE(i) & ptemask) == pte) regs->hostregs->tlb.TLB_VADDR(i) &= TLBID_PAGEMASK; } #endif /*defined(_FEATURE_SIE)*/ } /* end function purge_tlbe */ /*-------------------------------------------------------------------*/ /* Purge translation lookaside buffer entries for all CPUs */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(purge_tlbe_all) (RADR pfra) { int i; for (i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i) && (sysblk.regs[i]->cpubit & sysblk.started_mask)) ARCH_DEP(purge_tlbe) (sysblk.regs[i], pfra); } /* end function purge_tlbe_all */ /*-------------------------------------------------------------------*/ /* Invalidate all translation lookaside buffer entries */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(invalidate_tlb) (REGS *regs, BYTE mask) { int i; INVALIDATE_AIA(regs); if (mask == 0) memset(®s->tlb.acc, 0, TLBN); else for (i = 0; i < TLBN; i++) if ((regs->tlb.TLB_VADDR(i) & TLBID_BYTEMASK) == regs->tlbID) regs->tlb.acc[i] &= mask; #if defined(_FEATURE_SIE) /* Also invalidate the guest registers in the SIE copy */ if(regs->host && regs->guestregs) { INVALIDATE_AIA(regs->guestregs); if (mask == 0) memset(®s->guestregs->tlb.acc, 0, TLBN); else for (i = 0; i < TLBN; i++) if ((regs->guestregs->tlb.TLB_VADDR(i) & TLBID_BYTEMASK) == regs->guestregs->tlbID) regs->guestregs->tlb.acc[i] &= mask; } else /* Also invalidate the guest registers in the SIE copy */ if(regs->guest) { INVALIDATE_AIA(regs->hostregs); if (mask == 0) memset(®s->hostregs->tlb.acc, 0, TLBN); else for (i = 0; i < TLBN; i++) if ((regs->hostregs->tlb.TLB_VADDR(i) & TLBID_BYTEMASK) == regs->hostregs->tlbID) regs->hostregs->tlb.acc[i] &= mask; } #endif /*defined(_FEATURE_SIE)*/ } /* end function invalidate_tlb */ /*-------------------------------------------------------------------*/ /* Invalidate matching translation lookaside buffer entries */ /* */ /* Input: */ /* main mainstore address to match on. This is mainstore */ /* base plus absolute address (regs->mainstor+aaddr) */ /* */ /* This function is called by the SSK(E) instructions to purge */ /* TLB entries that match the mainstore address. The "main" */ /* field in the TLB contains the mainstore address plus an */ /* XOR hash with effective address (regs->mainstor+aaddr^addr). */ /* Before the compare can happen, the effective address from */ /* the tlb (TLB_VADDR) must be XORed with the "main" field from */ /* the tlb (removing hash). This is done using MAINADDR() macro. */ /* NOTES: */ /* TLB_VADDR does not contain all the effective address bits and */ /* must be created on-the-fly using the tlb index (i << shift). */ /* TLB_VADDR also contains the tlbid, so the regs->tlbid is merged */ /* with the main input variable before the search is begun. */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(invalidate_tlbe) (REGS *regs, BYTE *main) { int i; /* index into TLB */ int shift; /* Number of bits to shift */ BYTE *mainwid; /* mainstore with tlbid */ if (main == NULL) { ARCH_DEP(invalidate_tlb)(regs, 0); return; } mainwid = main + regs->tlbID; INVALIDATE_AIA_MAIN(regs, main); shift = regs->arch_mode == ARCH_370 ? 11 : 12; for (i = 0; i < TLBN; i++) if (MAINADDR(regs->tlb.main[i], (regs->tlb.TLB_VADDR(i) | (i << shift))) == mainwid) { regs->tlb.acc[i] = 0; #if !defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME) if ((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) regs->tlb.acc[i^1] = 0; #endif } #if defined(_FEATURE_SIE) /* Also clear the guest registers in the SIE copy */ if (regs->host && regs->guestregs) { INVALIDATE_AIA_MAIN(regs->guestregs, main); shift = regs->guestregs->arch_mode == ARCH_370 ? 11 : 12; for (i = 0; i < TLBN; i++) if (MAINADDR(regs->guestregs->tlb.main[i], (regs->guestregs->tlb.TLB_VADDR(i) | (i << shift))) == mainwid) { regs->guestregs->tlb.acc[i] = 0; #if !defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME) if ((regs->guestregs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) regs->guestregs->tlb.acc[i^1] = 0; #endif } } /* Also clear the host registers in the SIE copy */ if (regs->guest) { INVALIDATE_AIA_MAIN(regs->hostregs, main); shift = regs->hostregs->arch_mode == ARCH_370 ? 11 : 12; for (i = 0; i < TLBN; i++) if (MAINADDR(regs->hostregs->tlb.main[i], (regs->hostregs->tlb.TLB_VADDR(i) | (i << shift))) == mainwid) { regs->hostregs->tlb.acc[i] = 0; #if !defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME) if ((regs->hostregs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) regs->hostregs->tlb.acc[i^1] = 0; #endif } } #endif /*defined(_FEATURE_SIE)*/ } /* end function invalidate_tlbe */ /*-------------------------------------------------------------------*/ /* Invalidate page table entry */ /* */ /* Input: */ /* ibyte 0x21=IPTE instruction, 0x59=IESBE instruction */ /* r1 First operand register number */ /* r2 Second operand register number */ /* regs CPU register context */ /* */ /* This function is called by the IPTE and IESBE instructions. */ /* It sets the PAGETAB_INVALID bit (for IPTE) or resets the */ /* PAGETAB_ESVALID bit (for IESBE) in the page table entry */ /* addressed by the page table origin in the R1 register and */ /* the page index in the R2 register. It clears the TLB of */ /* all entries whose PFRA matches the page table entry. */ /* */ /* invalidate_pte should be called with the intlock held and */ /* SYNCHRONIZE_CPUS issued while intlock is held. */ /* */ /*-------------------------------------------------------------------*/ _DAT_C_STATIC void ARCH_DEP(invalidate_pte) (BYTE ibyte, RADR op1, U32 op2, REGS *regs) { RADR raddr; /* Addr of page table entry */ RADR pte; RADR pfra; UNREFERENCED_370(ibyte); #if !defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME) { /* Program check if translation format is invalid */ if ((((regs->CR(0) & CR0_PAGE_SIZE) != CR0_PAGE_SZ_2K) && ((regs->CR(0) & CR0_PAGE_SIZE) != CR0_PAGE_SZ_4K)) || (((regs->CR(0) & CR0_SEG_SIZE) != CR0_SEG_SZ_64K) && ((regs->CR(0) & CR0_SEG_SIZE) != CR0_SEG_SZ_1M))) regs->program_interrupt (regs, PGM_TRANSLATION_SPECIFICATION_EXCEPTION); /* Combine the page table origin in the R1 register with the page index in the R2 register, ignoring carry, to form the 31-bit real address of the page table entry */ raddr = (op1 & SEGTAB_370_PTO) + (((regs->CR(0) & CR0_SEG_SIZE) == CR0_SEG_SZ_1M) ? (((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) ? ((op2 & 0x000FF000) >> 11) : ((op2 & 0x000FF800) >> 10)) : (((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) ? ((op2 & 0x0000F000) >> 11) : ((op2 & 0x0000F800) >> 10))); raddr &= 0x00FFFFFF; /* Fetch the page table entry from real storage, subject to normal storage protection mechanisms */ pte = ARCH_DEP(vfetch2) ( raddr, USE_REAL_ADDR, regs ); /* Set the page invalid bit in the page table entry, again subject to storage protection mechansims */ // /*debug*/ logmsg("dat.c: IPTE issued for entry %4.4X at %8.8X...\n" // " page table %8.8X, page index %8.8X, cr0 %8.8X\n", // pte, raddr, regs->GR_L(r1), regs->GR_L(r2), regs->CR(0)); if ((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_2K) pte |= PAGETAB_INV_2K; else pte |= PAGETAB_INV_4K; ARCH_DEP(vstore2) ( pte, raddr, USE_REAL_ADDR, regs ); pfra = ((regs->CR(0) & CR0_PAGE_SIZE) == CR0_PAGE_SZ_4K) ? #if defined(FEATURE_S370E_EXTENDED_ADDRESSING) (((U32)pte & PAGETAB_EA_4K) << 23) | #endif (((U32)pte & PAGETAB_PFRA_4K) << 8) : (((U32)pte & PAGETAB_PFRA_2K) << 8); } #elif defined(FEATURE_S390_DAT) { /* Program check if translation format is invalid */ if ((regs->CR(0) & CR0_TRAN_FMT) != CR0_TRAN_ESA390) regs->program_interrupt (regs, PGM_TRANSLATION_SPECIFICATION_EXCEPTION); /* Combine the page table origin in the R1 register with the page index in the R2 register, ignoring carry, to form the 31-bit real address of the page table entry */ raddr = (op1 & SEGTAB_PTO) + ((op2 & 0x000FF000) >> 10); raddr &= 0x7FFFFFFF; /* Fetch the page table entry from real storage, subject to normal storage protection mechanisms */ pte = ARCH_DEP(vfetch4) ( raddr, USE_REAL_ADDR, regs ); /* Set the page invalid bit in the page table entry, again subject to storage protection mechansims */ #if defined(FEATURE_MOVE_PAGE_FACILITY_2) && defined(FEATURE_EXPANDED_STORAGE) if(ibyte == 0x59) pte &= ~PAGETAB_ESVALID; else #endif /*defined(FEATURE_MOVE_PAGE_FACILITY_2)*/ pte |= PAGETAB_INVALID; ARCH_DEP(vstore4) ( pte, raddr, USE_REAL_ADDR, regs ); pfra = pte & PAGETAB_PFRA; } #else /*defined(FEATURE_ESAME)*/ { /* Combine the page table origin in the R1 register with the page index in the R2 register, ignoring carry, to form the 64-bit real address of the page table entry */ raddr = (op1 & ZSEGTAB_PTO) + ((op2 & 0x000FF000) >> 9); #if defined(MODEL_DEPENDENT) raddr = APPLY_PREFIXING (raddr, regs->PX); #endif /*defined(MODEL_DEPENDENT)*/ /* Fetch the page table entry from real storage, subject to normal storage protection mechanisms */ pte = ARCH_DEP(vfetch8) ( raddr, USE_REAL_ADDR, regs ); /* Set the page invalid bit in the page table entry, again subject to storage protection mechansims */ #if defined(FEATURE_MOVE_PAGE_FACILITY_2) && defined(FEATURE_EXPANDED_STORAGE) if(ibyte == 0x59) pte &= ~ZPGETAB_ESVALID; else #endif /*defined(FEATURE_MOVE_PAGE_FACILITY_2)*/ pte |= ZPGETAB_I; ARCH_DEP(vstore8) ( pte, raddr, USE_REAL_ADDR, regs ); pfra = pte & ZPGETAB_PFRA; } #endif /*defined(FEATURE_ESAME)*/ /* Invalidate TLB entries */ ARCH_DEP(purge_tlbe_all) (pfra); } /* end function invalidate_pte */ #endif /*!defined(OPTION_NO_INLINE_DAT) || defined(_DAT_C) */ #if defined(FEATURE_PER2) /*-------------------------------------------------------------------*/ /* Check for a storage alteration PER2 event */ /* Returns 1 if true, 0 if false */ /*-------------------------------------------------------------------*/ static inline int ARCH_DEP(check_sa_per2) (int arn, int acctype, REGS *regs) { UNREFERENCED(acctype); if((regs->dat.asd & SAEVENT_BIT) || !(regs->CR(9) & CR9_SAC)) { regs->peraid = arn > 0 && arn < 16 ? arn : 0; regs->perc |= regs->dat.stid; return 1; } return 0; } /* end function check_sa_per2 */ #endif /*defined(FEATURE_PER2)*/ #if !defined(OPTION_NO_INLINE_LOGICAL) || defined(_DAT_C) /*-------------------------------------------------------------------*/ /* Convert logical address to absolute address and check protection */ /* */ /* Input: */ /* addr Logical address to be translated */ /* arn Access register number (or USE_REAL_ADDR, */ /* USE_PRIMARY_SPACE, USE_SECONDARY_SPACE) */ /* regs CPU register context */ /* acctype Type of access requested: READ, WRITE, or instfetch */ /* akey Bits 0-3=access key, 4-7=zeroes */ /* len Length of data access for PER SA purpose */ /* Returns: */ /* Absolute storage address. */ /* */ /* If the PSW indicates DAT-off, or if the access register */ /* number parameter is the special value USE_REAL_ADDR, */ /* then the addr parameter is treated as a real address. */ /* Otherwise addr is a virtual address, so dynamic address */ /* translation is called to convert it to a real address. */ /* Prefixing is then applied to convert the real address to */ /* an absolute address, and then low-address protection, */ /* access-list controlled protection, page protection, and */ /* key controlled protection checks are applied to the address. */ /* If successful, the reference and change bits of the storage */ /* key are updated, and the absolute address is returned. */ /* */ /* If the logical address causes an addressing, protection, */ /* or translation exception then a program check is generated */ /* and the function does not return. */ /*-------------------------------------------------------------------*/ _LOGICAL_C_STATIC BYTE *ARCH_DEP(logical_to_main_l) (VADR addr, int arn, REGS *regs, int acctype, BYTE akey, size_t len) { RADR aaddr; /* Absolute address */ RADR apfra; /* Abs page frame address */ int ix = TLBIX(addr); /* TLB index */ /* Convert logical address to real address */ if ( (REAL_MODE(®s->psw) || arn == USE_REAL_ADDR) #if defined(FEATURE_INTERPRETIVE_EXECUTION) /* Under SIE guest real is always host primary, regardless of the DAT mode */ && !(regs->sie_active #if !defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) && arn == USE_PRIMARY_SPACE #else // && ( (arn == USE_PRIMARY_SPACE) // || SIE_STATB(regs->guestregs, MX, XC) ) #endif /*defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ ) { regs->dat.private = regs->dat.protect = 0; regs->dat.raddr = addr; regs->dat.rpfra = addr & PAGEFRAME_PAGEMASK; /* Setup `real' TLB entry (for MADDR) */ regs->tlb.TLB_ASD(ix) = TLB_REAL_ASD; regs->tlb.TLB_VADDR(ix) = (addr & TLBID_PAGEMASK) | regs->tlbID; regs->tlb.TLB_PTE(ix) = addr & TLBID_PAGEMASK; regs->tlb.acc[ix] = regs->tlb.common[ix] = regs->tlb.protect[ix] = 0; } else { if (ARCH_DEP(translate_addr) (addr, arn, regs, acctype)) goto vabs_prog_check; } if (regs->dat.protect && (acctype & (ACC_WRITE|ACC_CHECK))) goto vabs_prot_excp; /* Convert real address to absolute address */ regs->dat.aaddr = aaddr = APPLY_PREFIXING (regs->dat.raddr, regs->PX); apfra=APPLY_PREFIXING(regs->dat.rpfra,regs->PX); /* Program check if absolute address is outside main storage */ if (regs->dat.aaddr > regs->mainlim) goto vabs_addr_excp; #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) regs->hostregs->dat.protect = 0; if(SIE_MODE(regs) && !regs->sie_pref) { if (SIE_TRANSLATE_ADDR (regs->sie_mso + regs->dat.aaddr, (arn > 0 && arn < 16 && MULTIPLE_CONTROLLED_DATA_SPACE(regs)) ? arn : USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) (regs->hostregs->program_interrupt) (regs->hostregs, regs->hostregs->dat.xcode); regs->dat.protect |= regs->hostregs->dat.protect; regs->tlb.protect[ix] |= regs->hostregs->dat.protect; if ( REAL_MODE(®s->psw) || (arn == USE_REAL_ADDR) ) regs->tlb.TLB_PTE(ix) = addr & TLBID_PAGEMASK; /* Indicate a host real space entry for a XC dataspace */ if (arn > 0 && arn < 16 && MULTIPLE_CONTROLLED_DATA_SPACE(regs)) { regs->tlb.TLB_ASD(ix) = regs->dat.asd; /* Ensure that the private bit is percolated to the guest such that LAP is applied correctly */ regs->dat.private = regs->hostregs->dat.private; /* Build tlb entry of XC dataspace */ regs->dat.asd = regs->hostregs->dat.asd ^ TLB_HOST_ASD; regs->CR(CR_ALB_OFFSET + arn) = regs->dat.asd; regs->aea_ar[arn] = CR_ALB_OFFSET + arn; regs->aea_common[CR_ALB_OFFSET + arn] = (regs->dat.asd & ASD_PRIVATE) == 0; regs->aea_aleprot[arn] = regs->hostregs->dat.protect & 2; } /* Convert host real address to host absolute address */ regs->hostregs->dat.aaddr = aaddr = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); apfra = APPLY_PREFIXING(regs->hostregs->dat.rpfra, regs->hostregs->PX); if(regs->hostregs->dat.aaddr > regs->hostregs->mainlim) goto vabs_addr_excp; /* Take into account SIE guests with a 2K page scheme because the SIE host may be operating with a 4K page system */ #if defined(FEATURE_2K_STORAGE_KEYS) if((addr & PAGEFRAME_PAGEMASK) & 0x800) { apfra|=0x800; } #endif } #endif /*defined(_FEATURE_SIE)*/ /* Check protection and set reference and change bits */ regs->dat.storkey = &(STORAGE_KEY(aaddr, regs)); #if defined(_FEATURE_SIE) /* Do not apply host key access when SIE fetches/stores data */ if (unlikely(SIE_ACTIVE(regs))) return regs->mainstor + aaddr; #endif /*defined(_FEATURE_SIE)*/ if (likely(acctype & ACC_READ)) { /* Program check if fetch protected location */ if (unlikely(ARCH_DEP(is_fetch_protected) (addr, *regs->dat.storkey, akey, regs))) { if (SIE_MODE(regs)) regs->hostregs->dat.protect = 0; goto vabs_prot_excp; } /* Set the reference bit in the storage key */ *regs->dat.storkey |= STORKEY_REF; /* Update accelerated lookup TLB fields */ regs->tlb.storkey[ix] = regs->dat.storkey; regs->tlb.skey[ix] = *regs->dat.storkey & STORKEY_KEY; regs->tlb.acc[ix] = ACC_READ; regs->tlb.main[ix] = NEW_MAINADDR (regs, addr, apfra); } else /* if(acctype & (ACC_WRITE|ACC_CHECK)) */ { /* Program check if store protected location */ if (unlikely(ARCH_DEP(is_store_protected) (addr, *regs->dat.storkey, akey, regs))) { if (SIE_MODE(regs)) regs->hostregs->dat.protect = 0; goto vabs_prot_excp; } if (SIE_MODE(regs) && regs->hostregs->dat.protect) goto vabs_prot_excp; /* Set the reference and change bits in the storage key */ if (acctype & ACC_WRITE) *regs->dat.storkey |= (STORKEY_REF | STORKEY_CHANGE); /* Update accelerated lookup TLB fields */ regs->tlb.storkey[ix] = regs->dat.storkey; regs->tlb.skey[ix] = *regs->dat.storkey & STORKEY_KEY; regs->tlb.acc[ix] = (addr >= PSA_SIZE || regs->dat.private) ? (ACC_READ|ACC_CHECK|acctype) : ACC_READ; regs->tlb.main[ix] = NEW_MAINADDR (regs, addr, apfra); #if defined(FEATURE_PER) if (EN_IC_PER_SA(regs)) { regs->tlb.acc[ix] = ACC_READ; if (arn != USE_REAL_ADDR #if defined(FEATURE_PER2) && ( REAL_MODE(®s->psw) || ARCH_DEP(check_sa_per2) (arn, acctype, regs) ) #endif /*defined(FEATURE_PER2)*/ /* Check the range altered enters the SA PER range */ && PER_RANGE_CHECK2(addr,addr+(len-1),regs->CR(10),regs->CR(11)) ) ON_IC_PER_SA(regs); } #endif /*defined(FEATURE_PER)*/ } /* acctype & ACC_WRITE|CHECK */ /* Return mainstor address */ return regs->mainstor + aaddr; vabs_addr_excp: regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); vabs_prot_excp: #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = addr & STORAGE_KEY_PAGEMASK; if (regs->dat.protect && (acctype & (ACC_WRITE|ACC_CHECK)) ) { regs->TEA |= TEA_PROT_AP; #if defined(FEATURE_ESAME) if (regs->dat.protect & 2) regs->TEA |= TEA_PROT_A; #endif /*defined(FEATURE_ESAME)*/ } regs->TEA |= regs->dat.stid; regs->excarid = (arn > 0 && arn < 16 ? arn : 0); #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ #if defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL) if(SIE_MODE(regs) && regs->hostregs->dat.protect) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->hostregs->TEA = regs->TEA; regs->hostregs->excarid = regs->excarid; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ (regs->hostregs->program_interrupt) (regs->hostregs, PGM_PROTECTION_EXCEPTION); } else #endif /*defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL)*/ regs->program_interrupt (regs, PGM_PROTECTION_EXCEPTION); vabs_prog_check: regs->program_interrupt (regs, regs->dat.xcode); return NULL; /* prevent warning from compiler */ } /* end function ARCH_DEP(logical_to_main_l) */ /* Original logical_to_main() for compatiblity purpose */ _LOGICAL_C_STATIC BYTE *ARCH_DEP(logical_to_main) (VADR addr, int arn, REGS *regs, int acctype, BYTE akey) { return ARCH_DEP(logical_to_main_l)(addr,arn,regs,acctype,akey,1); } #endif /*!defined(OPTION_NO_INLINE_LOGICAL) || defined(_DAT_C) */ /* end of DAT.H */ hercules-3.12/vstore.h0000664000175000017500000014632212564723224011706 00000000000000/* VSTORE.H (c) Copyright Roger Bowler, 1999-2011 */ /* ESA/390 Virtual Storage Functions */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module contains various functions which store, fetch, and */ /* copy values to, from, or between virtual storage locations. */ /* */ /* Functions provided in this module are: */ /* vstorec Store 1 to 256 characters into virtual storage */ /* vstoreb Store a single byte into virtual storage */ /* vstore2 Store a two-byte integer into virtual storage */ /* vstore4 Store a four-byte integer into virtual storage */ /* vstore8 Store an eight-byte integer into virtual storage */ /* vfetchc Fetch 1 to 256 characters from virtual storage */ /* vfetchb Fetch a single byte from virtual storage */ /* vfetch2 Fetch a two-byte integer from virtual storage */ /* vfetch4 Fetch a four-byte integer from virtual storage */ /* vfetch8 Fetch an eight-byte integer from virtual storage */ /* instfetch Fetch instruction from virtual storage */ /* move_chars Move characters using specified keys and addrspaces */ /* move_charx Move characters with optional specifications */ /* validate_operand Validate addressing, protection, translation */ /*-------------------------------------------------------------------*/ /* And provided by means of macro's address wrapping versions of */ /* the above: */ /* wstoreX */ /* wfetchX */ /* wmove_chars */ /* wvalidate_operand */ /*-------------------------------------------------------------------*/ #define s370_wstorec(_src, _len, _addr, _arn, _regs) \ s370_vstorec((_src), (_len), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wstoreb(_value, _addr, _arn, _regs) \ s370_vstoreb((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wstore2(_value, _addr, _arn, _regs) \ s370_vstore2((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wstore4(_value, _addr, _arn, _regs) \ s370_vstore4((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wstore8(_value, _addr, _arn, _regs) \ s370_vstore8((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wfetchc(_dest, _len, _addr, _arn, _regs) \ s370_vfetchc((_dest), (_len), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wfetchb(_addr, _arn, _regs) \ s370_vfetchb(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wfetch2(_addr, _arn, _regs) \ s370_vfetch2(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wfetch4(_addr, _arn, _regs) \ s370_vfetch4(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wfetch8(_addr, _arn, _regs) \ s370_vfetch8(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s370_wmove_chars(_addr1, _arn1, _key1, _addr2, _arn2, _key2, _len, _regs) \ s370_move_chars(((_addr1) & ADDRESS_MAXWRAP((_regs))), (_arn1), (_key1), \ ((_addr2) & ADDRESS_MAXWRAP((_regs))), (_arn2), (_key2), (_len), (_regs)) #define s370_wvalidate_operand(_addr, _arn, _len, _acctype, _regs) \ s370_validate_operand(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_len), (_acctype), (_regs)) #define s390_wstorec(_src, _len, _addr, _arn, _regs) \ s390_vstorec((_src), (_len), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wstoreb(_value, _addr, _arn, _regs) \ s390_vstoreb((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wstore2(_value, _addr, _arn, _regs) \ s390_vstore2((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wstore4(_value, _addr, _arn, _regs) \ s390_vstore4((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wstore8(_value, _addr, _arn, _regs) \ s390_vstore8((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wfetchc(_dest, _len, _addr, _arn, _regs) \ s390_vfetchc((_dest), (_len), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wfetchb(_addr, _arn, _regs) \ s390_vfetchb(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wfetch2(_addr, _arn, _regs) \ s390_vfetch2(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wfetch4(_addr, _arn, _regs) \ s390_vfetch4(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wfetch8(_addr, _arn, _regs) \ s390_vfetch8(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define s390_wmove_chars(_addr1, _arn1, _key1, _addr2, _arn2, _key2, _len, _regs) \ s390_move_chars(((_addr1) & ADDRESS_MAXWRAP((_regs))), (_arn1), (_key1), \ ((_addr2) & ADDRESS_MAXWRAP((_regs))), (_arn2), (_key2), (_len), (_regs)) #define s390_wvalidate_operand(_addr, _arn, _len, _acctype, _regs) \ s390_validate_operand(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_len), (_acctype), (_regs)) #define z900_wstorec(_src, _len, _addr, _arn, _regs) \ z900_vstorec((_src), (_len), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wstoreb(_value, _addr, _arn, _regs) \ z900_vstoreb((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wstore2(_value, _addr, _arn, _regs) \ z900_vstore2((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wstore4(_value, _addr, _arn, _regs) \ z900_vstore4((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wstore8(_value, _addr, _arn, _regs) \ z900_vstore8((_value), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wfetchc(_dest, _len, _addr, _arn, _regs) \ z900_vfetchc((_dest), (_len), ((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wfetchb(_addr, _arn, _regs) \ z900_vfetchb(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wfetch2(_addr, _arn, _regs) \ z900_vfetch2(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wfetch4(_addr, _arn, _regs) \ z900_vfetch4(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wfetch8(_addr, _arn, _regs) \ z900_vfetch8(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_regs)) #define z900_wmove_chars(_addr1, _arn1, _key1, _addr2, _arn2, _key2, _len, _regs) \ z900_move_chars(((_addr1) & ADDRESS_MAXWRAP((_regs))), (_arn1), (_key1), \ ((_addr2) & ADDRESS_MAXWRAP((_regs))), (_arn2), (_key2), (_len), (_regs)) #define z900_wvalidate_operand(_addr, _arn, _len, _acctype, _regs) \ z900_validate_operand(((_addr) & ADDRESS_MAXWRAP((_regs))), (_arn), (_len), (_acctype), (_regs)) /*-------------------------------------------------------------------*/ /* Operand Length Checking Macros */ /* */ /* The following macros are used to determine whether an operand */ /* storage access will cross a 2K page boundary or not. */ /* */ /* The first 'plain' pair of macros (without the 'L') are used for */ /* 0-based lengths wherein zero = 1 byte is being referenced and 255 */ /* means 256 bytes are being referenced. They are obviously designed */ /* for maximum length values of 0-255 as used w/MVC instructions. */ /* */ /* The second pair of 'L' macros are using for 1-based lengths where */ /* 0 = no bytes are being referenced, 1 = one byte, etc. They are */ /* designed for 'Large' maximum length values such as occur with the */ /* MVCL instruction for example (where the length can be up to 16MB) */ /*-------------------------------------------------------------------*/ #define NOCROSS2K(_addr,_len) likely( ( (int)((_addr) & 0x7FF)) <= ( 0x7FF - (_len) ) ) #define CROSS2K(_addr,_len) unlikely( ( (int)((_addr) & 0x7FF)) > ( 0x7FF - (_len) ) ) #define NOCROSS2KL(_addr,_len) likely( ( (int)((_addr) & 0x7FF)) <= ( 0x800 - (_len) ) ) #define CROSS2KL(_addr,_len) unlikely( ( (int)((_addr) & 0x7FF)) > ( 0x800 - (_len) ) ) #if !defined(OPTION_NO_INLINE_VSTORE) || defined(_VSTORE_C) /*-------------------------------------------------------------------*/ /* Store 1 to 256 characters into virtual storage operand */ /* */ /* Input: */ /* src 1 to 256 byte input buffer */ /* len Size of operand minus 1 */ /* addr Logical address of leftmost character of operand */ /* arn Access register number */ /* regs CPU register context */ /* */ /* A program check may be generated if the logical address */ /* range causes an addressing, translation, or protection */ /* exception, and in this case no real storage locations are */ /* updated, and the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_C_STATIC void ARCH_DEP(vstorec) (void *src, BYTE len, VADR addr, int arn, REGS *regs) { BYTE *main1, *main2; /* Mainstor addresses */ BYTE *sk; /* Storage key addresses */ int len2; /* Length to end of page */ if ( NOCROSS2K(addr,len) ) { memcpy(MADDRL(addr, len+1, arn, regs, ACCTYPE_WRITE, regs->psw.pkey), src, len + 1); ITIMER_UPDATE(addr,len,regs); } else { len2 = 0x800 - (addr & 0x7FF); main1 = MADDRL(addr, len2, arn, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk = regs->dat.storkey; main2 = MADDRL((addr + len2) & ADDRESS_MAXWRAP(regs), len+1-len2, arn, regs, ACCTYPE_WRITE, regs->psw.pkey); *sk |= (STORKEY_REF | STORKEY_CHANGE); memcpy (main1, src, len2); memcpy (main2, (BYTE*)src + len2, len + 1 - len2); } } /* end function ARCH_DEP(vstorec) */ /*-------------------------------------------------------------------*/ /* Store a single byte into virtual storage operand */ /* */ /* Input: */ /* value Byte value to be stored */ /* addr Logical address of operand byte */ /* arn Access register number */ /* regs CPU register context */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_C_STATIC void ARCH_DEP(vstoreb) (BYTE value, VADR addr, int arn, REGS *regs) { BYTE *main1; /* Mainstor address */ main1 = MADDR(addr, arn, regs, ACCTYPE_WRITE, regs->psw.pkey); *main1 = value; ITIMER_UPDATE(addr,1-1,regs); } /* end function ARCH_DEP(vstoreb) */ /*-------------------------------------------------------------------*/ /* Store a two-byte integer into virtual storage operand */ /* */ /* Input: */ /* value 16-bit integer value to be stored */ /* addr Logical address of leftmost operand byte */ /* arn Access register number */ /* regs CPU register context */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_FULL_C_STATIC void ARCH_DEP(vstore2_full)(U16 value, VADR addr, int arn, REGS *regs) { BYTE *main1, *main2; /* Mainstor addresses */ BYTE *sk; /* Storage key addresses */ main1 = MADDR(addr, arn, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk = regs->dat.storkey; main2 = MADDR((addr + 1) & ADDRESS_MAXWRAP(regs), arn, regs, ACCTYPE_WRITE, regs->psw.pkey); *sk |= (STORKEY_REF | STORKEY_CHANGE); *main1 = value >> 8; *main2 = value & 0xFF; } /* end function ARCH_DEP(vstore2_full) */ /* vstore2 accelerator - Simple case only (better inline candidate) */ _VSTORE_C_STATIC void ARCH_DEP(vstore2) (U16 value, VADR addr, int arn, REGS *regs) { /* Most common case : Aligned & not crossing page boundary */ if (likely(!((VADR_L)addr & 1) || ((VADR_L)addr & 0x7FF) != 0x7FF)) { BYTE *mn; mn = MADDRL (addr, 2, arn, regs, ACCTYPE_WRITE, regs->psw.pkey); STORE_HW(mn, value); ITIMER_UPDATE(addr,2-1,regs); } else ARCH_DEP(vstore2_full)(value, addr, arn, regs); } /* end function ARCH_DEP(vstore2) */ /*-------------------------------------------------------------------*/ /* Store a four-byte integer into virtual storage operand */ /* */ /* Input: */ /* value 32-bit integer value to be stored */ /* addr Logical address of leftmost operand byte */ /* arn Access register number */ /* regs CPU register context */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_FULL_C_STATIC void ARCH_DEP(vstore4_full)(U32 value, VADR addr, int arn, REGS *regs) { BYTE *main1, *main2; /* Mainstor addresses */ BYTE *sk; /* Storage key addresses */ int len; /* Length to end of page */ BYTE temp[4]; /* Copied value */ len = 0x800 - (addr & 0x7FF); main1 = MADDRL(addr, len, arn, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk = regs->dat.storkey; main2 = MADDRL((addr + len) & ADDRESS_MAXWRAP(regs), 4-len, arn, regs, ACCTYPE_WRITE, regs->psw.pkey); *sk |= (STORKEY_REF | STORKEY_CHANGE); STORE_FW(temp, value); memcpy(main1, temp, len); memcpy(main2, temp+len, 4-len); } /* end function ARCH_DEP(vstore4_full) */ /* vstore4 accelerator - Simple case only (better inline candidate) */ _VSTORE_C_STATIC void ARCH_DEP(vstore4) (U32 value, VADR addr, int arn, REGS *regs) { /* Most common case : Aligned & not crossing page boundary */ if(likely(!((VADR_L)addr & 0x03)) || (((VADR_L)addr & 0x7ff) <= 0x7fc)) { BYTE *mn; mn = MADDRL(addr, 4, arn, regs, ACCTYPE_WRITE, regs->psw.pkey); STORE_FW(mn, value); ITIMER_UPDATE(addr,4-1,regs); } else ARCH_DEP(vstore4_full)(value,addr,arn,regs); } /*-------------------------------------------------------------------*/ /* Store an eight-byte integer into virtual storage operand */ /* */ /* Input: */ /* value 64-bit integer value to be stored */ /* addr Logical address of leftmost operand byte */ /* arn Access register number */ /* regs CPU register context */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or protection */ /* exception, and in this case the function does not return. */ /* */ /* NOTE that vstore8_full should only be invoked when a page */ /* boundary IS going to be crossed. */ /*-------------------------------------------------------------------*/ _VSTORE_FULL_C_STATIC void ARCH_DEP(vstore8_full)(U64 value, VADR addr, int arn, REGS *regs) { BYTE *main1, *main2; /* Mainstor addresses */ BYTE *sk; /* Storage key addresses */ int len; /* Length to end of page */ BYTE temp[8]; /* Copied value */ len = 0x800 - (addr & 0x7FF); main1 = MADDRL(addr, len, arn, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk = regs->dat.storkey; main2 = MADDRL((addr + len) & ADDRESS_MAXWRAP(regs), 8-len, arn, regs, ACCTYPE_WRITE, regs->psw.pkey); *sk |= (STORKEY_REF | STORKEY_CHANGE); STORE_DW(temp, value); memcpy(main1, temp, len); memcpy(main2, temp+len, 8-len); } /* end function ARCH_DEP(vstore8) */ _VSTORE_C_STATIC void ARCH_DEP(vstore8) (U64 value, VADR addr, int arn, REGS *regs) { #if defined(OPTION_SINGLE_CPU_DW) && defined(ASSIST_STORE_DW) /* Check alignement. If aligned then we are guaranteed not to cross a page boundary */ if(likely(!((VADR_L)addr & 0x07))) { /* Most common case : Aligned */ U64 *mn; mn = (U64*)MADDRL(addr,8,arn,regs,ACCTYPE_WRITE,regs->psw.pkey); if (regs->cpubit == regs->sysblk->started_mask) *mn = CSWAP64(value); else STORE_DW(mn, value); } else #endif { /* We're not aligned. So we have to check whether we are crossing a page boundary. This cannot be the same code as above because casting U64 * to a non aligned pointer may break on those architectures mandating strict alignement */ if(likely(((VADR_L)addr & 0x7ff) <= 0x7f8)) { /* Non aligned but not crossing page boundary */ BYTE *mn; mn = MADDRL(addr,8,arn,regs,ACCTYPE_WRITE,regs->psw.pkey); /* invoking STORE_DW ensures endianness correctness */ STORE_DW(mn,value); } else /* Crossing page boundary */ ARCH_DEP(vstore8_full)(value,addr,arn,regs); } ITIMER_UPDATE(addr,8-1,regs); } /*-------------------------------------------------------------------*/ /* Fetch a 1 to 256 character operand from virtual storage */ /* */ /* Input: */ /* len Size of operand minus 1 */ /* addr Logical address of leftmost character of operand */ /* arn Access register number */ /* regs CPU register context */ /* Output: */ /* dest 1 to 256 byte output buffer */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_C_STATIC void ARCH_DEP(vfetchc) (void *dest, BYTE len, VADR addr, int arn, REGS *regs) { BYTE *main1, *main2; /* Main storage addresses */ int len2; /* Length to copy on page */ main1 = MADDR(addr,arn,regs,ACCTYPE_READ,regs->psw.pkey); if ( NOCROSS2K(addr,len) ) { ITIMER_SYNC(addr,len,regs); memcpy (dest, main1, len + 1); } else { len2 = 0x800 - (addr & 0x7FF); main2 = MADDR ((addr + len2) & ADDRESS_MAXWRAP(regs), arn, regs, ACCTYPE_READ, regs->psw.pkey); memcpy (dest, main1, len2); memcpy ((BYTE*)dest + len2, main2, len + 1 - len2); } } /* end function ARCH_DEP(vfetchc) */ /*-------------------------------------------------------------------*/ /* Fetch a single byte operand from virtual storage */ /* */ /* Input: */ /* addr Logical address of operand character */ /* arn Access register number */ /* regs CPU register context */ /* Returns: */ /* Operand byte */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_C_STATIC BYTE ARCH_DEP(vfetchb) (VADR addr, int arn, REGS *regs) { BYTE *mn; /* Main storage address */ ITIMER_SYNC(addr,1-1,regs); mn = MADDR (addr, arn, regs, ACCTYPE_READ, regs->psw.pkey); return *mn; } /* end function ARCH_DEP(vfetchb) */ /*-------------------------------------------------------------------*/ /* Fetch a two-byte integer operand from virtual storage */ /* */ /* Input: */ /* addr Logical address of leftmost byte of operand */ /* arn Access register number */ /* regs CPU register context */ /* Returns: */ /* Operand in 16-bit integer format */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_FULL_C_STATIC U16 ARCH_DEP(vfetch2_full) (VADR addr, int arn, REGS *regs) { BYTE *mn; /* Main storage addresses */ U16 value; mn = MADDR (addr, arn, regs, ACCTYPE_READ, regs->psw.pkey); value = *mn << 8; mn = MADDR ((addr + 1) & ADDRESS_MAXWRAP(regs), arn, regs, ACCTYPE_READ, regs->psw.pkey); value |= *mn; return value; } /* end function ARCH_DEP(vfetch2) */ _VSTORE_C_STATIC U16 ARCH_DEP(vfetch2) (VADR addr, int arn, REGS *regs) { if(likely(!((VADR_L)addr & 0x01)) || (((VADR_L)addr & 0x7ff) !=0x7ff )) { BYTE *mn; ITIMER_SYNC(addr,2-1,regs); mn = MADDR(addr,arn,regs,ACCTYPE_READ,regs->psw.pkey); return fetch_hw(mn); } return(ARCH_DEP(vfetch2_full)(addr,arn,regs)); } /*-------------------------------------------------------------------*/ /* Fetch a four-byte integer operand from virtual storage */ /* */ /* Input: */ /* addr Logical address of leftmost byte of operand */ /* arn Access register number */ /* regs CPU register context */ /* Returns: */ /* Operand in 32-bit integer format */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_FULL_C_STATIC U32 ARCH_DEP(vfetch4_full) (VADR addr, int arn, REGS *regs) { BYTE *mn; /* Main storage addresses */ int len; /* Length to end of page */ BYTE temp[8]; /* Copy destination */ mn = MADDR (addr, arn, regs, ACCTYPE_READ, regs->psw.pkey); memcpy(temp, mn, 4); len = 0x800 - (addr & 0x7FF); mn = MADDR ((addr + len) & ADDRESS_MAXWRAP(regs), arn, regs, ACCTYPE_READ, regs->psw.pkey); memcpy(temp+len, mn, 4); return fetch_fw(temp); } /* end function ARCH_DEP(vfetch4_full) */ _VSTORE_C_STATIC U32 ARCH_DEP(vfetch4) (VADR addr, int arn, REGS *regs) { if ( (likely(!((VADR_L)addr & 0x03)) || (((VADR_L)addr & 0x7ff) <= 0x7fc ))) { BYTE *mn; ITIMER_SYNC(addr,4-1,regs); mn=MADDR(addr,arn,regs,ACCTYPE_READ,regs->psw.pkey); return fetch_fw(mn); } return(ARCH_DEP(vfetch4_full)(addr,arn,regs)); } /*-------------------------------------------------------------------*/ /* Fetch an eight-byte integer operand from virtual storage */ /* */ /* Input: */ /* addr Logical address of leftmost byte of operand */ /* arn Access register number */ /* regs CPU register context */ /* Returns: */ /* Operand in 64-bit integer format */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_FULL_C_STATIC U64 ARCH_DEP(vfetch8_full) (VADR addr, int arn, REGS *regs) { BYTE *mn; /* Main storage addresses */ int len; /* Length to end of page */ BYTE temp[16]; /* Copy destination */ /* Get absolute address of first byte of operand */ mn = MADDR (addr, arn, regs, ACCTYPE_READ, regs->psw.pkey); memcpy(temp, mn, 8); len = 0x800 - (addr & 0x7FF); mn = MADDR ((addr + len) & ADDRESS_MAXWRAP(regs), arn, regs, ACCTYPE_READ, regs->psw.pkey); memcpy(temp+len, mn, 8); return fetch_dw(temp); } /* end function ARCH_DEP(vfetch8) */ _VSTORE_C_STATIC U64 ARCH_DEP(vfetch8) (VADR addr, int arn, REGS *regs) { #if defined(OPTION_SINGLE_CPU_DW) && defined(ASSIST_STORE_DW) if(likely(!((VADR_L)addr & 0x07))) { /* doubleword aligned fetch */ U64 *mn; ITIMER_SYNC(addr,8-1,regs); mn=(U64*)MADDR (addr, arn, regs, ACCTYPE_READ, regs->psw.pkey); if (regs->cpubit == regs->sysblk->started_mask) return CSWAP64(*mn); return fetch_dw(mn); } else #endif { if(likely(((VADR_L)addr & 0x7ff) <= 0x7f8)) { /* unaligned, non-crossing doubleword fetch */ BYTE *mn; ITIMER_SYNC(addr,8-1,regs); mn=MADDR (addr, arn, regs, ACCTYPE_READ, regs->psw.pkey); return fetch_dw(mn); } } /* page crossing doubleword fetch */ return ARCH_DEP(vfetch8_full)(addr,arn,regs); } #endif #if !defined(OPTION_NO_INLINE_IFETCH) || defined(_VSTORE_C) /*-------------------------------------------------------------------*/ /* Fetch instruction from halfword-aligned virtual storage location */ /* */ /* Input: */ /* regs Pointer to the CPU register context */ /* exec If 1 then called by EXecute otherwise called by */ /* INSTRUCTION_FETCH */ /* */ /* If called by INSTRUCTION_FETCH then */ /* addr regs->psw.IA */ /* dest regs->inst */ /* */ /* If called by EXecute then */ /* addr regs->ET */ /* dest regs->exinst */ /* */ /* Output: */ /* If successful, a pointer is returned to the instruction. If */ /* the instruction crossed a page boundary then the instruction */ /* is copied either to regs->inst or regs->exinst (depending on */ /* the exec flag). Otherwise the pointer points into mainstor. */ /* */ /* If the exec flag is 0 and tracing or PER is not active then */ /* the AIA is updated. This forces interrupts to be checked */ /* instfetch to be call for each instruction. Note that */ /* process_trace() is called from here if tracing is active. */ /* */ /* A program check may be generated if the instruction address */ /* is odd, or causes an addressing or translation exception, */ /* and in this case the function does not return. In the */ /* latter case, regs->instinvalid is 1 which indicates to */ /* program_interrupt that the exception occurred during */ /* instruction fetch. */ /* */ /* Because this function is inlined and `exec' is a constant */ /* (either 0 or 1) the references to exec are optimized out by */ /* the compiler. */ /*-------------------------------------------------------------------*/ _VFETCH_C_STATIC BYTE * ARCH_DEP(instfetch) (REGS *regs, int exec) { VADR addr; /* Instruction address */ BYTE *ia; /* Instruction pointer */ BYTE *dest; /* Copied instruction */ int pagesz; /* Effective page size */ int offset; /* Address offset into page */ int len; /* Length for page crossing */ SET_BEAR_REG(regs, regs->bear_ip); addr = exec ? regs->ET : likely(regs->aie == NULL) ? regs->psw.IA : PSW_IA(regs,0); offset = (int)(addr & PAGEFRAME_BYTEMASK); /* Program check if instruction address is odd */ if ( unlikely(offset & 0x01) ) { if (!exec) regs->instinvalid = 1; regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION); } pagesz = unlikely(addr < 0x800) ? 0x800 : PAGEFRAME_PAGESIZE; #if defined(FEATURE_PER) /* Save the address address used to fetch the instruction */ if( EN_IC_PER(regs) ) { #if defined(FEATURE_PER2) regs->perc = 0x40 /* ATMID-validity */ | (regs->psw.amode64 << 7) | (regs->psw.amode << 5) | (!REAL_MODE(®s->psw) ? 0x10 : 0) | (SPACE_BIT(®s->psw) << 3) | (AR_BIT(®s->psw) << 2); #else /*!defined(FEATURE_PER2)*/ regs->perc = 0; #endif /*!defined(FEATURE_PER2)*/ if(!exec) regs->peradr = addr; /* Test for PER instruction-fetching event */ if( EN_IC_PER_IF(regs) && PER_RANGE_CHECK(addr,regs->CR(10),regs->CR(11)) ) { ON_IC_PER_IF(regs); #if defined(FEATURE_PER3) /* If CR9_IFNUL (PER instruction-fetching nullification) is set, take a program check immediately, without executing the instruction or updating the PSW instruction address */ if ( EN_IC_PER_IFNUL(regs) ) { ON_IC_PER_IFNUL(regs); regs->psw.IA = addr; regs->psw.zeroilc = 1; regs->program_interrupt(regs, PGM_PER_EVENT); } #endif /*defined(FEATURE_PER3)*/ } /* Quick exit if aia valid */ if (!exec && !regs->tracing && regs->aie && regs->ip < regs->aip + pagesz - 5) return regs->ip; } #endif /*defined(FEATURE_PER)*/ if (!exec) regs->instinvalid = 1; /* Get instruction address */ ia = MADDR (addr, USE_INST_SPACE, regs, ACCTYPE_INSTFETCH, regs->psw.pkey); /* If boundary is crossed then copy instruction to destination */ if ( offset + ILC(ia[0]) > pagesz ) { /* Note - dest is 8 bytes */ dest = exec ? regs->exinst : regs->inst; memcpy (dest, ia, 4); len = pagesz - offset; offset = 0; addr = (addr + len) & ADDRESS_MAXWRAP(regs); ia = MADDR(addr, USE_INST_SPACE, regs, ACCTYPE_INSTFETCH, regs->psw.pkey); if (!exec) regs->ip = ia - len; memcpy(dest + len, ia, 4); } else { dest = ia; if (!exec) regs->ip = ia; } if (!exec) { regs->instinvalid = 0; /* Update the AIA */ regs->AIV = addr & PAGEFRAME_PAGEMASK; regs->aip = (BYTE *)((uintptr_t)ia & ~PAGEFRAME_BYTEMASK); regs->aim = (uintptr_t)regs->aip ^ (uintptr_t)regs->AIV; if (likely(!regs->tracing && !regs->permode)) regs->aie = regs->aip + pagesz - 5; else { regs->aie = (BYTE *)1; if (regs->tracing) ARCH_DEP(process_trace)(regs); } } return dest; } /* end function ARCH_DEP(instfetch) */ #endif /*-------------------------------------------------------------------*/ /* Copy 8 bytes at a time concurrently */ /*-------------------------------------------------------------------*/ #ifndef _VSTORE_CONCPY #define _VSTORE_CONCPY static __inline__ void concpy (REGS *regs, void *d, void *s, int n) { int n2; BYTE *dest = (BYTE *)d, *src = (BYTE *)s; /* Byte for byte copy if short length or possible overlap */ if (n < 8 || (dest <= src && dest + 8 > src) || (src <= dest && src + 8 > dest)) { /* use memset directly when the copy's effect is to propagate a byte over an area - like in MVC 1(255,2),0(2) */ if(dest==src+1) { memset(dest,*src,n); } else { for ( ; n; n--) *(dest++) = *(src++); } return; } /* copy to an 8 byte boundary */ n2 = (intptr_t)dest & 7; n -= n2; for ( ; n2; n2--) *(dest++) = *(src++); #if !defined(OPTION_STRICT_ALIGNMENT) && \ ((!defined(_MSVC_) && defined(SIZEOF_LONG) && SIZEOF_LONG >= 8) || \ ( defined(_MSVC_) && defined(SIZEOF_INT_P) && SIZEOF_INT_P >= 8)) /* Below for 64-bit BUILDS ONLY, since the below C code does NOT generate atomic 64-bit load/store assembler code sequence compatible with Concurrent Block Update except when building for 64-bit systems... */ UNREFERENCED(regs); /* copy 8 bytes at a time */ for ( ; n >= 8; n -= 8, dest += 8, src += 8) *(U64 *)dest = *(U64 *)src; #else /* 32-bit builds... */ #if !defined(OPTION_STRICT_ALIGNMENT) /* copy 4 bytes at a time if only one cpu started */ if (regs->cpubit == regs->sysblk->started_mask) for ( ; n >= 4; n -= 4, dest += 4, src += 4) *(U32 *)dest = *(U32 *)src; else #else /* defined(OPTION_STRICT_ALIGNMENT) */ UNREFERENCED(regs); #endif /* else copy 8 bytes at a time concurrently */ for ( ; n >= 8; n -= 8, dest += 8, src += 8) store_dw_noswap(dest,fetch_dw_noswap(src)); #endif /* (64-bit builds test...) */ /* copy leftovers */ for ( ; n; n--) *(dest++) = *(src++); } #endif /* !defined(_VSTORE_CONCPY) */ #if !defined(OPTION_NO_INLINE_VSTORE) || defined(_VSTORE_C) /*-------------------------------------------------------------------*/ /* Move characters using specified keys and address spaces */ /* */ /* Input: */ /* addr1 Effective address of first operand */ /* arn1 Access register number for first operand, */ /* or USE_PRIMARY_SPACE or USE_SECONDARY_SPACE */ /* key1 Bits 0-3=first operand access key, 4-7=zeroes */ /* addr2 Effective address of second operand */ /* arn2 Access register number for second operand, */ /* or USE_PRIMARY_SPACE or USE_SECONDARY_SPACE */ /* key2 Bits 0-3=second operand access key, 4-7=zeroes */ /* len Operand length minus 1 (range 0-255) */ /* regs Pointer to the CPU register context */ /* */ /* This function implements the MVC, MVCP, MVCS, MVCK, MVCSK, */ /* and MVCDK instructions. These instructions move up to 256 */ /* characters using the address space and key specified by */ /* the caller for each operand. Operands are moved byte by */ /* byte to ensure correct processing of overlapping operands. */ /* */ /* The arn parameter for each operand may be an access */ /* register number, in which case the operand is in the */ /* primary, secondary, or home space, or in the space */ /* designated by the specified access register, according to */ /* the current PSW addressing mode. */ /* */ /* Alternatively the arn parameter may be one of the special */ /* values USE_PRIMARY_SPACE or USE_SECONDARY_SPACE in which */ /* case the operand is in the specified space regardless of */ /* the current PSW addressing mode. */ /* */ /* A program check may be generated if either logical address */ /* causes an addressing, protection, or translation exception, */ /* and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_C_STATIC void ARCH_DEP(move_chars) (VADR addr1, int arn1, BYTE key1, VADR addr2, int arn2, BYTE key2, int len, REGS *regs) { BYTE *dest1, *dest2; /* Destination addresses */ BYTE *source1, *source2; /* Source addresses */ BYTE *sk1, *sk2; /* Storage key addresses */ int len2, len3; /* Lengths to copy */ ITIMER_SYNC(addr2,len,regs); /* Quick out if copying just 1 byte */ if (unlikely(len == 0)) { source1 = MADDR (addr2, arn2, regs, ACCTYPE_READ, key2); dest1 = MADDR (addr1, arn1, regs, ACCTYPE_WRITE, key1); *dest1 = *source1; ITIMER_UPDATE(addr1,len,regs); return; } /* Translate addresses of leftmost operand bytes */ source1 = MADDR (addr2, arn2, regs, ACCTYPE_READ, key2); dest1 = MADDRL (addr1, len+1, arn1, regs, ACCTYPE_WRITE_SKP, key1); sk1 = regs->dat.storkey; /* There are several scenarios (in optimal order): * (1) dest boundary and source boundary not crossed * (2) dest boundary not crossed and source boundary crossed * (3) dest boundary crossed and source boundary not crossed * (4) dest boundary and source boundary are crossed * (a) dest and source boundary cross at the same time * (b) dest boundary crossed first * (c) source boundary crossed first * Note: since the operand length is limited to 256 bytes, * neither operand can cross more than one 2K boundary. */ if ( NOCROSS2K(addr1,len) ) { if ( NOCROSS2K(addr2,len) ) { /* (1) - No boundaries are crossed */ concpy (regs, dest1, source1, len + 1); } else { /* (2) - Second operand crosses a boundary */ len2 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len2) & ADDRESS_MAXWRAP(regs), arn2, regs, ACCTYPE_READ, key2); concpy (regs, dest1, source1, len2); concpy (regs, dest1 + len2, source2, len - len2 + 1); } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); } else { /* First operand crosses a boundary */ len2 = 0x800 - (addr1 & 0x7FF); dest2 = MADDR ((addr1 + len2) & ADDRESS_MAXWRAP(regs), arn1, regs, ACCTYPE_WRITE_SKP, key1); sk2 = regs->dat.storkey; if ( NOCROSS2K(addr2,len) ) { /* (3) - First operand crosses a boundary */ concpy (regs, dest1, source1, len2); concpy (regs, dest2, source1 + len2, len - len2 + 1); } else { /* (4) - Both operands cross a boundary */ len3 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len3) & ADDRESS_MAXWRAP(regs), arn2, regs, ACCTYPE_READ, key2); if (len2 == len3) { /* (4a) - Both operands cross at the same time */ concpy (regs, dest1, source1, len2); concpy (regs, dest2, source2, len - len2 + 1); } else if (len2 < len3) { /* (4b) - First operand crosses first */ concpy (regs, dest1, source1, len2); concpy (regs, dest2, source1 + len2, len3 - len2); concpy (regs, dest2 + len3 - len2, source2, len - len3 + 1); } else { /* (4c) - Second operand crosses first */ concpy (regs, dest1, source1, len3); concpy (regs, dest1 + len3, source2, len2 - len3); concpy (regs, dest2, source2 + len2 - len3, len - len2 + 1); } } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); *sk2 |= (STORKEY_REF | STORKEY_CHANGE); } ITIMER_UPDATE(addr1,len,regs); } /* end function ARCH_DEP(move_chars) */ #if defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS) /*-------------------------------------------------------------------*/ /* Move characters with optional specifications */ /* */ /* Input: */ /* addr1 Effective address of first operand */ /* space1 Address space for first operand: */ /* USE_PRIMARY_SPACE */ /* USE_SECONDARY_SPACE */ /* USE_ARMODE + access register number */ /* USE_HOME_SPACE */ /* key1 Bits 0-3=first operand access key, 4-7=zeroes */ /* addr2 Effective address of second operand */ /* space1 Address space for second operand (values as space1) */ /* key2 Bits 0-3=second operand access key, 4-7=zeroes */ /* len Operand length (range 0-4096) */ /* regs Pointer to the CPU register context */ /* */ /* This function implements the MVCOS instruction which moves */ /* up to 4096 characters using the address space and key */ /* specified by the caller for each operand. Results are */ /* unpredictable if destructive overlap exists. */ /* */ /* The space1 and space2 parameters force the use of the */ /* specified address space, or the use of the specified */ /* access register, regardless of the current PSW addressing */ /* mode. */ /* */ /* A program check may be generated if either logical address */ /* causes an addressing, protection, or translation exception, */ /* and in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_C_STATIC void ARCH_DEP(move_charx) (VADR addr1, int space1, BYTE key1, VADR addr2, int space2, BYTE key2, int len, REGS *regs) { BYTE *main1, *main2; /* Main storage pointers */ int len1, len2, len3; /* Work areas for lengths */ /* Ultra quick out if copying zero bytes */ if (unlikely(len == 0)) return; ITIMER_SYNC(addr2,len-1,regs); /* Quick out if copying just 1 byte */ if (unlikely(len == 1)) { main2 = MADDR (addr2, space2, regs, ACCTYPE_READ, key2); main1 = MADDR (addr1, space1, regs, ACCTYPE_WRITE, key1); *main1 = *main2; ITIMER_UPDATE(addr1,len-1,regs); return; } /* Translate addresses of leftmost operand bytes */ main2 = MADDR (addr2, space2, regs, ACCTYPE_READ, key2); main1 = MADDRL (addr1, len, space1, regs, ACCTYPE_WRITE, key1); /* Copy the largest chunks which do not cross a 2K boundary of either source or destination operand */ while (len > 0) { /* Calculate distance to next 2K boundary */ len1 = NOCROSS2KL(addr1,len) ? len : (int)(0x800 - (addr1 & 0x7FF)); len2 = NOCROSS2KL(addr2,len) ? len : (int)(0x800 - (addr2 & 0x7FF)); len3 = len1 < len2 ? len1 : len2; /* Copy bytes from source to destination */ concpy (regs, main1, main2, len3); /* Calculate virtual addresses for next chunk */ addr1 = (addr1 + len3) & ADDRESS_MAXWRAP(regs); addr2 = (addr2 + len3) & ADDRESS_MAXWRAP(regs); /* Adjust remaining length */ len -= len3; /* Exit if no more bytes to move */ if (len == 0) break; /* Adjust addresses for start of next chunk, or translate again if a 2K boundary was crossed */ main2 = (addr2 & 0x7FF) ? main2 + len3 : MADDR (addr2, space2, regs, ACCTYPE_READ, key2); main1 = (addr1 & 0x7FF) ? main1 + len3 : MADDR (addr1, space1, regs, ACCTYPE_WRITE, key1); } /* end while(len) */ ITIMER_UPDATE(addr1,len-1,regs); } /* end function ARCH_DEP(move_charx) */ #endif /*defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS)*/ /*-------------------------------------------------------------------*/ /* Validate operand for addressing, protection, translation */ /* */ /* Input: */ /* addr Effective address of operand */ /* arn Access register number */ /* len Operand length minus 1 (range 0-255) */ /* acctype Type of access requested: READ or WRITE */ /* regs Pointer to the CPU register context */ /* */ /* The purpose of this function is to allow an instruction */ /* operand to be validated for addressing, protection, and */ /* translation exceptions, thus allowing the instruction to */ /* be nullified or suppressed before any updates occur. */ /* */ /* A program check is generated if the operand causes an */ /* addressing, protection, or translation exception, and */ /* in this case the function does not return. */ /*-------------------------------------------------------------------*/ _VSTORE_C_STATIC void ARCH_DEP(validate_operand) (VADR addr, int arn, int len, int acctype, REGS *regs) { /* Translate address of leftmost operand byte */ MADDR (addr, arn, regs, acctype, regs->psw.pkey); /* Translate next page if boundary crossed */ if ( CROSS2K(addr,len) ) { MADDR ((addr + len) & ADDRESS_MAXWRAP(regs), arn, regs, acctype, regs->psw.pkey); } #ifdef FEATURE_INTERVAL_TIMER else ITIMER_SYNC(addr,len,regs); #endif /*FEATURE_INTERVAL_TIMER*/ } /* end function ARCH_DEP(validate_operand) */ #endif /*!defined(OPTION_NO_INLINE_VSTORE) || defined(_VSTORE_C)*/ hercules-3.12/hbyteswp.h0000664000175000017500000000740312564723224012225 00000000000000/* HBYTESWP.H (c) Copyright Jan Jaeger, 2001-2009 */ /* Hercules Little <> Big Endian conversion */ /* These definitions are only nessesary when running on older */ /* versions of linux that do not have /usr/include/byteswap.h */ /* compile option -DNO_ASM_BYTESWAP will expand 'C' code */ /* otherwise Intel (486+) assember will be generated */ #ifndef _BYTESWAP_H #define _BYTESWAP_H #if !defined(NO_ASM_BYTESWAP) #include "htypes.h" // (need Hercules fixed-size data types) #if defined( _MSVC_ ) static __inline uint16_t __fastcall bswap_16 ( uint16_t x ) { return _byteswap_ushort((x)); } static __inline uint32_t __fastcall bswap_32 ( uint32_t x ) { return _byteswap_ulong((x)); } #else // !defined( _MSVC_ ) static __inline__ uint16_t (ATTR_REGPARM(1) bswap_16)(uint16_t x) { #if defined(__x86_64__) __asm__("xchgb %b0,%h0" : "=Q" (x) : "0" (x)); #else __asm__("xchgb %b0,%h0" : "=q" (x) : "0" (x)); #endif return x; } static __inline__ uint32_t (ATTR_REGPARM(1) bswap_32)(uint32_t x) { #if defined(__x86_64__) __asm__("bswapl %0" : "=r" (x) : "0" (x)); #else __asm__("bswap %0" : "=r" (x) : "0" (x)); #endif return x; } #endif // defined( _MSVC_ ) #else // defined(NO_ASM_BYTESWAP) #define bswap_16(_x) \ ( (((_x) & 0xFF00) >> 8) \ | (((_x) & 0x00FF) << 8) ) #define bswap_32(_x) \ ( (((_x) & 0xFF000000) >> 24) \ | (((_x) & 0x00FF0000) >> 8) \ | (((_x) & 0x0000FF00) << 8) \ | (((_x) & 0x000000FF) << 24) ) #endif // !defined(NO_ASM_BYTESWAP) #if defined( _MSVC_ ) // Microsoft's Toolkit 2003 compiler (version 1300) has a known bug // that causes the _byteswap_uint64 intrinsic to screw up if global // otimizations are enabled. The new VStudio 8.0 compiler (version // 14.00) doesn't have this problem that I am aware of. NOTE that // the #pragma must be outside the function (at global scope) to // prevent compiler error C2156 "pragma must be outside function". #if ( _MSC_VER < 1400 ) #pragma optimize("g",off) // (disable global optimizations) #endif static __inline uint64_t __fastcall bswap_64(uint64_t x) { return _byteswap_uint64((x)); } #if ( _MSC_VER < 1400 ) #pragma optimize ( "", on ) #endif #else // !defined( _MSVC_ ) #if defined(NO_ASM_BYTESWAP) #define bswap_64(_x) \ ( ((U64)((_x) & 0xFF00000000000000ULL) >> 56) \ | ((U64)((_x) & 0x00FF000000000000ULL) >> 40) \ | ((U64)((_x) & 0x0000FF0000000000ULL) >> 24) \ | ((U64)((_x) & 0x000000FF00000000ULL) >> 8) \ | ((U64)((_x) & 0x00000000FF000000ULL) << 8) \ | ((U64)((_x) & 0x0000000000FF0000ULL) << 24) \ | ((U64)((_x) & 0x000000000000FF00ULL) << 40) \ | ((U64)((_x) & 0x00000000000000FFULL) << 56) ) #else static __inline__ uint64_t (ATTR_REGPARM(1) bswap_64)(uint64_t x) { #if defined(__x86_64__) __asm__("bswapq %0" : "=r" (x) : "0" (x)); return x; #else // swap the two words after byteswapping them union { struct { uint32_t high,low; } words; uint64_t quad; } value; value.quad=x; __asm__("bswap %0" : "=r" (value.words.high) : "0" (value.words.high)); __asm__("bswap %0" : "=r" (value.words.low) : "0" (value.words.low)); __asm__("xchgl %0,%1" : "=r" (value.words.high), "=r" (value.words.low) : "0" (value.words.high), "1" (value.words.low)); return value.quad; #endif // defined(__x86_64__) } #endif // defined(NO_ASM_BYTESWAP) #endif // defined( _MSVC_ ) #endif // _BYTESWAP_H hercules-3.12/dasdblks.h0000664000175000017500000005523412564723224012154 00000000000000/* DASDBLKS.H (c) Copyright Roger Bowler, 1999-2009 */ /* DASD control block structures */ /*-------------------------------------------------------------------*/ /* This header file contains definitions of OS Data Management */ /* control block structures for use by the Hercules DASD utilities. */ /* It also contains function prototypes for the DASD utilities. */ /*-------------------------------------------------------------------*/ #include "hercules.h" #ifndef _DASDUTIL_C_ #ifndef _HDASD_DLL_ #define DUT_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define DUT_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define DUT_DLL_IMPORT DLL_EXPORT #endif // Forward references... typedef struct FORMAT1_DSCB FORMAT1_DSCB; // DSCB1: Dataset descriptor typedef struct FORMAT3_DSCB FORMAT3_DSCB; // DSCB3: Additional extents typedef struct FORMAT4_DSCB FORMAT4_DSCB; // DSCB4: VTOC descriptor typedef struct FORMAT5_DSCB FORMAT5_DSCB; // DSCB5: Free space map typedef struct F5AVEXT F5AVEXT; // Available extent in DSCB5 typedef struct DSXTENT DSXTENT; // Dataset extent descriptor typedef struct PDSDIR PDSDIR; // PDS directory entry typedef struct CIFBLK CIFBLK; // CKD image file descriptor typedef struct COPYR1 COPYR1; // IEBCOPY header record 1 typedef struct COPYR2 COPYR2; // IEBCOPY header record 2 typedef struct DATABLK DATABLK; // IEBCOPY unload data rec #define MAX_TRACKS 32767 /*-------------------------------------------------------------------*/ /* Definition of DSCB records in VTOC */ /*-------------------------------------------------------------------*/ struct DSXTENT { /* Dataset extent descriptor */ BYTE xttype; /* Extent type */ BYTE xtseqn; /* Extent sequence number */ HWORD xtbcyl; /* Extent begin cylinder */ HWORD xtbtrk; /* Extent begin track */ HWORD xtecyl; /* Extent end cylinder */ HWORD xtetrk; /* Extent end track */ }; /* Bit definitions for extent type */ #define XTTYPE_UNUSED 0x00 /* Unused extent descriptor */ #define XTTYPE_DATA 0x01 /* Data extent */ #define XTTYPE_OVERFLOW 0x02 /* Overflow extent */ #define XTTYPE_INDEX 0x04 /* Index extent */ #define XTTYPE_USERLBL 0x40 /* User label extent */ #define XTTYPE_SHARCYL 0x80 /* Shared cylinders */ #define XTTYPE_CYLBOUND 0x81 /* Extent on cyl boundary */ struct FORMAT1_DSCB { /* DSCB1: Dataset descriptor */ BYTE ds1dsnam[44]; /* Key (44 byte dataset name)*/ BYTE ds1fmtid; /* Format identifier (0xF1) */ BYTE ds1dssn[6]; /* Volume serial number */ HWORD ds1volsq; /* Volume sequence number */ BYTE ds1credt[3]; /* Dataset creation date... ...byte 0: Binary year-1900 ...bytes 1-2: Binary day */ BYTE ds1expdt[3]; /* Dataset expiry date */ BYTE ds1noepv; /* Number of extents */ BYTE ds1bodbd; /* #bytes used in last dirblk*/ BYTE resv1; /* Reserved */ BYTE ds1syscd[13]; /* System code (IBMOSVS2) */ BYTE resv2[7]; /* Reserved */ BYTE ds1dsorg[2]; /* Dataset organization */ BYTE ds1recfm; /* Record format */ BYTE ds1optcd; /* Option codes */ HWORD ds1blkl; /* Block length */ HWORD ds1lrecl; /* Logical record length */ BYTE ds1keyl; /* Key length */ HWORD ds1rkp; /* Relative key position */ BYTE ds1dsind; /* Dataset indicators */ FWORD ds1scalo; /* Secondary allocation... ...byte 0: Allocation units ...bytes 1-3: Quantity */ BYTE ds1lstar[3]; /* Last used TTR */ HWORD ds1trbal; /* Bytes unused on last trk */ BYTE resv3[2]; /* Reserved */ DSXTENT ds1ext1; /* First extent descriptor */ DSXTENT ds1ext2; /* Second extent descriptor */ DSXTENT ds1ext3; /* Third extent descriptor */ BYTE ds1ptrds[5]; /* CCHHR of F2 or F3 DSCB */ }; /* Bit definitions for ds1dsind */ #define DS1DSIND_LASTVOL 0x80 /* Last volume of dataset */ #define DS1DSIND_RACFIND 0x40 /* RACF indicated */ #define DS1DSIND_BLKSIZ8 0x20 /* Blocksize multiple of 8 */ #define DS1DSIND_PASSWD 0x10 /* Password protected */ #define DS1DSIND_WRTPROT 0x04 /* Write protected */ #define DS1DSIND_UPDATED 0x02 /* Updated since last backup */ #define DS1DSIND_SECCKPT 0x01 /* Secure checkpoint dataset */ /* Bit definitions for ds1optcd */ #define DS1OPTCD_ICFDSET 0x80 /* Dataset in ICF catalog */ #define DS1OPTCD_ICFCTLG 0x40 /* ICF catalog */ /* Bit definitions for ds1scalo byte 0 */ #define DS1SCALO_UNITS 0xC0 /* Allocation units... */ #define DS1SCALO_UNITS_ABSTR 0x00 /* ...absolute tracks */ #define DS1SCALO_UNITS_BLK 0x40 /* ...blocks */ #define DS1SCALO_UNITS_TRK 0x80 /* ...tracks */ #define DS1SCALO_UNITS_CYL 0xC0 /* ...cylinders */ #define DS1SCALO_CONTIG 0x08 /* Contiguous space */ #define DS1SCALO_MXIG 0x04 /* Maximum contiguous extent */ #define DS1SCALO_ALX 0x02 /* Up to 5 largest extents */ #define DS1SCALO_ROUND 0x01 /* Round to cylinders */ struct FORMAT3_DSCB { /* DSCB3: Additional extents */ BYTE ds3keyid[4]; /* Key (4 bytes of 0x03) */ DSXTENT ds3extnt[4]; /* Four extent descriptors */ BYTE ds3fmtid; /* Format identifier (0xF3) */ DSXTENT ds3adext[9]; /* Nine extent descriptors */ BYTE ds3ptrds[5]; /* CCHHR of next F3 DSCB */ }; struct FORMAT4_DSCB { /* DSCB4: VTOC descriptor */ BYTE ds4keyid[44]; /* Key (44 bytes of 0x04) */ BYTE ds4fmtid; /* Format identifier (0xF4) */ BYTE ds4hpchr[5]; /* CCHHR of highest F1 DSCB */ HWORD ds4dsrec; /* Number of format 0 DSCBs */ BYTE ds4hcchh[4]; /* CCHH of next avail alt trk*/ HWORD ds4noatk; /* Number of avail alt tracks*/ BYTE ds4vtoci; /* VTOC indicators */ BYTE ds4noext; /* Number of extents in VTOC */ BYTE resv1[2]; /* Reserved */ FWORD ds4devsz; /* Device size (CCHH) */ HWORD ds4devtk; /* Device track length */ BYTE ds4devi; /* Non-last keyed blk overhd */ BYTE ds4devl; /* Last keyed block overhead */ BYTE ds4devk; /* Non-keyed block difference*/ BYTE ds4devfg; /* Device flags */ HWORD ds4devtl; /* Device tolerance */ BYTE ds4devdt; /* Number of DSCBs per track */ BYTE ds4devdb; /* Number of dirblks/track */ DBLWRD ds4amtim; /* VSAM timestamp */ BYTE ds4vsind; /* VSAM indicators */ HWORD ds4vscra; /* CRA track location */ DBLWRD ds4r2tim; /* VSAM vol/cat timestamp */ BYTE resv2[5]; /* Reserved */ BYTE ds4f6ptr[5]; /* CCHHR of first F6 DSCB */ DSXTENT ds4vtoce; /* VTOC extent descriptor */ BYTE resv3[25]; /* Reserved */ }; /* Bit definitions for ds4vtoci */ #define DS4VTOCI_DOS 0x80 /* Format 5 DSCBs not valid */ #define DS4VTOCI_DOSSTCK 0x10 /* DOS stacked pack */ #define DS4VTOCI_DOSCNVT 0x08 /* DOS converted pack */ #define DS4VTOCI_DIRF 0x40 /* VTOC contains errors */ #define DS4VTOCI_DIRFCVT 0x20 /* DIRF reclaimed */ /* Bit definitions for ds4devfg */ #define DS4DEVFG_TOL 0x01 /* Tolerance factor applies to all but last block of trk */ struct F5AVEXT { /* Available extent in DSCB5 */ HWORD btrk; /* Extent begin track address*/ HWORD ncyl; /* Number of full cylinders */ BYTE ntrk; /* Number of odd tracks */ }; struct FORMAT5_DSCB { /* DSCB5: Free space map */ BYTE ds5keyid[4]; /* Key (4 bytes of 0x05) */ F5AVEXT ds5avext[8]; /* First 8 available extents */ BYTE ds5fmtid; /* Format identifier (0xF5) */ F5AVEXT ds5mavet[18]; /* 18 more available extents */ BYTE ds5ptrds[5]; /* CCHHR of next F5 DSCB */ }; /*-------------------------------------------------------------------*/ /* Definitions of DSORG and RECFM fields */ /*-------------------------------------------------------------------*/ /* Bit settings for dataset organization byte 0 */ #define DSORG_IS 0x80 /* Indexed sequential */ #define DSORG_PS 0x40 /* Physically sequential */ #define DSORG_DA 0x20 /* Direct access */ #define DSORG_PO 0x02 /* Partitioned organization */ #define DSORG_U 0x01 /* Unmovable */ /* Bit settings for dataset organization byte 1 */ #define DSORG_AM 0x08 /* VSAM dataset */ /* Bit settings for record format */ #define RECFM_FORMAT 0xC0 /* Bits 0-1=Record format */ #define RECFM_FORMAT_V 0x40 /* ...variable length */ #define RECFM_FORMAT_F 0x80 /* ...fixed length */ #define RECFM_FORMAT_U 0xC0 /* ...undefined length */ #define RECFM_TRKOFLOW 0x20 /* Bit 2=Track overflow */ #define RECFM_BLOCKED 0x10 /* Bit 3=Blocked */ #define RECFM_SPANNED 0x08 /* Bit 4=Spanned or standard */ #define RECFM_CTLCHAR 0x06 /* Bits 5-6=Carriage control */ #define RECFM_CTLCHAR_A 0x04 /* ...ANSI carriage control */ #define RECFM_CTLCHAR_M 0x02 /* ...Machine carriage ctl. */ /*-------------------------------------------------------------------*/ /* Definition of PDS directory entry */ /*-------------------------------------------------------------------*/ struct PDSDIR { /* PDS directory entry */ BYTE pds2name[8]; /* Member name */ BYTE pds2ttrp[3]; /* TTR of first block */ BYTE pds2indc; /* Indicator byte */ BYTE pds2usrd[62]; /* User data (0-31 halfwords)*/ }; /* Bit definitions for PDS directory indicator byte */ #define PDS2INDC_ALIAS 0x80 /* Bit 0: Name is an alias */ #define PDS2INDC_NTTR 0x60 /* Bits 1-2: User TTR count */ #define PDS2INDC_NTTR_SHIFT 5 /* Shift count for NTTR */ #define PDS2INDC_LUSR 0x1F /* Bits 3-7: User halfwords */ /*-------------------------------------------------------------------*/ /* Text unit keys for transmit/receive */ /*-------------------------------------------------------------------*/ #define INMDDNAM 0x0001 /* DDNAME for the file */ #define INMDSNAM 0x0002 /* Name of the file */ #define INMMEMBR 0x0003 /* Member name list */ #define INMSECND 0x000B /* Secondary space quantity */ #define INMDIR 0x000C /* Directory space quantity */ #define INMEXPDT 0x0022 /* Expiration date */ #define INMTERM 0x0028 /* Data transmitted as msg */ #define INMBLKSZ 0x0030 /* Block size */ #define INMDSORG 0x003C /* File organization */ #define INMLRECL 0x0042 /* Logical record length */ #define INMRECFM 0x0049 /* Record format */ #define INMTNODE 0x1001 /* Target node name/number */ #define INMTUID 0x1002 /* Target user ID */ #define INMFNODE 0x1011 /* Origin node name/number */ #define INMFUID 0x1012 /* Origin user ID */ #define INMLREF 0x1020 /* Date last referenced */ #define INMLCHG 0x1021 /* Date last changed */ #define INMCREAT 0x1022 /* Creation date */ #define INMFVERS 0x1023 /* Origin vers# of data fmt */ #define INMFTIME 0x1024 /* Origin timestamp */ #define INMTTIME 0x1025 /* Destination timestamp */ #define INMFACK 0x1026 /* Originator request notify */ #define INMERRCD 0x1027 /* RECEIVE command error code*/ #define INMUTILN 0x1028 /* Name of utility program */ #define INMUSERP 0x1029 /* User parameter string */ #define INMRECCT 0x102A /* Transmitted record count */ #define INMSIZE 0x102C /* File size in bytes */ #define INMFFM 0x102D /* Filemode number */ #define INMNUMF 0x102F /* #of files transmitted */ #define INMTYPE 0x8012 /* Dataset type */ /*-------------------------------------------------------------------*/ /* Definitions of IEBCOPY header records */ /*-------------------------------------------------------------------*/ struct COPYR1 { /* IEBCOPY header record 1 */ BYTE uldfmt; /* Unload format */ BYTE hdrid[3]; /* Header identifier */ HWORD ds1dsorg; /* Dataset organization */ HWORD ds1blkl; /* Block size */ HWORD ds1lrecl; /* Logical record length */ BYTE ds1recfm; /* Record format */ BYTE ds1keyl; /* Key length */ BYTE ds1optcd; /* Option codes */ BYTE ds1smsfg; /* SMS indicators */ HWORD uldblksz; /* Block size of container */ /* Start of DEVTYPE fields */ FWORD ucbtype; /* Original device type */ FWORD maxblksz; /* Maximum block size */ HWORD cyls; /* Number of cylinders */ HWORD heads; /* Number of tracks/cylinder */ HWORD tracklen; /* Track length */ HWORD overhead; /* Block overhead */ BYTE keyovhead; /* Keyed block overhead */ BYTE devflags; /* Flags */ HWORD tolerance; /* Tolerance factor */ /* End of DEVTYPE fields */ HWORD hdrcount; /* Number of header records (if zero, then 2 headers) */ BYTE resv1; /* Reserved */ BYTE ds1refd[3]; /* Last reference date */ BYTE ds1scext[3]; /* Secondary space extension */ BYTE ds1scalo[4]; /* Secondary allocation */ BYTE ds1lstar[3]; /* Last track used TTR */ HWORD ds1trbal; /* Last track balance */ HWORD resv2; /* Reserved */ }; /* Bit settings for unload format byte */ #define COPYR1_ULD_FORMAT 0xC0 /* Bits 0-1=unload format... */ #define COPYR1_ULD_FORMAT_OLD 0x00 /* ...old format */ #define COPYR1_ULD_FORMAT_PDSE 0x40 /* ...PDSE format */ #define COPYR1_ULD_FORMAT_ERROR 0x80 /* ...error during unload */ #define COPYR1_ULD_FORMAT_XFER 0xC0 /* ...transfer format */ #define COPYR1_ULD_PROGRAM 0x10 /* Bit 3=Contains programs */ #define COPYR1_ULD_PDSE 0x01 /* Bit 7=Contains PDSE */ /* Bit settings for header identifier */ #define COPYR1_HDRID "\xCA\x6D\x0F" /* Constant value for hdrid */ struct COPYR2 { /* IEBCOPY header record 2 */ BYTE debbasic[16]; /* Last 16 bytes of basic section of original DEB */ BYTE debxtent[16][16]; /* First 16 extent descriptors from original DEB */ FWORD resv; /* Reserved */ }; /*-------------------------------------------------------------------*/ /* Definition of data record block in IEBCOPY unload file */ /*-------------------------------------------------------------------*/ struct DATABLK { /* IEBCOPY unload data rec */ FWORD header; /* Reserved */ HWORD cyl; /* Cylinder number */ HWORD head; /* Head number */ BYTE rec; /* Record number */ BYTE klen; /* Key length */ HWORD dlen; /* Data length */ #define MAX_DATALEN 32767 BYTE kdarea[MAX_DATALEN]; /* Key and data area */ }; /*-------------------------------------------------------------------*/ /* Internal structures used by DASD utility functions */ /*-------------------------------------------------------------------*/ struct CIFBLK { /* CKD image file descriptor */ char *fname; /* -> CKD image file name */ int fd; /* CKD image file descriptor */ int trksz; /* CKD image track size */ BYTE *trkbuf; /* -> Track buffer */ int curcyl; /* Cylinder number of track currently in track buffer */ int curhead; /* Head number of track currently in track buffer */ int trkmodif; /* 1=Track has been modified */ int heads; /* Tracks per cylinder */ DEVBLK devblk; /* Device Block */ }; /*-------------------------------------------------------------------*/ /* Macro definitions */ /*-------------------------------------------------------------------*/ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)*(y)) /*-------------------------------------------------------------------*/ /* Function prototypes */ /*-------------------------------------------------------------------*/ /* Functions in module dasdutil.c */ DUT_DLL_IMPORT void string_to_upper (char *source); DUT_DLL_IMPORT void string_to_lower (char *source); DUT_DLL_IMPORT void convert_to_ebcdic (BYTE *dest, int len, char *source); DUT_DLL_IMPORT int make_asciiz (char *dest, int destlen, BYTE *src, int srclen); DUT_DLL_IMPORT void data_dump (void *addr, int len); DUT_DLL_IMPORT int read_track (CIFBLK *cif, int cyl, int head); int rewrite_track (CIFBLK *cif); DUT_DLL_IMPORT int read_block (CIFBLK *cif, int cyl, int head, int rec, BYTE **keyptr, int *keylen, BYTE **dataptr, int *datalen); DUT_DLL_IMPORT int search_key_equal (CIFBLK *cif, BYTE *key, int keylen, int noext, DSXTENT extent[], int *cyl, int *head, int *rec); DUT_DLL_IMPORT int convert_tt (int tt, int noext, DSXTENT extent[], int heads, int *cyl, int *head); DUT_DLL_IMPORT CIFBLK* open_ckd_image (char *fname, char *sfname, int omode, int dasdcopy); DUT_DLL_IMPORT CIFBLK* open_fba_image (char *fname, char *sfname, int omode, int dasdcopy); DUT_DLL_IMPORT int close_ckd_image (CIFBLK *cif); #define close_image_file(cif) close_ckd_image((cif)) DUT_DLL_IMPORT int build_extent_array (CIFBLK *cif, char *dsnama, DSXTENT extent[], int *noext); DUT_DLL_IMPORT int capacity_calc (CIFBLK *cif, int used, int keylen, int datalen, int *newused, int *trkbaln, int *physlen, int *kbconst, int *lbconst, int *nkconst, BYTE*devflag, int *tolfact, int *maxdlen, int *numrecs, int *numhead, int *numcyls); DUT_DLL_IMPORT int create_ckd (char *fname, U16 devtype, U32 heads, U32 maxdlen, U32 volcyls, char *volser, BYTE comp, int lfs, int dasdcopy, int nullfmt, int rawflag); DUT_DLL_IMPORT int create_fba (char *fname, U16 devtype, U32 sectsz, U32 sectors, char *volser, BYTE comp, int lfs, int dasdcopy, int rawflag); int create_compressed_fba (char *fname, U16 devtype, U32 sectsz, U32 sectors, char *volser, BYTE comp, int lfs, int dasdcopy, int rawflag); int get_verbose_util(void); DUT_DLL_IMPORT void set_verbose_util(int v); DUT_DLL_IMPORT int valid_dsname( const char *pszdsname ); #define DEFAULT_FBA_TYPE 0x3370 hercules-3.12/hetlib.h0000664000175000017500000002046412564723224011631 00000000000000/* HETLIB.H (c) Copyright Leland Lucius, 2000-2009 */ /* Header for the Hercules Emulated Tape library */ #if !defined( _HETLIB_H_ ) #define _HETLIB_H_ /* || ---------------------------------------------------------------------------- || || HETLIB.H (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Header for the Hercules Emulated Tape library. || || ---------------------------------------------------------------------------- */ #include "hercules.h" #ifndef _HETLIB_C_ #ifndef _HTAPE_DLL_ #define HET_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define HET_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define HET_DLL_IMPORT DLL_EXPORT #endif #if !defined( TRUE ) #define TRUE (1L) #endif #if !defined( FALSE ) #define FALSE (0L) #endif /* || Chunk header for an HET. Physically compatable with AWSTAPE format. */ typedef struct _hethdr { uint8_t clen[ 2 ]; /* Length of current block */ uint8_t plen[ 2 ]; /* Length of previous block */ uint8_t flags1; /* Flags byte 1 */ uint8_t flags2; /* Flags byte 2 */ } HETHDR; /* || Macros for accessing current and previous sizes - accept ptr to HETHDR */ #define HETHDR_CLEN( h ) ( ( (h)->chdr.clen[ 1 ] << 8 ) + (h)->chdr.clen[ 0 ] ) #define HETHDR_PLEN( h ) ( ( (h)->chdr.plen[ 1 ] << 8 ) + (h)->chdr.plen[ 0 ] ) /* || Definitions for HETHDR flags byte 1 (compression incompatable with AWSTAPE) */ #define HETHDR_FLAGS1_BOR 0x80 /* Start of new record */ #define HETHDR_FLAGS1_TAPEMARK 0x40 /* Tape mark */ #define HETHDR_FLAGS1_EOR 0x20 /* End of record */ #define HETHDR_FLAGS1_COMPRESS 0x03 /* Compression method mask */ #define HETHDR_FLAGS1_BZLIB 0x02 /* BZLIB compression */ #define HETHDR_FLAGS1_ZLIB 0x01 /* ZLIB compression */ /* || Definitions for HETHDR flags byte 2 (incompatable with AWSTAPE and HET) */ #define HETHDR_FLAGS2_COMPRESS 0x80 /* Compression method mask */ #define HETHDR_FLAGS2_ZLIB_BUSTECH 0x80 /* Bus-Tech ZLIB compression */ /* || Control block for Hercules Emulated Tape files */ typedef struct _hetb { FILE *fd; /* Tape file descriptor */ uint32_t chksize; /* Size of output chunks */ uint32_t ublksize; /* Current block compressed size */ uint32_t cblksize; /* Current block uncompressed size */ uint32_t cblk; /* Current block number */ HETHDR chdr; /* Current block header */ u_int writeprotect:1; /* TRUE=write protected */ u_int readlast:1; /* TRUE=last i/o was read */ u_int truncated:1; /* TRUE=file truncated */ u_int compress:1; /* TRUE=compress written data */ u_int decompress:1; /* TRUE=decompress read data */ u_int method:2; /* 1=ZLIB, 2=BZLIB compresion */ u_int level:4; /* 1=devnum & 0xffe0) /* Storage subsystem identifier 32 devices per subsystem */ #else #define myssid SSID(dev) #endif /* 32 devices per subsystem */ #define DEVICES_PER_SUBSYS_SHIFT 5 #define DEVICES_PER_SUBSYS (1 << DEVICES_PER_SUBSYS_SHIFT) #define SSID(_dev) ((_dev)->devnum & ~(DEVICES_PER_SUBSYS-1)) #define IFID(_dev) ((SSID((_dev)) >> DEVICES_PER_SUBSYS_SHIFT) & 0x7) /* Test for 3990-3 or 3990-6 control unit */ #define MODEL3(_cu) ((_cu)->devt == 0x3990 && (_cu)->model == 0xec) #define MODEL6(_cu) ((_cu)->devt == 0x3990 && (_cu)->model == 0xe9) /*-------------------------------------------------------------------*/ /* Definition of a CKD DASD device entry */ /*-------------------------------------------------------------------*/ typedef struct _CKDDEV { /* CKD Device table entry */ char *name; /* Device name */ U16 devt; /* Device type */ BYTE model; /* Device model */ BYTE class; /* Device class */ BYTE code; /* Device code */ U16 cyls; /* Number primary cylinders */ U16 altcyls; /* Number alternate cylinders*/ U16 heads; /* Number heads (trks/cyl) */ U16 r0; /* R0 max size */ U16 r1; /* R1 max size */ U16 har0; /* HA/R0 overhead size */ U16 len; /* Max length */ U16 sectors; /* Number sectors */ U16 rpscalc; /* RPS calculation factor */ S16 formula; /* Space calculation formula */ U16 f1,f2,f3,f4,f5,f6; /* Space calculation factors */ char *cu; /* Default control unit name */ } CKDDEV; #define CKDDEV_SIZE sizeof(CKDDEV) /*-------------------------------------------------------------------*/ /* Definition of a CKD DASD control unit entry */ /*-------------------------------------------------------------------*/ typedef struct _CKDCU { /* CKD Control Unit entry */ char *name; /* Control Unit name */ U16 devt; /* Control Unit type */ BYTE model; /* Control Unit model */ BYTE code; /* Control Unit code */ BYTE funcfeat; /* Functions/Features */ BYTE typecode; /* CU Type Code */ U32 sctlfeat; /* Control Unit features */ U32 ciw1; /* CIW 1 */ U32 ciw2; /* CIW 2 */ U32 ciw3; /* CIW 3 */ U32 ciw4; /* CIW 4 */ U32 ciw5; /* CIW 5 */ U32 ciw6; /* CIW 6 */ U32 ciw7; /* CIW 7 */ U32 ciw8; /* CIW 8 */ U8 senselength; /* Sense length */ } CKDCU; #define CKDCU_SIZE sizeof(CKDCU) /*-------------------------------------------------------------------*/ /* Definition of a FBA DASD device entry */ /*-------------------------------------------------------------------*/ typedef struct _FBADEV { /* FBA Device entry */ char *name; /* Device name */ U16 devt; /* Device type */ BYTE class; /* Device class */ BYTE type; /* Type */ BYTE model; /* Model */ U32 bpg; /* Blocks per cyclical group */ U32 bpp; /* Blocks per access position*/ U32 size; /* Block size */ U32 blks; /* Number of blocks */ U16 cu; /* Default control unit type */ } FBADEV; #define FBADEV_SIZE sizeof(FBADEV) #if defined(FEATURE_VM_BLOCKIO) /*-------------------------------------------------------------------*/ /* Device Standard Block Size Information Table */ /*-------------------------------------------------------------------*/ typedef struct _BLKTAB { char *name; /* Device name */ U16 devt; /* Hercules supported device Type */ int darch; /* FBA (0) or CKD (1) device */ #define VMDEVFBA 0 /* Fixed-Block Architecture device */ #define VMDEVCKD 1 /* (Extended-)Count-Key-Data device */ /* sectors per block or blocks per track for standardblock sizes */ int phys512; /* Block size 512 */ int phys1024; /* Block size 1024 */ int phys2048; /* Block size 2048 */ int phys4096; /* Block size 4096 */ } BLKTAB; #define BLKTAB_SIZE sizeof(BLKTAB) /* Macros that define a table entry */ #define CKDIOT(_name,_type,_bs512,_bs1024,_bs2048,_bs4096) \ { _name, _type, 1, _bs512, _bs1024, _bs2048, _bs4906 } #define FBAIOT(_name,_type) \ { _name, _type, 0, 1, 2, 4, 8 } #endif /* defined(FEATURE_VM_BLOCKIO) */ /*-------------------------------------------------------------------*/ /* Request types for dasd_lookup */ /*-------------------------------------------------------------------*/ #define DASD_CKDDEV 1 /* Lookup CKD device */ #define DASD_CKDCU 2 /* Lookup CKD control unit */ #define DASD_FBADEV 3 /* Lookup FBA device */ #if defined(FEATURE_VM_BLOCKIO) #define DASD_STDBLK 4 /* Lookup device standard block/physical */ #endif /* defined(FEATURE_VM_BLOCKIO) */ /*-------------------------------------------------------------------*/ /* Dasd table function prototypes */ /*-------------------------------------------------------------------*/ DTB_DLL_IMPORT void *dasd_lookup (int, char *, U32 , U32 ); int dasd_build_ckd_devid (CKDDEV *, CKDCU *, BYTE *); int dasd_build_ckd_devchar (CKDDEV *, CKDCU *, BYTE *, int); DTB_DLL_IMPORT int dasd_build_ckd_config_data (DEVBLK *, BYTE *, int); DTB_DLL_IMPORT int dasd_build_ckd_subsys_status (DEVBLK *, BYTE *, int); int dasd_build_fba_devid (FBADEV *, BYTE *); int dasd_build_fba_devchar (FBADEV *, BYTE *, int); #endif /*!defined(_DASDTAB_H)*/ hercules-3.12/sllib.h0000664000175000017500000001762412564723224011473 00000000000000/* SLLIB.H (c) Copyright Leland Lucius, 2000-2009 */ /* Header for Standard Label library */ #if !defined( _SLLIB_H_ ) #define _SLLIB_H_ #include "hercules.h" #ifndef _SLLIB_C_ #ifndef _HTAPE_DLL_ #define SLL_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define SLL_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define SLL_DLL_IMPORT DLL_EXPORT #endif /* || ---------------------------------------------------------------------------- || || SLLIB.H (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Header for Standard Label library. || || ---------------------------------------------------------------------------- */ #if !defined( TRUE ) #define TRUE 1 #endif #if !defined( FALSE ) #define FALSE 0 #endif /* || Raw label structure */ typedef struct _sllabel { char id[ 3 ]; char num[ 1 ]; union { struct { char volser[ 6 ]; char rsvd1[ 25 ]; char idrc[ 1 ]; char rsvd2[ 5 ]; char owner[ 10 ]; char rsvd3[ 29 ]; } vol; struct { char dsid[ 17 ]; char volser[ 6 ]; char volseq[ 4 ]; char dsseq[ 4 ]; char genno[ 4 ]; char verno[ 2 ]; char crtdt[ 6 ]; char expdt[ 6 ]; char dssec[ 1 ]; char blklo[ 6 ]; char syscd[ 13 ]; char rsvd1[ 3 ]; char blkhi[ 4 ]; } ds1; struct { char recfm[ 1 ]; char blksize[ 5 ]; char lrecl[ 5 ]; char den[ 1 ]; char dspos[ 1 ]; char jobid[ 17 ]; char trtch[ 2 ]; char ctrl[ 1 ]; char rsvd1[ 1 ]; char blkattr[ 1 ]; char rsvd2[ 2 ]; char devser[ 6 ]; char ckptid[ 1 ]; char rsvd3[ 22 ]; char lblkln[ 10 ]; } ds2; struct { char data[ 76 ]; } usr; } u; } SLLABEL; /* || Cooked label structure */ typedef struct _slfmt { char *key[ 14 ]; char *val[ 14 ]; char type[ 4 + 1 ]; union { struct { char volser[ 6 + 1 ]; char idrc[ 1 + 1 ]; char owner[ 10 + 1 ]; } vol; struct { char dsid[ 17 + 1 ]; char volser[ 6 + 1 ]; char volseq[ 4 + 1 ]; char dsseq[ 4 + 1 ]; char genno[ 4 + 1 ]; char verno[ 2 + 1 ]; char crtdt[ 6 + 1 ]; char expdt[ 6 + 1 ]; char dssec[ 1 + 1 ]; char blklo[ 6 + 1 ]; char syscd[ 13 + 1 ]; char blkhi[ 4 + 1 ]; } ds1; struct { char recfm[ 1 + 1 ]; char blksize[ 5 + 1 ]; char lrecl[ 5 + 1 ]; char den[ 1 + 1 ]; char dspos[ 1 + 1 ]; char jobid[ 17 + 1 ]; char trtch[ 2 + 1 ]; char ctrl[ 1 + 1 ]; char blkattr[ 1 + 1 ]; char devser[ 6 + 1 ]; char ckptid[ 1 + 1 ]; char lblkln[ 10 + 1 ]; } ds2; struct { char data[ 76 + 1 ]; } usr; } u; } SLFMT; /* || Prettier label structure mappings */ #define slvol u.vol #define slds1 u.ds1 #define slds2 u.ds2 #define slusr u.usr /* || Special dataset name used to generate an IEHINITT HDR1 label */ #define SL_INITDSN "_IEHINITT_" /* || Length of SL format date */ #define SL_DATELEN 6 /* || Label types */ #define SLT_UNKOWN 0 #define SLT_VOL 1 #define SLT_HDR 2 #define SLT_UHL 3 #define SLT_EOF 4 #define SLT_EOV 5 #define SLT_UTL 6 /* || Macros to test label type */ #define sl_isvol( s, n ) sl_istype( (s), SLT_VOL, (n) ) #define sl_ishdr( s, n ) sl_istype( (s), SLT_HDR, (n) ) #define sl_isuhl( s, n ) sl_istype( (s), SLT_UHL, (n) ) #define sl_iseof( s, n ) sl_istype( (s), SLT_EOF, (n) ) #define sl_iseov( s, n ) sl_istype( (s), SLT_EOV, (n) ) #define sl_isutl( s, n ) sl_istype( (s), SLT_UTL, (n) ) /* || Macros to define specific labels */ #define sl_vol1( p1, p2, p3 ) \ sl_vol( p1, p2, p3 ) #define sl_hdr1( p1, p2, p3, p4, p5, p6, p7 ) \ sl_ds1( p1, SLT_HDR, p2, p3, p4, p5, p6, p7 ) #define sl_eof1( p1, p2, p3, p4, p5, p6 ) \ sl_ds1( p1, SLT_EOF, p2, p3, p4, p5, p6 ) #define sl_eov1( p1, p2, p3, p4, p5, p6 ) \ sl_ds1( p1, SLT_EOV, p2, p3, p4, p5, p6 ) #define sl_hdr2( p1, p2, p3, p4, p5, p6, p7, p8 ) \ sl_ds2( p1, SLT_HDR, p2, p3, p4, p5, p6, p7, p8 ) #define sl_eof2( p1, p2, p3, p4, p5, p6, p7, p8 ) \ sl_ds2( p1, SLT_EOF, p2, p3, p4, p5, p6, p7, p8 ) #define sl_eov2( p1, p2, p3, p4, p5, p6, p7, p8 ) \ sl_ds2( p1, SLT_EOV, p2, p3, p4, p5, p6, p7, p8 ) #define sl_uhl1( p1, p2 ) sl_usr( p1, SLT_UHL, 1, p2 ) #define sl_uhl2( p1, p2 ) sl_usr( p1, SLT_UHL, 2, p2 ) #define sl_uhl3( p1, p2 ) sl_usr( p1, SLT_UHL, 3, p2 ) #define sl_uhl4( p1, p2 ) sl_usr( p1, SLT_UHL, 4, p2 ) #define sl_uhl5( p1, p2 ) sl_usr( p1, SLT_UHL, 5, p2 ) #define sl_uhl6( p1, p2 ) sl_usr( p1, SLT_UHL, 6, p2 ) #define sl_uhl7( p1, p2 ) sl_usr( p1, SLT_UHL, 7, p2 ) #define sl_uhl8( p1, p2 ) sl_usr( p1, SLT_UHL, 8, p2 ) #define sl_utl1( p1, p2 ) sl_usr( p1, SLT_UTL, 1, p2 ) #define sl_utl2( p1, p2 ) sl_usr( p1, SLT_UTL, 2, p2 ) #define sl_utl3( p1, p2 ) sl_usr( p1, SLT_UTL, 3, p2 ) #define sl_utl4( p1, p2 ) sl_usr( p1, SLT_UTL, 4, p2 ) #define sl_utl5( p1, p2 ) sl_usr( p1, SLT_UTL, 5, p2 ) #define sl_utl6( p1, p2 ) sl_usr( p1, SLT_UTL, 6, p2 ) #define sl_utl7( p1, p2 ) sl_usr( p1, SLT_UTL, 7, p2 ) #define sl_utl8( p1, p2 ) sl_usr( p1, SLT_UTL, 8, p2 ) /* || Error definitions */ #define SLE_BLKSIZE -1 /* Block size out of range */ #define SLE_DSSEQ -2 /* Data set sequence out of range */ #define SLE_EXPDT -3 /* Invalid expiration date */ #define SLE_JOBNAME -4 /* Missing or invalid job name */ #define SLE_LRECL -5 /* Invalid record length */ #define SLE_OWNER -6 /* Owner string too long */ #define SLE_RECFM -7 /* Missing or invalid record format */ #define SLE_STEPNAME -8 /* Missing or invalid step name */ #define SLE_TRTCH -9 /* Invalid recording technique */ #define SLE_VOLSEQ -10 /* Volume sequence out of range */ #define SLE_VOLSER -11 /* Missing or invalid volume serial */ #define SLE_DATA -12 /* User data too long */ #define SLE_INVALIDTYPE -13 /* Label type invalid */ #define SLE_INVALIDNUM -14 /* Label number invalid */ /* || Public functions/data */ SLL_DLL_IMPORT char *sl_atoe( void *, void *, int ); SLL_DLL_IMPORT char *sl_etoa( void *, void *, int ); SLL_DLL_IMPORT char *sl_fmtdate( char *, char *, int ); SLL_DLL_IMPORT void sl_fmtlab( SLFMT *, SLLABEL * ); SLL_DLL_IMPORT int sl_islabel( SLLABEL *, void *, int ); SLL_DLL_IMPORT int sl_istype( void *, int type, int num ); SLL_DLL_IMPORT int sl_vol( SLLABEL *, char *, char * ); SLL_DLL_IMPORT int sl_ds1( SLLABEL *, int type, char *, char *, int, int, char *, int ); SLL_DLL_IMPORT int sl_ds2( SLLABEL *, int type, char *, int, int, char *, char *, char * ); SLL_DLL_IMPORT int sl_usr( SLLABEL *, int type, int num, char * ); SLL_DLL_IMPORT const char *sl_error( int rc ); #endif /* defined( _SLLIB_H_ ) */ hercules-3.12/htypes.h0000664000175000017500000002221712564723224011674 00000000000000/* HTYPES.H (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Type Definitions */ #ifndef _HTYPES_H_ #define _HTYPES_H_ /* Try to pull in as many typedef's as possible from the provided system headers for whatever system we're building on... */ #ifndef HAVE_INTTYPES_H #ifdef HAVE_U_INT #define uint8_t u_int8_t #define uint16_t u_int16_t #define uint32_t u_int32_t #define uint64_t u_int64_t #else #error Unable to find fixed-size data types #endif #endif #ifndef HAVE_U_INT8_T #ifdef HAVE_INTTYPES_H typedef uint8_t u_int8_t; typedef uint16_t u_int16_t; typedef uint32_t u_int32_t; typedef uint64_t u_int64_t; #else #error Unable to define u_intNN_t data types #endif #endif typedef int8_t S8; // signed 8-bits typedef int16_t S16; // signed 16-bits typedef int32_t S32; // signed 32-bits typedef int64_t S64; // signed 64-bits typedef uint8_t U8; // unsigned 8-bits typedef uint16_t U16; // unsigned 16-bits typedef uint32_t U32; // unsigned 32-bits typedef uint64_t U64; // unsigned 64-bits #ifndef _MSVC_ // (MSVC typedef's it too) typedef uint8_t BYTE; // unsigned byte (1 byte) #endif typedef uint8_t HWORD[2]; // unsigned halfword (2 bytes) typedef uint8_t FWORD[4]; // unsigned fullword (4 bytes) typedef uint8_t DBLWRD[8]; // unsigned doubleword (8 bytes) typedef uint8_t QWORD[16]; // unsigned quadword (16 bytes) /*-------------------------------------------------------------------*/ /* Format size modifiers for printf and scanf */ /*-------------------------------------------------------------------*/ #if defined(_MSVC_) #define I16_FMT "h" #define I32_FMT "I32" #define I64_FMT "I64" #elif defined(__PRI_64_LENGTH_MODIFIER__) // MAC #define I16_FMT "h" #define I32_FMT "" #define I64_FMT __PRI_64_LENGTH_MODIFIER__ #elif defined(SIZEOF_LONG) && SIZEOF_LONG >= 8 #define I16_FMT "h" #define I32_FMT "" #define I64_FMT "l" #else // !defined(SIZEOF_LONG) || SIZEOF_LONG < 8 #define I16_FMT "h" #define I32_FMT "" #define I64_FMT "ll" #endif #define I16_FMTx "%4.4" I16_FMT "x" #define I32_FMTx "%8.8" I32_FMT "x" #define I64_FMTx "%16.16" I64_FMT "x" #define I16_FMTX "%4.4" I16_FMT "X" #define I32_FMTX "%8.8" I32_FMT "X" #define I64_FMTX "%16.16" I64_FMT "X" #if defined(SIZEOF_INT_P) && SIZEOF_INT_P >= 8 #define FMT_PFX_P "%16.16" #else // !defined(SIZEOF_INT_P) || SIZEOF_INT_P < 8 #define FMT_PFX_P "%8.8" #endif #if defined(__PRI_64_LENGTH_MODIFIER__) // MAC #define UINT_PTR_FMT PRIuPTR #define PTR_FMTx FMT_PFX_P PRIxPTR #define PTR_FMTX FMT_PFX_P PRIXPTR #elif defined(SIZEOF_INT_P) && SIZEOF_INT_P >= 8 #define UINT_PTR_FMT I64_FMT #define PTR_FMTx I64_FMTx #define PTR_FMTX I64_FMTX #else // !defined(SIZEOF_INT_P) || SIZEOF_INT_P < 8 #define UINT_PTR_FMT I32_FMT #define PTR_FMTx I32_FMTx #define PTR_FMTX I32_FMTX #endif #if defined(SIZEOF_SIZE_T) && SIZEOF_SIZE_T >= 8 #define FMT_PFX_Z "%16.16" #else // !defined(SIZEOF_INT_P) || SIZEOF_INT_P < 8 #define FMT_PFX_Z "%8.8" #endif #if defined(__PRI_64_LENGTH_MODIFIER__) // MAC #define SIZE_T_FMT PRIuPTR #define SIZE_T_FMTx FMT_PFX_Z PRIxPTR #define SIZE_T_FMTX FMT_PFX_Z PRIXPTR #elif defined(SIZEOF_SIZE_T) && SIZEOF_SIZE_T >= 8 #define SIZE_T_FMT I64_FMT #define SIZE_T_FMTx I64_FMTx #define SIZE_T_FMTX I64_FMTX #else // !defined(SIZEOF_SIZE_T) || SIZEOF_SIZE_T < 8 #define SIZE_T_FMT I32_FMT #define SIZE_T_FMTx I32_FMTx #define SIZE_T_FMTX I32_FMTX #endif /*-------------------------------------------------------------------*/ /* Socket stuff */ /*-------------------------------------------------------------------*/ #ifndef _BSDTYPES_DEFINED #ifndef HAVE_U_CHAR typedef unsigned char u_char; #endif #ifndef HAVE_U_SHORT typedef unsigned short u_short; #endif #ifndef HAVE_U_INT typedef unsigned int u_int; #endif #ifndef HAVE_U_LONG typedef unsigned long u_long; #endif #define _BSDTYPES_DEFINED #endif #ifndef HAVE_SOCKLEN_T typedef unsigned int socklen_t; #endif #ifndef HAVE_IN_ADDR_T typedef unsigned int in_addr_t; #endif /* FIXME : THAT'S WRONG ! BUT IT WORKS FOR THE TIME BEING */ #if defined(_MSVC_) #ifndef HAVE_USECONDS_T typedef long useconds_t; #endif #endif #if !defined( HAVE_STRUCT_IN_ADDR_S_ADDR ) && !defined( _WINSOCK_H ) struct in_addr { in_addr_t s_addr; }; #endif // (The following are simply to silence some compile time warnings) #ifdef _MSVC_ typedef char GETSET_SOCKOPT_T; typedef const char *const *EXECV_ARG2_ARGV_T; #else typedef void GETSET_SOCKOPT_T; typedef char *const *EXECV_ARG2_ARGV_T; #endif #if defined( OPTION_SCSI_TAPE ) && !defined( HAVE_SYS_MTIO_H ) struct mt_tape_info { long t_type; /* device type id (mt_type) */ char *t_name; /* descriptive name */ }; #define MT_TAPE_INFO { { 0, NULL } } #endif /*-------------------------------------------------------------------*/ /* Primary Hercules Control Structures */ /*-------------------------------------------------------------------*/ typedef struct SYSBLK SYSBLK; // System configuration block typedef struct REGS REGS; // CPU register context typedef struct VFREGS VFREGS; // Vector Facility Registers typedef struct ZPBLK ZPBLK; // Zone Parameter Block typedef struct DEVBLK DEVBLK; // Device configuration block typedef struct IOINT IOINT; // I/O interrupt queue typedef struct DEVDATA DEVDATA; // xxxxxxxxx typedef struct DEVGRP DEVGRP; // xxxxxxxxx typedef struct DEVHND DEVHND; // xxxxxxxxx typedef struct SHRD SHRD; // xxxxxxxxx #ifdef EXTERNALGUI typedef struct GUISTAT GUISTAT; // EXTERNALGUI Device Status Ctl #endif /*-------------------------------------------------------------------*/ /* Secondary Device and I/O Control Related Structures */ /*-------------------------------------------------------------------*/ typedef struct CKDDASD_DEVHDR CKDDASD_DEVHDR; // Device header typedef struct CKDDASD_TRKHDR CKDDASD_TRKHDR; // Track header typedef struct CKDDASD_RECHDR CKDDASD_RECHDR; // Record header typedef struct CCKDDASD_DEVHDR CCKDDASD_DEVHDR; // Compress device header typedef struct CCKD_L2ENT CCKD_L2ENT; // Level 2 table entry typedef struct CCKD_FREEBLK CCKD_FREEBLK; // Free block typedef struct CCKD_IFREEBLK CCKD_IFREEBLK; // Free block (internal) typedef struct CCKD_RA CCKD_RA; // Readahead queue entry typedef struct CCKDBLK CCKDBLK; // Global cckd dasd block typedef struct CCKDDASD_EXT CCKDDASD_EXT; // Ext for compressed ckd typedef struct COMMADPT COMMADPT; // Comm Adapter typedef struct bind_struct bind_struct; // Socket Device Ctl typedef struct TAPEMEDIA_HANDLER TAPEMEDIA_HANDLER; // (see tapedev.h) typedef struct TAPEAUTOLOADENTRY TAPEAUTOLOADENTRY; // (see tapedev.h) typedef struct TAMDIR TAMDIR; // (see tapedev.h) /*-------------------------------------------------------------------*/ /* Device handler function prototypes */ /*-------------------------------------------------------------------*/ typedef int DEVIF (DEVBLK *dev, int argc, char *argv[]); typedef void DEVQF (DEVBLK *dev, char **class, int buflen, char *buffer); typedef void DEVXF (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual); typedef int DEVCF (DEVBLK *dev); typedef void DEVSF (DEVBLK *dev); typedef int DEVRF (DEVBLK *dev, int ix, BYTE *unitstat); typedef int DEVWF (DEVBLK *dev, int rcd, int off, BYTE *buf, int len, BYTE *unitstat); typedef int DEVUF (DEVBLK *dev); typedef void DEVRR (DEVBLK *dev); typedef int DEVSA (DEVBLK *dev, U32 qmask); typedef int DEVSR (DEVBLK *dev, void *file); /*-------------------------------------------------------------------*/ /* Device handler description structures */ /*-------------------------------------------------------------------*/ typedef BYTE *DEVIM; /* Immediate CCW Codes Table */ #endif // _HTYPES_H_ hercules-3.12/fthreads.h0000664000175000017500000003266612564723224012171 00000000000000/* FTHREADS.H (c) Copyright "Fish" (David B. Trout), 2001-2012 */ /* Fish's WIN32 version of pthreads */ //////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2001-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// #ifndef _FTHREADS_H_ #define _FTHREADS_H_ #include "hercules.h" #ifndef _FTHREADS_C_ #ifndef _HUTIL_DLL_ #define FT_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define FT_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define FT_DLL_IMPORT DLL_EXPORT #endif //////////////////////////////////////////////////////////////////////////////////// // Just a handy macro to have around... #define RC(rc) (rc) //////////////////////////////////////////////////////////////////////////////////// #define MyInitializeCriticalSection(pCS) (InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION*)(pCS),3000)) #define MyEnterCriticalSection(pCS) (EnterCriticalSection((CRITICAL_SECTION*)(pCS))) #define MyTryEnterCriticalSection(pCS) (TryEnterCriticalSection((CRITICAL_SECTION*)(pCS))) #define MyLeaveCriticalSection(pCS) (LeaveCriticalSection((CRITICAL_SECTION*)(pCS))) #define MyDeleteCriticalSection(pCS) (DeleteCriticalSection((CRITICAL_SECTION*)(pCS))) #ifdef _MSVC_ #define MyCreateThread(sec,stack,start,parm,flags,tid) ((HANDLE) _beginthreadex((sec),(unsigned)(stack),(start),(parm),(flags),(tid))) #define MyExitThread(code) (_endthreadex((code))) #else // (Cygwin) #define MyCreateThread(sec,stack,start,parm,flags,tid) (CreateThread((sec),(stack),(start),(parm),(flags),(tid))) #define MyExitThread(code) (ExitThread((code))) #endif // _MSVC_ #define MyCreateEvent(sec,man,set,name) (CreateEvent((sec),(man),(set),(name))) #define MySetEvent(h) (SetEvent((h))) #define MyResetEvent(h) (ResetEvent((h))) #define MyDeleteEvent(h) (CloseHandle((h))) #define MyCloseHandle(h) (CloseHandle((h))) #define MyWaitForSingleObject(h,millisecs) (WaitForSingleObject((h),(millisecs))) //////////////////////////////////////////////////////////////////////////////////// // (need struct timespec for fthread_cond_timedwait) #if !defined(TIMESPEC_IN_SYS_TYPES_H) && !defined(TIMESPEC_IN_TIME_H) // (need to define it ourselves) struct timespec { time_t tv_sec; // (seconds) long tv_nsec; // (nanoseconds) }; #endif //////////////////////////////////////////////////////////////////////////////////// // fthread typedefs... typedef void* FT_W32_HANDLE; // HANDLE typedef unsigned long FT_W32_DWORD; // DWORD typedef FT_W32_DWORD fthread_t; // thread id typedef FT_W32_DWORD fthread_mutexattr_t; // mutex attribute typedef void* (FT_THREAD_FUNC)(void*); // thread function typedef FT_THREAD_FUNC* PFT_THREAD_FUNC; // thread function ptr typedef struct _tagFTU_MUTEX // fthread "mutex" structure { FT_W32_DWORD dwMutexMagic; // (magic number) FT_W32_HANDLE hMutex; // (ptr to actual mutex structure) } fthread_mutex_t; typedef struct _tagFTU_COND // fthread "condition variable" structure { FT_W32_DWORD dwCondMagic; // (magic number) FT_W32_HANDLE hCondVar; // (ptr to actual condition variable structure) } fthread_cond_t; typedef struct _tagFTU_ATTR // fthread "thread attribute" structure { FT_W32_DWORD dwAttrMagic; // (magic number) size_t nStackSize; // (initial stack size in bytes) int nDetachState; // (requested detach state: detached/joinable) } fthread_attr_t; //////////////////////////////////////////////////////////////////////////////////// // fthread thread attribute types... #define FTHREAD_CREATE_JOINABLE 0x4A6F696E // "Join" in ASCII #define FTHREAD_CREATE_DETACHED 0x44697363 // "Disc" in ASCII #define FTHREAD_CREATE_DEFAULT FTHREAD_CREATE_JOINABLE //////////////////////////////////////////////////////////////////////////////////// // Initialize a "thread attribute"... FT_DLL_IMPORT int fthread_attr_init ( fthread_attr_t* pThreadAttr ); //////////////////////////////////////////////////////////////////////////////////// // Destroy a "thread attribute"... FT_DLL_IMPORT int fthread_attr_destroy ( fthread_attr_t* pThreadAttr ); //////////////////////////////////////////////////////////////////////////////////// // Set a thread's "detachstate" attribute... FT_DLL_IMPORT int fthread_attr_setdetachstate ( fthread_attr_t* pThreadAttr, int nDetachState ); //////////////////////////////////////////////////////////////////////////////////// // Retrieve a thread's "detachstate" attribute... FT_DLL_IMPORT int fthread_attr_getdetachstate ( const fthread_attr_t* pThreadAttr, int* pnDetachState ); //////////////////////////////////////////////////////////////////////////////////// // Set a thread's initial stack size... FT_DLL_IMPORT int fthread_attr_setstacksize ( fthread_attr_t* pThreadAttr, size_t nStackSize ); //////////////////////////////////////////////////////////////////////////////////// // Retrieve a thread's initial stack size... FT_DLL_IMPORT int fthread_attr_getstacksize ( const fthread_attr_t* pThreadAttr, size_t* pnStackSize ); //////////////////////////////////////////////////////////////////////////////////// // Join a thread (i.e. wait for a thread's termination)... FT_DLL_IMPORT int fthread_join ( fthread_t dwThreadID, void** pExitVal ); //////////////////////////////////////////////////////////////////////////////////// // Detach a thread (i.e. ignore a thread's termination)... FT_DLL_IMPORT int fthread_detach ( fthread_t dwThreadID ); //////////////////////////////////////////////////////////////////////////////////// // Create a new thread... FT_DLL_IMPORT int fthread_create ( fthread_t* pdwThreadID, fthread_attr_t* pThreadAttr, PFT_THREAD_FUNC pfnThreadFunc, void* pvThreadArgs, char* pszThreadName ); //////////////////////////////////////////////////////////////////////////////////// // Exit from a thread... FT_DLL_IMPORT void fthread_exit ( void* ExitVal ); //////////////////////////////////////////////////////////////////////////////////// // Return thread-id... FT_DLL_IMPORT fthread_t fthread_self ( ); //////////////////////////////////////////////////////////////////////////////////// // Compare thread-ids... FT_DLL_IMPORT int fthread_equal ( fthread_t pdwThreadID_1, fthread_t pdwThreadID_2 ); //////////////////////////////////////////////////////////////////////////////////// // (thread signalling not [currently] supported (yet); always returns ENOTSUP...) FT_DLL_IMPORT int fthread_kill // FIXME: TODO: ( int dummy1, int dummy2 ); //////////////////////////////////////////////////////////////////////////////////// // Initialize a "mutex"... FT_DLL_IMPORT int fthread_mutex_init ( fthread_mutex_t* pFT_MUTEX, const fthread_mutexattr_t* pFT_MUTEX_ATTR ); //////////////////////////////////////////////////////////////////////////////////// // Destroy a "mutex"... FT_DLL_IMPORT int fthread_mutex_destroy ( fthread_mutex_t* pFT_MUTEX ); //////////////////////////////////////////////////////////////////////////////////// // Lock a "mutex"... FT_DLL_IMPORT int fthread_mutex_lock ( fthread_mutex_t* pFT_MUTEX ); //////////////////////////////////////////////////////////////////////////////////// // Try to lock a "mutex"... FT_DLL_IMPORT int fthread_mutex_trylock ( fthread_mutex_t* pFT_MUTEX ); //////////////////////////////////////////////////////////////////////////////////// // Unlock a "mutex"... FT_DLL_IMPORT int fthread_mutex_unlock ( fthread_mutex_t* pFT_MUTEX ); //////////////////////////////////////////////////////////////////////////////////// // Initialize a "condition"... FT_DLL_IMPORT int fthread_cond_init ( fthread_cond_t* pFT_COND_VAR ); //////////////////////////////////////////////////////////////////////////////////// // Destroy a "condition"... FT_DLL_IMPORT int fthread_cond_destroy ( fthread_cond_t* pFT_COND_VAR ); //////////////////////////////////////////////////////////////////////////////////// // 'Signal' a "condition"... (causes ONE waiting thread to be released) FT_DLL_IMPORT int fthread_cond_signal ( fthread_cond_t* pFT_COND_VAR ); //////////////////////////////////////////////////////////////////////////////////// // 'Broadcast' a "condition"... (causes ALL waiting threads to be released) FT_DLL_IMPORT int fthread_cond_broadcast ( fthread_cond_t* pFT_COND_VAR ); //////////////////////////////////////////////////////////////////////////////////// // Wait for a "condition" to occur... FT_DLL_IMPORT int fthread_cond_wait ( fthread_cond_t* pFT_COND_VAR, fthread_mutex_t* pFT_MUTEX ); //////////////////////////////////////////////////////////////////////////////////// // Wait (but not forever) for a "condition" to occur... FT_DLL_IMPORT int fthread_cond_timedwait ( fthread_cond_t* pFT_COND_VAR, fthread_mutex_t* pFT_MUTEX, struct timespec* pTimeTimeout ); //////////////////////////////////////////////////////////////////////////////////// // fthread mutex attribute types... // // FTHREAD_MUTEX_NORMAL This type of mutex does not detect deadlock. A thread // attempting to relock this mutex without first unlocking // it shall deadlock. Attempting to unlock a mutex locked // by a different thread results in undefined behavior. // Attempting to unlock an unlocked mutex results in // undefined behavior. The FTHREAD_MUTEX_NORMAL mutex type // is not currently supported by fthreads. // // FTHREAD_MUTEX_ERRORCHECK This type of mutex provides error checking. A thread // attempting to relock this mutex without first unlocking // it shall return with an error. A thread attempting to // unlock a mutex which another thread has locked shall // return with an error. A thread attempting to unlock an // unlocked mutex shall return with an error. // // FTHREAD_MUTEX_RECURSIVE A thread attempting to relock this mutex without first // unlocking it shall succeed in locking the mutex. The // relocking deadlock which can occur with mutexes of type // FTHREAD_MUTEX_NORMAL cannot occur with this type of mutex. // Multiple locks of this mutex shall require the same number // of unlocks to release the mutex before another thread // can acquire the mutex. A thread attempting to unlock a // mutex which another thread has locked shall return with // an error. A thread attempting to unlock an unlocked mutex // shall return with an error. // // FTHREAD_MUTEX_DEFAULT Attempting to recursively lock a mutex of this type results // in undefined behavior. Attempting to unlock a mutex of this // type which was not locked by the calling thread results // in undefined behavior. Attempting to unlock a mutex of this // type which is not locked results in undefined behavior. // An implementation may map this mutex to one of the other // mutex types. #define FTHREAD_MUTEX_ERRORCHECK 0x4F6E6365 // "Once" in ASCII #define FTHREAD_MUTEX_RECURSIVE 0x4D616E79 // "Many" in ASCII #define FTHREAD_MUTEX_DEFAULT FTHREAD_MUTEX_ERRORCHECK //////////////////////////////////////////////////////////////////////////////////// // Initialize a "mutex" attribute... FT_DLL_IMPORT int fthread_mutexattr_init ( fthread_mutexattr_t* pFT_MUTEX_ATTR ); //////////////////////////////////////////////////////////////////////////////////// // Destroy a "mutex" attribute... FT_DLL_IMPORT int fthread_mutexattr_destroy ( fthread_mutexattr_t* pFT_MUTEX_ATTR ); //////////////////////////////////////////////////////////////////////////////////// // Retrieve "mutex" attribute type... FT_DLL_IMPORT int fthread_mutexattr_gettype ( const fthread_mutexattr_t* pFT_MUTEX_ATTR, int* pnMutexType ); //////////////////////////////////////////////////////////////////////////////////// // Set "mutex" attribute type... FT_DLL_IMPORT int fthread_mutexattr_settype ( fthread_mutexattr_t* pFT_MUTEX_ATTR, int nMutexType ); //////////////////////////////////////////////////////////////////////////////////// #endif // _FTHREADS_H_ hercules-3.12/w32chan.h0000664000175000017500000000345712564723224011632 00000000000000//////////////////////////////////////////////////////////////////////////////////// // w32chan.h Fish's new i/o scheduling logic //////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2001-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// #ifndef _W32CHANN_H_ #define _W32CHANN_H_ ///////////////////////////////////////////////////////////////////////////// // I/O Scheduler functions... extern void InitIOScheduler // initialize i/o scheduler vars // Only call this function ONCE -- at startup! From // then on, just set the variables directly as needed. ( int arch_mode, // (for calling execute_ccw_chain) int* devt_prio, // (ptr to device thread priority) int devt_timeout, // (maximum device thread wait time) long devt_max // (maximum #of device threads allowed) ); extern int ScheduleIORequest(void* pDevBlk, unsigned short wDevNum, int* pnDevPrio); extern void TrimDeviceThreads(); extern void KillAllDeviceThreads(); ///////////////////////////////////////////////////////////////////////////// // I/O Scheduler variables... extern long ios_devtwait; // #of threads currently idle extern int ios_devtnbr; // #of threads currently active extern int ios_devthwm; // max #of threads that WERE active extern int ios_devtmax; // max #of threads there can be extern int ios_devtunavail; // #of times 'idle' thread unavailable extern int ios_arch_mode; // architectural mode ///////////////////////////////////////////////////////////////////////////// #endif // _W32CHANN_H_ hercules-3.12/w32ctca.h0000664000175000017500000000316612564723224011630 00000000000000//////////////////////////////////////////////////////////////////////////////////// // w32ctca.h CTCI-W32 (Channel to Channel link to Win32 TCP/IP stack) //////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2002-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// #ifndef _W32CTCA_H_ #define _W32CTCA_H_ #if defined(OPTION_W32_CTCI) #include "tt32api.h" // (#define TUNTAP32_DLLNAME) #define MAX_TT32_DLLNAMELEN (512) #define DEF_TT32_DLLNAME TUNTAP32_DLLNAME // (from tt32api.h) #ifndef MODULESDIR #define MODULESDIR "." // (i.e. "Current Directory") #endif extern char g_tt32_dllname [MAX_TT32_DLLNAMELEN]; extern void tt32_init ( ); extern int tt32_open ( char* pszGatewayDevice, int iFlags ); extern int tt32_read ( int fd, u_char* buffer, u_long size ); extern int tt32_write ( int fd, u_char* buffer, u_long size ); extern int tt32_close ( int fd ); extern int tt32_ioctl ( int fd, int iRequest, char* argp ); extern const char* tt32_get_default_iface (); extern int display_tt32_stats ( int fd ); extern void enable_tt32_debug_tracing( int enable ); // (boolean helper function) extern int tt32_build_herc_iface_mac ( BYTE* out_mac, const BYTE* in_ip ); #endif // defined(OPTION_W32_CTCI) #endif // _W32CTCA_H_ hercules-3.12/tt32api.h0000664000175000017500000003000112564723224011634 00000000000000// Copyright (c) 2002-2008, Software Development Laboratories, "Fish" (David B. Trout) ///////////////////////////////////////////////////////////////////////////////////////// // // TT32API.h -- TunTap32 DLL exported functions interface // ///////////////////////////////////////////////////////////////////////////////////////// // // T U N T A P 3 2 . D L L // // EXPORTED FUNCTION DEFINITIONS // // These functions provide a 'C' language interface and can be called from // any type of app that can access a DLL: VB, C/C++, PowerBuilder, etc. // ///////////////////////////////////////////////////////////////////////////////////////// // // Change History: // // 12/22/01 1.0.0 Created. // 07/20/02 2.0.0 JAP: LCS modifications/enhancements. // 07/02/03 2.0.2 use std 'uint32_t' type instead of Win32 DWORD // 06/16/04 2.1.0 'ex' variant functions to pass errno value. // 11/01/03 3.1.0 TT32MINMTU, TT32MAXMTU, TT32DEFMTU // 11/03/03 3.1.0 TT32_MAX_MULTICAST_LIST_ENTRIES // 12/31/03 3.1.0 support for deprecated functions dropped/deleted. // 02/05/06 3.1.0 New exported function: 'tuntap32_build_herc_iface_mac' // 02/14/06 3.1.0 Added #defines for TUNTAP32_DLLNAME // 04/14/06 3.1.0 Added 'tuntap32_calc_checksum' function // 07/02/06 3.1.2 Added #defines for min/max/def buffer sizes // 08/09/06 3.1.6 Added 'tuntap32_calc_checksum' function // mm/dd/07 3.2.0 VS2005 + x64 + WinPCap 4.0 // 11/06/08 3.3.0 VS2008 + auto-link pragma. // 11/06/08 3.3.0 Additional counters... // ////////////////////////////////////////////////////////////////////////////////////////// #ifndef _TT32API_H_ #define _TT32API_H_ ///////////////////////////////////////////////////////////////////////////////////////// // TunTap32.dll name ///////////////////////////////////////////////////////////////////////////////////////// #if defined(_WIN64) #if defined(_UNICODE) || defined(UNICODE) #if defined(_DEBUG) || defined(DEBUG) #define BASE_TUNTAP32_NAME "TunTap64UD" #else #define BASE_TUNTAP32_NAME "TunTap64U" #endif #else #if defined(_DEBUG) || defined(DEBUG) #define BASE_TUNTAP32_NAME "TunTap64D" #else #define BASE_TUNTAP32_NAME "TunTap64" #endif #endif #else #if defined(_UNICODE) || defined(UNICODE) #if defined(_DEBUG) || defined(DEBUG) #define BASE_TUNTAP32_NAME "TunTap32UD" #else #define BASE_TUNTAP32_NAME "TunTap32U" #endif #else #if defined(_DEBUG) || defined(DEBUG) #define BASE_TUNTAP32_NAME "TunTap32D" #else #define BASE_TUNTAP32_NAME "TunTap32" #endif #endif #endif #if defined( _MSC_VER ) && defined( AUTOLINK_TUNTAP32_LIB ) #pragma comment ( lib, BASE_TUNTAP32_NAME ".lib" ) #endif #define TUNTAP32_DLLNAME BASE_TUNTAP32_NAME ".dll" ///////////////////////////////////////////////////////////////////////////////////////// // TunTap32 structures, #defines and typedefs, etc... ///////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { #endif #define TT32MINMTU ( 60) // minimum MTU value #define TT32DEFMTU ( 1500) // default MTU value #define TT32MAXMTU ((64*1024)-14) // maximum MTU value (14 == eth_hdr_size) #define TT32_MAX_MULTICAST_LIST_ENTRIES (32) #define TT32SDEVBUFF _IOW('T', 220, int) #define TT32GDEVBUFF _IOR('T', 220, int) #define TT32SIOBUFF _IOW('T', 221, int) #define TT32GIOBUFF _IOR('T', 221, int) #define TT32STIMEOUT _IOW('T', 222, int) #define TT32GTIMEOUT _IOR('T', 222, int) #define TT32GSTATS _IOR('T', 223, int) struct tt32ctl { union { char ctln_name[IFNAMSIZ]; // iface name (e.g. "tun0") } tt32_ctln; union { int ctlu_devbuffsize; // Kernel buffer size int ctlu_iobuffsize; // Read buffer size int ctlu_readtimeout; // Read timeout value } tt32_ctlu; }; #define tt32ctl_name tt32_ctln.ctln_name #define tt32ctl_devbuffsize tt32_ctlu.ctlu_devbuffsize #define tt32ctl_iobuffsize tt32_ctlu.ctlu_iobuffsize #define tt32ctl_readtimeout tt32_ctlu.ctlu_readtimeout // WinPCap device driver capture buffer sizes #define MIN_CAPTURE_BUFFSIZE (64*1024) // minimum = 64K #define DEF_CAPTURE_BUFFSIZE (1*1024*1024) // default = 1M #define MAX_CAPTURE_BUFFSIZE (16*1024*1024) // maximum = 16M // FishPack I/O buffer sizes #define MIN_PACKET_BUFFSIZE (16*1024) // minimum = 16K #define DEF_PACKET_BUFFSIZE (1*64*1024) // default = 64K #define MAX_PACKET_BUFFSIZE (1024*1024) // maximum = 1M typedef struct TT32STATS { uint32_t dwStructSize; // size of this structure uint32_t dwKernelBuffSize; // size of kernel capture buffer uint32_t dwReadBuffSize; // size of dll I/O buffer uint32_t dwMaxBytesReceived; // max dll I/O bytes received int64_t n64WriteCalls; // total #of write requests int64_t n64WriteIOs; // total #of write I/Os int64_t n64ReadCalls; // total #of read requests int64_t n64ReadIOs; // total #of read I/Os int64_t n64PacketsRead; // total #of packets read int64_t n64PacketsWritten; // total #of packets written int64_t n64BytesRead; // total #of bytes read int64_t n64BytesWritten; // total #of bytes written int64_t n64InternalPackets; // total #of packets handled internally int64_t n64IgnoredPackets; // total #of packets ignored // New version 3.3 counters... int64_t n64OwnPacketsIgnored; // total #of packets read with our source MAC int64_t n64ZeroMACPacketsRead; // total #of packets read with dest MAC all zeros int64_t n64ZeroMACPacketsWritten; // total #of packets written with dest MAC all zeros } TT32STATS, *PTT32STATS; #ifndef EXPORT #define EXPORT // we must be importing instead of exporting) #endif ///////////////////////////////////////////////////////////////////////////////////////// // TunTap32.dll exported functions... ///////////////////////////////////////////////////////////////////////////////////////// typedef void (__cdecl *ptr_to_print_debug_string_func)(const char* debug_string); extern const char* WINAPI EXPORT tuntap32_copyright_string (); extern const char* WINAPI EXPORT tuntap32_version_string (); extern void WINAPI EXPORT tuntap32_version_numbers (int* major, int* inter, int* minor, int* build); extern int WINAPI EXPORT tuntap32_set_debug_output_func (ptr_to_print_debug_string_func pfn); extern int WINAPI EXPORT tuntap32_open (char* gatewaydev, int flags); extern int WINAPI EXPORT tuntap32_write (int fd, u_char* buffer, u_long len); extern int WINAPI EXPORT tuntap32_read (int fd, u_char* buffer, u_long len); extern int WINAPI EXPORT tuntap32_close (int fd); extern int WINAPI EXPORT tuntap32_ioctl (int fd, int request, char* argp); extern int WINAPI EXPORT tuntap32_get_stats (int fd, TT32STATS* stats); extern const char* WINAPI EXPORT tuntap32_get_default_iface (); extern void WINAPI EXPORT tuntap32_build_herc_iface_mac (u_char* mac, const u_char* ip); extern u_short WINAPI EXPORT tuntap32_calc_inet_checksum (u_char* buffer, u_long bytes); extern u_short WINAPI EXPORT tuntap32_calc_checksum (u_char* buffer, u_long bytes); // (functions to work around an as-yet unidentified/unresolved 'errno' bug) extern const char* WINAPI EXPORT tuntap32_copyright_string_ex ( int* eno); extern const char* WINAPI EXPORT tuntap32_version_string_ex ( int* eno); extern void WINAPI EXPORT tuntap32_version_numbers_ex (int* major, int* inter, int* minor, int* build, int* eno); extern int WINAPI EXPORT tuntap32_set_debug_output_func_ex (ptr_to_print_debug_string_func pfn, int* eno); extern int WINAPI EXPORT tuntap32_open_ex (char* gatewaydev, int flags, int* eno); extern int WINAPI EXPORT tuntap32_write_ex (int fd, u_char* buffer, u_long len, int* eno); extern int WINAPI EXPORT tuntap32_read_ex (int fd, u_char* buffer, u_long len, int* eno); extern int WINAPI EXPORT tuntap32_close_ex (int fd, int* eno); extern int WINAPI EXPORT tuntap32_ioctl_ex (int fd, int request, char* argp, int* eno); extern int WINAPI EXPORT tuntap32_get_stats_ex (int fd, TT32STATS* stats, int* eno); extern const char* WINAPI EXPORT tuntap32_get_default_iface_ex ( int* eno); // (in case they want to use LoadLibrary and GetProcAddress instead) typedef const char* (WINAPI *ptuntap32_copyright_string) (); typedef const char* (WINAPI *ptuntap32_version_string) (); typedef void (WINAPI *ptuntap32_version_numbers) (int*,int*,int*,int*); typedef int (WINAPI *ptuntap32_set_debug_output_func) (ptr_to_print_debug_string_func); typedef int (WINAPI *ptuntap32_open) (char*,int); typedef int (WINAPI *ptuntap32_write) (int,u_char*,u_long); typedef int (WINAPI *ptuntap32_read) (int,u_char*,u_long); typedef int (WINAPI *ptuntap32_close) (int); typedef int (WINAPI *ptuntap32_ioctl) (int,int,char*); typedef int (WINAPI *ptuntap32_get_stats) (int fd, TT32STATS* stats); typedef const char* (WINAPI *ptuntap32_get_default_iface) (); typedef void (WINAPI *ptuntap32_build_herc_iface_mac) (u_char* mac, const u_char* ip); typedef u_short (WINAPI *ptuntap32_calc_inet_checksum) (u_char*, u_long); typedef u_short (WINAPI *ptuntap32_calc_checksum) (u_char*, u_long); // (functions to work around an as-yet unidentified/unresolved 'errno' bug) typedef const char* (WINAPI *ptuntap32_copyright_string_ex) ( int* eno); typedef const char* (WINAPI *ptuntap32_version_string_ex) ( int* eno); typedef void (WINAPI *ptuntap32_version_numbers_ex) (int* major, int* inter, int* minor, int* build, int* eno); typedef int (WINAPI *ptuntap32_set_debug_output_func_ex) (ptr_to_print_debug_string_func pfn, int* eno); typedef int (WINAPI *ptuntap32_open_ex) (char* gatewaydev, int flags, int* eno); typedef int (WINAPI *ptuntap32_write_ex) (int fd, u_char* buffer, u_long len, int* eno); typedef int (WINAPI *ptuntap32_read_ex) (int fd, u_char* buffer, u_long len, int* eno); typedef int (WINAPI *ptuntap32_close_ex) (int fd, int* eno); typedef int (WINAPI *ptuntap32_ioctl_ex) (int fd, int request, char* argp, int* eno); typedef int (WINAPI *ptuntap32_get_stats_ex) (int fd, TT32STATS* stats, int* eno); typedef const char* (WINAPI *ptuntap32_get_default_iface_ex) ( int* eno); ///////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus } #endif #endif /* _TT32API_H_ */ ///////////////////////////////////////////////////////////////////////////////////////// hercules-3.12/linklist.h0000664000175000017500000002614012564723224012210 00000000000000/* LINKLIST.H (c) Copyright "Fish" (David B. Trout), 2001-2005 */ /* Linked-list macros */ #ifndef _LLIST_ #define _LLIST_ ////////////////////////////////////////////////////////////////////////////////////////// /* This module is a standalone collection of linked-list definition, and manipulation macros originally defined for Windows NT development. Samples: // Define a list head. LIST_ENTRY FooList; // Define a structure that will be on the list. // (NOTE: To make debugging easier, it's best to define the LIST_ENTRY field // as the very first field in your structure, but it's not a requirement.) typedef struct _FOO { LIST_ENTRY FooListEntry; . . . } FOO, *PFOO; // Initialize an empty list. InitializeListHead(&FooList); // Create an object, append it to the end of the list. FOO* pFoo; pFoo = ALLOC(sizeof(FOO)); {check for errors, initialize FOO structure} InsertListTail(&FooList,&pFoo->FooListEntry); // Scan list and delete selected items. LIST_ENTRY* pListEntry = FooList.Flink; while (pListEntry != &FooList) { pFoo = CONTAINING_RECORD(pListEntry,FOO,FooListEntry); pListEntry = pListEntry->Flink; if (SomeFunction(pFoo)) { RemoveListEntry(&pFoo->FooListEntry); FREE(pFoo); } } // Purge all items from a list. while (!IsListEmpty(&FooList)) { pListEntry = RemoveListHead(&FooList); pFoo = CONTAINING_RECORD(pListEntry,FOO,FooListEntry); FREE(pFoo); } */ ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( WIN32 ) || \ ( defined( _MSVC_ ) && !defined(_WINNT_) && !defined(_WINNT_H) ) typedef struct _LIST_ENTRY { struct _LIST_ENTRY* Flink; // ptr to next link in chain struct _LIST_ENTRY* Blink; // ptr to previous link in chain } LIST_ENTRY, *PLIST_ENTRY; #endif // !defined(_WINNT_) ////////////////////////////////////////////////////////////////////////////////////////// // // * CONTAINING_RECORD // ( // VOID* address, // type, // field // ); // /* Retrieves a typed pointer to a linked list item given the address of the link storage structure embedded in the linked list item, the type of the linked list item, and the field name of the embedded link storage structure. NOTE: since this macro uses compile-time type knowledge, there is no equivalent C procedure for this macro. Arguments: address - The address of a LIST_ENTRY structure embedded in an a linked list item. type - The type name of the containing linked list item structure. field - The field name of the LIST_ENTRY structure embedded within the linked list item structure. Return Value: Pointer to the linked list item. For Example: If your record looked like this: typedef struct _MYRECORD { int alpha; int beta; LIST_ENTRY gamma; int delta; int epsilon; } MYRECORD, *PMYRECORD; Then, given a variable called "pListEntry" that pointed to the LIST_ENTRY field within your record (i.e. gamma), you can obtain a pointer to the beginning of your record by coding the following CONTAINING_RECORD macro expression: MYRECORD* pMyRecord; // the variable you wish to point to your record // LIST_ENTRY* pListEntry; // already points to the LIST_ENTRY field within // your record (i.e. points to field "gamma") pMyRecord = CONTAINING_RECORD(pListEntry,MYRECORD,gamma); --*/ #ifndef CONTAINING_RECORD #define CONTAINING_RECORD( address, type, field ) \ \ ( (type*) ((char*)(address) - (char*)(&((type*)0)->field)) ) #endif ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // // From NTRTL.H: Doubly-linked list manipulation routines. // // (NOTE: implemented as macros but logically these are procedures) // ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // // void InitializeListHead // ( // LIST_ENTRY* head // ); // /* Initializes a LIST_ENTRY structure to be the head of an initially empty linked list. Arguments: head - Reference to the structure to be initialized. Return Value: None */ #define InitializeListHead(head) \ \ ( (head)->Flink = (head)->Blink = (head) ) ////////////////////////////////////////////////////////////////////////////////////////// // (I created this one myself -- Fish) // // void InitializeListLink // ( // LIST_ENTRY* link // ); // /* Initializes a LIST_ENTRY structure to be an unlinked link. Arguments: link - Reference to the structure to be initialized. Return Value: None */ #define InitializeListLink(link) \ \ ( (link)->Flink = (link)->Blink = (NULL) ) ////////////////////////////////////////////////////////////////////////////////////////// // // IsListEmpty // ( // LIST_ENTRY* head // ); // /* Determines whether or not a list is empty. Arguments: head - Reference to the head of the linked list to be examined. Return Value: - List is empty. - List contains at least one item. --*/ #define IsListEmpty(head) \ \ ( (head)->Flink == (head) ) ////////////////////////////////////////////////////////////////////////////////////////// // // VOID InsertListHead // ( // LIST_ENTRY* head, // LIST_ENTRY* entry // ); // /* Inserts a new item as the "head" (first) item of a linked list. Arguments: head - Reference to the head of the linked list to be operated upon. entry - Reference to the linkage structure embedded in the linked list item to be added to the linked list. Return Value: None */ #define InsertListHead(head,entry) \ { \ LIST_ENTRY* _EX_Head; \ LIST_ENTRY* _EX_Next; \ \ _EX_Head = (head); \ _EX_Next = _EX_Head->Flink; \ \ (entry)->Flink = _EX_Next; \ (entry)->Blink = _EX_Head; \ \ _EX_Head->Flink = (entry); \ _EX_Next->Blink = (entry); \ } ////////////////////////////////////////////////////////////////////////////////////////// // // VOID InsertListTail // ( // LIST_ENTRY* head, // LIST_ENTRY* entry // ); // /* Inserts a new item as the "tail" (last) item of a linked list. Arguments: head - Reference to the head of the linked list to be operated upon. entry - Reference to the linkage structure embedded in the linked list item to be added to the linked list. Return Value: None */ #define InsertListTail(head,entry) \ { \ LIST_ENTRY* _EX_Head; \ LIST_ENTRY* _EX_Tail; \ \ _EX_Head = (head); \ _EX_Tail = _EX_Head->Blink; \ \ (entry)->Flink = _EX_Head; \ (entry)->Blink = _EX_Tail; \ \ _EX_Tail->Flink = (entry); \ _EX_Head->Blink = (entry); \ } ////////////////////////////////////////////////////////////////////////////////////////// // // LIST_ENTRY* RemoveListHead // ( // LIST_ENTRY* head // ); // /* Removes the "head" (first) item from a linked list, returning the pointer to the removed entry's embedded linkage structure. Attempting to remove the head item from a (properly initialized) linked list is a no-op and returns the pointer to the head of the linked list. The caller may use the CONTAINING_RECORD macro to amplify the returned linkage structure pointer to the containing linked list item structure. Arguments: head - Reference to the head of the linked list to be operated upon. Return Value: Returns a pointer to the newly removed linked list item's embedded linkage structure, or the linked list head in the case of an empty list. */ #define RemoveListHead(head) \ \ (head)->Flink; \ \ { \ RemoveListEntry((head)->Flink) \ } ////////////////////////////////////////////////////////////////////////////////////////// // // LIST_ENTRY* RemoveListTail // ( // LIST_ENTRY* head // ); // /* Removes the "tail" (last) item from a linked list, returning the pointer to the removed entry's embedded linkage structure. Attempting to remove the tail item from a (properly initialized) linked list is a no-op and returns the pointer to the head of the linked list. The caller may use the CONTAINING_RECORD macro to amplify the returned linkage structure pointer to the containing linked list item structure. Arguments: head - Reference to the head of the linked list to be operated upon. Return Value: Pointer to the newly removed linked list item's embedded linkage structure, or the linked list head in the case of an empty list. */ #define RemoveListTail(head) \ \ (head)->Blink; \ \ { \ RemoveListEntry((head)->Blink) \ } ////////////////////////////////////////////////////////////////////////////////////////// // // VOID RemoveListEntry // ( // LIST_ENTRY* entry // ); // /* Removes an item from a linked list. (Removing the head of an empty list is a no-op.) Arguments: entry - Reference to the linkage structure embedded in a linked list item structure. Return Value: None */ #define RemoveListEntry(entry) \ { \ LIST_ENTRY* _EX_Blink; \ LIST_ENTRY* _EX_Flink; \ \ _EX_Flink = (entry)->Flink; \ _EX_Blink = (entry)->Blink; \ \ _EX_Blink->Flink = _EX_Flink; \ _EX_Flink->Blink = _EX_Blink; \ } ////////////////////////////////////////////////////////////////////////////////////////// #endif // _LLIST_ hercules-3.12/httpmisc.h0000664000175000017500000000546612564723224012222 00000000000000/* HTTPMISC.H (c)Copyright Jan Jaeger, 2002-2009 */ /* HTTP Server header file */ #ifndef _HTTPMISC_H #define _HTTPMISC_H #ifdef _HTTPSERV_C_ /* We're building the 'httpserv.c' module, so export our entry-points so that others may import them */ #define HTTP_DLL_IMPORT DLL_EXPORT #else /* _HTTPSERV_C_ */ /* We're building the 'hengine.dll' module, so declare our entry-points as extern so we can link ourselves */ #ifdef _HENGINE_DLL_ #define HTTP_DLL_IMPORT extern #else /* _HENGINE_DLL_ */ /* Some other module is being built, so declare our entry-points as 'import' so they can import them */ #define HTTP_DLL_IMPORT DLL_IMPORT #endif /* _HENGINE_DLL_ */ #endif /* _HTTPSERV_C_ */ #if !defined(PKGDATADIR) #if !defined(_MSVC_) #define HTTP_ROOT "/usr/local/share/hercules/" #else #define HTTP_ROOT "%ProgramFiles%\\Hercules\\html\\" #endif #else #define HTTP_ROOT PKGDATADIR "/" #endif #if !defined(_MSVC_) #define HTTP_PS "/" #else #define HTTP_PS "\\" #endif #define HTTP_WELCOME "hercules.html" #define HTML_HEADER "include/header.htmlpart" #define HTML_FOOTER "include/footer.htmlpart" #define HTML_STATIC_EXPIRY_TIME (60*60*24*7) #if defined(PATH_MAX) #define HTTP_PATH_LENGTH PATH_MAX #else #define HTTP_PATH_LENGTH 1024 #endif typedef struct _CGIVAR { struct _CGIVAR *next; char *name; char *value; int type; #define VARTYPE_NONE 0 #define VARTYPE_GET 1 #define VARTYPE_POST 2 #define VARTYPE_PUT 4 #define VARTYPE_COOKIE 8 } CGIVAR; #define cgi_variable(_webblk, _varname) \ http_variable((_webblk), (_varname), (VARTYPE_GET|VARTYPE_POST)) #define cgi_cookie(_webblk, _varname) \ http_variable((_webblk), (_varname), (VARTYPE_COOKIE)) #define cgi_username(_webblk) \ ((_webblk)->user) #define cgi_baseurl(_webblk) \ ((_webblk)->baseurl) typedef struct _MIMETAB { char *suffix; char *type; } MIMETAB; typedef struct _WEBBLK { #define HDL_VERS_WEBBLK "2.17" #define HDL_SIZE_WEBBLK sizeof(WEBBLK) int sock; int request_type; #define REQTYPE_NONE 0 #define REQTYPE_GET 1 #define REQTYPE_POST 2 #define REQTYPE_PUT 4 char *request; char *baseurl; char *user; CGIVAR *cgivar; } WEBBLK; typedef void (*zz_cgibin) (WEBBLK *webblk); typedef struct _CGITAB { char *path; zz_cgibin cgibin; } CGITAB; HTTP_DLL_IMPORT void html_header (WEBBLK *webblk); HTTP_DLL_IMPORT void html_footer (WEBBLK *webblk); HTTP_DLL_IMPORT int html_include (WEBBLK *webblk, char *filename); HTTP_DLL_IMPORT char *http_variable (WEBBLK *webblk, char *name, int type); void *http_server (void *arg); #endif /* _HTTPMISC_H */ hercules-3.12/devtype.h0000664000175000017500000000544012564723224012037 00000000000000/* DEVTYPE.H (c) Copyright Jan Jaeger, 1999-2009 */ /* Hercules Device Definitions */ #if !defined(_DEVICES_H) #define _DEVICES_H #ifndef _FBADASD_C_ #ifndef _HDASD_DLL_ #define FBA_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define FBA_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define FBA_DLL_IMPORT DLL_EXPORT #endif #ifndef _CKDDASD_C_ #ifndef _HDASD_DLL_ #define CKD_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define CKD_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define CKD_DLL_IMPORT DLL_EXPORT #endif struct DEVHND { DEVIF *init; /* Device Initialisation */ DEVXF *exec; /* Device CCW execute */ DEVCF *close; /* Device Close */ DEVQF *query; /* Device Query */ DEVSF *start; /* Device Start channel pgm */ DEVSF *end; /* Device End channel pgm */ DEVSF *resume; /* Device Resume channel pgm */ DEVSF *suspend; /* Device Suspend channel pgm */ DEVRF *read; /* Device Read */ DEVWF *write; /* Device Write */ DEVUF *used; /* Device Query used */ DEVRR *reserve; /* Device Reserve */ DEVRR *release; /* Device Release */ DEVRR *attention; /* Device Attention */ DEVIM immed; /* Immediate CCW Codes */ DEVSA *siga_r; /* Signal Adapter Input */ DEVSA *siga_w; /* Signal Adapter Output */ DEVSR *hsuspend; /* Hercules suspend */ DEVSR *hresume; /* Hercules resume */ }; #define BEGIN_DEVICE_CLASS_QUERY( _classname, _dev, _class, _buflen, _buffer ) \ if (_class) *_class = _classname; \ if (!_dev || !_class || !_buflen || !_buffer) return #if !defined(OPTION_DYNAMIC_LOAD) extern DEVHND constty_device_hndinfo; extern DEVHND loc3270_device_hndinfo; extern DEVHND comadpt_device_hndinfo; extern DEVHND cardrdr_device_hndinfo; extern DEVHND cardpch_device_hndinfo; extern DEVHND printer_device_hndinfo; extern DEVHND tapedev_device_hndinfo; #endif /*!defined(OPTION_DYNAMIC_LOAD)*/ CKD_DLL_IMPORT DEVHND ckddasd_device_hndinfo; FBA_DLL_IMPORT DEVHND fbadasd_device_hndinfo; extern DEVHND ctcadpt_device_hndinfo; extern DEVHND ctci_device_hndinfo; extern DEVHND ctct_device_hndinfo; extern DEVHND ctce_device_hndinfo; extern DEVHND lcs_device_hndinfo; extern DEVHND vmnet_device_hndinfo; #endif /*!defined(_DEVICES_H)*/ hercules-3.12/codepage.h0000664000175000017500000000125012564723224012121 00000000000000/* CODEPAGE.H (c) Copyright Jan Jaeger, 1999-2009 */ /* Code Page conversion */ #ifndef _HERCULES_CODEPAGE_H #define _HERCULES_CODEPAGE_H #include "hercules.h" #ifndef _CODEPAGE_C_ #ifndef _HUTIL_DLL_ #define COD_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define COD_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else /* _LOGGER_C_ */ #define COD_DLL_IMPORT DLL_EXPORT #endif /* _LOGGER_C_ */ COD_DLL_IMPORT void set_codepage(char *name); COD_DLL_IMPORT unsigned char host_to_guest (unsigned char byte); COD_DLL_IMPORT unsigned char guest_to_host (unsigned char byte); #endif /* _HERCULES_CODEPAGE_H */ hercules-3.12/ctcadpt.h0000664000175000017500000006636612564723224012017 00000000000000/* CTCADPT.H (c) Copyright James A. Pierson, 2002-2012 */ /* (c) Copyright Roger Bowler, 2000-2012 */ /* (c) Copyright Willem Konynenberg, 2000-2009 */ /* (c) Copyright Vic Cross, 2001-2009 */ /* (c) Copyright David B. Trout, 2002-2009 */ /* Hercules Channel-to-Channel Emulation Support */ #ifndef __CTCADPT_H_ #define __CTCADPT_H_ // -------------------------------------------------------------------- // Pack all structures to byte boundary... // -------------------------------------------------------------------- #undef ATTRIBUTE_PACKED #if defined(_MSVC_) #pragma pack(push) #pragma pack(1) #define ATTRIBUTE_PACKED #else #define ATTRIBUTE_PACKED __attribute__((packed)) #endif // -------------------------------------------------------------------- // Definitions for 3088 model numbers // -------------------------------------------------------------------- #define CTC_3088_01 0x308801 // 3172 XCA #define CTC_3088_04 0x308804 // 3088 model 1 CTCA #define CTC_3088_08 0x308808 // 3088 model 2 CTCA #define CTC_3088_1F 0x30881F // 3172 LCS #define CTC_3088_60 0x308860 // OSA or 8232 LCS #define CTC_3088_61 0x308861 // CLAW device // -------------------------------------------------------------------- // Media Access Control address (MAC address) // -------------------------------------------------------------------- #ifndef IFHWADDRLEN // (only predefined on Linux) #define IFHWADDRLEN 6 // Ethernet MAC address length #endif typedef uint8_t MAC[ IFHWADDRLEN ]; // Data Type for MAC Addresses // -------------------------------------------------------------------- // External Declarations // -------------------------------------------------------------------- extern int CTCX_Init( DEVBLK* pDEVBLK, int argc, char *argv[] ); extern int CTCX_Close( DEVBLK* pDEVBLK ); extern void CTCX_Query( DEVBLK* pDEVBLK, char** ppszClass, int iBufLen, char* pBuffer ); extern void CTCX_ExecuteCCW( DEVBLK* pDEVBLK, BYTE bCode, BYTE bFlags, BYTE bChained, U16 sCount, BYTE bPrevCode, int iCCWSeq, BYTE* pIOBuf, BYTE* pMore, BYTE* pUnitStat, U16* pResidual ); extern int CTCI_Init( DEVBLK* pDEVBLK, int argc, char *argv[] ); extern int CTCI_Close( DEVBLK* pDEVBLK ); extern void CTCI_Query( DEVBLK* pDEVBLK, char** ppszClass, int iBufLen, char* pBuffer ); extern void CTCI_ExecuteCCW( DEVBLK* pDEVBLK, BYTE bCode, BYTE bFlags, BYTE bChained, U16 sCount, BYTE bPrevCode, int iCCWSeq, BYTE* pIOBuf, BYTE* pMore, BYTE* pUnitStat, U16* pResidual ); extern void CTCI_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* UnitStat, U16* pResidual, BYTE* pMore ); extern void CTCI_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* UnitStat, U16* pResidual ); extern int LCS_Init( DEVBLK* pDEVBLK, int argc, char *argv[] ); extern int LCS_Close( DEVBLK* pDEVBLK ); extern void LCS_Query( DEVBLK* pDEVBLK, char** ppszClass, int iBufLen, char* pBuffer ); extern void LCS_ExecuteCCW( DEVBLK* pDEVBLK, BYTE bCode, BYTE bFlags, BYTE bChained, U16 sCount, BYTE bPrevCode, int iCCWSeq, BYTE* pIOBuf, BYTE* pMore, BYTE* pUnitStat, U16* pResidual ); extern void LCS_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* UnitStat, U16* pResidual, BYTE* pMore ); extern void LCS_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* UnitStat, U16* pResidual ); extern void LCS_SDC( DEVBLK* pDEVBLK, BYTE bOpCode, U16 sCount, BYTE* pIOBuf, BYTE* UnitStat, U16* pResidual, BYTE* pMore ); extern int ParseMAC( char* pszMACAddr, BYTE* pbMACAddr ); extern void packet_trace( BYTE *addr, int len ); /**********************************************************************\ ********************************************************************** ** ** ** STANDARD ETHERNET FRAMES LAYOUT ** ** ** ********************************************************************** \**********************************************************************/ // -------------------------------------------------------------------- // Ethernet Frame Header (network byte order) // -------------------------------------------------------------------- struct _ETHFRM { MAC bDestMAC; // 0x00 MAC bSrcMAC; // 0x06 HWORD hwEthernetType; // 0x0C (see below #defines) BYTE bData[FLEXIBLE_ARRAY]; // 0x0E } ATTRIBUTE_PACKED; typedef struct _ETHFRM ETHFRM, *PETHFRM; #define ETH_TYPE_IP 0x0800 #define ETH_TYPE_ARP 0x0806 #define ETH_TYPE_RARP 0x0835 #define ETH_TYPE_SNA 0x80D5 // -------------------------------------------------------------------- // IP Version 4 Frame Header (Type 0x0800) (network byte order) // -------------------------------------------------------------------- struct _IP4FRM { BYTE bVersIHL; // 0x00 Vers:4, IHL:4 BYTE bTOS; // 0x01 HWORD hwTotalLength; // 0x02 HWORD hwIdentification; // 0x04 U16 bFlagsFragOffset; // 0x06 Flags:3, FragOffset:13 BYTE bTTL; // 0x08 BYTE bProtocol; // 0x09 HWORD hwChecksum; // 0x0A U32 lSrcIP; // 0x0C U32 lDstIP; // 0x10 BYTE bData[FLEXIBLE_ARRAY]; // 0x14 } ATTRIBUTE_PACKED; typedef struct _IP4FRM IP4FRM, *PIP4FRM; // -------------------------------------------------------------------- // Address Resolution Protocol Frame (Type 0x0806) (network byte order) // -------------------------------------------------------------------- struct _ARPFRM { HWORD hwHardwareType; // 0x00 HWORD hwProtocolType; // 0x02 BYTE bHardwareSize; // 0x04 BYTE bProtocolSize; // 0x05 HWORD hwOperation; // 0x06 MAC bSendEthAddr; // 0x08 U32 lSendIPAddr; // 0x12 MAC bTargEthAddr; // 0x16 U32 lTargIPAddr; // 0x1C } ATTRIBUTE_PACKED; typedef struct _ARPFRM ARPFRM, *PARPFRM; #define ARP_REQUEST 0x01 #define ARP_REPLY 0x02 #define RARP_REQUEST 0x03 #define RARP_REPLY 0x04 /**********************************************************************\ ********************************************************************** ** ** ** CTCI DEVICE CONTROL BLOCKS ** ** ** ********************************************************************** \**********************************************************************/ #define MAX_CTCI_FRAME_SIZE( pCTCBLK ) \ ( \ pCTCBLK->iMaxFrameBufferSize /* (whatever CTCI_Init defined) */ \ - sizeof( CTCIHDR ) \ - sizeof( CTCISEG ) \ - sizeof_member(CTCIHDR,hwOffset) \ ) #define MAX_LCS_ETH_FRAME_SIZE( pLCSDEV ) \ ( \ pLCSDEV->iMaxFrameBufferSize /* (whatever LCS_Startup defined) */ \ - sizeof( LCSETHFRM ) \ - sizeof_member(LCSHDR,hwOffset) \ ) // PROGRAMMING NOTE: the following frame buffer size should always be // no smaller than the maximum frame buffer size possible for an LCS // device (currently hard-coded in S390 Linux to be 0x5000 via the // #define LCS_IOBUFFERSIZE). Also note that the minimum and maximum // frame buffer size, according to IBM documentation, is 16K to 64K. #define CTC_FRAME_BUFFER_SIZE (0x5000) // 20K CTCI/LCS frame buffer #define CTC_MIN_FRAME_BUFFER_SIZE (0x4000) // Minimum frame buffer size #define CTC_MAX_FRAME_BUFFER_SIZE (0xFFFF) // Maximum frame buffer size #define CTC_READ_TIMEOUT_SECS (5) // five seconds #define CTC_DELAY_USECS (100) // 100 microseconds delay; used // mostly by enqueue frame buffer // full delay loop... struct _CTCBLK; struct _CTCIHDR; struct _CTCISEG; typedef struct _CTCBLK CTCBLK, *PCTCBLK; typedef struct _CTCIHDR CTCIHDR,*PCTCIHDR; typedef struct _CTCISEG CTCISEG,*PCTCISEG; // -------------------------------------------------------------------- // CTCBLK - (host byte order) // -------------------------------------------------------------------- struct _CTCBLK { int fd; // TUN/TAP fd TID tid; // Read Thread ID pid_t pid; // Read Thread pid DEVBLK* pDEVBLK[2]; // 0 - Read subchannel // 1 - Write subchannel U16 iMaxFrameBufferSize; // Device Buffer Size BYTE bFrameBuffer[CTC_FRAME_BUFFER_SIZE]; // (this really SHOULD be dynamically allocated!) U16 iFrameOffset; // Curr Offset into Buffer U16 sMTU; // Max MTU LOCK Lock; // Data LOCK LOCK EventLock; // Condition LOCK COND Event; // Condition signal u_int fDebug:1; // Debugging u_int fOldFormat:1; // Old Config Format u_int fCreated:1; // Interface Created u_int fStarted:1; // Startup Received u_int fDataPending:1; // Data is pending for // read device u_int fCloseInProgress:1; // Close in progress int iKernBuff; // Kernel buffer in K bytes. int iIOBuff; // I/O buffer in K bytes. char szGuestIPAddr[32]; // IP Address (Guest OS) char szDriveIPAddr[32]; // IP Address (Driver) char szNetMask[32]; // Netmask for P2P link char szMTU[32]; char szTUNCharName[256]; // TUN/TAP char filename char szTUNDevName[IFNAMSIZ]; // Network Device Name char szMACAddress[32]; // MAC Address }; /**********************************************************************\ ********************************************************************** ** ** ** CTCI DEVICE FRAMES ** ** ** ********************************************************************** \**********************************************************************/ // -------------------------------------------------------------------- // CTCI Block Header (host byte order) // -------------------------------------------------------------------- struct _CTCIHDR // CTCI Block Header { HWORD hwOffset; // Offset of next block BYTE bData[FLEXIBLE_ARRAY]; // start of data (CTCISEG) } ATTRIBUTE_PACKED; // -------------------------------------------------------------------- // CTCI Segment Header (host byte order) // -------------------------------------------------------------------- struct _CTCISEG // CTCI Segment Header { HWORD hwLength; // Segment length including // this header HWORD hwType; // Ethernet packet type HWORD _reserved; // Unused, set to zeroes BYTE bData[FLEXIBLE_ARRAY]; // Start of data (IP pakcet) } ATTRIBUTE_PACKED; /**********************************************************************\ ********************************************************************** ** ** ** LCS DEVICE CONTROL BLOCKS ** ** ** ********************************************************************** \**********************************************************************/ #define LCS_MAX_PORTS 4 struct _LCSBLK; struct _LCSDEV; struct _LCSPORT; struct _LCSRTE; struct _LCSHDR; struct _LCSCMDHDR; struct _LCSSTDFRM; struct _LCSSTRTFRM; struct _LCSQIPFRM; struct _LCSLSTFRM; struct _LCSIPMPAIR; struct _LCSIPMFRM; struct _LCSETHFRM; typedef struct _LCSBLK LCSBLK, *PLCSBLK; typedef struct _LCSDEV LCSDEV, *PLCSDEV; typedef struct _LCSPORT LCSPORT, *PLCSPORT; typedef struct _LCSRTE LCSRTE, *PLCSRTE; typedef struct _LCSHDR LCSHDR, *PLCSHDR; typedef struct _LCSCMDHDR LCSCMDHDR, *PLCSCMDHDR; typedef struct _LCSSTDFRM LCSSTDFRM, *PLCSSTDFRM; typedef struct _LCSSTRTFRM LCSSTRTFRM, *PLCSSTRTFRM; typedef struct _LCSQIPFRM LCSQIPFRM, *PLCSQIPFRM; typedef struct _LCSLSTFRM LCSLSTFRM, *PLCSLSTFRM; typedef struct _LCSIPMPAIR LCSIPMPAIR, *PLCSIPMPAIR; typedef struct _LCSIPMFRM LCSIPMFRM, *PLCSIPMFRM; typedef struct _LCSETHFRM LCSETHFRM, *PLCSETHFRM; // -------------------------------------------------------------------- // LCS Device (host byte order) // -------------------------------------------------------------------- struct _LCSDEV { U16 sAddr; // Device Base Address BYTE bMode; // (see below #defines) BYTE bPort; // Relative Adapter No. BYTE bType; // (see below #defines) char* pszIPAddress; // IP Address (string) U32 lIPAddress; // IP Address (binary), // (network byte order) PLCSBLK pLCSBLK; // -> LCSBLK DEVBLK* pDEVBLK[2]; // 0 - Read subchannel // 1 - Write cubchannel U16 iMaxFrameBufferSize; // Device Buffer Size BYTE bFrameBuffer[CTC_FRAME_BUFFER_SIZE]; // (this really SHOULD be dynamically allocated!) U16 iFrameOffset; // Curr Offset into Buffer LOCK Lock; // Data LOCK LOCK EventLock; // Condition LOCK COND Event; // Condition signal u_int fCreated:1; // DEVBLK(s) Created u_int fStarted:1; // Device Started u_int fRouteAdded:1; // Routing Added u_int fReplyPending:1; // Cmd Reply is Pending u_int fDataPending:1; // Data is Pending PLCSDEV pNext; // Next device }; #define LCSDEV_MODE_IP 0x01 #define LCSDEV_MODE_SNA 0x02 #define LCSDEV_TYPE_NONE 0x00 #define LCSDEV_TYPE_PRIMARY 0x01 #define LCSDEV_TYPE_SECONDARY 0x02 // -------------------------------------------------------------------- // LCS Port (or Relative Adapter) (host byte order) // -------------------------------------------------------------------- struct _LCSPORT { BYTE bPort; // Relative Adapter No MAC MAC_Address; // MAC Address of Adapter PLCSRTE pRoutes; // -> Routes chain PLCSBLK pLCSBLK; // -> LCSBLK U16 sIPAssistsSupported; // IP Assist Info U16 sIPAssistsEnabled; LOCK Lock; // Data LOCK LOCK EventLock; // Condition LOCK COND Event; // Condition signal u_int fUsed:1; // Port is used u_int fLocalMAC:1; // MAC is specified in OAT u_int fCreated:1; // Interface Created u_int fStarted:1; // Startup Received u_int fRouteAdded:1; // Routing Added u_int fCloseInProgress:1; // Close in progress int fd; // TUN/TAP fd TID tid; // Read Thread ID pid_t pid; // Read Thread pid int icDevices; // Device count char szNetDevName[IFNAMSIZ]; // Network Device Name char szMACAddress[32]; // MAC Address char szGWAddress[32]; // Gateway for W32 }; // -------------------------------------------------------------------- // LCSRTE - Routing Entries (host byte order) // -------------------------------------------------------------------- struct _LCSRTE { char* pszNetAddr; char* pszNetMask; PLCSRTE pNext; }; // -------------------------------------------------------------------- // LCSBLK - Common Storage for LCS Emulation (host byte order) // -------------------------------------------------------------------- struct _LCSBLK { // Config line parameters char* pszTUNDevice; // TUN/TAP char device char* pszOATFilename; // OAT Filename char* pszIPAddress; // IP Address char* pszMACAddress; // MAC Address (string) MAC MAC_Address; // MAC Address (binary) u_int fDebug:1; int icDevices; // Number of devices int iKernBuff; // Kernel buffer in K bytes. int iIOBuff; // I/O buffer in K bytes. PLCSDEV pDevices; // -> Device chain LCSPORT Port[LCS_MAX_PORTS]; // Port Blocks // Self Describing Component Information char szSerialNumber[13]; }; /**********************************************************************\ ********************************************************************** ** ** ** LCS DEVICE FRAMES ** ** ** ********************************************************************** \**********************************************************************/ // -------------------------------------------------------------------- // LCS Frame Header (network byte order) // -------------------------------------------------------------------- struct _LCSHDR // *ALL* LCS Frames start with the following header { HWORD hwOffset; // Offset to next frame or 0 BYTE bType; // (see below #defines) BYTE bSlot; // (i.e. port) } ATTRIBUTE_PACKED; #define LCS_FRMTYP_CMD 0x00 // LCS command mode #define LCS_FRMTYP_ENET 0x01 // Ethernet Passthru #define LCS_FRMTYP_TR 0x02 // Token Ring #define LCS_FRMTYP_FDDI 0x07 // FDDI #define LCS_FRMTYP_AUTO 0xFF // auto-detect // -------------------------------------------------------------------- // LCS Command Frame Header (network byte order) // -------------------------------------------------------------------- struct _LCSCMDHDR // All LCS *COMMAND* Frames start with this header { LCSHDR bLCSHdr; // LCS Frame header BYTE bCmdCode; // (see below #defines) BYTE bInitiator; HWORD hwSequenceNo; HWORD hwReturnCode; BYTE bLanType; // usually LCS_FRMTYP_ENET BYTE bRelAdapterNo; // (i.e. port) } ATTRIBUTE_PACKED; #define LCS_CMD_TIMING 0x00 // Timing request #define LCS_CMD_STRTLAN 0x01 // Start LAN #define LCS_CMD_STOPLAN 0x02 // Stop LAN #define LCS_CMD_GENSTAT 0x03 // Generate Stats #define LCS_CMD_LANSTAT 0x04 // LAN Stats #define LCS_CMD_LISTLAN 0x06 // List LAN #define LCS_CMD_STARTUP 0x07 // Start Host #define LCS_CMD_SHUTDOWN 0x08 // Shutdown Host #define LCS_CMD_LISTLAN2 0x0B // List LAN (another version) #define LCS_CMD_QIPASSIST 0xB2 // Query IP Assists #define LCS_CMD_SETIPM 0xB4 // Set IP Multicast #define LCS_CMD_DELIPM 0xB5 // Delete IP Multicast // -------------------------------------------------------------------- // LCS Standard Command Frame (network byte order) // -------------------------------------------------------------------- struct _LCSSTDFRM { LCSCMDHDR bLCSCmdHdr; // LCS Command Frame header HWORD hwParameterCount; BYTE bOperatorFlags[3]; BYTE _reserved[3]; BYTE bData[FLEXIBLE_ARRAY]; } ATTRIBUTE_PACKED; // -------------------------------------------------------------------- // LCS Startup Command Frame (network byte order) // -------------------------------------------------------------------- struct _LCSSTRTFRM { LCSCMDHDR bLCSCmdHdr; // LCS Command Frame header HWORD hwBufferSize; BYTE _unused2[6]; } ATTRIBUTE_PACKED; // -------------------------------------------------------------------- // LCS Query IP Assists Command Frame (network byte order) // -------------------------------------------------------------------- struct _LCSQIPFRM { LCSCMDHDR bLCSCmdHdr; // LCS Command Frame header HWORD hwNumIPPairs; HWORD hwIPAssistsSupported; HWORD hwIPAssistsEnabled; HWORD hwIPVersion; } ATTRIBUTE_PACKED; #define LCS_ARP_PROCESSING 0x0001 #define LCS_INBOUND_CHECKSUM_SUPPORT 0x0002 #define LCS_OUTBOUND_CHECKSUM_SUPPORT 0x0004 #define LCS_IP_FRAG_REASSEMBLY 0x0008 #define LCS_IP_FILTERING 0x0010 #define LCS_IP_V6_SUPPORT 0x0020 #define LCS_MULTICAST_SUPPORT 0x0040 // -------------------------------------------------------------------- // LCS LAN Statistics Command Frame (network byte order) // -------------------------------------------------------------------- struct _LCSLSTFRM { LCSCMDHDR bLCSCmdHdr; // LCS Command Frame header BYTE _unused1[10]; MAC MAC_Address; // MAC Address of Adapter FWORD fwPacketsDeblocked; FWORD fwPacketsBlocked; FWORD fwTX_Packets; FWORD fwTX_Errors; FWORD fwTX_PacketsDiscarded; FWORD fwRX_Packets; FWORD fwRX_Errors; FWORD fwRX_DiscardedNoBuffs; U32 fwRX_DiscardedTooLarge; } ATTRIBUTE_PACKED; // -------------------------------------------------------------------- // LCS Set IP Multicast Command Frame (network byte order) // -------------------------------------------------------------------- struct _LCSIPMPAIR { U32 IP_Addr; MAC MAC_Address; // MAC Address of Adapter BYTE _reserved[2]; } ATTRIBUTE_PACKED; #define MAX_IP_MAC_PAIRS 32 struct _LCSIPMFRM { LCSCMDHDR bLCSCmdHdr; // LCS Command Frame header HWORD hwNumIPPairs; U16 hwIPAssistsSupported; U16 hwIPAssistsEnabled; U16 hwIPVersion; LCSIPMPAIR IP_MAC_Pair[MAX_IP_MAC_PAIRS]; U32 fwResponseData; } ATTRIBUTE_PACKED; // -------------------------------------------------------------------- // LCS Ethernet Passthru Frame (network byte order) // -------------------------------------------------------------------- struct _LCSETHFRM { LCSHDR bLCSHdr; // LCS Frame header BYTE bData[FLEXIBLE_ARRAY]; // Ethernet Frame } ATTRIBUTE_PACKED; /**********************************************************************\ ********************************************************************** ** ** ** INLINE FUNCTIONS ** ** ** ********************************************************************** \**********************************************************************/ // -------------------------------------------------------------------- // Set SenseID Information // -------------------------------------------------------------------- static inline void SetSIDInfo( DEVBLK* pDEVBLK, U16 wCUType, BYTE bCUMod, U16 wDevType, BYTE bDevMod ) { BYTE* pSIDInfo = pDEVBLK->devid; memset( pSIDInfo, 0, 256 ); *pSIDInfo++ = 0x0FF; *pSIDInfo++ = (BYTE)(( wCUType >> 8 ) & 0x00FF ); *pSIDInfo++ = (BYTE)( wCUType & 0x00FF ); *pSIDInfo++ = bCUMod; *pSIDInfo++ = (BYTE)(( wDevType >> 8 ) & 0x00FF ); *pSIDInfo++ = (BYTE)( wDevType & 0x00FF ); *pSIDInfo++ = bDevMod; *pSIDInfo++ = 0x00; pDEVBLK->numdevid = 7; } // -------------------------------------------------------------------- // Set SenseID CIW Information // -------------------------------------------------------------------- static inline void SetCIWInfo( DEVBLK* pDEVBLK, U16 bOffset, BYTE bCIWType, BYTE bCIWOp, U16 wCIWCount ) { BYTE* pSIDInfo = pDEVBLK->devid; pSIDInfo += 8; pSIDInfo += ( bOffset * 4 ); *pSIDInfo++ = bCIWType | 0x40; *pSIDInfo++ = bCIWOp; *pSIDInfo++ = (BYTE)(( wCIWCount >> 8 ) & 0x00FF ); *pSIDInfo++ = (BYTE)( wCIWCount & 0x00FF ); pDEVBLK->numdevid += pDEVBLK->numdevid == 7 ? 5 : 4; } // -------------------------------------------------------------------- #if defined(_MSVC_) #pragma pack(pop) #endif #endif // __CTCADPT_H_ hercules-3.12/hercifc.h0000664000175000017500000000606712564723224011770 00000000000000/* HERCIFC.H (c) Copyright Roger Bowler, 2000-2012 */ /* (c) Copyright James A. Pierson, 2002-2009 */ /* Hercules Interface Control Program */ #if defined(NEED_HERCIFC_H) #ifndef __HERCIFC_H_ #define __HERCIFC_H_ #if ( (!defined(WIN32) && \ !(defined(HAVE_LINUX_IF_TUN_H) || defined(HAVE_NET_IF_H)) ) || \ (defined(WIN32) && !defined(HAVE_NET_IF_H)) ) struct ifreq { union { char ifrn_name[IFNAMSIZ]; // (interface name) } ifr_ifrn; union { struct sockaddr ifru_addr; // (IP address) struct sockaddr ifru_netmask; // (network mask) struct sockaddr ifru_hwaddr; // (MAC address) short int ifru_flags; // (flags) int ifru_mtu; // (maximum transmission unit) } ifr_ifru; }; #define ifr_name ifr_ifrn.ifrn_name #define ifr_hwaddr ifr_ifru.ifru_hwaddr #define ifr_addr ifr_ifru.ifru_addr #define ifr_netmask ifr_ifru.ifru_netmask #define ifr_flags ifr_ifru.ifru_flags #define ifr_mtu ifr_ifru.ifru_mtu #endif #if ( !defined(WIN32) && !defined(HAVE_LINUX_IF_TUN_H) ) || \ ( defined(OPTION_W32_CTCI) ) /* Ioctl defines */ #define TUNSETNOCSUM _IOW('T', 200, int) #define TUNSETDEBUG _IOW('T', 201, int) #define TUNSETIFF _IOW('T', 202, int) #define TUNSETPERSIST _IOW('T', 203, int) #define TUNSETOWNER _IOW('T', 204, int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 #define IFF_TAP 0x0002 #define IFF_NO_PI 0x1000 #define IFF_ONE_QUEUE 0x2000 #endif #if !defined(HAVE_NET_IF_H) /* Standard interface flags. */ #define IFF_UP 0x1 /* interface is up */ #define IFF_BROADCAST 0x2 /* broadcast address valid */ #define IFF_LOOPBACK 0x8 /* is a loopback net */ #define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ #define IFF_RUNNING 0x40 /* resources allocated */ #define IFF_PROMISC 0x100 /* receive all packets */ #define IFF_MULTICAST 0x1000 /* Supports multicast */ #endif // -------------------------------------------------------------------- // Definition of the control request structure // -------------------------------------------------------------------- #define HERCIFC_CMD "hercifc" // Interface config command #define HERCTUN_DEV "/dev/net/tun" // Default TUN/TAP char dev typedef struct _CTLREQ { long iType; int iProcID; unsigned long int iCtlOp; char szIFName[IFNAMSIZ]; union { struct ifreq ifreq; #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__SOLARIS__) struct rtentry rtentry; #endif } iru; } CTLREQ, *PCTLREQ; #define CTLREQ_SIZE sizeof( CTLREQ ) #define CTLREQ_OP_DONE 0 #endif // __HERCIFC_H_ #endif // #if defined(NEED_HERCIFC_H) hercules-3.12/tuntap.h0000664000175000017500000003033312564723224011671 00000000000000/* TUNTAP.H (c) Copyright James A. Pierson, 2002-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* Hercules - TUN/TAP Abstraction Layer */ #ifndef __TUNTAP_H_ #define __TUNTAP_H_ #include "hercules.h" #if defined( HAVE_STRUCT_SOCKADDR_IN_SIN_LEN ) #define set_sockaddr_in_sin_len( sockaddr_in_ptr ) \ (sockaddr_in_ptr)->sin_len = sizeof( struct sockaddr_in ) #else #define set_sockaddr_in_sin_len( sockaddr_in_ptr ) #endif // ==================================================================== // Declarations // ==================================================================== // // Create TUN/TAP Interface // extern int TUNTAP_CreateInterface ( char* pszTUNDevice, int iFlags, int* pfd, char* pszNetDevName ); // // Configure TUN/TAP Interface // #ifdef OPTION_TUNTAP_CLRIPADDR extern int TUNTAP_ClrIPAddr ( char* pszNetDevName ); #endif extern int TUNTAP_SetIPAddr ( char* pszNetDevName, char* pszIPAddr ); extern int TUNTAP_SetDestAddr ( char* pszNetDevName, char* pszDestAddr ); #ifdef OPTION_TUNTAP_SETNETMASK extern int TUNTAP_SetNetMask ( char* pszNetDevName, char* pszNetMask ); #endif extern int TUNTAP_SetMTU ( char* pszNetDevName, char* pszMTU ); #ifdef OPTION_TUNTAP_SETMACADDR extern int TUNTAP_SetMACAddr ( char* pszNetDevName, char* pszMACAddr ); #endif extern int TUNTAP_SetFlags ( char* pszNetDevName, int iFlags ); extern int TUNTAP_GetFlags ( char* pszNetDevName, int* piFlags ); #ifdef OPTION_TUNTAP_DELADD_ROUTES extern int TUNTAP_AddRoute ( char* pszNetDevName, char* pszDestAddr, char* pszNetMask, char* pszGWAddr, int iFlags ); extern int TUNTAP_DelRoute ( char* pszNetDevName, char* pszDestAddr, char* pszNetMask, char* pszGWAddr, int iFlags ); #endif // (the following function used by Win32 *and* NON-Win32 platforms) extern void build_herc_iface_mac ( BYTE* out_mac, const BYTE* in_ip ); // // Helper Macros // #if defined( WIN32 ) #define TUNTAP_Open tt32_open #define TUNTAP_Close tt32_close #define TUNTAP_Read tt32_read #define TUNTAP_Write tt32_write #define TUNTAP_IOCtl tt32_ioctl #else #define TUNTAP_Open open #define TUNTAP_Close close #define TUNTAP_Read read #define TUNTAP_Write write #define TUNTAP_IOCtl ioctl #endif // defined( WIN32 ) #if defined( WIN32 ) // Win32 (MinGW/Cygwin/MSVC) does not have these // so we need to define them ourselves... struct rtentry { unsigned long int rt_pad1; struct sockaddr rt_dst; // Target address. struct sockaddr rt_gateway; // Gateway addr (RTF_GATEWAY) struct sockaddr rt_genmask; // Target network mask (IP) unsigned short int rt_flags; short int rt_pad2; unsigned long int rt_pad3; unsigned char rt_tos; unsigned char rt_class; short int rt_pad4; short int rt_metric; // +1 for binary compatibility! char * rt_dev; // Forcing the device at add. unsigned long int rt_mtu; // Per route MTU/Window. unsigned long int rt_window; // Window clamping. unsigned short int rt_irtt; // Initial RTT. }; #define RTF_UP 0x0001 /* Route usable. */ #define RTF_GATEWAY 0x0002 /* Destination is a gateway. */ #define RTF_HOST 0x0004 /* Host entry (net otherwise). */ #define RTF_REINSTATE 0x0008 /* Reinstate route after timeout. */ #define RTF_DYNAMIC 0x0010 /* Created dyn. (by redirect). */ #define RTF_MODIFIED 0x0020 /* Modified dyn. (by redirect). */ #define RTF_MTU 0x0040 /* Specific MTU for this route. */ #define RTF_MSS RTF_MTU /* Compatibility. */ #define RTF_WINDOW 0x0080 /* Per route window clamping. */ #define RTF_IRTT 0x0100 /* Initial round trip time. */ #define RTF_REJECT 0x0200 /* Reject route. */ #define RTF_STATIC 0x0400 /* Manually injected route. */ #define RTF_XRESOLVE 0x0800 /* External resolver. */ #define RTF_NOFORWARD 0x1000 /* Forwarding inhibited. */ #define RTF_THROW 0x2000 /* Go to next class. */ #define RTF_NOPMTUDISC 0x4000 /* Do not send packets with DF. */ /* for IPv6 */ #define RTF_DEFAULT 0x00010000 /* default - learned via ND */ #define RTF_ALLONLINK 0x00020000 /* fallback, no routers on link */ #define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ #define RTF_LINKRT 0x00100000 /* link specific - device match */ #define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */ #define RTF_CACHE 0x01000000 /* cache entry */ #define RTF_FLOW 0x02000000 /* flow significant route */ #define RTF_POLICY 0x04000000 /* policy route */ #define RTCF_VALVE 0x00200000 #define RTCF_MASQ 0x00400000 #define RTCF_NAT 0x00800000 #define RTCF_DOREDIRECT 0x01000000 #define RTCF_LOG 0x02000000 #define RTCF_DIRECTSRC 0x04000000 #define RTF_LOCAL 0x80000000 #define RTF_INTERFACE 0x40000000 #define RTF_MULTICAST 0x20000000 #define RTF_BROADCAST 0x10000000 #define RTF_NAT 0x08000000 #define RTF_ADDRCLASSMASK 0xF8000000 #define RT_ADDRCLASS(flags) ((__u_int32_t) flags >> 23) #define RT_TOS(tos) ((tos) & IPTOS_TOS_MASK) #define RT_LOCALADDR(flags) ((flags & RTF_ADDRCLASSMASK) \ == (RTF_LOCAL|RTF_INTERFACE)) #define RT_CLASS_UNSPEC 0 #define RT_CLASS_DEFAULT 253 #define RT_CLASS_MAIN 254 #define RT_CLASS_LOCAL 255 #define RT_CLASS_MAX 255 #define RTMSG_ACK NLMSG_ACK #define RTMSG_OVERRUN NLMSG_OVERRUN #define RTMSG_NEWDEVICE 0x11 #define RTMSG_DELDEVICE 0x12 #define RTMSG_NEWROUTE 0x21 #define RTMSG_DELROUTE 0x22 #define RTMSG_NEWRULE 0x31 #define RTMSG_DELRULE 0x32 #define RTMSG_CONTROL 0x40 #define RTMSG_AR_FAILED 0x51 /* Address Resolution failed. */ /* Use the definitions from the kernel header files. */ //#include // PROGRAMMING NOTE: Cygwin's headers define some (but not all) // of the below values, but we unfortunately MUST use the below // defined values since they're what TunTap32 expects... #undef SIOCGIFCONF // (discard Cygwin's value to use below instead) #undef SIOCGIFFLAGS // (discard Cygwin's value to use below instead) #undef SIOCGIFADDR // (discard Cygwin's value to use below instead) #undef SIOCGIFBRDADDR // (discard Cygwin's value to use below instead) #undef SIOCGIFNETMASK // (discard Cygwin's value to use below instead) #undef SIOCGIFMETRIC // (discard Cygwin's value to use below instead) #undef SIOCGIFMTU // (discard Cygwin's value to use below instead) #undef SIOCGIFHWADDR // (discard Cygwin's value to use below instead) /* Routing table calls. */ #define SIOCADDRT 0x890B /* add routing table entry */ #define SIOCDELRT 0x890C /* delete routing table entry */ #define SIOCRTMSG 0x890D /* call to routing system */ /* Socket configuration controls. */ #define SIOCGIFNAME 0x8910 /* get iface name */ #define SIOCSIFLINK 0x8911 /* set iface channel */ #define SIOCGIFCONF 0x8912 /* get iface list */ #define SIOCGIFFLAGS 0x8913 /* get flags */ #define SIOCSIFFLAGS 0x8914 /* set flags */ #define SIOCGIFADDR 0x8915 /* get PA address */ #define SIOCSIFADDR 0x8916 /* set PA address */ #define SIOCGIFDSTADDR 0x8917 /* get remote PA address */ #define SIOCSIFDSTADDR 0x8918 /* set remote PA address */ #define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ #define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ #define SIOCGIFNETMASK 0x891b /* get network PA mask */ #define SIOCSIFNETMASK 0x891c /* set network PA mask */ #define SIOCGIFMETRIC 0x891d /* get metric */ #define SIOCSIFMETRIC 0x891e /* set metric */ #define SIOCGIFMEM 0x891f /* get memory address (BSD) */ #define SIOCSIFMEM 0x8920 /* set memory address (BSD) */ #define SIOCGIFMTU 0x8921 /* get MTU size */ #define SIOCSIFMTU 0x8922 /* set MTU size */ #define SIOCSIFHWADDR 0x8924 /* set hardware address */ #define SIOCGIFENCAP 0x8925 /* get/set encapsulations */ #define SIOCSIFENCAP 0x8926 #define SIOCGIFHWADDR 0x8927 /* Get hardware address */ #define SIOCGIFSLAVE 0x8929 /* Driver slaving support */ #define SIOCSIFSLAVE 0x8930 #define SIOCADDMULTI 0x8931 /* Multicast address lists */ #define SIOCDELMULTI 0x8932 #define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */ #define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */ #define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */ #define SIOCGIFPFLAGS 0x8935 #define SIOCDIFADDR 0x8936 /* delete PA address */ #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ #define SIOCGIFCOUNT 0x8938 /* get number of devices */ #define SIOCGIFBR 0x8940 /* Bridging support */ #define SIOCSIFBR 0x8941 /* Set bridging options */ #define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ #define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ /* ARP cache control calls. */ /* 0x8950 - 0x8952 * obsolete calls, don't re-use */ #define SIOCDARP 0x8953 /* delete ARP table entry */ #define SIOCGARP 0x8954 /* get ARP table entry */ #define SIOCSARP 0x8955 /* set ARP table entry */ /* RARP cache control calls. */ #define SIOCDRARP 0x8960 /* delete RARP table entry */ #define SIOCGRARP 0x8961 /* get RARP table entry */ #define SIOCSRARP 0x8962 /* set RARP table entry */ /* Driver configuration calls */ #define SIOCGIFMAP 0x8970 /* Get device parameters */ #define SIOCSIFMAP 0x8971 /* Set device parameters */ /* DLCI configuration calls */ #define SIOCADDDLCI 0x8980 /* Create new DLCI device */ #define SIOCDELDLCI 0x8981 /* Delete DLCI device */ /* Device private ioctl calls. */ /* These 16 ioctls are available to devices via the do_ioctl() device vector. Each device should include this file and redefine these names as their own. Because these are device dependent it is a good idea _NOT_ to issue them to random objects and hope. */ #define SIOCDEVPRIVATE 0x89F0 /* to 89FF */ /* * These 16 ioctl calls are protocol private */ #define SIOCPROTOPRIVATE 0x89E0 /* to 89EF */ #endif // defined( WIN32 ) #endif // __TUNTAP_H_ hercules-3.12/tapedev.h0000664000175000017500000012324512564723224012013 00000000000000/* TAPEDEV.H (c) Copyright Ivan Warren and others, 2003-2009 */ /* Tape Device Handler Structure Definitions */ /*-------------------------------------------------------------------*/ /* This header file contains tape related structures and defines */ /* for the Hercules ESA/390 emulator. */ /*-------------------------------------------------------------------*/ #ifndef __TAPEDEV_H__ #define __TAPEDEV_H__ #include "scsitape.h" /* SCSI Tape handling functions */ #include "htypes.h" /* Hercules struct typedefs */ #include "opcode.h" /* device_attention, SETMODE, etc. */ #include "parser.h" /* generic parameter string parser */ /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ #define MAX_BLKLEN 65535 /* Maximum I/O buffer size */ #define TAPE_UNLOADED "*" /* Name for unloaded drive */ /*-------------------------------------------------------------------*/ /* Definitions for 3420/3480 sense bytes */ /*-------------------------------------------------------------------*/ #define SENSE1_TAPE_NOISE 0x80 /* Noise */ #define SENSE1_TAPE_TUA 0x40 /* TU Status A (ready) */ #define SENSE1_TAPE_TUB 0x20 /* TU Status B (not ready) */ #define SENSE1_TAPE_7TRK 0x10 /* 7-track feature */ #define SENSE1_TAPE_RSE 0x10 /* Record sequence error */ #define SENSE1_TAPE_LOADPT 0x08 /* Tape is at load point */ #define SENSE1_TAPE_WRT 0x04 /* Tape is in write status */ #define SENSE1_TAPE_FP 0x02 /* File protect status */ #define SENSE1_TAPE_NCA 0x01 /* Not capable */ #define SENSE4_TAPE_EOT 0x20 /* Tape indicate (EOT) */ #define SENSE5_TAPE_SRDCHK 0x08 /* Start read check */ #define SENSE5_TAPE_PARTREC 0x04 /* Partial record */ #define SENSE7_TAPE_LOADFAIL 0x01 /* Load failure */ /*-------------------------------------------------------------------*/ /* ISW : Internal error types used to build Device Dependent Sense */ /*-------------------------------------------------------------------*/ #define TAPE_BSENSE_TAPEUNLOADED 0 /* I/O Attempted but no tape loaded */ #define TAPE_BSENSE_TAPELOADFAIL 1 /* I/O and load failed */ #define TAPE_BSENSE_READFAIL 2 /* Error reading block */ #define TAPE_BSENSE_WRITEFAIL 3 /* Error writing block */ #define TAPE_BSENSE_BADCOMMAND 4 /* The CCW code is not known or sequence error */ #define TAPE_BSENSE_INCOMPAT 5 /* The CCW code is known but is not unsupported */ #define TAPE_BSENSE_WRITEPROTECT 6 /* Write CCW code was issued to a read-only media */ #define TAPE_BSENSE_EMPTYTAPE 7 /* A read was issued but the tape is empty */ #define TAPE_BSENSE_ENDOFTAPE 8 /* A read was issued past the end of the tape or a write was issued and there is no space left on the tape */ #define TAPE_BSENSE_LOADPTERR 9 /* BSF/BSR/RdBW attempted from BOT */ #define TAPE_BSENSE_FENCED 10 /* Media damaged - unload or /reload required */ #define TAPE_BSENSE_BADALGORITHM 11 /* Bad compression - HET tape compressed with an unsuported method */ #define TAPE_BSENSE_RUN_SUCCESS 12 /* Rewind Unload success */ #define TAPE_BSENSE_STATUSONLY 13 /* No exception occured */ #define TAPE_BSENSE_LOCATEERR 14 /* Can't find block or TM */ #define TAPE_BSENSE_READTM 15 /* A Tape Mark was read */ #define TAPE_BSENSE_BLOCKSHORT 17 /* Short Tape block */ #define TAPE_BSENSE_ITFERROR 18 /* Interface error (SCSI driver unexpected err) */ #define TAPE_BSENSE_REWINDFAILED 19 /* Rewind operation failed */ #define TAPE_BSENSE_UNSOLICITED 20 /* Sense without UC */ /*-------------------------------------------------------------------*/ /* Definitions for 3480 and later commands */ /*-------------------------------------------------------------------*/ /* Format control byte for Load Display command */ #define FCB_FS 0xE0 /* Function Select bits... */ #define FCB_FS_READYGO 0x00 /* Display msg until motion, */ /* or until msg is updated */ #define FCB_FS_UNMOUNT 0x20 /* Display msg until unloaded*/ #define FCB_FS_MOUNT 0x40 /* Display msg until loaded */ #define FCB_FS_RESET_DISPLAY 0x80 /* Reset display (clear Host */ /* msg; replace w/Unit msg) */ #define FCB_FS_NOP 0x60 /* No-op */ #define FCB_FS_UMOUNTMOUNT 0xE0 /* Display msg 1 until tape */ /* is unloaded, then msg 2 */ /* until tape is loaded */ #define FCB_AM 0x10 /* Alternate between msg 1/2 */ #define FCB_BM 0x08 /* Blink message */ #define FCB_M2 0x04 /* Display only message 2 */ #define FCB_RESV 0x02 /* (reserved) */ #define FCB_AL 0x01 /* Activate AutoLoader on */ /* mount/unmount messages */ /* Mode Set commands */ #define MSET_WRITE_IMMED 0x20 /* Tape-Write-Immediate mode */ #define MSET_SUPVR_INHIBIT 0x10 /* Supervisor Inhibit mode */ #define MSET_IDRC 0x08 /* IDRC mode */ /* Path state byte for Sense Path Group ID command */ #define SPG_PATHSTAT 0xC0 /* Pathing status bits... */ #define SPG_PATHSTAT_RESET 0x00 /* ...reset */ #define SPG_PATHSTAT_RESV 0x40 /* ...reserved bit setting */ #define SPG_PATHSTAT_UNGROUPED 0x80 /* ...ungrouped */ #define SPG_PATHSTAT_GROUPED 0xC0 /* ...grouped */ #define SPG_PARTSTAT 0x30 /* Partitioning status bits..*/ #define SPG_PARTSTAT_IENABLED 0x00 /* ...implicitly enabled */ #define SPG_PARTSTAT_RESV 0x10 /* ...reserved bit setting */ #define SPG_PARTSTAT_DISABLED 0x20 /* ...disabled */ #define SPG_PARTSTAT_XENABLED 0x30 /* ...explicitly enabled */ #define SPG_PATHMODE 0x08 /* Path mode bit... */ #define SPG_PATHMODE_SINGLE 0x00 /* ...single path mode */ #define SPG_PATHMODE_RESV 0x08 /* ...reserved bit setting */ #define SPG_RESERVED 0x07 /* Reserved bits, must be 0 */ /* Function control byte for Set Path Group ID command */ #define SPG_SET_MULTIPATH 0x80 /* Set multipath mode */ #define SPG_SET_COMMAND 0x60 /* Set path command bits... */ #define SPG_SET_ESTABLISH 0x00 /* ...establish group */ #define SPG_SET_DISBAND 0x20 /* ...disband group */ #define SPG_SET_RESIGN 0x40 /* ...resign from group */ #define SPG_SET_COMMAND_RESV 0x60 /* ...reserved bit setting */ #define SPG_SET_RESV 0x1F /* Reserved bits, must be 0 */ /* Perform Subsystem Function order byte for PSF command */ #define PSF_ORDER_PRSD 0x18 /* Prep for Read Subsys Data */ #define PSF_ACTION_SSD_ATNMSG 0x03 /* ..Attention Message */ #define PSF_ORDER_SSIC 0x1B /* Set Special Intercept Cond*/ #define PSF_ORDER_MNS 0x1C /* Message Not Supported */ #define PSF_ORDER_AFEL 0x80 /* Activate Forced Error Log.*/ #define PSF_ORDER_DFEL 0x81 /* Deact. Forced Error Log. */ #define PSF_ACTION_FEL_IMPLICIT 0x01 /* ..Implicit (De)Activate */ #define PSF_ACTION_FEL_EXPLICIT 0x02 /* ..Explicit (De)Activate */ #define PSF_ORDER_AAC 0x82 /* Activate Access Control */ #define PSF_ORDER_DAC 0x83 /* Deact. Access Control */ #define PSF_ACTION_AC_LWP 0x80 /* ..Logical Write Protect */ #define PSF_ACTION_AC_DCD 0x10 /* ..Data Compaction Default */ #define PSF_ACTION_AC_DCR 0x02 /* ..Data Check Recovery */ #define PSF_ACTION_AC_ER 0x01 /* ..Extended Recovery */ #define PSF_ORDER_RVF 0x90 /* Reset Volume Fenced */ #define PSF_ORDER_PIN_DEV 0xA1 /* Pin Device */ #define PSF_ACTION_PIN_CU0 0x00 /* ..Control unit 0 */ #define PSF_ACTION_PIN_CU1 0x01 /* ..Control unit 1 */ #define PSF_ORDER_UNPIN_DEV 0xA2 /* Unpin Device */ #define PSF_FLAG_ZERO 0x00 /* Must be zero for all ord. */ /* Control Access Function Control */ #define CAC_FUNCTION 0xC0 /* Function control bits */ #define CAC_SET_PASSWORD 0x00 /* ..Set Password */ #define CAC_COND_ENABLE 0x80 /* ..Conditional Enable */ #define CAC_COND_DISABLE 0x40 /* ..Conditional Disable */ /*-------------------------------------------------------------------*/ /* Definitions for tape device type field in device block */ /*-------------------------------------------------------------------*/ #define TAPEDEVT_UNKNOWN 0 /* AWSTAPE format disk file */ #define TAPEDEVT_AWSTAPE 1 /* AWSTAPE format disk file */ #define TAPEDEVT_OMATAPE 2 /* OMATAPE format disk files */ #define TAPEDEVT_SCSITAPE 3 /* Physical SCSI tape */ #define TAPEDEVT_HETTAPE 4 /* HET format disk file */ #define TAPEDEVT_FAKETAPE 5 /* Flex FakeTape disk format */ /*-------------------------------------------------------------------*/ /* Fish - macros for checking SCSI tape device-independent status */ /*-------------------------------------------------------------------*/ #if defined(OPTION_SCSI_TAPE) #define STS_TAPEMARK(dev) GMT_SM ( (dev)->sstat ) #define STS_EOF(dev) GMT_EOF ( (dev)->sstat ) #define STS_BOT(dev) GMT_BOT ( (dev)->sstat ) #define STS_EOT(dev) GMT_EOT ( (dev)->sstat ) #define STS_EOD(dev) GMT_EOD ( (dev)->sstat ) #define STS_WR_PROT(dev) GMT_WR_PROT ( (dev)->sstat ) #define STS_ONLINE(dev) GMT_ONLINE ( (dev)->sstat ) #define STS_MOUNTED(dev) ((dev)->fd >= 0 && !GMT_DR_OPEN( (dev)->sstat )) #define STS_NOT_MOUNTED(dev) (!STS_MOUNTED(dev)) #endif #define AUTOLOAD_WAIT_FOR_TAPEMOUNT_INTERVAL_SECS (5) /* (default) */ /*-------------------------------------------------------------------*/ /* Structure definition for HET/AWS/OMA tape block headers */ /*-------------------------------------------------------------------*/ /* * The integer fields in the HET, AWSTAPE and OMATAPE headers are * encoded in the Intel format (i.e. the bytes of the integer are held * in reverse order). For this reason the integers are defined as byte * arrays, and the bytes are fetched individually in order to make * the code portable across architectures which use either the Intel * format or the S/370 format. * * Block length fields contain the length of the emulated tape block * and do not include the length of the header. * * For the AWSTAPE and HET formats: * - the first block has a previous block length of zero * - a tapemark is indicated by a header with a block length of zero * and a flag byte of X'40' * * For the OMATAPE format: * - the first block has a previous header offset of X'FFFFFFFF' * - a tapemark is indicated by a header with a block length of * X'FFFFFFFF' * - each block is followed by padding bytes if necessary to ensure * that the next header starts on a 16-byte boundary * */ typedef struct _AWSTAPE_BLKHDR { /* * PROGRAMMING NOTE: note that for AWS tape files, the "current * chunk size" comes FIRST and the "previous chunk size" comes * second. This is the complete opposite from the way it is for * Flex FakeTape. Also note that for AWS the size fields are in * LITTLE endian binary whereas for Flex FakeTape they're a BIG * endian ASCII hex-string. */ HWORD curblkl; /* Length of this block */ HWORD prvblkl; /* Length of previous block */ BYTE flags1; /* Flags byte 1 (see below) */ BYTE flags2; /* Flags byte 2 */ /* Definitions for AWSTAPE_BLKHDR flags byte 1 */ #define AWSTAPE_FLAG1_NEWREC 0x80 /* Start of new record */ #define AWSTAPE_FLAG1_TAPEMARK 0x40 /* Tape mark */ #define AWSTAPE_FLAG1_ENDREC 0x20 /* End of record */ } AWSTAPE_BLKHDR; /*-------------------------------------------------------------------*/ /* Structure definition for OMA block header */ /*-------------------------------------------------------------------*/ typedef struct _OMATAPE_BLKHDR { FWORD curblkl; /* Length of this block */ FWORD prvhdro; /* Offset of previous block header from start of file */ FWORD omaid; /* OMA identifier (contains ASCII characters "@HDF") */ FWORD resv; /* Reserved */ } OMATAPE_BLKHDR; /*-------------------------------------------------------------------*/ /* Structure definition for OMA tape descriptor array */ /*-------------------------------------------------------------------*/ typedef struct _OMATAPE_DESC { int fd; /* File Descriptor for file */ char filename[256]; /* Filename of data file */ char format; /* H=HEADERS,T=TEXT,F=FIXED,X=Tape Mark */ BYTE resv; /* Reserved for alignment */ U16 blklen; /* Fixed block length */ } OMATAPE_DESC; /*-------------------------------------------------------------------*/ /* Structure definition for Flex FakeTape block headers */ /*-------------------------------------------------------------------*/ /* * The character length fields in a Flex FakeTape header are in BIG * endian ASCII hex. That is to say, when the length field is ASCII * "0123" (i.e. 0x30, 0x31, 0x32, 0x33), the length of the block is * decimal 291 bytes (0x0123 == 291). * * The two block length fields are followed by an XOR "check" field * calculated as the XOR of the two preceding length fields and is * used to verify the integrity of the header. * * The Flex FakeTape tape format does not support any flag fields * in its header and thus does not support any type of compression. */ typedef struct _FAKETAPE_BLKHDR { /* * PROGRAMMING NOTE: note that for Flex FakeTapes, the "previous * chunk size" comes FIRST, followed by the "current chunk size" * second. This is the complete opposite from the way it is for * AWS tape files. Also note that for Flex FakeTape the size fields * are in BIG endian ASCII hex-string whereas for AWS tapes * they're LITTLE endian binary. */ char sprvblkl[4]; /* length of previous block */ char scurblkl[4]; /* length of this block */ char sxorblkl[4]; /* XOR both lengths together */ } FAKETAPE_BLKHDR; /*-------------------------------------------------------------------*/ /* Tape Auto-Loader table entry */ /*-------------------------------------------------------------------*/ struct TAPEAUTOLOADENTRY { char *filename; int argc; char **argv; }; /*-------------------------------------------------------------------*/ /* Tape AUTOMOUNT CCWS directory control */ /*-------------------------------------------------------------------*/ struct TAMDIR { TAMDIR *next; /* ptr to next entry or NULL */ char *dir; /* resolved directory value */ int len; /* strlen(dir) */ int rej; /* 1 == reject, 0 == accept */ }; /*-------------------------------------------------------------------*/ /* Generic media-handler-call parameters block */ /*-------------------------------------------------------------------*/ typedef struct _GENTMH_PARMS { int action; // action code (i.e. "what to do") DEVBLK* dev; // -> device block BYTE* unitstat; // -> unit status BYTE code; // CCW opcode // TODO: define whatever additional arguments may be needed... } GENTMH_PARMS; /*-------------------------------------------------------------------*/ /* Generic media-handler-call action codes */ /*-------------------------------------------------------------------*/ #define GENTMH_SCSI_ACTION_UPDATE_STATUS (0) //efine GENTMH_AWS_ACTION_xxxxx... (x) //efine GENTMH_HET_ACTION_xxxxx... (x) //efine GENTMH_OMA_ACTION_xxxxx... (x) /*-------------------------------------------------------------------*/ /* Tape media I/O function vector table layout */ /*-------------------------------------------------------------------*/ struct TAPEMEDIA_HANDLER { int (*generic) (GENTMH_PARMS*); // (generic call) int (*open) (DEVBLK*, BYTE *unitstat, BYTE code); void (*close) (DEVBLK*); int (*read) (DEVBLK*, BYTE *buf, BYTE *unitstat, BYTE code); int (*write) (DEVBLK*, BYTE *buf, U16 blklen, BYTE *unitstat, BYTE code); int (*rewind) (DEVBLK*, BYTE *unitstat, BYTE code); int (*bsb) (DEVBLK*, BYTE *unitstat, BYTE code); int (*fsb) (DEVBLK*, BYTE *unitstat, BYTE code); int (*bsf) (DEVBLK*, BYTE *unitstat, BYTE code); int (*fsf) (DEVBLK*, BYTE *unitstat, BYTE code); int (*wtm) (DEVBLK*, BYTE *unitstat, BYTE code); int (*sync) (DEVBLK*, BYTE *unitstat, BYTE code); int (*dse) (DEVBLK*, BYTE *unitstat, BYTE code); int (*erg) (DEVBLK*, BYTE *unitstat, BYTE code); int (*tapeloaded) (DEVBLK*, BYTE *unitstat, BYTE code); int (*passedeot) (DEVBLK*); /* readblkid o/p values are returned in BIG-ENDIAN guest format */ int (*readblkid) (DEVBLK*, BYTE* logical, BYTE* physical); /* locateblk i/p value is passed in little-endian host format */ int (*locateblk) (DEVBLK*, U32 blockid, BYTE *unitstat, BYTE code); }; /*-------------------------------------------------------------------*/ /* Functions defined in TAPEDEV.C */ /*-------------------------------------------------------------------*/ extern int tapedev_init_handler (DEVBLK *dev, int argc, char *argv[]); extern int tapedev_close_device (DEVBLK *dev ); extern void tapedev_query_device (DEVBLK *dev, char **class, int buflen, char *buffer); extern void autoload_init (DEVBLK *dev, int ac, char **av); extern int autoload_mount_first (DEVBLK *dev); extern int autoload_mount_next (DEVBLK *dev); extern void autoload_close (DEVBLK *dev); extern void autoload_global_parms (DEVBLK *dev, char *par); extern void autoload_clean_entry (DEVBLK *dev, int ix); extern void autoload_tape_entry (DEVBLK *dev, char *fn, char **strtokw); extern int autoload_mount_tape (DEVBLK *dev, int alix); extern void* autoload_wait_for_tapemount_thread (void *db); extern int gettapetype (DEVBLK *dev, char **short_descr); extern int gettapetype_byname (DEVBLK *dev); extern int gettapetype_bydata (DEVBLK *dev); extern int mountnewtape (DEVBLK *dev, int argc, char **argv); extern void GetDisplayMsg (DEVBLK *dev, char *msgbfr, size_t lenbfr); extern int IsAtLoadPoint (DEVBLK *dev); extern void ReqAutoMount (DEVBLK *dev); extern void UpdateDisplay (DEVBLK *dev); extern int return_false1 (DEVBLK *dev); extern int write_READONLY5 (DEVBLK *dev, BYTE *bfr, U16 blklen, BYTE *unitstat, BYTE code); extern int is_tapeloaded_filename (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int write_READONLY (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int no_operation (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int readblkid_virtual (DEVBLK*, BYTE* logical, BYTE* physical); extern int locateblk_virtual (DEVBLK*, U32 blockid, BYTE *unitstat, BYTE code); extern int generic_tmhcall (GENTMH_PARMS*); /*-------------------------------------------------------------------*/ /* Functions (and data areas) defined in TAPECCWS.C */ /*-------------------------------------------------------------------*/ typedef void TapeSenseFunc( int, DEVBLK*, BYTE*, BYTE ); // (sense handling function) #define TAPEDEVTYPELIST_ENTRYSIZE (5) // #of int's per 'TapeDevtypeList' table entry extern int TapeDevtypeList[]; extern BYTE* TapeCommandTable[]; extern TapeSenseFunc* TapeSenseTable[]; //tern BYTE TapeCommandsXXXX[256]... extern BYTE TapeImmedCommands[]; extern int TapeCommandIsValid (BYTE code, U16 devtype, BYTE *rustat); extern void tapedev_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual); extern void load_display (DEVBLK *dev, BYTE *buf, U16 count); extern void build_senseX (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); extern void build_sense_3410 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); extern void build_sense_3420 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); extern void build_sense_3410_3420 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); extern void build_sense_3480_etal (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); extern void build_sense_3490 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); extern void build_sense_3590 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); extern void build_sense_Streaming (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode); /*-------------------------------------------------------------------*/ /* Calculate I/O Residual */ /*-------------------------------------------------------------------*/ #define RESIDUAL_CALC(_data_len) \ len = (_data_len); \ num = (count < len) ? count : len; \ *residual = count - num; \ if (count < len) *more = 1 /*-------------------------------------------------------------------*/ /* Assign a unique Message Id for this asynchronous I/O if needed */ /*-------------------------------------------------------------------*/ #if defined(OPTION_SCSI_TAPE) #define INCREMENT_MESSAGEID(_dev) \ if ((_dev)->SIC_active) \ (_dev)->msgid++ #else #define INCREMENT_MESSAGEID(_dev) #endif // defined(OPTION_SCSI_TAPE) /*-------------------------------------------------------------------*/ /* Functions defined in AWSTAPE.C */ /*-------------------------------------------------------------------*/ extern int open_awstape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern void close_awstape (DEVBLK *dev); extern int passedeot_awstape (DEVBLK *dev); extern int rewind_awstape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int write_awsmark (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int sync_awstape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsb_awstape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsb_awstape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsf_awstape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsf_awstape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int readhdr_awstape (DEVBLK *dev, off_t blkpos, AWSTAPE_BLKHDR *buf, BYTE *unitstat, BYTE code); extern int read_awstape (DEVBLK *dev, BYTE *buf, BYTE *unitstat, BYTE code); extern int write_awstape (DEVBLK *dev, BYTE *buf, U16 blklen, BYTE *unitstat, BYTE code); /*-------------------------------------------------------------------*/ /* Functions defined in FAKETAPE.C */ /*-------------------------------------------------------------------*/ extern int open_faketape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern void close_faketape (DEVBLK *dev); extern int passedeot_faketape (DEVBLK *dev); extern int rewind_faketape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int write_fakemark (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int sync_faketape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsb_faketape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsb_faketape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsf_faketape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsf_faketape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int readhdr_faketape (DEVBLK *dev, off_t blkpos, U16* pprvblkl, U16* pcurblkl, BYTE *unitstat, BYTE code); extern int writehdr_faketape (DEVBLK *dev, off_t blkpos, U16 prvblkl, U16 curblkl, BYTE *unitstat, BYTE code); extern int read_faketape (DEVBLK *dev, BYTE *buf, BYTE *unitstat, BYTE code); extern int write_faketape (DEVBLK *dev, BYTE *buf, U16 blklen, BYTE *unitstat, BYTE code); /*-------------------------------------------------------------------*/ /* Functions defined in HETTAPE.C */ /*-------------------------------------------------------------------*/ extern int open_het (DEVBLK *dev, BYTE *unitstat, BYTE code); extern void close_het (DEVBLK *dev); extern int passedeot_het (DEVBLK *dev); extern int rewind_het (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int write_hetmark (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int sync_het (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsb_het (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsb_het (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsf_het (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsf_het (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int read_het (DEVBLK *dev, BYTE *buf, BYTE *unitstat, BYTE code); extern int write_het (DEVBLK *dev, BYTE *buf, U16 blklen, BYTE *unitstat, BYTE code); /*-------------------------------------------------------------------*/ /* Functions defined in OMATAPE.C */ /*-------------------------------------------------------------------*/ extern int open_omatape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern void close_omatape (DEVBLK *dev); extern void close_omatape2 (DEVBLK *dev); extern int rewind_omatape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsb_omatape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsb_omatape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int fsf_omatape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int bsf_omatape (DEVBLK *dev, BYTE *unitstat, BYTE code); extern int read_omadesc (DEVBLK *dev); extern int fsb_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *unitstat, BYTE code); extern int fsb_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *unitstat, BYTE code); extern int read_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat, BYTE code); extern int read_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat, BYTE code); extern int read_omatext (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat, BYTE code); extern int read_omatape (DEVBLK *dev, BYTE *buf, BYTE *unitstat, BYTE code); extern int readhdr_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc, long blkpos, S32 *pcurblkl, S32 *pprvhdro, S32 *pnxthdro, BYTE *unitstat, BYTE code); /*-------------------------------------------------------------------*/ /* Functions defined in SCSITAPE.C */ /*-------------------------------------------------------------------*/ // (see SCSITAPE.H) /* || Tape ERA, HRA and SENSE constants || Note: For 3480/3490 tape drives HRA was an assumed function of the OS || For 3590 (NTP) tape drives HRA is no longer assumed. The labels || here are the 3480/3590 labels but the values are NTP values. See || sense byte 2 for additional information. */ /*-------------------------------------------------------------------*/ /* Host Recovery Action (HRA) (these are the 3590 codes */ /*-------------------------------------------------------------------*/ #define TAPE_HRA_PERMANENT_ERROR 0x00 #define TAPE_HRA_RETRY 0x80 #define TAPE_HRA_DDR 0x00 // Same as error for VT #define TAPE_HRA_RESUME 0x40 #define TAPE_HRA_OPERATOR_INTERVENTION 0xC0 // Sense byte 0 #define TAPE_SNS0_CMDREJ 0x80 // Command Reject #define TAPE_SNS0_INTVREQ 0x40 // Intervention Required #define TAPE_SNS0_BUSCHK 0x20 // Bus-out Check #define TAPE_SNS0_EQUIPCHK 0x10 // Equipment Check #define TAPE_SNS0_DATACHK 0x08 // Data check #define TAPE_SNS0_OVERRUN 0x04 // Overrun #define TAPE_SNS0_DEFUNITCK 0x02 // Deferred Unit Check #define TAPE_SNS0_ASSIGNED 0x01 // Assigned Elsewhere // Sense byte 1 #define TAPE_SNS1_LOCFAIL 0x80 // Locate Failure #define TAPE_SNS1_ONLINE 0x40 // Drive Online to CU #define TAPE_SNS1_RSRVD 0x20 // Reserved #define TAPE_SNS1_RCDSEQ 0x10 // Record Sequence Error #define TAPE_SNS1_BOT 0x08 // Beginning of Tape #define TAPE_SNS1_WRTMODE 0x04 // Write Mode #define TAPE_SNS1_FILEPROT 0x02 // Write Protect #define TAPE_SNS1_NOTCAPBL 0x01 // Not Capable // Sense byte 2 /* || NTP SENSE BYTE 2 || Log code is in byte 2(3-4), BRAC is in byte 2(0-1) */ #define TAPE_SNS2_NTP_BRAC_00_PERM_ERR 0x00 // BRAC 00 - PERM ERR #define TAPE_SNS2_NTP_BRAC_01_CONTINUE 0x40 // BRAC 01 - Continue ( RESUME ) #define TAPE_SNS2_NTP_BRAC_10_REISSUE 0x80 // BRAC 10 - Reissue ( RETRY ) #define TAPE_SNS2_NTP_BRAC_11_DEFER_REISS 0xC0 // BRAC 11 - Deferred Reissue ( I/R ? ) #define TAPE_SNS2_NTP_LOG_CD0_NO_LOG 0x00 #define TAPE_SNS2_NTP_LOG_CD1_TEMP_OBR 0x08 #define TAPE_SNS2_NTP_LOG_CD2_PERM_OBR 0x10 #define TAPE_SNS2_NTP_LOG_CD3_A3 0x18 #define TAPE_SNS2_REPORTING_CHAN_PATH 0xF0 // Interface in the first 4 bits #define TAPE_SNS2_REPORTING_CHAN_A 0x20 // Channel A Interface #define TAPE_SNS2_REPORTING_CHAN_B 0x40 // Channel B Interface #define TAPE_SNS2_REPORTING_CU 0x00 // Always 0 (ZERO) Bit 4 #define TAPE_SNS2_ACL_ACTIVE 0x04 // AutoLoader in SYS MODE and has Cart #define TAPE_SNS2_SYNCMODE 0x02 // Tape Synchronous Mode #define TAPE_SNS2_POSITION 0x01 // Tape Positioning // Sense Byte 3 /*-------------------------------------------------------------------*/ /* Error Recovery Action (ERA) SENSE BYTE 3 */ /*-------------------------------------------------------------------*/ #define TAPE_ERA_UNSOLICITED_SENSE 0x00 #define TAPE_ERA_DATA_STREAMING_NOT_OPER 0x21 #define TAPE_ERA_PATH_EQUIPMENT_CHECK 0x22 #define TAPE_ERA_READ_DATA_CHECK 0x23 #define TAPE_ERA_LOAD_DISPLAY_CHECK 0x24 #define TAPE_ERA_WRITE_DATA_CHECK 0x25 #define TAPE_ERA_READ_OPPOSITE 0x26 #define TAPE_ERA_COMMAND_REJECT 0x27 #define TAPE_ERA_WRITE_ID_MARK_CHECK 0x28 #define TAPE_ERA_FUNCTION_INCOMPATIBLE 0x29 #define TAPE_ERA_UNSOL_ENVIRONMENTAL_DATA 0x2A #define TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT 0x2B #define TAPE_ERA_PERMANENT_EQUIPMENT_CHECK 0x2C #define TAPE_ERA_DATA_SECURE_ERASE_FAILURE 0x2D #define TAPE_ERA_NOT_CAPABLE_BOT_ERROR 0x2E #define TAPE_ERA_WRITE_PROTECTED 0x30 #define TAPE_ERA_TAPE_VOID 0x31 #define TAPE_ERA_TENSION_LOST 0x32 #define TAPE_ERA_LOAD_FAILURE 0x33 #define TAPE_ERA_UNLOAD_FAILURE 0x34 #define TAPE_ERA_MANUAL_UNLOAD 0x34 #define TAPE_ERA_DRIVE_EQUIPMENT_CHECK 0x35 #define TAPE_ERA_END_OF_DATA 0x36 #define TAPE_ERA_TAPE_LENGTH_ERROR 0x37 #define TAPE_ERA_PHYSICAL_END_OF_TAPE 0x38 #define TAPE_ERA_BACKWARD_AT_BOT 0x39 #define TAPE_ERA_DRIVE_SWITCHED_NOT_READY 0x3A #define TAPE_ERA_DRIVE_RESET_BY_OPERATOR 0x3A #define TAPE_ERA_MANUAL_REWIND_OR_UNLOAD 0x3B #define TAPE_ERA_VOLUME_REMOVE_BY_OPERATOR 0x3B #define TAPE_ERA_VOLUME_MANUALLY_UNLOADED 0x3C #define TAPE_ERA_OVERRUN 0x40 #define TAPE_ERA_DEVICE_DEFERRED_ACCESS 0x40 #define TAPE_ERA_RECORD_SEQUENCE_ERROR 0x41 #define TAPE_ERA_BLOCK_ID_SEQUENCE_ERROR 0x41 #define TAPE_ERA_DEGRADED_MODE 0x42 #define TAPE_ERA_DRIVE_NOT_READY 0x43 #define TAPE_ERA_INTERVENTION_REQ 0x43 #define TAPE_ERA_LOCATE_BLOCK_FAILED 0x44 #define TAPE_ERA_DRIVE_ASSIGNED_ELSEWHERE 0x45 #define TAPE_ERA_DRIVE_NOT_ONLINE 0x46 #define TAPE_ERA_VOLUME_FENCED 0x47 #define TAPE_ERA_UNSOL_INFORMATIONAL_DATA 0x48 #define TAPE_ERA_CONTROLLING_COMP_RETRY_REQ 0x48 #define TAPE_ERA_BUS_OUT_CHECK 0x49 #define TAPE_ERA_BUS_OUT_PARITY 0x49 #define TAPE_ERA_CU_ERP_FAILURE 0x4A #define TAPE_ERA_CU_AND_DRIVE_INCOMPATIBLE 0x4B #define TAPE_ERA_RECOVERED_CHECKONE_FAILURE 0x4C #define TAPE_ERA_RESETTING_EVENT 0x4D #define TAPE_ERA_MAX_BLOCKSIZE_EXCEEDED 0x4E #define TAPE_ERA_DEVICE_CONTROLLER_INCOMP 0x4F #define TAPE_ERA_READ_BUFFERED_LOG 0x50 #define TAPE_ERA_BUFFERED_LOG_OVERFLOW 0x50 #define TAPE_ERA_BUFFERED_LOG_END_OF_VOLUME 0x51 #define TAPE_ERA_END_OF_VOLUME_PROCESSING 0x51 #define TAPE_ERA_END_OF_VOLUME_COMPLETE 0x52 #define TAPE_ERA_GLOBAL_COMMAND_INTERCEPT 0x53 #define TAPE_ERA_TEMP_CHNL_INTERFACE_ERROR 0x54 #define TAPE_ERA_PERM_CHNL_INTERFACE_ERROR 0x55 #define TAPE_ERA_CHNL_PROTOCOL_ERROR 0x56 #define TAPE_ERA_GLOBAL_STATUS_INTERCEPT 0x57 #define TAPE_ERA_ATTENTION_INTERCEPT 0x57 #define TAPE_ERA_TAPE_LENGTH_INCOMPAT 0x5A #define TAPE_ERA_FORMAT_3480_XF_INCOMPAT 0x5B #define TAPE_ERA_FORMAT_3480_2_XF_INCOMPAT 0x5C #define TAPE_ERA_TAPE_LENGTH_VIOLATION 0x5D #define TAPE_ERA_COMPACT_ALGORITHM_INCOMPAT 0x5E /* || 3490/3590/NTP IN AN AUTOMATED LIBRARY SYSTEM */ #define TAPE_ERA_LIB_ATT_FAC_EQ_CHK 0x60 #define TAPE_ERA_LIB_MGR_OFFLINE_TO_SUBSYS 0x62 #define TAPE_ERA_LIB_MGR_CU_INCOMPAT 0x63 #define TAPE_ERA_LIB_VOLSER_IN_USE 0x64 #define TAPE_ERA_LIB_VOLUME_RESERVED 0x65 #define TAPE_ERA_LIB_VOLSER_NOT_IN_LIB 0x66 #define TAPE_ERA_LIB_CATEGORY_EMPTY 0x67 #define TAPE_ERA_LIB_ORDER_SEQ_CHK 0x68 #define TAPE_ERA_LIB_OUTPUT_STATIONS_FULL 0x69 #define TAPE_ERA_LIB_VOLUME_MISPLACED 0x6B #define TAPE_ERA_LIB_MISPLACED_VOLUME_FOUND 0x6C #define TAPE_ERA_LIB_DRIVE_NOT_UNLOADED 0x6D #define TAPE_ERA_LIB_INACCESS_VOLUME_REST 0x6E #define TAPE_ERA_LIB_OPTICS_FAILURE 0x6F #define TAPE_ERA_LIB_MGR_EQ_CHK 0x70 #define TAPE_ERA_LIB_EQ_CHK 0x71 #define TAPE_ERA_LIB_NOT_CAP_MANUAL_MODE 0x72 #define TAPE_ERA_LIB_INTERVENTION_REQ 0x73 #define TAPE_ERA_LIB_INFORMATION_DATA 0x74 #define TAPE_ERA_LIB_VOLSER_INACCESS 0x75 #define TAPE_ERA_LIB_ALL_CELLS_FULL 0x76 #define TAPE_ERA_LIB_DUP_VOLSER_EJECTED 0x77 #define TAPE_ERA_LIB_DUP_VOLSER_LEFT_IN_STAT 0x78 #define TAPE_ERA_LIB_UNREADABLE_INVLD_VOLSER 0x79 #define TAPE_ERA_LIB_READ_STATISTICS 0x7A #define TAPE_ERA_LIB_VOLUME_MAN_EJECTED 0x7B #define TAPE_ERA_LIB_OUT_OF_CLEANER_VOLUMES 0x7C #define TAPE_ERA_LIB_VOLUME_EXPORTED 0x7D #define TAPE_ERA_LIB_CATEGORY_IN_USE 0x7F #define TAPE_ERA_LIB_UNEXPECTED_VOLUME_EJECT 0x80 #define TAPE_ERA_LIB_IO_STATION_DOOR_OPEN 0x81 #define TAPE_ERA_LIB_MGR_PROG_EXCEPTION 0x82 #define TAPE_ERA_LIB_DRIVE_EXCEPTION 0x83 #define TAPE_ERA_LIB_DRIVE_FAILURE 0x84 #define TAPE_ERA_LIB_SMOKE_DETECTION_ALERT 0x85 #define TAPE_ERA_LIB_ALL_CATEGORYS_RESERVED 0x86 #define TAPE_ERA_LIB_DUP_VOLSER_ADDITION 0x87 #define TAPE_ERA_LIB_DAMAGE_CART_EJECTED 0x88 #define TAPE_ERA_LIB_VOLUME_INACCESSIBLE 0x91 /* || SENSE BYTE 3 for NTP (3590) TAPES */ #define TAPE_ERA_RAC_USE_BRAC 0xC0 #define TAPE_ERA_RAC_FENCE_DEVICE 0xC1 #define TAPE_ERA_RAC_FENCH_DEVICE_PATH 0xC2 #define TAPE_ERA_RAC_LONG_BUSY 0xC6 #define TAPE_ERA_RAC_READ_ALT 0xD2 // Sense byte 4 /* || SENSE BYTE 4 FOR TAPES */ #define TAPE_SNS4_3420_TAPE_INDICATE 0x20 // EOT FOUND #define TAPE_SNS4_3480_FORMAT_MODE 0xC0 #define TAPE_SNS4_3480_FORMAT_MODE_XF 0x80 #define TAPE_SNS4_3490_FORMAT_MODE 0x00 #define TAPE_SNS4_3490_FORMAT_MODE_RSVD 0x40 #define TAPE_SNS4_3490_FORMAT_MODE_IDRC 0x80 #define TAPE_SNS4_3490_FORMAT_MODE_SPECIAL 0xC0 #define TAPE_SNS4_3480_HO_CHAN_LOG_BLK_ID 0x3F // 22-bits for BLK ID // Sense byte 5 /* || SENSE BYTE 5 FOR TAPES */ #define TAPE_SNS5_3480_MO_CHAN_LOG_BLK_ID 0xFF // Sense byte 6 /* || SENSE BYTE 6 FOR TAPES */ #define TAPE_SNS6_3480_LO_CHAN_LOG_BLK_ID 0xFF /* || SENSE BYTES 4-5 FOR NTP BYTE 4 is Reason Code(RC) and 5 is Reason Qualifer Code(RQC) */ #define TAPE_SNS4_5_NTP_RC_UA_RQC_DEV_LOG 0x1110 // UNIT ATTENTION/Device Log #define TAPE_SNS4_5_NTP_RC_LA_RQC_DEV_CLEANED 0x1211 // LIBRARY ATTENTION/Device CLEANED #define TAPE_SNS4_5_NTP_RC_LA_RQC_DEV_QUIESCED 0x1212 // LIBRARY ATTENTION/Device QUIESCE #define TAPE_SNS4_5_NTP_RC_LA_RQC_DEV_RESUMED 0x1213 // LIBRARY ATTENTION/Device RESUMED #define TAPE_SNS4_5_NTP_RC_CMD_REJ 0x2000 // COMMAND REJECT #define TAPE_SNS4_5_NTP_RC_PE_RQC_GBL_CMD 0x2230 // PROTECTION EXCEPTION/Global Command #define TAPE_SNS4_5_NTP_RC_PE_RQC_GBL_STATUS 0x2231 // PROTECTION EXCEPTION/Global Status #define TAPE_SNS4_5_NTP_RC_BE_RQC_EOV 0x3012 // BOUNDARY EXCEPTION/End of Volume #define TAPE_SNS4_5_NTP_RC_DC_RQC_NO_FMT_BOV 0x5050 // DATA CHECK/No Formatting at BOV #define TAPE_SNS4_5_NTP_RC_DC_RQC_NO_FMT 0x5051 // DATA CHECK/No Formatting Past BOV #define TAPE_SNS4_5_NTP_RC_OE_RQC_MED_NOT_LD 0x4010 // OPERATIONAL EXCEPTION/Medium Not Loaded #define TAPE_SNS4_5_NTP_RC_OE_RQC_DRV_NOT_RDY 0x4011 // OPERATIONAL EXCEPTION/Drive Not Ready #define TAPE_SNS4_5_NTP_RC_OE_RQC_DEV_LONG_BSY 0x4012 // OPERATIONAL EXCEPTION/Device long busy #define TAPE_SNS4_5_NTP_RC_OE_RQC_LDR_IR 0x4020 // OPERATIONAL EXCEPTION/Loader Interv Req'd // Sense byte 7 /* || SENSE BYTE 7 FOR TAPES */ #define TAPE_SNS7_TAPE_SECURITY_ERASE_CMD 0x08 #define TAPE_SNS7_FMT_20_3480 0x20 // DRIVE AND CU ERROR INFORMATION #define TAPE_SNS7_FMT_21_3480_READ_BUF_LOG 0x21 // BUFFERED LOG DATA WHEN NO IDRC is installed #define TAPE_SNS7_FMT_30_3480_READ_BUF_LOG 0x30 // BUFFERED LOG DATA WHEN IDRC is installed #define TAPE_SNS7_FMT_22_3480_EOV_STATS 0x22 #define TAPE_SNS7_FMT_23_ALT 0x23 #define TAPE_SNS7_FMT_50_NTP 0x50 #define TAPE_SNS7_FMT_51_NTP 0x51 #define TAPE_SNS7_FMT_70_3490 0x70 #define TAPE_SNS7_FMT_71_3490 0x71 #endif // __TAPEDEV_H__ hercules-3.12/scsitape.h0000664000175000017500000001312512564723224012171 00000000000000/* SCSITAPE.H (c) Copyright "Fish" (David B. Trout), 2005-2012 */ /* Hercules SCSI tape handling module header file */ // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under // the Q Public License (http://www.hercules-390.org/herclic.html) // as modifications to Hercules. #ifndef _SCSITAPE_H_ #define _SCSITAPE_H_ #if defined(OPTION_SCSI_TAPE) #include "tapedev.h" #include "w32stape.h" // External TMH-vector calls... extern int update_status_scsitape ( DEVBLK *dev ); // (via "generic" vector) extern int open_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int finish_scsitape_open ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern void close_scsitape ( DEVBLK *dev ); extern int read_scsitape ( DEVBLK *dev, BYTE *buf, BYTE *unitstat, BYTE code ); extern int write_scsitape ( DEVBLK *dev, BYTE *buf, U16 len, BYTE *unitstat, BYTE code ); extern int rewind_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int bsb_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int fsb_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int bsf_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int fsf_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int write_scsimark ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int sync_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int dse_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int erg_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int is_tape_mounted_scsitape ( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern int passedeot_scsitape ( DEVBLK *dev ); extern int readblkid_scsitape ( DEVBLK* dev, BYTE* logical, BYTE* physical ); extern int locateblk_scsitape ( DEVBLK* dev, U32 blockid, BYTE *unitstat, BYTE code ); // Internal functions... extern void int_scsi_rewind_unload( DEVBLK *dev, BYTE *unitstat, BYTE code ); extern void int_scsi_status_update( DEVBLK *dev, int mountstat_only ); extern int int_write_scsimark ( DEVBLK *dev ); extern void blockid_emulated_to_actual( DEVBLK *dev, BYTE *emu_blkid, BYTE *act_blkid ); extern void blockid_actual_to_emulated( DEVBLK *dev, BYTE *act_blkid, BYTE *emu_blkid ); extern void blockid_32_to_22( BYTE *in_32blkid, BYTE *out_22blkid ); extern void blockid_22_to_32( BYTE *in_22blkid, BYTE *out_32blkid ); extern void create_automount_thread( DEVBLK* dev ); extern void *scsi_tapemountmon_thread( void* notused ); extern void define_BOT_pos( DEVBLK *dev ); // PROGRAMMING NOTE: I'm not sure of what the the actual/proper value // should be (or is) for the following value but I've coded what seems // to me to be a reasonable value for it. As you can probably guess // based on its [admittedly rather verbose] name, it's the maximum // amount of time that a SCSI tape drive query call should take (i.e. // asking the system for the drive's status shouldn't, under normal // circumstances, take any longer than this time). It should be set // to the most pessimistic value we can reasonably stand, and should // probably be at least as long as the host operating system's thread // scheduling time-slice quantum. -- Fish, April 2006 // August, 2006: further testing/experimentation has revealed that the // "proper" value (i.e. one that causes the fewest potential problems) // for the below timeout setting varies greatly from one system to an- // other with different host CPU speeds and different hardware (SCSI // adapter cards, etc) being the largest factors. Thus, in order to try // and define it to a value likely to cause the LEAST number of problems // on the largest number of systems, I am changing it from its original // 25 millisecond value to the EXTREMELY PESSIMISTIC (but nonetheless // completely(?) safe (since it is afterall only a timeout setting!)) // value of 250 milliseconds. // This is because I happened to notice on some systems with moderate // host (Windows) workload, etc, querying the status of the tape drive, // while *usually* only taking 4-6 milliseconds maximum, would sometimes // take up to 113 or more milliseconds! (thereby sometimes causing the // guest to experience intermittent/sporadic unsolicited ATTN interrupts // on the tape drive as their tape jobs ran (since "not mounted" status // was thus getting set as a result of the status query taking longer // than expected, causing the auto-mount thread to kick-in and then // immediately exit again (with an ATTN interrupt of course) whenever // it eventually noticed a tape was indeed still mounted on the drive)). // Thus, even though such unsolicited ATTN interrupts occuring in the // middle of (i.e. during) an already running tape job should NOT, under // ordinary circumstances, cause any problems (as long as auto-scsi-mount // is enabled of course), in order to reduce the likelihood of it happening, // I am increasing the below timeout setting to a value that, ideally, // *should* work on most *all* systems, even under the most pessimistic // of host workloads. -- Fish, August 2006. // ZZ FIXME: should we maybe make this a config file option?? #define MAX_NORMAL_SCSI_DRIVE_QUERY_RESPONSE_TIMEOUT_USECS (250*1000) #endif // defined(OPTION_SCSI_TAPE) #endif // _SCSITAPE_H_ hercules-3.12/logger.h0000664000175000017500000000320512564723224011633 00000000000000/* LOGGER.H (c) Copyright Jan Jaeger, 2003-2009 */ /* System logger functions */ #ifndef __LOGGER_H__ #define __LOGGER_H__ #ifndef _LOGMSG_C_ #ifndef _HUTIL_DLL_ #define LOG_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define LOG_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else /* _LOGGER_C_ */ #define LOG_DLL_IMPORT DLL_EXPORT #endif /* _LOGGER_C_ */ #ifndef _LOGGER_C_ #ifndef _HUTIL_DLL_ #define LOGR_DLL_IMPORT DLL_IMPORT #else #define LOGR_DLL_IMPORT extern #endif #else #define LOGR_DLL_IMPORT DLL_EXPORT #endif #define LOG_READ 0 #define LOG_WRITE 1 extern int logger_syslogfd[2]; #define LOG_NOBLOCK 0 #define LOG_BLOCK 1 #if defined(SSIZE_MAX) && SSIZE_MAX < 1048576 #define LOG_DEFSIZE SSIZE_MAX #else #define LOG_DEFSIZE 65536 #endif /* Logging functions in logmsg.c */ LOG_DLL_IMPORT void logmsg(char *,...); LOG_DLL_IMPORT void logmsgp(char *,...); LOG_DLL_IMPORT void logmsgb(char *,...); LOG_DLL_IMPORT void logdevtr(DEVBLK *dev, char *, ...); LOGR_DLL_IMPORT void logger_init(void); LOGR_DLL_IMPORT int log_read(char **buffer, int *msgindex, int block); LOGR_DLL_IMPORT int log_line(int linenumber); LOGR_DLL_IMPORT void log_sethrdcpy(char *filename); LOGR_DLL_IMPORT void log_wakeup(void *arg); /* Log routing section */ typedef void LOG_WRITER(void *,char *); typedef void LOG_CLOSER(void *); LOG_DLL_IMPORT int log_open(LOG_WRITER*,LOG_CLOSER*,void *); LOG_DLL_IMPORT void log_close(void); LOG_DLL_IMPORT void log_write(int,char *); /* End of log routing section */ /* Log routing utility */ LOG_DLL_IMPORT char *log_capture(void *(*)(void *),void *); #endif hercules-3.12/commadpt.h0000664000175000017500000002016712564723224012166 00000000000000/* COMMADPT.H (c)Copyright Ivan Warren, 2003-2009 */ /* Structure definitions for 2703 line driver */ #ifndef __COMMADPT_H__ #define __COMMADPT_H__ #include "hercules.h" #define TTYLINE_SZ 512 typedef struct _COMMADPT_RING { BYTE *bfr; size_t sz; size_t hi; size_t lo; u_int havedata:1; u_int overflow:1; } COMMADPT_RING; struct COMMADPT { DEVBLK *dev; /* the devblk to which this CA is attched */ BYTE lnctl; /* Line control used */ BYTE term; /* Terminal type */ BYTE* code_table_toebcdic; /* correspondence or EBCD code tables */ BYTE* code_table_fromebcdic; /* correspondence or EBCD code tables */ int rto; /* Read Time-Out */ int pto; /* Poll Time-Out */ int eto; /* Enable Time-Out */ TID cthread; /* Thread used to control the socket */ BYTE curpending; /* Current pending operation */ U16 lport; /* Local listening port */ in_addr_t lhost; /* Local listening address */ U16 rport; /* Remote TCP Port */ in_addr_t rhost; /* Remote connection IP address */ int sfd; /* Communication socket FD */ int lfd; /* Listen socket for DIAL=IN, INOUT & NO */ COND ipc; /* I/O <-> thread IPC condition EVB */ COND ipc_halt; /* I/O <-> thread IPC HALT special EVB */ LOCK lock; /* COMMADPT lock */ int pipe[2]; /* pipe used for I/O to thread signaling */ COMMADPT_RING inbfr; /* Input buffer ring */ COMMADPT_RING outbfr; /* Output buffer ring */ COMMADPT_RING pollbfr; /* Ring used for POLL data */ COMMADPT_RING rdwrk; /* Inbound data flow work ring */ COMMADPT_RING ttybuf; /* async: partial TTY input line */ U16 devnum; /* devnum copy from DEVBLK */ BYTE dialdata[32]; /* Dial data information */ U16 dialcount; /* data count for dial */ BYTE pollix; /* Next POLL Index */ U16 pollused; /* Count of Poll data used during Poll */ u_int enabled:1; /* An ENABLE CCW has been sucesfully issued */ u_int connect:1; /* A connection exists with the remote peer */ u_int eibmode:1; /* EIB Setmode issued */ u_int dialin:1; /* This is a SWITCHED DIALIN line */ u_int dialout:1; /* This is a SWITCHED DIALOUT line */ u_int have_cthread:1; /* the comm thread is running */ u_int dolisten:1; /* Start a listen */ u_int listening:1; /* Listening */ u_int haltpending:1; /* A request has been issued to halt current*/ /* CCW */ u_int xparwwait:1; /* Transparent Write Wait state : a Write */ /* was previously issued that turned the */ /* line into transparent mode. Anything */ /* else than another write, Sense or NO-OP */ /* is rejected with SENSE_CR */ /* This condition is reset upon receipt of */ /* DLE/ETX or DLE/ETB on a subsequent write */ u_int input_overrun:1; /* The input ring buffer has overwritten */ /* itself */ u_int in_textmode:1; /* Input buffer processing : text mode */ u_int in_xparmode:1; /* Input buffer processing : transparent */ u_int gotdle:1; /* DLE Received in inbound flow */ u_int pollsm:1; /* Issue Status Modifier on POLL Exit */ u_int badpoll:1; /* Bad poll data (>7 Bytes before ENQ) */ u_int callissued:1; /* The connect out for the DIAL/ENABLE */ /* has already been issued */ u_int readcomp:1; /* Data in the read buffer completes a read */ u_int datalostcond:1; /* Data Lost Condition Raised */ u_int telnet_opt:1; /* expecting telnet option char */ u_int telnet_iac:1; /* expecting telnet command char */ u_int telnet_int:1; /* telnet interrupt received */ u_int eol_flag:1; /* carriage return received flag */ u_int uctrans:1; /* Uppercase translate flag */ u_int dumb_bs:1; /* perform backspace editing in driver */ u_int dumb_break:1; /* map ASCII ETX (Ctrl-C) to interrupt/attn */ u_int haltprepare:1; /* for race condition circumvention */ u_int rxvt4apl:1; /* 2741 mode for rxvt4apl */ u_int overstrike_flag:1; /* overstrike sequence in progress */ u_int crlf_opt:1; /* map 2741 NL to CRLF */ u_int sendcr_opt:1; /* send CR after input line received */ u_int binary_opt:1; /* initiate telnet binary mode */ BYTE telnet_cmd; /* telnet command received */ BYTE byte_skip_table[256]; /* async: characters to suppress in output */ BYTE input_byte_skip_table[256]; /* async: characters to suppress in input */ BYTE prepend_length; /* number of bytes (0-4) to prepend */ BYTE prepend_bytes[4]; /* bytes to prepend (per prepend_length) */ BYTE append_length; /* number of bytes (0-4) to append */ BYTE append_bytes[4]; /* bytes to append (per append_length) */ BYTE eol_char; /* end of line character */ BYTE saved_char; /* saved previous character for overstrike */ }; enum commadpt_lnctl { COMMADPT_LNCTL_BSC=1, /* BSC Line Control */ COMMADPT_LNCTL_ASYNC /* ASYNC Line Control */ }; enum commadpt_term { COMMADPT_TERM_TTY, /* TTY (TELE2) */ COMMADPT_TERM_2741, /* 2741 (IBM1) */ }; #define IS_BSC_LNCTL(ca) ((ca->lnctl == COMMADPT_LNCTL_BSC)) #define IS_ASYNC_LNCTL(ca) ((ca->lnctl == COMMADPT_LNCTL_ASYNC)) enum commadpt_pendccw { COMMADPT_PEND_IDLE=0, /* NO CCW currently executing */ COMMADPT_PEND_READ, /* A READ CCW is running */ COMMADPT_PEND_WRITE, /* A WRITE CCW is running */ COMMADPT_PEND_ENABLE, /* A ENABLE CCW is running */ COMMADPT_PEND_DIAL, /* A DIAL CCW is running */ COMMADPT_PEND_DISABLE, /* A DISABLE CCW is running */ COMMADPT_PEND_PREPARE, /* A PREPARE CCW is running */ COMMADPT_PEND_POLL, /* A POLL CCW Is Running */ COMMADPT_PEND_TINIT, /* */ COMMADPT_PEND_CLOSED, /* */ COMMADPT_PEND_SHUTDOWN /* */ }; #define COMMADPT_PEND_TEXT static char *commadpt_pendccw_text[]={\ "IDLE",\ "READ",\ "WRITE",\ "ENABLE",\ "DIAL",\ "DISABLE",\ "PREPARE",\ "POLL",\ "TINIT",\ "TCLOSED",\ "SHUTDOWN"} #endif hercules-3.12/comm3705.h0000664000175000017500000000645112564723224011634 00000000000000/* COMM3705.H (c) Copyright Max H. Parke, 2007-2012 */ /* Hercules 3705 communications controller */ /* running NCP */ #ifndef __COMM3705_H__ #define __COMM3705_H__ #include "hercules.h" struct COMMADPT { DEVBLK *dev; /* the devblk to which this CA is attched */ TID cthread; /* Thread used to control the socket */ TID tthread; /* Thread used to control the socket */ U16 lport; /* Local listening port */ in_addr_t lhost; /* Local listening address */ int sfd; /* Communication socket FD */ int lfd; /* Listen socket for DIAL=IN, INOUT & NO */ COND ipc; /* I/O <-> thread IPC condition EVB */ COND ipc_halt; /* I/O <-> thread IPC HALT special EVB */ LOCK lock; /* COMMADPT lock */ int pipe[2]; /* pipe used for I/O to thread signaling */ char locncpnm[9], /* name of local NCP (in EBCDIC) */ rmtncpnm[9]; /* name of remote NCP (in EBCDIC) */ U16 devnum, /* devnum copy from DEVBLK */ locsuba, /* local NCP or local 3791 node subarea number */ rmtsuba; /* remote NCP subarea number */ U32 have_cthread:1, /* the comm thread is running */ haltpending:1, /* A request has been issued to halt current*/ /* CCW */ bindflag:1, telnet_opt:1, /* expecting telnet option char */ telnet_iac:1, /* expecting telnet command char */ telnet_int:1, /* telnet interrupt received */ hangup:1, /* host initated shutdown */ is_3270:1, /* 0=tty 1=3270 */ eol_flag:1, /* 1 = CR has been received */ debug_sna:1, /* 1 = write debug messages */ emu3791:1, /* mode (0=default=3705;1=3791) */ idblk, /* IDBLK of switched PU (default=0x017) */ idnum; /* IDNUM of switched PU (default=0x00017) */ U32 rlen3270; /* amt of data in 3270 recv buf */ BYTE telnet_cmd; /* telnet command */ int read_ccw_count; int write_ccw_count; int unack_attn_count; int ncpa_sscp_seqn; int ncpb_sscp_seqn; int lu_sscp_seqn; int lu_lu_seqn; BYTE inpbuf[65536]; int inpbufl, unitsz, /* I/O blocksize (default=256) */ ackspeed; /* slow down factor for unacknowledged attn */ void * freeq; void * sendq; BYTE * poolarea; BYTE sscp_addr0; BYTE sscp_addr1; BYTE ncp_addr0; BYTE ncp_addr1; BYTE pu_addr0; BYTE pu_addr1; BYTE lu_addr0; BYTE lu_addr1; BYTE tso_addr0; BYTE tso_addr1; }; #endif hercules-3.12/cache.h0000664000175000017500000004205012564723224011420 00000000000000/* CACHE.H (c)Copyright Greg Smith, 2002-2009 */ /* Buffer Cache Manager */ /*------------------------------------------------------------------- Description: Manages multiple caches in a multi-threaded environment. A cache is dynamically created and destroyed. It's size or number of entries is also dynamically determined. A cache entry contains an identifying `key', `flags' which indicate whether an entry is busy or not, and a `buf' which is a pointer to the cached object. Cache entry: The structure of a cache entry is: U64 key; U32 flag; int len; void *buf; int value; U64 age; The first 8 bits of the flag indicates if the entry is `busy' or not. If any of the first 8 bits are non-zero then the entry is considered `busy' and will not be stolen or otherwise reused. APIs: General query functions: int cache_nbr(int ix); [0] Number of entries int cache_busy(int ix); Number of busy entries int cache_empty(int ix); Number of empty entries [1] int cache_waiters(int ix); Number of waiters for a non-busy cache entry long long cache_size(int ix); Size of all allocated objects long long cache_hits(int ix); Number of successful lookups long long cache_misses(int ix); Number of unsuccessful lookups int cache_busy_percent(int ix); Percentage (0 .. 100) of entries that are busy int cache_empty_percent(int ix); Percentage of entries that are empty [1] int cache_hit_percent(int ix); Percentage of successful lookups to total lookups Notes [0] `ix' identifies the cache. This is an integer and is reserved in `cache.h' [1] An empty entry contains a zero key value. A valid key should not be all zeroes (0x0000000000000000) or all ones (0xffffffffffffffff). All ones is used to indicate an error circumstance. Entry specific functions: U64 cache_getkey(int ix, int i); [0] Return key for the specified cache entry U64 cache_setkey(int ix, int i, U64 key); Set the key for the specified cache entry; the old key is returned U32 cache_getflag(int ix, int i); Return the flag for the specified cache entry U32 cache_setflag(int ix, int i, U32 andbits, U32 orbits); Set the flag for the specified cache entry; first the `andbits' value is `and'ed against the entry then the `orbits' value is `or'ed against the entry. The old flag is returned. U64 cache_getage(int ix, int i); [1] Return age for the specified cache entry U64 cache_setage(int ix, int i); Set age for the specified cache entry void *cache_getbuf(int ix, int i, int len); Return address of the object buf for the cache entry. If `len' is non-zero, then if the current object is null or `len' is greater than the current object length then the old object is freed and a new object is obtained. void *cache_setbuf(int ix, int i, void *buf, int len); The old object address and length is replaced. The address of the old object is returned and can be freed using `free()'. int cache_getlen(int ix, int i); Return the length of the current object Notes [0] `i' is the index of the entry in cache `ix' [1] `age' is a sequentially incremented value and does not correspond to date or time Locking functions: int cache_lock(int ix); Obtain the lock for cache `ix'. If the cache does not exist then it will be created. Generally, the lock should be obtained when referencing cache entries and must be held when a cache entry status may change from `busy' to `not busy' or vice versa. Likewise, the lock must be held when a cache entry changes from `empty' to `not empty' or vice versa. int cache_unlock(int ix); Release the cache lock Search functions: int cache_lookup(int ix, U64 key, int *o); Search cache `ix' for entry matching `key'. If a non-NULL pointer `o' is provided, then the oldest or preferred cache entry index is returned that is available to be stolen. int cache_scan (int ix, int (rtn)(), void *data); Scan a cache routine entry by entry calling routine `rtn'. Parameters passed to the routine are `(int *answer, int ix, int i, void *data)' where `ix' is the cache index, `i' is the cache entry index and `data' is the value passed to cache_scan. `*answer' is initialized to -1 and can be set by the scan subroutine. This will be the value returned by cache_scan. If the routine returns a non-zero value then the scan is terminated. Other functions: int cache_wait(int ix); Wait for a non-busy cache entry to become available. Typically called after `cache_lookup' was unsuccessful and `*o' is -1. int cache_release(int ix, int i, int flag); Release the cache entry. If flag is CACHE_FREEBUF then the object buffer is also freed. int cache_cmd(int argc, char *argv[], char *cmdline); Interface with the cache command processor. This interface is subject to change. -------------------------------------------------------------------*/ #ifndef _HERCULES_CACHE_H #define _HERCULES_CACHE_H 1 #include "hercules.h" #ifndef _CACHE_C_ #ifndef _HDASD_DLL_ #define CCH_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define CCH_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define CCH_DLL_IMPORT DLL_EXPORT #endif /*-------------------------------------------------------------------*/ /* Reserve cache indexes here */ /*-------------------------------------------------------------------*/ #define CACHE_MAX_INDEX 8 /* Max number caches [0..7] */ #define CACHE_DEVBUF 0 /* Device Buffer cache */ #define CACHE_L2 1 /* L2 cache */ #define CACHE_2 2 /* (available) */ #define CACHE_3 3 /* (available) */ #define CACHE_4 4 /* (available) */ #define CACHE_5 5 /* (available) */ #define CACHE_6 6 /* (available) */ #define CACHE_7 7 /* (available) */ #ifdef _CACHE_C_ /*-------------------------------------------------------------------*/ /* Cache entry */ /*-------------------------------------------------------------------*/ typedef struct _CACHE { /* Cache entry */ U64 key; /* Key */ U32 flag; /* Flags */ int len; /* Buffer length */ void *buf; /* Buffer address */ int value; /* Arbitrary value */ U64 age; /* Age */ } CACHE; /*-------------------------------------------------------------------*/ /* Cache header */ /*-------------------------------------------------------------------*/ typedef struct _CACHEBLK { /* Cache header */ int magic; /* Magic number */ int nbr; /* Number entries */ int busy; /* Number busy entries */ int empty; /* Number empty entries */ int waiters; /* Number waiters */ int waits; /* Number times waited */ long long size; /* Allocated buffer size */ long long hits; /* Number lookup hits */ long long fasthits; /* Number fast lookup hits */ long long misses; /* Number lookup misses */ U64 age; /* Age counter */ LOCK lock; /* Lock */ COND waitcond; /* Wait for available entry */ CACHE *cache; /* Cache table address */ time_t atime; /* Time last adjustment */ time_t wtime; /* Time last wait */ int adjusts; /* Number of adjustments */ } CACHEBLK; #endif /*-------------------------------------------------------------------*/ /* Flag definitions */ /*-------------------------------------------------------------------*/ #define CACHE_BUSY 0xFF000000 /* Busy bits */ #define CACHE_TYPE 0x000000FF /* Type bits */ #define CACHE_FREEBUF 1 /* Free buf on release */ #ifdef _CACHE_C_ #define CACHE_MAGIC 0x01CACE10 /* Magic number */ #define CACHE_DEFAULT_NBR 229 /* Initial entries (prime) */ //FIXME the line below increases the size for CACHE_L2. Since each // cckd device always has an active l2 entry this number // actually limits the number of cckd devices that can be // attached. // This is a workaround to increase the max number of devices #define CACHE_DEFAULT_L2_NBR 1031 /* Initial entries for L2 */ #define CACHE_WAITTIME 1000 /* Wait time for entry(usec) */ #define CACHE_ADJUST_INTERVAL 15 /* Adjustment interval (sec) */ #define CACHE_ADJUST_NUMBER 128 /* Uninhibited nbr entries */ #define CACHE_ADJUST_BUSY1 70 /* Increase when this busy 1 */ #define CACHE_ADJUST_BUSY2 80 /* Increase when this busy 2 */ #define CACHE_ADJUST_RESIZE 8 /* Nbr entries adjusted */ #define CACHE_ADJUST_EMPTY 16 /* Decrease this many empty */ #define CACHE_ADJUST_HIT1 60 /* Increase hit% this low 1 */ #define CACHE_ADJUST_HIT2 50 /* Increase hit% this low 2 */ #define CACHE_ADJUST_BUSY3 20 /* Decrease not this busy */ #define CACHE_ADJUST_HIT3 90 /* and hit% this high */ #define CACHE_ADJUST_SIZE (8*1024*1024)/* and size this high */ #define CACHE_ADJUST_WAITTIME 10 /* Increase last wait (sec) */ #endif /*-------------------------------------------------------------------*/ /* Functions */ /*-------------------------------------------------------------------*/ int cache_nbr(int ix); int cache_busy(int ix); int cache_empty(int ix); int cache_waiters(int ix); long long cache_size(int ix); long long cache_hits(int ix); long long cache_misses(int ix); int cache_busy_percent(int ix); int cache_empty_percent(int ix); int cache_hit_percent(int ix); int cache_lookup(int ix, U64 key, int *o); typedef int CACHE_SCAN_RTN (int *answer, int ix, int i, void *data); int cache_scan (int ix, CACHE_SCAN_RTN rtn, void *data); int cache_lock(int ix); int cache_unlock(int ix); int cache_wait(int ix); U64 cache_getkey(int ix, int i); U64 cache_setkey(int ix, int i, U64 key); U32 cache_getflag(int ix, int i); U32 cache_setflag(int ix, int i, U32 andbits, U32 orbits); U64 cache_getage(int ix, int i); U64 cache_setage(int ix, int i); void *cache_getbuf(int ix, int i, int len); void *cache_setbuf(int ix, int i, void *buf, int len); int cache_getlen(int ix, int i); int cache_getval(int ix, int i); int cache_setval(int ix, int i, int val); int cache_release(int ix, int i, int flag); CCH_DLL_IMPORT int cache_cmd(int argc, char *argv[], char *cmdline); #ifdef _CACHE_C_ static int cache_create (int ix); static int cache_destroy (int ix); static int cache_check_ix(int ix); static int cache_check_cache(int ix); static int cache_check(int ix, int i); static int cache_isbusy(int ix, int i); static int cache_isempty(int ix, int i); static int cache_adjust(int ix, int n); #if 0 static int cache_resize (int ix, int n); #endif static void cache_allocbuf(int ix, int i, int len); #endif /*-------------------------------------------------------------------*/ /* Specific cache definitions (until a better place is found) */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Device buffer definitions */ /*-------------------------------------------------------------------*/ #define CCKD_CACHE_ACTIVE 0x80000000 /* Active entry */ #define CCKD_CACHE_READING 0x40000000 /* Entry being read */ #define CCKD_CACHE_WRITING 0x20000000 /* Entry being written */ #define CCKD_CACHE_IOBUSY (CCKD_CACHE_READING|CCKD_CACHE_WRITING) #define CCKD_CACHE_IOWAIT 0x10000000 /* Waiters for i/o */ #define CCKD_CACHE_UPDATED 0x08000000 /* Buffer has been updated */ #define CCKD_CACHE_WRITE 0x04000000 /* Entry pending write */ #define CCKD_CACHE_USED 0x00800000 /* Entry has been used */ #define CKD_CACHE_ACTIVE 0x80000000 /* Active entry */ #define FBA_CACHE_ACTIVE 0x80000000 /* Active entry */ #define SHRD_CACHE_ACTIVE 0x80000000 /* Active entry */ #define DEVBUF_TYPE_SHARED 0x00000080 /* Shared entry type */ #define DEVBUF_TYPE_COMP 0x00000040 /* CCKD/CFBA entry type */ #define DEVBUF_TYPE_CKD 0x00000002 /* CKD entry type */ #define DEVBUF_TYPE_FBA 0x00000001 /* FBA entry type */ #define DEVBUF_TYPE_CCKD (DEVBUF_TYPE_COMP|DEVBUF_TYPE_CKD) #define DEVBUF_TYPE_CFBA (DEVBUF_TYPE_COMP|DEVBUF_TYPE_FBA) #define DEVBUF_TYPE_SCKD (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_CKD) #define DEVBUF_TYPE_SFBA (DEVBUF_TYPE_SHARED|DEVBUF_TYPE_FBA) #define CCKD_CACHE_GETKEY(_ix, _devnum, _trk) \ do { \ (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ } while (0) #define CCKD_CACHE_SETKEY(_devnum, _trk) \ ((U64)(((U64)(_devnum) << 32) | (U64)(_trk))) #define CKD_CACHE_GETKEY(_ix, _devnum, _trk) \ { \ (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ } #define CKD_CACHE_SETKEY(_devnum, _trk) \ ((U64)(((U64)(_devnum) << 32) | (U64)(_trk))) #define FBA_CACHE_GETKEY(_ix, _devnum, _blkgrp) \ { \ (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ (_blkgrp) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ } #define FBA_CACHE_SETKEY(_devnum, _blkgrp) \ ((U64)(((U64)(_devnum) << 32) | (U64)(_blkgrp))) #define SHRD_CACHE_GETKEY(_ix, _devnum, _trk) \ { \ (_devnum) = (U16)((cache_getkey(CACHE_DEVBUF,(_ix)) >> 32) & 0xFFFF); \ (_trk) = (U32)(cache_getkey(CACHE_DEVBUF,(_ix)) & 0xFFFFFFFF); \ } #define SHRD_CACHE_SETKEY(_devnum, _trk) \ ((U64)(((U64)(_devnum) << 32) | (U64)(_trk))) /*-------------------------------------------------------------------*/ /* L2 definitions */ /*-------------------------------------------------------------------*/ #define L2_CACHE_ACTIVE 0x80000000 /* Active entry */ #define L2_CACHE_GETKEY(_ix, _sfx, _devnum, _trk) \ do { \ (_sfx) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 48) & 0xFFFF); \ (_devnum) = (U16)((cache_getkey(CACHE_L2,(_ix)) >> 32) & 0xFFFF); \ (_trk) = (U32)(cache_getkey(CACHE_L2,(_ix)) & 0xFFFFFFFF); \ } while (0) #define L2_CACHE_SETKEY(_sfx, _devnum, _trk) \ ((U64)(((U64)(_sfx) << 48) | ((U64)(_devnum) << 32) | (U64)(_trk))) #endif /* _HERCULES_CACHE_H */ hercules-3.12/ecpsvm.h0000664000175000017500000002542412564723224011660 00000000000000/*ECPSVM.H (c) Copyright Ivan Warren, 2003-2009 */ /* Hercules ECPS:VM Support */ #ifndef __ECPSVM_H__ #define __ECPSVM_H__ /* CR6 Definitions */ #define ECPSVM_CR6_VMASSIST 0x80000000 /* DO Privop Sim */ #define ECPSVM_CR6_VIRTPROB 0x40000000 /* Running user in Problem State */ #define ECPSVM_CR6_ISKINHIB 0x20000000 /* Inhibit ISK/SSK Sim */ #define ECPSVM_CR6_S360ONLY 0x10000000 /* Only S/360 Operations */ #define ECPSVM_CR6_SVCINHIB 0x08000000 /* No SVC sim */ #define ECPSVM_CR6_STVINHIB 0x04000000 /* No Shadow Table Validation */ #define ECPSVM_CR6_ECPSVM 0x02000000 /* ECPS:VM Enable */ #define ECPSVM_CR6_VIRTTIMR 0x01000000 /* Virtual Interval Timer update */ #define ECPSVM_CR6_MICBLOK 0x00FFFFF8 /* MICBLOK Address mask */ #define ECPSVM_CR6_VMMVSAS 0x00000004 /* VM Assists for MVS Enable (370E) */ /* CR6 Definitions (VMBLOK style) */ #define VMMFE 0x80 #define VMMPROB 0x40 #define VMMNOSK 0x20 #define VMM360 0x10 #define VMMSVC 0x08 #define VMMSHADT 0x04 #define VMMCPAST 0x02 #define VMMVTMR 0x01 /* MICBLOK */ typedef struct _ECPSVM_MICBLOK { U32 MICRSEG; U32 MICCREG; U32 MICVPSW; #define MICVIP MICVPSW #define MICPEND 0x80 U32 MICWORK; U32 MICVTMR; U32 MICACF; U32 RESERVED1; U32 RESERVED2; U32 MICCREG0; U32 RESERVED3; /* Bits defined in MICEVMA */ #define MICLPSW 0x80 /* LPSW SIM */ #define MICPTLB 0x40 /* PTLB SIM */ #define MICSCSP 0x20 /* SCKC, SPT SIM */ #define MICSIO 0x10 /* SIO, SIOF SIM */ #define MICSTSM 0x08 /* SSM, STNSM, STOSM SIM */ #define MICSTPT 0x04 /* STPT SIM */ #define MICTCH 0x02 /* TCH SIM */ #define MICDIAG 0x01 /* DIAG SIM */ /* Hint : The following bits may be irrelevant for ECPS:VM Level 20 */ /* Bits defined in MICEVMA2 */ /* V=R Shadow Table Bypass assists */ #define MICSTBVR 0x80 /* V=R STBYPASS Assist active */ #define MICPTLB2 0x40 /* VRSTBYPASS PTLB Simulation */ #define MICIPTP2 0x20 /* VRSTBYPASS IPTE/TPRT Simulation */ #define MICVPFR2 0x10 /* Virtual Page Fault reflection Assists */ #define MICLRA2 0x08 /* VRSTBYPASS LRA Simulation */ #define MICSTSM2 0x02 /* VRSTBYPASS SSM/STxSM Sim */ #define MICLCTL2 0x01 /* VRSTBYPASS LCTL Sim */ /* Bits define in MICEVMA3 */ #define MICSKYMD 0x20 /* Unknown */ #define MICISKE 0x10 /* PTLB Sim */ #define MICRRBE 0x08 /* IPTE/TPRT Sim */ #define MICSSKE 0x04 /* V Page Fault Sim */ /* Bits defined in MICEVMA4 */ #define MICSVC4 0x40 /* SVC/LPSW/LCTL Assists Extentions */ #define MICSPT4 0x20 /* SPT Assist Extension */ #define MICIUCV 0x10 /* IUCV ASSIST */ } ECPSVM_MICBLOK; /* PSA Usefull Values */ #define IOOPSW 0x038 #define QUANTUMR 0x04C /* Usefull little unused space for MVCing NEW ITIMER */ #define INTTIMER 0x050 #define QUANTUM 0x054 /* Usefull little unused space for MVCing OLD ITIMER */ /* PSA Displacements used by ECPS:VM */ /* PSA Entries used by DISPx Instructions */ #define CPSTATUS 0x348 /* PSA + 348 : CPSTATUS */ #define CPWAIT 0x80 /* CP IN WAIT STATE */ #define CPRUN 0x40 /* RUNUSER is use running */ #define CPEX 0x20 /* CPEXBLOK RUNNING */ #define CPSUPER 0x08 /* Supervisor State */ /* PSA + 349 : SYSTEM EXTENDING FREE STORAGE BYTE */ /* Note : PSA+0X349 = 0xFF if storage extending */ #define XTENDLOCK 0x349 #define XTENDLOCKSET 0xff /* PSA + 34A : CPSTAT2 */ #define CPSTAT2 0x34A #define CPMICAVL 0x80 #define CPMICON 0x40 #define CPSHRLK 0x20 #define CPASTAVL 0x08 #define CPASTON 0x04 /* RUNPSW */ /* PSW used during dispatch */ #define RUNPSW 0x330 /* RUNUSER PSA+338 */ #define RUNUSER 0x338 /* RUNCR0, RUNCR1 */ /* CR0 & CR1 used during dispatch */ #define RUNCR0 0x340 #define RUNCR1 0x344 /* ASYSVM : PSA+37C */ #define ASYSVM 0x37C /* PSA + X'3D4' - ASSISTS STUFF */ #define CPCREG0 0x3D4 #define CPCREG6 0x3D8 #define CPCREG8 0x3DC #define TIMEDISP 0x3E0 #define ASVCLIST 0x3E4 #define AVMALIST 0x3E8 #define LASTUSER 0x3EC /* PSA + 328 : PROBTIME */ /* Total time spent in problem state (2's complement) */ #define PROBTIME 0x328 /* PSA + 69D : APSTAT2 - Machine check recov & PTLB Required */ #define APSTAT2 0x69D #define CPMCHLK 0x10 #define CPPTLBR 0x02 /* PSA + 6A8 : PROBSTRT */ /* TOD Clock at Proble state entry */ #define PROBSTRT 0x6A8 /* PSA + 6D0 : STACKVM - GPR11 Backup for dispatcher */ #define STACKVM 0x6D0 /* CP ASSIST SVC (Not VM Assist SVC) LIST */ /* ASSISTS FOR CP LINK/RETURN SVCs */ /* DMKSVCNS */ /* Address found @ PSA+3E4 */ typedef struct _ECPSVM_SVCLIST { DW NEXTSAVE; /* Pointer to next Save Area + 8 */ DW SLCADDR; /* V=R Start */ DW DMKSVCHI; /* DMKFREHI */ DW DMKSVCLO; /* DMKFRELO + SAVEAREA LENGTH */ } ECPSVM_SVCLIST; /* VM ASSIST LISTS */ /* ENTRYPOINT TO VARIOUS PRIVOP SIM FASTPATH */ /* (DMKPRVMA) */ /* Address found @ PSA+3E8 */ typedef struct _ECPSVM_VMALIST { DW VSIVS; /* EP To DMKVSIVS (Fastpath SIO/SIOF) */ DW VSIEX; /* Base addr for VSIVS */ DW DSPCH; /* Scheduler - Fast path for LPSW/SSM/STNSM/STOSM */ DW TMRCC; /* SCKC EP */ DW TMR; /* Timer ops base */ DW TMRSP; /* SPT EP */ DW VATAT; /* ARCHITECT */ DW DSPB; /* Slow Path Dispatcher - PSW Revalidate required */ DW PRVVS; /* VSIVS COUNT */ DW PRVVL; /* LPSW Count */ DW PRVVM; /* SSM/STxSM COUNT */ DW PRVVC; /* SCKC COUNT */ DW RESERVED; DW PRVVP; /* SPT COUNT */ } ECPSVM_VMALIST; /* VMBLOK Displacements */ #define VMQFPNT 0x000 #define VMQBPNT 0x004 #define VMPNT 0x008 #define VMECEXT 0x00C #define VMVCR0 VMECEXT #define VMSEG 0x010 #define VMSIZE 0x014 #define VMCHSTRT 0x018 #define VMCUSTRT 0x01C #define VMDVSTRT 0x020 #define VMTERM 0x024 #define VMVTERM 0x028 #define VMTRMID 0x02A #define VMTLEND 0x02C #define VMTLDEL 0x02D #define VMTCDEL 0x02E #define VMTESCP 0x02F #define VMCHCNT 0x030 #define VMCUCNT 0x032 #define VMDVCNT 0x034 #define VMIOACTV 0x036 #define VMCHTBL 0x038 #define VMRSTAT 0x058 /* Flags defined in VMRSTAT */ #define VMCFWAIT 0x80 #define VMPGWAIT 0x40 #define VMIOWAIT 0x20 #define VMPSWAIT 0x10 #define VMEXWAIT 0x08 #define VMLOGON 0x04 #define VMLOGOFF 0x02 #define VMIDLE 0x01 #define VMCPWAIT (VMCFWAIT|VMPGWAIT|VMIOWAIT|VMEXWAIT|VMLOGOFF|VMLOGON) #define VMNORUN (VMCPWAIT|VMPSWAIT) #define VMLONGWT (VMCFWAIT|VMLOGON|VMLOGOFF|VMIDLE) #define VMDSTAT 0x059 /* Flags defined in VMDSTAT */ #define VMDSP 0x80 #define VMTSEND 0x40 #define VMQSEND 0x20 #define VMTIO 0x10 #define VMRUN 0x08 #define VMINQ 0x04 #define VMELIG 0x02 #define VMDSPCH 0x01 #define VMOSTAT 0x05A /* Flags defined in VMOSTAT */ #define VMSYSOP 0x80 #define VMSHR 0x40 #define VMSLEEP 0x20 #define VMDISC 0x10 #define VMCFRUN 0x08 #define VMVIRCF 0x04 #define VMCF 0x02 #define VMKILL 0x01 #define VMQSTAT 0x05B /* Flags defined in VMQSTAT */ #define VMPRIDSP 0x80 #define VMAUTOLOG 0x40 #define VMWSERNG 0x20 #define VMDLDRP 0x10 #define VMWSCHG 0x08 #define VMINHMIG 0x04 #define VMCFREAD 0x02 #define VMPA2APL 0x01 #define VMPSTAT 0x05C /* Flags defined in VMPSTAT */ #define VMISAM 0x80 #define VMV370R 0x40 #define VMRPAGE 0x20 #define VMREAL 0x10 #define VMNOTRAN 0x08 #define VMNSHR 0x04 #define VMACCOUN 0x02 #define VMPAGEX 0x01 #define VMESTAT 0x05D /* Flags defined in VMESTAT */ #define VMSHADT 0x80 #define VMPERCM 0x40 #define VMBADCR0 0x20 #define VMMICSVC 0x10 #define VMEXTCM 0x08 #define VMNEWCR0 0x04 #define VMINVSEG 0x02 #define VMINVPAG 0x01 #define VMECZAP ~VMMICSVC #define VMTRCTL 0x05E /* Bits defined in VMTRCTL */ #define VMTRPER 0x80 #define VMTRSVC 0x40 #define VMTRPRG 0x20 #define VMTRIO 0x10 #define VMTREX 0x08 #define VMTRPRV 0x04 #define VMTRSIO 0x02 #define VMTRBRIN 0x01 #define VMTRINT (VMTRSVC|VMTRPRG|VMTRIO|VMTREX) #define VMMLEVEL 0x05F #define VMQLEVEL 0x060 /* Bits defined in VMQLEVEL */ #define VMQ1 0x80 #define VMCOMP 0x40 #define VMHIPRI 0x20 #define VMLOPRI 0x10 #define VMAEX 0x08 #define VMAEXP 0x04 #define VMAQ3 0x02 #define VMDROP1 0x02 #define VMFS 0x01 #define VM_RESERVED1 0x061 #define VMTLEVEL 0x062 /* Flags defined for VMTLEVEL */ #define VMTON 0x80 #define VMRON 0x40 #define VMCPUTMR 0x20 #define VMSTMPI 0x08 #define VMSTMPT 0x04 #define VMTMRINT 0x01 #define VMPEND 0x063 /* Flags defined in VMPEND */ #define VMDEFSTK 0x80 #define VMPERPND 0x40 #define VMPRGPND 0x20 #define VMSVCPND 0x10 #define VMPGPND 0x08 #define VMIOPND 0x02 #define VMEXTPND 0x01 #define VMLOCKER 0x064 #define VMFSTAT 0x068 #define VMMLVL2 0x069 #define VMIOINT 0x06A #define VMTIMER 0x06C #define VMVTIME 0x070 #define VMTMOUTQ 0x078 #define VMTTIME 0x080 #define VMTMINQ 0x088 #define VMTSOUTQ VMTMINQ #define VMTODINQ 0x090 #define VMINST 0x098 #define VMUPRIOR 0x09E #define VMPSWCT 0x09F #define VMTREXT 0x0A0 #define VMADSTOP 0x0A4 #define VMPSW 0x0A8 #define VMGPRS 0x0B0 #define VMFPRS 0x0F0 #define VMUSER 0x110 #define VMACCNT 0x118 #define VMDIST 0x120 #define VMMICRO 0x17C #define VMMCR6 VMMICRO #define VMMADDR VMMICRO+1 #define VMPXINT 0x184 #define VMNOECPS 0x1A7 #define VMSTKCNT 0x1CC /* ECBLOK Specifics */ #define EXTSHCR0 0x40 #define EXTSHCR1 0x44 typedef struct _ECPSVM_STAT { char *name; U32 call; U32 hit; u_int support:1; u_int enabled:1; u_int debug:1; u_int total:1; } ECPSVM_STAT; /* THE FOLLOWING ARE C99 INITIALISATION OF THE ECPSVM INSTRUCTION STATE STRUCTURES */ /* SINCE MSVC SEEMS TO NOT LIKE THOSE, THEY ARE REPLACED FOR THE TIME BEING */ #if 0 #define ECPSVM_STAT_DCL(_name) ECPSVM_STAT _name #define ECPSVM_STAT_DEF(_name) ._name = { .name = ""#_name"" ,.call=0,.hit=0,.support=1,.total=0,.enabled=1,.debug=0} #define ECPSVM_STAT_DEFU(_name) ._name = { .name = ""#_name"" ,.call=0,.hit=0,.support=0,.total=0,.enabled=1,.debug=0} #define ECPSVM_STAT_DEFM(_name) ._name = { .name = ""#_name"" ,.call=0,.hit=0,.support=1,.total=1,.enabled=1,.debug=0} #endif /* BELOW ARE NON C99 STRUCTURE INITIALIZERS KEEP THE ABOVE IN SYNC PLEASE */ #define ECPSVM_STAT_DCL(_name) ECPSVM_STAT _name #define ECPSVM_STAT_DEF(_name) { ""#_name"" ,0,0,1,1,0,0} #define ECPSVM_STAT_DEFU(_name) {""#_name"" ,0,0,0,1,0,0} #define ECPSVM_STAT_DEFM(_name) {""#_name"" ,0,0,1,1,0,1} typedef struct _ECPSVM_CMDENT { char *name; int abbrev; void (*fun)(int argc,char **av); char *expl; char *help; } ECPSVM_CMDENT; #endif hercules-3.12/memrchr.h0000664000175000017500000000202412564723224012007 00000000000000/* MEMRCHR.H (c) Copyright Volker Bandke, 2003 */ /* Hercules Right to Left memory scan header file */ /*-------------------------------------------------------------------*/ /* Scans the memory block and reports the last occurrence of */ /* the specified byte in the buffer. Returns a pointer to */ /* the byte if found, or NULL if not found. */ /*-------------------------------------------------------------------*/ #ifndef MEMRCHR_H #define MEMRCHR_H #include "hercules.h" #ifndef _MEMRCHR_C_ #ifndef _HUTIL_DLL_ #define MEM_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define MEM_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define MEM_DLL_IMPORT DLL_EXPORT #endif #if !defined(HAVE_MEMRCHR) // (only if we need it) #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ MEM_DLL_IMPORT void *memrchr(const void *buf, int c, size_t num); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif // !defined(HAVE_MEMRCHR) #endif // MEMRCHR_H hercules-3.12/shared.h0000664000175000017500000006047512564723224011636 00000000000000/* SHARED.H (c) Copyright Greg Smith, 2002-2009 */ /* Shared Device Server header file */ /*------------------------------------------------------------------- * Shared device support (c)Copyright Greg Smith, 2002-2009 * * Shared device support allows multiple Hercules instances to share * devices. The device will be `local' to one instance and `remote' * to all other instances. The local instance is the * `server' for * that device and the remote instance is the `client'. You do not * have to IPL an operating system on the device server. Any number * of Hercules instances can act as a server in a Hercplex ;-) * * To use a device on a remote system, instead of specifying a file * name on the device config statement, you specify * * ip_address_or_name:port:devnum * * For example: * * 0100 3350 localhost:3990:0100 * * which says there is a device server on the local host listening * on port 3990 and we want to use its 0100 device as 0100. The * default port is 3990 and the default remote device number is the * local device number. So we could say * * 0100 3350 localhost * * instead, providing we don't actually have a file `localhost'. * Interestingly, the instance on the local host listening on 3990 * could have a statement * * 0100 3350 192.168.200.1::0200 * * which means that instance in turn will use device 0200 on the * server at 192.168.200.1 listening on port 3990. The original * instance will have to `hop' thru the second instance to get * to the real device. * * Device sharing can be `split' between multiple instances. * For example, suppose instance A has * * SHRDPORT 3990 * 0100 3350 localhost:3991 * 0101 3350 mvscat * * and instance B has * * SHRDPORT 3991 * 0100 3350 mvsres * 0101 3350 localhost * * Then each instance acts as both a client and as a server. * * When `SHRDPORT' is specified, thread `shared_server' is started * at the end of Hercules initialization. In the example above, * neither Hercules instance can initialize their devices until the * server is started on each system. In this case, the device trying * to access a server gets the `connecting' bit set on in the DEVBLK * and the device still needs to initialize. After the shared server * is started, a thread is attached for each device that is connecting * to complete the connection (which is the device init handler). * * TECHNICAL BS: * * There are (at least) two approaches to sharing devices. One is to * execute the channel program on the server system. The server will * need to request from the client system information such as the ccw * and the data to be written, and will need to send to the client * data that has been read and status information. The second is to * execute the channel program on the client system. Here the client * system makes requests to the server system to read and write data. * * The second approach is currently implemented. The first approach * arguably emulates `more correctly'. However, an advantage of the * implemented approach is that it is easier because only the * client sends requests and only the server sends responses. * * Both client and server have a DEVBLK structure for the device. * Absurdly, perhaps, in originally designing an implementation for * shared devices it was not clear what type of process should be the * server. It was a quantum leap forward to realize that it could * just be another hercules instance. * * PROTOCOL: * (If this section is as boring for you to read as it was for me * to write then please skip to the next section ;-) * * The client sends an 8 byte request header and maybe some data: * * +-----+-----+-----+-----+-----+-----+-----+-----+ * | cmd |flag | devnum | id | length | * +-----+-----+-----+-----+-----+-----+-----+-----+ * * <-------- length ---------> * +----- . . . . . -----+ * | data | * +----- . . . . . -----+ * * `cmd' identifies the client request. The requests are: * * 0xe0 CONNECT Connect to the server. This requires * the server to allocate resources to * support the connection. Typically issued * during device initialization or after being * disconnected after a network error or timeout. * 0xe1 DISCONNECT Disconnect from the server. The server * can now release the allocated resources * for the connection. Typically issued during * device close or detach. * 0xe2 START Start a channel program on the device. * If the device is busy or reserved by * another system then wait until the device * is available unless the NOWAIT flag bit * is set, then return a BUSY code. Once * START succeeds then the device is unavailable * until the END request. * 0xe3 END Channel program has ended. Any waiters * for the device can now retry. * 0xe4 RESUME Similar to START except a suspended * channel program has resumed. * 0xe5 SUSPEND Similar to END except a channel program * has suspended itself. If the channel * program is not resumed then the END * request is *not* issued. * 0xe6 RESERVE Makes the device unavailable to any other * system until a RELEASE request is issued. * *Must* be issued within the scope of START/END. * 0xe7 RELEASE Makes the device available to other systems * after the next END request. * *Must* be issued within the scope of * START/END. * 0xe8 READ Read from a device. A 4-byte `record' * identifier is specified in the request * data to identify what data to read in the * device context. * *Must* be issued within the scope of START/END. * 0xe9 WRITE Write to a device. A 2-byte `offset' and * a 4-byte `record' is specified in the request * data, followed by the data to be written. * `record' identifies what data is to be written * in the device context and `offset' and `length' * identify what to update in `record'. * *Must* be issued within the scope of START/END. * 0xea SENSE Retrieves the sense information after an i/o * error has occurred on the server side. This * is typically issued within the scope of the * channel program having the error. Client side * sense or concurrent sense will then pick up the * sense data relevant to the i/o error. * *Must* be issued within the scope of START/END. * 0xeb QUERY Obtain device information, typically during * device initialization. * 0xec COMPRESS Negotiate compression parameters. Notifies the * server what compression algorithms are supported * by the client and whether or not data sent back * and forth from the client or server should be * compressed or not. Typically issued after CONNECT. * *NOTE* This action should actually be SETOPT or * some such; it was just easier to code a COMPRESS * specific SETOPT (less code). * * `flag' qualifies the client request and varies by the request. * * 0x80 NOWAIT For START, if the device is unavailable then * return BUSY instead of waiting for the device. * 0x40 QUERY Identifies the QUERY request: * 0x41 DEVCHAR Device characteristics data * 0x42 DEVID Device identifier data * 0x43 DEVUSED Hi used track/block (for dasdcopy) * 0x48 CKDCYLS Number cylinders for CKD device * 0x4c FBAORIGIN Origin block for FBA * 0x4d FBANUMBLK Number of FBA blocks * 0x4e FBABLKSIZ Size of an FBA block * 0x3x COMP For WRITE, data is compressed at offset `x': * 0x2x BZIP2 using bzip2 * 0x1x LIBZ using zlib * 0xxy For COMPRESS, identifies the compression * algorithms supported by the client (0x2y for bzip2, * 0x1y for zlib, 0x3y for both) and the zlib compression * parameter `y' for sending otherwise uncompressed data * back and forth. If `y' is zero (default) then no * uncompressed data is compressed between client & server. * * `devnum' identifies the device by number on the server instance. * The device number may be different than the * device number on the client instance. * `id' identifies the client to the server. Each client has a unique * positive (non-zero) identifier. For the initial * CONNECT request `id' is zero. After a successful * CONNECT, the server returns in the response header * the identifier to be used for all other requests * (including subsequent CONNECT requests). This is * saved in dev->rmtid. * `length' specifies the length of the data following the request header. * Currently length is non-zero for READ/WRITE requests. * * The server sends an 8 byte response header and maybe some data: * * +-----+-----+-----+-----+-----+-----+-----+-----+ * |code |stat | devnum | id | length | * +-----+-----+-----+-----+-----+-----+-----+-----+ * * <-------- length ---------> * +----- . . . . . -----+ * | data | * +----- . . . . . -----+ * * `code' indicates the response to the request. OK (0x00) indicates * success however other codes also indicate success * but qualified in some manner: * 0x80 ERROR An error occurred. The server provides an error * message in the data section. * 0x40 IOERR An i/o error occurred during a READ/WRITE * request. The status byte has the `unitstat' * data. This should signal the client to issue the * SENSE request to obtain the current sense data. * 0x20 BUSY Device was not available for a START request and * the NOWAIT flag bit was turned on. * 0x10 COMP Data returned is compressed. The status byte * indicates how the data is compressed (zlib or * bzip2) and at what offset the compressed data * starts (0 .. 15). This bit is only turned on * when both the `code' and `status' bytes would * otherwise be zero. * 0x08 PURGE START request was issued by the client. A list * of `records' to be purged from local cache is * returned. These are `records' that have been * updated since the last START/END request from * the client by other systems. Each record identifier * is a 4-byte field in the data segment. The number * of records then is `length'/4. If the number of * records exceeds a threshold (16) then `length' * will be zero indicating that the client should * purge all locally cached records for the device. * * `stat' contains status information as a result of the request. * For READ/WRITE requests this contains the `unitstat' * information if an IOERR occurred. * * `devnum' specifies the server device number * * `id' specifies the system identifier for the request. * * `length' is the size of the data returned. * * * CACHING * * Cached records (eg CKD tracks or FBA blocks) are kept independently on * both the client and server sides. Whenever the client issues a START * request to initiate a channel program the server will return a list * of records to purge from the client's cache that have been updated by * other clients since the last START request. If the list is too large * the server will indicate that the client should purge all records for * the device. * * COMPRESSION * * Data that would normally be transferred uncompressed between client * and host can optionally be compressed by specifying the `comp=' * keyword on the device configuration statement or attach command. * For example * * 0100 3350 192.168.2.12 comp=3 * * The value of the `comp=' keyword is the zlib compression parameter * which should be a number between 1 .. 9. A value closer to 1 means * less compression but less processor time to perform the compression. * A value closer to 9 means the data is compressed more but more processor * time is required. * * If the server is on `localhost' then you should not specify `comp='. * Otherwise you are just stealing processor time to do compression/ * uncompression from hercules. If the server is on a local network * then I would recommend specifying a low value such as 1, 2 or 3. * We are on a curve here, trying to trade cpu cycles for network traffic * to derive an optimal throughput. * * If the devices on the server are compressed devices (eg CCKD or CFBA) * then the `records' (eg. track images or block groups) may be transferred * compressed regardless of the `comp=' setting. This depends on whether * the client supports the compression type (zlib or bzip2) of the record * on the server and whether the record is actually compressed in the * server cache. * * For example: * * Suppose on the client that you execute one or more channel programs * to read a record on a ckd track, update a record on the same track, * and then read another (or the same) record on the track. * * For the first read the server will read the track image and * pass it to the client as it was originally compressed in the file. * To update a portion of the track image the server must uncompress * the track image so data in it can be updated. When the client next * reads from the track image, the track image is uncompressed. * * Specifying `comp=' means that uncompressed data sent to the client * will be compressed. If the data to be sent to the client is already * compressed then the data is sent as is, unless the client has indicated * that it does not support that compression algorithm. * * * TODO * * 1. More doc (sorry, I got winded) * 2. Delays observed during short transfers (redrive select ?) * 3. Better server side behaviour due to disconnect * 3. etc. * * *-------------------------------------------------------------------*/ #ifndef _HERCULES_SHARED_H #define _HERCULES_SHARED_H 1 #include "hercules.h" #ifndef _SHARED_C_ #ifndef _HDASD_DLL_ #define SHR_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define SHR_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define SHR_DLL_IMPORT DLL_EXPORT #endif #define OPTION_SHARED_DEVICES #undef FBA_SHARED /* * Differing version levels are not compatible * Differing release levels are compatible */ #define SHARED_VERSION 0 /* Version level (0 .. 15) */ #define SHARED_RELEASE 1 /* Release level (0 .. 15) */ #define SHARED_MAX_SYS 8 /* Max number connections */ typedef char SHRD_TRACE[128]; /* Trace entry */ #include "hercules.h" /* Requests */ #define SHRD_CONNECT 0xe0 /* Connect */ #define SHRD_DISCONNECT 0xe1 /* Disconnect */ #define SHRD_START 0xe2 /* Start channel program */ #define SHRD_END 0xe3 /* End channel program */ #define SHRD_RESUME 0xe4 /* Resume channel program */ #define SHRD_SUSPEND 0xe5 /* Suspend channel program */ #define SHRD_RESERVE 0xe6 /* Reserve */ #define SHRD_RELEASE 0xe7 /* Release */ #define SHRD_READ 0xe8 /* Read data */ #define SHRD_WRITE 0xe9 /* Write data */ #define SHRD_SENSE 0xea /* Sense */ #define SHRD_QUERY 0xeb /* Query */ #define SHRD_COMPRESS 0xec /* Compress request */ /* Response codes */ #define SHRD_OK 0x00 /* Success */ #define SHRD_ERROR 0x80 /* Failure */ #define SHRD_IOERR 0x40 /* I/O error */ #define SHRD_BUSY 0x20 /* Resource is busy */ #define SHRD_COMP 0x10 /* Data is compressed */ #define SHRD_PURGE 0x08 /* Purge list provided */ #define SHRD_ERROR_INVALID 0xf0 /* Invalid request */ #define SHRD_ERROR_BADVERS 0xf1 /* Version mismatch */ #define SHRD_ERROR_NOTINIT 0xf2 /* Device not initialized */ #define SHRD_ERROR_NOTCONN 0xf3 /* Not connected to device */ #define SHRD_ERROR_NOTAVAIL 0xf4 /* No available SHRD */ #define SHRD_ERROR_NOMEM 0xf5 /* Out of memory */ #define SHRD_ERROR_NOTACTIVE 0xf6 /* Not device owner */ #define SHRD_ERROR_NODEVICE 0xf7 /* No such device */ #define SHRD_ERROR_CONNECTED 0xf8 /* Already connected */ /* Flags */ #define SHRD_NOWAIT 0x80 /* Don't wait if busy */ #define SHRD_QUERY_REQUEST 0x40 /* Query request */ #define SHRD_COMP_MASK 0x30 /* Mask to detect compression*/ #define SHRD_COMP_OFF 0x0f /* Offset to compressed data */ #define SHRD_COMP_MAX_OFF 15 /* Max offset allowed */ #define SHRD_LIBZ 0x01 /* Compressed using zlib */ #define SHRD_BZIP2 0x02 /* Compressed using bzip2 */ /* Query Types */ #define SHRD_DEVCHAR 0x41 /* Device characteristics */ #define SHRD_DEVID 0x42 /* Device identifier */ #define SHRD_USED 0x43 /* Device usage */ #define SHRD_CKDCYLS 0x48 /* CKD number cylinders */ #define SHRD_FBAORIGIN 0x4c /* FBA origin */ #define SHRD_FBANUMBLK 0x4d /* FBA number blocks */ #define SHRD_FBABLKSIZ 0x4e /* FBA block size */ /* Constraints */ #define SHARED_DEFAULT_PORT 3990 /* Default shared port */ #define SHARED_PURGE_MAX 16 /* Max size of purge list */ #define SHARED_MAX_MSGLEN 255 /* Max message length */ #define SHARED_TIMEOUT 120 /* Disconnect timeout (sec) */ #define SHARED_FORCE_TIMEOUT 300 /* Force disconnect (sec) */ #define SHARED_SELECT_WAIT 10 /* Select timeout (sec) */ #define SHARED_COMPRESS_MINLEN 512 /* Min length for compression*/ struct SHRD { int id; /* Identifier */ int fd; /* Socket */ char *ipaddr; /* IP addr of connected peer */ time_t time; /* Time last request */ int release; /* Client release level */ int comp; /* Compression parameter */ int comps; /* Compression supported */ int pending:1, /* 1=Request pending */ waiting:1, /* 1=Waiting for device */ havehdr:1, /* 1=Header already read */ disconnect:1; /* 1=Disconnect device */ DBLWRD hdr; /* Header */ int purgen; /* Number purge entries */ FWORD purge[SHARED_PURGE_MAX];/* Purge list */ }; typedef struct _SHRD_HDR { BYTE cmd; /* 0 Command */ BYTE code; /* 1 Flags and Codes */ U16 devnum; /* 2 Device number */ U16 id; /* 4 Identifier */ U16 len; /* 6 Data length */ } SHRD_HDR; /* Size must be 8 bytes */ #define SHRD_HDR_SIZE sizeof(DBLWRD) #define SHRD_SET_HDR(_buf, _cmd, _code, _devnum, _len, _id) \ do { \ SHRD_HDR *shdr = (SHRD_HDR *)(_buf); \ shdr->cmd = (_cmd); \ shdr->code = (_code); \ store_hw (&shdr->devnum, (_devnum)); \ store_hw (&shdr->len, (_len)); \ store_hw (&shdr->id, (_id)); \ } while (0) #define SHRD_GET_HDR(_buf, _cmd, _code, _devnum, _len, _id) \ do { \ SHRD_HDR *shdr = (SHRD_HDR *)(_buf); \ (_cmd) = shdr->cmd; \ (_code) = shdr->code; \ (_devnum) = (U16)fetch_hw (&shdr->devnum); \ (_len) = (int)fetch_hw (&shdr->len); \ (_id) = (int)fetch_hw (&shdr->id); \ } while (0) int shared_update_notify (DEVBLK *dev, int block); int shared_ckd_init (DEVBLK *dev, int argc, char *argv[] ); int shared_fba_init (DEVBLK *dev, int argc, char *argv[] ); SHR_DLL_IMPORT void *shared_server (void *arg); SHR_DLL_IMPORT int shared_cmd(int argc, char *argv[], char *cmdline); #ifdef _SHARED_C_ static int shared_ckd_close ( DEVBLK *dev ); static int shared_fba_close (DEVBLK *dev); static void shared_start(DEVBLK *dev); static void shared_end (DEVBLK *dev); static int shared_ckd_read (DEVBLK *dev, int trk, BYTE *unitstat); static int shared_ckd_write (DEVBLK *dev, int trk, int off, BYTE *buf, int len, BYTE *unitstat); static int shared_ckd_trklen (DEVBLK *dev, BYTE *buf); #if defined(FBA_SHARED) static int shared_fba_read (DEVBLK *dev, int blkgrp, BYTE *unitstat); static int shared_fba_write (DEVBLK *dev, int blkgrp, int off, BYTE *buf, int len, BYTE *unitstat); static int shared_fba_blkgrp_len (DEVBLK *dev, int blkgrp); #endif static int shared_used (DEVBLK *dev); static void shared_reserve (DEVBLK *dev); static void shared_release (DEVBLK *dev); static int clientWrite (DEVBLK *dev, int block); static void clientPurge (DEVBLK *dev, int n, void *buf); static int clientPurgescan (int *answer, int ix, int i, void *data); static int clientConnect (DEVBLK *dev, int retry); static int clientRequest (DEVBLK *dev, BYTE *buf, int len, int cmd, int flags, int *code, int *status); static int clientSend (DEVBLK *dev, BYTE *hdr, BYTE *buf, int buflen); static int clientRecv (DEVBLK *dev, BYTE *hdr, BYTE *buf, int buflen); static int recvData(int sock, BYTE *hdr, BYTE *buf, int buflen, int server); static void serverRequest (DEVBLK *dev, int ix, BYTE *hdr, BYTE *buf); static int serverLocate (DEVBLK *dev, int id, int *avail); static int serverId (DEVBLK *dev); static int serverError (DEVBLK *dev, int ix, int code, int status, char *msg); static int serverSend (DEVBLK *dev, int ix, BYTE *hdr, BYTE *buf, int buflen); static int serverDisconnectable (DEVBLK *dev, int ix); static void serverDisconnect (DEVBLK *dev, int ix); static char *clientip (int sock); static DEVBLK *findDevice (U16 devnum); static void *serverConnect (int *psock); static void shrdtrc (DEVBLK *dev, char *msg, ...); #endif /* _SHARED_C_ */ #endif /* _HERCULES_SHARED_H */ hercules-3.12/hscutl.h0000664000175000017500000001604512564723224011664 00000000000000/* HSCUTL.H (c) Copyright Roger Bowler, 1999-2009 */ /* Host-specific functions header file */ /*-------------------------------------------------------------------*/ /* Implementation of functions used in Hercules that may */ /* be missing on some platform ports, or other convenient */ /* miscellaneous global utility functions. */ /*-------------------------------------------------------------------*/ #ifndef __HSCUTL_H__ #define __HSCUTL_H__ #include "hercules.h" #ifndef _HSCUTL_C_ #ifndef _HUTIL_DLL_ #define HUT_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define HUT_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define HUT_DLL_IMPORT DLL_EXPORT #endif #ifndef _HSCUTL2_C_ #ifndef _HUTIL_DLL_ #define HU2_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define HU2_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define HU2_DLL_IMPORT DLL_EXPORT #endif /********************************************************************* The following couple of Hercules 'utility' functions may be defined elsewhere depending on which host platform we're being built for... For Windows builds (e.g. MingW32), the functionality for the below functions is defined in 'w32util.c'. For other host build platforms (e.g. Linux, Apple, etc), the functionality for the below functions is defined right here in 'hscutil.c'... *********************************************************************/ #if defined(_MSVC_) /* The w32util.c module will provide the below functionality... */ #else /* THIS module (hscutil.c) is to provide the below functionality.. */ /* Returns outpath as a host filesystem compatible filename path. This is a Cygwin-to-MSVC transitional period helper function. On non-Windows platforms it simply copies inpath to outpath. On Windows it converts inpath of the form "/cygdrive/x/foo.bar" to outpath in the form "x:/foo.bar" for Windows compatibility. */ char *hostpath( char *outpath, const char *inpath, size_t buffsize ); /* Poor man's "fcntl( fd, F_GETFL )"... */ /* (only returns access-mode flags and not any others) */ int get_file_accmode_flags( int fd ); /* Initialize/Deinitialize sockets package... */ int socket_init( void ); int socket_deinit( void ); /* Set socket to blocking or non-blocking mode... */ int socket_set_blocking_mode( int sfd, int blocking_mode ); /* Determine whether a file descriptor is a socket or not... */ /* (returns 1==true if it's a socket, 0==false otherwise) */ int socket_is_socket( int sfd ); /* Set the SO_KEEPALIVE option and timeout values for a socket connection to detect when client disconnects */ void socket_keepalive( int sfd, int idle_time, int probe_interval, int probe_count ); #endif // !defined(_MSVC_) /*********************************************************************/ #if !defined(_MSVC_) && !defined(HAVE_STRERROR_R) HUT_DLL_IMPORT void strerror_r_init(void); HUT_DLL_IMPORT int strerror_r(int, char *, size_t); #endif #if defined(OPTION_CONFIG_SYMBOLS) HUT_DLL_IMPORT void set_symbol(const char *,const char *); HUT_DLL_IMPORT const char *get_symbol(const char *); HUT_DLL_IMPORT char *resolve_symbol_string(const char *); HUT_DLL_IMPORT void kill_all_symbols(void); HUT_DLL_IMPORT void list_all_symbols(void); #endif #ifdef _MSVC_ #ifndef HAVE_ID_T #define HAVE_ID_T typedef unsigned long id_t; #endif HU2_DLL_IMPORT int getpriority(int, id_t); HU2_DLL_IMPORT int setpriority(int, id_t, int); #ifndef HAVE_SYS_RESOURCE_H #define PRIO_PROCESS 0 #define PRIO_PGRP 1 #define PRIO_USER 2 #endif // Win32 'winbase.h' updates // REALTIME_PRIORITY_CLASS 256 // -20 // HIGH_PRIORITY_CLASS 128 // -15 #ifndef ABOVE_NORMAL_PRIORITY_CLASS #define ABOVE_NORMAL_PRIORITY_CLASS 32768 // -8 #endif // NORMAL_PRIORITY_CLASS 32 // 0 #ifndef BELOW_NORMAL_PRIORITY_CLASS #define BELOW_NORMAL_PRIORITY_CLASS 16384 // 8 #endif // IDLE_PRIORITY_CLASS 64 // 15 #endif // _MSVC_ #if !defined(HAVE_STRLCPY) /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ /* ** NOTE ** returns 'size_t' and NOT 'char*' like strncpy! */ HUT_DLL_IMPORT size_t strlcpy(char *dst, const char *src, size_t siz); #endif #if !defined(HAVE_STRLCAT) /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ /* ** NOTE ** returns 'size_t' and NOT 'char*' like strncat! */ HUT_DLL_IMPORT size_t strlcat(char *dst, const char *src, size_t siz); #endif /* Subtract/add gettimeofday struct timeval */ HUT_DLL_IMPORT int timeval_subtract (struct timeval *beg_timeval, struct timeval *end_timeval, struct timeval *dif_timeval); HUT_DLL_IMPORT int timeval_add (struct timeval *dif_timeval, struct timeval *accum_timeval); /* Easier to use timed_wait_condition that waits for the specified relative amount of time without you having to build an absolute timeout time yourself */ HUT_DLL_IMPORT int timed_wait_condition_relative_usecs ( COND* pCOND, // ptr to condition to wait on LOCK* pLOCK, // ptr to controlling lock (must be held!) U32 usecs, // max #of microseconds to wait struct timeval* pTV // [OPTIONAL] ptr to tod value (may be NULL) ); // TEST HUT_DLL_IMPORT void cause_crash(); /* Read/write to socket functions */ HUT_DLL_IMPORT int hprintf(int s,char *fmt,...); HUT_DLL_IMPORT int hwrite(int s,const char *,size_t); HUT_DLL_IMPORT int hgetc(int s); HUT_DLL_IMPORT char *hgets(char *b,size_t c,int s); #if !defined(_MSVC_) /* Hercules file open */ HUT_DLL_IMPORT int hopen(const char* path, int oflag, ...); #endif // !defined(_MSVC_) /* Posix 1003.e capabilities */ #if defined(OPTION_CAPABILITIES) HUT_DLL_IMPORT int drop_privileges(int c); HUT_DLL_IMPORT int drop_all_caps(void); #endif #endif /* __HSCUTL_H__ */ hercules-3.12/cmdtab.h0000664000175000017500000010734712564723224011622 00000000000000/* CMDTAB.H (c) Copyright Roger Bowler, 1999-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* (c) Copyright Jan Jaeger, 2003-2009 */ /* Defines all Hercules Configuration statements */ /* and panel commands */ // command type function one-line description... // COMMAND ("sample" PANEL, sample_cmd, "short help text", "long help text" ) // COMMAND ("sample2" PANEL+CONFIG, sample2_cmd, "short help text", NULL ) // No long help provided // COMMAND ("sample3" CONFIG, sample3_cmd, NULL, NULL ) // No help provided at all // COMMAND ("sample4" DISABLED, sample4_cmd, NULL, NULL ) // Disabled command - generally debugging only COMMAND ( "help", PANEL, HelpCommand, "list all commands / command specific help", "Enter \"help cmd\" where cmd is the command you need help\n" "with. If the command has additional help text defined for it,\n" "it will be displayed. Help text is usually limited to explaining\n" "the format of the command and its various required or optional\n" "parameters and is not meant to replace reading the documentation.\n" ) COMMAND ( "?", PANEL, HelpCommand, "alias for help\n", NULL ) COMMAND ( "*", CONFIG+PANEL, comment_cmd, "Comment", NULL ) COMMAND ( "#", CONFIG+PANEL, comment_cmd, "Comment\n", NULL ) CMDABBR ( "message",1, PANEL, msg_cmd, "Display message on console a la VM", NULL ) CMDABBR ( "msg",1, PANEL, msg_cmd, "Alias for message", NULL ) COMMAND ( "msgnoh", PANEL, msgnoh_cmd, "Similar to \"message\" but no header\n", NULL ) COMMAND ( "hst", PANEL, History, "history of commands", "Format: \"hst | hst n | hst l\". Command \"hst l\" or \"hst 0\" displays\n" "list of last ten commands entered from command line\n" "hst n, where n is a positive number retrieves n-th command from list\n" "hst n, where n is a negative number retrieves n-th last command\n" "hst without an argument works exactly as hst -1, it retrieves last command\n" ) #if defined(OPTION_HAO) COMMAND ( "hao", PANEL, hao_cmd, "Hercules Automatic Operator", "Format: \"hao tgt | cmd | list | del | clear \".\n" " hao tgt : define target rule (regex pattern) to react on\n" " hao cmd : define command for previously defined rule\n" " hao list : list all rules/commands or only at index \n" " hao del : delete the rule at index \n" " hao clear : delete all rules (stops automatic operator)\n" ) #endif /* defined(OPTION_HAO) */ COMMAND ( "log", PANEL, log_cmd, "direct log output", NULL ) COMMAND ( "logopt", PANEL+CONFIG, logopt_cmd, "change log options", "Format: \"logopt [timestamp | notimestamp]\". Sets logging options.\n" "\"timestamp\" inserts a time stamp in front of each log message.\n" "\"notimestamp\" displays log messages with no time stamps. Entering\n" "the command with no arguments displays current logging options.\n" "\"timestamp\" and \"notimestamp\" may be abbreviated as \"time\"\n" "and \"notime\" respectively.\n" ) COMMAND ( "uptime", PANEL, uptime_cmd, "display how long Hercules has been running\n", NULL ) COMMAND ( "version", PANEL, version_cmd, "display version information\n", NULL ) COMMAND ( "quit", PANEL, quit_cmd, "terminate the emulator", NULL ) COMMAND ( "exit", PANEL, quit_cmd, "(synonym for 'quit')\n", NULL ) COMMAND ( "cpu", PANEL, cpu_cmd, "Define target cpu for panel display and commands\n", "Format: \"cpu hh\" where 'hh' is the hexadecimal cpu address of the cpu\n" "in your multiprocessor configuration which you wish all panel commands\n" "to apply to. For example, entering 'cpu 1F' followed by \"gpr\" will\n" "display the general purpose registers for cpu 31 of your configuration.\n" ) COMMAND ( "fcb", PANEL, fcb_cmd, "display the current FCB (if only the printer is given)\n", "Reset the fcb to the standard one \n" "Load a fcb image \n" ) COMMAND ( "start", PANEL, start_cmd, "start CPU (or printer device if argument given)", "Entering the 'start' command by itself simply starts a stopped\n" "CPU, whereas 'start ' presses the virtual start button on\n" "printer device .\n" ) COMMAND ( "stop", PANEL, stop_cmd, "stop CPU (or printer device if argument given)\n", "Entering the 'stop' command by itself simply stops a running\n" "CPU, whereas 'stop ' presses the virtual stop button on\n" "printer device , usually causing an INTREQ.\n" ) COMMAND ( "startall", PANEL, startall_cmd, "start all CPU's", NULL ) COMMAND ( "stopall", PANEL, stopall_cmd, "stop all CPU's\n", NULL ) #ifdef _FEATURE_CPU_RECONFIG COMMAND ( "cf", PANEL, cf_cmd, "Configure current CPU online or offline", "Configure current CPU online or offline: Format-> \"cf [on|off]\"\n" "Where the 'current' CPU is defined as whatever CPU was defined as\n" "the panel command target cpu via the \"cpu\" panel command. (Refer\n" "to the 'cpu' command for further information) Entering 'cf' by itself\n" "simply displays the current online/offline status of the current cpu.\n" "Otherwise the current cpu is configured online or offline as specified.\n" "Use 'cfall' to configure/display all CPUs online/offline state.\n" ) COMMAND ( "cfall", PANEL, cfall_cmd, "configure all CPU's online or offline\n", NULL ) #endif #ifdef _FEATURE_SYSTEM_CONSOLE COMMAND ( ".reply", PANEL, g_cmd, "scp command", "To reply to a system control program (i.e. guest operating system)\n" "message that gets issued to the hercules console, prefix the reply\n" "with a period.\n" ) COMMAND ( "!message", PANEL, g_cmd, "scp priority messsage", "To enter a system control program (i.e. guest operating system)\n" "priority command on the hercules console, simply prefix the command\n" "with an exclamation point '!'.\n" ) COMMAND ( "ssd", PANEL, ssd_cmd, "signal shutdown\n", "The SSD (signal shutdown) command signals an imminent hypervisor shutdown to\n" "the guest. Guests who support this are supposed to perform a shutdown upon\n" "receiving this request.\n" "An implicit ssd command is given on a hercules \"quit\" command if the guest\n" "supports ssd. In that case hercules shutdown will be delayed until the guest\n" "has shutdown or a 2nd quit command is given.\n" ) #endif #ifdef OPTION_PTTRACE COMMAND ( "ptt", PANEL+CONFIG, EXT_CMD(ptt_cmd), "Set or display internal trace\n", "Format: \"ptt [options] [nnn]\"\n" "When specified with no operands, the ptt command displays the trace options\n" "and the contents of the internal trace table.\n" "When specified with operands, the ptt command sets the trace options and/or\n" "specifies which events are to be traced. If the last operand is numeric, it\n" "sets the size of the trace table and activates the trace.\n" "options:\n" " (no)error - error trace\n" " (no)control - control trace\n" " (no)prog - program interrupt trace\n" " (no)inter - interlock failure trace\n" " (no)sie - sie trace\n" " (no)signal - signaling trace\n" " (no)io - io trace\n" " (no)timer - timer trace\n" " (no)threads - thread trace\n" " (no)logger - logger trace\n" " (no)lock - lock trace buffer\n" " (no)tod - timestamp trace entries\n" " (no)wrap - wrap trace buffer\n" " to=nnn - trace buffer display timeout\n" " nnn - trace buffer size\n" ) #endif COMMAND ( "i", PANEL, i_cmd, "generate I/O attention interrupt for device", NULL ) COMMAND ( "ext", PANEL, ext_cmd, "generate external interrupt", NULL ) COMMAND ( "restart", PANEL, restart_cmd, "generate restart interrupt", NULL ) COMMAND ( "archmode", PANEL+CONFIG, archmode_cmd, "Set architecture mode", "Format: \"archmode [S/370 | ESA/390 | z/Arch | ESAME]\". Entering the command\n" "without any argument simply displays the current architecture mode. Entering\n" "the command with an argument sets the architecture mode to the specified value.\n" "Note: \"ESAME\" (Enterprise System Architecture, Modal Extensions) is simply a\n" "synonym for \"z/Arch\". (they are identical to each other and mean the same thing)\n" ) COMMAND ( "loadparm", PANEL+CONFIG, loadparm_cmd, "set IPL parameter\n", NULL ) COMMAND ( "lparname", PANEL+CONFIG, lparname_cmd, "set LPAR name\n", NULL ) COMMAND ( "lparnum", PANEL+CONFIG, lparnum_cmd, "set LPAR identification number\n", NULL ) #if defined(OPTION_SET_STSI_INFO) COMMAND ( "model", CONFIG, stsi_model_cmd,"Set STSI model code", NULL ) COMMAND ( "plant", CONFIG, stsi_plant_cmd,"Set STSI plant code", NULL ) COMMAND ( "manufacturer",CONFIG, stsi_mfct_cmd,"Set STSI manufacturer code\n", NULL ) #endif /* defined(OPTION_SET_STSI_INFO) */ COMMAND ( "pgmprdos", CONFIG, pgmprdos_cmd,"set LPP license setting\n", NULL ) COMMAND ( "codepage", CONFIG, codepage_cmd,"set codepage conversion table\n", NULL ) COMMAND ( "diag8cmd", CONFIG, diag8_cmd, "Set diag8 command option\n", NULL ) // The shcmdopt config statement should never be a command as it will introduce a possible integrity exposure *JJ COMMAND ( "shcmdopt", CONFIG, shcmdopt_cmd,"Set diag8 sh option\n", NULL ) COMMAND ( "legacysenseid",CONFIG, lsid_cmd, "set legacysenseid setting\n", NULL ) COMMAND ( "ipl", PANEL, ipl_cmd, "IPL Normal from device xxxx", "Format: \"ipl nnnn [parm xxxxxxxxxxxxxx]\"\n" "Performs the Initial Program Load manual control function. If the first operand\n" "'nnnn' is a 1- to 4-digit hexadecimal number, a CCW-type IPL is initiated from\n" "the indicated device number, and SCLP disk I/O is disabled.\n" "Otherwise a list-directed IPL is performed from the .ins file named 'nnnn', and\n" "SCLP disk I/O is enabled for the directory path where the .ins file is located.\n" "An optional 'parm' keyword followed by a string can also be passed to the IPL\n" "command processor. The string will be loaded into the low-order 32 bits of the\n" "general purpose registers (4 characters per register for up to 64 bytes).\n" "The PARM option behaves similarly to the VM IPL command.\n" ) COMMAND ( "iplc", PANEL, iplc_cmd, "IPL Clear from device xxxx", "Performs the Load Clear manual control function. See \"ipl\".\n" ) COMMAND ( "sysreset", PANEL, sysr_cmd, "issue SYSTEM Reset manual operation", "Performs the System Reset manual control function. A CPU and I/O\n" "subsystem reset are performed.\n" ) COMMAND ( "sysclear", PANEL, sysc_cmd, "issue SYSTEM Clear Reset manual operation", "Performs the System Reset Clear manual control function. Same as\n" "the \"sysreset\" command but also clears main storage to 0. Also, registers\n" "control registers, etc.. are reset to their initial value. At this\n" "point, the system is essentially in the same state as it was just after\n" "having been started\n" ) COMMAND ( "store", PANEL, store_cmd, "store CPU status at absolute zero\n", NULL ) COMMAND ( "sclproot", CONFIG+PANEL, sclproot_cmd, "set SCLP base directory", "Format: \"sclproot [path|NONE]\"\n" "Enables SCLP disk I/O for the specified directory path, or disables SCLP disk\n" "I/O if NONE is specified. A subsequent list-directed IPL resets the path to\n" "the location of the .ins file, and a CCW-type IPL disables SCLP disk I/O.\n" "If no operand is specified, sclproot displays the current setting.\n") #if defined(OPTION_HTTP_SERVER) COMMAND ( "httproot", CONFIG, httproot_cmd, "Set HTTP server root directory", NULL ) COMMAND ( "httpport", CONFIG, httpport_cmd, "Set HTTP server port\n", NULL ) #if defined( HTTP_SERVER_CONNECT_KLUDGE ) COMMAND ( "HTTP_SERVER_CONNECT_KLUDGE", CONFIG, httpskm_cmd, "HTTP_SERVER_CONNECT_KLUDGE", NULL ) #endif // defined( HTTP_SERVER_CONNECT_KLUDGE ) #endif /*defined(OPTION_HTTP_SERVER)*/ COMMAND ( "psw", PANEL, psw_cmd, "display or alter program status word", "Format: \"psw [operand ...]\" where 'operand ...' is one or more optional\n" "parameters which modify the contents of the Program Status Word:\n\n" " sm=xx system mask (2 hex digits)\n" " pk=n protection key (decimal 0 to 15)\n" " cmwp=x C/M/W/P bits (one hex digit)\n" " as=pri|sec|ar|home address-space\n" " cc=n condition code (decimal 0 to 3)\n" " pm=x program mask (one hex digit)\n" " am=24|31|64 addressing mode\n" " ia=xxx instruction address (1 to 16 hex digits)\n\n" "Enter \"psw\" by itself to display the current PSW without altering it.\n" ) COMMAND ( "gpr", PANEL, gpr_cmd, "display or alter general purpose registers", "Format: \"gpr [nn=xxxxxxxxxxxxxxxx]\" where 'nn' is the optional register\n" "number (0 to 15) and 'xxxxxxxxxxxxxxxx' is the register value in hexadecimal\n" "(1-8 hex digits for 32-bit registers or 1-16 hex digits for 64-bit registers).\n" "Enter \"gpr\" by itself to display the register values without altering them.\n" ) COMMAND ( "fpr", PANEL, fpr_cmd, "display floating point registers", NULL ) COMMAND ( "fpc", PANEL, fpc_cmd, "display floating point control register", NULL ) COMMAND ( "cr", PANEL, cr_cmd, "display or alter control registers", "Format: \"cr [nn=xxxxxxxxxxxxxxxx]\" where 'nn' is the optional control register\n" "number (0 to 15) and 'xxxxxxxxxxxxxxxx' is the control register value in hex\n" "(1-8 hex digits for 32-bit registers or 1-16 hex digits for 64-bit registers).\n" "Enter \"cr\" by itself to display the control registers without altering them.\n" ) COMMAND ( "ar", PANEL, ar_cmd, "display access registers", NULL ) COMMAND ( "pr", PANEL, pr_cmd, "display prefix register", NULL ) COMMAND ( "timerint", PANEL+CONFIG, timerint_cmd,"display or set timers update interval", NULL ) COMMAND ( "clocks", PANEL, clocks_cmd, "display tod clkc and cpu timer", NULL ) COMMAND ( "ipending", PANEL, ipending_cmd, "display pending interrupts", NULL ) COMMAND ( "ds", PANEL, ds_cmd, "display subchannel", NULL ) COMMAND ( "r", PANEL, r_cmd, "display or alter real storage", "Format: \"r addr[.len]\" or \"r addr-addr\" to display real\n" "storage, or \"r addr=value\" to alter real storage, where 'value'\n" "is a hex string of up to 32 pairs of digits.\n" ) COMMAND ( "v", PANEL, v_cmd, "display or alter virtual storage", "Format: \"v [P|S|H] addr[.len]\" or \"v [P|S|H] addr-addr\" to display virtual\n" "storage, or \"v [P|S|H] addr=value\" to alter virtual storage, where 'value'\n" "is a hex string of up to 32 pairs of digits. The optional 'P' or 'S' or 'H'\n" "will force Primary, Secondary, or Home translation instead of current PSW mode.\n" ) COMMAND ( "u", PANEL, u_cmd, "disassemble storage", NULL ) COMMAND ( "devtmax", PANEL+CONFIG, devtmax_cmd, "display or set max device threads", NULL ) COMMAND ( "k", PANEL, k_cmd, "display cckd internal trace\n", NULL ) COMMAND ( "attach", PANEL, attach_cmd, "configure device", "Format: \"attach devn type [arg...]\n" ) COMMAND ( "detach", PANEL, detach_cmd, "remove device", NULL ) COMMAND ( "define", PANEL, define_cmd, "rename device", "Format: \"define olddevn newdevn\"\n" ) COMMAND ( "devinit", PANEL, devinit_cmd, "reinitialize device", "Format: \"devinit devn [arg...]\"\n" "If no arguments are given then the same arguments are used\n" "as were used the last time the device was created/initialized.\n" ) COMMAND ( "devlist", PANEL, devlist_cmd, "list device or all devices\n", NULL ) COMMAND ( "qd", PANEL, qd_cmd, "query dasd\n", NULL ) COMMAND ( "mounted_tape_reinit", PANEL+CONFIG, mnttapri_cmd, "Control tape initilisation", NULL ) #if defined( OPTION_TAPE_AUTOMOUNT ) COMMAND ( "automount", PANEL+CONFIG, automount_cmd, "Show/Update allowable tape automount directories\n", "Format: \"automount { add | del | list }\"\n" "\n" "Adds or deletes entries from the list of allowable/unallowable tape\n" "automount directories, or lists all currently defined list entries,\n" "if any.\n" "\n" "The format of the directory operand for add/del operations is\n" "identical to that as described in the documentation for the AUTOMOUNT\n" "configuration file statement (i.e. prefix with '+' or '-' as needed).\n" "\n" "The automount feature is appropriately enabled or disabled for all tape\n" "devices as needed depending on the updated empty/non-empty list state.\n" ) #endif /* OPTION_TAPE_AUTOMOUNT */ #if defined( OPTION_SCSI_TAPE ) COMMAND ( "auto_scsi_mount", PANEL+CONFIG, ascsimnt_cmd, "Control SCSI tape mount", NULL ) COMMAND ( "scsimount", PANEL, scsimount_cmd, "automatic SCSI tape mounts\n", "Format: \"scsimount [ no | yes | 0-99 ]\".\n" "\n" "Displays or modifies the automatic SCSI tape mounts option.\n\n" "When entered without any operands, it displays the current interval\n" "and any pending tape mount requests. Entering 'no' (or 0 seconds)\n" "disables automount detection.\n" "\n" "Entering a value between 1-99 seconds (or 'yes') enables the option\n" "and specifies how often to query SCSI tape drives to automatically\n" "detect when a tape has been mounted (upon which an unsolicited\n" "device-attention interrupt will be presented to the guest operating\n" "system). 'yes' is equivalent to specifying a 5 second interval.\n" ) #endif /* defined( OPTION_SCSI_TAPE ) */ COMMAND ( "cd", PANEL, cd_cmd, "change directory", NULL ) COMMAND ( "pwd", PANEL, pwd_cmd, "print working directory", NULL ) COMMAND ( "sh", PANEL, sh_cmd, "shell command\n", "Format: \"sh command [args...]\" where 'command' is any valid shell\n" "command. The entered command and any arguments are passed as-is to the\n" "shell for processing and the results are displayed on the console.\n" ) COMMAND ( "cache", PANEL, EXT_CMD(cache_cmd), "cache command", NULL ) COMMAND ( "cckd", PANEL+CONFIG, cckd_cmd, "cckd command", NULL ) COMMAND ( "shrd", PANEL, EXT_CMD(shared_cmd), "shrd command", NULL ) COMMAND ( "conkpalv", PANEL+CONFIG, conkpalv_cmd, "Display/alter console TCP keep-alive settings", "Format: \"conkpalv (idle,intv,count)\" where 'idle', 'intv' and 'count' are the\n" "new values for the TCP keep-alive settings for console connections:\n" "- send probe when connection goes idle for 'idle' seconds\n" "- wait maximum of 'intv' seconds for a response to probe\n" "- disconnect after 'count' consecutive failed probes\n" "The format must be exactly as shown, with each value separated from the next by\n" "a single comma, no intervening spaces between them, surrounded by parenthesis.\n" "The command \"conkpalv\" without any operand displays the current values.\n" ) COMMAND ( "quiet", PANEL, quiet_cmd, "Toggle automatic refresh of panel display data\n", "'quiet' either disables automatic screen refreshing if it is\n" "currently enabled or enables it if it is currently disabled.\n" "When disabled you will no be able to see the response of any\n" "entered commands nor any messages issued by the system nor be\n" "able to scroll the display, etc. Basically all screen updating\n" "is disabled. Entering 'quiet' again re-enables screen updating.\n" ) COMMAND ( "t", PANEL, trace_cmd, "instruction trace", "Format: \"t addr-addr\" or \"t addr:addr\" or \"t addr.length\"\n" "sets the instruction tracing range (which is totally separate from\n" "the instruction stepping and breaking range).\n" "With or without a range, the t command displays whether instruction\n" "tracing is on or off and the range if any.\n" "The t command by itself does not activate instruction tracing.\n" "Use the t+ command to activate instruction tracing.\n" "\"t 0\" eliminates the range (all addresses will be traced).\n" ) COMMAND ( "t+", PANEL, trace_cmd, "instruction trace on", "Format: \"t+\" turns on instruction tracing. A range can be specified\n" "as for the \"t\" command, otherwise the existing range is used. If there\n" "is no range (or range was specified as 0) then all instructions will be\n" "traced.\n" ) COMMAND ( "t-", PANEL, trace_cmd, "instruction trace off", "Format: \"t-\" turns off instruction tracing.\n" ) COMMAND ( "t?", PANEL, trace_cmd, "instruction trace query", "Format: \"t?\" displays whether instruction tracing is on or off\n" "and the range if any.\n" ) COMMAND ( "s", PANEL, trace_cmd, "instruction stepping", "Format: \"s addr-addr\" or \"s addr:addr\" or \"s addr.length\"\n" "sets the instruction stepping and instruction breaking range,\n" "(which is totally separate from the instruction tracing range).\n" "With or without a range, the s command displays whether instruction\n" "stepping is on or off and the range if any.\n" "The s command by itself does not activate instruction stepping.\n" "Use the s+ command to activate instruction stepping.\n" "\"s 0\" eliminates the range (all addresses will be stepped).\n" ) COMMAND ( "s+", PANEL, trace_cmd, "instruction stepping on", "Format: \"s+\" turns on instruction stepping. A range can be specified\n" "as for the \"s\" command, otherwise the existing range is used. If there\n" "is no range (or range was specified as 0) then the range includes all\n" "addresses. When an instruction within the range is about to be executed,\n" "the CPU is temporarily stopped and the next instruction is displayed.\n" "You may then examine registers and/or storage, etc, before pressing Enter\n" "to execute the instruction and stop at the next instruction. To turn\n" "off instruction stepping and continue execution, enter the \"g\" command.\n" ) COMMAND ( "s-", PANEL, trace_cmd, "instruction stepping off", "Format: \"s-\" turns off instruction stepping.\n" ) COMMAND ( "s?", PANEL, trace_cmd, "instruction stepping query", "Format: \"s?\" displays whether instruction stepping is on or off\n" "and the range if any.\n" ) COMMAND ( "b", PANEL, trace_cmd, "set breakpoint", "Format: \"b addr\" or \"b addr-addr\" where 'addr' is the instruction\n" "address or range of addresses where you wish to halt execution. This\n" "command is synonymous with the \"s+\" command.\n" ) COMMAND ( "b+", PANEL, trace_cmd, "set breakpoint", NULL ) COMMAND ( "b-", PANEL, trace_cmd, "delete breakpoint", "Format: \"b-\" This command is the same as \"s-\"\n" ) COMMAND ( "g", PANEL, g_cmd, "turn off instruction stepping and start all CPUs\n", NULL ) COMMAND ( "ostailor", PANEL+CONFIG, ostailor_cmd, "trace program interrupts", "Format: \"ostailor quiet | os/390 | z/os | vm | vse | linux | null\". Specifies\n" "the intended operating system. The effect is to reduce control panel message\n" "traffic by selectively suppressing program check trace messages which are\n" "considered normal in the specified environment. 'quiet' suppresses all\n" "exception messages, whereas 'null' suppresses none of them. The other options\n" "suppress some messages and not others depending on the specified o/s. Prefix\n" "values with '+' to combine them with existing values or '-' to exclude them.\n" "SEE ALSO the 'pgmtrace' command which allows you to further fine tune\n" "the tracing of program interrupt exceptions.\n" ) COMMAND ( "pgmtrace", PANEL, pgmtrace_cmd, "trace program interrupts", "Format: \"pgmtrace [-]intcode\" where 'intcode' is any valid program\n" "interruption code in the range 0x01 to 0x40. Precede the interrupt code\n" "with a '-' to stop tracing of that particular program interruption.\n" ) COMMAND ( "savecore", PANEL, savecore_cmd, "save a core image to file", "Format: \"savecore filename [{start|*}] [{end|*}]\" where 'start' and 'end'\n" "define the starting and ending addresss of the range of real storage to be\n" "saved to file 'filename'. '*' for either the start address or end address\n" "(the default) means: \"the first/last byte of the first/last modified page\n" "as determined by the storage-key 'changed' bit\".\n" ) COMMAND ( "loadcore", PANEL, loadcore_cmd, "load a core image file", "Format: \"loadcore filename [address]\" where 'address' is the storage address\n" "of where to begin loading memory. The file 'filename' is presumed to be a pure\n" "binary image file previously created via the 'savecore' command. The default for\n" "'address' is 0 (begining of storage).\n" ) COMMAND ( "loadtext", PANEL, loadtext_cmd, "load a text deck file\n", "Format: \"loadtext filename [address]\". This command is essentially identical\n" "to the 'loadcore' command except that it loads a text deck file with \"TXT\"\n" "and \"END\" 80 byte records (i.e. an object deck).\n" ) #if defined(OPTION_DYNAMIC_LOAD) COMMAND ( "modpath", CONFIG, modpath_cmd, "set module load path", NULL ) COMMAND ( "ldmod", CONFIG+PANEL, ldmod_cmd, "load a module", NULL ) COMMAND ( "rmmod", PANEL, rmmod_cmd, "delete a module", NULL ) COMMAND ( "lsmod", PANEL, lsmod_cmd, "list dynamic modules", NULL ) COMMAND ( "lsdep", PANEL, lsdep_cmd, "list module dependencies\n", NULL ) #endif /*defined(OPTION_DYNAMIC_LOAD)*/ #ifdef OPTION_IODELAY_KLUDGE COMMAND ( "iodelay", PANEL+CONFIG, iodelay_cmd, "display or set I/O delay value", NULL ) #endif COMMAND ( "ctc", PANEL, ctc_cmd, "Enable/Disable CTC debugging", "Format: \"ctc debug { on | off } [ | ALL ]\".\n\n" "Enables/disables debug packet tracing for the specified CTCI/LCS\n" "device group(s) identified by or for all CTCI/LCS device\n" "groups if is not specified or specified as 'ALL'.\n" ) #if defined(OPTION_W32_CTCI) COMMAND ( "tt32", PANEL, tt32_cmd, "control/query CTCI-W32 functionality", "Format: \"tt32 debug | nodebug | stats \".\n" "\n" "Enables or disables global CTCI-W32 debug tracing\n" "or displays TunTap32 stats for the specified CTC device.\n" ) #endif COMMAND ( "toddrag", PANEL+CONFIG, toddrag_cmd, "display or set TOD clock drag factor", NULL ) #ifdef PANEL_REFRESH_RATE COMMAND ( "panrate", PANEL+CONFIG, panrate_cmd, "Display or set rate at which console refreshes", "Format: \"panrate [nnn | fast | slow]\". Sets or displays the panel refresh rate.\n" "panrate nnn sets the refresh rate to nnn milliseconds.\n" "panrate fast sets the refresh rate to " MSTRING(PANEL_REFRESH_RATE_FAST) " milliseconds.\n" "panrate slow sets the refresh rate to " MSTRING(PANEL_REFRESH_RATE_SLOW) " milliseconds.\n" "If no operand is specified, panrate displays the current refresh rate.\n") #endif COMMAND ( "pantitle", CONFIG, pantitle_cmd, "display or set console title", NULL ) #ifdef OPTION_MSGHLD COMMAND ( "msghld", PANEL, msghld_cmd, "Display or set the timeout of held messages", "Format: \"msghld [value | info | clear]\".\n" "value: timeout value of held message in seconds\n" "info: displays the timeout value\n" "clear: releases the held messages\n" ) #endif COMMAND ( "syncio", PANEL, syncio_cmd, "display syncio devices statistics", NULL ) #if defined(OPTION_INSTRUCTION_COUNTING) COMMAND ( "icount", PANEL, icount_cmd, "display individual instruction counts", NULL ) #endif #ifdef OPTION_MIPS_COUNTING COMMAND ( "maxrates", PANEL, maxrates_cmd, "display maximum observed MIPS/SIOS rate for the\n" " defined interval or define a new reporting interval\n", "Format: \"maxrates [nnnn]\" where 'nnnn' is the desired reporting\n" "interval in minutes. Acceptable values are from 1 to 1440. The default\n" "is 1440 minutes (one day). Entering \"maxrates\" by itself displays\n" "the current highest rates observed during the defined intervals.\n" ) #endif // OPTION_MIPS_COUNTING #if defined(_FEATURE_ASN_AND_LX_REUSE) COMMAND ( "asn_and_lx_reuse", CONFIG, alrf_cmd, "Enable/Disable ASN and LX reuse facility", NULL ) COMMAND ( "alrf" , CONFIG, alrf_cmd, "Alias for asn_and_lx_reuse\n", NULL ) #endif /* defined(_FEATURE_ASN_AND_LX_REUSE) */ #if defined(OPTION_CONFIG_SYMBOLS) COMMAND ( "defsym", PANEL+CONFIG, defsym_cmd, "Define symbol", "Format: \"defsym symbol [value]\". Defines symbol 'symbol' to contain value 'value'.\n" "The symbol can then be the object of a substitution for later panel commands.\n" "If 'value' contains blanks or spaces, then it must be enclosed within quotes\n" "or apostrophes. For more detailed information regarding symbol substitution\n" "refer to the 'DEFSYM' configuration file statement in Hercules documentation.\n" "Enter \"defsym\" by itself to display the values of all defined symbols.\n" ) #endif COMMAND ( "script", PANEL, script_cmd, "Run a sequence of panel commands contained in a file", "Format: \"script filename [...filename...]\". Sequentially executes the commands contained\n" "within the file -filename-. The script file may also contain \"script\" commands,\n" "but the system ensures that no more than 10 levels of script are invoked at any\n" "one time (to avoid a recursion loop)\n" ) COMMAND ( "cscript", PANEL, cscript_cmd, "Cancels a running script thread\n", "Format: \"cscript\". This command will cancel the currently running script.\n" "if no script is running, no action is taken\n" ) #if defined(FEATURE_ECPSVM) COMMAND ( "evm", PANEL, evm_cmd_1, "ECPS:VM Commands (Deprecated)", "Format: \"evm\". This command is deprecated.\n" "use \"ecpsvm\" instead\n" ) COMMAND ( "ecpsvm", PANEL, evm_cmd, "ECPS:VM Commands\n", "Format: \"ecpsvm\". This command invokes ECPS:VM Subcommands.\n" "Type \"ecpsvm help\" to see a list of available commands\n" ) #endif COMMAND ( "aea", PANEL, aea_cmd, "Display AEA tables", NULL ) COMMAND ( "aia", PANEL, aia_cmd, "Display AIA fields", NULL ) COMMAND ( "tlb", PANEL, tlb_cmd, "Display TLB tables\n", NULL ) #if defined(SIE_DEBUG_PERFMON) COMMAND ( "spm", PANEL, spm_cmd, "SIE performance monitor\n", NULL ) #endif #if defined(OPTION_COUNTING) COMMAND ( "count", PANEL, count_cmd, "Display/clear overall instruction count\n", NULL ) #endif COMMAND ( "sizeof", PANEL, sizeof_cmd, "Display size of structures\n", NULL ) COMMAND ( "suspend", PANEL, suspend_cmd, "Suspend hercules", NULL ) COMMAND ( "resume", PANEL, resume_cmd, "Resume hercules\n", NULL ) COMMAND ( "herclogo", PANEL, herclogo_cmd, "Read a new hercules logo file\n", "Format: \"herclogo []\". Load a new logo file for 3270 terminal sessions\n" "If no filename is specified, the built-in logo is used instead\n" ) COMMAND ( "traceopt", CONFIG+PANEL, traceopt_cmd, "Instruction trace display options\n", "Format: \"traceopt [regsfirst | noregs | traditional]\". Determines how the\n" "registers are displayed during instruction tracing and stepping. Entering\n" "the command without any argument simply displays the current mode.\n" ) COMMAND ( "symptom", CONFIG, traceopt_cmd, "Alias for traceopt\n", NULL ) COMMAND ( "$zapcmd", CONFIG, zapcmd_cmd, NULL, NULL ) // enable/disable commands and config statements COMMAND ( "$test", DISABLED, test_cmd, NULL, NULL ) // enable in config with: $zapcmd $test cmd #ifdef OPTION_CMDTGT COMMAND ( "cmdtgt", PANEL, cmdtgt_cmd, "Specify the command target", "Format: \"cmdtgt [herc | scp | pscp | ?]\". Specify the command target.\n" ) COMMAND ( "herc", PANEL, herc_cmd, "Hercules command", "Format: \"herc [cmd]\". Send hercules cmd in any cmdtgt mode.\n" ) COMMAND ( "scp", PANEL, scp_cmd, "Send scp command", "Format: \"scp [cmd]\". Send scp cmd in any cmdtgt mode.\n" ) COMMAND ( "pscp", PANEL, prioscp_cmd, "Send prio message scp command\n", "Format: \"pscp [cmd]\". Send priority message cmd to scp in any cmdtgt mode.\n" ) #endif // OPTION_CMDTGT // The actual command table ends here, the next entries are just for help // as the associated command are processed as part of commandline parsing // and there are no forward references to be created #if !defined(_FW_REF) COMMAND ( "sf+dev", PANEL, NULL, "add shadow file", NULL ) COMMAND ( "sf-dev", PANEL, NULL, "delete shadow file", NULL ) COMMAND ( "sfc", PANEL, NULL, "compress shadow files", NULL ) COMMAND ( "sfk", PANEL, NULL, "Check shadow files", "Format: \"sfk{*|xxxx} [n]\". Performs a chkdsk on the active shadow file\n" "where xxxx is the device number (*=all cckd devices)\n" "and n is the optional check level (default is 2):\n" " -1 devhdr, cdevhdr, l1 table\n" " 0 devhdr, cdevhdr, l1 table, l2 tables\n" " 1 devhdr, cdevhdr, l1 table, l2 tables, free spaces\n" " 2 devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkhdrs\n" " 3 devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkimgs\n" " 4 devhdr, cdevhdr. Build everything else from recovery\n" "You probably don't want to use `4' unless you have a backup and are\n" "prepared to wait a long time.\n" ) COMMAND ( "sfd", PANEL, NULL, "display shadow file stats\n", NULL ) COMMAND ( "t{+/-}dev", PANEL, NULL, "turn CCW tracing on/off", NULL ) COMMAND ( "s{+/-}dev", PANEL, NULL, "turn CCW stepping on/off\n", NULL ) #ifdef OPTION_CKD_KEY_TRACING COMMAND ( "t{+/-}CKD", PANEL, NULL, "turn CKD_KEY tracing on/off\n", NULL ) #endif COMMAND ( "f{+/-}adr", PANEL, NULL, "mark frames unusable/usable\n", NULL ) #endif /*!defined(_FW_REF)*/ hercules-3.12/hdl.h0000664000175000017500000002745612564723224011141 00000000000000/* HDL.H (c) Copyright Jan Jaeger, 2003-2009 */ /* Hercules Dynamic Loader */ #ifndef _HDL_H #define _HDL_H #include "hercules.h" #if !defined(_MSVC_) #define _HDL_UNUSED __attribute__ ((unused)) #else #define _HDL_UNUSED #endif #ifndef _HDL_C_ #ifndef _HUTIL_DLL_ #define HDL_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define HDL_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define HDL_DLL_IMPORT DLL_EXPORT #endif #ifndef _HDLMAIN_C_ #ifndef _HENGINE_DLL_ #define HDM_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define HDM_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define HDM_DLL_IMPORT DLL_EXPORT #endif /*********************************************************************/ #define STRING_M( _string ) #_string #define STRING_Q( _string ) STRING_M( _string ) struct _HDLSHD; typedef struct _HDLSHD { struct _HDLSHD *next; char* shdname; /* identifying name */ void (*shdcall) (void *); /* Entry to be called */ void *shdarg; /* Optional argument */ } HDLSHD; HDL_DLL_IMPORT void hdl_adsc(char*, void *, void *);/* Add shutdown routine */ HDL_DLL_IMPORT int hdl_rmsc(void *, void *); /* Remove shutdown routine */ HDL_DLL_IMPORT void hdl_shut(void); /* Call all shutdown routines*/ DLL_EXPORT DEVHND *hdl_ghnd(const char *devname); /* Get device handler */ /*********************************************************************/ #if !defined(OPTION_DYNAMIC_LOAD) #define HDL_DEVICE_SECTION \ DLL_EXPORT DEVHND *hdl_ghnd(const char *devtype) \ { #define HDL_DEVICE( _devname, _devhnd ) \ if(!strcasecmp( STRING_Q(_devname), devtype )) \ return &(_devhnd); #define END_DEVICE_SECTION \ return NULL; \ } #else /* defined(OPTION_DYNAMIC_LOAD) */ /*********************************************************************/ #if !defined(HDL_USE_LIBTOOL) #define dlinit() #else #define dlinit() lt_dlinit() #define dlopen(_name, _flags) lt_dlopen(_name) #define dlsym(_handle, _symbol) lt_dlsym(_handle, _symbol) #define dlclose(_handle) lt_dlclose(_handle) #define dlerror() lt_dlerror() #define RTLD_NOW 0 #endif // extern char *(*hdl_device_type_equates)(char *); typedef struct _HDLDEV { /* Device entry */ char *name; /* Device type name */ DEVHND *hnd; /* Device handlers */ struct _HDLDEV *next; /* Next entry */ } HDLDEV; typedef struct _HDLINS { /* Instruction entry */ int opcode; /* Opcode */ int archflags; /* Architecture flags */ char *instname; /* Instruction name */ void *instruction; /* Instruction routine */ void *original; /* Original instruction */ struct _HDLINS *next; /* Next entry */ } HDLINS; struct _HDLDEP; typedef struct _HDLDEP { /* Dependency entry */ char *name; /* Dependency name */ char *version; /* Version */ int size; /* Structure/module size */ struct _HDLDEP *next; /* Next entry */ } HDLDEP; typedef struct _HDLPRE { /* Preload list entry */ char *name; /* Module name */ int flag; /* Load flags */ } HDLPRE; struct _MODENT; typedef struct _MODENT { /* External Symbol entry */ void (*fep)(); /* Function entry point */ char *name; /* Function symbol name */ int count; /* Symbol load count */ struct _MODENT *modnext; /* Next entry in chain */ } MODENT; struct _DLLENT; typedef struct _DLLENT { /* DLL entry */ char *name; /* load module name */ void *dll; /* DLL handle (dlopen) */ int flags; /* load flags */ int (*hdldepc)(void *); /* hdl_depc */ int (*hdlreso)(void *); /* hdl_reso */ int (*hdlinit)(void *); /* hdl_init */ int (*hdlddev)(void *); /* hdl_ddev */ int (*hdldins)(void *); /* hdl_dins */ int (*hdlfini)(); /* hdl_fini */ struct _MODENT *modent; /* First symbol entry */ struct _HDLDEV *hndent; /* First device entry */ struct _HDLINS *insent; /* First instruction entry */ struct _DLLENT *dllnext; /* Next entry in chain */ } DLLENT; #if defined(MODULESDIR) #define HDL_DEFAULT_PATH MODULESDIR #else #define HDL_DEFAULT_PATH "hercules" #endif /* SHLIBEXT defined by ISW in configure.ac/config.h */ #if defined( HDL_BUILD_SHARED ) && defined( LTDL_SHLIB_EXT ) #define HDL_MODULE_SUFFIX LTDL_SHLIB_EXT #else #if defined(LT_MODULE_EXT) #define HDL_MODULE_SUFFIX LT_MODULE_EXT #elif defined(_MSVC_) #define HDL_MODULE_SUFFIX ".dll" #else #define HDL_MODULE_SUFFIX ".la" #endif #endif #if defined( HDL_MODULE_SUFFIX ) #define HDL_SUFFIX_LENGTH (sizeof(HDL_MODULE_SUFFIX) - 1) #else #define HDL_SUFFIX_LENGTH 0 #endif DLL_EXPORT int hdl_load(char *, int); /* load dll */ #define HDL_LOAD_DEFAULT 0x00000000 #define HDL_LOAD_MAIN 0x00000001 /* Hercules MAIN module flag */ #define HDL_LOAD_NOUNLOAD 0x00000002 /* Module cannot be unloaded */ #define HDL_LOAD_FORCE 0x00000004 /* Override dependency check */ #define HDL_LOAD_NOMSG 0x00000008 /* Do not issue not found msg*/ #define HDL_LOAD_WAS_FORCED 0x00000010 /* Module load was forced */ #define HDL_INSTARCH_370 0x00000001 #define HDL_INSTARCH_390 0x00000002 #define HDL_INSTARCH_900 0x00000004 #define HDL_INSTARCH_ALL (HDL_INSTARCH_370|HDL_INSTARCH_390|HDL_INSTARCH_900) DLL_EXPORT int hdl_dele(char *); /* Unload dll */ DLL_EXPORT void hdl_list(int); /* list all loaded modules */ #define HDL_LIST_DEFAULT 0x00000000 #define HDL_LIST_ALL 0x00000001 /* list all references */ DLL_EXPORT void hdl_dlst(); /* list all dependencies */ DLL_EXPORT void hdl_main(); /* Main initialization rtn */ DLL_EXPORT void hdl_setpath(char *); /* Set module path */ DLL_EXPORT void * hdl_fent(char *); /* Find entry name */ DLL_EXPORT void * hdl_nent(void *); /* Find next in chain */ /* The following statement should be void *(*unresolved)(void) = NULL*/ static void **unresolved _HDL_UNUSED = NULL; #define UNRESOLVED *unresolved #define HDL_DEPC hdl_depc #define HDL_RESO hdl_reso #define HDL_INIT hdl_init #define HDL_FINI hdl_fini #define HDL_DDEV hdl_ddev #define HDL_DINS hdl_dins #define HDL_HDTP hdt #define HDL_DEPC_Q STRING_Q(HDL_DEPC) #define HDL_RESO_Q STRING_Q(HDL_RESO) #define HDL_INIT_Q STRING_Q(HDL_INIT) #define HDL_FINI_Q STRING_Q(HDL_FINI) #define HDL_DDEV_Q STRING_Q(HDL_DDEV) #define HDL_DINS_Q STRING_Q(HDL_DINS) #define HDL_HDTP_Q STRING_Q(HDL_HDTP) #define HDL_FINDSYM(_name) \ hdl_fent( (_name) ) #define HDL_FINDNXT(_ep) \ hdl_nent( &(_ep) ) #define HDL_DEPENDENCY_SECTION \ DLL_EXPORT int HDL_DEPC(int (*hdl_depc_vers)(char *, char *, int) _HDL_UNUSED ) \ { \ int hdl_depc_rc = 0 #define HDL_DEPENDENCY(_comp) \ if (hdl_depc_vers( STRING_Q(_comp), HDL_VERS_ ## _comp, HDL_SIZE_ ## _comp)) \ hdl_depc_rc = 1 #define END_DEPENDENCY_SECTION \ return hdl_depc_rc; } #define HDL_REGISTER_SECTION \ DLL_EXPORT void HDL_INIT(int (*hdl_init_regi)(char *, void *) _HDL_UNUSED ) \ { /* register this epname, as ep = addr of this var or func... */ #define HDL_REGISTER( _epname, _varname ) \ (hdl_init_regi)( STRING_Q(_epname), &(_varname) ) #define END_REGISTER_SECTION \ } #define HDL_DEVICE_SECTION \ DLL_EXPORT void HDL_DDEV(int (*hdl_init_ddev)(char *, void *) _HDL_UNUSED ) \ { #define HDL_DEVICE( _devname, _devhnd ) \ (hdl_init_ddev)( STRING_Q(_devname), &(_devhnd) ) #define END_DEVICE_SECTION \ } #define HDL_INSTRUCTION_SECTION \ DLL_EXPORT void HDL_DINS(int (*hdl_init_dins)(int, int, void *, void *) _HDL_UNUSED ) \ { #if defined(_370) #define HDL_370_DEFINST( _arch, _opcode, _instruction) \ do { \ if( (_arch) & HDL_INSTARCH_370 ) \ (hdl_init_dins)( _arch, _opcode, STRING_Q(_instruction), &(s370_ ## _instruction) ); \ } while(0) #else #define HDL_370_DEFINST( _arch, _opcode, _instruction) #endif #if defined(_390) #define HDL_390_DEFINST( _arch, _opcode, _instruction) \ do { \ if( (_arch) & HDL_INSTARCH_390 ) \ (hdl_init_dins)( _arch, _opcode, STRING_Q(_instruction), &(s390_ ## _instruction) ); \ } while(0) #else #define HDL_390_DEFINST( _arch, _opcode, _instruction) #endif #if defined(_900) #define HDL_900_DEFINST( _arch, _opcode, _instruction) \ do { \ if( (_arch) & HDL_INSTARCH_900 ) \ (hdl_init_dins)( _arch, _opcode, STRING_Q(_instruction), &(z900_ ## _instruction) ); \ } while(0) #else #define HDL_900_DEFINST( _arch, _opcode, _instruction) #endif #define HDL_DEFINST( _arch, _opcode, _instruction ) \ do { \ HDL_370_DEFINST(( (_arch) & HDL_INSTARCH_370), _opcode, _instruction); \ HDL_390_DEFINST(( (_arch) & HDL_INSTARCH_390), _opcode, _instruction); \ HDL_900_DEFINST(( (_arch) & HDL_INSTARCH_900), _opcode, _instruction); \ } while(0) #define END_INSTRUCTION_SECTION \ } #define HDL_RESOLVER_SECTION \ DLL_EXPORT void HDL_RESO(void *(*hdl_reso_fent)(char *) _HDL_UNUSED ) \ { #define HDL_RESOLVE(_name) \ (_name) = (hdl_reso_fent)(STRING_Q(_name)) /* set this ptrvar, to this ep value... */ #define HDL_RESOLVE_PTRVAR( _ptrvar, _epname ) \ (_ptrvar) = (hdl_reso_fent)( STRING_Q(_epname) ) #define END_RESOLVER_SECTION \ } #define HDL_FINAL_SECTION \ DLL_EXPORT int HDL_FINI() \ { #define END_FINAL_SECTION \ return 0; } #endif /* defined(OPTION_DYNAMIC_LOAD) */ /*********************************************************************/ #endif /* _HDL_H */ hercules-3.12/crypto.h0000664000175000017500000000303112564723224011671 00000000000000/* CRYPTO.H (c) Copyright Jan Jaeger, 2000-2009 */ /* Cryptographic instructions */ #if defined(_FEATURE_MESSAGE_SECURITY_ASSIST) #ifndef _CRYPTO_C_ #ifndef _HENGINE_DLL_ #define CRY_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define CRY_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define CRY_DLL_IMPORT DLL_EXPORT #endif CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(cipher_message ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(cipher_message_with_chaining ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(cipher_message_with_cipher_feedback ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(cipher_message_with_counter ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(cipher_message_with_output_feedback ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(compute_intermediate_message_digest ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(compute_last_message_digest ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(compute_message_authentication_code ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(perform_cryptographic_computation ))(BYTE*, REGS*); CRY_DLL_IMPORT void (ATTR_REGPARM(2) *ARCH_DEP(perform_cryptographic_key_management_operation))(BYTE*, REGS*); #endif /*defined(_FEATURE_MESSAGE_SECURITY_ASSIST)*/ hercules-3.12/sockdev.h0000664000175000017500000000463212564723224012017 00000000000000/* SOCKDEV.H (c) Copyright Malcolm Beattie, 2001 */ /* Hercules socket device header file */ #include "htypes.h" #ifndef _SOCKDEV_H_ #define _SOCKDEV_H_ /*-------------------------------------------------------------------*/ /* The sockdev callback function is an optional callback function */ /* that the sockdev connection handler calls after the connection */ /* has been established but before it has logged the connection to */ /* the console. The boolean return code from the callback indicates */ /* true or false (!0 or 0) whether the connection should be accepted */ /* or not. If the return from the callback is 0 (false), the socket */ /* is immediately closed and the "connection not accepted" message */ /* is logged to the console. You should NOT perform any significant */ /* processing in your callback. If you need to do any significant */ /* processing you should instead create a worker to perform it in. */ /*-------------------------------------------------------------------*/ typedef int (*ONCONNECT)( DEVBLK* ); // onconnect callback function (opt) /*-------------------------------------------------------------------*/ /* Bind structure for "Socket Devices" */ /*-------------------------------------------------------------------*/ struct bind_struct // Bind structure for "Socket Devices" { LIST_ENTRY bind_link; // (just a link in the chain) DEVBLK *dev; // ptr to corresponding device block char *spec; // socket_spec for listening socket int sd; // listening socket to use in select // NOTE: Following 2 fields malloc'ed. char *clientname; // connected client's hostname char *clientip; // conencted client's ip address ONCONNECT fn; // ptr to onconnect callback func (opt) void *arg; // argument for callback function (opt) }; /* "Socket Device" functions */ extern int bind_device_ex (DEVBLK* dev, char* spec, ONCONNECT fn, void* arg ); extern int unbind_device_ex (DEVBLK* dev, int forced); static inline int bind_device (DEVBLK* dev, char* spec) { return bind_device_ex ( dev, spec, NULL, NULL ); } static inline int unbind_device (DEVBLK* dev) { return unbind_device_ex ( dev, 0 ); } #endif // _SOCKDEV_H_ hercules-3.12/ltdl.h0000664000175000017500000003061712564723224011322 00000000000000/* ltdl.h -- generic dlopen functions Copyright (C) 1998-2000 Free Software Foundation, Inc. Originally by Thomas Tanner This file is part of GNU Libtool. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. As a special exception to the GNU Lesser General Public License, if you distribute this file as part of a program or library that is built using GNU libtool, you may include it under the same distribution terms that you use for the rest of that program. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Only include this header file once. */ #ifndef LTDL_H #define LTDL_H 1 #include /* for size_t declaration */ /* --- MACROS FOR PORTABILITY --- */ /* Saves on those hard to debug '\0' typos.... */ #define LT_EOS_CHAR '\0' /* LTDL_BEGIN_C_DECLS should be used at the beginning of your declarations, so that C++ compilers don't mangle their names. Use LTDL_END_C_DECLS at the end of C declarations. */ #ifdef __cplusplus # define LT_BEGIN_C_DECLS extern "C" { # define LT_END_C_DECLS } #else # define LT_BEGIN_C_DECLS /* empty */ # define LT_END_C_DECLS /* empty */ #endif LT_BEGIN_C_DECLS /* LT_PARAMS is a macro used to wrap function prototypes, so that compilers that don't understand ANSI C prototypes still work, and ANSI C compilers can issue warnings about type mismatches. */ #if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) || defined(__cplusplus) # define LT_PARAMS(protos) protos # define lt_ptr void* #else # define LT_PARAMS(protos) () # define lt_ptr char* #endif /* LT_STMT_START/END are used to create macros which expand to a a single compound statement in a portable way. */ #if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) # define LT_STMT_START (void)( # define LT_STMT_END ) #else # if (defined (sun) || defined (__sun__)) # define LT_STMT_START if (1) # define LT_STMT_END else (void)0 # else # define LT_STMT_START do # define LT_STMT_END while (0) # endif #endif /* LT_CONC creates a new concatenated symbol for the compiler in a portable way. */ #if defined(__STDC__) || defined(__cplusplus) || defined(_MSC_VER) # define LT_CONC(s,t) s##t #else # define LT_CONC(s,t) s/**/t #endif /* LT_STRLEN can be used safely on NULL pointers. */ #define LT_STRLEN(s) (((s) && (s)[0]) ? strlen (s) : 0) /* --- WINDOWS SUPPORT --- */ /* Canonicalise Windows and Cygwin recognition macros. */ #ifdef __CYGWIN32__ # ifndef __CYGWIN__ # define __CYGWIN__ __CYGWIN32__ # endif #endif #if defined(_WIN32) || defined(WIN32) # ifndef __WINDOWS__ # ifdef _WIN32 # define __WINDOWS__ _WIN32 # else # ifdef WIN32 # define __WINDOWS__ WIN32 # endif # endif # endif #endif #ifdef __WINDOWS__ # ifndef __CYGWIN__ /* LT_DIRSEP_CHAR is accepted *in addition* to '/' as a directory separator when it is set. */ # define LT_DIRSEP_CHAR '\\' # define LT_PATHSEP_CHAR ';' # endif #endif #ifndef LT_PATHSEP_CHAR # define LT_PATHSEP_CHAR ':' #endif /* DLL building support on win32 hosts; mostly to workaround their ridiculous implementation of data symbol exporting. */ #ifndef LT_SCOPE # ifdef __WINDOWS__ # ifdef DLL_EXPORT /* defined by libtool (if required) */ # define LT_SCOPE __declspec(dllexport) # endif # ifdef LIBLTDL_DLL_IMPORT /* define if linking with this dll */ # define LT_SCOPE extern __declspec(dllimport) # endif # endif # ifndef LT_SCOPE /* static linking or !__WINDOWS__ */ # define LT_SCOPE extern # endif #endif #if defined(_MSC_VER) /* Visual Studio */ # define R_OK 4 #endif /* --- DYNAMIC MODULE LOADING API --- */ typedef struct lt_dlhandle_struct *lt_dlhandle; /* A loaded module. */ /* Initialisation and finalisation functions for libltdl. */ LT_SCOPE int lt_dlinit LT_PARAMS((void)); LT_SCOPE int lt_dlexit LT_PARAMS((void)); /* Module search path manipulation. */ LT_SCOPE int lt_dladdsearchdir LT_PARAMS((const char *search_dir)); LT_SCOPE int lt_dlinsertsearchdir LT_PARAMS((const char *before, const char *search_dir)); LT_SCOPE int lt_dlsetsearchpath LT_PARAMS((const char *search_path)); LT_SCOPE const char *lt_dlgetsearchpath LT_PARAMS((void)); LT_SCOPE int lt_dlforeachfile LT_PARAMS(( const char *search_path, int (*func) (const char *filename, lt_ptr data), lt_ptr data)); /* Portable libltdl versions of the system dlopen() API. */ LT_SCOPE lt_dlhandle lt_dlopen LT_PARAMS((const char *filename)); LT_SCOPE lt_dlhandle lt_dlopenext LT_PARAMS((const char *filename)); LT_SCOPE lt_ptr lt_dlsym LT_PARAMS((lt_dlhandle handle, const char *name)); LT_SCOPE const char *lt_dlerror LT_PARAMS((void)); LT_SCOPE int lt_dlclose LT_PARAMS((lt_dlhandle handle)); /* Module residency management. */ LT_SCOPE int lt_dlmakeresident LT_PARAMS((lt_dlhandle handle)); LT_SCOPE int lt_dlisresident LT_PARAMS((lt_dlhandle handle)); /* --- MUTEX LOCKING --- */ typedef void lt_dlmutex_lock LT_PARAMS((void)); typedef void lt_dlmutex_unlock LT_PARAMS((void)); typedef void lt_dlmutex_seterror LT_PARAMS((const char *errmsg)); typedef const char *lt_dlmutex_geterror LT_PARAMS((void)); LT_SCOPE int lt_dlmutex_register LT_PARAMS((lt_dlmutex_lock *lock, lt_dlmutex_unlock *unlock, lt_dlmutex_seterror *seterror, lt_dlmutex_geterror *geterror)); /* --- MEMORY HANDLING --- */ /* By default, the realloc function pointer is set to our internal realloc implementation which iself uses lt_dlmalloc and lt_dlfree. libltdl relies on a featureful realloc, but if you are sure yours has the right semantics then you can assign it directly. Generally, it is safe to assign just a malloc() and a free() function. */ LT_SCOPE lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)); LT_SCOPE lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)); LT_SCOPE void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)); /* --- PRELOADED MODULE SUPPORT --- */ /* A preopened symbol. Arrays of this type comprise the exported symbols for a dlpreopened module. */ typedef struct { const char *name; lt_ptr address; } lt_dlsymlist; LT_SCOPE int lt_dlpreload LT_PARAMS((const lt_dlsymlist *preloaded)); LT_SCOPE int lt_dlpreload_default LT_PARAMS((const lt_dlsymlist *preloaded)); #define LTDL_SET_PRELOADED_SYMBOLS() LT_STMT_START{ \ extern const lt_dlsymlist lt_preloaded_symbols[]; \ lt_dlpreload_default(lt_preloaded_symbols); \ }LT_STMT_END /* --- MODULE INFORMATION --- */ /* Read only information pertaining to a loaded module. */ typedef struct { char *filename; /* file name */ char *name; /* module name */ int ref_count; /* number of times lt_dlopened minus number of times lt_dlclosed. */ } lt_dlinfo; LT_SCOPE const lt_dlinfo *lt_dlgetinfo LT_PARAMS((lt_dlhandle handle)); LT_SCOPE lt_dlhandle lt_dlhandle_next LT_PARAMS((lt_dlhandle place)); LT_SCOPE int lt_dlforeach LT_PARAMS(( int (*func) (lt_dlhandle handle, lt_ptr data), lt_ptr data)); /* Associating user data with loaded modules. */ typedef unsigned lt_dlcaller_id; LT_SCOPE lt_dlcaller_id lt_dlcaller_register LT_PARAMS((void)); LT_SCOPE lt_ptr lt_dlcaller_set_data LT_PARAMS((lt_dlcaller_id key, lt_dlhandle handle, lt_ptr data)); LT_SCOPE lt_ptr lt_dlcaller_get_data LT_PARAMS((lt_dlcaller_id key, lt_dlhandle handle)); /* --- USER MODULE LOADER API --- */ typedef struct lt_dlloader lt_dlloader; typedef lt_ptr lt_user_data; typedef lt_ptr lt_module; /* Function pointer types for creating user defined module loaders. */ typedef lt_module lt_module_open LT_PARAMS((lt_user_data loader_data, const char *filename)); typedef int lt_module_close LT_PARAMS((lt_user_data loader_data, lt_module handle)); typedef lt_ptr lt_find_sym LT_PARAMS((lt_user_data loader_data, lt_module handle, const char *symbol)); typedef int lt_dlloader_exit LT_PARAMS((lt_user_data loader_data)); struct lt_user_dlloader { const char *sym_prefix; lt_module_open *module_open; lt_module_close *module_close; lt_find_sym *find_sym; lt_dlloader_exit *dlloader_exit; lt_user_data dlloader_data; }; LT_SCOPE lt_dlloader *lt_dlloader_next LT_PARAMS((lt_dlloader *place)); LT_SCOPE lt_dlloader *lt_dlloader_find LT_PARAMS(( const char *loader_name)); LT_SCOPE const char *lt_dlloader_name LT_PARAMS((lt_dlloader *place)); LT_SCOPE lt_user_data *lt_dlloader_data LT_PARAMS((lt_dlloader *place)); LT_SCOPE int lt_dlloader_add LT_PARAMS((lt_dlloader *place, const struct lt_user_dlloader *dlloader, const char *loader_name)); LT_SCOPE int lt_dlloader_remove LT_PARAMS(( const char *loader_name)); /* --- ERROR MESSAGE HANDLING --- */ /* Defining error strings alongside their symbolic names in a macro in this way allows us to expand the macro in different contexts with confidence that the enumeration of symbolic names will map correctly onto the table of error strings. */ #define lt_dlerror_table \ LT_ERROR(UNKNOWN, "unknown error") \ LT_ERROR(DLOPEN_NOT_SUPPORTED, "dlopen support not available") \ LT_ERROR(INVALID_LOADER, "invalid loader") \ LT_ERROR(INIT_LOADER, "loader initialization failed") \ LT_ERROR(REMOVE_LOADER, "loader removal failed") \ LT_ERROR(FILE_NOT_FOUND, "file not found") \ LT_ERROR(DEPLIB_NOT_FOUND, "dependency library not found") \ LT_ERROR(NO_SYMBOLS, "no symbols defined") \ LT_ERROR(CANNOT_OPEN, "can't open the module") \ LT_ERROR(CANNOT_CLOSE, "can't close the module") \ LT_ERROR(SYMBOL_NOT_FOUND, "symbol not found") \ LT_ERROR(NO_MEMORY, "not enough memory") \ LT_ERROR(INVALID_HANDLE, "invalid module handle") \ LT_ERROR(BUFFER_OVERFLOW, "internal buffer overflow") \ LT_ERROR(INVALID_ERRORCODE, "invalid errorcode") \ LT_ERROR(SHUTDOWN, "library already shutdown") \ LT_ERROR(CLOSE_RESIDENT_MODULE, "can't close resident module") \ LT_ERROR(INVALID_MUTEX_ARGS, "invalid mutex handler registration") \ LT_ERROR(INVALID_POSITION, "invalid search path insert position") /* Enumerate the symbolic error names. */ enum { #define LT_ERROR(name, diagnostic) LT_CONC(LT_ERROR_, name), lt_dlerror_table #undef LT_ERROR LT_ERROR_MAX }; /* These functions are only useful from inside custom module loaders. */ LT_SCOPE int lt_dladderror LT_PARAMS((const char *diagnostic)); LT_SCOPE int lt_dlseterror LT_PARAMS((int errorcode)); /* --- SOURCE COMPATIBILITY WITH OLD LIBLTDL --- */ #ifdef LT_NON_POSIX_NAMESPACE # define lt_ptr_t lt_ptr # define lt_module_t lt_module # define lt_module_open_t lt_module_open # define lt_module_close_t lt_module_close # define lt_find_sym_t lt_find_sym # define lt_dlloader_exit_t lt_dlloader_exit # define lt_dlloader_t lt_dlloader # define lt_dlloader_data_t lt_user_data #endif LT_END_C_DECLS #endif /* !LTDL_H */ hercules-3.12/herc_getopt.h0000664000175000017500000000234712564723224012665 00000000000000/* HERC_GETOPT.H (c) Copyright Ivan Warren, 2003 */ /* Hercules getopt interface */ #if !defined(__HERC_GETOPT_H__) # define __HERC_GETOPT_H__ #include "hercules.h" #include "getopt.h" #if defined(NEED_GETOPT_OPTRESET) #define OPTRESET() optreset=1 #else #define OPTRESET() #endif #if defined(NEED_GETOPT_WRAPPER) // The following series of defines end up causing the source file // that happens to include "herc_getopt.h" to end up calling HERC's // version of getopt instead of the normal system getopt. #define getopt herc_getopt #define optarg herc_optarg #define optind herc_optind #define optopt herc_optopt #define optreset herc_optreset int herc_getopt(int,char * const *,const char *); #if defined(HAVE_GETOPT_LONG) #define getopt_long herc_getopt_long struct option; // (fwd ref) int herc_getopt_long(int,char * const *,const char *,const struct option *,int *); #endif extern char *herc_optarg; extern int herc_optind; extern int herc_opterr; extern int herc_optopt; extern int herc_optreset; #endif /* defined(NEED_GETOPT_WRAPPER) */ #endif /* __HERC_GETOPT_H__ */ hercules-3.12/service.h0000664000175000017500000006205712564723224012026 00000000000000/* SERVICE.H (c) Copyright Jan Jaeger, 1999-2009 */ /* Service Processor Architectured fields */ #if !defined(_SERVICE_H) #define _SERVICE_H /*-------------------------------------------------------------------*/ /* Service Call Logical Processor command word definitions */ /*-------------------------------------------------------------------*/ #define SCLP_READ_SCP_INFO 0x00020001 #define SCLP_READ_IFL_INFO 0x00120001 #define SCLP_READ_CHP_INFO 0x00030001 #define SCLP_READ_CSI_INFO 0x001C0001 #define SCLP_READ_XST_MAP 0x00250001 #define SCLP_WRITE_EVENT_DATA 0x00760005 #define SCLP_READ_EVENT_DATA 0x00770005 #define SCLP_WRITE_EVENT_MASK 0x00780005 #define SCLP_DECONFIGURE_CPU 0x00100001 #define SCLP_CONFIGURE_CPU 0x00110001 #define SCLP_DISCONNECT_VF 0x001A0001 #define SCLP_CONNECT_VF 0x001B0001 #define SCLP_COMMAND_MASK 0xFFFF00FF #define SCLP_COMMAND_CLASS 0x000000FF #define SCLP_RESOURCE_MASK 0x0000FF00 #define SCLP_RESOURCE_SHIFT 8 /*-------------------------------------------------------------------*/ /* Service Call Control Block structure definitions */ /*-------------------------------------------------------------------*/ typedef struct _SCCB_HEADER { HWORD length; /* Total length of SCCB */ BYTE flag; /* Flag byte */ BYTE resv1[2]; /* Reserved */ BYTE type; /* Request type */ BYTE reas; /* Reason code */ BYTE resp; /* Response class code */ } SCCB_HEADER; /* Bit definitions for SCCB header flag byte */ #define SCCB_FLAG_SYNC 0x80 /* Synchronous request */ /* Bit definitions for SCCB header request type */ #define SCCB_TYPE_VARIABLE 0x80 /* Variable request */ /* Bit definitions for SCCB header reason code */ #define SCCB_REAS_NONE 0x00 /* No reason */ #define SCCB_REAS_NOT_PGBNDRY 0x01 /* SCCB crosses page boundary*/ #define SCCB_REAS_ODD_LENGTH 0x02 /* Length not multiple of 8 */ #define SCCB_REAS_TOO_SHORT 0x03 /* Length is inadequate */ #define SCCB_REAS_NOACTION 0x02 /* Resource in req. state */ #define SCCB_REAS_STANDBY 0x04 /* Resource in standby state */ #define SCCB_REAS_INVALID_CMD 0x01 /* Invalid SCLP command code */ #define SCCB_REAS_INVALID_RSCP 0x03 /* Invalid resource in parm */ #define SCCB_REAS_IMPROPER_RSC 0x05 /* Resource in improper state*/ #define SCCB_REAS_INVALID_RSC 0x09 /* Invalid resource */ /* Bit definitions for SCCB header response class code */ #define SCCB_RESP_BLOCK_ERROR 0x00 /* Data block error */ #define SCCB_RESP_INFO 0x10 /* Information returned */ #define SCCB_RESP_COMPLETE 0x20 /* Command complete */ #define SCCB_RESP_BACKOUT 0x40 /* Command backed out */ #define SCCB_RESP_REJECT 0xF0 /* Command reject */ // #ifdef FEATURE_SYSTEM_CONSOLE #define SCCB_REAS_NO_EVENTS 0x60 /* No outstanding EVENTs */ #define SCCB_RESP_NO_EVENTS 0xF0 #define SCCB_REAS_EVENTS_SUP 0x62 /* All events suppressed */ #define SCCB_RESP_EVENTS_SUP 0xF0 #define SCCB_REAS_INVALID_MASK 0x70 /* Invalid events mask */ #define SCCB_RESP_INVALID_MASK 0xF0 #define SCCB_REAS_MAX_BUFF 0x71 /* Buffer exceeds maximum */ #define SCCB_RESP_MAX_BUFF 0xF0 #define SCCB_REAS_BUFF_LEN_ERR 0x72 /* Buffer len verification */ #define SCCB_RESP_BUFF_LEN_ERR 0xF0 #define SCCB_REAS_SYNTAX_ERROR 0x73 /* Buffer syntax error */ #define SCCB_RESP_SYNTAX_ERROR 0xF0 #define SCCB_REAS_INVALID_MSKL 0x74 /* Invalid mask length */ #define SCCB_RESP_INVALID_MSKL 0xF0 #define SCCB_REAS_EXCEEDS_SCCB 0x75 /* Exceeds SCCB max capacity */ #define SCCB_RESP_EXCEEDS_SCCB 0xF0 // #endif /*FEATURE_SYSTEM_CONSOLE*/ /* SCP information data area */ typedef struct _SCCB_SCP_INFO { HWORD realinum; /* Number of real storage increments installed */ BYTE realiszm; /* Size of each real storage increment in MB */ BYTE realbszk; /* Size of each real storage block in KB */ HWORD realiint; /* Real storage increment block interleave interval */ HWORD resv2; /* Reserved */ HWORD numcpu; /* Number of CPUs installed */ HWORD offcpu; /* Offset from start of SCCB to CPU information array */ HWORD numhsa; /* Number of HSAs */ HWORD offhsa; /* Offset from start of SCCB to HSA information array */ BYTE loadparm[8]; /* Load parameter */ FWORD xpndinum; /* Number of expanded storage increments installed */ FWORD xpndsz4K; /* Number of 4KB blocks in an expanded storage increment*/ HWORD xpndenum; /* Number of expanded storage elements installed */ HWORD resv3; /* Reserved */ HWORD vectssiz; /* Vector section size */ HWORD vectpsum; /* Vector partial sum number */ BYTE ifm[8]; /* Installed facilities */ BYTE resv4[8]; /* Reserved */ HWORD maxresgp; /* Maximum resource group */ BYTE resv5[6]; /* Reserved */ HWORD nummpf; /* Number of entries in MPF information array */ HWORD offmpf; /* Offset from start of SCCB to MPF information array */ BYTE resv6[4]; /* Reserved */ BYTE cfg[6]; /* Config characteristics */ FWORD rcci; /* Capacity */ BYTE cfg11; /* Config char. byte 11 */ BYTE numcrl; /* Max #of copy and reassign list elements allowed */ FWORD etrtol; /* ETR sync check tolerance */ BYTE resv60[3]; BYTE maxvm; /* Max guest storage size >= 31 and <= 64 (2**pow)-1 is the max supported guest real size. 0 means not constrained. */ FWORD grzm; /* Addess increment size in units of 1M, valid only if realiszm is zero */ DBLWRD grnmx; /* Maximum increment number when it is larger then 64K or when ESAME is on */ BYTE resv8[16]; /* Reserved */ } SCCB_SCP_INFO; /* Bit definitions for installed facilities */ #define SCCB_IFM0_CHANNEL_PATH_INFORMATION 0x80 #define SCCB_IFM0_CHANNEL_PATH_SUBSYSTEM_COMMAND 0x40 #define SCCB_IFM0_CHANNEL_PATH_RECONFIG 0x20 #define SCCB_IFM0_CPU_INFORMATION 0x08 #define SCCB_IFM0_CPU_RECONFIG 0x04 #define SCCB_IFM1_SIGNAL_ALARM 0x80 #define SCCB_IFM1_WRITE_OPERATOR_MESSAGE 0x40 #define SCCB_IFM1_STORE_STATUS_ON_LOAD 0x20 #define SCCB_IFM1_RESTART_REASONS 0x10 #define SCCB_IFM1_INSTRUCTION_ADDRESS_TRACE_BUFFER 0x08 #define SCCB_IFM1_LOAD_PARAMETER 0x04 #define SCCB_IFM1_READ_AND_WRITE_DATA 0x02 #define SCCB_IFM2_REAL_STORAGE_INCREMENT_RECONFIG 0x80 #define SCCB_IFM2_REAL_STORAGE_ELEMENT_INFO 0x40 #define SCCB_IFM2_REAL_STORAGE_ELEMENT_RECONFIG 0x20 #define SCCB_IFM2_COPY_AND_REASSIGN_STORAGE 0x10 #define SCCB_IFM2_EXTENDED_STORAGE_USABILITY_MAP 0x08 #define SCCB_IFM2_EXTENDED_STORAGE_ELEMENT_INFO 0x04 #define SCCB_IFM2_EXTENDED_STORAGE_ELEMENT_RECONFIG 0x02 #define SCCB_IFM2_COPY_AND_REASSIGN_STORAGE_LIST 0x01 #define SCCB_IFM3_VECTOR_FEATURE_RECONFIG 0x80 #define SCCB_IFM3_READ_WRITE_EVENT_FEATURE 0x40 #define SCCB_IFM3_EXTENDED_STORAGE_USABILITY_MAP_EXT 0x20 #define SCCB_IFM3_READ_RESOURCE_GROUP_INFO 0x08 #define SCCB_IFM4_READ_STORAGE_STATUS 0x80 /* Bit definitions for configuration characteristics */ #define SCCB_CFG0_LOGICALLY_PARTITIONED 0x80 #define SCCB_CFG0_SUPPRESSION_ON_PROTECTION 0x20 #define SCCB_CFG0_INITIATE_RESET 0x10 #define SCCB_CFG0_STORE_CHANNEL_SUBSYS_CHARACTERISTICS 0x08 #define SCCB_CFG0_FAST_SYNCHRONOUS_DATA_MOVER 0x01 #define SCCB_CFG0_MVPG_FOR_ALL_GUESTS 0x04 #define SCCB_CFG0_UNKNOWN_BUT_SET_UNDER_VM 0x02 #define SCCB_CFG1_CSLO 0x40 #define SCCB_CFG2_DEVICE_ACTIVE_ONLY_MEASUREMENT 0x40 #define SCCB_CFG2_CALLED_SPACE_IDENTIFICATION 0x02 #define SCCB_CFG2_CHECKSUM_INSTRUCTION 0x01 #define SCCB_CFG3_RESUME_PROGRAM 0x80 #define SCCB_CFG3_PERFORM_LOCKED_OPERATION 0x40 #define SCCB_CFG3_IMMEDIATE_AND_RELATIVE 0x10 #define SCCB_CFG3_COMPARE_AND_MOVE_EXTENDED 0x08 #define SCCB_CFG3_BRANCH_AND_SET_AUTHORITY 0x04 #define SCCB_CFG3_EXTENDED_FLOATING_POINT 0x02 #define SCCB_CFG3_EXTENDED_LOGICAL_COMPUTATION_FACILITY 0x01 #define SCCB_CFG4_EXTENDED_TOD_CLOCK 0x80 #define SCCB_CFG4_EXTENDED_TRANSLATION 0x40 #define SCCB_CFG4_LOAD_REVERSED_FACILITY 0x20 #define SCCB_CFG4_EXTENDED_TRANSLATION_FACILITY2 0x10 #define SCCB_CFG4_STORE_SYSTEM_INFORMATION 0x08 #define SCCB_CFG4_LPAR_CLUSTERING 0x02 #define SCCB_CFG4_IFA_FACILITY 0x01 #define SCCB_CFG5_SENSE_RUNNING_STATUS 0x08 #define SCCB_CFG5_ESAME 0x01 #define SCCB_CFGB_PER_3 0x04 #define SCCB_CFGB_LOAD_WITH_DUMP 0x02 #define SCCB_CFGB_LIST_DIRECTED_IPL 0x01 /* CPU information array entry */ typedef struct _SCCB_CPU_INFO { BYTE cpa; /* CPU address */ BYTE tod; /* TOD clock number */ BYTE cpf[12]; /* RCPU facility map */ BYTE ptyp; /* Processor type */ BYTE ksid; /* Crypto unit identifier */ } SCCB_CPU_INFO; /* Bit definitions for CPU installed features */ #define SCCB_CPF0_SIE_370_MODE 0x80 #define SCCB_CPF0_SIE_XA_MODE 0x40 #define SCCB_CPF0_SIE_SET_II_370_MODE 0x20 #define SCCB_CPF0_SIE_SET_II_XA_MODE 0x10 #define SCCB_CPF0_SIE_NEW_INTERCEPT_FORMAT 0x08 #define SCCB_CPF0_STORAGE_KEY_ASSIST 0x04 #define SCCB_CPF0_MULTIPLE_CONTROLLED_DATA_SPACE 0x02 #define SCCB_CPF1_IO_INTERPRETATION_LEVEL_2 0x40 #define SCCB_CPF1_GUEST_PER_ENHANCED 0x20 #define SCCB_CPF1_SIGP_INTERPRETATION_ASSIST 0x08 #define SCCB_CPF1_RCP_BYPASS_FACILITY 0x04 #define SCCB_CPF1_REGION_RELOCATE_FACILITY 0x02 #define SCCB_CPF1_EXPEDITE_TIMER_PROCESSING 0x01 #define SCCB_CPF2_VECTOR_FEATURE_INSTALLED 0x80 #define SCCB_CPF2_VECTOR_FEATURE_CONNECTED 0x40 #define SCCB_CPF2_VECTOR_FEATURE_STANDBY_STATE 0x20 #define SCCB_CPF2_CRYPTO_FEATURE_ACCESSED 0x10 #define SCCB_CPF2_EXPEDITE_RUN_PROCESSING 0x04 #define SCCB_CPF3_PRIVATE_SPACE_FEATURE 0x80 #define SCCB_CPF3_FETCH_ONLY_BIT 0x40 #define SCCB_CPF3_PER2_INSTALLED 0x01 #define SCCB_CPF4_OMISION_GR_ALTERATION_370 0x80 #define SCCB_CPF5_GUEST_WAIT_STATE_ASSIST 0x40 /* Definitions for processor type code */ #define SCCB_PTYP_CP 0 #define SCCB_PTYP_ICF 1 #define SCCB_PTYP_IFA 2 #define SCCB_PTYP_IFL 3 #define SCCB_PTYP_SUP 5 #define SCCB_PTYP_MAX 5 /*(maximum value)*/ /* processor type macro */ #define PTYPSTR(i) ( \ sysblk.ptyp[(i)] == SCCB_PTYP_CP ? "CP" : \ sysblk.ptyp[(i)] == SCCB_PTYP_ICF ? "CF" : \ sysblk.ptyp[(i)] == SCCB_PTYP_IFA ? "AP" : \ sysblk.ptyp[(i)] == SCCB_PTYP_IFL ? "IL" : \ sysblk.ptyp[(i)] == SCCB_PTYP_SUP ? "IP" : \ "") /* Definitions for crypto unit identifier */ #define SCCB_KSID_CRYPTO_UNIT_ID 0x01 /* HSA information array entry */ typedef struct _SCCB_HSA_INFO { HWORD hssz; /* Size of HSA in 4K blocks */ FWORD ahsa; /* Address of HSA */ } SCCB_HSA_INFO; /* MPF information array entry */ typedef struct _SCCB_MPF_INFO { HWORD mpfy; /* MPF info array entry */ } SCCB_MPF_INFO; /* Channel path information data area */ typedef struct _SCCB_CHP_INFO { BYTE installed[32]; /* Channels installed bits */ BYTE standby[32]; /* Channels standby bits */ BYTE online[32]; /* Channels online bits */ } SCCB_CHP_INFO; /* Channel path information data area */ typedef struct _SCCB_CHSET { BYTE chanset0a[32]; /* 370 channel set 0A */ BYTE chanset1a[32]; /* 370 channel set 1A */ BYTE chanset0b[32]; /* 370 channel set 0B */ BYTE chanset1b[32]; /* 370 channel set 1B */ BYTE csconfig; /* Channel set configuration */ BYTE resv[23]; /* Reserved, set to zero */ } SCCB_CHSET_INFO; /* Read Channel Subsystem Information data area */ typedef struct _SCCB_CSI_INFO { BYTE csif[8]; /* Channel Subsystem installed facility field */ BYTE resv[48]; } SCCB_CSI_INFO; /* Bit definitions for channel subsystem installed facilities */ #define SCCB_CSI0_CANCEL_IO_REQUEST_FACILITY 0x02 #define SCCB_CSI0_CONCURRENT_SENSE_FACILITY 0x01 // #ifdef FEATURE_SYSTEM_CONSOLE /* Write Event Mask */ typedef struct _SCCB_EVENT_MASK { HWORD reserved; HWORD length; /* Event mask length */ BYTE masks[32]; /* Event masks */ // FWORD cp_recv_mask; /* These mask fields have */ // FWORD cp_send_mask; /* the length defined by */ // FWORD sclp_recv_mask; /* the length halfword */ // FWORD sclp_send_mask; } SCCB_EVENT_MASK; #define SCCB_EVENT_CONS_RECV_MASK ( \ (0x80000000 >> (SCCB_EVD_TYPE_MSG-1)) | \ (0x80000000 >> (SCCB_EVD_TYPE_PRIOR-1)) ) #define SCCB_EVENT_CONS_SEND_MASK ( \ (0x80000000 >> (SCCB_EVD_TYPE_OPCMD-1)) | \ (0x80000000 >> (SCCB_EVD_TYPE_PRIOR-1)) | \ (0x80000000 >> (SCCB_EVD_TYPE_CPCMD-1)) ) /* Read/Write Event Data Header */ typedef struct _SCCB_EVD_HDR { HWORD totlen; /* Event Data Buffer total length */ BYTE type; #define SCCB_EVD_TYPE_OPCMD 0x01 /* Operator command */ #define SCCB_EVD_TYPE_MSG 0x02 /* Message from Control Pgm */ // #if defined(FEATURE_SCEDIO ) #define SCCB_EVD_TYPE_SCEDIO 0x07 /* SCE DASD I/O */ // #endif /*defined(FEATURE_SCEDIO )*/ #define SCCB_EVD_TYPE_STATECH 0x08 /* State Change */ #define SCCB_EVD_TYPE_PRIOR 0x09 /* Priority message/command */ #define SCCB_EVD_TYPE_CPIDENT 0x0B /* CntlProgIdent */ #define SCCB_EVD_TYPE_VT220 0x1A /* VT220 Msg */ #define SCCB_EVD_TYPE_SYSG 0x1B /* 3270 Msg (SYSG console) */ #define SCCB_EVD_TYPE_SIGQ 0x1D /* SigQuiesce */ #define SCCB_EVD_TYPE_CPCMD 0x20 /* CntlProgOpCmd */ BYTE flag; #define SCCB_EVD_FLAG_PROC 0x80 /* Event successful */ HWORD resv; /* Reserved for future use */ } SCCB_EVD_HDR; /* Read/Write Event Data Buffer */ typedef struct _SCCB_EVD_BK { HWORD msglen; BYTE const1[51]; HWORD cplen; /* CP message length */ BYTE const2[24]; HWORD tdlen; /* Text Data length */ BYTE const3[2]; BYTE sdtlen; BYTE const4; /* Self defining tag */ BYTE tmlen; BYTE const5; /* Text Message format */ // BYTE txtmsg[n]; } SCCB_EVD_BK; /* Message Control Data Block */ typedef struct _SCCB_MCD_BK { HWORD length; /* Total length of MCD */ HWORD type; /* Type must be 0x0001 */ FWORD tag; /* Tag must be 0xD4C4C240 */ FWORD revcd; /* Revision code 0x00000001 */ } SCCB_MCD_BK; /* Message Control Data Block Header */ typedef struct _SCCB_OBJ_HDR { HWORD length; /* Total length of OBJ */ HWORD type; /* Object type */ #define SCCB_OBJ_TYPE_GENERAL 0x0001 /* General Object */ #define SCCB_OBJ_TYPE_CPO 0x0002 /* Control Program Object */ #define SCCB_OBJ_TYPE_NLS 0x0003 /* NLS data Object */ #define SCCB_OBJ_TYPE_MESSAGE 0x0004 /* Message Text Object */ } SCCB_OBJ_HDR; /* Message Control Data Block Message Text Object */ typedef struct _SCCB_MTO_BK { BYTE ltflag[2]; /* Line type flag */ #define SCCB_MTO_LTFLG0_CNTL 0x80 /* Control text line */ #define SCCB_MTO_LTFLG0_LABEL 0x40 /* Label text line */ #define SCCB_MTO_LTFLG0_DATA 0x20 /* Data text line */ #define SCCB_MTO_LTFLG0_END 0x10 /* Last line of message */ #define SCCB_MTO_LTFLG0_PROMPT 0x08 /* Prompt line - response requested (WTOR) */ #define SCCB_MTO_LTFLG0_DBCS 0x04 /* DBCS text */ #define SCCB_MTO_LTFLG0_MIX 0x02 /* Mixed SBCS/DBCS text */ #define SCCB_MTO_LTFLG1_OVER 0x01 /* Foreground presentation field override */ BYTE presattr[4]; /* Presentation Attribute Byte 0 - control Byte 1 - color Byte 2 - highlighting Byte 3 - intensity */ #define SCCB_MTO_PRATTR0_ALARM 0x80 /* Sound alarm (console) */ #define SCCB_MTO_PRATTR3_HIGH 0xE8 /* Highlighted */ #define SCCB_MTO_PRATTR3_NORM 0xE4 /* Normal */ } SCCB_MTO_BK; /* Message Control Data Block General Object */ typedef struct _SCCB_MGO_BK { FWORD seq; /* Message DOM ID */ BYTE time[11]; /* C'HH.MM.SS.th' */ BYTE resv1; BYTE date[7]; /* C'YYYYDDD' */ BYTE resv2; BYTE mflag[2]; /* Message Flags */ #define SCCB_MGO_MFLAG0_DOM 0x80 /* Delete Operator Message */ #define SCCB_MGO_MFLAG0_ALARM 0x40 /* Sound the SCLP alarm */ #define SCCB_MGO_MFLAG0_HOLD 0x20 /* Hold message until DOM */ BYTE presattr[4]; /* Presentation Attribute Byte 0 - control Byte 1 - color Byte 2 - highlighting Byte 3 - intensity */ #define SCCB_MGO_PRATTR0_ALARM 0x80 /* Sound alarm (console) */ #define SCCB_MGO_PRATTR3_HIGH 0xE8 /* Highlighted */ #define SCCB_MGO_PRATTR3_NORM 0xE4 /* Normal */ BYTE bckattr[4]; /* Background presentation attributes - covers all message-test foreground presentation attribute field overrides */ BYTE sysname[8]; /* Originating system name */ BYTE jobname[8]; /* Jobname or guestname */ } SCCB_MGO_BK; /* Control Program Information */ typedef struct _SCCB_CPI_BK { BYTE id_fmt; BYTE resv0; BYTE system_type[8]; DBLWRD resv1; BYTE system_name[8]; DBLWRD resv2; DBLWRD system_level; DBLWRD resv3; BYTE sysplex_name[8]; BYTE resv4[16]; } SCCB_CPI_BK; /* Message Control Data Block NLS Object */ typedef struct _SCCB_NLS_BK { HWORD scpgid; /* CPGID for SBCS (def 037) */ HWORD scpsgid; /* CPSGID for SBCS (def 637) */ HWORD dcpgid; /* CPGID for DBCS (def 037) */ HWORD dcpsgid; /* CPSGID for DBCS (def 637) */ } SCCB_NLS_BK; /* Signal Quiesce */ typedef struct _SCCB_SGQ_BK { HWORD count; /* Countdown in units */ BYTE unit; /* Unit type */ #define SCCB_SGQ_SEC 0 #define SCCB_SGQ_MIN 1 #define SCCB_SGQ_HR 2 } SCCB_SGQ_BK; // #endif /*FEATURE_SYSTEM_CONSOLE*/ // #ifdef FEATURE_EXPANDED_STORAGE typedef struct _SCCB_XST_INFO { HWORD elmid; /* Extended storage element id */ BYTE resv1[6]; FWORD elmsin; /* Starting increment number */ FWORD elmein; /* Ending increment number */ BYTE elmchar; /* Element characteristics */ #define SCCB_XST_INFO_ELMCHAR_REQ 0x80; /* Required element */ BYTE resv2[39]; } SCCB_XST_INFO; typedef struct _SCCB_XST_MAP { FWORD incnum; /* Increment number */ FWORD resv; // BYTE map[]; /* Bitmap of all usable // expanded storage blocks */ } SCCB_XST_MAP; // #endif /*FEATURE_EXPANDED_STORAGE*/ // #if defined(FEATURE_SCEDIO ) /* SCE DASD I/O Request */ typedef struct _SCCB_SCEDIO_BK { BYTE flag0; BYTE flag1; #define SCCB_SCEDIO_FLG1_IOR 0x03 #define SCCB_SCEDIO_FLG1_IOV 0x04 BYTE flag2; BYTE flag3; #define SCCB_SCEDIO_FLG3_COMPLETE 0x80 } SCCB_SCEDIO_BK; typedef struct _SCCB_SCEDIOV_BK { BYTE type; #define SCCB_SCEDIOV_TYPE_INIT 0x00 #define SCCB_SCEDIOV_TYPE_READ 0x01 #define SCCB_SCEDIOV_TYPE_CREATE 0x02 #define SCCB_SCEDIOV_TYPE_APPEND 0x03 BYTE flag1; BYTE flag2; BYTE flag3; DBLWRD seek; DBLWRD ncomp; DBLWRD length; DBLWRD resv2; DBLWRD resv3; DBLWRD sto; BYTE filename[256]; } SCCB_SCEDIOV_BK; typedef struct _SCCB_SCEDIOR_BK { BYTE type; #define SCCB_SCEDIOR_TYPE_INIT 0x00 #define SCCB_SCEDIOR_TYPE_READ 0x01 BYTE flag1; BYTE flag2; BYTE flag3; FWORD origin; FWORD resv1; FWORD resv2; BYTE image[8]; } SCCB_SCEDIOR_BK; // #endif /*defined(FEATURE_SCEDIO )*/ #endif /*!defined(_SERVICE_H)*/ hercules-3.12/chsc.h0000664000175000017500000000662612564723224011306 00000000000000/* CHSC.H (c) Copyright Jan Jaeger, 1999-2000 */ /* Channel Subsystem interface fields */ #if !defined(_CHSC_H) #define _CHSC_H // #if defined(FEATURE_CHSC) typedef struct _CHSC_REQ { HWORD length; /* Offset to response field */ HWORD req; /* Request code */ FWORD resv[3]; } CHSC_REQ; typedef struct _CHSC_REQ4 { HWORD length; /* Offset to response field */ HWORD req; /* Request code */ #define CHSC_REQ_SCHDESC 0x04 #define CHSC_REQ_CSSINFO 0x10 HWORD resv1; HWORD f_sch; /* First subchannel */ HWORD resv2; HWORD l_sch; /* Last subchannel */ FWORD resv3; } CHSC_REQ4; typedef struct _CHSC_RSP { HWORD length; /* Length of response field */ HWORD rsp; /* Reponse code */ #define CHSC_REQ_OK 0x0001 /* No error */ #define CHSC_REQ_INVALID 0x0002 /* Invalid request */ #define CHSC_REQ_ERRREQ 0x0003 /* Error in request block */ #define CHSC_REQ_NOTSUPP 0x0004 /* Request not supported */ FWORD info; } CHSC_RSP; typedef struct _CHSC_RSP4 { BYTE sch_val : 1; /* Subchannel valid */ BYTE dev_val : 1; /* Device number valid */ BYTE st : 3; /* Subchannel type */ #define CHSC_RSP4_ST_IO 0 /* I/O Subchannel; all fields have a meaning */ #define CHSC_RSP4_ST_CHSC 1 /* CHSC Subchannel only sch_val st and sch have a meaning */ #define CHSC_RSP4_ST_MSG 2 /* MSG Subchannel; all fields except unit_addr have a meaning */ #define CHSC_RPS4_ST_ADM 3 /* ADM Subchannel; Only sch_val st and sch have a meaning */ BYTE zeros : 3; BYTE unit_addr; /* Unit address */ HWORD devno; /* Device number */ BYTE path_mask; /* Valid path mask */ BYTE fla_valid_mask; /* Valid link mask */ HWORD sch; /* Subchannel number */ BYTE chpid[8]; /* Channel path array */ BYTE fla[8]; /* Full link address array */ } CHSC_RSP4; typedef struct _CHSC_RSP10 { FWORD general_char[510]; FWORD chsc_char[508]; /* ZZ: Linux/390 code indicates this field has a length of 518, however, that would mean that the entire CHSC request would be 4K + 16 in length which is probably an error - *JJ/10/10/04*/ } CHSC_RSP10; // #endif /*defined(FEATURE_CHSC)*/ #endif /*!defined(_CHSC_H)*/ hercules-3.12/pttrace.h0000664000175000017500000001200712564723224012016 00000000000000/* PTTRACE.H (c) Copyright Greg Smith, 2003-2009 */ /* Header file for pthreads trace debugger */ /*-------------------------------------------------------------------*/ /* Pthread tracing structures and prototypes */ /*-------------------------------------------------------------------*/ #if !defined( _PTTHREAD_H_ ) #define _PTTHREAD_H_ #ifndef _PTTRACE_C_ #ifndef _HUTIL_DLL_ #define PTT_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define PTT_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else /* _PTTRACE_C_ */ #define PTT_DLL_IMPORT DLL_EXPORT #endif /* _PTTRACE_C_ */ #if defined(OPTION_FTHREADS) #define OBTAIN_PTTLOCK \ do { \ if (!pttnolock) fthread_mutex_lock(&pttlock); \ } while (0) #define RELEASE_PTTLOCK \ do { \ if (!pttnolock) fthread_mutex_unlock(&pttlock); \ } while (0) PTT_DLL_IMPORT int ptt_pthread_mutex_init(LOCK *, void *, char *); PTT_DLL_IMPORT int ptt_pthread_mutex_lock(LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_mutex_trylock(LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_mutex_unlock(LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_init(COND *, void *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_signal(COND *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_broadcast(COND *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_wait(COND *, LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_timedwait(COND *, LOCK *, struct timespec *, char *); PTT_DLL_IMPORT int ptt_pthread_create(TID *, ATTR *, PFT_THREAD_FUNC, void *, char *, char *); PTT_DLL_IMPORT int ptt_pthread_join(TID, void **, char *); PTT_DLL_IMPORT int ptt_pthread_detach(TID, char *); PTT_DLL_IMPORT int ptt_pthread_kill(TID, int, char *); #else #define OBTAIN_PTTLOCK \ do { \ if (!pttnolock) pthread_mutex_lock(&pttlock); \ } while (0) #define RELEASE_PTTLOCK \ do { \ if (!pttnolock) pthread_mutex_unlock(&pttlock); \ } while (0) PTT_DLL_IMPORT int ptt_pthread_mutex_init(LOCK *, pthread_mutexattr_t *, char *); PTT_DLL_IMPORT int ptt_pthread_mutex_lock(LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_mutex_trylock(LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_mutex_unlock(LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_init(COND *, pthread_condattr_t *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_signal(COND *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_broadcast(COND *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_wait(COND *, LOCK *, char *); PTT_DLL_IMPORT int ptt_pthread_cond_timedwait(COND *, LOCK *, const struct timespec *, char *); PTT_DLL_IMPORT int ptt_pthread_create(TID *, ATTR *, void *(*)(), void *, char *, char *); PTT_DLL_IMPORT int ptt_pthread_join(TID, void **, char *); PTT_DLL_IMPORT int ptt_pthread_detach(TID, char *); PTT_DLL_IMPORT int ptt_pthread_kill(TID, int, char *); #endif PTT_DLL_IMPORT void ptt_trace_init (int n, int init); PTT_DLL_IMPORT int ptt_cmd(int argc, char *argv[], char*cmdline); PTT_DLL_IMPORT void ptt_pthread_trace (int, char *, void *, void *, char *, int); PTT_DLL_IMPORT int ptt_pthread_print (); PTT_DLL_IMPORT int pttclass; void *ptt_timeout(); typedef struct _PTT_TRACE { TID tid; /* Thread id */ int class; /* Trace record class */ #define PTT_CL_LOG 0x0001 /* Logger records */ #define PTT_CL_TMR 0x0002 /* Timer/Clock records */ #define PTT_CL_THR 0x0004 /* Thread records */ #define PTT_CL_INF 0x0100 /* Instruction info */ #define PTT_CL_ERR 0x0200 /* Instruction error/unsup */ #define PTT_CL_PGM 0x0400 /* Program interrupt */ #define PTT_CL_CSF 0x0800 /* Compare&Swap failure */ #define PTT_CL_SIE 0x1000 /* Interpretive Execution */ #define PTT_CL_SIG 0x2000 /* SIGP signalling */ #define PTT_CL_IO 0x4000 /* IO */ char *type; /* Trace type */ void *data1; /* Data 1 */ void *data2; /* Data 2 */ char *loc; /* File name:line number */ struct timeval tv; /* Time of day */ int result; /* Result */ } PTT_TRACE; #define PTT_LOC_Q( _string ) #_string #define PTT_LOC_M( _string ) PTT_LOC_Q( _string ) #define PTT_LOC __FILE__ ":" PTT_LOC_M( __LINE__ ) #define PTT_TRACE_SIZE sizeof(PTT_TRACE) #define PTT_MAGIC -99 #define PTT(_class,_type,_data1,_data2,_result) \ do { \ if (pttclass & (_class)) \ ptt_pthread_trace(_class,_type,(void *)(uintptr_t)(_data1),(void *)(uintptr_t)(_data2),PTT_LOC,(int)(_result)); \ } while(0) #define PTTRACE(_type,_data1,_data2,_loc,_result) \ do { \ if (pttclass & PTT_CL_THR) \ ptt_pthread_trace(PTT_CL_THR,_type,_data1,_data2,_loc,_result); \ } while(0) #endif /* defined( _PTTHREAD_H_ ) */ hercules-3.12/history.h0000664000175000017500000000071712564723224012062 00000000000000/* HISTORY.H (c) Copyright Volker Bandke, 2003-2009 */ /* Hercules Command History header */ #ifndef HISTORY_H #define HISTORY_H extern int history_requested; extern char *historyCmdLine; int history_init(); int history_add(char *cmdline); int history_show(); int history_absolute_line(int x); int history_relative_line(int x); int history_next(void); int history_prev(void); int history_remove(void); #endif hercules-3.12/sr.h0000664000175000017500000005425612564723224011014 00000000000000/* SR.H (c)Copyright Greg Smith, 2004-2009 */ /* Suspend/Resume a Hercules session */ /* * The suspend/resume functions allow a hercules instance to be * captured to a file and later resumed. Note that the suspend * function also terminates the hercules instance. * * In order for an instance to be resumed, hercules must be started * with a config file describing the configuration at suspend time. * For example, mainsize and xpndsize must match. Also, all devices * present at suspend time must be present at resume time. * * Disk devices must be at the same state as they were at suspend * time. They can, however, be a different file type. That is, * a disk could be a cckd disk at suspend time. Then a ckd disk * could be created using dasdcopy and hercules resumed using the * ckd disk instead. * * Also, hercules must be configured similarly as at suspend time. * For example, if 4 emulated CPUs were active at suspend time * then the session can not be resumed on a hercules with a * maximum of two CPUs. Another example, you will not be able * to resume a session in z900 architecture mode for a hercules * that was built without z900 architecture. * * Device state * * Currently, device state is only fully saved for CKD disks. * Each device class (eg TAPE, RDR, PUN, CTC) will need code * to save and restore their state. Some states may not be * possible to restore (eg active tcp/ip connections at the * time of suspend). * * Further limitations * * Currently the vector facility state is not saved. * Also, the ecpsvm state is not currently saved. * * File Structure * * The suspend/resume file (.srf) contains some number of `text * units'. A text unit has an 8 byte header followed by zero or * more bytes of data. * * The file is designed to be hercules release independent and * to be host architecture independent. For example, I should be * able to take an srf file created on hercules 3.02 on an intel * machine and resume on a Sun machine running hercules 3.04. * * The header contains a 4 byte key and a 4 byte length. Both * the key and the length are stored in big-endian byte order. * * There are 3 types of data: STRING, BUF and VALUE. * * A string is a null terminated sequence of bytes. The string * includes the null terminator byte. The total length of a * string cannot exceed SR_MAX_STRING_LENGTH (4096). The * length is checked by SR_READ_STRING. * * A buf is a sequence of bytes whose length must be provided. * The length should be checked before issuing SR_READ_BUF. * * A value is an arithmetic number. It's length can be * 0, 1, 2, 4 or 8 bytes. Values are stored in big-endian * byte order. A zero length indicates the value is 0. * * Text Units * * There are 4 categories (so far) of text units: * HDR ... fields that describe the file * SYS ... fields from SYSBLK * CPU ... fields from REGS * DEV ... fields from DEVBLK * * The format of a text unit key value is * ace c t xxx * * ace -- all keys start with 0xace * c -- category (0 - HDR, 1 - SYS, 2 - CPU, 3 - DEV) * t -- for DEV keys, identifies the subtype for the * device type (0 - general, 1 - CKD, ...) * xxx -- field identifier * * Note that there is no array data type. When an array * needs to be used, the elements should have ascending * text unit key values. For example: * * #define SR_CPU_GR 0xace20020 * #define SR_CPU_GR_0 0xace20020 * #define SR_CPU_GR_1 0xace20021 * #define SR_CPU_GR_2 0xace20022 * #define SR_CPU_GR_3 0xace20023 * . . . . . . * * The array can be written during suspend as follows: * * for (i = 0; i < 16; i++) * SR_WRITE_VALUE(fd, SR_CPU_GR+i, regs->gr[i], sizeof(regs->gr[0])); * * The array can be processed during resume as follows * * case SR_CPU_GR_0: * case SR_CPU_GR_1: * case SR_CPU_GR_2: * case SR_CPU_GR_3: * . . . . . . * i = key - SR_CPU_GR; * SR_READ_VALUE(fd, len, ®s->gr[i], sizeof(regs->gr[0])); * break; * * The format of the .srf file is deliberately unstructured to * allow for flexibility in future enhancements. However there * are a few restrictions. * * o Key SR_SYS_ARCHNAME shoud be specified before any * SR_CPU keys. The corresponding CPU is configured * when the SR_CPU key is read, so sysblk.arch_mode must * already be correctly set. * o SR_CPU_ keys must follow the corresponding SR_CPU key. * o Likewise SR_DEV_ keys must follow the corresponding SR_DEV key * * There may be other instances where the processing of one * key requires that another key has been previously processed. * */ // $Log$ // Revision 1.15 2007/06/23 00:04:16 ivan // Update copyright notices to include current year (2007) // // Revision 1.14 2006/12/08 09:43:30 jj // Add CVS message log // #ifndef _HERCULES_SR_H #define _HERCULES_SR_H #include "opcode.h" #define SR_ID "Hercules suspend/resume file" #define SR_MAX_STRING_LENGTH 4096 #define SR_KEY_ID_MASK 0xfff00000 #define SR_KEY_ID 0xace00000 #define SR_HDR_ID 0xace00000 #define SR_HDR_VERSION 0xace00001 #define SR_HDR_DATE 0xace00002 #define SR_SYS_MASK 0xfffff000 #define SR_SYS_STARTED_MASK 0xace10000 #define SR_SYS_INTS_STATE 0xace10001 #define SR_SYS_ARCH_NAME 0xace10002 #define SR_SYS_MAINSIZE 0xace10007 #define SR_SYS_MAINSTOR 0xace10008 #define SR_SYS_SKEYSIZE 0xace10009 #define SR_SYS_STORKEYS 0xace1000a #define SR_SYS_XPNDSIZE 0xace1000b #define SR_SYS_XPNDSTOR 0xace1000c #define SR_SYS_CPUID 0xace1000d #define SR_SYS_IPLDEV 0xace1000e #define SR_SYS_IPLCPU 0xace1000f #define SR_SYS_MBO 0xace10010 #define SR_SYS_MBK 0xace10011 #define SR_SYS_MBM 0xace10012 #define SR_SYS_MBD 0xace10013 #define SR_SYS_IOINTQ 0xace10020 #define SR_SYS_IOPENDING 0xace10021 #define SR_SYS_PCIPENDING 0xace10022 #define SR_SYS_ATTNPENDING 0xace10023 #define SR_SYS_CHP_RESET 0xace10030 #define SR_SYS_CHP_RESET_0 0xace10030 #define SR_SYS_CHP_RESET_1 0xace10031 #define SR_SYS_CHP_RESET_2 0xace10032 #define SR_SYS_CHP_RESET_3 0xace10033 #define SR_SYS_CHP_RESET_4 0xace10034 #define SR_SYS_CHP_RESET_5 0xace10035 #define SR_SYS_CHP_RESET_6 0xace10036 #define SR_SYS_CHP_RESET_7 0xace10037 #define SR_SYS_SERVPARM 0xace10040 #define SR_SYS_SIGINTREQ 0xace10041 #define SR_SYS_VMACTIVE 0xace10042 #define SR_SYS_MSCHDELAY 0xace10043 #define SR_SYS_LOADPARM 0xace10044 /* * Following 3 tags added for Multiple * Logical Channel Subsystem support */ #define SR_SYS_IOPENDING_LCSS 0xace10045 #define SR_SYS_PCIPENDING_LCSS 0xace10046 #define SR_SYS_ATTNPENDING_LCSS 0xace10047 #define SR_SYS_SERVC 0xace11000 #define SR_SYS_CLOCK 0xace12000 #define SR_CPU 0xace20000 #define SR_CPU_ARCHMODE 0xace20001 #define SR_CPU_PX 0xace20002 #define SR_CPU_PSW 0xace20003 #define SR_CPU_GR 0xace20020 #define SR_CPU_GR_0 0xace20020 #define SR_CPU_GR_1 0xace20021 #define SR_CPU_GR_2 0xace20022 #define SR_CPU_GR_3 0xace20023 #define SR_CPU_GR_4 0xace20024 #define SR_CPU_GR_5 0xace20025 #define SR_CPU_GR_6 0xace20026 #define SR_CPU_GR_7 0xace20027 #define SR_CPU_GR_8 0xace20028 #define SR_CPU_GR_9 0xace20029 #define SR_CPU_GR_10 0xace2002a #define SR_CPU_GR_11 0xace2002b #define SR_CPU_GR_12 0xace2002c #define SR_CPU_GR_13 0xace2002d #define SR_CPU_GR_14 0xace2002e #define SR_CPU_GR_15 0xace2002f #define SR_CPU_CR 0xace20040 #define SR_CPU_CR_0 0xace20040 #define SR_CPU_CR_1 0xace20041 #define SR_CPU_CR_2 0xace20042 #define SR_CPU_CR_3 0xace20043 #define SR_CPU_CR_4 0xace20044 #define SR_CPU_CR_5 0xace20045 #define SR_CPU_CR_6 0xace20046 #define SR_CPU_CR_7 0xace20047 #define SR_CPU_CR_8 0xace20048 #define SR_CPU_CR_9 0xace20049 #define SR_CPU_CR_10 0xace2004a #define SR_CPU_CR_11 0xace2004b #define SR_CPU_CR_12 0xace2004c #define SR_CPU_CR_13 0xace2004d #define SR_CPU_CR_14 0xace2004e #define SR_CPU_CR_15 0xace2004f #define SR_CPU_AR 0xace20060 #define SR_CPU_AR_0 0xace20060 #define SR_CPU_AR_1 0xace20061 #define SR_CPU_AR_2 0xace20062 #define SR_CPU_AR_3 0xace20063 #define SR_CPU_AR_4 0xace20064 #define SR_CPU_AR_5 0xace20065 #define SR_CPU_AR_6 0xace20066 #define SR_CPU_AR_7 0xace20067 #define SR_CPU_AR_8 0xace20068 #define SR_CPU_AR_9 0xace20069 #define SR_CPU_AR_10 0xace2006a #define SR_CPU_AR_11 0xace2006b #define SR_CPU_AR_12 0xace2006c #define SR_CPU_AR_13 0xace2006d #define SR_CPU_AR_14 0xace2006e #define SR_CPU_AR_15 0xace2006f #define SR_CPU_FPR 0xace20080 #define SR_CPU_FPR_0 0xace20080 #define SR_CPU_FPR_1 0xace20081 #define SR_CPU_FPR_2 0xace20082 #define SR_CPU_FPR_3 0xace20083 #define SR_CPU_FPR_4 0xace20084 #define SR_CPU_FPR_5 0xace20085 #define SR_CPU_FPR_6 0xace20086 #define SR_CPU_FPR_7 0xace20087 #define SR_CPU_FPR_8 0xace20088 #define SR_CPU_FPR_9 0xace20089 #define SR_CPU_FPR_10 0xace2008a #define SR_CPU_FPR_11 0xace2008b #define SR_CPU_FPR_12 0xace2008c #define SR_CPU_FPR_13 0xace2008d #define SR_CPU_FPR_14 0xace2008e #define SR_CPU_FPR_15 0xace2008f #define SR_CPU_FPR_16 0xace20090 #define SR_CPU_FPR_17 0xace20091 #define SR_CPU_FPR_18 0xace20092 #define SR_CPU_FPR_19 0xace20093 #define SR_CPU_FPR_20 0xace20094 #define SR_CPU_FPR_21 0xace20095 #define SR_CPU_FPR_22 0xace20096 #define SR_CPU_FPR_23 0xace20097 #define SR_CPU_FPR_24 0xace20098 #define SR_CPU_FPR_25 0xace20099 #define SR_CPU_FPR_26 0xace2009a #define SR_CPU_FPR_27 0xace2009b #define SR_CPU_FPR_28 0xace2009c #define SR_CPU_FPR_29 0xace2009d #define SR_CPU_FPR_30 0xace2009e #define SR_CPU_FPR_31 0xace2009f #define SR_CPU_FPC 0xace20100 #define SR_CPU_DXC 0xace20101 #define SR_CPU_MC 0xace20102 #define SR_CPU_EA 0xace20103 #define SR_CPU_PTIMER 0xace20104 #define SR_CPU_CLKC 0xace20105 #define SR_CPU_CHANSET 0xace20106 #define SR_CPU_TODPR 0xace20107 #define SR_CPU_MONCLASS 0xace20108 #define SR_CPU_EXCARID 0xace20109 #define SR_CPU_INTS_STATE 0xace2010a #define SR_CPU_INTS_MASK 0xace2010b #define SR_CPU_EXTCCPU 0xace2010c #define SR_CPU_BEAR 0xace2010d #define SR_CPU_OPNDRID 0xace20110 #define SR_CPU_CHECKSTOP 0xace20111 #define SR_CPU_HOSTINT 0xace20112 #define SR_CPU_EXECFLAG 0xace20113 #define SR_CPU_INSTVALID 0xace20114 #define SR_CPU_PERMODE 0xace20115 #define SR_CPU_LOADSTATE 0xace20116 #define SR_CPU_INVALIDATE 0xace20117 #define SR_CPU_RESET_OPCTAB 0xace20118 #define SR_CPU_SIGPRESET 0xace20119 #define SR_CPU_SIGPIRESET 0xace2011a #define SR_CPU_VTIMERINT 0xace2011b #define SR_CPU_RTIMERINT 0xace2011c #define SR_CPU_MALFCPU 0xace20120 #define SR_CPU_MALFCPU_0 0xace20120 #define SR_CPU_MALFCPU_1 0xace20121 #define SR_CPU_MALFCPU_2 0xace20122 #define SR_CPU_MALFCPU_3 0xace20123 #define SR_CPU_MALFCPU_4 0xace20124 #define SR_CPU_MALFCPU_5 0xace20125 #define SR_CPU_MALFCPU_6 0xace20126 #define SR_CPU_MALFCPU_7 0xace20127 #define SR_CPU_MALFCPU_8 0xace20128 #define SR_CPU_MALFCPU_9 0xace20129 #define SR_CPU_MALFCPU_10 0xace2012a #define SR_CPU_MALFCPU_11 0xace2012b #define SR_CPU_MALFCPU_12 0xace2012c #define SR_CPU_MALFCPU_13 0xace2012d #define SR_CPU_MALFCPU_14 0xace2012e #define SR_CPU_MALFCPU_15 0xace2012f #define SR_CPU_MALFCPU_16 0xace20130 #define SR_CPU_MALFCPU_17 0xace20131 #define SR_CPU_MALFCPU_18 0xace20132 #define SR_CPU_MALFCPU_19 0xace20133 #define SR_CPU_MALFCPU_20 0xace20134 #define SR_CPU_MALFCPU_21 0xace20135 #define SR_CPU_MALFCPU_22 0xace20136 #define SR_CPU_MALFCPU_23 0xace20137 #define SR_CPU_MALFCPU_24 0xace20138 #define SR_CPU_MALFCPU_25 0xace20139 #define SR_CPU_MALFCPU_26 0xace2013a #define SR_CPU_MALFCPU_27 0xace2013b #define SR_CPU_MALFCPU_28 0xace2013c #define SR_CPU_MALFCPU_29 0xace2013d #define SR_CPU_MALFCPU_30 0xace2013e #define SR_CPU_MALFCPU_31 0xace2013f #define SR_CPU_EMERCPU 0xace20140 #define SR_CPU_EMERCPU_0 0xace20140 #define SR_CPU_EMERCPU_1 0xace20141 #define SR_CPU_EMERCPU_2 0xace20142 #define SR_CPU_EMERCPU_3 0xace20143 #define SR_CPU_EMERCPU_4 0xace20144 #define SR_CPU_EMERCPU_5 0xace20145 #define SR_CPU_EMERCPU_6 0xace20146 #define SR_CPU_EMERCPU_7 0xace20147 #define SR_CPU_EMERCPU_8 0xace20148 #define SR_CPU_EMERCPU_9 0xace20149 #define SR_CPU_EMERCPU_10 0xace2014a #define SR_CPU_EMERCPU_11 0xace2014b #define SR_CPU_EMERCPU_12 0xace2014c #define SR_CPU_EMERCPU_13 0xace2014d #define SR_CPU_EMERCPU_14 0xace2014e #define SR_CPU_EMERCPU_15 0xace2014f #define SR_CPU_EMERCPU_16 0xace20150 #define SR_CPU_EMERCPU_17 0xace20151 #define SR_CPU_EMERCPU_18 0xace20152 #define SR_CPU_EMERCPU_19 0xace20153 #define SR_CPU_EMERCPU_20 0xace20154 #define SR_CPU_EMERCPU_21 0xace20155 #define SR_CPU_EMERCPU_22 0xace20156 #define SR_CPU_EMERCPU_23 0xace20157 #define SR_CPU_EMERCPU_24 0xace20158 #define SR_CPU_EMERCPU_25 0xace20159 #define SR_CPU_EMERCPU_26 0xace2015a #define SR_CPU_EMERCPU_27 0xace2015b #define SR_CPU_EMERCPU_28 0xace2015c #define SR_CPU_EMERCPU_29 0xace2015d #define SR_CPU_EMERCPU_30 0xace2015e #define SR_CPU_EMERCPU_31 0xace2015f #define SR_DEV 0xace30000 #define SR_DEV_DEVTYPE 0xace30001 #define SR_DEV_ARGC 0xace30002 #define SR_DEV_ARGV 0xace30003 #define SR_DEV_TYPNAME 0xace30004 /* * Following tag added for multiple Logical * Channel subsystem support */ #define SR_DEV_LCSS 0xace30005 #define SR_DEV_ORB 0xace30010 #define SR_DEV_PMCW 0xace30011 #define SR_DEV_SCSW 0xace30012 #define SR_DEV_PCISCSW 0xace30013 #define SR_DEV_ATTNSCSW 0xace30014 #define SR_DEV_CSW 0xace30015 #define SR_DEV_PCICSW 0xace30016 #define SR_DEV_ATTNCSW 0xace30017 #define SR_DEV_ESW 0xace30018 #define SR_DEV_ECW 0xace30019 #define SR_DEV_SENSE 0xace3001a #define SR_DEV_PGSTAT 0xace3001b #define SR_DEV_PGID 0xace3001c /* By Adrian - SR_DEV_DRVPWD */ #define SR_DEV_DRVPWD 0xace3001d #define SR_DEV_BUSY 0xace30020 #define SR_DEV_RESERVED 0xace30021 #define SR_DEV_SUSPENDED 0xace30022 #define SR_DEV_PENDING 0xace30023 #define SR_DEV_PCIPENDING 0xace30024 #define SR_DEV_ATTNPENDING 0xace30025 #define SR_DEV_STARTPENDING 0xace30026 #define SR_DEV_CRWPENDING 0xace30027 #define SR_DEV_CCWADDR 0xace30028 #define SR_DEV_IDAPMASK 0xace30029 #define SR_DEV_IDAWFMT 0xace3002a #define SR_DEV_CCWFMT 0xace3002b #define SR_DEV_CCWKEY 0xace3002c #define SR_DEV_MASK 0xfffff000 #define SR_DEV_CKD 0xace31000 #define SR_DEV_FBA 0xace32000 #define SR_DEV_TTY 0xace33000 #define SR_DEV_3270 0xace34000 #define SR_DEV_RDR 0xace35000 #define SR_DEV_PUN 0xace36000 #define SR_DEV_PRT 0xace37000 #define SR_DEV_TAPE 0xace38000 #define SR_DEV_COMM 0xace39000 #define SR_DEV_CTC 0xace3a000 #define SR_DEV_CTCI 0xace3b000 #define SR_DEV_CTCT 0xace3c000 #define SR_DEV_VMNET 0xace3d000 #define SR_DEV_LCS 0xace3e000 #define SR_DEV_CTCE 0xace3f000 #define SR_DELIMITER 0xaceffffe #define SR_EOF 0xacefffff #if defined (_HERCULES_SR_C) #define SR_WRITE_ERROR goto sr_write_error #define SR_READ_ERROR goto sr_read_error #define SR_SEEK_ERROR goto sr_seek_error #define SR_VALUE_ERROR goto sr_value_error #define SR_STRING_ERROR goto sr_string_error #else #define SR_WRITE_ERROR \ do { \ logmsg(_("HHCSR010E write error: %s\n"), strerror(errno)); \ return -1; \ } while (0) #define SR_READ_ERROR \ do { \ logmsg(_("HHCSR011E read error: %s\n"), strerror(errno)); \ return -1; \ } while (0) #define SR_SEEK_ERROR \ do { \ logmsg(_("HHCSR012E seek error: %s\n"), strerror(errno)); \ return -1; \ } while (0) #define SR_VALUE_ERROR \ do { \ logmsg(_("HHCSR013E value error, incorrect length\n")); \ return -1; \ } while (0) #define SR_STRING_ERROR \ do { \ logmsg(_("HHCSR014E string error, incorrect length\n")); \ return -1; \ } while (0) #endif #ifdef HAVE_LIBZ #define SR_DEFAULT_FILENAME "hercules.srf.gz" #define SR_FILE gzFile #define SR_OPEN(_path, _mode) \ gzopen((_path), (_mode)) #define SR_READ(_ptr, _size, _nmemb, _stream) \ gzread((_stream), (_ptr), (unsigned int)((_size) * (_nmemb))) #define SR_WRITE(_ptr, _size, _nmemb, _stream) \ gzwrite((_stream), (_ptr), (unsigned int)((_size) * (_nmemb))) #define SR_SEEK(_stream, _offset, _whence) \ gzseek((_stream), (_offset), (_whence)) #define SR_CLOSE(_stream) \ gzclose((_stream)) #else #define SR_DEFAULT_FILENAME "hercules.srf" #define SR_FILE FILE* #define SR_OPEN(_path, _mode) \ fopen((_path), (_mode)) #define SR_READ(_ptr, _size, _nmemb, _stream) \ fread((_ptr), (_size), (_nmemb), (_stream)) #define SR_WRITE(_ptr, _size, _nmemb, _stream) \ fwrite((_ptr), (_size), (_nmemb), (_stream)) #define SR_SEEK(_stream, _offset, _whence) \ fseek((_stream), (_offset), (_whence)) #define SR_CLOSE(_stream) \ fclose((_stream)) #endif #define SR_WRITE_HDR(_file, _key, _len) \ do { \ size_t _rc; \ BYTE _buf[8]; \ store_fw (_buf, (_key)); \ store_fw (_buf+4, (_len)); \ _rc = SR_WRITE(_buf, 1, 8, (_file)); \ if (_rc != 8) SR_WRITE_ERROR; \ } while (0) #define SR_WRITE_STRING(_file, _key, _s) \ do { \ size_t _rc; \ if (strlen((_s)) + 1 > SR_MAX_STRING_LENGTH) SR_STRING_ERROR; \ SR_WRITE_HDR((_file), (_key), strlen((_s)) + 1); \ _rc = SR_WRITE((_s), 1, strlen((_s)) + 1, (_file)); \ if (_rc != strlen((_s)) + 1) SR_WRITE_ERROR; \ } while (0); #define SR_WRITE_BUF(_file, _key, _buf, _len) \ do { \ size_t _rc; \ if ((_len)) { \ SR_WRITE_HDR((_file), (_key), (_len)); \ _rc = SR_WRITE((_buf), 1, (_len), (_file)); \ if (_rc != (_len)) SR_WRITE_ERROR; \ } else \ SR_WRITE_HDR((_file), (_key), 0); \ } while (0) #define SR_WRITE_VALUE(_file, _key, _val, _len) \ do { \ size_t _rc; \ BYTE _buf[8]; \ if ((_len) != 1 && (_len) != 2 && (_len) != 4 && (_len) != 8) \ SR_VALUE_ERROR; \ SR_WRITE_HDR((_file), (_key), (_len)); \ switch ((_len)) { \ case 1: _buf[0] = (_val); break; \ case 2: store_hw(_buf, (_val)); break; \ case 4: store_fw(_buf, (_val)); break; \ case 8: store_dw(_buf, (_val)); break; \ } \ _rc = SR_WRITE(_buf, 1, (_len), (_file)); \ if (_rc != (_len)) SR_WRITE_ERROR; \ } while (0) #define SR_READ_HDR(_file, _key, _len) \ do { \ size_t _rc; \ BYTE _buf[8]; \ _rc = SR_READ(_buf, 1, 8, (_file)); \ if (_rc != 8) SR_READ_ERROR; \ (_key) = fetch_fw(_buf); \ (_len) = fetch_fw(_buf+4); \ } while (0) //FIXME: Workaround for problem involving gzseek // and large files. Just read the data. #define SR_READ_SKIP(_file, _len) \ do { \ size_t _rc; \ size_t _l; \ BYTE _buf[256]; \ _l = (_len); \ while (_l) { \ _rc = SR_READ(_buf, 1, _l < 256 ? _l : 256, (_file)); \ if (_rc == (size_t)-1) SR_READ_ERROR; \ _l -= _l < 256 ? _l : 256; \ } \ } while (0) #define SR_READ_STRING(_file, _p, _len) \ do { \ size_t _rc; \ if ((_len) > SR_MAX_STRING_LENGTH) SR_STRING_ERROR; \ _rc = SR_READ((_p), 1, (_len), (_file)); \ if (_rc != (_len)) SR_READ_ERROR; \ } while (0) #define SR_READ_BUF(_file, _p, _len) \ do { \ size_t _rc; \ _rc = SR_READ((_p), 1, (_len), (_file)); \ if (_rc != (_len)) SR_READ_ERROR; \ } while (0) #define SR_READ_VALUE(_file, _len1, _p, _len2) \ do { \ size_t _rc; \ BYTE _buf[8]; \ U64 _value; \ if ((_len1) != 1 && (_len1) != 2 && (_len1) != 4 && (_len1) != 8) \ SR_VALUE_ERROR; \ _rc = SR_READ(_buf, 1, (_len1), (_file)); \ if (_rc != (_len1)) SR_READ_ERROR; \ switch ((_len1)) { \ case 1: _value = _buf[0]; break; \ case 2: _value = fetch_hw(_buf); break; \ case 4: _value = fetch_fw(_buf); break; \ case 8: _value = fetch_dw(_buf); break; \ default: _value=0; break; /* To ward off gcc -Wall */ \ } \ switch ((_len2)) { \ case 1: \ { \ BYTE *_ptr = (void *)(_p); \ *_ptr = _value & 0xff; \ break; \ } \ case 2: \ { \ U16 *_ptr = (void *)(_p); \ *_ptr = _value & 0xffff; \ break; \ } \ case 4: \ { \ U32 *_ptr = (void *)(_p); \ *_ptr = _value & 0xffffffff; \ break; \ } \ case 8: \ { \ U64 *_ptr = (void *)(_p); \ *_ptr = _value; \ break; \ } \ } \ } while (0) #define SR_SKIP_NULL_DEV(_dev, _file, _len) \ if ((_dev) == NULL) { \ SR_READ_SKIP((_file),(_len)); \ break; \ } #endif /* !defined(_HERCULES_SR_H) */ hercules-3.12/hchan.h0000664000175000017500000000107212564723224011435 00000000000000/* HCHAN.H (c) Copyright Ivan Warren, 2004-2006 */ /* Generic channel device handler header file */ #ifndef __HCHAN_H__ #define __HCHAN_H__ /* * Hercules Generic Channel internal definitions * (c) Ivan Scott Warren 2004-2006 * based on work * (c) Roger Bowler, Jan Jaeger and Others 1999-2006 * This code is covered by the QPL Licence */ static int hchan_init_exec(DEVBLK *,int,char **); static int hchan_init_connect(DEVBLK *,int,char **); static int hchan_init_int(DEVBLK *,int,char **); #endif hercules-3.12/fillfnam.h0000664000175000017500000000037412564723224012150 00000000000000/* FILLFNAM.H (c) Copyright Volker Bandke, 2003-2006 */ /* Hercules filename completion functions */ #ifndef __FILLFNAM_H__ #define __FILLFNAM_H__ int tab_pressed(char *cmdlinefull, int *cmdoffset); #endif hercules-3.12/hthreads.h0000664000175000017500000002254312564723224012164 00000000000000/* HTHREADS.H (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Threading Macros and Functions */ #ifndef _HTHREADS_H #define _HTHREADS_H #include "hercules.h" #if defined(OPTION_FTHREADS) /////////////////////////////////////////////////////////////////////// // FTHREADS /////////////////////////////////////////////////////////////////////// #include "fthreads.h" typedef fthread_t TID; typedef fthread_mutex_t LOCK; typedef fthread_cond_t COND; typedef fthread_attr_t ATTR; #define create_thread(ptid,pat,fn,arg,nm) fthread_create((ptid),(pat),(PFT_THREAD_FUNC)&(fn),(arg),nm) #define join_thread(tid,pcode) fthread_join((tid),(pcode)) #define initialize_lock(plk) fthread_mutex_init((plk),NULL) #define destroy_lock(plk) fthread_mutex_destroy((plk)) #define obtain_lock(plk) fthread_mutex_lock((plk)) #define try_obtain_lock(plk) fthread_mutex_trylock((plk)) #define test_lock(plk) \ (fthread_mutex_trylock((plk)) ? 1 : fthread_mutex_unlock((plk)) ) #define release_lock(plk) fthread_mutex_unlock((plk)) #define initialize_condition(pcond) fthread_cond_init((pcond)) #define destroy_condition(pcond) fthread_cond_destroy((pcond)) #define signal_condition(pcond) fthread_cond_signal((pcond)) #define broadcast_condition(pcond) fthread_cond_broadcast((pcond)) #define wait_condition(pcond,plk) fthread_cond_wait((pcond),(plk)) #define timed_wait_condition(pcond,plk,tm) fthread_cond_timedwait((pcond),(plk),(tm)) #define initialize_detach_attr(pat) fthread_attr_init((pat)); \ fthread_attr_setstacksize((pat),1048576); \ fthread_attr_setdetachstate((pat),FTHREAD_CREATE_DETACHED) #define initialize_join_attr(pat) fthread_attr_init((pat)); \ fthread_attr_setstacksize((pat),1048576); \ fthread_attr_setdetachstate((pat),FTHREAD_CREATE_JOINABLE) #define detach_thread(tid) fthread_detach((tid)) #define signal_thread(tid,signo) fthread_kill((tid),(signo)) #define thread_id() fthread_self() #define exit_thread(exitvar_ptr) fthread_exit((exitvar_ptr)) #define equal_threads(tid1,tid2) fthread_equal((tid1),(tid2)) #else // !defined(OPTION_FTHREADS) /////////////////////////////////////////////////////////////////////// // PTHREADS /////////////////////////////////////////////////////////////////////// #include typedef pthread_t TID; typedef pthread_mutex_t LOCK; typedef pthread_cond_t COND; typedef pthread_attr_t ATTR; #define initialize_lock(plk) \ pthread_mutex_init((plk),NULL) #define destroy_lock(plk) \ pthread_mutex_destroy((plk)) #define obtain_lock(plk) \ pthread_mutex_lock((plk)) #define try_obtain_lock(plk) \ pthread_mutex_trylock((plk)) #define release_lock(plk) \ pthread_mutex_unlock((plk)) #define test_lock(plk) \ (pthread_mutex_trylock((plk)) ? 1 : pthread_mutex_unlock((plk)) ) #define initialize_condition(pcond) \ pthread_cond_init((pcond),NULL) #define destroy_condition(pcond) \ pthread_cond_destroy((pcond)) #define signal_condition(pcond) \ pthread_cond_signal((pcond)) #define broadcast_condition(pcond) \ pthread_cond_broadcast((pcond)) #define wait_condition(pcond,plk) \ pthread_cond_wait((pcond),(plk)) #define timed_wait_condition(pcond,plk,timeout) \ pthread_cond_timedwait((pcond),(plk),(timeout)) #define initialize_detach_attr(pat) \ pthread_attr_init((pat)); \ pthread_attr_setstacksize((pat),1048576); \ pthread_attr_setdetachstate((pat),PTHREAD_CREATE_DETACHED) #define initialize_join_attr(pat) \ pthread_attr_init((pat)); \ pthread_attr_setstacksize((pat),1048576); \ pthread_attr_setdetachstate((pat),PTHREAD_CREATE_JOINABLE) #define join_thread(tid,pcode) \ pthread_join((tid),(pcode)) #define detach_thread(tid) \ pthread_detach((tid)) typedef void*THREAD_FUNC(void*); #define create_thread(ptid,pat,fn,arg,nm) \ pthread_create(ptid,pat,(THREAD_FUNC*)&(fn),arg) #define exit_thread(_code) \ pthread_exit((_code)) #define signal_thread(tid,signo) \ pthread_kill((tid),(signo)) #define thread_id() \ pthread_self() #define equal_threads(tid1,tid2) \ pthread_equal(tid1,tid2) #endif // defined(OPTION_FTHREADS) /////////////////////////////////////////////////////////////////////// // 'Thread' tracing... /////////////////////////////////////////////////////////////////////// #ifdef OPTION_PTTRACE #include "pttrace.h" #undef initialize_lock #define initialize_lock(plk) \ ptt_pthread_mutex_init((plk),NULL,PTT_LOC) #undef obtain_lock #define obtain_lock(plk) \ ptt_pthread_mutex_lock((plk),PTT_LOC) #undef try_obtain_lock #define try_obtain_lock(plk) \ ptt_pthread_mutex_trylock((plk),PTT_LOC) #undef test_lock #define test_lock(plk) \ (ptt_pthread_mutex_trylock ((plk),PTT_LOC) ? 1 : \ ptt_pthread_mutex_unlock ((plk),PTT_LOC)) #undef release_lock #define release_lock(plk) \ ptt_pthread_mutex_unlock((plk),PTT_LOC) #undef initialize_condition #define initialize_condition(pcond) \ ptt_pthread_cond_init((pcond),NULL,PTT_LOC) #undef signal_condition #define signal_condition(pcond) \ ptt_pthread_cond_signal((pcond),PTT_LOC) #undef broadcast_condition #define broadcast_condition(pcond) \ ptt_pthread_cond_broadcast((pcond),PTT_LOC) #undef wait_condition #define wait_condition(pcond,plk) \ ptt_pthread_cond_wait((pcond),(plk),PTT_LOC) #undef timed_wait_condition #define timed_wait_condition(pcond,plk,timeout) \ ptt_pthread_cond_timedwait((pcond),(plk),(timeout),PTT_LOC) #undef create_thread #if defined(OPTION_FTHREADS) #define create_thread(ptid,pat,fn,arg,nm) \ ptt_pthread_create((ptid),(pat),(PFT_THREAD_FUNC)&(fn),(arg),(nm),PTT_LOC) #else #define create_thread(ptid,pat,fn,arg,nm) \ ptt_pthread_create(ptid,pat,(THREAD_FUNC*)&(fn),arg,(nm),PTT_LOC) #endif #undef join_thread #define join_thread(tid,pcode) \ ptt_pthread_join((tid),(pcode),PTT_LOC) #undef detach_thread #define detach_thread(tid) \ ptt_pthread_detach((tid),PTT_LOC) #undef signal_thread #define signal_thread(tid,signo) \ ptt_pthread_kill((tid),(signo),PTT_LOC) #endif // OPTION_PTTRACE /////////////////////////////////////////////////////////////////////// // (Misc) /////////////////////////////////////////////////////////////////////// /* Pattern for displaying the thread_id */ #define TIDPAT "%8.8lX" /*-------------------------------------------------------------------*/ /* Pipe signaling support... */ /*-------------------------------------------------------------------*/ #if defined( OPTION_WAKEUP_SELECT_VIA_PIPE ) #define RECV_PIPE_SIGNAL( rfd, lock, flag ) \ do { \ int f; int saved_errno=get_HSO_errno(); BYTE c=0; \ 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; int saved_errno=get_HSO_errno(); BYTE c=0; \ 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 ) \ FD_SET((pipe_rfd),(prset)); \ (maxfd)=(maxfd)>(pipe_rfd)?(maxfd):(pipe_rfd) #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 ) #else // !defined( OPTION_WAKEUP_SELECT_VIA_PIPE ) #define RECV_PIPE_SIGNAL( rfd, lock, flag ) #define SEND_PIPE_SIGNAL( wfd, lock, flag ) #define SUPPORT_WAKEUP_SELECT_VIA_PIPE( pipe_rfd, maxfd, prset ) #define SUPPORT_WAKEUP_CONSOLE_SELECT_VIA_PIPE( maxfd, prset ) #define SUPPORT_WAKEUP_SOCKDEV_SELECT_VIA_PIPE( maxfd, prset ) #define RECV_CONSOLE_THREAD_PIPE_SIGNAL() #define RECV_SOCKDEV_THREAD_PIPE_SIGNAL() #define SIGNAL_CONSOLE_THREAD() signal_thread( sysblk.cnsltid, SIGUSR2 ) #define SIGNAL_SOCKDEV_THREAD() signal_thread( sysblk.socktid, SIGUSR2 ) #endif // defined( OPTION_WAKEUP_SELECT_VIA_PIPE ) #endif // _HTHREADS_H hercules-3.12/hostopts.h0000664000175000017500000003521212564723224012242 00000000000000/* HOSTOPTS.H (c) Copyright "Fish" (David B. Trout), 2005-2009 */ /* Host-specific features and options for Hercules */ /* All HOST-operating-specific (Win32, Apple. Linux, etc) FEATures and OPTIONs that cannot be otherwise determined via configure.ac tests should be #defined here, and ONLY here! ----------------------------------------------------------------- REMINDER: please do NOT use host-specific tests anywhere else in Hercules source code if you can help it! (e.g. #ifdef WIN32, etc) Instead, add a test to configure.ac which tests for the availability of the specific feature in question and then #defines a OPTION_XXX which can then be used in Hercules source code. ----------------------------------------------------------------- The ONLY allowed exception is in the Hercules.h and htypes.h header files where different header files need to be #included (e.g. sockets) and/or typedef/#defines need to be made depending on the host build system type. ONLY IF such a configure.ac test is impractical or otherwise not possible should you then hard-code the OPTION_XXX setting here in this member (and ONLY in this member!) depending on the host o/s. Thus, all of the below hard-coded options are candidates for some future configure.ac test. Feel free to design one. Please. :) */ #ifndef _HOSTOPTS_H #define _HOSTOPTS_H #if defined(_MSVC_) #include "hercwind.h" // (need HAVE_DECL_SIOCSIFHWADDR, etc) #endif /*-------------------------------------------------------------------*/ /* ZZ FIXME 'OPTION_SCSI_ERASE_TAPE' 'OPTION_SCSI_ERASE_GAP' NOTE: The following SHOULD in reality be some sort of test within configure.ac, but until we can devise some sort of simple configure test, we must hard-code them for now. According to the only docs I could find: MTERASE Erase the media from current position. If the field mt_count is nonzero, a full erase is done (from current position to end of media). If mt_count is zero, only an erase gap is written. It is hard to say which drives support only one but not the other option HOWEVER, since it's hard to say which drivers support short erase-gaps and which support erase-tape (and HOW they support them if they do! For example, Cygwin is currently coded to perform whichever type of erase the drive happens to support; e.g. if you try to do an erase-gap but the drive doesn't support short erases, it will end up doing a LONG erase [of the entire tape]!! (and vice-versa: doing a long erase-tape on a drive that doesn't support it will cause [Cygwin] to do an erase- gap instead)). THUS, the SAFEST thing to do is to simply treat all "erases", whether short or long, as 'nop's for now (in order to prevent the accidental erasure of an entire tape!) Once we happen to know for DAMN SURE that a particular host o/s ALWAYS does what we want it to should we then change the below #defines. (and like I said, they really SHOULD be in some type of configure test/setting and not here). */ /*-------------------------------------------------------------------*\ File name comparisons ('strcmp' vs. 'strcasecmp') On Windows, file names are not case sensitive. While the case of the file name may be preserved by the file system (and thus show file names in both upper/lower case in directory listings for example), the file system itself is NOT case-sensitive. File names "Foo", "foo", "fOo", "FoO", etc, all refer to the same file. On other platforms however (e.g. *nix), the file system IS case sensitive. File names "Foo", "foo", "fOo", "FoO", etc, all refer to different files on such systems. Thus we define a 'strfilecmp' macro to be used for filename comparisons and define it to be strcasecmp on Win32 platforms and strcmp for other platforms. \*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Constants used in "#if OPTION_NAME == OPTION_VALUE" statements */ /*-------------------------------------------------------------------*/ // HOW_TO_IMPLEMENT_SH_COMMAND #define USE_FORK_API_FOR_SH_COMMAND 4 #define USE_W32_POOR_MANS_FORK 5 #define USE_ANSI_SYSTEM_API_FOR_SH_COMMAND 9 // SET_CONSOLE_CURSOR_SHAPE_METHOD #define CURSOR_SHAPE_NOT_SUPPORTED 0 #define CURSOR_SHAPE_VIA_SPECIAL_LINUX_ESCAPE 1 #define CURSOR_SHAPE_WINDOWS_NATIVE 2 /*-------------------------------------------------------------------*/ /* The following is now handled automatically for ALL host platforms */ /*-------------------------------------------------------------------*/ #undef OPTION_TUNTAP_SETNETMASK /* (default initial setting) */ #undef OPTION_TUNTAP_SETMACADDR /* (default initial setting) */ #undef OPTION_TUNTAP_DELADD_ROUTES /* (default initial setting) */ #undef OPTION_TUNTAP_CLRIPADDR /* (default initial setting) */ #undef OPTION_TUNTAP_LCS_SAME_ADDR /* (default initial setting) */ #if defined(HAVE_DECL_SIOCSIFNETMASK) && \ HAVE_DECL_SIOCSIFNETMASK #define OPTION_TUNTAP_SETNETMASK /* TUNTAP_SetNetMask works */ #endif #if defined(HAVE_DECL_SIOCSIFHWADDR) && \ HAVE_DECL_SIOCSIFHWADDR #define OPTION_TUNTAP_SETMACADDR /* TUNTAP_SetMACAddr works */ #endif #if defined(HAVE_DECL_SIOCADDRT) && defined(HAVE_DECL_SIOCDELRT) && \ HAVE_DECL_SIOCADDRT && HAVE_DECL_SIOCDELRT #define OPTION_TUNTAP_DELADD_ROUTES /* Del/Add Routes works */ #endif #if defined(HAVE_DECL_SIOCDIFADDR) && \ HAVE_DECL_SIOCDIFADDR #define OPTION_TUNTAP_CLRIPADDR /* TUNTAP_ClrIPAddr works */ #endif /*-------------------------------------------------------------------*/ /* Hard-coded Win32-specific features and options... */ /*-------------------------------------------------------------------*/ #if defined(WIN32) /* "Windows" options */ #if defined(HDL_BUILD_SHARED) && defined(_MSVC_) #define DLL_IMPORT __declspec ( dllimport ) #define DLL_EXPORT __declspec ( dllexport ) #else #define DLL_IMPORT extern #define DLL_EXPORT #endif #define HTTP_SERVER_CONNECT_KLUDGE #define OPTION_W32_CTCI /* Fish's TunTap for CTCA's */ #undef TUNTAP_IFF_RUNNING_NEEDED /* TunTap32 doesn't allow it */ #define OPTION_SCSI_TAPE /* SCSI tape support */ #ifdef _MSVC_ #define OPTION_SCSI_ERASE_TAPE /* SUPPORTED! */ #define OPTION_SCSI_ERASE_GAP /* SUPPORTED! */ #else // (mingw or cygwin?) #undef OPTION_SCSI_ERASE_TAPE /* (NOT supported!) */ #undef OPTION_SCSI_ERASE_GAP /* (NOT supported!) */ #endif #undef OPTION_FBA_BLKDEVICE /* (no FBA BLKDEVICE support)*/ #define MAX_DEVICE_THREADS 0 /* (0 == unlimited) */ #undef MIXEDCASE_FILENAMES_ARE_UNIQUE /* ("Foo" same as "fOo"!!) */ #define DEFAULT_HERCPRIO 0 #define DEFAULT_TOD_PRIO -20 #define DEFAULT_CPU_PRIO 15 #define DEFAULT_DEV_PRIO 8 #ifdef _MSVC_ #define HOW_TO_IMPLEMENT_SH_COMMAND USE_W32_POOR_MANS_FORK #define SET_CONSOLE_CURSOR_SHAPE_METHOD CURSOR_SHAPE_WINDOWS_NATIVE #define OPTION_EXTCURS /* Extended cursor handling */ #else #define HOW_TO_IMPLEMENT_SH_COMMAND USE_FORK_API_FOR_SH_COMMAND #define SET_CONSOLE_CURSOR_SHAPE_METHOD CURSOR_SHAPE_VIA_SPECIAL_LINUX_ESCAPE #undef OPTION_EXTCURS /* Normal cursor handling */ #endif #define IsEventSet(h) (WaitForSingleObject(h,0) == WAIT_OBJECT_0) /* Because Fish's TUNTAP emulation isn't seen as a network interface */ /* by the host operating system, there is only one MAC address. */ /* (The Windows "tap" is a capture and re-inject mechanism) */ /* For other tuntap implementation, the host and guest have */ /* separate abstracted NIC implementation - and therefore require */ /* a separate MAC address to address that (lest briding won't work) */ /* If at one point, a TUNTAP implementation comes up and is then */ /* seen as a proper network interface by Windows, then this option */ /* will have to go away - or anyway "undefined" for windows */ #define OPTION_TUNTAP_LCS_SAME_ADDR 1 /*-------------------------------------------------------------------*/ /* Hard-coded Solaris-specific features and options... */ /*-------------------------------------------------------------------*/ #elif defined(__sun__) && defined(__svr4__) #define __SOLARIS__ 1 /* jbs 10/15/2003 need to define INADDR_NONE if using Solaris 10 and not Solaris Nevada aka OpenSolaris */ #if !defined(INADDR_NONE) #define INADDR_NONE 0xffffffffU #endif #undef OPTION_SCSI_TAPE /* No SCSI tape support */ #undef OPTION_SCSI_ERASE_TAPE /* (NOT supported) */ #undef OPTION_SCSI_ERASE_GAP /* (NOT supported) */ #define DLL_IMPORT extern #define DLL_EXPORT /* #undef OPTION_PTTRACE maybe not, after all */ #define MAX_DEVICE_THREADS 0 /* (0 == unlimited) */ #define MIXEDCASE_FILENAMES_ARE_UNIQUE /* ("Foo" and "fOo" unique) */ #define DEFAULT_HERCPRIO 0 #define DEFAULT_TOD_PRIO -20 #define DEFAULT_CPU_PRIO 15 #define DEFAULT_DEV_PRIO 8 #define HOW_TO_IMPLEMENT_SH_COMMAND USE_ANSI_SYSTEM_API_FOR_SH_COMMAND #define SET_CONSOLE_CURSOR_SHAPE_METHOD CURSOR_SHAPE_NOT_SUPPORTED #undef OPTION_EXTCURS /* Normal cursor handling */ /*-------------------------------------------------------------------*/ /* Hard-coded Apple-specific features and options... */ /*-------------------------------------------------------------------*/ #elif defined(__APPLE__) /* "Apple" options */ #define DLL_IMPORT extern #define DLL_EXPORT #define TUNTAP_IFF_RUNNING_NEEDED /* Needed by tuntap driver?? */ #undef OPTION_SCSI_TAPE /* No SCSI tape support */ #undef OPTION_SCSI_ERASE_TAPE /* (NOT supported) */ #undef OPTION_SCSI_ERASE_GAP /* (NOT supported) */ #undef OPTION_FBA_BLKDEVICE /* (no FBA BLKDEVICE support)*/ #define MAX_DEVICE_THREADS 0 /* (0 == unlimited) */ #define MIXEDCASE_FILENAMES_ARE_UNIQUE /* ("Foo" and "fOo" unique) */ #define DEFAULT_HERCPRIO 0 #define DEFAULT_TOD_PRIO -20 #define DEFAULT_CPU_PRIO 15 #define DEFAULT_DEV_PRIO 8 #define HOW_TO_IMPLEMENT_SH_COMMAND USE_ANSI_SYSTEM_API_FOR_SH_COMMAND #define SET_CONSOLE_CURSOR_SHAPE_METHOD CURSOR_SHAPE_NOT_SUPPORTED #undef OPTION_EXTCURS /* Normal cursor handling */ /*-------------------------------------------------------------------*/ /* Hard-coded FreeBSD-specific features and options... */ /*-------------------------------------------------------------------*/ #elif defined(__FreeBSD__) /* "FreeBSD" options */ #define DLL_IMPORT extern #define DLL_EXPORT #define TUNTAP_IFF_RUNNING_NEEDED /* Needed by tuntap driver?? */ #undef OPTION_SCSI_ERASE_TAPE /* (NOT supported) */ #undef OPTION_SCSI_ERASE_GAP /* (NOT supported) */ #define MAX_DEVICE_THREADS 0 /* (0 == unlimited) */ #define MIXEDCASE_FILENAMES_ARE_UNIQUE /* ("Foo" and "fOo" unique) */ #define DEFAULT_HERCPRIO 0 #define DEFAULT_TOD_PRIO -20 #define DEFAULT_CPU_PRIO 15 #define DEFAULT_DEV_PRIO 8 #define HOW_TO_IMPLEMENT_SH_COMMAND USE_ANSI_SYSTEM_API_FOR_SH_COMMAND #define SET_CONSOLE_CURSOR_SHAPE_METHOD CURSOR_SHAPE_NOT_SUPPORTED #undef OPTION_EXTCURS /* Normal cursor handling */ /*-------------------------------------------------------------------*/ /* GNU Linux options... */ /*-------------------------------------------------------------------*/ #elif defined(__gnu_linux__) /* GNU Linux options */ #define DLL_IMPORT extern #define DLL_EXPORT #define TUNTAP_IFF_RUNNING_NEEDED /* Needed by tuntap driver?? */ #define OPTION_SCSI_TAPE /* SCSI tape support */ #undef OPTION_SCSI_ERASE_TAPE /* (NOT supported) */ #undef OPTION_SCSI_ERASE_GAP /* (NOT supported) */ #define OPTION_FBA_BLKDEVICE /* FBA block device support */ #define MAX_DEVICE_THREADS 0 /* (0 == unlimited) */ #define MIXEDCASE_FILENAMES_ARE_UNIQUE /* ("Foo" and "fOo" unique) */ #define DEFAULT_HERCPRIO 0 #define DEFAULT_TOD_PRIO -20 #define DEFAULT_CPU_PRIO 15 #define DEFAULT_DEV_PRIO 8 #if defined( HAVE_FORK ) #define HOW_TO_IMPLEMENT_SH_COMMAND USE_FORK_API_FOR_SH_COMMAND #else #define HOW_TO_IMPLEMENT_SH_COMMAND USE_ANSI_SYSTEM_API_FOR_SH_COMMAND #endif #define SET_CONSOLE_CURSOR_SHAPE_METHOD CURSOR_SHAPE_VIA_SPECIAL_LINUX_ESCAPE #undef OPTION_EXTCURS /* Normal cursor handling */ /*-------------------------------------------------------------------*/ /* Hard-coded OTHER (DEFAULT) host-specific features and options... */ /*-------------------------------------------------------------------*/ #else /* "Other platform" options */ #warning hostopts.h: unknown target platform: defaulting to generic platform settings. #define DLL_IMPORT extern /* (a safe default) */ #define DLL_EXPORT #undef TUNTAP_IFF_RUNNING_NEEDED /* (tuntap support unknown) */ #undef OPTION_SCSI_TAPE /* (NO SCSI tape support) */ #undef OPTION_SCSI_ERASE_TAPE /* (NOT supported) */ #undef OPTION_SCSI_ERASE_GAP /* (NOT supported) */ #undef OPTION_FBA_BLKDEVICE /* (no FBA BLKDEVICE support)*/ #define MAX_DEVICE_THREADS 0 /* (0 == unlimited) */ #define MIXEDCASE_FILENAMES_ARE_UNIQUE /* ("Foo" and "fOo" unique) */ #define DEFAULT_HERCPRIO 0 #define DEFAULT_TOD_PRIO -20 #define DEFAULT_CPU_PRIO 15 #define DEFAULT_DEV_PRIO 8 #if defined( HAVE_FORK ) #define HOW_TO_IMPLEMENT_SH_COMMAND USE_FORK_API_FOR_SH_COMMAND #else #define HOW_TO_IMPLEMENT_SH_COMMAND USE_ANSI_SYSTEM_API_FOR_SH_COMMAND #endif #define SET_CONSOLE_CURSOR_SHAPE_METHOD CURSOR_SHAPE_NOT_SUPPORTED #undef OPTION_EXTCURS /* Normal cursor handling */ #endif // (host-specific tests) #endif // _HOSTOPTS_H hercules-3.12/w32util.h0000664000175000017500000002133412564723224011670 00000000000000////////////////////////////////////////////////////////////////////////////////////////// // w32util.h Windows porting functions ////////////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. ////////////////////////////////////////////////////////////////////////////////////////// #ifndef _W32UTIL_H #define _W32UTIL_H #if defined( _MSVC_ ) #include "hercules.h" #ifndef _W32UTIL_C_ #ifndef _HUTIL_DLL_ #define W32_DLL_IMPORT DLL_IMPORT #else #define W32_DLL_IMPORT extern #endif #else #define W32_DLL_IMPORT DLL_EXPORT #endif ////////////////////////////////////////////////////////////////////////////////////////// // Translates a Win32 '[WSA]GetLastError()' value into a 'errno' value (if possible // and/or if needed) that can then be used in the below 'w32_strerror' string function... W32_DLL_IMPORT int w32_trans_w32error( const DWORD dwLastError ); ////////////////////////////////////////////////////////////////////////////////////////// // ("unsafe" version -- use "safer" 'w32_strerror_r' instead if possible) W32_DLL_IMPORT char* w32_strerror( int errnum ); ////////////////////////////////////////////////////////////////////////////////////////// // Handles both regular 'errno' values as well as [WSA]GetLastError() values too... W32_DLL_IMPORT int w32_strerror_r( int errnum, char* buffer, size_t buffsize ); ////////////////////////////////////////////////////////////////////////////////////////// // Return Win32 error message text associated with an error number value // as returned by a call to either GetLastError() or WSAGetLastError()... W32_DLL_IMPORT char* w32_w32errmsg( int errnum, char* pszBuffer, size_t nBuffSize ); ////////////////////////////////////////////////////////////////////////////////////////// // Large File Support... #if (_MSC_VER < 1400) W32_DLL_IMPORT __int64 w32_ftelli64 ( FILE* stream ); W32_DLL_IMPORT int w32_fseeki64 ( FILE* stream, __int64 offset, int origin ); W32_DLL_IMPORT int w32_ftrunc64 ( int fd, __int64 new_size ); #endif ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( HAVE_SOCKETPAIR ) W32_DLL_IMPORT int socketpair( int domain, int type, int protocol, int socket_vector[2] ); #endif #if !defined( HAVE_FORK ) W32_DLL_IMPORT pid_t fork( void ); #endif #if !defined( HAVE_STRTOK_R ) W32_DLL_IMPORT char* strtok_r ( char* s, const char* sep, char** lasts); #endif #if !defined( HAVE_GETTIMEOFDAY ) W32_DLL_IMPORT int gettimeofday ( struct timeval* pTV, void* pTZ); #endif #if !defined( HAVE_NANOSLEEP ) W32_DLL_IMPORT int nanosleep ( const struct timespec* rqtp, struct timespec* rmtp ); #endif #if !defined( HAVE_USLEEP ) W32_DLL_IMPORT int usleep ( useconds_t useconds ); #endif // Can't use "HAVE_SLEEP" since Win32's "Sleep" causes HAVE_SLEEP to // be erroneously #defined due to autoconf AC_CHECK_FUNCS case issues... //#if !defined( HAVE_SLEEP ) W32_DLL_IMPORT unsigned sleep ( unsigned seconds ); //#endif #if !defined( HAVE_SCHED_YIELD ) W32_DLL_IMPORT int sched_yield ( void ); #endif #if !defined( HAVE_GETPGRP ) #define getpgrp getpid #endif #if !defined( HAVE_SCANDIR ) W32_DLL_IMPORT int scandir ( const char *dir, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **) ); #endif #if !defined( HAVE_ALPHASORT ) W32_DLL_IMPORT int alphasort ( const struct dirent **a, const struct dirent **b ); #endif #if !defined(HAVE_SYS_RESOURCE_H) // Note: we only provide the absolute minimum required information #define RUSAGE_SELF 0 // Current process #define RUSAGE_CHILDREN -1 // Children of the current process struct rusage // Resource utilization information { struct timeval ru_utime; // User time used struct timeval ru_stime; // System time used }; W32_DLL_IMPORT int getrusage ( int who, struct rusage* r_usage ); #endif #if !defined(HAVE_DECL_LOGIN_NAME_MAX) || !HAVE_DECL_LOGIN_NAME_MAX #define LOGIN_NAME_MAX UNLEN #endif #if !defined( HAVE_GETLOGIN ) W32_DLL_IMPORT char* getlogin ( void ); #endif #if !defined( HAVE_GETLOGIN_R ) W32_DLL_IMPORT int getlogin_r ( char* name, size_t namesize ); #endif #if !defined( HAVE_REALPATH ) W32_DLL_IMPORT char* realpath ( const char* file_name, char* resolved_name ); #endif // The inet_aton() function converts the specified string, // in the Internet standard dot notation, to a network address, // and stores the address in the structure provided. // // The inet_aton() function returns 1 if the address is successfully converted, // or 0 if the conversion failed. #if !defined( HAVE_INET_ATON ) W32_DLL_IMPORT int inet_aton( const char* cp, struct in_addr* addr ); #endif // Returns outpath as a host filesystem compatible filename path. // This is a Cygwin-to-MSVC transitional period helper function. // On non-Windows platforms it simply copies inpath to outpath. // On Windows it converts inpath of the form "/cygdrive/x/foo.bar" // to outpath in the form "x:/foo.bar" for Windows compatibility. W32_DLL_IMPORT BYTE *hostpath( BYTE *outpath, const BYTE *inpath, size_t buffsize ); // Poor man's "fcntl( fd, F_GETFL )"... // (only returns access-mode flags and not any others) W32_DLL_IMPORT int get_file_accmode_flags( int fd ); // Retrieve unique host id W32_DLL_IMPORT long gethostid( void ); // Initialize/Deinitialize sockets package... W32_DLL_IMPORT int socket_init ( void ); W32_DLL_IMPORT int socket_deinit ( void ); // Set socket to blocking or non-blocking mode... W32_DLL_IMPORT int socket_set_blocking_mode( int sfd, int blocking_mode ); // Determine whether a file descriptor is a socket or not... // (returns 1==true if it's a socket, 0==false otherwise) W32_DLL_IMPORT int socket_is_socket( int sfd ); // Set the SO_KEEPALIVE option and timeout values for a // socket connection to detect when client disconnects */ W32_DLL_IMPORT void socket_keepalive( int sfd, int idle_time, int probe_interval, int probe_count ); // Retrieve directory where process was loaded from... // (returns >0 == success, 0 == failure) W32_DLL_IMPORT int get_process_directory( char* dirbuf, size_t bufsiz ); // Expand environment variables... (e.g. %SystemRoot%, etc); 0==success W32_DLL_IMPORT int expand_environ_vars( const char* inbuff, char* outbuff, DWORD outbufsiz ); // Initialize Hercules HOSTINFO structure W32_DLL_IMPORT void w32_init_hostinfo( HOST_INFO* pHostInfo ); W32_DLL_IMPORT int w32_socket ( int af, int type, int protocol ); W32_DLL_IMPORT void w32_FD_SET ( int fd, fd_set* pSet ); W32_DLL_IMPORT int w32_FD_ISSET ( int fd, fd_set* pSet ); W32_DLL_IMPORT int w32_select ( int nfds, fd_set* pReadSet, fd_set* pWriteSet, fd_set* pExceptSet, const struct timeval* pTimeVal, const char* pszSourceFile, int nLineNumber ); W32_DLL_IMPORT FILE* w32_fdopen ( int their_fd, const char* their_mode ); W32_DLL_IMPORT size_t w32_fwrite ( const void* buff, size_t size, size_t count, FILE* stream ); W32_DLL_IMPORT int w32_fprintf( FILE* stream, const char* format, ... ); W32_DLL_IMPORT int w32_fclose ( FILE* stream ); W32_DLL_IMPORT int w32_get_stdin_char ( char* pCharBuff, int wait_millisecs ); W32_DLL_IMPORT pid_t w32_poor_mans_fork ( char* pszCommandLine, int* pnWriteToChildStdinFD ); W32_DLL_IMPORT void w32_set_thread_name( TID tid, char* name ); W32_DLL_IMPORT int w32_hopen ( const char* path, int oflag, ... ); ////////////////////////////////////////////////////////////////////////////////////////// #endif // defined(_MSVC_) ////////////////////////////////////////////////////////////////////////////////////////// // Support for disabling of CRT Invalid Parameter Handler... #if defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) #define DISABLE_CRT_INVALID_PARAMETER_HANDLER() DisableInvalidParameterHandling() #define ENABLE_CRT_INVALID_PARAMETER_HANDLING() EnableInvalidParameterHandling() W32_DLL_IMPORT void DisableInvalidParameterHandling(); W32_DLL_IMPORT void EnableInvalidParameterHandling(); #else // !defined( _MSVC_ ) || !defined( _MSC_VER ) || ( _MSC_VER < 1400 ) #define DISABLE_CRT_INVALID_PARAMETER_HANDLER() /* (no nothing) */ #define ENABLE_CRT_INVALID_PARAMETER_HANDLING() /* (no nothing) */ #endif // defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) ////////////////////////////////////////////////////////////////////////////////////////// #endif // _W32UTIL_H hercules-3.12/hconsts.h0000664000175000017500000002622612564723224012045 00000000000000/* HCONSTS.H (c) Copyright "Fish" (David B. Trout), 2005-2009 */ /* Hercules constants */ #ifndef _HCONSTS_H #define _HCONSTS_H #include "hercules.h" /*-------------------------------------------------------------------*/ /* Miscellaneous system related constants we could be missing... */ /*-------------------------------------------------------------------*/ #ifndef MAX_PATH #ifdef PATH_MAX #define MAX_PATH PATH_MAX #else #define MAX_PATH 4096 #endif #endif #ifndef PATH_SEP #ifdef _MSVC_ #define PATH_SEP "\\" #else #define PATH_SEP "/" #endif #endif #if defined( _MSVC_ ) // The following are missing from MINGW32/MSVC... #ifndef S_IRGRP #define S_IRGRP 0 #endif #ifndef S_IWGRP #define S_IWGRP 0 #endif #ifndef SIGUSR2 // (needs defined for OPTION_WAKEUP_SELECT_VIA_PIPE) #define SIGUSR2 31 // (the value's unimportant, but we'll be accurate) #endif #ifndef IFNAMSIZ #define IFNAMSIZ 16 #endif #ifndef IFHWADDRLEN #define IFHWADDRLEN 6 #endif #ifndef EFAULT #if defined (WSAEFAULT) #define EFAULT WSAEFAULT #else #define EFAULT 14 #endif #endif #ifndef ENOSYS #if defined (WSASYSCALLFAILURE) #define ENOSYS WSASYSCALLFAILURE #else #define ENOSYS 88 #endif #endif #ifndef EOPNOTSUPP #if defined (WSAEOPNOTSUPP) #define EOPNOTSUPP WSAEOPNOTSUPP #else #define EOPNOTSUPP 95 #endif #endif #ifndef ECONNRESET #if defined (WSAECONNRESET) #define ECONNRESET WSAECONNRESET #else #define ECONNRESET 104 #endif #endif #ifndef ENOBUFS #if defined (ENOMEM) #define ENOBUFS ENOMEM #else #define ENOBUFS 105 #endif #endif #ifndef EAFNOSUPPORT #if defined (WSAEAFNOSUPPORT) #define EAFNOSUPPORT WSAEAFNOSUPPORT #else #define EAFNOSUPPORT 106 #endif #endif #ifndef EPROTOTYPE #if defined (WSAEPROTOTYPE) #define EPROTOTYPE WSAEPROTOTYPE #else #define EPROTOTYPE 107 #endif #endif #ifndef ENOTSOCK #if defined (WSAENOTSOCK) #define ENOTSOCK WSAENOTSOCK #else #define ENOTSOCK 108 #endif #endif #ifndef EADDRINUSE #if defined (WSAEADDRINUSE) #define EADDRINUSE WSAEADDRINUSE #else #define EADDRINUSE 112 #endif #endif #ifndef ENETDOWN #if defined (WSAENETDOWN) #define ENETDOWN WSAENETDOWN #else #define ENETDOWN 115 #endif #endif #ifndef ETIMEDOUT #if defined (WSAETIMEDOUT) #define ETIMEDOUT WSAETIMEDOUT #else #define ETIMEDOUT 116 #endif #endif #ifndef EINPROGRESS #if defined (WSAEINPROGRESS) #define EINPROGRESS WSAEINPROGRESS #else #define EINPROGRESS 119 #endif #endif #ifndef EMSGSIZE #if defined (E2BIG) #define EMSGSIZE E2BIG #else #define EMSGSIZE 122 #endif #endif #ifndef EPROTONOSUPPORT #if defined (WSAEPROTONOSUPPORT) #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #else #define EPROTONOSUPPORT 123 #endif #endif #ifndef ENOTCONN #if defined (WSAENOTCONN) #define ENOTCONN WSAENOTCONN #else #define ENOTCONN 128 #endif #endif #ifndef ENOTSUP #if defined (ENOSYS) #define ENOTSUP ENOSYS #else #define ENOTSUP 134 #endif #endif #ifndef ENOMEDIUM #if defined (ENOENT) #define ENOMEDIUM ENOENT #else #define ENOMEDIUM 135 #endif #endif #ifndef EOVERFLOW #if defined (ERANGE) #define EOVERFLOW ERANGE #else #define EOVERFLOW 139 #endif #endif #endif // defined(_MSVC_) // CLK_TCK not part of SUSE 7.2 specs; added. (VB) #ifndef CLK_TCK #define CLK_TCK CLOCKS_PER_SEC #endif /*-------------------------------------------------------------------*/ /* Console tn3270/telnet session TCP "Keep-Alive" values... */ /*-------------------------------------------------------------------*/ #define KEEPALIVE_IDLE_TIME 3 /* Idle time to first probe */ #define KEEPALIVE_PROBE_INTERVAL 1 /* Probe timeout value */ #define KEEPALIVE_PROBE_COUNT 10 /* Max probe timeouts */ /*-------------------------------------------------------------------*/ /* Miscellaneous Hercules-related constants... */ /*-------------------------------------------------------------------*/ #define SPACE ' ' /* <---<<< Look close! There's a space there! */ /* Definitions for OS tailoring - msb eq mon event, lsb eq oper exc. */ #define OS_NONE 0x7FFFFFFFF7DE7FFFULL /* No spec OS tail. */ #define OS_OS390 0x7FF673FFF7DE7FFDULL /* OS/390 */ #define OS_ZOS 0x7B7673FFF7DE7FB7ULL /* z/OS */ #define OS_VSE 0x7FF673FFF7DE7FFFULL /* VSE */ #define OS_VM 0x7FFFFFFFF7DE7FFCULL /* VM */ #define OS_OPENSOLARIS 0xF8FFFFFFFFDE7FF7ULL /* OpenSolaris */ #define OS_LINUX 0x78FFFFFFF7DE7FF7ULL /* Linux */ /* Definitions for program product OS restriction flag. This flag is ORed with the SCLP READ CPU INFO response code. A 4 here makes the CPU look like an IFL (Integrated Facility for Linux) engine, which cannot run licensed ESA/390 or z/Architecture OSes. */ #define PGM_PRD_OS_RESTRICTED 4 /* Restricted */ #define PGM_PRD_OS_LICENSED 0 /* Licensed */ /* Storage access bits used by logical_to_main */ #define ACC_CHECK 0x0001 /* Possible storage update*/ #define ACC_WRITE 0x0002 /* Storage update */ #define ACC_READ 0x0004 /* Storage read */ /* Storage access bits used by other dat.h routines */ #define ACC_NOTLB 0x0100 /* Don't do TLB lookup */ #define ACC_PTE 0x0200 /* Return page table entry*/ #define ACC_LPTEA 0x0400 /* Esame page table entry */ #define ACC_SPECIAL_ART 0x0800 /* Used by BSG */ #define ACC_ENH_MC 0x1000 /* Used by Enhanced MC */ #define ACCTYPE_HW 0 /* Hardware access */ #define ACCTYPE_INSTFETCH ACC_READ /* Instruction fetch */ #define ACCTYPE_READ ACC_READ /* Read storage */ #define ACCTYPE_WRITE_SKP ACC_CHECK /* Write, skip change bit */ #define ACCTYPE_WRITE ACC_WRITE /* Write storage */ #define ACCTYPE_TAR 0 /* TAR instruction */ #define ACCTYPE_LRA ACC_NOTLB /* LRA instruction */ #define ACCTYPE_TPROT 0 /* TPROT instruction */ #define ACCTYPE_IVSK 0 /* ISVK instruction */ #define ACCTYPE_BSG ACC_SPECIAL_ART /* BSG instruction */ #define ACCTYPE_PTE (ACC_PTE|ACC_NOTLB) /* page table entry */ #define ACCTYPE_SIE 0 /* SIE host access */ #define ACCTYPE_STRAG 0 /* STRAG instruction */ #define ACCTYPE_LPTEA (ACC_LPTEA|ACC_NOTLB) /* LPTEA instruction */ #define ACCTYPE_EMC (ACC_ENH_MC|ACCTYPE_WRITE) /* MC instr. */ /* Special value for arn parameter for translate functions in dat.c */ /* _USE_... values for killing the "array subscript" warnings */ #define USE_INST_SPACE 20 /* Instruction space virtual */ #define USE_REAL_ADDR 19 /* Real address */ #define USE_PRIMARY_SPACE 18 /* Primary space virtual */ #define USE_SECONDARY_SPACE 17 /* Secondary space virtual */ #define USE_HOME_SPACE 16 /* Home space virtual */ #define USE_ARMODE 16 /* OR with access register number to force AR mode */ /* Interception codes used by longjmp/SIE */ #define SIE_NO_INTERCEPT (-1) /* Continue (after pgmint) */ #define SIE_HOST_INTERRUPT (-2) /* Host interrupt pending */ #define SIE_HOST_PGMINT (-3) /* Host program interrupt */ #define SIE_INTERCEPT_INST (-4) /* Instruction interception */ #define SIE_INTERCEPT_INSTCOMP (-5) /* Instr. int TS/CS/CDS */ #define SIE_INTERCEPT_EXTREQ (-6) /* External interrupt */ #define SIE_INTERCEPT_IOREQ (-7) /* I/O interrupt */ #define SIE_INTERCEPT_WAIT (-8) /* Wait state loaded */ #define SIE_INTERCEPT_STOPREQ (-9) /* STOP reqeust */ #define SIE_INTERCEPT_RESTART (-10) /* Restart interrupt */ #define SIE_INTERCEPT_MCK (-11) /* Machine Check interrupt */ #define SIE_INTERCEPT_EXT (-12) /* External interrupt pending*/ #define SIE_INTERCEPT_VALIDITY (-13) /* SIE validity check */ #define SIE_INTERCEPT_PER (-14) /* SIE guest per event */ #define SIE_INTERCEPT_IOINT (-15) /* I/O Interruption */ #define SIE_INTERCEPT_IOINTP (-16) /* I/O Interruption pending */ #define SIE_INTERCEPT_IOINST (-17) /* I/O Instruction */ #if defined(SIE_DEBUG_PERFMON) #define SIE_PERF_ENTER 0 /* SIE performance monitor */ #define SIE_PERF_ENTER_F -31 /* Enter Fast (retain state) */ #define SIE_PERF_EXIT -30 /* SIE exit */ #define SIE_PERF_RUNSIE -29 /* run_sie entered */ #define SIE_PERF_RUNLOOP_1 -28 /* run_sie runloop 1 */ #define SIE_PERF_RUNLOOP_2 -27 /* run_sue runloop 2 */ #define SIE_PERF_INTCHECK -26 /* run_sie intcheck */ #define SIE_PERF_EXEC -25 /* run_sie execute inst */ #define SIE_PERF_EXEC_U -24 /* run_sie unrolled exec */ #endif /*defined(SIE_DEBUG_PERFMON)*/ /*-------------------------------------------------------------------*/ /* Definitions for CTC protocol types */ /*-------------------------------------------------------------------*/ #define CTC_XCA 1 /* XCA device */ #define CTC_LCS 2 /* LCS device */ #define CTC_CETI 3 /* CETI device */ #define CTC_CLAW 4 /* CLAW device */ #define CTC_CTCN 5 /* CTC link via NETBIOS */ #define CTC_CTCT 6 /* CTC link via TCP */ #define CTC_CTCI 7 /* CTC link to TCP/IP stack */ #define CTC_VMNET 8 /* CTC link via wfk's vmnet */ #define CTC_CFC 9 /* Coupling facility channel */ #define CTC_CTCE 10 /* Enhanced CTC link via TCP */ #endif // _HCONSTS_H hercules-3.12/hmacros.h0000664000175000017500000005560112564723224012017 00000000000000/* HMACROS.H (c) Copyright Roger Bowler, 1999-2014 */ /* Hercules macros */ #ifndef _HMACROS_H #define _HMACROS_H #include "hercules.h" /*-------------------------------------------------------------------*/ /* "Portability" macros for handling _MSVC_ port... */ /*-------------------------------------------------------------------*/ /* 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 /* 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) closesocket(f) #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) #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 fdopen w32_fdopen #define fwrite w32_fwrite #define fprintf w32_fprintf #define fclose w32_fclose #endif #ifdef _MSVC_ #define fdatasync _commit #define atoll _atoi64 #else #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 /*-------------------------------------------------------------------*/ /* 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 /*-------------------------------------------------------------------*/ /* Large File Support portability... */ /*-------------------------------------------------------------------*/ #ifdef _MSVC_ /* "Native" 64-bit Large File Support */ #define off_t __int64 #if (_MSC_VER >= 1400) #define ftruncate _chsize_s #define ftell _ftelli64 #define fseek _fseeki64 #else // (_MSC_VER < 1400) #define ftruncate w32_ftrunc64 #define ftell w32_ftelli64 #define fseek w32_fseeki64 #endif #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 /*-------------------------------------------------------------------*/ /* Macro definitions for version number */ /*-------------------------------------------------------------------*/ #define STRINGMAC(x) #x #define MSTRING(x) STRINGMAC(x) /*-------------------------------------------------------------------*/ /* Use these to suppress unreferenced variable warnings... */ /*-------------------------------------------------------------------*/ #define UNREFERENCED(x) ((x)=(x)) #define UNREFERENCED_370(x) ((x)=(x)) #define UNREFERENCED_390(x) ((x)=(x)) #define UNREFERENCED_900(x) ((x)=(x)) /*-------------------------------------------------------------------*/ /* Macro for Debugging / Tracing... */ /*-------------------------------------------------------------------*/ /* Add message prefix filename:linenumber: to messages when compiled with debug enabled - JJ 30/12/99 */ /* But only if OPTION_DEBUG_MESSAGES defined in featall.h - Fish */ #define DEBUG_MSG_Q( _string ) #_string #define DEBUG_MSG_M( _string ) DEBUG_MSG_Q( _string ) #define DEBUG_MSG( _string ) __FILE__ ":" DEBUG_MSG_M( __LINE__ ) ":" _string #define D_( _string ) DEBUG_MSG( _string ) #if defined(OPTION_DEBUG_MESSAGES) && defined(DEBUG) #define DEBUG_( _string ) D_( _string ) #else #define DEBUG_( _string ) _string #endif #define _(_string) (DEBUG_(_string)) #if defined(DEBUG) || defined(_DEBUG) #ifdef _MSVC_ #define TRACE(...) \ do \ { \ IsDebuggerPresent() ? DebugTrace (__VA_ARGS__): \ logmsg (__VA_ARGS__); \ } \ while (0) #undef ASSERT /* For VS9 2008 */ #define ASSERT(a) \ do \ { \ if (!(a)) \ { \ TRACE("HHCxx999W *** Assertion Failed! *** %s(%d); function: %s\n",__FILE__,__LINE__,__FUNCTION__); \ if (IsDebuggerPresent()) DebugBreak(); /* (break into debugger) */ \ } \ } \ while(0) #else // ! _MSVC_ #define TRACE logmsg #define ASSERT(a) \ do \ { \ if (!(a)) \ { \ TRACE("HHCxx999W *** Assertion Failed! *** %s(%d)\n",__FILE__,__LINE__); \ } \ } \ while(0) #endif // _MSVC_ #define VERIFY ASSERT #else // non-debug build... #ifdef _MSVC_ #define TRACE __noop #undef ASSERT /* For VS9 2008 */ #define ASSERT(a) __noop #define VERIFY(a) ((void)(a)) #else // ! _MSVC_ #define TRACE 1 ? ((void)0) : logmsg #define ASSERT(a) #define VERIFY(a) ((void)(a)) #endif // _MSVC_ #endif /* 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); /*-------------------------------------------------------------------*/ /* Compiler optimization hints (for performance) */ /*-------------------------------------------------------------------*/ #undef likely #undef unlikely #ifdef _MSVC_ #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_ /*-------------------------------------------------------------------*/ /* 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) #if defined(_FEATURE_CPU_RECONFIG) #define MAX_CPU sysblk.maxcpu #else #define MAX_CPU sysblk.numcpu #endif #define HI_CPU sysblk.hicpu #define MAX_REPORTED_MIPSRATE (250000000) /* instructions / second */ #define MAX_REPORTED_SIOSRATE (10000) /* SIOs per second */ /* Instruction count for a CPU */ #define INSTCOUNT(_regs) \ ((_regs)->hostregs->prevcount + (_regs)->hostregs->instcount) /*-------------------------------------------------------------------*/ /* Obtain/Release mainlock. */ /* mainlock is only obtained by a CPU thread */ /*-------------------------------------------------------------------*/ #define OBTAIN_MAINLOCK(_regs) \ do { \ if ((_regs)->hostregs->cpubit != (_regs)->sysblk->started_mask) { \ obtain_lock(&(_regs)->sysblk->mainlock); \ (_regs)->sysblk->mainowner = regs->hostregs->cpuad; \ } \ } while (0) #define RELEASE_MAINLOCK(_regs) \ do { \ if ((_regs)->sysblk->mainowner == (_regs)->hostregs->cpuad) { \ (_regs)->sysblk->mainowner = LOCK_OWNER_NONE; \ release_lock(&(_regs)->sysblk->mainlock); \ } \ } while (0) /*-------------------------------------------------------------------*/ /* Obtain/Release intlock. */ /* intlock can be obtained by any thread */ /* if obtained by a cpu thread, check to see if synchronize_cpus */ /* is in progress. */ /*-------------------------------------------------------------------*/ #define OBTAIN_INTLOCK(_iregs) \ do { \ REGS *_regs = (_iregs); \ if ((_regs)) \ (_regs)->hostregs->intwait = 1; \ obtain_lock (&sysblk.intlock); \ if ((_regs)) { \ while (sysblk.syncing) { \ sysblk.sync_mask &= ~(_regs)->hostregs->cpubit; \ if (!sysblk.sync_mask) \ signal_condition(&sysblk.sync_cond); \ wait_condition(&sysblk.sync_bc_cond, &sysblk.intlock); \ } \ (_regs)->hostregs->intwait = 0; \ sysblk.intowner = (_regs)->hostregs->cpuad; \ } else \ sysblk.intowner = LOCK_OWNER_OTHER; \ } while (0) #define RELEASE_INTLOCK(_regs) \ do { \ sysblk.intowner = LOCK_OWNER_NONE; \ release_lock(&sysblk.intlock); \ } while (0) /*-------------------------------------------------------------------*/ /* Returns when all other CPU threads are blocked on intlock */ /*-------------------------------------------------------------------*/ #define SYNCHRONIZE_CPUS(_regs) \ do { \ int _i, _n = 0; \ CPU_BITMAP _mask = sysblk.started_mask \ ^ (sysblk.waiting_mask | (_regs)->hostregs->cpubit); \ for (_i = 0; _mask && _i < sysblk.hicpu; _i++) { \ if ((_mask & CPU_BIT(_i))) { \ if (sysblk.regs[_i]->intwait || sysblk.regs[_i]->syncio) \ _mask ^= CPU_BIT(_i); \ else { \ ON_IC_INTERRUPT(sysblk.regs[_i]); \ if (SIE_MODE(sysblk.regs[_i])) \ ON_IC_INTERRUPT(sysblk.regs[_i]->guestregs); \ _n++; \ } \ } \ } \ if (_n) { \ if (_n < hostinfo.num_procs) { \ for (_n = 1; _mask; _n++) { \ if (_n & 0xff) \ sched_yield(); \ else \ usleep(1); \ for (_i = 0; _i < sysblk.hicpu; _i++) \ if ((_mask & CPU_BIT(_i)) && sysblk.regs[_i]->intwait) \ _mask ^= CPU_BIT(_i); \ } \ } else { \ sysblk.sync_mask = sysblk.started_mask \ ^ (sysblk.waiting_mask | (_regs)->hostregs->cpubit); \ sysblk.syncing = 1; \ sysblk.intowner = LOCK_OWNER_NONE; \ wait_condition(&sysblk.sync_cond, &sysblk.intlock); \ sysblk.intowner = (_regs)->hostregs->cpuad; \ sysblk.syncing = 0; \ broadcast_condition(&sysblk.sync_bc_cond); \ } \ } \ } while (0) /*-------------------------------------------------------------------*/ /* Macros to signal interrupt condition to a CPU[s]... */ /*-------------------------------------------------------------------*/ #define WAKEUP_CPU(_regs) \ do { \ signal_condition(&(_regs)->intcond); \ } while (0) #define WAKEUP_CPU_MASK(_mask) \ do { \ int i; \ CPU_BITMAP mask = (_mask); \ for (i = 0; mask; i++) { \ if (mask & 1) \ { \ signal_condition(&sysblk.regs[i]->intcond); \ break; \ } \ mask >>= 1; \ } \ } while (0) #define WAKEUP_CPUS_MASK(_mask) \ do { \ int i; \ CPU_BITMAP mask = (_mask); \ for (i = 0; mask; i++) { \ if (mask & 1) \ signal_condition(&sysblk.regs[i]->intcond); \ mask >>= 1; \ } \ } while (0) /*-------------------------------------------------------------------*/ /* Macros to queue/dequeue a device on the I/O interrupt queue... */ /*-------------------------------------------------------------------*/ /* NOTE: sysblk.iointqlk ALWAYS needed to examine sysblk.iointq */ #define QUEUE_IO_INTERRUPT(_io) \ do { \ obtain_lock(&sysblk.iointqlk); \ QUEUE_IO_INTERRUPT_QLOCKED((_io)); \ release_lock(&sysblk.iointqlk); \ } while (0) #define QUEUE_IO_INTERRUPT_QLOCKED(_io) \ do { \ IOINT *prev; \ for (prev = (IOINT *)&sysblk.iointq; prev->next != NULL; prev = prev->next) \ if (prev->next == (_io) || prev->next->priority > (_io)->dev->priority) \ break; \ if (prev->next != (_io)) { \ (_io)->next = prev->next; \ prev->next = (_io); \ (_io)->priority = (_io)->dev->priority; \ } \ if ((_io)->pending) (_io)->dev->pending = 1; \ else if ((_io)->pcipending) (_io)->dev->pcipending = 1; \ else if ((_io)->attnpending) (_io)->dev->attnpending = 1; \ } while (0) #define DEQUEUE_IO_INTERRUPT(_io) \ do { \ obtain_lock(&sysblk.iointqlk); \ DEQUEUE_IO_INTERRUPT_QLOCKED((_io)); \ release_lock(&sysblk.iointqlk); \ } while (0) #define DEQUEUE_IO_INTERRUPT_QLOCKED(_io) \ do { \ IOINT *prev; \ for (prev = (IOINT *)&sysblk.iointq; prev->next != NULL; prev = prev->next) \ if (prev->next == (_io)) { \ prev->next = (_io)->next; \ if ((_io)->pending) (_io)->dev->pending = 0; \ else if ((_io)->pcipending) (_io)->dev->pcipending = 0; \ else if ((_io)->attnpending) (_io)->dev->attnpending = 0; \ break; \ } \ } while (0) /* NOTE: sysblk.iointqlk needed to examine sysblk.iointq, sysblk.intlock (which MUST be held before calling these macros) needed in order to set/reset IC_IOPENDING flag */ #define UPDATE_IC_IOPENDING() \ do { \ obtain_lock(&sysblk.iointqlk); \ UPDATE_IC_IOPENDING_QLOCKED(); \ release_lock(&sysblk.iointqlk); \ } while (0) #define UPDATE_IC_IOPENDING_QLOCKED() \ do { \ if (sysblk.iointq == NULL) \ OFF_IC_IOPENDING; \ else { \ ON_IC_IOPENDING; \ WAKEUP_CPU_MASK (sysblk.waiting_mask); \ } \ } while (0) /*-------------------------------------------------------------------*/ /* Handy utility macro for channel.c */ /*-------------------------------------------------------------------*/ #define IS_CCW_IMMEDIATE(_dev) \ ( \ ( (_dev)->hnd->immed && (_dev)->hnd->immed[(_dev)->code]) \ || ( (_dev)->immed && (_dev)->immed[(_dev)->code]) \ || IS_CCW_NOP((_dev)->code) \ ) /*-------------------------------------------------------------------*/ /* Hercules Dynamic Loader macro to call optional function override */ /*-------------------------------------------------------------------*/ #if defined(OPTION_DYNAMIC_LOAD) #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)) #else #define HDC1(_func, _arg1) \ (NULL) #define HDC2(_func, _arg1,_arg2) \ (NULL) #define HDC3(_func, _arg1,_arg2,_arg3) \ (NULL) #define HDC4(_func, _arg1,_arg2,arg3,arg4) \ (NULL) #define HDC5(_func, _arg1,_arg2,_arg3,_arg4,_arg5) \ (NULL) #define HDC6(_func, _arg1,_arg2,_arg3,_arg4,_arg5,_arg6) \ (NULL) #endif /*-------------------------------------------------------------------*/ /* sleep for as long as we like */ /*-------------------------------------------------------------------*/ #define SLEEP(_n) \ do { \ unsigned int rc = (_n); \ while (rc) \ if ((rc = sleep (rc))) \ sched_yield(); \ } while (0) /*-------------------------------------------------------------------*/ /* Perform standard utility initialization */ /*-------------------------------------------------------------------*/ #if !defined(EXTERNALGUI) #define INITIALIZE_EXTERNAL_GUI() #else #define INITIALIZE_EXTERNAL_GUI() \ do { \ if (argc >= 1 && strncmp(argv[argc-1],"EXTERNALGUI",11) == 0) { \ extgui = 1; \ argv[argc-1] = NULL; \ argc--; \ setvbuf(stderr, NULL, _IONBF, 0); \ setvbuf(stdout, NULL, _IONBF, 0); \ } \ } while (0) #endif #define INITIALIZE_UTILITY(name) \ do { \ SET_THREAD_NAME(name); \ INITIALIZE_EXTERNAL_GUI(); \ memset (&sysblk, 0, sizeof(SYSBLK)); \ initialize_detach_attr (DETACHED); \ initialize_join_attr (JOINABLE); \ set_codepage(NULL); \ init_hostinfo( &hostinfo ); \ } while (0) /*-------------------------------------------------------------------*/ /* Macro for Setting a Thread Name (mostly for debugging purposes) */ /*-------------------------------------------------------------------*/ #ifdef _MSVC_ #define SET_THREAD_NAME_ID(t,n) w32_set_thread_name((t),(n)) #define SET_THREAD_NAME(n) SET_THREAD_NAME_ID(GetCurrentThreadId(),(n)) #else #define SET_THREAD_NAME_ID(t,n) #define SET_THREAD_NAME(n) #endif #if !defined(NO_SETUID) /* 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 then that it may switch to * the saved uid by 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 * upon entry to the program (as 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. */ #if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H) && defined(OPTION_CAPABILITIES) #define SETMODE(_x) #define DROP_PRIVILEGES(_capa) drop_privileges(_capa) #define DROP_ALL_CAPS() drop_all_caps() #else #define DROP_PRIVILEGES(_capa) #define DROP_ALL_CAPS() #if defined(HAVE_SETRESUID) #define _SETMODE_INIT \ do { \ getresuid(&sysblk.ruid,&sysblk.euid,&sysblk.suid); \ getresgid(&sysblk.rgid,&sysblk.egid,&sysblk.sgid); \ setresuid(sysblk.ruid,sysblk.ruid,sysblk.euid); \ setresgid(sysblk.rgid,sysblk.rgid,sysblk.egid); \ } while(0) #define _SETMODE_ROOT \ do { \ setresuid(sysblk.suid,sysblk.suid,sysblk.ruid); \ } while(0) #define _SETMODE_USER \ do { \ setresuid(sysblk.ruid,sysblk.ruid,sysblk.suid); \ } while(0) #define _SETMODE_TERM \ do { \ setresuid(sysblk.ruid,sysblk.ruid,sysblk.ruid); \ setresgid(sysblk.rgid,sysblk.rgid,sysblk.rgid); \ } while(0) #elif defined(HAVE_SETREUID) #define _SETMODE_INIT \ do { \ sysblk.ruid = getuid(); \ sysblk.euid = geteuid(); \ sysblk.rgid = getgid(); \ sysblk.egid = getegid(); \ setreuid(sysblk.euid, sysblk.ruid); \ setregid(sysblk.egid, sysblk.rgid); \ } while (0) #define _SETMODE_ROOT \ do { \ setreuid(sysblk.ruid, sysblk.euid); \ setregid(sysblk.rgid, sysblk.egid); \ } while (0) #define _SETMODE_USER \ do { \ setregid(sysblk.egid, sysblk.rgid); \ setreuid(sysblk.euid, sysblk.ruid); \ } while (0) #define _SETMODE_TERM \ do { \ setuid(sysblk.ruid); \ setgid(sysblk.rgid); \ } 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) */ #define SETMODE(_func) _SETMODE_ ## _func #endif /* !defined(HAVE_SYS_CAPABILITY_H) */ #else /* !defined(NO_SETUID) */ #define SETMODE(_func) #define DROP_PRIVILEGES(_capa) #define DROP_ALL_CAPS() #endif /* !defined(NO_SETUID) */ /* min/max macros */ #if !defined(MIN) #define MIN(_x,_y) ( ( ( _x ) < ( _y ) ) ? ( _x ) : ( _y ) ) #endif /*!defined(MIN)*/ #if !defined(MAX) #define MAX(_x,_y) ( ( ( _x ) > ( _y ) ) ? ( _x ) : ( _y ) ) #endif /*!defined(MAX)*/ #if !defined(MINMAX) #define MINMAX(_x,_y,_z) ((_x) = MIN(MAX((_x),(_y)),(_z))) #endif /*!defined(MINMAX)*/ #endif // _HMACROS_H hercules-3.12/hstructs.h0000664000175000017500000026022212564723224012237 00000000000000/* HSTRUCTS.H (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Structure Definitions */ #ifndef _HSTRUCTS_H #define _HSTRUCTS_H #include "hercules.h" #include "opcode.h" /*-------------------------------------------------------------------*/ /* Typedefs for CPU bitmap fields */ /* */ /* A CPU bitmap contains one bit for each processing engine. */ /* The width of the bitmap depends on the maximum number of */ /* processing engines which was selected at build time. */ /*-------------------------------------------------------------------*/ #if MAX_CPU_ENGINES <= 32 typedef U32 CPU_BITMAP; #define F_CPU_BITMAP "%8.8"I32_FMT"X" #elif MAX_CPU_ENGINES <= 64 typedef U64 CPU_BITMAP; #define F_CPU_BITMAP "%16.16"I64_FMT"X" #elif MAX_CPU_ENGINES <= 128 #if defined(_MSVC_) #error MAX_CPU_ENGINES > 64 not supported in Windows #endif #if SIZEOF_SIZE_T == 4 #error MAX_CPU_ENGINES > 64 only supported on 64 bit platforms #endif typedef __uint128_t CPU_BITMAP; // ZZ FIXME: No printf format support for __int128 yet, so we will incorrectly display... #define F_CPU_BITMAP "%16.16"I64_FMT"X" #else #error MAX_CPU_ENGINES cannot exceed 128 #endif /*-------------------------------------------------------------------*/ /* Structure definition for CPU register context */ /*-------------------------------------------------------------------*/ struct REGS { /* Processor registers */ #define HDL_VERS_REGS "3.08" /* Internal Version Number */ #define HDL_SIZE_REGS sizeof(REGS) int arch_mode; /* Architectural mode */ DW px; /* Prefix register */ PSW psw; /* Program status word */ BYTE *ip; /* Mainstor inst address */ /* AIA - Instruction fetch accelerator */ BYTE *aip; /* Mainstor page address */ uintptr_t aim; /* Mainstor xor address */ BYTE *aie; /* Mainstor page end address */ DW aiv; /* Virtual page address */ U64 bear; /* Breaking event address reg*/ BYTE *bear_ip; /* Breaking event inst ptr */ DW gr[16]; /* General registers */ DW cr[16+16+1]; /* 16 Control registers */ #define CR_ALB_OFFSET 16 /* 16 Accesslist lookaside */ #define CR_ASD_REAL 32 /* 1 Real asd register */ U32 ar[16]; /* Access registers */ U32 fpr[32]; /* Floating point registers */ U32 fpc; /* IEEE Floating Point Control Register */ U32 dxc; /* Data exception code */ DW mc; /* Monitor Code */ DW ea; /* Exception address */ DW et; /* Execute Target address */ unsigned int /* Flags (cpu thread only) */ execflag:1, /* 1=EXecuted instruction */ exrl:1, /* 1=EXRL, 0=EX instruction */ permode:1, /* 1=PER active */ instinvalid:1, /* 1=Inst field is invalid */ opinterv:1, /* 1=Operator intervening */ checkstop:1, /* 1=CPU is checkstop-ed */ hostint:1, /* 1=Host generated interrupt*/ host:1, /* REGS are hostregs */ guest:1; /* REGS are guestregs */ unsigned int /* Flags (intlock serialized)*/ dummy:1, /* 1=Dummy regs structure */ configured:1, /* 1=CPU is online */ loadstate:1, /* 1=CPU is in load state */ ghostregs:1, /* 1=Ghost registers (panel) */ invalidate:1, /* 1=Do AIA/AEA invalidation */ tracing:1, /* 1=Trace is active */ stepwait:1, /* 1=Wait in inst stepping */ sigpreset:1, /* 1=SIGP cpu reset received */ sigpireset:1; /* 1=SIGP initial cpu reset */ S64 cpu_timer; /* CPU timer epoch */ S64 int_timer; /* S/370 Interval timer */ S32 old_timer; /* S/370 Interval timer int */ U64 clkc; /* 0-7=Clock comparator epoch, 8-63=Comparator bits 0-55 */ S64 tod_epoch; /* TOD epoch for this CPU */ S64 ecps_vtimer; /* ECPS Virtual Int. timer */ S32 ecps_oldtmr; /* ECPS Virtual Int. tmr int */ BYTE *ecps_vtmrpt; /* Pointer to VTMR or zero */ U32 instcount; /* Instruction counter */ U64 prevcount; /* Previous instruction count*/ U32 mipsrate; /* Instructions per second */ U32 siocount; /* SIO/SSCH counter */ U32 siosrate; /* IOs per second */ U64 siototal; /* Total SIO/SSCH count */ int cpupct; /* Percent CPU busy */ U64 waittod; /* Time of day last wait (us)*/ U64 waittime; /* Wait time (us) in interval*/ DAT dat; /* Fields for DAT use */ #define GR_G(_r) gr[(_r)].D #define GR_H(_r) gr[(_r)].F.H.F /* Fullword bits 0-31 */ #define GR_HHH(_r) gr[(_r)].F.H.H.H.H /* Halfword bits 0-15 */ #define GR_HHL(_r) gr[(_r)].F.H.H.L.H /* Halfword low, bits 16-31 */ #define GR_HHLCL(_r) gr[(_r)].F.H.H.L.B.L /* Character, bits 24-31 */ #define GR_L(_r) gr[(_r)].F.L.F /* Fullword low, bits 32-63 */ #define GR_LHH(_r) gr[(_r)].F.L.H.H.H /* Halfword bits 32-47 */ #define GR_LHL(_r) gr[(_r)].F.L.H.L.H /* Halfword low, bits 48-63 */ #define GR_LHHCH(_r) gr[(_r)].F.L.H.H.B.H /* Character, bits 32-39 */ #define GR_LA24(_r) gr[(_r)].F.L.A.A /* 24 bit addr, bits 40-63 */ #define GR_LA8(_r) gr[(_r)].F.L.A.B /* 24 bit addr, unused bits */ #define GR_LHLCL(_r) gr[(_r)].F.L.H.L.B.L /* Character, bits 56-63 */ #define GR_LHLCH(_r) gr[(_r)].F.L.H.L.B.H /* Character, bits 48-55 */ #define CR_G(_r) cr[(_r)].D /* Bits 0-63 */ #define CR_H(_r) cr[(_r)].F.H.F /* Fullword bits 0-31 */ #define CR_HHH(_r) cr[(_r)].F.H.H.H.H /* Halfword bits 0-15 */ #define CR_HHL(_r) cr[(_r)].F.H.H.L.H /* Halfword low, bits 16-31 */ #define CR_L(_r) cr[(_r)].F.L.F /* Fullword low, bits 32-63 */ #define CR_LHH(_r) cr[(_r)].F.L.H.H.H /* Halfword bits 32-47 */ #define CR_LHHCH(_r) cr[(_r)].F.L.H.H.B.H /* Character, bits 32-39 */ #define CR_LHL(_r) cr[(_r)].F.L.H.L.H /* Halfword low, bits 48-63 */ #define MC_G mc.D #define MC_L mc.F.L.F #define EA_G ea.D #define EA_L ea.F.L.F #define ET_G et.D #define ET_L et.F.L.F #define PX_G px.D #define PX_L px.F.L.F #define AIV_G aiv.D #define AIV_L aiv.F.L.F #define AR(_r) ar[(_r)] U16 chanset; /* Connected channel set */ U32 todpr; /* TOD programmable register */ U16 monclass; /* Monitor event class */ U16 cpuad; /* CPU address for STAP */ BYTE excarid; /* Exception access register */ BYTE opndrid; /* Operand access register */ BYTE exinst[8]; /* Target of Execute (EX) */ BYTE *mainstor; /* -> Main storage */ BYTE *storkeys; /* -> Main storage key array */ RADR mainlim; /* Central Storage limit or */ /* guest storage limit (SIE) */ PSA_3XX *psa; /* -> PSA for this CPU */ /* * The fields hostregs and guestregs have been move outside the * scope of _FEATURE_SIE to reduce conditional code. * * sysblk.regs[i] always points to the host regs * flag `host' is always 1 for the host regs * flag `guest' is always 1 for the guest regs * `hostregs' is always equal to sysblk.regs[i] (in both * hostregs and guestregs) * `guestregs' is always equal to sysblk.regs[i]->guestregs * (in both hostregs and guestregs). * sysblk.regs[i]->guestregs is NULL until the first SIE * instruction is executed on that CPU. * `sie_active' is 1 in hostregs if SIE is executing * and the current register context is `guestregs' * `sie_mode' is 1 in guestregs always * `sie_state' has the real address of the SIEBK * `siebk' has the mainstor address of the SIEBK */ REGS *hostregs; /* Pointer to the hypervisor register context */ REGS *guestregs; /* Pointer to the guest register context */ SYSBLK *sysblk; /* Pointer to sysblk */ #if defined(_FEATURE_SIE) RADR sie_state; /* Address of the SIE state descriptor block or 0 when not running under SIE */ SIEBK *siebk; /* Sie State Desc structure */ RADR sie_px; /* Host address of guest px */ RADR sie_mso; /* Main Storage Origin */ RADR sie_xso; /* eXpanded Storage Origin */ RADR sie_xsl; /* eXpanded Storage Limit */ RADR sie_rcpo; /* Ref and Change Preserv. */ RADR sie_scao; /* System Contol Area */ S64 sie_epoch; /* TOD offset in state desc. */ #endif /*defined(_FEATURE_SIE)*/ unsigned int sie_active:1, /* SIE active (host only) */ sie_mode:1, /* Running under SIE (guest) */ sie_pref:1; /* Preferred-storage mode */ // #if defined(FEATURE_PER) U16 perc; /* PER code */ RADR peradr; /* PER address */ BYTE peraid; /* PER access id */ // #endif /*defined(FEATURE_PER)*/ CPU_BITMAP cpubit; /* Only this CPU's bit is 1 */ U32 ints_state; /* CPU Interrupts Status */ U32 ints_mask; /* Respective Interrupts Mask*/ /* * Making the following flags 'stand-alone' (instead of bit- * flags like they were) addresses a compiler bit-flag serial- * ization issue that occurs with the 'SYNCHRONIZE_CPUS' macro * used during synchronize broadcast (cpu<->cpu communication) */ int intwait; /* 1=Waiting on intlock */ int syncio; /* 1=Synchronous i/o active */ BYTE cpustate; /* CPU stopped/started state */ BYTE malfcpu /* Malfuction alert flags */ [MAX_CPU_ENGINES]; /* for each CPU (1=pending) */ BYTE emercpu /* Emergency signal flags */ [MAX_CPU_ENGINES]; /* for each CPU (1=pending) */ U16 extccpu; /* CPU causing external call */ BYTE inst[8]; /* Fetched instruction when instruction crosses a page boundary */ BYTE *invalidate_main; /* Mainstor addr to invalidat*/ PSW captured_zpsw; /* Captured-z/Arch PSW reg */ #if defined(_FEATURE_VECTOR_FACILITY) VFREGS *vf; /* Vector Facility */ #endif /*defined(_FEATURE_VECTOR_FACILITY)*/ jmp_buf progjmp; /* longjmp destination for program check return */ jmp_buf archjmp; /* longjmp destination to switch architecture mode */ jmp_buf exitjmp; /* longjmp destination for CPU thread exit */ COND intcond; /* CPU interrupt condition */ LOCK *cpulock; /* CPU lock for this CPU */ /* Mainstor address lookup accelerator */ BYTE aea_mode; /* aea addressing mode */ int aea_ar[16+5]; /* arn to cr number */ /* 5 Special registers */ BYTE aea_common[16+16+1]; /* 1=asd is not private */ /* 16 Accesslist lookaside */ /* 1 Real asd register */ BYTE aea_aleprot[16]; /* ale protected */ /* Function pointers */ pi_func program_interrupt; func trace_br; /* ------------------------------------------------------------ */ U64 regs_copy_end; /* Copy regs to here */ /* ------------------------------------------------------------ */ /* Opcode table pointers */ FUNC s370_opcode_table[256]; FUNC *s370_opcode_a4xx, *s370_opcode_a5xx, *s370_opcode_a6xx, #if defined(MULTI_BYTE_ASSIST) s370_opcode_a7xx[256], s370_opcode_b2xx[256], s370_opcode_b9xx[256], s370_opcode_c0xx[256], /*@N3*/ s370_opcode_e3xx[256], /*@N3*/ s370_opcode_ebxx[256], #else *s370_opcode_a7xx, *s370_opcode_b2xx, *s370_opcode_b9xx, *s370_opcode_c0xx, /*@N3*/ *s370_opcode_e3xx, /*@N3*/ *s370_opcode_ebxx, #endif *s370_opcode_b3xx, /*FPE*/ *s370_opcode_c2xx, /*208*/ *s370_opcode_c4xx, /*208*/ *s370_opcode_c6xx, /*208*/ *s370_opcode_e4xx, *s370_opcode_e5xx, *s370_opcode_e6xx, *s370_opcode_ecxx, /*@N3*/ *s370_opcode_edxx; FUNC s390_opcode_table[256]; FUNC *s390_opcode_01xx, *s390_opcode_a4xx, *s390_opcode_a5xx, *s390_opcode_a6xx, #if defined(MULTI_BYTE_ASSIST) s390_opcode_a7xx[256], s390_opcode_b2xx[256], s390_opcode_b9xx[256], s390_opcode_c0xx[256], s390_opcode_e3xx[256], s390_opcode_ebxx[256], #else *s390_opcode_a7xx, *s390_opcode_b2xx, *s390_opcode_b9xx, *s390_opcode_c0xx, *s390_opcode_e3xx, *s390_opcode_ebxx, #endif *s390_opcode_b3xx, *s390_opcode_c2xx, *s390_opcode_c4xx, /*208*/ *s390_opcode_c6xx, /*208*/ *s390_opcode_e4xx, *s390_opcode_e5xx, *s390_opcode_ecxx, *s390_opcode_edxx; FUNC z900_opcode_table[256]; FUNC *z900_opcode_01xx, *z900_opcode_a5xx, #if defined(MULTI_BYTE_ASSIST) z900_opcode_a7xx[256], z900_opcode_b2xx[256], z900_opcode_b9xx[256], z900_opcode_c0xx[256], z900_opcode_e3xx[256], z900_opcode_ebxx[256], #else *z900_opcode_a7xx, *z900_opcode_b2xx, *z900_opcode_b9xx, *z900_opcode_c0xx, *z900_opcode_e3xx, *z900_opcode_ebxx, #endif *z900_opcode_b3xx, *z900_opcode_c2xx, *z900_opcode_c4xx, /*208*/ *z900_opcode_c6xx, /*208*/ *z900_opcode_c8xx, *z900_opcode_ccxx, /*810*/ *z900_opcode_e5xx, *z900_opcode_ecxx, *z900_opcode_edxx; /* TLB - Translation lookaside buffer */ unsigned int tlbID; /* Validation identifier */ TLB tlb; /* Translation lookaside buf */ }; /*-------------------------------------------------------------------*/ /* Structure definition for the Vector Facility */ /*-------------------------------------------------------------------*/ #if defined(_FEATURE_VECTOR_FACILITY) struct VFREGS { /* Vector Facility Registers*/ unsigned int online:1; /* 1=VF is online */ U64 vsr; /* Vector Status Register */ U64 vac; /* Vector Activity Count */ BYTE vmr[VECTOR_SECTION_SIZE/8]; /* Vector Mask Register */ U32 vr[16][VECTOR_SECTION_SIZE]; /* Vector Registers */ }; #endif /*defined(_FEATURE_VECTOR_FACILITY)*/ // #if defined(FEATURE_REGION_RELOCATE) /*-------------------------------------------------------------------*/ /* Zone Parameter Block */ /*-------------------------------------------------------------------*/ struct ZPBLK { RADR mso; /* Main Storage Origin */ RADR msl; /* Main Storage Length */ RADR eso; /* Expanded Storage Origin */ RADR esl; /* Expanded Storage Length */ RADR mbo; /* Measurement block origin */ BYTE mbk; /* Measurement block key */ int mbm; /* Measurement block mode */ int mbd; /* Device connect time mode */ }; // #endif /*defined(FEATURE_REGION_RELOCATE)*/ /*-------------------------------------------------------------------*/ /* System configuration block */ /*-------------------------------------------------------------------*/ struct SYSBLK { #define HDL_VERS_SYSBLK "3.06" /* Internal Version Number */ #define HDL_SIZE_SYSBLK sizeof(SYSBLK) time_t impltime; /* TOD system was IMPL'ed */ int arch_mode; /* Architecturual mode */ /* 0 == S/370 (ARCH_370) */ /* 1 == ESA/390 (ARCH_390) */ /* 2 == ESAME (ARCH_900) */ int arch_z900; /* 1 == ESAME supported */ RADR mainsize; /* Main storage size (bytes) */ BYTE *mainstor; /* -> Main storage */ BYTE *storkeys; /* -> Main storage key array */ U32 xpndsize; /* Expanded size (4K pages) */ BYTE *xpndstor; /* -> Expanded storage */ U64 todstart; /* Time of initialisation */ U64 cpuid; /* CPU identifier for STIDP */ TID impltid; /* Thread-id for main progr. */ TID wdtid; /* Thread-id for watchdog */ U16 lparnuml; /* #digits (0-2) in lparnum */ U16 lparnum; /* LPAR identification number*/ U16 ipldev; /* IPL device */ int iplcpu; /* IPL cpu */ int ipllcss; /* IPL lcss */ int numcpu; /* Number of CPUs installed */ int numvec; /* Number vector processors */ int maxcpu; /* Max number of CPUs */ int cpus; /* Number CPUs configured */ int hicpu; /* Hi cpu + 1 configured */ int sysepoch; /* TOD clk epoch (1900/1960) */ int topology; /* Configuration topology... */ #define TOPOLOGY_HORIZ 0 /* ...horizontal polarization*/ #define TOPOLOGY_VERT 1 /* ...vertical polarization */ int topchnge; /* 1 = Topology Change Report pending (CPU cfg on/off) */ COND cpucond; /* CPU config/deconfig cond */ LOCK cpulock[MAX_CPU_ENGINES]; /* CPU lock */ TID cputid[MAX_CPU_ENGINES]; /* CPU thread identifiers */ BYTE ptyp[MAX_CPU_ENGINES]; /* SCCB ptyp for each engine */ LOCK todlock; /* TOD clock update lock */ TID todtid; /* Thread-id for TOD update */ REGS *regs[MAX_CPU_ENGINES+1]; /* Registers for each CPU */ #if defined(_FEATURE_MESSAGE_SECURITY_ASSIST) LOCK wklock; /* Update lock */ BYTE wkaes_reg[32]; /* Wrapping-key registers */ BYTE wkdea_reg[24]; BYTE wkvpaes_reg[32]; /* Wrapping-key Verification */ BYTE wkvpdea_reg[24]; /* Pattern registers */ #endif /*defined(_FEATURE_MESSAGE_SECURITY_ASSIST)*/ /* CPU Measurement Counter facility CPU Measurement Sampling facility Load Program Parameter facility */ U64 program_parameter; /* Program Parameter Register*/ #if defined(_FEATURE_VECTOR_FACILITY) VFREGS vf[MAX_CPU_ENGINES]; /* Vector Facility */ #endif /*defined(_FEATURE_VECTOR_FACILITY)*/ #if defined(_FEATURE_SIE) ZPBLK zpb[FEATURE_SIE_MAXZONES]; /* SIE Zone Parameter Blk*/ #endif /*defined(_FEATURE_SIE)*/ #if defined(OPTION_FOOTPRINT_BUFFER) REGS footprregs[MAX_CPU_ENGINES][OPTION_FOOTPRINT_BUFFER]; U32 footprptr[MAX_CPU_ENGINES]; #endif #define LOCK_OWNER_NONE 0xFFFF #define LOCK_OWNER_OTHER 0xFFFE U16 mainowner; /* Mainlock owner */ U16 intowner; /* Intlock owner */ LOCK mainlock; /* Main storage lock */ LOCK intlock; /* Interrupt lock */ LOCK iointqlk; /* I/O Interrupt Queue lock */ LOCK sigplock; /* Signal processor lock */ ATTR detattr; /* Detached thread attribute */ ATTR joinattr; /* Joinable thread attribute */ #define DETACHED &sysblk.detattr /* (helper macro) */ #define JOINABLE &sysblk.joinattr /* (helper macro) */ TID cnsltid; /* Thread-id for console */ TID socktid; /* Thread-id for sockdev */ /* 3270 Console Keep-Alive: */ int kaidle; /* Keepalive idle seconds */ int kaintv; /* Keepalive probe interval */ int kacnt; /* Keepalive probe count */ #if defined( OPTION_WAKEUP_SELECT_VIA_PIPE ) LOCK cnslpipe_lock; /* signaled flag access lock */ int cnslpipe_flag; /* 1 == already signaled */ int cnslwpipe; /* fd for sending signal */ int cnslrpipe; /* fd for receiving signal */ LOCK sockpipe_lock; /* signaled flag access lock */ int sockpipe_flag; /* 1 == already signaled */ int sockwpipe; /* Sockdev signaling pipe Wr */ int sockrpipe; /* Sockdev signaling pipe Rd */ #endif // defined( OPTION_WAKEUP_SELECT_VIA_PIPE ) RADR mbo; /* Measurement block origin */ BYTE mbk; /* Measurement block key */ int mbm; /* Measurement block mode */ int mbd; /* Device connect time mode */ int diag8cmd; /* Allow diagnose 8 commands */ #define DIAG8CMD_ECHO 0x80 /* Echo command to console */ #define DIAG8CMD_ENABLE 0x01 /* Enable DIAG8 interface */ BYTE shcmdopt; /* 'sh'ell command option */ #define SHCMDOPT_DISABLE 0x80 /* Globally disable 'sh' cmd */ #define SHCMDOPT_NODIAG8 0x40 /* Disallow only for DIAG8 */ int panrate; /* Panel refresh rate */ int timerint; /* microsecs timer interval */ char *pantitle; /* Alt console panel title */ #if defined(OPTION_HAO) TID haotid; /* Herc Auto-Oper thread-id */ #endif /* defined(OPTION_HAO) */ #if defined(OPTION_SCSI_TAPE) /* Access to all SCSI fields controlled by sysblk.stape_lock */ LOCK stape_lock; /* LOCK for all SCSI fields */ int auto_scsi_mount_secs; /* Check for SCSI tape mount frequency; 0 == disabled */ #define DEFAULT_AUTO_SCSI_MOUNT_SECS (5) TID stape_getstat_tid; /* Tape-status worker thread */ TID stape_mountmon_tid; /* Tape-mount worker thread */ COND stape_getstat_cond; /* Tape-status thread COND */ u_int stape_getstat_busy:1; /* 1=Status thread is busy */ LIST_ENTRY stape_status_link; /* get status request chain */ LIST_ENTRY stape_mount_link; /* scsimount request chain */ struct timeval stape_query_status_tod; /* TOD of last status query */ #endif /* defined(OPTION_SCSI_TAPE) */ DEVBLK *firstdev; /* -> First device block */ DEVBLK *sysgdev; /* -> devblk for SYSG console*/ #if defined(OPTION_FAST_DEVLOOKUP) DEVBLK ***devnum_fl; /* 1st level table for fast */ /* devnum lookup */ DEVBLK ***subchan_fl; /* Subchannel table fast */ /* lookup table */ #endif /* FAST_DEVICE_LOOKUP */ U16 highsubchan[FEATURE_LCSS_MAX]; /* Highest subchan+1 */ U32 chp_reset[8]; /* Channel path reset masks */ IOINT *iointq; /* I/O interrupt queue */ #if !defined(OPTION_FISHIO) DEVBLK *ioq; /* I/O queue */ LOCK ioqlock; /* I/O queue lock */ COND ioqcond; /* I/O queue condition */ int devtwait; /* Device threads waiting */ int devtnbr; /* Number of device threads */ int devtmax; /* Max device threads */ int devthwm; /* High water mark */ int devtunavail; /* Count thread unavailable */ #endif // !defined(OPTION_FISHIO) RADR addrlimval; /* Address limit value (SAL) */ #if defined(FEATURE_VM_BLOCKIO) U16 servcode; /* External interrupt code */ BYTE biosubcd; /* Block I/O sub int. code */ BYTE biostat; /* Block I/O status */ U64 bioparm; /* Block I/O interrupt parm */ DEVBLK *biodev; /* Block I/O device */ /* Note: biodev is only used to detect BIO interrupt tracing */ #endif /* defined(FEATURE_VM_BLOCKIO) */ U32 servparm; /* Service signal parameter */ unsigned int /* Flags */ daemon_mode:1, /* Daemon mode active */ panel_init:1, /* Panel display initialized */ npquiet:1, /* New Panel quiet indicator */ sigintreq:1, /* 1 = SIGINT request pending*/ insttrace:1, /* 1 = Instruction trace */ inststep:1, /* 1 = Instruction step */ shutdown:1, /* 1 = shutdown requested */ shutfini:1, /* 1 = shutdown complete */ #if defined( _MSVC_ ) shutimmed:1, /* 1 = shutdown req immed */ #endif // defined( _MSVC_ ) main_clear:1, /* 1 = mainstor is cleared */ xpnd_clear:1, /* 1 = xpndstor is cleared */ showregsfirst:1, /* 1 = show regs before inst */ showregsnone:1, /* 1 = show no registers */ nomountedtapereinit:1, /* 1 = disallow tape devinit if tape already mounted */ legacysenseid:1, /* ena/disa senseid on */ /* legacy devices */ #if defined(OPTION_IPLPARM) haveiplparm:1, /* IPL PARM a la VM */ #endif logoptnotime:1; /* 1 = don't timestamp log */ U32 ints_state; /* Common Interrupts Status */ CPU_BITMAP config_mask; /* Configured CPUs */ CPU_BITMAP started_mask; /* Started CPUs */ CPU_BITMAP waiting_mask; /* Waiting CPUs */ U64 traceaddr[2]; /* Tracing address range */ U64 stepaddr[2]; /* Stepping address range */ #if defined(OPTION_IPLPARM) BYTE iplparmstring[64]; /* 64 bytes loadable at IPL */ #endif #ifdef FEATURE_ECPSVM // /* ECPS:VM */ struct { u_int level:16; u_int debug:1; u_int available:1; } ecpsvm; /* ECPS:VM structure */ // #endif U64 pgminttr; /* Program int trace mask */ int pcpu; /* Tgt CPU panel cmd & displ */ int hercprio; /* Hercules process priority */ int todprio; /* TOD Clock thread priority */ int cpuprio; /* CPU thread priority */ int devprio; /* Device thread priority */ TID httptid; /* HTTP listener thread id */ U16 httpport; /* HTTP port number or zero */ int httpauth; /* HTTP auth required flag */ char *httpuser; /* HTTP userid */ char *httppass; /* HTTP password */ char *httproot; /* HTTP root */ #if defined( OPTION_TAPE_AUTOMOUNT ) TAMDIR *tamdir; /* Acc/Rej AUTOMOUNT dir ctl */ char *defdir; /* Default AUTOMOUNT dir */ #endif /* Fields used by SYNCHRONIZE_CPUS */ int syncing; /* 1=Sync in progress */ CPU_BITMAP sync_mask; /* CPU mask for syncing CPUs */ COND sync_cond; /* COND for syncing CPU */ COND sync_bc_cond; /* COND for other CPUs */ #if defined(_FEATURE_ASN_AND_LX_REUSE) int asnandlxreuse; /* ASN And LX Reuse enable */ #endif #if defined(OPTION_SHARED_DEVICES) TID shrdtid; /* Shared device listener */ U16 shrdport; /* Shared device server port */ U32 shrdcount; /* IO count */ SHRD_TRACE *shrdtrace; /* Internal trace table */ SHRD_TRACE *shrdtracep; /* Current pointer */ SHRD_TRACE *shrdtracex; /* End of trace table */ int shrdtracen; /* Number of entries */ #endif #ifdef OPTION_IODELAY_KLUDGE int iodelay; /* I/O delay kludge for linux*/ #endif /*OPTION_IODELAY_KLUDGE*/ #if defined( HTTP_SERVER_CONNECT_KLUDGE ) int http_server_kludge_msecs; #endif // defined( HTTP_SERVER_CONNECT_KLUDGE ) #if !defined(NO_SETUID) uid_t ruid, euid, suid; gid_t rgid, egid, sgid; #endif /*!defined(NO_SETUID)*/ #if defined(OPTION_COUNTING) long long count[OPTION_COUNTING]; #define COUNT(n) sysblk.count[(n)]++ #else #define COUNT(n) #endif #if defined(OPTION_INSTRUCTION_COUNTING) LOCK icount_lock; #define IMAP_FIRST sysblk.imap01 U64 imap01[256]; U64 imapa4[256]; U64 imapa5[16]; U64 imapa6[256]; U64 imapa7[16]; U64 imapb2[256]; U64 imapb3[256]; U64 imapb9[256]; U64 imapc0[16]; U64 imapc2[16]; /*@Z9*/ U64 imapc4[16]; /*208*/ U64 imapc6[16]; /*208*/ U64 imapc8[16]; U64 imape3[256]; U64 imape4[256]; U64 imape5[256]; U64 imapeb[256]; U64 imapec[256]; U64 imaped[256]; U64 imapxx[256]; #define IMAP_SIZE \ ( sizeof(sysblk.imap01) \ + sizeof(sysblk.imapa4) \ + sizeof(sysblk.imapa5) \ + sizeof(sysblk.imapa6) \ + sizeof(sysblk.imapa7) \ + sizeof(sysblk.imapb2) \ + sizeof(sysblk.imapb3) \ + sizeof(sysblk.imapb9) \ + sizeof(sysblk.imapc0) \ + sizeof(sysblk.imapc2) /*@Z9*/ \ + sizeof(sysblk.imapc4) /*208*/ \ + sizeof(sysblk.imapc6) /*208*/ \ + sizeof(sysblk.imapc8) \ + sizeof(sysblk.imape3) \ + sizeof(sysblk.imape4) \ + sizeof(sysblk.imape5) \ + sizeof(sysblk.imapeb) \ + sizeof(sysblk.imapec) \ + sizeof(sysblk.imaped) \ + sizeof(sysblk.imapxx) ) #endif char *logofile; /* Fancy 3270 logo box */ char **herclogo; /* 3270 Logo data */ size_t logolines; /* Number of lines in logo */ #if defined(OPTION_MIPS_COUNTING) /* Merged Counters for all CPUs */ U64 instcount; /* Instruction counter */ U32 mipsrate; /* Instructions per second */ U32 siosrate; /* IOs per second */ #endif /*defined(OPTION_MIPS_COUNTING)*/ #ifdef OPTION_CMDTGT int cmdtgt; /* 0=herc,1=scp,2=!scp */ #endif // OPTION_CMDTGT int regs_copy_len; /* Length to copy for REGS */ REGS dummyregs; /* Regs for unconfigured CPU */ #ifdef OPTION_MSGHLD int keep_timeout_secs; /* Message hold time */ #endif }; /*-------------------------------------------------------------------*/ /* I/O interrupt queue entry */ /*-------------------------------------------------------------------*/ struct IOINT { /* I/O interrupt queue entry */ IOINT *next; /* -> next interrupt entry */ DEVBLK *dev; /* -> Device block */ int priority; /* Device priority */ unsigned int pending:1, /* 1=Normal interrupt */ pcipending:1, /* 1=PCI interrupt */ attnpending:1; /* 1=ATTN interrupt */ }; /*-------------------------------------------------------------------*/ /* SCSI support threads request structures... (i.e. work items) */ /*-------------------------------------------------------------------*/ #if defined(OPTION_SCSI_TAPE) struct STSTATRQ /* Status Update Request */ { LIST_ENTRY link; /* just a link in the chain */ DEVBLK* dev; /* ptr to device block */ }; typedef struct STSTATRQ STSTATRQ; struct STMNTDRQ /* Automatic Mount Request */ { LIST_ENTRY link; /* just a link in the chain */ DEVBLK* dev; /* ptr to device block */ }; typedef struct STMNTDRQ STMNTDRQ; #endif /* defined(OPTION_SCSI_TAPE) */ /*-------------------------------------------------------------------*/ /* Device configuration block */ /*-------------------------------------------------------------------*/ struct DEVBLK { /* Device configuration block*/ #define HDL_VERS_DEVBLK "3.08" /* Internal Version Number */ #define HDL_SIZE_DEVBLK sizeof(DEVBLK) DEVBLK *nextdev; /* -> next device block */ REGS *regs; /* -> REGS if syncio */ LOCK lock; /* Device block lock */ int allocated; /* Device block free/in use */ /* device identification */ U16 ssid; /* Subsystem ID incl. lcssid */ U16 subchan; /* Subchannel number */ U16 devnum; /* Device number */ U16 devtype; /* Device type */ U16 chanset; /* Channel Set to which this device is connected S/370 */ char *typname; /* Device type name */ int member; /* Group member number */ DEVGRP *group; /* Device Group */ int argc; /* Init number arguments */ char **argv; /* Init arguments */ /* Storage accessible by device */ BYTE *mainstor; /* -> Main storage */ BYTE *storkeys; /* -> Main storage key array */ RADR mainlim; /* Central Storage limit or */ /* guest storage limit (SIE) */ char filename[PATH_MAX+1]; /* filename (plus poss "|") */ /* device i/o fields... */ int fd; /* File desc / socket number */ FILE *fh; /* associated File handle */ bind_struct* bs; /* -> bind_struct if socket- device, NULL otherwise */ /* device buffer management fields */ int bufcur; /* Buffer data identifier */ BYTE *buf; /* -> Device data buffer */ int bufsize; /* Device data buffer size */ int buflen; /* Device buffer length used */ int bufoff; /* Offset into data buffer */ int bufres; /* buffer residual length */ int bufoffhi; /* Highest offset allowed */ int bufupdlo; /* Lowest offset updated */ int bufupdhi; /* Highest offset updated */ U32 bufupd; /* 1=Buffer updated */ /* device cache management fields */ int cache; /* Current cache index */ int cachehits; /* Cache hits */ int cachemisses; /* Cache misses */ int cachewaits; /* Cache waits */ /* device compression support */ int comps; /* Acceptable compressions */ int comp; /* Compression used */ int compoff; /* Offset to compressed data */ /* device i/o scheduling fields... */ TID tid; /* Thread-id executing CCW */ int priority; /* I/O q scehduling priority */ DEVBLK *nextioq; /* -> next device in I/O q */ IOINT ioint; /* Normal i/o interrupt queue entry */ IOINT pciioint; /* PCI i/o interrupt queue entry */ IOINT attnioint; /* ATTN i/o interrupt queue entry */ int cpuprio; /* CPU thread priority */ int devprio; /* Device thread priority */ /* fields used during ccw execution... */ BYTE chained; /* Command chain and data chain bits from previous CCW */ BYTE prev_chained; /* Chaining flags from CCW preceding the data chain */ BYTE code; /* Current CCW opcode */ BYTE prevcode; /* Previous CCW opcode */ int ccwseq; /* CCW sequence number */ U32 ccwaddr; U16 idapmask; BYTE idawfmt; BYTE ccwfmt; BYTE ccwkey; /* device handler function pointers... */ DEVHND *hnd; /* -> Device handlers */ /* Supplemental handler functions - Set by init handler @ISW */ /* Function invoked during HDV/HIO & HSCH instructions @ISW */ /* processing occurs in channel.c in haltio et al. @ISW */ /* when the device is busy, but the channel subsystem @ISW */ /* does not know how to perform the halt itself but has @ISW */ /* to rely on the handler to perform the halt @ISW */ void ( *halt_device)(DEVBLK *); /* @ISW */ DEVIM *immed; /* Model Specific IM codes */ /* (overrides devhnd immed) */ int is_immed; /* Last command is Immediate */ /* emulated architecture fields... (MUST be aligned!) */ int reserved1; /* ---(ensure alignment)---- */ ORB orb; /* Operation request blk @IWZ*/ PMCW pmcw; /* Path management ctl word */ SCSW scsw; /* Subchannel status word(XA)*/ SCSW pciscsw; /* PCI subchannel status word*/ SCSW attnscsw; /* ATTNsubchannel status word*/ BYTE csw[8]; /* Channel status word(S/370)*/ BYTE pcicsw[8]; /* PCI channel status word */ BYTE attncsw[8]; /* ATTN channel status word */ ESW esw; /* Extended status word */ BYTE ecw[32]; /* Extended control word */ U32 numsense; /* Number of sense bytes */ BYTE sense[256]; /* Sense bytes 3480+ 64 bytes*/ U32 numdevid; /* Number of device id bytes */ BYTE devid[256]; /* Device identifier bytes */ U32 numdevchar; /* Number of devchar bytes */ BYTE devchar[64]; /* Device characteristics */ BYTE pgstat; /* Path Group Status */ BYTE pgid[11]; /* Path Group ID */ BYTE reserved2[4]; /* (pad/align/unused/avail) */ COND resumecond; /* Resume condition */ COND iocond; /* I/O active condition */ int iowaiters; /* Number of I/O waiters */ int ioactive; /* System Id active on device*/ #define DEV_SYS_NONE 0 /* No active system on device*/ #define DEV_SYS_LOCAL 0xffff /* Local system active on dev*/ BYTE drvpwd[11]; /* Password for drive */ BYTE reserved3; /* (pad/align/unused/avail) */ /* control flags... */ unsigned int /* Flags */ #ifdef OPTION_CKD_KEY_TRACING ckdkeytrace:1, /* 1=Log CKD_KEY_TRACE */ #endif /*OPTION_CKD_KEY_TRACING*/ syncio:2, /* 1=Synchronous I/Os allowed*/ shared:1, /* 1=Device is shareable */ console:1, /* 1=Console device */ connected:1, /* 1=Console client connected*/ readpending:2, /* 1=Console read pending */ connecting:1, /* 1=Connecting to remote */ localhost:1, /* 1=Remote is local */ batch:1, /* 1=Called by dasdutil */ dasdcopy:1, /* 1=Called by dasdcopy */ oslinux:1, /* 1=Linux */ ccwtrace:1, /* 1=CCW trace */ ccwstep:1, /* 1=CCW single step */ cdwmerge:1; /* 1=Channel will merge data chained write CCWs */ unsigned int /* Device state - serialized by dev->lock */ busy:1, /* 1=Device is busy */ reserved:1, /* 1=Device is reserved */ suspended:1, /* 1=Channel pgm suspended */ pending:1, /* 1=I/O interrupt pending */ pcipending:1, /* 1=PCI interrupt pending */ attnpending:1, /* 1=ATTN interrupt pending */ startpending:1, /* 1=startio pending */ resumesuspended:1; /* 1=Hresuming suspended dev */ #define IOPENDING(_dev) ((_dev)->pending || (_dev)->pcipending || (_dev)->attnpending) #define INITIAL_POWERON_370() \ ( dev->crwpending && ARCH_370 == sysblk.arch_mode ) int crwpending; /* 1=CRW pending */ int syncio_active; /* 1=Synchronous I/O active */ int syncio_retry; /* 1=Retry I/O asynchronously*/ /* Synchronous I/O */ U32 syncio_addr; /* Synchronous i/o ccw addr */ U64 syncios; /* Number synchronous I/Os */ U64 asyncios; /* Number asynchronous I/Os */ /* Device dependent data (generic) */ void *dev_data; #ifdef EXTERNALGUI /* External GUI fields */ GUISTAT* pGUIStat; /* EXTERNALGUI Dev Stat Ctl */ #endif #if defined(FEATURE_VM_BLOCKIO) /* VM DIAGNOSE X'250' Emulation Environment */ struct VMBIOENV *vmd250env; /* Established environment */ #endif /* defined(FEATURE_VM_BLOCKIO) */ /* Fields for remote devices */ struct in_addr rmtaddr; /* Remote address */ U16 rmtport; /* Remote port number */ U16 rmtnum; /* Remote device number */ int rmtid; /* Remote Id */ int rmtrel; /* Remote release level */ DBLWRD rmthdr; /* Remote header */ int rmtcomp; /* Remote compression parm */ int rmtcomps; /* Supported compressions */ int rmtpurgen; /* Remote purge count */ FWORD *rmtpurge; /* Remote purge list */ #ifdef OPTION_SHARED_DEVICES /* Fields for device sharing */ TID shrdtid; /* Device thread id */ int shrdid; /* Id for next client */ int shrdconn; /* Number connected clients */ int shrdwait; /* Signal indicator */ SHRD *shrd[SHARED_MAX_SYS]; /* ->SHRD block */ #endif /* Device dependent fields for console */ struct in_addr ipaddr; /* Client IP address */ in_addr_t acc_ipaddr; /* Allowable clients IP addr */ in_addr_t acc_ipmask; /* Allowable clients IP mask */ U32 rlen3270; /* Length of data in buffer */ int pos3270; /* Current screen position */ int keybdrem; /* Number of bytes remaining in keyboard read buffer */ u_int eab3270:1; /* 1=Extended attributes */ u_int ewa3270:1; /* 1=Last erase was EWA */ u_int prompt1052:1; /* 1=Prompt for linemode i/p */ BYTE aid3270; /* Current input AID value */ BYTE mod3270; /* 3270 model number */ /* Device dependent fields for cardrdr */ char **more_files; /* for more that one file in reader */ char **current_file; /* counts how many additional reader files are avail */ int cardpos; /* Offset of next byte to be read from data buffer */ int cardrem; /* Number of bytes remaining in data buffer */ u_int multifile:1; /* 1=auto-open next i/p file */ u_int rdreof:1; /* 1=Unit exception at EOF */ u_int ebcdic:1; /* 1=Card deck is EBCDIC */ u_int ascii:1; /* 1=Convert ASCII to EBCDIC */ u_int trunc:1; /* Truncate overlength record*/ u_int autopad:1; /* 1=Pad incomplete last rec to 80 bytes if EBCDIC */ /* Device dependent fields for ctcadpt */ DEVBLK *ctcpair; /* -> Paired device block */ int ctcpos; /* next byte offset */ int ctcrem; /* bytes remaining in buffer */ int ctclastpos; /* last packet read */ int ctclastrem; /* last packet read */ u_int ctcxmode:1; /* 0=Basic mode, 1=Extended */ BYTE ctctype; /* CTC_xxx device type */ BYTE netdevname[IFNAMSIZ]; /* network device name */ /* Device dependent fields for ctcadpt : Enhanced CTC @PJJ */ U16 ctcePktSeq; /* CTCE Packet Sequence @PJJ */ /* # in debug msgs @PJJ */ int ctceSndSml; /* CTCE Send Small size @PJJ */ BYTE ctcexState; /* CTCE State x-side @PJJ */ BYTE ctcexCmd; /* CTCE Command x-side @PJJ */ BYTE ctceyState; /* CTCE State y-side @PJJ */ BYTE ctceyCmd; /* CTCE Command y-side @PJJ */ BYTE ctceyCmdSCB; /* CTCE Cmd SCB source @PJJ */ int ctcefd; /* CTCE RecvThread File @PJJ */ /* Desc / socket # @PJJ */ LOCK ctceEventLock; /* CTCE Condition LOCK @PJJ */ COND ctceEvent; /* CTCE Recvd Condition @PJJ */ /* Device dependent fields for printer */ int printpos; /* Number of bytes already placed in print buffer */ int printrem; /* Number of bytes remaining in print buffer */ pid_t ptpcpid; /* print-to-pipe child pid */ u_int crlf:1; /* 1=CRLF delimiters, 0=LF */ u_int diaggate:1; /* 1=Diagnostic gate command */ u_int fold:1; /* 1=Fold to upper case */ u_int ispiped:1; /* 1=Piped device */ u_int stopprt:1; /* 1=stopped; 0=started */ u_int notrunc:1; /* 1=do not truncate at open */ u_int fcbsupp:1; /* fcb support flag */ u_int cc:1; /* emit line controls */ u_int rawcc:1; /* emit just cc(hex) and data*/ u_int fcbcheck:1; /* signal FCB errors */ u_int nofcbcheck:1; /* ignore FCB errors */ u_int ccpend:1; /* cc process pending */ u_int chskip:1; /* cc process pending */ int print; /* optimize for print 0 */ int browse; /* optimize for browse 1 */ int lpi; /* lines per inch 6/8 */ int index; /* 3211 indexing */ int lpp; /* lines per page */ int ffchan ; /* ff when skip here */ #define FCBSIZE 256 int fcb[FCBSIZE+1]; /* FCB image */ int fcbisdef; /* FCB is default */ int prevline; /* previous line number */ int currline; /* curr line number */ int destline; /* destination line number */ /* Device dependent fields for tapedev */ void *omadesc; /* -> OMA descriptor array */ U16 omafiles; /* Number of OMA tape files */ U16 curfilen; /* Current file number */ U32 blockid; /* Current device block ID */ off_t nxtblkpos; /* Offset from start of file to next block */ off_t prvblkpos; /* Offset from start of file to previous block */ U16 curblkrem; /* Number of bytes unread from current block */ U16 curbufoff; /* Offset into buffer of data for next data chained CCW */ U16 tapssdlen; /* #of bytes of data prepared for Read Subsystem Data */ HETB *hetb; /* HET control block */ struct /* HET device parms */ { u_int compress:1; /* 1=Compression enabled */ u_int method:3; /* Compression method */ u_int level:4; /* Compression level */ u_int strictsize:1; /* Strictly enforce MAXSIZE */ u_int displayfeat:1; /* Device has a display */ /* feature installed */ u_int deonirq:1; /* DE on IRQ on tape motion */ /* MVS 3.8j workaround */ u_int logical_readonly:1; /* Tape is forced READ ONLY */ U16 chksize; /* Chunk size */ off_t maxsize; /* Maximum allowed TAPE file size */ } tdparms; /* HET device parms */ off_t eotmargin; /* Amount of space left before reporting EOT (in bytes) */ u_int fenced:1; /* 1=Pos err; volume fenced */ u_int readonly:1; /* 1=Tape is write-protected */ u_int sns_pending:1; /* Contingency Allegiance */ /* - means : don't build a */ /* sense on X'04' : it's */ /* aleady there */ /* NOTE : flag cleared by */ /* sense command only */ /* or a device init */ u_int SIC_supported:1; /* 1=Spec Intcpt Cond support*/ u_int SIC_active:1; /* 1=SIC active */ u_int forced_logging:1; /* 1=Forced Error Logging */ u_int eotwarning:1; /* 1=EOT warning area reached*/ #if defined( OPTION_TAPE_AUTOMOUNT ) u_int noautomount:1; /* 1=AUTOMOUNT disabled */ #endif u_int supvr_inhibit:1; /* 1=Supvr-Inhibit mode */ u_int write_immed:1; /* 1=Write-Immediate mode */ #if defined(OPTION_SCSI_TAPE) struct mtget mtget; /* SCSI tape status struct */ #define sstat mtget.mt_gstat /* Generic SCSI tape device- independent status field; (struct mtget->mt_gstat) */ u_int stape_close_rewinds:1; /* 1=Rewind at close */ u_int stape_blkid_32:1; /* 1=block-ids are 32 bits */ u_int stape_no_erg:1; /* 1=ignore Erase Gap CCWs */ /* Access to SCSI fields controlled via sysblk.stape_lock */ COND stape_sstat_cond; /* Tape-status updated COND */ STSTATRQ stape_statrq; /* Status request structure */ STMNTDRQ stape_mntdrq; /* Mounted request structure */ #endif /* defined(OPTION_SCSI_TAPE) */ U32 msgid; /* Message Id of async. i/o */ BYTE tapedevt; /* Hercules tape device type */ TAPEMEDIA_HANDLER *tmh; /* Tape Media Handling */ /* dispatcher */ /* ---------- Autoloader feature --------------------------- */ TAPEAUTOLOADENTRY *als; /* Autoloader stack */ int alss; /* Autoloader stack size */ int alsix; /* Current Autoloader index */ char **al_argv; /* ARGV in autoloader */ int al_argc; /* ARGC in autoloader */ /* ---------- end Autoloader feature ----------------------- */ /* 3480/3490/3590 Message display */ char tapemsg1[9]; /* 1st Host Message */ char tapemsg2[9]; /* 2nd Host Message */ char tapesysmsg[32]; /* Unit Message (SYS)*/ char *prev_tapemsg; /* Previously displayed msg */ BYTE tapedisptype; /* Type of message display */ BYTE tapedispflags; /* How the msg is displayed */ #define TAPEDISPTYP_IDLE 0 /* "READY" "NT RDY" etc (SYS)*/ #define TAPEDISPTYP_LOCATING 1 /* Locate in progress (SYS)*/ #define TAPEDISPTYP_ERASING 2 /* DSE in progress (SYS)*/ #define TAPEDISPTYP_REWINDING 3 /* Rewind in progress (SYS)*/ #define TAPEDISPTYP_UNLOADING 4 /* Unload in progress (SYS)*/ #define TAPEDISPTYP_CLEAN 5 /* Clean recommended (SYS)*/ #define TAPEDISPTYP_MOUNT 6 /* Display Until Mounted */ #define TAPEDISPTYP_UNMOUNT 7 /* Display Until Unmounted */ #define TAPEDISPTYP_UMOUNTMOUNT 8 /* Display #1 Until Unmounted, then #2 Until Mounted */ #define TAPEDISPTYP_WAITACT 9 /* Display until motion */ #define IS_TAPEDISPTYP_SYSMSG( dev ) \ (0 \ || TAPEDISPTYP_IDLE == (dev)->tapedisptype \ || TAPEDISPTYP_LOCATING == (dev)->tapedisptype \ || TAPEDISPTYP_ERASING == (dev)->tapedisptype \ || TAPEDISPTYP_REWINDING == (dev)->tapedisptype \ || TAPEDISPTYP_UNLOADING == (dev)->tapedisptype \ || TAPEDISPTYP_CLEAN == (dev)->tapedisptype \ ) #define TAPEDISPFLG_ALTERNATE 0x80 /* Alternate msgs 1 & 2 */ #define TAPEDISPFLG_BLINKING 0x40 /* Selected msg blinks */ #define TAPEDISPFLG_MESSAGE2 0x20 /* Display msg 2 instead of 1*/ #define TAPEDISPFLG_AUTOLOADER 0x10 /* Autoloader request */ #define TAPEDISPFLG_REQAUTOMNT 0x08 /* ReqAutoMount has work */ /* Device dependent fields for Comm Line */ COMMADPT *commadpt; /* Single structure pointer */ /* Device dependent fields for dasd (fba and ckd) */ char *dasdsfn; /* Shadow file name */ char *dasdsfx; /* Pointer to suffix char */ /* Device dependent fields for fbadasd */ FBADEV *fbatab; /* Device table entry */ int fbanumblk; /* Number of blocks in device*/ int fbablksiz; /* Physical block size */ off_t fbaorigin; /* Device origin block number*/ off_t fbarba; /* Relative byte offset */ off_t fbaend; /* Last RBA in file */ /* Values from define extent */ u_int fbaxtdef:1; /* 1=Extent defined */ BYTE fbamask; /* Define extent file mask */ U32 fbaxblkn; /* Offset from start of device to first block of extent */ U32 fbaxfirst; /* Block number within dataset of first block of extent */ U32 fbaxlast; /* Block number within dataset of last block of extent */ /* Values from locate */ BYTE fbaoper; /* Locate operation byte */ U16 fbalcnum; /* Block count for locate */ U32 fbalcblk; /* Block number within dataset of first block for locate */ /* Device dependent fields for ckddasd */ int ckdnumfd; /* Number of CKD image files */ int ckdfd[CKD_MAXFILES]; /* CKD image file descriptors*/ int ckdhitrk[CKD_MAXFILES]; /* Highest track number in each CKD image file */ CKDDEV *ckdtab; /* Device table entry */ CKDCU *ckdcu; /* Control unit entry */ off_t ckdtrkoff; /* Track image file offset */ int ckdcyls; /* Number of cylinders */ int ckdtrks; /* Number of tracks */ int ckdheads; /* #of heads per cylinder */ int ckdtrksz; /* Track size */ int ckdcurcyl; /* Current cylinder */ int ckdcurhead; /* Current head */ int ckdcurrec; /* Current record id */ int ckdcurkl; /* Current record key length */ int ckdorient; /* Current orientation */ int ckdcuroper; /* Curr op: read=6, write=5 */ U16 ckdcurdl; /* Current record data length*/ U16 ckdrem; /* #of bytes from current position to end of field */ U16 ckdpos; /* Offset into buffer of data for next data chained CCW */ U16 ckdxblksz; /* Define extent block size */ U16 ckdxbcyl; /* Define extent begin cyl */ U16 ckdxbhead; /* Define extent begin head */ U16 ckdxecyl; /* Define extent end cyl */ U16 ckdxehead; /* Define extent end head */ BYTE ckdfmask; /* Define extent file mask */ BYTE ckdxgattr; /* Define extent global attr */ U16 ckdltranlf; /* Locate record transfer length factor */ U16 ckdlmask; /* Locate record mask */ BYTE ckdloper; /* Locate record operation */ BYTE ckdlaux; /* Locate record aux byte */ BYTE ckdlcount; /* Locate record count */ BYTE ckdreserved1; /* Alignment */ void *cckd_ext; /* -> Compressed ckddasd extension otherwise NULL */ u_int ckd3990:1; /* 1=Control unit is 3990 */ u_int ckdxtdef:1; /* 1=Define Extent processed */ u_int ckdsetfm:1; /* 1=Set File Mask processed */ u_int ckdlocat:1; /* 1=Locate Record processed */ u_int ckdspcnt:1; /* 1=Space Count processed */ u_int ckdseek:1; /* 1=Seek command processed */ u_int ckdskcyl:1; /* 1=Seek cylinder processed */ u_int ckdrecal:1; /* 1=Recalibrate processed */ u_int ckdrdipl:1; /* 1=Read IPL processed */ u_int ckdxmark:1; /* 1=End of track mark found */ u_int ckdhaeq:1; /* 1=Search Home Addr Equal */ u_int ckdideq:1; /* 1=Search ID Equal */ u_int ckdkyeq:1; /* 1=Search Key Equal */ u_int ckdwckd:1; /* 1=Write R0 or Write CKD */ u_int ckdtrkof:1; /* 1=Track ovfl on this blk */ u_int ckdssi:1; /* 1=Set Special Intercept */ u_int ckdnolazywr:1; /* 1=Perform updates now */ u_int ckdrdonly:1; /* 1=Open read only */ u_int ckdwrha:1; /* 1=Write Home Address */ /* Line above ISW20030819-1 */ u_int ckdfakewr:1; /* 1=Fake successful write for read only file */ U16 ckdssdlen; /* #of bytes of data prepared for Read Subsystem Data */ }; /*-------------------------------------------------------------------*/ /* Device Group Structure (just a group of related devices) */ /*-------------------------------------------------------------------*/ struct DEVGRP { /* Device Group Structure */ int members; /* #of member devices in grp */ int acount; /* #allocated members in grp */ void *grp_data; /* Group dep data (generic) */ DEVBLK *memdev[FLEXIBLE_ARRAY]; /* Member devices */ }; /*-------------------------------------------------------------------*/ /* Structure definitions for CKD headers */ /*-------------------------------------------------------------------*/ struct CKDDASD_DEVHDR { /* Device header */ BYTE devid[8]; /* Device identifier */ FWORD heads; /* #of heads per cylinder (bytes in reverse order) */ FWORD trksize; /* Track size (reverse order)*/ BYTE devtype; /* Last 2 digits of device type (0x80=3380, 0x90=3390) */ BYTE fileseq; /* CKD image file sequence no. (0x00=only file, 0x01=first file of multiple files) */ HWORD highcyl; /* Highest cylinder number on this file, or zero if this is the last or only file (bytes in reverse order) */ BYTE resv[492]; /* Reserved */ }; struct CKDDASD_TRKHDR { /* Track header */ BYTE bin; /* Bin number */ HWORD cyl; /* Cylinder number */ HWORD head; /* Head number */ }; struct CKDDASD_RECHDR { /* Record header */ HWORD cyl; /* Cylinder number */ HWORD head; /* Head number */ BYTE rec; /* Record number */ BYTE klen; /* Key length */ HWORD dlen; /* Data length */ }; #define CKDDASD_DEVHDR_SIZE ((ssize_t)sizeof(CKDDASD_DEVHDR)) #define CKDDASD_TRKHDR_SIZE ((ssize_t)sizeof(CKDDASD_TRKHDR)) #define CKDDASD_RECHDR_SIZE ((ssize_t)sizeof(CKDDASD_RECHDR)) /* Null track formats */ #define CKDDASD_NULLTRK_FMT0 0 /* ha r0 r1 eot */ #define CKDDASD_NULLTRK_FMT1 1 /* ha r0 eot */ #define CKDDASD_NULLTRK_FMT2 2 /* linux (3390 only) */ #define CKDDASD_NULLTRK_FMTMAX CKDDASD_NULLTRK_FMT2 #define CKDDASD_NULLTRK_SIZE0 (5 + 8 + 8 + 8 + 8) #define CKDDASD_NULLTRK_SIZE1 (5 + 8 + 8 + 8) #define CKDDASD_NULLTRK_SIZE2 (5 + 8 + 8 + (12 * (8 + 4096)) + 8) /*-------------------------------------------------------------------*/ /* Structure definitions for Compressed CKD devices */ /*-------------------------------------------------------------------*/ struct CCKDDASD_DEVHDR { /* Compress device header */ /* 0 */BYTE vrm[3]; /* Version Release Modifier */ /* 3 */BYTE options; /* Options byte */ /* 4 */S32 numl1tab; /* Size of lvl 1 table */ /* 8 */S32 numl2tab; /* Size of lvl 2 tables */ /* 12 */U32 size; /* File size */ /* 16 */U32 used; /* File used */ /* 20 */U32 free; /* Position to free space */ /* 24 */U32 free_total; /* Total free space */ /* 28 */U32 free_largest; /* Largest free space */ /* 32 */S32 free_number; /* Number free spaces */ /* 36 */U32 free_imbed; /* Imbedded free space */ /* 40 */FWORD cyls; /* Cylinders on device */ /* 44 */BYTE nullfmt; /* Null track format */ /* 45 */BYTE compress; /* Compression algorithm */ /* 46 */S16 compress_parm; /* Compression parameter */ /* 48 */BYTE resv2[464]; /* Reserved */ }; #define CCKD_DEVHDR CCKDDASD_DEVHDR #define CCKD_VERSION 0 #define CCKD_RELEASE 3 #define CCKD_MODLVL 1 #define CCKD_NOFUDGE 1 /* [deprecated] */ #define CCKD_BIGENDIAN 2 #define CCKD_SPERRS 32 /* Space errors detected */ #define CCKD_ORDWR 64 /* Opened read/write since last chkdsk */ #define CCKD_OPENED 128 #define CCKD_COMPRESS_NONE 0x00 #define CCKD_COMPRESS_ZLIB 0x01 #define CCKD_COMPRESS_BZIP2 0x02 #define CCKD_COMPRESS_MASK 0x03 #define CCKD_STRESS_MINLEN 4096 #if defined(HAVE_LIBZ) #define CCKD_STRESS_COMP CCKD_COMPRESS_ZLIB #else #define CCKD_STRESS_COMP CCKD_COMPRESS_NONE #endif #define CCKD_STRESS_PARM1 4 #define CCKD_STRESS_PARM2 2 struct CCKD_L2ENT { /* Level 2 table entry */ U32 pos; /* Track offset */ U16 len; /* Track length */ U16 size; /* Track size (size >= len) */ }; struct CCKD_FREEBLK { /* Free block (file) */ U32 pos; /* Position next free blk */ U32 len; /* Length this free blk */ }; struct CCKD_IFREEBLK { /* Free block (internal) */ U32 pos; /* Position next free blk */ U32 len; /* Length this free blk */ int prev; /* Index to prev free blk */ int next; /* Index to next free blk */ int pending; /* 1=Free pending (don't use)*/ }; struct CCKD_RA { /* Readahead queue entry */ DEVBLK *dev; /* Readahead device */ int trk; /* Readahead track */ int prev; /* Index to prev entry */ int next; /* Index to next entry */ }; typedef U32 CCKD_L1ENT; /* Level 1 table entry */ typedef CCKD_L1ENT CCKD_L1TAB[]; /* Level 1 table */ typedef CCKD_L2ENT CCKD_L2TAB[256]; /* Level 2 table */ typedef char CCKD_TRACE[128]; /* Trace table entry */ #define CCKDDASD_DEVHDR_SIZE ((ssize_t)sizeof(CCKDDASD_DEVHDR)) #define CCKD_DEVHDR_SIZE CCKDDASD_DEVHDR_SIZE #define CCKD_DEVHDR_POS CKDDASD_DEVHDR_SIZE #define CCKD_L1ENT_SIZE ((ssize_t)sizeof(CCKD_L1ENT)) #define CCKD_L1TAB_POS ((CCKD_DEVHDR_POS)+(CCKD_DEVHDR_SIZE)) #define CCKD_L2ENT_SIZE ((ssize_t)sizeof(CCKD_L2ENT)) #define CCKD_L2TAB_SIZE ((ssize_t)sizeof(CCKD_L2TAB)) #define CCKD_FREEBLK_SIZE ((ssize_t)sizeof(CCKD_FREEBLK)) #define CCKD_FREEBLK_ISIZE ((ssize_t)sizeof(CCKD_IFREEBLK)) #define CCKD_IFREEBLK_SIZE (CCKD_FREEBLK_ISIZE) /* Flag bits */ #define CCKD_SIZE_EXACT 0x01 /* Space obtained is exact */ #define CCKD_SIZE_ANY 0x02 /* Space can be any size */ #define CCKD_L2SPACE 0x04 /* Space for a l2 table */ /* adjustable values */ #define CCKD_FREE_MIN_SIZE 96 /* Minimum free space size */ #define CCKD_FREE_MIN_INCR 32 /* Added for each 1024 spaces*/ #define CCKD_COMPRESS_MIN 512 /* Track images smaller than this won't be compressed */ #define CCKD_MAX_SF 8 /* Maximum number of shadow files: 0 to 9 [0 disables shadow file support] */ #define CCKD_MAX_READAHEADS 16 /* Max readahead trks */ #define CCKD_MAX_RA_SIZE 16 /* Readahead queue size */ #define CCKD_MAX_RA 9 /* Max readahead threads */ #define CCKD_MAX_WRITER 9 /* Max writer threads */ #define CCKD_MAX_GCOL 1 /* Max garbage collectors */ #define CCKD_MAX_TRACE 200000 /* Max nbr trace entries */ #define CCKD_MAX_FREEPEND 4 /* Max free pending cycles */ #define CCKD_MIN_READAHEADS 0 /* Min readahead trks */ #define CCKD_MIN_RA 0 /* Min readahead threads */ #define CCKD_MIN_WRITER 1 /* Min writer threads */ #define CCKD_MIN_GCOL 0 /* Min garbage collectors */ #define CCKD_DEFAULT_RA_SIZE 4 /* Readahead queue size */ #define CCKD_DEFAULT_RA 2 /* Default number readaheads */ #define CCKD_DEFAULT_WRITER 2 /* Default number writers */ #define CCKD_DEFAULT_GCOL 1 /* Default number garbage collectors */ #define CCKD_DEFAULT_GCOLWAIT 10 /* Default wait (seconds) */ #define CCKD_DEFAULT_GCOLPARM 0 /* Default adjustment parm */ #define CCKD_DEFAULT_READAHEADS 2 /* Default nbr to read ahead */ #define CCKD_DEFAULT_FREEPEND -1 /* Default freepend cycles */ #define CFBA_BLOCK_NUM 120 /* Number fba blocks / group */ #define CFBA_BLOCK_SIZE 61440 /* Size of a block group 60k */ /* Number of bytes in an fba block group. Probably should be a multiple of 512 but has to be < 64K */ struct CCKDBLK { /* Global cckd dasd block */ BYTE id[8]; /* "CCKDBLK " */ DEVBLK *dev1st; /* 1st device in cckd queue */ unsigned int batch:1, /* 1=called in batch mode */ sfmerge:1, /* 1=sf-* merge */ sfforce:1; /* 1=sf-* force */ int sflevel; /* sfk xxxx level */ BYTE comps; /* Supported compressions */ BYTE comp; /* Override compression */ int compparm; /* Override compression parm */ LOCK gclock; /* Garbage collector lock */ COND gccond; /* Garbage collector cond */ int gcs; /* Number garbage collectors */ int gcmax; /* Max garbage collectors */ int gcwait; /* Wait time in seconds */ int gcparm; /* Adjustment parm */ LOCK wrlock; /* I/O lock */ COND wrcond; /* I/O condition */ int wrpending; /* Number writes pending */ int wrwaiting; /* Number writers waiting */ int wrs; /* Number writer threads */ int wrmax; /* Max writer threads */ int wrprio; /* Writer thread priority */ LOCK ralock; /* Readahead lock */ COND racond; /* Readahead condition */ int ras; /* Number readahead threads */ int ramax; /* Max readahead threads */ int rawaiting; /* Number threads waiting */ int ranbr; /* Readahead queue size */ int readaheads; /* Nbr tracks to read ahead */ CCKD_RA ra[CCKD_MAX_RA_SIZE]; /* Readahead queue */ int ra1st; /* First readahead entry */ int ralast; /* Last readahead entry */ int rafree; /* Free readahead entry */ LOCK devlock; /* Device chain lock */ COND devcond; /* Device chain condition */ int devusers; /* Number shared users */ int devwaiters; /* Number of waiters */ int freepend; /* Number freepend cycles */ int nostress; /* 1=No stress writes */ int linuxnull; /* 1=Always check nulltrk */ int fsync; /* 1=Perform fsync() */ COND termcond; /* Termination condition */ U64 stats_switches; /* Switches */ U64 stats_cachehits; /* Cache hits */ U64 stats_cachemisses; /* Cache misses */ U64 stats_readaheads; /* Readaheads */ U64 stats_readaheadmisses;/* Readahead misses */ U64 stats_syncios; /* Synchronous i/os */ U64 stats_synciomisses; /* Missed syncios */ U64 stats_iowaits; /* Waits for i/o */ U64 stats_cachewaits; /* Waits for cache */ U64 stats_stresswrites; /* Writes under stress*/ U64 stats_l2cachehits; /* L2 cache hits */ U64 stats_l2cachemisses; /* L2 cache misses */ U64 stats_l2reads; /* L2 reads */ U64 stats_reads; /* Number reads */ U64 stats_readbytes; /* Bytes read */ U64 stats_writes; /* Number writes */ U64 stats_writebytes; /* Bytes written */ U64 stats_gcolmoves; /* Spaces moved */ U64 stats_gcolbytes; /* Bytes moved */ CCKD_TRACE *itrace; /* Internal trace table */ CCKD_TRACE *itracep; /* Current pointer */ CCKD_TRACE *itracex; /* End of trace table */ int itracen; /* Number of entries */ int bytemsgs; /* Limit for `byte 0' msgs */ }; struct CCKDDASD_EXT { /* Ext for compressed ckd */ DEVBLK *devnext; /* cckd device queue */ unsigned int ckddasd:1, /* 1=CKD dasd */ fbadasd:1, /* 1=FBA dasd */ ioactive:1, /* 1=Channel program active */ bufused:1, /* 1=newbuf was used */ updated:1, /* 1=Update occurred */ merging:1, /* 1=File merge in progress */ stopping:1, /* 1=Device is closing */ notnull:1, /* 1=Device has track images */ l2ok:1, /* 1=All l2s below bounds */ sfmerge:1, /* 1=sf-xxxx merge */ sfforce:1; /* 1=sf-xxxx force */ int sflevel; /* sfk xxxx level */ LOCK filelock; /* File lock */ LOCK iolock; /* I/O lock */ COND iocond; /* I/O condition */ long long maxsize; /* Maximum file size */ int iowaiters; /* Number I/O waiters */ int wrpending; /* Number writes pending */ int ras; /* Number readaheads active */ int sfn; /* Number active shadow files*/ int sfx; /* Active level 2 file index */ int l1x; /* Active level 2 table index*/ CCKD_L2ENT *l2; /* Active level 2 table */ int l2active; /* Active level 2 cache entry*/ off_t l2bounds; /* L2 tables boundary */ int active; /* Active cache entry */ BYTE *newbuf; /* Uncompressed buffer */ unsigned int freemin; /* Minimum free space size */ CCKD_IFREEBLK *free; /* Internal free space chain */ int freenbr; /* Number free space entries */ int free1st; /* Index of 1st entry */ int freelast; /* Index of last entry */ int freeavail; /* Index of available entry */ int lastsync; /* Time of last sync */ int ralkup[CCKD_MAX_RA_SIZE];/* Lookup table */ int ratrk; /* Track to readahead */ unsigned int totreads; /* Total nbr trk reads */ unsigned int totwrites; /* Total nbr trk writes */ unsigned int totl2reads; /* Total nbr l2 reads */ unsigned int cachehits; /* Cache hits */ unsigned int readaheads; /* Number trks read ahead */ unsigned int switches; /* Number trk switches */ unsigned int misses; /* Number readahead misses */ int fd[CCKD_MAX_SF+1]; /* File descriptors */ BYTE swapend[CCKD_MAX_SF+1]; /* Swap endian flag */ BYTE open[CCKD_MAX_SF+1]; /* Open flag */ int reads[CCKD_MAX_SF+1]; /* Nbr track reads */ int l2reads[CCKD_MAX_SF+1]; /* Nbr l2 reads */ int writes[CCKD_MAX_SF+1]; /* Nbr track writes */ CCKD_L1ENT *l1[CCKD_MAX_SF+1]; /* Level 1 tables */ CCKDDASD_DEVHDR cdevhdr[CCKD_MAX_SF+1]; /* cckd device hdr */ }; #define CCKD_OPEN_NONE 0 #define CCKD_OPEN_RO 1 #define CCKD_OPEN_RD 2 #define CCKD_OPEN_RW 3 #ifdef EXTERNALGUI struct GUISTAT { char* pszOldStatStr; char* pszNewStatStr; #define GUI_STATSTR_BUFSIZ 256 char szStatStrBuff1[GUI_STATSTR_BUFSIZ]; char szStatStrBuff2[GUI_STATSTR_BUFSIZ]; }; #endif // EXTERNALGUI #endif // _HSTRUCTS_H hercules-3.12/hexterns.h0000664000175000017500000003617312564723224012226 00000000000000/* HEXTERNS.H (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules function prototypes */ #ifndef _HEXTERNS_H #define _HEXTERNS_H #include "hercules.h" // Define all DLL Imports depending on current file #ifndef _HSYS_C_ #define HSYS_DLL_IMPORT DLL_IMPORT #else /* _HSYS_C_ */ #define HSYS_DLL_IMPORT DLL_EXPORT #endif /* _HSYS_C_ */ #ifndef _CCKDDASD_C_ #ifndef _HDASD_DLL_ #define CCKD_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define CCKD_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define CCKD_DLL_IMPORT DLL_EXPORT #endif #ifndef _HDL_C_ #ifndef _HUTIL_DLL_ #define HHDL_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define HHDL_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define HHDL_DLL_IMPORT DLL_EXPORT #endif #ifndef _HSCCMD_C_ #ifndef _HENGINE_DLL_ #define HCMD_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define HCMD_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define HCMD_DLL_IMPORT DLL_EXPORT #endif #ifndef _CMDTAB_C_ #ifndef _HENGINE_DLL_ #define CMDT_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define CMDT_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define CMDT_DLL_IMPORT DLL_EXPORT #endif #ifndef _HAO_C_ #ifndef _HENGINE_DLL_ #define HAO_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define HAO_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define HAO_DLL_IMPORT DLL_EXPORT #endif #ifndef _PANEL_C_ #ifndef _HENGINE_DLL_ #define HPAN_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define HPAN_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define HPAN_DLL_IMPORT DLL_EXPORT #endif #ifndef _IMPL_C_ #ifndef _HENGINE_DLL_ #define IMPL_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define IMPL_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define IMPL_DLL_IMPORT DLL_EXPORT #endif #ifndef _CCKDUTIL_C_ #ifndef _HDASD_DLL_ #define CCDU_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define CCDU_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define CCDU_DLL_IMPORT DLL_EXPORT #endif #ifndef _CONFIG_C_ #ifndef _HENGINE_DLL_ #define CONF_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define CONF_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define CONF_DLL_IMPORT DLL_EXPORT #endif #ifndef _BLDCFG_C_ #ifndef _HENGINE_DLL_ #define BLDC_DLL_IMPORT DLL_IMPORT #else /* _HDASD_DLL_ */ #define BLDC_DLL_IMPORT extern #endif /* _HDASD_DLL_ */ #else #define BLDC_DLL_IMPORT DLL_EXPORT #endif #ifndef _SERVICE_C_ #ifndef _HENGINE_DLL_ #define SERV_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define SERV_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define SERV_DLL_IMPORT DLL_EXPORT #endif #ifndef _LOADPARM_C_ #ifndef _HENGINE_DLL_ #define LOADPARM_DLL_IMPORT DLL_IMPORT #else /* _HENGINE_DLL_ */ #define LOADPARM_DLL_IMPORT extern #endif /* _HENGINE_DLL_ */ #else #define LOADPARM_DLL_IMPORT DLL_EXPORT #endif #if defined( _MSC_VER ) && (_MSC_VER >= 1300) && (_MSC_VER < 1400) // '_ftol' is defined in MSVCRT.DLL // '_ftol2' we define ourselves in "w32ftol2.c" extern long _ftol ( double dblSource ); extern long _ftol2( double dblSource ); #endif #if !defined(HAVE_STRSIGNAL) const char* strsignal(int signo); // (ours is in 'strsignal.c') #endif #if defined(HAVE_SETRESUID) /* (the following missing from SUSE 7.1) */ int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); int setresuid(uid_t ruid, uid_t euid, uid_t suid); int setresgid(gid_t rgid, gid_t egid, gid_t sgid); #endif /* Function used to compare filenames */ #if defined(MIXEDCASE_FILENAMES_ARE_UNIQUE) #define strfilenamecmp strcmp #define strnfilenamecmp strncmp #else #define strfilenamecmp strcasecmp #define strnfilenamecmp strncasecmp #endif /* Global data areas in module config.c */ HSYS_DLL_IMPORT SYSBLK sysblk; /* System control block */ CCKD_DLL_IMPORT CCKDBLK cckdblk; /* CCKD global block */ #ifdef EXTERNALGUI HSYS_DLL_IMPORT int extgui; // __attribute__ ((deprecated)); /* The external gui interface is now external and now uses the HDC(debug_cpu_state, regs) interface */ #endif /*EXTERNALGUI*/ /* Functions in module config.c or bldcfg.c */ void build_config (char *fname); void release_config (); CONF_DLL_IMPORT DEVBLK *find_device_by_devnum (U16 lcss, U16 devnum); DEVBLK *find_device_by_subchan (U32 ioid); REGS *devregs(DEVBLK *dev); DEVBLK *get_devblk (U16 lcss, U16 devnum); void ret_devblk (DEVBLK *dev); int attach_device (U16 lcss, U16 devnum, const char *devtype, int addargc, char *addargv[]); int detach_subchan (U16 lcss, U16 subchan); int detach_device (U16 lcss, U16 devnum); int define_device (U16 lcss, U16 olddev, U16 newdev); CONF_DLL_IMPORT int group_device(DEVBLK *dev, int members); int configure_cpu (int cpu); int deconfigure_cpu (int cpu); BLDC_DLL_IMPORT int parse_args (char* p, int maxargc, char** pargv, int* pargc); #define MAX_ARGS 128 /* Max argv[] array size */ int parse_and_attach_devices(const char *devnums,const char *devtype,int ac,char **av); CONF_DLL_IMPORT int parse_single_devnum(const char *spec, U16 *lcss, U16 *devnum); int parse_single_devnum_silent(const char *spec, U16 *lcss, U16 *devnum); int readlogo(char *fn); void clearlogo(void); CONF_DLL_IMPORT int parse_conkpalv(char* s, int* idle, int* intv, int* cnt ); #if defined( OPTION_TAPE_AUTOMOUNT ) BLDC_DLL_IMPORT int add_tamdir( char *tamdir, TAMDIR **ppTAMDIR ); #endif /* OPTION_TAPE_AUTOMOUNT */ /* Global data areas and functions in module cpu.c */ extern const char* arch_name[]; extern const char* get_arch_mode_string(REGS* regs); /* Functions in module panel.c */ void expire_kept_msgs(int unconditional); #ifdef OPTION_MIPS_COUNTING HPAN_DLL_IMPORT U32 maxrates_rpt_intvl; // (reporting interval) HPAN_DLL_IMPORT U32 curr_high_mips_rate; // (high water mark for current interval) HPAN_DLL_IMPORT U32 curr_high_sios_rate; // (high water mark for current interval) HPAN_DLL_IMPORT U32 prev_high_mips_rate; // (saved high water mark for previous interval) HPAN_DLL_IMPORT U32 prev_high_sios_rate; // (saved high water mark for previous interval) HPAN_DLL_IMPORT time_t curr_int_start_time; // (start time of current interval) HPAN_DLL_IMPORT time_t prev_int_start_time; // (start time of previous interval) HPAN_DLL_IMPORT void update_maxrates_hwm(); // (update high-water-mark values) #endif // OPTION_MIPS_COUNTING /* Functions in module hao.c (Hercules Automatic Operator) */ #if defined(OPTION_HAO) HAO_DLL_IMPORT int hao_initialize(void); /* initialize hao */ HAO_DLL_IMPORT void hao_command(char *command); /* process hao command */ HAO_DLL_IMPORT void hao_message(char *message); /* process message */ #endif /* defined(OPTION_HAO) */ /* Functions in module hsccmd.c (so PTT debugging patches can access them) */ HCMD_DLL_IMPORT int aia_cmd (int argc, char *argv[], char *cmdline); HCMD_DLL_IMPORT int stopall_cmd (int argc, char *argv[], char *cmdline); /* Functions in module cmdtab.c */ CMDT_DLL_IMPORT int ProcessConfigCommand (int argc, char **argv, char *cmdline); /* Functions in losc.c */ void losc_set (int license_status); void losc_check(char *ostype); #if defined(OPTION_DYNAMIC_LOAD) HHDL_DLL_IMPORT char *(*hdl_device_type_equates) (const char *); CMDT_DLL_IMPORT void *(panel_command_r) (void *cmdline); HPAN_DLL_IMPORT void (panel_display_r) (void); HSYS_DLL_IMPORT int (*config_command) (int argc, char *argv[], char *cmdline); HSYS_DLL_IMPORT int (*system_command) (int argc, char *argv[], char *cmdline); HSYS_DLL_IMPORT void (*daemon_task) (void); HSYS_DLL_IMPORT void (*panel_display) (void); HSYS_DLL_IMPORT void *(*panel_command) (void *); HSYS_DLL_IMPORT void *(*debug_device_state) (DEVBLK *); HSYS_DLL_IMPORT void *(*debug_cpu_state) (REGS *); HSYS_DLL_IMPORT void *(*debug_cd_cmd) (char *); HSYS_DLL_IMPORT void *(*debug_watchdog_signal) (REGS *); HSYS_DLL_IMPORT void *(*debug_program_interrupt) (REGS *, int); HSYS_DLL_IMPORT void *(*debug_diagnose) (U32, int, int, REGS *); HSYS_DLL_IMPORT void *(*debug_iucv) (int, VADR, REGS *); HSYS_DLL_IMPORT void *(*debug_sclp_unknown_command) (U32, void *, REGS *); HSYS_DLL_IMPORT void *(*debug_sclp_unknown_event) (void *, void *, REGS *); HSYS_DLL_IMPORT void *(*debug_sclp_unknown_event_mask) (void *, void *, REGS *); HSYS_DLL_IMPORT void *(*debug_chsc_unknown_request) (void *, void *, REGS *); HSYS_DLL_IMPORT void *(*debug_sclp_event_data) (void *, void *, REGS *); #else void *panel_command (void *cmdline); void panel_display (void); #define debug_cpu_state NULL #define debug_cd_cmd NULL #define debug_device_state NULL #define debug_program_interrupt NULL #define debug_diagnose NULL #define debug_iucv NULL #define debug_sclp_unknown_command NULL #define debug_sclp_unknown_event NULL #define debug_sclp_event_data NULL #define debug_chsc_unknown_request NULL #define debug_watchdog_signal NULL #endif /* Functions in module loadparm.c */ void set_loadparm(char *name); void get_loadparm(BYTE *dest); char *str_loadparm(); void set_lparname(char *name); void get_lparname(BYTE *dest); LOADPARM_DLL_IMPORT char *str_lparname(); void set_manufacturer(char *name); void set_plant(char *name); void set_model(int argc, char *m1, char* m2, char* m3, char* m4); void get_manufacturer(BYTE *name); void get_plant(BYTE *name); void get_model(BYTE *name); void get_modelcapa(BYTE *name); void get_modelperm(BYTE *name); void get_modeltemp(BYTE *name); void get_sysname(BYTE *name); void get_systype(BYTE *name); void get_sysplex(BYTE *name); void set_sysname(BYTE *name); void set_systype(BYTE *name); void set_sysplex(BYTE *name); void get_mpfactors(BYTE *dest); /* Functions in module impl.c */ IMPL_DLL_IMPORT void system_cleanup(void); typedef void (*LOGCALLBACK)(const char *,size_t); typedef void *(*COMMANDHANDLER)(void *); IMPL_DLL_IMPORT int impl(int,char **); IMPL_DLL_IMPORT void regiserLogCallback(LOGCALLBACK); IMPL_DLL_IMPORT COMMANDHANDLER getCommandHandler(void); /* Functions in module timer.c */ void update_TOD_clock (void); void *timer_update_thread (void *argp); /* Functions in module service.c */ void scp_command (char *command, int priomsg); int can_signal_quiesce (); int signal_quiesce (U16 count, BYTE unit); void sclp_attention(U16 type); void sclp_reset(); SERV_DLL_IMPORT void sclp_sysg_attention(); int servc_hsuspend(void *file); int servc_hresume(void *file); /* Functions in module ckddasd.c */ void ckd_build_sense ( DEVBLK *, BYTE, BYTE, BYTE, BYTE, BYTE); int ckddasd_init_handler ( DEVBLK *dev, int argc, char *argv[]); void ckddasd_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ); int ckddasd_close_device ( DEVBLK *dev ); void ckddasd_query_device (DEVBLK *dev, char **class, int buflen, char *buffer); int ckddasd_hsuspend ( DEVBLK *dev, void *file ); int ckddasd_hresume ( DEVBLK *dev, void *file ); /* Functions in module fbadasd.c */ FBA_DLL_IMPORT void fbadasd_syncblk_io (DEVBLK *dev, BYTE type, int blknum, int blksize, BYTE *iobuf, BYTE *unitstat, U16 *residual); FBA_DLL_IMPORT void fbadasd_read_block ( DEVBLK *dev, int blknum, int blksize, int blkfactor, BYTE *iobuf, BYTE *unitstat, U16 *residual ); FBA_DLL_IMPORT void fbadasd_write_block ( DEVBLK *dev, int blknum, int blksize, int blkfactor, BYTE *iobuf, BYTE *unitstat, U16 *residual ); int fbadasd_init_handler ( DEVBLK *dev, int argc, char *argv[]); void fbadasd_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ); int fbadasd_close_device ( DEVBLK *dev ); void fbadasd_query_device (DEVBLK *dev, char **class, int buflen, char *buffer); int fbadasd_hsuspend ( DEVBLK *dev, void *file ); int fbadasd_hresume ( DEVBLK *dev, void *file ); /* Functions in module cckddasd.c */ DEVIF cckddasd_init_handler; int cckddasd_close_device (DEVBLK *); int cckd_read_track (DEVBLK *, int, BYTE *); int cckd_update_track (DEVBLK *, int, int, BYTE *, int, BYTE *); int cfba_read_block (DEVBLK *, int, BYTE *); int cfba_write_block (DEVBLK *, int, int, BYTE *, int, BYTE *); CCKD_DLL_IMPORT void *cckd_sf_add (void *); CCKD_DLL_IMPORT void *cckd_sf_remove (void *); CCKD_DLL_IMPORT void *cckd_sf_stats (void *); CCKD_DLL_IMPORT void *cckd_sf_comp (void *); CCKD_DLL_IMPORT void *cckd_sf_chk (void *); CCKD_DLL_IMPORT int cckd_command(char *, int); CCKD_DLL_IMPORT void cckd_print_itrace (); /* Functions in module cckdutil.c */ CCDU_DLL_IMPORT int cckd_swapend (DEVBLK *); CCDU_DLL_IMPORT void cckd_swapend_chdr (CCKD_DEVHDR *); CCDU_DLL_IMPORT void cckd_swapend_l1 (CCKD_L1ENT *, int); CCDU_DLL_IMPORT void cckd_swapend_l2 (CCKD_L2ENT *); CCDU_DLL_IMPORT void cckd_swapend_free (CCKD_FREEBLK *); CCDU_DLL_IMPORT void cckd_swapend4 (char *); CCDU_DLL_IMPORT void cckd_swapend2 (char *); CCDU_DLL_IMPORT int cckd_endian (); CCDU_DLL_IMPORT int cckd_comp (DEVBLK *); CCDU_DLL_IMPORT int cckd_chkdsk (DEVBLK *, int); CCDU_DLL_IMPORT void cckdumsg (DEVBLK *, int, char *, ...); /* Functions in module hscmisc.c */ int herc_system (char* command); void do_shutdown(); void display_regs (REGS *regs); void display_fregs (REGS *regs); void display_cregs (REGS *regs); void display_aregs (REGS *regs); void display_subchannel (DEVBLK *dev); void get_connected_client (DEVBLK* dev, char** pclientip, char** pclientname); void alter_display_real (char *opnd, REGS *regs); void alter_display_virt (char *opnd, REGS *regs); void disasm_stor(REGS *regs, char *opnd); int drop_privileges(int capa); /* Functions in module sr.c */ int suspend_cmd(int argc, char *argv[],char *cmdline); int resume_cmd(int argc, char *argv[],char *cmdline); /* Functions in ecpsvm.c that are not *direct* instructions */ /* but support functions either used by other instruction */ /* functions or from somewhere else */ #ifdef FEATURE_ECPSVM int ecpsvm_dosvc(REGS *regs, int svccode); int ecpsvm_dossm(REGS *regs,int b,VADR ea); int ecpsvm_dolpsw(REGS *regs,int b,VADR ea); int ecpsvm_dostnsm(REGS *regs,int b,VADR ea,int imm); int ecpsvm_dostosm(REGS *regs,int b,VADR ea,int imm); int ecpsvm_dosio(REGS *regs,int b,VADR ea); int ecpsvm_dodiag(REGS *regs,int r1,int r3,int b2,VADR effective_addr2); int ecpsvm_dolctl(REGS *regs,int r1,int r3,int b2,VADR effective_addr2); int ecpsvm_dostctl(REGS *regs,int r1,int r3,int b2,VADR effective_addr2); int ecpsvm_doiucv(REGS *regs,int b2,VADR effective_addr2); int ecpsvm_virttmr_ext(REGS *regs); #endif /* Functions in module w32ctca.c */ #if defined(OPTION_W32_CTCI) HSYS_DLL_IMPORT int (*debug_tt32_stats) (int); HSYS_DLL_IMPORT void (*debug_tt32_tracing) (int); #endif // defined(OPTION_W32_CTCI) /* Function in crypto.c */ #if defined(_FEATURE_MESSAGE_SECURITY_ASSIST) void renew_wrapping_keys(void); #endif #endif // _HEXTERNS_H hercules-3.12/hconsole.h0000664000175000017500000001077012564723224012173 00000000000000/* HCONSOLE.H (c) Copyright "Fish" (David B. Trout), 2009 */ /* Hercules console panel support functions header file */ ////////////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. ////////////////////////////////////////////////////////////////////////////////////////// #ifndef _HCONSOLE_H #define _HCONSOLE_H //----------------------------------------------------------------------------- // // VT100 User Guide // // Table 3-6 Cursor Control Key Codes // // Cursor Key VT52 ANSI and Cursor Key Mode ANSI and Cursor Key Mode // (Arrow) Mode Reset (Normal mode) Set (Application mode) // // Up ESC A ESC [ A ESC O A // Down ESC B ESC [ B ESC O B // Right ESC C ESC [ C ESC O C // Left ESC D ESC [ D ESC O D // //----------------------------------------------------------------------------- #define ANSI_RESET_ALL_ATTRIBUTES "\x1B[0m" #define KBD_HOME "\x1B[1~" #define KBD_INSERT "\x1B[2~" #define KBD_DELETE "\x1B[3~" #define KBD_END "\x1B[4~" #define KBD_PAGE_UP "\x1B[5~" #define KBD_PAGE_DOWN "\x1B[6~" #define KBD_UP_ARROW "\x1B[A" #define KBD_DOWN_ARROW "\x1B[B" #define KBD_RIGHT_ARROW "\x1B[C" #define KBD_LEFT_ARROW "\x1B[D" #define KBD_UP_ARROW2 "\x1BOA" #define KBD_DOWN_ARROW2 "\x1BOB" #define KBD_RIGHT_ARROW2 "\x1BOC" #define KBD_LEFT_ARROW2 "\x1BOD" // Does anyone know what the actual escape sequence that // gets generated actually is on Linux for "Alt+UpArrow" // and "Alt+DownArrow", etc?? Thanks! -- Fish #define KBD_ALT_UP_ARROW KBD_UP_ARROW2 #define KBD_ALT_DOWN_ARROW KBD_DOWN_ARROW2 #define KBD_ALT_RIGHT_ARROW KBD_RIGHT_ARROW2 #define KBD_ALT_LEFT_ARROW KBD_LEFT_ARROW2 #define KBD_CTRL_HOME "\x1B""w" // (is this right??) #define KBD_CTRL_END "\x1B""u" // (is this right??) #define KBD_CTRL_UP_ARROW "\x1B""D" // (is this right??) #define KBD_CTRL_DOWN_ARROW "\x1B""M" // (is this right??) //efine KBD_CTRL_RIGHT_ARROW "???????" // (luckily we don't need it right now) //efine KBD_CTRL_LEFT_ARROW "???????" // (luckily we don't need it right now) #define KBD_ASK_CURSOR_POS "\x1B[6n" // Return value is the string "\x1B[n;mR" // returned in the keyboard buffer where // n = decimal row, m = decimal column. // Hercules console color codes... #define COLOR_BLACK 0 #define COLOR_RED 1 #define COLOR_GREEN 2 #define COLOR_BLUE 3 #define COLOR_CYAN 4 #define COLOR_MAGENTA 5 #define COLOR_YELLOW 6 #define COLOR_DARK_GREY 7 #define COLOR_LIGHT_GREY 8 #define COLOR_LIGHT_RED 9 #define COLOR_LIGHT_GREEN 10 #define COLOR_LIGHT_BLUE 11 #define COLOR_LIGHT_CYAN 12 #define COLOR_LIGHT_MAGENTA 13 #define COLOR_LIGHT_YELLOW 14 #define COLOR_WHITE 15 #define COLOR_DEFAULT_FG 16 #define COLOR_DEFAULT_BG 17 #define COLOR_DEFAULT_LIGHT 18 extern int set_screen_color ( FILE* confp, short herc_fore, short herc_back ); // screen positions are 1-based; row 1 == top line; col 1 == leftmost column extern int set_screen_pos ( FILE* confp, short rowY1, short colX1 ); extern int clear_screen ( FILE* confp ); extern int erase_to_eol ( FILE* confp ); // 'save_and_set' = 1 --> just what it says; 0 --> restore from saved value. extern int set_or_reset_console_mode ( int keybrd_fd, short save_and_set ); extern void translate_keystroke( char kbbuf[], int* pkblen ); extern int console_beep( FILE* confp ); extern int get_console_dim( FILE* confp, int* rows, int* cols ); #ifdef OPTION_EXTCURS extern int get_cursor_pos( int keybrd_fd, FILE* confp, short* row, short* col ); #endif // OPTION_EXTCURS extern int set_console_cursor_shape( FILE* confp, int ins ); #if defined( _MSVC_ ) extern int w32_set_console_title( char* pszTitle ); #endif #endif // _HCONSOLE_H hercules-3.12/hextapi.h0000664000175000017500000000174012564723224012020 00000000000000/* HEXTAPI.H (c) Copyright Roger Bowler & Others, 2005-2009 */ /* Definition of Hercules External (public) APIs */ /********************************************************/ /* This file originally written by Ivan Warren */ /* THE STATE OF THIS API IS NOT YET FINALIZED */ /* AND THEREFORE, THE INTERFACE MAY CHANGE */ /********************************************************/ #ifndef _HEXTAPI_H_ #define _HEXTAPI_H_ #if defined(_MSVC_) && defined(HERC_DLL_BUILD) #define DLL_IMPORT __declspec(dllimport) #else #define DLL_IMPORT extern #endif typedef void (*LOGCALLBACK)(const char *,size_t); typedef void (*COMMANDHANDLER)(void *); #ifdef __cplusplus extern "C" { #endif /* LOG Callback */ DLL_IMPORT void registerLogCallback(LOGCALLBACK); /* Panel Commands */ DLL_IMPORT COMMANDHANDLER getCommandHandler(void); /* IMPL */ DLL_IMPORT int impl(int ac,char **av); #ifdef __cplusplus } #endif #endif hercules-3.12/hstdinc.h0000664000175000017500000001265112564723224012015 00000000000000/* HSTDINC.H (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules precompilation-eligible Header Files */ /* This file contains #include statements for all of the header */ /* files which are not dependent on the mainframe architectural */ /* features selected and thus are eligible for precompilation */ #ifndef _HSTDINC_H #define _HSTDINC_H #ifdef HAVE_CONFIG_H #include // Hercules build configuration options/settings #endif /////////////////////////////////////////////////////////////////////// // Required and optional SYSTEM headers... ////////////////////////////////////////////////////////////////////// #define _REENTRANT /* Ensure that reentrant code is generated *JJ */ #define _THREAD_SAFE /* Some systems use this instead *JJ */ #if defined(HAVE_STRSIGNAL) && defined(__GNUC__) && !defined(_GNU_SOURCE) #define _GNU_SOURCE /* required by strsignal() *JJ */ #endif /* Required headers -- These we ALWAYS need to have... */ #ifdef _MSVC_ // The following ensures certain functions get defined... // (such as TryEnterCriticalSection and InitializeCriticalSectionAndSpinCount) #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0403 // Windows 98 or WinNT SP4 or greater #endif #include // Windows Sockets 2 #include // (need struct tcp_keepalive) #endif #ifdef WIN32 #include #endif #ifdef _MSVC_ #include #include #include #include #include #include #include #include #endif #include #include #include #include #include #include #include #include #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef O_NONBLOCK #define O_NONBLOCK 0 #endif #include #include #include #if !defined(_MSVC_) #include #include #endif #include /* Optional headers -- These we can live without */ /* PROGRAMMING NOTE: On Darwin, must be included before , and on older Darwin systems, before and */ #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #if defined(BUILD_HERCIFC) #ifdef HAVE_LINUX_IF_TUN_H #include #endif #ifdef HAVE_NET_ROUTE_H #include #endif #endif // (just make it easier to #include hercifc.h) #if defined(BUILD_HERCIFC) || defined(_MSVC_) || !defined(HAVE_LINUX_IF_TUN_H) || !defined(HAVE_NET_IF_H) #define NEED_HERCIFC_H #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_MMAN_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_SYS_MTIO_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef HAVE_SYS_UN_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifdef HAVE_SYS_UTSNAME_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_BYTESWAP_H #ifndef NO_ASM_BYTESWAP #include #endif #endif #ifdef HAVE_BZLIB_H // windows.h #defines 'small' as char and bzlib.h // uses it for a variable name so we must #undef. #if defined(__CYGWIN__) #undef small #endif #include /* ISW 20050427 : CCKD_BZIP2/HET_BZIP2 are usually */ /* controlled by config.h (automagic). If config.h */ /* is not present however, then define them here. */ #if !defined(HAVE_CONFIG_H) #define CCKD_BZIP2 #define HET_BZIP2 #endif #endif #ifdef HAVE_DIRENT_H #include #endif #ifdef OPTION_DYNAMIC_LOAD #ifdef HDL_USE_LIBTOOL #include #else #if defined(__MINGW__) || defined(_MSVC_) #include "w32dl.h" #else #include #endif #endif #endif #ifdef HAVE_ICONV #include #endif #ifdef HAVE_INTTYPES_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_MATH_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_REGEX_H #include #endif #ifdef HAVE_SCHED_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_TERMIOS_H #include #endif #ifdef HAVE_ZLIB_H #include #endif #ifdef HAVE_SYS_CAPABILITY_H #include #endif #ifdef HAVE_SYS_PRCTL_H #include #endif // Some Hercules specific files, NOT guest arch dependent #if defined(_MSVC_) #include "hercwind.h" // Hercules definitions for Windows #else #include // Unix standard definitions #endif #ifdef C99_FLEXIBLE_ARRAYS #define FLEXIBLE_ARRAY // ("DEVBLK *memdev[];" syntax is supported) #else #define FLEXIBLE_ARRAY 0 // ("DEVBLK *memdev[0];" must be used instead) #endif #include "hostopts.h" // Must come before htypes.h #include "htypes.h" // Hercules-wide data types #endif // _HSTDINC_H hercules-3.12/hstdint.h0000664000175000017500000000270412564723224012034 00000000000000/* HSTDINT.H (c) Copyright Roger Bowler, 2006 */ /* Hercules standard integer definitions */ /*-------------------------------------------------------------------*/ /* The purpose of this file is to define the following typedefs: */ /* uint8_t, uint16_t, uint32_t, uint64_t */ /* int8_t, int16_t, int32_t, int64_t */ /* For Windows, the MSVC-specific C sized integer types are used. */ /* For Unix, definitions are included from stdint.h if it exists, */ /* otherwise from inttypes.h (if it exists), otherwise unistd.h */ /*-------------------------------------------------------------------*/ #ifndef _HSTDINT_H #define _HSTDINT_H #ifdef HAVE_CONFIG_H #include /* Hercules build configuration */ #endif #if defined(_MSVC_) typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef signed __int64 int64_t; #elif defined(HAVE_STDINT_H) #include /* Standard integer definitions */ #elif defined(HAVE_INTTYPES_H) #include /* Fixed size integral types */ #else #include /* Unix standard definitions */ #endif #endif /*_HSTDINT_H*/ hercules-3.12/hsocket.h0000664000175000017500000001330712564723224012020 00000000000000/* HSOCKET.H (c) Copyright Roger Bowler, 2005-2009 */ /* Equates for socket functions */ /* This header file contains equates for the socket functions */ /* and constants whose values differ between Unix and Winsock */ #if !defined(_HSOCKET_H) #define _HSOCKET_H #ifndef _HSOCKET_C_ #ifndef _HUTIL_DLL_ #define HSOCK_DLL_IMPORT DLL_IMPORT #else #define HSOCK_DLL_IMPORT extern #endif #else #define HSOCK_DLL_IMPORT DLL_EXPORT #endif /*-------------------------------------------------------------------*/ /* Socket related constants related to 'shutdown' API call */ /*-------------------------------------------------------------------*/ #ifdef _MSVC_ /* Map SUS\*nix constants to Windows socket equivalents */ #define SHUT_RD SD_RECEIVE #define SHUT_WR SD_SEND #define SHUT_RDWR SD_BOTH #endif #if defined(_WINSOCKAPI_) /*-------------------------------------------------------------------*/ /* Equates for systems which use the Winsock API */ /*-------------------------------------------------------------------*/ #define get_HSO_errno() ((int)WSAGetLastError()) #define set_HSO_errno(e) (WSASetLastError(e)) #define HSO_errno get_HSO_errno() #define HSO_EINTR WSAEINTR #define HSO_EBADF WSAEBADF #define HSO_EACCES WSAEACCES #define HSO_EFAULT WSAEFAULT #define HSO_EINVAL WSAEINVAL #define HSO_EMFILE WSAEMFILE #define HSO_EWOULDBLOCK WSAEWOULDBLOCK #define HSO_EINPROGRESS WSAEINPROGRESS #define HSO_EALREADY WSAEALREADY #define HSO_ENOTSOCK WSAENOTSOCK #define HSO_EDESTADDRREQ WSAEDESTADDRREQ #define HSO_EMSGSIZE WSAEMSGSIZE #define HSO_EPROTOTYPE WSAEPROTOTYPE #define HSO_ENOPROTOOPT WSAENOPROTOOPT #define HSO_EPROTONOSUPPORT WSAEPROTONOSUPPORT #define HSO_ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #define HSO_EOPNOTSUPP WSAEOPNOTSUPP #define HSO_EPFNOSUPPORT WSAEPFNOSUPPORT #define HSO_EAFNOSUPPORT WSAEAFNOSUPPORT #define HSO_EADDRINUSE WSAEADDRINUSE #define HSO_EADDRNOTAVAIL WSAEADDRNOTAVAIL #define HSO_ENETDOWN WSAENETDOWN #define HSO_ENETUNREACH WSAENETUNREACH #define HSO_ENETRESET WSAENETRESET #define HSO_ECONNABORTED WSAECONNABORTED #define HSO_ECONNRESET WSAECONNRESET #define HSO_ENOBUFS WSAENOBUFS #define HSO_EISCONN WSAEISCONN #define HSO_ENOTCONN WSAENOTCONN #define HSO_ESHUTDOWN WSAESHUTDOWN #define HSO_ETOOMANYREFS WSAETOOMANYREFS #define HSO_ETIMEDOUT WSAETIMEDOUT #define HSO_ECONNREFUSED WSAECONNREFUSED #define HSO_ELOOP WSAELOOP #define HSO_ENAMETOOLONG WSAENAMETOOLONG #define HSO_EHOSTDOWN WSAEHOSTDOWN #define HSO_EHOSTUNREACH WSAEHOSTUNREACH #define HSO_ENOTEMPTY WSAENOTEMPTY #define HSO_EPROCLIM WSAEPROCLIM #define HSO_EUSERS WSAEUSERS #define HSO_EDQUOT WSAEDQUOT #define HSO_ESTALE WSAESTALE #define HSO_EREMOTE WSAEREMOTE #else /*-------------------------------------------------------------------*/ /* Equates for systems which use the Berkeley sockets API */ /*-------------------------------------------------------------------*/ #define get_HSO_errno() (errno) #define set_HSO_errno(e) (errno=(e)) #define HSO_errno get_HSO_errno() #define HSO_EINTR EINTR #define HSO_EBADF EBADF #define HSO_EACCES EACCES #define HSO_EFAULT EFAULT #define HSO_EINVAL EINVAL #define HSO_EMFILE EMFILE #define HSO_EWOULDBLOCK EWOULDBLOCK #define HSO_EINPROGRESS EINPROGRESS #define HSO_EALREADY EALREADY #define HSO_ENOTSOCK ENOTSOCK #define HSO_EDESTADDRREQ EDESTADDRREQ #define HSO_EMSGSIZE EMSGSIZE #define HSO_EPROTOTYPE EPROTOTYPE #define HSO_ENOPROTOOPT ENOPROTOOPT #define HSO_EPROTONOSUPPORT EPROTONOSUPPORT #define HSO_ESOCKTNOSUPPORT ESOCKTNOSUPPORT #define HSO_EOPNOTSUPP EOPNOTSUPP #define HSO_EPFNOSUPPORT EPFNOSUPPORT #define HSO_EAFNOSUPPORT EAFNOSUPPORT #define HSO_EADDRINUSE EADDRINUSE #define HSO_EADDRNOTAVAIL EADDRNOTAVAIL #define HSO_ENETDOWN ENETDOWN #define HSO_ENETUNREACH ENETUNREACH #define HSO_ENETRESET ENETRESET #define HSO_ECONNABORTED ECONNABORTED #define HSO_ECONNRESET ECONNRESET #define HSO_ENOBUFS ENOBUFS #define HSO_EISCONN EISCONN #define HSO_ENOTCONN ENOTCONN #define HSO_ESHUTDOWN ESHUTDOWN #define HSO_ETOOMANYREFS ETOOMANYREFS #define HSO_ETIMEDOUT ETIMEDOUT #define HSO_ECONNREFUSED ECONNREFUSED #define HSO_ELOOP ELOOP #define HSO_ENAMETOOLONG ENAMETOOLONG #define HSO_EHOSTDOWN EHOSTDOWN #define HSO_EHOSTUNREACH EHOSTUNREACH #define HSO_ENOTEMPTY ENOTEMPTY #define HSO_EPROCLIM EPROCLIM #define HSO_EUSERS EUSERS #define HSO_EDQUOT EDQUOT #define HSO_ESTALE ESTALE #define HSO_EREMOTE EREMOTE #endif /*-------------------------------------------------------------------*/ /* Local function definitions */ /*-------------------------------------------------------------------*/ HSOCK_DLL_IMPORT int read_socket(int fd, void *ptr, int nbytes); HSOCK_DLL_IMPORT int write_socket(int fd, const void *ptr, int nbytes); #endif /*!defined(_HSOCKET_H)*/ hercules-3.12/w32stape.h0000664000175000017500000000266312564723224012033 00000000000000//////////////////////////////////////////////////////////////////////////////////// // W32STAPE.H -- Hercules Win32 SCSI Tape handling module // // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under // the Q Public License (http://www.hercules-390.org/herclic.html) // as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// // // This module contains only MSVC support for SCSI tapes. // Primary SCSI Tape support is in module 'scsitape.c'... // //////////////////////////////////////////////////////////////////////////////////// #ifndef _W32STAPE_H_ #define _W32STAPE_H_ #ifdef _MSVC_ #include "w32mtio.h" // Win32 version of 'mtio.h' #define WIN32_TAPE_DEVICE_NAME "\\\\.\\Tape0" #ifndef _W32STAPE_C_ #ifndef _HTAPE_DLL_ #define W32ST_DLL_IMPORT DLL_IMPORT #else #define W32ST_DLL_IMPORT extern #endif #else #define W32ST_DLL_IMPORT DLL_EXPORT #endif W32ST_DLL_IMPORT int w32_open_tape ( const char* path, int oflag, ... ); W32ST_DLL_IMPORT int w32_define_BOT ( int fd, U32 msk, U32 bot ); W32ST_DLL_IMPORT int w32_ioctl_tape ( int fd, int request, ... ); W32ST_DLL_IMPORT int w32_close_tape ( int fd ); W32ST_DLL_IMPORT ssize_t w32_read_tape ( int fd, void* buf, size_t nbyte ); W32ST_DLL_IMPORT ssize_t w32_write_tape ( int fd, const void* buf, size_t nbyte ); #endif // _MSVC_ #endif // _W32STAPE_H_ hercules-3.12/w32dl.h0000664000175000017500000000107712564723224011314 00000000000000/* W32DL.H (c) Copyright Jan Jaeger, 2004-2009 */ /* dlopen compat */ #ifndef _W32_DL_H #define _W32_DL_H #ifdef _WIN32 #define RTLD_NOW 0 #define dlopen(_name, _flags) \ (void*) ((_name) ? LoadLibrary((_name)) : GetModuleHandle( NULL ) ) #define dlsym(_handle, _symbol) \ (void*)GetProcAddress((HMODULE)(_handle), (_symbol)) #define dlclose(_handle) \ FreeLibrary((HMODULE)(_handle)) #define dlerror() \ ("(unknown)") #endif /* _WIN32 */ #endif /* _W32_DL_H */ hercules-3.12/hercwind.h0000664000175000017500000001552212564723224012164 00000000000000/* HERCWIND.H (c) Copyright Roger Bowler, 2005-2009 */ /* MSVC Environment Specific Definitions */ /*-------------------------------------------------------------------*/ /* Header file containing additional data structures and function */ /* prototypes required by Hercules in the MSVC environment */ /*-------------------------------------------------------------------*/ #if !defined(_HERCWIND_H) #define _HERCWIND_H // PROGRAMMING NOTE: Cygwin has a bug in setvbuf requiring us // to do an 'fflush()' after each stdout/err write, and it doesn't // hurt doing it for the MSVC build either... #define NEED_LOGMSG_FFLUSH #if !defined( _MSVC_ ) #error This file is only for building Hercules with MSVC #endif #if defined( _MSC_VER ) && (_MSC_VER < 1300) #error MSVC compiler versions less than 13.0 not supported. #endif #pragma intrinsic( memset, memcmp, memcpy ) /////////////////////////////////////////////////////////////////////// // The following is mostly for issuing "warning" messages since MS's // compiler doesn't support #warning. Instead, we must use #pragma // message as follows: // // #pragma message( MSVC_MESSAGE_LINENUM "blah, blah..." ) // // which results in: // // foobar.c(123) : blah, blah... // // which is really handy when using their Visual Studio IDE since // it allows us to quickly jump to that specific source statement // with just the press of a function key... #if !defined( MSVC_MESSAGE_LINENUM ) #define MSVC_STRINGIZE( L ) #L #define MSVC_MAKESTRING( M, L ) M( L ) #define MSVC_QUOTED_LINENUM MSVC_MAKESTRING( MSVC_STRINGIZE, __LINE__ ) #define MSVC_MESSAGE_LINENUM __FILE__ "(" MSVC_QUOTED_LINENUM ") : " #endif /////////////////////////////////////////////////////////////////////// // Disable some warnings that tend to get in the way... // // FIXME: purposely disabling warning C4244 is dangerous IMO and might // come back to haunt us in the future when we DO happen to introduce // an unintentional coding error that results in unexpected data loss. // // We should instead take the time to fix all places where it's issued // (being sure to add comments when we do) so that we can then rely on // C4244 to warn us of real/actual coding errors. - Fish, April 2006 #pragma warning( disable: 4142 ) // C4142: benign redefinition of type #pragma warning( disable: 4244 ) // C4244: conversion from 'type' to 'type', possible loss of data /////////////////////////////////////////////////////////////////////// #ifdef _MAX_PATH #define PATH_MAX _MAX_PATH #else #ifdef FILENAME_MAX #define PATH_MAX FILENAME_MAX #else #define PATH_MAX 260 #endif #endif struct dirent { long d_ino; char d_name[FILENAME_MAX + 1]; }; typedef unsigned __int32 in_addr_t; typedef unsigned char u_char; typedef unsigned int u_int; typedef unsigned long u_long; typedef unsigned __int8 u_int8_t; typedef unsigned __int16 u_int16_t; typedef unsigned __int32 u_int32_t; typedef unsigned __int64 u_int64_t; typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef signed __int64 int64_t; typedef int ssize_t; typedef int pid_t; typedef int mode_t; #include #include #include #include #include #define STDIN_FILENO fileno(stdin) #define STDOUT_FILENO fileno(stdout) #define STDERR_FILENO fileno(stderr) /* Bit settings for open() and stat() functions */ #define S_IRUSR _S_IREAD #define S_IWUSR _S_IWRITE #define S_IRGRP _S_IREAD #define S_IROTH _S_IREAD #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) #define S_ISCHR(m) (((m) & _S_IFMT) == _S_IFCHR) #define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO) /* Bit settings for access() function */ #define F_OK 0 #define W_OK 2 #define R_OK 4 #define hopen w32_hopen #define strcasecmp stricmp #define strncasecmp strnicmp #define snprintf _snprintf #define vsnprintf _vsnprintf #define strerror w32_strerror #define strerror_r w32_strerror_r #define srandom srand #define random rand #define inline __inline #define __inline__ __inline #define HAVE_STRUCT_IN_ADDR_S_ADDR #define HAVE_U_INT #define HAVE_U_INT8_T #define HAVE_LIBMSVCRT #define HAVE_SYS_MTIO_H // (ours is called 'w32mtio.h') #ifndef MAX_CPU_ENGINES #define MAX_CPU_ENGINES 8 #endif #define OPTION_CONFIG_SYMBOLS #define OPTION_ENHANCED_CONFIG_SYMBOLS #define OPTION_ENHANCED_CONFIG_INCLUDE #define OPTION_FTHREADS #define HAVE_STRSIGNAL #define EXTERNALGUI #define NO_SETUID #define NO_SIGABEND_HANDLER #undef NO_ATTR_REGPARM // ( ATTR_REGPARM(x) == __fastcall ) #define HAVE_ATTR_REGPARM // ( ATTR_REGPARM(x) == __fastcall ) #define C99_FLEXIBLE_ARRAYS // ("DEVBLK *memdev[];" supported) //#include "getopt.h" #define HAVE_GETOPT_LONG #include #define HAVE_SQRTL #define HAVE_LDEXPL #define HAVE_FABSL #define HAVE_FMODL #define HAVE_FREXPL // The following are needed by hostopts.h... #define HAVE_DECL_SIOCSIFNETMASK 1 // (manually defined in tuntap.h) #define HAVE_DECL_SIOCSIFHWADDR 1 // (manually defined in tuntap.h) #define HAVE_DECL_SIOCADDRT 0 // (unsupported by CTCI-W32) #define HAVE_DECL_SIOCDELRT 0 // (unsupported by CTCI-W32) #define HAVE_DECL_SIOCDIFADDR 0 // (unsupported by CTCI-W32) // SCSI tape handling transparency/portability #define HAVE_DECL_MTEOTWARN 1 // (always true since I made it up!) #define HAVE_DECL_MTEWARN 1 // (same as HAVE_DECL_MTEOTWARN) // GNUWin32 PCRE (Perl-Compatible Regular Expressions) support... #if defined(HAVE_PCRE) // (earlier packages failed to define this so we must do so ourselves) #define PCRE_DATA_SCOPE extern __declspec(dllimport) #include PCRE_INCNAME // (passed by makefile) #define OPTION_HAO // Hercules Automatic Operator #endif #if defined( _WIN64 ) #define SIZEOF_INT_P 8 #define SIZEOF_SIZE_T 8 #else #define SIZEOF_INT_P 4 #define SIZEOF_SIZE_T 4 #endif #define DBGTRACE DebugTrace inline void DebugTrace(char* fmt, ...) { const int chunksize = 512; int buffsize = 0; char* buffer = NULL; int rc = -1; va_list args; va_start( args, fmt ); do { if (buffer) free( buffer ); buffsize += chunksize; buffer = malloc( buffsize ); if (!buffer) __debugbreak(); rc = vsnprintf( buffer, buffsize, fmt, args); } while (rc < 0 || rc >= buffsize); OutputDebugStringA( buffer ); free( buffer ); va_end( args ); } #endif /*!defined(_HERCWIND_H)*/ hercules-3.12/getopt.h0000664000175000017500000000660712564723224011667 00000000000000/* GETOPT.H (c) Copyright see notice below */ /* NetBSD getopt parsing function */ /* * Copyright (c) 1987, 1993, 1994, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef __GETOPT_H__ #define __GETOPT_H__ #ifdef _MSVC_ #include "hostopts.h" #ifdef HDL_BUILD_SHARED #ifndef _GETOPT_C_ #ifndef _HUTIL_DLL_ #define GOP_DLL_IMPORT DLL_IMPORT #else /* _HUTIL_DLL_ */ #define GOP_DLL_IMPORT extern #endif /* _HUTIL_DLL_ */ #else #define GOP_DLL_IMPORT DLL_EXPORT #endif #else #define GOP_DLL_IMPORT extern #endif #endif #ifndef _MSVC_ #define GOP_DLL_IMPORT extern #endif #ifdef __cplusplus extern "C" { #endif GOP_DLL_IMPORT int opterr; /* if error message should be printed */ GOP_DLL_IMPORT int optind; /* index into parent argv vector */ GOP_DLL_IMPORT int optopt; /* character checked for validity */ GOP_DLL_IMPORT int optreset; /* reset getopt */ GOP_DLL_IMPORT char *optarg; /* argument associated with option */ GOP_DLL_IMPORT int getopt (int, char * const *, const char *); #ifdef __cplusplus } #endif #endif /* __GETOPT_H__ */ #ifndef __UNISTD_GETOPT__ #ifndef __GETOPT_LONG_H__ #define __GETOPT_LONG_H__ #ifdef __cplusplus extern "C" { #endif struct option { const char *name; int has_arg; int *flag; int val; }; GOP_DLL_IMPORT int getopt_long (int, char *const *, const char *, const struct option *, int *); #ifndef HAVE_DECL_GETOPT #define HAVE_DECL_GETOPT 1 #endif #define no_argument 0 #define required_argument 1 #define optional_argument 2 #ifdef __cplusplus } #endif #endif /* __GETOPT_LONG_H__ */ #endif /* __UNISTD_GETOPT__ */ hercules-3.12/w32mtio.h0000664000175000017500000003714712564723224011674 00000000000000//////////////////////////////////////////////////////////////////////////////////// // W32MTIO.H -- Win32 'mtio.h' (Magnetic Tape structures) // // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under // the Q Public License (http://www.hercules-390.org/herclic.html) // as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// // // From the Koders.com (http://www.koders.com/) entry for // the Unununium(uuu) project (http://unununium.org/) which, // believe it or not, states their source code is COMPLETELY // FREE (i.e. no licensing restrictions AT ALL!). // Modified as needed by Fish for Hercules Win32 port. // Original filename: mtio.h; new filename: w32mtio.h // //////////////////////////////////////////////////////////////////////////////////// #ifndef _W32MTIO_H_ #define _W32MTIO_H_ #ifdef _MSVC_ // (Fish: only needed for MSVC) //#include // (Fish: not needed) #define _IOWR _IOW // (Fish: see 'winsock2.h') //__BEGIN_DECLS // (Fish: not needed) /* structure for MTIOCTOP - mag tape op command */ struct mtop { short int mt_op; /* operations defined below */ int mt_count; /* how many of them */ }; /* Magnetic Tape operations [Not all operations supported by all drivers]: */ #define MTRESET 0 /* +reset drive in case of problems */ #define MTFSF 1 /* forward space over FileMark, * position at first record of next file */ #define MTBSF 2 /* backward space FileMark (position before FM) */ #define MTFSR 3 /* forward space record */ #define MTBSR 4 /* backward space record */ #define MTWEOF 5 /* write an end-of-file record (mark) */ #define MTREW 6 /* rewind */ #define MTOFFL 7 /* rewind and put the drive offline (eject?) */ #define MTNOP 8 /* no op, set status only (read with MTIOCGET) */ #define MTRETEN 9 /* retension tape */ #define MTBSFM 10 /* +backward space FileMark, position at FM */ #define MTFSFM 11 /* +forward space FileMark, position at FM */ #define MTEOM 12 /* goto end of recorded media (for appending files). * MTEOM positions after the last FM, ready for * appending another file. */ #define MTERASE 13 /* erase tape -- be careful! */ #define MTRAS1 14 /* run self test 1 (nondestructive) */ #define MTRAS2 15 /* run self test 2 (destructive) */ #define MTRAS3 16 /* reserved for self test 3 */ #define MTEOTWARN 17 /* Fish: Warning Zone size (0 bytes == disable) */ /* Some BSD's only support an "MTEWARN" boolean */ #define MTEWARN MTEOTWARN /* (for transparency/portability) */ #define MTSETBLK 20 /* set block length (SCSI) */ #define MTSETDENSITY 21 /* set tape density (SCSI) */ #define MTSEEK 22 /* seek to block (Tandberg, etc.) */ #define MTTELL 23 /* tell block (Tandberg, etc.) */ #define MTSETDRVBUFFER 24 /* set the drive buffering according to SCSI-2 */ /* ordinary buffered operation with code 1 */ #define MTFSS 25 /* space forward over setmarks */ #define MTBSS 26 /* space backward over setmarks */ #define MTWSM 27 /* write setmarks */ #define MTLOCK 28 /* lock the drive door */ #define MTUNLOCK 29 /* unlock the drive door */ #define MTLOAD 30 /* execute the SCSI load command */ #define MTUNLOAD 31 /* execute the SCSI unload command */ #define MTCOMPRESSION 32 /* control compression with SCSI mode page 15 */ #define MTSETPART 33 /* Change the active tape partition */ #define MTMKPART 34 /* Format the tape with one or two partitions */ /* structure for MTIOCGET - mag tape get status command */ struct mtget { long int mt_type; /* type of magtape device */ long int mt_resid; /* residual count: (not sure) * number of bytes ignored, or * number of files not skipped, or * number of records not skipped. */ /* the following registers are device dependent */ long int mt_dsreg; /* status register */ long int mt_gstat; /* generic (device independent) status */ long int mt_erreg; /* error register */ /* The next two fields are not always used */ /* these really are daddr_t, but that is only declared with _BSD_SOURCE */ long mt_fileno; /* number of current file on tape */ long mt_blkno; /* current block number */ }; /* * Constants for mt_type. Not all of these are supported, * and these are not all of the ones that are supported. */ #define MT_ISUNKNOWN 0x01 #define MT_ISQIC02 0x02 /* Generic QIC-02 tape streamer */ #define MT_ISWT5150 0x03 /* Wangtek 5150EQ, QIC-150, QIC-02 */ #define MT_ISARCHIVE_5945L2 0x04 /* Archive 5945L-2, QIC-24, QIC-02? */ #define MT_ISCMSJ500 0x05 /* CMS Jumbo 500 (QIC-02?) */ #define MT_ISTDC3610 0x06 /* Tandberg 6310, QIC-24 */ #define MT_ISARCHIVE_VP60I 0x07 /* Archive VP60i, QIC-02 */ #define MT_ISARCHIVE_2150L 0x08 /* Archive Viper 2150L */ #define MT_ISARCHIVE_2060L 0x09 /* Archive Viper 2060L */ #define MT_ISARCHIVESC499 0x0A /* Archive SC-499 QIC-36 controller */ #define MT_ISQIC02_ALL_FEATURES 0x0F/* Generic QIC-02 with all features */ #define MT_ISWT5099EEN24 0x11 /* Wangtek 5099-een24, 60MB, QIC-24 */ #define MT_ISTEAC_MT2ST 0x12 /* Teac MT-2ST 155mb drive, Teac DC-1 card (Wangtek type) */ #define MT_ISEVEREX_FT40A 0x32 /* Everex FT40A (QIC-40) */ #define MT_ISDDS1 0x51 /* DDS device without partitions */ #define MT_ISDDS2 0x52 /* DDS device with partitions */ #define MT_ISONSTREAM_SC 0x61 /* OnStream SCSI tape drives (SC-x0) and SCSI emulated (DI, DP, USB) */ #define MT_ISSCSI1 0x71 /* Generic ANSI SCSI-1 tape unit */ #define MT_ISSCSI2 0x72 /* Generic ANSI SCSI-2 tape unit */ /* QIC-40/80/3010/3020 ftape supported drives. * 20bit vendor ID + 0x800000 (see ftape-vendors.h) */ #define MT_ISFTAPE_UNKNOWN 0x800000 /* obsolete */ #define MT_ISFTAPE_FLAG 0x800000 struct mt_tape_info { long int t_type; /* device type id (mt_type) */ char* t_name; /* descriptive name */ }; #define MT_TAPE_INFO { \ {MT_ISUNKNOWN, "Unknown type of tape device"}, \ {MT_ISQIC02, "Generic QIC-02 tape streamer"}, \ {MT_ISWT5150, "Wangtek 5150, QIC-150"}, \ {MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, \ {MT_ISCMSJ500, "CMS Jumbo 500"}, \ {MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \ {MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \ {MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \ {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \ {MT_ISARCHIVESC499, "Archive SC-499 QIC-36 controller"}, \ {MT_ISQIC02_ALL_FEATURES, "Generic QIC-02 tape, all features"}, \ {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \ {MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \ {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \ {MT_ISONSTREAM_SC, "OnStream SC-, DI-, DP-, or USB tape drive"}, \ {MT_ISSCSI1, "Generic SCSI-1 tape"}, \ {MT_ISSCSI2, "Generic SCSI-2 tape"}, \ {0, NULL} \ } /* structure for MTIOCPOS - mag tape get position command */ struct mtpos { long int mt_blkno; /* current block number */ }; /* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended * as an interim solution for QIC-02 until DDI is fully implemented. */ struct mtconfiginfo { long int mt_type; /* drive type */ long int ifc_type; /* interface card type */ unsigned short int irqnr; /* IRQ number to use */ unsigned short int dmanr; /* DMA channel to use */ unsigned short int port; /* IO port base address */ unsigned long int debug; /* debugging flags */ unsigned int have_dens:1; unsigned int have_bsf:1; unsigned int have_fsr:1; unsigned int have_bsr:1; unsigned int have_eod:1; unsigned int have_seek:1; unsigned int have_tell:1; unsigned int have_ras1:1; unsigned int have_ras2:1; unsigned int have_ras3:1; unsigned int have_qfa:1; unsigned int pad1:5; char reserved[10]; }; /* structure for MTIOCVOLINFO, query information about the volume * currently positioned at (zftape) */ struct mtvolinfo { unsigned int mt_volno; /* vol-number */ unsigned int mt_blksz; /* blocksize used when recording */ unsigned int mt_rawsize; /* raw tape space consumed, in kb */ unsigned int mt_size; /* volume size after decompression, in kb */ unsigned int mt_cmpr:1; /* this volume has been compressed */ }; /* raw access to a floppy drive, read and write an arbitrary segment. * For ftape/zftape to support formatting etc. */ #define MT_FT_RD_SINGLE 0 #define MT_FT_RD_AHEAD 1 #define MT_FT_WR_ASYNC 0 /* start tape only when all buffers are full */ #define MT_FT_WR_MULTI 1 /* start tape, continue until buffers are empty */ #define MT_FT_WR_SINGLE 2 /* write a single segment and stop afterwards */ #define MT_FT_WR_DELETE 3 /* write deleted data marks, one segment at time */ struct mtftseg { unsigned int mt_segno; /* the segment to read or write */ unsigned int mt_mode; /* modes for read/write (sync/async etc.) */ int mt_result; /* result of r/w request, not of the ioctl */ void *mt_data; /* User space buffer: must be 29kb */ }; /* get tape capacity (ftape/zftape) */ struct mttapesize { unsigned long mt_capacity; /* entire, uncompressed capacity of a cartridge */ unsigned long mt_used; /* what has been used so far, raw uncompressed amount */ }; /* possible values of the ftfmt_op field */ #define FTFMT_SET_PARMS 1 /* set software parms */ #define FTFMT_GET_PARMS 2 /* get software parms */ #define FTFMT_FORMAT_TRACK 3 /* start formatting a tape track */ #define FTFMT_STATUS 4 /* monitor formatting a tape track */ #define FTFMT_VERIFY 5 /* verify the given segment */ struct ftfmtparms { unsigned char ft_qicstd; /* QIC-40/QIC-80/QIC-3010/QIC-3020 */ unsigned char ft_fmtcode; /* Refer to the QIC specs */ unsigned char ft_fhm; /* floppy head max */ unsigned char ft_ftm; /* floppy track max */ unsigned short ft_spt; /* segments per track */ unsigned short ft_tpc; /* tracks per cartridge */ }; struct ftfmttrack { unsigned int ft_track; /* track to format */ unsigned char ft_gap3; /* size of gap3, for FORMAT_TRK */ }; struct ftfmtstatus { unsigned int ft_segment; /* segment currently being formatted */ }; struct ftfmtverify { unsigned int ft_segment; /* segment to verify */ unsigned long ft_bsm; /* bsm as result of VERIFY cmd */ }; struct mtftformat { unsigned int fmt_op; /* operation to perform */ union fmt_arg { struct ftfmtparms fmt_parms; /* format parameters */ struct ftfmttrack fmt_track; /* ctrl while formatting */ struct ftfmtstatus fmt_status; struct ftfmtverify fmt_verify; /* for verifying */ } fmt_arg; }; /* mag tape io control commands */ #define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ #define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */ #define MTIOCPOS _IOR('m', 3, struct mtpos) /* get tape position */ /* The next two are used by the QIC-02 driver for runtime reconfiguration. * See tpqic02.h for struct mtconfiginfo. */ #define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) /* get tape config */ #define MTIOCSETCONFIG _IOW('m', 5, struct mtconfiginfo) /* set tape config */ /* the next six are used by the floppy ftape drivers and its frontends * sorry, but MTIOCTOP commands are write only. */ #define MTIOCRDFTSEG _IOWR('m', 6, struct mtftseg) /* read a segment */ #define MTIOCWRFTSEG _IOWR('m', 7, struct mtftseg) /* write a segment */ #define MTIOCVOLINFO _IOR('m', 8, struct mtvolinfo) /* info about volume */ #define MTIOCGETSIZE _IOR('m', 9, struct mttapesize) /* get cartridge size*/ #define MTIOCFTFORMAT _IOWR('m', 10, struct mtftformat) /* format ftape */ #define MTIOCFTCMD _IOWR('m', 11, struct mtftcmd) /* send QIC-117 cmd */ /* Generic Mag Tape (device independent) status macros for examining * mt_gstat -- HP-UX compatible. * There is room for more generic status bits here, but I don't * know which of them are reserved. At least three or so should * be added to make this really useful. */ #define GMT_EOF(x) ((x) & 0x80000000) #define GMT_BOT(x) ((x) & 0x40000000) #define GMT_EOT(x) ((x) & 0x20000000) #define GMT_SM(x) ((x) & 0x10000000) /* DDS setmark */ #define GMT_EOD(x) ((x) & 0x08000000) /* DDS EOD */ #define GMT_WR_PROT(x) ((x) & 0x04000000) /* #define GMT_ ? ((x) & 0x02000000) */ #define GMT_ONLINE(x) ((x) & 0x01000000) #define GMT_D_6250(x) ((x) & 0x00800000) #define GMT_D_1600(x) ((x) & 0x00400000) #define GMT_D_800(x) ((x) & 0x00200000) /* #define GMT_ ? ((x) & 0x00100000) */ /* #define GMT_ ? ((x) & 0x00080000) */ #define GMT_DR_OPEN(x) ((x) & 0x00040000) /* door open (no tape) */ /* #define GMT_ ? ((x) & 0x00020000) */ #define GMT_IM_REP_EN(x) ((x) & 0x00010000) /* immediate report mode */ /* 16 generic status bits unused */ /* SCSI-tape specific definitions */ /* Bitfield shifts in the status */ #define MT_ST_BLKSIZE_SHIFT 0 #define MT_ST_BLKSIZE_MASK 0xffffff #define MT_ST_DENSITY_SHIFT 24 #define MT_ST_DENSITY_MASK 0xff000000 #define MT_ST_SOFTERR_SHIFT 0 #define MT_ST_SOFTERR_MASK 0xffff /* Bitfields for the MTSETDRVBUFFER ioctl */ #define MT_ST_OPTIONS 0xf0000000 #define MT_ST_BOOLEANS 0x10000000 #define MT_ST_SETBOOLEANS 0x30000000 #define MT_ST_CLEARBOOLEANS 0x40000000 #define MT_ST_WRITE_THRESHOLD 0x20000000 #define MT_ST_DEF_BLKSIZE 0x50000000 #define MT_ST_DEF_OPTIONS 0x60000000 #define MT_ST_TIMEOUTS 0x70000000 #define MT_ST_SET_TIMEOUT (MT_ST_TIMEOUTS | 0x000000) #define MT_ST_SET_LONG_TIMEOUT (MT_ST_TIMEOUTS | 0x100000) #define MT_ST_BUFFER_WRITES 0x0001 #define MT_ST_ASYNC_WRITES 0x0002 #define MT_ST_READ_AHEAD 0x0004 #define MT_ST_DEBUGGING 0x0008 #define MT_ST_TWO_FM 0x0010 #define MT_ST_FAST_MTEOM 0x0020 #define MT_ST_AUTO_LOCK 0x0040 #define MT_ST_DEF_WRITES 0x0080 #define MT_ST_CAN_BSR 0x0100 #define MT_ST_NO_BLKLIMS 0x0200 #define MT_ST_CAN_PARTITIONS 0x0400 #define MT_ST_SCSI2LOGICAL 0x0800 #define MT_ST_SYSV 0x1000 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */ #define MT_ST_CLEAR_DEFAULT 0xfffff #define MT_ST_DEF_DENSITY (MT_ST_DEF_OPTIONS | 0x100000) #define MT_ST_DEF_COMPRESSION (MT_ST_DEF_OPTIONS | 0x200000) #define MT_ST_DEF_DRVBUFFER (MT_ST_DEF_OPTIONS | 0x300000) /* The offset for the arguments for the special HP changer load command. */ #define MT_ST_HPLOADER_OFFSET 10000 /* Specify default tape device. */ #ifndef DEFTAPE #define DEFTAPE "/dev/tape/0" #endif //__END_DECLS // (Fish: not needed) #endif // _MSVC_ #endif // _W32MTIO_H_ hercules-3.12/vmd250.h0000664000175000017500000000235412564723224011375 00000000000000/* VMD250.H (c) Copyright Harold Grovesteen, 2009 */ /* z/VM 5.4 DIAGNOSE call X'250' */ #if !defined(__VMD250_H__) #define __VMD250_H__ /*-------------------------------------------------------------------*/ /* DIAGNOSE X'250' Block I/O - Device Environment */ /*-------------------------------------------------------------------*/ struct VMBIOENV { DEVBLK *dev; /* Device block pointer of device */ S32 blksiz; /* Block size being used by the guest */ S64 offset; /* Guest provided offset */ S64 begblk; /* BIO established beginning block number */ S64 endblk; /* BIO established ending block number */ int isCKD; /* Count-Key-Data device */ int isRO; /* Device is read-only */ int blkphys; /* Block to physical relationship */ /* For FBA: physical sectors per block */ /* For CKD: physical blocks per track */ BYTE sense[32]; /* Save area for any pending sense data */ }; #endif /* !defined(__VMD250_H__) */ hercules-3.12/INSTALL0000664000175000017500000001732112564723224011240 00000000000000Basic Installation ================== These are generic installation instructions for Unix-like systems. For Windows refer to README.WIN32 or README.WIN64 instead. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code. 2. Check that you have all of the necessary packages installed: utils/bldlvlck then create the configure script by running: ./autogen.sh 3. Build the Makefiles by running: ./configure Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 4. Type `make' to compile the package. 5. Optionally, type `make check' to run any self-tests that come with the package. 6. Type `make install' to install the programs and any data files and documentation. 7. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. hercules-3.12/dyngui.c0000664000175000017500000020670112564723224011654 00000000000000/* DYNGUI.C (c) Copyright "Fish" (David B. Trout), 2003-2014 */ /* Hercules External GUI Interface DLL */ #include "hstdinc.h" #include "hercules.h" // (#includes "config." w/#define for VERSION) #ifdef EXTERNALGUI #if defined(OPTION_DYNAMIC_LOAD) #include "devtype.h" #include "opcode.h" /////////////////////////////////////////////////////////////////////////////// // Some handy macros... (feel free to add these to hercules.h) #ifndef BOOL #define BOOL BYTE #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif /////////////////////////////////////////////////////////////////////////////// // Our global variables... (initialized by our "Initialize" function) #define INPUT_STREAM_FILE_PTR ( stdin ) #define OUTPUT_STREAM_FILE_PTR ( stdout ) #define STATUS_STREAM_FILE_PTR ( stderr ) #define MAX_COMMAND_LEN ( 1024 ) #define DEF_MAXRATES_RPT_INTVL ( 1440 ) #if defined( WIN32 ) && !defined( HDL_USE_LIBTOOL ) #if !defined( _MSVC_ ) SYSBLK *psysblk; // (ptr to Herc's SYSBLK structure) #define sysblk (*psysblk) #endif #endif static FILE* fOutputStream = NULL; // (stdout stream) static FILE* fStatusStream = NULL; // (stderr stream) static int nInputStreamFileNum = -1; // (file descriptor for stdin stream) static int gui_nounload = 1; // (nounload indicator) // The device query buffer SHOULD be the maximum device filename length // plus the maximum descriptive length of any/all options for the device, // but there is no #define for either so we have no choice but to impose // our own maximum. #define MAX_DEVICEQUERY_LEN ( 1024 + 256 ) /////////////////////////////////////////////////////////////////////////////// // Some forward references... (our own functions that we call) void Initialize (); void ProcessingLoop (); void Cleanup (); void UpdateTargetCPU (); void ReadInputData (int nTimeoutMillsecs); void ProcessInputData (); void* gui_panel_command (char* pszCommand); void UpdateStatus (); void HandleForcedRefresh(); void UpdateCPUStatus (); void UpdateRegisters (); void UpdateDeviceStatus (); void NewUpdateDevStats (); void gui_fprintf( FILE* stream, const char* pszFormat, ... ); /////////////////////////////////////////////////////////////////////////////// // Our main processing loop... BOOL bDoneProcessing = FALSE; // (set to TRUE to exit) void ProcessingLoop() { // Notify logger_thread we're in control sysblk.panel_init = 1; // Our main purpose in life: read input stream and process // any commands that may be entered, and send periodic status // information back to the external gui via its status stream. // Note we only exit whenever our bDoneProcessing flag is set // which is normally not done until just before Herc unloads // us which is normally not done until immediately before it // terminates. // Also note we re-retrieve sysblk.panrate each iteration // since it could change from one iteration to the next as a result // of the Hercules "panrate" command being entered and processed. while (!bDoneProcessing) { UpdateTargetCPU(); // ("cpu" command could have changed it) UpdateStatus(); // (keep sending status back to gui...) ReadInputData( sysblk.panrate ); ProcessInputData(); // (if there even is any of course...) } } /////////////////////////////////////////////////////////////////////////////// int pcpu = INT_MAX; // target cpu# for commands and displays REGS* pTargetCPU_REGS = NULL; // pointer to target cpu REGS int prev_pcpu = INT_MAX; // (previous value) REGS* pPrevTargetCPU_REGS = NULL; // (previous value) REGS copyregs; // (copy of active cpu's REGS) REGS copysieregs; // (same but when in SIE mode) REGS* CopyREGS( int cpu ); // (fwd ref) /////////////////////////////////////////////////////////////////////////////// void UpdateTargetCPU () { if (!sysblk.shutdown) pTargetCPU_REGS = CopyREGS( pcpu = sysblk.pcpu ); } /////////////////////////////////////////////////////////////////////////////// // (get non-moving/non-dynamic working copy of active cpu's register context) REGS* CopyREGS( int cpu ) // (same logic as in panel.c) { REGS* regs; if (cpu < 0 || cpu >= sysblk.maxcpu) cpu = 0; obtain_lock( &sysblk.cpulock[cpu] ); if (!(regs = sysblk.regs[cpu])) { release_lock( &sysblk.cpulock[cpu] ); return &sysblk.dummyregs; } memcpy( ©regs, regs, sysblk.regs_copy_len ); if (!copyregs.hostregs) { release_lock(&sysblk.cpulock[cpu]); return &sysblk.dummyregs; } #if defined(_FEATURE_SIE) if (regs->sie_active) { memcpy( ©sieregs, regs->guestregs, sysblk.regs_copy_len ); copyregs.guestregs = ©sieregs; copysieregs.hostregs = ©regs; regs = ©sieregs; } else #endif regs = ©regs; SET_PSW_IA( regs ); release_lock( &sysblk.cpulock[cpu] ); return regs; } /////////////////////////////////////////////////////////////////////////////// char* pszInputBuff = NULL; // ptr to buffer int nInputBuffSize = (MAX_COMMAND_LEN+1); // how big the buffer is int nInputLen = 0; // amount of data it's holding /////////////////////////////////////////////////////////////////////////////// void ReadInputData ( int nTimeoutMillsecs ) { size_t nMaxBytesToRead; int nBytesRead; char* pReadBuffer; // Wait for keyboard input data to arrive... #if !defined( _MSVC_ ) fd_set input_fd_set; struct timeval wait_interval_timeval; int rc; FD_ZERO ( &input_fd_set ); FD_SET ( nInputStreamFileNum, &input_fd_set ); wait_interval_timeval.tv_sec = nTimeoutMillsecs / 1000; wait_interval_timeval.tv_usec = (nTimeoutMillsecs % 1000) * 1000; if ((rc = select( nInputStreamFileNum+1, &input_fd_set, NULL, NULL, &wait_interval_timeval )) < 0) { if (HSO_EINTR == HSO_errno) return; // (we were interrupted by a signal) // A bona fide error occurred; abort... logmsg ( _("HHCDG003S select failed on input stream: %s\n") ,strerror(HSO_errno) ); bDoneProcessing = TRUE; // (force main loop to exit) return; } // Has keyboard input data indeed arrived yet? if (!FD_ISSET( nInputStreamFileNum, &input_fd_set )) return; // (nothing for us to do...) #endif // !defined( _MSVC_ ) // Ensure our buffer never overflows... (-2 because // we need room for at least 1 byte + NULL terminator) MINMAX(nInputLen,0,(nInputBuffSize-2)); // Read input data into next available buffer location... // (nMaxBytesToRead-1 == room for NULL terminator) pReadBuffer = (pszInputBuff + nInputLen); nMaxBytesToRead = (nInputBuffSize - nInputLen) - 1; #if !defined( _MSVC_ ) if ((nBytesRead = read( nInputStreamFileNum, pReadBuffer, nMaxBytesToRead )) < 0) { if (EINTR == errno) return; // (we were interrupted by a signal) // A bona fide error occurred; abort... logmsg ( _("HHCDG004S read failed on input stream: %s\n") ,strerror(errno) ); bDoneProcessing = TRUE; // (force main loop to exit) return; } #else // defined( _MSVC_ ) if ( ( nBytesRead = w32_get_stdin_char( pReadBuffer, nTimeoutMillsecs ) ) <= 0 ) return; #endif // !defined( _MSVC_ ) // Update amount of input data we have and // ensure that it's always NULL terminated... MINMAX(nBytesRead,0,nInputBuffSize); nInputLen += nBytesRead; MINMAX(nInputLen,0,(nInputBuffSize-1)); *(pszInputBuff + nInputLen) = 0; } /////////////////////////////////////////////////////////////////////////////// char* pszCommandBuff = NULL; // ptr to buffer int nCommandBuffSize = (MAX_COMMAND_LEN+1); // how big the buffer is int nCommandLen = 0; // amount of data it's holding /////////////////////////////////////////////////////////////////////////////// // Process the data we just read from the input stream... void ProcessInputData () { char* pNewLineChar; // Ensure our buffer is NULL terminated... MINMAX(nInputLen,0,(nInputBuffSize-1)); *(pszInputBuff + nInputLen) = 0; // Input commands are delimited by newline characters... while (nInputLen && (pNewLineChar = strchr(pszInputBuff,'\n')) != NULL) { // Extract command from input buffer // into our command processing buffer... nCommandLen = (pNewLineChar - pszInputBuff); MINMAX(nCommandLen,0,(nCommandBuffSize-1)); memcpy(pszCommandBuff, pszInputBuff, nCommandLen); *(pszCommandBuff + nCommandLen) = 0; // Process the extracted command... // Note that we always call the registered "panel_command" function // rather than call our "gui_panel_command" function directly. This // is in case some other DLL has overridden OUR command handler... panel_command ( pszCommandBuff ); // (call registered handler) // Shift remaining data back to beginning of input buffer... nInputLen = ((pszInputBuff + nInputLen) - (pNewLineChar+1)); MINMAX(nInputLen,0,(nInputBuffSize-1)); memmove(pszInputBuff,pNewLineChar+1,nInputLen); *(pszInputBuff + nInputLen) = 0; } } /////////////////////////////////////////////////////////////////////////////// // (These are actually boolean flags..) double gui_version = 0.0; // (version of HercGUI we're talking to) BYTE gui_forced_refresh = 1; // (force initial update refresh) BYTE gui_wants_gregs = 0; BYTE gui_wants_gregs64 = 0; BYTE gui_wants_cregs = 0; BYTE gui_wants_cregs64 = 0; BYTE gui_wants_aregs = 0; BYTE gui_wants_fregs = 0; BYTE gui_wants_fregs64 = 0; BYTE gui_wants_devlist = 0; BYTE gui_wants_new_devlist = 1; // (should always be initially on) #if defined(OPTION_MIPS_COUNTING) BYTE gui_wants_aggregates = 1; BYTE gui_wants_cpupct = 0; BYTE gui_wants_cpupct_all = 0; int prev_cpupct [ MAX_CPU_ENGINES ]; U32 prev_mips_rate = 0; U32 prev_sios_rate = 0; #endif // defined(OPTION_MIPS_COUNTING) /////////////////////////////////////////////////////////////////////////////// // Our Hercules "panel_command" override... void* gui_panel_command (char* pszCommand) { void* (*next_panel_command_handler)(char* pszCommand); // Special GUI commands start with ']'. At the moment, all these special // gui commands tell us is what status information it's interested in... if ( ']' != *pszCommand ) goto NotSpecialGUICommand; gui_forced_refresh = 1; // (forced update refresh) pszCommand++; // (bump past ']') if (strncasecmp(pszCommand,"VERS=",5) == 0) { gui_version = atof(pszCommand+5); return NULL; } if (strncasecmp(pszCommand,"SCD=",4) == 0) { // (set current directory) if (chdir(pszCommand+4) != 0) { // (inform gui of error) char *cwd = getcwd( NULL, 0 ); if (cwd) { debug_cd_cmd( cwd ); free( cwd ); } } return NULL; } if (strncasecmp(pszCommand,"GREGS=",6) == 0) { gui_wants_gregs = atoi(pszCommand+6); return NULL; } if (strncasecmp(pszCommand,"GREGS64=",8) == 0) { gui_wants_gregs64 = atoi(pszCommand+8); return NULL; } if (strncasecmp(pszCommand,"CREGS=",6) == 0) { gui_wants_cregs = atoi(pszCommand+6); return NULL; } if (strncasecmp(pszCommand,"CREGS64=",8) == 0) { gui_wants_cregs64 = atoi(pszCommand+8); return NULL; } if (strncasecmp(pszCommand,"AREGS=",6) == 0) { gui_wants_aregs = atoi(pszCommand+6); return NULL; } if (strncasecmp(pszCommand,"FREGS=",6) == 0) { gui_wants_fregs = atoi(pszCommand+6); return NULL; } if (strncasecmp(pszCommand,"FREGS64=",8) == 0) { gui_wants_fregs64 = atoi(pszCommand+8); return NULL; } if (strncasecmp(pszCommand,"DEVLIST=",8) == 0) { gui_wants_devlist = atoi(pszCommand+8); if ( gui_wants_devlist ) gui_wants_new_devlist = 0; return NULL; } if (strncasecmp(pszCommand,"NEWDEVLIST=",11) == 0) { gui_wants_new_devlist = atoi(pszCommand+11); if ( gui_wants_new_devlist ) gui_wants_devlist = 0; return NULL; } if (strncasecmp(pszCommand,"MAINSTOR=",9) == 0) { gui_fprintf(fStatusStream,"MAINSTOR=%"UINT_PTR_FMT"d\n",(uintptr_t)pTargetCPU_REGS->mainstor); // Here's a trick! Hercules reports its version number to the GUI // by means of the MAINSIZE value! Later releases of HercGUI know // to interpret mainsizes less than 1000 as Hercule's version number. // Earlier versions of HercGUI will simply try to interpret it as // the actual mainsize, but no real harm is done since we immediately // send it the CORRECT mainsize immediately afterwards. This allows // future versions of HercGUI to know whether the version of Hercules // that it's talking to supports a given feature or not. Slick, eh? :) gui_fprintf(fStatusStream,"MAINSIZE=%s\n",VERSION); if (gui_version < 1.12) gui_fprintf(fStatusStream,"MAINSIZE=%d\n",(U32)sysblk.mainsize); else gui_fprintf(fStatusStream,"MAINSIZE=%"UINT_PTR_FMT"d\n",(uintptr_t)sysblk.mainsize); return NULL; } #if defined(OPTION_MIPS_COUNTING) if (strncasecmp(pszCommand,"CPUPCT=",7) == 0) { gui_wants_cpupct = atoi(pszCommand+7); return NULL; } if (strncasecmp(pszCommand,"CPUPCTALL=",10) == 0) { if (!(gui_wants_cpupct_all = atoi(pszCommand+10))) memset( &prev_cpupct[0], 0xFF, sizeof(prev_cpupct) ); return NULL; } if (strncasecmp(pszCommand,"AGGREGATE=",10) == 0) { gui_wants_aggregates = atoi(pszCommand+10); gui_forced_refresh = 1; return NULL; } #endif // Silently ignore any unrecognized special GUI commands... return NULL; // (silently ignore it) NotSpecialGUICommand: // Ignore "commands" that are actually just comments (start with '*' or '#') if ('*' == pszCommand[0] || '#' == pszCommand[0]) { if ('*' == pszCommand[0]) // (LOUD comment?) logmsg("%s\n",pszCommand); // (then log to console) return NULL; // (and otherwise ignore it) } // Otherwise it's not a command that we handle. Call the next higher // level command handler which, under normal circumstances SHOULD be // Hercules's "panel_command" function, but which MAY have been over- // ridden by yet some OTHER dynamically loaded command handler... next_panel_command_handler = HDL_FINDNXT( gui_panel_command ); if (!next_panel_command_handler) // (extremely unlikely!) return (char *)-1; // (extremely unlikely!) return next_panel_command_handler( pszCommand ); } /////////////////////////////////////////////////////////////////////////////// // Status updating control fields... QWORD psw, prev_psw; BYTE wait_bit; BYTE prev_cpustate = 0xFF; U64 prev_instcount = 0; U32 prev_gr [16]; U64 prev_gr64 [16]; U32 prev_cr [16]; U64 prev_cr64 [16]; U32 prev_ar [16]; U32 prev_fpr [8*2]; U32 prev_fpr64[16*2]; /////////////////////////////////////////////////////////////////////////////// // Send status information messages back to the gui... void UpdateStatus () { BOOL bStatusChanged = FALSE; // (whether or not anything has changed) if (sysblk.shutdown) return; copy_psw(pTargetCPU_REGS, psw); wait_bit = (psw[1] & 0x02); // The SYS light and %CPU-Utilization // information we send *ALL* the time... if (!(0 || CPUSTATE_STOPPING == pTargetCPU_REGS->cpustate || CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate )) { gui_fprintf(fStatusStream, "SYS=%c\n" ,wait_bit ? '0' : '1' ); } #if defined(OPTION_MIPS_COUNTING) if (gui_wants_cpupct) { if (gui_wants_aggregates) { int cpu, cpupct = 0, started = 0; for (cpupct=0, cpu=0; cpu < sysblk.maxcpu; cpu++) { if (1 && IS_CPU_ONLINE( cpu ) && CPUSTATE_STARTED == sysblk.regs[ cpu ]->cpustate ) { started++; cpupct += sysblk.regs[ cpu ]->cpupct; } } gui_fprintf(fStatusStream, "CPUPCT=%d\n" ,started ? (cpupct / started) : 0 ); } else { gui_fprintf(fStatusStream, "CPUPCT=%d\n" ,pTargetCPU_REGS->cpupct ); } } if (gui_wants_cpupct_all) { int i, cpupct; for (i = 0; i < sysblk.hicpu; i++) { if (0 || !IS_CPU_ONLINE(i) || CPUSTATE_STARTED != sysblk.regs[i]->cpustate ) cpupct = 0; else cpupct = sysblk.regs[i]->cpupct; if (cpupct != prev_cpupct[i]) { prev_cpupct[i] = cpupct; gui_fprintf( fStatusStream, "CPUPCT%02d=%d\n", i, cpupct ); } } } #endif // Determine if we need to inform the GUI of anything... bStatusChanged = FALSE; // (whether or not anything has changed) if (0 || gui_forced_refresh || pTargetCPU_REGS != pPrevTargetCPU_REGS || pcpu != prev_pcpu || memcmp(prev_psw, psw, sizeof(prev_psw)) != 0 || prev_cpustate != pTargetCPU_REGS->cpustate || prev_instcount != INSTCOUNT(pTargetCPU_REGS) ) { bStatusChanged = TRUE; // (something has indeed changed...) if (gui_forced_refresh) // (forced refresh?) HandleForcedRefresh(); // (reset all prev values) // Save new values for next time... pPrevTargetCPU_REGS = pTargetCPU_REGS; prev_pcpu = pcpu; memcpy(prev_psw, psw, sizeof(prev_psw)); prev_cpustate = pTargetCPU_REGS->cpustate; prev_instcount = INSTCOUNT(pTargetCPU_REGS); } // If anything has changed, inform the GUI... if (bStatusChanged) { UpdateCPUStatus(); // (update the status line info...) UpdateRegisters(); // (update the registers display...) } // PROGRAMMING NOTE: my original [rather poorly designed I admit] logic // sent device status messages to the GUI *continuously* (i.e. all the // time), even when both Herc and the channel subsystem was idle. This // proved to be terribly inefficient, causing the GUI to consume *FAR* // too much valuable CPU cycles parsing all of those messages. // Thus, starting with this version of dyngui, we now only send device // status messages to the GUI only whenever the device's status actually // changes, but only if it (the GUI) specifically requests such notifi- // cations of course (via the new "]NEWDEVLIST=" special message). // The new(er) version of HercGUI understands (and thus requests) these // newer format device status messages, but older versions of HercGUI // of course do not. Thus in order to remain compatible with the current // (older) version of the GUI, we still need to support the inefficient // technique of constantly sending a constant stream of device status // messages. // Eventually at some point this existing original inefficient technique // logic will be removed (once everyone has had time to upgrade to the // newer version of HercGUI), but for now, at least for the next couple // of HercGUI release cycles, we need to keep it. if (gui_wants_devlist) // (if the device list is visible) UpdateDeviceStatus(); // (update the list of devices...) else // (the two options are mutually exclusive from one another) if (gui_wants_new_devlist) // (if the device list is visible) NewUpdateDevStats(); // (update the list of devices...) gui_forced_refresh = 0; // (reset switch; must follow devlist update) } /////////////////////////////////////////////////////////////////////////////// // Forced GUI Refresh: reset all "previous" values to force update... void HandleForcedRefresh() { #ifdef OPTION_MIPS_COUNTING prev_mips_rate = INT_MAX; prev_sios_rate = INT_MAX; #endif prev_instcount = ULLONG_MAX; prev_pcpu = INT_MAX; pPrevTargetCPU_REGS = NULL; prev_cpustate = 0xFF; memset( prev_psw, 0xFF, sizeof(prev_psw) ); memset( &prev_gr [0], 0xFF, sizeof(prev_gr) ); memset( &prev_cr [0], 0xFF, sizeof(prev_cr) ); memset( &prev_ar [0], 0xFF, sizeof(prev_ar) ); memset( &prev_fpr [0], 0xFF, sizeof(prev_fpr) ); memset( &prev_gr64 [0], 0xFF, sizeof(prev_gr64) ); memset( &prev_cr64 [0], 0xFF, sizeof(prev_cr64) ); memset( &prev_fpr64[0], 0xFF, sizeof(prev_fpr64) ); #if defined(OPTION_MIPS_COUNTING) memset( &prev_cpupct [0], 0xFF, sizeof(prev_cpupct ) ); #endif } /////////////////////////////////////////////////////////////////////////////// // Send status information messages back to the gui... void UpdateCPUStatus () { if (sysblk.shutdown) return; if (pTargetCPU_REGS == &sysblk.dummyregs) { // pTargetCPU_REGS == &sysblk.dummyregs; cpu is offline gui_fprintf(fStatusStream, "STATUS=" "%s%02X (((((((((((((((((((((((( OFFLINE ))))))))))))))))))))))))\n", PTYPSTR(pcpu) ,pcpu); } else // pTargetCPU_REGS != &sysblk.dummyregs; cpu is online { // CPU status line... (PSW, status indicators, and instruction count) gui_fprintf(fStatusStream, "STATUS=" "%s%02X " "PSW=%2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X " "%c%c%c%c%c%c%c%c " "instcount=%" I64_FMT "u\n" ,PTYPSTR(pTargetCPU_REGS->cpuad), pTargetCPU_REGS->cpuad ,psw[0], psw[1], psw[2], psw[3] ,psw[4], psw[5], psw[6], psw[7] ,psw[8], psw[9], psw[10], psw[11], psw[12], psw[13], psw[14], psw[15] ,CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate ? 'M' : '.' ,sysblk.inststep ? 'T' : '.' ,wait_bit ? 'W' : '.' ,pTargetCPU_REGS->loadstate ? 'L' : '.' ,pTargetCPU_REGS->checkstop ? 'C' : '.' ,PROBSTATE(&pTargetCPU_REGS->psw) ? 'P' : '.' , #if defined(_FEATURE_SIE) SIE_MODE(pTargetCPU_REGS) ? 'S' : '.' #else // !defined(_FEATURE_SIE) '.' #endif // defined(_FEATURE_SIE) , #if defined(_900) ARCH_900 == pTargetCPU_REGS->arch_mode ? 'Z' : '.' #else // !defined(_900) '.' #endif // defined(_900) ,(U64)INSTCOUNT(pTargetCPU_REGS) ); } // endif cpu is online/offline #if defined(OPTION_MIPS_COUNTING) // MIPS rate and SIOS rate... { U32* mipsrate; U32* siosrate; if (gui_wants_aggregates) { mipsrate = &sysblk.mipsrate; siosrate = &sysblk.siosrate; } else { mipsrate = &pTargetCPU_REGS->mipsrate; siosrate = &pTargetCPU_REGS->siosrate; } if (*mipsrate != prev_mips_rate) { gui_fprintf( fStatusStream, "MIPS=%4d.%2.2d\n" , *mipsrate / 1000000 ,(*mipsrate % 1000000) / 10000 ); prev_mips_rate = *mipsrate; } if (*siosrate != prev_sios_rate) { gui_fprintf( fStatusStream, "SIOS=%4d\n" ,*siosrate ); prev_sios_rate = *siosrate; } } update_maxrates_hwm(); // (update high-water-mark values) #endif // defined(OPTION_MIPS_COUNTING) } /////////////////////////////////////////////////////////////////////////////// // Send status information messages back to the gui... #define REG32FMT "%8.8"I32_FMT"X" #define REG64FMT "%16.16"I64_FMT"X" void UpdateRegisters () { if (sysblk.shutdown) return; if (gui_wants_gregs) { if (0 || prev_gr[0] != pTargetCPU_REGS->GR_L(0) || prev_gr[1] != pTargetCPU_REGS->GR_L(1) || prev_gr[2] != pTargetCPU_REGS->GR_L(2) || prev_gr[3] != pTargetCPU_REGS->GR_L(3) ) { prev_gr[0] = pTargetCPU_REGS->GR_L(0); prev_gr[1] = pTargetCPU_REGS->GR_L(1); prev_gr[2] = pTargetCPU_REGS->GR_L(2); prev_gr[3] = pTargetCPU_REGS->GR_L(3); gui_fprintf(fStatusStream, "GR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->GR_L(0) ,pTargetCPU_REGS->GR_L(1) ,pTargetCPU_REGS->GR_L(2) ,pTargetCPU_REGS->GR_L(3) ); } if (0 || prev_gr[4] != pTargetCPU_REGS->GR_L(4) || prev_gr[5] != pTargetCPU_REGS->GR_L(5) || prev_gr[6] != pTargetCPU_REGS->GR_L(6) || prev_gr[7] != pTargetCPU_REGS->GR_L(7) ) { prev_gr[4] = pTargetCPU_REGS->GR_L(4); prev_gr[5] = pTargetCPU_REGS->GR_L(5); prev_gr[6] = pTargetCPU_REGS->GR_L(6); prev_gr[7] = pTargetCPU_REGS->GR_L(7); gui_fprintf(fStatusStream, "GR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->GR_L(4) ,pTargetCPU_REGS->GR_L(5) ,pTargetCPU_REGS->GR_L(6) ,pTargetCPU_REGS->GR_L(7) ); } if (0 || prev_gr[8] != pTargetCPU_REGS->GR_L(8) || prev_gr[9] != pTargetCPU_REGS->GR_L(9) || prev_gr[10] != pTargetCPU_REGS->GR_L(10) || prev_gr[11] != pTargetCPU_REGS->GR_L(11) ) { prev_gr[8] = pTargetCPU_REGS->GR_L(8); prev_gr[9] = pTargetCPU_REGS->GR_L(9); prev_gr[10] = pTargetCPU_REGS->GR_L(10); prev_gr[11] = pTargetCPU_REGS->GR_L(11); gui_fprintf(fStatusStream, "GR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->GR_L(8) ,pTargetCPU_REGS->GR_L(9) ,pTargetCPU_REGS->GR_L(10) ,pTargetCPU_REGS->GR_L(11) ); } if (0 || prev_gr[12] != pTargetCPU_REGS->GR_L(12) || prev_gr[13] != pTargetCPU_REGS->GR_L(13) || prev_gr[14] != pTargetCPU_REGS->GR_L(14) || prev_gr[15] != pTargetCPU_REGS->GR_L(15) ) { prev_gr[12] = pTargetCPU_REGS->GR_L(12); prev_gr[13] = pTargetCPU_REGS->GR_L(13); prev_gr[14] = pTargetCPU_REGS->GR_L(14); prev_gr[15] = pTargetCPU_REGS->GR_L(15); gui_fprintf(fStatusStream, "GRC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->GR_L(12) ,pTargetCPU_REGS->GR_L(13) ,pTargetCPU_REGS->GR_L(14) ,pTargetCPU_REGS->GR_L(15) ); } } if (gui_wants_gregs64) { if (0 || prev_gr64[0] != pTargetCPU_REGS->GR_G(0) || prev_gr64[1] != pTargetCPU_REGS->GR_G(1) ) { prev_gr64[0] = pTargetCPU_REGS->GR_G(0); prev_gr64[1] = pTargetCPU_REGS->GR_G(1); gui_fprintf(fStatusStream, "64_GR0-1="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(0) ,pTargetCPU_REGS->GR_G(1) ); } if (0 || prev_gr64[2] != pTargetCPU_REGS->GR_G(2) || prev_gr64[3] != pTargetCPU_REGS->GR_G(3) ) { prev_gr64[2] = pTargetCPU_REGS->GR_G(2); prev_gr64[3] = pTargetCPU_REGS->GR_G(3); gui_fprintf(fStatusStream, "64_GR2-3="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(2) ,pTargetCPU_REGS->GR_G(3) ); } if (0 || prev_gr64[4] != pTargetCPU_REGS->GR_G(4) || prev_gr64[5] != pTargetCPU_REGS->GR_G(5) ) { prev_gr64[4] = pTargetCPU_REGS->GR_G(4); prev_gr64[5] = pTargetCPU_REGS->GR_G(5); gui_fprintf(fStatusStream, "64_GR4-5="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(4) ,pTargetCPU_REGS->GR_G(5) ); } if (0 || prev_gr64[6] != pTargetCPU_REGS->GR_G(6) || prev_gr64[7] != pTargetCPU_REGS->GR_G(7) ) { prev_gr64[6] = pTargetCPU_REGS->GR_G(6); prev_gr64[7] = pTargetCPU_REGS->GR_G(7); gui_fprintf(fStatusStream, "64_GR6-7="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(6) ,pTargetCPU_REGS->GR_G(7) ); } if (0 || prev_gr64[8] != pTargetCPU_REGS->GR_G(8) || prev_gr64[9] != pTargetCPU_REGS->GR_G(9) ) { prev_gr64[8] = pTargetCPU_REGS->GR_G(8); prev_gr64[9] = pTargetCPU_REGS->GR_G(9); gui_fprintf(fStatusStream, "64_GR8-9="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(8) ,pTargetCPU_REGS->GR_G(9) ); } if (0 || prev_gr64[10] != pTargetCPU_REGS->GR_G(10) || prev_gr64[11] != pTargetCPU_REGS->GR_G(11) ) { prev_gr64[10] = pTargetCPU_REGS->GR_G(10); prev_gr64[11] = pTargetCPU_REGS->GR_G(11); gui_fprintf(fStatusStream, "64_GRA-B="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(10) ,pTargetCPU_REGS->GR_G(11) ); } if (0 || prev_gr64[12] != pTargetCPU_REGS->GR_G(12) || prev_gr64[13] != pTargetCPU_REGS->GR_G(13) ) { prev_gr64[12] = pTargetCPU_REGS->GR_G(12); prev_gr64[13] = pTargetCPU_REGS->GR_G(13); gui_fprintf(fStatusStream, "64_GRC-D="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(12) ,pTargetCPU_REGS->GR_G(13) ); } if (0 || prev_gr64[14] != pTargetCPU_REGS->GR_G(14) || prev_gr64[15] != pTargetCPU_REGS->GR_G(15) ) { prev_gr64[14] = pTargetCPU_REGS->GR_G(14); prev_gr64[15] = pTargetCPU_REGS->GR_G(15); gui_fprintf(fStatusStream, "64_GRE-F="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->GR_G(14) ,pTargetCPU_REGS->GR_G(15) ); } } if (gui_wants_cregs) { if (0 || prev_cr[0] != pTargetCPU_REGS->CR_L(0) || prev_cr[1] != pTargetCPU_REGS->CR_L(1) || prev_cr[2] != pTargetCPU_REGS->CR_L(2) || prev_cr[3] != pTargetCPU_REGS->CR_L(3) ) { prev_cr[0] = pTargetCPU_REGS->CR_L(0); prev_cr[1] = pTargetCPU_REGS->CR_L(1); prev_cr[2] = pTargetCPU_REGS->CR_L(2); prev_cr[3] = pTargetCPU_REGS->CR_L(3); gui_fprintf(fStatusStream, "CR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->CR_L(0) ,pTargetCPU_REGS->CR_L(1) ,pTargetCPU_REGS->CR_L(2) ,pTargetCPU_REGS->CR_L(3) ); } if (0 || prev_cr[4] != pTargetCPU_REGS->CR_L(4) || prev_cr[5] != pTargetCPU_REGS->CR_L(5) || prev_cr[6] != pTargetCPU_REGS->CR_L(6) || prev_cr[7] != pTargetCPU_REGS->CR_L(7) ) { prev_cr[4] = pTargetCPU_REGS->CR_L(4); prev_cr[5] = pTargetCPU_REGS->CR_L(5); prev_cr[6] = pTargetCPU_REGS->CR_L(6); prev_cr[7] = pTargetCPU_REGS->CR_L(7); gui_fprintf(fStatusStream, "CR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->CR_L(4) ,pTargetCPU_REGS->CR_L(5) ,pTargetCPU_REGS->CR_L(6) ,pTargetCPU_REGS->CR_L(7) ); } if (0 || prev_cr[8] != pTargetCPU_REGS->CR_L(8) || prev_cr[9] != pTargetCPU_REGS->CR_L(9) || prev_cr[10] != pTargetCPU_REGS->CR_L(10) || prev_cr[11] != pTargetCPU_REGS->CR_L(11) ) { prev_cr[8] = pTargetCPU_REGS->CR_L(8); prev_cr[9] = pTargetCPU_REGS->CR_L(9); prev_cr[10] = pTargetCPU_REGS->CR_L(10); prev_cr[10] = pTargetCPU_REGS->CR_L(10); gui_fprintf(fStatusStream, "CR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->CR_L(8) ,pTargetCPU_REGS->CR_L(9) ,pTargetCPU_REGS->CR_L(10) ,pTargetCPU_REGS->CR_L(11) ); } if (0 || prev_cr[12] != pTargetCPU_REGS->CR_L(12) || prev_cr[13] != pTargetCPU_REGS->CR_L(13) || prev_cr[14] != pTargetCPU_REGS->CR_L(14) || prev_cr[15] != pTargetCPU_REGS->CR_L(15) ) { prev_cr[12] = pTargetCPU_REGS->CR_L(12); prev_cr[13] = pTargetCPU_REGS->CR_L(13); prev_cr[14] = pTargetCPU_REGS->CR_L(14); prev_cr[15] = pTargetCPU_REGS->CR_L(15); gui_fprintf(fStatusStream, "CRC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->CR_L(12) ,pTargetCPU_REGS->CR_L(13) ,pTargetCPU_REGS->CR_L(14) ,pTargetCPU_REGS->CR_L(15) ); } } if (gui_wants_cregs64) { if (0 || prev_cr64[0] != pTargetCPU_REGS->CR_G(0) || prev_cr64[1] != pTargetCPU_REGS->CR_G(1) ) { prev_cr64[0] = pTargetCPU_REGS->CR_G(0); prev_cr64[1] = pTargetCPU_REGS->CR_G(1); gui_fprintf(fStatusStream, "64_CR0-1="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(0) ,pTargetCPU_REGS->CR_G(1) ); } if (0 || prev_cr64[2] != pTargetCPU_REGS->CR_G(2) || prev_cr64[3] != pTargetCPU_REGS->CR_G(3) ) { prev_cr64[2] = pTargetCPU_REGS->CR_G(2); prev_cr64[3] = pTargetCPU_REGS->CR_G(3); gui_fprintf(fStatusStream, "64_CR2-3="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(2) ,pTargetCPU_REGS->CR_G(3) ); } if (0 || prev_cr64[4] != pTargetCPU_REGS->CR_G(4) || prev_cr64[5] != pTargetCPU_REGS->CR_G(5) ) { prev_cr64[4] = pTargetCPU_REGS->CR_G(4); prev_cr64[5] = pTargetCPU_REGS->CR_G(5); gui_fprintf(fStatusStream, "64_CR4-5="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(4) ,pTargetCPU_REGS->CR_G(5) ); } if (0 || prev_cr64[6] != pTargetCPU_REGS->CR_G(6) || prev_cr64[7] != pTargetCPU_REGS->CR_G(7) ) { prev_cr64[6] = pTargetCPU_REGS->CR_G(6); prev_cr64[7] = pTargetCPU_REGS->CR_G(7); gui_fprintf(fStatusStream, "64_CR6-7="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(6) ,pTargetCPU_REGS->CR_G(7) ); } if (0 || prev_cr64[8] != pTargetCPU_REGS->CR_G(8) || prev_cr64[9] != pTargetCPU_REGS->CR_G(9) ) { prev_cr64[8] = pTargetCPU_REGS->CR_G(8); prev_cr64[9] = pTargetCPU_REGS->CR_G(9); gui_fprintf(fStatusStream, "64_CR8-9="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(8) ,pTargetCPU_REGS->CR_G(9) ); } if (0 || prev_cr64[10] != pTargetCPU_REGS->CR_G(10) || prev_cr64[11] != pTargetCPU_REGS->CR_G(11) ) { prev_cr64[10] = pTargetCPU_REGS->CR_G(10); prev_cr64[11] = pTargetCPU_REGS->CR_G(11); gui_fprintf(fStatusStream, "64_CRA-B="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(10) ,pTargetCPU_REGS->CR_G(11) ); } if (0 || prev_cr64[12] != pTargetCPU_REGS->CR_G(12) || prev_cr64[13] != pTargetCPU_REGS->CR_G(13) ) { prev_cr64[12] = pTargetCPU_REGS->CR_G(12); prev_cr64[13] = pTargetCPU_REGS->CR_G(13); gui_fprintf(fStatusStream, "64_CRC-D="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(12) ,pTargetCPU_REGS->CR_G(13) ); } if (0 || prev_cr64[14] != pTargetCPU_REGS->CR_G(14) || prev_cr64[15] != pTargetCPU_REGS->CR_G(15) ) { prev_cr64[14] = pTargetCPU_REGS->CR_G(14); prev_cr64[15] = pTargetCPU_REGS->CR_G(15); gui_fprintf(fStatusStream, "64_CRE-F="REG64FMT" "REG64FMT"\n" ,pTargetCPU_REGS->CR_G(14) ,pTargetCPU_REGS->CR_G(15) ); } } if (gui_wants_aregs) { if (0 || prev_ar[0] != pTargetCPU_REGS->AR(0) || prev_ar[1] != pTargetCPU_REGS->AR(1) || prev_ar[2] != pTargetCPU_REGS->AR(2) || prev_ar[3] != pTargetCPU_REGS->AR(3) ) { prev_ar[0] = pTargetCPU_REGS->AR(0); prev_ar[1] = pTargetCPU_REGS->AR(1); prev_ar[2] = pTargetCPU_REGS->AR(2); prev_ar[3] = pTargetCPU_REGS->AR(3); gui_fprintf(fStatusStream, "AR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->AR(0) ,pTargetCPU_REGS->AR(1) ,pTargetCPU_REGS->AR(2) ,pTargetCPU_REGS->AR(3) ); } if (0 || prev_ar[4] != pTargetCPU_REGS->AR(4) || prev_ar[5] != pTargetCPU_REGS->AR(5) || prev_ar[6] != pTargetCPU_REGS->AR(6) || prev_ar[7] != pTargetCPU_REGS->AR(7) ) { prev_ar[4] = pTargetCPU_REGS->AR(4); prev_ar[5] = pTargetCPU_REGS->AR(5); prev_ar[6] = pTargetCPU_REGS->AR(6); prev_ar[7] = pTargetCPU_REGS->AR(7); gui_fprintf(fStatusStream, "AR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->AR(4) ,pTargetCPU_REGS->AR(5) ,pTargetCPU_REGS->AR(6) ,pTargetCPU_REGS->AR(7) ); } if (0 || prev_ar[8] != pTargetCPU_REGS->AR(8) || prev_ar[9] != pTargetCPU_REGS->AR(9) || prev_ar[10] != pTargetCPU_REGS->AR(10) || prev_ar[11] != pTargetCPU_REGS->AR(11) ) { prev_ar[8] = pTargetCPU_REGS->AR(8); prev_ar[9] = pTargetCPU_REGS->AR(9); prev_ar[10] = pTargetCPU_REGS->AR(10); prev_ar[11] = pTargetCPU_REGS->AR(11); gui_fprintf(fStatusStream, "AR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->AR(8) ,pTargetCPU_REGS->AR(9) ,pTargetCPU_REGS->AR(10) ,pTargetCPU_REGS->AR(11) ); } if (0 || prev_ar[12] != pTargetCPU_REGS->AR(12) || prev_ar[13] != pTargetCPU_REGS->AR(13) || prev_ar[14] != pTargetCPU_REGS->AR(14) || prev_ar[15] != pTargetCPU_REGS->AR(15) ) { prev_ar[12] = pTargetCPU_REGS->AR(12); prev_ar[13] = pTargetCPU_REGS->AR(13); prev_ar[14] = pTargetCPU_REGS->AR(14); prev_ar[15] = pTargetCPU_REGS->AR(15); gui_fprintf(fStatusStream, "ARC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->AR(12) ,pTargetCPU_REGS->AR(13) ,pTargetCPU_REGS->AR(14) ,pTargetCPU_REGS->AR(15) ); } } if (gui_wants_fregs) { if (0 || prev_fpr[0] != pTargetCPU_REGS->fpr[0] || prev_fpr[1] != pTargetCPU_REGS->fpr[1] || prev_fpr[2] != pTargetCPU_REGS->fpr[2] || prev_fpr[3] != pTargetCPU_REGS->fpr[3] ) { prev_fpr[0] = pTargetCPU_REGS->fpr[0]; prev_fpr[1] = pTargetCPU_REGS->fpr[1]; prev_fpr[2] = pTargetCPU_REGS->fpr[2]; prev_fpr[3] = pTargetCPU_REGS->fpr[3]; gui_fprintf(fStatusStream, "FR0-2="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->fpr[0] ,pTargetCPU_REGS->fpr[1] ,pTargetCPU_REGS->fpr[2] ,pTargetCPU_REGS->fpr[3] ); } if (0 || prev_fpr[4] != pTargetCPU_REGS->fpr[4] || prev_fpr[5] != pTargetCPU_REGS->fpr[5] || prev_fpr[6] != pTargetCPU_REGS->fpr[6] || prev_fpr[7] != pTargetCPU_REGS->fpr[7] ) { prev_fpr[4] = pTargetCPU_REGS->fpr[4]; prev_fpr[5] = pTargetCPU_REGS->fpr[5]; prev_fpr[6] = pTargetCPU_REGS->fpr[6]; prev_fpr[7] = pTargetCPU_REGS->fpr[7]; gui_fprintf(fStatusStream, "FR4-6="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n" ,pTargetCPU_REGS->fpr[4] ,pTargetCPU_REGS->fpr[5] ,pTargetCPU_REGS->fpr[6] ,pTargetCPU_REGS->fpr[7] ); } } if (gui_wants_fregs64) { if (0 || prev_fpr64[0] != pTargetCPU_REGS->fpr[0] || prev_fpr64[1] != pTargetCPU_REGS->fpr[1] || prev_fpr64[2] != pTargetCPU_REGS->fpr[2] || prev_fpr64[3] != pTargetCPU_REGS->fpr[3] ) { prev_fpr64[0] = pTargetCPU_REGS->fpr[0]; prev_fpr64[1] = pTargetCPU_REGS->fpr[1]; prev_fpr64[2] = pTargetCPU_REGS->fpr[2]; prev_fpr64[3] = pTargetCPU_REGS->fpr[3]; gui_fprintf(fStatusStream, "64_FR0-1="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[0] ,pTargetCPU_REGS->fpr[1] ,pTargetCPU_REGS->fpr[2] ,pTargetCPU_REGS->fpr[3] ); } if (0 || prev_fpr64[4] != pTargetCPU_REGS->fpr[4] || prev_fpr64[5] != pTargetCPU_REGS->fpr[5] || prev_fpr64[6] != pTargetCPU_REGS->fpr[6] || prev_fpr64[7] != pTargetCPU_REGS->fpr[7] ) { prev_fpr64[4] = pTargetCPU_REGS->fpr[4]; prev_fpr64[5] = pTargetCPU_REGS->fpr[5]; prev_fpr64[6] = pTargetCPU_REGS->fpr[6]; prev_fpr64[7] = pTargetCPU_REGS->fpr[7]; gui_fprintf(fStatusStream, "64_FR2-3="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[4] ,pTargetCPU_REGS->fpr[5] ,pTargetCPU_REGS->fpr[6] ,pTargetCPU_REGS->fpr[7] ); } if (0 || prev_fpr64[8] != pTargetCPU_REGS->fpr[8] || prev_fpr64[9] != pTargetCPU_REGS->fpr[9] || prev_fpr64[10] != pTargetCPU_REGS->fpr[10] || prev_fpr64[11] != pTargetCPU_REGS->fpr[11] ) { prev_fpr64[8] = pTargetCPU_REGS->fpr[8]; prev_fpr64[9] = pTargetCPU_REGS->fpr[9]; prev_fpr64[10] = pTargetCPU_REGS->fpr[10]; prev_fpr64[11] = pTargetCPU_REGS->fpr[11]; gui_fprintf(fStatusStream, "64_FR4-5="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[8] ,pTargetCPU_REGS->fpr[9] ,pTargetCPU_REGS->fpr[10] ,pTargetCPU_REGS->fpr[11] ); } if (0 || prev_fpr64[12] != pTargetCPU_REGS->fpr[12] || prev_fpr64[13] != pTargetCPU_REGS->fpr[13] || prev_fpr64[14] != pTargetCPU_REGS->fpr[14] || prev_fpr64[15] != pTargetCPU_REGS->fpr[15] ) { prev_fpr64[12] = pTargetCPU_REGS->fpr[12]; prev_fpr64[13] = pTargetCPU_REGS->fpr[13]; prev_fpr64[14] = pTargetCPU_REGS->fpr[14]; prev_fpr64[15] = pTargetCPU_REGS->fpr[15]; gui_fprintf(fStatusStream, "64_FR6-7="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[12] ,pTargetCPU_REGS->fpr[13] ,pTargetCPU_REGS->fpr[14] ,pTargetCPU_REGS->fpr[15] ); } if (0 || prev_fpr64[16] != pTargetCPU_REGS->fpr[16] || prev_fpr64[17] != pTargetCPU_REGS->fpr[17] || prev_fpr64[18] != pTargetCPU_REGS->fpr[18] || prev_fpr64[19] != pTargetCPU_REGS->fpr[19] ) { prev_fpr64[16] = pTargetCPU_REGS->fpr[16]; prev_fpr64[17] = pTargetCPU_REGS->fpr[17]; prev_fpr64[18] = pTargetCPU_REGS->fpr[18]; prev_fpr64[19] = pTargetCPU_REGS->fpr[19]; gui_fprintf(fStatusStream, "64_FR8-9="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[16] ,pTargetCPU_REGS->fpr[17] ,pTargetCPU_REGS->fpr[18] ,pTargetCPU_REGS->fpr[19] ); } if (0 || prev_fpr64[20] != pTargetCPU_REGS->fpr[20] || prev_fpr64[21] != pTargetCPU_REGS->fpr[21] || prev_fpr64[22] != pTargetCPU_REGS->fpr[22] || prev_fpr64[23] != pTargetCPU_REGS->fpr[23] ) { prev_fpr64[20] = pTargetCPU_REGS->fpr[20]; prev_fpr64[21] = pTargetCPU_REGS->fpr[21]; prev_fpr64[22] = pTargetCPU_REGS->fpr[22]; prev_fpr64[23] = pTargetCPU_REGS->fpr[23]; gui_fprintf(fStatusStream, "64_FRA-B="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[20] ,pTargetCPU_REGS->fpr[21] ,pTargetCPU_REGS->fpr[22] ,pTargetCPU_REGS->fpr[23] ); } if (0 || prev_fpr64[24] != pTargetCPU_REGS->fpr[24] || prev_fpr64[25] != pTargetCPU_REGS->fpr[25] || prev_fpr64[26] != pTargetCPU_REGS->fpr[26] || prev_fpr64[27] != pTargetCPU_REGS->fpr[27] ) { prev_fpr64[24] = pTargetCPU_REGS->fpr[24]; prev_fpr64[25] = pTargetCPU_REGS->fpr[25]; prev_fpr64[26] = pTargetCPU_REGS->fpr[26]; prev_fpr64[27] = pTargetCPU_REGS->fpr[27]; gui_fprintf(fStatusStream, "64_FRC-D="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[24] ,pTargetCPU_REGS->fpr[25] ,pTargetCPU_REGS->fpr[26] ,pTargetCPU_REGS->fpr[27] ); } if (0 || prev_fpr64[28] != pTargetCPU_REGS->fpr[28] || prev_fpr64[29] != pTargetCPU_REGS->fpr[29] || prev_fpr64[30] != pTargetCPU_REGS->fpr[30] || prev_fpr64[31] != pTargetCPU_REGS->fpr[31] ) { prev_fpr64[28] = pTargetCPU_REGS->fpr[28]; prev_fpr64[29] = pTargetCPU_REGS->fpr[29]; prev_fpr64[30] = pTargetCPU_REGS->fpr[30]; prev_fpr64[31] = pTargetCPU_REGS->fpr[31]; gui_fprintf(fStatusStream, "64_FRE-F="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n" ,pTargetCPU_REGS->fpr[28] ,pTargetCPU_REGS->fpr[29] ,pTargetCPU_REGS->fpr[30] ,pTargetCPU_REGS->fpr[31] ); } } } /////////////////////////////////////////////////////////////////////////////// char szQueryDeviceBuff[ MAX_DEVICEQUERY_LEN + 1 ]; // (always +1 for safety!) /////////////////////////////////////////////////////////////////////////////// // Send status information messages back to the gui... (VERY inefficient!) void UpdateDeviceStatus () { DEVBLK* pDEVBLK; char* pDEVClass; BYTE chOnlineStat, chBusyStat, chPendingStat, chOpenStat; if (sysblk.shutdown) return; // Process ALL the devices in the entire configuration each time... for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev) { // Does this device actually exist in the configuration? if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V)) continue; // (no, skip) // Retrieve this device's filename and optional settings parameter values... szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra) (pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff); if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN]) // (buffer overflow?) { logmsg ( _("HHCDG005E Device query buffer overflow! (device=%4.4X)\n") ,pDEVBLK->devnum ); } szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (enforce NULL termination) // Device status flags... chOnlineStat = chBusyStat = chPendingStat = chOpenStat = '0'; if ((!pDEVBLK->console && pDEVBLK->fd >= 0) || ( pDEVBLK->console && pDEVBLK->connected)) chOnlineStat = '1'; if (pDEVBLK->busy) chBusyStat = '1'; if (IOPENDING(pDEVBLK)) chPendingStat = '1'; if (pDEVBLK->fd > MAX(STDIN_FILENO,MAX(STDOUT_FILENO,STDERR_FILENO))) chOpenStat = '1'; // Send status message back to gui... #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) if (pDEVBLK == sysblk.sysgdev) { gui_fprintf( fStatusStream, "DEV=0000 SYSG %-4.4s %c%c%c%c %s\n" ,pDEVClass ,chOnlineStat ,chBusyStat ,chPendingStat ,chOpenStat ,szQueryDeviceBuff ); } else #endif // defined(_FEATURE_INTEGRATED_3270_CONSOLE) gui_fprintf(fStatusStream, "DEV=%4.4X %4.4X %-4.4s %c%c%c%c %s\n" ,pDEVBLK->devnum ,pDEVBLK->devtype ,pDEVClass ,chOnlineStat ,chBusyStat ,chPendingStat ,chOpenStat ,szQueryDeviceBuff ); } // Since the device list can be in any order and devices can be added // and/or removed at any time, the GUI needs to know "That's all the // devices there are" so that it can detect when devices are removed... gui_fprintf(fStatusStream, "DEV=X\n"); // (indicates end of list) } /////////////////////////////////////////////////////////////////////////////// // Send device status msgs to the gui IF NEEDED... (slightly more efficient) void NewUpdateDevStats () { DEVBLK* pDEVBLK; GUISTAT* pGUIStat; char* pDEVClass; BYTE chOnlineStat, chBusyStat, chPendingStat, chOpenStat; BOOL bUpdatesSent = FALSE; static BOOL bFirstBatch = TRUE; if (sysblk.shutdown) return; // Process ALL the devices in the entire configuration each time... // (But only send device status messages to the GUI only when the // device's status actually changes and not continuously like before) for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev) { pGUIStat = pDEVBLK->pGUIStat; // Does this device exist in the configuration? if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V)) { // This device no longer exists in the configuration... // If we haven't yet notified the GUI about this device // being deleted from the configuration, then do so at // this time... if (*pGUIStat->pszNewStatStr) { // Send "device deleted" message... gui_fprintf ( fStatusStream, "DEVD=%4.4X\n", pDEVBLK->devnum ); bUpdatesSent = TRUE; *pGUIStat->pszNewStatStr = 0; // (prevent re-reporting it) *pGUIStat->pszOldStatStr = 0; // (prevent re-reporting it) } continue; // (go on to next device) } // Retrieve this device's filename and optional settings parameter values... szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra) (pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff); if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN]) // (buffer overflow?) { logmsg ( _("HHCDG005E Device query buffer overflow! (device=%4.4X)\n") ,pDEVBLK->devnum ); } szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (enforce NULL termination) // Device status flags... chOnlineStat = chBusyStat = chPendingStat = chOpenStat = '0'; if ((!pDEVBLK->console && pDEVBLK->fd >= 0) || ( pDEVBLK->console && pDEVBLK->connected)) chOnlineStat = '1'; if (pDEVBLK->busy) chBusyStat = '1'; if (IOPENDING(pDEVBLK)) chPendingStat = '1'; if (pDEVBLK->fd > MAX(STDIN_FILENO,MAX(STDOUT_FILENO,STDERR_FILENO))) chOpenStat = '1'; // Build a new "device added" or "device changed" // status string for this device... #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) if (pDEVBLK == sysblk.sysgdev) { snprintf( pGUIStat->pszNewStatStr, GUI_STATSTR_BUFSIZ, "DEV%c=0000 SYSG %-4.4s %c%c%c%c %s" ,*pGUIStat->pszOldStatStr ? 'C' : 'A' ,pDEVClass ,chOnlineStat ,chBusyStat ,chPendingStat ,chOpenStat ,szQueryDeviceBuff ); } else #endif // defined(_FEATURE_INTEGRATED_3270_CONSOLE) snprintf( pGUIStat->pszNewStatStr, GUI_STATSTR_BUFSIZ, "DEV%c=%4.4X %4.4X %-4.4s %c%c%c%c %s" ,*pGUIStat->pszOldStatStr ? 'C' : 'A' ,pDEVBLK->devnum ,pDEVBLK->devtype ,pDEVClass ,chOnlineStat ,chBusyStat ,chPendingStat ,chOpenStat ,szQueryDeviceBuff ); *(pGUIStat->pszNewStatStr + GUI_STATSTR_BUFSIZ - 1) = 0; // If the new status string is different from the old one, // then send the new one to the GUI and swap buffer ptrs // for next time. In this way we only send device status // msgs to the GUI only when the status actually changes... if (strcmp( pGUIStat->pszNewStatStr, pGUIStat->pszOldStatStr )) { gui_fprintf ( fStatusStream, "%s\n", pGUIStat->pszNewStatStr ); bUpdatesSent = TRUE; { register char* pszSavStatStr = pGUIStat->pszNewStatStr; pGUIStat->pszNewStatStr = pGUIStat->pszOldStatStr; pGUIStat->pszOldStatStr = pszSavStatStr; } } } // Only send End-of-Batch indicator if we sent any updates or // if this is the first device-list update since powering on. if ( bUpdatesSent || bFirstBatch ) { bFirstBatch = FALSE; gui_fprintf(fStatusStream, "DEVX=\n"); // (send end-of-batch indicator) } } /////////////////////////////////////////////////////////////////////////////// // Our Hercules "debug_cpu_state" override... // // Hercules calls the following function from several different places to fix // an unintentional problem caused by the new logger mechanism (wherein stdout // and stderr now point to the same stream) due to a oversight (bug) on my part // wherein the 'LOAD' and 'MAN' messages are being [mistakenly] written to stdout // instead of stderr (where they normally should be). The current version of // the gui expects both messages to come in on the stdout stream, but due to the // recent logger changes, they now come in on the stderr stream instead (because // stdout was duped to stderr by the new logger logic) thus causing the gui to // miss seeing them without the below fix. The below fix simply corrects for the // problem by simply writing the two messages to the stdout stream where older // versions of the gui expect to see them. void* gui_debug_cpu_state ( REGS* pREGS ) { void *(*next_debug_call)(REGS *); static BOOL bLoading = FALSE; static BOOL bStopped = FALSE; if (sysblk.shutdown) return NULL; if (pTargetCPU_REGS && pREGS != pTargetCPU_REGS) return NULL; if (bLoading != (pREGS->loadstate ? TRUE : FALSE)) { bLoading = (pREGS->loadstate ? TRUE : FALSE); gui_fprintf(stdout,"LOAD=%c\n", bLoading ? '1' : '0'); } if (bStopped != ((CPUSTATE_STOPPED == pREGS->cpustate) ? TRUE : FALSE)) { bStopped = ((CPUSTATE_STOPPED == pREGS->cpustate) ? TRUE : FALSE); gui_fprintf(stdout,"MAN=%c\n", bStopped ? '1' : '0'); } if((next_debug_call = HDL_FINDNXT( gui_debug_cpu_state ))) return next_debug_call( pREGS ); return NULL; // (I have no idea why this is a void* func) } /////////////////////////////////////////////////////////////////////////////// // Our Hercules "debug_cd_cmd" hook... // // The following function is called by the 'cd_cmd' panel command to notify // the GUI of what the new current directory was just changed to... void* gui_debug_cd_cmd( char* pszCWD ) { ASSERT( pszCWD ); if (gui_version >= 1.12) gui_fprintf( fStatusStream, "]CWD=%s\n", pszCWD ); return NULL; } /////////////////////////////////////////////////////////////////////////////// // Streams 'fprintf' function to prevent interleaving collision problem... LOCK gui_fprintf_lock; void gui_fprintf( FILE* stream, const char* pszFormat, ... ) { va_list vl; va_start( vl, pszFormat ); obtain_lock ( &gui_fprintf_lock ); vfprintf( stream, pszFormat, vl ); fflush( stream ); release_lock( &gui_fprintf_lock ); } /////////////////////////////////////////////////////////////////////////////// // Acquire any resources we need in order to operate... // (called by 'gui_panel_display' before main loop initiates...) void Initialize () { // Initialize streams... fOutputStream = OUTPUT_STREAM_FILE_PTR; fStatusStream = STATUS_STREAM_FILE_PTR; nInputStreamFileNum = fileno( INPUT_STREAM_FILE_PTR ); // Allocate input stream buffer... if (!(pszInputBuff = (char *) malloc( nInputBuffSize ))) { fprintf(stderr, _("HHCDG006S malloc pszInputBuff failed: %s\n") ,strerror(errno)); exit(0); } memset(pszInputBuff, 0, nInputBuffSize); nInputLen = 0; // Allocate command processing buffer... if (!(pszCommandBuff = (char *) malloc( nCommandBuffSize ))) { fprintf(stderr, _("HHCDG007S malloc pszCommandBuff failed: %s\n") ,strerror(errno)); exit(0); } memset(pszCommandBuff, 0, nCommandBuffSize); nCommandLen = 0; // Initialize some variables... HandleForcedRefresh(); } /////////////////////////////////////////////////////////////////////////////// // Release any resources we acquired in order to operate... // (called by 'gui_panel_display' when main loop terminates...) void Cleanup() { if (pszInputBuff) free(pszInputBuff); if (pszCommandBuff) free(pszCommandBuff); } /////////////////////////////////////////////////////////////////////////////// // Hercules "daemon_task" -or- "panel_display" override... void gui_panel_display () { static char *DisQuietCmd[] = { "$zapcmd", "quiet", "NoCmd" }; SET_THREAD_NAME("dyngui"); ProcessConfigCommand(3,DisQuietCmd,NULL); // Disable the quiet command if ( !bDoneProcessing ) { logmsg(_("HHCDG001I dyngui.dll initiated\n")); Initialize(); // (allocate buffers, etc) ProcessingLoop(); // (primary processing loop) logmsg(_("HHCDG002I dyngui.dll terminated\n")); Cleanup(); // (de-allocate resources) } } /*****************************************************************************\ Hercules Dynamic Loader control sections... \*****************************************************************************/ /* Note that ALL of the below "sections" are actually just simple functions that Hercules's dynamic loader logic calls, thus allowing you to insert whatever 'C' code you may need directly into any of the below sections. */ /////////////////////////////////////////////////////////////////////////////// // HDL_DEPENDENCY_SECTION // The following are the various Hercules structures whose layout this module // depends on. The layout of the following structures (size and version) MUST // match the layout that was used to build Hercules with. If the size/version // of any of the following structures changes (and a new version of Hercules // is built using the new layout), then THIS module must also be built with // the new layout as well. The layout (size/version) of the structure as it // was when Hercules was built MUST MATCH the layout as it was when THIS DLL // was built) /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev dyngui_LTX_hdl_ddev #define hdl_depc dyngui_LTX_hdl_depc #define hdl_reso dyngui_LTX_hdl_reso #define hdl_init dyngui_LTX_hdl_init #define hdl_fini dyngui_LTX_hdl_fini #endif HDL_DEPENDENCY_SECTION; // (define module dependencies) HDL_DEPENDENCY ( HERCULES ); // Hercules itself HDL_DEPENDENCY ( SYSBLK ); // Master control block HDL_DEPENDENCY ( REGS ); // CPU regs and such HDL_DEPENDENCY ( DEVBLK ); // Device info block END_DEPENDENCY_SECTION /////////////////////////////////////////////////////////////////////////////// // HDL_REGISTER_SECTION // The following section defines the entry points within Hercules that THIS // module is overriding (replacing). That is to say, THIS module's functions // will be called by Hercules instead of the normal Hercules function (if any). // The functions defined below thus provide additional/different functionality // above/beyond the functionality normally provided by Hercules. (Of course, // yet OTHER dlls may have further overridden whatever overrides we register // here, such as would likely be the case for panel command overrides). HDL_REGISTER_SECTION; // ("Register" our entry-points) { // Perform static module initialization... gui_nounload = 1; // (reject any unload attempt) initialize_lock( &gui_fprintf_lock ); // (initialize GUI fprintf LOCK) // Register all of our override entry-points... // Hercules's Our // registered overriding // entry-point entry-point // name value HDL_REGISTER ( panel_display, gui_panel_display );// (Yep! We override EITHER!) HDL_REGISTER ( daemon_task, gui_panel_display );// (Yep! We override EITHER!) HDL_REGISTER ( debug_cpu_state, gui_debug_cpu_state ); HDL_REGISTER ( debug_cd_cmd, gui_debug_cd_cmd ); HDL_REGISTER ( panel_command, gui_panel_command ); } END_REGISTER_SECTION #if defined( WIN32 ) && !defined( HDL_USE_LIBTOOL ) #if !defined( _MSVC_ ) #undef sysblk #endif /////////////////////////////////////////////////////////////////////////////// // HDL_RESOLVER_SECTION // The following section "resolves" entry-points that this module needs. The // below HDL_RESOLVE entries define the names of Hercules's registered entry- // points that we need "imported" to us (so that we may call those functions // directly ourselves). The HDL_RESOLVE_PTRVAR entries set the named pointer // variable value (i.e. the name of OUR pointer variable) to the registered // entry-point value that was registered by Hercules or some other DLL. HDL_RESOLVER_SECTION; // ("Resolve" needed entry-points) { // Registered // entry-points // that we call HDL_RESOLVE ( panel_command ); #if !defined( _MSVC_ ) // Our pointer- Registered entry- // variable name point value name HDL_RESOLVE_PTRVAR ( psysblk, sysblk ); #endif } END_RESOLVER_SECTION #endif /////////////////////////////////////////////////////////////////////////////// // HDL_FINAL_SECTION // The following section defines what should be done immediately before this // module is unloaded. It is nothing more than a function that is called by // Hercules just before your module is unloaded. You can do anything you want // but the normal thing to do is release any resources that were acquired when // your module was loaded (e.g. release memory that was malloc'ed, etc). HDL_FINAL_SECTION; { bDoneProcessing = TRUE; // (tell main loop to stop processing) usleep(100000); // (brief delay to give GUI time // to display ALL shutdown msgs) return gui_nounload; // (reject unloads when activated) } END_FINAL_SECTION /////////////////////////////////////////////////////////////////////////////// #endif /*defined(OPTION_DYNAMIC_LOAD)*/ #endif // EXTERNALGUI hercules-3.12/dyninst.c0000664000175000017500000003550712564723224012051 00000000000000/* DYNINST.C (c) Copyright Jan Jaeger, 2003-2009 */ /* Hercules Dynamic Loader */ /*-------------------------------------------------------------------*/ /* This module dynamically loads instructions. Instruction routine */ /* names must be registered under the name of s370_opcode_B220 for */ /* example, where s370 may also be s390 or z900 for ESA/390 or ESAME */ /* mode respectively. B220 is the opcode, and is depending on the */ /* instruction 2 3 or 4 digits. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #if defined(OPTION_DYNAMIC_LOAD) #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) /* We need to do some special tricks for windows here, since windows */ /* does not support backlink and we need to resolve symbols during */ /* dll initialisation (REGISTER/RESOLVER). Opcode tables are renamed */ /* such that no naming conflicts occur. */ #define copy_opcode_tables copy_opcode_tables_r #define opcode_table opcode_table_r #define opcode_01xx opcode_01xx_r #define opcode_a5xx opcode_a5xx_r #define opcode_a4xx opcode_a4xx_r #define opcode_a7xx opcode_a1xx_r #define opcode_b2xx opcode_b2xx_r #define opcode_b3xx opcode_b3xx_r #define opcode_b9xx opcode_b9xx_r #define opcode_c0xx opcode_c0xx_r #define opcode_c2xx opcode_c2xx_r #define opcode_c4xx opcode_c4xx_r /*208*/ #define opcode_c6xx opcode_c6xx_r /*208*/ #define opcode_c8xx opcode_c8xx_r #define opcode_ccxx opcode_ccxx_r /*810*/ #define opcode_e3xx opcode_e3xx_r #define opcode_e5xx opcode_e5xx_r #define opcode_e6xx opcode_e6xx_r #define opcode_ebxx opcode_ebxx_r #define opcode_ecxx opcode_ecxx_r #define opcode_edxx opcode_edxx_r #endif #include "opcode.h" #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef copy_opcode_tables #undef opcode_table #undef opcode_01xx #undef opcode_a5xx #undef opcode_a4xx #undef opcode_a7xx #undef opcode_b2xx #undef opcode_b3xx #undef opcode_b9xx #undef opcode_c0xx #undef opcode_c2xx #undef opcode_c4xx /*208*/ #undef opcode_c6xx /*208*/ #undef opcode_c8xx #undef opcode_ccxx /*810*/ #undef opcode_e3xx #undef opcode_e5xx #undef opcode_e6xx #undef opcode_ebxx #undef opcode_ecxx #undef opcode_edxx #endif #include "inline.h" #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "dyninst.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "dyninst.c" #endif static zz_func save_table[256][GEN_MAXARCH]; static zz_func save_01xx[256][GEN_MAXARCH]; #if defined (FEATURE_VECTOR_FACILITY) static zz_func save_a4xx[256][GEN_MAXARCH]; #endif static zz_func save_a5xx[16][GEN_MAXARCH]; static zz_func save_a7xx[16][GEN_MAXARCH]; static zz_func save_b2xx[256][GEN_MAXARCH]; static zz_func save_b3xx[256][GEN_MAXARCH]; static zz_func save_b9xx[256][GEN_MAXARCH]; static zz_func save_c0xx[16][GEN_MAXARCH]; static zz_func save_c2xx[16][GEN_MAXARCH]; /*@Z9*/ static zz_func save_c4xx[16][GEN_MAXARCH]; /*208*/ static zz_func save_c6xx[16][GEN_MAXARCH]; /*208*/ static zz_func save_c8xx[16][GEN_MAXARCH]; static zz_func save_ccxx[16][GEN_MAXARCH]; /*810*/ static zz_func save_e3xx[256][GEN_MAXARCH]; static zz_func save_e5xx[256][GEN_MAXARCH]; static zz_func save_e6xx[256][GEN_MAXARCH]; static zz_func save_ebxx[256][GEN_MAXARCH]; static zz_func save_ecxx[256][GEN_MAXARCH]; static zz_func save_edxx[256][GEN_MAXARCH]; #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) static int opcodes_saved; static void copy_opcode_tables (); static void * opcode_table; static void * opcode_01xx; #if defined (FEATURE_VECTOR_FACILITY) static void * opcode_a4xx; #endif static void * opcode_a5xx; static void * opcode_a7xx; static void * opcode_b2xx; static void * opcode_b3xx; static void * opcode_b9xx; static void * opcode_c0xx; static void * opcode_c2xx; /*@Z9*/ static void * opcode_c4xx; /*208*/ static void * opcode_c6xx; /*208*/ static void * opcode_c8xx; static void * opcode_ccxx; /*810*/ static void * opcode_e3xx; static void * opcode_e5xx; static void * opcode_e6xx; static void * opcode_ebxx; static void * opcode_ecxx; static void * opcode_edxx; #endif static char *prefix[] = { #if defined(_370) "s370_dyninst_opcode_", #endif #if defined(_390) "s390_dyninst_opcode_", #endif #if defined(_900) "z900_dyninst_opcode_" #endif }; static void opcode_save() { memcpy(save_table,opcode_table,sizeof(save_table)); memcpy(save_01xx,opcode_01xx,sizeof(save_01xx)); #if defined (FEATURE_VECTOR_FACILITY) memcpy(save_a4xx,opcode_a4xx,sizeof(save_a4xx)); #endif memcpy(save_a5xx,opcode_a5xx,sizeof(save_a5xx)); memcpy(save_a7xx,opcode_a7xx,sizeof(save_a7xx)); memcpy(save_b2xx,opcode_b2xx,sizeof(save_b2xx)); memcpy(save_b3xx,opcode_b3xx,sizeof(save_b3xx)); memcpy(save_b9xx,opcode_b9xx,sizeof(save_b9xx)); memcpy(save_c0xx,opcode_c0xx,sizeof(save_c0xx)); memcpy(save_c2xx,opcode_c2xx,sizeof(save_c2xx)); /*@Z9*/ memcpy(save_c4xx,opcode_c4xx,sizeof(save_c4xx)); /*208*/ memcpy(save_c6xx,opcode_c6xx,sizeof(save_c6xx)); /*208*/ memcpy(save_c8xx,opcode_c8xx,sizeof(save_c8xx)); memcpy(save_ccxx,opcode_ccxx,sizeof(save_ccxx)); /*810*/ memcpy(save_e3xx,opcode_e3xx,sizeof(save_e3xx)); memcpy(save_e5xx,opcode_e5xx,sizeof(save_e5xx)); memcpy(save_e6xx,opcode_e6xx,sizeof(save_e6xx)); memcpy(save_ebxx,opcode_ebxx,sizeof(save_ebxx)); memcpy(save_ecxx,opcode_ecxx,sizeof(save_ecxx)); memcpy(save_edxx,opcode_edxx,sizeof(save_edxx)); } static void opcode_restore() { memcpy(opcode_table,save_table,sizeof(save_table)); memcpy(opcode_01xx,save_01xx,sizeof(save_01xx)); #if defined (FEATURE_VECTOR_FACILITY) memcpy(opcode_a4xx,save_a4xx,sizeof(save_a4xx)); #endif memcpy(opcode_a5xx,save_a5xx,sizeof(save_a5xx)); memcpy(opcode_a7xx,save_a7xx,sizeof(save_a7xx)); memcpy(opcode_b2xx,save_b2xx,sizeof(save_b2xx)); memcpy(opcode_b3xx,save_b3xx,sizeof(save_b3xx)); memcpy(opcode_b9xx,save_b9xx,sizeof(save_b9xx)); memcpy(opcode_c0xx,save_c0xx,sizeof(save_c0xx)); memcpy(opcode_c2xx,save_c2xx,sizeof(save_c2xx)); /*@Z9*/ memcpy(opcode_c4xx,save_c4xx,sizeof(save_c4xx)); /*208*/ memcpy(opcode_c6xx,save_c6xx,sizeof(save_c6xx)); /*208*/ memcpy(opcode_c8xx,save_c8xx,sizeof(save_c8xx)); memcpy(opcode_ccxx,save_ccxx,sizeof(save_ccxx)); /*810*/ memcpy(opcode_e3xx,save_e3xx,sizeof(save_e3xx)); memcpy(opcode_e5xx,save_e5xx,sizeof(save_e5xx)); memcpy(opcode_e6xx,save_e6xx,sizeof(save_e6xx)); memcpy(opcode_ebxx,save_ebxx,sizeof(save_ebxx)); memcpy(opcode_ecxx,save_ecxx,sizeof(save_ecxx)); memcpy(opcode_edxx,save_edxx,sizeof(save_edxx)); } static void assign_extop1(int opcode, int extop, zz_func table[256][GEN_MAXARCH], zz_func saved[256][GEN_MAXARCH]) { int arch; void *tmp; for(arch = 0; arch < GEN_MAXARCH - 2; arch++) { char name[32]; sprintf(name,"%s%02X%1X",prefix[arch],opcode,extop); if((tmp = HDL_FINDSYM(name))) table[extop][arch] = tmp; else table[extop][arch] = saved[extop][arch]; } } static void assign_extop(int opcode, int extop, zz_func table[256][GEN_MAXARCH], zz_func saved[256][GEN_MAXARCH]) { int arch; void *tmp; for(arch = 0; arch < GEN_MAXARCH - 2; arch++) { char name[32]; sprintf(name,"%s%02X%02X",prefix[arch],opcode,extop); if((tmp = HDL_FINDSYM(name))) table[extop][arch] = tmp; else table[extop][arch] = saved[extop][arch]; } } static void assign_opcode(int opcode, zz_func table[256][GEN_MAXARCH], zz_func saved[256][GEN_MAXARCH]) { int arch; void *tmp; for(arch = 0; arch < GEN_MAXARCH - 2; arch++) { char name[32]; sprintf(name,"%s%02X",prefix[arch],opcode); if((tmp = HDL_FINDSYM(name))) table[opcode][arch] = tmp; else table[opcode][arch] = saved[opcode][arch]; } } /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev dyninst_LTX_hdl_ddev #define hdl_depc dyninst_LTX_hdl_depc #define hdl_reso dyninst_LTX_hdl_reso #define hdl_init dyninst_LTX_hdl_init #define hdl_fini dyninst_LTX_hdl_fini #endif HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY (HERCULES); HDL_DEPENDENCY (REGS); HDL_DEPENDENCY (DEVBLK); HDL_DEPENDENCY (SYSBLK); } END_DEPENDENCY_SECTION HDL_REGISTER_SECTION; { #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) opcodes_saved = 0; #else opcode_save(); #endif } END_REGISTER_SECTION HDL_RESOLVER_SECTION; { int opcode, extop; #if 0 #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) if(!opcodes_saved) { HDL_RESOLVE(copy_opcode_tables); HDL_RESOLVE(opcode_table); HDL_RESOLVE(opcode_01xx); #if defined(FEATURE_VECTOR_FACILITY) HDL_RESOLVE(opcode_a4xx); #endif HDL_RESOLVE(opcode_a5xx); HDL_RESOLVE(opcode_a7xx); HDL_RESOLVE(opcode_b2xx); HDL_RESOLVE(opcode_b3xx); HDL_RESOLVE(opcode_b9xx); HDL_RESOLVE(opcode_c0xx); HDL_RESOLVE(opcode_c2xx); /*@Z9*/ HDL_RESOLVE(opcode_c4xx); /*208*/ HDL_RESOLVE(opcode_c6xx); /*208*/ HDL_RESOLVE(opcode_c8xx); HDL_RESOLVE(opcode_ccxx); /*810*/ HDL_RESOLVE(opcode_e3xx); HDL_RESOLVE(opcode_e5xx); HDL_RESOLVE(opcode_e6xx); HDL_RESOLVE(opcode_ebxx); HDL_RESOLVE(opcode_ecxx); HDL_RESOLVE(opcode_edxx); opcode_save(); opcodes_saved = 1; } #endif #endif for(opcode = 0; opcode < 256; opcode++) { switch(opcode) { case 0x01: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_01xx, save_01xx); break; #if defined (FEATURE_VECTOR_FACILITY) case 0xA4: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, v_opcode_a4xx, save_a4xx); break; #endif case 0xA5: for(extop = 0; extop < 16; extop++) assign_extop1(opcode, extop, opcode_a5xx, save_a5xx); break; case 0xA7: for(extop = 0; extop < 16; extop++) assign_extop1(opcode, extop, opcode_a7xx, save_a7xx); break; case 0xB2: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_b2xx, save_b2xx); break; case 0xB3: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_b3xx, save_b3xx); break; case 0xB9: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_b9xx, save_b9xx); break; case 0xC0: for(extop = 0; extop < 16; extop++) assign_extop1(opcode, extop, opcode_c0xx, save_c0xx); break; case 0xC2: /*@Z9*/ for(extop = 0; extop < 16; extop++) /*@Z9*/ assign_extop1(opcode, extop, opcode_c2xx, save_c2xx); /*@Z9*/ break; /*@Z9*/ case 0xC4: /*208*/ for(extop = 0; extop < 16; extop++) /*208*/ assign_extop1(opcode, extop, opcode_c4xx, save_c4xx); /*208*/ break; /*208*/ case 0xC6: /*208*/ for(extop = 0; extop < 16; extop++) /*208*/ assign_extop1(opcode, extop, opcode_c6xx, save_c6xx); /*208*/ break; /*208*/ case 0xC8: for(extop = 0; extop < 16; extop++) assign_extop1(opcode, extop, opcode_c8xx, save_c8xx); break; case 0xCC: /*810*/ for(extop = 0; extop < 16; extop++) /*810*/ assign_extop1(opcode, extop, opcode_ccxx, save_ccxx); /*810*/ break; /*810*/ case 0xE3: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_e3xx, save_e3xx); break; case 0xE5: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_e5xx, save_e5xx); break; case 0xE6: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_e6xx, save_e6xx); break; case 0xEB: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_ebxx, save_ebxx); break; case 0xEC: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_ecxx, save_ecxx); break; case 0xED: for(extop = 0; extop < 256; extop++) assign_extop(opcode, extop, opcode_edxx, save_edxx); break; default: assign_opcode(opcode, opcode_table, save_table); } } /* Copy opcodes to performance shadow tables */ copy_opcode_tables(); } END_RESOLVER_SECTION HDL_FINAL_SECTION; { opcode_restore(); } END_FINAL_SECTION #endif /*!defined(_GEN_ARCH)*/ #endif /*defined(OPTION_DYNAMIC_LOAD)*/ hercules-3.12/con1052c.c0000664000175000017500000003464312564723224011613 00000000000000/* CON1052.C (c)Copyright Jan Jaeger, 2004-2009 */ /* Emulated 1052 on hercules console */ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "sr.h" #if defined(OPTION_DYNAMIC_LOAD) && defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) SYSBLK *psysblk; #define sysblk (*psysblk) void* (*panel_command) (void*); #endif #if defined(OPTION_DYNAMIC_LOAD) static void* con1052_panel_command (char *cmd); #endif #define BUFLEN_1052 150 /* 1052 Send/Receive buffer */ /*-------------------------------------------------------------------*/ /* Ivan Warren 20040227 */ /* This table is used by channel.c to determine if a CCW code is an */ /* immediate command or not */ /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */ /* 0 : Command is NOT an immediate command */ /* 1 : Command is an immediate command */ /* Note : An immediate command is defined as a command which returns */ /* CE (channel end) during initialisation (that is, no data is */ /* actually transfered. In this case, IL is not indicated for a CCW */ /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */ /* effect */ /*-------------------------------------------------------------------*/ static BYTE con1052_immed[256]= /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ { 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* E0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* F0 */ /*-------------------------------------------------------------------*/ /* INITIALIZE THE 1052/3215 DEVICE HANDLER */ /*-------------------------------------------------------------------*/ static int con1052_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { int ac=0; /* Integrated console is always connected */ dev->connected = 1; /* Set number of sense bytes */ dev->numsense = 1; /* Initialize device dependent fields */ dev->keybdrem = 0; /* Set length of print buffer */ dev->bufsize = BUFLEN_1052; /* Assume we want to prompt */ dev->prompt1052 = 1; /* Default command character is "/" */ strcpy(dev->filename,"/"); /* Is there an argument? */ if (argc > 0) { /* Look at the argument and set noprompt flag if specified. */ if (strcasecmp(argv[ac], "noprompt") == 0) { dev->prompt1052 = 0; ac++; argc--; } else strlcpy(dev->filename,argv[ac],sizeof(dev->filename)); } if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x1052; /* Initialize the device identifier bytes */ dev->devid[0] = 0xFF; dev->devid[1] = dev->devtype >> 8; dev->devid[2] = dev->devtype & 0xFF; dev->devid[3] = 0x00; dev->devid[4] = dev->devtype >> 8; dev->devid[5] = dev->devtype & 0xFF; dev->devid[6] = 0x00; dev->numdevid = 7; return 0; } /* end function con1052_init_handler */ /*-------------------------------------------------------------------*/ /* QUERY THE 1052/3215 DEVICE DEFINITION */ /*-------------------------------------------------------------------*/ static void con1052_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "CON", dev, class, buflen, buffer ); snprintf(buffer, buflen, "*syscons cmdpref(%s)%s", dev->filename, !dev->prompt1052 ? " noprompt" : ""); } /* end function con1052_query_device */ /*-------------------------------------------------------------------*/ /* CLOSE THE 1052/3215 DEVICE HANDLER */ /*-------------------------------------------------------------------*/ static int con1052_close_device ( DEVBLK *dev ) { UNREFERENCED(dev); return 0; } /* end function con1052_close_device */ /*-------------------------------------------------------------------*/ /* EXECUTE A 1052/3215 CHANNEL COMMAND WORD */ /*-------------------------------------------------------------------*/ static void con1052_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { int len; /* Length of data */ int num; /* Number of bytes to move */ BYTE c; /* Print character */ UNREFERENCED(chained); UNREFERENCED(prevcode); UNREFERENCED(ccwseq); /* Unit check with intervention required if no client connected */ if (dev->connected == 0 && !IS_CCW_SENSE(code)) { dev->sense[0] = SENSE_IR; *unitstat = CSW_UC; return; } /* Process depending on CCW opcode */ switch (code) { case 0x01: /*---------------------------------------------------------------*/ /* WRITE NO CARRIER RETURN */ /*---------------------------------------------------------------*/ case 0x09: /*---------------------------------------------------------------*/ /* WRITE AUTO CARRIER RETURN */ /*---------------------------------------------------------------*/ /* Calculate number of bytes to write and set residual count */ num = (count < BUFLEN_1052) ? count : BUFLEN_1052; *residual = count - num; /* Translate data in channel buffer to ASCII */ for (len = 0; len < num; len++) { c = guest_to_host(iobuf[len]); if (!isprint(c) && c != 0x0a && c != 0x0d) c = SPACE; iobuf[len] = c; } /* end for(len) */ /* Perform end of record processing if not data-chaining, and append carriage return and newline if required */ if ((flags & CCW_FLAGS_CD) == 0 && code == 0x09 && len < BUFLEN_1052) iobuf[len++] = '\n'; iobuf[len] = '\0'; /* Send the data to the console */ logmsg("%s",(char *)iobuf); /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x03: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ *unitstat = CSW_CE | CSW_DE; break; case 0x0A: /*---------------------------------------------------------------*/ /* READ INQUIRY */ /*---------------------------------------------------------------*/ /* Solicit console input if no data in the device buffer */ if (!dev->keybdrem) { /* Display prompting message on console if allowed */ if (dev->prompt1052) logmsg (_("HHC1C001A Enter input for console device %4.4X\n"), dev->devnum); obtain_lock(&dev->lock); dev->iowaiters++; wait_condition(&dev->iocond, &dev->lock); dev->iowaiters--; release_lock(&dev->lock); } /* Calculate number of bytes to move and residual byte count */ len = dev->keybdrem; num = (count < len) ? count : len; *residual = count - num; if (count < len) *more = 1; /* Copy data from device buffer to channel buffer */ memcpy (iobuf, dev->buf, num); /* If data chaining is specified, save remaining data */ if ((flags & CCW_FLAGS_CD) && len > count) { memmove (dev->buf, dev->buf + count, len - count); dev->keybdrem = len - count; } else { dev->keybdrem = 0; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x0B: /*---------------------------------------------------------------*/ /* AUDIBLE ALARM */ /*---------------------------------------------------------------*/ logmsg("\a"); /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ } /* end function con1052_execute_ccw */ #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND con1052_device_hndinfo = { &con1052_init_handler, /* Device Initialisation */ &con1052_execute_ccw, /* Device CCW execute */ &con1052_close_device, /* Device Close */ &con1052_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ con1052_immed, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; #if defined(OPTION_DYNAMIC_LOAD) static void* con1052_panel_command (char *cmd) { DEVBLK *dev; char *input; int i; void* (*next_panel_command_handler)(char *cmd); for(dev = sysblk.firstdev; dev; dev = dev->nextdev) { if(dev->allocated && dev->hnd == &con1052_device_hndinfo && !strncasecmp(cmd,dev->filename,strlen(dev->filename)) ) { input = cmd + strlen(dev->filename); logmsg("%s(%4.4X) %s\n",dev->filename,dev->devnum, cmd+strlen(dev->filename) ); for(i = 0; i < dev->bufsize && input[i] != '\0'; i++) dev->buf[i] = isprint(input[i]) ? host_to_guest(input[i]) : SPACE; dev->keybdrem = dev->buflen = i; obtain_lock(&dev->lock); if(dev->iowaiters) { signal_condition(&dev->iocond); release_lock(&dev->lock); } else { release_lock(&dev->lock); device_attention (dev, CSW_ATTN); } return NULL; } } next_panel_command_handler = HDL_FINDNXT(con1052_panel_command); if (!next_panel_command_handler) return NULL; return next_panel_command_handler(cmd); } #endif /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt1052c_LTX_hdl_ddev #define hdl_depc hdt1052c_LTX_hdl_depc #define hdl_reso hdt1052c_LTX_hdl_reso #define hdl_init hdt1052c_LTX_hdl_init #define hdl_fini hdt1052c_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); } END_DEPENDENCY_SECTION #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR(psysblk, sysblk); HDL_RESOLVE(panel_command); } END_RESOLVER_SECTION #endif HDL_DEVICE_SECTION; { HDL_DEVICE(1052-C, con1052_device_hndinfo); HDL_DEVICE(3215-C, con1052_device_hndinfo); } END_DEVICE_SECTION HDL_REGISTER_SECTION; { HDL_REGISTER (panel_command, con1052_panel_command); } END_REGISTER_SECTION #endif hercules-3.12/printer.c0000664000175000017500000014022712622153562012035 00000000000000/* PRINTER.C (c) Copyright Roger Bowler, 1999-2010 */ /* (c) Copyright Enrico Sorichetti, 2012 */ /* ESA/390 Line Printer Device Handler */ /*-------------------------------------------------------------------*/ /* This module contains device handling functions for emulated */ /* System/370 line printer devices with fcb support and more */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "opcode.h" /*-------------------------------------------------------------------*/ /* Ivan Warren 20040227 */ /* This table is used by channel.c to determine if a CCW code is an */ /* immediate command or not */ /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */ /* 0 : Command is NOT an immediate command */ /* 1 : Command is an immediate command */ /* Note : An immediate command is defined as a command which returns */ /* CE (channel end) during initialisation (that is, no data is */ /* actually transfered. In this case, IL is not indicated for a CCW */ /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */ /* effect */ /*-------------------------------------------------------------------*/ /* Printer Specific : 1403 */ /* The following are considered IMMEDIATE commands : */ /* CTL-NOOP, Skip Channel 'n' Immediate, Block Data check , Allow Data Check * Space 1,2,3 Lines Immediate, UCS Gate Load, Load UCS Buffer & Fold, * Load UCS Buffer (No Fold) */ static BYTE printer_immed_commands[256]= /* *0 1 2 3 4 5 6 7 8 9 A B C D E F */ { 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0}; /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ //#define LINE_LENGTH 150 #define BUFF_SIZE 1500 #define BUFF_OVFL 150 int line; int coun; int chan; int FCBMASK[] = {66,1,7,13,19,25,31,37,43,63,49,55,61}; int havechan; #define LINENUM(n) ( 1 + ( ( (n)-1) % dev->lpp)) #define WRITE_LINE() \ do { \ /* Start a new record if not data-chained from previous CCW */ \ if ((chained & CCW_FLAGS_CD) == 0) \ { \ dev->bufoff = 0; \ dev->bufres = BUFF_SIZE; \ } /* end if(!data-chained) */ \ if ( dev->index > 1 ) \ { \ for (i = 1; i < dev->index; i++) \ { \ dev->buf[dev->bufoff] = SPACE; \ dev->bufoff++; \ dev->bufres--; \ } /* end for(i) */ \ } /* end if ( dev->index > 1 ) */ \ /* Calculate number of bytes to write and set residual count */ \ num = (count < dev->bufres) ? count : dev->bufres; \ *residual = count - num; \ /* Copy data from channel buffer to print buffer */ \ for (i = 0; i < num; i++) \ { \ c = guest_to_host(iobuf[i]); \ if (dev->fold) c = toupper(c); \ if (c == 0) c = SPACE; \ dev->buf[dev->bufoff] = c; \ dev->bufoff++; \ dev->bufres--; \ } /* end for(i) */ \ /* Perform end of record processing if not data-chaining */ \ if ((flags & CCW_FLAGS_CD) == 0) \ { \ /* Truncate trailing blanks from print line */ \ for (i = dev->bufoff; i > 0; i--) \ if (dev->buf[i-1] != SPACE) break; \ /* Write print line */ \ write_buffer (dev, (char *)dev->buf, i, unitstat); \ if (*unitstat != 0) return; \ if ( dev->crlf ) \ { \ write_buffer (dev, "\r", 1, unitstat); \ if (*unitstat != 0) return; \ } \ } /* end if(!data-chaining) */ \ /* Return normal status */ \ } while(0) /* changed to */ /* search the fcb array starting at the CURRENT line position */ /* check if the previous operation was a write no space */ #define SKIP_TO_CHAN() \ do { \ havechan = 0; \ for ( i = 0; i < dev->lpp; i++ ) \ { \ line = LINENUM( dev->currline + i ); \ if ( dev->fcb[line] != chan ) \ continue; \ havechan = 1; \ dev->destline = line; \ break; \ } \ if ( havechan == 1 ) \ { \ if ( ( dev->destline < dev->currline ) || \ ( dev->chskip == 1 && dev->destline <= dev->currline ) ) \ { \ dev->chskip = 0; \ write_buffer (dev, "\f", 1, unitstat); \ if (*unitstat != 0) return; \ dev->currline = 1; \ } \ for (; dev->currline < dev->destline; dev->currline++ ) \ { \ write_buffer (dev, "\n", 1, unitstat); \ if (*unitstat != 0) return; \ } \ *unitstat = CSW_CE | CSW_DE; \ return; \ } \ /* channel not found */ \ { \ if ( dev->nofcbcheck ) \ { \ if ( ( code & 0x02 ) != 0 ) \ { \ write_buffer (dev, "\n", 1, unitstat); \ if (*unitstat != 0) return; \ } \ } \ else \ { \ dev->sense[0] = (dev->devtype == 0x1403 ) ? SENSE_EC :SENSE_EC; \ *unitstat = CSW_CE | CSW_DE | CSW_UC; \ return; \ } \ } \ } while (0) static void* spthread (DEVBLK* dev); /* (forward reference) */ /*-------------------------------------------------------------------*/ /* Dump the FCB info */ /*-------------------------------------------------------------------*/ static void fcb_dump(DEVBLK* dev, char *buf, unsigned int buflen) { int i; char wrk[16]; char sep[1]; sep[0] = '='; snprintf(buf, buflen, "LOADED lpi=%d index=%d lpp=%d fcb", dev->lpi, dev->index, dev->lpp ); for (i = 1; i <= dev->lpp; i++) { if (dev->fcb[i] != 0) { sprintf(wrk, "%c%d:%d", sep[0], i, dev->fcb[i]); sep[0] = ','; if (strlen(buf) + strlen(wrk) >= buflen - 4) { /* Too long, truncate it */ strcat(buf, ",..."); return; } strcat(buf, wrk); } } return; } /*-------------------------------------------------------------------*/ /* Sockdev "OnConnection" callback function */ /*-------------------------------------------------------------------*/ static int onconnect_callback (DEVBLK* dev) { TID tid; if (create_thread( &tid, DETACHED, spthread, dev, NULL )) { logmsg(_("HHCPR015E Create spthread failed for %4.4X: errno=%d: %s\n" ), dev->devnum, errno, strerror( errno ) ); return 0; } return 1; } /*-------------------------------------------------------------------*/ /* Thread to monitor the sockdev remote print spooler connection */ /*-------------------------------------------------------------------*/ static void* spthread (DEVBLK* dev) { BYTE byte; fd_set readset, errorset; struct timeval tv; int rc, fd = dev->fd; // (save original fd) /* Fix thread name */ { char thread_name[32]; thread_name[sizeof(thread_name)-1] = 0; snprintf( thread_name, sizeof(thread_name)-1, "spthread %4.4X", dev->devnum ); SET_THREAD_NAME( thread_name ); } // Looooop... until shutdown or disconnect... // PROGRAMMING NOTE: we do our select specifying an immediate // timeout to prevent our select from holding up (slowing down) // the device thread (which does the actual writing of data to // the client). The only purpose for our thread even existing // is to detect a severed connection (i.e. to detect when the // client disconnects)... while ( !sysblk.shutdown && dev->fd == fd ) { if (dev->busy) { SLEEP(3); continue; } FD_ZERO( &readset ); FD_ZERO( &errorset ); FD_SET( fd, &readset ); FD_SET( fd, &errorset ); tv.tv_sec = 0; tv.tv_usec = 0; rc = select( fd+1, &readset, NULL, &errorset, &tv ); if (rc < 0) break; if (rc == 0) { SLEEP(3); continue; } if (FD_ISSET( fd, &errorset )) break; // Read and ignore any data they send us... // Note: recv should complete immediately // as we know data is waiting to be read. ASSERT( FD_ISSET( fd, &readset ) ); rc = recv( fd, &byte, sizeof(byte), 0 ); if (rc <= 0) break; } obtain_lock( &dev->lock ); // PROGRAMMING NOTE: the following tells us whether we detected // the error or if the device thread already did. If the device // thread detected it while we were sleeping (and subsequently // closed the connection) then we don't need to do anything at // all; just exit. If we were the ones that detected the error // however, then we need to close the connection so the device // thread can learn of it... if (dev->fd == fd) { dev->fd = -1; close_socket( fd ); logmsg (_("HHCPR016I %s (%s) disconnected from device %4.4X (%s)\n"), dev->bs->clientname, dev->bs->clientip, dev->devnum, dev->bs->spec); } release_lock( &dev->lock ); return NULL; } /* end function spthread */ /*-------------------------------------------------------------------*/ /* Initialize the device handler */ /*-------------------------------------------------------------------*/ static int printer_init_handler (DEVBLK *dev, int argc, char *argv[]) { int iarg,i,j; /* Array subscripts */ char *ptr; char *nxt; int sockdev = 0; /* 1 == is socket device */ /* Forcibly disconnect anyone already currently connected */ if (dev->bs && !unbind_device_ex(dev,1)) return -1; // (error msg already issued) /* The first argument is the file name */ if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1) { logmsg (_("HHCPR001E File name missing or invalid for printer %4.4X\n"), dev->devnum); return -1; } /* Save the file name in the device block */ strncpy (dev->filename, argv[0], sizeof(dev->filename)); if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x3211; /* Initialize device dependent fields */ dev->fd = -1; dev->diaggate = 0; dev->fold = 0; dev->crlf = 0; dev->stopprt = 0; dev->notrunc = 0; dev->ispiped = (dev->filename[0] == '|'); /* initialize the new fields for FCB+ support */ dev->fcbsupp = 1; dev->cc = 0; dev->rawcc = 0; dev->fcbcheck = 1; dev->nofcbcheck = 0; dev->ccpend = 0; dev->chskip = 0; dev->prevline = 1; dev->currline = 1; dev->destline = 1; dev->print = 1; dev->browse = 0; dev->lpi = 6; dev->index = 0; dev->ffchan = 1; for (i = 0; i < FCBSIZE; i++) dev->fcb[i] = 0; for (i = 1; i <= 12; i++ ) { if ( FCBMASK[i] != 0 ) dev->fcb[FCBMASK[i]] = i; } dev->lpp = FCBMASK[0]; dev->fcbisdef = 0; /* Process the driver arguments */ for (iarg = 1; iarg < argc; iarg++) { if (strcasecmp(argv[iarg], "crlf") == 0) { dev->crlf = 1; continue; } /* sockdev means the device file is actually a connected socket instead of a disk file. The file name is the socket_spec (host:port) to listen for connections on. */ if (!dev->ispiped && strcasecmp(argv[iarg], "sockdev") == 0) { sockdev = 1; continue; } if (strcasecmp(argv[iarg], "noclear") == 0) { dev->notrunc = 1; continue; } if (strcasecmp(argv[iarg], "cc") == 0) { dev->cc = 1; dev->rawcc = 0; continue; } if (strcasecmp(argv[iarg], "rawcc") == 0) { dev->cc = 0; dev->rawcc = 1; continue; } if (strcasecmp(argv[iarg], "nofcbcheck") == 0) { dev->fcbcheck = 0; dev->nofcbcheck = 1; continue; } if (strcasecmp(argv[iarg], "fcbcheck") == 0) { dev->fcbcheck = 1; dev->nofcbcheck = 0; continue; } if ( (strcasecmp(argv[iarg], "browse") == 0) || (strcasecmp(argv[iarg], "optbrowse") == 0 ) ) { dev->print = 0; dev->browse = 1; continue; } if ( (strcasecmp(argv[iarg], "print") == 0 ) || (strcasecmp(argv[iarg], "optprint") == 0) ) { dev->print = 1; dev->browse = 0; continue; } if (strncasecmp("lpi=", argv[iarg], 4) == 0) { ptr = argv[iarg]+4; errno = 0; dev->lpi = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 || ( dev->lpi != 6 && dev->lpi != 8 ) ) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } continue; } if (strncasecmp("index=", argv[iarg], 6) == 0) { if (dev->devtype != 0x3211 ) { logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, 1); return -1; } ptr = argv[iarg]+6; errno = 0; dev->index = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 || ( dev->index < 0 || dev->index > 15) ) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } continue; } if (strncasecmp("lpp=", argv[iarg], 4) == 0) { ptr = argv[iarg]+4; errno = 0; dev->lpp = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 ||dev->lpp > FCBSIZE) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } continue; } #if 0 if (strncasecmp("ffchan=", argv[iarg], 7) == 0) { ptr = argv[iarg]+7; errno = 0; dev->ffchan = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 || dev->ffchan < 1 || dev->ffchan > 12) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } continue; } #endif if (strncasecmp("fcb=", argv[iarg], 4) == 0) { for (line = 0; line <= FCBSIZE; line++) dev->fcb[line] = 0; /* check for simple mode */ if ( strstr(argv[iarg],":") ) { /* ':" found ==> new mode */ ptr = argv[iarg]+4; while (*ptr) { errno = 0; line = (int) strtoul(ptr,&nxt,10); if (errno != 0 || *nxt != ':' || nxt == ptr || line > dev->lpp || dev->fcb[line] != 0 ) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } ptr = nxt + 1; errno = 0; chan = (int) strtoul(ptr,&nxt,10); if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || chan < 1 || chan > 12 ) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } dev->fcb[line] = chan; if ( *nxt == 0 ) break; ptr = nxt + 1; } } else { /* ':" NOT found ==> old mode */ ptr = argv[iarg]+4; chan = 0; while (*ptr) { errno = 0; line = (int) strtoul(ptr,&nxt,10); if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || line > dev->lpp || dev->fcb[line] != 0 ) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } chan += 1; if ( chan > 12 ) { j = ptr - argv[iarg]; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } dev->fcb[line] = chan; if ( *nxt == 0 ) break; ptr = nxt + 1; } if ( chan != 12 ) { j = 5; logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j); return -1; } } continue; } logmsg("HHCPR102E %d:%4.4X Printer: parameter %s in argument %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1); return -1; } /* Check for incompatible options */ if (dev->rawcc && dev->browse) { logmsg("HHCPR104E %d:%4.4X Printer: option %s is incompatible\n", SSID_TO_LCSS(dev->ssid), dev->devnum, "rawcc/browse"); return -1; } if (sockdev && dev->crlf) { logmsg("HHCPR104E %d:%4.4X Printer: option %s is incompatible\n", SSID_TO_LCSS(dev->ssid), dev->devnum, "sockdev/crlf"); return -1; } if (sockdev && dev->notrunc) { logmsg("HHCPR104E %d:%4.4X Printer: option %s is incompatible\n", SSID_TO_LCSS(dev->ssid), dev->devnum, "sockdev/noclear"); return -1; } /* If socket device, create a listening socket to accept connections on. */ if (sockdev && !bind_device_ex( dev, dev->filename, onconnect_callback, dev )) { return -1; // (error msg already issued) } /* Set length of print buffer */ // dev->bufsize = LINE_LENGTH + 8; dev->bufsize = BUFF_SIZE + BUFF_OVFL; dev->bufres = BUFF_SIZE; dev->bufoff = 0; /* Set number of sense bytes */ dev->numsense = 1; /* Initialize the device identifier bytes */ dev->devid[0] = 0xFF; dev->devid[1] = 0x28; /* Control unit type is 2821-1 */ dev->devid[2] = 0x21; dev->devid[3] = 0x01; dev->devid[4] = dev->devtype >> 8; dev->devid[5] = dev->devtype & 0xFF; dev->devid[6] = 0x01; dev->numdevid = 7; /* Activate I/O tracing */ // dev->ccwtrace = 1; return 0; } /* end function printer_init_handler */ /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ static void printer_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "PRT", dev, class, buflen, buffer ); snprintf (buffer, buflen, "%s%s%s%s%s%s%s", dev->filename, (dev->bs ? " sockdev" : ""), (dev->crlf ? " crlf" : ""), (dev->notrunc ? " noclear" : ""), (dev->rawcc ? " rawcc" : dev->browse ? " brwse" : " print"), (dev->nofcbcheck ? " nofcbck" : " fcbck"), (dev->stopprt ? " (stopped)" : "")); } /* end function printer_query_device */ /*-------------------------------------------------------------------*/ /* Subroutine to open the printer file or pipe */ /*-------------------------------------------------------------------*/ static int open_printer (DEVBLK *dev) { pid_t pid; /* Child process identifier */ char pathname[MAX_PATH]; /* file path in host format */ int open_flags; /* File open flags */ #if !defined( _MSVC_ ) int pipefd[2]; /* Pipe descriptors */ int rc; /* Return code */ #endif /* Regular open if 1st char of filename is not vertical bar */ if (!dev->ispiped) { int fd; /* Socket printer? */ if (dev->bs) return (dev->fd < 0 ? -1 : 0); /* Normal printer */ hostpath(pathname, dev->filename, sizeof(pathname)); open_flags = O_BINARY | O_WRONLY | O_CREAT /* | O_SYNC */; if (dev->notrunc != 1) { open_flags |= O_TRUNC; } fd = hopen(pathname, open_flags, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { logmsg (_("HHCPR004E Error opening file %s: %s\n"), dev->filename, strerror(errno)); return -1; } /* Save file descriptor in device block and return */ dev->fd = fd; return 0; } /* Filename is in format |xxx, set up pipe to program xxx */ #if defined( _MSVC_ ) /* "Poor man's" fork... */ pid = w32_poor_mans_fork ( dev->filename+1, &dev->fd ); if (pid < 0) { logmsg (_("HHCPR006E %4.4X device initialization error: fork: %s\n"), dev->devnum, strerror(errno)); return -1; } /* Log start of child process */ logmsg (_("HHCPR007I pipe receiver (pid=%d) starting for %4.4X\n"), pid, dev->devnum); dev->ptpcpid = pid; #else /* !defined( _MSVC_ ) */ /* Create a pipe */ rc = create_pipe (pipefd); if (rc < 0) { logmsg (_("HHCPR005E %4.4X device initialization error: pipe: %s\n"), dev->devnum, strerror(errno)); return -1; } /* Fork a child process to receive the pipe data */ pid = fork(); if (pid < 0) { logmsg (_("HHCPR006E %4.4X device initialization error: fork: %s\n"), dev->devnum, strerror(errno)); close_pipe ( pipefd[0] ); close_pipe ( pipefd[1] ); return -1; } /* The child process executes the pipe receiver program... */ if (pid == 0) { /* Log start of child process */ logmsg (_("HHCPR007I pipe receiver (pid=%d) starting for %4.4X\n"), getpid(), dev->devnum); /* Close the write end of the pipe */ close_pipe ( pipefd[1] ); /* Duplicate the read end of the pipe onto STDIN */ if (pipefd[0] != STDIN_FILENO) { rc = dup2 (pipefd[0], STDIN_FILENO); if (rc != STDIN_FILENO) { logmsg (_("HHCPR008E %4.4X dup2 error: %s\n"), dev->devnum, strerror(errno)); close_pipe ( pipefd[0] ); _exit(127); } } /* end if(pipefd[0] != STDIN_FILENO) */ /* Close the original descriptor now duplicated to STDIN */ close_pipe ( pipefd[0] ); /* Redirect stderr (screen) to hercules log task */ dup2(STDOUT_FILENO, STDERR_FILENO); /* Relinquish any ROOT authority before calling shell */ SETMODE(TERM); /* Execute the specified pipe receiver program */ rc = system (dev->filename+1); if (rc == 0) { /* Log end of child process */ logmsg (_("HHCPR011I pipe receiver (pid=%d) terminating for %4.4X\n"), getpid(), dev->devnum); } else { /* Log error */ logmsg (_("HHCPR012E %4.4X Unable to execute %s: %s\n"), dev->devnum, dev->filename+1, strerror(errno)); } /* The child process terminates using _exit instead of exit to avoid invoking the panel atexit cleanup routine */ _exit(rc); } /* end if(pid==0) */ /* The parent process continues as the pipe sender */ /* Close the read end of the pipe */ close_pipe ( pipefd[0] ); /* Save pipe write descriptor in the device block */ dev->fd = pipefd[1]; dev->ptpcpid = pid; #endif /* defined( _MSVC_ ) */ return 0; } /* end function open_printer */ /*-------------------------------------------------------------------*/ /* Subroutine to write data to the printer */ /*-------------------------------------------------------------------*/ static void write_buffer (DEVBLK *dev, char *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Write data to the printer file */ if (dev->bs) { /* (socket printer) */ rc = write_socket (dev->fd, buf, len); /* Check for socket error */ if (rc < len) { /* Close the connection */ if (dev->fd != -1) { int fd = dev->fd; dev->fd = -1; close_socket( fd ); logmsg (_("HHCPR017I %s (%s) disconnected from device %4.4X (%s)\n"), dev->bs->clientname, dev->bs->clientip, dev->devnum, dev->bs->spec); } /* Set unit check with intervention required */ dev->sense[0] = SENSE_IR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } } else { /* Write data to the printer file */ rc = write (dev->fd, buf, len); /* Equipment check if error writing to printer file */ if (rc < len) { logmsg (_("HHCPR003E %4.4X Error writing to %s: %s\n"), dev->devnum, dev->filename, (errno == 0 ? _("incomplete"): strerror(errno))); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; } } } /* end function write_buffer */ /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ static int printer_close_device ( DEVBLK *dev ) { int fd = dev->fd; if (fd == -1) return 0; dev->fd = -1; dev->stopprt = 0; /* Close the device file */ if ( dev->ispiped ) { #if !defined( _MSVC_ ) close_pipe (fd); #else /* defined( _MSVC_ ) */ close (fd); /* Log end of child process */ logmsg (_("HHCPR011I pipe receiver (pid=%d) terminating for %4.4X\n"), dev->ptpcpid, dev->devnum); #endif /* defined( _MSVC_ ) */ dev->ptpcpid = 0; } else { if (dev->bs) { /* Socket printer */ close_socket (fd); logmsg (_("HHCPR018I %s (%s) disconnected from device %4.4X (%s)\n"), dev->bs->clientname, dev->bs->clientip, dev->devnum, dev->bs->spec); } else { /* Regular printer */ close (fd); } } return 0; } /* end function printer_close_device */ /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ static void printer_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual) { int rc = 0; /* Return code */ int i; /* Loop counter */ int num; /* Number of bytes to move */ char *eor; /* -> end of record string */ char *nls = "\n\n\n"; /* -> new lines */ BYTE c; /* Print character */ char hex[3]; /* for hex conversion */ char wbuf[150]; /* Reset flags at start of CCW chain */ if (chained == 0) { dev->diaggate = 0; } /* Open the device file if necessary */ if (dev->fd < 0 && !IS_CCW_SENSE(code)) rc = open_printer (dev); else { /* If printer stopped, return intervention required */ if (dev->stopprt && !IS_CCW_SENSE(code)) rc = -1; else rc = 0; } if (rc < 0) { /* Set unit check with intervention required */ dev->sense[0] = SENSE_IR; *unitstat = CSW_UC; return; } /* Process depending on CCW opcode */ switch (code) { case 0x01: /* Write No Space */ case 0x09: /* Write and Space 1 Line */ case 0x11: /* Write and Space 2 Lines */ case 0x19: /* Write and Space 3 Lines */ case 0x89: /* Write and Skip to Channel 1 */ case 0x91: /* Write and Skip to Channel 2 */ case 0x99: /* Write and Skip to Channel 3 */ case 0xA1: /* Write and Skip to Channel 4 */ case 0xA9: /* Write and Skip to Channel 5 */ case 0xB1: /* Write and Skip to Channel 6 */ case 0xB9: /* Write and Skip to Channel 7 */ case 0xC1: /* Write and Skip to Channel 8 */ case 0xC9: /* Write and Skip to Channel 9 */ case 0xD1: /* Write and Skip to Channel 10 */ case 0xD9: /* Write and Skip to Channel 11 */ case 0xE1: /* Write and Skip to Channel 12 */ if (dev->rawcc) { sprintf(hex,"%02x",code); write_buffer(dev, hex, 2, unitstat); if (*unitstat != 0) return; WRITE_LINE(); write_buffer(dev, "\n", 1, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } if ( dev->browse && dev->ccpend && ((chained & CCW_FLAGS_CD) == 0) ) { dev->ccpend = 0; /* dev->currline++; */ write_buffer(dev, "\n", 1, unitstat); if (*unitstat != 0) return; } WRITE_LINE(); if ((flags & CCW_FLAGS_CD) == 0) { if ( code <= 0x80 ) /* line control */ { coun = code / 8; if ( coun == 0 ) { dev->chskip = 1; if ( dev->browse ) { dev->ccpend = 1; *unitstat = 0; } else write_buffer(dev, "\r", 1, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } dev->ccpend = 0; dev->currline += coun; write_buffer(dev, nls, coun, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } else /*code > 0x80*/ /* chan control */ { /* if ( dev->browse ) { dev->currline++; write_buffer(dev, "\n", 1, unitstat); if (*unitstat != 0) return; } */ chan = ( code - 128 ) / 8; if ( chan == 1 ) { write_buffer(dev, "\r", 1, unitstat); if (*unitstat != 0) return; } SKIP_TO_CHAN(); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } } *unitstat = CSW_CE | CSW_DE; return; case 0x03: /* No Operation */ *unitstat = CSW_CE | CSW_DE; break; case 0x0B: /* Space 1 Line */ case 0x13: /* Space 2 Lines */ case 0x1B: /* Space 3 Lines */ case 0x8B: /* Skip to Channel 1 */ case 0x93: /* Skip to Channel 2 */ case 0x9B: /* Skip to Channel 3 */ case 0xA3: /* Skip to Channel 4 */ case 0xAB: /* Skip to Channel 5 */ case 0xB3: /* Skip to Channel 6 */ case 0xBB: /* Skip to Channel 7 */ case 0xC3: /* Skip to Channel 8 */ case 0xCB: /* Skip to Channel 9 */ case 0xD3: /* Skip to Channel 10 */ case 0xDB: /* Skip to Channel 11 */ case 0xE3: /* Skip to Channel 12 */ if (dev->rawcc) { sprintf(hex,"%02x",code); write_buffer(dev, hex, 2, unitstat); if (*unitstat != 0) return; eor = (dev->crlf) ? "\r\n" : "\n"; write_buffer(dev, eor, strlen(eor), unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } if ( code <= 0x80 ) /* line control */ { coun = code / 8; dev->ccpend = 0; dev->currline += coun; write_buffer(dev, nls, coun, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } else /*code > 0x80*/ /* chan control */ { /* if ( dev->browse && dev->ccpend) { coun = 1; dev->ccpend = 0; dev->currline += coun; write_buffer(dev, nls, coun, unitstat); if (*unitstat != 0) return; } */ chan = ( code - 128 ) / 8; SKIP_TO_CHAN(); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } break; case 0x63: /*---------------------------------------------------------------*/ /* LOAD FORMS CONTROL BUFFER */ /*---------------------------------------------------------------*/ if (dev->rawcc) { sprintf(hex,"%02x",code); write_buffer(dev, hex, 2, unitstat); if (*unitstat != 0) return; for (i = 0; i < count; i++) { sprintf(hex,"%02x",iobuf[i]); dev->buf[i*2] = hex[0]; dev->buf[i*2+1] = hex[1]; } /* end for(i) */ write_buffer(dev, (char *)dev->buf, i*2, unitstat); if (*unitstat != 0) return; eor = (dev->crlf) ? "\r\n" : "\n"; write_buffer(dev, eor, strlen(eor), unitstat); if (*unitstat != 0) return; } else { int i = 0; int j = 1; int more = 1; for (i = 0; i <= FCBSIZE; i++) dev->fcb[i] = 0; dev->lpi = 6; dev->index = 0; i = 0; if (iobuf[0] & 0xc0) { /* First byte is a print position index */ if ((iobuf[0] & 0xc0) == 0x80) /* Indexing right */ dev->index = iobuf[0] & 0x1f; else /* Indexing left */ dev->index = - (iobuf[0] & 0x1f); i = 1; } for (; i < count && j <= FCBSIZE && more; i++, j++) { dev->fcb[i] = iobuf[i] & 0x0f; if (dev->fcb[j] > 12) { *residual = count - i; *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->sense[0] = SENSE_CC; return; } if (iobuf[i] & 0x10) { /* Flag bit is on */ if (j == 1) /* Flag bit in first byte means eight lines per inch */ dev->lpi = 8; else more = 0; } } if (more) { /* No flag in last byte or too many bytes */ *residual = count - i; *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->sense[0] = SENSE_CC; return; } *residual = count - i; dev->lpp = j - 1; fcb_dump(dev, wbuf, 150); logmsg("HHCPN210I %d:%4.4X %s\n", SSID_TO_LCSS(dev->ssid), dev->devnum, wbuf); } /* Return normal status */ *residual = 0; *unitstat = CSW_CE | CSW_DE; break; case 0x06: /*---------------------------------------------------------------*/ /* DIAGNOSTIC CHECK READ */ /*---------------------------------------------------------------*/ /* If not 1403, reject if not preceded by DIAGNOSTIC GATE */ if (dev->devtype != 0x1403 && dev->diaggate == 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x07: /*---------------------------------------------------------------*/ /* DIAGNOSTIC GATE */ /*---------------------------------------------------------------*/ /* Command reject if 1403, or if chained to another CCW except a no-operation at the start of the CCW chain */ if (dev->devtype == 0x1403 || ccwseq > 1 || (chained && prevcode != 0x03)) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set diagnostic gate flag */ dev->diaggate = 1; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x0A: /*---------------------------------------------------------------*/ /* DIAGNOSTIC READ UCS BUFFER */ /*---------------------------------------------------------------*/ /* Reject if 1403 or not preceded by DIAGNOSTIC GATE */ if (dev->devtype == 0x1403 || dev->diaggate == 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x12: /*---------------------------------------------------------------*/ /* DIAGNOSTIC READ fcb */ /*---------------------------------------------------------------*/ /* Reject if 1403 or not preceded by DIAGNOSTIC GATE */ if (dev->devtype == 0x1403 || dev->diaggate == 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x23: /*---------------------------------------------------------------*/ /* UNFOLD */ /*---------------------------------------------------------------*/ dev->fold = 0; *unitstat = CSW_CE | CSW_DE; break; case 0x43: /*---------------------------------------------------------------*/ /* FOLD */ /*---------------------------------------------------------------*/ dev->fold = 1; *unitstat = CSW_CE | CSW_DE; break; case 0x73: /*---------------------------------------------------------------*/ /* BLOCK DATA CHECK */ /*---------------------------------------------------------------*/ /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0x7B: /*---------------------------------------------------------------*/ /* ALLOW DATA CHECK */ /*---------------------------------------------------------------*/ /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0xEB: /*---------------------------------------------------------------*/ /* UCS GATE LOAD */ /*---------------------------------------------------------------*/ /* Command reject if not first command in chain */ if (chained != 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0xF3: /*---------------------------------------------------------------*/ /* LOAD UCS BUFFER AND FOLD */ /*---------------------------------------------------------------*/ /* For 1403, command reject if not chained to UCS GATE */ /* Also allow ALLOW DATA CHECK to get TSS/370 working */ /* -- JRM 11/28/2007 */ if (dev->devtype == 0x1403 && ((prevcode != 0xEB) && (prevcode != 0x7B))) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set fold indicator and return normal status */ dev->fold = 1; dev->chskip = 1; /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0xFB: /*---------------------------------------------------------------*/ /* LOAD UCS BUFFER (NO FOLD) */ /*---------------------------------------------------------------*/ /* For 1403, command reject if not chained to UCS GATE */ if (dev->devtype == 0x1403 && prevcode != 0xEB) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Reset fold indicator and return normal status */ dev->fold = 0; dev->chskip = 1; /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_UC; } /* end switch(code) */ } /* end function printer_execute_ccw */ #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND printer_device_hndinfo = { &printer_init_handler, /* Device Initialisation */ &printer_execute_ccw, /* Device CCW execute */ &printer_close_device, /* Device Close */ &printer_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ printer_immed_commands, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt1403_LTX_hdl_ddev #define hdl_depc hdt1403_LTX_hdl_depc #define hdl_reso hdt1403_LTX_hdl_reso #define hdl_init hdt1403_LTX_hdl_init #define hdl_fini hdt1403_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); } END_DEPENDENCY_SECTION HDL_DEVICE_SECTION; { HDL_DEVICE(1403, printer_device_hndinfo ); HDL_DEVICE(3211, printer_device_hndinfo ); } END_DEVICE_SECTION #endif hercules-3.12/sockdev.c0000664000175000017500000004170412564723224012013 00000000000000/* SOCKDEV.C (c) Copyright Malcolm Beattie, 2001 */ /* Hercules socket device support */ #include "hstdinc.h" #include "hercules.h" #include "opcode.h" #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) extern SYSBLK *psysblk; #define sysblk (*psysblk) #endif /*===================================================================*/ /* S o c k e t D e v i c e s ... */ /*===================================================================*/ // #define DEBUG_SOCKDEV #ifdef DEBUG_SOCKDEV #define logdebug logmsg #else #define logdebug 1 ? ((void)0) : logmsg #endif /*-------------------------------------------------------------------*/ /* Working storage */ /*-------------------------------------------------------------------*/ static int init_done = FALSE; static LIST_ENTRY bind_head; /* (bind_struct list anchor) */ static LOCK bind_lock; /* (lock for accessing list) */ /*-------------------------------------------------------------------*/ /* Initialization / termination functions... */ /*-------------------------------------------------------------------*/ static void init_sockdev ( void ); static void term_sockdev ( void* ); static void init_sockdev ( void ) { if (init_done) return; InitializeListHead( &bind_head ); initialize_lock( &bind_lock ); hdl_adsc( "term_sockdev", term_sockdev, NULL ); init_done = TRUE; } static void term_sockdev ( void* arg ) { UNREFERENCED( arg ); if (!init_done) init_sockdev(); SIGNAL_SOCKDEV_THREAD(); join_thread ( sysblk.socktid, NULL ); detach_thread ( sysblk.socktid ); } /*-------------------------------------------------------------------*/ /* unix_socket create and bind a Unix domain socket */ /*-------------------------------------------------------------------*/ int unix_socket (char* path) { #if !defined( HAVE_SYS_UN_H ) UNREFERENCED(path); logmsg (_("HHCSD024E This build does not support Unix domain sockets.\n") ); return -1; #else // defined( HAVE_SYS_UN_H ) struct sockaddr_un addr; int sd; logdebug ("unix_socket(%s)\n", path); if (strlen (path) > sizeof(addr.sun_path) - 1) { logmsg (_("HHCSD008E Socket pathname \"%s\" exceeds limit of %d\n"), path, (int) sizeof(addr.sun_path) - 1); return -1; } addr.sun_family = AF_UNIX; strcpy (addr.sun_path, path); /* guaranteed room by above check */ sd = socket (PF_UNIX, SOCK_STREAM, 0); if (sd == -1) { logmsg (_("HHCSD009E Error creating socket for %s: %s\n"), path, strerror(HSO_errno)); return -1; } unlink (path); fchmod (sd, 0700); if (0 || bind (sd, (struct sockaddr*) &addr, sizeof(addr)) == -1 || listen (sd, 0) == -1 ) { logmsg (_("HHCSD010E Failed to bind or listen on socket %s: %s\n"), path, strerror(HSO_errno)); return -1; } return sd; #endif // !defined( HAVE_SYS_UN_H ) } /*-------------------------------------------------------------------*/ /* inet_socket create and bind a regular TCP/IP socket */ /*-------------------------------------------------------------------*/ int inet_socket (char* spec) { /* We need a copy of the path to overwrite a ':' with '\0' */ char buf[sizeof(((DEVBLK*)0)->filename)]; char* colon; char* node; char* service; int sd; int one = 1; struct sockaddr_in sin; logdebug("inet_socket(%s)\n", spec); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; strcpy(buf, spec); colon = strchr(buf, ':'); if (colon) { *colon = '\0'; node = buf; service = colon + 1; } else { node = NULL; service = buf; } if (!node) sin.sin_addr.s_addr = INADDR_ANY; else { struct hostent* he = gethostbyname(node); if (!he) { logmsg (_("HHCSD011E Failed to determine IP address from %s\n"), node); return -1; } memcpy(&sin.sin_addr, he->h_addr_list[0], sizeof(sin.sin_addr)); } if (isdigit(service[0])) { sin.sin_port = htons(atoi(service)); } else { struct servent* se = getservbyname(service, "tcp"); if (!se) { logmsg (_("HHCSD012E Failed to determine port number from %s\n"), service); return -1; } sin.sin_port = se->s_port; } sd = socket (PF_INET, SOCK_STREAM, 0); if (sd == -1) { logmsg (_("HHCSD013E Error creating socket for %s: %s\n"), spec, strerror(HSO_errno)); return -1; } setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (GETSET_SOCKOPT_T*)&one, sizeof(one)); if (0 || bind (sd, (struct sockaddr*) &sin, sizeof(sin)) == -1 || listen (sd, 0) == -1 ) { logmsg (_("HHCSD014E Failed to bind or listen on socket %s: %s\n"), spec, strerror(HSO_errno)); return -1; } return sd; } /*-------------------------------------------------------------------*/ /* add_socket_devices_to_fd_set add all bound socket devices' */ /* listening sockets to the FD_SET */ /*-------------------------------------------------------------------*/ int add_socket_devices_to_fd_set (int maxfd, fd_set* readset) { DEVBLK* dev; bind_struct* bs; LIST_ENTRY* pListEntry; obtain_lock(&bind_lock); pListEntry = bind_head.Flink; while (pListEntry != &bind_head) { bs = CONTAINING_RECORD(pListEntry,bind_struct,bind_link); if (bs->sd != -1) /* if listening for connections, */ { dev = bs->dev; FD_SET(bs->sd, readset); /* then add file to set */ if (bs->sd > maxfd) maxfd = bs->sd; } pListEntry = pListEntry->Flink; } release_lock(&bind_lock); return maxfd; } /*-------------------------------------------------------------------*/ /* socket_device_connection_handler */ /*-------------------------------------------------------------------*/ void socket_device_connection_handler (bind_struct* bs) { struct sockaddr_in client; /* Client address structure */ struct hostent* pHE; /* Addr of hostent structure */ socklen_t namelen; /* Length of client structure*/ char* clientip; /* Addr of client ip address */ char* clientname; /* Addr of client hostname */ DEVBLK* dev; /* Device Block pointer */ int csock; /* Client socket */ dev = bs->dev; logdebug("socket_device_connection_handler(dev=%4.4X)\n", dev->devnum); /* Accept the connection... */ csock = accept(bs->sd, 0, 0); if (csock == -1) { logmsg (_("HHCSD017E Connect to device %4.4X (%s) failed: %s\n"), dev->devnum, bs->spec, strerror(HSO_errno)); return; } /* Determine the connected client's IP address and hostname */ namelen = sizeof(client); clientip = NULL; clientname = ""; if (1 && getpeername(csock, (struct sockaddr*) &client, &namelen) == 0 && (clientip = inet_ntoa(client.sin_addr)) != NULL && (pHE = gethostbyaddr((unsigned char*)(&client.sin_addr), sizeof(client.sin_addr), AF_INET)) != NULL && pHE->h_name && *pHE->h_name ) { clientname = (char*) pHE->h_name; } if (!clientip) clientip = ""; /* Obtain the device lock */ obtain_lock (&dev->lock); /* Reject if device is busy or interrupt pending */ if (dev->busy || IOPENDING(dev) || (dev->scsw.flag3 & SCSW3_SC_PEND)) { close_socket( csock ); logmsg (_("HHCSD015E Client %s (%s) connection to device %4.4X " "(%s) rejected: device busy or interrupt pending\n"), clientname, clientip, dev->devnum, bs->spec); release_lock (&dev->lock); return; } /* Reject new client if previous client still connected */ if (dev->fd != -1) { close_socket( csock ); logmsg (_("HHCSD016E Client %s (%s) connection to device %4.4X " "(%s) rejected: client %s (%s) still connected\n"), clientname, clientip, dev->devnum, bs->spec, bs->clientname, bs->clientip); release_lock (&dev->lock); return; } /* Indicate that a client is now connected to this device */ dev->fd = csock; if (bs->clientip) free(bs->clientip); if (bs->clientname) free(bs->clientname); bs->clientip = strdup(clientip); bs->clientname = strdup(clientname); /* Call the boolean onconnect callback */ if (bs->fn && !bs->fn( bs->arg )) { /* Callback says it can't accept it */ close_socket( dev->fd ); dev->fd = -1; logmsg (_("HHCSD026E Client %s (%s) connection to device %4.4X " "(%s) rejected: by onconnect callback\n"), clientname, clientip, dev->devnum, bs->spec); release_lock (&dev->lock); return; } logmsg (_("HHCSD018I Client %s (%s) connected to device %4.4X (%s)\n"), clientname, clientip, dev->devnum, bs->spec); release_lock (&dev->lock); device_attention (dev, CSW_DE); } /*-------------------------------------------------------------------*/ /* check_socket_devices_for_connections */ /*-------------------------------------------------------------------*/ void check_socket_devices_for_connections (fd_set* readset) { bind_struct* bs; LIST_ENTRY* pListEntry; obtain_lock(&bind_lock); pListEntry = bind_head.Flink; while (pListEntry != &bind_head) { bs = CONTAINING_RECORD(pListEntry,bind_struct,bind_link); if (bs->sd != -1 && FD_ISSET(bs->sd, readset)) { /* Note: there may be other connection requests * waiting to be serviced, but we'll catch them * the next time the panel thread calls us. */ release_lock(&bind_lock); socket_device_connection_handler(bs); return; } pListEntry = pListEntry->Flink; } release_lock(&bind_lock); } /*-------------------------------------------------------------------*/ /* socket_thread listen for socket device connections */ /*-------------------------------------------------------------------*/ void* socket_thread( void* arg ) { int rc; fd_set sockset; int maxfd = 0; int select_errno; int exit_now; UNREFERENCED( arg ); /* Display thread started message on control panel */ logmsg (_("HHCSD020I Socketdevice listener thread started: " "tid="TIDPAT", pid=%d\n"), thread_id(), getpid()); for (;;) { /* Set the file descriptors for select */ FD_ZERO ( &sockset ); maxfd = add_socket_devices_to_fd_set ( 0, &sockset ); SUPPORT_WAKEUP_SOCKDEV_SELECT_VIA_PIPE( maxfd, &sockset ); /* Do the select and save results */ rc = select ( maxfd+1, &sockset, NULL, NULL, NULL ); select_errno = HSO_errno; /* Clear the pipe signal if necessary */ RECV_SOCKDEV_THREAD_PIPE_SIGNAL(); /* Check if it's time to exit yet */ obtain_lock( &bind_lock ); exit_now = ( sysblk.shutdown || IsListEmpty( &bind_head ) ); release_lock( &bind_lock ); if ( exit_now ) break; /* Log select errors */ if ( rc < 0 ) { if ( HSO_EINTR != select_errno ) logmsg( _( "HHCSD021E select failed; errno=%d: %s\n"), select_errno, strerror( select_errno ) ); continue; } /* Check if any sockets have received new connections */ check_socket_devices_for_connections( &sockset ); } logmsg( _( "HHCSD022I Socketdevice listener thread terminated\n" ) ); return NULL; } /* (end socket_thread) */ /*-------------------------------------------------------------------*/ /* bind_device bind a device to a socket (adds entry to our list */ /* of bound devices) (1=success, 0=failure) */ /*-------------------------------------------------------------------*/ int bind_device_ex (DEVBLK* dev, char* spec, ONCONNECT fn, void* arg ) { bind_struct* bs; int was_list_empty; if (!init_done) init_sockdev(); if (sysblk.shutdown) return 0; logdebug("bind_device (%4.4X, %s)\n", dev->devnum, spec); /* Error if device already bound */ if (dev->bs) { logmsg (_("HHCSD001E Device %4.4X already bound to socket %s\n"), dev->devnum, dev->bs->spec); return 0; /* (failure) */ } /* Create a new bind_struct entry */ bs = malloc(sizeof(bind_struct)); if (!bs) { logmsg (_("HHCSD002E bind_device malloc() failed for device %4.4X\n"), dev->devnum); return 0; /* (failure) */ } memset(bs,0,sizeof(bind_struct)); bs->fn = fn; bs->arg = arg; if (!(bs->spec = strdup(spec))) { logmsg (_("HHCSD003E bind_device strdup() failed for device %4.4X\n"), dev->devnum); free (bs); return 0; /* (failure) */ } /* Create a listening socket */ if (bs->spec[0] == '/') bs->sd = unix_socket (bs->spec); else bs->sd = inet_socket (bs->spec); if (bs->sd == -1) { /* (error message already issued) */ free( bs->spec ); free( bs ); return 0; /* (failure) */ } /* Chain device and bind_struct to each other */ dev->bs = bs; bs->dev = dev; /* Add the new entry to our list of bound devices and create the socket thread that will listen for connections (if it doesn't already exist) */ obtain_lock( &bind_lock ); was_list_empty = IsListEmpty( &bind_head ); InsertListTail( &bind_head, &bs->bind_link ); if ( was_list_empty ) { if ( create_thread( &sysblk.socktid, JOINABLE, socket_thread, NULL, "socket_thread" ) ) { logmsg( _( "HHCSD023E Cannot create socketdevice thread: errno=%d: %s\n" ), errno, strerror( errno ) ); RemoveListEntry( &bs->bind_link ); close_socket(bs->sd); free( bs->spec ); free( bs ); release_lock( &bind_lock ); return 0; /* (failure) */ } } SIGNAL_SOCKDEV_THREAD(); release_lock( &bind_lock ); logmsg (_("HHCSD004I Device %4.4X bound to socket %s\n"), dev->devnum, dev->bs->spec); return 1; /* (success) */ } /*-------------------------------------------------------------------*/ /* unbind_device unbind a device from a socket (removes entry from */ /* our list and discards it) (1=success, 0=failure) */ /*-------------------------------------------------------------------*/ int unbind_device_ex (DEVBLK* dev, int forced) { bind_struct* bs; logdebug("unbind_device(%4.4X)\n", dev->devnum); /* Error if device not bound */ if (!(bs = dev->bs)) { logmsg (_("HHCSD005E Device %4.4X not bound to any socket\n"), dev->devnum); return 0; /* (failure) */ } /* Is anyone still connected? */ if (dev->fd != -1) { /* Yes. Should we forcibly disconnect them? */ if (forced) { /* Yes. Then do so... */ close_socket( dev->fd ); dev->fd = -1; logmsg (_("HHCSD025I Client %s (%s) disconnected from device %4.4X (%s)\n"), dev->bs->clientip, dev->bs->clientname, dev->devnum, dev->bs->spec); } else { /* No. Then fail the request. */ logmsg (_("HHCSD006E Client %s (%s) still connected to device %4.4X (%s)\n"), dev->bs->clientip, dev->bs->clientname, dev->devnum, dev->bs->spec); return 0; /* (failure) */ } } /* Remove the entry from our list */ obtain_lock( &bind_lock ); RemoveListEntry( &bs->bind_link ); SIGNAL_SOCKDEV_THREAD(); release_lock( &bind_lock ); logmsg (_("HHCSD007I Device %4.4X unbound from socket %s\n"), dev->devnum, bs->spec); if (bs->sd != -1) close_socket (bs->sd); /* Unchain device and bind_struct from each another */ dev->bs = NULL; bs->dev = NULL; /* Discard the entry */ if ( bs->clientname ) free( bs->clientname ); if ( bs->clientip ) free( bs->clientip ); bs->clientname = NULL; bs->clientip = NULL; free ( bs->spec ); free ( bs ); return 1; /* (success) */ } hercules-3.12/commadpt.c0000664000175000017500000043355212564723224012167 00000000000000/* COMMADPT.C (c) Copyright Roger Bowler & Others, 2002-2011 */ /* (c) Copyright, MHP, 2007-2008 (see below) */ /* Hercules Communication Line Driver */ /*-------------------------------------------------------------------*/ /* Hercules Communication Line Driver */ /* (c) 1999-2006 Roger Bowler & Others */ /* Use of this program is governed by the QPL License */ /* Original Author : Ivan Warren */ /* Prime Maintainer : Ivan Warren */ /*-------------------------------------------------------------------*/ /* ******************************************************************** TTY Mode Additions (c) Copyright, 2007 MHP Feb. 2007- Add support for 2703 Telegraph Terminal Control Type II (for use with TTY ASR 33/35 or compatible terminals). To enable TTY mode for a particular port, specify ``LNCTL=ASYNC'' in the hercules conf file. The host sends and receives bytes directly in ASCII, but bits are reversed from standard ASCII bit order. Lookup tables are used to perform the reversals on each byte, to make even parity for sending toward the host, and to skip certain noxious characters emitted by TSO/TCAM. This code contains minimal TELNET support. It accepts TELNET IP (Interrupt Process) which is mapped and transmitted to the host as a BREAK (ATTN) sequence. All TELNET commands are responded negatively. ***************************************************************** 2741 Mode Additions (c) Copyright, 2008 MHP 2741 mode is now working, though imperfectly as of yet. There is a new param (term=tty|2741) in the conf file to select termtype. Specify code=ebcd for EBCD, or code=corr for correspondence code. Also code=none to disable all translation. The code= option applies to 2741 mode only. Another new param (skip=) is a byte string, specified in hex, to specify "garbage" code points that are to be suppressed in output processing. This allows distinct lists to be used for different terminal types. Automatic translation to Uppercase is enabled by setting uctrans=yes . This is for both 2741 and TTY terminals. You can specify lnctl=tele2 for TTY and lnctl=ibm1 for 2741. Samples: 0045 2703 lport=32003 dial=IN lnctl=ibm1 term=2741 skip=5EDE code=ebcd 0045 2703 lport=32003 dial=IN lnctl=tele2 uctrans=yes term=tty skip=88C9DF For TCAM, if you are zapping device UCB's, the following type values seem to work: 55 10 40 13 - 2741 51 10 40 53 - TTY (3335) When running TCAM in 2741 mode if you experience A00 abends, the following zap (to member IEDQTCAM in 'SYS1.LINKLIB') may help NAME IEDQTCAM IEDQKA01 VER 0E38 012C REP 0E38 0101 The 2741 mode enables ordinary remote ASCII TELNET clients to connect. The translate tables were lifted from IEDQ27 and IEDQ28. Instead of translating directly between ASCII and the host's 2741-correspondence code, we add an intermediate EBCDIC step. This enables use of all pre- existing tables so I don't have to code any new ones :) Also, 2740 OS consoles should work. It may be necessary to modify the driver to end READ CCWs even when no data has been received (see comment) ***************************************************************** Some TTY Fixes - 2012-01-30 MHP This async/2703 driver release contains several bug fixes and minor enhancements (primarily to fix windows telnet clients). In addition there are three new configuration parameters (iskip=, bs=dumb, break=dumb) When using windows telnet, it's recommended to set bs=dumb and break=dumb . The new iskip= option is analogous to the skip= option, except that it chooses input ASCII characters to suppress (the skip= option is used to suppress characters in output processing). Note that while both options are entered as hex bytes, the skip= option uses S/370 mainframe code points (either byte-reversed ASCII for TTY or correspondence code/EBCD for 2741), whereas the iskip= option requires ASCII code points. Here's an example: 0045 2703 lport=32003 dial=IN lnctl=tele2 uctrans=yes term=tty skip=88C9DF iskip=0A Here's an example, for windows telnet clients 0046 2703 lport=32003 dial=IN lnctl=tele2 uctrans=yes term=tty skip=88C9DF iskip=0A bs=dumb break=dumb ***************************************************************** driver mods for APL\360 December 2012 MHP - circumvention for several race conditions - new "eol" parameter specifies a byte value (ASCII), default 0x0D, which when received marks the end of the input line - new "prepend" and "append" parameters to specify zero to four bytes to be prepended and appended (respectively) to input lines that have been received from terminals before being sent to the mainframe OS. Typical use is to add Circle D and C around each input transmission (2741's for APL\360). Bytes must be specified in S/370 channel format, not in ASCII. - new terminal type "rxvt4apl" with 8-bit and character translation support for rxvt4apl in 2741 mode. Use the following conf definition entry 0402 2703 dial=in lport=57413 lnctl=ibm1 term=rxvt4apl skip=5EDE code=ebcd iskip=0D0A prepend=16 append=5B1F eol=0A binary=yes crlf=yes sendcr=yes [all on a single line] - negotiation to telnet binary mode when using rxvt4apl ("binary" parameter) - send CR back to terminal when input line received ("sendcr" parameter) - option to map 2741 NL to TTY CRLF sequence ("crlf" parameter) - increase Hercules MAX_ARGS ******************************************************************** */ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "parser.h" #include "commadpt.h" #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) SYSBLK *psysblk; #define sysblk (*psysblk) #endif /*-------------------------------------------------------------------*/ /* Ivan Warren 20040227 */ /* This table is used by channel.c to determine if a CCW code is an */ /* immediate command or not */ /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */ /* 0 : Command is NOT an immediate command */ /* 1 : Command is an immediate command */ /* Note : An immediate command is defined as a command which returns */ /* CE (channel end) during initialisation (that is, no data is */ /* actually transfered. In this case, IL is not indicated for a CCW */ /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */ /* effect */ /*-------------------------------------------------------------------*/ static BYTE commadpt_immed_command[256]= { 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; COMMADPT_PEND_TEXT; /* Defined in commadpt.h */ /* Defines commadpt_pendccw_text array */ /*---------------------------------------------------------------*/ /* PARSER TABLES */ /*---------------------------------------------------------------*/ static PARSER ptab[]={ {"lport","%s"}, {"lhost","%s"}, {"rport","%s"}, {"rhost","%s"}, {"dial","%s"}, {"rto","%s"}, {"pto","%s"}, {"eto","%s"}, {"switched","%s"}, {"lnctl","%s"}, {"term","%s"}, {"code","%s"}, {"uctrans","%s"}, {"skip","%s"}, {"iskip","%s"}, {"bs","%s"}, {"break","%s"}, {"prepend","%s"}, {"append","%s"}, {"eol","%s"}, {"crlf","%s"}, {"sendcr","%s"}, {"binary","%s"}, {NULL,NULL} }; enum { COMMADPT_KW_LPORT=1, COMMADPT_KW_LHOST, COMMADPT_KW_RPORT, COMMADPT_KW_RHOST, COMMADPT_KW_DIAL, COMMADPT_KW_READTO, COMMADPT_KW_POLLTO, COMMADPT_KW_ENABLETO, COMMADPT_KW_SWITCHED, COMMADPT_KW_LNCTL, COMMADPT_KW_TERM, COMMADPT_KW_CODE, COMMADPT_KW_UCTRANS, COMMADPT_KW_SKIP, COMMADPT_KW_ISKIP, COMMADPT_KW_BS, COMMADPT_KW_BREAK, COMMADPT_KW_PREPEND, COMMADPT_KW_APPEND, COMMADPT_KW_EOL, COMMADPT_KW_CRLF, COMMADPT_KW_SENDCR, COMMADPT_KW_BINARY, } commadpt_kw; static BYTE byte_reverse_table[256] = { 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF }; static BYTE telnet_binary[6] = { 0xff, 0xfd, 0x00, 0xff, 0xfb, 0x00 }; BYTE overstrike_2741_pairs[] = { 0x93, 0xA6, /* nor */ 0xC9, 0xCC, /* rotate */ 0xCC, 0xCF, /* log */ 0xC9, 0xEE, /* grade down */ 0xC3, 0xE7, /* lamp */ 0xC5, 0xC6, /* quote quad */ 0x93, 0xA6, /* nand */ 0xA3, 0xCC, /* transpose */ 0xA6, 0xEE, /* locked fn */ 0xC9, 0xF0, /* grade up */ 0x76, 0xC5, /* exclamation */ 0xCA, 0xE4, /* ibeam */ 0xC6, 0xE1, /* domino */ }; BYTE overstrike_rxvt4apl_chars[] = { /* must match overstrike_2741_pairs */ 0xe5, 0xe8, 0x89, 0x9d, 0xa6, 0x97, 0xea, 0xed, 0xa1, /* locked fn - no exact match for this */ 0x93, 0x21, 0x84, 0x98, }; static BYTE overstrike_map [256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static BYTE rxvt4apl_from_2741[256] = { 0x3f, 0x20, 0x31, 0x3f, 0x32, 0x3f, 0x3f, 0x33, 0x34, 0x3f, 0x3f, 0x35, 0x3f, 0x36, 0x37, 0x3f, 0x38, 0x3f, 0x3f, 0x39, 0x3f, 0x30, 0x5d, 0x3f, 0x3f, 0x3f, 0x95, 0x3f, 0x96, 0x3f, 0x3f, 0x04, 0x90, 0x3f, 0x3f, 0x2f, 0x3f, 0x53, 0x54, 0x3f, 0x3f, 0x55, 0x56, 0x3f, 0x57, 0x3f, 0x3f, 0x58, 0x3f, 0x59, 0x5a, 0x3f, 0x3f, 0x3f, 0x3f, 0x2c, 0x84, 0x3f, 0x3f, 0x0a, 0x3f, 0x17, 0x1b, 0x3f, 0x2b, 0x3f, 0x3f, 0x4a, 0x3f, 0x4b, 0x4c, 0x3f, 0x3f, 0x4d, 0x4e, 0x3f, 0x4f, 0x3f, 0x3f, 0x50, 0x3f, 0x51, 0x52, 0x3f, 0x3f, 0x3f, 0x3f, 0x5b, 0x9d, 0x3f, 0x3f, 0x0d, 0x3f, 0x08, 0x87, 0x3f, 0x3f, 0x92, 0x41, 0x3f, 0x42, 0x3f, 0x3f, 0x43, 0x44, 0x3f, 0x3f, 0x45, 0x3f, 0x46, 0x47, 0x3f, 0x48, 0x3f, 0x3f, 0x49, 0x3f, 0x3f, 0x2e, 0x3f, 0x3f, 0x3f, 0x09, 0x3f, 0x86, 0x3f, 0x3f, 0x7f, 0x3f, 0x20, 0x9a, 0x3f, 0xfd, 0x3f, 0x3f, 0x3c, 0xf3, 0x3f, 0x3f, 0x3d, 0x3f, 0xf2, 0x3e, 0x3f, 0x86, 0x3f, 0x3f, 0xfa, 0x3f, 0x5e, 0x29, 0x3f, 0x3f, 0x3f, 0x95, 0x3f, 0x96, 0x3f, 0x3f, 0x3f, 0x85, 0x3f, 0x3f, 0x5c, 0x3f, 0x8d, 0x7e, 0x3f, 0x3f, 0x8b, 0xfc, 0x3f, 0xf7, 0x3f, 0x3f, 0x83, 0x3f, 0x8c, 0x82, 0x3f, 0x3f, 0x3f, 0x3f, 0x3b, 0x84, 0x3f, 0x3f, 0x0a, 0x3f, 0x17, 0x1b, 0x3f, 0x2d, 0x3f, 0x3f, 0xf8, 0x3f, 0x27, 0x95, 0x3f, 0x3f, 0x7c, 0xe7, 0x3f, 0xf9, 0x3f, 0x3f, 0x2a, 0x3f, 0x3f, 0xfb, 0x3f, 0x3f, 0x3f, 0x3f, 0x28, 0x9d, 0x3f, 0x3f, 0x0d, 0x3f, 0x08, 0x87, 0x3f, 0x3f, 0xf6, 0xe0, 0x3f, 0xe6, 0x3f, 0x3f, 0xef, 0x8f, 0x3f, 0x3f, 0xee, 0x3f, 0x5f, 0xec, 0x3f, 0x91, 0x3f, 0x3f, 0xe2, 0x3f, 0x3f, 0x3a, 0x3f, 0x3f, 0x3f, 0x09, 0x3f, 0x86, 0x3f, 0x3f, 0x7f, }; static BYTE rxvt4apl_to_2741[256] = { 0x88, 0x88, 0x88, 0x88, 0x1f, 0x88, 0x88, 0x88, 0x5d, 0x7a, 0x3b, 0x88, 0x88, 0x5b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x5e, 0x88, 0x88, 0x88, 0x88, 0x3e, 0x88, 0x88, 0x88, 0x88, 0x01, 0xb7, 0x96, 0x16, 0x57, 0x8b, 0x61, 0xc5, 0xd7, 0x96, 0xcf, 0x40, 0x37, 0xc0, 0x76, 0x23, 0x15, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e, 0x10, 0x13, 0xf6, 0xb7, 0x87, 0x8b, 0x8e, 0xd1, 0x20, 0xe2, 0xe4, 0xe7, 0xe8, 0xeb, 0xed, 0xee, 0xf0, 0xf3, 0xc3, 0xc5, 0xc6, 0xc9, 0xca, 0xcc, 0xcf, 0xd1, 0xd2, 0xa5, 0xa6, 0xa9, 0xaa, 0xac, 0xaf, 0xb1, 0xb2, 0x57, 0xa3, 0x16, 0x95, 0xed, 0x88, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e, 0x70, 0x73, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c, 0x4f, 0x51, 0x52, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f, 0x31, 0x32, 0x88, 0xc9, 0x88, 0xa6, 0x88, 0x88, 0x88, 0xb2, 0xaf, 0x88, 0xa0, 0x90, 0x88, 0x88, 0x88, 0x88, 0xa9, 0xb1, 0xa5, 0x88, 0xe8, 0x20, 0xf0, 0x61, 0x88, 0x88, 0xc6, 0x88, 0x88, 0x88, 0x88, 0x82, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe2, 0x88, 0xf3, 0x88, 0x88, 0x88, 0xe4, 0xca, 0x88, 0x88, 0x88, 0x88, 0xee, 0x88, 0xeb, 0xe7, 0x88, 0x88, 0x8d, 0x88, 0x88, 0x88, 0xe1, 0xac, 0xc3, 0xcc, 0x93, 0xd2, 0xaa, 0x84, 0x88, 0x88, }; /* 2741 EBCD code tables */ /* directly copied from mvs src file iedq27 */ static BYTE xlate_table_ebcd_toebcdic[256] = { 0x3F, 0x40, 0xF1, 0x3F, 0xF2, 0x3F, 0x3F, 0xF3, 0xF4, 0x3F, 0x3F, 0xF5, 0x3F, 0xF6, 0xF7, 0x3F, 0xF8, 0x3F, 0x3F, 0xF9, 0x3F, 0xF0, 0x7B, 0x3F, 0x3F, 0x3F, 0x35, 0x3F, 0x36, 0x3F, 0x3F, 0x37, 0x7C, 0x3F, 0x3F, 0x61, 0x3F, 0xA2, 0xA3, 0x3F, 0x3F, 0xA4, 0xA5, 0x3F, 0xA6, 0x3F, 0x3F, 0xA7, 0x3F, 0xA8, 0xA9, 0x3F, 0x3F, 0x3F, 0x3F, 0x6B, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x26, 0x27, 0x3F, 0x60, 0x3F, 0x3F, 0x91, 0x3F, 0x92, 0x93, 0x3F, 0x3F, 0x94, 0x95, 0x3F, 0x96, 0x3F, 0x3F, 0x97, 0x3F, 0x98, 0x99, 0x3F, 0x3F, 0x3F, 0x3F, 0x5B, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x17, 0x3F, 0x3F, 0x50, 0x81, 0x3F, 0x82, 0x3F, 0x3F, 0x83, 0x84, 0x3F, 0x3F, 0x85, 0x3F, 0x86, 0x87, 0x3F, 0x88, 0x3F, 0x3F, 0x89, 0x3F, 0x3F, 0x4B, 0x3F, 0x3F, 0x3F, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x07, 0x3F, 0x40, 0x7E, 0x3F, 0x4C, 0x3F, 0x3F, 0x5E, 0x7A, 0x3F, 0x3F, 0x6C, 0x3F, 0x7D, 0x6E, 0x3F, 0x5C, 0x3F, 0x3F, 0x4D, 0x3F, 0x5D, 0x7F, 0x3F, 0x3F, 0x3F, 0x35, 0x3F, 0x36, 0x3F, 0x3F, 0x3F, 0x4A, 0x3F, 0x3F, 0x6F, 0x3F, 0xE2, 0xE3, 0x3F, 0x3F, 0xE4, 0xE5, 0x3F, 0xE6, 0x3F, 0x3F, 0xE7, 0x3F, 0xE8, 0xE9, 0x3F, 0x3F, 0x3F, 0x3F, 0x4F, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x26, 0x27, 0x3F, 0x6D, 0x3F, 0x3F, 0xD1, 0x3F, 0xD2, 0xD3, 0x3F, 0x3F, 0xD4, 0xD5, 0x3F, 0xD6, 0x3F, 0x3F, 0xD7, 0x3F, 0xD8, 0xD9, 0x3F, 0x3F, 0x3F, 0x3F, 0x5A, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x17, 0x3F, 0x3F, 0x4E, 0xC1, 0x3F, 0xC2, 0x3F, 0x3F, 0xC3, 0xC4, 0x3F, 0x3F, 0xC5, 0x3F, 0xC6, 0xC7, 0x3F, 0xC8, 0x3F, 0x3F, 0xC9, 0x3F, 0x3F, 0x5F, 0x3F, 0x3F, 0x3F, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x07 }; static BYTE xlate_table_ebcd_fromebcdic[256] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x7A, 0x7C, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x5B, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x58, 0x5B, 0x5D, 0x5E, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x38, 0x3B, 0x88, 0x3E, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x5E, 0x88, 0x88, 0x88, 0x1C, 0x1F, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x01, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xA0, 0x76, 0x84, 0x93, 0xE1, 0xB7, 0x61, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xD7, 0x57, 0x90, 0x95, 0x87, 0xF6, 0x40, 0x23, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x37, 0x8B, 0xC0, 0x8E, 0xA3, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x16, 0x20, 0x8D, 0x82, 0x96, 0x88, 0x62, 0x64, 0x67, 0x68, 0x6B, 0x6D, 0x6E, 0x70, 0x73, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x43, 0x45, 0x46, 0x49, 0x4A, 0x4C, 0x4F, 0x51, 0x52, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x25, 0x26, 0x29, 0x2A, 0x2C, 0x2F, 0x31, 0x32, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xE2, 0xE4, 0xE7, 0xE8, 0xEB, 0xED, 0xEE, 0xF0, 0xF3, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xC3, 0xC5, 0xC6, 0xC9, 0xCA, 0xCC, 0xCF, 0xD1, 0xD2, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xA5, 0xA6, 0xA9, 0xAA, 0xAC, 0xAF, 0xB1, 0xB2, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x15, 0x02, 0x04, 0x07, 0x08, 0x0B, 0x0D, 0x0E, 0x10, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }; /* 2741 correspondence code tables */ /* directly copied from mvs src file iedq28 */ static BYTE xlate_table_cc_toebcdic[256] = { 0x3F, 0x40, 0xF1, 0x3F, 0xF2, 0x3F, 0x3F, 0xF3, 0xF5, 0x3F, 0x3F, 0xF7, 0x3F, 0xF6, 0xF8, 0x3F, 0xF4, 0x3F, 0x3F, 0xF0, 0x3F, 0xA9, 0xF9, 0x3F, 0x3F, 0x34, 0x35, 0x3F, 0x36, 0x3F, 0x3F, 0x37, 0xA3, 0x3F, 0x3F, 0xA7, 0x3F, 0x95, 0xA4, 0x3F, 0x3F, 0x85, 0x84, 0x3F, 0x92, 0x3F, 0x3F, 0x83, 0x3F, 0x93, 0x88, 0x3F, 0x3F, 0x3F, 0x3F, 0x82, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x26, 0x27, 0x3F, 0x5A, 0x3F, 0x3F, 0x94, 0x3F, 0x4B, 0xA5, 0x3F, 0x3F, 0x7D, 0x99, 0x3F, 0x89, 0x3F, 0x3F, 0x81, 0x3F, 0x96, 0xA2, 0x3F, 0x3F, 0x3F, 0x3F, 0xA6, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x17, 0x3F, 0x3F, 0x91, 0x87, 0x3F, 0x7E, 0x3F, 0x3F, 0x86, 0x97, 0x3F, 0x3F, 0x5E, 0x3F, 0x98, 0x6B, 0x3F, 0x61, 0x3F, 0x3F, 0xA8, 0x3F, 0x3F, 0x60, 0x3F, 0x3F, 0x04, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x07, 0x3F, 0x40, 0x4F, 0x3F, 0x7C, 0x3F, 0x3F, 0x7B, 0x6C, 0x3F, 0x3F, 0x50, 0x3F, 0x4C, 0x5C, 0x3F, 0x5B, 0x3F, 0x3F, 0x5D, 0x3F, 0xE9, 0x4D, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x36, 0x3F, 0x3F, 0x37, 0xE3, 0x3F, 0x3F, 0xE7, 0x3F, 0xD5, 0xE4, 0x3F, 0x3F, 0xC5, 0xC4, 0x3F, 0xD2, 0x3F, 0x3F, 0xC3, 0x3F, 0xD3, 0xC8, 0x3F, 0x3F, 0x3F, 0x3F, 0xC2, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x3F, 0x27, 0x3F, 0x6E, 0x3F, 0x3F, 0xD4, 0x3F, 0x4B, 0xE5, 0x3F, 0x3F, 0x7F, 0xD9, 0x3F, 0xC9, 0x3F, 0x3F, 0xC1, 0x3F, 0xD6, 0xE2, 0x3F, 0x3F, 0x3F, 0x3F, 0xE6, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x3F, 0x3F, 0x3F, 0xD1, 0xC7, 0x3F, 0x4E, 0x3F, 0x3F, 0xC6, 0xD7, 0x3F, 0x3F, 0x7A, 0x3F, 0xD8, 0x6B, 0x3F, 0x6F, 0x3F, 0x3F, 0xE8, 0x3F, 0x3F, 0x6D, 0x3F, 0x3F, 0x3F, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x3F, }; static BYTE xlate_table_cc_fromebcdic[256] = { 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x7A, 0x7C, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x5B, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x58, 0x5B, 0x5D, 0x5E, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x38, 0x3B, 0xEB, 0x3E, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x5E, 0xEB, 0x19, 0x1A, 0x1C, 0x1F, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x01, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x45, 0x8D, 0x96, 0xE4, 0x82, 0x8B, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x40, 0x90, 0x8E, 0x93, 0x6B, 0xEB, 0x76, 0x70, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x6E, 0x88, 0xF6, 0xC0, 0xF0, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x87, 0x84, 0x49, 0x64, 0xC9, 0xEB, 0x4F, 0x37, 0x2F, 0x2A, 0x29, 0x67, 0x62, 0x32, 0x4C, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x61, 0x2C, 0x31, 0x43, 0x25, 0x51, 0x68, 0x6D, 0x4A, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x52, 0x20, 0x26, 0x46, 0x57, 0x23, 0x73, 0x15, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xCF, 0xB7, 0xAF, 0xAA, 0xA9, 0xE7, 0xE2, 0xB2, 0xCC, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xE1, 0xAC, 0xB1, 0xC3, 0xA5, 0xD1, 0xE8, 0xED, 0xCA, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xD2, 0xA0, 0xA6, 0xC6, 0xD7, 0xA3, 0xF3, 0x95, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x13, 0x02, 0x04, 0x07, 0x10, 0x08, 0x0D, 0x0B, 0x0E, 0x16, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, }; #define CIRCLE_C 0x1F #define CIRCLE_D 0x16 static BYTE byte_parity_table [128] = { /* value: 0 = even parity, 1 = odd parity */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; static void logdump(char *txt,DEVBLK *dev,BYTE *bfr,size_t sz) { size_t i; if ( !dev->ccwtrace ) { return; } logmsg(_("HHCCA300D %4.4X:%s : Status = TEXT=%s, TRANS=%s, TWS=%s\n"), dev->devnum, txt, dev->commadpt->in_textmode?"YES":"NO", dev->commadpt->in_xparmode?"YES":"NO", dev->commadpt->xparwwait?"YES":"NO"); logmsg(_("HHCCA300D %4.4X:%s : Dump of %d (%x) byte(s)\n"),dev->devnum,txt,sz,sz); for( i=0; idevnum,txt,i); } if( i%4 == 0 ) { logmsg(" "); } logmsg("%2.2X",bfr[i]); } logmsg("\n"); } /*-------------------------------------------------------------------*/ /* Handler utility routines */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Buffer ring management */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Buffer ring management : Init a buffer ring */ /*-------------------------------------------------------------------*/ void commadpt_ring_init(COMMADPT_RING *ring,size_t sz,int trace) { ring->bfr=malloc(sz); ring->sz=sz; ring->hi=0; ring->lo=0; ring->havedata=0; ring->overflow=0; if(trace) { logmsg("HCCCA999D : Ring buffer for ring %p allocated at %p\n", ring, ring->bfr); } } /*-------------------------------------------------------------------*/ /* Buffer ring management : Free a buffer ring */ /*-------------------------------------------------------------------*/ static void commadpt_ring_terminate(COMMADPT_RING *ring,int trace) { if(trace) { logmsg("HCCCA999D : Ring buffer for ring %p at %p freed\n", ring, ring->bfr); } if(ring->bfr!=NULL) { free(ring->bfr); ring->bfr=NULL; } ring->sz=0; ring->hi=0; ring->lo=0; ring->havedata=0; ring->overflow=0; } /*-------------------------------------------------------------------*/ /* Buffer ring management : Flush a buffer ring */ /*-------------------------------------------------------------------*/ static void commadpt_ring_flush(COMMADPT_RING *ring) { ring->hi=0; ring->lo=0; ring->havedata=0; ring->overflow=0; } /*-------------------------------------------------------------------*/ /* Buffer ring management : Queue a byte in the ring */ /*-------------------------------------------------------------------*/ inline static void commadpt_ring_push(COMMADPT_RING *ring,BYTE b) { ring->bfr[ring->hi++]=b; if(ring->hi>=ring->sz) { ring->hi=0; } if(ring->hi==ring->lo) { ring->overflow=1; } ring->havedata=1; } /*-------------------------------------------------------------------*/ /* Buffer ring management : Queue a byte array in the ring */ /*-------------------------------------------------------------------*/ inline static void commadpt_ring_pushbfr(COMMADPT_RING *ring,BYTE *b,size_t sz) { size_t i; for(i=0;ibfr[ring->lo++]; if(ring->lo>=ring->sz) { ring->lo=0; } if(ring->hi==ring->lo) { ring->havedata=0; } return b; } /*-------------------------------------------------------------------*/ /* Buffer ring management : Retrive a byte array from the ring */ /*-------------------------------------------------------------------*/ inline static size_t commadpt_ring_popbfr(COMMADPT_RING *ring,BYTE *b,size_t sz) { size_t i; for(i=0;ihavedata;i++) { b[i]=commadpt_ring_pop(ring); } return i; } /*-------------------------------------------------------------------*/ /* Free all private structures and buffers */ /*-------------------------------------------------------------------*/ static void commadpt_clean_device(DEVBLK *dev) { if(!dev) { /* * Shouldn't happen.. But during shutdown, some weird * things happen ! */ return; } if(dev->commadpt!=NULL) { commadpt_ring_terminate(&dev->commadpt->inbfr,dev->ccwtrace); commadpt_ring_terminate(&dev->commadpt->outbfr,dev->ccwtrace); commadpt_ring_terminate(&dev->commadpt->rdwrk,dev->ccwtrace); commadpt_ring_terminate(&dev->commadpt->pollbfr,dev->ccwtrace); commadpt_ring_terminate(&dev->commadpt->ttybuf,dev->ccwtrace); /* release the CA lock */ release_lock(&dev->commadpt->lock); free(dev->commadpt); dev->commadpt=NULL; if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:clean : Control block freed\n"), dev->devnum); } } else { if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:clean : Control block not freed : not allocated\n"),dev->devnum); } } return; } /*-------------------------------------------------------------------*/ /* Allocate initial private structures */ /*-------------------------------------------------------------------*/ static int commadpt_alloc_device(DEVBLK *dev) { dev->commadpt=malloc(sizeof(COMMADPT)); if(dev->commadpt==NULL) { logmsg(_("HHCCA020E %4.4X:Memory allocation failure for main control block\n"), dev->devnum); return -1; } memset(dev->commadpt,0,sizeof(COMMADPT)); commadpt_ring_init(&dev->commadpt->inbfr,4096,dev->ccwtrace); commadpt_ring_init(&dev->commadpt->outbfr,4096,dev->ccwtrace); commadpt_ring_init(&dev->commadpt->pollbfr,4096,dev->ccwtrace); commadpt_ring_init(&dev->commadpt->rdwrk,65536,dev->ccwtrace); commadpt_ring_init(&dev->commadpt->ttybuf,TTYLINE_SZ,dev->ccwtrace); dev->commadpt->dev=dev; return 0; } /*-------------------------------------------------------------------*/ /* Parsing utilities */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* commadpt_getport : returns a port number or -1 */ /*-------------------------------------------------------------------*/ static int commadpt_getport(char *txt) { int pno; struct servent *se; pno=atoi(txt); if(pno==0) { se=getservbyname(txt,"tcp"); if(se==NULL) { return -1; } pno=se->s_port; } return(pno); } /*-------------------------------------------------------------------*/ /* commadpt_getaddr : set an in_addr_t if ok, else return -1 */ /*-------------------------------------------------------------------*/ static int commadpt_getaddr(in_addr_t *ia,char *txt) { struct hostent *he; he=gethostbyname(txt); if(he==NULL) { return(-1); } memcpy(ia,he->h_addr_list[0],4); return(0); } /*-------------------------------------------------------------------*/ /* commadpt_connout : make a tcp outgoing call */ /* return values : 0 -> call succeeded or initiated */ /* <0 -> call failed */ /*-------------------------------------------------------------------*/ static int commadpt_connout(COMMADPT *ca) { int rc; char wbfr[256]; struct sockaddr_in sin; struct in_addr intmp; sin.sin_family=AF_INET; sin.sin_addr.s_addr=ca->rhost; sin.sin_port=htons(ca->rport); if(socket_is_socket(ca->sfd)) { close_socket(ca->sfd); ca->connect=0; } ca->sfd=socket(AF_INET,SOCK_STREAM,0); /* set socket to NON-blocking mode */ socket_set_blocking_mode(ca->sfd,0); rc=connect(ca->sfd,(struct sockaddr *)&sin,sizeof(sin)); if(rc<0) { if(HSO_errno==HSO_EINPROGRESS) { return(0); } else { strerror_r(HSO_errno,wbfr,256); intmp.s_addr=ca->rhost; logmsg(_("HHCCA001I %4.4X:Connect out to %s:%d failed during initial status : %s\n"), ca->devnum, inet_ntoa(intmp), ca->rport, wbfr); close_socket(ca->sfd); ca->connect=0; return(-1); } } ca->connect=1; return(0); } /*-------------------------------------------------------------------*/ /* commadpt_initiate_userdial : interpret DIAL data and initiate call*/ /* return values : 0 -> call succeeded or initiated */ /* <0 -> call failed */ /*-------------------------------------------------------------------*/ static int commadpt_initiate_userdial(COMMADPT *ca) { int dotcount; /* Number of seps (the 4th is the port separator) */ int i; /* work */ int cur; /* Current section */ in_addr_t destip; /* Destination IP address */ U16 destport; /* Destination TCP port */ int incdata; /* Incorrect dial data found */ int goteon; /* EON presence flag */ /* See the DIAL CCW portion in execute_ccw for dial format information */ incdata=0; goteon=0; dotcount=0; cur=0; destip=0; for(i=0;idialcount;i++) { if(goteon) { /* EON MUST be last data byte */ if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4x : Found data beyond EON\n"),ca->devnum); } incdata=1; break; } switch(ca->dialdata[i]&0x0f) { case 0x0d: /* SEP */ if(dotcount<4) { if(cur>255) { incdata=1; if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4x : Found incorrect IP address section at position %d\n"),ca->devnum,dotcount+1); logmsg(_("HHCCA300D %4.4x : %d greater than 255\n"),ca->devnum,cur); } break; } destip<<=8; destip+=cur; cur=0; dotcount++; } else { incdata=1; if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4x : Too many separators in dial data\n"),ca->devnum); } break; } break; case 0x0c: /* EON */ goteon=1; break; /* A,B,E,F not valid */ case 0x0a: case 0x0b: case 0x0e: case 0x0f: incdata=1; if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4x : Incorrect dial data byte %2.2x\n"),ca->devnum,ca->dialdata[i]); } break; default: cur*=10; cur+=ca->dialdata[i]&0x0f; break; } if(incdata) { break; } } if(incdata) { return -1; } if(dotcount<4) { if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4x : Not enough separators (only %d found) in dial data\n"),ca->devnum,dotcount); } return -1; } if(cur>65535) { if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4x : Destination TCP port %d exceeds maximum of 65535\n"),ca->devnum,cur); } return -1; } destport=cur; /* Update RHOST/RPORT */ ca->rport=destport; ca->rhost=destip; return(commadpt_connout(ca)); } static void connect_message(int sfd, int devnum, int term, int binary_opt) { int rc; struct sockaddr_in client; socklen_t namelen; char *ipaddr; char msgtext[256]; namelen = sizeof(client); rc = getpeername (sfd, (struct sockaddr *)&client, &namelen); ipaddr = inet_ntoa(client.sin_addr); sprintf(msgtext, "%s:%d TERMINAL CONNECTED CUA=%4.4X TERM=%s", ipaddr, (int)ntohs(client.sin_port), devnum, (term == COMMADPT_TERM_TTY) ? "TTY" : "2741"); logmsg( _("%s\n"), msgtext); write(sfd, msgtext, strlen(msgtext)); write(sfd, "\r\n", 2); if (binary_opt) write(sfd, telnet_binary, sizeof(telnet_binary)); } /*-------------------------------------------------------------------*/ /* Communication Thread - Read socket data (after POLL request */ /*-------------------------------------------------------------------*/ static int commadpt_read_poll(COMMADPT *ca) { BYTE b; int rc; while((rc=read_socket(ca->sfd,&b,1))>0) { if(b==0x32) { continue; } if(b==0x37) { return(1); } } if(rc>0) { /* Store POLL IX in bfr followed by byte */ commadpt_ring_push(&ca->inbfr,ca->pollix); commadpt_ring_push(&ca->inbfr,b); return(2); } return(0); } static void commadpt_read_tty(COMMADPT *ca, BYTE * bfr, int len) { BYTE bfr3[3]; BYTE c; BYTE dump_buf[TTYLINE_SZ]; int dump_bp=0; BYTE tty_buf[TTYLINE_SZ]; int tty_bp=0; int i1; u_int j; int crflag = 0; for (i1 = 0; i1 < len; i1++) { c = (unsigned char) bfr[i1]; if (ca->telnet_opt) { ca->telnet_opt = 0; if(ca->dev->ccwtrace) logmsg(_("HHCCA300D %4.4X: Received TELNET CMD 0x%02x 0x%02x\n"), ca->dev->devnum, ca->telnet_cmd, c); if (c == 0x00 && ca->binary_opt) continue; /* for binary: assume it's a response, so don't answer */ bfr3[0] = 0xff; /* IAC */ /* set won't/don't for all received commands */ bfr3[1] = (ca->telnet_cmd == 0xfd) ? 0xfc : 0xfe; bfr3[2] = c; if(ca->dev->ccwtrace) logmsg(_("HHCCA300D %4.4X: Sending TELNET CMD 0x%02x 0x%02x\n"), ca->dev->devnum, bfr3[1], bfr3[2]); commadpt_ring_pushbfr(&ca->outbfr,bfr3,3); continue; } if (ca->telnet_iac) { ca->telnet_iac = 0; if(ca->dev->ccwtrace) logmsg(_("HHCCA300D %4.4X: Received TELNET IAC 0x%02x\n"), ca->dev->devnum, c); switch (c) { case 0xFB: /* TELNET WILL option cmd */ case 0xFD: /* TELNET DO option cmd */ ca->telnet_opt = 1; ca->telnet_cmd = c; break; case 0xF4: /* TELNET interrupt */ if (!ca->telnet_int) { ca->telnet_int = 1; commadpt_ring_flush(&ca->ttybuf); commadpt_ring_flush(&ca->inbfr); commadpt_ring_flush(&ca->rdwrk); commadpt_ring_flush(&ca->outbfr); } break; } continue; } if (c == 0xFF) { /* TELNET IAC */ ca->telnet_iac = 1; continue; } else { ca->telnet_iac = 0; } if (c == ca->eol_char) { // char was CR ? crflag = 1; } if (c == 0x03 && ca->dumb_break) { /* Ctrl-C */ ca->telnet_int = 1; commadpt_ring_flush(&ca->ttybuf); commadpt_ring_flush(&ca->inbfr); commadpt_ring_flush(&ca->rdwrk); commadpt_ring_flush(&ca->outbfr); continue; } commadpt_ring_push(&ca->ttybuf,c); } if (crflag) { /* process complete line, perform editing and translation, etc. */ if (ca->prepend_length) { for (i1 = 0; i1 < ca->prepend_length; i1++) { tty_buf[tty_bp++] = ca->prepend_bytes[i1]; if (tty_bp >= TTYLINE_SZ) tty_bp = TTYLINE_SZ - 1; // prevent buf overflow } } while (ca->ttybuf.havedata) { c = commadpt_ring_pop(&ca->ttybuf); if ((c & 0x7f) == 0x08 && ca->dumb_bs) // backspace editing { if (tty_bp > 0) tty_bp --; continue; } if (ca->input_byte_skip_table[c]) continue; // skip this byte per cfg if (!(ca->rxvt4apl || !ca->code_table_fromebcdic)) { /* tty33 and 2741 emulation are 7-bit, code=none and rxvt4apl want 8 bit */ c &= 0x7f; // make 7 bit ASCII } if (ca->uctrans && c >= 'a' && c <= 'z') { c = toupper( c ); /* make uppercase */ } /* now map the character from ASCII into proper S/370 byte format */ if (ca->term == COMMADPT_TERM_TTY) { if (byte_parity_table[(unsigned int)(c & 0x7f)]) c |= 0x80; // make even parity c = byte_reverse_table[(unsigned int)(c & 0xff)]; } else { /* 2741 */ if (ca->rxvt4apl) { if (overstrike_map[c] == 1) { for (j = 0; j < sizeof(overstrike_rxvt4apl_chars); j++) { if (c == overstrike_rxvt4apl_chars[j]) { tty_buf[tty_bp++] = overstrike_2741_pairs[j*2]; if (tty_bp >= TTYLINE_SZ) tty_bp = TTYLINE_SZ - 1; // prevent buf overflow tty_buf[tty_bp++] = 0xDD; // 2741 backspace if (tty_bp >= TTYLINE_SZ) tty_bp = TTYLINE_SZ - 1; // prevent buf overflow c = overstrike_2741_pairs[ (j*2) + 1]; } } } else { c = rxvt4apl_to_2741[c]; } } else if (ca->code_table_fromebcdic) { c = host_to_guest(c & 0x7f); // first translate to EBCDIC c = ca->code_table_fromebcdic[ c ]; // then to 2741 code } } tty_buf[tty_bp++] = c; if (tty_bp >= TTYLINE_SZ) tty_bp = TTYLINE_SZ - 1; // prevent buf overflow } if (ca->append_length) { for (i1 = 0; i1 < ca->append_length; i1++) { tty_buf[tty_bp++] = ca->append_bytes[i1]; if (tty_bp >= TTYLINE_SZ) tty_bp = TTYLINE_SZ - 1; // prevent buf overflow } } if (tty_bp > 0) { for (i1 = 0; i1 < tty_bp; i1++) { commadpt_ring_push(&ca->rdwrk, tty_buf[i1]); dump_buf[dump_bp++] = tty_buf[i1]; if (dump_bp >= TTYLINE_SZ) dump_bp = TTYLINE_SZ - 1; } } logdump("RCV2",ca->dev,dump_buf,dump_bp); ca->eol_flag = 1; // set end of line flag if (ca->sendcr_opt) { /* move carriage to left margin */ commadpt_ring_push(&ca->outbfr,0x0d); } } /* end of if(crflag) */ } /*-------------------------------------------------------------------*/ /* Communication Thread - Read socket data */ /*-------------------------------------------------------------------*/ static void commadpt_read(COMMADPT *ca) { BYTE bfr[256]; int gotdata; int rc; gotdata=0; for (;;) { /* if (IS_BSC_LNCTL(ca)) { rc=read_socket(ca->sfd,bfr,256); } else { */ /* read_socket has changed from 3.04 to 3.06 - async needs old way */ /* is BSC similarly broken? */ /* --> Yes, it is! I propose to fully remove the if/else construct */ /* i.e. to handle BSC and async identically here (JW) */ #ifdef _MSVC_ rc=recv(ca->sfd,bfr,256,0); #else rc=read(ca->sfd,bfr,256); #endif /* } */ if (rc <= 0) break; logdump("RECV",ca->dev,bfr,rc); if (IS_ASYNC_LNCTL(ca)) { commadpt_read_tty(ca, bfr, rc); } else { commadpt_ring_pushbfr(&ca->inbfr,bfr,(size_t)rc); } /* end of else (async) */ gotdata=1; } if(!gotdata) { if(ca->connect) { ca->connect=0; close_socket(ca->sfd); ca->sfd=-1; if(ca->curpending!=COMMADPT_PEND_IDLE) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); } } } } /*-------------------------------------------------------------------*/ /* Communication Thread - Set TimeOut */ /*-------------------------------------------------------------------*/ static struct timeval *commadpt_setto(struct timeval *tv,int tmo) { if(tmo!=0) { if(tmo<0) { tv->tv_sec=0; tv->tv_usec=1; } else { tv->tv_sec=tmo/1000; tv->tv_usec=(tmo%1000)*1000; } return(tv); } return(NULL); } /*-------------------------------------------------------------------*/ /* Communication Thread main loop */ /*-------------------------------------------------------------------*/ static void *commadpt_thread(void *vca) { COMMADPT *ca; /* Work CA Control Block Pointer */ int sockopt; /* Used for setsocketoption */ struct sockaddr_in sin; /* bind socket address structure */ int devnum; /* device number copy for convenience*/ int rc; /* return code from various rtns */ struct timeval tv; /* select timeout structure */ struct timeval *seltv; /* ptr to the timeout structure */ fd_set rfd,wfd,xfd; /* SELECT File Descriptor Sets */ BYTE pipecom; /* Byte read from IPC pipe */ int tempfd; /* Temporary FileDesc holder */ BYTE b; /* Work data byte */ int writecont; /* Write contention active */ int soerr; /* getsockopt SOERROR value */ socklen_t soerrsz; /* Size for getsockopt */ int maxfd; /* highest FD for select */ int ca_shutdown; /* Thread shutdown internal flag */ int init_signaled; /* Thread initialisation signaled */ int pollact; /* A Poll Command is in progress */ int i; /* Ye Old Loop Counter */ /*---------------------END OF DECLARES---------------------------*/ /* fetch the commadpt structure */ ca=(COMMADPT *)vca; /* Obtain the CA lock */ obtain_lock(&ca->lock); /* get a work copy of devnum (for messages) */ devnum=ca->devnum; /* reset shutdown flag */ ca_shutdown=0; init_signaled=0; logmsg(_("HHCCA002I %4.4X:Line Communication thread "TIDPAT" started\n"),devnum,thread_id()); pollact=0; /* Initialise Poll activity flag */ /* Determine if we should listen */ /* if this is a DIAL=OUT only line, no listen is necessary */ if(ca->dolisten) { /* Create the socket for a listen */ ca->lfd=socket(AF_INET,SOCK_STREAM,0); if(!socket_is_socket(ca->lfd)) { logmsg(_("HHCCA003E %4.4X:Cannot obtain socket for incoming calls : %s\n"),devnum,strerror(HSO_errno)); ca->have_cthread=0; release_lock(&ca->lock); return NULL; } /* Turn blocking I/O off */ /* set socket to NON-blocking mode */ socket_set_blocking_mode(ca->lfd,0); /* Reuse the address regardless of any */ /* spurious connection on that port */ sockopt=1; setsockopt(ca->lfd,SOL_SOCKET,SO_REUSEADDR,(GETSET_SOCKOPT_T*)&sockopt,sizeof(sockopt)); /* Bind the socket */ sin.sin_family=AF_INET; sin.sin_addr.s_addr=ca->lhost; sin.sin_port=htons(ca->lport); while(1) { rc=bind(ca->lfd,(struct sockaddr *)&sin,sizeof(sin)); if(rc<0) { if(HSO_errno==HSO_EADDRINUSE) { logmsg(_("HHCCA004W %4.4X:Waiting 5 seconds for port %d to become available\n"),devnum,ca->lport); /* * Check for a shutdown condition on entry */ if(ca->curpending==COMMADPT_PEND_SHUTDOWN) { ca_shutdown=1; ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } /* Set to wait 5 seconds or input on the IPC pipe */ /* whichever comes 1st */ if(!init_signaled) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); init_signaled=1; } FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&xfd); FD_SET(ca->pipe[1],&rfd); tv.tv_sec=5; tv.tv_usec=0; release_lock(&ca->lock); rc=select(ca->pipe[1]+1,&rfd,&wfd,&wfd,&tv); obtain_lock(&ca->lock); /* * Check for a shutdown condition again after the sleep */ if(ca->curpending==COMMADPT_PEND_SHUTDOWN) { ca_shutdown=1; ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } if(rc!=0) { /* Ignore any other command at this stage */ read_pipe(ca->pipe[1],&b,1); ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); } } else { logmsg(_("HHCCA018E %4.4X:Bind failed : %s\n"),devnum,strerror(HSO_errno)); ca_shutdown=1; break; } } else { break; } } /* Start the listen */ if(!ca_shutdown) { listen(ca->lfd,10); logmsg(_("HHCCA005I %4.4X:Listening on port %d for incoming TCP connections\n"), devnum, ca->lport); ca->listening=1; } } if(!init_signaled) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); init_signaled=1; } /* The MAIN select loop */ /* It will listen on the following sockets : */ /* ca->lfd : The listen socket */ /* ca->sfd : * read : When a read, prepare or DIAL command is in effect * write : When a write contention occurs * ca->pipe[0] : Always * * A 3 Seconds timer is started for a read operation */ while(!ca_shutdown) { FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&xfd); maxfd=0; if(ca->listening) { FD_SET(ca->lfd,&rfd); maxfd=maxfdlfd?ca->lfd:maxfd; } seltv=NULL; if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - Entry - DevExec = %s\n"), devnum, commadpt_pendccw_text[ca->curpending]); } writecont=0; switch(ca->curpending) { case COMMADPT_PEND_SHUTDOWN: ca_shutdown=1; break; case COMMADPT_PEND_IDLE: break; case COMMADPT_PEND_READ: if(!ca->connect) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } if(ca->inbfr.havedata || ca->eol_flag) { if (ca->term == COMMADPT_TERM_2741) { usleep(10000); } ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } seltv=commadpt_setto(&tv,ca->rto); FD_SET(ca->sfd,&rfd); maxfd=maxfdsfd?ca->sfd:maxfd; break; case COMMADPT_PEND_POLL: /* Poll active check - provision for write contention */ /* pollact will be reset when NON syn data is received*/ /* or when the read times out */ /* Also prevents WRITE from exiting early */ if(!pollact && !writecont) { int gotenq; pollact=1; gotenq=0; /* Send SYN+SYN */ commadpt_ring_push(&ca->outbfr,0x32); commadpt_ring_push(&ca->outbfr,0x32); /* Fill the Output ring with POLL Data */ /* Up to 7 chars or ENQ */ for(i=0;i<7;i++) { if(!ca->pollbfr.havedata) { break; } ca->pollused++; b=commadpt_ring_pop(&ca->pollbfr); if(b!=0x2D) { commadpt_ring_push(&ca->outbfr,b); } else { gotenq=1; break; } } if(!gotenq) { if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Poll Command abort - Poll address >7 Bytes\n"),devnum); } ca->badpoll=1; ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } b=commadpt_ring_pop(&ca->pollbfr); ca->pollix=b; seltv=commadpt_setto(&tv,ca->pto); } if(!writecont && ca->pto!=0) { /* Set tv value (have been set earlier) */ seltv=&tv; /* Set to read data still */ FD_SET(ca->sfd,&rfd); maxfd=maxfdsfd?ca->sfd:maxfd; } /* DO NOT BREAK - Continue with WRITE processing */ case COMMADPT_PEND_WRITE: if(!writecont) { while(ca->outbfr.havedata) { b=commadpt_ring_pop(&ca->outbfr); if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Writing 1 byte in socket : %2.2X\n"),ca->devnum,b); } rc=write_socket(ca->sfd,&b,1); if(rc!=1) { if(0 #ifndef WIN32 || EAGAIN == errno #endif || HSO_EWOULDBLOCK == HSO_errno ) { /* Contending for write */ writecont=1; FD_SET(ca->sfd,&wfd); maxfd=maxfdsfd?ca->sfd:maxfd; break; } else { close_socket(ca->sfd); ca->sfd=-1; ca->connect=0; ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } } } if (IS_ASYNC_LNCTL(ca)) { /* Sleep for 0.01 sec - for faithful emulation we would * slow everything down to 110 or 150 baud or worse :) * Without this sleep, CPU use is excessive. */ usleep(10000); } } else { FD_SET(ca->sfd,&wfd); maxfd=maxfdsfd?ca->sfd:maxfd; } if(!writecont && !pollact) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } break; case COMMADPT_PEND_DIAL: if(ca->connect) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } rc=commadpt_initiate_userdial(ca); if(rc!=0 || (rc==0 && ca->connect)) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } FD_SET(ca->sfd,&wfd); maxfd=maxfdsfd?ca->sfd:maxfd; break; case COMMADPT_PEND_ENABLE: if(ca->connect) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } switch(ca->dialin+ca->dialout*2) { case 0: /* DIAL=NO */ /* callissued is set here when the call */ /* actually failed. But we want to time */ /* a bit for program issuing ENABLES in */ /* a tight loop */ if(ca->callissued) { seltv=commadpt_setto(&tv,ca->eto); break; } /* Issue a Connect out */ rc=commadpt_connout(ca); if(rc==0) { /* Call issued */ if(ca->connect) { /* Call completed already */ ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); } else { /* Call initiated - FD will be ready */ /* for writing when the connect ends */ /* getsockopt/SOERROR will tell if */ /* the call was sucessfull or not */ FD_SET(ca->sfd,&wfd); maxfd=maxfdsfd?ca->sfd:maxfd; ca->callissued=1; } } /* Call did not succeed */ /* Manual says : on a leased line, if DSR is not up */ /* the terminate enable after a timeout.. That is */ /* what the call just did (although the time out */ /* was probably instantaneous) */ /* This is the equivalent of the comm equipment */ /* being offline */ /* INITIATE A 3 SECOND TIMEOUT */ /* to prevent OSes from issuing a loop of ENABLES */ else { seltv=commadpt_setto(&tv,ca->eto); } break; default: case 3: /* DIAL=INOUT */ case 1: /* DIAL=IN */ /* Wait forever */ break; case 2: /* DIAL=OUT */ /* Makes no sense */ /* line must be enabled through a DIAL command */ ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } /* For cases not DIAL=OUT, the listen is already started */ break; /* The CCW Executor says : DISABLE */ case COMMADPT_PEND_DISABLE: if(ca->connect) { close_socket(ca->sfd); ca->sfd=-1; ca->connect=0; } ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; /* A PREPARE has been issued */ case COMMADPT_PEND_PREPARE: if(!ca->connect || ca->inbfr.havedata) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } FD_SET(ca->sfd,&rfd); maxfd=maxfdsfd?ca->sfd:maxfd; break; /* Don't know - shouldn't be here anyway */ default: break; } /* If the CA is shutting down, exit the loop now */ if(ca_shutdown) { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); break; } /* Set the IPC pipe in the select */ FD_SET(ca->pipe[0],&rfd); /* The the MAX File Desc for Arg 1 of SELECT */ maxfd=maxfdpipe[0]?ca->pipe[0]:maxfd; maxfd++; /* Release the CA Lock before the select - all FDs addressed by the select are only */ /* handled by the thread, and communication from CCW Executor/others to this thread */ /* is via the pipe, which queues the info */ release_lock(&ca->lock); if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - Select IN maxfd = %d / Devexec = %s\n"),devnum,maxfd,commadpt_pendccw_text[ca->curpending]); } rc=select(maxfd,&rfd,&wfd,&xfd,seltv); if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - Select OUT rc=%d\n"),devnum,rc); } /* Get the CA lock back */ obtain_lock(&ca->lock); if(rc==-1) { if(errno==EINTR) { continue; /* thanks Fish! */ } logmsg(_("HHCCA006T %4.4X:Select failed : %s\n"),devnum,strerror(HSO_errno)); break; } /* Select timed out */ if(rc==0) { pollact=0; /* Poll not active */ if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - Select TIME OUT\n"),devnum); } /* Reset Call issued flag */ ca->callissued=0; /* timeout condition */ signal_condition(&ca->ipc); ca->curpending=COMMADPT_PEND_IDLE; continue; } if(FD_ISSET(ca->pipe[0],&rfd)) { rc=read_pipe(ca->pipe[0],&pipecom,1); if(rc==0) { if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - IPC Pipe closed\n"),devnum); } /* Pipe closed : terminate thread & release CA */ ca_shutdown=1; break; } if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - IPC Pipe Data ; code = %d\n"),devnum,pipecom); } switch(pipecom) { case 0: /* redrive select */ /* occurs when a new CCW is being executed */ break; case 1: /* Halt current I/O */ ca->callissued=0; if(ca->curpending==COMMADPT_PEND_DIAL) { close_socket(ca->sfd); ca->sfd=-1; } ca->curpending=COMMADPT_PEND_IDLE; ca->haltpending=1; signal_condition(&ca->ipc); signal_condition(&ca->ipc_halt); /* Tell the halt initiator too */ break; default: break; } continue; } if(ca->connect) { if(FD_ISSET(ca->sfd,&rfd)) { int dopoll; dopoll=0; if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - inbound socket data\n"),devnum); } if(pollact && IS_BSC_LNCTL(ca)) { switch(commadpt_read_poll(ca)) { case 0: /* Only SYNs received */ /* Continue the timeout */ dopoll=1; break; case 1: /* EOT Received */ /* Send next poll sequence */ pollact=0; dopoll=1; break; case 2: /* Something else received */ /* Index byte already stored in inbfr */ /* read the remaining data and return */ ca->pollsm=1; dopoll=0; break; default: /* Same as 0 */ dopoll=1; break; } } if(IS_ASYNC_LNCTL(ca) || !dopoll) { commadpt_read(ca); if(IS_ASYNC_LNCTL(ca) && !ca->eol_flag && !ca->telnet_int) { /* async: EOL char not yet received and not attn: no data to read */ /* ... just remain in COMMADPT_PEND_READ state ... */ } else { ca->curpending=COMMADPT_PEND_IDLE; signal_condition(&ca->ipc); } continue; } } } if(ca->sfd>=0) { if(FD_ISSET(ca->sfd,&wfd)) { if(ca->dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:cthread - socket write available\n"),devnum); } switch(ca->curpending) { case COMMADPT_PEND_DIAL: case COMMADPT_PEND_ENABLE: /* Leased line enable call case */ soerrsz=sizeof(soerr); getsockopt(ca->sfd,SOL_SOCKET,SO_ERROR,(GETSET_SOCKOPT_T*)&soerr,&soerrsz); if(soerr==0) { ca->connect=1; } else { logmsg(_("HHCCA007W %4.4X:Outgoing call failed during %s command : %s\n"),devnum,commadpt_pendccw_text[ca->curpending],strerror(soerr)); if(ca->curpending==COMMADPT_PEND_ENABLE) { /* Ensure top of the loop doesn't restart a new call */ /* but starts a 3 second timer instead */ ca->callissued=1; } ca->connect=0; close_socket(ca->sfd); ca->sfd=-1; } signal_condition(&ca->ipc); ca->curpending=COMMADPT_PEND_IDLE; break; case COMMADPT_PEND_WRITE: writecont=0; break; default: break; } continue; } } /* Test for incoming call */ if(ca->listening) { if(FD_ISSET(ca->lfd,&rfd)) { logmsg(_("HHCCA008I %4.4X:cthread - Incoming Call\n"),devnum); tempfd=accept(ca->lfd,NULL,0); if(tempfd<0) { continue; } /* If the line is already connected, just close */ /* this call */ if(ca->connect) { close_socket(tempfd); continue; } /* Turn non-blocking I/O on */ /* set socket to NON-blocking mode */ socket_set_blocking_mode(tempfd,0); /* Check the line type & current operation */ /* if DIAL=IN or DIAL=INOUT or DIAL=NO */ if(ca->dialin || (ca->dialin+ca->dialout==0)) { /* check if ENABLE is in progress */ if(ca->curpending==COMMADPT_PEND_ENABLE) { /* Accept the call, indicate the line */ /* is connected and notify CCW exec */ ca->curpending=COMMADPT_PEND_IDLE; ca->connect=1; ca->sfd=tempfd; signal_condition(&ca->ipc); if (IS_ASYNC_LNCTL(ca)) { connect_message(ca->sfd, ca->devnum, ca->term, ca->binary_opt); } continue; } /* if this is a leased line, accept the */ /* call anyway */ if(ca->dialin==0) { ca->connect=1; ca->sfd=tempfd; if (IS_ASYNC_LNCTL(ca)) { connect_message(ca->sfd, ca->devnum, ca->term, ca->binary_opt); } continue; } } /* All other cases : just reject the call */ close_socket(tempfd); } } } ca->curpending=COMMADPT_PEND_CLOSED; /* Check if we already signaled the init process */ if(!init_signaled) { signal_condition(&ca->ipc); } /* The CA is shutting down - terminate the thread */ /* NOTE : the requestor was already notified upon */ /* detection of PEND_SHTDOWN. However */ /* the requestor will only run when the */ /* lock is released, because back */ /* notification was made while holding */ /* the lock */ logmsg(_("HHCCA009I %4.4X:BSC utility thread terminated\n"),ca->devnum); release_lock(&ca->lock); return NULL; } /*-------------------------------------------------------------------*/ /* Wakeup the comm thread */ /* Code : 0 -> Just wakeup the thread to redrive the select */ /* Code : 1 -> Halt the current executing I/O */ /*-------------------------------------------------------------------*/ static void commadpt_wakeup(COMMADPT *ca,BYTE code) { write_pipe(ca->pipe[1],&code,1); } /*-------------------------------------------------------------------*/ /* Wait for a copndition from the thread */ /* MUST HOLD the CA lock */ /*-------------------------------------------------------------------*/ static void commadpt_wait(DEVBLK *dev) { COMMADPT *ca; ca=dev->commadpt; wait_condition(&ca->ipc,&ca->lock); } /*-------------------------------------------------------------------*/ /* Halt currently executing I/O command */ /*-------------------------------------------------------------------*/ static void commadpt_halt(DEVBLK *dev) { if(!dev->busy) { return; } obtain_lock(&dev->commadpt->lock); commadpt_wakeup(dev->commadpt,1); /* Due to the mysteries of the host OS scheduling */ /* the wait_condition may or may not exit after */ /* the CCW executor thread relinquishes control */ /* This however should not be of any concern */ /* */ /* but returning from the wait guarantees that */ /* the working thread will (or has) notified */ /* the CCW executor to terminate the current I/O */ wait_condition(&dev->commadpt->ipc_halt,&dev->commadpt->lock); dev->commadpt->haltprepare = 1; /* part of APL\360 2741 race cond I circumvention */ release_lock(&dev->commadpt->lock); } /* The following 3 MSG functions ensure only 1 (one) */ /* hardcoded instance exist for the same numbered msg */ /* that is issued on multiple situations */ static void msg013e(DEVBLK *dev,char *kw,char *kv) { logmsg(_("HHCCA013E %4.4X:Incorrect %s specification %s\n"),dev->devnum,kw,kv); } static void msg015e(DEVBLK *dev,char *dialt,char *kw) { logmsg(_("HHCCA015E %4.4X:Missing parameter : DIAL=%s and %s not specified\n"),dev->devnum,dialt,kw); } static void msg016w017i(DEVBLK *dev,char *dialt,char *kw,char *kv) { logmsg(_("HHCCA016W %4.4X:Conflicting parameter : DIAL=%s and %s=%s specified\n"),dev->devnum,dialt,kw,kv); logmsg(_("HHCCA017I %4.4X:RPORT parameter ignored\n"),dev->devnum); } /*-------------------------------------------------------------------*/ /* Device Initialisation */ /*-------------------------------------------------------------------*/ static int commadpt_init_handler (DEVBLK *dev, int argc, char *argv[]) { char thread_name[32]; int i,j; int ix; int rc; int pc; /* Parse code */ int errcnt; struct in_addr in_temp; char *dialt; char fmtbfr[64]; int etospec; /* ETO= Specified */ union { int num; char text[80]; } res; char bf[4]; dev->devtype=0x2703; if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Initialisation starting\n"),dev->devnum); } rc=commadpt_alloc_device(dev); if(rc<0) { logmsg(_("HHCCA010I %4.4X:initialisation not performed\n"), dev->devnum); return(-1); } if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Initialisation : Control block allocated\n"),dev->devnum); } errcnt=0; /* * Initialise ports & hosts */ dev->commadpt->sfd=-1; dev->commadpt->lport=0; dev->commadpt->rport=0; dev->commadpt->lhost=INADDR_ANY; dev->commadpt->rhost=INADDR_NONE; dev->commadpt->dialin=0; dev->commadpt->dialout=1; dev->commadpt->rto=3000; /* Read Time-Out in milis */ dev->commadpt->pto=3000; /* Poll Time-out in milis */ dev->commadpt->eto=10000; /* Enable Time-out in milis */ dev->commadpt->lnctl=COMMADPT_LNCTL_BSC; dev->commadpt->term=COMMADPT_TERM_TTY; dev->commadpt->uctrans=FALSE; dev->commadpt->code_table_toebcdic = xlate_table_ebcd_toebcdic; dev->commadpt->code_table_fromebcdic = xlate_table_ebcd_fromebcdic; memset(dev->commadpt->byte_skip_table, 0, sizeof(dev->commadpt->byte_skip_table) ); memset(dev->commadpt->input_byte_skip_table, 0, sizeof(dev->commadpt->input_byte_skip_table) ); dev->commadpt->dumb_bs=0; dev->commadpt->dumb_break=0; dev->commadpt->prepend_length = 0; dev->commadpt->append_length = 0; dev->commadpt->rxvt4apl = 0; dev->commadpt->overstrike_flag = 0; dev->commadpt->crlf_opt = 0; dev->commadpt->sendcr_opt = 0; dev->commadpt->binary_opt = 0; dev->commadpt->eol_char = 0x0d; // default is ascii CR memset(dev->commadpt->prepend_bytes, 0, sizeof(dev->commadpt->prepend_bytes)); memset(dev->commadpt->append_bytes, 0, sizeof(dev->commadpt->append_bytes)); etospec=0; for(i=0;idevnum,argv[i]); errcnt++; continue; } if(pc==0) { logmsg(_("HHCCA012E %4.4X:Unrecognized parameter %s\n"),dev->devnum,argv[i]); errcnt++; continue; } switch(pc) { case COMMADPT_KW_LPORT: rc=commadpt_getport(res.text); if(rc<0) { errcnt++; msg013e(dev,"LPORT",res.text); break; } dev->commadpt->lport=rc; break; case COMMADPT_KW_LHOST: if(strcmp(res.text,"*")==0) { dev->commadpt->lhost=INADDR_ANY; break; } rc=commadpt_getaddr(&dev->commadpt->lhost,res.text); if(rc!=0) { msg013e(dev,"LHOST",res.text); errcnt++; } break; case COMMADPT_KW_RPORT: rc=commadpt_getport(res.text); if(rc<0) { errcnt++; msg013e(dev,"RPORT",res.text); break; } dev->commadpt->rport=rc; break; case COMMADPT_KW_RHOST: if(strcmp(res.text,"*")==0) { dev->commadpt->rhost=INADDR_NONE; break; } rc=commadpt_getaddr(&dev->commadpt->rhost,res.text); if(rc!=0) { msg013e(dev,"RHOST",res.text); errcnt++; } break; case COMMADPT_KW_READTO: dev->commadpt->rto=atoi(res.text); break; case COMMADPT_KW_POLLTO: dev->commadpt->pto=atoi(res.text); break; case COMMADPT_KW_ENABLETO: dev->commadpt->eto=atoi(res.text); etospec=1; break; case COMMADPT_KW_LNCTL: if(strcasecmp(res.text,"tele2")==0 || strcasecmp(res.text,"ibm1")==0 ) { dev->commadpt->lnctl = COMMADPT_LNCTL_ASYNC; dev->commadpt->rto=28000; /* Read Time-Out in milis */ } else if(strcasecmp(res.text,"bsc")==0) { dev->commadpt->lnctl = COMMADPT_LNCTL_BSC; } else { msg013e(dev,"LNCTL",res.text); } break; case COMMADPT_KW_TERM: if(strcasecmp(res.text,"tty")==0) { dev->commadpt->term = COMMADPT_TERM_TTY; } else if(strcasecmp(res.text,"2741")==0) { dev->commadpt->term = COMMADPT_TERM_2741; } else if(strcasecmp(res.text,"rxvt4apl")==0) { dev->commadpt->term = COMMADPT_TERM_2741; dev->commadpt->rxvt4apl = 1; } else { msg013e(dev,"TERM",res.text); } break; case COMMADPT_KW_CODE: if(strcasecmp(res.text,"corr")==0) { dev->commadpt->code_table_toebcdic = xlate_table_cc_toebcdic; dev->commadpt->code_table_fromebcdic = xlate_table_cc_fromebcdic; } else if(strcasecmp(res.text,"ebcd")==0) { dev->commadpt->code_table_toebcdic = xlate_table_ebcd_toebcdic; dev->commadpt->code_table_fromebcdic = xlate_table_ebcd_fromebcdic; } else if(strcasecmp(res.text,"none")==0) { dev->commadpt->code_table_toebcdic = NULL; dev->commadpt->code_table_fromebcdic = NULL; } else { msg013e(dev,"CODE",res.text); } break; case COMMADPT_KW_CRLF: if(strcasecmp(res.text,"no")==0) { dev->commadpt->crlf_opt = FALSE; } else if(strcasecmp(res.text,"yes")==0) { dev->commadpt->crlf_opt = TRUE; } else { msg013e(dev,"CRLF",res.text); } break; case COMMADPT_KW_SENDCR: if(strcasecmp(res.text,"no")==0) { dev->commadpt->sendcr_opt = FALSE; } else if(strcasecmp(res.text,"yes")==0) { dev->commadpt->sendcr_opt = TRUE; } else { msg013e(dev,"SENDCR",res.text); } break; case COMMADPT_KW_BINARY: if(strcasecmp(res.text,"no")==0) { dev->commadpt->binary_opt = FALSE; } else if(strcasecmp(res.text,"yes")==0) { dev->commadpt->binary_opt = TRUE; } else { msg013e(dev,"BINARY",res.text); } break; case COMMADPT_KW_UCTRANS: if(strcasecmp(res.text,"no")==0) { dev->commadpt->uctrans = FALSE; } else if(strcasecmp(res.text,"yes")==0) { dev->commadpt->uctrans = TRUE; } else { msg013e(dev,"UCTRANS",res.text); } break; case COMMADPT_KW_EOL: if (strlen(res.text) < 2) break; bf[0] = res.text[0]; bf[1] = res.text[1]; bf[2] = 0; sscanf(bf, "%x", &ix); dev->commadpt->eol_char = ix; break; case COMMADPT_KW_SKIP: if (strlen(res.text) < 2) break; for (j=0; j < (int)strlen(res.text); j+= 2) { bf[0] = res.text[j+0]; bf[1] = res.text[j+1]; bf[2] = 0; sscanf(bf, "%x", &ix); dev->commadpt->byte_skip_table[ix] = 1; } break; case COMMADPT_KW_PREPEND: if (strlen(res.text) != 2 && strlen(res.text) != 4 && strlen(res.text) != 6 && strlen(res.text) != 8) break; for (j=0; j < (int)strlen(res.text); j+= 2) { bf[0] = res.text[j+0]; bf[1] = res.text[j+1]; bf[2] = 0; sscanf(bf, "%x", &ix); dev->commadpt->prepend_bytes[j>>1] = ix; } dev->commadpt->prepend_length = strlen(res.text) >> 1; break; case COMMADPT_KW_APPEND: if (strlen(res.text) != 2 && strlen(res.text) != 4 && strlen(res.text) != 6 && strlen(res.text) != 8) break; for (j=0; j < (int)strlen(res.text); j+= 2) { bf[0] = res.text[j+0]; bf[1] = res.text[j+1]; bf[2] = 0; sscanf(bf, "%x", &ix); dev->commadpt->append_bytes[j>>1] = ix; } dev->commadpt->append_length = strlen(res.text) >> 1; break; case COMMADPT_KW_ISKIP: if (strlen(res.text) < 2) break; for (j=0; j < (int)strlen(res.text); j+= 2) { bf[0] = res.text[j+0]; bf[1] = res.text[j+1]; bf[2] = 0; sscanf(bf, "%x", &ix); dev->commadpt->input_byte_skip_table[ix] = 1; } break; case COMMADPT_KW_BS: if(strcasecmp(res.text,"dumb")==0) { dev->commadpt->dumb_bs = 1; } break; case COMMADPT_KW_BREAK: if(strcasecmp(res.text,"dumb")==0) dev->commadpt->dumb_break = 1; break; case COMMADPT_KW_SWITCHED: case COMMADPT_KW_DIAL: if(strcasecmp(res.text,"yes")==0 || strcmp(res.text,"1")==0 || strcasecmp(res.text,"inout")==0) { dev->commadpt->dialin=1; dev->commadpt->dialout=1; break; } if(strcasecmp(res.text,"no")==0 || strcmp(res.text,"0")==0) { dev->commadpt->dialin=0; dev->commadpt->dialout=0; break; } if(strcasecmp(res.text,"in")==0) { dev->commadpt->dialin=1; dev->commadpt->dialout=0; break; } if(strcasecmp(res.text,"out")==0) { dev->commadpt->dialin=0; dev->commadpt->dialout=1; break; } logmsg(_("HHCCA014E %4.4X:Incorrect switched/dial specification %s; defaulting to DIAL=OUT\n"),dev->devnum,res.text); dev->commadpt->dialin=0; dev->commadpt->dialout=0; break; default: break; } } /* * Check parameters consistency * when DIAL=NO : * lport must not be 0 * lhost may be anything * rport must not be 0 * rhost must not be INADDR_NONE * when DIAL=IN or DIAL=INOUT * lport must NOT be 0 * lhost may be anything * rport MUST be 0 * rhost MUST be INADDR_NONE * when DIAL=OUT * lport MUST be 0 * lhost MUST be INADDR_ANY * rport MUST be 0 * rhost MUST be INADDR_NONE */ switch(dev->commadpt->dialin+dev->commadpt->dialout*2) { case 0: dialt="NO"; break; case 1: dialt="IN"; break; case 2: dialt="OUT"; break; case 3: dialt="INOUT"; break; default: dialt="*ERR*"; break; } switch(dev->commadpt->dialin+dev->commadpt->dialout*2) { case 0: /* DIAL = NO */ dev->commadpt->eto=0; if(dev->commadpt->lport==0) { msg015e(dev,dialt,"LPORT"); errcnt++; } if(dev->commadpt->rport==0) { msg015e(dev,dialt,"RPORT"); errcnt++; } if(dev->commadpt->rhost==INADDR_NONE) { msg015e(dev,dialt,"RHOST"); errcnt++; } if(etospec) { snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->eto); msg016w017i(dev,dialt,"ETO",fmtbfr); errcnt++; } dev->commadpt->eto=0; break; case 1: /* DIAL = IN */ case 3: /* DIAL = INOUT */ if(dev->commadpt->lport==0) { msg015e(dev,dialt,"LPORT"); errcnt++; } if(dev->commadpt->rport!=0) { snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->rport); msg016w017i(dev,dialt,"RPORT",fmtbfr); } if(dev->commadpt->rhost!=INADDR_NONE) { in_temp.s_addr=dev->commadpt->rhost; msg016w017i(dev,dialt,"RHOST",inet_ntoa(in_temp)); dev->commadpt->rhost=INADDR_NONE; } break; case 2: /* DIAL = OUT */ if(dev->commadpt->lport!=0) { snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->lport); msg016w017i(dev,dialt,"LPORT",fmtbfr); dev->commadpt->lport=0; } if(dev->commadpt->rport!=0) { snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->rport); msg016w017i(dev,dialt,"RPORT",fmtbfr); dev->commadpt->rport=0; } if(dev->commadpt->lhost!=INADDR_ANY) /* Actually it's more like INADDR_NONE */ { in_temp.s_addr=dev->commadpt->lhost; msg016w017i(dev,dialt,"LHOST",inet_ntoa(in_temp)); dev->commadpt->lhost=INADDR_ANY; } if(dev->commadpt->rhost!=INADDR_NONE) { in_temp.s_addr=dev->commadpt->rhost; msg016w017i(dev,dialt,"RHOST",inet_ntoa(in_temp)); dev->commadpt->rhost=INADDR_NONE; } break; } if(errcnt>0) { logmsg(_("HHCCA021I %4.4X:Initialisation failed due to previous errors\n"),dev->devnum); return -1; } in_temp.s_addr=dev->commadpt->lhost; in_temp.s_addr=dev->commadpt->rhost; dev->bufsize=256; dev->numsense=2; memset(dev->sense,0,sizeof(dev->sense)); /* Initialise various flags & statuses */ dev->commadpt->enabled=0; dev->commadpt->connect=0; dev->fd=100; /* Ensures 'close' function called */ dev->commadpt->devnum=dev->devnum; dev->commadpt->telnet_opt=0; dev->commadpt->telnet_iac=0; dev->commadpt->telnet_int=0; dev->commadpt->eol_flag=0; dev->commadpt->telnet_cmd=0; dev->commadpt->haltpending=0; dev->commadpt->haltprepare=0; /* Initialize the device identifier bytes */ dev->numdevid = sysblk.legacysenseid ? 7 : 0; dev->devid[0] = 0xFF; dev->devid[1] = dev->devtype >> 8; dev->devid[2] = dev->devtype & 0xFF; dev->devid[3] = 0x00; dev->devid[4] = dev->devtype >> 8; dev->devid[5] = dev->devtype & 0xFF; dev->devid[6] = 0x00; /* Initialize the CA lock */ initialize_lock(&dev->commadpt->lock); /* Initialise thread->I/O & halt initiation EVB */ initialize_condition(&dev->commadpt->ipc); initialize_condition(&dev->commadpt->ipc_halt); /* Allocate I/O -> Thread signaling pipe */ create_pipe(dev->commadpt->pipe); /* Point to the halt routine for HDV/HIO/HSCH handling */ dev->halt_device=commadpt_halt; /* Obtain the CA lock */ obtain_lock(&dev->commadpt->lock); /* Indicate listen required if DIAL!=OUT */ if(dev->commadpt->dialin || (!dev->commadpt->dialin && !dev->commadpt->dialout)) { dev->commadpt->dolisten=1; } else { dev->commadpt->dolisten=0; } /* Start the async worker thread */ /* Set thread-name for debugging purposes */ snprintf(thread_name,sizeof(thread_name), "commadpt %4.4X thread",dev->devnum); thread_name[sizeof(thread_name)-1]=0; dev->commadpt->curpending=COMMADPT_PEND_TINIT; rc = create_thread(&dev->commadpt->cthread,DETACHED,commadpt_thread,dev->commadpt,thread_name); if(rc) { logmsg(D_("HHCCA022E create_thread: %s\n"),strerror(errno)); release_lock(&dev->commadpt->lock); return -1; } commadpt_wait(dev); if(dev->commadpt->curpending!=COMMADPT_PEND_IDLE) { logmsg(_("HHCCA019E %4.4x : BSC comm thread did not initialise\n"),dev->devnum); /* Release the CA lock */ release_lock(&dev->commadpt->lock); return -1; } dev->commadpt->have_cthread=1; /* Release the CA lock */ release_lock(&dev->commadpt->lock); /* Indicate succesfull completion */ return 0; } static char *commadpt_lnctl_names[]={ "NONE", "BSC", "ASYNC" }; /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ static void commadpt_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "LINE", dev, class, buflen, buffer ); snprintf(buffer,buflen,"%s STA=%s CN=%s, EIB=%s OP=%s", commadpt_lnctl_names[dev->commadpt->lnctl], dev->commadpt->enabled?"ENA":"DISA", dev->commadpt->connect?"YES":"NO", dev->commadpt->eibmode?"YES":"NO", commadpt_pendccw_text[dev->commadpt->curpending]); } /*-------------------------------------------------------------------*/ /* Close the device */ /* Invoked by HERCULES shutdown & DEVINIT processing */ /*-------------------------------------------------------------------*/ static int commadpt_close_device ( DEVBLK *dev ) { if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Closing down\n"),dev->devnum); } /* Terminate current I/O thread if necessary */ if(dev->busy) { commadpt_halt(dev); } /* Obtain the CA lock */ obtain_lock(&dev->commadpt->lock); /* Terminate worker thread if it is still up */ if(dev->commadpt->have_cthread) { dev->commadpt->curpending=COMMADPT_PEND_SHUTDOWN; commadpt_wakeup(dev->commadpt,0); commadpt_wait(dev); dev->commadpt->cthread=(TID)-1; dev->commadpt->have_cthread=0; } /* Free all work storage */ /* The CA lock will be released by the cleanup routine */ commadpt_clean_device(dev); /* Indicate to hercules the device is no longer opened */ dev->fd=-1; if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Closed down\n"),dev->devnum); } return 0; } /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ static void commadpt_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual) { U32 num; /* Work : Actual CCW transfer count */ BYTE b; /* Input processing work variable : Current character */ BYTE setux; /* EOT kludge */ BYTE turnxpar; /* Write contains turn to transparent mode */ int i; /* work */ u_int j; /* work */ BYTE gotdle; /* Write routine DLE marker */ BYTE b1, b2; /* 2741 overstrike rewriting */ UNREFERENCED(flags); UNREFERENCED(chained); UNREFERENCED(prevcode); UNREFERENCED(ccwseq); *residual = 0; /* * Obtain the COMMADPT lock */ if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:CCW Exec - Entry code = %x\n"),dev->devnum,code); } obtain_lock(&dev->commadpt->lock); if(code != 0x06) /* for any command other than PREPARE */ { dev->commadpt->haltprepare = 0; } switch (code) { /*---------------------------------------------------------------*/ /* CONTROL NO-OP */ /*---------------------------------------------------------------*/ case 0x03: *residual=0; *unitstat=CSW_CE|CSW_DE; break; /*---------------------------------------------------------------*/ /* BASIC SENSE */ /*---------------------------------------------------------------*/ case 0x04: num=countnumsense?count:dev->numsense; *more=countnumsense?1:0; memcpy(iobuf,dev->sense,num); *residual=count-num; *unitstat=CSW_CE|CSW_DE; break; /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ case 0xE4: /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; *more = count < dev->numdevid ? 1 : 0; /* Copy device identifier bytes to channel I/O Buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; /*---------------------------------------------------------------*/ /* ENABLE */ /*---------------------------------------------------------------*/ case 0x27: if(dev->commadpt->dialin+dev->commadpt->dialout*2==2) { /* Enable makes no sense on a dial out only line */ *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; dev->sense[1]=0x2E; /* Simulate Failed Call In */ break; } if(dev->commadpt->connect) { /* Already connected */ dev->commadpt->enabled=1; *unitstat=CSW_CE|CSW_DE; break; } dev->commadpt->curpending=COMMADPT_PEND_ENABLE; commadpt_wakeup(dev->commadpt,0); commadpt_wait(dev); /* If the line is not connected now, then ENABLE failed */ if(dev->commadpt->connect) { *unitstat=CSW_CE|CSW_DE; dev->commadpt->enabled=1; /* Clean the input buffer */ commadpt_ring_flush(&dev->commadpt->inbfr); break; } if(dev->commadpt->haltpending) { *unitstat=CSW_CE|CSW_DE|CSW_UX; dev->commadpt->haltpending=0; break; } if(dev->commadpt->dialin) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; dev->sense[1]=0x2e; } else { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; dev->sense[1]=0x21; } break; /*---------------------------------------------------------------*/ /* DISABLE */ /*---------------------------------------------------------------*/ case 0x2F: /* Reset some flags */ dev->commadpt->xparwwait=0; commadpt_ring_flush(&dev->commadpt->inbfr); /* Flush buffers */ commadpt_ring_flush(&dev->commadpt->outbfr); /* Flush buffers */ commadpt_ring_flush(&dev->commadpt->ttybuf); /* Flush buffers */ if((!dev->commadpt->dialin && !dev->commadpt->dialout) || !dev->commadpt->connect) { *unitstat=CSW_CE|CSW_DE; dev->commadpt->enabled=0; break; } dev->commadpt->curpending=COMMADPT_PEND_DISABLE; commadpt_wakeup(dev->commadpt,0); commadpt_wait(dev); dev->commadpt->enabled=0; *unitstat=CSW_CE|CSW_DE; break; /*---------------------------------------------------------------*/ /* SET MODE */ /*---------------------------------------------------------------*/ case 0x23: /* Transparent Write Wait State test */ if(dev->commadpt->xparwwait) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; return; } num=1; *residual=count-num; *unitstat=CSW_CE|CSW_DE; if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X Set Mode : %s\n"),dev->devnum,iobuf[0]&0x40 ? "EIB":"NO EIB"); } dev->commadpt->eibmode=(iobuf[0]&0x40)?1:0; break; /*---------------------------------------------------------------*/ /* POLL Command */ /*---------------------------------------------------------------*/ case 0x09: /* Transparent Write Wait State test */ if(dev->commadpt->xparwwait) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; return; } /* Save POLL data */ commadpt_ring_flush(&dev->commadpt->pollbfr); commadpt_ring_pushbfr(&dev->commadpt->pollbfr,iobuf,count); /* Set some utility variables */ dev->commadpt->pollused=0; dev->commadpt->badpoll=0; /* Tell thread */ dev->commadpt->curpending=COMMADPT_PEND_POLL; commadpt_wakeup(dev->commadpt,0); commadpt_wait(dev); /* Flush the output & poll rings */ commadpt_ring_flush(&dev->commadpt->outbfr); commadpt_ring_flush(&dev->commadpt->pollbfr); /* Check for HALT */ if(dev->commadpt->haltpending) { *unitstat=CSW_CE|CSW_DE|CSW_UX; dev->commadpt->haltpending=0; break; } /* Check for bad poll data */ if(dev->commadpt->badpoll) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=0x08; dev->sense[1]=0x84; break; } /* Determine remaining length */ *residual=count-dev->commadpt->pollused; /* Determine if SM should be set (succesfull or unsucessfull POLLs) */ /* exhausting poll data when all stations reported NO data */ /* does not set Status Modifier */ *unitstat=CSW_CE|CSW_DE|(dev->commadpt->pollsm?CSW_SM:0); /* NOTE : The index byte (and rest) are in the Input Ring */ break; /*---------------------------------------------------------------*/ /* DIAL */ /* Info on DIAL DATA : */ /* Dial character formats : */ /* x x x x 0 0 0 0 : 0 */ /* ........ */ /* x x x x 1 0 0 1 : 9 */ /* x x x x 1 1 0 0 : SEP */ /* x x x x 1 1 0 1 : EON */ /* EON is ignored */ /* format is : AAA/SEP/BBB/SEP/CCC/SEP/DDD/SEP/PPPP */ /* where A,B,C,D,P are numbers from 0 to 9 */ /* This perfoms an outgoing call to AAA.BBB.CCC.DDD port PPPP */ /*---------------------------------------------------------------*/ case 0x29: /* The line must have dial-out capability */ if(!dev->commadpt->dialout) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; dev->sense[1]=0x04; break; } /* The line must be disabled */ if(dev->commadpt->enabled) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; dev->sense[1]=0x05; break; } num=count>sizeof(dev->commadpt->dialdata) ? sizeof(dev->commadpt->dialdata) : count; memcpy(dev->commadpt->dialdata,iobuf,num); dev->commadpt->curpending=COMMADPT_PEND_DIAL; commadpt_wakeup(dev->commadpt,0); commadpt_wait(dev); *residual=count-num; if(dev->commadpt->haltpending) { *unitstat=CSW_CE|CSW_DE|CSW_UX; dev->commadpt->haltpending=0; break; } if(!dev->commadpt->connect) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; dev->commadpt->enabled=0; } else { *unitstat=CSW_CE|CSW_DE; dev->commadpt->enabled=1; } break; /*---------------------------------------------------------------*/ /* READ */ /*---------------------------------------------------------------*/ case 0x02: case 0x0a: /* also INHIBIT */ setux=0; /* Check the line is enabled */ if(!dev->commadpt->enabled) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; dev->sense[1]=0x06; break; } /* Transparent Write Wait State test */ if(dev->commadpt->xparwwait) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; break; } /* Check for any remaining data in read work buffer */ /* for async, we allow all reads to wait (even if data is available now) */ /* (APL\360 2741 race cond III circumvention) see APLSASUP label UNRZ19 */ if(dev->commadpt->readcomp && IS_BSC_LNCTL(dev->commadpt)) { if (dev->commadpt->rdwrk.havedata) { num=(U32)commadpt_ring_popbfr(&dev->commadpt->rdwrk,iobuf,count); if(dev->commadpt->rdwrk.havedata) { *more=1; } *residual=count-num; *unitstat=CSW_CE|CSW_DE; break; } } if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int) { dev->commadpt->telnet_int = 0; *residual=count; *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; break; } /* Catch a race condition. */ /* TCAM likes to issue halt I/O as a matter of routine, and it expects to get back a */ /* unit exception along with the normal channel end + device end. */ /* Sometimes the halt I/O loses the race (with the write CCW) and we catch up here. */ if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->haltpending) { dev->commadpt->haltpending = 0; *residual=0; *unitstat=CSW_CE|CSW_DE|CSW_UX; break; } #if 0 // MHP TEST 2740 *residual=count; *unitstat=CSW_CE|CSW_DE; break; #endif if(dev->commadpt->datalostcond) { dev->commadpt->datalostcond=0; commadpt_ring_flush(&dev->commadpt->inbfr); *residual=count; *unitstat=CSW_CE|CSW_DE; break; } dev->commadpt->readcomp=0; *unitstat=0; num=0; /* The following is the BIG READ ROUTINE MESS */ /* the manual's indications on when to exit */ /* a read and what to transfer to the main */ /* storage is fuzzy (at best) */ /* */ /* The line input can be in 3 possible */ /* conditions : */ /* Transparent Text Mode */ /* Text Mode */ /* none of the above (initial status) */ /* transition from one mode to the other is */ /* also not very well documented */ /* so the following code is based on */ /* empirical knowledge and some interpretation*/ /* also... the logic should probably be */ /* rewritten */ /* We will remain in READ state with the thread */ /* as long as we haven't met a read ending condition */ while(1) { /* READ state */ dev->commadpt->curpending=COMMADPT_PEND_READ; /* Tell worker thread */ commadpt_wakeup(dev->commadpt,0); /* Wait for some data */ commadpt_wait(dev); /* If we are not connected, the read fails */ if(!dev->commadpt->connect) { *unitstat=CSW_DE|CSW_CE|CSW_UC; dev->sense[0]=SENSE_IR; break; } /* If the I/O was halted - indicate Unit Check */ if(dev->commadpt->haltpending) { *unitstat=CSW_CE|CSW_DE|CSW_UX; dev->commadpt->haltpending=0; break; } if (IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int) { dev->commadpt->telnet_int = 0; *residual=count; *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; break; } /* If no data is present - 3 seconds have passed without */ /* receiving data (or a SYNC) */ /* (28 seconds for LNCTL_ASYNC) */ /* INHIBIT command does not time out */ /* eol_flag set means data is present */ if(!dev->commadpt->inbfr.havedata && code != 0x0a && !dev->commadpt->eol_flag) { *unitstat=CSW_DE|CSW_CE|CSW_UC; dev->sense[0]=0x01; dev->sense[1]=0xe3; break; } if (IS_BSC_LNCTL(dev->commadpt)) { /* Start processing data flow here */ /* Pop bytes until we run out of data or */ /* until the processing indicates the read */ /* should now terminate */ while( dev->commadpt->inbfr.havedata && !dev->commadpt->readcomp) { /* fetch 1 byte from the input ring */ b=commadpt_ring_pop(&dev->commadpt->inbfr); if(!dev->commadpt->gotdle) { if(b==0x10) { dev->commadpt->gotdle=1; continue; } } if(dev->commadpt->in_textmode) { if(dev->commadpt->in_xparmode) { /* TRANSPARENT MODE READ */ if(dev->commadpt->gotdle) { switch(b) { case 0x10: commadpt_ring_push(&dev->commadpt->rdwrk,b); break; case 0x32: break; case 0x1F: /* ITB - Exit xparent, set EIB - do NOT exit read yet */ dev->commadpt->in_xparmode=0; commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); if(dev->commadpt->eibmode) { commadpt_ring_push(&dev->commadpt->rdwrk,0); } break; case 0x26: /* ETB - Same as ITB but DO exit read now */ dev->commadpt->in_xparmode=0; commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); if(dev->commadpt->eibmode) { commadpt_ring_push(&dev->commadpt->rdwrk,0); } dev->commadpt->readcomp=1; break; case 0x03: /* ETX - Same as ETB */ dev->commadpt->in_xparmode=0; commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); if(dev->commadpt->eibmode) { commadpt_ring_push(&dev->commadpt->rdwrk,0); } dev->commadpt->readcomp=1; break; case 0x2D: /* ENQ */ dev->commadpt->in_xparmode=0; dev->commadpt->in_textmode=0; commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); dev->commadpt->readcomp=1; break; default: commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); break; } } else { commadpt_ring_push(&dev->commadpt->rdwrk,b); } } else { if(b!=0x32) { /* TEXT MODE READ */ if(dev->commadpt->gotdle) { switch(b) { case 0x02: /* STX */ dev->commadpt->in_xparmode=1; break; case 0x2D: /* ENQ */ dev->commadpt->readcomp=1; break; default: if((b&0xf0)==0x60 || (b&0xf0)==0x70) { dev->commadpt->readcomp=1; } break; } commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); } else { switch(b) { case 0x2D: /* ENQ */ dev->commadpt->readcomp=1; dev->commadpt->in_textmode=0; commadpt_ring_push(&dev->commadpt->rdwrk,b); break; case 0x3D: /* NAK */ dev->commadpt->readcomp=1; commadpt_ring_push(&dev->commadpt->rdwrk,b); break; case 0x26: /* ETB */ case 0x03: /* ETX */ dev->commadpt->readcomp=1; dev->commadpt->in_textmode=0; commadpt_ring_push(&dev->commadpt->rdwrk,b); if(dev->commadpt->eibmode) { commadpt_ring_push(&dev->commadpt->rdwrk,0); } break; case 0x1F: /* ITB */ commadpt_ring_push(&dev->commadpt->rdwrk,b); if(dev->commadpt->eibmode) { commadpt_ring_push(&dev->commadpt->rdwrk,0); } break; default: commadpt_ring_push(&dev->commadpt->rdwrk,b); break; } } } } } else { if(b!=0x32) { if(dev->commadpt->gotdle) { if((b & 0xf0) == 0x60 || (b&0xf0)==0x70) { commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); dev->commadpt->readcomp=1; } else { if(b==0x02) { commadpt_ring_push(&dev->commadpt->rdwrk,0x10); commadpt_ring_push(&dev->commadpt->rdwrk,b); dev->commadpt->in_textmode=1; dev->commadpt->in_xparmode=1; } } } else { switch(b) { case 0x37: /* EOT */ setux=1; dev->commadpt->readcomp=1; break; case 0x01: case 0x02: dev->commadpt->in_textmode=1; break; case 0x2D: /* ENQ */ dev->commadpt->readcomp=1; break; case 0x3D: /* NAK */ dev->commadpt->readcomp=1; break; default: break; } commadpt_ring_push(&dev->commadpt->rdwrk,b); } } } dev->commadpt->gotdle=0; } /* END WHILE - READ FROM DATA BUFFER */ } /* end of if (bsc) */ /* If readcomp is set, then we may exit the read loop */ if(dev->commadpt->readcomp || dev->commadpt->eol_flag) { if (dev->commadpt->rdwrk.havedata || dev->commadpt->eol_flag) { num=commadpt_ring_popbfr(&dev->commadpt->rdwrk,iobuf,count); if(dev->commadpt->rdwrk.havedata) { *more=1; } *residual=count-num; *unitstat=CSW_CE|CSW_DE|(setux?CSW_UX:0); logdump("Read",dev,iobuf,num); if(IS_ASYNC_LNCTL(dev->commadpt)&& !dev->commadpt->rdwrk.havedata && *residual > 0) dev->commadpt->eol_flag = 0; break; } } } /* END WHILE - READ FROM THREAD */ break; /*---------------------------------------------------------------*/ /* WRITE */ /*---------------------------------------------------------------*/ case 0x01: case 0x0d: /* also CCW=BREAK */ logdump("Writ",dev,iobuf,count); *residual=count; /* Check if we have an opened path */ if(!dev->commadpt->connect) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; break; } /* Check if the line has been enabled */ if(!dev->commadpt->enabled) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; break; } dev->commadpt->haltpending = 0; /* circumvent APL\360 2741 race cond II */ /* read 1 byte to check for pending input */ i=read_socket(dev->commadpt->sfd,&b,1); if (IS_ASYNC_LNCTL(dev->commadpt)) { if(i>0) { logdump("RCV0",dev,&b,1); commadpt_read_tty(dev->commadpt,&b,1); } } else { if(i>0) { /* Push it in the communication input buffer ring */ commadpt_ring_push(&dev->commadpt->inbfr,b); } /* Set UX on write if line has pending inbound data */ if(dev->commadpt->inbfr.havedata) { dev->commadpt->datalostcond=1; *unitstat=CSW_CE|CSW_DE|CSW_UX; break; } } /* end of else (async) */ /* * Fill in the Write Buffer */ /* To start : not transparent mode, no DLE received yet */ turnxpar=0; gotdle=0; if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int /* ugly hack for TSO ATTN to fix IEA000I 0C3,IOE,01,0E40,40008900002C,,,TCAM */ && !(iobuf[0] == 0xdf && iobuf[1] == 0xdf && iobuf[2] == 0xdf && count == 3)) { dev->commadpt->telnet_int = 0; *residual=count; *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; break; } /* Scan the I/O buffer */ for(i=0;icommadpt)) { if (dev->commadpt->byte_skip_table[b]) continue; if (dev->commadpt->term == COMMADPT_TERM_TTY) { b = byte_reverse_table[b] & 0x7f; } else { /* 2741 */ if (count == 1 && b == CIRCLE_D) { b = 0x00; /* map initial Circle-D to NUL */ } else if (dev->commadpt->rxvt4apl) { if (dev->commadpt->overstrike_flag == 1 && (b & 0x7f) == 0x5d) { /* char is another backspace but overstrike was expected */ dev->commadpt->overstrike_flag = 0; dev->commadpt->saved_char = b; b = rxvt4apl_from_2741[b]; } else if (dev->commadpt->overstrike_flag == 1) { dev->commadpt->overstrike_flag = 0; if (((u_int)dev->commadpt->saved_char) > ((u_int)b)) { b1 = b; b2 = dev->commadpt->saved_char; } else { b1 = dev->commadpt->saved_char; b2 = b; } b = '?'; for (j = 0; j < sizeof(overstrike_2741_pairs); j+=2) { if (overstrike_2741_pairs[j] == b1 && overstrike_2741_pairs[j+1] == b2) { b = overstrike_rxvt4apl_chars[j>>1]; } } } else if ((b & 0x7f) == 0x5d /* 2741 backspace */ && (dev->commadpt->saved_char & 0x7f) != 0x5d && (dev->commadpt->saved_char & 0x7f) != 0x3b && (dev->commadpt->saved_char & 0x7f) != 0x7f) { dev->commadpt->overstrike_flag = 1; b = rxvt4apl_from_2741[b]; } else { dev->commadpt->overstrike_flag = 0; dev->commadpt->saved_char = b; b = rxvt4apl_from_2741[b]; if (b == 0x0d && dev->commadpt->crlf_opt) /* ascii CR? */ { /* 2741 NL has been mapped to CR, we need to append LF to this (sigh) */ commadpt_ring_push(&dev->commadpt->outbfr,b); b = 0x0a; } } } else if (dev->commadpt->code_table_toebcdic) { b = dev->commadpt->code_table_toebcdic[b]; // first translate to EBCDIC b = guest_to_host(b) & 0x7f; // then EBCDIC to ASCII } } } else { /* line is BSC */ /* If we are in transparent mode, we must double the DLEs */ if(turnxpar) { /* Check for a DLE */ if(b==0x10) { /* put another one in the output buffer */ commadpt_ring_push(&dev->commadpt->outbfr,0x10); } } else /* non transparent mode */ { if(b==0x10) { gotdle=1; /* Indicate we have a DLE for next pass */ } else { /* If there was a DLE on previous pass */ if(gotdle) { /* check for DLE/ETX */ if(b==0x02) { /* Indicate transparent mode on */ turnxpar=1; } } } } } /* end of else (async) */ /* Put the current byte on the output ring */ commadpt_ring_push(&dev->commadpt->outbfr,b); } if (IS_BSC_LNCTL(dev->commadpt)) { /* If we had a DLE/STX, the line is now in Transparent Write Wait state */ /* meaning that no CCW codes except Write, No-Op, Sense are allowed */ /* (that's what the manual says.. I doubt DISABLE is disallowed) */ /* Anyway.. The program will have an opportunity to turn XPARENT mode */ /* off on the next CCW. */ /* CAVEAT : The manual doesn't say if the line remains in transparent */ /* Write Wait state if the next CCW doesn't start with DLE/ETX */ /* or DLE/ITB */ if(turnxpar) { dev->commadpt->xparwwait=1; } else { dev->commadpt->xparwwait=0; } } /* end of if(bsc line) */ /* Indicate to the worker thread the current operation is OUTPUT */ dev->commadpt->curpending=COMMADPT_PEND_WRITE; /* All bytes written out - residual = 0 */ *residual=0; /* Wake-up the worker thread */ commadpt_wakeup(dev->commadpt,0); /* Wait for operation completion */ commadpt_wait(dev); /* Check if the line is still connected */ if(!dev->commadpt->connect) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; break; } /* Check if the I/O was interrupted */ if(dev->commadpt->haltpending) { *unitstat=CSW_CE|CSW_DE|CSW_UX; dev->commadpt->haltpending = 0; break; } *unitstat=CSW_CE|CSW_DE; break; /*---------------------------------------------------------------*/ /* PREPARE */ /* NOTE : DO NOT SET RESIDUAL to 0 : Otherwise, channel.c */ /* will reflect a channel prot check - residual */ /* should indicate NO data was transfered for this */ /* pseudo-read operation */ /*---------------------------------------------------------------*/ case 0x06: *residual=count; /* PREPARE not allowed unless line is enabled */ if(!dev->commadpt->enabled) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; dev->sense[1]=0x06; break; } if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->haltprepare) { /* circumvent APL\360 2741 race cond I */ *unitstat=CSW_CE|CSW_DE|CSW_UX; break; } /* end of if(async) */ if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int) { dev->commadpt->telnet_int = 0; *unitstat=CSW_CE|CSW_DE; if(dev->commadpt->haltpending) { dev->commadpt->haltpending=0; *unitstat |= CSW_UX; } break; } /* end of if(async) */ /* Transparent Write Wait State test */ if(dev->commadpt->xparwwait) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_CR; return; } /* If data is present, prepare ends immediatly */ if(dev->commadpt->inbfr.havedata) { *unitstat=CSW_CE|CSW_DE; break; } /* Indicate to the worker thread to notify us when data arrives */ dev->commadpt->curpending=COMMADPT_PEND_PREPARE; /* Wakeup worker thread */ commadpt_wakeup(dev->commadpt,0); /* Wait for completion */ commadpt_wait(dev); /* If I/O was halted (this one happens often) */ if(dev->commadpt->haltpending) { *unitstat=CSW_CE|CSW_DE|CSW_UX; dev->commadpt->haltpending=0; break; } /* Check if the line is still connected */ if(!dev->commadpt->connect) { *unitstat=CSW_CE|CSW_DE|CSW_UC; dev->sense[0]=SENSE_IR; break; } /* Normal Prepare exit condition - data is present in the input buffer */ *unitstat=CSW_CE|CSW_DE; dev->commadpt->telnet_int = 0; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ *unitstat=CSW_CE+CSW_DE+CSW_UC; dev->sense[0]=SENSE_CR; break; } release_lock(&dev->commadpt->lock); } /*---------------------------------------------------------------*/ /* DEVICE FUNCTION POINTERS */ /*---------------------------------------------------------------*/ #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND comadpt_device_hndinfo = { &commadpt_init_handler, /* Device Initialisation */ &commadpt_execute_ccw, /* Device CCW execute */ &commadpt_close_device, /* Device Close */ &commadpt_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ commadpt_immed_command, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt2703_LTX_hdl_ddev #define hdl_depc hdt2703_LTX_hdl_depc #define hdl_reso hdt2703_LTX_hdl_reso #define hdl_init hdt2703_LTX_hdl_init #define hdl_fini hdt2703_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); } END_DEPENDENCY_SECTION #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR( psysblk, sysblk ); } END_RESOLVER_SECTION #endif HDL_DEVICE_SECTION; { HDL_DEVICE(2703, comadpt_device_hndinfo ); } END_DEVICE_SECTION #endif hercules-3.12/hchan.c0000664000175000017500000001707512564723224011442 00000000000000/* HCHAN.C (c) Copyright Ivan Warren, 2005-2009 */ /* Generic channel device handler */ /* Based on work (c)Roger Bowler, Jan Jaeger & Others 1999-2009 */ /* This code is covered by the QPL Licence */ /**CAUTION*CAUTION*CAUTION*CAUTION*CAUTION*CAUTION*CAUTION*CAUTION****/ /* THIS CODE IS CURRENTLY IN A DEVELOPMENT STAGE AND IS NOT */ /* OPERATIONAL */ /* THIS FONCTIONALITY IS NOT YET SUPPORTED */ /**CAUTION*CAUTION*CAUTION*CAUTION*CAUTION*CAUTION*CAUTION*CAUTION****/ /*-------------------------------------------------------------------*/ /* This module contains code to handle a generic protocol to */ /* communicate with external device handlers. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "hchan.h" #if defined(OPTION_DYNAMIC_LOAD) && defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) SYSBLK *psysblk; #define sysblk (*psysblk) #endif /* * Initialisation string for a Generic Subchannel * * Format : * parms * The 'EXEC' method will attempt to fork/exec the specified * program. If the program dies during device initialisation, the * subchannel will be invalidated (initialisation error). If it fails * afterwards, the subchannel will be put offline and the offload * thread will attempt to restart it at periodic intervals. * The 'CONNECT' method will attempt to establish a TCP connection * to the IP/PORT specified. If the connection fails, the connection * will be attempted at periodic intervals. * The 'ITHREAD' method will spawn a thread using a dynamically loaded module */ static int hchan_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { int rc; dev->devtype=0x2880; /* Temporary until the device is actually initialised */ while(1) { if(argc<1) { logmsg("HHCGCH003E %4.4X : Missing Generic Channel method\n",dev->devnum); rc=-1; break; } if(strcasecmp(argv[0],"EXEC")==0) { rc=hchan_init_exec(dev,argc,argv); break; } if(strcasecmp(argv[0],"CONNECT")==0) { rc=hchan_init_connect(dev,argc,argv); break; } if(strcasecmp(argv[0],"ITHREAD")==0) { rc=hchan_init_int(dev,argc,argv); break; } logmsg("HHCGCH001E %4.4X : Incorrect Generic Channel method %s\n",dev->devnum,argv[0]); rc=-1; break; } if(rc) { logmsg("HHCGCH002T %4.4X : Generic channel initialisation failed\n",dev->devnum); } logmsg("HHCGCH999W %4.4X : Generic channel is currently in development\n",dev->devnum); return(rc); } static int hchan_init_exec(DEVBLK *dev,int ac,char **av) { UNREFERENCED(dev); UNREFERENCED(ac); UNREFERENCED(av); return(0); } static int hchan_init_connect(DEVBLK *dev,int ac,char **av) { UNREFERENCED(dev); UNREFERENCED(ac); UNREFERENCED(av); return(0); } static int hchan_init_int(DEVBLK *dev,int ac,char **av) { UNREFERENCED(dev); UNREFERENCED(ac); UNREFERENCED(av); return(0); } /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ static void hchan_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "CHAN", dev, class, buflen, buffer ); snprintf(buffer,buflen,"** CONTROL UNIT OFFLINE **"); } /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ static int hchan_close_device ( DEVBLK *dev ) { UNREFERENCED(dev); return 0; } /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ static void hchan_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { UNREFERENCED(flags); UNREFERENCED(prevcode); UNREFERENCED(ccwseq); UNREFERENCED(chained); UNREFERENCED(count); UNREFERENCED(iobuf); UNREFERENCED(more); UNREFERENCED(residual); /* Process depending on CCW opcode */ switch (code) { default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } } #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND hchan_device_hndinfo = { &hchan_init_handler, /* Device Initialisation */ &hchan_execute_ccw, /* Device CCW execute */ &hchan_close_device, /* Device Close */ &hchan_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt0000_LTX_hdl_ddev #define hdl_depc hdt0000_LTX_hdl_depc #define hdl_reso hdt0000_LTX_hdl_reso #define hdl_init hdt0000_LTX_hdl_init #define hdl_fini hdt0000_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); } END_DEPENDENCY_SECTION #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR( psysblk, sysblk ); } END_RESOLVER_SECTION #endif HDL_DEVICE_SECTION; { HDL_DEVICE(HCHAN, hchan_device_hndinfo ); HDL_DEVICE(2860, hchan_device_hndinfo ); HDL_DEVICE(2870, hchan_device_hndinfo ); HDL_DEVICE(2880, hchan_device_hndinfo ); HDL_DEVICE(9032, hchan_device_hndinfo ); } END_DEVICE_SECTION #endif hercules-3.12/ctc_lcs.c0000664000175000017500000026264412564723224011777 00000000000000/* CTC_LCS.C (c) Copyright James A. Pierson, 2002-2012 */ /* (c) Copyright "Fish" (David B. Trout), 2002-2011 */ /* Hercules LAN Channel Station Support */ #include "hstdinc.h" /* jbs 10/27/2007 added _SOLARIS_ */ #if !defined(__SOLARIS__) #include "hercules.h" #include "ctcadpt.h" #include "tuntap.h" #include "hercifc.h" #include "opcode.h" #include "herc_getopt.h" #if defined(OPTION_W32_CTCI) #include "tt32api.h" #endif //----------------------------------------------------------------------------- // Debugging... //#define NO_LCS_OPTIMIZE // #undef for Release, #define while testing #if !defined( DEBUG) && !defined( _DEBUG ) // only needed for Release builds #ifdef NO_LCS_OPTIMIZE // for reliable breakpoints and instr stepping #pragma optimize( "", off ) // disable optimizations for reliable breakpoints #pragma warning( push ) // save current settings #pragma warning( disable: 4748 ) // C4748: /GS can not ... because optimizations are disabled... #endif // NO_LCS_OPTIMIZE #endif // !defined( DEBUG) && !defined( _DEBUG ) #ifdef NO_LCS_OPTIMIZE #undef ASSERT #undef VERIFY #ifdef _MSVC_ #define ASSERT(a) \ do \ { \ if (!(a)) \ { \ logmsg("HHCxx999W *** Assertion Failed! *** %s(%d); function: %s\n",__FILE__,__LINE__,__FUNCTION__); \ if (IsDebuggerPresent()) DebugBreak(); /* (break into debugger) */ \ } \ } \ while(0) #else // ! _MSVC_ #define ASSERT(a) \ do \ { \ if (!(a)) \ { \ logmsg("HHCxx999W *** Assertion Failed! *** %s(%d)\n",__FILE__,__LINE__); \ } \ } \ while(0) #endif // _MSVC_ #define VERIFY(a) ASSERT((a)) #endif // NO_LCS_OPTIMIZE //----------------------------------------------------------------------------- /* CCW Codes 0x03 & 0xC3 are immediate commands */ static BYTE CTC_Immed_Commands [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */ 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* E0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* F0 */ }; // ==================================================================== // Declarations // ==================================================================== static void LCS_Startup ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ); static void LCS_Shutdown ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ); static void LCS_StartLan ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ); static void LCS_StopLan ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ); static void LCS_QueryIPAssists( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ); static void LCS_LanStats ( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ); static void LCS_DefaultCmdProc( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ); static void* LCS_PortThread( PLCSPORT pLCSPORT ); static int LCS_EnqueueEthFrame( PLCSDEV pLCSDEV, BYTE bPort, BYTE* pData, size_t iSize ); static int LCS_EnqueueReplyFrame( PLCSDEV pLCSDEV, PLCSCMDHDR pReply, size_t iSize ); static int BuildOAT( char* pszOATName, PLCSBLK pLCSBLK ); static char* ReadOAT( char* pszOATName, FILE* fp, char* pszBuff ); static int ParseArgs( DEVBLK* pDEVBLK, PLCSBLK pLCSBLK, int argc, char** argv ); // ==================================================================== // Helper macros // ==================================================================== #define INIT_REPLY_FRAME( reply, pCmdFrame ) \ \ memset( &(reply), 0, sizeof( reply )); \ memcpy( &(reply), (pCmdFrame), sizeof( LCSCMDHDR )); \ STORE_HW( (reply).bLCSCmdHdr.hwReturnCode, 0x0000 ) #define ENQUEUE_REPLY_FRAME( pLCSDEV, reply ) \ \ while \ (1 \ && LCS_EnqueueReplyFrame( (pLCSDEV), (PLCSCMDHDR) &(reply), \ sizeof( reply )) != 0 \ && (pLCSDEV)->pLCSBLK->Port[(pLCSDEV)->bPort].fd != -1 \ && !(pLCSDEV)->pLCSBLK->Port[(pLCSDEV)->bPort].fCloseInProgress \ ) \ { \ TRACE("** ENQUEUE_REPLY_FRAME() failed...\n"); \ SLEEP( 1 ); \ } // ==================================================================== // find_group_device // ==================================================================== static DEVBLK * find_group_device(DEVGRP *group, U16 devnum) { int i; for(i = 0; i < group->acount; i++) if( group->memdev[i]->devnum == devnum ) return group->memdev[i]; return NULL; } // ==================================================================== // LCS_Init // ==================================================================== int LCS_Init( DEVBLK* pDEVBLK, int argc, char *argv[] ) { PLCSBLK pLCSBLK; PLCSDEV pLCSDev; int i; struct in_addr addr; // Work area for addresses pDEVBLK->devtype = 0x3088; // Return when an existing group has been joined but is still incomplete if(!group_device(pDEVBLK, 0) && pDEVBLK->group) return 0; // We need to create a group, and as such determine the number of devices if(!pDEVBLK->group) { // Housekeeping pLCSBLK = malloc( sizeof( LCSBLK ) ); if( !pLCSBLK ) { logmsg( _("HHCLC001E %4.4X unable to allocate LCSBLK\n"), pDEVBLK->devnum ); return -1; } memset( pLCSBLK, 0, sizeof( LCSBLK ) ); for( i = 0; i < LCS_MAX_PORTS; i++ ) { memset( &pLCSBLK->Port[i], 0, sizeof ( LCSPORT ) ); pLCSBLK->Port[i].bPort = i; pLCSBLK->Port[i].pLCSBLK = pLCSBLK; // Initialize locking and event mechanisms initialize_lock( &pLCSBLK->Port[i].Lock ); initialize_lock( &pLCSBLK->Port[i].EventLock ); initialize_condition( &pLCSBLK->Port[i].Event ); } // Parse configuration file statement if( ParseArgs( pDEVBLK, pLCSBLK, argc, (char**)argv ) != 0 ) { free( pLCSBLK ); pLCSBLK = NULL; return -1; } if( pLCSBLK->pszOATFilename ) { // If an OAT file was specified, Parse it and build the // OAT table. if( BuildOAT( pLCSBLK->pszOATFilename, pLCSBLK ) != 0 ) { free( pLCSBLK ); pLCSBLK = NULL; return -1; } } else { // Otherwise, build an OAT based on the address specified // in the config file with an assumption of IP mode. pLCSBLK->pDevices = malloc( sizeof( LCSDEV ) ); memset( pLCSBLK->pDevices, 0, sizeof( LCSDEV ) ); if( pLCSBLK->pszIPAddress ) inet_aton( pLCSBLK->pszIPAddress, &addr ); pLCSBLK->pDevices->sAddr = pDEVBLK->devnum; pLCSBLK->pDevices->bMode = LCSDEV_MODE_IP; pLCSBLK->pDevices->bPort = 0; pLCSBLK->pDevices->bType = 0; pLCSBLK->pDevices->lIPAddress = addr.s_addr; // (network byte order) pLCSBLK->pDevices->pszIPAddress = pLCSBLK->pszIPAddress; pLCSBLK->pDevices->pNext = NULL; pLCSBLK->icDevices = 2; } // Now we must create the group if(!group_device(pDEVBLK, pLCSBLK->icDevices)) { pDEVBLK->group->grp_data = pLCSBLK; return 0; } else pDEVBLK->group->grp_data = pLCSBLK; } else pLCSBLK = pDEVBLK->group->grp_data; // When this code is reached the last devblk has been allocated... // // Now build the LCSDEV's. // If an OAT is specified, the addresses that were specified in the // hercules.cnf file must match those that are specified in the OAT. for( pLCSDev = pLCSBLK->pDevices; pLCSDev; pLCSDev = pLCSDev->pNext ) { pLCSDev->pDEVBLK[0] = find_group_device(pDEVBLK->group, pLCSDev->sAddr); if( !pLCSDev->pDEVBLK[0] ) { logmsg(D_("HHCLC040E %4.4X LCSDEV %4.4X not in configuration\n"), pDEVBLK->group->memdev[0]->devnum, pLCSDev->sAddr ); return -1; } // Establish SENSE ID and Command Information Word data. SetSIDInfo( pLCSDev->pDEVBLK[0], 0x3088, 0x60, 0x3088, 0x01 ); // SetCIWInfo( pLCSDev->pDEVBLK[0], 0, 0, 0x72, 0x0080 ); // SetCIWInfo( pLCSDev->pDEVBLK[0], 1, 1, 0x83, 0x0004 ); // SetCIWInfo( pLCSDev->pDEVBLK[0], 2, 2, 0x82, 0x0040 ); pLCSDev->pDEVBLK[0]->ctctype = CTC_LCS; pLCSDev->pDEVBLK[0]->ctcxmode = 1; pLCSDev->pDEVBLK[0]->dev_data = pLCSDev; pLCSDev->pLCSBLK = pLCSBLK; strcpy( pLCSDev->pDEVBLK[0]->filename, pLCSBLK->pszTUNDevice ); // If this is an IP Passthru address, we need a write address if( pLCSDev->bMode == LCSDEV_MODE_IP ) { pLCSDev->pDEVBLK[1] = find_group_device(pDEVBLK->group, pLCSDev->sAddr^1); if( !pLCSDev->pDEVBLK[1] ) { logmsg(D_("HHCLC040E %4.4X LCSDEV %4.4X not in configuration\n"), pDEVBLK->group->memdev[0]->devnum, pLCSDev->sAddr^1 ); return -1; } // Establish SENSE ID and Command Information Word data. SetSIDInfo( pLCSDev->pDEVBLK[1], 0x3088, 0x60, 0x3088, 0x01 ); // SetCIWInfo( pLCSDev->pDEVBLK[1], 0, 0, 0x72, 0x0080 ); // SetCIWInfo( pLCSDev->pDEVBLK[1], 1, 1, 0x83, 0x0004 ); // SetCIWInfo( pLCSDev->pDEVBLK[1], 2, 2, 0x82, 0x0040 ); pLCSDev->pDEVBLK[1]->ctctype = CTC_LCS; pLCSDev->pDEVBLK[1]->ctcxmode = 1; pLCSDev->pDEVBLK[1]->dev_data = pLCSDev; strcpy( pLCSDev->pDEVBLK[1]->filename, pLCSBLK->pszTUNDevice ); } // Indicate that the DEVBLK(s) have been create sucessfully pLCSDev->fCreated = 1; // Initialize locking and event mechanisms initialize_lock( &pLCSDev->Lock ); initialize_lock( &pLCSDev->EventLock ); initialize_condition( &pLCSDev->Event ); // Create the TAP interface (if not already created by a // previous pass. More than one interface can exist on a port. if( !pLCSBLK->Port[pLCSDev->bPort].fCreated ) { int rc; rc = TUNTAP_CreateInterface( pLCSBLK->pszTUNDevice, IFF_TAP | IFF_NO_PI, &pLCSBLK->Port[pLCSDev->bPort].fd, pLCSBLK->Port[pLCSDev->bPort].szNetDevName ); logmsg(_("HHCLC073I %4.4X: TAP device %s opened\n"), pLCSDev->pDEVBLK[0]->devnum, pLCSBLK->Port[pLCSDev->bPort].szNetDevName); #if defined(OPTION_W32_CTCI) // Set the specified driver/dll i/o buffer sizes.. { struct tt32ctl tt32ctl; memset( &tt32ctl, 0, sizeof(tt32ctl) ); strlcpy( tt32ctl.tt32ctl_name, pLCSBLK->Port[pLCSDev->bPort].szNetDevName, sizeof(tt32ctl.tt32ctl_name) ); tt32ctl.tt32ctl_devbuffsize = pLCSBLK->iKernBuff; if( TUNTAP_IOCtl( pLCSBLK->Port[pLCSDev->bPort].fd, TT32SDEVBUFF, (char*)&tt32ctl ) != 0 ) { logmsg( _("HHCLC074W TT32SDEVBUFF failed for device %s: %s.\n"), pLCSBLK->Port[pLCSDev->bPort].szNetDevName, strerror( errno ) ); } tt32ctl.tt32ctl_iobuffsize = pLCSBLK->iIOBuff; if( TUNTAP_IOCtl( pLCSBLK->Port[pLCSDev->bPort].fd, TT32SIOBUFF, (char*)&tt32ctl ) != 0 ) { logmsg( _("HHCLC075W TT32SIOBUFF failed for device %s: %s.\n"), pLCSBLK->Port[pLCSDev->bPort].szNetDevName, strerror( errno ) ); } } #endif // Indicate that the port is used. pLCSBLK->Port[pLCSDev->bPort].fUsed = 1; pLCSBLK->Port[pLCSDev->bPort].fCreated = 1; create_thread( &pLCSBLK->Port[pLCSDev->bPort].tid, JOINABLE, LCS_PortThread, &pLCSBLK->Port[pLCSDev->bPort], "LCS_PortThread" ); /* Identify the thread ID with the devices on which they are active */ pLCSDev->pDEVBLK[0]->tid = pLCSBLK->Port[pLCSDev->bPort].tid; if (pLCSDev->pDEVBLK[1]) pLCSDev->pDEVBLK[1]->tid = pLCSBLK->Port[pLCSDev->bPort].tid; } // Add these devices to the ports device list. pLCSBLK->Port[pLCSDev->bPort].icDevices++; pLCSDev->pDEVBLK[0]->fd = pLCSBLK->Port[pLCSDev->bPort].fd; if( pLCSDev->pDEVBLK[1] ) pLCSDev->pDEVBLK[1]->fd = pLCSBLK->Port[pLCSDev->bPort].fd; } return 0; } // ==================================================================== // LCS_ExecuteCCW // ==================================================================== void LCS_ExecuteCCW( DEVBLK* pDEVBLK, BYTE bCode, BYTE bFlags, BYTE bChained, U16 sCount, BYTE bPrevCode, int iCCWSeq, BYTE* pIOBuf, BYTE* pMore, BYTE* pUnitStat, U16* pResidual ) { int iNum; // Number of bytes to move BYTE bOpCode; // CCW opcode with modifier // bits masked off UNREFERENCED( bFlags ); UNREFERENCED( bChained ); UNREFERENCED( bPrevCode ); UNREFERENCED( iCCWSeq ); // Intervention required if the device file is not open if( pDEVBLK->fd < 0 && !IS_CCW_SENSE( bCode ) && !IS_CCW_CONTROL( bCode ) ) { pDEVBLK->sense[0] = SENSE_IR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Mask off the modifier bits in the CCW bOpCode if( ( bCode & 0x07 ) == 0x07 ) bOpCode = 0x07; else if( ( bCode & 0x03 ) == 0x02 ) bOpCode = 0x02; else if( ( bCode & 0x0F ) == 0x0C ) bOpCode = 0x0C; else if( ( bCode & 0x03 ) == 0x01 ) bOpCode = pDEVBLK->ctcxmode ? ( bCode & 0x83 ) : 0x01; else if( ( bCode & 0x1F ) == 0x14 ) bOpCode = 0x14; else if( ( bCode & 0x47 ) == 0x03 ) bOpCode = 0x03; else if( ( bCode & 0xC7 ) == 0x43 ) bOpCode = 0x43; #if 0 // Special case for LCS CIW's else if( ( bCode == 72 || bCode == 82 || bCode == 83 ) ) bOpCode == bCode; #endif else bOpCode = bCode; // Process depending on CCW bOpCode switch (bOpCode) { case 0x01: // 0MMMMM01 WRITE //------------------------------------------------------------ // WRITE //------------------------------------------------------------ // Return normal status if CCW count is zero if( sCount == 0 ) { *pUnitStat = CSW_CE | CSW_DE; break; } LCS_Write( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual ); break; case 0x81: // 1MMMMM01 WEOF //------------------------------------------------------------ // WRITE EOF //------------------------------------------------------------ // Return normal status *pUnitStat = CSW_CE | CSW_DE; break; case 0x02: // MMMMMM10 READ case 0x0C: // MMMM1100 RDBACK // ----------------------------------------------------------- // READ & READ BACKWARDS // ----------------------------------------------------------- // Read data and set unit status and residual byte count LCS_Read( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual, pMore ); break; case 0x07: // MMMMM111 CTL // ----------------------------------------------------------- // CONTROL // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x03: // M0MMM011 NOP // ----------------------------------------------------------- // CONTROL NO-OPERATON // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x43: // 00XXX011 SBM // ----------------------------------------------------------- // SET BASIC MODE // ----------------------------------------------------------- // Command reject if in basic mode if( pDEVBLK->ctcxmode == 0 ) { pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; break; } // Reset extended mode and return normal status pDEVBLK->ctcxmode = 0; *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE; break; case 0xC3: // 11000011 SEM // ----------------------------------------------------------- // SET EXTENDED MODE // ----------------------------------------------------------- pDEVBLK->ctcxmode = 1; *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE; break; case 0xE3: // 11100011 // ----------------------------------------------------------- // PREPARE (PREP) // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x14: // XXX10100 SCB // ----------------------------------------------------------- // SENSE COMMAND BYTE // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x04: // 00000100 SENSE // ----------------------------------------------------------- // SENSE // ----------------------------------------------------------- // Command reject if in basic mode if( pDEVBLK->ctcxmode == 0 ) { pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; break; } // Calculate residual byte count iNum = ( sCount < pDEVBLK->numsense ) ? sCount : pDEVBLK->numsense; *pResidual = sCount - iNum; if( sCount < pDEVBLK->numsense ) *pMore = 1; // Copy device sense bytes to channel I/O buffer memcpy( pIOBuf, pDEVBLK->sense, iNum ); // Clear the device sense bytes memset( pDEVBLK->sense, 0, sizeof( pDEVBLK->sense ) ); // Return unit status *pUnitStat = CSW_CE | CSW_DE; break; case 0xE4: // 11100100 SID // ----------------------------------------------------------- // SENSE ID // ----------------------------------------------------------- // Calculate residual byte count iNum = ( sCount < pDEVBLK->numdevid ) ? sCount : pDEVBLK->numdevid; *pResidual = sCount - iNum; if( sCount < pDEVBLK->numdevid ) *pMore = 1; // Copy device identifier bytes to channel I/O buffer memcpy( pIOBuf, pDEVBLK->devid, iNum ); // Return unit status *pUnitStat = CSW_CE | CSW_DE; break; #if 0 case 0x72: // 0111010 RCD // ------------------------------------------------------------ // READ CONFIGURATION DATA // ------------------------------------------------------------ case 0x82: // 10000010 SID // ------------------------------------------------------------ // SET INTERFACE IDENTIFER // ------------------------------------------------------------ case 0x83: // 10000011 RID // ------------------------------------------------------------ // READ NODE IDENTIFER // ------------------------------------------------------------ LCS_SDC( pDEVBLK, bOpCode, sCount, pIOBuf, pUnitStat, pResidual, pMore ); break; #endif default: // ------------------------------------------------------------ // INVALID OPERATION // ------------------------------------------------------------ // Set command reject sense byte, and unit check status pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; } } // ==================================================================== // LCS_Close // ==================================================================== int LCS_Close( DEVBLK* pDEVBLK ) { PLCSDEV pLCSDEV; PLCSBLK pLCSBLK; PLCSPORT pLCSPORT; if (!(pLCSDEV = (PLCSDEV)pDEVBLK->dev_data)) return 0; // (was incomplete group) pLCSBLK = pLCSDEV->pLCSBLK; pLCSPORT = &pLCSBLK->Port[pLCSDEV->bPort]; pLCSPORT->icDevices--; // Is this the last device on the port? if( !pLCSPORT->icDevices ) { // PROGRAMMING NOTE: there's currently no way to interrupt // the "LCS_PortThread"s TUNTAP_Read of the adapter. Thus // we must simply wait for LCS_PortThread to eventually // notice that we're doing a close (via our setting of the // fCloseInProgress flag). Its TUNTAP_Read will eventually // timeout after a few seconds (currently 5, which is dif- // ferent than the CTC_READ_TIMEOUT_SECS timeout value the // CTCI_Read function uses) and will then do the close of // the adapter for us (TUNTAP_Close) so we don't have to. // All we need to do is ask it to exit (via our setting of // the fCloseInProgress flag) and then wait for it to exit // (which, as stated, could take up to a max of 5 seconds). // All of this is simply because it's poor form to close a // device from one thread while another thread is reading // from it. Attempting to do so could trip a race condition // wherein the internal i/o buffers used to process the // read request could have been freed (by the close call) // by the time the read request eventually gets serviced. if( pLCSPORT->fd >= 0 ) { TID tid = pLCSPORT->tid; obtain_lock( &pLCSPORT->EventLock ); { pLCSPORT->fStarted = 0; pLCSPORT->fCloseInProgress = 1; signal_condition( &pLCSPORT->Event ); } release_lock( &pLCSPORT->EventLock ); signal_thread( tid, SIGUSR2 ); join_thread( tid, NULL ); detach_thread( tid ); } if( pLCSDEV->pDEVBLK[0] && pLCSDEV->pDEVBLK[0]->fd >= 0 ) pLCSDEV->pDEVBLK[0]->fd = -1; if( pLCSDEV->pDEVBLK[1] && pLCSDEV->pDEVBLK[1]->fd >= 0 ) pLCSDEV->pDEVBLK[1]->fd = -1; } // Housekeeping if( pLCSDEV->pDEVBLK[0] == pDEVBLK ) pLCSDEV->pDEVBLK[0] = NULL; if( pLCSDEV->pDEVBLK[1] == pDEVBLK ) pLCSDEV->pDEVBLK[1] = NULL; if( !pLCSDEV->pDEVBLK[0] && !pLCSDEV->pDEVBLK[1] ) { // Remove this LCS Device from the chain... PLCSDEV pCurrLCSDev = NULL; PLCSDEV* ppPrevLCSDev = &pLCSBLK->pDevices; for( pCurrLCSDev = pLCSBLK->pDevices; pCurrLCSDev; pCurrLCSDev = pCurrLCSDev->pNext ) { if( pCurrLCSDev == pLCSDEV ) { *ppPrevLCSDev = pCurrLCSDev->pNext; if( pCurrLCSDev->pszIPAddress ) { free( pCurrLCSDev->pszIPAddress ); pCurrLCSDev->pszIPAddress = NULL; } free( pLCSDEV ); pLCSDEV = NULL; break; } ppPrevLCSDev = &pCurrLCSDev->pNext; } } if( !pLCSBLK->pDevices ) { if( pLCSBLK->pszTUNDevice ) { free( pLCSBLK->pszTUNDevice ); pLCSBLK->pszTUNDevice = NULL; } if( pLCSBLK->pszOATFilename ) { free( pLCSBLK->pszOATFilename ); pLCSBLK->pszOATFilename = NULL; } // if( pLCSBLK->pszIPAddress ) { free( pLCSBLK->pszIPAddress ); pLCSBLK->pszIPAddress = NULL; } if( pLCSBLK->pszMACAddress ) { free( pLCSBLK->pszMACAddress ); pLCSBLK->pszMACAddress = NULL; } if( pLCSBLK->pszOATFilename ) { if( pLCSBLK->pszIPAddress ) { free( pLCSBLK->pszIPAddress ); pLCSBLK->pszIPAddress = NULL; } } free( pLCSBLK ); pLCSBLK = NULL; } pDEVBLK->dev_data = NULL; return 0; } // ==================================================================== // LCS_Query // ==================================================================== void LCS_Query( DEVBLK* pDEVBLK, char** ppszClass, int iBufLen, char* pBuffer ) { char *sType[] = { "", " Pri", " Sec" }; LCSDEV* pLCSDEV; BEGIN_DEVICE_CLASS_QUERY( "CTCA", pDEVBLK, ppszClass, iBufLen, pBuffer ); pLCSDEV = (LCSDEV*) pDEVBLK->dev_data; if(!pLCSDEV) { strlcpy(pBuffer,"*Uninitialized",iBufLen); return; } snprintf( pBuffer, iBufLen, "LCS Port %2.2X %s%s (%s)%s", pLCSDEV->bPort, pLCSDEV->bMode == LCSDEV_MODE_IP ? "IP" : "SNA", sType[pLCSDEV->bType], pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort].szNetDevName, pLCSDEV->pLCSBLK->fDebug ? " -d" : "" ); } // ==================================================================== // LCS_Read // ==================================================================== // The guest o/s is issuing a Read CCW for our LCS device. Return to // it all available LCS Frames that we have buffered up in our buffer. // -------------------------------------------------------------------- void LCS_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual, BYTE* pMore ) { PLCSHDR pLCSHdr; PLCSDEV pLCSDEV = (PLCSDEV)pDEVBLK->dev_data; size_t iLength = 0; int rc = 0; // FIXME: we currently don't support data-chaining but // probably should if real LCS devices do (I was unable // to determine whether they do or not). -- Fish for (;;) { // Wait for some LCS Frames to arrive in our buffer... obtain_lock( &pLCSDEV->Lock ); if( !( pLCSDEV->fDataPending || pLCSDEV->fReplyPending ) ) { struct timespec waittime; struct timeval now; release_lock( &pLCSDEV->Lock ); // Wait 5 seconds then check for channel conditions gettimeofday( &now, NULL ); waittime.tv_sec = now.tv_sec + CTC_READ_TIMEOUT_SECS; waittime.tv_nsec = now.tv_usec * 1000; obtain_lock( &pLCSDEV->EventLock ); rc = timed_wait_condition( &pLCSDEV->Event, &pLCSDEV->EventLock, &waittime ); release_lock( &pLCSDEV->EventLock ); // If we didn't receive any, keep waiting... if( rc == ETIMEDOUT || rc == EINTR ) { // check for halt condition if( pDEVBLK->scsw.flag2 & SCSW2_FC_HALT || pDEVBLK->scsw.flag2 & SCSW2_FC_CLEAR ) { if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCLC002I %4.4X: Halt or Clear Recognized\n"), pDEVBLK->devnum ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = sCount; return; } continue; // (keep waiting) } // We received some LCS Frames... obtain_lock( &pLCSDEV->Lock ); } // Point to the end of all buffered LCS Frames... // (where the next Frame *would* go if there was one) pLCSHdr = (PLCSHDR)( pLCSDEV->bFrameBuffer + pLCSDEV->iFrameOffset ); // Mark the end of this batch of LCS Frames by setting // the "offset to NEXT frame" LCS Header field to zero. // (a zero "next Frame offset" is like an "EOF" flag) STORE_HW( pLCSHdr->hwOffset, 0x0000 ); // Calculate how much data we're going to be giving them. // Since 'iFrameOffset' points to the next available LCS // Frame slot in our buffer, the total amount of LCS Frame // data we have is exactly that amount. We give them two // extra bytes however so that they can optionally chase // the "hwOffset" field in each LCS Frame's LCS Header to // eventually reach our zero hwOffset "EOF" flag). iLength = pLCSDEV->iFrameOffset + sizeof(pLCSHdr->hwOffset); // (calculate residual and set memcpy amount) // FIXME: we currently don't support data-chaining but // probably should if real LCS devices do (I was unable // to determine whether they do or not). -- Fish if( sCount < iLength ) { *pMore = 1; *pResidual = 0; iLength = sCount; // PROGRAMMING NOTE: As a result of the caller asking // for less data than we actually have available, the // remainder of their unread data they didn't ask for // will end up being silently discarded. Refer to the // other NOTEs and FIXME's sprinkled throughout this // function... } else { *pMore = 0; *pResidual -= iLength; } *pUnitStat = CSW_CE | CSW_DE; memcpy( pIOBuf, pLCSDEV->bFrameBuffer, iLength ); // Trace the i/o if requested... if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { logmsg( _("HHCLC003I %4.4X: LCS Read:\n"), pDEVBLK->devnum ); packet_trace( pIOBuf, iLength ); } // Reset frame buffer to empty... // PROGRAMMING NOTE: even though not all available data // may have been read by the guest, we don't currently // support data-chaining. Thus any unread data is always // discarded by resetting both of the iFrameOffset and // fDataPending fields to 0 so that the next read always // grabs a new batch of LCS Frames starting at the very // beginning of our frame buffer again. (I was unable // to determine whether real LCS devices support data- // chaining or not, but if they do we should fix this). pLCSDEV->iFrameOffset = 0; pLCSDEV->fReplyPending = 0; pLCSDEV->fDataPending = 0; release_lock( &pLCSDEV->Lock ); return; } } // ==================================================================== // LCS_Write // ==================================================================== void LCS_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ) { PLCSDEV pLCSDEV = (PLCSDEV)pDEVBLK->dev_data; PLCSHDR pLCSHDR = NULL; PLCSCMDHDR pCmdFrame = NULL; PLCSETHFRM pLCSEthFrame = NULL; PETHFRM pEthFrame = NULL; U16 iOffset = 0; U16 iPrevOffset = 0; U16 iLength = 0; U16 iEthLen = 0; UNREFERENCED( sCount ); // Process each frame in the buffer... while( 1 ) { // Fix-up the LCS header pointer to the current frame pLCSHDR = (PLCSHDR)( pIOBuf + iOffset ); // Save current offset so we can tell how big next frame is iPrevOffset = iOffset; // Get the next frame offset, exit loop if 0 FETCH_HW( iOffset, pLCSHDR->hwOffset ); if( iOffset == 0 ) // ("EOF") break; // Calculate size of this LCS Frame iLength = iOffset - iPrevOffset; switch( pLCSHDR->bType ) { case LCS_FRMTYP_CMD: // LCS Command Frame pCmdFrame = (PLCSCMDHDR)pLCSHDR; // Trace received command frame... if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { logmsg( _("HHCLC051I %4.4X: Cmd Packet...\n"), pDEVBLK->devnum ); packet_trace( (BYTE*)pCmdFrame, iLength ); } // FIXME: what is this all about? I'm not saying it's wrong, // only that we need to document via comments the purpose of // this test. What's it doing? Why ignore "initiator 1"? etc. // PLEASE EXPLAIN! -- Fish if( pCmdFrame->bInitiator == 0x01 ) break; switch( pCmdFrame->bCmdCode ) { case LCS_CMD_STARTUP: // Start Host if( pLCSDEV->pLCSBLK->fDebug ) logmsg( _("HHCLC043I %4.4X: Startup\n"),pDEVBLK->devnum); LCS_Startup( pLCSDEV, pCmdFrame ); break; case LCS_CMD_SHUTDOWN: // Shutdown Host if( pLCSDEV->pLCSBLK->fDebug ) logmsg( _("HHCLC044I %4.4X: Shutdown\n"),pDEVBLK->devnum); LCS_Shutdown( pLCSDEV, pCmdFrame ); break; case LCS_CMD_STRTLAN: // Start LAN if( pLCSDEV->pLCSBLK->fDebug ) logmsg( _("HHCLC045I %4.4X: Start LAN\n"),pDEVBLK->devnum); LCS_StartLan( pLCSDEV, pCmdFrame ); break; case LCS_CMD_STOPLAN: // Stop LAN if( pLCSDEV->pLCSBLK->fDebug ) logmsg( _("HHCLC046I %4.4X: Stop LAN\n"),pDEVBLK->devnum); LCS_StopLan( pLCSDEV, pCmdFrame ); break; case LCS_CMD_QIPASSIST: // Query IP Assists if( pLCSDEV->pLCSBLK->fDebug ) logmsg( _("HHCLC047I %4.4X: Query IP Assists\n"),pDEVBLK->devnum); LCS_QueryIPAssists( pLCSDEV, pCmdFrame ); break; case LCS_CMD_LANSTAT: // LAN Stats if( pLCSDEV->pLCSBLK->fDebug ) logmsg( _("HHCLC048I %4.4X: Statistics\n"),pDEVBLK->devnum); LCS_LanStats( pLCSDEV, pCmdFrame ); break; // ZZ FIXME: Once multicasting support is confirmed in tuntap // and/or TunTap32, we need to add support in Herc by handling // the below LCS_CMD_SETIPM and LCS_CMD_DELIPM frames and then // issuing an ioctl( SIOCADDMULTI ) to tuntap/TunTap32... case LCS_CMD_SETIPM: // Set IP Multicast case LCS_CMD_DELIPM: // Delete IP Multicast case LCS_CMD_GENSTAT: // General Stats case LCS_CMD_LISTLAN: // List LAN case LCS_CMD_LISTLAN2: // List LAN (another version) case LCS_CMD_TIMING: // Timing request default: LCS_DefaultCmdProc( pLCSDEV, pCmdFrame ); break; } // end switch( LCS Command Frame cmd code ) break; // end case LCS_FRMTYP_CMD case LCS_FRMTYP_ENET: // Ethernet Passthru case LCS_FRMTYP_TR: // Token Ring case LCS_FRMTYP_FDDI: // FDDI case LCS_FRMTYP_AUTO: // auto-detect pLCSEthFrame = (PLCSETHFRM)pLCSHDR; pEthFrame = (PETHFRM)pLCSEthFrame->bData; iEthLen = iLength - sizeof(LCSETHFRM); // Trace Ethernet frame before sending to TAP device if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { logmsg( _("HHCLC004I %4.4X: Sending packet to %s:\n"), pDEVBLK->devnum, pDEVBLK->filename ); packet_trace( (BYTE*)pEthFrame, iEthLen ); } // Write the Ethernet frame to the TAP device if( TUNTAP_Write( pDEVBLK->fd, (BYTE*)pEthFrame, iEthLen ) != iEthLen ) { logmsg( _("HHCLC005E %4.4X: Error writing to %s: %s\n"), pDEVBLK->devnum, pDEVBLK->filename, strerror( errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } break; default: logmsg( _("HHCLC050E %4.4X: LCS_Write: Unsupported frame type 0x%2.2X\n"), pDEVBLK->devnum, pDEVBLK->filename ); ASSERT( FALSE ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // end switch( LCS Frame type ) } // end while (1) *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE; if( pLCSDEV->fReplyPending ) { if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCLC006I %4.4X Triggering Event.\n"), pDEVBLK->devnum ); obtain_lock( &pLCSDEV->EventLock ); signal_condition( &pLCSDEV->Event ); release_lock( &pLCSDEV->EventLock ); } } #if 0 // ==================================================================== // LCS_SDC // ==================================================================== void LCS_SDC( DEVBLK* pDEVBLK, BYTE bOpCode, U16 sCount, BYTE* pIOBuf, BYTE* UnitStat, U16* pResidual, BYTE* pMore ) { PLCSDEV pLCSDEV = (PLCSDEV)pDEVBLK->dev_data; PLCSBLK pLCSBLK = pLCSDEV->pLCSBLK; switch( bOpCode ) { case 0x72: // 0111010 RCD // ------------------------------------------------------------ // READ CONFIGURATION DATA // ------------------------------------------------------------ SDC_CreateNED( pIOBuf, 0, NED_EMULATION, NED_TYPE_DEV, NED_CLASS_CTCA, 0, "003088", "001", "", "", "", 0 ); SDC_CreateNED( pIOBuf, 1, NED_SERIAL_VALID, NED_TYPE_DEV, NED_CLASS_UNSPECIFIED, 0, "003172", "000", "HDG", "00", pLCSBLK->szSerialNumber, pLCSDEV->bPort ); SDC_CreateGeneralNEQ( pIOBuf, 2, 0, // Interface ID 60, // Timeout NULL ); // Extended Info SDC_CreateNED( pIOBuf, 3, NED_TOKEN | NED_SERIAL_UNIQUE, NED_TYPE_DEV, NED_CLASS_UNSPECIFIED, 0, "003172", "000", "HDG", "00", pLCSBLK->szSerialNumber, 0 ); break; case 0x82: // 10000010 SID // ------------------------------------------------------------ // SET INTERFACE IDENTIFER // ------------------------------------------------------------ break; case 0x83: // 10000011 RID // ------------------------------------------------------------ // READ NODE IDENTIFER // ------------------------------------------------------------ break; } } #endif // ==================================================================== // LCS_Startup // ==================================================================== static void LCS_Startup( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ) { LCSSTRTFRM reply; PLCSPORT pLCSPORT; U16 iOrigMaxFrameBufferSize; INIT_REPLY_FRAME( reply, pCmdFrame ); reply.bLCSCmdHdr.bLanType = LCS_FRMTYP_ENET; reply.bLCSCmdHdr.bRelAdapterNo = pLCSDEV->bPort; // Save the max buffer size parameter iOrigMaxFrameBufferSize = pLCSDEV->iMaxFrameBufferSize; FETCH_HW( pLCSDEV->iMaxFrameBufferSize, ((PLCSSTRTFRM)pCmdFrame)->hwBufferSize ); // Make sure it doesn't exceed our compiled maximum if (pLCSDEV->iMaxFrameBufferSize > sizeof(pLCSDEV->bFrameBuffer)) { logmsg( _("HHCLC049W %4.4X: LCS_Startup: Requested frame buffer size of 0x%4.4X " "larger than compiled size of 0x%4.4X; requested size ignored.\n"), pLCSDEV->pDEVBLK[1]->devnum, pLCSDEV->iMaxFrameBufferSize, sizeof( pLCSDEV->bFrameBuffer ) ); pLCSDEV->iMaxFrameBufferSize = iOrigMaxFrameBufferSize; } // Make sure it's not smaller than the compiled minimum size if (pLCSDEV->iMaxFrameBufferSize < CTC_MIN_FRAME_BUFFER_SIZE) { logmsg( _("HHCLC054W %4.4X: LCS_Startup: Requested frame buffer size of 0x%4.4X " "smaller than compiled minimum size of 0x%4.4X; requested size ignored.\n"), pLCSDEV->pDEVBLK[1]->devnum, pLCSDEV->iMaxFrameBufferSize, CTC_MIN_FRAME_BUFFER_SIZE ); pLCSDEV->iMaxFrameBufferSize = iOrigMaxFrameBufferSize; } pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort]; VERIFY( TUNTAP_SetIPAddr( pLCSPORT->szNetDevName, "0.0.0.0" ) == 0 ); VERIFY( TUNTAP_SetMTU ( pLCSPORT->szNetDevName, "1500" ) == 0 ); #ifdef OPTION_TUNTAP_SETMACADDR if (pLCSPORT->fLocalMAC) { VERIFY( TUNTAP_SetMACAddr( pLCSPORT->szNetDevName, pLCSPORT->szMACAddress ) == 0 ); } #endif // OPTION_TUNTAP_SETMACADDR ENQUEUE_REPLY_FRAME( pLCSDEV, reply ); pLCSDEV->fStarted = 1; } // ==================================================================== // LCS_Shutdown // ==================================================================== static void LCS_Shutdown( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ) { LCSSTDFRM reply; INIT_REPLY_FRAME( reply, pCmdFrame ); reply.bLCSCmdHdr.bLanType = LCS_FRMTYP_ENET; reply.bLCSCmdHdr.bRelAdapterNo = pLCSDEV->bPort; ENQUEUE_REPLY_FRAME( pLCSDEV, reply ); pLCSDEV->fStarted = 0; } // ==================================================================== // LCS_StartLan // ==================================================================== static void LCS_StartLan( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ) { LCSSTDFRM reply; PLCSPORT pLCSPORT; #ifdef OPTION_TUNTAP_DELADD_ROUTES PLCSRTE pLCSRTE; #endif // OPTION_TUNTAP_DELADD_ROUTES int nIFFlags; INIT_REPLY_FRAME( reply, pCmdFrame ); pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort]; // Serialize access to eliminate ioctl errors obtain_lock( &pLCSPORT->Lock ); // Configure the TAP interface if used if( pLCSPORT->fUsed && pLCSPORT->fCreated && !pLCSPORT->fStarted ) { nIFFlags = // Interface flags 0 | IFF_UP // (interface is being enabled) | IFF_BROADCAST // (interface broadcast addr is valid) ; #if defined( TUNTAP_IFF_RUNNING_NEEDED ) nIFFlags |= // ADDITIONAL Interface flags 0 | IFF_RUNNING // (interface is ALSO operational) ; #endif /* defined( TUNTAP_IFF_RUNNING_NEEDED ) */ // Enable the interface by turning on the IFF_UP flag... VERIFY( TUNTAP_SetFlags( pLCSPORT->szNetDevName, nIFFlags ) == 0 ); #ifdef OPTION_TUNTAP_DELADD_ROUTES // Add any needed extra routing entries the // user may have specified in their OAT file // to the host's routing table... for( pLCSRTE = pLCSPORT->pRoutes; pLCSRTE; pLCSRTE = pLCSRTE->pNext ) { VERIFY( TUNTAP_AddRoute( pLCSPORT->szNetDevName, pLCSRTE->pszNetAddr, pLCSRTE->pszNetMask, NULL, RTF_UP ) == 0 ); } #endif // OPTION_TUNTAP_DELADD_ROUTES obtain_lock( &pLCSPORT->EventLock ); pLCSPORT->fStarted = 1; signal_condition( &pLCSPORT->Event ); release_lock( &pLCSPORT->EventLock ); usleep( 250*1000 ); } release_lock( &pLCSPORT->Lock ); #ifdef OPTION_TUNTAP_DELADD_ROUTES // Add a Point-To-Point routing entry to the // host's routing table for our interface... if( pLCSDEV->pszIPAddress ) { VERIFY( TUNTAP_AddRoute( pLCSPORT->szNetDevName, pLCSDEV->pszIPAddress, "255.255.255.255", NULL, RTF_UP | RTF_HOST ) == 0 ); } #endif // OPTION_TUNTAP_DELADD_ROUTES ENQUEUE_REPLY_FRAME( pLCSDEV, reply ); } // ==================================================================== // LCS_StopLan // ==================================================================== static void LCS_StopLan( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ) { LCSSTDFRM reply; PLCSPORT pLCSPORT; #ifdef OPTION_TUNTAP_DELADD_ROUTES PLCSRTE pLCSRTE; #endif // OPTION_TUNTAP_DELADD_ROUTES INIT_REPLY_FRAME( reply, pCmdFrame ); pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort]; // Serialize access to eliminate ioctl errors obtain_lock( &pLCSPORT->Lock ); obtain_lock( &pLCSPORT->EventLock ); pLCSPORT->fStarted = 0; signal_condition( &pLCSPORT->Event ); release_lock( &pLCSPORT->EventLock ); usleep( 250*1000 ); // Disable the interface by turning off the IFF_UP flag... VERIFY( TUNTAP_SetFlags( pLCSPORT->szNetDevName, 0 ) == 0 ); #ifdef OPTION_TUNTAP_DELADD_ROUTES // Remove routing entries from host's routing table... // First, remove the Point-To-Point routing entry // we added when we brought the interface IFF_UP... if( pLCSDEV->pszIPAddress ) { VERIFY( TUNTAP_DelRoute( pLCSPORT->szNetDevName, pLCSDEV->pszIPAddress, "255.255.255.255", NULL, RTF_HOST ) == 0 ); } // Next, remove any extra routing entries // (specified by the user in their OAT file) // that we may have also added... for( pLCSRTE = pLCSPORT->pRoutes; pLCSRTE; pLCSRTE = pLCSRTE->pNext ) { VERIFY( TUNTAP_DelRoute( pLCSPORT->szNetDevName, pLCSRTE->pszNetAddr, pLCSRTE->pszNetMask, NULL, RTF_UP ) == 0 ); } #endif // OPTION_TUNTAP_DELADD_ROUTES release_lock( &pLCSPORT->Lock ); // FIXME: Really need to iterate through the devices and close // the TAP interface if all devices have been stopped. ENQUEUE_REPLY_FRAME( pLCSDEV, reply ); } // ==================================================================== // LCS_QueryIPAssists // ==================================================================== static void LCS_QueryIPAssists( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ) { LCSQIPFRM reply; PLCSPORT pLCSPORT; INIT_REPLY_FRAME( reply, pCmdFrame ); pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort]; #if defined( WIN32 ) // FIXME: TunTap32 *does* support TCP/IP checksum offloading // (for both inbound and outbound packets), but Microsoft's // latest NDIS 6.0 release has broken it, so until I can get // it straightened out we can't support it. Sorry! -- Fish // The other assists however, TunTap32 does not yet support. pLCSPORT->sIPAssistsSupported = 0 // | LCS_INBOUND_CHECKSUM_SUPPORT // | LCS_OUTBOUND_CHECKSUM_SUPPORT // | LCS_ARP_PROCESSING // | LCS_IP_FRAG_REASSEMBLY // | LCS_IP_FILTERING // | LCS_IP_V6_SUPPORT // | LCS_MULTICAST_SUPPORT ; pLCSPORT->sIPAssistsEnabled = 0 // | LCS_INBOUND_CHECKSUM_SUPPORT // | LCS_OUTBOUND_CHECKSUM_SUPPORT // | LCS_ARP_PROCESSING // | LCS_IP_FRAG_REASSEMBLY // | LCS_IP_FILTERING // | LCS_IP_V6_SUPPORT // | LCS_MULTICAST_SUPPORT ; #else // !WIN32 (Linux, Apple, etc) // Linux/Apple/etc 'tuntap' driver DOES support // certain types of assists?? (task offloading) pLCSPORT->sIPAssistsSupported = 0 // | LCS_INBOUND_CHECKSUM_SUPPORT // | LCS_OUTBOUND_CHECKSUM_SUPPORT // | LCS_ARP_PROCESSING | LCS_IP_FRAG_REASSEMBLY // | LCS_IP_FILTERING // | LCS_IP_V6_SUPPORT | LCS_MULTICAST_SUPPORT ; pLCSPORT->sIPAssistsEnabled = 0 // | LCS_INBOUND_CHECKSUM_SUPPORT // | LCS_OUTBOUND_CHECKSUM_SUPPORT // | LCS_ARP_PROCESSING | LCS_IP_FRAG_REASSEMBLY // | LCS_IP_FILTERING // | LCS_IP_V6_SUPPORT | LCS_MULTICAST_SUPPORT ; #endif // WIN32 STORE_HW( reply.hwNumIPPairs, 0x0000 ); STORE_HW( reply.hwIPAssistsSupported, pLCSPORT->sIPAssistsSupported ); STORE_HW( reply.hwIPAssistsEnabled, pLCSPORT->sIPAssistsEnabled ); STORE_HW( reply.hwIPVersion, 0x0004 ); ENQUEUE_REPLY_FRAME( pLCSDEV, reply ); } // ==================================================================== // LCS_LanStats // ==================================================================== static void LCS_LanStats( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ) { LCSLSTFRM reply; PLCSPORT pLCSPORT; int fd; struct ifreq ifr; BYTE* pPortMAC; BYTE* pIFaceMAC; INIT_REPLY_FRAME( reply, pCmdFrame ); pLCSPORT = &pLCSDEV->pLCSBLK->Port[pLCSDEV->bPort]; fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ); if( fd == -1 ) { logmsg( _("HHCLC007E Error in call to socket: %s.\n"), strerror( HSO_errno ) ); // FIXME: we should probably be returning a non-zero hwReturnCode // STORE_HW( reply.bLCSCmdHdr.hwReturnCode, 0x0001 ); return; } memset( &ifr, 0, sizeof( ifr ) ); strcpy( ifr.ifr_name, pLCSPORT->szNetDevName ); pPortMAC = (BYTE*) &pLCSPORT->MAC_Address; /* Not all systems can return the hardware address of an interface. */ #if defined(SIOCGIFHWADDR) if( TUNTAP_IOCtl( fd, SIOCGIFHWADDR, (char*)&ifr ) != 0 ) { logmsg( _("HHCLC008E ioctl error on device %s: %s.\n"), pLCSPORT->szNetDevName, strerror( errno ) ); // FIXME: we should probably be returning a non-zero hwReturnCode // STORE_HW( reply.bLCSCmdHdr.hwReturnCode, 0x0002 ); return; } pIFaceMAC = (BYTE*) ifr.ifr_hwaddr.sa_data; #else // !defined(SIOCGIFHWADDR) pIFaceMAC = pPortMAC; #endif // defined(SIOCGIFHWADDR) /* Report what MAC address we will really be using */ logmsg( _("HHCLC055I %s using MAC %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n"), pLCSPORT->szNetDevName, *(pIFaceMAC+0),*(pIFaceMAC+1), *(pIFaceMAC+2),*(pIFaceMAC+3), *(pIFaceMAC+4),*(pIFaceMAC+5)); /* Issue warning if different from specified value */ if (memcmp( pPortMAC, pIFaceMAC, IFHWADDRLEN ) != 0) { logmsg( _("HHCLC056W %s NOT using MAC %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n"), pLCSPORT->szNetDevName, *(pPortMAC+0),*(pPortMAC+1), *(pPortMAC+2),*(pPortMAC+3), *(pPortMAC+4),*(pPortMAC+5)); memcpy( pPortMAC, pIFaceMAC, IFHWADDRLEN ); snprintf(pLCSPORT->szMACAddress, sizeof(pLCSPORT->szMACAddress)-1, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", *(pPortMAC+0), *(pPortMAC+1), *(pPortMAC+2), *(pPortMAC+3), *(pPortMAC+4), *(pPortMAC+5)); } memcpy( reply.MAC_Address, pIFaceMAC, IFHWADDRLEN ); /* Respond with a different MAC address for the LCS side */ /* unless the TAP mechanism is designed as such */ /* cf : hostopts.h for an explanation */ #if !defined(OPTION_TUNTAP_LCS_SAME_ADDR) reply.MAC_Address[5]++; #endif // FIXME: Really should read /proc/net/dev to retrieve actual stats ENQUEUE_REPLY_FRAME( pLCSDEV, reply ); } // ==================================================================== // LCS_DefaultCmdProc // ==================================================================== static void LCS_DefaultCmdProc( PLCSDEV pLCSDEV, PLCSCMDHDR pCmdFrame ) { LCSSTDFRM reply; INIT_REPLY_FRAME( reply, pCmdFrame ); reply.bLCSCmdHdr.bLanType = LCS_FRMTYP_ENET; reply.bLCSCmdHdr.bRelAdapterNo = pLCSDEV->bPort; ENQUEUE_REPLY_FRAME( pLCSDEV, reply ); } // ==================================================================== // LCS_PortThread // ==================================================================== static void* LCS_PortThread( PLCSPORT pLCSPORT ) { PLCSDEV pLCSDev; PLCSDEV pPrimaryLCSDEV; PLCSDEV pSecondaryLCSDEV; PLCSDEV pMatchingLCSDEV; PLCSRTE pLCSRTE; PETHFRM pEthFrame; PIP4FRM pIPFrame = NULL; PARPFRM pARPFrame = NULL; int iLength; U16 hwEthernetType; U32 lIPAddress; // (network byte order) BYTE* pMAC; BYTE szBuff[2048]; char bReported = 0; pLCSPORT->pid = getpid(); for (;;) { obtain_lock( &pLCSPORT->EventLock ); { // Don't read unless/until port is enabled... while (1 && !(pLCSPORT->fd < 0) && !pLCSPORT->fCloseInProgress && !pLCSPORT->fStarted ) { timed_wait_condition_relative_usecs ( &pLCSPORT->Event, // ptr to condition to wait on &pLCSPORT->EventLock, // ptr to controlling lock (must be held!) 250*1000, // max #of microseconds to wait NULL // [OPTIONAL] ptr to tod value (may be NULL) ); } } release_lock( &pLCSPORT->EventLock ); // Exit when told... if ( pLCSPORT->fd < 0 || pLCSPORT->fCloseInProgress ) break; // Read an IP packet from the TAP device iLength = TUNTAP_Read( pLCSPORT->fd, szBuff, sizeof( szBuff ) ); if( iLength == 0 ) // (probably EINTR; ignore) continue; // Check for other error condition if( iLength < 0 ) { if( pLCSPORT->fd < 0 || pLCSPORT->fCloseInProgress ) break; logmsg( _("HHCLC042E Port %2.2X: Read error: %s\n"), pLCSPORT->bPort, strerror( errno ) ); break; } if( pLCSPORT->pLCSBLK->fDebug ) { // Trace the frame logmsg( _("HHCLC009I Port %2.2X: Read Buffer:\n"), pLCSPORT->bPort ); packet_trace( szBuff, iLength ); bReported = 0; } pEthFrame = (PETHFRM)szBuff; FETCH_HW( hwEthernetType, pEthFrame->hwEthernetType ); // Housekeeping pPrimaryLCSDEV = NULL; pSecondaryLCSDEV = NULL; pMatchingLCSDEV = NULL; // Attempt to find the device that this frame belongs to for( pLCSDev = pLCSPORT->pLCSBLK->pDevices; pLCSDev; pLCSDev = pLCSDev->pNext ) { // Only process devices that are on this port if( pLCSDev->bPort == pLCSPORT->bPort ) { if( hwEthernetType == ETH_TYPE_IP ) { pIPFrame = (PIP4FRM)pEthFrame->bData; lIPAddress = pIPFrame->lDstIP; // (network byte order) if( pLCSPORT->pLCSBLK->fDebug && !bReported ) { logmsg( _("HHCLC010I Port %2.2X: " "IPV4 frame for %8.8X\n"), pLCSPORT->bPort, ntohl(lIPAddress) ); bReported = 1; } // If this is an exact match use it // otherwise look for primary and secondary // default devices if( pLCSDev->lIPAddress == lIPAddress ) { pMatchingLCSDEV = pLCSDev; break; } else if( pLCSDev->bType == LCSDEV_TYPE_PRIMARY ) pPrimaryLCSDEV = pLCSDev; else if( pLCSDev->bType == LCSDEV_TYPE_SECONDARY ) pSecondaryLCSDEV = pLCSDev; } else if( hwEthernetType == ETH_TYPE_ARP ) { pARPFrame = (PARPFRM)pEthFrame->bData; lIPAddress = pARPFrame->lTargIPAddr; // (network byte order) if( pLCSPORT->pLCSBLK->fDebug && !bReported ) { logmsg( _("HHCLC011I Port %2.2X: " "ARP frame for %8.8X\n"), pLCSPORT->bPort, ntohl(lIPAddress) ); bReported = 1; } // If this is an exact match use it // otherwise look for primary and secondary // default devices if( pLCSDev->lIPAddress == lIPAddress ) { pMatchingLCSDEV = pLCSDev; break; } else if( pLCSDev->bType == LCSDEV_TYPE_PRIMARY ) pPrimaryLCSDEV = pLCSDev; else if( pLCSDev->bType == LCSDEV_TYPE_SECONDARY ) pSecondaryLCSDEV = pLCSDev; } else if( hwEthernetType == ETH_TYPE_RARP ) { pARPFrame = (PARPFRM)pEthFrame->bData; pMAC = pARPFrame->bTargEthAddr; if( pLCSPORT->pLCSBLK->fDebug && !bReported ) { logmsg ( _("HHCLC011I Port %2.2X: RARP frame for " "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n") ,pLCSPORT->bPort ,*(pMAC+0) ,*(pMAC+1) ,*(pMAC+2) ,*(pMAC+3) ,*(pMAC+4) ,*(pMAC+5) ); bReported = 1; } // If this is an exact match use it // otherwise look for primary and secondary // default devices if( memcmp( pMAC, pLCSPORT->MAC_Address, IFHWADDRLEN ) == 0 ) { pMatchingLCSDEV = pLCSDev; break; } else if( pLCSDev->bType == LCSDEV_TYPE_PRIMARY ) pPrimaryLCSDEV = pLCSDev; else if( pLCSDev->bType == LCSDEV_TYPE_SECONDARY ) pSecondaryLCSDEV = pLCSDev; } else if( hwEthernetType == ETH_TYPE_SNA ) { if( pLCSPORT->pLCSBLK->fDebug && !bReported ) { logmsg( _("HHCLC012I Port %2.2X: SNA frame\n"), pLCSPORT->bPort ); bReported = 1; } if( pLCSDev->bMode == LCSDEV_MODE_SNA ) { pMatchingLCSDEV = pLCSDev; break; } } } } // If the matching device is not started // nullify the pointer and pass frame to one // of the defaults if present if( pMatchingLCSDEV && !pMatchingLCSDEV->fStarted ) pMatchingLCSDEV = NULL; // Match not found, check for default devices // If one is defined and started, use it if( !pMatchingLCSDEV ) { if( pPrimaryLCSDEV && pPrimaryLCSDEV->fStarted ) { pMatchingLCSDEV = pPrimaryLCSDEV; if( pLCSPORT->pLCSBLK->fDebug ) logmsg( _("HHCLC013I Port %2.2X: " "No match found - " "selecting primary %4.4X\n"), pLCSPORT->bPort, pMatchingLCSDEV->sAddr ); } else if( pSecondaryLCSDEV && pSecondaryLCSDEV->fStarted ) { pMatchingLCSDEV = pSecondaryLCSDEV; if( pLCSPORT->pLCSBLK->fDebug ) logmsg( _("HHCLC014I Port %2.2X: " "No match found - " "selecting secondary %4.4X\n"), pLCSPORT->bPort, pMatchingLCSDEV->sAddr ); } } // No match found, discard frame if( !pMatchingLCSDEV ) { if( pLCSPORT->pLCSBLK->fDebug ) logmsg( _("HHCLC015I Port %2.2X: " "No match found - Discarding frame\n"), pLCSPORT->bPort ); continue; } if( pLCSPORT->pLCSBLK->fDebug ) logmsg( _("HHCLC016I Port %2.2X: " "Enqueing frame to device %4.4X (%8.8X)\n"), pLCSPORT->bPort, pMatchingLCSDEV->sAddr, ntohl(pMatchingLCSDEV->lIPAddress) ); // Match was found. // Enqueue frame on buffer, if buffer is full, keep trying while( LCS_EnqueueEthFrame( pMatchingLCSDEV, pLCSPORT->bPort, szBuff, iLength ) < 0 && pLCSPORT->fd != -1 && !pLCSPORT->fCloseInProgress ) { if (EMSGSIZE == errno) { if( pLCSPORT->pLCSBLK->fDebug ) logmsg( _("HHCLC041W Port %2.2X: " "Frame too big; discarded.\n"), pLCSPORT->bPort ); break; } ASSERT( ENOBUFS == errno ); usleep( CTC_DELAY_USECS ); } } // end for(;;) // We must do the close since we were the one doing the i/o... VERIFY( pLCSPORT->fd == -1 || TUNTAP_Close( pLCSPORT->fd ) == 0 ); // Housekeeping - Cleanup Port Block memset( pLCSPORT->MAC_Address, 0, sizeof( MAC ) ); memset( pLCSPORT->szNetDevName, 0, IFNAMSIZ ); memset( pLCSPORT->szMACAddress, 0, 32 ); for( pLCSRTE = pLCSPORT->pRoutes; pLCSRTE; pLCSRTE = pLCSPORT->pRoutes ) { pLCSPORT->pRoutes = pLCSRTE->pNext; free( pLCSRTE ); pLCSRTE = NULL; } pLCSPORT->sIPAssistsSupported = 0; pLCSPORT->sIPAssistsEnabled = 0; pLCSPORT->fUsed = 0; pLCSPORT->fLocalMAC = 0; pLCSPORT->fCreated = 0; pLCSPORT->fStarted = 0; pLCSPORT->fRouteAdded = 0; pLCSPORT->fd = -1; return NULL; } // end of LCS_PortThread // ==================================================================== // LCS_EnqueueEthFrame // ==================================================================== // // Places the provided ethernet frame in the next available frame // slot in the adapter buffer. // // pData points the the Ethernet packet just received // iSize is the size of the Ethernet packet // // Returns: // // 0 == Success // -1 == Failure; errno = ENOBUFS: No buffer space available // EMSGSIZE: Message too long // // -------------------------------------------------------------------- static int LCS_EnqueueEthFrame( PLCSDEV pLCSDEV, BYTE bPort, BYTE* pData, size_t iSize ) { PLCSETHFRM pLCSEthFrame; // Will frame NEVER fit into buffer?? if( iSize > MAX_LCS_ETH_FRAME_SIZE( pLCSDEV ) ) { errno = EMSGSIZE; // Message too long return -1; // (-1==failure) } obtain_lock( &pLCSDEV->Lock ); // Ensure we dont overflow the buffer if( ( pLCSDEV->iFrameOffset + // Current buffer Offset sizeof( LCSETHFRM ) + // Size of Frame Header iSize + // Size of Ethernet packet sizeof(pLCSEthFrame->bLCSHdr.hwOffset) ) // Size of Frame terminator > pLCSDEV->iMaxFrameBufferSize ) // Size of Frame buffer { release_lock( &pLCSDEV->Lock ); errno = ENOBUFS; // No buffer space available return -1; // (-1==failure) } // Point to next available LCS Frame slot in our buffer pLCSEthFrame = (PLCSETHFRM)( pLCSDEV->bFrameBuffer + pLCSDEV->iFrameOffset ); // Increment offset to NEXT available slot (after ours) pLCSDEV->iFrameOffset += (U16)(sizeof(LCSETHFRM) + iSize); // Plug updated offset to next frame into our frame header STORE_HW( pLCSEthFrame->bLCSHdr.hwOffset, pLCSDEV->iFrameOffset ); // Finish building the LCS Ethernet Passthru frame header pLCSEthFrame->bLCSHdr.bType = LCS_FRMTYP_ENET; pLCSEthFrame->bLCSHdr.bSlot = bPort; // Copy Ethernet packet to LCS Ethernet Passthru frame memcpy( pLCSEthFrame->bData, pData, iSize ); // Tell "LCS_Read" function that data is available for reading pLCSDEV->fDataPending = 1; release_lock( &pLCSDEV->Lock ); // (wake up "LCS_Read" function) obtain_lock( &pLCSDEV->EventLock ); signal_condition( &pLCSDEV->Event ); release_lock( &pLCSDEV->EventLock ); return 0; // (success) } // ==================================================================== // LCS_EnqueueReplyFrame // ==================================================================== // // Copy a pre-built LCS Command Frame reply frame of iSize bytes // to the next available frame slot. Returns 0 on success, -1 and // errno set to ENOBUFS on failure (no room (yet) in o/p buffer). // The LCS device lock must NOT be held when called. // // -------------------------------------------------------------------- static int LCS_EnqueueReplyFrame( PLCSDEV pLCSDEV, PLCSCMDHDR pReply, size_t iSize ) { PLCSCMDHDR pReplyCmdFrame; obtain_lock( &pLCSDEV->Lock ); // Ensure we dont overflow the buffer if( ( pLCSDEV->iFrameOffset + // Current buffer Offset iSize + // Size of reply frame sizeof(pReply->bLCSHdr.hwOffset)) // Size of Frame terminator > pLCSDEV->iMaxFrameBufferSize ) // Size of Frame buffer { release_lock( &pLCSDEV->Lock ); errno = ENOBUFS; // No buffer space available return -1; // (-1==failure) } // Point to next available LCS Frame slot in our buffer... pReplyCmdFrame = (PLCSCMDHDR)( pLCSDEV->bFrameBuffer + pLCSDEV->iFrameOffset ); // Copy the reply frame into the frame buffer slot... memcpy( pReplyCmdFrame, pReply, iSize ); // Increment buffer offset to NEXT next-available-slot... pLCSDEV->iFrameOffset += (U16) iSize; // Store offset of next frame STORE_HW( pReplyCmdFrame->bLCSHdr.hwOffset, pLCSDEV->iFrameOffset ); // Mark reply pending pLCSDEV->fReplyPending = 1; release_lock( &pLCSDEV->Lock ); return 0; // success } // ==================================================================== // ParseArgs // ==================================================================== int ParseArgs( DEVBLK* pDEVBLK, PLCSBLK pLCSBLK, int argc, char** argv ) { struct in_addr addr; // Work area for addresses MAC mac; int i; #if defined(OPTION_W32_CTCI) int iKernBuff; int iIOBuff; #endif // Housekeeping memset( &addr, 0, sizeof( struct in_addr ) ); // Set some initial defaults #if defined( WIN32 ) pLCSBLK->pszTUNDevice = strdup( tt32_get_default_iface() ); #else pLCSBLK->pszTUNDevice = strdup( HERCTUN_DEV ); #endif pLCSBLK->pszOATFilename = NULL; pLCSBLK->pszIPAddress = NULL; pLCSBLK->pszMACAddress = NULL; #if defined( OPTION_W32_CTCI ) pLCSBLK->iKernBuff = DEF_CAPTURE_BUFFSIZE; pLCSBLK->iIOBuff = DEF_PACKET_BUFFSIZE; #endif // Initialize getopt's counter. This is necessary in the case // that getopt was used previously for another device. optind = 0; // Build new argv list. // getopt_long used to work on old format configuration statements // because LCS was the first argument passed to the device // initialization routine (and was interpreted by getopt* // as the program name and ignored). Now that argv[0] is a valid // argument, we need to shift the arguments and insert a dummy // argv[0]; // Don't allow us to exceed the allocated storage (sanity check) if( argc > (MAX_ARGS-1)) argc = (MAX_ARGS-1); for( i = argc; i > 0; i-- ) argv[i] = argv[i - 1]; argc++; argv[0] = pDEVBLK->typname; // Parse the optional arguments OPTRESET(); optind=0; while( 1 ) { int c; #if defined(HAVE_GETOPT_LONG) int iOpt; static struct option options[] = { { "dev", 1, NULL, 'n' }, #if defined(OPTION_W32_CTCI) { "kbuff", 1, NULL, 'k' }, { "ibuff", 1, NULL, 'i' }, #endif { "oat", 1, NULL, 'o' }, { "mac", 1, NULL, 'm' }, { "debug", 0, NULL, 'd' }, { NULL, 0, NULL, 0 } }; c = getopt_long( argc, argv, "n" #if defined( OPTION_W32_CTCI ) ":k:i" #endif ":o:m:d", options, &iOpt ); #else /* defined(HAVE_GETOPT_LONG) */ c = getopt( argc, argv, "n" #if defined( OPTION_W32_CTCI ) ":k:i" #endif ":o:m:d" ); #endif /* defined(HAVE_GETOPT_LONG) */ if( c == -1 ) break; switch( c ) { case 'n': if( strlen( optarg ) > sizeof( pDEVBLK->filename ) - 1 ) { logmsg( _("HHCLC017E %4.4X invalid device name %s\n"), pDEVBLK->devnum, optarg ); return -1; } pLCSBLK->pszTUNDevice = strdup( optarg ); break; #if defined( OPTION_W32_CTCI ) case 'k': // Kernel Buffer Size (Windows only) iKernBuff = atoi( optarg ); if( iKernBuff * 1024 < MIN_CAPTURE_BUFFSIZE || iKernBuff * 1024 > MAX_CAPTURE_BUFFSIZE ) { logmsg( _("HHCLC052E %4.4X: Invalid kernel buffer size %s\n"), pDEVBLK->devnum, optarg ); return -1; } pLCSBLK->iKernBuff = iKernBuff * 1024; break; case 'i': // I/O Buffer Size (Windows only) iIOBuff = atoi( optarg ); if( iIOBuff * 1024 < MIN_PACKET_BUFFSIZE || iIOBuff * 1024 > MAX_PACKET_BUFFSIZE ) { logmsg( _("HHCLC053E %4.4X: Invalid DLL I/O buffer size %s\n"), pDEVBLK->devnum, optarg ); return -1; } pLCSBLK->iIOBuff = iIOBuff * 1024; break; #endif // defined( OPTION_W32_CTCI ) case 'o': pLCSBLK->pszOATFilename = strdup( optarg ); break; case 'm': if( ParseMAC( optarg, mac ) != 0 ) { logmsg( _("HHCLC018E %4.4X invalid MAC address %s\n"), pDEVBLK->devnum, optarg ); return -1; } strcpy( pLCSBLK->Port[0].szMACAddress, optarg ); pLCSBLK->Port[0].fLocalMAC = TRUE; break; case 'd': pLCSBLK->fDebug = TRUE; break; default: break; } } argc -= optind; argv += optind; if( argc > 1 ) { logmsg( _("HHCLC019E %4.4X too many arguments in statement.\n"), pDEVBLK->devnum ); return -1; } // If an argument is left, it is the optional IP Address if( argc ) { if( inet_aton( *argv, &addr ) == 0 ) { logmsg( _("HHCLC020E %4.4X invalid IP address %s\n"), pDEVBLK->devnum, *argv ); return -1; } if ( pLCSBLK->pszIPAddress ) { free( pLCSBLK->pszIPAddress ); pLCSBLK->pszIPAddress = NULL; } pLCSBLK->pszIPAddress = strdup( *argv ); } return 0; } // ==================================================================== // BuildOAT // ==================================================================== static int BuildOAT( char* pszOATName, PLCSBLK pLCSBLK ) { FILE* fp; char szBuff[255]; int i; char c; // Character work area char* pszStatement = NULL; // -> Resolved statement char* pszKeyword; // -> Statement keyword char* pszOperand; // -> Statement operand int argc; // Number of args char* argv[MAX_ARGS]; // Argument array PLCSPORT pLCSPORT; PLCSDEV pLCSDev; PLCSRTE pLCSRTE; U16 sPort; BYTE bMode; U16 sDevNum; BYTE bType; U32 lIPAddr = 0; // (network byte order) char* pszIPAddress = NULL; char* pszNetAddr = NULL; char* pszNetMask = NULL; struct in_addr addr; // Work area for addresses char pathname[MAX_PATH]; // pszOATName in host path format // Open the configuration file hostpath(pathname, pszOATName, sizeof(pathname)); fp = fopen( pathname, "r" ); if( !fp ) { logmsg( _("HHCLC039E Cannot open file %s: %s\n"), pszOATName, strerror( errno ) ); return -1; } for(;;) { // Read next record from the OAT file if( !ReadOAT( pszOATName, fp, szBuff ) ) { fclose( fp ); return 0; } if( pszStatement ) { free( pszStatement ); pszStatement = NULL; } #if defined(OPTION_CONFIG_SYMBOLS) // Make a copy of the OAT statement with symbols resolved pszStatement = resolve_symbol_string( szBuff ); #else // Make a copy of the OAT statement pszStatement = strdup( szBuff ); #endif sPort = 0; bMode = 0; sDevNum = 0; bType = 0; pszIPAddress = NULL; pszNetAddr = NULL; pszNetMask = NULL; memset( &addr, 0, sizeof( addr ) ); // Split the statement into keyword and first operand pszKeyword = strtok( pszStatement, " \t" ); pszOperand = strtok( NULL, " \t" ); // Extract any arguments for( argc = 0; argc < MAX_ARGS && ( argv[argc] = strtok( NULL, " \t" ) ) != NULL && argv[argc][0] != '#'; argc++ ); // Clear any unused argument pointers for( i = argc; i < MAX_ARGS; i++ ) argv[i] = NULL; if( strcasecmp( pszKeyword, "HWADD" ) == 0 ) { if( !pszOperand || argc != 1 || sscanf( pszOperand, "%hi%c", &sPort, &c ) != 1 ) { logmsg( _("HHCLC021E Invalid HWADD statement in %s: %s\n"), pszOATName, szBuff ); return -1; } pLCSPORT = &pLCSBLK->Port[sPort]; if( ParseMAC( argv[0], pLCSPORT->MAC_Address ) != 0 ) { logmsg( _("HHCLC022E Invalid MAC in HWADD statement " "in %s: %s (%s)\n "), pszOATName, szBuff, argv[0] ); memset( pLCSPORT->MAC_Address, 0, sizeof(MAC) ); return -1; } strcpy( pLCSPORT->szMACAddress, argv[0] ); pLCSPORT->fLocalMAC = TRUE; } else if( strcasecmp( pszKeyword, "ROUTE" ) == 0 ) { if( !pszOperand || argc != 2 || sscanf( pszOperand, "%hi%c", &sPort, &c ) != 1 ) { logmsg( _("HHCLC023E Invalid ROUTE statement in %s: %s\n"), pszOATName, szBuff ); return -1; } if( inet_aton( argv[0], &addr ) == 0 ) { logmsg( _("HHCLC024E Invalid net address in ROUTE %s: %s (%s)\n"), pszOATName, szBuff, argv[0] ); return -1; } pszNetAddr = strdup( argv[0] ); if( inet_aton( argv[1], &addr ) == 0 ) { free(pszNetAddr); logmsg( _("HHCLC025E Invalid net mask in ROUTE %s: %s (%s)\n"), pszOATName, szBuff, argv[1] ); return -1; } pszNetMask = strdup( argv[1] ); pLCSPORT = &pLCSBLK->Port[sPort]; if( !pLCSPORT->pRoutes ) { pLCSPORT->pRoutes = malloc( sizeof( LCSRTE ) ); pLCSRTE = pLCSPORT->pRoutes; } else { for( pLCSRTE = pLCSPORT->pRoutes; pLCSRTE->pNext; pLCSRTE = pLCSRTE->pNext ); pLCSRTE->pNext = malloc( sizeof( LCSRTE ) ); pLCSRTE = pLCSRTE->pNext; } pLCSRTE->pszNetAddr = pszNetAddr; pLCSRTE->pszNetMask = pszNetMask; pLCSRTE->pNext = NULL; } else // (presumed OAT file device statement) { if( !pszKeyword || !pszOperand ) { logmsg( _("HHCLC026E Error in %s: " "Missing device number or mode\n"), pszOATName ); return -1; } if( strlen( pszKeyword ) > 4 || sscanf( pszKeyword, "%hx%c", &sDevNum, &c ) != 1 ) { logmsg( _("HHCLC027E Error in %s: %s: " "Invalid device number\n"), pszOATName, pszKeyword ); return -1; } if( strcasecmp( pszOperand, "IP" ) == 0 ) { bMode = LCSDEV_MODE_IP; if( argc < 1 ) { logmsg( _("HHCLC028E Error in %s: %s:" "Missing PORT number\n"), pszOATName, szBuff ); return -1; } if( sscanf( argv[0], "%hi%c", &sPort, &c ) != 1 ) { logmsg( _("HHCLC029E Error in %s: %s: " "Invalid PORT number\n"), pszOATName, argv[0] ); return -1; } if( argc > 1 ) { if( strcasecmp( argv[1], "PRI" ) == 0 ) bType = LCSDEV_TYPE_PRIMARY; else if( strcasecmp( argv[1], "SEC" ) == 0 ) bType = LCSDEV_TYPE_SECONDARY; else if( strcasecmp( argv[1], "NO" ) == 0 ) bType = LCSDEV_TYPE_NONE; else { logmsg( _("HHCLC031E Error in %s: %s: " "Invalid entry starting at %s\n"), pszOATName, szBuff, argv[1] ); return -1; } if( argc > 2 ) { pszIPAddress = strdup( argv[2] ); if( inet_aton( pszIPAddress, &addr ) == 0 ) { logmsg( _("HHCLC032E Error in %s: %s: " "Invalid IP address (%s)\n"), pszOATName, szBuff, pszIPAddress ); return -1; } lIPAddr = addr.s_addr; // (network byte order) } } } else if( strcasecmp( pszOperand, "SNA" ) == 0 ) { bMode = LCSDEV_MODE_SNA; if( argc < 1 ) { logmsg( _("HHCLC033E Error in %s: %s: " "Missing PORT number\n"), pszOATName, szBuff ); return -1; } if( sscanf( argv[0], "%hi%c", &sPort, &c ) != 1 ) { logmsg( _("HHCLC034E Error in %s: %s:" "Invalid PORT number\n"), pszOATName, argv[0] ); return -1; } if( argc > 1 ) { logmsg( _("HHCLC035E Error in %s: %s: " "SNA does not accept any arguments\n"), pszOATName, szBuff ); return -1; } } else { logmsg( _("HHCLC036E Error in %s: %s: " "Invalid MODE\n"), pszOATName, pszOperand ); return -1; } // Create new LCS Device... pLCSDev = malloc( sizeof( LCSDEV ) ); memset( pLCSDev, 0, sizeof( LCSDEV ) ); pLCSDev->sAddr = sDevNum; pLCSDev->bMode = bMode; pLCSDev->bPort = sPort; pLCSDev->bType = bType; pLCSDev->lIPAddress = lIPAddr; // (network byte order) pLCSDev->pszIPAddress = pszIPAddress; pLCSDev->pNext = NULL; // Add it to end of chain... if( !pLCSBLK->pDevices ) pLCSBLK->pDevices = pLCSDev; // (first link in chain) else { PLCSDEV pOldLastLCSDEV; // (find last link in chain) for( pOldLastLCSDEV = pLCSBLK->pDevices; pOldLastLCSDEV->pNext; pOldLastLCSDEV = pOldLastLCSDEV->pNext ); // (add new link to end of chain) pOldLastLCSDEV->pNext = pLCSDev; } // Count it... if(pLCSDev->bMode == LCSDEV_MODE_IP) pLCSBLK->icDevices += 2; else pLCSBLK->icDevices += 1; } // end OAT file statement } // end for(;;) return 0; } // ==================================================================== // ReadOAT // ==================================================================== static char* ReadOAT( char* pszOATName, FILE* fp, char* pszBuff ) { int c; // Character work area int iLine = 0; // Statement number int iLen; // Statement length while( 1 ) { // Increment statement number iLine++; // Read next statement from OAT for( iLen = 0; ; ) { // Read character from OAT c = fgetc( fp ); // Check for I/O error if( ferror( fp ) ) { logmsg( _("HHCLC037E Error reading file %s line %d: %s\n"), pszOATName, iLine, strerror( errno ) ); return NULL; } // Check for end of file if( iLen == 0 && ( c == EOF || c == '\x1A' ) ) return NULL; // Check for end of line if( c == '\n' || c == EOF || c == '\x1A' ) break; // Ignore leading blanks and tabs if( iLen == 0 && ( c == ' ' || c == '\t' ) ) continue; // Ignore nulls and carriage returns if( c == '\0' || c == '\r' ) continue; // Check that statement does not overflow bufffer if( iLen >= 255 ) { logmsg( _("HHCLC038E File %s line %d is too long\n"), pszOATName, iLine ); exit(1); } // Append character to buffer pszBuff[iLen++] = c; } // Remove trailing blanks and tabs while( iLen > 0 && ( pszBuff[iLen-1] == ' ' || pszBuff[iLen-1] == '\t' ) ) iLen--; pszBuff[iLen] = '\0'; // Ignore comments and null statements if( iLen == 0 || pszBuff[0] == '*' || pszBuff[0] == '#' ) continue; break; } return pszBuff; } // ==================================================================== // Device Handler Information // ==================================================================== /* NOTE : lcs_device_hndinfo is NEVER static as it is referenced by the CTC meta driver */ DEVHND lcs_device_hndinfo = { &LCS_Init, /* Device Initialisation */ &LCS_ExecuteCCW, /* Device CCW execute */ &LCS_Close, /* Device Close */ &LCS_Query, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ CTC_Immed_Commands, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt3088_LTX_hdl_ddev #define hdl_depc hdt3088_LTX_hdl_depc #define hdl_reso hdt3088_LTX_hdl_reso #define hdl_init hdt3088_LTX_hdl_init #define hdl_fini hdt3088_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); } END_DEPENDENCY_SECTION HDL_REGISTER_SECTION; // ("Register" our entry-points) // Hercules's Our // registered overriding // entry-point entry-point // name value #if defined( WIN32 ) HDL_REGISTER ( debug_tt32_stats, display_tt32_stats ); HDL_REGISTER ( debug_tt32_tracing, enable_tt32_debug_tracing ); #endif END_REGISTER_SECTION HDL_DEVICE_SECTION; { HDL_DEVICE(LCS, lcs_device_hndinfo ); // ZZ the following device types should be moved to // ZZ their own loadable modules HDL_DEVICE(3088, ctcadpt_device_hndinfo ); HDL_DEVICE(CTCI, ctci_device_hndinfo ); HDL_DEVICE(CTCT, ctct_device_hndinfo ); HDL_DEVICE(CTCE, ctce_device_hndinfo ); HDL_DEVICE(VMNET,vmnet_device_hndinfo ); #if defined(WIN32) HDL_DEVICE(CTCI-W32,ctci_device_hndinfo ); #endif } END_DEVICE_SECTION #endif //----------------------------------------------------------------------------- // Debugging... #if !defined( DEBUG) && !defined( _DEBUG ) // only needed for Release builds #ifdef NO_LCS_OPTIMIZE // for reliable breakpoints and instr stepping #pragma warning( pop ) // restore previous settings #pragma optimize( "", on ) // restore previous settings #endif // NO_LCS_OPTIMIZE #endif // !defined( DEBUG) && !defined( _DEBUG ) //----------------------------------------------------------------------------- #endif /* !defined(__SOLARIS__) jbs 10/2007 10/2007 */ hercules-3.12/ctc_ctci.c0000664000175000017500000014236312564723224012133 00000000000000/* CTC_CTCI.C (c) Copyright Roger Bowler, 2000-2012 */ /* (c) Copyright James A. Pierson, 2002-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* (c) Copyright Fritz Elfert, 2001-2009 */ /* Hercules IP Channel-to-Channel Support (CTCI) */ #include "hstdinc.h" /* jbs 10/27/2007 added _SOLARIS_ silly typo fixed 01/18/08 when looked at this again */ #if !defined(__SOLARIS__) #include "hercules.h" #include "ctcadpt.h" #include "tuntap.h" #include "hercifc.h" #include "opcode.h" /* getopt dynamic linking kludge */ #include "herc_getopt.h" #if defined(OPTION_W32_CTCI) #include "tt32api.h" #endif /*-------------------------------------------------------------------*/ /* Ivan Warren 20040227 */ /* This table is used by channel.c to determine if a CCW code is an */ /* immediate command or not */ /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */ /* 0 : Command is NOT an immediate command */ /* 1 : Command is an immediate command */ /* Note : An immediate command is defined as a command which returns */ /* CE (channel end) during initialisation (that is, no data is */ /* actually transfered. In this case, IL is not indicated for a CCW */ /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */ /* effect */ /*-------------------------------------------------------------------*/ static BYTE CTCI_Immed_Commands[256]= { 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // ==================================================================== // Declarations // ==================================================================== static void* CTCI_ReadThread( PCTCBLK pCTCBLK ); static int CTCI_EnqueueIPFrame( DEVBLK* pDEVBLK, BYTE* pData, size_t iSize ); static int ParseArgs( DEVBLK* pDEVBLK, PCTCBLK pCTCBLK, int argc, char** argv ); // -------------------------------------------------------------------- // Device Handler Information Block // -------------------------------------------------------------------- DEVHND ctci_device_hndinfo = { &CTCI_Init, /* Device Initialisation */ &CTCI_ExecuteCCW, /* Device CCW execute */ &CTCI_Close, /* Device Close */ &CTCI_Query, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ CTCI_Immed_Commands, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; // ==================================================================== // // ==================================================================== // // CTCI_Init // #define CTC_DEVICES_IN_GROUP 2 // a read and write device int CTCI_Init( DEVBLK* pDEVBLK, int argc, char *argv[] ) { PCTCBLK pWrkCTCBLK = NULL; // Working CTCBLK PCTCBLK pDevCTCBLK = NULL; // Device CTCBLK int rc = 0; // Return code int nIFType; // Interface type int nIFFlags; // Interface flags char thread_name[32]; // CTCI_ReadThread nIFType = // Interface type 0 | IFF_TUN // ("TUN", not "tap") | IFF_NO_PI // (no packet info) ; nIFFlags = // Interface flags 0 | IFF_UP // (interface is being enabled) | IFF_BROADCAST // (interface broadcast addr is valid) ; #if defined( TUNTAP_IFF_RUNNING_NEEDED ) nIFFlags |= // ADDITIONAL Interface flags 0 | IFF_RUNNING // (interface is ALSO operational) ; #endif /* defined( TUNTAP_IFF_RUNNING_NEEDED ) */ pDEVBLK->devtype = 0x3088; // CTC is a group device if(!group_device(pDEVBLK, CTC_DEVICES_IN_GROUP)) return 0; // Housekeeping pWrkCTCBLK = malloc( sizeof( CTCBLK ) ); if( !pWrkCTCBLK ) { logmsg( _("HHCCT037E %4.4X: Unable to allocate CTCBLK\n"), pDEVBLK->devnum ); return -1; } memset( pWrkCTCBLK, 0, sizeof( CTCBLK ) ); // Parse configuration file statement if( ParseArgs( pDEVBLK, pWrkCTCBLK, argc, (char**)argv ) != 0 ) { free( pWrkCTCBLK ); pWrkCTCBLK = NULL; return -1; } // Allocate the device CTCBLK and copy parsed information. pDevCTCBLK = malloc( sizeof( CTCBLK ) ); if( !pDevCTCBLK ) { logmsg( _("HHCCT038E %4.4X: Unable to allocate CTCBLK\n"), pDEVBLK->devnum ); free( pWrkCTCBLK ); pWrkCTCBLK = NULL; return -1; } memcpy( pDevCTCBLK, pWrkCTCBLK, sizeof( CTCBLK ) ); // New format has only one device statement for both addresses // We need to dynamically allocate the read device block pDevCTCBLK->pDEVBLK[0] = pDEVBLK->group->memdev[0]; pDevCTCBLK->pDEVBLK[1] = pDEVBLK->group->memdev[1]; pDevCTCBLK->pDEVBLK[0]->dev_data = pDevCTCBLK; pDevCTCBLK->pDEVBLK[1]->dev_data = pDevCTCBLK; SetSIDInfo( pDevCTCBLK->pDEVBLK[0], 0x3088, 0x08, 0x3088, 0x01 ); SetSIDInfo( pDevCTCBLK->pDEVBLK[1], 0x3088, 0x08, 0x3088, 0x01 ); pDevCTCBLK->pDEVBLK[0]->ctctype = CTC_CTCI; pDevCTCBLK->pDEVBLK[0]->ctcxmode = 1; pDevCTCBLK->pDEVBLK[1]->ctctype = CTC_CTCI; pDevCTCBLK->pDEVBLK[1]->ctcxmode = 1; pDevCTCBLK->sMTU = atoi( pDevCTCBLK->szMTU ); pDevCTCBLK->iMaxFrameBufferSize = sizeof(pDevCTCBLK->bFrameBuffer); initialize_lock( &pDevCTCBLK->Lock ); initialize_lock( &pDevCTCBLK->EventLock ); initialize_condition( &pDevCTCBLK->Event ); // Give both Herc devices a reasonable name... strlcpy( pDevCTCBLK->pDEVBLK[0]->filename, pDevCTCBLK->szTUNCharName, sizeof( pDevCTCBLK->pDEVBLK[0]->filename ) ); strlcpy( pDevCTCBLK->pDEVBLK[1]->filename, pDevCTCBLK->szTUNCharName, sizeof( pDevCTCBLK->pDEVBLK[1]->filename ) ); rc = TUNTAP_CreateInterface( pDevCTCBLK->szTUNCharName, IFF_TUN | IFF_NO_PI, &pDevCTCBLK->fd, pDevCTCBLK->szTUNDevName ); if( rc < 0 ) { free( pWrkCTCBLK ); pWrkCTCBLK = NULL; return -1; } else { logmsg(_("HHCCT073I %4.4X: TUN device %s opened\n"), pDevCTCBLK->pDEVBLK[0]->devnum, pDevCTCBLK->szTUNDevName); } #if defined(OPTION_W32_CTCI) // Set the specified driver/dll i/o buffer sizes.. { struct tt32ctl tt32ctl; memset( &tt32ctl, 0, sizeof(tt32ctl) ); strlcpy( tt32ctl.tt32ctl_name, pDevCTCBLK->szTUNDevName, sizeof(tt32ctl.tt32ctl_name) ); tt32ctl.tt32ctl_devbuffsize = pDevCTCBLK->iKernBuff; if( TUNTAP_IOCtl( pDevCTCBLK->fd, TT32SDEVBUFF, (char*)&tt32ctl ) != 0 ) { logmsg( _("HHCCT074W TT32SDEVBUFF failed for device %s: %s.\n"), pDevCTCBLK->szTUNDevName, strerror( errno ) ); } tt32ctl.tt32ctl_iobuffsize = pDevCTCBLK->iIOBuff; if( TUNTAP_IOCtl( pDevCTCBLK->fd, TT32SIOBUFF, (char*)&tt32ctl ) != 0 ) { logmsg( _("HHCCT075W TT32SIOBUFF failed for device %s: %s.\n"), pDevCTCBLK->szTUNDevName, strerror( errno ) ); } } #endif #ifdef OPTION_TUNTAP_CLRIPADDR VERIFY( TUNTAP_ClrIPAddr ( pDevCTCBLK->szTUNDevName ) == 0 ); #endif #ifdef OPTION_TUNTAP_SETMACADDR if( !pDevCTCBLK->szMACAddress[0] ) // (if MAC address unspecified) { in_addr_t wrk_guest_ip_addr; MAC wrk_guest_mac_addr; if ((in_addr_t)-1 != (wrk_guest_ip_addr = inet_addr( pDevCTCBLK->szGuestIPAddr ))) { build_herc_iface_mac ( wrk_guest_mac_addr, (const BYTE*) &wrk_guest_ip_addr ); snprintf ( pDevCTCBLK->szMACAddress, sizeof( pDevCTCBLK->szMACAddress ), "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X" ,wrk_guest_mac_addr[0] ,wrk_guest_mac_addr[1] ,wrk_guest_mac_addr[2] ,wrk_guest_mac_addr[3] ,wrk_guest_mac_addr[4] ,wrk_guest_mac_addr[5] ); } } TRACE ( "** CTCI_Init: %4.4X (%s): IP \"%s\" --> default MAC \"%s\"\n" ,pDevCTCBLK->pDEVBLK[0]->devnum ,pDevCTCBLK->szTUNDevName ,pDevCTCBLK->szGuestIPAddr ,pDevCTCBLK->szMACAddress ); VERIFY( TUNTAP_SetMACAddr ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szMACAddress ) == 0 ); #endif VERIFY( TUNTAP_SetIPAddr ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szDriveIPAddr ) == 0 ); VERIFY( TUNTAP_SetDestAddr( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szGuestIPAddr ) == 0 ); #ifdef OPTION_TUNTAP_SETNETMASK VERIFY( TUNTAP_SetNetMask ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szNetMask ) == 0 ); #endif VERIFY( TUNTAP_SetMTU ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szMTU ) == 0 ); VERIFY( TUNTAP_SetFlags ( pDevCTCBLK->szTUNDevName, nIFFlags ) == 0 ); // Copy the fd to make panel.c happy pDevCTCBLK->pDEVBLK[0]->fd = pDevCTCBLK->pDEVBLK[1]->fd = pDevCTCBLK->fd; snprintf(thread_name,sizeof(thread_name),"CTCI %4.4X ReadThread",pDEVBLK->devnum); thread_name[sizeof(thread_name)-1]=0; create_thread( &pDevCTCBLK->tid, JOINABLE, CTCI_ReadThread, pDevCTCBLK, thread_name ); pDevCTCBLK->pDEVBLK[0]->tid = pDevCTCBLK->tid; pDevCTCBLK->pDEVBLK[1]->tid = pDevCTCBLK->tid; free( pWrkCTCBLK ); pWrkCTCBLK = NULL; return 0; } // // CTCI_ExecuteCCW // void CTCI_ExecuteCCW( DEVBLK* pDEVBLK, BYTE bCode, BYTE bFlags, BYTE bChained, U16 sCount, BYTE bPrevCode, int iCCWSeq, BYTE* pIOBuf, BYTE* pMore, BYTE* pUnitStat, U16* pResidual ) { int iNum; // Number of bytes to move BYTE bOpCode; // CCW opcode with modifier // bits masked off UNREFERENCED( bFlags ); UNREFERENCED( bChained ); UNREFERENCED( bPrevCode ); UNREFERENCED( iCCWSeq ); // Intervention required if the device file is not open if( pDEVBLK->fd < 0 && !IS_CCW_SENSE( bCode ) && !IS_CCW_CONTROL( bCode ) ) { pDEVBLK->sense[0] = SENSE_IR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Mask off the modifier bits in the CCW bOpCode if( ( bCode & 0x07 ) == 0x07 ) bOpCode = 0x07; else if( ( bCode & 0x03 ) == 0x02 ) bOpCode = 0x02; else if( ( bCode & 0x0F ) == 0x0C ) bOpCode = 0x0C; else if( ( bCode & 0x03 ) == 0x01 ) bOpCode = pDEVBLK->ctcxmode ? ( bCode & 0x83 ) : 0x01; else if( ( bCode & 0x1F ) == 0x14 ) bOpCode = 0x14; else if( ( bCode & 0x47 ) == 0x03 ) bOpCode = 0x03; else if( ( bCode & 0xC7 ) == 0x43 ) bOpCode = 0x43; else bOpCode = bCode; // Process depending on CCW bOpCode switch (bOpCode) { case 0x01: // 0MMMMM01 WRITE //------------------------------------------------------------ // WRITE //------------------------------------------------------------ // Return normal status if CCW count is zero if( sCount == 0 ) { *pUnitStat = CSW_CE | CSW_DE; break; } CTCI_Write( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual ); break; case 0x81: // 1MMMMM01 WEOF //------------------------------------------------------------ // WRITE EOF //------------------------------------------------------------ // Return normal status *pUnitStat = CSW_CE | CSW_DE; break; case 0x02: // MMMMMM10 READ case 0x0C: // MMMM1100 RDBACK // ----------------------------------------------------------- // READ & READ BACKWARDS // ----------------------------------------------------------- // Read data and set unit status and residual byte count CTCI_Read( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual, pMore ); break; case 0x07: // MMMMM111 CTL // ----------------------------------------------------------- // CONTROL // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x03: // M0MMM011 NOP // ----------------------------------------------------------- // CONTROL NO-OPERATON // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x43: // 00XXX011 SBM // ----------------------------------------------------------- // SET BASIC MODE // ----------------------------------------------------------- // Command reject if in basic mode if( pDEVBLK->ctcxmode == 0 ) { pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; break; } // Reset extended mode and return normal status pDEVBLK->ctcxmode = 0; *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE; break; case 0xC3: // 11000011 SEM // ----------------------------------------------------------- // SET EXTENDED MODE // ----------------------------------------------------------- pDEVBLK->ctcxmode = 1; *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE; break; case 0xE3: // 11100011 // ----------------------------------------------------------- // PREPARE (PREP) // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x14: // XXX10100 SCB // ----------------------------------------------------------- // SENSE COMMAND BYTE // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x04: // 00000100 SENSE // ----------------------------------------------------------- // SENSE // ----------------------------------------------------------- // Command reject if in basic mode if( pDEVBLK->ctcxmode == 0 ) { pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; break; } // Calculate residual byte count iNum = ( sCount < pDEVBLK->numsense ) ? sCount : pDEVBLK->numsense; *pResidual = sCount - iNum; if( sCount < pDEVBLK->numsense ) *pMore = 1; // Copy device sense bytes to channel I/O buffer memcpy( pIOBuf, pDEVBLK->sense, iNum ); // Clear the device sense bytes memset( pDEVBLK->sense, 0, sizeof( pDEVBLK->sense ) ); // Return unit status *pUnitStat = CSW_CE | CSW_DE; break; case 0xE4: // 11100100 SID // ----------------------------------------------------------- // SENSE ID // ----------------------------------------------------------- // Calculate residual byte count iNum = ( sCount < pDEVBLK->numdevid ) ? sCount : pDEVBLK->numdevid; *pResidual = sCount - iNum; if( sCount < pDEVBLK->numdevid ) *pMore = 1; // Copy device identifier bytes to channel I/O buffer memcpy( pIOBuf, pDEVBLK->devid, iNum ); // Return unit status *pUnitStat = CSW_CE | CSW_DE; break; default: // ------------------------------------------------------------ // INVALID OPERATION // ------------------------------------------------------------ // Set command reject sense byte, and unit check status pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; } } // ------------------------------------------------------------------- // CTCI_Close // ------------------------------------------------------------------- int CTCI_Close( DEVBLK* pDEVBLK ) { /* DEVBLK* pDEVBLK2; */ PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; // Close the device file (if not already closed) if( pCTCBLK->fd >= 0 ) { // PROGRAMMING NOTE: there's currently no way to interrupt // the "CTCI_ReadThread"s TUNTAP_Read of the adapter. Thus // we must simply wait for CTCI_ReadThread to eventually // notice that we're doing a close (via our setting of the // fCloseInProgress flag). Its TUNTAP_Read will eventually // timeout after a few seconds (currently 5, which is dif- // ferent than the CTC_READ_TIMEOUT_SECS timeout value the // CTCI_Read function uses) and will then do the close of // the adapter for us (TUNTAP_Close) so we don't have to. // All we need to do is ask it to exit (via our setting of // the fCloseInProgress flag) and then wait for it to exit // (which, as stated, could take up to a max of 5 seconds). // All of this is simply because it's poor form to close a // device from one thread while another thread is reading // from it. Attempting to do so could trip a race condition // wherein the internal i/o buffers used to process the // read request could have been freed (by the close call) // by the time the read request eventually gets serviced. TID tid = pCTCBLK->tid; pCTCBLK->fCloseInProgress = 1; // (ask read thread to exit) signal_thread( tid, SIGUSR2 ); // (for non-Win32 platforms) //FIXME signal_thread not working for non-MSVC platforms #if defined(_MSVC_) join_thread( tid, NULL ); // (wait for thread to end) #endif detach_thread( tid ); // (wait for thread to end) } pDEVBLK->fd = -1; // indicate we're now closed return 0; } // ------------------------------------------------------------------- // CTCI_Query // ------------------------------------------------------------------- void CTCI_Query( DEVBLK* pDEVBLK, char** ppszClass, int iBufLen, char* pBuffer ) { CTCBLK* pCTCBLK; BEGIN_DEVICE_CLASS_QUERY( "CTCA", pDEVBLK, ppszClass, iBufLen, pBuffer ); pCTCBLK = (CTCBLK*) pDEVBLK->dev_data; if(!pCTCBLK) { strlcpy(pBuffer,"*Uninitialized",iBufLen); return; } snprintf( pBuffer, iBufLen, "CTCI %s/%s (%s)%s", pCTCBLK->szGuestIPAddr, pCTCBLK->szDriveIPAddr, pCTCBLK->szTUNDevName, pCTCBLK->fDebug ? " -d" : "" ); } // ------------------------------------------------------------------- // CTCI_Read // ------------------------------------------------------------------- // // Once an IP frame is received by the Read Thread, it is enqueued // on the device frame buffer for presentation to the host program. // The residual byte count is set to indicate the amount of the buffer // which was not filled. // // For details regarding the actual buffer layout, please refer to // the comments preceding the CTCI_ReadThread function. // Input: // pDEVBLK A pointer to the CTC adapter device block // sCount The I/O buffer length from the read CCW // pIOBuf The I/O buffer from the read CCW // // Output: // pUnitStat The CSW status (CE+DE or CE+DE+UC or CE+DE+UC+SM) // pResidual The CSW residual byte count // pMore Set to 1 if packet data exceeds CCW count // void CTCI_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual, BYTE* pMore ) { PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; PCTCIHDR pFrame = NULL; size_t iLength = 0; int rc = 0; for ( ; ; ) { obtain_lock( &pCTCBLK->Lock ); if( !pCTCBLK->fDataPending ) { struct timespec waittime; struct timeval now; release_lock( &pCTCBLK->Lock ); gettimeofday( &now, NULL ); waittime.tv_sec = now.tv_sec + CTC_READ_TIMEOUT_SECS; waittime.tv_nsec = now.tv_usec * 1000; obtain_lock( &pCTCBLK->EventLock ); rc = timed_wait_condition( &pCTCBLK->Event, &pCTCBLK->EventLock, &waittime ); release_lock( &pCTCBLK->EventLock ); if( rc == ETIMEDOUT || rc == EINTR ) { // check for halt condition if( pDEVBLK->scsw.flag2 & SCSW2_FC_HALT || pDEVBLK->scsw.flag2 & SCSW2_FC_CLEAR ) { if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCCT040I %4.4X: Halt or Clear Recognized\n"), pDEVBLK->devnum ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = sCount; return; } continue; } obtain_lock( &pCTCBLK->Lock ); } // Sanity check if( pCTCBLK->iFrameOffset == 0 ) { release_lock( &pCTCBLK->Lock ); continue; } // Fix-up frame pointer and terminate block pFrame = (PCTCIHDR)( pCTCBLK->bFrameBuffer + sizeof( CTCIHDR ) + pCTCBLK->iFrameOffset ); STORE_HW( pFrame->hwOffset, 0x0000 ); // (fix for day-1 bug offered by Vince Weaver [vince@deater.net]) // iLength = pCTCBLK->iFrameOffset + sizeof( CTCIHDR ) + 2; iLength = pCTCBLK->iFrameOffset + sizeof( CTCIHDR ); if( sCount < iLength ) { *pMore = 1; *pResidual = 0; iLength = sCount; } else { *pMore = 0; *pResidual -= iLength; } *pUnitStat = CSW_CE | CSW_DE; memcpy( pIOBuf, pCTCBLK->bFrameBuffer, iLength ); if( pCTCBLK->fDebug ) { logmsg( _("HHCCT041I %4.4X: CTC Received Frame (%d bytes):\n"), pDEVBLK->devnum, iLength ); packet_trace( pCTCBLK->bFrameBuffer, iLength ); } // Reset frame buffer pCTCBLK->iFrameOffset = 0; pCTCBLK->fDataPending = 0; release_lock( &pCTCBLK->Lock ); return; } } // ------------------------------------------------------------------- // CTCI_Write // ------------------------------------------------------------------- // // For details regarding the actual buffer layout, please refer to // the comments preceding the CTCI_ReadThread function. // void CTCI_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ) { PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; PCTCIHDR pFrame; // -> Frame header PCTCISEG pSegment; // -> Segment in buffer U16 sOffset; // Offset of next frame U16 sSegLen; // Current segment length U16 sDataLen; // Length of IP Frame data int iPos; // Offset into buffer U16 i; // Array subscript int rc; // Return code BYTE szStackID[33]; // VSE IP stack identity U32 iStackCmd; // VSE IP stack command // Check that CCW count is sufficient to contain block header if( sCount < sizeof( CTCIHDR ) ) { logmsg( _("HHCCT042E %4.4X: Write CCW count %u is invalid\n"), pDEVBLK->devnum, sCount ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up frame pointer pFrame = (PCTCIHDR)pIOBuf; // Extract the frame length from the header FETCH_HW( sOffset, pFrame->hwOffset ); // Check for special VSE TCP/IP stack command packet if( sOffset == 0 && sCount == 40 ) { // Extract the 32-byte stack identity string for( i = 0; i < sizeof( szStackID ) - 1 && i < sCount - 4; i++) szStackID[i] = guest_to_host( pIOBuf[i+4] ); szStackID[i] = '\0'; // Extract the stack command word FETCH_FW( iStackCmd, *((FWORD*)&pIOBuf[36]) ); // Display stack command and discard the packet logmsg( _("HHCCT043I %4.4X: Interface command: %s %8.8X\n"), pDEVBLK->devnum, szStackID, iStackCmd ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } // Check for special L/390 initialization packet if( sOffset == 0 ) { // Return normal status and discard the packet *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } #if 0 // Notes: It appears that TurboLinux has gotten sloppy in their // ways. They are now giving us buffer sizes that are // greater than the CCW count, but the segment size // is within the count. // Check that the frame offset is valid if( sOffset < sizeof( CTCIHDR ) || sOffset > sCount ) { logmsg( _("CTC101W %4.4X: Write buffer contains invalid " "frame offset %u\n"), pDEVBLK->devnum, sOffset ); pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } #endif // Adjust the residual byte count *pResidual -= sizeof( CTCIHDR ); // Process each segment in the buffer for( iPos = sizeof( CTCIHDR ); iPos < sOffset; iPos += sSegLen ) { // Check that the segment is fully contained within the block if( iPos + sizeof( CTCISEG ) > sOffset ) { logmsg( _("HHCCT044E %4.4X: Write buffer contains incomplete " "segment header at offset %4.4X\n"), pDEVBLK->devnum, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up segment header in the I/O buffer pSegment = (PCTCISEG)(pIOBuf + iPos); // Extract the segment length from the segment header FETCH_HW( sSegLen, pSegment->hwLength ); // Check that the segment length is valid if( ( sSegLen < sizeof( CTCISEG ) ) || ( iPos + sSegLen > sOffset ) || ( iPos + sSegLen > sCount ) ) { logmsg( _("HHCCT045E %4.4X: Write buffer contains invalid " "segment length %u at offset %4.4X\n"), pDEVBLK->devnum, sSegLen, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Calculate length of IP frame data sDataLen = sSegLen - sizeof( CTCISEG ); // Trace the IP packet before sending to TUN device if( pCTCBLK->fDebug ) { logmsg( _("HHCCT046I %4.4X: Sending packet to %s:\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName ); packet_trace( pSegment->bData, sDataLen ); } // Write the IP packet to the TUN/TAP interface rc = TUNTAP_Write( pCTCBLK->fd, pSegment->bData, sDataLen ); if( rc < 0 ) { logmsg( _("HHCCT047E %4.4X: Error writing to %s: rc=%d errno=%d %s\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName, rc, errno, strerror(errno)); } /* Kludge for Ubuntu 10.04 by Martin Truebner */ if (rc == -1 && errno == 22) rc = 0; if (rc < 0) { pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Adjust the residual byte count *pResidual -= sSegLen; // We are done if current segment satisfies CCW count if( iPos + sSegLen == sCount ) { *pResidual -= sSegLen; *pUnitStat = CSW_CE | CSW_DE; return; } } // Set unit status and residual byte count *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; } // -------------------------------------------------------------------- // CTCI_ReadThread // -------------------------------------------------------------------- // // When an IP frame is received from the TUN/TAP interface, the frame // is enqueued on the device frame buffer. // // The device frame buffer is a chain of blocks. The first 2 bytes of // a block (CTCIHDR) specify the offset in the buffer of the next block. // The final block in indicated by a CTCIHDR offset value of 0x0000. // // Within each block, each IP frame is preceeded by a segment header // (CTCISEG). This segment header has a 2 byte length field that // specifies the length of the segment (including the segment header), // a 2 byte frame type field (always 0x0800 = IPv4), and a 2 byte // reserved area (always 0000), followed by the actual frame data. // // The CTCI_ReadThread reads the IP frame, then CTCI_EnqueueIPFrame // function is called to add it to the frame buffer (which precedes // each one with a CTCISEG and adjusts the block header (CTCIHDR) // offset value as appropriate. // // Oddly, it is the CTCI_Read function (called by CCW processing in // response to a guest SIO request) that adds the CTCIHDR with the // 000 offset value marking the end of the buffer's chain of blocks, // and not the CTCI_EnqueueIPFrame nor the CTCI_ReadThread as would // be expected. // // Also note that the iFrameOffset field in the CTCI device's CTCBLK // control block is the offset from the end of the buffer's first // CTCIHDR to where the end-of-chain CTCIHDR is, and is identical to // all of the queued CTCISEG's hwLength fields added together. // static void* CTCI_ReadThread( PCTCBLK pCTCBLK ) { DEVBLK* pDEVBLK = pCTCBLK->pDEVBLK[0]; int iLength; BYTE szBuff[2048]; // ZZ FIXME: Try to avoid race condition at startup with hercifc SLEEP(10); pCTCBLK->pid = getpid(); while( pCTCBLK->fd != -1 && !pCTCBLK->fCloseInProgress ) { // Read frame from the TUN/TAP interface iLength = TUNTAP_Read( pCTCBLK->fd, szBuff, sizeof(szBuff) ); // Check for error condition if( iLength < 0 ) { logmsg( _("HHCCT048E %4.4X: Error reading from %s: %s\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName, strerror( errno ) ); break; } if( iLength == 0 ) // (probably EINTR; ignore) continue; if( pCTCBLK->fDebug ) { logmsg( _("HHCCT049I %4.4X: Received packet from %s (%d bytes):\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName, iLength ); packet_trace( szBuff, iLength ); } // Enqueue frame on buffer, if buffer is full, keep trying while( CTCI_EnqueueIPFrame( pDEVBLK, szBuff, iLength ) < 0 && pCTCBLK->fd != -1 && !pCTCBLK->fCloseInProgress ) { if( EMSGSIZE == errno ) // (if too large for buffer) { if( pCTCBLK->fDebug ) logmsg( _("HHCCT072W %4.4X: Packet too big; dropped.\n"), pDEVBLK->devnum ); break; // (discard it...) } ASSERT( ENOBUFS == errno ); // Don't use sched_yield() here; use an actual non-dispatchable // delay instead so as to allow another [possibly lower priority] // thread to 'read' (remove) some packet(s) from our frame buffer. usleep( CTC_DELAY_USECS ); // (wait a bit before retrying...) } } // We must do the close since we were the one doing the i/o... VERIFY( pCTCBLK->fd == -1 || TUNTAP_Close( pCTCBLK->fd ) == 0 ); pCTCBLK->fd = -1; return NULL; } // -------------------------------------------------------------------- // CTCI_EnqueueIPFrame // -------------------------------------------------------------------- // // Places the provided IP frame in the next available frame slot in // the adapter buffer. For details regarding the actual buffer layout // please refer to the comments preceding the CTCI_ReadThread function. // // Returns: // // 0 == Success // -1 == Failure; errno = ENOBUFS: No buffer space available // EMSGSIZE: Message too long // static int CTCI_EnqueueIPFrame( DEVBLK* pDEVBLK, BYTE* pData, size_t iSize ) { PCTCIHDR pFrame; PCTCISEG pSegment; PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; // Will frame NEVER fit into buffer?? if( iSize > MAX_CTCI_FRAME_SIZE( pCTCBLK ) ) { errno = EMSGSIZE; // Message too long return -1; // (-1==failure) } obtain_lock( &pCTCBLK->Lock ); // Ensure we dont overflow the buffer if( ( pCTCBLK->iFrameOffset + // Current buffer Offset sizeof( CTCIHDR ) + // Size of Block Header sizeof( CTCISEG ) + // Size of Segment Header iSize + // Size of Ethernet packet sizeof(pFrame->hwOffset) ) // Size of Block terminator > pCTCBLK->iMaxFrameBufferSize ) // Size of Frame buffer { release_lock( &pCTCBLK->Lock ); errno = ENOBUFS; // No buffer space available return -1; // (-1==failure) } // Fix-up Frame pointer pFrame = (PCTCIHDR)pCTCBLK->bFrameBuffer; // Fix-up Segment pointer pSegment = (PCTCISEG)( pCTCBLK->bFrameBuffer + sizeof( CTCIHDR ) + pCTCBLK->iFrameOffset ); // Initialize segment memset( pSegment, 0, iSize + sizeof( CTCISEG ) ); // Increment offset pCTCBLK->iFrameOffset += sizeof( CTCISEG ) + iSize; // Update next frame offset STORE_HW( pFrame->hwOffset, pCTCBLK->iFrameOffset + sizeof( CTCIHDR ) ); // Store segment length STORE_HW( pSegment->hwLength, sizeof( CTCISEG ) + iSize ); // Store Frame type STORE_HW( pSegment->hwType, ETH_TYPE_IP ); // Copy data memcpy( pSegment->bData, pData, iSize ); // Mark data pending pCTCBLK->fDataPending = 1; release_lock( &pCTCBLK->Lock ); obtain_lock( &pCTCBLK->EventLock ); signal_condition( &pCTCBLK->Event ); release_lock( &pCTCBLK->EventLock ); return 0; // (0==success) } // // ParseArgs // static int ParseArgs( DEVBLK* pDEVBLK, PCTCBLK pCTCBLK, int argc, char** argv ) { struct in_addr addr; // Work area for addresses int iMTU; int i; MAC mac; // Work area for MAC address #if defined(OPTION_W32_CTCI) int iKernBuff; int iIOBuff; #endif // Housekeeping memset( &addr, 0, sizeof( struct in_addr ) ); memset( &mac, 0, sizeof( MAC ) ); // Set some initial defaults strcpy( pCTCBLK->szMTU, "1500" ); strcpy( pCTCBLK->szNetMask, "255.255.255.255" ); #if defined( OPTION_W32_CTCI ) strcpy( pCTCBLK->szTUNCharName, tt32_get_default_iface() ); #else strcpy( pCTCBLK->szTUNCharName, HERCTUN_DEV ); #endif #if defined( OPTION_W32_CTCI ) pCTCBLK->iKernBuff = DEF_CAPTURE_BUFFSIZE; pCTCBLK->iIOBuff = DEF_PACKET_BUFFSIZE; #endif // Initialize getopt's counter. This is necessary in the case // that getopt was used previously for another device. OPTRESET(); optind = 0; // Check for correct number of arguments if( argc < 2 ) { logmsg( _("HHCCT056E %4.4X: Incorrect number of parameters\n"), pDEVBLK->devnum ); return -1; } // Compatability with old format configuration files needs to be // maintained. Old format statements have the tun character device // name as the second argument on Linux, or CTCI-W32 as the first // argument on Windows. if( ( strncasecmp( argv[0], "/", 1 ) == 0 ) || ( strncasecmp( pDEVBLK->typname, "CTCI-W32", 8 ) == 0 ) ) { pCTCBLK->fOldFormat = 1; } else { // Build new argv list. // getopt_long used to work on old format configuration statements // because LCS was the first argument passed to the device // initialization routine (and was interpreted by getopt* // as the program name and ignored). Now that argv[0] is a valid // argument, we need to shift the arguments and insert a dummy // argv[0]; // Don't allow us to exceed the allocated storage (sanity check) if( argc > (MAX_ARGS-1) ) argc = (MAX_ARGS-1); for( i = argc; i > 0; i-- ) argv[i] = argv[i - 1]; argc++; argv[0] = pDEVBLK->typname; } // Parse any optional arguments if not old format while( !pCTCBLK->fOldFormat ) { int c; #if defined(HAVE_GETOPT_LONG) int iOpt; static struct option options[] = { { "dev", 1, NULL, 'n' }, #if defined( OPTION_W32_CTCI ) { "kbuff", 1, NULL, 'k' }, { "ibuff", 1, NULL, 'i' }, #endif { "mtu", 1, NULL, 't' }, { "netmask", 1, NULL, 's' }, { "mac", 1, NULL, 'm' }, { "debug", 0, NULL, 'd' }, { NULL, 0, NULL, 0 } }; c = getopt_long( argc, argv, "n" #if defined( OPTION_W32_CTCI ) ":k:i" #endif ":t:s:m:d", options, &iOpt ); #else /* defined(HAVE_GETOPT_LONG) */ c = getopt( argc, argv, "n" #if defined( OPTION_W32_CTCI ) ":k:i" #endif ":t:s:m:d"); #endif /* defined(HAVE_GETOPT_LONG) */ if( c == -1 ) // No more options found break; switch( c ) { case 'n': // Network Device #if defined( OPTION_W32_CTCI ) // This could be the IP or MAC address of the // host ethernet adapter. if( inet_aton( optarg, &addr ) == 0 ) { // Not an IP address, check for valid MAC if( ParseMAC( optarg, mac ) != 0 ) { logmsg( _("HHCCT050E %4.4X: Invalid adapter address %s\n"), pDEVBLK->devnum, optarg ); return -1; } } #endif // defined( OPTION_W32_CTCI ) // This is the file name of the special TUN/TAP character device if( strlen( optarg ) > sizeof( pCTCBLK->szTUNCharName ) - 1 ) { logmsg( _("HHCCT051E %4.4X: Invalid device name %s\n"), pDEVBLK->devnum, optarg ); return -1; } strcpy( pCTCBLK->szTUNCharName, optarg ); break; #if defined( OPTION_W32_CTCI ) case 'k': // Kernel Buffer Size (Windows only) iKernBuff = atoi( optarg ); if( iKernBuff * 1024 < MIN_CAPTURE_BUFFSIZE || iKernBuff * 1024 > MAX_CAPTURE_BUFFSIZE ) { logmsg( _("HHCCT052E %4.4X: Invalid kernel buffer size %s\n"), pDEVBLK->devnum, optarg ); return -1; } pCTCBLK->iKernBuff = iKernBuff * 1024; break; case 'i': // I/O Buffer Size (Windows only) iIOBuff = atoi( optarg ); if( iIOBuff * 1024 < MIN_PACKET_BUFFSIZE || iIOBuff * 1024 > MAX_PACKET_BUFFSIZE ) { logmsg( _("HHCCT053E %4.4X: Invalid DLL I/O buffer size %s\n"), pDEVBLK->devnum, optarg ); return -1; } pCTCBLK->iIOBuff = iIOBuff * 1024; break; #endif // defined( OPTION_W32_CTCI ) case 't': // MTU of point-to-point link (ignored if Windows) iMTU = atoi( optarg ); if( iMTU < 46 || iMTU > 65536 ) { logmsg( _("HHCCT054E %4.4X: Invalid MTU size %s\n"), pDEVBLK->devnum, optarg ); return -1; } strcpy( pCTCBLK->szMTU, optarg ); break; case 's': // Netmask of point-to-point link if( inet_aton( optarg, &addr ) == 0 ) { logmsg( _("HHCCT055E %4.4X: Invalid netmask %s\n"), pDEVBLK->devnum, optarg ); return -1; } strcpy( pCTCBLK->szNetMask, optarg ); break; case 'm': if( ParseMAC( optarg, mac ) != 0 ) { logmsg( _("HHCCT056E %4.4X: Invalid MAC address %s\n"), pDEVBLK->devnum, optarg ); return -1; } strcpy( pCTCBLK->szMACAddress, optarg ); break; case 'd': // Diagnostics pCTCBLK->fDebug = TRUE; break; default: break; } } // Shift past any options argc -= optind; argv += optind; i = 0; // Check for correct number of arguments if( argc == 0 ) { logmsg( _("HHCCT056E %4.4X: Incorrect number of parameters\n"), pDEVBLK->devnum ); return -1; } if( !pCTCBLK->fOldFormat ) { // New format has 2 and only 2 parameters (Though several options). if( argc != 2 ) { logmsg( _("HHCCT057E %4.4X: Incorrect number of parameters\n"), pDEVBLK->devnum ); return -1; } // Guest IP Address if( inet_aton( *argv, &addr ) == 0 ) { logmsg( _("HHCCT058E %4.4X: Invalid IP address %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szGuestIPAddr, *argv ); argc--; argv++; // Driver IP Address if( inet_aton( *argv, &addr ) == 0 ) { logmsg( _("HHCCT059E %4.4X: Invalid IP address %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szDriveIPAddr, *argv ); argc--; argv++; } else // if( pCTCBLK->fOldFormat ) { #if !defined( OPTION_W32_CTCI ) // All arguments are non-optional in linux old-format // Old format has 5 and only 5 arguments if( argc != 5 ) { logmsg( _("HHCCT060E %4.4X: Incorrect number of parameters\n"), pDEVBLK->devnum ); return -1; } // TUN/TAP Device if( **argv != '/' || strlen( *argv ) > sizeof( pCTCBLK->szTUNCharName ) - 1 ) { logmsg( _("HHCCT061E %4.4X: invalid device name %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szTUNCharName, *argv ); argc--; argv++; // MTU Size iMTU = atoi( *argv ); if( iMTU < 46 || iMTU > 65536 ) { logmsg( _("HHCCT062E %4.4X: Invalid MTU size %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szMTU, *argv ); argc--; argv++; // Guest IP Address if( inet_aton( *argv, &addr ) == 0 ) { logmsg( _("HHCCT063E %4.4X: Invalid IP address %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szGuestIPAddr, *argv ); argc--; argv++; // Driver IP Address if( inet_aton( *argv, &addr ) == 0 ) { logmsg( _("HHCCT064E %4.4X: Invalid IP address %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szDriveIPAddr, *argv ); argc--; argv++; // Netmask if( inet_aton( *argv, &addr ) == 0 ) { logmsg( _("HHCCT065E %4.4X: Invalid netmask %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szNetMask, *argv ); argc--; argv++; if( argc > 0 ) { logmsg( _("HHCCT066E %4.4X: Incorrect number of parameters\n"), pDEVBLK->devnum ); return -1; } #else // defined( OPTION_W32_CTCI ) // There are 2 non-optional arguments in the Windows old-format: // Guest IP address and Gateway address. // There are also 2 additional optional arguments: // Kernel buffer size and I/O buffer size. while( argc > 0 ) { switch( i ) { case 0: // Non-optional arguments // Guest IP Address if( inet_aton( *argv, &addr ) == 0 ) { logmsg( _("HHCCT067E %4.4X: Invalid IP address %s\n"), pDEVBLK->devnum, *argv ); return -1; } strcpy( pCTCBLK->szGuestIPAddr, *argv ); argc--; argv++; // Destination (Gateway) Address if( inet_aton( *argv, &addr ) == 0 ) { // Not an IP address, check for valid MAC if( ParseMAC( *argv, mac ) != 0 ) { logmsg( _("HHCCT068E %4.4X: Invalid MAC address %s\n"), pDEVBLK->devnum, *argv ); return -1; } } strcpy( pCTCBLK->szTUNCharName, *argv ); // Kludge: This may look strange at first, but with // TunTap32, only the last 3 bytes of the "driver IP // address" is actually used. It's purpose is to // generate a unique MAC for the virtual interface. // Thus, having the same address for the adapter and // destination is not an issue. This used to be // generated from the guest IP address, I screwed up // TunTap32 V2. (JAP) // This also fixes the confusing error messages from // TunTap.c when a MAC is given for this argument. strcpy( pCTCBLK->szDriveIPAddr, pCTCBLK->szGuestIPAddr ); argc--; argv++; i++; continue; case 1: // Optional arguments from here on: // Kernel Buffer Size iKernBuff = atoi( *argv ); if( iKernBuff * 1024 < MIN_CAPTURE_BUFFSIZE || iKernBuff * 1024 > MAX_CAPTURE_BUFFSIZE ) { logmsg( _("HHCCT069E %4.4X: Invalid kernel buffer size %s\n"), pDEVBLK->devnum, *argv ); return -1; } pCTCBLK->iKernBuff = iKernBuff * 1024; argc--; argv++; i++; continue; case 2: // I/O Buffer Size iIOBuff = atoi( *argv ); if( iIOBuff * 1024 < MIN_PACKET_BUFFSIZE || iIOBuff * 1024 > MAX_PACKET_BUFFSIZE ) { logmsg( _("HHCCT070E %4.4X: Invalid DLL I/O buffer size %s\n"), pDEVBLK->devnum, *argv ); return -1; } pCTCBLK->iIOBuff = iIOBuff * 1024; argc--; argv++; i++; continue; default: logmsg( _("HHCCT071E %4.4X: Incorrect number of parameters\n"), pDEVBLK->devnum ); return -1; } } #endif // !defined( OPTION_W32_CTCI ) } return 0; } #endif /* !defined(__SOLARIS__) jbs */ hercules-3.12/ctcadpt.c0000664000175000017500000027000412564723224011774 00000000000000/* CTCADPT.C (c) Copyright James A. Pierson, 2002-2012 */ /* (c) Copyright Roger Bowler, 2000-2012 */ /* (c) Copyright Willem Konynenberg, 2000-2009 */ /* (c) Copyright Vic Cross, 2001-2009 */ /* Hercules Channel-to-Channel Emulation Support */ // vmnet (C) Copyright Willem Konynenberg, 2000-2009 // CTCT (C) Copyright Vic Cross, 2001-2009 // CTCE (C) Copyright Peter J. Jansen, 2014 // Notes: // This module contains the remaining CTC emulation modes that // have not been moved to seperate modules. There is also logic // to allow old style 3088 device definitions for compatibility // and may be removed in a future release. // // Please read README.NETWORKING for more info. // #include "hstdinc.h" #define _CTCADPT_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "devtype.h" #include "ctcadpt.h" #include "opcode.h" #include "devtype.h" // ==================================================================== // Declarations // ==================================================================== static int CTCT_Init( DEVBLK *dev, int argc, char *argv[] ); static void CTCT_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual, BYTE* pMore ); static void CTCT_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ); static void* CTCT_ListenThread( void* argp ); static int CTCE_Init( DEVBLK *dev, int argc, char *argv[] ); static void CTCE_Send( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ); static void* CTCE_RecvThread( DEVBLK* pDEVBLK ); static void* CTCE_ListenThread( void* argp ); static int VMNET_Init( DEVBLK *dev, int argc, char *argv[] ); static int VMNET_Write( DEVBLK *dev, BYTE *iobuf, U16 count, BYTE *unitstat ); static int VMNET_Read( DEVBLK *dev, BYTE *iobuf, U16 count, BYTE *unitstat ); // -------------------------------------------------------------------- // Definitions for CTC general data blocks // -------------------------------------------------------------------- typedef struct _CTCG_PARMBLK { int listenfd; struct sockaddr_in addr; DEVBLK* dev; } CTCG_PARMBLK; // -------------------------------------------------------------------- // CTCE Send-Receive Socket Prefix at the start of the DEVBLK buf // -------------------------------------------------------------------- typedef struct _CTCE_SOKPFX { BYTE CmdReg; /* CTCE command register */ BYTE FsmSta; /* CTCE FSM state */ U16 sCount; /* CTCE sCount copy */ U16 PktSeq; /* CTCE Packet Sequence ID */ U16 SndLen; /* CTCE Packet Sent Length */ } CTCE_SOKPFX; // -------------------------------------------------------------------- // CTCE Equivalent of CTCG_PARMBLK // -------------------------------------------------------------------- typedef struct _CTCE_PARMBLK { int listenfd[2]; /* [0] = read, [1] = write */ u_int ctceWrPort; /* 0 = read, 1 = write */ struct sockaddr_in addr; DEVBLK* dev; } CTCE_PARMBLK; // -------------------------------------------------------------------- // CTCE Constants (generated by a small REXX script) // -------------------------------------------------------------------- static char *CTCE_CmdStr[14] = { "PRE" , // 0 = 00 = Prepare "CTL" , // 1 = 01 = Control "RED" , // 2 = 02 = Read "WRT" , // 3 = 03 = Write "SCB" , // 4 = 04 = Sense Command Byte "???" , // 5 = 05 = Not Used "RBK" , // 6 = 06 = Read Backward "WEF" , // 7 = 07 = Write End Of File "NOP" , // 8 = 10 = No Operation "SEM" , // 9 = 11 = Set Extended Mode "SAS" , // 10 = 12 = Sense Adapter State "SID" , // 11 = 13 = Sense ID "RCD" , // 12 = 14 = Read Configuration Data "???" // 13 = 15 = Invalid Command Code }; static BYTE CTCE_Cmd[256] = { 13, 3, 2, 8,10, 3, 2, 1,13, 3, 2, 8, 6, 3, 2, 1, 13, 3, 2, 8, 4, 3, 2, 1,13, 3, 2, 8, 6, 3, 2, 1, 13, 3, 2, 8,13, 3, 2, 1,13, 3, 2, 8, 6, 3, 2, 1, 13, 3, 2, 8, 4, 3, 2, 1,13, 3, 2, 8, 6, 3, 2, 1, 13, 3, 2,13,13, 3, 2, 1,13, 3, 2,13, 6, 3, 2, 1, 13, 3, 2,13, 4, 3, 2, 1,13, 3, 2,13, 6, 3, 2, 1, 13, 3, 2,13,13, 3, 2, 1,13, 3, 2,13, 6, 3, 2, 1, 13, 3, 2,13, 4, 3, 2, 1,13, 3, 2,13, 6, 3, 2, 1, 13, 7, 2, 8,13, 7, 2, 1,13, 7, 2, 8, 6, 7, 2, 1, 13, 7, 2, 8, 4, 7, 2, 1,13, 7, 2, 8, 6, 7, 2, 1, 13, 7, 2, 8,13, 7, 2, 1,13, 7, 2, 8, 6, 7, 2, 1, 13, 7, 2, 8, 4, 7, 2, 1,13, 7, 2, 8, 6, 7, 2, 1, 13, 7, 2, 9,13, 7, 2, 1,13, 7, 2,13, 6, 7, 2, 1, 13, 7, 2,13, 4, 7, 2, 1,13, 7, 2,13, 6, 7, 2, 1, 13, 7, 2, 0,11, 7, 2, 1,13, 7, 2,13, 6, 7, 2, 1, 13, 7, 2,13, 4, 7, 2, 1,13, 7, 2,13, 6, 7, 2, 1 }; #define IS_CTCE_CCW_PRE(c) ((CTCE_Cmd[c]==0)) #define IS_CTCE_CCW_CTL(c) ((CTCE_Cmd[c]==1)) #define IS_CTCE_CCW_RED(c) ((CTCE_Cmd[c]==2)) #define IS_CTCE_CCW_WRT(c) ((CTCE_Cmd[c]==3)) #define IS_CTCE_CCW_SCB(c) ((CTCE_Cmd[c]==4)) #define IS_CTCE_CCW_RBK(c) ((CTCE_Cmd[c]==6)) #define IS_CTCE_CCW_WEF(c) ((CTCE_Cmd[c]==7)) #define IS_CTCE_CCW_NOP(c) ((CTCE_Cmd[c]==8)) #define IS_CTCE_CCW_SEM(c) ((CTCE_Cmd[c]==9)) #define IS_CTCE_CCW_SAS(c) ((CTCE_Cmd[c]==10)) #define IS_CTCE_CCW_SID(c) ((CTCE_Cmd[c]==11)) #define IS_CTCE_CCW_RCD(c) ((CTCE_Cmd[c]==12)) #define IS_CTCE_CCW_RDY(c) ((CTCE_Cmd[c]<10)) #define IS_CTCE_CCW_RDA(c) (((CTCE_Cmd[c]&0xFB)==2)) /* Read or Read Backward */ #define IS_CTCE_CCW_WRA(c) (((CTCE_Cmd[c]&0xFB)==3)) /* Write or Write EOF */ /* Macros for classifying CTC states */ /* These are numbered 0 thru 7 as per the */ /* column numbers 0-3 and 4-7 in the table */ /* in section 2.13 in SA22-7203-00 by IBM */ #define IS_CTCE_YWP(c) (((c)&0x07)==0x00) #define IS_CTCE_YWC(c) (((c)&0x07)==0x01) #define IS_CTCE_YWR(c) (((c)&0x07)==0x02) #define IS_CTCE_YWW(c) (((c)&0x07)==0x03) #define IS_CTCE_YAV(c) (((c)&0x07)==0x04) #define IS_CTCE_YNR(c) (((c)&0x07)==0x05) #define IS_CTCE_XWK(c) (((c)&0x07)==0x06) #define IS_CTCE_XIP(c) (((c)&0x07)==0x07) /* This last one is useful, tests for either */ /* the 0 (YWP) or 4 (YAV) whilst READY */ #define IS_CTCE_YAP(c) (((c)&0x83)==0x00) /* And the corresponding SET macros for these */ #define SET_CTCE_YWP(c) (c&=&0x0F8) #define SET_CTCE_YWC(c) (c=(((c)&0xF8)|0x01)) #define SET_CTCE_YWR(c) (c=(((c)&0xF8)|0x02)) #define SET_CTCE_YWW(c) (c=(((c)&0xF8)|0x03)) #define SET_CTCE_YAV(c) (c=(((c)&0xF8)|0x04)) #define SET_CTCE_YNR(c) (c=(((c)&0xF8)|0x05)) #define SET_CTCE_XWK(c) (c=(((c)&0xF8)|0x06)) #define SET_CTCE_XIP(c) (c|=0x07)) /* Some additional flags are also present. */ #define IS_CTCE_NRDY(c) (((c)&0x80)==0x80) #define IS_CTCE_WEOF(c) (((c)&0x40)==0x40) #define IS_CTCE_MATCH(c) (((c)&0x20)==0x20) #define IS_CTCE_ATTN(c) (((c)&0x10)==0x10) /* And the corresponding SET macros for these */ #define SET_CTCE_NRDY(c) (c|=0x80) #define SET_CTCE_WEOF(c) (c|=0x40) #define SET_CTCE_MATCH(c) (c|=0x20) #define SET_CTCE_ATTN(c) (c|=0x10) /* And the corresponding CLeaR macros */ #define CLR_CTCE_NRDY(c) (c&=~0x80) #define CLR_CTCE_WEOF(c) (c&=~0x40) #define CLR_CTCE_MATCH(c) (c&=~0x20) #define CLR_CTCE_ATTN(c) (c&=~0x10) /* To CLeaR all flags */ #define CLR_CTCE_ALLF(c) (c&=~0xF0) /* Enhanced CTCT processing is selected by */ /* omitting default MTU bufsize CTCE_MTU_MIN, */ /* or by specifying a larger number. The */ /* default is equal to sizeof(CTCE_SOKPFX) + */ /* sizeof(U16) (sCount = 2) + 32K, where 32K */ /* is the largest data sCount seen used by */ /* CTC programs. If that number would be too */ /* small one day, error message HHCCT051S */ /* would instruct the user to specify an */ /* increased MTU bufsize in the device */ /* configuration statement. */ #define CTCE_MTU_MIN ( (int)( 32768 + sizeof(CTCE_SOKPFX) + sizeof(U16 /* sCount */) ) ) // -------------------------------------------------------------------- // Device Handler Information Block // -------------------------------------------------------------------- DEVHND ctcadpt_device_hndinfo = { &CTCX_Init, /* Device Initialisation */ &CTCX_ExecuteCCW, /* Device CCW execute */ &CTCX_Close, /* Device Close */ &CTCX_Query, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; DEVHND ctct_device_hndinfo = { &CTCT_Init, /* Device Initialisation */ &CTCX_ExecuteCCW, /* Device CCW execute */ &CTCX_Close, /* Device Close */ &CTCX_Query, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; DEVHND ctce_device_hndinfo = { &CTCE_Init, /* Device Initialisation */ &CTCX_ExecuteCCW, /* Device CCW execute */ &CTCX_Close, /* Device Close */ &CTCX_Query, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; DEVHND vmnet_device_hndinfo = { &VMNET_Init, /* Device Initialisation */ &CTCX_ExecuteCCW, /* Device CCW execute */ &CTCX_Close, /* Device Close */ &CTCX_Query, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; extern DEVHND ctci_device_hndinfo; extern DEVHND lcs_device_hndinfo; // ==================================================================== // Primary Module Entry Points // ==================================================================== // -------------------------------------------------------------------- // Device Initialization Handler (Generic) // -------------------------------------------------------------------- int CTCX_Init( DEVBLK* pDEVBLK, int argc, char *argv[] ) { pDEVBLK->devtype = 0x3088; // The first argument is the device emulation type if( argc < 1 ) { logmsg( _("HHCCT001E %4.4X: Incorrect number of parameters\n"), pDEVBLK->devnum ); return -1; } if((pDEVBLK->hnd = hdl_ghnd(argv[0]))) { if(pDEVBLK->hnd->init == &CTCX_Init) return -1; free(pDEVBLK->typname); pDEVBLK->typname = strdup(argv[0]); return (pDEVBLK->hnd->init)( pDEVBLK, --argc, ++argv ); } logmsg (_("HHCCT034E %s: Unrecognized/unsupported CTC emulation type\n"), argv[0]); return -1; } // ------------------------------------------------------------------- // Query the device definition (Generic) // ------------------------------------------------------------------- void CTCX_Query( DEVBLK* pDEVBLK, char** ppszClass, int iBufLen, char* pBuffer ) { BEGIN_DEVICE_CLASS_QUERY( "CTCA", pDEVBLK, ppszClass, iBufLen, pBuffer ); snprintf( pBuffer, iBufLen, "%s", pDEVBLK->filename ); } // ------------------------------------------------------------------- // Close the device (Generic) // ------------------------------------------------------------------- int CTCX_Close( DEVBLK* pDEVBLK ) { // Close the device file (if not already closed) if( pDEVBLK->fd >= 0 ) { if (socket_is_socket( pDEVBLK->fd )) close_socket( pDEVBLK->fd ); else close( pDEVBLK->fd ); pDEVBLK->fd = -1; // indicate we're now closed } // Also for the CTCE RecvThread socket if applicable if( ( pDEVBLK->ctctype == CTC_CTCE ) && pDEVBLK->ctcefd >= 0 ) { if (socket_is_socket( pDEVBLK->ctcefd )) close_socket( pDEVBLK->ctcefd ); else close( pDEVBLK->ctcefd ); pDEVBLK->ctcefd = -1; } return 0; } // ------------------------------------------------------------------- // Execute a Channel Command Word (Generic) // ------------------------------------------------------------------- void CTCX_ExecuteCCW( DEVBLK* pDEVBLK, BYTE bCode, BYTE bFlags, BYTE bChained, U16 sCount, BYTE bPrevCode, int iCCWSeq, BYTE* pIOBuf, BYTE* pMore, BYTE* pUnitStat, U16* pResidual ) { int iNum; // Number of bytes to move BYTE bOpCode; // CCW opcode with modifier // bits masked off UNREFERENCED( bFlags ); UNREFERENCED( bChained ); UNREFERENCED( bPrevCode ); UNREFERENCED( iCCWSeq ); // Intervention required if the device file is not open if( ( pDEVBLK->fd < 0 || ( ( pDEVBLK->ctctype == CTC_CTCE ) && pDEVBLK->ctcefd < 0 ) ) && !IS_CCW_SENSE( bCode ) && !IS_CCW_CONTROL( bCode ) ) { pDEVBLK->sense[0] = SENSE_IR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Enhanced CTCT processing is implemented as an addition to // the already existing older code. if( pDEVBLK->ctctype == CTC_CTCE ) { // Changes to DEVBLK are lock protected as the CTCT_RecvThread // might update as well, but, due to the way actually existing // software uses CTC devices, this may not be needed at all. obtain_lock( &pDEVBLK->lock ); // Copy control command byte in x command register pDEVBLK->ctcexCmd = bCode; // Any command different from READ and RDBACK will reset the WEOF flag. if( !IS_CTCE_CCW_RDA( bCode ) ) { CLR_CTCE_WEOF( pDEVBLK->ctcexState ); } } // Mask off the modifier bits in the CCW bOpCode if( ( bCode & 0x07 ) == 0x07 ) bOpCode = 0x07; else if( ( bCode & 0x03 ) == 0x02 ) bOpCode = 0x02; else if( ( bCode & 0x0F ) == 0x0C ) bOpCode = 0x0C; else if( ( bCode & 0x03 ) == 0x01 ) bOpCode = pDEVBLK->ctcxmode ? ( bCode & 0x83 ) : 0x01; else if( ( bCode & 0x1F ) == 0x14 ) bOpCode = 0x14; else if( ( bCode & 0x47 ) == 0x03 ) bOpCode = 0x03; else if( ( bCode & 0xC7 ) == 0x43 ) bOpCode = 0x43; else bOpCode = bCode; // Process depending on CCW bOpCode switch (bOpCode) { case 0x01: // 0MMMMM01 WRITE //------------------------------------------------------------ // WRITE //------------------------------------------------------------ // Return normal status if CCW count is zero if( sCount == 0 ) { *pUnitStat = CSW_CE | CSW_DE; break; } // Write data and set unit status and residual byte count switch( pDEVBLK->ctctype ) { case CTC_CTCT: CTCT_Write( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual ); break; case CTC_VMNET: *pResidual = sCount - VMNET_Write( pDEVBLK, pIOBuf, sCount, pUnitStat ); break; case CTC_CTCE: // Enhanced CTC processing: // A write command is accepted if we are available and in // states YWR or YWP or YAV (the latter two equals YAP). if( IS_CTCE_YWR( pDEVBLK->ctcexState ) || IS_CTCE_YAP( pDEVBLK->ctcexState ) ) { // If available then we send the ATTN flag. if( IS_CTCE_YAV( pDEVBLK->ctcexState ) ) { SET_CTCE_ATTN( pDEVBLK->ctcexState ); } // In state YWP or YAV (= YAP) then we move to state YWW. if( IS_CTCE_YAP( pDEVBLK->ctcexState ) ) { SET_CTCE_YWW( pDEVBLK->ctcexState ); } // Otherwise we received a matching complementary command. else { SET_CTCE_MATCH( pDEVBLK->ctcexState ); } // Data and state info must be sent to the other (y-) side. CTCE_Send( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual ); // The above only proceeds when the matching read command // completes or was already done, unitistat and residual // will be set, so we just return to state available. SET_CTCE_YAV( pDEVBLK->ctcexState ); } break; } break; case 0x81: // 1MMMMM01 WEOF //------------------------------------------------------------ // WRITE EOF //------------------------------------------------------------ // Enhanced CTC processing write EOF command is accepted if // in states YWR or YWP or YAV (the latter two equals YAP). if( ( pDEVBLK->ctctype == CTC_CTCE ) && ( IS_CTCE_YWR( pDEVBLK->ctcexState ) || IS_CTCE_YAP( pDEVBLK->ctcexState ) ) ) { // This command is a matching complementary command for read. if( IS_CTCE_YWR( pDEVBLK->ctcexState ) ) SET_CTCE_MATCH( pDEVBLK->ctcexState ); // We then inform the other (y-)side we received a WEOF. CTCE_Send( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual ); // And we always return to state available. SET_CTCE_YAV( pDEVBLK->ctcexState ); break; } // Non-Enhanced CTC processing is retained. // Return normal status *pUnitStat = CSW_CE | CSW_DE; break; case 0x02: // MMMMMM10 READ case 0x0C: // MMMM1100 RDBACK // ----------------------------------------------------------- // READ & READ BACKWARDS // ----------------------------------------------------------- // Read data and set unit status and residual byte count switch( pDEVBLK->ctctype ) { case CTC_CTCT: CTCT_Read( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual, pMore ); break; case CTC_VMNET: *pResidual = sCount - VMNET_Read( pDEVBLK, pIOBuf, sCount, pUnitStat ); break; case CTC_CTCE: // Enhanced CTCT processing: // If WEOF is set on our side whilst we are available and // the other side also available or in the W(D)P state, then // the read command will be rejected with unit exception. if( IS_CTCE_WEOF( pDEVBLK->ctcexState ) && IS_CTCE_YAP ( pDEVBLK->ctcexState ) ) { *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE | CSW_UX ; } // A read command is accepted if we are available and in // states YWW or YWP or YAV (the latter two equals YAP). else if( IS_CTCE_YWW( pDEVBLK->ctcexState ) || IS_CTCE_YAP( pDEVBLK->ctcexState ) ) { // If available then we send the ATTN flag. if( IS_CTCE_YAV( pDEVBLK->ctcexState ) ) { SET_CTCE_ATTN( pDEVBLK->ctcexState ); } // In state YWP or YAV (= YAP) then we move to state YWR. if( IS_CTCE_YAP( pDEVBLK->ctcexState ) ) { SET_CTCE_YWR( pDEVBLK->ctcexState ); } // Otherwise we received a matching complementary command. else { SET_CTCE_MATCH( pDEVBLK->ctcexState ); } // Data and state info must be sent to the other (y-) side, // proceeding only when the matching write command completes // or was already done, unitstat and residual will be set. CTCE_Send( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual ); } // And we return to state available. SET_CTCE_YAV( pDEVBLK->ctcexState ); break; } break; case 0x07: // MMMMM111 CTL // ----------------------------------------------------------- // CONTROL // ----------------------------------------------------------- // CTC Enhanced processing. if( pDEVBLK->ctctype == CTC_CTCE ) { // The control command is accepted if we are available and // the other side is also available or in the YWP state. if( IS_CTCE_YAP( pDEVBLK->ctcexState ) ) { // If available then we send the ATTN flag. if( IS_CTCE_YAV( pDEVBLK->ctcexState ) ) SET_CTCE_ATTN( pDEVBLK->ctcexState ); // We always end up in the YWC state. SET_CTCE_YWC( pDEVBLK->ctcexState ); // And then we always notify the other (y-)side. CTCE_Send( pDEVBLK, sCount, pIOBuf, pUnitStat, pResidual ); // The above only proceeds when the matching SCB command // completes, unitistat and residual will be set, // and then we just return to available. SET_CTCE_YAV( pDEVBLK->ctcexState ); } break; } // Non-Enhanced CTC processing is retained. *pUnitStat = CSW_CE | CSW_DE; break; case 0x03: // M0MMM011 NOP // ----------------------------------------------------------- // CONTROL NO-OPERATON // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x43: // 00XXX011 SBM // ----------------------------------------------------------- // SET BASIC MODE // ----------------------------------------------------------- // Command reject if in basic mode if( pDEVBLK->ctcxmode == 0 ) { pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; break; } // Reset extended mode and return normal status pDEVBLK->ctcxmode = 0; *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE; break; case 0xC3: // 11000011 SEM // ----------------------------------------------------------- // SET EXTENDED MODE // ----------------------------------------------------------- pDEVBLK->ctcxmode = 1; *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE; break; case 0xE3: // 11100011 // ----------------------------------------------------------- // PREPARE (PREP) // ----------------------------------------------------------- *pUnitStat = CSW_CE | CSW_DE; break; case 0x14: // XXX10100 SCB // ----------------------------------------------------------- // SENSE COMMAND BYTE // ----------------------------------------------------------- // Enhanced CTC processing. if( pDEVBLK->ctctype == CTC_CTCE ) { // If we were awaiting this SCB, i.e. if we are in the // YWC state, then we signal matching command received. if( IS_CTCE_YWC( pDEVBLK->ctcexState ) ) { SET_CTCE_MATCH( pDEVBLK->ctcexState ); // We complete the above signalling (if any) to the other (y-)side. CTCE_Send( pDEVBLK, sCount, NULL, pUnitStat, pResidual ); // And only then to we return to state YAV. SET_CTCE_YAV( pDEVBLK->ctcexState ); } *pIOBuf = pDEVBLK->ctceyCmdSCB; *pResidual = sCount - 1; *pUnitStat = CSW_CE | CSW_DE; if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { logmsg( _("HHCCT001I %4.4X: SCB executed: CB=%2.2X (x=%2.2X y=%2.2X)\n"), pDEVBLK->devnum, *pIOBuf, pDEVBLK->ctcexState, pDEVBLK->ctceyState ); } break; } // Non-Enhanced CTC processing is retained. *pUnitStat = CSW_CE | CSW_DE; break; case 0x04: // 00000100 SENSE // ----------------------------------------------------------- // SENSE // ----------------------------------------------------------- // Command reject if in basic mode if( pDEVBLK->ctcxmode == 0 ) { pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; break; } // Calculate residual byte count iNum = ( sCount < pDEVBLK->numsense ) ? sCount : pDEVBLK->numsense; *pResidual = sCount - iNum; if( sCount < pDEVBLK->numsense ) *pMore = 1; // Copy device sense bytes to channel I/O buffer memcpy( pIOBuf, pDEVBLK->sense, iNum ); // Clear the device sense bytes memset( pDEVBLK->sense, 0, sizeof( pDEVBLK->sense ) ); // Return unit status *pUnitStat = CSW_CE | CSW_DE; break; case 0xE4: // 11100100 SID // ----------------------------------------------------------- // SENSE ID // ----------------------------------------------------------- // Calculate residual byte count iNum = ( sCount < pDEVBLK->numdevid ) ? sCount : pDEVBLK->numdevid; *pResidual = sCount - iNum; if( sCount < pDEVBLK->numdevid ) *pMore = 1; // Copy device identifier bytes to channel I/O buffer memcpy( pIOBuf, pDEVBLK->devid, iNum ); // Return unit status *pUnitStat = CSW_CE | CSW_DE; break; default: // ------------------------------------------------------------ // INVALID OPERATION // ------------------------------------------------------------ // Set command reject sense byte, and unit check status pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; } // Enhanced CTC processing. if( pDEVBLK->ctctype == CTC_CTCE ) { // Clear all flags when in state YAP if( IS_CTCE_YAP( pDEVBLK->ctcexState ) ) { CLR_CTCE_ALLF( pDEVBLK->ctcexState ); } release_lock( &pDEVBLK->lock ); } } // ==================================================================== // CTCT Support // ==================================================================== // // CTCT_Init // static int CTCT_Init( DEVBLK *dev, int argc, char *argv[] ) { char str[80]; // Thread name int rc; // Return code int mtu; // MTU size (binary) int lport; // Listen port (binary) int rport; // Destination port (binary) char* listenp; // Listening port number char* remotep; // Destination port number char* mtusize; // MTU size (characters) char* remaddr; // Remote IP address struct in_addr ipaddr; // Work area for IP address BYTE c; // Character work area TID tid; // Thread ID for server CTCG_PARMBLK parm; // Parameters for the server char address[20]=""; // temp space for IP address dev->devtype = 0x3088; dev->ctctype = CTC_CTCT; SetSIDInfo( dev, 0x3088, 0x08, 0x3088, 0x01 ); // Check for correct number of arguments if (argc != 4) { logmsg( _("HHCCT002E %4.4X: Incorrect number of parameters\n"), dev->devnum ); return -1; } // The first argument is the listening port number listenp = *argv++; if( strlen( listenp ) > 5 || sscanf( listenp, "%u%c", &lport, &c ) != 1 || lport < 1024 || lport > 65534 ) { logmsg( _("HHCCT003E %4.4X: Invalid port number: %s\n"), dev->devnum, listenp ); return -1; } // The second argument is the IP address or hostname of the // remote side of the point-to-point link remaddr = *argv++; if( inet_aton( remaddr, &ipaddr ) == 0 ) { struct hostent *hp; if( ( hp = gethostbyname( remaddr ) ) != NULL ) { memcpy( &ipaddr, hp->h_addr, hp->h_length ); strcpy( address, inet_ntoa( ipaddr ) ); remaddr = address; } else { logmsg( _("HHCCT004E %4.4X: Invalid IP address %s\n"), dev->devnum, remaddr ); return -1; } } // The third argument is the destination port number remotep = *argv++; if( strlen( remotep ) > 5 || sscanf( remotep, "%u%c", &rport, &c ) != 1 || rport < 1024 || rport > 65534 ) { logmsg( _("HHCCT005E %4.4X: Invalid port number: %s\n"), dev->devnum, remotep ); return -1; } // The fourth argument is the maximum transmission unit (MTU) size mtusize = *argv; if( strlen( mtusize ) > 5 || sscanf( mtusize, "%u%c", &mtu, &c ) != 1 || mtu < 46 || mtu > 65536 ) { logmsg( _("HHCCT006E %4.4X: Invalid MTU size %s\n"), dev->devnum, mtusize ); return -1; } // Set the device buffer size equal to the MTU size dev->bufsize = mtu; // Initialize the file descriptor for the socket connection // It's a little confusing, but we're using a couple of the // members of the server paramter structure to initiate the // outgoing connection. Saves a couple of variable declarations, // though. If we feel strongly about it, we can declare separate // variables... // make a TCP socket parm.listenfd = socket( AF_INET, SOCK_STREAM, 0 ); if( parm.listenfd < 0 ) { logmsg( _("HHCCT007E %4.4X: Error creating socket: %s\n"), dev->devnum, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // bind socket to our local port // (might seem like overkill, and usually isn't done, but doing this // bind() to the local port we configure gives the other end a chance // at validating the connection request) memset( &(parm.addr), 0, sizeof( parm.addr ) ); parm.addr.sin_family = AF_INET; parm.addr.sin_port = htons(lport); parm.addr.sin_addr.s_addr = htonl(INADDR_ANY); rc = bind( parm.listenfd, (struct sockaddr *)&parm.addr, sizeof( parm.addr ) ); if( rc < 0 ) { logmsg( _("HHCCT008E %4.4X: Error binding to socket: %s\n"), dev->devnum, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // initiate a connection to the other end memset( &(parm.addr), 0, sizeof( parm.addr ) ); parm.addr.sin_family = AF_INET; parm.addr.sin_port = htons(rport); parm.addr.sin_addr = ipaddr; rc = connect( parm.listenfd, (struct sockaddr *)&parm.addr, sizeof( parm.addr ) ); // if connection was not successful, start a server if( rc < 0 ) { // used to pass parameters to the server thread CTCG_PARMBLK* arg; logmsg( _("HHCCT009I %4.4X: Connect to %s:%s failed, starting server\n"), dev->devnum, remaddr, remotep ); // probably don't need to do this, not sure... close_socket( parm.listenfd ); parm.listenfd = socket( AF_INET, SOCK_STREAM, 0 ); if( parm.listenfd < 0 ) { logmsg( _("HHCCT010E %4.4X: Error creating socket: %s\n"), dev->devnum, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // set up the listening port memset( &(parm.addr), 0, sizeof( parm.addr ) ); parm.addr.sin_family = AF_INET; parm.addr.sin_port = htons(lport); parm.addr.sin_addr.s_addr = htonl(INADDR_ANY); if( bind( parm.listenfd, (struct sockaddr *)&parm.addr, sizeof( parm.addr ) ) < 0 ) { logmsg( _("HHCCT011E %4.4X: Error binding to socket: %s\n"), dev->devnum, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } if( listen( parm.listenfd, 1 ) < 0 ) { logmsg( _("HHCCT012E %4.4X: Error on call to listen: %s\n"), dev->devnum, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // we are listening, so create a thread to accept connection arg = malloc( sizeof( CTCG_PARMBLK ) ); memcpy( arg, &parm, sizeof( parm ) ); arg->dev = dev; snprintf(str,sizeof(str),"CTCT %4.4X ListenThread",dev->devnum); str[sizeof(str)-1]=0; create_thread( &tid, JOINABLE, CTCT_ListenThread, arg, str ); } else // successfully connected (outbound) to the other end { logmsg( _("HHCCT013I %4.4X: Connected to %s:%s\n"), dev->devnum, remaddr, remotep ); dev->fd = parm.listenfd; } // for cosmetics, since we are successfully connected or serving, // fill in some details for the panel. sprintf( dev->filename, "%s:%s", remaddr, remotep ); return 0; } // // CTCT_Write // static void CTCT_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ) { PCTCIHDR pFrame; // -> Frame header PCTCISEG pSegment; // -> Segment in buffer U16 sOffset; // Offset of next frame U16 sSegLen; // Current segment length U16 sDataLen; // Length of IP Frame data int iPos; // Offset into buffer U16 i; // Array subscript int rc; // Return code BYTE szStackID[33]; // VSE IP stack identity U32 iStackCmd; // VSE IP stack command // Check that CCW count is sufficient to contain block header if( sCount < sizeof( CTCIHDR ) ) { logmsg( _("HHCCT014E %4.4X: Write CCW count %u is invalid\n"), pDEVBLK->devnum, sCount ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up frame pointer pFrame = (PCTCIHDR)pIOBuf; // Extract the frame length from the header FETCH_HW( sOffset, pFrame->hwOffset ); // Check for special VSE TCP/IP stack command packet if( sOffset == 0 && sCount == 40 ) { // Extract the 32-byte stack identity string for( i = 0; i < sizeof( szStackID ) - 1 && i < sCount - 4; i++) szStackID[i] = guest_to_host( pIOBuf[i+4] ); szStackID[i] = '\0'; // Extract the stack command word FETCH_FW( iStackCmd, *((FWORD*)&pIOBuf[36]) ); // Display stack command and discard the packet logmsg( _("HHCCT015I %4.4X: Interface command: %s %8.8X\n"), pDEVBLK->devnum, szStackID, iStackCmd ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } // Check for special L/390 initialization packet if( sOffset == 0 ) { // Return normal status and discard the packet *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } #if 0 // Notes: It appears that TurboLinux has gotten sloppy in their // ways. They are now giving us buffer sizes that are // greater than the CCW count, but the segment size // is within the count. // Check that the frame offset is valid if( sOffset < sizeof( CTCIHDR ) || sOffset > sCount ) { logmsg( _("CTC101W %4.4X: Write buffer contains invalid " "frame offset %u\n"), pDEVBLK->devnum, sOffset ); pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } #endif // Adjust the residual byte count *pResidual -= sizeof( CTCIHDR ); // Process each segment in the buffer for( iPos = sizeof( CTCIHDR ); iPos < sOffset; iPos += sSegLen ) { // Check that the segment is fully contained within the block if( iPos + sizeof( CTCISEG ) > sOffset ) { logmsg( _("HHCCT016E %4.4X: Write buffer contains incomplete " "segment header at offset %4.4X\n"), pDEVBLK->devnum, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up segment header in the I/O buffer pSegment = (PCTCISEG)(pIOBuf + iPos); // Extract the segment length from the segment header FETCH_HW( sSegLen, pSegment->hwLength ); // Check that the segment length is valid if( ( sSegLen < sizeof( CTCISEG ) ) || ( iPos + sSegLen > sOffset ) || ( iPos + sSegLen > sCount ) ) { logmsg( _("HHCCT017E %4.4X: Write buffer contains invalid " "segment length %u at offset %4.4X\n"), pDEVBLK->devnum, sSegLen, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Calculate length of IP frame data sDataLen = sSegLen - sizeof( CTCISEG ); // Trace the IP packet before sending if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { logmsg( _("HHCCT018I %4.4X: Sending packet to %s:\n"), pDEVBLK->devnum, pDEVBLK->filename ); if( pDEVBLK->ccwtrace ) packet_trace( pSegment->bData, sDataLen ); } // Write the IP packet rc = write_socket( pDEVBLK->fd, pSegment->bData, sDataLen ); if( rc < 0 ) { logmsg( _("HHCCT019E %4.4X: Error writing to %s: %s\n"), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Adjust the residual byte count *pResidual -= sSegLen; // We are done if current segment satisfies CCW count if( iPos + sSegLen == sCount ) { *pResidual -= sSegLen; *pUnitStat = CSW_CE | CSW_DE; return; } } // Set unit status and residual byte count *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; } // // CTCT_Read // static void CTCT_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual, BYTE* pMore ) { PCTCIHDR pFrame = NULL; // -> Frame header PCTCISEG pSegment = NULL; // -> Segment in buffer fd_set rfds; // Read FD_SET int iRetVal; // Return code from 'select' ssize_t iLength = 0; static struct timeval tv; // Timeout time for 'select' // Limit how long we should wait for data to come in FD_ZERO( &rfds ); FD_SET( pDEVBLK->fd, &rfds ); tv.tv_sec = CTC_READ_TIMEOUT_SECS; tv.tv_usec = 0; iRetVal = select( pDEVBLK->fd + 1, &rfds, NULL, NULL, &tv ); switch( iRetVal ) { case 0: *pUnitStat = CSW_CE | CSW_DE | CSW_UC | CSW_SM; pDEVBLK->sense[0] = 0; return; case -1: if( HSO_errno == HSO_EINTR ) return; logmsg( _("HHCCT020E %4.4X: Error reading from %s: %s\n"), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; default: break; } // Read an IP packet from the TUN device iLength = read_socket( pDEVBLK->fd, pDEVBLK->buf, pDEVBLK->bufsize ); // Check for other error condition if( iLength < 0 ) { logmsg( _("HHCCT021E %4.4X: Error reading from %s: %s\n"), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Trace the packet received from the TUN device if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { logmsg( _("HHCCT022I %4.4X: Received packet from %s (%d bytes):\n"), pDEVBLK->devnum, pDEVBLK->filename, iLength ); packet_trace( pDEVBLK->buf, iLength ); } // Fix-up Frame pointer pFrame = (PCTCIHDR)pIOBuf; // Fix-up Segment pointer pSegment = (PCTCISEG)( pIOBuf + sizeof( CTCIHDR ) ); // Initialize segment memset( pSegment, 0, iLength + sizeof( CTCISEG ) ); // Update next frame offset STORE_HW( pFrame->hwOffset, iLength + sizeof( CTCIHDR ) + sizeof( CTCISEG ) ); // Store segment length STORE_HW( pSegment->hwLength, iLength + sizeof( CTCISEG ) ); // Store Frame type STORE_HW( pSegment->hwType, ETH_TYPE_IP ); // Copy data memcpy( pSegment->bData, pDEVBLK->buf, iLength ); // Fix-up frame pointer and terminate block pFrame = (PCTCIHDR)( pIOBuf + sizeof( CTCIHDR ) + sizeof( CTCISEG ) + iLength ); STORE_HW( pFrame->hwOffset, 0x0000 ); // Calculate #of bytes returned including two slack bytes iLength += sizeof( CTCIHDR ) + sizeof( CTCISEG ) + 2; if( sCount < iLength ) { *pMore = 1; *pResidual = 0; iLength = sCount; } else { *pMore = 0; *pResidual -= iLength; } // Set unit status *pUnitStat = CSW_CE | CSW_DE; } // // CTCT_ListenThread // static void* CTCT_ListenThread( void* argp ) { int connfd; socklen_t servlen; char str[80]; CTCG_PARMBLK parm; // set up the parameters passed via create_thread parm = *((CTCG_PARMBLK*) argp); free( argp ); for( ; ; ) { servlen = sizeof(parm.addr); // await a connection connfd = accept( parm.listenfd, (struct sockaddr *)&parm.addr, &servlen ); sprintf( str, "%s:%d", inet_ntoa( parm.addr.sin_addr ), ntohs( parm.addr.sin_port ) ); if( strcmp( str, parm.dev->filename ) != 0 ) { logmsg( _("HHCCT023E %4.4X: Incorrect client or config error\n" " Config=%s, connecting client=%s\n"), parm.dev->devnum, parm.dev->filename, str); close_socket( connfd ); } else { parm.dev->fd = connfd; } // Ok, so having done that we're going to loop back to the // accept(). This was meant to handle the connection failing // at the other end; this end will be ready to accept another // connection. Although this will happen, I'm sure you can // see the possibility for bad things to occur (eg if another // Hercules tries to connect). This will also be fixed RSN. } return NULL; // make compiler happy } // ==================================================================== // VMNET Support -- written by Willem Konynenberg // ==================================================================== /*-------------------------------------------------------------------*/ /* Definitions for SLIP encapsulation */ /*-------------------------------------------------------------------*/ #define SLIP_END 0300 #define SLIP_ESC 0333 #define SLIP_ESC_END 0334 #define SLIP_ESC_ESC 0335 /*-------------------------------------------------------------------*/ /* Functions to support vmnet written by Willem Konynenberg */ /*-------------------------------------------------------------------*/ static int start_vmnet(DEVBLK *dev, DEVBLK *xdev, int argc, char *argv[]) { int sockfd[2]; int r, i; char *ipaddress; if (argc < 2) { logmsg (_("HHCCT024E %4.4X: Not enough arguments to start vmnet\n"), dev->devnum); return -1; } ipaddress = argv[0]; argc--; argv++; if (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) { logmsg (_("HHCCT025E %4.4X: Failed: socketpair: %s\n"), dev->devnum, strerror(errno)); return -1; } r = fork (); if (r < 0) { logmsg (_("HHCCT026E %4.4X: Failed: fork: %s\n"), dev->devnum, strerror(errno)); return -1; } else if (r == 0) { /* child */ close (0); close (1); dup (sockfd[1]); dup (sockfd[1]); r = (sockfd[0] > sockfd[1]) ? sockfd[0] : sockfd[1]; for (i = 3; i <= r; i++) { close (i); } /* the ugly cast is to silence a compiler warning due to const */ execv (argv[0], (EXECV_ARG2_ARGV_T)argv); exit (1); } close (sockfd[1]); dev->fd = sockfd[0]; xdev->fd = sockfd[0]; /* We just blindly copy these out in the hope vmnet will pick them * up correctly. I don't feel like implementing a complete login * scripting facility here... */ write(dev->fd, ipaddress, strlen(ipaddress)); write(dev->fd, "\n", 1); return 0; } static int VMNET_Init(DEVBLK *dev, int argc, char *argv[]) { U16 xdevnum; /* Pair device devnum */ DEVBLK *xdev; /* Pair device */ int rc; U16 lcss; dev->devtype = 0x3088; /* parameters for network CTC are: * devnum of the other CTC device of the pair * ipaddress * vmnet command line * * CTC adapters are used in pairs, one for READ, one for WRITE. * The vmnet is only initialised when both are initialised. */ if (argc < 3) { logmsg(_("HHCCT027E %4.4X: Not enough parameters\n"), dev->devnum); return -1; } rc=parse_single_devnum(argv[0],&lcss,&xdevnum); if (rc<0) { logmsg(_("HHCCT028E %d:%4.4X: Bad device number '%s'\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, argv[0]); return -1; } xdev = find_device_by_devnum(lcss,xdevnum); if (xdev != NULL) { if (start_vmnet(dev, xdev, argc - 1, &argv[1])) return -1; } strcpy(dev->filename, "vmnet"); /* Set the control unit type */ /* Linux/390 currently only supports 3088 model 2 CTCA and ESCON */ dev->ctctype = CTC_VMNET; SetSIDInfo( dev, 0x3088, 0x08, 0x3088, 0x01 ); /* Initialize the device dependent fields */ dev->ctcpos = 0; dev->ctcrem = 0; /* Set length of buffer */ /* This size guarantees we can write a full iobuf of 65536 * as a SLIP packet in a single write. Probably overkill... */ dev->bufsize = 65536 * 2 + 1; return 0; } static int VMNET_Write(DEVBLK *dev, BYTE *iobuf, U16 count, BYTE *unitstat) { int blklen = (iobuf[0]<<8) | iobuf[1]; int pktlen; BYTE *p = iobuf + 2; BYTE *buffer = dev->buf; int len = 0, rem; if (count < blklen) { logmsg (_("HHCCT029E %4.4X: bad block length: %d < %d\n"), dev->devnum, count, blklen); blklen = count; } while (p < iobuf + blklen) { pktlen = (p[0]<<8) | p[1]; rem = iobuf + blklen - p; if (rem < pktlen) { logmsg (_("HHCCT030E %4.4X: bad packet length: %d < %d\n"), dev->devnum, rem, pktlen); pktlen = rem; } if (pktlen < 6) { logmsg (_("HHCCT031E %4.4X: bad packet length: %d < 6\n"), dev->devnum, pktlen); pktlen = 6; } pktlen -= 6; p += 6; while (pktlen--) { switch (*p) { case SLIP_END: buffer[len++] = SLIP_ESC; buffer[len++] = SLIP_ESC_END; break; case SLIP_ESC: buffer[len++] = SLIP_ESC; buffer[len++] = SLIP_ESC_ESC; break; default: buffer[len++] = *p; break; } p++; } buffer[len++] = SLIP_END; write(dev->fd, buffer, len); /* should check error conditions? */ len = 0; } *unitstat = CSW_CE | CSW_DE; return count; } static int bufgetc(DEVBLK *dev, int blocking) { BYTE *bufp = dev->buf + dev->ctcpos, *bufend = bufp + dev->ctcrem; int n; if (bufp >= bufend) { if (blocking == 0) return -1; do { n = read(dev->fd, dev->buf, dev->bufsize); if (n <= 0) { if (n == 0) { /* VMnet died on us. */ logmsg (_("HHCCT032E %4.4X: Error: EOF on read, " "CTC network down\n"), dev->devnum); /* -2 will cause an error status to be set */ return -2; } if( n == EINTR ) return -3; logmsg (_("HHCCT033E %4.4X: Error: read: %s\n"), dev->devnum, strerror(errno)); SLEEP(2); } } while (n <= 0); dev->ctcrem = n; bufend = &dev->buf[n]; dev->ctclastpos = dev->ctclastrem = dev->ctcpos = 0; bufp = dev->buf; } dev->ctcpos++; dev->ctcrem--; return *bufp; } static void setblkheader(BYTE *iobuf, int buflen) { iobuf[0] = (buflen >> 8) & 0xFF; iobuf[1] = buflen & 0xFF; } static void setpktheader(BYTE *iobuf, int packetpos, int packetlen) { iobuf[packetpos] = (packetlen >> 8) & 0xFF; iobuf[packetpos+1] = packetlen & 0xFF; iobuf[packetpos+2] = 0x08; iobuf[packetpos+3] = 0; iobuf[packetpos+4] = 0; iobuf[packetpos+5] = 0; } /* read data from the CTC connection. * If a packet overflows the iobuf or the read buffer runs out, there are * 2 possibilities: * - block has single packet: continue reading packet, drop bytes, * then return truncated packet. * - block has multiple packets: back up on last packet and return * what we have. Do this last packet in the next IO. */ static int VMNET_Read(DEVBLK *dev, BYTE *iobuf, U16 count, BYTE *unitstat) { int c; /* next byte to process */ int len = 8; /* length of block */ int lastlen = 2; /* block length at last pckt */ dev->ctclastpos = dev->ctcpos; dev->ctclastrem = dev->ctcrem; while (1) { c = bufgetc(dev, lastlen == 2); if (c < 0) { if(c == -3) return 0; /* End of input buffer. Return what we have. */ setblkheader (iobuf, lastlen); dev->ctcpos = dev->ctclastpos; dev->ctcrem = dev->ctclastrem; *unitstat = CSW_CE | CSW_DE | (c == -2 ? CSW_UX : 0); return lastlen; } switch (c) { case SLIP_END: if (len > 8) { /* End of packet. Set up for next. */ setpktheader (iobuf, lastlen, len-lastlen); dev->ctclastpos = dev->ctcpos; dev->ctclastrem = dev->ctcrem; lastlen = len; len += 6; } break; case SLIP_ESC: c = bufgetc(dev, lastlen == 2); if (c < 0) { if(c == -3) return 0; /* End of input buffer. Return what we have. */ setblkheader (iobuf, lastlen); dev->ctcpos = dev->ctclastpos; dev->ctcrem = dev->ctclastrem; *unitstat = CSW_CE | CSW_DE | (c == -2 ? CSW_UX : 0); return lastlen; } switch (c) { case SLIP_ESC_END: c = SLIP_END; break; case SLIP_ESC_ESC: c = SLIP_ESC; break; } /* FALLTHRU */ default: if (len < count) { iobuf[len++] = c; } else if (lastlen > 2) { /* IO buffer is full and we have data to return */ setblkheader (iobuf, lastlen); dev->ctcpos = dev->ctclastpos; dev->ctcrem = dev->ctclastrem; *unitstat = CSW_CE | CSW_DE | (c == -2 ? CSW_UX : 0); return lastlen; } /* else truncate end of very large single packet... */ } } } /*-------------------------------------------------------------------*/ /* End of VMNET functions written by Willem Konynenberg */ /*-------------------------------------------------------------------*/ // ==================================================================== // CTCE Support // ==================================================================== // CTC Enhanced // ============ // Enhanced CTC functionality is designed to emulate real // 3088 CTC Adapter hardware, using a pair of TCP sockets // with a likewise configured Hercules instance on a // different PC (or same PC). The new device type is CTCE. // The implementation is based mostly on an IBM publication, // "ESCON Channel-to-Channel Adapter", SA22-7203-00, although // no claim for completeness of this implemenation is feasible. // The CTCE configuration is similar to the CTCT device. The // MTU bufsize parameter is optional, but when specified must be // >= CTCE_MTU_MIN (=32778). This is the default value when omitted. // (Please note that 32778 = sizeof(CTCE_SOKPFX) + sizeof(sCount) + 32K, // with 32K the maximum sCount experienced in CTC CCW programs.) // CTCE requires an even-odd pair of port numbers per device side // but only the even port numbers are to be configured; the odd // numbers are just derived by adding 1 to the (configured) even // port numbers. The socket connection pairs cross-connect, the // arrows showing the send->receive direction : // // x-lport-even -> y-rport-odd // x-lport-odd <- y-rport-even // // A sample CTCE device configuration is shown below: // // Hercules PC Host A with IP address 192.168.1.100 : // // 0E40 CTCE 30880 192.168.1.200 30880 // 0E41 CTCE 30882 192.168.1.200 30882 // // Hercules PC Host B with IP address 192.168.1.200 : // // 0E40 CTCE 30880 192.168.1.100 30880 // 0E41 CTCE 30882 192.168.1.100 30882 // // CTCE_Init // static int CTCE_Init( DEVBLK *dev, int argc, char *argv[] ) { char str[80]; // Thread name int rc; // Return code int mtu; // MTU size (binary) int lport; // Listen port (binary) int rport; // Destination port (binary) char* listenp; // Listening port number char* remotep; // Destination port number char* mtusize; // MTU size (characters) char* remaddr; // Remote IP address struct in_addr ipaddr; // Work area for IP address BYTE c; // Character work area TID tid; // Thread ID for server TID tid2; // Thread ID for read thread u_int ctceWrPort = 0; // 0=read port, 1=write port int ctceSmlBin; // Small size (binary) char* ctceSmlChr; // Small size (characters) CTCE_PARMBLK parm; // Parameters for the server char address[20]=""; // temp space for IP address dev->devtype = 0x3088; dev->ctctype = CTC_CTCE; SetSIDInfo( dev, 0x3088, 0x08, 0x3088, 0x01 ); // Enhanced CTC needs extended mode from the start. dev->ctcxmode = 1; // Mark both socket file descriptors as not yet connected. dev->fd = -1; dev->ctcefd = -1; // Check for correct number of arguments if( (argc < 3) && (argc > 5) ) { logmsg( _("HHCCT035E %4.4X: Incorrect number of CTCE parameters\n"), dev->devnum ); return -1; } // The first argument is the listening port number // which for CTCE must be an even port number. listenp = *argv++; if( strlen( listenp ) > 5 || sscanf( listenp, "%u%c", &lport, &c ) != 1 || lport < 1024 || lport > 65534 ) { logmsg( _("HHCCT036E %4.4X: Invalid CTCE port number: %s\n"), dev->devnum, listenp ); return -1; } if( lport % 2 ) { logmsg( _("HHCCT037E %4.4X: CTCE local port number not even: %s\n"), dev->devnum, listenp ); return -1; } // The second argument is the IP address or hostname of the // remote side of the point-to-point link remaddr = *argv++; if( inet_aton( remaddr, &ipaddr ) == 0 ) { struct hostent *hp; if( ( hp = gethostbyname( remaddr ) ) != NULL ) { memcpy( &ipaddr, hp->h_addr, hp->h_length ); strcpy( address, inet_ntoa( ipaddr ) ); remaddr = address; } else { logmsg( _("HHCCT038E %4.4X: Invalid CTCE IP address %s\n"), dev->devnum, remaddr ); return -1; } } // The third argument is the destination port number // which for CTCE must be an even port number. remotep = *argv++; if( strlen( remotep ) > 5 || sscanf( remotep, "%u%c", &rport, &c ) != 1 || rport < 1024 || rport > 65534 ) { logmsg( _("HHCCT039E %4.4X: Invalid CTCE port number: %s\n"), dev->devnum, remotep ); return -1; } if( rport % 2 ) { logmsg( _("HHCCT040E %4.4X: CTCE remote port number not even: %s\n"), dev->devnum, remotep ); return -1; } // Enhanced CTC default MTU bufsize is CTCE_MTU_MIN. if( argc < 4 ) { mtu = CTCE_MTU_MIN; } else { // The fourth argument is the maximum transmission unit (MTU) size mtusize = *argv; if( strlen( mtusize ) > 5 || sscanf( mtusize, "%u%c", &mtu, &c ) != 1 || mtu < CTCE_MTU_MIN || mtu > 65536 ) { logmsg( _("HHCCT041E %4.4X: Invalid CTCE MTU size %s, allowed range is %d to 65536\n"), dev->devnum, mtusize, CTCE_MTU_MIN ); return -1; } } // Enhanced CTCT only supports an optional 5th parameter, // the Small MTU size, which defaults to the minimum size // of the TCP/IP packets exchanged: CTCE_SOKPFX. ctceSmlBin = sizeof(CTCE_SOKPFX); if( argc == 5 ) { ctceSmlChr = *(++argv); if( strlen( ctceSmlChr ) > 5 || sscanf( ctceSmlChr, "%u%c", &ctceSmlBin, &c ) != 1 || ctceSmlBin < (int)sizeof(CTCE_SOKPFX) || ctceSmlBin > mtu ) { ctceSmlBin = sizeof(CTCE_SOKPFX); logmsg( _("HHCCT042W %4.4X: Invalid CTCE Small MTU size %s ignored\n"), dev->devnum, ctceSmlChr ); } } dev->ctceSndSml = ctceSmlBin; // Set the device buffer size equal to the MTU size dev->bufsize = mtu; // Initialize the file descriptor for the socket connection // It's a little confusing, but we're using a couple of the // members of the server paramter structure to initiate the // outgoing connection. Saves a couple of variable declarations, // though. If we feel strongly about it, we can declare separate // variables... // Enhanced CTCT will require a second pass for the odd port number. for(ctceWrPort = 0; ctceWrPort <= 1; ctceWrPort++ ) { // make a TCP socket parm.listenfd[ctceWrPort] = socket( AF_INET, SOCK_STREAM, 0 ); if( parm.listenfd[ctceWrPort] < 0 ) { logmsg( _("HHCCT043E %4.4X: Error creating CTCE socket: %s\n"), dev->devnum, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // bind socket to our local port // (might seem like overkill, and usually isn't done, but doing this // bind() to the local port we configure gives the other end a chance // at validating the connection request) memset( &(parm.addr), 0, sizeof( parm.addr ) ); parm.addr.sin_family = AF_INET; parm.addr.sin_port = htons(lport + ctceWrPort); parm.addr.sin_addr.s_addr = htonl(INADDR_ANY); rc = bind( parm.listenfd[ctceWrPort], (struct sockaddr *)&parm.addr, sizeof( parm.addr ) ); if( rc < 0 ) { logmsg( _("HHCCT044E %4.4X: Error binding to CTCE socket (port %d): %s\n"), dev->devnum, lport + ctceWrPort, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // initiate a connection to the other end memset( &(parm.addr), 0, sizeof( parm.addr ) ); parm.addr.sin_family = AF_INET; // the even (=read) port must connect to the odd (=write) port // at the other side and vice-versa parm.addr.sin_port = htons(rport + ( ( ctceWrPort + 1 ) % 2 ) ); parm.addr.sin_addr = ipaddr; rc = connect( parm.listenfd[ctceWrPort], (struct sockaddr *)&parm.addr, sizeof( parm.addr ) ); // if connection was not successful, start a server if( rc < 0 ) { // used to pass parameters to the server thread CTCE_PARMBLK* arg; logmsg( _("HHCCT045I %4.4X: Waiting for CTCE connection :%d %s %s:%d\n"), dev->devnum, lport + ctceWrPort, ctceWrPort == 0 ? "->" : "<-", remaddr, rport + ( ( ctceWrPort + 1 ) % 2 ) ); // probably don't need to do this, not sure... close_socket( parm.listenfd[ctceWrPort] ); parm.listenfd[ctceWrPort] = socket( AF_INET, SOCK_STREAM, 0 ); if( parm.listenfd[ctceWrPort] < 0 ) { logmsg( _("HHCCT046E %4.4X: Error creating CTCE socket: %s\n"), dev->devnum, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // set up the listening port memset( &(parm.addr), 0, sizeof( parm.addr ) ); parm.addr.sin_family = AF_INET; parm.addr.sin_port = htons(lport + ctceWrPort) ; parm.addr.sin_addr.s_addr = htonl(INADDR_ANY); if( bind( parm.listenfd[ctceWrPort], (struct sockaddr *)&parm.addr, sizeof( parm.addr ) ) < 0 ) { logmsg( _("HHCCT047E %4.4X: Error binding to CTCE socket (port=%d): %s\n"), dev->devnum, lport + ctceWrPort, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } if( listen( parm.listenfd[ctceWrPort], 1 ) < 0 ) { logmsg( _("HHCCT048E %4.4X: Error on call to CTCE listen (port=%d): %s\n"), dev->devnum, lport + ctceWrPort, strerror( HSO_errno ) ); CTCX_Close( dev ); return -1; } // we are listening, so create a thread to accept connection arg = malloc( sizeof( CTCE_PARMBLK ) ); memcpy( arg, &parm, sizeof( parm ) ); arg->dev = dev; arg->ctceWrPort = ctceWrPort; snprintf(str,sizeof(str),"CTCE %4.4X ListenThread %d",dev->devnum, ctceWrPort); str[sizeof(str)-1]=0; create_thread( &tid, JOINABLE, CTCE_ListenThread, arg, str ); } else // successfully connected (outbound) to the other end { logmsg( _("HHCCT049I %4.4X: Established CTCE connection :%d %s %s:%d\n"), dev->devnum, lport + ctceWrPort, ctceWrPort == 0 ? "->" : "<-", remaddr, rport + ( ( ctceWrPort + 1 ) % 2 ) ); // The even local port (form the config) is for writing if( ctceWrPort == 0 ) { dev->fd = parm.listenfd[ctceWrPort]; } else { // The next odd local port (form the config) is for reading dev->ctcefd = parm.listenfd[ctceWrPort]; // This side is ready to start receiving and sending so we // start a read thread to do the receiving part; identical // code will be found in the CTCT_ListenThread after a // successful connect was accepted there. snprintf(str,sizeof(str),"CTCE %4.4X RecvThread %d",dev->devnum, ctceWrPort); str[sizeof(str)-1]=0; create_thread( &tid2, JOINABLE, CTCE_RecvThread, dev, str ); } } // for cosmetics, since we are successfully connected or serving, // fill in some details for the panel. // Also used for connection verification in CTCE_ListenThread sprintf( dev->filename, "%s:%d", remaddr, rport + ( ( ctceWrPort + 1 ) % 2 ) ); } // Enhanced CTC adapter intiialization for command register and CB. dev->ctcexCmd = 0x00; dev->ctceyCmd = 0x00; dev->ctceyCmdSCB = 0x00; // Enhanced CTC adapter sides are state-aware, with initial // state "Available" = YAV which corresponds to column 5 in // the table 2.13 in SA22-7203-00, i.e. we consider both // x- and y-side READY from the start. ALL Flags are cleared. CLR_CTCE_ALLF( dev->ctcexState ); SET_CTCE_YAV ( dev->ctcexState ); CLR_CTCE_ALLF( dev->ctceyState ); SET_CTCE_YAV ( dev->ctceyState ); // Initialize the 12 bits Send->Recv packet sequence ID with // the leftmost 4 bits C of the CCUU devnum at this side, // which helps distinguishing same-host traffic if the // Send-Recv side CCUU's have a diffent leftmost C. dev->ctcePktSeq = dev->devnum & 0xF000; // Initialize the CTC lock and condition used to signal // reception of a command matching the dependent one. initialize_lock( &dev->ctceEventLock ); initialize_condition( &dev->ctceEvent ); return 0; } // // CTCE_ListenThread // static void* CTCE_ListenThread( void* argp ) { int connfd; socklen_t servlen; char str[80]; CTCE_PARMBLK parm; TID tid2; // Thread ID for read thread // set up the parameters passed via create_thread parm = *((CTCE_PARMBLK*) argp); free( argp ); for( ; ; ) { servlen = sizeof(parm.addr); // await a connection connfd = accept( parm.listenfd[parm.ctceWrPort], (struct sockaddr *)&parm.addr, &servlen ); sprintf( str, "%s:%d", inet_ntoa( parm.addr.sin_addr ), ntohs( parm.addr.sin_port ) - (parm.ctceWrPort + 1) % 2 ); if( strcmp( str, parm.dev->filename ) != 0 ) { logmsg( _("HHCCT050E %4.4X: Incorrect client or config error\n" " Config=%s+%d, connecting client=%s\n"), parm.dev->devnum, parm.dev->filename, parm.ctceWrPort, str); close_socket( connfd ); } else { // The even local port (as in the config) is for writing if( parm.ctceWrPort == 0 ) { parm.dev->fd = connfd; } else { // The next odd local port is for reading parm.dev->ctcefd = connfd; // This side is ready to start receiving and sending so we // start a read thread to do the receiving part; identical // code will be found in the CTCT_ListenThread after a // successful connect was accepted there snprintf(str,sizeof(str),"CTCE %4.4X RecvThread %d",parm.dev->devnum, parm.ctceWrPort); str[sizeof(str)-1]=0; create_thread( &tid2, JOINABLE, CTCE_RecvThread, parm.dev, str ); } } // Ok, so having done that we're going to loop back to the // accept(). This was meant to handle the connection failing // at the other end; this end will be ready to accept another // connection. Although this will happen, I'm sure you can // see the possibility for bad things to occur (eg if another // Hercules tries to connect). This will also be fixed RSN. } return NULL; // make compiler happy } // // CTCE_Send // static void CTCE_Send( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ) { CTCE_SOKPFX *pSokBuf; // overlay for buf inside DEVBLK int rc; // Return code int i; // temp counter U32 XORChk = 0; // XOR of sent buffer for checking BYTE *pXOR = (BYTE*)&XORChk; // -> XORChk BYTE *pBuf = pDEVBLK->buf; // temp pointer inside buf pSokBuf = (CTCE_SOKPFX*) pDEVBLK->buf; pSokBuf->CmdReg = pDEVBLK->ctcexCmd; pSokBuf->FsmSta = pDEVBLK->ctcexState; pSokBuf->sCount = sCount; pSokBuf->PktSeq = ++pDEVBLK->ctcePktSeq; pSokBuf->SndLen = pDEVBLK->ctceSndSml; // We only ever Send if the sockets are connected. if( ( pDEVBLK->fd < 0) || ( pDEVBLK->ctcefd < 0) ) return ; // Only a (non-WEOF) write command data includes sending the IOBuf. if( IS_CTCE_CCW_WRT( pDEVBLK->ctcexCmd ) ) { memcpy( pDEVBLK->buf + sizeof(CTCE_SOKPFX), pIOBuf, sCount ); // Increase the SndLen if the sCount is too large. if( pSokBuf->SndLen < ( sCount + sizeof(CTCE_SOKPFX) ) ) pSokBuf->SndLen = ( sCount + sizeof(CTCE_SOKPFX) ); //1 if( pDEVBLK->ccwstep ) //1 packet_trace( pIOBuf, sCount ); // If bufsize (init from the MTU parameter) is not large enough // then we will have a severe error as the CTC will not connect. if( pDEVBLK->bufsize < pSokBuf->SndLen ) { logmsg( _("HHCCT051S %4.4X: bufsize parameter %d is too small; increase at least to %d\n"), pDEVBLK->devnum, pDEVBLK->bufsize, pSokBuf->SndLen ); } } // Write the all of this to the other (y-)side. rc = write_socket( pDEVBLK->fd, pDEVBLK->buf, pSokBuf->SndLen ); // Trace the IP packet just sent if needed. if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { XORChk = 0; pBuf = pDEVBLK->buf; for(i = 0; i < pSokBuf->SndLen; i++) { if( (i % 4) == 0 ) pXOR = (BYTE*)&XORChk; *pXOR++ ^= *pBuf++; } logmsg( _("HHCCT052I %4.4X: Send %4.4X->%s %s=%2.2X x=%2.2X y=%2.2X l=%4.4X k=%8.8X\n"), pDEVBLK->devnum, pSokBuf->PktSeq, pDEVBLK->filename, CTCE_CmdStr[CTCE_Cmd[pDEVBLK->ctcexCmd]], pDEVBLK->ctcexCmd, pDEVBLK->ctcexState, pDEVBLK->ctceyState, sCount, XORChk ) ; if( pDEVBLK->ccwtrace ) packet_trace( pDEVBLK->buf, pSokBuf->SndLen ); } if( rc < 0 ) { logmsg( _("HHCCT053E %4.4X: Error writing to %s: %s\n"), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // The ATTN flag signals entering a Working(D) state. If this was // because of a READ command then we need to wait for the matching // WRITE command from the other (y-)side to arrive. // Please note that initially we believed such processing to be // needed for READ and CONTROL commands as well, but this turned out // not to be the case. Even stronger, we have not yet seen a READ // command BEFORE the matching WRITE command, thus this processing // is perhaps never needed at all ... // (PJJ, April 2014) else if( IS_CTCE_ATTN( pDEVBLK->ctcexState ) && IS_CTCE_CCW_RED( pDEVBLK->ctcexCmd ) ) // IS_CCW_READ( pDEVBLK->ctcexCmd ) ) { struct timespec waittime; struct timeval now; // Any request to signal attention has now been sent. CLR_CTCE_ATTN( pDEVBLK->ctcexState ); gettimeofday( &now, NULL ); waittime.tv_sec = now.tv_sec + CTC_READ_TIMEOUT_SECS; waittime.tv_nsec = now.tv_usec * 1000; obtain_lock( &pDEVBLK->ctceEventLock ); rc = timed_wait_condition( &pDEVBLK->ctceEvent, &pDEVBLK->ctceEventLock, &waittime ); release_lock( &pDEVBLK->ctceEventLock ); // Trace the reception of the matching command, or the wait timeout (RC=138). if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCCT054W %4.4X: Send %4.4X->%s %s=%2.2X x=%2.2X y=%2.2X: wait RC=%d\n"), pDEVBLK->devnum, pSokBuf->PktSeq, pDEVBLK->filename, CTCE_CmdStr[CTCE_Cmd[pDEVBLK->ctcexCmd]], pDEVBLK->ctcexCmd, pDEVBLK->ctcexState, pDEVBLK->ctceyState, rc ) ; // First we check for Halt or Clear Subchannel if( rc == ETIMEDOUT || rc == EINTR ) { // check for halt condition if( pDEVBLK->scsw.flag2 & SCSW2_FC_HALT || pDEVBLK->scsw.flag2 & SCSW2_FC_CLEAR ) { if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCCT055I %4.4X: Halt or Clear Recognized\n"), pDEVBLK->devnum ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = sCount; } // Other timeouts or errors should not occur. else { *pUnitStat = CSW_CE | CSW_DE | CSW_UC | CSW_SM; pDEVBLK->sense[0] = 0; } return; } // A WRITE EOF command from the other side will have resulted // in the WEOF flag being set. If this was a matching command // for a READ then unit exception needs to be included. else if( IS_CTCE_WEOF( pDEVBLK->ctcexState ) ) { *pResidual = 0; *pUnitStat = CSW_CE | CSW_DE | CSW_UX; if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCCT056I %4.4X: Recv %4.4X<-%s %s=%2.2X x=%2.2X y=%2.2X: WEOF -> UX\n"), pDEVBLK->devnum, pSokBuf->PktSeq, pDEVBLK->filename, CTCE_CmdStr[CTCE_Cmd[pDEVBLK->ctcexCmd]], pDEVBLK->ctcexCmd, pDEVBLK->ctcexState, pDEVBLK->ctceyState ) ; return; } } // Reset the attention signal flag. CLR_CTCE_ATTN( pDEVBLK->ctcexState ); // If the command (by now matched) was a READ command, then the // other (y-)side data is available in the DEVBLK buf, so we // can copy it into the IO channel buffer and compute residual. // if( IS_CCW_READ( pDEVBLK->ctcexCmd ) ) if( IS_CTCE_CCW_RED( pDEVBLK->ctcexCmd ) ) { // The actual length of data transferred is the minimum of // the current READ sCount, and the original WRITE sCount // which is recorded immediately following the CTCE_SOKPFX. pSokBuf->sCount = ( sCount <= *(U16*)( pDEVBLK->buf + sizeof(CTCE_SOKPFX) ) ) ? sCount : *(U16*)( pDEVBLK->buf + sizeof(CTCE_SOKPFX) ); // Immediately followed by the WRITE data previously received. memcpy( pIOBuf, pDEVBLK->buf + sizeof(CTCE_SOKPFX) + sizeof(pSokBuf->sCount) , pSokBuf->sCount ) ; *pResidual = sCount - pSokBuf->sCount; //1 if( pDEVBLK->ccwstep ) //1 packet_trace( pIOBuf, sCount ); } else *pResidual = 0; // if( IS_CCW_WRITE( pDEVBLK->ctcexCmd ) ) if( IS_CTCE_CCW_WRA( pDEVBLK->ctcexCmd ) ) *pUnitStat = 0; else *pUnitStat = CSW_CE | CSW_DE; return; } // // CTCE_RecvThread // static void* CTCE_RecvThread( DEVBLK* pDEVBLK ) { CTCE_SOKPFX *pSokBuf; // overlay for buf inside DEVBLK ssize_t iLength = 0; BYTE *buf; //-> Device recv data buffer U64 ctcePktSeq = 0; // Recvd Packet Sequence ID U64 ctceBytCnt = 0; // Recvd Byte Count int i; // temp counter int rc; // device_attention RC U32 XORChk = 0; // XOR of sent buffer for checking BYTE *pXOR = (BYTE*)&XORChk; // -> XORChk BYTE *pBuf = pDEVBLK->buf; // temp pointer inside buf logmsg( _("HHCCT057I %4.4X: Read thread CTCE started for %s (bufsize=%d,%d)\n"), pDEVBLK->devnum, pDEVBLK->filename, pDEVBLK->bufsize, pDEVBLK->ctceSndSml ); // logmsg( _("HHCCT057I %4.4X: Started %s reader thread (bufsize=%d,%d)\n"), // pDEVBLK->devnum, pDEVBLK->filename, pDEVBLK->bufsize, pDEVBLK->ctceSndSml ); // avoid having to lock the DEVBLK whilst awaiting data to arrive via read_socket buf = malloc( pDEVBLK->bufsize ); pSokBuf = (CTCE_SOKPFX*)buf; // This thread will loop until we receive a zero-length packet for( ; ; ) { // We read whatever the other (y-)side of the CTC has sent us, // which by now won't block until the complete bufsize is received. iLength = read_socket( pDEVBLK->ctcefd, buf, pDEVBLK->ctceSndSml ); // Followed by the receiving the rest if the default SndLen was too small. if( ( pDEVBLK->ctceSndSml < pSokBuf->SndLen ) && ( iLength != 0 ) ) iLength += read_socket( pDEVBLK->ctcefd, buf + pDEVBLK->ctceSndSml, pSokBuf->SndLen - pDEVBLK->ctceSndSml ); // In case we are closing down this thread can end. if( iLength == 0 ) { // And the other end can then close down as well. CTCX_Close( pDEVBLK ); // We report some statistics. logmsg( _("HHCCT058I %4.4X: Zero length read from %s\n"), pDEVBLK->devnum, pDEVBLK->filename ); logmsg( _("HHCCT059I %4.4X: %d MB received in %d packets\n"), pDEVBLK->devnum, ctceBytCnt / 1048576 , ctcePktSeq ); free( buf ); return NULL; // make compiler happy } // Changes to DEVBLK must be lock protected as other threads might update as well. obtain_lock( &pDEVBLK->lock ); // Check for other error condition if( iLength < 0 ) { logmsg( _("HHCCT060E %4.4X: Error reading from %s: %s\n"), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; pDEVBLK->scsw.unitstat = CSW_CE | CSW_DE | CSW_UC; } else { ctcePktSeq += 1 ; ctceBytCnt += iLength ; pDEVBLK->ctceyCmd = pSokBuf->CmdReg; pDEVBLK->ctceyState = pSokBuf->FsmSta; // Trace the packet received from the other side of the CTC if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { XORChk = 0; pBuf = buf; for(i = 0; i < iLength; i++) { if( (i % 4) == 0 ) pXOR = (BYTE*)&XORChk; *pXOR++ ^= *pBuf++; } logmsg( _("HHCCT061I %4.4X: Recv %4.4X<-%s %s=%2.2X x=%2.2X y=%2.2X l=%4.4X k=%8.8X\n"), pDEVBLK->devnum, pSokBuf->PktSeq, pDEVBLK->filename, CTCE_CmdStr[CTCE_Cmd[pDEVBLK->ctceyCmd]], pDEVBLK->ctceyCmd, pDEVBLK->ctcexState, pDEVBLK->ctceyState, pSokBuf->sCount, XORChk ) ; if( pDEVBLK->ccwtrace ) packet_trace( buf, iLength ); } // Only if the other (y-)side sent us a write command will // we copy the socket buffer into the device buffer. if( IS_CTCE_CCW_WRT( pDEVBLK->ctceyCmd ) ) { // We retain the sCount of this WRITE command for later // comparison against the matching READ command, ahead // of the data itself following CTCE_SOKPFX. *(U16*)( pDEVBLK->buf + sizeof(CTCE_SOKPFX) ) = pSokBuf->sCount ; memcpy( pDEVBLK->buf + sizeof(CTCE_SOKPFX) + sizeof(pSokBuf->sCount) , buf + sizeof(CTCE_SOKPFX), pSokBuf->sCount ); } // If the other side sent us a WRITE EOF command // then we just set the WEOF flag on our side. if( IS_CTCE_CCW_WEF( pDEVBLK->ctceyCmd ) ) { SET_CTCE_WEOF( pDEVBLK->ctcexState ); // But only if this does NOT match a Working(D) Read command will it remain set. if( ( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) && (!IS_CTCE_MATCH( pDEVBLK->ctceyState ) ) ) logmsg( _("HHCCT062I %4.4X: Recv %4.4X<-%s %s=%2.2X x=%2.2X y=%2.2X: WEOF ->set\n"), pDEVBLK->devnum, pSokBuf->PktSeq, pDEVBLK->filename, CTCE_CmdStr[CTCE_Cmd[pDEVBLK->ctceyCmd]], pDEVBLK->ctceyCmd, pDEVBLK->ctcexState, pDEVBLK->ctceyState ) ; } // If we were sent this command because the other side was // not ready yet, then we need to signal a device end and // reset SENSE[0] bits 1 (SENSE_IR) and 7 (SENSE_OC). // However, as stated earlier, this NOT READY handling did // not work and was effectively disabled by initializing // both adapter sides as being READY from the start. if( IS_CTCE_NRDY( pDEVBLK->ctceyState ) ) { pDEVBLK->sense[0] &= ~(SENSE_IR | SENSE_OC); release_lock( &pDEVBLK->lock ); device_attention( pDEVBLK, CSW_DE ); obtain_lock( &pDEVBLK->lock ); } // If the other (y-)side sent us a command that put them // in the Working(D) state asking us to signal attention // then we copy their state into ours. We also copy the // y command register for the SCB command to read from. else if( IS_CTCE_ATTN( pDEVBLK->ctceyState ) ) { CLR_CTCE_ATTN( pDEVBLK->ctceyState ); pDEVBLK->ctcexState = pDEVBLK->ctceyState; pDEVBLK->ctceyCmdSCB = pDEVBLK->ctceyCmd; // Then we signal that attention. The release and // obtain lock is only needed because device_attention // also obtains and releases the lock, which under // Unix causes HHCCP017I eventually. The retry // attempts were discovered to actually occur as // sometimes RC=1, about 6 times per hour. release_lock( &pDEVBLK->lock ); rc = device_attention( pDEVBLK, CSW_ATTN ); // Non-zero RC will be reported and re-tried (except RC=3). for( i = 1; ( rc != 0 ) && ( i < 10 ); i++ ) { logmsg( _("HHCCT063E %4.4X: Recv %4.4X<-%s %s=%2.2X x=%2.2X y=%2.2X: ATTN(%d) RC=%d\n"), pDEVBLK->devnum, pSokBuf->PktSeq, pDEVBLK->filename, CTCE_CmdStr[CTCE_Cmd[pDEVBLK->ctceyCmd]], pDEVBLK->ctceyCmd, pDEVBLK->ctcexState, pDEVBLK->ctceyState, i, rc ); if( rc == 3 ) { rc = 0; } else { usleep(1000); rc = device_attention( pDEVBLK, CSW_DE ); } } obtain_lock( &pDEVBLK->lock ); } // If the other (y-)side sent us a matching command then // the Working(D) state will cease into YAV state but // CTCT_Send is awaiting us to signal that condition. // We clear the SCB command buffer input. else if( IS_CTCE_MATCH( pDEVBLK->ctceyState ) ) { CLR_CTCE_MATCH( pDEVBLK->ctceyState ); pDEVBLK->ctceyCmdSCB = 0; obtain_lock( &pDEVBLK->ctceEventLock ); signal_condition( &pDEVBLK->ctceEvent ); release_lock( &pDEVBLK->ctceEventLock ); } } release_lock( &pDEVBLK->lock ); } free( buf ); return NULL; // make compiler happy } // ==================================================================== // Support Functions // ==================================================================== // --------------------------------------------------------------------- // ParseMAC // --------------------------------------------------------------------- // // Parse a string containing a MAC (hardware) address and return the // binary equivalent. // // Input: // pszMACAddr Pointer to string containing a MAC Address in the // format "xx-xx-xx-xx-xx-xx" or "xx:xx:xx:xx:xx:xx". // // Output: // pbMACAddr Pointer to a BYTE array to receive the MAC Address // that MUST be at least sizeof(MAC) bytes long. // // Returns: // 0 on success, -1 otherwise // int ParseMAC( char* pszMACAddr, BYTE* pbMACAddr ) { char work[((sizeof(MAC)*3)-0)]; BYTE sep; int x; unsigned i; if (strlen(pszMACAddr) != ((sizeof(MAC)*3)-1) || (sizeof(MAC) > 1 && *(pszMACAddr+2) != '-' && *(pszMACAddr+2) != ':') ) { errno = EINVAL; return -1; } strncpy(work,pszMACAddr,((sizeof(MAC)*3)-1)); work[((sizeof(MAC)*3)-1)] = sep = *(pszMACAddr+2); for (i=0; i < sizeof(MAC); i++) { if (0 || !isxdigit(work[(i*3)+0]) || !isxdigit(work[(i*3)+1]) || sep != work[(i*3)+2] ) { errno = EINVAL; return -1; } work[(i*3)+2] = 0; sscanf(&work[(i*3)+0],"%x",&x); *(pbMACAddr+i) = x; } return 0; } // --------------------------------------------------------------------- // packet_trace // --------------------------------------------------------------------- // // Subroutine to trace the contents of a buffer // void packet_trace( BYTE* pAddr, int iLen ) { int offset; unsigned int i; unsigned char c = '\0'; unsigned char e = '\0'; unsigned char print_chars[17]; for( offset = 0; offset < iLen; ) { memset( print_chars, 0, sizeof( print_chars ) ); logmsg( "+%4.4X ", offset ); for( i = 0; i < 16; i++ ) { c = *pAddr++; if( offset < iLen ) { logmsg("%2.2X", c); print_chars[i] = '.'; e = guest_to_host( c ); if( isprint( e ) ) print_chars[i] = e; if( isprint( c ) ) print_chars[i] = c; } else { logmsg( " " ); } offset++; if( ( offset & 3 ) == 0 ) { logmsg( " " ); } } logmsg( " %s\n", print_chars ); } } hercules-3.12/w32ctca.c0000664000175000017500000003575512564723224011634 00000000000000//////////////////////////////////////////////////////////////////////////////////// // w32ctca.c CTCI-W32 (Channel to Channel link to Win32 TCP/IP stack) //////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2002-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// #include "hstdinc.h" #include "hercules.h" #if !defined(OPTION_W32_CTCI) int w32ctca_dummy = 0; #else // defined(OPTION_W32_CTCI) #include "w32ctca.h" #include "tt32api.h" // (exported TunTap32.dll functions) #ifdef __CYGWIN__ #include // (for cygwin_conv_to_full_win32_path) #endif /////////////////////////////////////////////////////////////////////////////////////////// // We prefer the '_ex' variety as they resolve the "no error" errno issue... // But if they're not available we'll settle for the older version... #define TT32_PROCADDRS( name ) \ \ ptuntap32_ ## name ## _ex g_tt32_pfn_ ## name ## _ex = NULL; \ ptuntap32_ ## name g_tt32_pfn_ ## name = NULL #define GET_TT32_PROCADDRS( name ) \ \ g_tt32_pfn_ ## name ## _ex = \ (ptuntap32_ ## name ## _ex ) GetProcAddress( g_tt32_hmoddll, \ "tuntap32_" # name "_ex" ); \ g_tt32_pfn_ ## name = \ (ptuntap32_ ## name ) GetProcAddress( g_tt32_hmoddll, \ "tuntap32_" # name ); if (! \ g_tt32_pfn_ ## name ) goto error /////////////////////////////////////////////////////////////////////////////////////////// // Global variables... #define TT32_DEFAULT_IFACE "00-00-5E-80-00-00" CRITICAL_SECTION g_tt32_lock; // (lock for accessing ALL below variables) char g_tt32_dllname [ MAX_TT32_DLLNAMELEN ] = {0}; HMODULE g_tt32_hmoddll = NULL; TT32_PROCADDRS ( open ); TT32_PROCADDRS ( close ); TT32_PROCADDRS ( read ); TT32_PROCADDRS ( write ); TT32_PROCADDRS ( ioctl ); TT32_PROCADDRS ( get_stats ); TT32_PROCADDRS ( get_default_iface ); TT32_PROCADDRS ( set_debug_output_func ); TT32_PROCADDRS ( version_string ); TT32_PROCADDRS ( version_numbers ); TT32_PROCADDRS ( copyright_string ); // (NOTE: the following function only exists in v3.0+) ptuntap32_build_herc_iface_mac g_tt32_pfn_build_herc_iface_mac = NULL; /////////////////////////////////////////////////////////////////////////////////////////// BOOL GetTT32ProcAddrs() { GET_TT32_PROCADDRS ( open ); GET_TT32_PROCADDRS ( close ); GET_TT32_PROCADDRS ( read ); GET_TT32_PROCADDRS ( write ); GET_TT32_PROCADDRS ( ioctl ); GET_TT32_PROCADDRS ( get_stats ); GET_TT32_PROCADDRS ( get_default_iface ); GET_TT32_PROCADDRS ( set_debug_output_func ); GET_TT32_PROCADDRS ( version_string ); GET_TT32_PROCADDRS ( version_numbers ); GET_TT32_PROCADDRS ( copyright_string ); // (NOTE: we don't NEED this function (since it's new to // v3.0+ of tuntap32) so it's okay if it doesn't exist) g_tt32_pfn_build_herc_iface_mac = (ptuntap32_build_herc_iface_mac ) GetProcAddress( g_tt32_hmoddll, "tuntap32_build_herc_iface_mac" ); LeaveCriticalSection(&g_tt32_lock); return TRUE; error: FreeLibrary( g_tt32_hmoddll ); g_tt32_hmoddll = NULL; logmsg( "** tt32_loaddll: One of the GetProcAddress calls failed\n" ); LeaveCriticalSection(&g_tt32_lock); return FALSE; } /////////////////////////////////////////////////////////////////////////////////////////// // Debug string output function for use by the TUNTAP32.DLL... void __cdecl tt32_output_debug_string( const char* debug_string ) { logmsg( "%s", debug_string ); } void enable_tt32_debug_tracing( int enable ) { // Pass to TunTap32 DLL a pointer to the function it can use to // display debug messages with. This function of our's (that we // are passing it a pointer to) will then display its debugging // message (string) on the Hercules console so we can see it. g_tt32_pfn_set_debug_output_func( enable ? &tt32_output_debug_string : NULL ); } /////////////////////////////////////////////////////////////////////////////////////////// // Load the TUNTAP32.DLL... BOOL tt32_loaddll() { char* pszDLLName; char tt32_dllname_in_buff [ MAX_PATH ]; char tt32_dllname_out_buff [ MAX_PATH ] = {0}; static int tt32_init_done = 0; if (!tt32_init_done) { InitializeCriticalSection( &g_tt32_lock ); tt32_init_done = 1; } EnterCriticalSection(&g_tt32_lock); if (g_tt32_hmoddll) { LeaveCriticalSection(&g_tt32_lock); return TRUE; } // First, determine the name of the DLL we should try loading... if ( !( pszDLLName = getenv( "HERCULES_IFC" ) ) ) pszDLLName = DEF_TT32_DLLNAME; ASSERT( pszDLLName && *pszDLLName ); // Then check to see if the "name" contains path information or not... if ( strchr( pszDLLName, '/' ) || strchr( pszDLLName, '\\' ) ) { // It's already a path... strlcpy( tt32_dllname_in_buff, pszDLLName, sizeof(tt32_dllname_in_buff) ); } else { // It's not a path, so make it one... strlcpy( tt32_dllname_in_buff, MODULESDIR, sizeof(tt32_dllname_in_buff) ); strlcat( tt32_dllname_in_buff, "/" , sizeof(tt32_dllname_in_buff) ); strlcat( tt32_dllname_in_buff, pszDLLName, sizeof(tt32_dllname_in_buff) ); } // Now convert it to a full path... // PROGRAMMING NOTE: It's important here to ensure that our end result is a path // with BACKWARD slashes in it and NOT forward slashes! LoadLibrary is one of the // few Win32 functions that cannot handle paths with forward slashes in it. For // 'open', etc, yeah, forward slashes are fine, but for LoadLibrary they're not! #ifdef _MSVC_ if ( !_fullpath( tt32_dllname_out_buff, tt32_dllname_in_buff, sizeof(tt32_dllname_out_buff) ) ) strlcpy( tt32_dllname_out_buff, tt32_dllname_in_buff, sizeof(tt32_dllname_out_buff) ); #else // (presumed cygwin) cygwin_conv_to_full_win32_path( tt32_dllname_in_buff, tt32_dllname_out_buff ); #endif // _MSVC_ tt32_dllname_out_buff[ sizeof(tt32_dllname_out_buff) - 1 ] = 0; // Finally, copy it to our global home for it... strlcpy( g_tt32_dllname, tt32_dllname_out_buff, sizeof(g_tt32_dllname) ); ASSERT(g_tt32_dllname[0]); g_tt32_hmoddll = LoadLibraryEx( g_tt32_dllname, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); if (!g_tt32_hmoddll) { // Try again WITHOUT the path this time... strlcpy( g_tt32_dllname, pszDLLName, sizeof(g_tt32_dllname) ); g_tt32_hmoddll = LoadLibraryEx( g_tt32_dllname, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ); if (!g_tt32_hmoddll) { DWORD dwLastError = GetLastError(); LeaveCriticalSection(&g_tt32_lock); logmsg("** tt32_loaddll: LoadLibraryEx(\"%s\") failed; rc=%ld: %s\n", g_tt32_dllname,dwLastError,strerror(dwLastError)); return FALSE; } } // Resolve our required DLL entry-point variables... if (!GetTT32ProcAddrs()) return FALSE; logmsg("%s version %s initiated\n", g_tt32_dllname, g_tt32_pfn_version_string()); #if defined(DEBUG) || defined(_DEBUG) enable_tt32_debug_tracing(1); // (enable debug tracing by default for DEBUG builds) #endif return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////// int tt32_open( char* pszGatewayDevice, int iFlags ) { int rc, errnum; if (!tt32_loaddll()) return -1; if (! g_tt32_pfn_open_ex ) return g_tt32_pfn_open ( pszGatewayDevice, iFlags ); rc = g_tt32_pfn_open_ex ( pszGatewayDevice, iFlags, &errnum ); errno = errnum; return rc; } /////////////////////////////////////////////////////////////////////////////////////////// int tt32_read( int fd, u_char* buffer, u_long size ) { int rc, errnum; if (!tt32_loaddll()) return -1; if (! g_tt32_pfn_read_ex ) return g_tt32_pfn_read ( fd, buffer, size ); rc = g_tt32_pfn_read_ex ( fd, buffer, size, &errnum ); errno = errnum; return rc; } /////////////////////////////////////////////////////////////////////////////////////////// int tt32_write( int fd, u_char* buffer, u_long size ) { int rc, errnum; if (!tt32_loaddll()) return -1; if (! g_tt32_pfn_write_ex ) return g_tt32_pfn_write ( fd, buffer, size ); rc = g_tt32_pfn_write_ex ( fd, buffer, size, &errnum ); errno = errnum; return rc; } /////////////////////////////////////////////////////////////////////////////////////////// int tt32_close( int fd ) { int rc, errnum; if (!tt32_loaddll()) return -1; #if defined(DEBUG) || defined(_DEBUG) display_tt32_stats(fd); #endif if (! g_tt32_pfn_close_ex ) return g_tt32_pfn_close ( fd ); rc = g_tt32_pfn_close_ex ( fd, &errnum ); errno = errnum; return rc; } /////////////////////////////////////////////////////////////////////////////////////////// int tt32_ioctl( int fd, int iRequest, char* argp ) { int rc, errnum; if (!tt32_loaddll()) return -1; if (! g_tt32_pfn_ioctl_ex ) return g_tt32_pfn_ioctl ( fd, iRequest, argp ); rc = g_tt32_pfn_ioctl_ex ( fd, iRequest, argp, &errnum ); errno = errnum; return rc; } /////////////////////////////////////////////////////////////////////////////////////////// const char* tt32_get_default_iface() { int errnum; const char* pszDefaultIFace = NULL; if (tt32_loaddll()) { if (! g_tt32_pfn_get_default_iface_ex ) pszDefaultIFace = g_tt32_pfn_get_default_iface (); else { pszDefaultIFace = g_tt32_pfn_get_default_iface_ex ( &errnum ); errno = errnum; } } return ( pszDefaultIFace ? pszDefaultIFace : TT32_DEFAULT_IFACE ); } /////////////////////////////////////////////////////////////////////////////////////////// int display_tt32_stats( int fd ) { int errnum; TT32STATS stats; if (!tt32_loaddll()) return -1; memset(&stats,0,sizeof(stats)); stats.dwStructSize = sizeof(stats); if (! g_tt32_pfn_get_stats_ex ) g_tt32_pfn_get_stats ( fd, &stats ); else { g_tt32_pfn_get_stats_ex ( fd, &stats, &errnum ); errno = errnum; } if (stats.dwStructSize >= sizeof(stats)) { // New version 3.3 stats logmsg ( "\n%s Statistics:\n\n" "Size of Kernel Hold Buffer: %5luK\n" "Size of DLL I/O Buffer: %5luK\n" "Maximum DLL I/O Bytes Received: %5luK\n\n" "%12" I64_FMT "d Total Write Calls\n" "%12" I64_FMT "d Total Write I/Os\n" "%12" I64_FMT "d Packets To All Zeroes MAC Written\n" "%12" I64_FMT "d Total Packets Written\n" "%12" I64_FMT "d Total Bytes Written\n\n" "%12" I64_FMT "d Total Read Calls\n" "%12" I64_FMT "d Total Read I/Os\n" "%12" I64_FMT "d Internally Handled ARP Packets\n" "%12" I64_FMT "d Packets From Ourself\n" "%12" I64_FMT "d Total Ignored Packets\n" "%12" I64_FMT "d Packets To All Zeroes MAC Read\n" "%12" I64_FMT "d Total Packets Read\n" "%12" I64_FMT "d Total Bytes Read\n\n" ,g_tt32_dllname ,(stats.dwKernelBuffSize + 1023) / 1024 ,(stats.dwReadBuffSize + 1023) / 1024 ,(stats.dwMaxBytesReceived + 1023) / 1024 ,stats.n64WriteCalls ,stats.n64WriteIOs ,stats.n64ZeroMACPacketsWritten ,stats.n64PacketsWritten ,stats.n64BytesWritten ,stats.n64ReadCalls ,stats.n64ReadIOs ,stats.n64InternalPackets ,stats.n64OwnPacketsIgnored ,stats.n64IgnoredPackets ,stats.n64ZeroMACPacketsRead ,stats.n64PacketsRead ,stats.n64BytesRead ); } else { // Old pre version 3.3 stats logmsg ( "\n%s Statistics:\n\n" "Size of Kernel Hold Buffer: %5luK\n" "Size of DLL I/O Buffer: %5luK\n" "Maximum DLL I/O Bytes Received: %5luK\n\n" "%12" I64_FMT "d Write Calls\n" "%12" I64_FMT "d Write I/Os\n" "%12" I64_FMT "d Read Calls\n" "%12" I64_FMT "d Read I/Os\n" "%12" I64_FMT "d Packets Read\n" "%12" I64_FMT "d Packets Written\n" "%12" I64_FMT "d Bytes Read\n" "%12" I64_FMT "d Bytes Written\n" "%12" I64_FMT "d Internal Packets\n" "%12" I64_FMT "d Ignored Packets\n\n" , g_tt32_dllname ,(stats.dwKernelBuffSize + 1023) / 1024 ,(stats.dwReadBuffSize + 1023) / 1024 ,(stats.dwMaxBytesReceived + 1023) / 1024 ,stats.n64WriteCalls ,stats.n64WriteIOs ,stats.n64ReadCalls ,stats.n64ReadIOs ,stats.n64PacketsRead ,stats.n64PacketsWritten ,stats.n64BytesRead ,stats.n64BytesWritten ,stats.n64InternalPackets ,stats.n64IgnoredPackets ); } return 0; } /////////////////////////////////////////////////////////////////////////////////////////// // BOOLEAN FUNCTION int tt32_build_herc_iface_mac ( BYTE* out_mac, const BYTE* in_ip ) { // We prefer to let TunTap32 do it for us (since IT'S the one // that decides what it should really be) but if they're using // an older version of TunTap32 that doesn't have the function // then we'll do it ourselves just like before... if (!g_tt32_pfn_build_herc_iface_mac) return 0; // (FALSE: must do it yourself) g_tt32_pfn_build_herc_iface_mac( out_mac, in_ip ); return 1; // (TRUE: ok we did it for you) } /////////////////////////////////////////////////////////////////////////////////////////// #endif // !defined(OPTION_W32_CTCI) /////////////////////////////////////////////////////////////////////////////////////////// hercules-3.12/tuntap.c0000664000175000017500000006764212564723224011701 00000000000000/* TUNTAP.C (c) Copyright James A. Pierson, 2002-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* Hercules - TUN/TAP Abstraction Layer */ // TUN/TAP implementations differ among platforms. Linux and FreeBSD // offer much the same functionality but with differing semantics. // Windows does not have TUN/TAP but thanks to "Fish" (David B. Trout) // we have a way of emulating the TUN/TAP interface through a set of // custom DLLs he has provided us. // // This abstraction layer is an attempt to create a common API set // that works on all platforms with (hopefully) equal results. // #include "hstdinc.h" /* jbs 1/19/2008 added ifdef on __SOLARIS__ */ #if !defined(__SOLARIS__) #include "hercules.h" #include "tuntap.h" #include "devtype.h" #include "ctcadpt.h" #include "hercifc.h" #if defined( OPTION_W32_CTCI ) #include "w32ctca.h" #endif // ==================================================================== // Declarations // ==================================================================== #ifndef OPTION_W32_CTCI static int IFC_IOCtl( int fd, unsigned long int iRequest, char* argp ); static int ifc_fd[2] = { -1, -1 }; static pid_t ifc_pid = 0; static void tuntap_term(void) { close(ifc_fd[0]); close(ifc_fd[1]); ifc_fd[0] = ifc_fd[1] = -1; kill(ifc_pid, SIGINT); } #endif // ==================================================================== // Primary Module Entry Points // ==================================================================== static int TUNTAP_SetMode (int fd, struct ifreq *ifr) { int rc; /* Try TUNTAP_ioctl first */ rc = TUNTAP_IOCtl (fd, TUNSETIFF, (char *) ifr); #if !defined(OPTION_W32_CTCI) /* If invalid value, try with the pre-2.4.5 value */ if (rc != 0 && errno == EINVAL) rc = TUNTAP_IOCtl (fd, ('T' << 8) | 202, (char *) ifr); /* kludge for EPERM and linux 2.6.18 */ if (rc != 0 && errno == EPERM) { int ifd[2]; char *hercifc; pid_t pid; CTLREQ ctlreq; fd_set selset; struct timeval tv; int sv_err; int status; if (socketpair (AF_UNIX, SOCK_STREAM, 0, ifd) < 0) return -1; if (!(hercifc = getenv ("HERCULES_IFC"))) hercifc = HERCIFC_CMD; pid = fork(); if (pid < 0) return -1; else if (pid == 0) { /* child */ dup2 (ifd[0], STDIN_FILENO); dup2 (STDOUT_FILENO, STDERR_FILENO); dup2 (ifd[0], STDOUT_FILENO); close (ifd[1]); rc = execlp (hercifc, hercifc, NULL ); return -1; } /* parent */ close(ifd[0]); /* Request hercifc to issue the TUNSETIFF ioctl */ memset (&ctlreq, 0, CTLREQ_SIZE); ctlreq.iCtlOp = TUNSETIFF; ctlreq.iProcID = fd; memcpy (&ctlreq.iru.ifreq, ifr, sizeof (struct ifreq)); write (ifd[1], &ctlreq, CTLREQ_SIZE); /* Get response, if any, from hercifc */ FD_ZERO (&selset); FD_SET (ifd[1], &selset); tv.tv_sec = 5; tv.tv_usec = 0; rc = select (ifd[1]+1, &selset, NULL, NULL, &tv); if (rc > 0) { rc = read (ifd[1], &ctlreq, CTLREQ_SIZE); if (rc > 0) memcpy (ifr, &ctlreq.iru.ifreq, sizeof (struct ifreq)); } else if (rc == 0) { logmsg (_("HHCTU001E %s timeout, possible older version?\n"), hercifc); errno = EPERM; rc = -1; } /* clean-up */ sv_err = errno; close (ifd[1]); kill (pid, SIGINT); waitpid (pid, &status, 0); errno = sv_err; } #endif /* if !defined(OPTION_W32_CTCI) */ return rc; } // // TUNTAP_CreateInterface // // // Creates a new network interface using TUN/TAP. Reading from or // writing to the file descriptor returned from this call will pass // network packets to/from the virtual network interface. // // A TUN interface is a Point-To-Point connection from the driving // system's IP stack to the guest OS running within Hercules. // // A TAP interface in a virtual network adapter that "tap's" off the // driving system's network stack. // // On *nix boxen, this is accomplished by opening the special TUN/TAP // character device (usually /dev/net/tun). Once the character device // is opened, an ioctl call is done to set they type of interface to be // created, IFF_TUN or IFF_TAP. Once the interface is created, the // interface name is returned in pszNetDevName. // // Input: // pszTUNDevice Pointer to the name of the TUN/TAP char device // iFlags Flags for the new interface: // IFF_TAP - Create a TAP interface or // IFF_TUN - Create a TUN interface // IFF_NO_PI - Do not include packet information // // On Win32, calls are made to Fish's TT32 DLL's to accomplish the same // functionality. There are a few differences in regards to the arguments // however: // // Input: // pszTUNDevice Pointer to a string that describes the physical // adapter to attach the TUN/TAP interface to. // This string can contain any of the following: // 1) IP address (in a.b.c.d notation) // 2) MAC address (in xx-xx-xx-xx-xx-xx or // xx:xx:xx:xx:xx:xx notation). // 3) Name of the adapter as displayed on your // Network and Dial-ip Connections window // (Windows 2000 only future implementation) // iFlags Flags for the new interface: // IFF_TAP - Create a TAP interface or // IFF_TUN - Create a TUN interface // IFF_NO_PI - Do not include packet information // // Output: // pfd Pointer to receive the file descriptor of the // TUN/TAP interface. // pszNetDevName Pointer to receive the name if the interface. // int TUNTAP_CreateInterface( char* pszTUNDevice, int iFlags, int* pfd, char* pszNetDevName ) { int fd; // File descriptor #if !defined( OPTION_W32_CTCI ) struct utsname utsbuf; if( uname( &utsbuf ) != 0 ) { logmsg( _("HHCTU001E Unable to determine operating system type: %s\n"), strerror( errno ) ); return -1; } #endif // Open TUN device fd = TUNTAP_Open( pszTUNDevice, O_RDWR ); if( fd < 0 ) { logmsg( _("HHCTU002E Error opening TUN/TAP device: %s: %s\n"), pszTUNDevice, strerror( errno ) ); return -1; } *pfd = fd; #if !defined( OPTION_W32_CTCI ) if ( strncasecmp( utsbuf.sysname, "linux", 5 ) == 0 ) #endif { // Linux kernel (builtin tun device) or Windows struct ifreq ifr; memset( &ifr, 0, sizeof( ifr ) ); ifr.ifr_flags = iFlags; if( TUNTAP_SetMode (fd, &ifr) < 0 ) { logmsg( _("HHCTU003E Error setting TUN/TAP mode: %s: %s\n"), pszTUNDevice, strerror( errno ) ); return -1; } strcpy( pszNetDevName, ifr.ifr_name ); } #if !defined( OPTION_W32_CTCI ) else { // Other OS: Simply use basename of the device // Notes: (JAP) This is problematic at best. Until we have a // clean FreeBSD compile from the base tree I can't // spend a lot of time on this... so it will remain. // My best guess is that this will cause other functions // to fail miserably but I have no way to test it. // This should work on OS X with Christoph Pfisterer's TUN driver, // since it does set the device name to the basename of the // file. -- JRM char *p = strrchr( pszTUNDevice, '/' ); if( p ) strncpy( pszNetDevName, ++p, IFNAMSIZ ); else { logmsg( _("HHCTU004E Invalid TUN/TAP device name: %s\n"), pszTUNDevice ); return -1; } } #endif return 0; } // // Redefine 'TUNTAP_IOCtl' for the remainder of the functions. // This forces all 'ioctl' calls to go to 'hercifc'. // #if !defined( OPTION_W32_CTCI ) #undef TUNTAP_IOCtl #define TUNTAP_IOCtl IFC_IOCtl #endif #ifdef OPTION_TUNTAP_CLRIPADDR // // TUNTAP_ClrIPAddr // int TUNTAP_ClrIPAddr( char* pszNetDevName ) { struct ifreq ifreq; memset( &ifreq, 0, sizeof( struct ifreq ) ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU005E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strcpy( ifreq.ifr_name, pszNetDevName ); return TUNTAP_IOCtl( 0, SIOCDIFADDR, (char*)&ifreq ); } #endif /* OPTION_TUNTAP_CLRIPADDR */ // // TUNTAP_SetIPAddr // int TUNTAP_SetIPAddr( char* pszNetDevName, char* pszIPAddr ) { struct ifreq ifreq; struct sockaddr_in* sin; memset( &ifreq, 0, sizeof( struct ifreq ) ); sin = (struct sockaddr_in*)&ifreq.ifr_addr; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU005E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strcpy( ifreq.ifr_name, pszNetDevName ); if( !pszIPAddr || !inet_aton( pszIPAddr, &sin->sin_addr ) ) { logmsg( _("HHCTU006E %s: Invalid IP address: %s.\n"), pszNetDevName, !pszIPAddr ? "NULL" : pszIPAddr ); return -1; } return TUNTAP_IOCtl( 0, SIOCSIFADDR, (char*)&ifreq ); } // // TUNTAP_SetDestAddr // int TUNTAP_SetDestAddr( char* pszNetDevName, char* pszDestAddr ) { struct ifreq ifreq; struct sockaddr_in* sin; memset( &ifreq, 0, sizeof( struct ifreq ) ); sin = (struct sockaddr_in*)&ifreq.ifr_addr; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU007E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strcpy( ifreq.ifr_name, pszNetDevName ); if( !pszDestAddr || !inet_aton( pszDestAddr, &sin->sin_addr ) ) { logmsg( _("HHCTU008E %s: Invalid destination address: %s.\n"), pszNetDevName, !pszDestAddr ? "NULL" : pszDestAddr ); return -1; } return TUNTAP_IOCtl( 0, SIOCSIFDSTADDR, (char*)&ifreq ); } // // TUNTAP_SetNetMask // #ifdef OPTION_TUNTAP_SETNETMASK int TUNTAP_SetNetMask( char* pszNetDevName, char* pszNetMask ) { struct ifreq ifreq; struct sockaddr_in* sin; memset( &ifreq, 0, sizeof( struct ifreq ) ); sin = (struct sockaddr_in*)&ifreq.ifr_netmask; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU009E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strcpy( ifreq.ifr_name, pszNetDevName ); if( !pszNetMask || !inet_aton( pszNetMask, &sin->sin_addr ) ) { logmsg( _("HHCTU010E %s: Invalid net mask: %s.\n"), pszNetDevName, !pszNetMask ? "NULL" : pszNetMask ); return -1; } return TUNTAP_IOCtl( 0, SIOCSIFNETMASK, (char*)&ifreq ); } #endif // OPTION_TUNTAP_SETNETMASK // // TUNTAP_SetMTU // int TUNTAP_SetMTU( char* pszNetDevName, char* pszMTU ) { struct ifreq ifreq; struct sockaddr_in* sin; int iMTU; memset( &ifreq, 0, sizeof( struct ifreq ) ); sin = (struct sockaddr_in*)&ifreq.ifr_addr; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU011E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strcpy( ifreq.ifr_name, pszNetDevName ); if( !pszMTU || !*pszMTU ) { logmsg( _("HHCTU012E %s: Invalid null or empty MTU.\n"), pszNetDevName ); return -1; } iMTU = atoi( pszMTU ); if( iMTU < 46 || iMTU > 65536 ) { logmsg( _("HHCTU013E %s: Invalid MTU: %s.\n"), pszNetDevName, pszMTU ); return -1; } ifreq.ifr_mtu = iMTU; return TUNTAP_IOCtl( 0, SIOCSIFMTU, (char*)&ifreq ); } // // TUNTAP_SetMACAddr // #ifdef OPTION_TUNTAP_SETMACADDR int TUNTAP_SetMACAddr( char* pszNetDevName, char* pszMACAddr ) { struct ifreq ifreq; struct sockaddr* addr; MAC mac; memset( &ifreq, 0, sizeof( struct ifreq ) ); addr = (struct sockaddr*)&ifreq.ifr_hwaddr; addr->sa_family = AF_UNIX; if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU014E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strcpy( ifreq.ifr_name, pszNetDevName ); if( !pszMACAddr || ParseMAC( pszMACAddr, mac ) != 0 ) { logmsg( _("HHCTU015E %s: Invalid MAC address: %s.\n"), pszNetDevName, !pszMACAddr ? "NULL" : pszMACAddr ); return -1; } memcpy( addr->sa_data, mac, IFHWADDRLEN ); return TUNTAP_IOCtl( 0, SIOCSIFHWADDR, (char*)&ifreq ); } #endif // OPTION_TUNTAP_SETMACADDR // // TUNTAP_SetFlags // int TUNTAP_SetFlags ( char* pszNetDevName, int iFlags ) { struct ifreq ifreq; struct sockaddr_in* sin; memset( &ifreq, 0, sizeof( struct ifreq ) ); sin = (struct sockaddr_in*)&ifreq.ifr_addr; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU016E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strlcpy( ifreq.ifr_name, pszNetDevName, sizeof(ifreq.ifr_name) ); ifreq.ifr_flags = iFlags; return TUNTAP_IOCtl( 0, SIOCSIFFLAGS, (char*)&ifreq ); } // // TUNTAP_GetFlags // int TUNTAP_GetFlags ( char* pszNetDevName, int* piFlags ) { struct ifreq ifreq; struct sockaddr_in* sin; int rc; memset( &ifreq, 0, sizeof( struct ifreq ) ); sin = (struct sockaddr_in*)&ifreq.ifr_addr; sin->sin_family = AF_INET; if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU016E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } strlcpy( ifreq.ifr_name, pszNetDevName, sizeof(ifreq.ifr_name) ); // PROGRAMMING NOTE: hercifc can't "get" information, // only "set" it. Thus because we normally use hercifc // to issue ioctl codes to the interface (on non-Win32) // we bypass hercifc altogether and issue the ioctl // ourselves directly to the device itself, bypassing // hercifc completely. Note that for Win32 however, // 'TUNTAP_IOCtl' routes to a TunTap32.DLL call and // thus works just fine. We need special handling // only for non-Win32 platforms. - Fish #if defined( OPTION_W32_CTCI ) rc = TUNTAP_IOCtl( 0, SIOCGIFFLAGS, (char*)&ifreq ); #else // (non-Win32 platforms) { int sockfd = socket( AF_INET, SOCK_DGRAM, 0 ); rc = ioctl( sockfd, SIOCGIFFLAGS, &ifreq ); } #endif *piFlags = ifreq.ifr_flags; return rc; } // // TUNTAP_AddRoute // #ifdef OPTION_TUNTAP_DELADD_ROUTES int TUNTAP_AddRoute( char* pszNetDevName, char* pszDestAddr, char* pszNetMask, char* pszGWAddr, int iFlags ) { struct rtentry rtentry; struct sockaddr_in* sin; memset( &rtentry, 0, sizeof( struct rtentry ) ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU017E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } rtentry.rt_dev = pszNetDevName; sin = (struct sockaddr_in*)&rtentry.rt_dst; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszDestAddr || !inet_aton( pszDestAddr, &sin->sin_addr ) ) { logmsg( _("HHCTU018E %s: Invalid destiniation address: %s.\n"), pszNetDevName, !pszDestAddr ? "NULL" : pszDestAddr ); return -1; } sin = (struct sockaddr_in*)&rtentry.rt_genmask; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszNetMask || !inet_aton( pszNetMask, &sin->sin_addr ) ) { logmsg( _("HHCTU019E %s: Invalid net mask: %s.\n"), pszNetDevName, !pszNetMask ? "NULL" : pszNetMask ); return -1; } sin = (struct sockaddr_in*)&rtentry.rt_gateway; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( pszGWAddr ) { if( !inet_aton( pszGWAddr, &sin->sin_addr ) ) { logmsg( _("HHCTU020E %s: Invalid gateway address: %s.\n"), pszNetDevName, pszGWAddr ); return -1; } } rtentry.rt_flags = iFlags; return TUNTAP_IOCtl( 0, SIOCADDRT, (char*)&rtentry ); } #endif // OPTION_TUNTAP_DELADD_ROUTES // // TUNTAP_DelRoute // #ifdef OPTION_TUNTAP_DELADD_ROUTES int TUNTAP_DelRoute( char* pszNetDevName, char* pszDestAddr, char* pszNetMask, char* pszGWAddr, int iFlags ) { struct rtentry rtentry; struct sockaddr_in* sin; memset( &rtentry, 0, sizeof( struct rtentry ) ); if( !pszNetDevName || !*pszNetDevName ) { logmsg( _("HHCTU021E Invalid net device name specified: %s\n"), pszNetDevName ? pszNetDevName : "(null pointer)" ); return -1; } rtentry.rt_dev = pszNetDevName; sin = (struct sockaddr_in*)&rtentry.rt_dst; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszDestAddr || !inet_aton( pszDestAddr, &sin->sin_addr ) ) { logmsg( _("HHCTU022E %s: Invalid destiniation address: %s.\n"), pszNetDevName, !pszDestAddr ? "NULL" : pszDestAddr ); return -1; } sin = (struct sockaddr_in*)&rtentry.rt_genmask; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( !pszNetMask || !inet_aton( pszNetMask, &sin->sin_addr ) ) { logmsg( _("HHCTU023E %s: Invalid net mask: %s.\n"), pszNetDevName, !pszNetMask ? "NULL" : pszNetMask ); return -1; } sin = (struct sockaddr_in*)&rtentry.rt_gateway; sin->sin_family = AF_INET; set_sockaddr_in_sin_len( sin ); if( pszGWAddr ) { if( !inet_aton( pszGWAddr, &sin->sin_addr ) ) { logmsg( _("HHCTU024E %s: Invalid gateway address: %s.\n"), pszNetDevName, pszGWAddr ); return -1; } } rtentry.rt_flags = iFlags; return TUNTAP_IOCtl( 0, SIOCDELRT, (char*)&rtentry ); } #endif // OPTION_TUNTAP_DELADD_ROUTES #if !defined( OPTION_W32_CTCI ) // ==================================================================== // HercIFC Helper Functions // ==================================================================== // // IFC_IOCtl // static int IFC_IOCtl( int fd, unsigned long int iRequest, char* argp ) { char* pszCfgCmd; // Interface config command int rc; CTLREQ ctlreq; char* request_name; // debugging: name of ioctl request #if defined(DEBUG) || defined(_DEBUG) char unknown_request[] = "Unknown (0x00000000)"; #endif UNREFERENCED( fd ); memset( &ctlreq, 0, CTLREQ_SIZE ); ctlreq.iCtlOp = iRequest; #if defined(DEBUG) || defined(_DEBUG) // Select string to represent ioctl request for debugging. switch (iRequest) { #ifdef OPTION_TUNTAP_CLRIPADDR case SIOCDIFADDR: request_name="SIOCDIFADDR"; break; #endif case SIOCSIFADDR: request_name="SIOCSIFADDR"; break; case SIOCSIFDSTADDR: request_name="SIOCSIFDSTADDR"; break; case SIOCSIFMTU: request_name="SIOCSIFMTU"; break; case SIOCSIFFLAGS: request_name="SIOCSIFFLAGS"; break; case SIOCGIFFLAGS: request_name="SIOCGIFFLAGS"; break; #ifdef OPTION_TUNTAP_SETNETMASK case SIOCSIFNETMASK: request_name="SIOCSIFNETMASK"; break; #endif #ifdef OPTION_TUNTAP_SETMACADDR case SIOCSIFHWADDR: request_name="SIOCSIFHWADDR"; break; #endif #ifdef OPTION_TUNTAP_DELADD_ROUTES case SIOCADDRT: request_name="SIOCADDRT"; break; case SIOCDELRT: request_name="SIOCDELRT"; break; #endif default: sprintf(unknown_request,"Unknown (0x%x)",iRequest); request_name=unknown_request; } #endif // defined(DEBUG) || defined(_DEBUG) #ifdef OPTION_TUNTAP_DELADD_ROUTES if( iRequest == SIOCADDRT || iRequest == SIOCDELRT ) { strcpy( ctlreq.szIFName, ((struct rtentry*)argp)->rt_dev ); memcpy( &ctlreq.iru.rtentry, argp, sizeof( struct rtentry ) ); ((struct rtentry*)argp)->rt_dev = NULL; } else #endif { memcpy( &ctlreq.iru.ifreq, argp, sizeof( struct ifreq ) ); } if( ifc_fd[0] == -1 && ifc_fd[1] == -1 ) { if( socketpair( AF_UNIX, SOCK_STREAM, 0, ifc_fd ) < 0 ) { logmsg( _("HHCTU025E Call to socketpair failed: %s\n"), strerror( errno ) ); return -1; } // Obtain the name of the interface config program or default if( !( pszCfgCmd = getenv( "HERCULES_IFC" ) ) ) pszCfgCmd = HERCIFC_CMD; TRACE(_("HHCTU029I Executing '%s' to configure interface\n"), pszCfgCmd); // Fork a process to execute the hercifc ifc_pid = fork(); if( ifc_pid < 0 ) { logmsg( _("HHCTU026E Call to fork failed: %s\n"), strerror( errno ) ); return -1; } // The child process executes the configuration command if( ifc_pid == 0 ) { /* @ISW@ Close all file descriptors * (except ifc_fd[1] and STDOUT FILENO) * (otherwise some devices are never closed) * (ex: SCSI tape devices can never be re-opened) */ struct rlimit rlim; int i; rlim_t file_limit; getrlimit(RLIMIT_NOFILE,&rlim); /* While Linux and Cygwin have limits of 1024 files by default, * Mac OS X does not - its default is -1, or completely unlimited. * The following hack is to defend against trying to close 2 * billion files. -- JRM */ file_limit=rlim.rlim_max; file_limit=(file_limit>1024)?1024:file_limit; TRACE(_("HHCTU031I Closing %" I64_FMT "d files\n"), (long long)file_limit); for(i=0;(unsigned int)isin_family = AF_INET; if(host) { struct hostent *hostent; hostent = gethostbyname(host); if(!hostent) { logmsg(_("HHCGI001I Unable to determine IP address from %s\n"), host); free(sin); return NULL; } memcpy(&sin->sin_addr,*hostent->h_addr_list,sizeof(sin->sin_addr)); } else sin->sin_addr.s_addr = INADDR_ANY; if(serv) { if(!isdigit(*serv)) { struct servent *servent; servent = getservbyname(serv, "tcp"); if(!servent) { logmsg(_("HHCGI002I Unable to determine port number from %s\n"), host); free(sin); return NULL; } sin->sin_port = servent->s_port; } else sin->sin_port = htons(atoi(serv)); } else { logmsg(_("HHCGI003E Invalid parameter: %s\n"), host_serv); free(sin); return NULL; } return sin; } #endif /*-------------------------------------------------------------------*/ /* SUBROUTINE TO REMOVE ANY IAC SEQUENCES FROM THE DATA STREAM */ /* Returns the new length after deleting IAC commands */ /*-------------------------------------------------------------------*/ static int remove_iac (BYTE *buf, int len) { int m, n, c; for (m=0, n=0; m < len; ) { /* Interpret IAC commands */ if (buf[m] == IAC) { /* Treat IAC in last byte of buffer as IAC NOP */ c = (++m < len)? buf[m++] : NOP; /* Process IAC command */ switch (c) { case IAC: /* Insert single IAC in buffer */ buf[n++] = IAC; break; case BRK: /* Set ATTN indicator */ break; case IP: /* Set SYSREQ indicator */ break; case WILL: /* Skip option negotiation command */ case WONT: case DO: case DONT: m++; break; case SB: /* Skip until IAC SE sequence found */ for (; m < len; m++) { if (buf[m] != IAC) continue; if (++m >= len) break; if (buf[m] == SE) { m++; break; } } /* end for */ default: /* Ignore NOP or unknown command */ break; } /* end switch(c) */ } else { /* Copy data bytes */ if (n < m) buf[n] = buf[m]; m++; n++; } } /* end for */ if (n < m) { TNSDEBUG3("console: DBG001: %d IAC bytes removed, newlen=%d\n", m-n, n); packet_trace (buf, n); } return n; } /* end function remove_iac */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO DOUBLE UP ANY IAC BYTES IN THE DATA STREAM */ /* Returns the new length after inserting extra IAC bytes */ /*-------------------------------------------------------------------*/ static int double_up_iac (BYTE *buf, int len) { int m, n, x, newlen; /* Count the number of IAC bytes in the data */ for (x=0, n=0; n < len; n++) if (buf[n] == IAC) x++; /* Exit if nothing to do */ if (x == 0) return len; /* Insert extra IAC bytes backwards from the end of the buffer */ newlen = len + x; TNSDEBUG3("console: DBG002: %d IAC bytes added, newlen=%d\n", x, newlen); for (n=newlen, m=len; n > m; ) { buf[--n] = buf[--m]; if (buf[n] == IAC) buf[--n] = IAC; } packet_trace (buf, newlen); return newlen; } /* end function double_up_iac */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO TRANSLATE A NULL-TERMINATED STRING TO EBCDIC */ /*-------------------------------------------------------------------*/ static BYTE * translate_to_ebcdic (char *str) { int i; /* Array subscript */ BYTE c; /* Character work area */ for (i = 0; str[i] != '\0'; i++) { c = str[i]; str[i] = (isprint(c) ? host_to_guest(c) : SPACE); } return (BYTE *)str; } /* end function translate_to_ebcdic */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO SEND A DATA PACKET TO THE CLIENT */ /*-------------------------------------------------------------------*/ static int send_packet (int csock, BYTE *buf, int len, char *caption) { int rc; /* Return code */ if (caption != NULL) { TNSDEBUG2("console: DBG003: Sending %s\n", caption); packet_trace (buf, len); } rc = send (csock, buf, len, 0); if (rc < 0) { TNSERROR("console: DBG021: send: %s\n", strerror(HSO_errno)); return -1; } /* end if(rc) */ return 0; } /* end function send_packet */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO RECEIVE A DATA PACKET FROM THE CLIENT */ /* This subroutine receives bytes from the client. It stops when */ /* the receive buffer is full, or when the last two bytes received */ /* consist of the IAC character followed by a specified delimiter. */ /* If zero bytes are received, this means the client has closed the */ /* connection, and this is treated as an error. */ /* Input: */ /* csock is the socket number */ /* buf points to area to receive data */ /* reqlen is the number of bytes requested */ /* delim is the delimiter character (0=no delimiter) */ /* Output: */ /* buf is updated with data received */ /* The return value is the number of bytes received, or */ /* -1 if an error occurred. */ /*-------------------------------------------------------------------*/ static int recv_packet (int csock, BYTE *buf, int reqlen, BYTE delim) { int rc=0; /* Return code */ int rcvlen=0; /* Length of data received */ while (rcvlen < reqlen) { rc = recv (csock, buf + rcvlen, reqlen - rcvlen, 0); if (rc < 0) { TNSERROR("console: DBG022: recv: %s\n", strerror(HSO_errno)); return -1; } if (rc == 0) { TNSDEBUG1("console: DBG004: Connection closed by client\n"); return -1; } rcvlen += rc; if (delim != '\0' && rcvlen >= 2 && buf[rcvlen-2] == IAC && buf[rcvlen-1] == delim) break; } TNSDEBUG2("console: DBG005: Packet received length=%d\n", rcvlen); packet_trace (buf, rcvlen); return rcvlen; } /* end function recv_packet */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO RECEIVE A PACKET AND COMPARE WITH EXPECTED VALUE */ /*-------------------------------------------------------------------*/ static int expect (int csock, BYTE *expected, int len, char *caption) { int rc; /* Return code */ BYTE buf[512]; /* Receive buffer */ #if 1 /* TCP/IP for MVS returns the server sequence rather then the client sequence during bin negotiation 19/06/00 Jan Jaeger */ static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY }; static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY }; #endif UNREFERENCED(caption); rc = recv_packet (csock, buf, len, 0); if (rc < 0) return -1; #if 1 /* TCP/IP FOR MVS DOES NOT COMPLY TO RFC 1576 THIS IS A BYPASS */ if(memcmp(buf, expected, len) != 0 && !(len == sizeof(will_bin) && memcmp(expected, will_bin, len) == 0 && memcmp(buf, do_bin, len) == 0) ) #else if (memcmp(buf, expected, len) != 0) #endif { TNSDEBUG2("console: DBG006: Expected %s\n", caption); return -1; } TNSDEBUG2("console: DBG007: Received %s\n", caption); return 0; } /* end function expect */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO NEGOTIATE TELNET PARAMETERS */ /* This subroutine negotiates the terminal type with the client */ /* and uses the terminal type to determine whether the client */ /* is to be supported as a 3270 display console or as a 1052/3215 */ /* printer-keyboard console. */ /* */ /* Valid display terminal types are "IBM-NNNN", "IBM-NNNN-M", and */ /* "IBM-NNNN-M-E", where NNNN is 3270, 3277, 3278, 3279, 3178, 3179, */ /* or 3180, M indicates the screen size (2=25x80, 3=32x80, 4=43x80, */ /* 5=27x132, X=determined by Read Partition Query command), and */ /* -E is an optional suffix indicating that the terminal supports */ /* extended attributes. Displays are negotiated into tn3270 mode. */ /* An optional device number suffix (example: IBM-3270@01F) may */ /* be specified to request allocation to a specific device number. */ /* Valid 3270 printer type is "IBM-3287-1" */ /* */ /* Terminal types whose first four characters are not "IBM-" are */ /* handled as printer-keyboard consoles using telnet line mode. */ /* */ /* Input: */ /* csock Socket number for client connection */ /* Output: */ /* class D=3270 display console, K=printer-keyboard console */ /* P=3270 printer */ /* model 3270 model indicator (2,3,4,5,X) */ /* extatr 3270 extended attributes (Y,N) */ /* devn Requested device number, or FFFF=any device number */ /* Return value: */ /* 0=negotiation successful, -1=negotiation error */ /*-------------------------------------------------------------------*/ static int negotiate(int csock, BYTE *class, BYTE *model, BYTE *extatr, U16 *devn,char *group) { int rc; /* Return code */ char *termtype; /* Pointer to terminal type */ char *s; /* String pointer */ BYTE c; /* Trailing character */ U16 devnum; /* Requested device number */ BYTE buf[512]; /* Telnet negotiation buffer */ static BYTE do_term[] = { IAC, DO, TERMINAL_TYPE }; static BYTE will_term[] = { IAC, WILL, TERMINAL_TYPE }; static BYTE req_type[] = { IAC, SB, TERMINAL_TYPE, SEND, IAC, SE }; static BYTE type_is[] = { IAC, SB, TERMINAL_TYPE, IS }; static BYTE do_eor[] = { IAC, DO, EOR, IAC, WILL, EOR }; static BYTE will_eor[] = { IAC, WILL, EOR, IAC, DO, EOR }; static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY }; static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY }; #if 0 static BYTE do_tmark[] = { IAC, DO, TIMING_MARK }; static BYTE will_tmark[] = { IAC, WILL, TIMING_MARK }; static BYTE wont_sga[] = { IAC, WONT, SUPPRESS_GA }; static BYTE dont_sga[] = { IAC, DONT, SUPPRESS_GA }; #endif static BYTE wont_echo[] = { IAC, WONT, ECHO_OPTION }; static BYTE dont_echo[] = { IAC, DONT, ECHO_OPTION }; static BYTE will_naws[] = { IAC, WILL, NAWS }; /* Perform terminal-type negotiation */ rc = send_packet (csock, do_term, sizeof(do_term), "IAC DO TERMINAL_TYPE"); if (rc < 0) return -1; rc = expect (csock, will_term, sizeof(will_term), "IAC WILL TERMINAL_TYPE"); if (rc < 0) return -1; /* Request terminal type */ rc = send_packet (csock, req_type, sizeof(req_type), "IAC SB TERMINAL_TYPE SEND IAC SE"); if (rc < 0) return -1; rc = recv_packet (csock, buf, sizeof(buf)-2, SE); if (rc < 0) return -1; /* Ignore Negotiate About Window Size */ if (rc >= (int)sizeof(will_naws) && memcmp (buf, will_naws, sizeof(will_naws)) == 0) { memmove(buf, &buf[sizeof(will_naws)], (rc - sizeof(will_naws))); rc -= sizeof(will_naws); } if (rc < (int)(sizeof(type_is) + 2) || memcmp(buf, type_is, sizeof(type_is)) != 0 || buf[rc-2] != IAC || buf[rc-1] != SE) { TNSDEBUG2("console: DBG008: Expected IAC SB TERMINAL_TYPE IS\n"); return -1; } buf[rc-2] = '\0'; termtype = (char *)(buf + sizeof(type_is)); TNSDEBUG2("console: DBG009: Received IAC SB TERMINAL_TYPE IS %s IAC SE\n", termtype); /* Check terminal type string for device name suffix */ s = strchr (termtype, '@'); if(s!=NULL) { if(strlen(s)<16) { strlcpy(group,&s[1],16); } } else { group[0]=0; } if (s != NULL && sscanf (s, "@%hx%c", &devnum,&c) == 1) { *devn = devnum; group[0]=0; } else { *devn = 0xFFFF; } /* Test for non-display terminal type */ if (memcmp(termtype, "IBM-", 4) != 0) { #if 0 /* Perform line mode negotiation */ rc = send_packet (csock, do_tmark, sizeof(do_tmark), "IAC DO TIMING_MARK"); if (rc < 0) return -1; rc = expect (csock, will_tmark, sizeof(will_tmark), "IAC WILL TIMING_MARK"); if (rc < 0) return 0; rc = send_packet (csock, wont_sga, sizeof(wont_sga), "IAC WONT SUPPRESS_GA"); if (rc < 0) return -1; rc = expect (csock, dont_sga, sizeof(dont_sga), "IAC DONT SUPPRESS_GA"); if (rc < 0) return -1; #endif if (memcmp(termtype, "ANSI", 4) == 0) { rc = send_packet (csock, wont_echo, sizeof(wont_echo), "IAC WONT ECHO"); if (rc < 0) return -1; rc = expect (csock, dont_echo, sizeof(dont_echo), "IAC DONT ECHO"); if (rc < 0) return -1; } /* Return printer-keyboard terminal class */ *class = 'K'; *model = '-'; *extatr = '-'; return 0; } /* Determine display terminal model */ if (memcmp(termtype+4,"DYNAMIC",7) == 0) { *model = 'X'; *extatr = 'Y'; } else { if (!(memcmp(termtype+4, "3277", 4) == 0 || memcmp(termtype+4, "3270", 4) == 0 || memcmp(termtype+4, "3178", 4) == 0 || memcmp(termtype+4, "3278", 4) == 0 || memcmp(termtype+4, "3179", 4) == 0 || memcmp(termtype+4, "3180", 4) == 0 || memcmp(termtype+4, "3287", 4) == 0 || memcmp(termtype+4, "3279", 4) == 0)) return -1; *model = '2'; *extatr = 'N'; if (termtype[8]=='-') { if (termtype[9] < '1' || termtype[9] > '5') return -1; *model = termtype[9]; if (memcmp(termtype+4, "328",3) == 0) *model = '2'; if (memcmp(termtype+10, "-E", 2) == 0) *extatr = 'Y'; } } /* Perform end-of-record negotiation */ rc = send_packet (csock, do_eor, sizeof(do_eor), "IAC DO EOR IAC WILL EOR"); if (rc < 0) return -1; rc = expect (csock, will_eor, sizeof(will_eor), "IAC WILL EOR IAC DO EOR"); if (rc < 0) return -1; /* Perform binary negotiation */ rc = send_packet (csock, do_bin, sizeof(do_bin), "IAC DO BINARY IAC WILL BINARY"); if (rc < 0) return -1; rc = expect (csock, will_bin, sizeof(will_bin), "IAC WILL BINARY IAC DO BINARY"); if (rc < 0) return -1; /* Return display terminal class */ if (memcmp(termtype+4,"3287",4)==0) *class='P'; else *class = 'D'; return 0; } /* end function negotiate */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO RECEIVE 3270 DATA FROM THE CLIENT */ /* This subroutine receives bytes from the client and appends them */ /* to any data already in the 3270 receive buffer. */ /* If zero bytes are received, this means the client has closed the */ /* connection, and attention and unit check status is returned. */ /* If the buffer is filled before receiving end of record, then */ /* attention and unit check status is returned. */ /* If the data ends with IAC followed by EOR_MARK, then the data */ /* is scanned to remove any IAC sequences, attention status is */ /* returned, and the read pending indicator is set. */ /* If the data accumulated in the buffer does not yet constitute a */ /* complete record, then zero status is returned, and a further */ /* call must be made to this subroutine when more data is available. */ /*-------------------------------------------------------------------*/ static BYTE recv_3270_data (DEVBLK *dev) { int rc; /* Return code */ int eor = 0; /* 1=End of record received */ /* If there is a complete data record already in the buffer then discard it before reading more data */ if (dev->readpending) { dev->rlen3270 = 0; dev->readpending = 0; } /* The following chunk of code was added to try and catch a race condition that may or may no longer still exist. */ TNSDEBUG1("console: DBG031: verifying data is available...\n"); { fd_set readset; struct timeval tv = {0,0}; /* (non-blocking poll) */ FD_ZERO( &readset ); FD_SET( dev->fd, &readset ); while ( (rc = select ( dev->fd+1, &readset, NULL, NULL, &tv )) < 0 && HSO_EINTR == HSO_errno ) ; /* NOP (keep retrying if EINTR) */ if (rc < 0) { TNSERROR("console: DBG032: select failed: %s\n", strerror(HSO_errno)); return 0; } ASSERT(rc <= 1); if (!FD_ISSET(dev->fd, &readset)) { ASSERT(rc == 0); TNSDEBUG1("console: DBG033: no data available; returning 0...\n"); return 0; } ASSERT(rc == 1); } TNSDEBUG1("console: DBG034: data IS available; attempting recv...\n"); /* Receive bytes from client */ rc = recv (dev->fd, dev->buf + dev->rlen3270, BUFLEN_3270 - dev->rlen3270, 0); if (rc < 0) { if ( HSO_ECONNRESET == HSO_errno ) logmsg( _( "HHCTE014I %4.4X device %4.4X client %s connection reset\n" ), dev->devtype, dev->devnum, inet_ntoa(dev->ipaddr) ); else TNSERROR("console: DBG023: recv: %s\n", strerror(HSO_errno)); dev->sense[0] = SENSE_EC; return (CSW_ATTN | CSW_UC); } /* If zero bytes were received then client has closed connection */ if (rc == 0) { logmsg (_("HHCTE007I %4.4X device %4.4X client %s connection closed\n"), dev->devtype, dev->devnum, inet_ntoa(dev->ipaddr)); dev->sense[0] = SENSE_IR; return (CSW_ATTN | CSW_UC | CSW_DE); } /* Update number of bytes in receive buffer */ dev->rlen3270 += rc; /* Check whether Attn indicator was received */ if (dev->rlen3270 >= 2 && dev->buf[dev->rlen3270 - 2] == IAC && dev->buf[dev->rlen3270 - 1] == BRK) eor = 1; /* Check whether SysRq indicator was received */ if (dev->rlen3270 >= 2 && dev->buf[dev->rlen3270 - 2] == IAC && dev->buf[dev->rlen3270 - 1] == IP) eor = 1; /* Check whether end of record marker was received */ if (dev->rlen3270 >= 2 && dev->buf[dev->rlen3270 - 2] == IAC && dev->buf[dev->rlen3270 - 1] == EOR_MARK) eor = 1; /* If record is incomplete, test for buffer full */ if (eor == 0 && dev->rlen3270 >= BUFLEN_3270) { TNSDEBUG1("console: DBG010: 3270 buffer overflow\n"); dev->sense[0] = SENSE_DC; return (CSW_ATTN | CSW_UC); } /* Return zero status if record is incomplete */ if (eor == 0) return 0; /* Trace the complete 3270 data packet */ TNSDEBUG2("console: DBG011: Packet received length=%d\n", dev->rlen3270); packet_trace (dev->buf, dev->rlen3270); /* Strip off the telnet EOR marker */ dev->rlen3270 -= 2; /* Remove any embedded IAC commands */ dev->rlen3270 = remove_iac (dev->buf, dev->rlen3270); /* Set the read pending indicator and return attention status */ dev->readpending = 1; return (CSW_ATTN); } /* end function recv_3270_data */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO SOLICIT 3270 DATA FROM THE CLIENT */ /* This subroutine sends a Read or Read Modified command to the */ /* client and then receives the data into the 3270 receive buffer. */ /* This subroutine is called by loc3270_execute_ccw as a result of */ /* processing a Read Buffer CCW, or a Read Modified CCW when no */ /* data is waiting in the 3270 read buffer. It waits until the */ /* client sends end of record. Certain tn3270 clients fail to */ /* flush their buffer until the user presses an attention key; */ /* these clients cause this routine to hang and are not supported. */ /* Since this routine is only called while a channel program is */ /* active on the device, we can rely on the dev->busy flag to */ /* prevent the connection thread from issuing a read and capturing */ /* the incoming data intended for this routine. */ /* The caller MUST hold the device lock. */ /* Returns zero status if successful, or unit check if error. */ /*-------------------------------------------------------------------*/ static BYTE solicit_3270_data (DEVBLK *dev, BYTE cmd) { int rc; /* Return code */ int len; /* Data length */ BYTE buf[32]; /* tn3270 write buffer */ /* Clear the inbound buffer of any unsolicited data accumulated by the connection thread */ dev->rlen3270 = 0; dev->readpending = 0; /* Construct a 3270 read command in the outbound buffer */ len = 0; buf[len++] = cmd; /* Append telnet EOR marker to outbound buffer */ buf[len++] = IAC; buf[len++] = EOR_MARK; /* Send the 3270 read command to the client */ rc = send_packet(dev->fd, buf, len, "3270 Read Command"); if (rc < 0) { dev->sense[0] = SENSE_DC; return (CSW_UC); } /* Receive response data from the client */ do { len = dev->rlen3270; rc = recv_3270_data (dev); TNSDEBUG2("console: DBG012: read buffer: %d bytes received\n", dev->rlen3270 - len); } while(rc == 0); /* Close the connection if an error occurred */ if (rc & CSW_UC) { dev->connected = 0; dev->fd = -1; dev->sense[0] = SENSE_DC; return (CSW_UC); } /* Return zero status to indicate response received */ return 0; } /* end function solicit_3270_data */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO RECEIVE 1052/3215 DATA FROM THE CLIENT */ /* This subroutine receives keyboard input characters from the */ /* client, and appends the characters to any data already in the */ /* keyboard buffer. */ /* If zero bytes are received, this means the client has closed the */ /* connection, and attention and unit check status is returned. */ /* If the buffer is filled before receiving end of record, then */ /* attention and unit check status is returned. */ /* If a break indication (control-C, IAC BRK, or IAC IP) is */ /* received, the attention and unit exception status is returned. */ /* When carriage return and line feed (CRLF) is received, then */ /* the CRLF is discarded, the data in the keyboard buffer is */ /* translated to EBCDIC, the read pending indicator is set, and */ /* attention status is returned. */ /* If CRLF has not yet been received, then zero status is returned, */ /* and a further call must be made to this subroutine when more */ /* data is available. */ /*-------------------------------------------------------------------*/ static BYTE recv_1052_data (DEVBLK *dev) { int num; /* Number of bytes received */ int i; /* Array subscript */ BYTE buf[BUFLEN_1052]; /* Receive buffer */ BYTE c; /* Character work area */ /* Receive bytes from client */ num = recv (dev->fd, buf, BUFLEN_1052, 0); /* Return unit check if error on receive */ if (num < 0) { TNSERROR("console: DBG024: recv: %s\n", strerror(HSO_errno)); dev->sense[0] = SENSE_EC; return (CSW_ATTN | CSW_UC); } /* If zero bytes were received then client has closed connection */ if (num == 0) { logmsg (_("HHCTE008I Device %4.4X connection closed by client %s\n"), dev->devnum, inet_ntoa(dev->ipaddr)); dev->sense[0] = SENSE_IR; return (CSW_ATTN | CSW_UC); } /* Trace the bytes received */ TNSDEBUG2("console: DBG013: Bytes received length=%d\n", num); packet_trace (buf, num); /* Copy received bytes to keyboard buffer */ for (i = 0; i < num; i++) { /* Decrement keyboard buffer pointer if backspace received */ if (buf[i] == 0x08) { if (dev->keybdrem > 0) dev->keybdrem--; continue; } /* Return unit exception if control-C received */ if (buf[i] == 0x03) { dev->keybdrem = 0; return (CSW_ATTN | CSW_UX); } /* Return unit check if buffer is full */ if (dev->keybdrem >= BUFLEN_1052) { TNSDEBUG1("console: DBG014: Console keyboard buffer overflow\n"); dev->keybdrem = 0; dev->sense[0] = SENSE_EC; return (CSW_ATTN | CSW_UC); } /* Copy character to keyboard buffer */ dev->buf[dev->keybdrem++] = buf[i]; /* Decrement keyboard buffer pointer if telnet erase character sequence received */ if (dev->keybdrem >= 2 && dev->buf[dev->keybdrem - 2] == IAC && dev->buf[dev->keybdrem - 1] == EC) { dev->keybdrem -= 2; if (dev->keybdrem > 0) dev->keybdrem--; continue; } /* Zeroize keyboard buffer pointer if telnet erase line sequence received */ if (dev->keybdrem >= 2 && dev->buf[dev->keybdrem - 2] == IAC && dev->buf[dev->keybdrem - 1] == EL) { dev->keybdrem = 0; continue; } /* Zeroize keyboard buffer pointer if telnet carriage return sequence received */ if (dev->keybdrem >= 2 && dev->buf[dev->keybdrem - 2] == '\r' && dev->buf[dev->keybdrem - 1] == '\0') { dev->keybdrem = 0; continue; } /* Return unit exception if telnet break sequence received */ if (dev->keybdrem >= 2 && dev->buf[dev->keybdrem - 2] == IAC && (dev->buf[dev->keybdrem - 1] == BRK || dev->buf[dev->keybdrem - 1] == IP)) { dev->keybdrem = 0; return (CSW_ATTN | CSW_UX); } /* Return unit check with overrun if telnet CRLF sequence received and more data follows the CRLF */ if (dev->keybdrem >= 2 && dev->buf[dev->keybdrem - 2] == '\r' && dev->buf[dev->keybdrem - 1] == '\n' && i < num - 1) { TNSDEBUG1("console: DBG015: Console keyboard buffer overrun\n"); dev->keybdrem = 0; dev->sense[0] = SENSE_OR; return (CSW_ATTN | CSW_UC); } } /* end for(i) */ /* Return zero status if CRLF was not yet received */ if (dev->keybdrem < 2 || dev->buf[dev->keybdrem - 2] != '\r' || dev->buf[dev->keybdrem - 1] != '\n') return 0; /* Trace the complete keyboard data packet */ TNSDEBUG2("console: DBG016: Packet received length=%d\n", dev->keybdrem); packet_trace (dev->buf, dev->keybdrem); /* Strip off the CRLF sequence */ dev->keybdrem -= 2; /* Translate the keyboard buffer to EBCDIC */ for (i = 0; i < dev->keybdrem; i++) { c = dev->buf[i]; dev->buf[i] = (isprint(c) ? host_to_guest(c) : SPACE); } /* end for(i) */ /* Trace the EBCDIC input data */ TNSDEBUG2("console: DBG017: Input data line length=%d\n", dev->keybdrem); packet_trace (dev->buf, dev->keybdrem); /* Return attention status */ return (CSW_ATTN); } /* end function recv_1052_data */ /* The following code and functions are here * to build a more fancy logo */ #define SF_ATTR_PROTECTED 0x20 #define SF_ATTR_NUMERIC 0x10 /* One of */ #define SF_ATTR_WDISPNSEL 0x00 #define SF_ATTR_WDISPSEL 0x04 #define SF_ATTR_HIGHLIGHT 0x08 #define SF_ATTR_INVISIBLE 0x0C #define SF_ATTR_MDT 0x01 /* static char *herclogo[]={ " HHH HHH The S/370, ESA/390 and z/Architecture", " HHH HHH Emulator", " HHH HHH", " HHH HHH EEEE RRR CCC U U L EEEE SSS", " HHHHHHHHHHHHHHHH E R R C U U L E S", " HHHHHHHHHHHHHHHH EEE RRR C U U L EEE SS", " HHHHHHHHHHHHHHHH E R R C U U L E S", " HHH HHH EEEE R R CCC UU LLLL EEEE SSS ", " HHH HHH", " HHH HHH", " HHH HHH My PC thinks it's a MAINFRAME", "", " Copyright (C) 1999-2010 Roger Bowler, Jan Jaeger, and others"}; */ static char *herclogo[]={ "@ALIGN NONE", "@SBA 0,0", "@SF P", "Hercules Version :", "@SF HP", "$(VERSION)", "@NL", "@SF P", "Host name :", "@SF HP", "$(HOSTNAME)", "@NL", "@SF P", "Host OS :", "@SF HP", "$(HOSTOS)-$(HOSTOSREL) $(HOSTOSVER)", "@NL", "@SF P", "Host Architecture :", "@SF HP", "$(HOSTARCH)", "@NL", "@SF P", "Processors :", "@SF HP", "$(HOSTNUMCPUS)", "@NL", "@SF P", "Chanl Subsys :", "@SF HP", "$(CSS)", "@NL", "@SF P", "Device number :", "@SF HP", "$(CCUU)", "@NL", "@SF P", "Subchannel :", "@SF HP", "$(SUBCHAN)", "@SF P", "@ALIGN LEFT", "", "", " HHH HHH The S/370, ESA/390 and z/Architecture", " HHH HHH Emulator", " HHH HHH", " HHH HHH EEEE RRR CCC U U L EEEE SSS", " HHHHHHHHHHHHHHHH E R R C U U L E S", " HHHHHHHHHHHHHHHH EEE RRR C U U L EEE SS", " HHHHHHHHHHHHHHHH E R R C U U L E S", " HHH HHH EEEE R R CCC UU LLLL EEEE SSS", " HHH HHH", " HHH HHH", " HHH HHH My PC thinks it's a MAINFRAME", "", " Copyright (C) 1999-2010 Roger Bowler, Jan Jaeger, and others"}; #define LOGO_BUFFERSIZE 256; static char *buffer_addchar(char *b,size_t *l,size_t *al,char c) { size_t len; size_t alen; len=*l; alen=*al; if(len>=alen) { if(!alen) { alen=LOGO_BUFFERSIZE; b=malloc(alen); if(!b) { return NULL; } } else { alen+=LOGO_BUFFERSIZE; b=realloc(b,alen); if(!b) { return NULL; } } } b[len++]=c; *al=alen; *l=len; return b; } static char *buffer_addstring(char *b,size_t *l,size_t *al,char *s) { size_t i; for(i=0;s[i]!=0;i++) { b=buffer_addchar(b,l,al,s[i]); if(!b) { return NULL; } } return b; } static char *buffer_addsba(char *b,size_t *l,size_t *al,int x, int y) { int pos; pos=x*80+y; b=buffer_addchar(b,l,al,0x11); if(!b) return NULL; b=buffer_addchar(b,l,al,sba_code[pos>>6]); if(!b) return NULL; b=buffer_addchar(b,l,al,sba_code[pos & 0x3f]); return b; } static char *buffer_addsf(char *b,size_t *l,size_t *al,int a) { b=buffer_addchar(b,l,al,0x1d); if(!b) return NULL; b=buffer_addchar(b,l,al,sba_code[a & 0x3f]); return b; } #define ALIGN_NONE 0 #define ALIGN_CENTER 1 #define ALIGN_LEFT 2 #define ALIGN_RIGHT 3 static char *build_logo(char **logodata,size_t logosize,size_t *blen) { size_t len; size_t alen; char *bfr; char *cline; size_t i,j; char *verb; char *rest; int xpos,ypos; int attr; int align; char *wrk; bfr=NULL; len=0; alen=0; bfr=buffer_addchar(bfr,&len,&alen,0xf5); bfr=buffer_addchar(bfr,&len,&alen,0x42); if(bfr==NULL) { *blen=0; return NULL; } align=ALIGN_NONE; xpos=0; ypos=0; attr=SF_ATTR_PROTECTED; for(i=0;i Device block */ size_t len; /* Data length */ int csock; /* Socket for conversation */ struct sockaddr_in client; /* Client address structure */ socklen_t namelen; /* Length of client structure*/ char *clientip; /* Addr of client ip address */ U16 devnum; /* Requested device number */ BYTE class; /* D=3270, P=3287, K=3215/1052 */ BYTE model; /* 3270 model (2,3,4,5,X) */ BYTE extended; /* Extended attributes (Y,N) */ char buf[1920]; /* Message buffer */ char conmsg[256]; /* Connection message */ char devmsg[64]; /* Device message */ char hostmsg[256]; /* Host ID message */ char num_procs[16]; /* #of processors string */ char rejmsg[256]; /* Rejection message */ char group[16]; /* Console group */ size_t logoheight; char *logobfr; char *logoout; logobfr=NULL; /* Load the socket address from the thread parameter */ csock = *csockp; /* Obtain the client's IP address */ namelen = sizeof(client); rc = getpeername (csock, (struct sockaddr *)&client, &namelen); /* Log the client's IP address and hostname */ clientip = strdup(inet_ntoa(client.sin_addr)); #if 0 // The following isn't really needed and hangs under unusual // network configuration settings and thus has been removed. { struct hostent* pHE; /* Addr of hostent structure */ char* clientname; /* Addr of client hostname */ pHE = gethostbyaddr ((unsigned char*)(&client.sin_addr), sizeof(client.sin_addr), AF_INET); if (pHE != NULL && pHE->h_name != NULL && pHE->h_name[0] != '\0') { clientname = (char*) pHE->h_name; } else { clientname = "host name unknown"; } TNSDEBUG1("console: DBG018: Received connection from %s (%s)\n", clientip, clientname); } #else TNSDEBUG1("console: DBG018: Received connection from %s\n", clientip ); #endif /* Negotiate telnet parameters */ rc = negotiate (csock, &class, &model, &extended, &devnum, group); if (rc != 0) { close_socket (csock); if (clientip) free(clientip); return NULL; } /* Look for an available console device */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { /* Loop if the device is invalid */ if ( !dev->allocated ) continue; /* Loop if non-matching device type */ if (class == 'D' && dev->devtype != 0x3270) continue; if (class == 'P' && dev->devtype != 0x3287) continue; if (class == 'K' && dev->devtype != 0x1052 && dev->devtype != 0x3215) continue; /* Loop if a specific device number was requested and this device is not the requested device number */ if (devnum != 0xFFFF && dev->devnum != devnum) continue; /* Loop if no specific device number was requested, and either a group was requested OR the device is in a group, and the device group does not match the requested group */ if (devnum==0xFFFF && (group[0] || dev->filename[0])) { if (strncasecmp(group,dev->filename,16)!=0) { continue; } } /* Obtain the device lock */ obtain_lock (&dev->lock); /* Test for available device */ if (dev->connected == 0) { /* Check ipaddr mask to see if client allowed on this device */ if ( (client.sin_addr.s_addr & dev->acc_ipmask) != dev->acc_ipaddr ) { release_lock (&dev->lock); if ( 0xFFFF == devnum ) /* If they did NOT request a spe- */ continue; /* cifc devnum, then keep looking */ dev = NULL; /* Otherwise they did, */ break; /* but it's not available */ } /* Claim this device for the client */ dev->connected = 1; dev->fd = csock; dev->ipaddr = client.sin_addr; dev->mod3270 = model; dev->eab3270 = (extended == 'Y' ? 1 : 0); /* Reset the console device */ dev->readpending = 0; dev->rlen3270 = 0; dev->keybdrem = 0; memset (&dev->scsw, 0, sizeof(SCSW)); memset (&dev->pciscsw, 0, sizeof(SCSW)); dev->busy = dev->reserved = dev->suspended = dev->pending = dev->pcipending = dev->attnpending = 0; release_lock (&dev->lock); break; } /* Release the device lock */ release_lock (&dev->lock); } /* end for(dev) */ /* Build connection message for client */ if ( cons_hostinfo.num_procs > 1 ) snprintf( num_procs, sizeof(num_procs), "MP=%d", cons_hostinfo.num_procs ); else strlcpy( num_procs, "UP", sizeof(num_procs) ); snprintf ( hostmsg, sizeof(hostmsg), "running on %s (%s-%s.%s %s %s)" ,cons_hostinfo.nodename ,cons_hostinfo.sysname ,cons_hostinfo.release ,cons_hostinfo.version ,cons_hostinfo.machine ,num_procs ); snprintf (conmsg, sizeof(conmsg), "Hercules version %s built on %s %s", VERSION, __DATE__, __TIME__); /* Reject the connection if no available console device */ if (dev == NULL) { /* Build the rejection message */ if (devnum == 0xFFFF) { if(!group[0]) { snprintf (rejmsg, sizeof(rejmsg), "Connection rejected, no available %s device", (class=='D' ? "3270" : (class=='P' ? "3287" : "1052 or 3215"))); } else { snprintf (rejmsg, sizeof(rejmsg), "Connection rejected, no available %s devices in the %s group", (class=='D' ? "3270" : (class=='P' ? "3287" : "1052 or 3215")),group); } } else { snprintf (rejmsg, sizeof(rejmsg), "Connection rejected, device %4.4X unavailable", devnum); } TNSDEBUG1( "DBG019: %s\n", rejmsg); /* Send connection rejection message to client */ if (class != 'K') { len = snprintf (buf, sizeof(buf), "\xF5\x40\x11\x40\x40\x1D\x60%s" "\x11\xC1\x50\x1D\x60%s" "\x11\xC2\x60\x1D\x60%s", translate_to_ebcdic(conmsg), translate_to_ebcdic(hostmsg), translate_to_ebcdic(rejmsg)); if (len < sizeof(buf)) { buf[len++] = IAC; } else { ASSERT(FALSE); } if (len < sizeof(buf)) { buf[len++] = EOR_MARK; } else { ASSERT(FALSE); } } else { len = snprintf (buf, sizeof(buf), "%s\r\n%s\r\n%s\r\n", conmsg, hostmsg, rejmsg); } if (class != 'P') /* do not write connection resp on 3287 */ { rc = send_packet (csock, (BYTE *)buf, len, "CONNECTION RESPONSE"); } /* Close the connection and terminate the thread */ SLEEP (5); close_socket (csock); if (clientip) free(clientip); return NULL; } else { snprintf (devmsg, sizeof(devmsg), "Connected to device %d:%4.4X", SSID_TO_LCSS(dev->ssid), dev->devnum); } logmsg (_("HHCTE009I Client %s connected to %4.4X device %d:%4.4X\n"), clientip, dev->devtype, SSID_TO_LCSS(dev->ssid), dev->devnum); /* Send connection message to client */ if (class != 'K') { #if defined(OPTION_CONFIG_SYMBOLS) set_symbol("VERSION",VERSION); set_symbol("BDATE",__DATE__); set_symbol("BTIME",__TIME__); set_symbol("HOSTNAME",cons_hostinfo.nodename); set_symbol("HOSTOS",cons_hostinfo.sysname); set_symbol("HOSTOSREL",cons_hostinfo.release); set_symbol("HOSTOSVER",cons_hostinfo.version); set_symbol("HOSTARCH",cons_hostinfo.machine); set_symbol("HOSTNUMCPUS",num_procs); set_symbol("LPARNAME",str_lparname()); snprintf(conmsg,sizeof(conmsg),"%3.3X",dev->devnum); set_symbol("CUU",conmsg); snprintf(conmsg,sizeof(conmsg),"%3.3x",dev->devnum); set_symbol("cuu",conmsg); snprintf(conmsg,sizeof(conmsg),"%4.4X",dev->devnum); #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) if (dev == sysblk.sysgdev) strncpy(conmsg,"SYSG",sizeof(conmsg)); #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ set_symbol("CCUU",conmsg); snprintf(conmsg,sizeof(conmsg),"%4.4x",dev->devnum); set_symbol("ccuu",conmsg); snprintf(conmsg,sizeof(conmsg),"%d",SSID_TO_LCSS(dev->ssid)); set_symbol("CSS",conmsg); snprintf(conmsg,sizeof(conmsg),"%4.4X",dev->subchan); set_symbol("SUBCHAN",conmsg); #endif // defined(OPTION_CONFIG_SYMBOLS) if(sysblk.herclogo!=NULL) { logobfr=build_logo(sysblk.herclogo,sysblk.logolines,&len); } else { logoheight=sizeof(herclogo)/sizeof(char *); logobfr=build_logo(herclogo,logoheight,&len); } logoout=logobfr; } else { len = snprintf (buf, sizeof(buf), "%s\r\n%s\r\n%s\r\n", conmsg, hostmsg, devmsg); logoout=buf; } if (class != 'P') /* do not write connection resp on 3287 */ { rc = send_packet (csock, (BYTE *)logoout, len, "CONNECTION RESPONSE"); } if(logobfr) { free(logobfr); } /* Raise attention interrupt for the device, IF... (1) this is NOT a 3287 printer device, -AND- (2) this is NOT the System-370 mode initial power-on state and it is not the SYSG console */ if (class != 'P' #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) && dev != sysblk.sysgdev #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ && !INITIAL_POWERON_370()) device_attention (dev, CSW_DE); /* Try to detect dropped connections */ socket_keepalive( csock, sysblk.kaidle, sysblk.kaintv, sysblk.kacnt ); /* Signal connection thread to redrive its select loop */ SIGNAL_CONSOLE_THREAD(); if (clientip) free(clientip); return NULL; } /* end function connect_client */ /*-------------------------------------------------------------------*/ /* CONSOLE CONNECTION AND ATTENTION HANDLER THREAD */ /*-------------------------------------------------------------------*/ static int console_cnslcnt = 0; /* count of connected terms */ static LOCK console_lock; /* console_cnslcnt lock */ static int did_init = 0; /* console_lock initialized */ static void console_shutdown(void * unused) { UNREFERENCED(unused); obtain_lock( &console_lock ); { console_cnslcnt = 0; SIGNAL_CONSOLE_THREAD(); } release_lock( &console_lock ); } static void * console_connection_handler (void *arg) { int rc = 0; /* Return code */ int lsock; /* Socket for listening */ int csock; /* Socket for conversation */ struct sockaddr_in *server; /* Server address structure */ fd_set readset; /* Read bit map for select */ int maxfd; /* Highest fd for select */ int optval; /* Argument for setsockopt */ TID tidneg; /* Negotiation thread id */ DEVBLK *dev; /* -> Device block */ BYTE unitstat; /* Status after receive data */ UNREFERENCED(arg); hdl_adsc("console_shutdown",console_shutdown, NULL); /* Display thread started message on control panel */ logmsg (_("HHCTE001I Console connection thread started: " "tid="TIDPAT", pid=%d\n"), thread_id(), getpid()); /* Get information about this system */ init_hostinfo( &cons_hostinfo ); /* Obtain a socket */ lsock = socket (AF_INET, SOCK_STREAM, 0); if (lsock < 0) { TNSERROR("console: DBG025: socket: %s\n", strerror(HSO_errno)); return NULL; } /* Allow previous instance of socket to be reused */ optval = 1; setsockopt (lsock, SOL_SOCKET, SO_REUSEADDR, (GETSET_SOCKOPT_T*)&optval, sizeof(optval)); /* Prepare the sockaddr structure for the bind */ if(!( server = get_inet_socket(config_cnslport) )) { logmsg(_("HHCTE010E CNSLPORT statement invalid: %s\n"), config_cnslport); return NULL; } /* Attempt to bind the socket to the port */ do { rc = bind (lsock, (struct sockaddr *)server, sizeof(struct sockaddr_in)); if (rc == 0 || HSO_errno != HSO_EADDRINUSE) break; logmsg (_("HHCTE002W Waiting for port %u to become free\n"), ntohs(server->sin_port)); SLEEP(10); } while (console_cnslcnt); if (rc != 0) { TNSERROR("console: DBG026: bind: %s\n", strerror(HSO_errno)); return NULL; } /* Put the socket into listening state */ if ((rc = listen (lsock, 10)) < 0) { TNSERROR("console: DBG027: listen: %s\n", strerror(HSO_errno)); return NULL; } logmsg (_("HHCTE003I Waiting for console connection on port %u\n"), ntohs(server->sin_port)); /* Handle connection requests and attention interrupts */ for (;;) { /* Check if time to exit */ int time_to_exit; obtain_lock( &console_lock ); time_to_exit = console_cnslcnt <= 0 ? 1 : 0; release_lock( &console_lock ); if (time_to_exit) break; /* Initialize the select parameters */ FD_ZERO ( &readset ); maxfd=INT_MIN; FD_SET ( lsock, &readset ); maxfd = lsock; SUPPORT_WAKEUP_CONSOLE_SELECT_VIA_PIPE( maxfd, &readset ); /* Include the socket for each valid connected console */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { if ( !dev->allocated) continue; obtain_lock( &dev->lock ); { if ( dev->console ) { if ( dev->connected ) { /* VERIFY that the file descriptor is valid. If it's NOT, then IGNORE this console device since it's thus obvious that SOMETHING has gone wrong SOMEWHERE at some point! (some sort of race condition SOMEWHERE, obviously) */ if (dev->fd < 0) { // Ah-HA! We may have FINALLY found (or at // least have gotten a little bit closer to // finding) the ROOT CAUSE of our problematic // "DBG028 select: Bad FIle Number" problem! logmsg ( "\n" "*********** DBG028 CONSOLE BUG ***********\n" "device %4.4X: 'connected', but dev->fd = -1\n" "\n" ,dev->devnum ); dev->connected = 0; // (since it's not connected!) } else { /* Add it to our read set only if it's not busy nor interrupt pending */ if (1 && (!dev->busy || (dev->scsw.flag3 & SCSW3_AC_SUSP)) && !IOPENDING(dev) && !(dev->scsw.flag3 & SCSW3_SC_PEND) ) { FD_SET (dev->fd, &readset); if (dev->fd > maxfd) maxfd = dev->fd; } } } else // ( !dev->connected ) { if ( dev->fd >= 0 ) { close_socket ( dev->fd ); dev->fd = -1; } } /* if (dev->connected) */ } /* if (dev->console) */ } release_lock( &dev->lock ); } /* end for(dev) */ /* Wait for a file descriptor to become ready */ rc = select ( maxfd+1, &readset, NULL, NULL, NULL ); /* Clear the pipe signal if necessary */ RECV_CONSOLE_THREAD_PIPE_SIGNAL(); /* Log select errors */ if (rc < 0 ) { int select_errno = HSO_errno; // (preserve orig errno) static int issue_errmsg = 1; // (prevents msgs flood) if (EBADF == select_errno) { // Don't issue message more frequently // than once every second or so, just in // case the condition that's causing it // keeps reoccurring over and over... static struct timeval prev = {0,0}; struct timeval curr; struct timeval diff; gettimeofday( &curr, NULL ); timeval_subtract( &prev, &curr, &diff ); // Has it been longer than one second // since we last issued this message? if (diff.tv_sec >= 1) { issue_errmsg = 1; prev.tv_sec = curr.tv_sec; prev.tv_usec = curr.tv_usec; } else issue_errmsg = 0; // (prevents msgs flood) } else issue_errmsg = 1; if ( issue_errmsg && EINTR != select_errno ) { TNSERROR("console: DBG028: select: %s\n", strerror(select_errno)); usleep(50000); // (wait a bit; maybe it'll fix itself??) } continue; } /* If a client connection request has arrived then accept it */ if (FD_ISSET(lsock, &readset)) { /* Accept a connection and create conversation socket */ csock = accept (lsock, NULL, NULL); if (csock < 0) { TNSERROR("console: DBG029: accept: %s\n", strerror(HSO_errno)); continue; } /* Create a thread to complete the client connection */ if ( create_thread (&tidneg, DETACHED, connect_client, &csock, "connect_client") ) { TNSERROR("console: DBG030: connect_client create_thread: %s\n", strerror(errno)); close_socket (csock); } } /* end if(FD_ISSET(lsock, &readset)) */ /* Check if any connected client has data ready to send */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { /* Obtain the device lock */ obtain_lock (&dev->lock); /* Test for valid connected console with data available */ if (1 && dev->allocated && dev->console && dev->connected && (!dev->busy || (dev->scsw.flag3 & SCSW3_AC_SUSP)) && !( IOPENDING(dev) || (dev->scsw.flag3 & SCSW3_SC_PEND) ) && FD_ISSET (dev->fd, &readset) ) { /* Receive console input data from the client */ if ((dev->devtype == 0x3270) || (dev->devtype == 0x3287)) unitstat = recv_3270_data (dev); else unitstat = recv_1052_data (dev); /* Nothing more to do if incomplete record received */ if (unitstat == 0) { release_lock (&dev->lock); continue; } /* Close the connection if an error occurred */ if (unitstat & CSW_UC) { close_socket (dev->fd); dev->fd = -1; dev->connected = 0; } /* Indicate that data is available at the device */ if(dev->rlen3270) dev->readpending = 1; /* Release the device lock */ release_lock (&dev->lock); /* Raise attention interrupt for the device */ /* Do NOT raise attention interrupt for 3287 */ /* Otherwise zVM loops after ENABLE ccuu */ /* Following 5 lines are repeated on Hercules console: */ /* console: sending 3270 data */ /* +0000 F5C2FFEF */ /* console: Packet received length=7 */ /* +0000 016CD902 00FFEF */ /* I do not know what is this */ /* console: CCUU attention requests raised */ /* Do not raise attention interrupt for the SYSG console */ /* Do NOT raise attention interrupt if this is */ /* the System-370 mode initial power-on state */ if (1 && dev->connected && dev->devtype != 0x3287 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) && dev != sysblk.sysgdev #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ && !INITIAL_POWERON_370() ) { rc = device_attention (dev, unitstat); /* Trace the attention request */ TNSDEBUG2("console: DBG020: " "%4.4X attention request %s; rc=%d\n", dev->devnum, (rc == 0 ? "raised" : "rejected"), rc); } #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) /* For the SYSG console, generate an external interrupt */ if (dev == sysblk.sysgdev && dev->connected) { sclp_sysg_attention(); } #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ continue; /* (note: dev->lock already released) */ } /* end if(data available) */ /* Release the device lock */ release_lock (&dev->lock); } /* end for(dev) */ } /* end for */ /* Close all connected terminals */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { /* Obtain the device lock */ obtain_lock (&dev->lock); /* Test for connected console with data available */ if (dev->console && dev->fd>=0) { close_socket(dev->fd); dev->connected=0; dev->fd=-1; } release_lock (&dev->lock); } /* Close the listening socket */ close_socket (lsock); free(server); logmsg (_("HHCTE004I Console connection thread terminated\n")); sysblk.cnsltid = 0; return NULL; } /* end function console_connection_handler */ static int console_initialise() { int rc = 0; if (!did_init) { did_init = 1; initialize_lock( &console_lock ); } obtain_lock( &console_lock ); { console_cnslcnt++; if (!sysblk.cnsltid) { if ( create_thread (&sysblk.cnsltid, DETACHED, console_connection_handler, NULL, "console_connection_handler") ) { logmsg (_("HHCTE005E Cannot create console thread: %s\n"), strerror(errno)); rc = 1; } } } release_lock( &console_lock ); return rc; } static void console_remove(DEVBLK *dev) { obtain_lock( &console_lock ); { dev->connected = 0; dev->console = 0; dev->fd = -1; if (console_cnslcnt <= 0) logmsg(_("** BUG! console_remove() error! **\n")); else console_cnslcnt--; SIGNAL_CONSOLE_THREAD(); } release_lock( &console_lock ); } /*-------------------------------------------------------------------*/ /* INITIALIZE THE 3270 DEVICE HANDLER */ /*-------------------------------------------------------------------*/ static int loc3270_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { int ac = 0; /* Indicate that this is a console device */ dev->console = 1; /* Reset device dependent flags */ dev->connected = 0; /* Set number of sense bytes */ dev->numsense = 1; /* Set the size of the device buffer */ dev->bufsize = BUFLEN_3270; if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x3270; #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) /* Extra initialisation for the SYSG console */ if (strcasecmp(dev->typname,"SYSG") == 0) { dev->pmcw.flag5 &= ~PMCW5_V; // Not a regular device if (sysblk.sysgdev != NULL) { logmsg(_("HHCTE017E Device %4.4X: Duplicate SYSG console definition\n"), dev->devnum); return -1; } } #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ /* Initialize the device identifier bytes */ dev->devid[0] = 0xFF; dev->devid[1] = 0x32; /* Control unit type is 3274-1D */ dev->devid[2] = 0x74; dev->devid[3] = 0x1D; dev->devid[4] = 0x32; /* Device type is 3278-2 */ if ((dev->devtype & 0xFF)==0x70) { dev->devid[5] = 0x78; dev->devid[6] = 0x02; } else { dev->devid[5] = dev->devtype & 0xFF; /* device type is 3287-1 */ dev->devid[6] = 0x01; } dev->numdevid = 7; dev->filename[0] = 0; dev->acc_ipaddr = 0; dev->acc_ipmask = 0; if (argc > 0) // group name? { if ('*' == argv[ac][0] && '\0' == argv[ac][1]) ; // NOP (not really a group name; an '*' is // simply used as an argument place holder) else strlcpy(dev->filename,argv[ac],sizeof(dev->filename)); argc--; ac++; if (argc > 0) // ip address? { if ((dev->acc_ipaddr = inet_addr(argv[ac])) == (in_addr_t)(-1)) { logmsg(_("HHCTE011E Device %4.4X: Invalid IP address: %s\n"), dev->devnum, argv[ac]); return -1; } else { argc--; ac++; if (argc > 0) // ip addr mask? { if ((dev->acc_ipmask = inet_addr(argv[ac])) == (in_addr_t)(-1)) { logmsg(_("HHCTE012E Device %4.4X: Invalid mask value: %s\n"), dev->devnum, argv[ac]); return -1; } else { argc--; ac++; if (argc > 0) // too many args? { logmsg(_("HHCTE013E Device %4.4X: Extraneous argument(s): %s...\n"), dev->devnum, argv[ac] ); return -1; } } } else dev->acc_ipmask = (in_addr_t)(-1); } } } #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) /* Extra initialisation for the SYSG console */ if (strcasecmp(dev->typname,"SYSG") == 0) { /* Save the address of the SYSG console devblk */ sysblk.sysgdev = dev; } #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ return console_initialise(); } /* end function loc3270_init_handler */ /*-------------------------------------------------------------------*/ /* QUERY THE 3270 DEVICE DEFINITION */ /*-------------------------------------------------------------------*/ static void loc3270_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "DSP", dev, class, buflen, buffer ); if (dev->connected) { snprintf (buffer, buflen, "%s", inet_ntoa(dev->ipaddr)); } else { char acc[48]; if (dev->acc_ipaddr || dev->acc_ipmask) { char ip [16]; char mask [16]; struct in_addr xxxx; xxxx.s_addr = dev->acc_ipaddr; snprintf( ip, sizeof( ip ), "%s", inet_ntoa( xxxx )); xxxx.s_addr = dev->acc_ipmask; snprintf( mask, sizeof( mask ), "%s", inet_ntoa( xxxx )); snprintf( acc, sizeof( acc ), "%s mask %s", ip, mask ); } else acc[0] = 0; if (dev->filename[0]) { snprintf(buffer, buflen, "GROUP=%s%s%s", dev->filename, acc[0] ? " " : "", acc); } else { if (acc[0]) { snprintf(buffer, buflen, "* %s", acc); } else buffer[0] = 0; } } } /* end function loc3270_query_device */ /*-------------------------------------------------------------------*/ /* CLOSE THE 3270 DEVICE HANDLER */ /*-------------------------------------------------------------------*/ static int loc3270_close_device ( DEVBLK *dev ) { #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) /* Clear the pointer to the SYSG console */ if (dev == sysblk.sysgdev) { sysblk.sysgdev = NULL; } #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ console_remove(dev); return 0; } /* end function loc3270_close_device */ /*-------------------------------------------------------------------*/ /* 3270 Hercules Suspend/Resume text units */ /*-------------------------------------------------------------------*/ #define SR_DEV_3270_BUF ( SR_DEV_3270 | 0x001 ) #define SR_DEV_3270_EWA ( SR_DEV_3270 | 0x002 ) #define SR_DEV_3270_POS ( SR_DEV_3270 | 0x003 ) /*-------------------------------------------------------------------*/ /* 3270 Hercules Suspend Routine */ /*-------------------------------------------------------------------*/ static int loc3270_hsuspend(DEVBLK *dev, void *file) { size_t rc, len; BYTE buf[BUFLEN_3270]; if (!dev->connected) return 0; SR_WRITE_VALUE(file, SR_DEV_3270_POS, dev->pos3270, sizeof(dev->pos3270)); SR_WRITE_VALUE(file, SR_DEV_3270_EWA, dev->ewa3270, 1); obtain_lock(&dev->lock); rc = solicit_3270_data (dev, R3270_RB); if (rc == 0 && dev->rlen3270 > 0 && dev->rlen3270 <= BUFLEN_3270) { len = dev->rlen3270; memcpy (buf, dev->buf, len); } else len = 0; release_lock(&dev->lock); if (len) SR_WRITE_BUF(file, SR_DEV_3270_BUF, buf, len); return 0; } /*-------------------------------------------------------------------*/ /* 3270 Hercules Resume Routine */ /*-------------------------------------------------------------------*/ static int loc3270_hresume(DEVBLK *dev, void *file) { size_t rc, key, len, rbuflen = 0, pos = 0; BYTE *rbuf = NULL, buf[BUFLEN_3270]; do { SR_READ_HDR(file, key, len); switch (key) { case SR_DEV_3270_POS: SR_READ_VALUE(file, len, &pos, sizeof(pos)); break; case SR_DEV_3270_EWA: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ewa3270 = rc; break; case SR_DEV_3270_BUF: rbuflen = len; rbuf = malloc(len); if (rbuf == NULL) { logmsg(_("HHCTE090E %4.4X malloc() failed for resume buf: %s\n"), dev->devnum, strerror(errno)); return 0; } SR_READ_BUF(file, rbuf, rbuflen); break; default: SR_READ_SKIP(file, len); break; } /* switch (key) */ } while ((key & SR_DEV_MASK) == SR_DEV_3270); /* Dequeue any I/O interrupts for this device */ DEQUEUE_IO_INTERRUPT(&dev->ioint); DEQUEUE_IO_INTERRUPT(&dev->pciioint); DEQUEUE_IO_INTERRUPT(&dev->attnioint); /* Restore the 3270 screen image if connected and buf was provided */ if (dev->connected && rbuf && rbuflen > 3) { obtain_lock(&dev->lock); /* Construct buffer to send to the 3270 */ len = 0; buf[len++] = dev->ewa3270 ? R3270_EWA : R3270_EW; buf[len++] = 0xC2; memcpy (&buf[len], &rbuf[3], rbuflen - 3); len += rbuflen - 3; buf[len++] = O3270_SBA; buf[len++] = rbuf[1]; buf[len++] = rbuf[2]; buf[len++] = O3270_IC; /* Double up any IAC's in the data */ len = double_up_iac (buf, len); /* Append telnet EOR marker */ buf[len++] = IAC; buf[len++] = EOR_MARK; /* Restore the 3270 screen */ rc = send_packet(dev->fd, buf, len, "3270 data"); dev->pos3270 = pos; release_lock(&dev->lock); } if (rbuf) free(rbuf); return 0; } /*-------------------------------------------------------------------*/ /* INITIALIZE THE 1052/3215 DEVICE HANDLER */ /*-------------------------------------------------------------------*/ static int constty_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { int ac=0; /* Indicate that this is a console device */ dev->console = 1; /* Set number of sense bytes */ dev->numsense = 1; /* Initialize device dependent fields */ dev->keybdrem = 0; /* Set length of print buffer */ dev->bufsize = BUFLEN_1052; /* Assume we want to prompt */ dev->prompt1052 = 1; /* Is there an argument? */ if (argc > 0) { /* Look at the argument and set noprompt flag if specified. */ if (strcasecmp(argv[ac], "noprompt") == 0) { dev->prompt1052 = 0; ac++; argc--; } // (else it's a group name...) } if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x1052; /* Initialize the device identifier bytes */ dev->devid[0] = 0xFF; dev->devid[1] = dev->devtype >> 8; dev->devid[2] = dev->devtype & 0xFF; dev->devid[3] = 0x00; dev->devid[4] = dev->devtype >> 8; dev->devid[5] = dev->devtype & 0xFF; dev->devid[6] = 0x00; dev->numdevid = 7; dev->filename[0] = 0; dev->acc_ipaddr = 0; dev->acc_ipmask = 0; if (argc > 0) // group name? { if ('*' == argv[ac][0] && '\0' == argv[ac][1]) ; // NOP (not really a group name; an '*' is // simply used as an argument place holder) else strlcpy(dev->filename,argv[ac],sizeof(dev->filename)); argc--; ac++; if (argc > 0) // ip address? { if ((dev->acc_ipaddr = inet_addr(argv[ac])) == (in_addr_t)(-1)) { logmsg(_("HHCTE011E Device %4.4X: Invalid IP address: %s\n"), dev->devnum, argv[ac]); return -1; } else { argc--; ac++; if (argc > 0) // ip addr mask? { if ((dev->acc_ipmask = inet_addr(argv[ac])) == (in_addr_t)(-1)) { logmsg(_("HHCTE012E Device %4.4X: Invalid mask value: %s\n"), dev->devnum, argv[ac]); return -1; } else { argc--; ac++; if (argc > 0) // too many args? { logmsg(_("HHCTE013E Device %4.4X: Extraneous argument(s): %s...\n"), dev->devnum, argv[ac] ); return -1; } } } else dev->acc_ipmask = (in_addr_t)(-1); } } } return console_initialise(); } /* end function constty_init_handler */ /*-------------------------------------------------------------------*/ /* QUERY THE 1052/3215 DEVICE DEFINITION */ /*-------------------------------------------------------------------*/ static void constty_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "CON", dev, class, buflen, buffer ); if (dev->connected) { snprintf (buffer, buflen, "%s%s", inet_ntoa(dev->ipaddr), dev->prompt1052 ? "" : " noprompt"); } else { char acc[48]; if (dev->acc_ipaddr || dev->acc_ipmask) { char ip [16]; char mask [16]; struct in_addr xxxx; xxxx.s_addr = dev->acc_ipaddr; snprintf( ip, sizeof( ip ), "%s", inet_ntoa( xxxx )); xxxx.s_addr = dev->acc_ipmask; snprintf( mask, sizeof( mask ), "%s", inet_ntoa( xxxx )); snprintf( acc, sizeof( acc ), "%s mask %s", ip, mask ); } else acc[0] = 0; if (dev->filename[0]) { snprintf(buffer, buflen, "GROUP=%s%s%s%s", dev->filename, !dev->prompt1052 ? " noprompt" : "", acc[0] ? " " : "", acc); } else { if (acc[0]) { if (!dev->prompt1052) snprintf(buffer, buflen, "noprompt %s", acc); else snprintf(buffer, buflen, "* %s", acc); } else { if (!dev->prompt1052) strlcpy(buffer,"noprompt",buflen); else buffer[0] = 0; } } } } /* end function constty_query_device */ /*-------------------------------------------------------------------*/ /* CLOSE THE 1052/3215 DEVICE HANDLER */ /*-------------------------------------------------------------------*/ static int constty_close_device ( DEVBLK *dev ) { console_remove(dev); return 0; } /* end function constty_close_device */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO ADVANCE TO NEXT CHAR OR ORDER IN A 3270 DATA STREAM */ /* Input: */ /* buf Buffer containing 3270 data stream */ /* off Offset in buffer of current character or order */ /* pos Position on screen of current character or order */ /* Output: */ /* off Offset in buffer of next character or order */ /* pos Position on screen of next character or order */ /*-------------------------------------------------------------------*/ static void next_3270_pos (BYTE *buf, int *off, int *pos) { int i; /* Copy the offset and advance the offset by 1 byte */ i = (*off)++; /* Advance the offset past the argument bytes and set position */ switch (buf[i]) { /* The Repeat to Address order has 3 argument bytes (or in case of a Graphics Escape 4 bytes) and sets the screen position */ case O3270_RA: *off += (buf[i+3] == O3270_GE) ? 4 : 3; if ((buf[i+1] & 0xC0) == 0x00) *pos = (buf[i+1] << 8) | buf[i+2]; else *pos = ((buf[i+1] & 0x3F) << 6) | (buf[i+2] & 0x3F); break; /* The Start Field Extended and Modify Field orders have a count byte followed by a variable number of type- attribute pairs, and advance the screen position by 1 */ case O3270_SFE: case O3270_MF: *off += (1 + 2*buf[i+1]); (*pos)++; break; /* The Set Buffer Address and Erase Unprotected to Address orders have 2 argument bytes and set the screen position */ case O3270_SBA: case O3270_EUA: *off += 2; if ((buf[i+1] & 0xC0) == 0x00) *pos = (buf[i+1] << 8) | buf[i+2]; else *pos = ((buf[i+1] & 0x3F) << 6) | (buf[i+2] & 0x3F); break; /* The Set Attribute order has 2 argument bytes and does not change the screen position */ case O3270_SA: *off += 2; break; /* Insert Cursor and Program Tab have no argument bytes and do not change the screen position */ case O3270_IC: case O3270_PT: break; /* The Start Field and Graphics Escape orders have one argument byte, and advance the screen position by 1 */ case O3270_SF: case O3270_GE: (*off)++; (*pos)++; break; /* All other characters advance the screen position by 1 */ default: (*pos)++; break; } /* end switch */ } /* end function next_3270_pos */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO FIND A GIVEN SCREEN POSITION IN A 3270 READ BUFFER */ /* Input: */ /* buf Buffer containing an inbound 3270 data stream */ /* size Number of bytes in buffer */ /* pos Screen position whose offset in buffer is desired */ /* Return value: */ /* Offset in buffer of the character or order corresponding to */ /* the given screen position, or zero if position not found. */ /*-------------------------------------------------------------------*/ static int find_buffer_pos (BYTE *buf, int size, int pos) { int wpos; /* Current screen position */ int woff; /* Current offset in buffer */ /* Screen position 0 is at offset 3 in the device buffer, following the AID and cursor address bytes */ wpos = 0; woff = 3; while (woff < size) { /* Exit if desired screen position has been reached */ if (wpos >= pos) { // logmsg (_("console: Pos %4.4X reached at %4.4X\n"), // wpos, woff); #ifdef FIX_QWS_BUG_FOR_MCS_CONSOLES /* There is a bug in QWS3270 when used to emulate an MCS console with EAB. At position 1680 the Read Buffer contains two 6-byte SFE orders (12 bytes) preceding the entry area, whereas MCS expects the entry area to start 4 bytes after screen position 1680 in the buffer. The bypass is to add 8 to the calculated buffer offset if this appears to be an MCS console read buffer command */ if (pos == 0x0690 && buf[woff] == O3270_SFE && buf[woff+6] == O3270_SFE) { woff += 8; // logmsg (_("console: Pos %4.4X adjusted to %4.4X\n"), // wpos, woff); } #endif /*FIX_QWS_BUG_FOR_MCS_CONSOLES*/ return woff; } /* Process next character or order, update screen position */ next_3270_pos (buf, &woff, &wpos); } /* end while */ /* Return offset zero if the position cannot be determined */ return 0; } /* end function find_buffer_pos */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO UPDATE THE CURRENT SCREEN POSITION */ /* Input: */ /* pos Current screen position */ /* buf Pointer to the byte in the 3270 data stream */ /* corresponding to the current screen position */ /* size Number of bytes remaining in buffer */ /* Output: */ /* pos Updated screen position after end of buffer */ /*-------------------------------------------------------------------*/ static void get_screen_pos (int *pos, BYTE *buf, int size) { int woff = 0; /* Current offset in buffer */ while (woff < size) { /* Process next character or order, update screen position */ next_3270_pos (buf, &woff, pos); } /* end while */ } /* end function get_screen_pos */ /*-------------------------------------------------------------------*/ /* EXECUTE A 3270 CHANNEL COMMAND WORD */ /*-------------------------------------------------------------------*/ static void loc3270_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { int rc; /* Return code */ int num; /* Number of bytes to copy */ int len; /* Data length */ int aid; /* First read: AID present */ U32 off; /* Offset in device buffer */ BYTE cmd; /* tn3270 command code */ BYTE buf[BUFLEN_3270]; /* tn3270 write buffer */ UNREFERENCED(prevcode); UNREFERENCED(ccwseq); /* Clear the current screen position at start of CCW chain */ if (!chained) dev->pos3270 = 0; /* Unit check with intervention required if no client connected */ if (!dev->connected && !IS_CCW_SENSE(code)) { dev->sense[0] = SENSE_IR; /* *unitstat = CSW_CE | CSW_DE | CSW_UC; */ *unitstat = CSW_UC; /* *ISW3274DR* (as per GA23-0218-11 3.1.3.2.2 Table 5-5) */ return; } /* Process depending on CCW opcode */ switch (code) { case L3270_NOP: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ /* Reset the buffer address */ dev->pos3270 = 0; *unitstat = CSW_CE | CSW_DE; break; case L3270_SELRM: case L3270_SELRB: case L3270_SELRMP: case L3270_SELRBP: case L3270_SELWRT: /*---------------------------------------------------------------*/ /* SELECT */ /*---------------------------------------------------------------*/ /* Reset the buffer address */ dev->pos3270 = 0; /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case L3270_EAU: /*---------------------------------------------------------------*/ /* ERASE ALL UNPROTECTED */ /*---------------------------------------------------------------*/ dev->pos3270 = 0; cmd = R3270_EAU; goto write; case L3270_WRT: /*---------------------------------------------------------------*/ /* WRITE */ /*---------------------------------------------------------------*/ cmd = R3270_WRT; goto write; case L3270_EW: /*---------------------------------------------------------------*/ /* ERASE/WRITE */ /*---------------------------------------------------------------*/ dev->pos3270 = 0; cmd = R3270_EW; dev->ewa3270 = 0; goto write; case L3270_EWA: /*---------------------------------------------------------------*/ /* ERASE/WRITE ALTERNATE */ /*---------------------------------------------------------------*/ dev->pos3270 = 0; cmd = R3270_EWA; dev->ewa3270 = 1; goto write; case L3270_WSF: /*---------------------------------------------------------------*/ /* WRITE STRUCTURED FIELD */ /*---------------------------------------------------------------*/ /* Process WSF command if device has extended attributes */ if (dev->eab3270) { dev->pos3270 = 0; cmd = R3270_WSF; goto write; } /* Operation check, device does not have extended attributes */ dev->sense[0] = SENSE_OC; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; write: /*---------------------------------------------------------------*/ /* All write commands, and the EAU control command, come here */ /*---------------------------------------------------------------*/ /* Initialize the data length */ len = 0; /* Calculate number of bytes to move and residual byte count */ num = sizeof(buf) / 2; num = (count < num) ? count : num; if(cmd == R3270_EAU) num = 0; *residual = count - num; /* Move the 3270 command code to the first byte of the buffer unless data-chained from previous CCW */ if ((chained & CCW_FLAGS_CD) == 0) { buf[len++] = cmd; /* If this is a chained write then we start at the current buffer address rather then the cursor address. If the first action the datastream takes is not a positioning action then insert a SBA to position to the current buffer address */ if(chained && cmd == R3270_WRT && dev->pos3270 != 0 && iobuf[1] != O3270_SBA && iobuf[1] != O3270_RA && iobuf[1] != O3270_EUA) { /* Copy the write control character and adjust buffer */ buf[len++] = *iobuf++; num--; /* Insert the SBA order */ buf[len++] = O3270_SBA; if(dev->pos3270 < 4096) { buf[len++] = sba_code[dev->pos3270 >> 6]; buf[len++] = sba_code[dev->pos3270 & 0x3F]; } else { buf[len++] = dev->pos3270 >> 8; buf[len++] = dev->pos3270 & 0xFF; } } /* if(iobuf[0] != SBA, RA or EUA) */ /* Save the screen position at completion of the write. This is necessary in case a Read Buffer command is chained from another write or read, this does not apply for the write structured field command */ if(cmd != R3270_WSF) get_screen_pos (&dev->pos3270, iobuf+1, num-1); } /* if(!data_chained) */ else /* if(data_chained) */ if(cmd != R3270_WSF) get_screen_pos (&dev->pos3270, iobuf, num); /* Copy data from channel buffer to device buffer */ memcpy (buf + len, iobuf, num); len += num; /* Double up any IAC bytes in the data */ len = double_up_iac (buf, len); /* Append telnet EOR marker at end of data */ if ((flags & CCW_FLAGS_CD) == 0) { buf[len++] = IAC; buf[len++] = EOR_MARK; } /* Send the data to the client */ rc = send_packet(dev->fd, buf, len, "3270 data"); if (rc < 0) { dev->sense[0] = SENSE_DC; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case L3270_RB: /*---------------------------------------------------------------*/ /* READ BUFFER */ /*---------------------------------------------------------------*/ /* Obtain the device lock */ obtain_lock (&dev->lock); /* AID is only present during the first read */ aid = dev->readpending != 2; /* Receive buffer data from client if not data chained */ if ((chained & CCW_FLAGS_CD) == 0) { /* Send read buffer command to client and await response */ rc = solicit_3270_data (dev, R3270_RB); if (rc & CSW_UC) { *unitstat = CSW_CE | CSW_DE | CSW_UC; release_lock (&dev->lock); break; } /* Set AID in buffer flag */ aid = 1; /* Save the AID of the current inbound transmission */ dev->aid3270 = dev->buf[0]; if(dev->pos3270 != 0 && dev->aid3270 != SF3270_AID) { /* Find offset in buffer of current screen position */ off = find_buffer_pos (dev->buf, dev->rlen3270, dev->pos3270); /* Shift out unwanted characters from buffer */ num = (dev->rlen3270 > off ? dev->rlen3270 - off : 0); memmove (dev->buf + 3, dev->buf + off, num); dev->rlen3270 = 3 + num; } } /* end if(!CCW_FLAGS_CD) */ /* Calculate number of bytes to move and residual byte count */ len = dev->rlen3270; num = (count < len) ? count : len; *residual = count - num; if (count < len) *more = 1; /* Save the screen position at completion of the read. This is necessary in case a Read Buffer command is chained from another write or read. */ if(dev->aid3270 != SF3270_AID) { if(aid) get_screen_pos(&dev->pos3270, dev->buf+3, num-3); else get_screen_pos(&dev->pos3270, dev->buf, num); } /* Indicate that the AID bytes have been skipped */ if(dev->readpending == 1) dev->readpending = 2; /* Copy data from device buffer to channel buffer */ memcpy (iobuf, dev->buf, num); /* If data chaining is specified, save remaining data */ if ((flags & CCW_FLAGS_CD) && len > count) { memmove (dev->buf, dev->buf + count, len - count); dev->rlen3270 = len - count; } else { dev->rlen3270 = 0; dev->readpending = 0; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; /* Release the device lock */ release_lock (&dev->lock); /* Signal connection thread to redrive its select loop */ SIGNAL_CONSOLE_THREAD(); break; case L3270_RM: /*---------------------------------------------------------------*/ /* READ MODIFIED */ /*---------------------------------------------------------------*/ /* Obtain the device lock */ obtain_lock (&dev->lock); /* AID is only present during the first read */ aid = dev->readpending != 2; /* If not data chained from previous Read Modified CCW, and if the connection thread has not already accumulated a complete Read Modified record in the inbound buffer, then solicit a Read Modified operation at the client */ if ((chained & CCW_FLAGS_CD) == 0 && !dev->readpending) { /* Send read modified command to client, await response */ rc = solicit_3270_data (dev, R3270_RM); if (rc & CSW_UC) { *unitstat = CSW_CE | CSW_DE | CSW_UC; release_lock (&dev->lock); break; } /* Set AID in buffer flag */ aid = 1; dev->aid3270 = dev->buf[0]; if(dev->pos3270 != 0 && dev->aid3270 != SF3270_AID) { /* Find offset in buffer of current screen position */ off = find_buffer_pos (dev->buf, dev->rlen3270, dev->pos3270); /* Shift out unwanted characters from buffer */ num = (dev->rlen3270 > off ? dev->rlen3270 - off : 0); memmove (dev->buf + 3, dev->buf + off, num); dev->rlen3270 = 3 + num; } } /* end if(!CCW_FLAGS_CD) */ /* Calculate number of bytes to move and residual byte count */ len = dev->rlen3270; num = (count < len) ? count : len; *residual = count - num; if (count < len) *more = 1; /* Save the screen position at completion of the read. This is necessary in case a Read Buffer command is chained from another write or read. */ if(dev->aid3270 != SF3270_AID) { if(aid) get_screen_pos(&dev->pos3270, dev->buf+3, num-3); else get_screen_pos(&dev->pos3270, dev->buf, num); } /* Indicate that the AID bytes have been skipped */ if(dev->readpending == 1) dev->readpending = 2; /* Copy data from device buffer to channel buffer */ memcpy (iobuf, dev->buf, num); /* If data chaining is specified, save remaining data */ if ((flags & CCW_FLAGS_CD) && len > count) { memmove (dev->buf, dev->buf + count, len - count); dev->rlen3270 = len - count; } else { dev->rlen3270 = 0; dev->readpending = 0; } /* Set normal status */ *unitstat = CSW_CE | CSW_DE; /* Release the device lock */ release_lock (&dev->lock); /* Signal connection thread to redrive its select loop */ SIGNAL_CONSOLE_THREAD(); break; case L3270_SENSE: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Reset the buffer address */ dev->pos3270 = 0; /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case L3270_SENSEID: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Reset the buffer address */ dev->pos3270 = 0; /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ } /* end function loc3270_execute_ccw */ /*-------------------------------------------------------------------*/ /* EXECUTE A 1052/3215 CHANNEL COMMAND WORD */ /*-------------------------------------------------------------------*/ static void constty_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { int rc; /* Return code */ int len; /* Length of data */ int num; /* Number of bytes to move */ BYTE c; /* Print character */ BYTE stat; /* Unit status */ UNREFERENCED(chained); UNREFERENCED(prevcode); UNREFERENCED(ccwseq); /* Unit check with intervention required if no client connected */ if (dev->connected == 0 && !IS_CCW_SENSE(code)) { dev->sense[0] = SENSE_IR; *unitstat = CSW_UC; return; } /* Process depending on CCW opcode */ switch (code) { case 0x01: /*---------------------------------------------------------------*/ /* WRITE NO CARRIER RETURN */ /*---------------------------------------------------------------*/ case 0x09: /*---------------------------------------------------------------*/ /* WRITE AUTO CARRIER RETURN */ /*---------------------------------------------------------------*/ /* Calculate number of bytes to write and set residual count */ num = (count < BUFLEN_1052) ? count : BUFLEN_1052; *residual = count - num; /* Translate data in channel buffer to ASCII */ for (len = 0; len < num; len++) { c = guest_to_host(iobuf[len]); if (!isprint(c) && c != 0x0a && c != 0x0d) c = SPACE; iobuf[len] = c; } /* end for(len) */ ASSERT(len == num); /* Perform end of record processing if not data-chaining */ if ((flags & CCW_FLAGS_CD) == 0) { /* Append carriage return and newline if required */ if (code == 0x09) { if (len < BUFLEN_1052) iobuf[len++] = '\r'; if (len < BUFLEN_1052) iobuf[len++] = '\n'; } } /* end if(!data-chaining) */ /* Send the data to the client */ rc = send_packet (dev->fd, iobuf, len, NULL); if (rc < 0) { dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x03: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ *unitstat = CSW_CE | CSW_DE; break; case 0x0A: /*---------------------------------------------------------------*/ /* READ INQUIRY */ /*---------------------------------------------------------------*/ /* Solicit console input if no data in the device buffer */ if (!dev->keybdrem) { /* Display prompting message on console if allowed */ if (dev->prompt1052) { snprintf ((char *)dev->buf, dev->bufsize, _("HHCTE006A Enter input for console device %4.4X\n"), dev->devnum); len = strlen((char *)dev->buf); rc = send_packet (dev->fd, dev->buf, len, NULL); if (rc < 0) { dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* Accumulate client input data into device buffer */ while (1) { /* Receive client data and increment dev->keybdrem */ stat = recv_1052_data (dev); /* Exit if error or end of line */ if (stat != 0) break; } /* end while */ /* Exit if error status */ if (stat != CSW_ATTN) { *unitstat = (CSW_CE | CSW_DE) | (stat & ~CSW_ATTN); break; } } /* Calculate number of bytes to move and residual byte count */ len = dev->keybdrem; num = (count < len) ? count : len; *residual = count - num; if (count < len) *more = 1; /* Copy data from device buffer to channel buffer */ memcpy (iobuf, dev->buf, num); /* If data chaining is specified, save remaining data */ if ((flags & CCW_FLAGS_CD) && len > count) { memmove (dev->buf, dev->buf + count, len - count); dev->keybdrem = len - count; } else { dev->keybdrem = 0; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x0B: /*---------------------------------------------------------------*/ /* AUDIBLE ALARM */ /*---------------------------------------------------------------*/ rc = send_packet (dev->fd, (BYTE *)"\a", 1, NULL); /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ } /* end function constty_execute_ccw */ #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND constty_device_hndinfo = { &constty_init_handler, /* Device Initialisation */ &constty_execute_ccw, /* Device CCW execute */ &constty_close_device, /* Device Close */ &constty_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ constty_immed, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt3270_LTX_hdl_ddev #define hdl_depc hdt3270_LTX_hdl_depc #define hdl_reso hdt3270_LTX_hdl_reso #define hdl_init hdt3270_LTX_hdl_init #define hdl_fini hdt3270_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND loc3270_device_hndinfo = { &loc3270_init_handler, /* Device Initialisation */ &loc3270_execute_ccw, /* Device CCW execute */ &loc3270_close_device, /* Device Close */ &loc3270_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ loc3270_immed, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ &loc3270_hsuspend, /* Hercules suspend */ &loc3270_hresume /* Hercules resume */ }; #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); } END_DEPENDENCY_SECTION #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk #undef config_cnslport HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR( psysblk, sysblk ); HDL_RESOLVE( config_cnslport ); } END_RESOLVER_SECTION #endif HDL_DEVICE_SECTION { HDL_DEVICE(1052, constty_device_hndinfo ); HDL_DEVICE(3215, constty_device_hndinfo ); HDL_DEVICE(3270, loc3270_device_hndinfo ); HDL_DEVICE(3287, loc3270_device_hndinfo ); #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) HDL_DEVICE(SYSG, loc3270_device_hndinfo ); #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ } END_DEVICE_SECTION #endif hercules-3.12/tapedev.c0000664000175000017500000026161712564723224012014 00000000000000/* TAPEDEV.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Tape Device Handler */ /* Original Author: Roger Bowler */ /* Prime Maintainer: Ivan Warren */ /* Secondary Maintainer: "Fish" (David B. Trout) */ /*-------------------------------------------------------------------*/ /* This module contains device handling functions for emulated */ /* magnetic tape devices for the Hercules ESA/390 emulator. */ /*-------------------------------------------------------------------*/ /* Messages issued by the TAPEDEV.C module are prefixed HHCTA0nn */ /* CCW processing functions have been moved to module TAPECCW.C */ /* */ /* Five emulated tape formats are supported: */ /* */ /* 1. AWSTAPE This is the format used by the P/390. */ /* The entire tape is contained in a single flat file. */ /* A tape block consists of one or more block segments. */ /* Each block segment is preceded by a 6-byte header. */ /* Files are separated by tapemarks, which consist */ /* of headers with zero block length. */ /* AWSTAPE files are readable and writable. */ /* */ /* Support for AWSTAPE is in the "AWSTAPE.C" member. */ /* */ /* 2. OMATAPE This is the Optical Media Attach device format. */ /* Each physical file on the tape is represented by */ /* a separate flat file. The collection of files that */ /* make up the physical tape is obtained from an ASCII */ /* text file called the "tape description file", whose */ /* file name is always tapes/xxxxxx.tdf (where xxxxxx */ /* is the volume serial number of the tape). */ /* Three formats of tape files are supported: */ /* * FIXED files contain fixed length EBCDIC blocks */ /* with no headers or delimiters. The block length */ /* is specified in the TDF file. */ /* * TEXT files contain variable length ASCII blocks */ /* delimited by carriage return line feed sequences. */ /* The data is translated to EBCDIC by this module. */ /* * HEADER files contain variable length blocks of */ /* EBCDIC data prefixed by a 16-byte header. */ /* The TDF file and all of the tape files must reside */ /* reside under the same directory which is normally */ /* on CDROM but can be on disk. */ /* OMATAPE files are supported as read-only media. */ /* */ /* OMATAPE tape Support is in the "OMATAPE.C" member. */ /* */ /* 3. SCSITAPE This format allows reading and writing of 4mm or */ /* 8mm DAT tape, 9-track open-reel tape, or 3480-type */ /* cartridge on an appropriate SCSI-attached drive. */ /* All SCSI tapes are processed using the generalized */ /* SCSI tape driver (st.c) which is controlled using */ /* the MTIOCxxx set of IOCTL commands. */ /* PROGRAMMING NOTE: the 'tape' portability macros for */ /* physical (SCSI) tapes MUST be used for all tape i/o! */ /* */ /* SCSI tape Support is in the "SCSITAPE.C" member. */ /* */ /* 4. HET This format is based on the AWSTAPE format but has */ /* been extended to support compression. Since the */ /* basic file format has remained the same, AWSTAPEs */ /* can be read/written using the HET routines. */ /* */ /* Support for HET is in the "HETTAPE.C" member. */ /* */ /* 5. FAKETAPE This is the format used by Fundamental Software */ /* on their FLEX-ES systems. It it similar to the AWS */ /* format. The entire tape is contained in a single */ /* flat file. A tape block is preceded by a 12-ASCII- */ /* hex-characters header which indicate the size of */ /* the previous and next blocks. Files are separated */ /* by tapemarks which consist of headers with a zero */ /* current block length. FakeTapes are both readable */ /* and writable. */ /* */ /* Support for FAKETAPE is in the "FAKETAPE.C" member. */ /* */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* 3480 commands contributed by Jan Jaeger */ /* Sense byte improvements by Jan Jaeger */ /* 3480 Read Block ID and Locate CCWs by Brandon Hill */ /* Unloaded tape support by Brandon Hill v209*/ /* HET format support by Leland Lucius v209*/ /* JCS - minor changes by John Summerfield 2003*/ /* PERFORM SUBSYSTEM FUNCTION / CONTROL ACCESS support by */ /* Adrian Trenkwalder (with futher enhancements by Fish) */ /* **INCOMPLETE** 3590 support by Fish (David B. Trout) */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Reference information: */ /* SC53-1200 S/370 and S/390 Optical Media Attach/2 User's Guide */ /* SC53-1201 S/370 and S/390 Optical Media Attach/2 Technical Ref */ /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide */ /* GA32-0331 IBM 3590 Hardware Reference */ /* GA32-0329 IBM 3590 Introduction and Planning Guide */ /* SG24-2594 IBM 3590 Multiplatform Implementation */ /* ANSI INCITS 131-1994 (R1999) SCSI-2 Reference */ /* GA32-0127 IBM 3490E Hardware Reference */ /* GC35-0152 EREP Release 3.5.0 Reference */ /* SA22-7204 ESA/390 Common I/O-Device Commands */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /* need Hercules control blocks */ #include "tapedev.h" /* Main tape handler header file */ //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING) #ifdef ENABLE_TRACING_STMTS #if !defined(DEBUG) #warning DEBUG required for ENABLE_TRACING_STMTS #endif // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h) #else #undef TRACE #undef ASSERT #undef VERIFY #define TRACE 1 ? ((void)0) : logmsg #define ASSERT(a) #define VERIFY(a) ((void)(a)) #endif /*-------------------------------------------------------------------*/ #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) SYSBLK *psysblk; #define sysblk (*psysblk) #endif /*-------------------------------------------------------------------*/ DEVHND tapedev_device_hndinfo = { &tapedev_init_handler, /* Device Initialisation */ &tapedev_execute_ccw, /* Device CCW execute */ &tapedev_close_device, /* Device Close */ &tapedev_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ TapeImmedCommands, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /*-------------------------------------------------------------------*/ /* Libtool static name colision resolution... */ /* Note: lt_dlopen will look for symbol & modulename_LTX_symbol */ /*-------------------------------------------------------------------*/ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt3420_LTX_hdl_ddev #define hdl_depc hdt3420_LTX_hdl_depc #define hdl_reso hdt3420_LTX_hdl_reso #define hdl_init hdt3420_LTX_hdl_init #define hdl_fini hdt3420_LTX_hdl_fini #endif /*-------------------------------------------------------------------*/ #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY ( HERCULES ); HDL_DEPENDENCY ( DEVBLK ); HDL_DEPENDENCY ( SYSBLK ); } END_DEPENDENCY_SECTION /*-------------------------------------------------------------------*/ HDL_DEVICE_SECTION; { HDL_DEVICE ( 3410, tapedev_device_hndinfo ); HDL_DEVICE ( 3411, tapedev_device_hndinfo ); HDL_DEVICE ( 3420, tapedev_device_hndinfo ); HDL_DEVICE ( 3422, tapedev_device_hndinfo ); HDL_DEVICE ( 3430, tapedev_device_hndinfo ); HDL_DEVICE ( 3480, tapedev_device_hndinfo ); HDL_DEVICE ( 3490, tapedev_device_hndinfo ); HDL_DEVICE ( 3590, tapedev_device_hndinfo ); HDL_DEVICE ( 8809, tapedev_device_hndinfo ); HDL_DEVICE ( 9347, tapedev_device_hndinfo ); HDL_DEVICE ( 9348, tapedev_device_hndinfo ); } END_DEVICE_SECTION /*-------------------------------------------------------------------*/ #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR ( psysblk, sysblk ); } END_RESOLVER_SECTION #endif // defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #endif // defined(OPTION_DYNAMIC_LOAD) /*-------------------------------------------------------------------*/ /* (see 'tapedev.h' for layout of TAPEMEDIA_HANDLER structure) */ /*-------------------------------------------------------------------*/ TAPEMEDIA_HANDLER tmh_aws = { &generic_tmhcall, &open_awstape, &close_awstape, &read_awstape, &write_awstape, &rewind_awstape, &bsb_awstape, &fsb_awstape, &bsf_awstape, &fsf_awstape, &write_awsmark, &sync_awstape, &no_operation, // (DSE) ZZ FIXME: not coded yet &no_operation, // (ERG) &is_tapeloaded_filename, &passedeot_awstape, &readblkid_virtual, &locateblk_virtual }; /*-------------------------------------------------------------------*/ TAPEMEDIA_HANDLER tmh_het = { &generic_tmhcall, &open_het, &close_het, &read_het, &write_het, &rewind_het, &bsb_het, &fsb_het, &bsf_het, &fsf_het, &write_hetmark, &sync_het, &no_operation, // (DSE) ZZ FIXME: not coded yet &no_operation, // (ERG) &is_tapeloaded_filename, &passedeot_het, &readblkid_virtual, &locateblk_virtual }; /*-------------------------------------------------------------------*/ TAPEMEDIA_HANDLER tmh_fake = { &generic_tmhcall, &open_faketape, &close_faketape, &read_faketape, &write_faketape, &rewind_faketape, &bsb_faketape, &fsb_faketape, &bsf_faketape, &fsf_faketape, &write_fakemark, &sync_faketape, &no_operation, // (DSE) ZZ FIXME: not coded yet &no_operation, // (ERG) &is_tapeloaded_filename, &passedeot_faketape, &readblkid_virtual, &locateblk_virtual }; /*-------------------------------------------------------------------*/ TAPEMEDIA_HANDLER tmh_oma = { &generic_tmhcall, &open_omatape, &close_omatape, &read_omatape, &write_READONLY5, // WRITE &rewind_omatape, &bsb_omatape, &fsb_omatape, &bsf_omatape, &fsf_omatape, &write_READONLY, // WTM &write_READONLY, // SYNC &write_READONLY, // DSE &write_READONLY, // ERG &is_tapeloaded_filename, &return_false1, // passedeot &readblkid_virtual, &locateblk_virtual }; /*-------------------------------------------------------------------*/ #if defined(OPTION_SCSI_TAPE) TAPEMEDIA_HANDLER tmh_scsi = { &generic_tmhcall, &open_scsitape, &close_scsitape, &read_scsitape, &write_scsitape, &rewind_scsitape, &bsb_scsitape, &fsb_scsitape, &bsf_scsitape, &fsf_scsitape, &write_scsimark, &sync_scsitape, &dse_scsitape, &erg_scsitape, &is_tape_mounted_scsitape, &passedeot_scsitape, &readblkid_scsitape, &locateblk_scsitape }; #endif /* defined(OPTION_SCSI_TAPE) */ /*-------------------------------------------------------------------*/ /* Device-Type Initialization Table (DEV/CU MODEL, FEATURES, ETC) */ /*-------------------------------------------------------------------*/ /* PROGRAMMING NOTE: the MDR/OBR code (Device Characteristics bytes 40-41) are apparently CRITICALLY IMPORTANT for proper tape drive functioning for certain operating systems. If the bytes are not provided (set to zero) or are set incorrectly, certain operating systems end up using unusual/undesirable Mode Set values in their Channel Programs (such as x'20' Write Immediate for example). I only note it here because these two particular bytes are rather innocuous looking based upon their name and sparsely documented and largely unexplained values, thereby possibly misleading one into believing they weren't important and thus could be safely set to zero if their values were unknown. Rest assured they are NOT unimportant! Quite the opposite: the are, for some operating systems, CRITICALLY IMPORTANT and must NOT be returned as zeros. The following were obtained from "EREP Release 3.5.0 Reference" (GC35-0152-03): Model MDR OBR ------- ----- ----- 3480 0x41 0x80 3490 0x42 0x81 3590 0x46 0x83 3590 (3591/3490 EMU) 0x47 0x84 3590 (3590/3490 EMU) 0x48 0x85 NOTE: only models 3480, 3490 and 3590 support the RDC (Read Device Characteristics) channel command, and thus they're the only ones we must know the MDR/OBR codes for (since the MDR/OBR codes are only used in the RDC CCW and not anwhere else). That is to say, NONE of the Channel Commands (CCWs) that all the OTHER models happen to support have an MDR/OBR code anywhere in their data. Only models 3480, 3490 and 3590 have MDR/OBR codes buried in their CCW data (specifically the RDC CCW data). Also note that, at the moment, we do not support emulating 3590's or 3591's running in 3490 Emulation Mode (i.e. 3591/3490 EMU or 3590/3490 EMU). The user is free to use such a device with Herc- ules however, but if they do, it should be specified as a 3490. ---------------------------------------------------------------------*/ typedef struct DEVINITTAB /* Initialization values */ { U16 devtype; /* Device type */ BYTE devmodel; /* Device model number */ U16 cutype; /* Control unit type */ BYTE cumodel; /* Control unit model number */ U32 sctlfeat; /* Storage control features */ BYTE devclass; /* Device class code */ BYTE devtcode; /* Device type code */ BYTE MDR; /* Misc. Data Record ID */ BYTE OBR; /* Outboard Recorder ID */ int numdevid; /* #of SNSID bytes (see NOTE)*/ int numsense; /* #of SENSE bytes */ int haverdc; /* RDC Supported */ int displayfeat; /* Has LCD display */ } DEVINITTAB; DEVINITTAB DevInitTab[] = /* Initialization table */ { // PROGRAMMING NOTE: we currently do not support a #of Sense-ID bytes // value (numdevid) greater than 7 since our current channel-subsystem // design does not support the concept of hardware physical attachment // "Nodes" (i.e. separate control-unit, device and interface elements). // Supporting more than 7 bytes of Sense-ID information would require // support for Node Descriptors (ND) and Node Element Descriptors (NED) // and the associated commands (CCWs) to query them (Read Configuration // Data (0xFA) , Set Interface Identifier (0x73) and associated support // in the Read Subsystem Data (0x3E) command), which is vast overkill // and a complete waste of time given our current overly-simple channel // subsystem design. // //-------------------------------------------------------------------- // 3410/3411/3420/3422/3430/8809/9347/9348 //-------------------------------------------------------------------- // // devtype/mod cutype/mod sctlfeat cls typ MDR OBR sid sns rdc dsp { 0x3410,0x01, 0x3115,0x01, 0x00000000, 0, 0, 0, 0, 0, 9, 0, 0 }, { 0x3411,0x01, 0x3115,0x01, 0x00000000, 0, 0, 0, 0, 0, 9, 0, 0 }, { 0x3420,0x06, 0x3803,0x02, 0x00000000, 0, 0, 0, 0, 0, 24, 0, 0 }, // (DEFAULT: 3420) { 0x3422,0x01, 0x3422,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 }, { 0x3430,0x01, 0x3422,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 }, { 0x8809,0x01, 0x8809,0x01, 0x00000000, 0, 0, 0, 0, 0, 32, 0, 0 }, { 0x9347,0x01, 0x9347,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 }, { 0x9348,0x01, 0x9348,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 }, //-------------------------------------------------------------------- // 3480/3490/3590 //-------------------------------------------------------------------- // // PROGRAMMING NOTE: we currently do not support a #of Sense-ID bytes // value (numdevid) greater than 7 since our current channel-subsystem // design does not support the concept of hardware physical attachment // "Nodes" (i.e. separate control-unit, device and interface elements). // Supporting more than 7 bytes of Sense-ID information would require // support for Node Descriptors (ND) and Node Element Descriptors (NED) // and the associated commands (CCWs) to query them (Read Configuration // Data (0xFA) , Set Interface Identifier (0x73) and associated support // in the Read Subsystem Data (0x3E) command), which is vast overkill // and a complete waste of time given our current overly-simple channel // subsystem design. // // PROGRAMMING NOTE: if you change the below devtype/mod or cutype/mod // values, be sure to ALSO change tapeccws.c's READ CONFIGURATION DATA // (CCW opcode 0xFA) values as well! // // PROGRAMMING NOTE: the bit values of the 'sctlfeat' field are: // // ....40.. (unknown) // ....08.. Set Special Intercept Condition (SIC) supported // ....04.. Channel Path No-Operation supported (always // on if Library Attachment Facility installed) // ....02.. Logical Write-Protect supported (always on // if Read Device Characteristics is supported) // ....01.. Extended Buffered Log support enabled (if 64 // bytes of buffered log data, else 32 bytes) // ......80 Automatic Cartridge Loader installed/enabled // ......40 Improved Data Recording Capability (i.e. // compression support) installed/enabled // ......20 Suppress Volume Fencing // ......10 Library Interface online/enabled // ......08 Library Attachment Facility installed // ......04 (unknown) // // PROGRAMMING NOTE: the below "0x00004EC4" value for the 'sctlfeat' // field for Model 3590 was determined empirically on a real machine. // // devtype/mod cutype/mod sctlfeat cls typ MDR OBR sid sns rdc dsp { 0x3480,0x31, 0x3480,0x31, 0x000002C0, 0x80,0x80, 0x41,0x80, 7, 24, 1, 1 }, // 0x31 = D31 { 0x3490,0x50, 0x3490,0x50, 0x000002C0, 0x80,0x80, 0x42,0x81, 7, 32, 1, 1 }, // 0x50 = C10 { 0x3590,0x10, 0x3590,0x50, 0x00004EC4, 0x80,0x80, 0x46,0x83, 7, 32, 1, 1 }, // 0x10 = B1A, 0x50 = A50 { 0xFFFF,0xFF, 0xFFFF,0xFF, 0xFFFFFFFF, 0xFF,0xFF, 0xFF,0xFF, -1, -1, -1, -1 }, //**** END OF TABLE **** { 0x3420,0x06, 0x3803,0x02, 0x00000000, 0, 0, 0, 0, 0, 24, 0, 0 }, // (DEFAULT: 3420) }; /*-------------------------------------------------------------------*/ /* Initialize the device handler */ /*-------------------------------------------------------------------*/ int tapedev_init_handler (DEVBLK *dev, int argc, char *argv[]) { int rc; DEVINITTAB* pDevInitTab; int attn = 0; /* Set flag so attention will be raised for re-init */ if(dev->devtype) { attn = 1; } /* Close current tape */ if(dev->fd>=0) { /* Prevent accidental re-init'ing of already loaded tape drives */ if (sysblk.nomountedtapereinit) { char* devclass; tapedev_query_device(dev, &devclass, 0, NULL); if (1 && strcmp(devclass,"TAPE") == 0 && (0 || TAPEDEVT_SCSITAPE == dev->tapedevt || (argc >= 3 && strcmp(argv[2], TAPE_UNLOADED) != 0) ) ) { ASSERT( dev->tmh && dev->tmh->tapeloaded ); if (dev->tmh->tapeloaded( dev, NULL, 0 )) { release_lock (&dev->lock); logmsg(_("HHCPN183E Reinit rejected for drive %u:%4.4X; drive not empty\n"), SSID_TO_LCSS(dev->ssid), dev->devnum); return -1; } } } dev->tmh->close(dev); dev->fd=-1; } autoload_close(dev); dev->tdparms.displayfeat=0; /* Determine the control unit type and model number */ /* Support for 3490/3422/3430/8809/9347, etc.. */ if (!sscanf( dev->typname, "%hx", &dev->devtype )) dev->devtype = 0x3420; // PROGAMMING NOTE: we use hard-coded values from our DevInitTab // for virtual (non-SCSI) devices and, for the time being, for non- // virtual (SCSI) devices too. Once we add direct SCSI I/O support // we will need to add code to get this information directly from // the actual SCSI device itself. for ( pDevInitTab = &DevInitTab[0]; pDevInitTab->devtype != 0xFFFF && pDevInitTab->devtype != dev->devtype; pDevInitTab++ ); if (pDevInitTab->devtype == 0xFFFF) /* (entry not found?) */ { logmsg ( _("Unsupported device type specified %4.4x\n"), dev->devtype ); pDevInitTab++; /* (default entry; s/b same as 0x3420) */ pDevInitTab->devtype = dev->devtype; /* (don't know what else to do really) */ pDevInitTab->cutype = dev->devtype; /* (don't know what else to do really) */ } /* Allow SENSE ID for certain specific legacy devices if requested */ dev->numdevid = pDevInitTab->numdevid; // (default == from table) if (1 && sysblk.legacysenseid // (if option requested, AND is) && (0 // (for allowable legacy device) || 0x3410 == dev->devtype || 0x3411 == dev->devtype || 0x3420 == dev->devtype || 0x8809 == dev->devtype ) ) { dev->numdevid = 7; // (allow for this legacy device) } /* Initialize the Sense-Id bytes if needed... */ if (dev->numdevid > 0) { dev->devid[0] = 0xFF; dev->devid[1] = (pDevInitTab->cutype >> 8) & 0xFF; dev->devid[2] = (pDevInitTab->cutype >> 0) & 0xFF; dev->devid[3] = pDevInitTab->cumodel; dev->devid[4] = (pDevInitTab->devtype >> 8) & 0xFF; dev->devid[5] = (pDevInitTab->devtype >> 0) & 0xFF; dev->devid[6] = pDevInitTab->devmodel; /* Initialize the CIW information if needed... */ if (dev->numdevid > 7) { // PROGRAMMING NOTE: see note near 'DEVINITTAB' // struct definition regarding requirements for // supporting more than 7 bytes of SNSID info. memcpy (&dev->devid[8], "\x40\xFA\x00\xA0", 4); // CIW Read Configuration Data (0xFA) memcpy (&dev->devid[12], "\x41\x73\x00\x04", 4); // CIW Set Interface Identifier (0x73) memcpy (&dev->devid[16], "\x42\x3E\x00\x60", 4); // CIW Read Subsystem Data (0x3E) } } /* Initialize the Read Device Characteristics (RDC) bytes... */ if (pDevInitTab->haverdc) { dev->numdevchar = 64; memset (dev->devchar, 0, sizeof(dev->devchar)); memcpy (dev->devchar, dev->devid+1, 6); // Bytes 6-9: Subsystem Facilities... dev->devchar[6] = (pDevInitTab->sctlfeat >> 24) & 0xFF; dev->devchar[7] = (pDevInitTab->sctlfeat >> 16) & 0xFF; dev->devchar[8] = (pDevInitTab->sctlfeat >> 8) & 0xFF; dev->devchar[9] = (pDevInitTab->sctlfeat >> 0) & 0xFF; // Bytes 10/11: Device Class/Type ... dev->devchar[10] = pDevInitTab->devclass; dev->devchar[11] = pDevInitTab->devtcode; // Bytes 24-29: cutype/model & devtype/model ... // (Note: undocumented; determined empirically) dev->devchar[24] = (pDevInitTab->cutype >> 8) & 0xFF; dev->devchar[25] = (pDevInitTab->cutype >> 0) & 0xFF; dev->devchar[26] = pDevInitTab->cumodel; dev->devchar[27] = (pDevInitTab->devtype >> 8) & 0xFF; dev->devchar[28] = (pDevInitTab->devtype >> 0) & 0xFF; dev->devchar[29] = pDevInitTab->devmodel; // Bytes 40-41: MDR/OBR code... dev->devchar[40] = pDevInitTab->MDR; dev->devchar[41] = pDevInitTab->OBR; } /* Initialize other fields */ // dev->numdevid = pDevInitTab->numdevid; // (handled above) dev->numsense = pDevInitTab->numsense; dev->tdparms.displayfeat = pDevInitTab->displayfeat; dev->fenced = 0; // (always, initially) dev->SIC_active = 0; // (always, initially) dev->SIC_supported = 0; // (until we're sure) dev->forced_logging = 0; // (always, initially) #if defined( OPTION_TAPE_AUTOMOUNT ) dev->noautomount = 0; // (always, initially) #endif /* Initialize SCSI tape control fields */ #if defined(OPTION_SCSI_TAPE) dev->sstat = GMT_DR_OPEN(-1); #endif /* Clear the DPA */ memset (dev->pgid, 0, sizeof(dev->pgid)); /* Clear Drive password - Adrian */ memset (dev->drvpwd, 0, sizeof(dev->drvpwd)); /* Request the channel to merge data chained write CCWs into a single buffer before passing data to the device handler */ dev->cdwmerge = 1; /* ISW */ /* Build a 'clear' sense */ memset (dev->sense, 0, sizeof(dev->sense)); dev->sns_pending = 0; // Initialize the [non-SCSI] auto-loader... // PROGRAMMING NOTE: we don't [yet] know at this early stage // what type of tape device we're dealing with (SCSI (non-virtual) // or non-SCSI (virtual)) since 'mountnewtape' hasn't been called // yet (which is the function that determines which media handler // should be used and is the one that initializes dev->tapedevt) // The only thing we know (or WILL know once 'autoload_init' // is called) is whether or not there was a [non-SCSI] auto- // loader defined for the device. That's it and nothing more. autoload_init( dev, argc, argv ); // Was an auto-loader defined for this device? if ( !dev->als ) { // No. Just mount whatever tape there is (if any)... rc = mountnewtape( dev, argc, argv ); } else { // Yes. Try mounting the FIRST auto-loader slot... if ( (rc = autoload_mount_first( dev )) != 0 ) { // If that doesn't work, try subsequent slots... while ( dev->als && (rc = autoload_mount_next( dev )) != 0 ) { ; // (nop; just go on to next slot) } rc = dev->als ? rc : -1; } } if (dev->devchar[8] & 0x08) // SIC supported? dev->SIC_supported = 1; // remember that fact if (dev->tapedevt == TAPEDEVT_SCSITAPE) dev->syncio = 0; // (SCSI i/o too slow; causes Machine checks) else dev->syncio = 2; // (aws/het/etc are fast; syncio likely safe) /* Make attention pending if necessary */ if(attn) { release_lock (&dev->lock); device_attention (dev, CSW_DE); obtain_lock (&dev->lock); } return rc; } /* end function tapedev_init_handler */ /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ int tapedev_close_device ( DEVBLK *dev ) { autoload_close(dev); dev->tmh->close(dev); ASSERT( dev->fd < 0 ); dev->curfilen = 1; dev->nxtblkpos = 0; dev->prvblkpos = -1; dev->curblkrem = 0; dev->curbufoff = 0; dev->blockid = 0; dev->fenced = 0; return 0; } /* end function tapedev_close_device */ /*-------------------------------------------------------------------*/ /* Tape format determination REGEXPS. Used by gettapetype below */ /*-------------------------------------------------------------------*/ struct tape_format_entry /* (table layout) */ { char* fmtreg; /* A regular expression */ int fmtcode; /* the device code */ TAPEMEDIA_HANDLER* tmh; /* The media dispatcher */ char* descr; /* readable description */ char* short_descr; /* (same but shorter) */ }; /*-------------------------------------------------------------------*/ /* Tape format determination REGEXPS. Used by gettapetype below */ /*-------------------------------------------------------------------*/ struct tape_format_entry fmttab [] = /* (table itself) */ { /* This entry matches a filename ending with .aws */ #define AWSTAPE_FMTENTRY 0 #define DEFAULT_FMTENTRY AWSTAPE_FMTENTRY { "\\.aws$", TAPEDEVT_AWSTAPE, &tmh_aws, "AWS Format tape file", "AWS tape" }, /* This entry matches a filename ending with .het */ #define HETTAPE_FMTENTRY 1 { "\\.het$", TAPEDEVT_HETTAPE, &tmh_het, "Hercules Emulated Tape file", "HET tape" }, /* This entry matches a filename ending with .tdf */ #define OMATAPE_FMTENTRY 2 { "\\.tdf$", TAPEDEVT_OMATAPE, &tmh_oma, "Optical Media Attachment (OMA) tape", "OMA tape" }, /* This entry matches a filename ending with .fkt */ #define FAKETAPE_FMTENTRY 3 { "\\.fkt$", TAPEDEVT_FAKETAPE, &tmh_fake, "Flex FakeTape file", "FakeTape" }, #if defined(OPTION_SCSI_TAPE) /* This entry matches a filename starting with /dev/ */ #define SCSITAPE_FMTENTRY 4 { "^/dev/", TAPEDEVT_SCSITAPE, &tmh_scsi, "SCSI attached tape drive", "SCSI tape" }, #if defined(_MSVC_) /* (same idea but for Windows SCSI tape device names) */ #undef SCSITAPE_FMTENTRY #define SCSITAPE_FMTENTRY 5 { "^\\\\\\\\\\.\\\\\\w", TAPEDEVT_SCSITAPE, &tmh_scsi, "SCSI attached tape drive", "SCSI tape" }, #endif // _MSVC_ #endif // OPTION_SCSI_TAPE }; /*-------------------------------------------------------------------*/ /* gettapetype_byname determine tape device type by filename */ /*-------------------------------------------------------------------*/ /* returns fmttab entry# on success, -1 on error/unable to determine */ /*-------------------------------------------------------------------*/ int gettapetype_byname (DEVBLK *dev) { #if defined(HAVE_REGEX_H) || defined(HAVE_PCRE) regex_t regwrk; /* REGEXP work area */ regmatch_t regwrk2; /* REGEXP match area */ char errbfr[1024]; /* Working storage */ int i; /* Loop control */ #endif // HAVE_REGEX_H int rc; /* various rtns return codes */ /* Use the file name to determine the device type */ #if defined(HAVE_REGEX_H) || defined(HAVE_PCRE) for (i=0; i < (int)arraysize( fmttab ); i++) { rc = regcomp (®wrk, fmttab[i].fmtreg, REG_ICASE); if (rc < 0) { regerror (rc, ®wrk, errbfr, 1024); logmsg (_("HHCTA001E %4.4X: Unable to determine tape format type for %s: Internal error: Regcomp error %s on index %d\n"), dev->devnum, dev->filename, errbfr, i); return -1; } rc = regexec (®wrk, dev->filename, 1, ®wrk2, 0); if (rc < 0) { regerror (rc, ®wrk, errbfr, 1024); regfree ( ®wrk ); logmsg (_("HHCTA002E %4.4X: Unable to determine tape format type for %s: Internal error: Regexec error %s on index %d\n"), dev->devnum, dev->filename, errbfr, i); return -1; } regfree (®wrk); if (rc == 0) /* MATCH? */ return i; ASSERT( rc == REG_NOMATCH ); } #else // !HAVE_REGEX_H if (1 && (rc = strlen(dev->filename)) > 4 && (rc = strcasecmp( &dev->filename[rc-4], ".aws" )) == 0 ) { return AWSTAPE_FMTENTRY; } if (1 && (rc = strlen(dev->filename)) > 4 && (rc = strcasecmp( &dev->filename[rc-4], ".het" )) == 0 ) { return HETTAPE_FMTENTRY; } if (1 && (rc = strlen(dev->filename)) > 4 && (rc = strcasecmp( &dev->filename[rc-4], ".tdf" )) == 0 ) { return OMATAPE_FMTENTRY; } if (1 && (rc = strlen(dev->filename)) > 4 && (rc = strcasecmp( &dev->filename[rc-4], ".fkt" )) == 0 ) { return FAKETAPE_FMTENTRY; } #if defined(OPTION_SCSI_TAPE) if (1 && (rc = strlen(dev->filename)) > 5 && (rc = strncasecmp( dev->filename, "/dev/", 5 )) == 0 ) { if (strncasecmp( dev->filename+5, "st", 2 ) == 0) dev->stape_close_rewinds = 1; // (rewind at close) else dev->stape_close_rewinds = 0; // (otherwise don't) return SCSITAPE_FMTENTRY; } #if defined(_MSVC_) if (1 && strncasecmp(dev->filename, "\\\\.\\", 4) == 0 && *(dev->filename + 4) != 0 ) { return SCSITAPE_FMTENTRY; } #endif // _MSVC_ #endif // OPTION_SCSI_TAPE #endif // HAVE_REGEX_H return -1; /* -1 == "unable to determine" */ } /* end function gettapetype_byname */ /*-------------------------------------------------------------------*/ /* gettapetype_bydata determine tape device type by file data */ /*-------------------------------------------------------------------*/ /* returns fmttab entry# on success, -1 on error/unable to determine */ /*-------------------------------------------------------------------*/ int gettapetype_bydata (DEVBLK *dev) { char pathname[MAX_PATH]; /* file path in host format */ int rc; /* various rtns return codes */ /* Try to determine the type based on actual file contents */ hostpath( pathname, dev->filename, sizeof(pathname) ); rc = hopen( pathname, O_RDONLY | O_BINARY ); if (rc >= 0) { BYTE hdr[6]; /* block header i/o buffer */ int fd = rc; /* save file descriptor */ /* Read the header. If bytes 0-3 are ASCII "0000", then the * tape is likely a Flex FakeTape. Otherwise if bytes 2-3 are * binary zero (x'0000'), it's likely an AWS type tape. If byte * 4 (first flag byte) has either of the ZLIB or BZIP2 flags on, * then it's a HET tape. Otherwise it's just an ordinary AWS tape. */ rc = read (fd, hdr, sizeof(hdr)); close(fd); if (rc >= 6) { /* Use the data to make the possible determination */ if (memcmp(hdr, "@TDF", 4) == 0) return OMATAPE_FMTENTRY; if (1 && hdr[0] == 0x30 /* "ASCII"-zero len prev block? */ && hdr[1] == 0x30 && hdr[2] == 0x30 && hdr[3] == 0x30 ) return FAKETAPE_FMTENTRY; /* Then obviously Flex FakeTape */ if (hdr[2] == 0 && hdr[3] == 0) /* 0 len prev blk? */ { if (hdr[4] & HETHDR_FLAGS1_TAPEMARK) /* If tapemark then */ return -1; /* can't tell type. */ if (hdr[4] & HETHDR_FLAGS1_COMPRESS || /* ZLIB or BZIP2 or */ hdr[5] & HETHDR_FLAGS2_COMPRESS) /* Bus-Tech ZLIB? */ return HETTAPE_FMTENTRY; /* Then HET format. */ else return AWSTAPE_FMTENTRY; /* Else default AWS */ } } } return -1; /* -1 == "unable to determine" */ } /* end function gettapetype_bydata */ /*-------------------------------------------------------------------*/ /* gettapetype determine tape device type */ /*-------------------------------------------------------------------*/ /* returns fmttab entry# on success, -1 on error/unable to determine */ /*-------------------------------------------------------------------*/ int gettapetype (DEVBLK *dev, char **short_descr) { char* descr; /* Device descr from fmttab */ int i; /* fmttab entry# */ i = gettapetype_byname( dev ); /* Get type based on name */ #if defined(OPTION_SCSI_TAPE) if (i != SCSITAPE_FMTENTRY) /* If not SCSI tape... */ #endif { int i2 = gettapetype_bydata( dev ); // Get type based on data.. if (i2 >= 0 && // If valid type by data, AND (i2 != AWSTAPE_FMTENTRY || // *not* AWS by data (or if it i != HETTAPE_FMTENTRY) // is, if it's not HET by name).. ) i = i2; // ..Use type based on data. } /* If file type still unknown, use a reasonable default value... */ if (i < 0) { i = DEFAULT_FMTENTRY; if (strcmp (dev->filename, TAPE_UNLOADED) != 0) logmsg (_("HHCTA003W %4.4X: Unable to determine tape format type for %s; presuming %s.\n"), dev->devnum, dev->filename, fmttab[i].short_descr ); } dev->tapedevt = fmttab[i].fmtcode; dev->tmh = fmttab[i].tmh; descr = fmttab[i].descr; *short_descr = fmttab[i].short_descr; if (strcmp (dev->filename, TAPE_UNLOADED) != 0) logmsg (_("HHCTA004I %4.4X: %s is a %s\n"), dev->devnum, dev->filename, descr); return 0; // (success) } /* end function gettapetype */ /*-------------------------------------------------------------------*/ /* The following table goes hand-in-hand with the 'enum' values */ /* that immediately follow. Used by 'mountnewtape' function. */ /*-------------------------------------------------------------------*/ PARSER ptab [] = { { "awstape", NULL }, { "idrc", "%d" }, { "compress", "%d" }, { "method", "%d" }, { "level", "%d" }, { "chunksize", "%d" }, { "maxsize", "%d" }, { "maxsizeK", "%d" }, { "maxsizeM", "%d" }, { "eotmargin", "%d" }, { "strictsize", "%d" }, { "readonly", "%d" }, { "ro", NULL }, { "noring", NULL }, { "rw", NULL }, { "ring", NULL }, { "deonirq", "%d" }, #if defined( OPTION_TAPE_AUTOMOUNT ) { "noautomount",NULL }, #endif { "--blkid-22", NULL }, { "--blkid-24", NULL }, /* (synonym for --blkid-22) */ { "--blkid-32", NULL }, { "--no-erg", NULL }, { NULL, NULL }, /* (end of table) */ }; /*-------------------------------------------------------------------*/ /* The following table goes hand-in-hand with the 'ptab' PARSER */ /* table immediately above. Used by 'mountnewtape' function. */ /*-------------------------------------------------------------------*/ enum { TDPARM_NONE, TDPARM_AWSTAPE, TDPARM_IDRC, TDPARM_COMPRESS, TDPARM_METHOD, TDPARM_LEVEL, TDPARM_CHKSIZE, TDPARM_MAXSIZE, TDPARM_MAXSIZEK, TDPARM_MAXSIZEM, TDPARM_EOTMARGIN, TDPARM_STRICTSIZE, TDPARM_READONLY, TDPARM_RO, TDPARM_NORING, TDPARM_RW, TDPARM_RING, TDPARM_DEONIRQ, #if defined( OPTION_TAPE_AUTOMOUNT ) TDPARM_NOAUTOMOUNT, #endif TDPARM_BLKID22, TDPARM_BLKID24, TDPARM_BLKID32, TDPARM_NOERG }; /*-------------------------------------------------------------------*/ /* mountnewtape -- mount a tape in the drive */ /*-------------------------------------------------------------------*/ /* */ /* Syntax: filename [options] */ /* */ /* where options are any of the entries in the 'ptab' PARSER */ /* table defined further above. Some commonly used options are: */ /* */ /* awstape sets the HET parms to be compatible with the */ /* R|P/390|'s tape file Format (HET files) */ /* */ /* idrc|compress 0|1: Write tape blocks with compression */ /* (std deviation: Read backward allowed on */ /* compressed HET tapes while it is not on */ /* IDRC formated 3480 tapes) */ /* */ /* --no-erg for SCSI tape only, means the hardware does */ /* not support the "Erase Gap" command and all */ /* such i/o's should return 'success' instead. */ /* */ /* --blkid-32 for SCSI tape only, means the hardware */ /* only supports full 32-bit block-ids. */ /* */ /*-------------------------------------------------------------------*/ int mountnewtape ( DEVBLK *dev, int argc, char **argv ) { char* short_descr; /* Short descr from fmttab */ int i; /* Loop control */ int rc, optrc; /* various rtns return codes */ union { /* Parser results */ U32 num; /* Parser results */ BYTE str[ 80 ]; /* Parser results */ } res; /* Parser results */ /* Release the previous OMA descriptor array if allocated */ if (dev->omadesc != NULL) { free (dev->omadesc); dev->omadesc = NULL; } /* The first argument is the file name */ if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1) strcpy (dev->filename, TAPE_UNLOADED); else /* Save the file name in the device block */ strcpy (dev->filename, argv[0]); /* Determine tape device type... */ VERIFY( gettapetype( dev, &short_descr ) == 0 ); /* (sanity check) */ ASSERT(dev->tapedevt != TAPEDEVT_UNKNOWN); ASSERT(dev->tmh != NULL); ASSERT(short_descr != NULL); /* Initialize device dependent fields */ dev->fd = -1; #if defined(OPTION_SCSI_TAPE) dev->sstat = GMT_DR_OPEN(-1); #endif dev->omadesc = NULL; dev->omafiles = 0; dev->curfilen = 1; dev->nxtblkpos = 0; dev->prvblkpos = -1; dev->curblkrem = 0; dev->curbufoff = 0; dev->readonly = 0; dev->hetb = NULL; dev->tdparms.compress = HETDFLT_COMPRESS; dev->tdparms.method = HETDFLT_METHOD; dev->tdparms.level = HETDFLT_LEVEL; dev->tdparms.chksize = HETDFLT_CHKSIZE; dev->tdparms.maxsize = 0; // no max size (default) dev->eotmargin = 128*1024; // 128K EOT margin (default) dev->tdparms.logical_readonly = 0; // read/write (default) #if defined( OPTION_TAPE_AUTOMOUNT ) dev->noautomount = 0; #endif #if defined(OPTION_SCSI_TAPE) // Real 3590's support Erase Gap and use 32-bit blockids. if (TAPEDEVT_SCSITAPE == dev->tapedevt && 0x3590 == dev->devtype) { dev->stape_no_erg = 0; // (default for 3590 SCSI) dev->stape_blkid_32 = 1; // (default for 3590 SCSI) } #endif #define HHCTA078E() logmsg (_("HHCTA078E %4.4X: option '%s' not valid for %s\n"), \ dev->devnum, argv[i], short_descr) /* Process remaining options */ rc = 0; for (i = 1; i < argc; i++) { optrc = 0; switch (parser (&ptab[0], argv[i], &res)) { case TDPARM_NONE: logmsg (_("HHCTA067E %4.4X: option '%s' unrecognized\n"), dev->devnum, argv[i]); optrc = -1; break; case TDPARM_AWSTAPE: if (0 || TAPEDEVT_SCSITAPE == dev->tapedevt || TAPEDEVT_FAKETAPE == dev->tapedevt ) { HHCTA078E(); optrc = -1; break; } dev->tdparms.compress = FALSE; dev->tdparms.chksize = 4096; break; case TDPARM_IDRC: case TDPARM_COMPRESS: if (0 || TAPEDEVT_SCSITAPE == dev->tapedevt || TAPEDEVT_FAKETAPE == dev->tapedevt ) { HHCTA078E(); optrc = -1; break; } dev->tdparms.compress = (res.num ? TRUE : FALSE); break; case TDPARM_METHOD: if (0 || TAPEDEVT_SCSITAPE == dev->tapedevt || TAPEDEVT_FAKETAPE == dev->tapedevt ) { HHCTA078E(); optrc = -1; break; } if (res.num < HETMIN_METHOD || res.num > HETMAX_METHOD) { logmsg(_("HHCTA068E %4.4X: option '%s': method must be within %u-%u\n"), dev->devnum, argv[i], HETMIN_METHOD, HETMAX_METHOD); optrc = -1; break; } dev->tdparms.method = res.num; break; case TDPARM_LEVEL: if (0 || TAPEDEVT_SCSITAPE == dev->tapedevt || TAPEDEVT_FAKETAPE == dev->tapedevt ) { HHCTA078E(); optrc = -1; break; } if (res.num < HETMIN_LEVEL || res.num > HETMAX_LEVEL) { logmsg(_("HHCTA069E %4.4X: option '%s': level must be within %u-%u\n"), dev->devnum, argv[i], HETMIN_LEVEL, HETMAX_LEVEL); optrc = -1; break; } dev->tdparms.level = res.num; break; case TDPARM_CHKSIZE: if (0 || TAPEDEVT_SCSITAPE == dev->tapedevt || TAPEDEVT_FAKETAPE == dev->tapedevt ) { HHCTA078E(); optrc = -1; break; } if (res.num < HETMIN_CHUNKSIZE || res.num > HETMAX_CHUNKSIZE) { logmsg (_("HHCTA070E %4.4X: option '%s': chunksize must be within %u-%u\n"), dev->devnum, argv[i], HETMIN_CHUNKSIZE, HETMAX_CHUNKSIZE); optrc = -1; break; } dev->tdparms.chksize = res.num; break; case TDPARM_MAXSIZE: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.maxsize=res.num; break; case TDPARM_MAXSIZEK: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.maxsize=res.num*1024; break; case TDPARM_MAXSIZEM: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.maxsize=res.num*1024*1024; break; case TDPARM_EOTMARGIN: dev->eotmargin=res.num; break; case TDPARM_STRICTSIZE: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.strictsize=res.num; break; case TDPARM_READONLY: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.logical_readonly=(res.num ? 1 : 0 ); break; case TDPARM_RO: case TDPARM_NORING: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.logical_readonly=1; break; case TDPARM_RW: case TDPARM_RING: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.logical_readonly=0; break; case TDPARM_DEONIRQ: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->tdparms.deonirq=(res.num ? 1 : 0 ); break; #if defined( OPTION_TAPE_AUTOMOUNT ) case TDPARM_NOAUTOMOUNT: if (TAPEDEVT_SCSITAPE == dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->noautomount = 1; break; #endif /* OPTION_TAPE_AUTOMOUNT */ #if defined(OPTION_SCSI_TAPE) case TDPARM_BLKID22: case TDPARM_BLKID24: if (TAPEDEVT_SCSITAPE != dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->stape_blkid_32 = 0; break; case TDPARM_BLKID32: if (TAPEDEVT_SCSITAPE != dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->stape_blkid_32 = 1; break; case TDPARM_NOERG: if (TAPEDEVT_SCSITAPE != dev->tapedevt) { HHCTA078E(); optrc = -1; break; } dev->stape_no_erg = 1; break; #endif /* defined(OPTION_SCSI_TAPE) */ default: logmsg(_("HHCTA071E %4.4X: option '%s': parse error\n"), dev->devnum, argv[i]); optrc = -1; break; } // end switch (parser (&ptab[0], argv[i], &res)) if (optrc < 0) rc = -1; else logmsg (_("HHCTA066I %4.4X: option '%s' accepted.\n"), dev->devnum, argv[i]); } // end for (i = 1; i < argc; i++) if (0 != rc) return -1; /* Adjust the display if necessary */ if(dev->tdparms.displayfeat) { if(strcmp(dev->filename,TAPE_UNLOADED)==0) { /* NO tape is loaded */ if(TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype) { /* A new tape SHOULD be mounted */ dev->tapedisptype = TAPEDISPTYP_MOUNT; dev->tapedispflags |= TAPEDISPFLG_REQAUTOMNT; strlcpy( dev->tapemsg1, dev->tapemsg2, sizeof(dev->tapemsg1) ); } else if(TAPEDISPTYP_UNMOUNT == dev->tapedisptype) { dev->tapedisptype = TAPEDISPTYP_IDLE; } } else { /* A tape IS already loaded */ dev->tapedisptype = TAPEDISPTYP_IDLE; } } UpdateDisplay(dev); ReqAutoMount(dev); return 0; } /* end function mountnewtape */ /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ void tapedev_query_device ( DEVBLK *dev, char **class, int buflen, char *buffer ) { char devparms[ MAX_PATH+1 + 128 ]; char dispmsg [ 256 ]; BEGIN_DEVICE_CLASS_QUERY( "TAPE", dev, class, buflen, buffer ); *buffer = 0; devparms[0]=0; dispmsg [0]=0; GetDisplayMsg( dev, dispmsg, sizeof(dispmsg) ); if (strchr(dev->filename,' ')) strlcat( devparms, "\"", sizeof(devparms)); strlcat( devparms, dev->filename, sizeof(devparms)); if (strchr(dev->filename,' ')) strlcat( devparms, "\"", sizeof(devparms)); #if defined( OPTION_TAPE_AUTOMOUNT ) if (dev->noautomount) strlcat( devparms, " noautomount", sizeof(devparms)); #endif /* OPTION_TAPE_AUTOMOUNT */ if ( strcmp( dev->filename, TAPE_UNLOADED ) == 0 ) { #if defined(OPTION_SCSI_TAPE) if ( TAPEDEVT_SCSITAPE == dev->tapedevt ) { if (0x3590 == dev->devtype) // emulating 3590 { if (!dev->stape_blkid_32 ) strlcat( devparms, " --blkid-22", sizeof(devparms) ); } else // emulating 3480, 3490 { if ( dev->stape_blkid_32 ) strlcat( devparms, " --blkid-32", sizeof(devparms) ); } if ( dev->stape_no_erg ) strlcat( devparms, " --no-erg", sizeof(devparms) ); } #endif snprintf(buffer, buflen, "%s%s%s", devparms, dev->tdparms.displayfeat ? ", Display: " : "", dev->tdparms.displayfeat ? dispmsg : ""); } else // (filename was specified) { char tapepos[64]; tapepos[0]=0; if ( TAPEDEVT_SCSITAPE != dev->tapedevt ) { snprintf( tapepos, sizeof(tapepos), "[%d:%08"I64_FMT"X] ", dev->curfilen, dev->nxtblkpos ); tapepos[sizeof(tapepos)-1] = 0; } #if defined(OPTION_SCSI_TAPE) else // (this is a SCSI tape drive) { if (STS_BOT( dev )) { dev->eotwarning = 0; strlcat(tapepos,"*BOT* ",sizeof(tapepos)); } // If tape has a display, then GetDisplayMsg already // appended *FP* for us. Otherwise we need to do it. if ( !dev->tdparms.displayfeat ) if (STS_WR_PROT( dev )) strlcat(tapepos,"*FP* ",sizeof(tapepos)); if (0x3590 == dev->devtype) // emulating 3590 { if (!dev->stape_blkid_32 ) strlcat( devparms, " --blkid-22", sizeof(devparms) ); } else // emulating 3480, 3490 { if ( dev->stape_blkid_32 ) strlcat( devparms, " --blkid-32", sizeof(devparms) ); } if ( dev->stape_no_erg ) strlcat( devparms, " --no-erg", sizeof(devparms) ); } #endif if ( TAPEDEVT_SCSITAPE != dev->tapedevt #if defined(OPTION_SCSI_TAPE) || STS_MOUNTED(dev) #endif ) { // Not a SCSI tape, -or- mounted SCSI tape... snprintf (buffer, buflen, "%s%s %s%s%s", devparms, (dev->readonly ? " ro" : ""), tapepos, dev->tdparms.displayfeat ? "Display: " : "", dev->tdparms.displayfeat ? dispmsg : ""); } else /* ( TAPEDEVT_SCSITAPE == dev->tapedevt && STS_NOT_MOUNTED(dev) ) */ { // UNmounted SCSI tape... snprintf (buffer, buflen, "%s%s (%sNOTAPE)%s%s", devparms, (dev->readonly ? " ro" : ""), dev->fd < 0 ? "closed; " : "", dev->tdparms.displayfeat ? ", Display: " : "", dev->tdparms.displayfeat ? dispmsg : "" ); } } buffer[buflen-1] = 0; } /* end function tapedev_query_device */ /*-------------------------------------------------------------------*/ /* Issue a message on the console indicating the display status */ /*-------------------------------------------------------------------*/ void UpdateDisplay( DEVBLK *dev ) { if ( dev->tdparms.displayfeat ) { char msgbfr[256]; GetDisplayMsg( dev, msgbfr, sizeof(msgbfr) ); if ( dev->prev_tapemsg ) { if ( strcmp( msgbfr, dev->prev_tapemsg ) == 0 ) return; free( dev->prev_tapemsg ); dev->prev_tapemsg = NULL; } dev->prev_tapemsg = strdup( msgbfr ); logmsg(_("HHCTA010I %4.4X: Now Displays: %s\n"), dev->devnum, msgbfr ); } #if defined(OPTION_SCSI_TAPE) else if (TAPEDEVT_SCSITAPE == dev->tapedevt) int_scsi_status_update( dev, 1 ); #endif } /*-------------------------------------------------------------------*/ /* Issue Automatic Mount Requests as defined by the display */ /*-------------------------------------------------------------------*/ void ReqAutoMount( DEVBLK *dev ) { char volser[7]; BYTE tapeloaded, autoload, mountreq, unmountreq, stdlbled, ascii, scratch; char* lbltype; char* tapemsg = ""; /////////////////////////////////////////////////////////////////// // The Automatic Cartridge Loader or "ACL" (sometimes also referred // to as an "Automatic Cartridge Feeder" (ACF) too) automatically // loads the next cartridge [from the magazine] whenever a tape is // unloaded, BUT ONLY IF the 'Index Automatic Load' bit (bit 7) of // the FCB (Format Control Byte, byte 0) was on whenever the Load // Display ccw was sent to the drive. If the bit was not on when // the Load Display ccw was issued, then the requested message (if // any) is displayed until the next tape mount/dismount and the ACL // is NOT activated (i.e. the next tape is NOT automatically loaded). // If the bit was on however, then, as stated, the ACF component of // the drive will automatically load the next [specified] cartridge. // Whenever the ACL facility is activated (via bit 7 of byte 0 of // the Load Display ccw), then only bytes 1-8 of the "Display Until // Mounted" message (or bytes 9-17 of a "Display Until Dismounted // Then Mounted" message) are displayed to let the operator know // which tape is currently being processed by the autoloader and // thus is basically for informational purposes only (the operator // does NOT need to do anything since the auto-loader is handling // tape mounts for them automatically; i.e. the message is NOT an // operator mount/dismount request). // If the 'Index Automatic Load' bit was not set in the Load Display // CCW however, then the specified "Display Until Mounted", "Display // Until Unmounted" or "Display Until Unmounted Then Display Until // Mounted" message is meant as a mount, unmount, or unmount-then- // mount request for the actual [human being] operator, and thus // they DO need to take some sort of action (since the ACL automatic // loader facility is not active; i.e. the message is a request to // the operator to manually unload, load or unload then load a tape). // THUS... If the TAPEDISPFLG_AUTOLOADER flag is set (indicating // the autoloader is (or should be) active), then the message we // issue is simply for INFORMATIONAL purposes only (i.e. "FYI: the // following tape is being *automatically* loaded; you don't need // to actually do anything") // If the TAPEDISPFLG_AUTOLOADER is flag is NOT set however, then // we need to issue a message notifying the operator of what they // are *expected* to do (e.g. either unload, load or unload/load // the specified tape volume). // Also please note that while there are no formally established // standards regarding the format of the Load Display CCW message // text, there are however certain established conventions (estab- // lished by IBM naturally). If the first character is an 'M', it // means "Please MOUNT the indicated volume". An 'R' [apparently] // means "Retain", and, similarly, 'K' means "Keep" (same thing as // "Retain"). If the LAST character is an 'S', then it means that // a Standard Labeled volume is being requested, whereas an 'N' // (or really, anything OTHER than an 'S' (except 'A')) means an // unlabeled (or non-labeled) tape volume is being requested. An // 'A' as the last character means a Standard Labeled ASCII tape // is being requested. If the message is "SCRTCH" (or something // similar), then a either a standard labeled or unlabeled scratch // tape is obviously being requested (there doesn't seem to be any // convention/consensus regarding the format for requesting scratch // tapes; some shops for example use 'XXXSCR' to indicate that a // scratch tape from tape pool 'XXX' should be mounted). /////////////////////////////////////////////////////////////////// /* Open the file/drive if needed (kick off auto-mount if needed) */ if (dev->fd < 0) { BYTE unitstat = 0, code = 0; BYTE *sensebkup; /* Save any pending sense */ sensebkup=malloc(dev->numsense); memcpy(sensebkup,dev->sense,dev->numsense); dev->tmh->open( dev, &unitstat, code ); /* Restore pending sense */ memcpy(dev->sense,sensebkup,dev->numsense); free(sensebkup); #if defined(OPTION_SCSI_TAPE) if (TAPEDEVT_SCSITAPE == dev->tapedevt) { // PROGRAMMING NOTE: it's important to do TWO refreshes here // to cause the auto-mount thread to get created. Doing only // one doesn't work and doing two shouldn't cause any harm. GENTMH_PARMS gen_parms; gen_parms.action = GENTMH_SCSI_ACTION_UPDATE_STATUS; gen_parms.dev = dev; // (refresh potentially stale status) VERIFY( dev->tmh->generic( &gen_parms ) == 0 ); // (force auto-mount thread creation) VERIFY( dev->tmh->generic( &gen_parms ) == 0 ); } #endif /* defined(OPTION_SCSI_TAPE) */ } /* Disabled when [non-SCSI] ACL in use */ if ( dev->als ) return; /* Do we actually have any work to do? */ if ( !( dev->tapedispflags & TAPEDISPFLG_REQAUTOMNT ) ) return; // (nothing to do!) /* Reset work flag */ dev->tapedispflags &= ~TAPEDISPFLG_REQAUTOMNT; /* If the drive doesn't have a display, then it can't have an auto-loader either */ if ( !dev->tdparms.displayfeat ) return; /* Determine if mount or unmount request and get pointer to correct message */ tapeloaded = dev->tmh->tapeloaded( dev, NULL, 0 ) ? TRUE : FALSE; mountreq = FALSE; // (default) unmountreq = FALSE; // (default) if (tapeloaded) { // A tape IS already loaded... // 1st byte of message1 non-blank, *AND*, // unmount request or, // unmountmount request and not message2-only flag? if (' ' != *(tapemsg = dev->tapemsg1) && (0 || TAPEDISPTYP_UNMOUNT == dev->tapedisptype || (1 && TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype && !(dev->tapedispflags & TAPEDISPFLG_MESSAGE2) ) ) ) unmountreq = TRUE; } else { // NO TAPE is loaded yet... // mount request and 1st byte of msg1 non-blank, *OR*, // unmountmount request and 1st byte of msg2 non-blank? if ( (1 && TAPEDISPTYP_MOUNT == dev->tapedisptype && ' ' != *(tapemsg = dev->tapemsg1) ) || (1 && TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype && ' ' != *(tapemsg = dev->tapemsg2) )) mountreq = TRUE; } /* Extract volser from message */ strncpy( volser, tapemsg+1, 6 ); volser[6]=0; /* Set some boolean flags */ autoload = ( dev->tapedispflags & TAPEDISPFLG_AUTOLOADER ) ? TRUE : FALSE; stdlbled = ( 'S' == tapemsg[7] ) ? TRUE : FALSE; ascii = ( 'A' == tapemsg[7] ) ? TRUE : FALSE; scratch = ( 'S' == tapemsg[0] ) ? TRUE : FALSE; lbltype = stdlbled ? "SL" : "UL"; #if defined(OPTION_SCSI_TAPE) #if 1 // **************************************************************** // ZZ FIXME: ZZ TODO: *** Programming Note *** // Since we currently don't have any way of activating a SCSI tape // drive's REAL autoloader mechanism whenever we receive an auto- // mount message [from the guest o/s via the Load Display CCW], we // leave it to the operator to action the mount message displayed // Once ASPI code eventually gets added to Herc (and/or something // similar for the Linux world), then the following workaround can // be safely removed. autoload = FALSE; // (temporarily forced; see above) // **************************************************************** #endif #endif /* defined(OPTION_SCSI_TAPE) */ if ( autoload ) { // ZZ TODO: Here is where we'd issue i/o (ASPI?) to the actual // hardware autoloader facility (i.e. the SCSI medium changer) // to unload and/or load the tape(s) if this were a SCSI auto- // loading tape drive. if ( unmountreq ) { if ( scratch ) logmsg(_("AutoMount: %s%s scratch tape being auto-unloaded on %4.4X = %s\n"), ascii ? "ASCII " : "",lbltype, dev->devnum, dev->filename); else logmsg(_("AutoMount: %s%s tape volume \"%s\" being auto-unloaded on %4.4X = %s\n"), ascii ? "ASCII " : "",lbltype, volser, dev->devnum, dev->filename); } if ( mountreq ) { if ( scratch ) logmsg(_("AutoMount: %s%s scratch tape being auto-loaded on %4.4X = %s\n"), ascii ? "ASCII " : "",lbltype, dev->devnum, dev->filename); else logmsg(_("AutoMount: %s%s tape volume \"%s\" being auto-loaded on %4.4X = %s\n"), ascii ? "ASCII " : "",lbltype, volser, dev->devnum, dev->filename); } } } /* end function ReqAutoMount */ /*-------------------------------------------------------------------*/ /* Get 3480/3490/3590 Display text in 'human' form */ /* If not a 3480/3490/3590, then just update status if a SCSI tape */ /*-------------------------------------------------------------------*/ void GetDisplayMsg( DEVBLK *dev, char *msgbfr, size_t lenbfr ) { msgbfr[0]=0; if ( !dev->tdparms.displayfeat ) { // (drive doesn't have a display) #if defined(OPTION_SCSI_TAPE) if (TAPEDEVT_SCSITAPE == dev->tapedevt) int_scsi_status_update( dev, 1 ); #endif return; } if ( !IS_TAPEDISPTYP_SYSMSG( dev ) ) { // ------------------------- // Display Host message // ------------------------- // "When bit 3 (alternate) is set to 1, then // bits 4 (blink) and 5 (low/high) are ignored." strlcpy( msgbfr, "\"", lenbfr ); if ( dev->tapedispflags & TAPEDISPFLG_ALTERNATE ) { char msg1[9]; char msg2[9]; strlcpy ( msg1, dev->tapemsg1, sizeof(msg1) ); strlcat ( msg1, " ", sizeof(msg1) ); strlcpy ( msg2, dev->tapemsg2, sizeof(msg2) ); strlcat ( msg2, " ", sizeof(msg2) ); strlcat ( msgbfr, msg1, lenbfr ); strlcat ( msgbfr, "\" / \"", lenbfr ); strlcat ( msgbfr, msg2, lenbfr ); strlcat ( msgbfr, "\"", lenbfr ); strlcat ( msgbfr, " (alternating)", lenbfr ); } else { if ( dev->tapedispflags & TAPEDISPFLG_MESSAGE2 ) strlcat( msgbfr, dev->tapemsg2, lenbfr ); else strlcat( msgbfr, dev->tapemsg1, lenbfr ); strlcat ( msgbfr, "\"", lenbfr ); if ( dev->tapedispflags & TAPEDISPFLG_BLINKING ) strlcat ( msgbfr, " (blinking)", lenbfr ); } if ( dev->tapedispflags & TAPEDISPFLG_AUTOLOADER ) strlcat( msgbfr, " (AUTOLOADER)", lenbfr ); return; } // ---------------------------------------------- // Display SYS message (Unit/Device message) // ---------------------------------------------- // First, build the system message, then move it into // the caller's buffer... strlcpy( dev->tapesysmsg, "\"", sizeof(dev->tapesysmsg) ); switch ( dev->tapedisptype ) { case TAPEDISPTYP_IDLE: case TAPEDISPTYP_WAITACT: default: // Blank display if no tape loaded... if ( !dev->tmh->tapeloaded( dev, NULL, 0 ) ) { strlcat( dev->tapesysmsg, " ", sizeof(dev->tapesysmsg) ); break; } // " NT RDY " if tape IS loaded, but not ready... // (IBM docs say " NT RDY " means "Loaded but not ready") ASSERT( dev->tmh->tapeloaded( dev, NULL, 0 ) ); if (0 || dev->fd < 0 #if defined(OPTION_SCSI_TAPE) || (1 && TAPEDEVT_SCSITAPE == dev->tapedevt && !STS_ONLINE( dev ) ) #endif ) { strlcat( dev->tapesysmsg, " NT RDY ", sizeof(dev->tapesysmsg) ); break; } // Otherwise tape is loaded and ready --> "READY" ASSERT( dev->tmh->tapeloaded( dev, NULL, 0 ) ); strlcat ( dev->tapesysmsg, " READY ", sizeof(dev->tapesysmsg) ); strlcat( dev->tapesysmsg, "\"", sizeof(dev->tapesysmsg) ); if (0 || dev->readonly #if defined(OPTION_SCSI_TAPE) || (1 && TAPEDEVT_SCSITAPE == dev->tapedevt && STS_WR_PROT( dev ) ) #endif ) // (append "file protect" indicator) strlcat ( dev->tapesysmsg, " *FP*", sizeof(dev->tapesysmsg) ); // Copy system message to caller's buffer strlcpy( msgbfr, dev->tapesysmsg, lenbfr ); return; case TAPEDISPTYP_ERASING: strlcat ( dev->tapesysmsg, " ERASING", sizeof(dev->tapesysmsg) ); break; case TAPEDISPTYP_REWINDING: strlcat ( dev->tapesysmsg, "REWINDNG", sizeof(dev->tapesysmsg) ); break; case TAPEDISPTYP_UNLOADING: strlcat ( dev->tapesysmsg, "UNLOADNG", sizeof(dev->tapesysmsg) ); break; case TAPEDISPTYP_CLEAN: strlcat ( dev->tapesysmsg, "*CLEAN ", sizeof(dev->tapesysmsg) ); break; } strlcat( dev->tapesysmsg, "\"", sizeof(dev->tapesysmsg) ); // Copy system message to caller's buffer strlcpy( msgbfr, dev->tapesysmsg, lenbfr ); } /* end function GetDisplayMsg */ /*-------------------------------------------------------------------*/ /* IsAtLoadPoint */ /*-------------------------------------------------------------------*/ /* Called by the device-type-specific 'build_sense_xxxx' functions */ /* (indirectly via the 'build_senseX' function) when building sense */ /* for any i/o error (non-"TAPE_BSENSE_STATUSONLY" type call) */ /*-------------------------------------------------------------------*/ int IsAtLoadPoint (DEVBLK *dev) { int ldpt=0; if ( dev->fd >= 0 ) { /* Set load point indicator if tape is at load point */ switch (dev->tapedevt) { default: case TAPEDEVT_AWSTAPE: if (dev->nxtblkpos==0) { ldpt=1; } break; case TAPEDEVT_HETTAPE: if (dev->hetb->cblk == 0) { ldpt=1; } break; #if defined(OPTION_SCSI_TAPE) case TAPEDEVT_SCSITAPE: int_scsi_status_update( dev, 0 ); if ( STS_BOT( dev ) ) { dev->eotwarning = 0; ldpt=1; } break; #endif /* defined(OPTION_SCSI_TAPE) */ case TAPEDEVT_OMATAPE: if (dev->nxtblkpos == 0 && dev->curfilen == 1) { ldpt=1; } break; } /* end switch(dev->tapedevt) */ } else // ( dev->fd < 0 ) { if ( TAPEDEVT_SCSITAPE == dev->tapedevt ) ldpt=0; /* (tape cannot possibly be at loadpoint if the device cannot even be opened!) */ else if ( strcmp( dev->filename, TAPE_UNLOADED ) != 0 ) { /* If the tape has a filename but the tape is not yet */ /* opened, then we are at loadpoint */ ldpt=1; } } return ldpt; } /* end function IsAtLoadPoint */ /*********************************************************************/ /*********************************************************************/ /** **/ /** AUTOLOADER FUNCTIONS **/ /** **/ /*********************************************************************/ /*********************************************************************/ /*-------------------------------------------------------------------*/ /* autoload_init */ /*-------------------------------------------------------------------*/ /* initialise the Autoloader feature */ /*-------------------------------------------------------------------*/ void autoload_init(DEVBLK *dev,int ac,char **av) { char bfr[4096]; char *rec; FILE *aldf; char *verb; int i; char *strtokw; char pathname[MAX_PATH]; autoload_close(dev); if(ac<1) { return; } if(av[0][0]!='@') { return; } logmsg(_("TAPE: Autoloader file request fn=%s\n"),&av[0][1]); hostpath(pathname, &av[0][1], sizeof(pathname)); if(!(aldf=fopen(pathname,"r"))) { return; } for(i=1;i=0;i--) { rec[i]=0; } if(strlen(rec)==0) { continue; } verb=strtok_r(rec," \t",&strtokw); if(verb==NULL) { continue; } if(verb[0]==0) { continue; } if(verb[0]=='#') { continue; } if(strcmp(verb,"*")==0) { while((verb=strtok_r(NULL," \t",&strtokw))) { autoload_global_parms(dev,verb); } continue; } autoload_tape_entry(dev,verb,&strtokw); } // end while((rec=fgets(bfr,4096,aldf))) fclose(aldf); return; } /* end function autoload_init */ /*-------------------------------------------------------------------*/ /* autoload_close */ /*-------------------------------------------------------------------*/ /* terminate autoloader operations: release all storage that */ /* was allocated by the autoloader facility */ /*-------------------------------------------------------------------*/ void autoload_close(DEVBLK *dev) { int i; if(dev->al_argv!=NULL) { for(i=0;ial_argc;i++) { free(dev->al_argv[i]); dev->al_argv[i]=NULL; } free(dev->al_argv); dev->al_argv=NULL; dev->al_argc=0; } dev->al_argc=0; if(dev->als!=NULL) { for(i=0;ialss;i++) { autoload_clean_entry(dev,i); } free(dev->als); dev->als=NULL; dev->alss=0; } } /* end function autoload_close */ /*-------------------------------------------------------------------*/ /* autoload_clean_entry */ /*-------------------------------------------------------------------*/ /* release storage allocated for an autoloader slot */ /* (except the slot itself) */ /*-------------------------------------------------------------------*/ void autoload_clean_entry(DEVBLK *dev,int ix) { int i; for(i=0;ials[ix].argc;i++) { free(dev->als[ix].argv[i]); dev->als[ix].argv[i]=NULL; } dev->als[ix].argc=0; if(dev->als[ix].filename!=NULL) { free(dev->als[ix].filename); dev->als[ix].filename=NULL; } } /* end function autoload_clean_entry */ /*-------------------------------------------------------------------*/ /* autoload_global_parms */ /*-------------------------------------------------------------------*/ /* Appends a blank delimited word to the list of parameters */ /* that will be passed for every tape mounted by the autoloader */ /*-------------------------------------------------------------------*/ void autoload_global_parms(DEVBLK *dev,char *par) { logmsg(_("TAPE Autoloader - Adding global parm %s\n"),par); if(dev->al_argv==NULL) { dev->al_argv=malloc(sizeof(char *)*256); dev->al_argc=0; } dev->al_argv[dev->al_argc]=(char *)malloc(strlen(par)+sizeof(char)); strcpy(dev->al_argv[dev->al_argc],par); dev->al_argc++; } /* end function autoload_global_parms */ /*-------------------------------------------------------------------*/ /* autoload_tape_entry */ /*-------------------------------------------------------------------*/ /* populate an autoloader slot (creates new slot if needed) */ /*-------------------------------------------------------------------*/ void autoload_tape_entry(DEVBLK *dev,char *fn,char **strtokw) { char *p; TAPEAUTOLOADENTRY tae; logmsg(_("TAPE Autoloader: Adding tape entry %s\n"),fn); memset(&tae,0,sizeof(tae)); tae.filename=malloc(strlen(fn)+sizeof(char)+1); strcpy(tae.filename,fn); while((p=strtok_r(NULL," \t",strtokw))) { if(tae.argv==NULL) { tae.argv=malloc(sizeof(char *)*256); } tae.argv[tae.argc]=malloc(strlen(p)+sizeof(char)+1); strcpy(tae.argv[tae.argc],p); tae.argc++; } if(dev->als==NULL) { dev->als=malloc(sizeof(tae)); dev->alss=0; } else { dev->als=realloc(dev->als,sizeof(tae)*(dev->alss+1)); } memcpy(&dev->als[dev->alss],&tae,sizeof(tae)); dev->alss++; } /* end function autoload_tape_entry */ /*-------------------------------------------------------------------*/ /* autoload_wait_for_tapemount_thread */ /*-------------------------------------------------------------------*/ void *autoload_wait_for_tapemount_thread(void *db) { int rc = -1; DEVBLK *dev = (DEVBLK*) db; obtain_lock(&dev->lock); { while ( dev->als && (rc = autoload_mount_next( dev )) != 0 ) { release_lock( &dev->lock ); SLEEP(AUTOLOAD_WAIT_FOR_TAPEMOUNT_INTERVAL_SECS); obtain_lock( &dev->lock ); } } release_lock(&dev->lock); if ( rc == 0 ) device_attention(dev,CSW_DE); return NULL; } /* end function autoload_wait_for_tapemount_thread */ /*-------------------------------------------------------------------*/ /* autoload_mount_first */ /*-------------------------------------------------------------------*/ /* mount in the drive the tape which is */ /* positionned in the 1st autoloader slot */ /*-------------------------------------------------------------------*/ int autoload_mount_first(DEVBLK *dev) { dev->alsix=0; return(autoload_mount_tape(dev,0)); } /*-------------------------------------------------------------------*/ /* autoload_mount_next */ /*-------------------------------------------------------------------*/ /* mount in the drive the tape whch is */ /* positionned in the slot after the currently mounted tape. */ /* if this is the last tape, close the autoloader */ /*-------------------------------------------------------------------*/ int autoload_mount_next(DEVBLK *dev) { if(dev->alsix>=dev->alss) { autoload_close(dev); return -1; } dev->alsix++; return(autoload_mount_tape(dev,dev->alsix)); } /*-------------------------------------------------------------------*/ /* autoload_mount_tape */ /*-------------------------------------------------------------------*/ /* mount in the drive the tape which is */ /* positionned in the autoloader slot #alix */ /*-------------------------------------------------------------------*/ int autoload_mount_tape(DEVBLK *dev,int alix) { char **pars; int pcount=1; int i; int rc; if(alix>=dev->alss) { return -1; } pars=malloc(sizeof(BYTE *)*256); pars[0]=dev->als[alix].filename; for(i=0;ial_argc;i++,pcount++) { pars[pcount]=malloc(strlen(dev->al_argv[i])+10); strcpy(pars[pcount],dev->al_argv[i]); if(pcount>255) { break; } } for(i=0;ials[alix].argc;i++,pcount++) { pars[pcount]=malloc(strlen(dev->als[alix].argv[i])+10); strcpy(pars[pcount],dev->als[alix].argv[i]); if(pcount>255) { break; } } rc=mountnewtape(dev,pcount,pars); for(i=1;ifilename, TAPE_UNLOADED ) != 0 ? 1 : 0; } /*-------------------------------------------------------------------*/ /* return_false1 */ /*-------------------------------------------------------------------*/ int return_false1 ( DEVBLK *dev ) { UNREFERENCED(dev); return 0; } /*-------------------------------------------------------------------*/ /* write_READONLY */ /*-------------------------------------------------------------------*/ int write_READONLY ( DEVBLK *dev, BYTE *unitstat, BYTE code ) { build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); return -1; } /*-------------------------------------------------------------------*/ /* write_READONLY5 */ /*-------------------------------------------------------------------*/ int write_READONLY5 ( DEVBLK *dev, BYTE *bfr, U16 blklen, BYTE *unitstat, BYTE code ) { UNREFERENCED(bfr); UNREFERENCED(blklen); build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); return -1; } /*-------------------------------------------------------------------*/ /* no_operation */ /*-------------------------------------------------------------------*/ int no_operation ( DEVBLK *dev, BYTE *unitstat, BYTE code ) { build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); return 0; } /*-------------------------------------------------------------------*/ /* readblkid_virtual */ /*-------------------------------------------------------------------*/ int readblkid_virtual ( DEVBLK* dev, BYTE* logical, BYTE* physical ) { // NOTE: returned value is always in guest BIG-ENDIAN format... BYTE blockid[4]; if (0x3590 == dev->devtype) { // Full 32-bit block-id... blockid[0] = (dev->blockid >> 24) & 0xFF; blockid[1] = (dev->blockid >> 16) & 0xFF; blockid[2] = (dev->blockid >> 8 ) & 0xFF; blockid[3] = (dev->blockid ) & 0xFF; } else // (3480 et. al) { // "22-bit" block-id... blockid[0] = 0x01; // ("wrap" value) blockid[1] = (dev->blockid >> 16) & 0x3F; blockid[2] = (dev->blockid >> 8 ) & 0xFF; blockid[3] = (dev->blockid ) & 0xFF; } // NOTE: For virtual tape devices, we return the same value // for both the logical "Channel block ID" value as well as // the physical "Device block ID" value... if (logical) memcpy( logical, &blockid[0], 4 ); if (physical) memcpy( physical, &blockid[0], 4 ); return 0; } /*-------------------------------------------------------------------*/ /* locateblk_virtual */ /*-------------------------------------------------------------------*/ int locateblk_virtual ( DEVBLK* dev, U32 blockid, BYTE *unitstat, BYTE code ) { // NOTE: 'blockid' passed in host (little-endian) format... int rc; /* Do it the hard way: rewind to load-point and then keep doing fsb, fsb, fsb... until we find our block */ if ((rc = dev->tmh->rewind( dev, unitstat, code)) >= 0) { /* Reset position counters to start of file */ dev->curfilen = 1; dev->nxtblkpos = 0; dev->prvblkpos = -1; dev->blockid = 0; /* Do it the hard way */ while ( dev->blockid < blockid && ( rc >= 0 ) ) rc = dev->tmh->fsb( dev, unitstat, code ); } return rc; } /*-------------------------------------------------------------------*/ /* generic_tmhcall generic media-type-handler call... */ /*-------------------------------------------------------------------*/ int generic_tmhcall ( GENTMH_PARMS* pGenParms ) { if (!pGenParms) { errno = EINVAL; // (invalid arguments) return -1; // (return failure) } switch (pGenParms->action) { #if defined(OPTION_SCSI_TAPE) case GENTMH_SCSI_ACTION_UPDATE_STATUS: { return update_status_scsitape( pGenParms->dev ); } #endif /* defined(OPTION_SCSI_TAPE) */ default: { errno = EINVAL; // (invalid arguments) return -1; // (return failure) } } return -1; // (never reached) } hercules-3.12/tapeccws.c0000664000175000017500000052621612564723224012174 00000000000000/* TAPECCWS.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Tape Device Handler CCW Processing */ /* Original Author: Roger Bowler */ /* Prime Maintainer: Ivan Warren */ /* Secondary Maintainer: "Fish" (David B. Trout) */ /*-------------------------------------------------------------------*/ /* This module contains the CCW handling functions for tape devices. */ /* */ /* The subroutines in this module are called by the general tape */ /* device handler (tapedev.c) when the tape format is AWSTAPE. */ /* */ /* Messages issued by this module are prefixed HHCTA0nn */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Reference information: */ /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide */ /* GA32-0331 IBM 3590 Hardware Reference */ /* GA32-0329 IBM 3590 Introduction and Planning Guide */ /* SG24-2594 IBM 3590 Multiplatform Implementation */ /* ANSI INCITS 131-1994 (R1999) SCSI-2 Reference */ /* GA32-0127 IBM 3490E Hardware Reference */ /* GC35-0152 EREP Release 3.5.0 Reference */ /* SA22-7204 ESA/390 Common I/O-Device Commands */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /* need Hercules control blocks */ #include "tapedev.h" /* Main tape handler header file */ //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING) #ifdef ENABLE_TRACING_STMTS #if !defined(DEBUG) #warning DEBUG required for ENABLE_TRACING_STMTS #endif // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h) #else #undef TRACE #undef ASSERT #undef VERIFY #define TRACE 1 ? ((void)0) : logmsg #define ASSERT(a) #define VERIFY(a) ((void)(a)) #endif /*-------------------------------------------------------------------*/ /* (forward declarations needed by below tables) */ /*-------------------------------------------------------------------*/ extern BYTE TapeCommands3410 []; extern BYTE TapeCommands3420 []; extern BYTE TapeCommands3422 []; extern BYTE TapeCommands3430 []; extern BYTE TapeCommands3480 []; extern BYTE TapeCommands3490 []; extern BYTE TapeCommands3590 []; extern BYTE TapeCommands9347 []; extern TapeSenseFunc build_sense_3410; extern TapeSenseFunc build_sense_3420; #define build_sense_3422 build_sense_3420 #define build_sense_3430 build_sense_3420 extern TapeSenseFunc build_sense_3480_etal; extern TapeSenseFunc build_sense_3490; extern TapeSenseFunc build_sense_3590; extern TapeSenseFunc build_sense_Streaming; /*-------------------------------------------------------------------*/ /* TapeDevtypeList */ /* Format: */ /* */ /* A: Supported Device Type, */ /* B: Command table index, (TapeCommandTable) */ /* C: UC on RewUnld, (1/0 = true/false) */ /* D: CUE on RewUnld, (1/0 = true/false) */ /* E: Sense Build Function table index (TapeSenseTable) */ /* */ /*-------------------------------------------------------------------*/ int TapeDevtypeList [] = { /* A B C D E */ 0x3410, 0, 1, 0, 0, 0x3411, 0, 1, 0, 0, 0x3420, 1, 1, 1, 1, 0x3422, 2, 0, 0, 2, 0x3430, 3, 0, 0, 3, 0x3480, 4, 0, 0, 4, 0x3490, 5, 0, 0, 5, 0x3590, 6, 0, 0, 6, 0x9347, 7, 0, 0, 7, 0x9348, 7, 0, 0, 7, 0x8809, 7, 0, 0, 7, 0x0000, 0, 0, 0, 0 /* (end of table marker) */ }; /*-------------------------------------------------------------------*/ /* TapeCommandTable */ /* */ /* Specific supported CCW codes for each device type. Index is */ /* fetched by TapeCommandIsValid from "TapeDevtypeList[ n+1 ]". */ /* */ /*-------------------------------------------------------------------*/ BYTE* TapeCommandTable [] = { TapeCommands3410, /* 0 3410/3411 */ TapeCommands3420, /* 1 3420 */ TapeCommands3422, /* 2 3422 */ TapeCommands3430, /* 3 3430 */ TapeCommands3480, /* 4 3480 (Maybe all 38K Tapes) */ TapeCommands3490, /* 5 3490 */ TapeCommands3590, /* 6 3590 */ TapeCommands9347, /* 7 9347 (Maybe all streaming tapes) */ NULL }; /*-------------------------------------------------------------------*/ /* TapeSenseTable */ /* */ /* SENSE function routing table. Index is fetched by 'build_senseX' */ /* function from table entry "TapeDevtypeList[ i+4 ]". */ /*-------------------------------------------------------------------*/ TapeSenseFunc* TapeSenseTable [] = { build_sense_3410, /* 0 3410/3411 */ build_sense_3420, /* 1 3420 */ build_sense_3422, /* 2 3422 */ build_sense_3430, /* 3 3430 */ build_sense_3480_etal, /* 4 3480 (Maybe all 38K Tapes) */ build_sense_3490, /* 5 3490 */ build_sense_3590, /* 6 3590 */ build_sense_Streaming, /* 7 9347 (Maybe all streaming tapes) */ NULL }; /*-------------------------------------------------------------------*/ /* CCW opcode Validity Tables by Device Type */ /*-------------------------------------------------------------------*/ /* */ /* The below tables are used by 'TapeCommandIsValid' to determine */ /* if a CCW code is initially valid or not for the given device. */ /* */ /* 0: Command is NOT valid */ /* * 1: Command is Valid, Tape MUST be loaded */ /* * 2: Command is Valid, Tape NEED NOT be loaded */ /* 3: Command is Valid, But is a NO-OP (return CE+DE now) */ /* 4: Command is Valid, But is a NO-OP (for virtual tapes) */ /* * 5: Command is Valid, Tape MUST be loaded (add DE to status) */ /* */ /* * Note that CCWs codes marked as valid might still get rejected */ /* upon more stringent validity testing done by the actual CCW */ /* processing function itself. */ /* */ /* SOURCES: */ /* */ /* GX20-1850-2 "S/370 Reference Summary" (3410/3411/3420) */ /* GX20-0157-1 "370/XA Reference Summary" (3420/3422/3430/3480) */ /* GA33-1510-0 "S/370 Model 115 FC" (3410/3411) */ /* */ /* Ivan Warren, 2003-02-24 */ /*-------------------------------------------------------------------*/ BYTE TapeCommands3410 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,1,1,1,2,0,0,5,0,0,0,0,1,0,0,5, /* 00 */ 0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */ 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 20 */ 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */ 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 60 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */ 0,0,0,4,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* A0 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* B0 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* C0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */ 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* F0 */ }; BYTE TapeCommands3420 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */ 0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */ 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 20 */ 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */ 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 60 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 80 */ 0,0,0,4,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* A0 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* B0 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* C0 */ 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */ 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */ 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */ }; BYTE TapeCommands3422 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 20 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 80 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */ 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */ 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */ 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */ 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */ }; BYTE TapeCommands3430 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */ 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 20 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */ 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */ 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */ 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */ 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */ }; BYTE TapeCommands3480 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 3,1,1,1,2,0,0,5,0,0,0,0,1,0,0,5, /* 00 */ 0,0,1,3,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */ 0,0,1,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 20 */ 0,0,0,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 30 */ 0,0,0,1,0,0,0,0,0,0,0,2,0,0,0,1, /* 40 */ 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0, /* 50 */ 0,0,0,3,2,0,0,0,0,0,0,3,0,0,0,0, /* 60 */ 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */ 0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,2, /* 90 */ 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,2, /* A0 */ 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* B0 */ 0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,0, /* C0 */ 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* D0 */ 0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0, /* E0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* F0 */ }; BYTE TapeCommands3490 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 3,1,1,1,2,0,0,5,0,0,0,0,1,0,0,5, /* 00 */ 0,0,1,3,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */ 0,0,1,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 20 */ 0,0,0,3,2,0,0,1,0,0,0,3,0,0,2,1, /* 30 */ 0,0,0,1,0,0,0,0,0,0,0,2,0,0,2,1, /* 40 */ 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* 50 */ 0,0,0,3,2,0,0,0,0,0,0,3,0,0,0,0, /* 60 */ 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */ 0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,2, /* 90 */ 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,2, /* A0 */ 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* B0 */ 0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0, /* C0 */ 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* D0 */ 0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0, /* E0 */ 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0 /* F0 */ }; BYTE TapeCommands3590 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 3,1,1,1,2,0,1,5,0,0,1,0,1,0,0,5, /* 00 */ 0,0,1,3,0,0,0,1,0,0,0,0,0,0,0,1, /* 10 */ 0,0,1,3,2,0,0,1,0,0,0,3,0,0,0,1, /* 20 */ 0,0,0,3,2,0,0,1,0,0,0,3,0,0,2,1, /* 30 */ 0,0,0,1,0,0,0,0,0,0,0,2,0,0,2,1, /* 40 */ 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* 50 */ 0,0,1,3,2,0,0,0,0,0,0,3,0,0,0,0, /* 60 */ 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */ 0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,2, /* 90 */ 0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,2, /* A0 */ 0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,0, /* B0 */ 0,0,2,2,0,0,0,2,0,0,0,0,0,0,0,2, /* C0 */ 0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0, /* D0 */ 0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0, /* E0 */ 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0 /* F0 */ }; BYTE TapeCommands9347 [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,1,1,1,2,0,0,5,0,0,0,2,1,0,0,5, /* 00 */ 0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */ 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 20 */ 0,0,0,4,0,0,0,1,0,0,0,4,0,0,0,1, /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 40 */ 0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 60 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0, /* 80 */ 0,0,0,4,0,0,0,1,0,0,0,0,0,0,0,0, /* 90 */ 0,0,0,4,2,0,0,0,0,0,0,4,0,0,0,0, /* A0 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* B0 */ 0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0, /* C0 */ 0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0, /* D0 */ 0,0,0,0,2,0,0,0,0,0,0,3,0,0,0,0, /* E0 */ 0,0,0,2,4,0,0,0,0,0,0,0,0,2,0,0 /* F0 */ }; /*-------------------------------------------------------------------*/ /* Ivan Warren 20040227 */ /* */ /* This table is used by channel.c to determine if a CCW code */ /* is an immediate command or not. */ /* */ /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */ /* */ /* 0: ("false") Command is *NOT* an immediate command */ /* 1: ("true") Command *IS* an immediate command */ /* */ /* Note: An immediate command is defined as a command which returns */ /* CE (channel end) during initialization (that is, no data is */ /* actually transfered). In this case, IL is not indicated for a */ /* Format 0 or Format 1 CCW when IL Suppression Mode is in effect. */ /* */ /*-------------------------------------------------------------------*/ BYTE TapeImmedCommands [256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1, /* 00 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 10 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 20 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 30 */ 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, /* 40 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 50 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 60 */ 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1, /* 70 */ /* Adrian Trenkwalder - 77 was 1 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* 80 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0, /* 90 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0, /* A0 */ 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1, /* B0 */ 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1, /* C0 */ 0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1, /* D0 */ 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1, /* E0 */ 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1 /* F0 */ }; /*-------------------------------------------------------------------*/ /* TapeCommandIsValid (Ivan Warren 20030224) */ /*-------------------------------------------------------------------*/ /* */ /* Determine if a CCW code is valid for the Device */ /* */ /* rc 0: is *NOT* valid */ /* rc 1: is Valid, tape MUST be loaded */ /* rc 2: is Valid, tape NEED NOT be loaded */ /* rc 3: is Valid, But is a NO-OP (Return CE+DE now) */ /* rc 4: is Valid, But is a NO-OP for virtual tapes */ /* rc 5: is Valid, Tape Must be loaded - Add DE to status */ /* rc 6: is Valid, Tape load attempted - but not an error */ /* (used for sense and no contingency allegiance exists) */ /* */ /*-------------------------------------------------------------------*/ int TapeCommandIsValid (BYTE code, U16 devtype, BYTE *rustat) { int i, rc, tix = 0, devtfound = 0; /* ** Find the D/T in the table ** If not found, treat as invalid CCW code */ *rustat = 0; for (i = 0; TapeDevtypeList[i] != 0; i += TAPEDEVTYPELIST_ENTRYSIZE) { if (TapeDevtypeList[i] == devtype) { devtfound = 1; tix = TapeDevtypeList[i+1]; if (TapeDevtypeList[i+2]) { *rustat |= CSW_UC; } if (TapeDevtypeList[i+3]) { *rustat |= CSW_CUE; } break; } } if (!devtfound) return 0; rc = TapeCommandTable[tix][code]; return rc; } /* end function TapeCommandIsValid */ /*********************************************************************/ /*********************************************************************/ /** **/ /** MAIN TAPE CCW PROCESSING FUNCTION **/ /** **/ /*********************************************************************/ /*********************************************************************/ #if defined( OPTION_TAPE_AUTOMOUNT ) static TAMDIR* findtamdir( int rej, int minlen, const char* pszDir ); #endif void tapedev_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual) { int rc; /* Return code */ int len; /* Length of data block */ long num; /* Number of bytes to read */ int drc; /* code disposition */ BYTE rustat; /* Addl CSW stat on Rewind Unload */ UNREFERENCED(ccwseq); /* Reset flags at start of CCW chain */ if (dev->ccwseq == 0) { dev->supvr_inhibit = 0; /* (reset to default mode) */ dev->write_immed = 0; /* (reset to default mode) */ dev->tapssdlen = 0; /* (clear all subsys data) */ } /* If this is a data-chained READ, then return any data remaining in the buffer which was not used by the previous CCW */ if (chained & CCW_FLAGS_CD) { if (IS_CCW_RDBACK(code)) { /* We don't need to move anything in this case - just set length */ } else { memmove (iobuf, iobuf + dev->curbufoff, dev->curblkrem); } RESIDUAL_CALC (dev->curblkrem); dev->curblkrem -= num; dev->curbufoff = num; *unitstat = CSW_CE | CSW_DE; return; } /* Command reject if data chaining and command is not a read type */ if ((flags & CCW_FLAGS_CD) && !(IS_CCW_READ(code) || IS_CCW_RDBACK(code))) { logmsg(_("HHCTA072E Data chaining not supported for CCW %2.2X\n"), code); build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); return; } /* Command reject if command is not Read Subsystem Data command if the previous one was a Perform Subsystem Function command that prepared some subsystem data for subsequent reading */ if (0x77 == prevcode && dev->tapssdlen && 0x3E != code) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); return; } /* Early determination of CCW validity via TapeCommandTable lookup... */ drc = TapeCommandIsValid (code, dev->devtype, &rustat); switch (drc) { default: /* Should NOT occur! */ ASSERT(0); // (fall thru to case 0 = unsupported) case 0: /* Unsupported CCW code for given device-type */ build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); return; case 1: /* Valid - Tape MUST be loaded */ break; case 2: /* Valid - Tape NEED NOT be loaded */ break; case 3: /* Valid - But is a NO-OP (return CE+DE now) */ /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); return; } build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); return; case 4: /* Valid, But is a NO-OP (for virtual tapes) */ /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); return; } /* If non-virtual (SCSI) then further processing required */ if (dev->tapedevt == TAPEDEVT_SCSITAPE) break; build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); return; case 5: /* Valid - Tape MUST be loaded (add DE to status) */ break; } // end switch (drc) /* Verify a tape is loaded if that is required for this CCW... */ if ((1 == drc || 5 == drc) && // (tape MUST be loaded?) (dev->fd < 0 || TAPEDEVT_SCSITAPE == dev->tapedevt)) // (no tape loaded or non-virtual?) { *residual = count; /* Error if tape unloaded */ if (!strcmp (dev->filename, TAPE_UNLOADED)) { build_senseX (TAPE_BSENSE_TAPEUNLOADED, dev, unitstat, code); return; } /* Open the device file if necessary */ if (dev->fd < 0) { rc = dev->tmh->open( dev, unitstat, code ); if (rc < 0) /* Did open fail? */ { return; /* Yes, exit with unit status */ } } /* Error if tape is not loaded */ if (!dev->tmh->tapeloaded( dev, unitstat, code )) { build_senseX (TAPE_BSENSE_TAPEUNLOADED, dev, unitstat, code); return; } } /* Process depending on CCW opcode */ switch (code) { /*---------------------------------------------------------------*/ /* MODE SET (pre-3480 and earlier drives) */ /*---------------------------------------------------------------*/ /* Patch to no-op modeset 1 (7-track) commands - */ /* causes VM problems */ /* Andy Norrie 2002/10/06 */ case 0x13: case 0x23: case 0x33: case 0x3B: case 0x53: case 0x63: case 0x6B: // case 0x73: // Mode Set (7-track 556/Odd/Normal) for 3420-3/5/7 // with 7-track feature installed, No-op for 3420-2/4/6 // and 3480, Invalid for 3422/3430, "Set Interface // Identifier" for 3490 and later. NOTE: 3480 and earlier // interpretation handled by command-table; 3490 and // and later handled further below. case 0x7B: case 0x93: case 0xA3: case 0xAB: case 0xB3: case 0xBB: // case 0xC3: // Mode Set (9-track 1600 bpi) for models earlier than // 3480, "Set Tape-Write-Immediate" for 3480 and later. // NOTE: handled by command-table for all models earlier // than 3480; 3480 and later handled further below. case 0xCB: /* 9-track 800 bpi */ case 0xD3: /* 9-track 6250 bpi */ case 0xEB: /* invalid mode set issued by DOS/VS */ { build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code); break; } /*---------------------------------------------------------------*/ /* WRITE */ /*---------------------------------------------------------------*/ case 0x01: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Unit check if tape is write-protected */ if (dev->readonly || dev->tdparms.logical_readonly) { build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Write a block to the tape according to device type */ if ((rc = dev->tmh->write( dev, iobuf, count, unitstat, code)) < 0) break; // (error) *residual = 0; /* Perform flush/sync and/or set normal completion status */ if (0 || !dev->write_immed || (rc = dev->tmh->sync( dev, unitstat, code )) == 0 ) build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); break; } /*---------------------------------------------------------------*/ /* READ FORWARD (3590 only) */ /*---------------------------------------------------------------*/ case 0x06: { /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide 5.2.1 Separate Channel Commands for IPL Read and Normal Read On IBM 3480/3490 tape devices there is only one Read Forward CCW, the X'02' command code. This CCW is used to perform not only normal read operations but also an IPL Read from tape, for example, DFSMSdss Stand-Alone Restore. When the CCW is used as an IPL Read, it is not subject to resetting event notification, by definition. Because there is only one Read Forward CCW, it cannot be subject to resetting event notification on IBM 3480 and 3490 devices. To differentiate between an IPL Read and a normal read forward operation, the X'02' command code has been redefined to be the IPL Read CCW, and a new X'06' command code has been defined to be the Read Forward CCW. The new Read Forward CCW, X'06', is subject to resetting event notification, as should be the case for normal read CCWs issued by applications or other host software. */ // PROGRAMMING NOTE: I'm not sure what they mean by "resetting // event notification" above, but for now we'll just FALL THROUGH // to the below IPL READ logic... } // (purposely FALL THROUGH to below IPL READ logic for now) /*---------------------------------------------------------------*/ /* IPL READ (non-3590) */ /*---------------------------------------------------------------*/ case 0x02: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Read a block from the tape according to device type */ /* Exit with unit check status if read error condition */ if ((len = dev->tmh->read( dev, iobuf, unitstat, code)) < 0) break; // (error) /* Calculate number of bytes to read and residual byte count */ RESIDUAL_CALC (len); /* Save size and offset of data not used by this CCW */ dev->curblkrem = len - num; dev->curbufoff = num; /* Exit with unit exception status if tapemark was read */ if (len == 0) build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code); else build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ case 0x03: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ case 0x04: { /* Calculate residual byte count */ RESIDUAL_CALC (dev->numsense); /* If we don't already have some sense already pre-built and ready and waiting, then we'll have to build it fresh for this call... Otherwise, we use whatever we already have waiting for them pre-built from a previous call... */ if (!dev->sns_pending) build_senseX (TAPE_BSENSE_UNSOLICITED, dev, unitstat, code); *unitstat = CSW_CE|CSW_DE; /* Need to do this ourselves as */ /* we might not have gone thru */ /* build_senseX... */ /* Copy device sense bytes to channel I/O buffer, clear them for the next time, and then finally, reset the Contengent Allegiance condition... */ memcpy (iobuf, dev->sense, num); memset (dev->sense, 0, sizeof(dev->sense)); dev->sns_pending = 0; break; } /*---------------------------------------------------------------*/ /* READ FORWARD (3590 only) */ /*---------------------------------------------------------------*/ // case 0x06: // { // (handled by case 0x02: IPL READ) // } /*---------------------------------------------------------------*/ /* REWIND */ /*---------------------------------------------------------------*/ case 0x07: { /* Update matrix display if needed */ if ( TAPEDISPTYP_IDLE == dev->tapedisptype || TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_REWINDING; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Do the rewind */ rc = dev->tmh->rewind( dev, unitstat, code); /* Update matrix display if needed */ if ( TAPEDISPTYP_REWINDING == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Check for error */ if (rc < 0) { dev->fenced = 1; break; } dev->eotwarning = 0; dev->fenced = 0; build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* READ PREVIOUS (3590) */ /*---------------------------------------------------------------*/ case 0x0A: { /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide 5.2.2 Read Previous to Replace Read Backward: The ESCON-attached Magstar tape drive does not support the Read Backward CCW (command code, X'0C'). It supports a new Read Previous CCW that allows processing of an IBM 3590 High Performance Tape Cartridge in the backward direction without the performance penalties that exist with the Read Backward CCW. IBM 3480 and 3490 devices had to reread the physical block from the medium for each request of a logical block. The Magstar tape drive retains the physical block in the device buffer and satisfies any subsequent Read Previous from the buffer, similar to how Read Forward operates. The Read Previous CCW operates somewhat like the Read Backward CCW in that it can be used to process the volumes in the backward direction. It is different from the Read Backward, however, because the data is transferred to the host in the same order in which it was written, rather than in reverse order like Read Backward. */ /* SG24-2594 IBM 3590 Multiplatform Implementation 5.1.2 New and Changed Read Channel Commands [...] That is, the Read Backward command's data address will point to the end of the storage area, while a Read Previous command points to the beginning of the storage area... */ // PROGRAMMING NOTE: luckily, channel.c's buffer handling // causes transparent handling of Read Backward/Reverse, // so the above buffer alignment and data transfer order // is not a concern for us here. // PROGRAMMING NOTE: until we can add support to Hercules // allowing direct SCSI i/o (so that we can issue the 'Read // Reverse' command directly to the SCSI device), we will // simply FALL THROUGH to our existing "Read Backward" logic. } // (purposely FALL THROUGH to the 'READ BACKWARD' logic below) /*---------------------------------------------------------------*/ /* READ BACKWARD */ /*---------------------------------------------------------------*/ case 0x0C: { /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Backspace to previous block according to device type */ /* Exit with unit check status if error condition */ if ((rc = dev->tmh->bsb( dev, unitstat, code )) < 0) break; // (error) /* Exit with unit exception status if tapemark was sensed */ if (rc == 0) { *residual = 0; build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code); break; } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Now read in a forward direction the actual data block we just backspaced over, and exit with unit check status on any read error condition */ if ((len = dev->tmh->read( dev, iobuf, unitstat, code )) < 0) break; // (error) /* Calculate number of bytes to read and residual byte count */ RESIDUAL_CALC (len); /* Save size and offset of data not used by this CCW */ dev->curblkrem = len - num; dev->curbufoff = num; /* Backspace to previous block according to device type, and exit with unit check status if error condition */ if ((rc = dev->tmh->bsb( dev, unitstat, code )) < 0) break; // (error) /* Set normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /* End case 0x0C: READ BACKWARD */ /*---------------------------------------------------------------*/ /* REWIND UNLOAD */ /*---------------------------------------------------------------*/ case 0x0F: { /* Update matrix display if needed */ if ( dev->tdparms.displayfeat ) { if ( TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_MOUNT; dev->tapedispflags |= TAPEDISPFLG_REQAUTOMNT; strlcpy( dev->tapemsg1, dev->tapemsg2, sizeof(dev->tapemsg1) ); } else if ( TAPEDISPTYP_UNMOUNT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; } } if ( TAPEDISPTYP_IDLE == dev->tapedisptype || TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_UNLOADING; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Do the Rewind-Unload */ #if defined(OPTION_SCSI_TAPE) if ( TAPEDEVT_SCSITAPE == dev->tapedevt ) int_scsi_rewind_unload( dev, unitstat, code ); else #endif { dev->tmh->close(dev); *unitstat=0; } /* Update matrix display if needed */ if ( TAPEDISPTYP_UNLOADING == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } if ((*unitstat & CSW_UC) != 0) // (did it work?) break; // (no it didn't) dev->curfilen = 1; dev->nxtblkpos = 0; dev->prvblkpos = -1; dev->eotwarning = 0; // dev->fenced = 0; // (handler already did this) /* Update matrix display */ UpdateDisplay( dev ); build_senseX(TAPE_BSENSE_RUN_SUCCESS,dev,unitstat,code); if ( dev->als ) { TID dummy_tid; char thread_name[64]; snprintf(thread_name,sizeof(thread_name), "autoload wait for %4.4X tapemount thread", dev->devnum); thread_name[sizeof(thread_name)-1] = 0; create_thread( &dummy_tid, DETACHED, autoload_wait_for_tapemount_thread, dev, thread_name ); } ReqAutoMount( dev ); break; } /* End case 0x0F: REWIND UNLOAD */ /*---------------------------------------------------------------*/ /* READ BUFFER (3480 and later) */ /*---------------------------------------------------------------*/ case 0x12: { /* GA32-0127 IBM 3490E Hardware Reference Read Buffer (X'12') The Read Buffer command transfers data from the control unit to the channel if any buffered write data is in the control unit's buffer. For each Read Buffer command completed, the controlling computer retrieves one block of data in last-in/ first-out (LIFO) sequence until the buffer for the addressed tape drive is empty. The controlling computer usually issues this command when the tape drive or subsystem malfunctions and cannot write data from the buffer to the tape. */ /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } // PROGRAMMING NOTE: until we can add support for performing // SCSI i/o directly to the actual real device, we simply do // the same thing for non-virtual devices as we do for virtual // ones: we force-flush the data to the device (i.e. sync) // and then tell the truth: that there's zero bytes of data // still buffered (which is true if we just flushed it all) // Once we add direct SCSI i/o support though, we can change // the below to do an actual read-buffer SCSI command for // non-virtual devices. (We will still always need the below // for virtual devices though) /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); // Perform flush/sync; exit on error... if ((rc = dev->tmh->sync( dev, unitstat, code )) < 0) break; // (i/o error) // Flush complete. Our buffer is now empty. Tell them that. RESIDUAL_CALC (0); dev->curblkrem = 0; dev->curbufoff = 0; break; } /*---------------------------------------------------------------*/ /* ERASE GAP */ /*---------------------------------------------------------------*/ case 0x17: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Unit check if tape is write-protected */ if (dev->readonly || dev->tdparms.logical_readonly) { build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Do the ERG; exit if error */ if ((rc = dev->tmh->erg( dev, unitstat, code )) < 0) break; // (error) /* Perform flush/sync and/or set normal completion status */ if (0 || !dev->write_immed || (rc = dev->tmh->sync( dev, unitstat, code )) == 0 ) build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); break; } /*---------------------------------------------------------------*/ /* WRITE TAPE MARK */ /*---------------------------------------------------------------*/ case 0x1F: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Unit check if tape is write-protected */ if (dev->readonly || dev->tdparms.logical_readonly) { build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Do the WTM; exit if error */ if ((rc = dev->tmh->wtm(dev,unitstat,code)) < 0) break; // (error) dev->curfilen++; /* Perform flush/sync and/or set normal completion status */ if (0 || !dev->write_immed || (rc = dev->tmh->sync( dev, unitstat, code )) == 0 ) build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); break; } /*---------------------------------------------------------------*/ /* READ BLOCK ID */ /*---------------------------------------------------------------*/ case 0x22: { BYTE log_blockid [4]; // (temp; BIG-ENDIAN format) BYTE phys_blockid [4]; // (temp; BIG-ENDIAN format) int errcode = TAPE_BSENSE_STATUSONLY; // (presume success) /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Calculate number of bytes and residual byte count */ RESIDUAL_CALC( 2 * sizeof(dev->blockid) ); /* Ask media handler for actual value(s)... */ if ((rc = dev->tmh->readblkid( dev, log_blockid, phys_blockid )) < 0) errcode = TAPE_BSENSE_LOCATEERR; else { /* Copy results to channel I/O buffer... */ memcpy( &iobuf[0], log_blockid, 4 ); memcpy( &iobuf[4], phys_blockid, 4 ); } /* Set completion status... */ build_senseX( errcode, dev, unitstat, code ); break; } /*---------------------------------------------------------------*/ /* READ BUFFERED LOG */ /*---------------------------------------------------------------*/ case 0x24: { /* Calculate residual byte count... */ // PROGRAMMING NOTE: technically we *should* have up to // 64 bytes to give them, but we may not have that many. /* How many bytes we SHOULD have depends on whether Extended Buffered Log support is enabled or not */ len = (dev->devchar[8] & 0x01) ? 64 : 32; RESIDUAL_CALC (len); /* Clear the device sense bytes */ memset (iobuf, 0, num); /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, dev->numsense < (U32)num ? dev->numsense : (U32)num); /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* BACKSPACE BLOCK */ /*---------------------------------------------------------------*/ case 0x27: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Backspace to previous block according to device type, and exit with unit check status on error condition */ if ((rc = dev->tmh->bsb( dev, unitstat, code )) < 0) break; /* Exit with unit exception status if tapemark was sensed */ if (rc == 0) { build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code); break; } /* Set normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* BACKSPACE FILE */ /*---------------------------------------------------------------*/ case 0x2F: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Backspace to previous file according to device type, and exit with unit check status on error condition */ if ((rc = dev->tmh->bsf( dev, unitstat, code )) < 0) break; /* Set normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* SENSE PATH GROUP ID */ /*---------------------------------------------------------------*/ case 0x34: { /* GA32-0127 IBM 3490E Hardware Reference Sense Path Group ID (X'34') The Sense Path Group ID command transfers 12 bytes of information from the control unit to the channel. The first byte (byte 0) is the path state byte, and the remaining 11 bytes (bytes 1-11) contain the path-group ID. The bit assignments in the path state byte (byte 0) are: ________ ________ ____________________________________ | Bit | Value | Description | |________|________|____________________________________| | 0, 1 | | Pathing Status | |________|________|____________________________________| | | 00 | Reset | |________|________|____________________________________| | | 01 | Reserved | |________|________|____________________________________| | | 10 | Ungrouped | |________|________|____________________________________| | | 11 | Grouped | |________|________|____________________________________| | 2, 3 | | Partitioning State | |________|________|____________________________________| | | 00 | Implicitly Enabled | |________|________|____________________________________| | | 01 | Reserved | |________|________|____________________________________| | | 10 | Disabled | |________|________|____________________________________| | | 11 | Explicitly Enabled | |________|________|____________________________________| | 4 | | Path Mode | |________|________|____________________________________| | | 0 | Single path mode. | | | 1 | Reserved, invalid for this device. | |________|________|____________________________________| | 5-7 | 000 | Reserved | |________|________|____________________________________| */ /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Command reject if the command is not the ONLY command in the channel program */ if (chained & CCW_FLAGS_CC) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (12); /* Byte 0 is the path group state byte */ iobuf[0] = dev->pgstat; /* Bytes 1-11 contain the path group identifier */ if (num > 1) memcpy (iobuf+1, dev->pgid, num-1); /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /* End case 0x34: SENSE PATH GROUP ID */ /*---------------------------------------------------------------*/ /* FORWARD SPACE BLOCK */ /*---------------------------------------------------------------*/ case 0x37: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Forward to next block according to device type */ /* Exit with unit check status if error condition */ if ((rc = dev->tmh->fsb( dev, unitstat, code )) < 0) break; /* Exit with unit exception status if tapemark was sensed */ if (rc == 0) { build_senseX (TAPE_BSENSE_READTM, dev, unitstat, code); break; } /* Set normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* READ SUBSYSTEM DATA (3490/3590) */ /*---------------------------------------------------------------*/ case 0x3E: { /* GA32-0127 IBM 3490E Hardware Reference Read Subsystem Data (X'3E') The Read Subsystem Data command obtains various types of information from the 3480/3490 subsystem. The data presented is dependent on the command immediately preceding the Read Subsystem Data command in the command chain. If the preceding command in the command chain is a Perform Subsystem Function command with the Prepare for Read Subsystem Data order, the data presented is a function of the sub-order in the data transferred with the order. */ /* Command reject if not chained from either a Set Interface Identifier or Perform Subsystem Function command */ if (!((chained & CCW_FLAGS_CC) && (0x77 == prevcode || 0x73 == prevcode))) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } /* Command reject if no subsystem data was prepared by a previous Perform Subsystem Function command */ if (!dev->tapssdlen) // (any subsystem data?) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (dev->tapssdlen); /* PROGRAMMING NOTE: the Prepare for Read Subsystem Data order of the previous Perform Subsystem Function command has already prepared the subsystem data directly in the channel buffer itself (iobuf), so there isn't any data that actually needs to be moved/copied; the data is already sitting in the channel buffer. All we need do is return a normal status. */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /* End case 0x3E: READ SUBSYSTEM DATA */ /*---------------------------------------------------------------*/ /* FORWARD SPACE FILE */ /*---------------------------------------------------------------*/ case 0x3F: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Forward to next file according to device type */ /* Exit with unit check status if error condition */ if ((rc = dev->tmh->fsf( dev, unitstat, code )) < 0) break; /* Set normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* SYNCHRONIZE (3480 or later) */ /*---------------------------------------------------------------*/ case 0x43: { /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Do the sync */ if ((rc = dev->tmh->sync( dev, unitstat, code )) == 0) build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); break; } #if defined( OPTION_TAPE_AUTOMOUNT ) /*---------------------------------------------------------------*/ /* SET DIAGNOSE -- Special AUTOMOUNT support -- */ /*---------------------------------------------------------------*/ case 0x4B: { int argc, i; /* work */ char **argv; /* work */ char newfile [ sizeof(dev->filename) ]; /* work */ char lcss[8]; /* work */ /* Command reject if AUTOMOUNT support not enabled */ if (0 || dev->tapedevt == TAPEDEVT_SCSITAPE || sysblk.tamdir == NULL || dev->noautomount ) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Command Reject if command-chained and i/o length not 1 */ if (flags & CCW_FLAGS_CC) { if (count != 1) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* AUTOMOUNT QUERY - part 1 (chained 0xE4 SENSE ID = part 2) */ /* Set normal status but do nothing else; the next CCW should be a SENSE ID (0xE4) which will do the query */ build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); break; } /* AUTOMOUNT MOUNT... */ /* Calculate residual byte count */ RESIDUAL_CALC (sizeof(newfile)-1); /* (minus-1 for NULL) */ /* Copy the device's new filename from guest storage */ for (i=0; i < num; i++) newfile[i] = guest_to_host( iobuf[i] ); newfile[num] = 0; /* Change "OFFLINE" to "*" (tape unloaded) */ if (strcasecmp (newfile, "OFFLINE") == 0) strlcpy (newfile, TAPE_UNLOADED, sizeof(newfile)); /* (messages looks better without LCSS if not needed) */ lcss[0] = 0; if (SSID_TO_LCSS(dev->ssid) != 0) snprintf( lcss, sizeof(lcss), "%u:", SSID_TO_LCSS(dev->ssid) ); lcss[sizeof(lcss)-1] = 0; /* Obtain the device lock */ obtain_lock (&dev->lock); /* Validate the given path... */ if ( strcmp( newfile, TAPE_UNLOADED ) != 0 ) { TAMDIR *tamdir = NULL; int minlen = 0; int rej = 0; /* (because i hate typing) */ #define HHCTA090E(_file,_reason) \ { \ logmsg(_("HHCTA090E Auto-mount of file \"%s\" on drive %s%4.4X failed: " \ "%s\n"), _file, lcss, dev->devnum, _reason); \ build_senseX (TAPE_BSENSE_TAPELOADFAIL, dev, unitstat, code); \ release_lock (&dev->lock); \ break; \ } // Resolve given path... { char resolve_in [ MAX_PATH ] = {0}; /* (work) */ char resolve_out[ MAX_PATH ] = {0}; /* (work) */ /* (build path to be resolved...) */ if (0 #if defined(_MSVC_) || newfile[1] == ':' /* (fullpath given?) */ #else /* !_MSVC_ */ || newfile[0] == '/' /* (fullpath given?) */ #endif /* _MSVC_ */ || newfile[0] == '.' /* (relative path given?) */ ) resolve_in[0] = 0; /* (then use just given spec) */ else /* (else prepend with default) */ strlcpy( resolve_in, sysblk.defdir, sizeof(resolve_in) ); /* (finish building path to be resolved) */ strlcat( resolve_in, newfile, sizeof(resolve_in) ); /* (fully resolvable path?) */ if (realpath( resolve_in, resolve_out ) == NULL) HHCTA090E( resolve_in, "unresolvable path" ); /* Switch to fully resolved path */ strlcpy( newfile, resolve_out, sizeof(newfile) ); } /* Verify file is in an allowable directory... */ rej = 0; minlen = 0; while ((tamdir = findtamdir( rej, minlen, newfile )) != NULL) { rej = !rej; minlen = tamdir->len; } /* Error if "allowable" directory not found... */ if (!rej) HHCTA090E( newfile, "impermissible directory" ); /* Verify file exists... */ if (access( newfile, R_OK ) != 0) HHCTA090E( newfile, "file not found" ); } /* Prevent accidental re-init'ing of an already loaded tape drive */ if (1 && sysblk.nomountedtapereinit && strcmp (newfile, TAPE_UNLOADED) != 0 && strcmp (dev->filename, TAPE_UNLOADED) != 0 ) { logmsg(_("HHCTA091E Tape file auto-mount for drive %s%4.4X rejected: " "drive not empty\n"), lcss, dev->devnum); build_senseX (TAPE_BSENSE_TAPELOADFAIL, dev, unitstat, code); release_lock (&dev->lock); break; } /* Build re-initialization parameters using new filename */ argc = dev->argc; argv = malloc (dev->argc * sizeof(char*)); for (i=0; i < argc; i++) { if (dev->argv[i]) argv[i] = strdup(dev->argv[i]); else argv[i] = NULL; } /* (replace filename argument with new filename) */ free( argv[0] ); argv[0] = strdup( newfile ); /* Attempt reinitializing the device using the new filename... */ rc = (int)(dev->hnd->init)( dev, argc, argv ); /* (free temp copy of parms to prevent memory leak) */ for (i=0; i < argc; i++) if (argv[i]) free(argv[i]); /* Issue message and set status based on whether it worked or not... */ if (0 || rc < 0 || strfilenamecmp( dev->filename, newfile ) != 0 ) { // (failure) if (strcmp( newfile, TAPE_UNLOADED ) == 0) { /* (an error message explaining the reason for the failure should hopefully already have been issued) */ logmsg(_("HHCTA092E Tape file auto-unmount for drive %s%4.4X failed\n"), lcss, dev->devnum); } else HHCTA090E( newfile, "file not found" ); // (presumed) /* (the load or unload attempt failed) */ build_senseX (TAPE_BSENSE_TAPELOADFAIL, dev, unitstat, code); } else { // (success) if (strcmp( newfile, TAPE_UNLOADED ) == 0) logmsg(_("HHCTA093I Tape file on drive %s%4.4X auto-unmounted\n"), lcss, dev->devnum); else logmsg(_("HHCTA094I Tape file \"%s\" auto-mounted onto drive %s%4.4X\n"), dev->filename, lcss, dev->devnum); /* (save new parms for next time) */ free( dev->argv[0] ); dev->argv[0] = strdup( newfile ); /* (set normal status for this ccw) */ build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); } /* Release the device lock and exit function... */ release_lock (&dev->lock); break; } /* End case 0x4B: SET DIAGNOSE */ #endif /* OPTION_TAPE_AUTOMOUNT */ /*---------------------------------------------------------------*/ /* READ MESSAGE ID */ /*---------------------------------------------------------------*/ case 0x4E: { /* GA32-0127 IBM 3490E Hardware Reference Read Message ID (X'4E') The Read Message ID command is used to read the message identifier that was assigned by the control unit to commands that indicated the message-required flag requesting notification when an asynchronous operation is complete. The Read Message ID command must be chained directly from the specific command that requested the message notification or the command will be presented unit check status with associated sense indicating ERA code 27. If the Read Message ID command is chained to a specific command that requests notification, but the command does not result in an asynchronous operation, the message identifier field returned will be all zeroes. The data returned has the following format: ________ ____________________________________________________ | Byte | Description | |________|____________________________________________________| | 0,1 | Length (set to X'000A') | |________|____________________________________________________| | 2 | Format (set to X'02') | |________|____________________________________________________| | 3 | Message Code | | | | | | Value Description | | | | | | X'01' Delayed-Response Message | |________|____________________________________________________| | 4-7 | Message ID | | | | | | This field contains the message identifier | | | assigned by the control unit to the requested | | | operation. If the operation was executed by | | | the subsystem as an immediate operation, this | | | field contains all zeroes and a later delayed- | | | response message is not generated. | |________|____________________________________________________| | 8 | Flags (set to X'00') | |________|____________________________________________________| | 9 | Reserved (set to X'00') | |________|____________________________________________________| */ /* Command reject if not chained from a write command */ if (!((chained & CCW_FLAGS_CC) && IS_CCW_WRITE(prevcode))) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC( 10 ); // PROGRAMMING NOTE: at the moment all of our i/o's are synchronous. // Thus we always return zero indicating the i/o was not asynchronous. STORE_HW ( &iobuf[0], 10 ); // 0-1 iobuf[2] = 0x02; // 2 iobuf[3] = 0x01; // 3 STORE_FW ( &iobuf[4], 0 ); // 4-7 (Message Id) iobuf[8] = 0x00; // 8 iobuf[9] = 0x00; // 9 build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat,code); break; } /* End case 0x4E: READ MESSAGE ID */ /*---------------------------------------------------------------*/ /* LOCATE BLOCK */ /*---------------------------------------------------------------*/ case 0x4F: { U32 locblock; /* Block Id for Locate Block */ int errcode = TAPE_BSENSE_STATUSONLY; /* Presumed success */ /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Check for minimum count field */ if (count < sizeof(dev->blockid)) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Block to seek */ ASSERT( count >= sizeof(locblock) ); FETCH_FW(locblock, iobuf); /* Check for invalid/reserved Format Mode bits */ if (0x3590 != dev->devtype) { if (0x00C00000 == (locblock & 0x00C00000)) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* We only want the Block Number in the low-order 22 bits */ locblock &= 0x003FFFFF; } /* Calculate residual byte count */ RESIDUAL_CALC( sizeof(locblock) ); /* Informative message if tracing */ if ( dev->ccwtrace || dev->ccwstep ) logmsg(_("HHCTA081I Locate block 0x%8.8"I32_FMT"X on %s%s%4.4X\n") ,locblock ,TAPEDEVT_SCSITAPE == dev->tapedevt ? (char*)dev->filename : "" ,TAPEDEVT_SCSITAPE == dev->tapedevt ? " = " : "" ,dev->devnum ); /* Update display if needed */ if ( TAPEDISPTYP_IDLE == dev->tapedisptype || TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_LOCATING; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Ask media handler to perform the locate... */ if ((rc = dev->tmh->locateblk( dev, locblock, unitstat, code )) < 0) { errcode = TAPE_BSENSE_LOCATEERR; dev->fenced = 1; // (position lost; fence the volume) } /* Update display if needed */ if ( TAPEDISPTYP_LOCATING == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Set completion status... */ build_senseX( errcode, dev, unitstat, code ); break; } /* End case 0x4F: LOCATE BLOCK */ /*---------------------------------------------------------------*/ /* SUSPEND MULTIPATH RECONNECTION (3480 and later) */ /*---------------------------------------------------------------*/ case 0x5B: { /* GA32-0127 IBM 3490E Hardware Reference Suspend Multipath Reconnection (X'5B') The Suspend Multipath Reconnection command performs as a No-Operation command because all controlling-computer-to- subsystem operations occur in single-path status. */ /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Set normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* READ MEDIA CHARACTERISTICS (3590 only) */ /*---------------------------------------------------------------*/ case 0x62: { /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide 5.2.3 New Read Media Characteristics The new Read Media Characteristics CCW (command code x'62') provides up to 256 bytes of information about the media and formats supported by the Magstar tape drive." */ // ZZ FIXME: not coded yet. /* Set command reject sense byte, and unit check status */ build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* READ DEVICE CHARACTERISTICS */ /*---------------------------------------------------------------*/ case 0x64: { /* Command reject if device characteristics not available */ if (dev->numdevchar == 0) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (dev->numdevchar); /* Copy device characteristics bytes to channel buffer */ memcpy (iobuf, dev->devchar, num); /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } #if 0 /*---------------------------------------------------------------*/ /* SET INTERFACE IDENTIFIER (3490 and later) */ /*---------------------------------------------------------------*/ case 0x73: { // PROGRAMMING NOTE: the 3480 and earlier "Mode Set" interpretation // of this CCW is handled in the command-table as a no-op; the "Set // Interface Identifier" interpretation of this CCW for 3490 and // later model tape drives is *ALSO* handled in the command-table // as a no-op as well, so there's really no reason for this switch // case to even exist until such time as we need to support a model // that happens to require special handling (which is unlikely). // I'm keeping the code here however for documentation purposes // only, but of course disabling it from compilation via #if 0. build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } #endif /*---------------------------------------------------------------*/ /* PERFORM SUBSYSTEM FUNCTION */ /*---------------------------------------------------------------*/ case 0x77: { BYTE order = iobuf[0]; BYTE flag = iobuf[1]; BYTE parm = iobuf[2]; /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* The flag byte must be zero for all orders because none of our supported orders supports a flag byte */ if (PSF_FLAG_ZERO != flag) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Byte 0 is the PSF order */ switch (order) { /*-----------------------------------------------------------*/ /* Activate/Deactivate Forced Error Logging */ /* 0x8000nn / 0x8100nn */ /*-----------------------------------------------------------*/ case PSF_ORDER_AFEL: case PSF_ORDER_DFEL: { BYTE bEnable = (PSF_ORDER_AFEL == order) ? 1 : 0; /* Calculate residual byte count */ RESIDUAL_CALC (3); /* Control information length must be 3 bytes long */ /* and the parameter byte must be one or the other */ if ( (count < len) || ((PSF_ACTION_FEL_IMPLICIT != parm) && (PSF_ACTION_FEL_EXPLICIT != parm)) ) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } /* Enable/Disabled Forced Error Logging as requested... */ #if 0 // (implicit enabling for all devices not currently supported; treat as explicit instead) if (PSF_ACTION_FEL_IMPLICIT == parm) { // Implicit: for ALL devices... dev->forced_logging = bEnable ? 1 : 0; } else // (PSF_ACTION_FEL_EXPLICIT == parm) #endif // (implicit not supported) { // Explicit: for only THIS device... dev->forced_logging = bEnable ? 1 : 0; } build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code); break; } /*-----------------------------------------------------------*/ /* Activate/Deactivate Access Control */ /* 0x8200nn00 / 0x8300nn00 */ /*-----------------------------------------------------------*/ case PSF_ORDER_AAC: // (Activate) case PSF_ORDER_DAC: // (Dectivate) { BYTE bEnable = (PSF_ORDER_AAC == order) ? 1 : 0; /* Calculate residual byte count */ RESIDUAL_CALC (4); /* Control information length must be 4 bytes long */ /* and the parameter byte must not be invalid */ if (0 || (count < len) || (parm & ~(PSF_ACTION_AC_LWP | PSF_ACTION_AC_DCD | // (bits on that shouldn't be) PSF_ACTION_AC_DCR | PSF_ACTION_AC_ER)) || !(parm & (PSF_ACTION_AC_LWP | PSF_ACTION_AC_DCD | // (bits on that should be) PSF_ACTION_AC_DCR | PSF_ACTION_AC_ER)) ) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } /* Enable/Disable Logical Write Protect if requested */ if (parm & PSF_ACTION_AC_LWP) dev->tdparms.logical_readonly = bEnable ? 1 : 0; /* Enable/Disable Data Compaction (compression) if requested */ if (parm & PSF_ACTION_AC_DCD) { if (TAPEDEVT_HETTAPE == dev->tapedevt) { rc = het_cntl( dev->hetb, HETCNTL_SET | HETCNTL_COMPRESS, bEnable ? TRUE : FALSE ); } #if defined(OPTION_SCSI_TAPE) else if (TAPEDEVT_SCSITAPE == dev->tapedevt) { // ZZ FIXME: future place for direct SCSI i/o // to enable/disable compression for 3480/later. } #endif } build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code); break; } /*-----------------------------------------------------------*/ /* Reset Volume Fenced */ /* 0x9000 */ /*-----------------------------------------------------------*/ case PSF_ORDER_RVF: { /* GA32-0127 IBM 3490E Hardware Reference Volume Fencing When a condition results in a volume integrity exposure, the control unit will prevent further access to the volume. This process is called Volume Fencing and is primarily related to loss of buffered write data, tape positioning, or assignment protection. The control unit prevents further access to the tape volume by conditioning itself to generate deferred unit checks with associated sense data indicating ERA code 47, for all commands that are eligible to receive the deferred unit check until the condition is reset or until the cartridge is unloaded. The condition that caused the fencing to occur has already been indicated by the previous unit check and associated sense data. */ /* Calculate residual byte count */ RESIDUAL_CALC (2); /* Control information length must be 2 bytes long */ if (count < len) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } dev->fenced = 0; // (as requested!) build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code); break; } /*-----------------------------------------------------------*/ /* Pin Device */ /* 0xA100nn */ /*-----------------------------------------------------------*/ case PSF_ORDER_PIN_DEV: { /* Calculate residual byte count */ RESIDUAL_CALC (3); /* Control information length must be 3 bytes long and the parameter byte must not be invalid */ if ( (count < len) || ((parm != PSF_ACTION_PIN_CU0) && (parm != PSF_ACTION_PIN_CU1)) ) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } /* Not currently supported; treat as no-op */ build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code); break; } /*-----------------------------------------------------------*/ /* Unpin Device */ /* 0xA200 */ /*-----------------------------------------------------------*/ case PSF_ORDER_UNPIN_DEV: { /* Calculate residual byte count */ RESIDUAL_CALC (2); /* Control information length must be 2 bytes long */ if (count < len) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } /* Not currently supported; treat as no-op */ build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code); break; } /*-----------------------------------------------------------*/ /* Prepare for Read Subsystem Data */ /* 0x180000000000mm00iiiiiiii */ /*-----------------------------------------------------------*/ case PSF_ORDER_PRSD: { /* GA32-0127 IBM 3490E Hardware Reference Prepare for Read Subsystem Data (X'18') The order transfers 12 bytes of data used for processing a Read Subsystem Data command that immediately follows the Perform Subsystem Function command specifying this order in the command chain. If a Read Subsystem Data command is not issued as the next command in the command chain, the data is discarded and no other action is performed. If a Read Subsystem Data command is issued as the next command in the command chain, the data determines what type of information is presented to the Read Subsystem Data command. When the Prepare for Subsystem Data order with the attention message sub-order is specified in a Perform Subsystem Function command, the command is treated as a global command. If the command is issued while the Special Intercept Condition is active, a unit check status is presented with the associated sense data indicating ERA code 53. The Prepare for Read Subsystem Data order requires an order byte (byte 0), a flag byte (byte 1), and parameter bytes. The flag byte is set to 0. The parameter bytes are defined as follows: ________ ___________________________________________________ | Byte | Description | |________|___________________________________________________| | 2-5 | Reserved (X'00') | |________|___________________________________________________| | 6 | Attention Message (X'03') | | | | | | When active and bytes 8-11 contain X'00000000', | | | the program is requesting the control unit | | | to present any pending attention message or | | | unsolicited unit check condition that is | | | associated with the addressed device-path pair. | | | If there is no message or unit check condition | | | present, the subsystem displays the "No Message" | | | message. | | | | | | When active and bytes 8-11 contain anything | | | other than X'00000000', the program is re- | | | questing the control unit to present the status | | | of the asynchronous operation as identified by | | | the contents of bytes 8-11. | |________|___________________________________________________| | 7 | Reserved (X'00') | |________|___________________________________________________| | 8-11 | Message ID | |________|___________________________________________________| */ /* Calculate residual byte count */ RESIDUAL_CALC (12); /* Control information length must be 12 bytes long the */ /* parameter must be valid and all reserved bytes zero. */ /* Also note that the only sub-order we support is the */ /* only sub-order that is defined: attention message. */ if (0 || (count < len) || (iobuf[6] != PSF_ACTION_SSD_ATNMSG) || (memcmp( &iobuf[2], "\00\00\00\00", 4 ) != 0) || (iobuf[7] != 0x00) ) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* If the Special Intercept Condition is active, present unit check status with sense indicating ERA code 53 */ if (dev->SIC_active) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); dev->SIC_active = 0; break; } // Build the requested Subsystem Data... // PROGRAMMING NOTE: note that we build the requested data // directly in the channel i/o buffer itself (iobuf). This // relieves us from having to allocate/maintain a separate // buffer for it somewhere, and relieves the READ SUBSYSTEM // DATA command (0x3E) from having to copy the data into // the channel buffer from somewhere. Instead it can return // immediately since the data is already in the buffer. (See // the 0x3E: READ SUBSYSTEM DATA command for information). // PROGRAMMING NOTE: since at the moment we don't support // asynchronous i/o (all of our i/o's are synchronous), we // return either a Format x'00' (No Message) response if the // Message Id they specified was x'00000000' or, if they // requested the status for a specific Message Id, a format // x'02' (Message Id Status) response with x'00' Operation // Completion Status (I/O Completed). if (memcmp( &iobuf[8], "\00\00\00\00", 4 ) == 0) { /* Format x'00': "No Message" */ dev->tapssdlen = 9; // (Length) STORE_HW ( &iobuf[0], dev->tapssdlen ); // (Length = 9 bytes) iobuf[2] = 0x00; // (Format = x'00': "No Message") iobuf[3] = 0x00; // (Message Code = none) memcpy( &iobuf[4], &iobuf[8], 4 ); // (Message Id = same as requested) iobuf[8] = 0x00; // (Flags = none) } else { /* Format x'02': "Message Id Status" */ dev->tapssdlen = 10; // (Length) STORE_HW ( &iobuf[0], dev->tapssdlen ); // (Length = 10 bytes) iobuf[2] = 0x02; // (Format = x'01: Message Id Status) iobuf[3] = 0x01; // (Message Code = Delayed Response) memcpy( &iobuf[4], &iobuf[8], 4 ); // (Message Id = same as requested) iobuf[8] = 0x00; // (Reserved) iobuf[9] = 0x00; // (Status = "I/O Completed") } break; } /* End case PSF_ORDER_PRSD */ /*-----------------------------------------------------------*/ /* Set Special Intercept Condition */ /* 0x1B00 */ /*-----------------------------------------------------------*/ case PSF_ORDER_SSIC: { /* GA32-0127 IBM 3490E Hardware Reference Set Special Intercept Condition (X'1B') The order controls the activation or deactivation of the special intercept condition associated with the device-path group pair to which the command is issued. The order is supported by the model if byte 8 bit 4 is active in the data presented to the Read Device Characteristics command. The order requires an order byte (byte 0) and a flag byte (byte 1). The flag byte is set to 0. When processed, the command activates the special intercept condition for the device on each channel path that has the same path group ID as the issuing channel path. The path group ID is considered valid on a given channel path if it is valid for any device on the channel path. The special intercept condition controls the presentation of attention- intercept status. The sense data associated with the attention-intercept status indicates ERA code 57. The special intercept condition also causes the next global command issued to the device-path group pair to be presented unit check status with associated sense data indicating ERA code 53. The special intercept condition is deactivated on a channel path if a reset signal is received on the channel path. The special intercept condition is deactivated for the device-group pair if a global command is presented unit check status with associated sense data indicating ERA code 53, or if the last path in the associated set of channel paths (that is, with the same valid path group ID) is reset. After the Set Special Intercept Condition order is specified in a Perform Subsystem Function command, the command is treated as a global command. If the command is issued while the special intercept condition is active, a unit check status is presented with associated sense data indicating ERA code 53. If a command is issued to a channel path without a valid path group ID (that is, all devices in the reset state), unit check status is presented with associated sense data indicating ERA code 27. */ /* Command reject if Special Intercept Condition not supported */ if (!dev->SIC_supported) // (not supported?) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* If the command is issued while the Special Intercept */ /* Condition is active, a unit check status is presented */ /* with associated sense data indicating ERA code 53. */ if (dev->SIC_active) // (already active?) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); dev->SIC_active = 0; // (reset after UC) break; } /* Activate Special Intercept Condition */ dev->SIC_active = 1; break; } /* End case PSF_ORDER_SSIC */ /*-----------------------------------------------------------*/ /* Message Not Supported */ /* 0x1C00xxccnnnn0000iiiiii... */ /*-----------------------------------------------------------*/ case PSF_ORDER_MNS: { /* GA32-0127 IBM 3490E Hardware Reference Message Not Supported (X'1C') The order transfers 20 bytes of data that identify the host that does not support a prior attention message containing the Notify Nonsupport flag. The order requires an order byte (byte 0), a flag byte (byte 1), and parameter bytes. The flag byte is set to 0. The parameter bytes are defined as follows: ________ ________ ____________________________________________ | Byte | Value | Description | |________|________|____________________________________________| | 2 | | Response Code | |________|________|____________________________________________| | | 0 | Reserved (invalid). | |________|________|____________________________________________| | | 1 | Message rejected. Unknown format. | |________|________|____________________________________________| | | 2 | Message rejected. Function not supported. | |________|________|____________________________________________| | | 3-255 | Reserved (invalid). | |________|________|____________________________________________| | 3 | | Channel Path ID (CHPID) | | | | | | | | The byte identifies the channel path that | | | | received the attention message. | |________|________|____________________________________________| | 4, 5 | | Device Number | | | | | | | | The bytes identify the device number of | | | | the device that received the attention | | | | message. | |________|________|____________________________________________| | 6, 7 | | Reserved (must be X'00'). | |________|________|____________________________________________| | 8-11 | | Message ID | | | | | | | | The field contains the message ID that | | | | was presented to the host in the attention | | | | message. | |________|________|____________________________________________| | 12-19 | | System ID | | | | | | | | The field contains an 8-byte system ID | | | | that identifies the host or host partition | | | | responding to the attention message. | |________|________|____________________________________________| */ // PROGRAMMING NOTE: none of our responses to the Perform Sub- // System Function order Attention Message sub-order (see the // PSF_ORDER_PRSD case further above) support any flags. Thus // because we never set/request the "Notify Nonsupport" flag // in our Attention Message sub-order response, the host should // never actually ever be issuing this particular order of the // Perform Subsystem Functon command since it shouldn't be // trying to tell us what we never asked it to. Nevertheless // we should probably support it anyway just in case it does // by treating it as a no-op (as long as it's valid of course). /* Check for valid data (Note: we don't bother validating the Channel Path ID, Device Number, Message ID or System ID) */ if (0 // || flag != 0x00 // (flag byte) (note: already checked) || (parm != 0x01 && parm != 0x02) // (response code) || iobuf[6] != 0x00 // (reserved) || iobuf[7] != 0x00 // (reserved) ) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (20); /* Treat as No-op */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /* End case PSF_ORDER_MNS */ /*-----------------------------------------------------------*/ /* Unknown/Supported PSF order */ /*-----------------------------------------------------------*/ default: { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } } /* End PSF switch (order) */ break; } /* End case 0x77: PERFORM SUBSYSTEM FUNCTION */ /*---------------------------------------------------------------*/ /* DATA SECURITY ERASE */ /*---------------------------------------------------------------*/ case 0x97: { /* GA32-0127 IBM 3490E Hardware Reference Data Security Erase (X'97') The Data Security Erase command writes a random pattern from the position of the tape where the command is issued to the physical end of tape. The Data Security Erase command must be command-chained from an Erase Gap command. Most operating systems signal that the channel program is complete when the channel ending status is returned for the final command in the chain. If the Data Security Erase command is the last command in a channel program, another command should be chained after the Data Security Erase command. (The No-Operation command is appropriate.) This practice ensures that any error status returns with device ending status after the Data Security Erase command is completed. */ /* Command reject if not chained from Erase Gap command */ if (!((chained & CCW_FLAGS_CC) && 0x17 == prevcode)) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Command reject if tape is write-protected */ if (dev->readonly || dev->tdparms.logical_readonly) { build_senseX (TAPE_BSENSE_WRITEPROTECT, dev, unitstat, code); break; } /* Update matrix display if needed */ if ( TAPEDISPTYP_IDLE == dev->tapedisptype || TAPEDISPTYP_WAITACT == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_ERASING; UpdateDisplay( dev ); } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Do the DSE; exit if error */ if ((rc = dev->tmh->dse( dev, unitstat, code )) < 0) break; // (error) /* Update matrix display if needed */ if ( TAPEDISPTYP_ERASING == dev->tapedisptype ) { dev->tapedisptype = TAPEDISPTYP_IDLE; UpdateDisplay( dev ); } /* Perform flush/sync and/or set normal completion status */ if (0 || !dev->write_immed || (rc = dev->tmh->sync( dev, unitstat, code )) == 0 ) build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); break; } /* End case 0x97: DATA SECURITY ERASE */ /*---------------------------------------------------------------*/ /* LOAD DISPLAY */ /*---------------------------------------------------------------*/ case 0x9F: { /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (17); /* Issue message on 3480 matrix display */ load_display (dev, iobuf, count); /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* Read and Reset Buffered Log (9347) */ /*---------------------------------------------------------------*/ case 0xA4: { /* Calculate residual byte count */ RESIDUAL_CALC (dev->numsense); /* Reset SENSE Data */ memset (dev->sense, 0, sizeof(dev->sense)); *unitstat = CSW_CE|CSW_DE; /* Copy device Buffered log data (Bunch of 0s for now) */ memcpy (iobuf, dev->sense, num); /* Indicate Contengency Allegiance has been cleared */ dev->sns_pending = 0; break; } /*---------------------------------------------------------------*/ /* SET PATH GROUP ID */ /*---------------------------------------------------------------*/ case 0xAF: { /* GA32-0127 IBM 3490E Hardware Reference Set Path Group ID (X'AF') The Set Path Group ID command identifies a controlling computer and specific channel path to the addressed control unit and tape drive. The Set Path Group ID command transfers 12 bytes of path group ID information to the subsystem. The first byte (byte 0) is a function control byte, and the remaining 11 bytes (bytes 1-11) contain the path-group ID. The bit assignments in the function control byte (byte 0) are: ________ ________ ___________________________________________ | Bit | Value | Description | |________|________|___________________________________________| | 0 | | Path Mode | |________|________|___________________________________________| | | 0 | Single-path Mode | |________|________|___________________________________________| | | 1 | Multipath Mode (not supported by Models | | | | C10, C11, and C22) | |________|________|___________________________________________| | 1, 2 | | Group Code | |________|________|___________________________________________| | | 00 | Establish Group | |________|________|___________________________________________| | | 01 | Disband Group | |________|________|___________________________________________| | | 10 | Resign from Group | |________|________|___________________________________________| | | 11 | Reserved | |________|________|___________________________________________| | 3-7 | 00000 | Reserved | |________|________|___________________________________________| The final 11 bytes of the Set Path Group ID command identify the path group ID. The path group ID identifies the channel paths that belong to the same controlling computer. Path group ID bytes must be the same for all devices in a control unit on a given path. The Path Group ID bytes cannot be all zeroes. */ /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Command reject if the command is not the ONLY command in the channel program */ if (chained & CCW_FLAGS_CC) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (12); /* Control information length must be at least 12 bytes */ if (count < 12) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Byte 0 is the path group state byte */ switch((iobuf[0] & SPG_SET_COMMAND)) { case SPG_SET_ESTABLISH: /* Only accept the new pathgroup id when 1) it has not yet been set (ie contains zeros) or 2) It is set, but we are setting the same value */ if(memcmp(dev->pgid, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 11) && memcmp(dev->pgid, iobuf+1, 11)) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Bytes 1-11 contain the path group identifier */ memcpy (dev->pgid, iobuf+1, 11); // (set initial value) dev->pgstat = SPG_PATHSTAT_GROUPED | SPG_PARTSTAT_IENABLED; build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; case SPG_SET_DISBAND: dev->pgstat = 0; build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; default: case SPG_SET_RESIGN: dev->pgstat = 0; memset (dev->pgid, 0, 11); // (reset to zero) build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } // end switch((iobuf[0] & SPG_SET_COMMAND)) break; } /* End case 0xAF: SET PATH GROUP ID */ /*---------------------------------------------------------------*/ /* ASSIGN */ /*---------------------------------------------------------------*/ case 0xB7: { /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (11); /* Control information length must be at least 11 bytes */ if (count < len) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } if((memcmp(iobuf,"\00\00\00\00\00\00\00\00\00\00",11)==0) || (memcmp(iobuf,dev->pgid,11)==0)) { dev->pgstat |= SPG_PARTSTAT_XENABLED; /* Set Explicit Partition Enabled */ } else { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* MEDIUM SENSE (3590) */ /*---------------------------------------------------------------*/ case 0xC2: { /* GA32-0331 IBM 3590 Hardware Reference The 3590 Hardware Reference manual lists many different "Mode Sense" Pages that the 3590 supports, with one of the supported pages being Mode Page X'23': the "Medium Sense" mode page: The Medium Sense page provides information about the state of the medium currently associated with the device, if any. */ #if 0 // ZZ FIXME: not coded yet // PROGRAMMING NOTE: until we can add support to Hercules // allowing direct SCSI i/o (so that we can issue the 10-byte // Mode Sense (X'5A') command to ask for Mode Page x'23' = // Medium Sense) we have no choice but to reject the command. // ZZ FIXME: not written yet. build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); #else // ++++ BEGIN MEDIUM SENSE HACK ++++ /* ZZ FIXME: *** TEMPORARY(?) HACK *** The following clues were gleaned from Linux 390 source: struct tape_3590_med_sense { unsigned int macst:4; unsigned int masst:4; char pad[127]; } #define MSENSE_UNASSOCIATED 0x00 #define MSENSE_ASSOCIATED_MOUNT 0x01 #define MSENSE_ASSOCIATED_UMOUNT 0x02 case TO_MSEN: sense = (struct tape_3590_med_sense *) request->cpdata; if (sense->masst == MSENSE_UNASSOCIATED) tape_med_state_set(device, MS_UNLOADED); if (sense->masst == MSENSE_ASSOCIATED_MOUNT) tape_med_state_set(device, MS_LOADED); break; */ /* Calculate residual byte count */ RESIDUAL_CALC (128); /* Return Media Sense data... */ memset( iobuf, 0, num ); // (init to all zeroes first) if (dev->tmh->tapeloaded( dev, unitstat, code )) iobuf[0] |= (0x01 & 0x0F); // MSENSE_ASSOCIATED_MOUNT // else // iobuf[0] |= (0x00 & 0x0F); // MSENSE_UNASSOCIATED /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); #endif // ++++ END MEDIUM SENSE HACK ++++ break; } /* End case 0xC2: MEDIUM SENSE */ /*---------------------------------------------------------------*/ /* SET TAPE-WRITE IMMEDIATE (3480 and later) */ /*---------------------------------------------------------------*/ case 0xC3: { // NOTE: the "Mode Set" interpretation of this CCW for all // models earlier than 3480 are handled by the command-table; // the "Set Tape-Write Immediate" interpretation of this CCW // for 3480 and later models is handled below. /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* GA32-0127 IBM 3490E Hardware Reference Set Tape-Write-Immediate (X'C3') The Set Tape-Write-Immediate command causes all subsequent Write commands in the channel program to perform as write- immediate commands. The tape-write-immediate command is explicitly requested by a Mode Set or Set Tape-Write-Immediate command. The subsystem forces the tape-write-immediate command while the tape is positioned beyond logical end of volume. This prevents more than one record from being in the buffer if the physical end of volume is reached. It may also be forced when load balancing is performed or on drives that write the 3480-2 XF format just before end of wrap processing. */ /* GA32-0329 3590 Introduction and Planning Guide When data is physically transferred to the tape medium it is always immediately reread and verified. The writing of data is normally buffered, however, which defers the physical transfer of the logical blocks to the tape until the buffer conditions require the offloading of the data or until a synchronizing command requires the transfer. If immediate validation of a successful transfer of data to the tape is required at the time that each logical block is written, then Tape Write Immediate mode may be programmatically invoked. This results in block-by-block synchronization and verification of successful transfer all the way to the medium, but at a very substantial cost in application performance. */ /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* set write-immedediate mode and perform sync function */ dev->write_immed = 1; if ((rc = dev->tmh->sync( dev, unitstat, code )) == 0) build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code ); break; } /* End case 0xC3: SET TAPE-WRITE IMMEDIATE */ /*---------------------------------------------------------------*/ /* UNASSIGN */ /*---------------------------------------------------------------*/ case 0xC7: { /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (11); /* Control information length must be at least 11 bytes */ if (count < len) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Reset to All Implicitly enabled */ dev->pgstat=0; /* Reset Path group ID password */ memset(dev->pgid,0,11); /* Reset drive password */ memset(dev->drvpwd,0,sizeof(dev->drvpwd)); /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* MODE SENSE (3590) */ /*---------------------------------------------------------------*/ case 0xCF: { /* ANSI INCITS 131-1994 (R1999) SCSI-2 Reference The MODE SENSE command provides a means for a target to report parameters to the initiator. It is a complementary command to the MODE SELECT command. */ /* GA32-0331 IBM 3590 Hardware Reference The 3590 Hardware Reference manual lists many different "Mode Sense" Pages that the 3590 supports. */ // ZZ FIXME: not written yet. /* Set command reject sense byte, and unit check status */ build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* MODE SET (3480 or later) */ /*---------------------------------------------------------------*/ case 0xDB: { /* GA32-0127 IBM 3490E Hardware Reference Mode Set (X'DB') The Mode Set command controls specific aspects of command processing within a given command chain. The Mode Set command requires one byte of information from the channel. The format of the byte is: ________ __________________________________________________________ | Bit | Description | |________|__________________________________________________________| | 0,1 | Reserved | |________|__________________________________________________________| | 2 | Tape-Write-Immediate Mode | | | | | | If active, any subsequent Write commands within the | | | current command chain are processed in tape-write- | | | immediate mode if no other conditions preclude this | | | mode. If inactive, Write commands are processed in | | | buffered mode if no other conditions preclude this | | | mode. The default is inactivate. | |________|__________________________________________________________| | 3 | Supervisor Inhibit | | | | | | If active, any subsequent supervisor command within | | | the current command chain is presented unit check | | | status with associated sense data indicating ERA code | | | 27. The supervisor inhibit control also determines | | | if pending buffered log data is reset when a Read | | | Buffered Log command is issued. The default is | | | inactivate. | |________|__________________________________________________________| | 4 | Improved Data Recording Capability (IDRC) | | | | | | If active, IDRC is invoked for any subsequent Write | | | commands within the current command chain. See Table | | | 7 in topic 1.16.6 for the default settings. | |________|__________________________________________________________| | 5-7 | Reserved | |________|__________________________________________________________| The Mode Set command is a supervisor command and cannot be performed if preceded by a Mode Set command that inhibits supervisor commands. */ /* Command reject if the volume is currently fenced */ if (dev->fenced) { build_senseX (TAPE_BSENSE_FENCED, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (1); /* Check for count field of at least 1 byte, and that supvr-inhibit mode hasn't already been established */ if (0 || count < len || dev->supvr_inhibit ) { build_senseX(TAPE_BSENSE_BADCOMMAND,dev,unitstat,code); break; } /* Assign a unique Message Id for this I/O if needed */ INCREMENT_MESSAGEID(dev); /* Process request */ if (iobuf[0] & MSET_SUPVR_INHIBIT) dev->supvr_inhibit = 1; /* set supvr-inhibit mode*/ if (iobuf[0] & MSET_WRITE_IMMED) dev->write_immed = 1; /* set write-immed. mode */ build_senseX(TAPE_BSENSE_STATUSONLY,dev,unitstat,code); break; } /* End case 0xDB: MODE SET */ /*---------------------------------------------------------------*/ /* CONTROL ACCESS */ /*---------------------------------------------------------------*/ case 0xE3: { /* GA32-0127 IBM 3490E Hardware Reference Control Access (X'E3') The Control Access command is used to perform the set-password, conditional-enable, and conditional-disable functions of dynamic partitioning. The command requires 12 bytes of data to be transferred from the channel to the control unit which is defined as follows: ________ ________ ___________________________________________ | Byte | Bit | Description | |________|________|___________________________________________| | 0 | | Function Control | |________|________|___________________________________________| | | 0,1 | 0 (x'00') Set Password | | | | 1 (x'40') Conditional Disable | | | | 2 (x'80') Conditional Enable | | | | 3 (x'C0') Reserved (Invalid) | |________|________|___________________________________________| | | 2-7 | Reserved (must be B'0') | |________|________|___________________________________________| | 1-11 | | Password | |________|________|___________________________________________| */ /* Command Reject if Supervisor-Inhibit */ if (dev->supvr_inhibit) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (12); /* Control information length must be at least 12 bytes */ if (count < len) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Byte 0 is the CAC mode-of-use */ switch (iobuf[0]) { /*-----------------------------------------------------------*/ /* Set Password */ /* 0x00nnnnnnnnnnnnnnnnnnnnnn */ /*-----------------------------------------------------------*/ case CAC_SET_PASSWORD: { /* Password must not be zero and the device path must be Explicitly Enabled */ if (0 || memcmp( iobuf+1, "\00\00\00\00\00\00\00\00\00\00\00", 11 ) == 0 || (dev->pgstat & SPG_PARTSTAT_XENABLED) == 0 ) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Set Password if none set yet */ if (memcmp( dev->drvpwd, "\00\00\00\00\00\00\00\00\00\00\00", 11 ) == 0) { memcpy (dev->drvpwd, iobuf+1, 11); } else /* Password already set - they must match */ { if (memcmp( dev->drvpwd, iobuf+1, 11 ) != 0) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } } build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*-----------------------------------------------------------*/ /* Conditional Enable */ /* 0x80nnnnnnnnnnnnnnnnnnnnnn */ /*-----------------------------------------------------------*/ case CAC_COND_ENABLE: { /* A drive password must be set and it must match the one given as input */ if (0 || memcmp( dev->drvpwd, "\00\00\00\00\00\00\00\00\00\00\00", 11 ) == 0 || memcmp( dev->drvpwd, iobuf+1, 11 ) != 0 ) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*-----------------------------------------------------------*/ /* Conditional Disable */ /* 0x40nnnnnnnnnnnnnnnnnnnnnn */ /*-----------------------------------------------------------*/ case CAC_COND_DISABLE: { /* A drive password is set, it must match the one given as input */ if (1 && memcmp (dev->drvpwd, "\00\00\00\00\00\00\00\00\00\00\00", 11) != 0 && memcmp (dev->drvpwd, iobuf+1, 11) != 0 ) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } default: /* Unsupported Control Access Function */ { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } } /* End switch (iobuf[0]) */ break; } /* End case 0xE3 CONTROL ACCESS */ /*---------------------------------------------------------------*/ /* SENSE ID (3422 and later) */ /*---------------------------------------------------------------*/ case 0xE4: { #if defined( OPTION_TAPE_AUTOMOUNT ) /* AUTOMOUNT QUERY - part 2 (if command-chained from prior 0x4B) */ if (1 && dev->tapedevt != TAPEDEVT_SCSITAPE && sysblk.tamdir != NULL && !dev->noautomount && (chained & CCW_FLAGS_CC) && 0x4B == prevcode ) { int i; // (work) /* Calculate residual byte count */ RESIDUAL_CALC (strlen(dev->filename)); /* Copy device filename to guest storage */ for (i=0; i < num; i++) iobuf[i] = host_to_guest( dev->filename[i] ); /* Return normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } #endif /* OPTION_TAPE_AUTOMOUNT */ /* SENSE ID did not exist on the 3803 */ /* If numdevid is 0, then 0xE4 not supported */ if (dev->numdevid==0) { build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); break; } /* Calculate residual byte count */ RESIDUAL_CALC (dev->numdevid); /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /*---------------------------------------------------------------*/ /* READ CONFIGURATION DATA (3490 and later) */ /*---------------------------------------------------------------*/ case 0xFA: { /* GA32-0127 IBM 3490E Hardware Reference Read Configuration Data (X'FA') A Read Configuration Data command causes 160 bytes of data to be transferred from the control unit to the channel. The data transferred by this command is referred to as a configuration record and is associated with the addressed device-path pair. The configuration record from each device-path pair provides the host with identifiers of node elements internal to the subsystem. */ static const BYTE cfgdata[] = // (prototype data) { // ---------------- Device NED --------------------------------------------------- 0xCC, // 0: NED code 0x01, // 1: Type (X'01' = I/O Device) 0x02, // 2: Class (X'02' = Magnetic Tape) 0x00, // 3: (Reserved) 0xF0,0xF0,0xF3,0xF4,0xF9,0xF0, // 4-9: Type ('003490') 0xC3,0xF1,0xF0, // 10-12: Model ('C10') 0xC8,0xD9,0xC3, // 13-15: Manufacturer ('HRC' = Hercules) 0xE9,0xE9, // 16-17: Plant of Manufacture ('ZZ' = Herc) 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 18-29: Sequence Number 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 0x00, 0x00, // 30-31: Tag (x'000n', n = Logical Drive Address) // ---------------- Control Unit NED --------------------------------------------- 0xC4, // 32: NED code 0x02, // 33: Type (X'02' = Control Unit) 0x00, // 34: Class (X'00' = Undefined) 0x00, // 35: (Reserved) 0xF0,0xF0,0xF3,0xF4,0xF9,0xF0, // 36-41: Type ('003490') 0xC3,0xF1,0xF0, // 42-44: Model ('C10') 0xC8,0xD9,0xC3, // 45-47: Manufacturer ('HRC' = Hercules) 0xE9,0xE9, // 48-49: Plant of Manufacture ('ZZ' = Herc) 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 50-61: Sequence Number 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 0x00, 0x00, // 62-63: Tag (x'0000') // ---------------- Library NED -------------------------------------------------- 0x00, // 64: NED code (x'00' = Not Used) 0x00, // 65: Type 0x00, // 66: Class 0x00, // 67: (Reserved) 0x00,0x00,0x00,0x00,0x00,0x00, // 68-73: Type 0x00,0x00,0x00, // 74-76: Model 0x00,0x00,0x00, // 77-79: Manufacturer 0x00,0x00, // 80-81: Plant of Manufacture 0x00,0x00,0x00,0x00,0x00,0x00, // 82-93: Sequence Number 0x00,0x00,0x00,0x00,0x00,0x00, // 0x00, 0x00, // 94-95: Tag // ---------------- Token NED --------------------------------------------------- 0xEC, // 96: NED code 0x00, // 97: Type (X'00' = Unspecified) 0x00, // 98: Class (X'00' = Undefined) 0x00, // 99: (Reserved) 0xF0,0xF0,0xF3,0xF4,0xF9,0xF0, // 100-105: Type ('003490') 0xC3,0xF1,0xF0, // 106-108: Model ('C10') 0xC8,0xD9,0xC3, // 109-111: Manufacturer ('HRC' = Hercules) 0xE9,0xE9, // 112-113: Plant of Manufacture ('ZZ' = Herc) 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 114-125: Sequence Number 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // 0x00, 0x00, // 126-127: Tag (x'0000') // ---------------- General NEQ -------------------------------------------------- 0x80, // 128: NED code 0x80, // 129: Record Selector: // x'80' = Control Unit 0 // x'81' = Control Unit 1 0x00,0x80, // 130-131: Interface Id: // x'0080' = CU Channel Adapter A // x'0040' = CU Channel Adapter B 0x00, // 132: Device-Dependent Timeout 0x00,0x00,0x00, // 133-135: (Reserved) 0x00, // 136: Extended Information: // x'00' for Logical Drive Addresses 0-7 // x'01' for Logical Drive Addresses 8-F 0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 137-159: (Reserved) 0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00, }; ASSERT( sizeof(cfgdata) == 160 ); /* Calculate residual byte count */ RESIDUAL_CALC (160); /* Copy prototype Configuration Data to channel I/O buffer */ memcpy (iobuf, cfgdata, sizeof(cfgdata)); /* Fixup values for this particular device/type... NOTE: we only fixup the Device and Control Unit NEDs here. The Token NED's type/model values come from the Device NED's values. */ if (0x3480 == dev->devtype) { memcpy (&iobuf[7], "\xF4\xF8", 2); // '48' memcpy (&iobuf[39], "\xF4\xF8", 2); // '48' memcpy (&iobuf[10], "\xC4\xF3\xF1", 3); // 'D31' memcpy (&iobuf[42], "\xC4\xF3\xF1", 3); // 'D31' } else if (0x3490 == dev->devtype) { // memcpy (&iobuf[7], "\xF4\xF9", 2); // '49' // memcpy (&iobuf[39], "\xF4\xF9", 2); // '49' // memcpy (&iobuf[10], "\xC3\xF1\xF0", 3); // 'C10' // memcpy (&iobuf[42], "\xC3\xF1\xF0", 3); // 'C10' } else if (0x3590 == dev->devtype) { memcpy (&iobuf[7], "\xF5\xF9", 2); // '59' memcpy (&iobuf[39], "\xF5\xF9", 2); // '59' memcpy (&iobuf[10], "\xC2\xF1\xC1", 3); // 'B1A' memcpy (&iobuf[42], "\xC1\xF5\xF0", 3); // 'A50' } memcpy (&iobuf[100], &iobuf[4], 9); // (set Token NED Type/Model from Device NED) iobuf[31] |= (dev->devnum & 0x0F); // (set Logical Drive Address) if ((dev->devnum & 0x0F) > 7) iobuf[136] = 0x01; // (set Extended Information) /* Return normal status */ build_senseX (TAPE_BSENSE_STATUSONLY, dev, unitstat, code); break; } /* End case 0xFA: READ CONFIGURATION DATA */ /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ default: { /* Set command reject sense byte, and unit check status */ build_senseX (TAPE_BSENSE_BADCOMMAND, dev, unitstat, code); } } /* end switch (code) */ } /* end function tapedev_execute_ccw */ #if defined( OPTION_TAPE_AUTOMOUNT ) /*-------------------------------------------------------------------*/ /* Find next more-restrictive TAMDIR subdirectory entry... */ /*-------------------------------------------------------------------*/ static TAMDIR* findtamdir( int rej, int minlen, const char* pszDir ) { TAMDIR *pTAMDIR = sysblk.tamdir; /* always search entire list */ do if (1 && pTAMDIR->rej == rej && pTAMDIR->len > minlen && strnfilenamecmp( pszDir, pTAMDIR->dir, pTAMDIR->len ) == 0 ) return pTAMDIR; while ((pTAMDIR = pTAMDIR->next) != NULL); return NULL; } #endif // defined( OPTION_TAPE_AUTOMOUNT ) /*-------------------------------------------------------------------*/ /* Load Display channel command processing... */ /*-------------------------------------------------------------------*/ void load_display (DEVBLK *dev, BYTE *buf, U16 count) { U16 i; /* Array subscript */ char msg1[9], msg2[9]; /* Message areas (ASCIIZ) */ BYTE fcb; /* Format Control Byte */ BYTE tapeloaded; /* (boolean true/false) */ BYTE* msg; /* (work buf ptr) */ if ( !count ) return; /* Pick up format control byte */ fcb = *buf; /* Copy and translate messages... */ memset( msg1, 0, sizeof(msg1) ); memset( msg2, 0, sizeof(msg2) ); msg = buf+1; for (i=0; *msg && i < 8 && ((i+1)+0) < count; i++) msg1[i] = guest_to_host(*msg++); msg = buf+1+8; for (i=0; *msg && i < 8 && ((i+1)+8) < count; i++) msg2[i] = guest_to_host(*msg++); msg1[ sizeof(msg1) - 1 ] = 0; msg2[ sizeof(msg2) - 1 ] = 0; tapeloaded = dev->tmh->tapeloaded( dev, NULL, 0 ); switch ( fcb & FCB_FS ) // (high-order 3 bits) { case FCB_FS_READYGO: // 0x00 /* || 000b: "The message specified in bytes 1-8 and 9-16 is || maintained until the tape drive next starts tape || motion, or until the message is updated." */ dev->tapedispflags = 0; strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) ); strlcpy( dev->tapemsg2, msg2, sizeof(dev->tapemsg2) ); dev->tapedisptype = TAPEDISPTYP_WAITACT; break; case FCB_FS_UNMOUNT: // 0x20 /* || 001b: "The message specified in bytes 1-8 is maintained || until the tape cartridge is physically removed from || the tape drive, or until the next unload/load cycle. || If the drive does not contain a cartridge when the || Load Display command is received, the display will || contain the message that existed prior to the receipt || of the command." */ dev->tapedispflags = 0; if ( tapeloaded ) { dev->tapedisptype = TAPEDISPTYP_UNMOUNT; dev->tapedispflags = TAPEDISPFLG_REQAUTOMNT; strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) ); if ( dev->ccwtrace || dev->ccwstep ) logmsg(_("HHCTA099I %4.4X: Tape Display \"%s\" Until Unmounted\n"), dev->devnum, dev->tapemsg1 ); } break; case FCB_FS_MOUNT: // 0x40 /* || 010b: "The message specified in bytes 1-8 is maintained || until the drive is next loaded. If the drive is || loaded when the Load Display command is received, || the display will contain the message that existed || prior to the receipt of the command." */ dev->tapedispflags = 0; if ( !tapeloaded ) { dev->tapedisptype = TAPEDISPTYP_MOUNT; dev->tapedispflags = TAPEDISPFLG_REQAUTOMNT; strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) ); if ( dev->ccwtrace || dev->ccwstep ) logmsg(_("HHCTA099I %4.4X: Tape Display \"%s\" Until Mounted\n"), dev->devnum, dev->tapemsg1 ); } break; case FCB_FS_NOP: // 0x60 default: /* || 011b: "This value is used to physically access a drive || without changing the message display. This option || can be used to test whether a control unit can || physically communicate with a drive." */ return; case FCB_FS_RESET_DISPLAY: // 0x80 /* || 100b: "The host message being displayed is cancelled and || a unit message is displayed instead." */ dev->tapedispflags = 0; dev->tapedisptype = TAPEDISPTYP_IDLE; break; case FCB_FS_UMOUNTMOUNT: // 0xE0 /* || 111b: "The message in bytes 1-8 is displayed until a tape || cartridge is physically removed from the tape drive, || or until the drive is next loaded. The message in || bytes 9-16 is displayed until the drive is next loaded. || If no cartridge is present in the drive, the first || message is ignored and only the second message is || displayed until the drive is next loaded." */ dev->tapedispflags = 0; strlcpy( dev->tapemsg1, msg1, sizeof(dev->tapemsg1) ); strlcpy( dev->tapemsg2, msg2, sizeof(dev->tapemsg2) ); if ( tapeloaded ) { dev->tapedisptype = TAPEDISPTYP_UMOUNTMOUNT; dev->tapedispflags = TAPEDISPFLG_REQAUTOMNT; if ( dev->ccwtrace || dev->ccwstep ) logmsg(_("HHCTA099I %4.4X: Tape Display \"%s\" Until Unmounted, then \"%s\" Until Mounted\n"), dev->devnum, dev->tapemsg1, dev->tapemsg2 ); } else { dev->tapedisptype = TAPEDISPTYP_MOUNT; dev->tapedispflags = TAPEDISPFLG_MESSAGE2 | TAPEDISPFLG_REQAUTOMNT; if ( dev->ccwtrace || dev->ccwstep ) logmsg(_("HHCTA099I %4.4X: Tape \"%s\" Until Mounted\n"), dev->devnum, dev->tapemsg2 ); } break; } /* Set the flags... */ /* "When bit 7 (FCB_AL) is active and bits 0-2 (FCB_FS) specify a Mount Message, then only the first eight characters of the message are displayed and bits 3-5 (FCB_AM, FCB_BM, FCB_M2) are ignored." */ if (1 && ( fcb & FCB_AL ) && ( ( fcb & FCB_FS ) == FCB_FS_MOUNT ) ) { fcb &= ~( FCB_AM | FCB_BM | FCB_M2 ); dev->tapedispflags &= ~TAPEDISPFLG_MESSAGE2; } /* "When bit 7 (FCB_AL) is active and bits 0-2 (FCB_FS) specify a Demount/Mount message, then only the last eight characters of the message are displayed. Bits 3-5 (FCB_AM, FCB_BM, FCB_M2) are ignored." */ if (1 && ( fcb & FCB_AL ) && ( ( fcb & FCB_FS ) == FCB_FS_UMOUNTMOUNT ) ) { fcb &= ~( FCB_AM | FCB_BM | FCB_M2 ); dev->tapedispflags |= TAPEDISPFLG_MESSAGE2; } /* "When bit 3 (FCB_AM) is set to 1, then bits 4 (FCB_BM) and 5 (FCB_M2) are ignored." */ if ( fcb & FCB_AM ) fcb &= ~( FCB_BM | FCB_M2 ); dev->tapedispflags |= (((fcb & FCB_AM) ? TAPEDISPFLG_ALTERNATE : 0 ) | ( (fcb & FCB_BM) ? TAPEDISPFLG_BLINKING : 0 ) | ( (fcb & FCB_M2) ? TAPEDISPFLG_MESSAGE2 : 0 ) | ( (fcb & FCB_AL) ? TAPEDISPFLG_AUTOLOADER : 0 )); UpdateDisplay( dev ); ReqAutoMount( dev ); } /* end function load_display */ /*********************************************************************/ /*********************************************************************/ /** **/ /** SENSE CCW HANDLING FUNCTIONS **/ /** **/ /*********************************************************************/ /*********************************************************************/ /*-------------------------------------------------------------------*/ /* build_senseX */ /*-------------------------------------------------------------------*/ /* Construct sense bytes and unit status */ /* Note: name changed because semantic changed */ /* ERCode is our internal ERror-type code */ /* */ /* Uses the 'TapeSenseTable' table index */ /* from the 'TapeDevtypeList' table to route call to */ /* one of the below device-specific sense functions */ /*-------------------------------------------------------------------*/ void build_senseX (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode) { int i; BYTE usr; int sense_built; sense_built = 0; if(unitstat==NULL) { unitstat = &usr; } for(i = 0;TapeDevtypeList[i] != 0; i += TAPEDEVTYPELIST_ENTRYSIZE) { if (TapeDevtypeList[i] == dev->devtype) { // Clear old sense if we're going to completely rebuild it... if (TAPE_BSENSE_STATUSONLY != ERCode) { memset( dev->sense, 0, sizeof(dev->sense) ); dev->sns_pending = 0; } // Call the primary sense function (e.g. "build_sense_3480_etal")... TapeSenseTable[TapeDevtypeList[i+4]](ERCode,dev,unitstat,ccwcode); sense_built = 1; // Unit-exception s/b signalled for all write operations // once the end-of-tape (EOT) reflector has been passed... if (1 && TAPE_BSENSE_STATUSONLY == ERCode && (0 || 0x01 == ccwcode // write || 0x17 == ccwcode // erase gap || 0x1F == ccwcode // write tapemark ) && dev->tmh->passedeot(dev) ) { // We're still in the "Early Warning Zone", // so keep warning them... *unitstat |= CSW_UX; // ("Warning!") } break; } } if (!sense_built) { memset( dev->sense, 0, sizeof(dev->sense) ); dev->sense[0]=SENSE_EC; *unitstat = CSW_CE|CSW_DE|CSW_UC; } if (*unitstat & CSW_UC) { dev->sns_pending = 1; } return; } /* end function build_senseX */ /*-------------------------------------------------------------------*/ /* build_sense_3410_3420 */ /*-------------------------------------------------------------------*/ void build_sense_3410_3420 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode) { UNREFERENCED(ccwcode); // NOTE: caller should have cleared sense area to zeros // if this isn't a 'TAPE_BSENSE_STATUSONLY' call switch(ERCode) { case TAPE_BSENSE_TAPEUNLOADED: *unitstat = CSW_UC; dev->sense[0] = SENSE_IR; dev->sense[1] = SENSE1_TAPE_TUB; break; case TAPE_BSENSE_RUN_SUCCESS: /* RewUnld op */ /* FIXME : CE Should have been presented before */ /* Same as for 348x drives */ *unitstat = CSW_CE | CSW_UC | CSW_DE | CSW_CUE; /* *unitstat = CSW_UC | CSW_DE | CSW_CUE; */ dev->sense[0] = SENSE_IR; dev->sense[1] = SENSE1_TAPE_TUB; break; case TAPE_BSENSE_REWINDFAILED: case TAPE_BSENSE_FENCED: case TAPE_BSENSE_EMPTYTAPE: case TAPE_BSENSE_ENDOFTAPE: case TAPE_BSENSE_BLOCKSHORT: /* On 3411/3420 the tape runs off the reel in that case */ /* this will cause pressure loss in both columns */ case TAPE_BSENSE_LOCATEERR: /* Locate error: This is more like improperly formatted tape */ /* i.e. the tape broke inside the drive */ /* So EC instead of DC */ case TAPE_BSENSE_TAPELOADFAIL: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = SENSE_EC; dev->sense[1] = SENSE1_TAPE_TUB; dev->sense[7] = 0x60; break; case TAPE_BSENSE_ITFERROR: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = SENSE_EC; dev->sense[1] = SENSE1_TAPE_TUB; dev->sense[4] = 0x80; /* Tape Unit Reject */ break; case TAPE_BSENSE_READFAIL: case TAPE_BSENSE_BADALGORITHM: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = SENSE_DC; dev->sense[3] = 0xC0; /* Vertical CRC check & Multitrack error */ break; case TAPE_BSENSE_WRITEFAIL: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = SENSE_DC; dev->sense[3] = 0x60; /* Longitudinal CRC check & Multitrack error */ break; case TAPE_BSENSE_BADCOMMAND: case TAPE_BSENSE_INCOMPAT: *unitstat = CSW_UC; dev->sense[0] = SENSE_CR; dev->sense[4] = 0x01; break; case TAPE_BSENSE_WRITEPROTECT: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = SENSE_CR; break; case TAPE_BSENSE_LOADPTERR: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = 0; break; case TAPE_BSENSE_READTM: *unitstat = CSW_CE|CSW_DE|CSW_UX; break; case TAPE_BSENSE_UNSOLICITED: *unitstat = CSW_CE|CSW_DE; break; case TAPE_BSENSE_STATUSONLY: *unitstat = CSW_CE|CSW_DE; break; } // end switch(ERCode) if (TAPE_BSENSE_STATUSONLY == ERCode) return; // (mission accomplished) /* Fill in the common sense information */ if (strcmp(dev->filename,TAPE_UNLOADED) == 0 || !dev->tmh->tapeloaded(dev,NULL,0)) { dev->sense[0] |= SENSE_IR; dev->sense[1] |= SENSE1_TAPE_FP; dev->sense[1] &= ~SENSE1_TAPE_TUA; dev->sense[1] |= SENSE1_TAPE_TUB; } else { dev->sense[0] &= ~SENSE_IR; dev->sense[1] |= IsAtLoadPoint( dev ) ? SENSE1_TAPE_LOADPT : 0; dev->sense[1] |= dev->readonly || dev->tdparms.logical_readonly ? SENSE1_TAPE_FP : 0; dev->sense[1] |= SENSE1_TAPE_TUA; dev->sense[1] &= ~SENSE1_TAPE_TUB; } if (dev->tmh->passedeot(dev)) { dev->sense[4] |= 0x40; } } /* end function build_sense_3410_3420 */ /*-------------------------------------------------------------------*/ /* build_sense_3410 */ /*-------------------------------------------------------------------*/ void build_sense_3410 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode) { build_sense_3410_3420(ERCode,dev,unitstat,ccwcode); dev->sense[5] &= 0x80; dev->sense[5] |= 0x40; dev->sense[6] = 0x22; /* Dual Dens - 3410/3411 Model 2 */ dev->numsense = 9; } /* end function build_sense_3410 */ /*-------------------------------------------------------------------*/ /* build_sense_3420 */ /*-------------------------------------------------------------------*/ void build_sense_3420 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode) { build_sense_3410_3420(ERCode,dev,unitstat,ccwcode); /* Following stripped from original 'build_sense' */ dev->sense[5] |= 0xC0; dev->sense[6] |= 0x03; dev->sense[13] = 0x80; dev->sense[14] = 0x01; dev->sense[15] = 0x00; dev->sense[16] = 0x01; dev->sense[19] = 0xFF; dev->sense[20] = 0xFF; dev->numsense = 24; } /* end function build_sense_3420 */ /*-------------------------------------------------------------------*/ /* build_sense_3480_etal */ /*-------------------------------------------------------------------*/ void build_sense_3480_etal (int ERCode,DEVBLK *dev,BYTE *unitstat,BYTE ccwcode) { int sns4mat = TAPE_SNS7_FMT_20_3480; // NOTE: caller should have cleared sense area to zeros // if this isn't a 'TAPE_BSENSE_STATUSONLY' call switch(ERCode) { case TAPE_BSENSE_TAPEUNLOADED: dev->sense[0] = TAPE_SNS0_INTVREQ; dev->sense[3] = TAPE_ERA_DRIVE_NOT_READY; /* ERA 43 = Int Req */ *unitstat = CSW_UC; break; case TAPE_BSENSE_RUN_SUCCESS: /* Not an error */ /* NOT an error, But according to GA32-0219-02 2.1.2.2 Rewind Unload always ends with with DE+UC on secondary status */ /* FIXME! */ /* Note that Initial status & Secondary statuses are merged here */ /* when they should be presented separatly */ *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_INTVREQ; dev->sense[3] = TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT; sns4mat = TAPE_SNS7_FMT_22_3480_EOV_STATS; break; case TAPE_BSENSE_TAPELOADFAIL: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_INTVREQ|TAPE_SNS0_DEFUNITCK; dev->sense[3] = TAPE_ERA_LOAD_FAILURE; /* ERA 33 = Load Failed */ break; case TAPE_BSENSE_READFAIL: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_DATACHK; dev->sense[3] = TAPE_ERA_READ_DATA_CHECK; break; case TAPE_BSENSE_WRITEFAIL: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_DATACHK; dev->sense[3] = TAPE_ERA_WRITE_DATA_CHECK; break; case TAPE_BSENSE_BADCOMMAND: *unitstat = CSW_UC; dev->sense[0] = TAPE_SNS0_CMDREJ; dev->sense[3] = TAPE_ERA_COMMAND_REJECT; break; case TAPE_BSENSE_INCOMPAT: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_CMDREJ; dev->sense[3] = TAPE_ERA_FUNCTION_INCOMPATIBLE; break; case TAPE_BSENSE_WRITEPROTECT: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_CMDREJ; dev->sense[3] = TAPE_ERA_WRITE_PROTECTED; break; case TAPE_BSENSE_EMPTYTAPE: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_DATACHK; dev->sense[3] = TAPE_ERA_TAPE_VOID; break; case TAPE_BSENSE_ENDOFTAPE: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_EQUIPCHK; dev->sense[3] = TAPE_ERA_PHYSICAL_END_OF_TAPE; break; case TAPE_BSENSE_LOADPTERR: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = 0; dev->sense[3] = TAPE_ERA_BACKWARD_AT_BOT; break; case TAPE_BSENSE_FENCED: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_EQUIPCHK|TAPE_SNS0_DEFUNITCK; /* Deffered UC */ dev->sense[3] = TAPE_ERA_VOLUME_FENCED; break; case TAPE_BSENSE_BADALGORITHM: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_EQUIPCHK; if (dev->devtype==0x3480) { dev->sense[3] = TAPE_ERA_VOLUME_FENCED; // (volume fenced) } else // 3490, 3590, etc. { dev->sense[3] = TAPE_ERA_COMPACT_ALGORITHM_INCOMPAT; // (bad compaction algorithm) } break; case TAPE_BSENSE_LOCATEERR: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_EQUIPCHK; dev->sense[3] = TAPE_ERA_LOCATE_BLOCK_FAILED; break; case TAPE_BSENSE_BLOCKSHORT: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_EQUIPCHK; dev->sense[3] = TAPE_ERA_END_OF_DATA; break; case TAPE_BSENSE_ITFERROR: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_EQUIPCHK; dev->sense[3] = TAPE_ERA_PATH_EQUIPMENT_CHECK; break; case TAPE_BSENSE_REWINDFAILED: *unitstat = CSW_CE|CSW_DE|CSW_UC; dev->sense[0] = TAPE_SNS0_EQUIPCHK; dev->sense[3] = TAPE_ERA_PERMANENT_EQUIPMENT_CHECK; /* Generic Equipment Malfunction ERP code */ break; case TAPE_BSENSE_READTM: *unitstat = CSW_CE|CSW_DE|CSW_UX; break; case TAPE_BSENSE_UNSOLICITED: *unitstat = CSW_CE|CSW_DE; dev->sense[3] = TAPE_ERA_UNSOLICITED_SENSE; break; case TAPE_BSENSE_STATUSONLY: default: if ( ccwcode == 0x24 ) // READ BUFFERED LOG { if ( dev->tdparms.compress == 0 ) sns4mat = TAPE_SNS7_FMT_21_3480_READ_BUF_LOG; else sns4mat = TAPE_SNS7_FMT_30_3480_READ_BUF_LOG; } *unitstat = CSW_CE|CSW_DE; break; } // end switch(ERCode) if (TAPE_BSENSE_STATUSONLY == ERCode) return; // (mission accomplished) /* Fill in the common sense information */ if ( sns4mat == TAPE_SNS7_FMT_20_3480 || sns4mat == TAPE_SNS7_FMT_21_3480_READ_BUF_LOG || sns4mat == TAPE_SNS7_FMT_22_3480_EOV_STATS || sns4mat == TAPE_SNS7_FMT_30_3480_READ_BUF_LOG ) { dev->sense[7] = sns4mat; memset(&dev->sense[8],0,31-8); if ( sns4mat == TAPE_SNS7_FMT_20_3480 ) { dev->sense[25] = 0x06; // IDRC Installed & Upgraded Buffer if ( sysblk.tamdir != NULL ) // is AUTOLOADER ENABLED { dev->sense[25] |= 0x01; // ACL is installed } } if ( dev->devtype == 0x3480 ) { dev->sense[27] = 0xf0; // indicate 3480-A22/B22 } else if ( dev->devtype==0x3490 ) { dev->sense[27] = 0xe0; // indicate 3490-D31/D32 } else if ( dev->devtype==0x3590 ) { dev->sense[27] = 0xe0; // indicate same as 3490 for now } /* create a serial Number */ dev->sense[27] |= 0x0C; dev->sense[28] = (BYTE)( ( dev->devnum >> 12 ) & 0xFF ); dev->sense[29] = (BYTE)( ( dev->devnum >> 4 ) & 0xFF ); dev->sense[30] = (BYTE)( dev->devnum & 0x000F ) | ( (BYTE)((BYTE)( dev->devnum & 0x000F )) << 4 ); } if (strcmp(dev->filename,TAPE_UNLOADED) == 0 || !dev->tmh->tapeloaded(dev,NULL,0)) { dev->sense[0] |= TAPE_SNS0_INTVREQ; dev->sense[1] |= TAPE_SNS1_FILEPROT; } else { dev->sense[0] &= ~TAPE_SNS0_INTVREQ; dev->sense[1] &= ~(TAPE_SNS1_BOT|TAPE_SNS1_FILEPROT); dev->sense[1] |= IsAtLoadPoint( dev ) ? TAPE_SNS1_BOT : 0; dev->sense[1] |= dev->readonly || dev->tdparms.logical_readonly ? TAPE_SNS1_FILEPROT : 0; } dev->sense[1] |= TAPE_SNS1_ONLINE; dev->sense[2] |= TAPE_SNS2_REPORTING_CHAN_A; } /* end function build_sense_3480_etal */ /*-------------------------------------------------------------------*/ /* build_sense_3490 */ /*-------------------------------------------------------------------*/ void build_sense_3490 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode) { // Until we know for sure that we have to do something different, // we should be able to safely use the 3480 sense function here... build_sense_3480_etal( ERCode, dev, unitstat, ccwcode ); } /*-------------------------------------------------------------------*/ /* build_sense_3590 */ /*-------------------------------------------------------------------*/ void build_sense_3590 (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode) { unsigned char ERA; // Until we know for sure that we have to do something different, // we should be able to safely use the 3480 sense function here... build_sense_3480_etal( ERCode, dev, unitstat, ccwcode ); ERA = dev->sense[3]; switch ( ERA ) { case TAPE_ERA_LOAD_DISPLAY_CHECK: case TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT: case TAPE_ERA_READ_BUFFERED_LOG: case TAPE_ERA_END_OF_VOLUME_PROCESSING: case TAPE_ERA_END_OF_VOLUME_COMPLETE: dev->sense[2] |= TAPE_SNS2_NTP_BRAC_01_CONTINUE; break; case TAPE_ERA_DATA_STREAMING_NOT_OPER: case TAPE_ERA_UNSOL_ENVIRONMENTAL_DATA: case TAPE_ERA_DEGRADED_MODE: case TAPE_ERA_RECOVERED_CHECKONE_FAILURE: case TAPE_ERA_CONTROLLING_COMP_RETRY_REQ: dev->sense[2] |= TAPE_SNS2_NTP_BRAC_10_REISSUE; break; default: dev->sense[2] |= TAPE_SNS2_NTP_BRAC_00_PERM_ERR; break; } } /*-------------------------------------------------------------------*/ /* build_sense_Streaming */ /* (8809, 9347, 9348) */ /*-------------------------------------------------------------------*/ void build_sense_Streaming (int ERCode, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode) { UNREFERENCED(ccwcode); // NOTE: caller should have cleared sense area to zeros // if this isn't a 'TAPE_BSENSE_STATUSONLY' call switch(ERCode) { case TAPE_BSENSE_TAPEUNLOADED: *unitstat = CSW_UC; dev->sense[0] = SENSE_IR; dev->sense[3] = 6; /* Int Req ERAC */ break; case TAPE_BSENSE_RUN_SUCCESS: /* RewUnld op */ *unitstat = CSW_UC | CSW_CE | CSW_DE | CSW_CUE; /* *unitstat = CSW_CE | CSW_UC | CSW_DE | CSW_CUE; */ dev->sense[0] = SENSE_IR; dev->sense[3] = 6; /* Int Req ERAC */ break; case TAPE_BSENSE_REWINDFAILED: case TAPE_BSENSE_ITFERROR: dev->sense[0] = SENSE_EC; dev->sense[3] = 0x03; /* Perm Equip Check */ *unitstat = CSW_CE|CSW_DE|CSW_UC; break; case TAPE_BSENSE_TAPELOADFAIL: case TAPE_BSENSE_LOCATEERR: case TAPE_BSENSE_ENDOFTAPE: case TAPE_BSENSE_EMPTYTAPE: case TAPE_BSENSE_FENCED: case TAPE_BSENSE_BLOCKSHORT: case TAPE_BSENSE_INCOMPAT: dev->sense[0] = SENSE_EC; dev->sense[3] = 0x10; /* PE-ID Burst Check */ *unitstat = CSW_CE|CSW_DE|CSW_UC; break; case TAPE_BSENSE_BADALGORITHM: case TAPE_BSENSE_READFAIL: dev->sense[0] = SENSE_DC; dev->sense[3] = 0x09; /* Read Data Check */ *unitstat = CSW_CE|CSW_DE|CSW_UC; break; case TAPE_BSENSE_WRITEFAIL: dev->sense[0] = SENSE_DC; dev->sense[3] = 0x07; /* Write Data Check (Media Error) */ *unitstat = CSW_CE|CSW_DE|CSW_UC; break; case TAPE_BSENSE_BADCOMMAND: dev->sense[0] = SENSE_CR; dev->sense[3] = 0x0C; /* Bad Command */ *unitstat = CSW_UC; break; case TAPE_BSENSE_WRITEPROTECT: dev->sense[0] = SENSE_CR; dev->sense[3] = 0x0B; /* File Protect */ *unitstat = CSW_CE|CSW_DE|CSW_UC; break; case TAPE_BSENSE_LOADPTERR: dev->sense[0] = SENSE_CR; dev->sense[3] = 0x0D; /* Backspace at Load Point */ *unitstat = CSW_CE|CSW_DE|CSW_UC; break; case TAPE_BSENSE_READTM: *unitstat = CSW_CE|CSW_DE|CSW_UX; break; case TAPE_BSENSE_UNSOLICITED: *unitstat = CSW_CE|CSW_DE; break; case TAPE_BSENSE_STATUSONLY: *unitstat = CSW_CE|CSW_DE; break; } // end switch(ERCode) if (TAPE_BSENSE_STATUSONLY == ERCode) return; // (mission accomplished) /* Fill in the common sense information */ if (strcmp(dev->filename,TAPE_UNLOADED) == 0 || !dev->tmh->tapeloaded(dev,NULL,0)) { dev->sense[0] |= SENSE_IR; dev->sense[1] |= SENSE1_TAPE_FP; dev->sense[1] &= ~SENSE1_TAPE_TUA; dev->sense[1] |= SENSE1_TAPE_TUB; } else { dev->sense[0] &= ~SENSE_IR; dev->sense[1] |= IsAtLoadPoint( dev ) ? SENSE1_TAPE_LOADPT : 0; dev->sense[1] |= dev->readonly || dev->tdparms.logical_readonly ? SENSE1_TAPE_FP : 0; dev->sense[1] |= SENSE1_TAPE_TUA; dev->sense[1] &= ~SENSE1_TAPE_TUB; } if (dev->tmh->passedeot(dev)) { dev->sense[4] |= 0x40; } } /* end function build_sense_Streaming */ /*********************************************************************/ /*********************************************************************/ /** **/ /** (( I N C O M P L E T E )) **/ /** **/ /** (experimental possible new sense handling function) **/ /** **/ /*********************************************************************/ /*********************************************************************/ #if 0 // ZZ FIXME: To Do... /*-------------------------------------------------------------------*/ /* Error Recovery Action codes */ /*-------------------------------------------------------------------*/ /* Even though ERA codes are, technically, only applicable for model 3480/3490/3590 tape drives (the sense information that is returned for model 3480/3490/3590 tape drives include the ERA code in them), we can nonetheless still use them as an argument for our 'BuildTapeSense' function even for other model tape drives (e.g. 3420's for example). That is to say, even though model 3420's for example, don't have an ERA code anywhere in their sense information, we can still use the ERA code as an argument in our call to our 'BuildTapeSense' function without actually using it anywhere in our sense info. In such a case we would be just using it as an internal value to tell us what type of sense information to build for the model 3420, but not for any other purpose. For 3480/3490/3590 model drives however, we not only use it for the same purpose (i.e. as an internal value to tell us what format of sense we need to build) but ALSO as an actual value to be placed into the actual formatted sense information itself too. */ #define TAPE_ERA_UNSOLICITED_SENSE 0x00 #define TAPE_ERA_DATA_STREAMING_NOT_OPER 0x21 #define TAPE_ERA_PATH_EQUIPMENT_CHECK 0x22 #define TAPE_ERA_READ_DATA_CHECK 0x23 #define TAPE_ERA_LOAD_DISPLAY_CHECK 0x24 #define TAPE_ERA_WRITE_DATA_CHECK 0x25 #define TAPE_ERA_READ_OPPOSITE 0x26 #define TAPE_ERA_COMMAND_REJECT 0x27 #define TAPE_ERA_WRITE_ID_MARK_CHECK 0x28 #define TAPE_ERA_FUNCTION_INCOMPATIBLE 0x29 #define TAPE_ERA_UNSOL_ENVIRONMENTAL_DATA 0x2A #define TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT 0x2B #define TAPE_ERA_PERMANENT_EQUIPMENT_CHECK 0x2C #define TAPE_ERA_DATA_SECURE_ERASE_FAILURE 0x2D #define TAPE_ERA_NOT_CAPABLE_BOT_ERROR 0x2E #define TAPE_ERA_WRITE_PROTECTED 0x30 #define TAPE_ERA_TAPE_VOID 0x31 #define TAPE_ERA_TENSION_LOST 0x32 #define TAPE_ERA_LOAD_FAILURE 0x33 #define TAPE_ERA_UNLOAD_FAILURE 0x34 #define TAPE_ERA_DRIVE_EQUIPMENT_CHECK 0x35 #define TAPE_ERA_END_OF_DATA 0x36 #define TAPE_ERA_TAPE_LENGTH_ERROR 0x37 #define TAPE_ERA_PHYSICAL_END_OF_TAPE 0x38 #define TAPE_ERA_BACKWARD_AT_BOT 0x39 #define TAPE_ERA_DRIVE_SWITCHED_NOT_READY 0x3A #define TAPE_ERA_MANUAL_REWIND_OR_UNLOAD 0x3B #define TAPE_ERA_OVERRUN 0x40 #define TAPE_ERA_RECORD_SEQUENCE_ERROR 0x41 #define TAPE_ERA_DEGRADED_MODE 0x42 #define TAPE_ERA_DRIVE_NOT_READY 0x43 #define TAPE_ERA_LOCATE_BLOCK_FAILED 0x44 #define TAPE_ERA_DRIVE_ASSIGNED_ELSEWHERE 0x45 #define TAPE_ERA_DRIVE_NOT_ONLINE 0x46 #define TAPE_ERA_VOLUME_FENCED 0x47 #define TAPE_ERA_UNSOL_INFORMATIONAL_DATA 0x48 #define TAPE_ERA_BUS_OUT_CHECK 0x49 #define TAPE_ERA_CONTROL_UNIT_ERP_FAILURE 0x4A #define TAPE_ERA_CU_AND_DRIVE_INCOMPATIBLE 0x4B #define TAPE_ERA_RECOVERED_CHECKONE_FAILED 0x4C #define TAPE_ERA_RESETTING_EVENT 0x4D #define TAPE_ERA_MAX_BLOCKSIZE_EXCEEDED 0x4E #define TAPE_ERA_BUFFERED_LOG_OVERFLOW 0x50 #define TAPE_ERA_BUFFERED_LOG_END_OF_VOLUME 0x51 #define TAPE_ERA_END_OF_VOLUME_COMPLETE 0x52 #define TAPE_ERA_GLOBAL_COMMAND_INTERCEPT 0x53 #define TAPE_ERA_TEMP_CHANN_INTFACE_ERROR 0x54 #define TAPE_ERA_PERM_CHANN_INTFACE_ERROR 0x55 #define TAPE_ERA_CHANN_PROTOCOL_ERROR 0x56 #define TAPE_ERA_GLOBAL_STATUS_INTERCEPT 0x57 #define TAPE_ERA_TAPE_LENGTH_INCOMPATIBLE 0x5A #define TAPE_ERA_FORMAT_3480_XF_INCOMPAT 0x5B #define TAPE_ERA_FORMAT_3480_2_XF_INCOMPAT 0x5C #define TAPE_ERA_TAPE_LENGTH_VIOLATION 0x5D #define TAPE_ERA_COMPACT_ALGORITHM_INCOMPAT 0x5E // Sense byte 0 #define TAPE_SNS0_CMDREJ 0x80 // Command Reject #define TAPE_SNS0_INTVREQ 0x40 // Intervention Required #define TAPE_SNS0_BUSCHK 0x20 // Bus-out Check #define TAPE_SNS0_EQUIPCHK 0x10 // Equipment Check #define TAPE_SNS0_DATACHK 0x08 // Data check #define TAPE_SNS0_OVERRUN 0x04 // Overrun #define TAPE_SNS0_DEFUNITCK 0x02 // Deferred Unit Check #define TAPE_SNS0_ASSIGNED 0x01 // Assigned Elsewhere // Sense byte 1 #define TAPE_SNS1_LOCFAIL 0x80 // Locate Failure #define TAPE_SNS1_ONLINE 0x40 // Drive Online to CU #define TAPE_SNS1_RSRVD 0x20 // Reserved #define TAPE_SNS1_RCDSEQ 0x10 // Record Sequence Error #define TAPE_SNS1_BOT 0x08 // Beginning of Tape #define TAPE_SNS1_WRTMODE 0x04 // Write Mode #define TAPE_SNS1_FILEPROT 0x02 // Write Protect #define TAPE_SNS1_NOTCAPBL 0x01 // Not Capable // Sense byte 2 //efine TAPE_SNS2_XXXXXXX 0x80-0x04 // (not defined) #define TAPE_SNS2_SYNCMODE 0x02 // Tape Synchronous Mode #define TAPE_SNS2_POSITION 0x01 // Tape Positioning #define BUILD_TAPE_SENSE( _era ) BuildTapeSense( _era, dev, unitstat, code ) // BUILD_TAPE_SENSE( TAPE_ERA_COMMAND_REJECT ); /*-------------------------------------------------------------------*/ /* BuildTapeSense */ /*-------------------------------------------------------------------*/ /* Build appropriate sense information based on passed ERA code... */ /*-------------------------------------------------------------------*/ void BuildTapeSense( BYTE era, DEVBLK *dev, BYTE *unitstat, BYTE ccwcode ) { BYTE fmt; // ---------------- Determine Sense Format ----------------------- switch (era) { default: fmt = 0x20; break; case TAPE_ERA_UNSOL_ENVIRONMENTAL_DATA: // ERA 2A fmt = 0x21; break; case TAPE_ERA_ENVIRONMENTAL_DATA_PRESENT: // ERA 2B if (dev->devchar[8] & 0x01) // Extended Buffered Log support enabled? fmt = 0x30; // Yes, IDRC; 64-bytes of sense data else fmt = 0x21; // No, no IDRC; only 32-bytes of sense break; case TAPE_ERA_UNSOL_INFORMATIONAL_DATA: // ERA 48 if (dev->forced_logging) // Forced Error Logging enabled? fmt = 0x19; // Yes, Forced Error Logging sense else fmt = 0x20; // No, Normal Informational sense break; case TAPE_ERA_END_OF_VOLUME_COMPLETE: // ERA 52 fmt = 0x22; break; case TAPE_ERA_FORMAT_3480_2_XF_INCOMPAT: // ERA 5C fmt = 0x24; break; } // End switch (era) // ---------------- Build Sense Format ----------------------- switch (fmt) { case 0x19: break; default: case 0x20: break; case 0x21: break; case 0x22: break; case 0x24: break; case 0x30: break; } // End switch (fmt) } /* end function BuildTapeSense */ #endif // ZZ FIXME: To Do... /*********************************************************************/ /*********************************************************************/ hercules-3.12/awstape.c0000664000175000017500000007146712564723224012032 00000000000000/* AWSTAPE.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Tape Device Handler for AWSTAPE */ /* Original Author: Roger Bowler */ /* Prime Maintainer: Ivan Warren */ /* Secondary Maintainer: "Fish" (David B. Trout) */ /*-------------------------------------------------------------------*/ /* This module contains the AWSTAPE emulated tape format support. */ /* */ /* The subroutines in this module are called by the general tape */ /* device handler (tapedev.c) when the tape format is AWSTAPE. */ /* */ /* Messages issued by this module are prefixed HHCTA1nn */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /* need Hercules control blocks */ #include "tapedev.h" /* Main tape handler header file */ //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING) #ifdef ENABLE_TRACING_STMTS #if !defined(DEBUG) #warning DEBUG required for ENABLE_TRACING_STMTS #endif // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h) #else #undef TRACE #undef ASSERT #undef VERIFY #define TRACE 1 ? ((void)0) : logmsg #define ASSERT(a) #define VERIFY(a) ((void)(a)) #endif /*********************************************************************/ /* START OF ORIGINAL AWS FUNCTIONS (ISW Additions) */ /*********************************************************************/ /*-------------------------------------------------------------------*/ /* Close an AWSTAPE format file */ /* New Function added by ISW for consistency with other medias */ /*-------------------------------------------------------------------*/ void close_awstape (DEVBLK *dev) { if(dev->fd>=0) { logmsg (_("HHCTA101I %4.4X: AWS Tape %s closed\n"), dev->devnum, dev->filename); close(dev->fd); } strcpy(dev->filename, TAPE_UNLOADED); dev->fd=-1; dev->blockid = 0; dev->fenced = 0; return; } /*-------------------------------------------------------------------*/ /* Rewinds an AWS Tape format file */ /* New Function added by ISW for consistency with other medias */ /*-------------------------------------------------------------------*/ int rewind_awstape (DEVBLK *dev,BYTE *unitstat,BYTE code) { off_t rcoff; rcoff=lseek(dev->fd,0,SEEK_SET); if(rcoff<0) { build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code); return -1; } dev->nxtblkpos=0; dev->prvblkpos=-1; dev->curfilen=1; dev->blockid=0; dev->fenced = 0; return 0; } /*-------------------------------------------------------------------*/ /* Determines if a tape has passed a virtual EOT marker */ /* New Function added by ISW for consistency with other medias */ /*-------------------------------------------------------------------*/ int passedeot_awstape (DEVBLK *dev) { if(dev->nxtblkpos==0) { dev->eotwarning = 0; return 0; } if(dev->tdparms.maxsize==0) { dev->eotwarning = 0; return 0; } if(dev->nxtblkpos+dev->eotmargin > dev->tdparms.maxsize) { dev->eotwarning = 1; return 1; } dev->eotwarning = 0; return 0; } /*********************************************************************/ /* START OF ORIGINAL RB AWS FUNCTIONS */ /*********************************************************************/ /*-------------------------------------------------------------------*/ /* Open an AWSTAPE format file */ /* */ /* If successful, the file descriptor is stored in the device block */ /* and the return value is zero. Otherwise the return value is -1. */ /*-------------------------------------------------------------------*/ int open_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc = -1; /* Return code */ char pathname[MAX_PATH]; /* file path in host format */ /* Check for no tape in drive */ if (!strcmp (dev->filename, TAPE_UNLOADED)) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); return -1; } /* Open the AWSTAPE file */ hostpath(pathname, dev->filename, sizeof(pathname)); if(!dev->tdparms.logical_readonly) { rc = hopen(pathname, O_RDWR | O_BINARY); } /* If file is read-only, attempt to open again */ if (dev->tdparms.logical_readonly || (rc < 0 && (EROFS == errno || EACCES == errno))) { dev->readonly = 1; rc = hopen(pathname, O_RDONLY | O_BINARY); } /* Check for successful open */ if (rc < 0) { logmsg (_("HHCTA102E %4.4X: Error opening %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); strcpy(dev->filename, TAPE_UNLOADED); build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code); return -1; } /* Store the file descriptor in the device block */ dev->fd = rc; rc=rewind_awstape(dev,unitstat,code); return rc; } /* end function open_awstape */ /*-------------------------------------------------------------------*/ /* Read an AWSTAPE block header */ /* */ /* If successful, return value is zero, and buffer contains header. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int readhdr_awstape (DEVBLK *dev, off_t blkpos, AWSTAPE_BLKHDR *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ /* Reposition file to the requested block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA103E %4.4X: Error seeking to offset "I64_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Read the 6-byte block header */ rc = read (dev->fd, buf, sizeof(AWSTAPE_BLKHDR)); /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCTA104E %4.4X: Error reading block header " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file (uninitialized tape) condition */ if (rc == 0) { logmsg (_("HHCTA105E %4.4X: End of file (end of tape) " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); /* Set unit exception with tape indicate (end of tape) */ build_senseX(TAPE_BSENSE_EMPTYTAPE,dev,unitstat,code); return -1; } /* Handle end of file within block header */ if (rc < (int)sizeof(AWSTAPE_BLKHDR)) { logmsg (_("HHCTA106E %4.4X: Unexpected end of file in block header " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Successful return */ return 0; } /* end function readhdr_awstape */ /*-------------------------------------------------------------------*/ /* Read a block from an AWSTAPE format file */ /* */ /* The block may be formed of one or more block segments each */ /* preceded by an AWSTAPE block header. The ENDREC flag in the */ /* block header indicates the final segment of the block. */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the return value is zero, and the */ /* current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int read_awstape (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ off_t blkpos; /* Offset of block header */ int blklen = 0; /* Total length of block */ U16 seglen; /* Data length of segment */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Read block segments until end of block */ do { /* Read the 6-byte block header */ rc = readhdr_awstape (dev, blkpos, &awshdr, unitstat,code); if (rc < 0) return -1; /* Extract the segment length from the block header */ seglen = ((U16)(awshdr.curblkl[1]) << 8) | awshdr.curblkl[0]; /* Calculate the offset of the next block segment */ blkpos += sizeof(awshdr) + seglen; /* Check that block length will not exceed buffer size */ if (blklen + seglen > MAX_BLKLEN) { logmsg (_("HHCTA107E %4.4X: Block length exceeds %d " "at offset "I64_FMTX" in file %s\n"), dev->devnum, (int)MAX_BLKLEN, blkpos, dev->filename); /* Set unit check with data check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Check that tapemark blocksize is zero */ if ((awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) && blklen + seglen > 0) { logmsg (_("HHCTA108E %4.4X: Invalid tapemark " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); /* Set unit check with data check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Exit loop if this is a tapemark */ if (awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) break; /* Read data block segment from tape file */ rc = read (dev->fd, buf+blklen, seglen); /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCTA109E %4.4X: Error reading data block " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file within data block */ if (rc < seglen) { logmsg (_("HHCTA110E %4.4X: Unexpected end of file in data block " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); /* Set unit check with data check and partial record */ build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Accumulate the total block length */ blklen += seglen; } while ((awshdr.flags1 & AWSTAPE_FLAG1_ENDREC) == 0); /* Calculate the offsets of the next and previous blocks */ dev->prvblkpos = dev->nxtblkpos; dev->nxtblkpos = blkpos; /* Increment the block number */ dev->blockid++; /* Increment file number and return zero if tapemark was read */ if (blklen == 0) { dev->curfilen++; return 0; /* UX will be set by caller */ } /* Return block length */ return blklen; } /* end function read_awstape */ /*-------------------------------------------------------------------*/ /* Write a block to an AWSTAPE format file */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_awstape (DEVBLK *dev, BYTE *buf, U16 blklen, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ off_t blkpos; /* Offset of block header */ U16 prvblkl; /* Length of previous block */ /* Initialize current block position and previous block length */ blkpos = dev->nxtblkpos; prvblkl = 0; /* Determine previous block length if not at start of tape */ if (dev->nxtblkpos > 0) { /* Reread the previous block header */ rc = readhdr_awstape (dev, dev->prvblkpos, &awshdr, unitstat,code); if (rc < 0) return -1; /* Extract the block length from the block header */ prvblkl = ((U16)(awshdr.curblkl[1]) << 8) | awshdr.curblkl[0]; /* Recalculate the offset of the next block */ blkpos = dev->prvblkpos + sizeof(awshdr) + prvblkl; } /* Reposition file to the new block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA111E %4.4X: Error seeking to offset "I64_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* ISW: Determine if we are passed maxsize */ if(dev->tdparms.maxsize>0) { if((off_t)(dev->nxtblkpos+blklen+sizeof(awshdr)) > dev->tdparms.maxsize) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } } /* ISW: End of virtual physical EOT determination */ /* Build the 6-byte block header */ awshdr.curblkl[0] = blklen & 0xFF; awshdr.curblkl[1] = (blklen >> 8) & 0xFF; awshdr.prvblkl[0] = prvblkl & 0xFF; awshdr.prvblkl[1] = (prvblkl >>8) & 0xFF; awshdr.flags1 = AWSTAPE_FLAG1_NEWREC | AWSTAPE_FLAG1_ENDREC; awshdr.flags2 = 0; /* Write the block header */ rc = write (dev->fd, &awshdr, sizeof(awshdr)); if (rc < (int)sizeof(awshdr)) { if(errno==ENOSPC) { /* Disk FULL */ build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); logmsg (_("HHCTA112E %4.4X: Media full condition reached " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); return -1; } /* Handle write error condition */ logmsg (_("HHCTA113E %4.4X: Error writing block header " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Calculate the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos + sizeof(awshdr) + blklen; dev->prvblkpos = blkpos; /* Write the data block */ rc = write (dev->fd, buf, blklen); if (rc < blklen) { if(errno==ENOSPC) { /* Disk FULL */ build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); logmsg (_("HHCTA114E %4.4X: Media full condition reached " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); return -1; } /* Handle write error condition */ logmsg (_("HHCTA115E %4.4X: Error writing data block " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } dev->blockid++; /* Set new physical EOF */ do rc = ftruncate( dev->fd, dev->nxtblkpos ); while (EINTR == rc); if (rc != 0) { /* Handle write error condition */ logmsg (_("HHCTA116E %4.4X: Error writing data block " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ return 0; } /* end function write_awstape */ /*-------------------------------------------------------------------*/ /* Write a tapemark to an AWSTAPE format file */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_awsmark (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ off_t blkpos; /* Offset of block header */ U16 prvblkl; /* Length of previous block */ /* Initialize current block position and previous block length */ blkpos = dev->nxtblkpos; prvblkl = 0; /* Determine previous block length if not at start of tape */ if (dev->nxtblkpos > 0) { /* Reread the previous block header */ rc = readhdr_awstape (dev, dev->prvblkpos, &awshdr, unitstat,code); if (rc < 0) return -1; /* Extract the block length from the block header */ prvblkl = ((U16)(awshdr.curblkl[1]) << 8) | awshdr.curblkl[0]; /* Recalculate the offset of the next block */ blkpos = dev->prvblkpos + sizeof(awshdr) + prvblkl; } /* Reposition file to the new block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA117E %4.4X: Error seeking to offset "I64_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* ISW: Determine if we are passed maxsize */ if(dev->tdparms.maxsize>0) { if((off_t)(dev->nxtblkpos+sizeof(awshdr)) > dev->tdparms.maxsize) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } } /* ISW: End of virtual physical EOT determination */ /* Build the 6-byte block header */ awshdr.curblkl[0] = 0; awshdr.curblkl[1] = 0; awshdr.prvblkl[0] = prvblkl & 0xFF; awshdr.prvblkl[1] = (prvblkl >>8) & 0xFF; awshdr.flags1 = AWSTAPE_FLAG1_TAPEMARK; awshdr.flags2 = 0; /* Write the block header */ rc = write (dev->fd, &awshdr, sizeof(awshdr)); if (rc < (int)sizeof(awshdr)) { /* Handle write error condition */ logmsg (_("HHCTA118E %4.4X: Error writing block header " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } dev->blockid++; /* Calculate the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos + sizeof(awshdr); dev->prvblkpos = blkpos; /* Set new physical EOF */ do rc = ftruncate( dev->fd, dev->nxtblkpos ); while (EINTR == rc); if (rc != 0) { /* Handle write error condition */ logmsg (_("HHCTA119E Error writing tape mark " "at offset "I64_FMTX" in file %s: %s\n"), blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ return 0; } /* end function write_awsmark */ /*-------------------------------------------------------------------*/ /* Synchronize an AWSTAPE format file (i.e. flush buffers to disk) */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int sync_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code) { /* Unit check if tape is write-protected */ if (dev->readonly) { build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); return -1; } /* Perform sync. Return error on failure. */ if (fdatasync( dev->fd ) < 0) { /* Log the error */ logmsg (_("HHCTA120E %4.4X: Sync error on file %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ return 0; } /* end function sync_awstape */ /*-------------------------------------------------------------------*/ /* Forward space over next block of AWSTAPE format file */ /* */ /* If successful, return value is the length of the block skipped. */ /* If the block skipped was a tapemark, the return value is zero, */ /* and the current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsb_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ off_t blkpos; /* Offset of block header */ int blklen = 0; /* Total length of block */ U16 seglen; /* Data length of segment */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Read block segments until end of block */ do { /* Read the 6-byte block header */ rc = readhdr_awstape (dev, blkpos, &awshdr, unitstat,code); if (rc < 0) return -1; /* Extract the block length from the block header */ seglen = ((U16)(awshdr.curblkl[1]) << 8) | awshdr.curblkl[0]; /* Calculate the offset of the next block segment */ blkpos += sizeof(awshdr) + seglen; /* Accumulate the total block length */ blklen += seglen; /* Exit loop if this is a tapemark */ if (awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) break; } while ((awshdr.flags1 & AWSTAPE_FLAG1_ENDREC) == 0); /* Calculate the offsets of the next and previous blocks */ dev->prvblkpos = dev->nxtblkpos; dev->nxtblkpos = blkpos; /* Increment current file number if tapemark was skipped */ if (blklen == 0) dev->curfilen++; dev->blockid++; /* Return block length or zero if tapemark */ return blklen; } /* end function fsb_awstape */ /*-------------------------------------------------------------------*/ /* Backspace to previous block of AWSTAPE format file */ /* */ /* If successful, return value is the length of the block. */ /* If the block is a tapemark, the return value is zero, */ /* and the current file number in the device block is decremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsb_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ U16 curblkl; /* Length of current block */ U16 prvblkl; /* Length of previous block */ off_t blkpos; /* Offset of block header */ /* Unit check if already at start of tape */ if (dev->nxtblkpos == 0) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Backspace to previous block position */ blkpos = dev->prvblkpos; /* Read the 6-byte block header */ rc = readhdr_awstape (dev, blkpos, &awshdr, unitstat,code); if (rc < 0) return -1; /* Extract the block lengths from the block header */ curblkl = ((U16)(awshdr.curblkl[1]) << 8) | awshdr.curblkl[0]; prvblkl = ((U16)(awshdr.prvblkl[1]) << 8) | awshdr.prvblkl[0]; /* Calculate the offset of the previous block */ dev->prvblkpos = blkpos - sizeof(awshdr) - prvblkl; dev->nxtblkpos = blkpos; /* Decrement current file number if backspaced over tapemark */ if (curblkl == 0) dev->curfilen--; dev->blockid--; /* Return block length or zero if tapemark */ return curblkl; } /* end function bsb_awstape */ /*-------------------------------------------------------------------*/ /* Forward space to next logical file of AWSTAPE format file */ /* */ /* For AWSTAPE files, the forward space file operation is achieved */ /* by forward spacing blocks until positioned just after a tapemark. */ /* */ /* If successful, return value is zero, and the current file number */ /* in the device block is incremented by fsb_awstape. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsf_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ while (1) { /* Forward space over next block */ rc = fsb_awstape (dev, unitstat,code); if (rc < 0) return -1; /* Exit loop if spaced over a tapemark */ if (rc == 0) break; } /* end while */ /* Return normal status */ return 0; } /* end function fsf_awstape */ /*-------------------------------------------------------------------*/ /* Backspace to previous logical file of AWSTAPE format file */ /* */ /* For AWSTAPE files, the backspace file operation is achieved */ /* by backspacing blocks until positioned just before a tapemark */ /* or until positioned at start of tape. */ /* */ /* If successful, return value is zero, and the current file number */ /* in the device block is decremented by bsb_awstape. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsf_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ while (1) { /* Exit if now at start of tape */ if (dev->nxtblkpos == 0) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Backspace to previous block position */ rc = bsb_awstape (dev, unitstat,code); if (rc < 0) return -1; /* Exit loop if backspaced over a tapemark */ if (rc == 0) break; } /* end while */ /* Return normal status */ return 0; } /* end function bsf_awstape */ /*********************************************************************/ /* END OF ORIGINAL RB AWS FUNCTIONS */ /*********************************************************************/ hercules-3.12/faketape.c0000664000175000017500000007271612564723224012144 00000000000000/* FAKETAPE.C (c) Copyright "Fish" (David B. Trout), 2009 */ /* Hercules Tape Device Handler for FAKETAPE */ /*-------------------------------------------------------------------*/ /* This module contains the FAKETAPE emulated tape format support. */ /* */ /* The subroutines in this module are called by the general tape */ /* device handler (tapedev.c) when the tape format is FAKETAPE. */ /* */ /* Messages issued by this module are prefixed HHCTA5nn */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Reference information: */ /* FSIMS100 Faketape manual */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /* need Hercules control blocks */ #include "tapedev.h" /* Main tape handler header file */ //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING) #ifdef ENABLE_TRACING_STMTS #if !defined(DEBUG) #warning DEBUG required for ENABLE_TRACING_STMTS #endif // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h) #else #undef TRACE #undef ASSERT #undef VERIFY #define TRACE 1 ? ((void)0) : logmsg #define ASSERT(a) #define VERIFY(a) ((void)(a)) #endif /*********************************************************************/ /* START OF ORIGINAL AWS FUNCTIONS (ISW Additions) */ /*********************************************************************/ /*-------------------------------------------------------------------*/ /* Close a FAKETAPE format file */ /* New Function added by ISW for consistency with other medias */ /*-------------------------------------------------------------------*/ void close_faketape (DEVBLK *dev) { if(dev->fd>=0) { logmsg (_("HHCTA501I %4.4X: FakeTape %s closed\n"), dev->devnum, dev->filename); close(dev->fd); } strcpy(dev->filename, TAPE_UNLOADED); dev->fd=-1; dev->blockid = 0; dev->fenced = 0; return; } /*-------------------------------------------------------------------*/ /* Rewinds a FAKETAPE format file */ /* New Function added by ISW for consistency with other medias */ /*-------------------------------------------------------------------*/ int rewind_faketape (DEVBLK *dev,BYTE *unitstat,BYTE code) { off_t rcoff; rcoff=lseek(dev->fd,0,SEEK_SET); if(rcoff<0) { build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code); return -1; } dev->nxtblkpos=0; dev->prvblkpos=-1; dev->curfilen=1; dev->blockid=0; dev->fenced = 0; return 0; } /*-------------------------------------------------------------------*/ /* Determines if a FAKETAPE has passed a virtual EOT marker */ /* New Function added by ISW for consistency with other medias */ /*-------------------------------------------------------------------*/ int passedeot_faketape (DEVBLK *dev) { if(dev->nxtblkpos==0) { dev->eotwarning = 0; return 0; } if(dev->tdparms.maxsize==0) { dev->eotwarning = 0; return 0; } if(dev->nxtblkpos+dev->eotmargin > dev->tdparms.maxsize) { dev->eotwarning = 1; return 1; } dev->eotwarning = 0; return 0; } /*********************************************************************/ /* START OF ORIGINAL RB AWS FUNCTIONS */ /*********************************************************************/ /*-------------------------------------------------------------------*/ /* Open a FAKETAPE format file */ /* */ /* If successful, the file descriptor is stored in the device block */ /* and the return value is zero. Otherwise the return value is -1. */ /*-------------------------------------------------------------------*/ int open_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc = -1; /* Return code */ char pathname[MAX_PATH]; /* file path in host format */ /* Check for no tape in drive */ if (!strcmp (dev->filename, TAPE_UNLOADED)) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); return -1; } /* Open the FAKETAPE file */ hostpath(pathname, dev->filename, sizeof(pathname)); if(!dev->tdparms.logical_readonly) { rc = hopen(pathname, O_RDWR | O_BINARY); } /* If file is read-only, attempt to open again */ if (dev->tdparms.logical_readonly || (rc < 0 && (EROFS == errno || EACCES == errno))) { dev->readonly = 1; rc = hopen(pathname, O_RDONLY | O_BINARY); } /* Check for successful open */ if (rc < 0) { logmsg (_("HHCTA502E %4.4X: Error opening %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); strcpy(dev->filename, TAPE_UNLOADED); build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code); return -1; } /* Store the file descriptor in the device block */ dev->fd = rc; rc=rewind_faketape(dev,unitstat,code); return rc; } /* end function open_faketape */ /*-------------------------------------------------------------------*/ /* Read a FAKETAPE block header */ /* */ /* If successful, return value is zero, and prvblkl and curblkl are */ /* set to the previous and current block lengths respectively. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /* and prvblkl and curblkl are undefined. Either or both of prvblkl */ /* and/or curblkl may be NULL. */ /*-------------------------------------------------------------------*/ int readhdr_faketape (DEVBLK *dev, off_t blkpos, U16* pprvblkl, U16* pcurblkl, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ FAKETAPE_BLKHDR fakehdr; /* FakeTape block header */ char sblklen[5]; /* work for converting hdr */ int prvblkl; /* Previous block length */ int curblkl; /* Current block length */ int xorblkl; /* XOR check of block lens */ /* Reposition file to the requested block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA503E %4.4X: Error seeking to offset "I64_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Read the 12-ASCII-hex-character block header */ rc = read (dev->fd, &fakehdr, sizeof(FAKETAPE_BLKHDR)); /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCTA504E %4.4X: Error reading block header " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file (uninitialized tape) condition */ if (rc == 0) { logmsg (_("HHCTA505E %4.4X: End of file (end of tape) " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); /* Set unit exception with tape indicate (end of tape) */ build_senseX(TAPE_BSENSE_EMPTYTAPE,dev,unitstat,code); return -1; } /* Handle end of file within block header */ if (rc < (int)sizeof(FAKETAPE_BLKHDR)) { logmsg (_("HHCTA506E %4.4X: Unexpected end of file in block header " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Convert the ASCII-hex-character block lengths to binary */ strncpy( sblklen, fakehdr.sprvblkl, 4 ); sblklen[4] = 0; sscanf( sblklen, "%x", &prvblkl ); strncpy( sblklen, fakehdr.scurblkl, 4 ); sblklen[4] = 0; sscanf( sblklen, "%x", &curblkl ); strncpy( sblklen, fakehdr.sxorblkl, 4 ); sblklen[4] = 0; sscanf( sblklen, "%x", &xorblkl ); /* Verify header integrity using the XOR header field */ if ( (prvblkl ^ curblkl) != xorblkl ) { logmsg (_("HHCTA507E %4.4X: Block header damage " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Return the converted value(s) to the caller */ if (pprvblkl) *pprvblkl = prvblkl; if (pcurblkl) *pcurblkl = curblkl; /* Successful return */ return 0; } /* end function readhdr_faketape */ /*-------------------------------------------------------------------*/ /* Read a block from a FAKETAPE format file */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the return value is zero, and the */ /* current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int read_faketape (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t blkpos; /* Offset of block header */ U16 curblkl; /* Current block length */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Read the block header to obtain the current block length */ rc = readhdr_faketape (dev, blkpos, NULL, &curblkl, unitstat,code); if (rc < 0) return -1; /* (error message already issued) */ ASSERT( curblkl >= 0 ); /* Calculate the offset of the next block header */ blkpos += sizeof(FAKETAPE_BLKHDR) + curblkl; #if 0 /*BHE following code will never be true!!*/ /* Check that block length will not exceed buffer size */ if (curblkl > MAX_BLKLEN) { logmsg (_("HHCTA508E %4.4X: Block length exceeds %d " "at offset "I64_FMTX" in file %s\n"), dev->devnum, (int)MAX_BLKLEN, blkpos, dev->filename); /* Set unit check with data check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } #endif /* If not a tapemark, read the data block */ if (curblkl > 0) { rc = read (dev->fd, buf, curblkl); /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCTA510E %4.4X: Error reading data block " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file within data block */ if (rc < curblkl) { logmsg (_("HHCTA511E %4.4X: Unexpected end of file in data block " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); /* Set unit check with data check and partial record */ build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } } /* Calculate the offsets of the next and previous blocks */ dev->prvblkpos = dev->nxtblkpos; dev->nxtblkpos = blkpos; /* Increment the block number */ dev->blockid++; /* Increment file number and return zero if tapemark was read */ if (curblkl == 0) { dev->curfilen++; return 0; /* UX will be set by caller */ } /* Return block length */ return curblkl; } /* end function read_faketape */ /*-------------------------------------------------------------------*/ /* Write a FAKETAPE block header */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC. */ /*-------------------------------------------------------------------*/ int writehdr_faketape (DEVBLK *dev, off_t blkpos, U16 prvblkl, U16 curblkl, BYTE *unitstat, BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ FAKETAPE_BLKHDR fakehdr; /* FAKETAPE block header */ char sblklen[5]; /* work buffer */ /* Position file to where block header is to go */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA512E %4.4X: Error seeking to offset "I64_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Build the 12-ASCII-hex-character block header */ snprintf( sblklen, sizeof(sblklen), "%4.4X", prvblkl ); strncpy( fakehdr.sprvblkl, sblklen, sizeof(fakehdr.sprvblkl) ); snprintf( sblklen, sizeof(sblklen), "%4.4X", curblkl ); strncpy( fakehdr.scurblkl, sblklen, sizeof(fakehdr.scurblkl) ); snprintf( sblklen, sizeof(sblklen), "%4.4X", prvblkl ^ curblkl ); strncpy( fakehdr.sxorblkl, sblklen, sizeof(fakehdr.sxorblkl) ); /* Write the block header */ rc = write (dev->fd, &fakehdr, sizeof(FAKETAPE_BLKHDR)); if (rc < (int)sizeof(FAKETAPE_BLKHDR)) { if(errno==ENOSPC) { /* Disk FULL */ build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); logmsg (_("HHCTA513E %4.4X: Media full condition reached " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); return -1; } /* Handle write error condition */ logmsg (_("HHCTA514E %4.4X: Error writing block header " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } return 0; } /* end function writehdr_faketape */ /*-------------------------------------------------------------------*/ /* Write a block to a FAKETAPE format file */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_faketape (DEVBLK *dev, BYTE *buf, U16 blklen, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ off_t blkpos; /* Offset of block header */ U16 prvblkl; /* Length of previous block */ /* Initialize current block position and previous block length */ blkpos = dev->nxtblkpos; prvblkl = 0; /* Determine previous block length if not at start of tape */ if (dev->nxtblkpos > 0) { /* Retrieve the previous block length */ rc = readhdr_faketape (dev, dev->prvblkpos, NULL, &prvblkl, unitstat,code); if (rc < 0) return -1; /* Recalculate the offset of the next block */ blkpos = dev->prvblkpos + sizeof(FAKETAPE_BLKHDR) + prvblkl; } /* Reposition file to the new block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA515E %4.4X: Error seeking to offset "I64_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* ISW: Determine if we are passed maxsize */ if(dev->tdparms.maxsize>0) { if((off_t)(dev->nxtblkpos+blklen+sizeof(FAKETAPE_BLKHDR)) > dev->tdparms.maxsize) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } } /* ISW: End of virtual physical EOT determination */ /* Write the block header */ rc = writehdr_faketape (dev, rcoff, prvblkl, blklen, unitstat, code); if (rc < 0) return -1; /* (error message already issued) */ /* Calculate the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos + sizeof(FAKETAPE_BLKHDR) + blklen; dev->prvblkpos = blkpos; /* Write the data block */ rc = write (dev->fd, buf, blklen); if (rc < blklen) { if(errno==ENOSPC) { /* Disk FULL */ build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); logmsg (_("HHCTA516E %4.4X: Media full condition reached " "at offset "I64_FMTX" in file %s\n"), dev->devnum, blkpos, dev->filename); return -1; } /* Handle write error condition */ logmsg (_("HHCTA517E %4.4X: Error writing data block " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Increment the block number */ dev->blockid++; /* Set new physical EOF */ do rc = ftruncate( dev->fd, dev->nxtblkpos ); while (EINTR == rc); if (rc != 0) { /* Handle write error condition */ logmsg (_("HHCTA518E %4.4X: Error writing data block " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ return 0; } /* end function write_faketape */ /*-------------------------------------------------------------------*/ /* Write a tapemark to a FAKETAPE format file */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_fakemark (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ off_t blkpos; /* Offset of block header */ U16 prvblkl; /* Length of previous block */ /* Initialize current block position and previous block length */ blkpos = dev->nxtblkpos; prvblkl = 0; /* Determine previous block length if not at start of tape */ if (dev->nxtblkpos > 0) { /* Retrieve the previous block length */ rc = readhdr_faketape (dev, dev->prvblkpos, NULL, &prvblkl, unitstat,code); if (rc < 0) return -1; /* Recalculate the offset of the next block */ blkpos = dev->prvblkpos + sizeof(FAKETAPE_BLKHDR) + prvblkl; } /* Reposition file to the new block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA519E %4.4X: Error seeking to offset "I64_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* ISW: Determine if we are passed maxsize */ if(dev->tdparms.maxsize>0) { if((off_t)(dev->nxtblkpos+sizeof(FAKETAPE_BLKHDR)) > dev->tdparms.maxsize) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } } /* ISW: End of virtual physical EOT determination */ /* Write the block header */ rc = writehdr_faketape (dev, rcoff, prvblkl, 0, unitstat, code); if (rc < 0) return -1; /* (error message already issued) */ /* Increment the block number */ dev->blockid++; /* Calculate the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos + sizeof(FAKETAPE_BLKHDR); dev->prvblkpos = blkpos; /* Set new physical EOF */ do rc = ftruncate( dev->fd, dev->nxtblkpos ); while (EINTR == rc); if (rc != 0) { /* Handle write error condition */ logmsg (_("HHCTA520E %4.4X: Error writing tape mark " "at offset "I64_FMTX" in file %s: %s\n"), dev->devnum, blkpos, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ return 0; } /* end function write_fakemark */ /*-------------------------------------------------------------------*/ /* Synchronize a FAKETAPE format file (i.e. flush buffers to disk) */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int sync_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code) { /* Unit check if tape is write-protected */ if (dev->readonly) { build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); return -1; } /* Perform sync. Return error on failure. */ if (fdatasync( dev->fd ) < 0) { /* Log the error */ logmsg (_("HHCTA521E %4.4X: Sync error on file %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ return 0; } /* end function sync_faketape */ /*-------------------------------------------------------------------*/ /* Forward space over next block of a FAKETAPE format file */ /* */ /* If successful, return value is the length of the block skipped. */ /* If the block skipped was a tapemark, the return value is zero, */ /* and the current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsb_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t blkpos; /* Offset of block header */ U16 blklen; /* Block length */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Read the block header to obtain the current block length */ rc = readhdr_faketape (dev, blkpos, NULL, &blklen, unitstat,code); if (rc < 0) return -1; /* (error message already issued) */ /* Calculate the offset of the next block */ blkpos += sizeof(FAKETAPE_BLKHDR) + blklen; /* Calculate the offsets of the next and previous blocks */ dev->prvblkpos = dev->nxtblkpos; dev->nxtblkpos = blkpos; /* Increment current file number if tapemark was skipped */ if (blklen == 0) dev->curfilen++; /* Increment the block number */ dev->blockid++; /* Return block length or zero if tapemark */ return blklen; } /* end function fsb_faketape */ /*-------------------------------------------------------------------*/ /* Backspace to previous block of a FAKETAPE format file */ /* */ /* If successful, return value is the length of the block. */ /* If the block is a tapemark, the return value is zero, */ /* and the current file number in the device block is decremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsb_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ U16 curblkl; /* Length of current block */ U16 prvblkl; /* Length of previous block */ off_t blkpos; /* Offset of block header */ /* Unit check if already at start of tape */ if (dev->nxtblkpos == 0) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Backspace to previous block position */ blkpos = dev->prvblkpos; /* Read the block header to obtain the block lengths */ rc = readhdr_faketape (dev, blkpos, &prvblkl, &curblkl, unitstat,code); if (rc < 0) return -1; /* (error message already issued) */ /* Calculate the offset of the previous block */ dev->prvblkpos = blkpos - sizeof(FAKETAPE_BLKHDR) - prvblkl; dev->nxtblkpos = blkpos; /* Decrement current file number if backspaced over tapemark */ if (curblkl == 0) dev->curfilen--; /* Decrement the block number */ dev->blockid--; /* Return block length or zero if tapemark */ return curblkl; } /* end function bsb_faketape */ /*-------------------------------------------------------------------*/ /* Forward space to next logical file of a FAKETAPE format file */ /* */ /* For FAKETAPE files, the forward space file operation is achieved */ /* by forward spacing blocks until positioned just after a tapemark. */ /* */ /* If successful, return value is zero, and the current file number */ /* in the device block is incremented by fsb_faketape. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsf_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ while (1) { /* Forward space over next block */ rc = fsb_faketape (dev, unitstat,code); if (rc < 0) return -1; /* (error message already issued) */ /* Exit loop if spaced over a tapemark */ if (rc == 0) break; } /* end while */ /* Return normal status */ return 0; } /* end function fsf_faketape */ /*-------------------------------------------------------------------*/ /* Backspace to previous logical file of a FAKETAPE format file */ /* */ /* For FAKETAPE files, the backspace file operation is achieved */ /* by backspacing blocks until positioned just before a tapemark */ /* or until positioned at start of tape. */ /* */ /* If successful, return value is zero, and the current file number */ /* in the device block is decremented by bsb_faketape. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsf_faketape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ while (1) { /* Exit if now at start of tape */ if (dev->nxtblkpos == 0) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Backspace to previous block position */ rc = bsb_faketape (dev, unitstat,code); if (rc < 0) return -1; /* (error message already issued) */ /* Exit loop if backspaced over a tapemark */ if (rc == 0) break; } /* end while */ /* Return normal status */ return 0; } /* end function bsf_faketape */ /*********************************************************************/ /* END OF ORIGINAL RB AWS FUNCTIONS */ /*********************************************************************/ hercules-3.12/hettape.c0000664000175000017500000004404212564723224012005 00000000000000/* HETTAPE.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Tape Device Handler for HETTAPE */ /* Original Author: Leland Lucius */ /* Prime Maintainer: Ivan Warren */ /* Secondary Maintainer: "Fish" (David B. Trout) */ /*-------------------------------------------------------------------*/ /* This module contains the HET emulated tape format support. */ /* */ /* The subroutines in this module are called by the general tape */ /* device handler (tapedev.c) when the tape format is HETTAPE. */ /* */ /* Messages issued by this module are prefixed HHCTA4nn */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /* need Hercules control blocks */ #include "tapedev.h" /* Main tape handler header file */ //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING) #ifdef ENABLE_TRACING_STMTS #if !defined(DEBUG) #warning DEBUG required for ENABLE_TRACING_STMTS #endif // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h) #else #undef TRACE #undef ASSERT #undef VERIFY #define TRACE 1 ? ((void)0) : logmsg #define ASSERT(a) #define VERIFY(a) ((void)(a)) #endif /*-------------------------------------------------------------------*/ /* Open an HET format file */ /* */ /* If successful, the het control blk is stored in the device block */ /* and the return value is zero. Otherwise the return value is -1. */ /*-------------------------------------------------------------------*/ int open_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Check for no tape in drive */ if (!strcmp (dev->filename, TAPE_UNLOADED)) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); return -1; } /* Open the HET file */ rc = het_open (&dev->hetb, dev->filename, dev->tdparms.logical_readonly ? HETOPEN_READONLY : HETOPEN_CREATE ); if (rc >= 0) { if(dev->hetb->writeprotect) { dev->readonly=1; } rc = het_cntl (dev->hetb, HETCNTL_SET | HETCNTL_COMPRESS, dev->tdparms.compress); if (rc >= 0) { rc = het_cntl (dev->hetb, HETCNTL_SET | HETCNTL_METHOD, dev->tdparms.method); if (rc >= 0) { rc = het_cntl (dev->hetb, HETCNTL_SET | HETCNTL_LEVEL, dev->tdparms.level); if (rc >= 0) { rc = het_cntl (dev->hetb, HETCNTL_SET | HETCNTL_CHUNKSIZE, dev->tdparms.chksize); } } } } /* Check for successful open */ if (rc < 0) { int save_errno = errno; het_close (&dev->hetb); errno = save_errno; logmsg (_("HHCTA401E %4.4X: Error opening %s: %s(%s)\n"), dev->devnum, dev->filename, het_error(rc), strerror(errno)); strcpy(dev->filename, TAPE_UNLOADED); build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code); return -1; } /* Indicate file opened */ dev->fd = 1; return 0; } /* end function open_het */ /*-------------------------------------------------------------------*/ /* Close an HET format file */ /* */ /* The HET file is close and all device block fields reinitialized. */ /*-------------------------------------------------------------------*/ void close_het (DEVBLK *dev) { /* Close the HET file */ het_close (&dev->hetb); /* Reinitialize the DEV fields */ dev->fd = -1; strcpy (dev->filename, TAPE_UNLOADED); dev->blockid = 0; dev->fenced = 0; return; } /* end function close_het */ /*-------------------------------------------------------------------*/ /* Rewind HET format file */ /* */ /* The HET file is close and all device block fields reinitialized. */ /*-------------------------------------------------------------------*/ int rewind_het(DEVBLK *dev,BYTE *unitstat,BYTE code) { int rc; rc = het_rewind (dev->hetb); if (rc < 0) { /* Handle seek error condition */ logmsg (_("HHCTA402E %4.4X: Error seeking to start of %s: %s(%s)\n"), dev->devnum, dev->filename, het_error(rc), strerror(errno)); build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code); return -1; } dev->nxtblkpos=0; dev->prvblkpos=-1; dev->curfilen=1; dev->blockid=0; dev->fenced = 0; return 0; } /*-------------------------------------------------------------------*/ /* Read a block from an HET format file */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the return value is zero, and the */ /* current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int read_het (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ rc = het_read (dev->hetb, buf); if (rc < 0) { /* Increment file number and return zero if tapemark was read */ if (rc == HETE_TAPEMARK) { dev->curfilen++; dev->blockid++; return 0; } /* Handle end of file (uninitialized tape) condition */ if (rc == HETE_EOT) { logmsg (_("HHCTA414E %4.4X: End of file (end of tape) " "at block %8.8X in file %s\n"), dev->devnum, dev->hetb->cblk, dev->filename); /* Set unit exception with tape indicate (end of tape) */ build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } logmsg (_("HHCTA415E %4.4X: Error reading data block " "at block %8.8X in file %s: %s(%s)\n"), dev->devnum, dev->hetb->cblk, dev->filename, het_error(rc), strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } dev->blockid++; /* Return block length */ return rc; } /* end function read_het */ /*-------------------------------------------------------------------*/ /* Write a block to an HET format file */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_het (DEVBLK *dev, BYTE *buf, U16 blklen, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t cursize; /* Current size for size chk */ /* Check if we have already violated the size limit */ if(dev->tdparms.maxsize>0) { cursize=het_tell(dev->hetb); if(cursize>=dev->tdparms.maxsize) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } } /* Write the data block */ rc = het_write (dev->hetb, buf, blklen); if (rc < 0) { /* Handle write error condition */ logmsg (_("HHCTA416E %4.4X: Error writing data block " "at block %8.8X in file %s: %s(%s)\n"), dev->devnum, dev->hetb->cblk, dev->filename, het_error(rc), strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Check if we have violated the maxsize limit */ /* Also check if we are passed EOT marker */ if(dev->tdparms.maxsize>0) { cursize=het_tell(dev->hetb); if(cursize>dev->tdparms.maxsize) { logmsg (_("HHCTA430I %4.4X: max tape capacity exceeded\n"), dev->devnum); if(dev->tdparms.strictsize) { logmsg (_("HHCTA431I %4.4X: max tape capacity enforced\n"), dev->devnum); het_bsb(dev->hetb); cursize=het_tell(dev->hetb); ftruncate( fileno(dev->hetb->fd),cursize); dev->hetb->truncated=TRUE; /* SHOULD BE IN HETLIB */ } build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } } /* Return normal status */ dev->blockid++; return 0; } /* end function write_het */ /*-------------------------------------------------------------------*/ /* Write a tapemark to an HET format file */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_hetmark (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Write the tape mark */ rc = het_tapemark (dev->hetb); if (rc < 0) { /* Handle error condition */ logmsg (_("HHCTA417E %4.4X: Error writing tape mark " "at block %8.8X in file %s: %s(%s)\n"), dev->devnum, dev->hetb->cblk, dev->filename, het_error(rc), strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ dev->blockid++; return 0; } /* end function write_hetmark */ /*-------------------------------------------------------------------*/ /* Synchronize a HET format file (i.e. flush its buffers to disk) */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int sync_het(DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Perform the flush */ rc = het_sync (dev->hetb); if (rc < 0) { /* Handle error condition */ if (HETE_PROTECTED == rc) build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); else { logmsg (_("HHCTA488E %4.4X: Sync error on file %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); } return -1; } /* Return normal status */ return 0; } /* end function sync_het */ /*-------------------------------------------------------------------*/ /* Forward space over next block of an HET format file */ /* */ /* If successful, return value +1. */ /* If the block skipped was a tapemark, the return value is zero, */ /* and the current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsb_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Forward space one block */ rc = het_fsb (dev->hetb); if (rc < 0) { /* Increment file number and return zero if tapemark was read */ if (rc == HETE_TAPEMARK) { dev->blockid++; dev->curfilen++; return 0; } logmsg (_("HHCTA418E %4.4X: Error forward spacing " "at block %8.8X in file %s: %s(%s)\n"), dev->devnum, dev->hetb->cblk, dev->filename, het_error(rc), strerror(errno)); /* Set unit check with equipment check */ if(rc==HETE_EOT) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); } else { build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); } return -1; } dev->blockid++; /* Return +1 to indicate forward space successful */ return +1; } /* end function fsb_het */ /*-------------------------------------------------------------------*/ /* Backspace to previous block of an HET format file */ /* */ /* If successful, return value will be +1. */ /* If the block is a tapemark, the return value is zero, */ /* and the current file number in the device block is decremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsb_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Back space one block */ rc = het_bsb (dev->hetb); if (rc < 0) { /* Increment file number and return zero if tapemark was read */ if (rc == HETE_TAPEMARK) { dev->blockid--; dev->curfilen--; return 0; } /* Unit check if already at start of tape */ if (rc == HETE_BOT) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } logmsg (_("HHCTA419E %4.4X: Error reading data block " "at block %8.8X in file %s: %s(%s)\n"), dev->devnum, dev->hetb->cblk, dev->filename, het_error(rc), strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } dev->blockid--; /* Return +1 to indicate back space successful */ return +1; } /* end function bsb_het */ /*-------------------------------------------------------------------*/ /* Forward space to next logical file of HET format file */ /* */ /* If successful, return value is zero, and the current file number */ /* in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Forward space to start of next file */ rc = het_fsf (dev->hetb); if (rc < 0) { logmsg (_("HHCTA420E %4.4X: Error forward spacing to next file " "at block %8.8X in file %s: %s(%s)\n"), dev->devnum, dev->hetb->cblk, dev->filename, het_error(rc), strerror(errno)); if(rc==HETE_EOT) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); } else { build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); } return -1; } /* Maintain position */ dev->blockid = rc; dev->curfilen++; /* Return success */ return 0; } /* end function fsf_het */ /*-------------------------------------------------------------------*/ /* Check HET file is passed the allowed EOT margin */ /*-------------------------------------------------------------------*/ int passedeot_het (DEVBLK *dev) { off_t cursize; if(dev->fd>0) { if(dev->tdparms.maxsize>0) { cursize=het_tell(dev->hetb); if(cursize+dev->eotmargin>dev->tdparms.maxsize) { dev->eotwarning = 1; return 1; } } } dev->eotwarning = 0; return 0; } /*-------------------------------------------------------------------*/ /* Backspace to previous logical file of HET format file */ /* */ /* If successful, return value is zero, and the current file number */ /* in the device block is decremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Exit if already at BOT */ if (dev->curfilen==1 && dev->nxtblkpos == 0) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } rc = het_bsf (dev->hetb); if (rc < 0) { logmsg (_("HHCTA421E %4.4X: Error back spacing to previous file " "at block %8.8X in file %s:\n %s(%s)\n"), dev->devnum, dev->hetb->cblk, dev->filename, het_error(rc), strerror(errno)); build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Maintain position */ dev->blockid = rc; dev->curfilen--; /* Return success */ return 0; } /* end function bsf_het */ hercules-3.12/omatape.c0000664000175000017500000013164712564723224012011 00000000000000/* OMATAPE.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Tape Device Handler for OMATAPE */ /* Original Author: Roger Bowler */ /* Prime Maintainer: Ivan Warren */ /* Secondary Maintainer: "Fish" (David B. Trout) */ /*-------------------------------------------------------------------*/ /* This module contains the OMATAPE emulated tape format support. */ /* */ /* The subroutines in this module are called by the general tape */ /* device handler (tapedev.c) when the tape format is OMATAPE. */ /* */ /* Messages issued by this module are prefixed HHCTA2nn */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Reference information: */ /* SC53-1200 S/370 and S/390 Optical Media Attach/2 User's Guide */ /* SC53-1201 S/370 and S/390 Optical Media Attach/2 Technical Ref */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /* need Hercules control blocks */ #include "tapedev.h" /* Main tape handler header file */ //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING) #ifdef ENABLE_TRACING_STMTS #if !defined(DEBUG) #warning DEBUG required for ENABLE_TRACING_STMTS #endif // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h) #else #undef TRACE #undef ASSERT #undef VERIFY #define TRACE 1 ? ((void)0) : logmsg #define ASSERT(a) #define VERIFY(a) ((void)(a)) #endif /*-------------------------------------------------------------------*/ /* Read the OMA tape descriptor file */ /*-------------------------------------------------------------------*/ int read_omadesc (DEVBLK *dev) { int rc; /* Return code */ int i; /* Array subscript */ int pathlen; /* Length of TDF path name */ int tdfsize; /* Size of TDF file in bytes */ int filecount; /* Number of files */ int stmt; /* TDF file statement number */ int fd; /* TDF file descriptor */ struct stat statbuf; /* TDF file information */ U32 blklen; /* Fixed block length */ int tdfpos; /* Position in TDF buffer */ char *tdfbuf; /* -> TDF file buffer */ char *tdfrec; /* -> TDF record */ char *tdffilenm; /* -> Filename in TDF record */ char *tdfformat; /* -> Format in TDF record */ char *tdfreckwd; /* -> Keyword in TDF record */ char *tdfblklen; /* -> Length in TDF record */ OMATAPE_DESC *tdftab; /* -> Tape descriptor array */ BYTE c; /* Work area for sscanf */ char pathname[MAX_PATH]; /* file path in host format */ /* Isolate the base path name of the TDF file */ for (pathlen = strlen(dev->filename); pathlen > 0; ) { pathlen--; if (dev->filename[pathlen-1] == '/') break; } #if 0 // JCS thinks this is bad if (pathlen < 7 || strncasecmp(dev->filename+pathlen-7, "/tapes/", 7) != 0) { logmsg (_("HHCTA232I %4.4X: Invalid filename %s: " "TDF files must be in the TAPES subdirectory\n"), dev->devnum, dev->filename+pathlen); return -1; } pathlen -= 7; #endif /* Open the tape descriptor file */ hostpath(pathname, dev->filename, sizeof(pathname)); fd = hopen(pathname, O_RDONLY | O_BINARY); if (fd < 0) { logmsg (_("HHCTA239E %4.4X: Error opening TDF file %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); return -1; } /* Determine the size of the tape descriptor file */ rc = fstat (fd, &statbuf); if (rc < 0) { logmsg (_("HHCTA240E %4.4X: File %s fstat error: %s\n"), dev->devnum, dev->filename, strerror(errno)); close (fd); return -1; } tdfsize = statbuf.st_size; /* Obtain a buffer for the tape descriptor file */ tdfbuf = malloc (tdfsize); if (tdfbuf == NULL) { logmsg (_("HHCTA241E %4.4X: Cannot obtain buffer for TDF file %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); close (fd); return -1; } /* Read the tape descriptor file into the buffer */ rc = read (fd, tdfbuf, tdfsize); if (rc < tdfsize) { logmsg (_("HHCTA242E %4.4X: Error reading TDF file %s: %s\n"), dev->devnum, dev->filename, strerror(errno)); free (tdfbuf); close (fd); return -1; } /* Close the tape descriptor file */ close (fd); fd = -1; /* Check that the first record is a TDF header */ if (memcmp(tdfbuf, "@TDF", 4) != 0) { logmsg (_("HHCTA243E %4.4X: %s is not a valid TDF file\n"), dev->devnum, dev->filename); free (tdfbuf); return -1; } /* Count the number of linefeeds in the tape descriptor file to determine the size of the descriptor array required */ for (i = 0, filecount = 0; i < tdfsize; i++) { if (tdfbuf[i] == '\n') filecount++; } /* end for(i) */ /* ISW Add 1 to filecount to add an extra EOT marker */ filecount++; /* Obtain storage for the tape descriptor array */ tdftab = (OMATAPE_DESC*)malloc (filecount * sizeof(OMATAPE_DESC)); if (tdftab == NULL) { logmsg (_("HHCTA244E %4.4X: Cannot obtain buffer for TDF array: %s\n"), dev->devnum, strerror(errno)); free (tdfbuf); return -1; } /* Build the tape descriptor array */ for (filecount = 0, tdfpos = 0, stmt = 1; ; filecount++) { /* Clear the tape descriptor array entry */ memset (&(tdftab[filecount]), 0, sizeof(OMATAPE_DESC)); /* Point past the next linefeed in the TDF file */ while (tdfpos < tdfsize && tdfbuf[tdfpos++] != '\n'); stmt++; /* Exit at end of TDF file */ if (tdfpos >= tdfsize) break; /* Mark the end of the TDF record with a null terminator */ tdfrec = tdfbuf + tdfpos; while (tdfpos < tdfsize && tdfbuf[tdfpos]!='\r' && tdfbuf[tdfpos]!='\n') tdfpos++; c = tdfbuf[tdfpos]; if (tdfpos >= tdfsize) break; tdfbuf[tdfpos] = '\0'; /* Exit if TM or EOT record */ if (strcasecmp(tdfrec, "TM") == 0) { tdftab[filecount].format='X'; tdfbuf[tdfpos] = c; continue; } if(strcasecmp(tdfrec, "EOT") == 0) { tdftab[filecount].format='E'; break; } /* Parse the TDF record */ tdffilenm = strtok (tdfrec, " \t"); tdfformat = strtok (NULL, " \t"); tdfreckwd = strtok (NULL, " \t"); tdfblklen = strtok (NULL, " \t"); /* Check for missing fields */ if (tdffilenm == NULL || tdfformat == NULL) { logmsg (_("HHCTA245E %4.4X: Filename or format missing in " "line %d of file %s\n"), dev->devnum, stmt, dev->filename); free (tdftab); free (tdfbuf); return -1; } /* Check that the file name is not too long */ if (pathlen + 1 + strlen(tdffilenm) > sizeof(tdftab[filecount].filename) - 1) { logmsg (_("HHCTA246E %4.4X: Filename %s too long in " "line %d of file %s\n"), dev->devnum, tdffilenm, stmt, dev->filename); free (tdftab); free (tdfbuf); return -1; } /* Convert the file name to Unix format */ for (i = 0; i < (int)strlen(tdffilenm); i++) { if (tdffilenm[i] == '\\') tdffilenm[i] = '/'; /* JCS */ // else // tdffilenm[i] = tolower(tdffilenm[i]); } /* end for(i) */ /* Prefix the file name with the base path name and save it in the tape descriptor array */ /* but only if the filename lacks a leading slash - JCS */ /* strncpy (tdftab[filecount].filename, dev->filename, pathlen); if (tdffilenm[0] != '/') stlrcat ( tdftab[filecount].filename, "/", sizeof(tdftab[filecount].filename) ); strlcat ( tdftab[filecount].filename, tdffilenm, sizeof(tdftab[filecount].filename) ); */ tdftab[filecount].filename[0] = 0; if ((tdffilenm[0] != '/') && (tdffilenm[1] != ':')) { strncpy (tdftab[filecount].filename, dev->filename, pathlen); strlcat (tdftab[filecount].filename, "/", sizeof(tdftab[filecount].filename) ); } strlcat (tdftab[filecount].filename, tdffilenm, sizeof(tdftab[filecount].filename) ); /* Check for valid file format code */ if (strcasecmp(tdfformat, "HEADERS") == 0) { tdftab[filecount].format = 'H'; } else if (strcasecmp(tdfformat, "TEXT") == 0) { tdftab[filecount].format = 'T'; } else if (strcasecmp(tdfformat, "FIXED") == 0) { /* Check for RECSIZE keyword */ if (tdfreckwd == NULL || strcasecmp(tdfreckwd, "RECSIZE") != 0) { logmsg (_("HHCTA247E %4.4X: RECSIZE keyword missing in " "line %d of file %s\n"), dev->devnum, stmt, dev->filename); free (tdftab); free (tdfbuf); return -1; } /* Check for valid fixed block length */ if (tdfblklen == NULL || sscanf(tdfblklen, "%u%c", &blklen, &c) != 1 || blklen < 1 || blklen > MAX_BLKLEN) { logmsg (_("HHCTA248E %4.4X: Invalid record size %s in " "line %d of file %s\n"), dev->devnum, tdfblklen, stmt, dev->filename); free (tdftab); free (tdfbuf); return -1; } /* Set format and block length in descriptor array */ tdftab[filecount].format = 'F'; tdftab[filecount].blklen = blklen; } else { logmsg (_("HHCTA249E %4.4X: Invalid record format %s in " "line %d of file %s\n"), dev->devnum, tdfformat, stmt, dev->filename); free (tdftab); free (tdfbuf); return -1; } tdfbuf[tdfpos] = c; } /* end for(filecount) */ /* Force an EOT as last entry (filecount is correctly adjusted here) */ tdftab[filecount].format='E'; /* Save the file count and TDF array pointer in the device block */ dev->omafiles = filecount+1; dev->omadesc = tdftab; /* Release the TDF file buffer and exit */ free (tdfbuf); return 0; } /* end function read_omadesc */ /*-------------------------------------------------------------------*/ /* Open the OMATAPE file defined by the current file number */ /* */ /* The OMA tape descriptor file is read if necessary. */ /* If successful, the file descriptor is stored in the device block */ /* and the return value is zero. Otherwise the return value is -1. */ /*-------------------------------------------------------------------*/ int open_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int fd; /* File descriptor integer */ int rc; /* Return code */ OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */ char pathname[MAX_PATH]; /* file path in host format */ /* Check for no tape in drive */ if (!strcmp (dev->filename, TAPE_UNLOADED)) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); return -1; } /* Read the OMA descriptor file if necessary */ if (dev->omadesc == NULL) { rc = read_omadesc (dev); if (rc < 0) { build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code); return -1; } dev->blockid = 0; } dev->fenced = 0; /* Unit exception if beyond end of tape */ /* ISW: CHANGED PROCESSING - RETURN UNDEFINITE Tape Marks */ /* NOTE: The last entry in the TDF table is ALWAYS */ /* an EOT Condition */ /* This is ensured by the TDF reading routine */ #if 0 if (dev->curfilen >= dev->omafiles) { logmsg (_("HHCTA250E %4.4X: Attempt to access beyond end of tape %s\n"), dev->devnum, dev->filename); build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } #else if(dev->curfilen>dev->omafiles) { dev->curfilen=dev->omafiles; return(0); } #endif /* Point to the current file entry in the OMA descriptor table */ omadesc = (OMATAPE_DESC*)(dev->omadesc); omadesc += (dev->curfilen-1); if(omadesc->format=='X') { return 0; } if(omadesc->format=='E') { return 0; } /* Open the OMATAPE file */ hostpath(pathname, omadesc->filename, sizeof(pathname)); fd = hopen(pathname, O_RDONLY | O_BINARY); /* Check for successful open */ if (fd < 0 || lseek (fd, 0, SEEK_END) > LONG_MAX) { if (fd >= 0) /* (if open was successful, then it) */ errno = EOVERFLOW; /* (must have been a lseek overflow) */ logmsg (_("HHCTA251E %4.4X: Error opening %s: %s\n"), dev->devnum, omadesc->filename, strerror(errno)); if (fd >= 0) close(fd); /* (close the file if it was opened) */ build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code); return -1; } /* OMA tapes are always read-only */ dev->readonly = 1; /* Store the file descriptor in the device block */ dev->fd = fd; return 0; } /* end function open_omatape */ /*-------------------------------------------------------------------*/ /* Read a block header from an OMA tape file in OMA headers format */ /* */ /* If successful, return value is zero, and the current block */ /* length and previous and next header offsets are returned. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int readhdr_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc, long blkpos, S32 *pcurblkl, S32 *pprvhdro, S32 *pnxthdro, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ int padding; /* Number of padding bytes */ OMATAPE_BLKHDR omahdr; /* OMATAPE block header */ S32 curblkl; /* Length of current block */ S32 prvhdro; /* Offset of previous header */ S32 nxthdro; /* Offset of next header */ /* Seek to start of block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA252E %4.4X: Error seeking to offset "I32_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, omadesc->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Read the 16-byte block header */ rc = read (dev->fd, &omahdr, sizeof(omahdr)); /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCTA253E %4.4X: Error reading block header " "at offset "I32_FMTX" in file %s: %s\n"), dev->devnum, blkpos, omadesc->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file within block header */ if (rc < (int)sizeof(omahdr)) { logmsg (_("HHCTA254E %4.4X: Unexpected end of file in block header " "at offset "I32_FMTX" in file %s\n"), dev->devnum, blkpos, omadesc->filename); /* Set unit check with data check and partial record */ build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Extract the current block length and previous header offset */ curblkl = (S32)(((U32)(omahdr.curblkl[3]) << 24) | ((U32)(omahdr.curblkl[2]) << 16) | ((U32)(omahdr.curblkl[1]) << 8) | omahdr.curblkl[0]); prvhdro = (S32)((U32)(omahdr.prvhdro[3]) << 24) | ((U32)(omahdr.prvhdro[2]) << 16) | ((U32)(omahdr.prvhdro[1]) << 8) | omahdr.prvhdro[0]; /* Check for valid block header */ if (curblkl < -1 || curblkl == 0 || curblkl > MAX_BLKLEN || memcmp(omahdr.omaid, "@HDF", 4) != 0) { logmsg (_("HHCTA255E %4.4X: Invalid block header " "at offset "I32_FMTX" in file %s\n"), dev->devnum, blkpos, omadesc->filename); build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Calculate the number of padding bytes which follow the data */ padding = (16 - (curblkl & 15)) & 15; /* Calculate the offset of the next block header */ nxthdro = blkpos + sizeof(OMATAPE_BLKHDR) + curblkl + padding; /* Return current block length and previous/next header offsets */ *pcurblkl = curblkl; *pprvhdro = prvhdro; *pnxthdro = nxthdro; return 0; } /* end function readhdr_omaheaders */ /*-------------------------------------------------------------------*/ /* Read a block from an OMA tape file in OMA headers format */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the file is closed, the current file */ /* number in the device block is incremented so that the next file */ /* will be opened by the next CCW, and the return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int read_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ long blkpos; /* Offset to block header */ S32 curblkl; /* Length of current block */ S32 prvhdro; /* Offset of previous header */ S32 nxthdro; /* Offset of next header */ /* Read the 16-byte block header */ blkpos = dev->nxtblkpos; rc = readhdr_omaheaders (dev, omadesc, blkpos, &curblkl, &prvhdro, &nxthdro, unitstat,code); if (rc < 0) return -1; /* Update the offsets of the next and previous blocks */ dev->nxtblkpos = nxthdro; dev->prvblkpos = blkpos; /* Increment file number and return zero if tapemark */ if (curblkl == -1) { close (dev->fd); dev->fd = -1; dev->curfilen++; dev->nxtblkpos = 0; dev->prvblkpos = -1; return 0; } /* Read data block from tape file */ rc = read (dev->fd, buf, curblkl); /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCTA256E %4.4X: Error reading data block " "at offset "I32_FMTX" in file %s: %s\n"), dev->devnum, blkpos, omadesc->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file within data block */ if (rc < curblkl) { logmsg (_("HHCTA257E %4.4X: Unexpected end of file in data block " "at offset "I32_FMTX" in file %s\n"), dev->devnum, blkpos, omadesc->filename); /* Set unit check with data check and partial record */ build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Return block length */ return curblkl; } /* end function read_omaheaders */ /*-------------------------------------------------------------------*/ /* Read a block from an OMA tape file in fixed block format */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the file is closed, the current file */ /* number in the device block is incremented so that the next file */ /* will be opened by the next CCW, and the return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int read_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat,BYTE code) { off_t rcoff; /* Return code from lseek() */ int blklen; /* Block length */ long blkpos; /* Offset of block in file */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Seek to new current block position */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA258E %4.4X: Error seeking to offset "I32_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, omadesc->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Read fixed length block or short final block */ blklen = read (dev->fd, buf, omadesc->blklen); /* Handle read error condition */ if (blklen < 0) { logmsg (_("HHCTA259E %4.4X: Error reading data block " "at offset "I32_FMTX" in file %s: %s\n"), dev->devnum, blkpos, omadesc->filename, strerror(errno)); build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* At end of file return zero to indicate tapemark */ if (blklen == 0) { close (dev->fd); dev->fd = -1; dev->curfilen++; dev->nxtblkpos = 0; dev->prvblkpos = -1; return 0; } /* Calculate the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos + blklen; dev->prvblkpos = blkpos; /* Return block length, or zero to indicate tapemark */ return blklen; } /* end function read_omafixed */ /*-------------------------------------------------------------------*/ /* Read a block from an OMA tape file in ASCII text format */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the file is closed, the current file */ /* number in the device block is incremented so that the next file */ /* will be opened by the next CCW, and the return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /* */ /* The buf parameter points to the I/O buffer during a read */ /* operation, or is NULL for a forward space block operation. */ /*-------------------------------------------------------------------*/ int read_omatext (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ int num; /* Number of characters read */ int pos; /* Position in I/O buffer */ long blkpos; /* Offset of block in file */ BYTE c; /* Character work area */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Seek to new current block position */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ logmsg (_("HHCTA260E %4.4X: Error seeking to offset "I32_FMTX" " "in file %s: %s\n"), dev->devnum, blkpos, omadesc->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Read data from tape file until end of line */ for (num = 0, pos = 0; ; ) { rc = read (dev->fd, &c, 1); if (rc < 1) break; /* Treat X'1A' as end of file */ if (c == '\x1A') { rc = 0; break; } /* Count characters read */ num++; /* Ignore carriage return character */ if (c == '\r') continue; /* Exit if newline character */ if (c == '\n') break; /* Ignore characters in excess of I/O buffer length */ if (pos >= MAX_BLKLEN) continue; /* Translate character to EBCDIC and copy to I/O buffer */ if (buf != NULL) buf[pos] = host_to_guest(c); /* Count characters copied or skipped */ pos++; } /* end for(num) */ /* At end of file return zero to indicate tapemark */ if (rc == 0 && num == 0) { close (dev->fd); dev->fd = -1; dev->curfilen++; dev->nxtblkpos = 0; dev->prvblkpos = -1; return 0; } /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCTA261E %4.4X: Error reading data block " "at offset "I32_FMTX" in file %s: %s\n"), dev->devnum, blkpos, omadesc->filename, strerror(errno)); build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Check for block not terminated by newline */ if (rc < 1) { logmsg (_("HHCTA262E %4.4X: Unexpected end of file in data block " "at offset "I32_FMTX" in file %s\n"), dev->devnum, blkpos, omadesc->filename); /* Set unit check with data check and partial record */ build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Check for invalid zero length block */ if (pos == 0) { logmsg (_("HHCTA263E %4.4X: Invalid zero length block " "at offset "I32_FMTX" in file %s\n"), dev->devnum, blkpos, omadesc->filename); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Calculate the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos + num; dev->prvblkpos = blkpos; /* Return block length */ return pos; } /* end function read_omatext */ /*-------------------------------------------------------------------*/ /* Read a block from an OMA - Selection of format done here */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the file is closed, the current file */ /* number in the device block is incremented so that the next file */ /* will be opened by the next CCW, and the return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /* */ /* The buf parameter points to the I/O buffer during a read */ /* operation, or is NULL for a forward space block operation. */ /*-------------------------------------------------------------------*/ int read_omatape (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code) { int len; OMATAPE_DESC *omadesc; omadesc = (OMATAPE_DESC*)(dev->omadesc); omadesc += (dev->curfilen-1); switch (omadesc->format) { default: case 'H': len = read_omaheaders (dev, omadesc, buf, unitstat,code); break; case 'F': len = read_omafixed (dev, omadesc, buf, unitstat,code); break; case 'T': len = read_omatext (dev, omadesc, buf, unitstat,code); break; case 'X': len=0; dev->curfilen++; break; case 'E': len=0; break; } /* end switch(omadesc->format) */ if (len >= 0) dev->blockid++; return len; } /*-------------------------------------------------------------------*/ /* Forward space to next file of OMA tape device */ /* */ /* For OMA tape devices, the forward space file operation is */ /* achieved by closing the current file, and incrementing the */ /* current file number in the device block, which causes the */ /* next file will be opened when the next CCW is processed. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsf_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code) { UNREFERENCED(unitstat); UNREFERENCED(code); /* Close the current OMA file */ if (dev->fd >= 0) close (dev->fd); dev->fd = -1; dev->nxtblkpos = 0; dev->prvblkpos = -1; /* Increment the current file number */ dev->curfilen++; /* Return normal status */ return 0; } /* end function fsf_omatape */ /*-------------------------------------------------------------------*/ /* Forward space over next block of OMA file in OMA headers format */ /* */ /* If successful, return value is the length of the block skipped. */ /* If the block skipped was a tapemark, the return value is zero, */ /* the file is closed, and the current file number in the device */ /* block is incremented so that the next file belonging to the OMA */ /* tape will be opened when the next CCW is executed. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsb_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *unitstat,BYTE code) { int rc; /* Return code */ long blkpos; /* Offset of block header */ S32 curblkl; /* Length of current block */ S32 prvhdro; /* Offset of previous header */ S32 nxthdro; /* Offset of next header */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Read the 16-byte block header */ rc = readhdr_omaheaders (dev, omadesc, blkpos, &curblkl, &prvhdro, &nxthdro, unitstat,code); if (rc < 0) return -1; /* Check if tapemark was skipped */ if (curblkl == -1) { /* Close the current OMA file */ if (dev->fd >= 0) close (dev->fd); dev->fd = -1; dev->nxtblkpos = 0; dev->prvblkpos = -1; /* Increment the file number */ dev->curfilen++; /* Return zero to indicate tapemark */ return 0; } /* Update the offsets of the next and previous blocks */ dev->nxtblkpos = nxthdro; dev->prvblkpos = blkpos; /* Return block length */ return curblkl; } /* end function fsb_omaheaders */ /*-------------------------------------------------------------------*/ /* Forward space over next block of OMA file in fixed block format */ /* */ /* If successful, return value is the length of the block skipped. */ /* If already at end of file, the return value is zero, */ /* the file is closed, and the current file number in the device */ /* block is incremented so that the next file belonging to the OMA */ /* tape will be opened when the next CCW is executed. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsb_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *unitstat,BYTE code) { off_t eofpos; /* Offset of end of file */ off_t blkpos; /* Offset of current block */ int curblkl; /* Length of current block */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Seek to end of file to determine file size */ eofpos = lseek (dev->fd, 0, SEEK_END); if (eofpos < 0 || eofpos >= LONG_MAX) { /* Handle seek error condition */ if ( eofpos >= LONG_MAX) errno = EOVERFLOW; logmsg (_("HHCTA264E %4.4X: Error seeking to end of file %s: %s\n"), dev->devnum, omadesc->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Check if already at end of file */ if (blkpos >= eofpos) { /* Close the current OMA file */ if (dev->fd >= 0) close (dev->fd); dev->fd = -1; dev->nxtblkpos = 0; dev->prvblkpos = -1; /* Increment the file number */ dev->curfilen++; /* Return zero to indicate tapemark */ return 0; } /* Calculate current block length */ curblkl = (int)(eofpos - blkpos); if (curblkl > omadesc->blklen) curblkl = omadesc->blklen; /* Update the offsets of the next and previous blocks */ dev->nxtblkpos = (long)(blkpos + curblkl); dev->prvblkpos = (long)(blkpos); /* Return block length */ return curblkl; } /* end function fsb_omafixed */ /*-------------------------------------------------------------------*/ /* Forward space to next block of OMA file */ /* */ /* If successful, return value is the length of the block skipped. */ /* If forward spaced over end of file, return value is 0. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsb_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */ /* Point to the current file entry in the OMA descriptor table */ omadesc = (OMATAPE_DESC*)(dev->omadesc); omadesc += (dev->curfilen-1); /* Forward space block depending on OMA file type */ switch (omadesc->format) { default: case 'H': rc = fsb_omaheaders (dev, omadesc, unitstat,code); break; case 'F': rc = fsb_omafixed (dev, omadesc, unitstat,code); break; case 'T': rc = read_omatext (dev, omadesc, NULL, unitstat,code); break; } /* end switch(omadesc->format) */ if (rc >= 0) dev->blockid++; return rc; } /* end function fsb_omatape */ /*-------------------------------------------------------------------*/ /* Backspace to previous file of OMA tape device */ /* */ /* If the current file number is 1, then backspace file simply */ /* closes the file, setting the current position to start of tape. */ /* Otherwise, the current file is closed, the current file number */ /* is decremented, the new file is opened, and the new file is */ /* repositioned to just before the tape mark at the end of the file. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsf_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t pos; /* File position */ OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */ S32 curblkl; /* Length of current block */ S32 prvhdro; /* Offset of previous header */ S32 nxthdro; /* Offset of next header */ /* Close the current OMA file */ if (dev->fd >= 0) close (dev->fd); dev->fd = -1; dev->nxtblkpos = 0; dev->prvblkpos = -1; /* Exit with tape at load point if currently on first file */ if (dev->curfilen <= 1) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Decrement current file number */ dev->curfilen--; /* Point to the current file entry in the OMA descriptor table */ omadesc = (OMATAPE_DESC*)(dev->omadesc); omadesc += (dev->curfilen-1); /* Open the new current file */ rc = open_omatape (dev, unitstat,code); if (rc < 0) return rc; /* Reposition before tapemark header at end of file, or to end of file for fixed block or ASCII text files */ pos = 0; if ( 'H' == omadesc->format ) pos -= sizeof(OMATAPE_BLKHDR); pos = lseek (dev->fd, pos, SEEK_END); if (pos < 0) { /* Handle seek error condition */ logmsg (_("HHCTA265E %4.4X: Error seeking to end of file %s: %s\n"), dev->devnum, omadesc->filename, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } dev->nxtblkpos = pos; dev->prvblkpos = -1; /* Determine the offset of the previous block */ switch (omadesc->format) { case 'H': /* For OMA headers files, read the tapemark header and extract the previous block offset */ rc = readhdr_omaheaders (dev, omadesc, pos, &curblkl, &prvhdro, &nxthdro, unitstat,code); if (rc < 0) return -1; dev->prvblkpos = prvhdro; break; case 'F': /* For OMA fixed block files, calculate the previous block offset allowing for a possible short final block */ pos = (pos + omadesc->blklen - 1) / omadesc->blklen; dev->prvblkpos = (pos > 0 ? (pos - 1) * omadesc->blklen : -1); break; case 'T': /* For OMA ASCII text files, the previous block is unknown */ dev->prvblkpos = -1; break; } /* end switch(omadesc->format) */ /* Return normal status */ return 0; } /* end function bsf_omatape */ /*-------------------------------------------------------------------*/ /* Backspace to previous block of OMA file */ /* */ /* If successful, return value is +1. */ /* If current position is at start of a file, then a backspace file */ /* operation is performed to reset the position to the end of the */ /* previous file, and the return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /* */ /* Note that for ASCII text files, the previous block position is */ /* known only if the previous CCW was a read or a write, so any */ /* attempt to issue more than one consecutive backspace block on */ /* an ASCII text file will fail with unit check status. */ /*-------------------------------------------------------------------*/ int bsb_omatape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ OMATAPE_DESC *omadesc; /* -> OMA descriptor entry */ long blkpos; /* Offset of block header */ S32 curblkl; /* Length of current block */ S32 prvhdro; /* Offset of previous header */ S32 nxthdro; /* Offset of next header */ /* Point to the current file entry in the OMA descriptor table */ omadesc = (OMATAPE_DESC*)(dev->omadesc); omadesc += (dev->curfilen-1); /* Backspace file if current position is at start of file */ if (dev->nxtblkpos == 0) { /* Unit check if already at start of tape */ if (dev->curfilen <= 1) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Perform backspace file operation */ rc = bsf_omatape (dev, unitstat,code); if (rc < 0) return -1; dev->blockid--; /* Return zero to indicate tapemark detected */ return 0; } /* Unit check if previous block position is unknown */ if (dev->prvblkpos < 0) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Backspace to previous block position */ blkpos = dev->prvblkpos; /* Determine new previous block position */ switch (omadesc->format) { case 'H': /* For OMA headers files, read the previous block header to extract the block length and new previous block offset */ rc = readhdr_omaheaders (dev, omadesc, blkpos, &curblkl, &prvhdro, &nxthdro, unitstat,code); if (rc < 0) return -1; break; case 'F': /* For OMA fixed block files, calculate the new previous block offset by subtracting the fixed block length */ if (blkpos >= omadesc->blklen) prvhdro = blkpos - omadesc->blklen; else prvhdro = -1; break; default: case 'T': /* For OMA ASCII text files, new previous block is unknown */ prvhdro = -1; break; } /* end switch(omadesc->format) */ /* Update the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos; dev->prvblkpos = prvhdro; dev->blockid--; /* Return +1 to indicate backspace successful */ return +1; } /* end function bsb_omatape */ /*-------------------------------------------------------------------*/ /* Close an OMA tape file set */ /* */ /* All errors are ignored */ /*-------------------------------------------------------------------*/ void close_omatape2(DEVBLK *dev) { if (dev->fd >= 0) close (dev->fd); dev->fd=-1; if (dev->omadesc != NULL) { free (dev->omadesc); dev->omadesc = NULL; } /* Reset the device dependent fields */ dev->nxtblkpos=0; dev->prvblkpos=-1; dev->curfilen=1; dev->blockid=0; dev->fenced = 0; dev->omafiles = 0; return; } /*-------------------------------------------------------------------*/ /* Close an OMA tape file set */ /* */ /* All errors are ignored */ /* Change the filename to '*' - unloaded */ /* TAPE REALLY UNLOADED */ /*-------------------------------------------------------------------*/ void close_omatape(DEVBLK *dev) { close_omatape2(dev); strcpy(dev->filename,TAPE_UNLOADED); dev->blockid = 0; dev->fenced = 0; return; } /*-------------------------------------------------------------------*/ /* Rewind an OMA tape file set */ /* */ /* All errors are ignored */ /*-------------------------------------------------------------------*/ int rewind_omatape(DEVBLK *dev,BYTE *unitstat,BYTE code) { UNREFERENCED(unitstat); UNREFERENCED(code); close_omatape2(dev); dev->fenced = 0; return 0; } hercules-3.12/scsitape.c0000664000175000017500000023412712564723224012173 00000000000000/* SCSITAPE.C (c) Copyright "Fish" (David B. Trout), 2005-2012 */ /* Hercules SCSI tape handling module */ // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under // the Q Public License (http://www.hercules-390.org/herclic.html) // as modifications to Hercules. /*-------------------------------------------------------------------*/ /* This module contains only the support for SCSI tapes. Please see */ /* the 'tapedev.c' (and possibly other) source module(s) for infor- */ /* mation regarding other supported emulated tape/media formats. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Messages issued by this module are prefixed HHCTA3nn */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "scsitape.h" #if defined(OPTION_SCSI_TAPE) //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING) #ifdef ENABLE_TRACING_STMTS #if !defined(DEBUG) #warning DEBUG required for ENABLE_TRACING_STMTS #endif // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h) #else #undef TRACE #define TRACE 1 ? ((void)0) : logmsg #undef ASSERT #define ASSERT(a) #undef VERIFY #define VERIFY(a) ((void)(a)) #endif // (the following is just a [slightly] shorter name for our own internal use) #define SLOW_UPDATE_STATUS_TIMEOUT MAX_NORMAL_SCSI_DRIVE_QUERY_RESPONSE_TIMEOUT_USECS #define MAX_GSTAT_FREQ_USECS 1000000 // (once per second max) /*-------------------------------------------------------------------*/ /* Open a SCSI tape device */ /* */ /* If successful, the file descriptor is stored in the device block */ /* and the return value is zero. Otherwise the return value is -1. */ /* */ /* Note that not having a tape mounted is a non-fatal error (rc==0)) */ /* */ /* If the status indicates the tape is not mounted or a good status */ /* cannot otherwise be obtained, the file descriptor is CLOSED but */ /* THE RETURN CODE IS STILL == 0 !!!! */ /* */ /* ** WARNING! ** */ /* */ /* The caller MUST check for a valid (non-negative) file descriptor */ /* before trying to use it if this function returns 0 == success!! */ /* */ /* A success == 0 return means the device filename CAN be opened, */ /* but not necessarily that the file can be used! If the file cannot */ /* be used (i.e. no tape mounted), the file is CLOSED but the return */ /* code is still == 0. */ /* */ /* The return code is -1 ONLY when the filename itself is invalid */ /* and the device file thus cannot even be opened. */ /* */ /*-------------------------------------------------------------------*/ int open_scsitape (DEVBLK *dev, BYTE *unitstat, BYTE code) { int rc; /* Is an open for this device already in progress? */ if (dev->stape_mntdrq.link.Flink) { /* Yes. Device is good but no tape is mounted (yet) */ build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); return 0; // (quick exit; in progress == open success) } ASSERT( dev->fd < 0 ); // (sanity check) dev->fd = -1; dev->sstat = GMT_DR_OPEN( -1 ); /* Open the SCSI tape device */ dev->readonly = 0; rc = open_tape (dev->filename, O_RDWR | O_BINARY | O_NONBLOCK); if (rc < 0 && EROFS == errno ) { dev->readonly = 1; rc = open_tape (dev->filename, O_RDONLY | O_BINARY | O_NONBLOCK); } /* Check for successful open */ if (rc < 0) { logmsg (_("HHCTA324E Error opening %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code); return -1; // (FATAL error; device cannot be opened) } define_BOT_pos( dev ); // (always after successful open) /* Store the file descriptor in the device block */ dev->fd = rc; /* Obtain the initial tape device/media status information */ /* and start the mount-monitoring thread if option enabled */ int_scsi_status_update( dev, 0 ); /* Asynchronous open now in progress? */ if (dev->stape_mntdrq.link.Flink) { /* Yes. Device is good but no tape is mounted (yet) */ build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); return 0; // (quick exit; in progress == open success) } /* Finish up the open process... */ if ( STS_NOT_MOUNTED( dev ) ) { /* Intervention required if no tape is currently mounted. Note: we return "success" because the filename is good (device CAN be opened) but close the file descriptor since there's no tape currently mounted on the drive.*/ #if !defined( _MSVC_ ) int fd = dev->fd; dev->fd = -1; close_tape( fd ); #endif // !_MSVC_ build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); return 0; // (because device file IS valid and CAN be opened) } /* Set variable length block processing to complete the open */ if ( finish_scsitape_open( dev, unitstat, code ) != 0 ) { /* We cannot use this device; fail the open. 'finish_scsitape_open' has already issued the error message and closed the device. */ return -1; // (open failure) } return 0; // (open success) } /* end function open_scsitape */ /*-------------------------------------------------------------------*/ /* Finish SCSI Tape open: sets variable length block i/o mode... */ /* Returns 0 == success, -1 = failure. */ /*-------------------------------------------------------------------*/ /* THIS FUNCTION IS AN INTEGRAL PART OF TAPE OPEN PROCESSING! */ /* If this function fails then the overall tape device open fails! */ /*-------------------------------------------------------------------*/ int finish_scsitape_open( DEVBLK *dev, BYTE *unitstat, BYTE code ) { int rc; /* Return code */ int oflags; /* re-open flags */ struct mtop opblk; /* Area for MTIOCTOP ioctl */ /* Switch drive over to BLOCKING-mode i/o... */ close_tape( dev->fd ); oflags = O_BINARY | (dev->readonly ? O_RDONLY : O_RDWR); VERIFY( (dev->fd = open_tape (dev->filename, oflags)) > 0); /* Since a tape was just mounted, reset the blockid back to zero */ dev->blockid = 0; dev->fenced = 0; /* Set the tape device to process variable length blocks */ if (!STS_WR_PROT( dev )) { opblk.mt_op = MTSETBLK; opblk.mt_count = 0; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); if (rc < 0) { /* Device cannot be used; fail the open */ int save_errno = errno; rc = dev->fd; dev->fd = -1; close_tape( rc ); errno = save_errno; logmsg (_("HHCTA330E Error setting attributes for %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code); return -1; /* (fatal error) */ } } #if defined( HAVE_DECL_MTEWARN ) && HAVE_DECL_MTEWARN // Try to request EOM/EOT (end-of-media/tape) early-warning // Note: if it fails, oh well. There's no need to scare the // user with a warning message. We'll either get the warning // or we won't. Either way there's nothing we can do about it. // We did the best we could. if (!STS_WR_PROT( dev )) { opblk.mt_op = MTEWARN; opblk.mt_count = dev->eotmargin; ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); // (ignore any error; it either worked or it didn't) } #endif // defined( HAVE_DECL_MTEWARN ) && HAVE_DECL_MTEWARN return 0; /* (success) */ } /* end function finish_scsitape_open */ /*-------------------------------------------------------------------*/ /* Close SCSI tape device file */ /*-------------------------------------------------------------------*/ void close_scsitape(DEVBLK *dev) { int rc = 0; obtain_lock( &sysblk.stape_lock ); // Remove drive from SCSIMOUNT thread's work queue... if (dev->stape_mntdrq.link.Flink) { RemoveListEntry( &dev->stape_mntdrq.link ); InitializeListLink( &dev->stape_mntdrq.link ); } // Remove drive from the STATUS thread's work queue... if (dev->stape_statrq.link.Flink) { RemoveListEntry( &dev->stape_statrq.link ); InitializeListLink( &dev->stape_statrq.link ); } // Close the file if it's open... if (dev->fd >= 0) { if (dev->stape_close_rewinds) { struct mtop opblk; // opblk.mt_op = MTLOAD; // (not sure which is more correct) opblk.mt_op = MTREW; opblk.mt_count = 1; if ((rc = ioctl_tape ( dev->fd, MTIOCTOP, (char*)&opblk)) != 0) { logmsg (_("HHCTA373W Error rewinding %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); } } // Close tape drive... close_tape( dev->fd ); dev->fd = -1; dev->blockid = -1; dev->curfilen = 0; dev->nxtblkpos = 0; dev->prvblkpos = -1; } dev->sstat = GMT_DR_OPEN(-1); // (forced) dev->fenced = (rc >= 0) ? 0 : 1; release_lock( &sysblk.stape_lock ); } /* end function close_scsitape */ /*-------------------------------------------------------------------*/ /* Read a block from a SCSI tape device */ /* */ /* If successful, return value is block length read. */ /* If a tapemark was read, the return value is zero, and the */ /* current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int read_scsitape (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* int save_errno; */ rc = read_tape (dev->fd, buf, MAX_BLKLEN); if (rc >= 0) { dev->blockid++; /* Increment current file number if tapemark was read */ if (rc == 0) dev->curfilen++; /* Return block length or zero if tapemark */ return rc; } /* Handle read error condition */ logmsg (_("HHCTA332E Error reading data block from %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); if ( STS_NOT_MOUNTED( dev ) ) build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); else build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* end function read_scsitape */ /*-------------------------------------------------------------------*/ /* Write a block to a SCSI tape device */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_scsitape (DEVBLK *dev, BYTE *buf, U16 len, BYTE *unitstat, BYTE code) { int rc; int save_errno; /* Write data block to SCSI tape device */ rc = write_tape (dev->fd, buf, len); #if defined( _MSVC_ ) if (errno == ENOSPC) dev->eotwarning = 1; #endif if (rc >= len) { dev->blockid++; return 0; } /* LINUX EOM BEHAVIOUR WHEN WRITING When the end of medium early warning is encountered, the current write is finished and the number of bytes is returned. The next write returns -1 and errno is set to ENOSPC. To enable writing a trailer, the next write is allowed to proceed and, if successful, the number of bytes is returned. After this, -1 and the number of bytes are alternately returned until the physical end of medium (or some other error) occurs. */ if (errno == ENOSPC) { int_scsi_status_update( dev, 0 ); rc = write_tape (dev->fd, buf, len); if (rc >= len) { dev->eotwarning = 1; dev->blockid++; return 0; } } /* Handle write error condition... */ save_errno = errno; { logmsg (_("HHCTA333E Error writing data block to %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); int_scsi_status_update( dev, 0 ); } errno = save_errno; if ( STS_NOT_MOUNTED( dev ) ) build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); else { if (errno == EIO) { if(STS_EOT(dev)) build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); else build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); } else build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code); } return -1; } /* end function write_scsitape */ /*-------------------------------------------------------------------*/ /* Write a tapemark to a SCSI tape device */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int write_scsimark (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc, save_errno; /* Write tape mark to SCSI tape */ rc = int_write_scsimark( dev ); #if defined( _MSVC_ ) if (errno == ENOSPC) dev->eotwarning = 1; #endif if (rc >= 0) return 0; /* LINUX EOM BEHAVIOUR WHEN WRITING When the end of medium early warning is encountered, the current write is finished and the number of bytes is returned. The next write returns -1 and errno is set to ENOSPC. To enable writing a trailer, the next write is allowed to proceed and, if successful, the number of bytes is returned. After this, -1 and the number of bytes are alternately returned until the physical end of medium (or some other error) occurs. */ if (errno == ENOSPC) { int_scsi_status_update( dev, 0 ); if (int_write_scsimark( dev ) >= 0) { dev->eotwarning = 1; return 0; } } /* Handle write error condition... */ save_errno = errno; { logmsg (_("HHCTA334E Error writing tapemark to %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); int_scsi_status_update( dev, 0 ); } errno = save_errno; if ( STS_NOT_MOUNTED( dev ) ) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); } else { switch(errno) { case EIO: if(STS_EOT(dev)) build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); else build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); break; case ENOSPC: build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); break; default: build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code); break; } } return -1; } /* end function write_scsimark */ /*-------------------------------------------------------------------*/ /* (internal 'write_scsimark' helper function) */ /*-------------------------------------------------------------------*/ int int_write_scsimark (DEVBLK *dev) // (internal function) { int rc; struct mtop opblk; opblk.mt_op = MTWEOF; opblk.mt_count = 1; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); if (rc >= 0) { /* Increment current file number since tapemark was written */ /*dev->curfilen++;*/ /* (CCW processor handles this automatically so there's no need for us to do it here) */ /* (tapemarks count as block identifiers too!) */ dev->blockid++; } return rc; } /*-------------------------------------------------------------------*/ /* Synchronize a SCSI tape device (i.e. commit its data to tape) */ /* */ /* If successful, return value is zero. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int sync_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; int save_errno; struct mtop opblk; /* GA32-0566-02 ("IBM Tape Device Drivers - Programming Reference"): STIOCQRYPOS "[...] A write filemark of count 0 is always issued to the drive, which flushes all data from the buffers to the tape media. After the write filemark completes, the query is issued." Write Tapemark "[...] The WriteTapemark entry point may also be called with the dwTapemarkCount parameter set to 0 and the bImmediate parameter set to FALSE. This has the effect of committing any uncommitted data written by previous WriteFile calls ... to the media." */ opblk.mt_op = MTWEOF; opblk.mt_count = 0; // (zero to force a commit) if ((rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk)) >= 0) { #if defined( _MSVC_ ) if (errno == ENOSPC) dev->eotwarning = 1; #endif return 0; // (success) } /* LINUX EOM BEHAVIOUR WHEN WRITING When the end of medium early warning is encountered, the current write is finished and the number of bytes is returned. The next write returns -1 and errno is set to ENOSPC. To enable writing a trailer, the next write is allowed to proceed and, if successful, the number of bytes is returned. After this, -1 and the number of bytes are alternately returned until the physical end of medium (or some other error) occurs. */ if (errno == ENOSPC) { int_scsi_status_update( dev, 0 ); opblk.mt_op = MTWEOF; opblk.mt_count = 0; // (zero to force a commit) if ((rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk)) >= 0) { dev->eotwarning = 1; return 0; } } /* Handle write error condition... */ save_errno = errno; { logmsg (_("HHCTA389E Synchronize error on " "%u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); int_scsi_status_update( dev, 0 ); } errno = save_errno; if ( STS_NOT_MOUNTED( dev ) ) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); } else { switch(errno) { case EIO: if(STS_EOT(dev)) build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); else build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); break; case ENOSPC: build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); break; default: build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code); break; } } return -1; } /* end function sync_scsitape */ /*-------------------------------------------------------------------*/ /* Forward space over next block of SCSI tape device */ /* */ /* If successful, return value is +1. */ /* If the block skipped was a tapemark, the return value is zero, */ /* and the current file number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsb_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; int save_errno; struct mtop opblk; /* Forward space block on SCSI tape */ opblk.mt_op = MTFSR; opblk.mt_count = 1; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); if ( rc >= 0 ) { dev->blockid++; /* Return +1 to indicate forward space successful */ return +1; } /* Check for spacing over a tapemark... */ save_errno = errno; { int_scsi_status_update( dev, 0 ); } errno = save_errno; // PROGRAMMING NOTE: please see the "Programming Note" in the // 'bsb_scsitape' function regarding usage of the 'EOF' status // to detect spacing over tapemarks. if ( EIO == errno && STS_EOF(dev) ) // (fwd-spaced over tapemark?) { dev->curfilen++; dev->blockid++; /* Return 0 to indicate tapemark was spaced over */ return 0; } /* Bona fide forward space block error ... */ save_errno = errno; { logmsg (_("HHCTA335E Forward space block error on %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); } errno = save_errno; if ( STS_NOT_MOUNTED( dev ) ) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); } else { switch(errno) { case EIO: if(STS_EOT(dev)) build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); else build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); break; case ENOSPC: build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); break; default: build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code); break; } } return -1; } /* end function fsb_scsitape */ /*-------------------------------------------------------------------*/ /* Backspace to previous block of SCSI tape device */ /* */ /* If successful, return value is +1. */ /* If the block is a tapemark, the return value is zero, */ /* and the current file number in the device block is decremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsb_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; int save_errno; struct mtop opblk; struct mtget starting_mtget; /* PROGRAMMING NOTE: There is currently no way to distinguish ** between a "normal" backspace-block error and a "backspaced- ** into-loadpoint" i/o error, since the only error indication ** we get [in response to a backspace block attempt] is simply ** 'EIO'. (Interrogating the status AFTER the fact (to see if ** we're positioned at loadpoint) doesn't tell us whether we ** were already positioned at loadpoint *before* the error was ** was encountered or whether we're only positioned at load- ** point because we *did* in fact backspace over the very first ** block on the tape (and are thus now, after the fact, sitting ** at loadpoint because we *did* backspace over a block but it ** just got an error for some reason). ** ** Thus, we have absolutely no choice here but to retrieve the ** status BEFORE we attempt the i/o to see if we're ALREADY at ** loadpoint. If we are, then we immediately return an error ** ("backspaced-into-loadpoint") *without* even attemting the ** i/o at all. If we're *not* already sitting at loadpoint how- ** ever, then we go ahead an attempt the i/o and then check for ** an error afterwards. */ /* Obtain tape status before backward space... */ int_scsi_status_update( dev, 0 ); /* (save the current status before the i/o in case of error) */ memcpy( &starting_mtget, &dev->mtget, sizeof( struct mtget ) ); /* Unit check if already at start of tape */ if ( STS_BOT( dev ) ) { dev->eotwarning = 0; build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Attempt the backspace i/o...*/ opblk.mt_op = MTBSR; opblk.mt_count = 1; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); if ( rc >= 0 ) { dev->blockid--; /* Return +1 to indicate backspace successful */ return +1; } /* Retrieve new status after the [supposed] i/o error... */ save_errno = errno; { int_scsi_status_update( dev, 0 ); } errno = save_errno; /* Check for backspacing over tapemark... */ /* PROGRAMMING NOTE: on Windows, our scsi tape driver (w32stape.c) ** sets 'EOF' status whenever a tapemark is spaced over in EITHER ** direction (forward OR backward), whereas *nix operating systems ** do not. They set 'EOF' status only when FORWARD spacing over a ** tapemark but not when BACKSPACING over one. ** ** (Apparently the EOF status was actually meant to mean that the ** tape is "PHYSICALLY POSITIONED PAST [physical] eof" (i.e. past ** an "eof marker" (i.e. a tapemark)) and nothing more. That is to ** say, it is apparently NOT meant to mean a tapemark was passed ** over, but rather only that you're "POSITIONED PAST" a tapemark.) ** ** Therefore since 'EOF' status will thus *NEVER* be set whenever ** a tapemark is spaced over in the *BACKWARD* direction [on non- ** Windows operating systems], we need some other means of distin- ** guishing between true backspace-block i/o errors and ordinary ** spacing over a tapemark (which is NOT an i/o error but which ** *is* an "out of the ordinary" (unit exception) type of event). ** ** Extensive research on this issue has revealed the *ONLY* semi- ** reliable means of distinguishing between them is by checking ** the "file#" and "block#" fields of the status structure after ** the supposed i/o error. If the file# is one less than it was ** before and the block# is -1, then a tapemark was simply spaced ** over. If the file# and block# is anything else however, then ** the originally reported error was a bona-fide i/o error (i.e. ** the original backspace-block (MTBSR) actually *failed*). ** ** I say "semi-reliable" because comments seem to indicate that ** the "file#" and "block#" fields of the mtget status structure ** "are not always used". The best that I can tell however, is ** most *nix operating systems *do* seem to maintain them. Thus, ** for now, we're going to rely on their accuracy since without ** them there's really no way whatsoever to distingish between ** a normal backspacing over a tapemark unit exception condition ** and a bona-fide i/o error (other than doing our own SCSI i/o ** of course (which we don't support (yet))). -- Fish, May 2008 */ if ( EIO == errno ) { #if defined( _MSVC_ ) /* Windows always sets 'EOF' status whenever a tapemark is spaced over in EITHER direction (forward OR backward) */ if ( STS_EOF(dev) ) /* (passed over tapemark?) */ #else // !defined( _MSVC_ ) /* Unix-type systems unfortunately do NOT set 'EOF' whenever backspacing over a tapemark (see PROGRAMMING NOTE above), so we need to check the status struct's file# and block# fields instead... */ /* (passed over tapemark?) */ if (1 && dev->mtget.mt_fileno == (starting_mtget.mt_fileno - 1) && dev->mtget.mt_blkno == -1 ) #endif // defined( _MSVC_ ) { dev->curfilen--; dev->blockid--; /* Return 0 to indicate tapemark was spaced over */ return 0; } } /* Bona fide backspace block i/o error ... */ save_errno = errno; { logmsg (_("HHCTA336E Backspace block error on %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); } errno = save_errno; if ( STS_NOT_MOUNTED( dev ) ) build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); else { if ( EIO == errno && STS_BOT(dev) ) { dev->eotwarning = 0; build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); } else build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); } return -1; } /* end function bsb_scsitape */ /*-------------------------------------------------------------------*/ /* Forward space to next file of SCSI tape device */ /* */ /* If successful, the return value is zero, and the current file */ /* number in the device block is incremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int fsf_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; int save_errno; struct mtop opblk; /* Forward space file on SCSI tape */ opblk.mt_op = MTFSF; opblk.mt_count = 1; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); /* Since we have no idea how many blocks we've skipped over (as a result of doing the forward-space file), we now have no clue as to what the proper current blockid should be. */ dev->blockid = -1; // (actual position now unknown!) if ( rc >= 0 ) { dev->curfilen++; return 0; } /* Handle error condition */ dev->fenced = 1; // (actual position now unknown!) save_errno = errno; { logmsg (_("HHCTA337E Forward space file error on %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); } errno = save_errno; if ( STS_NOT_MOUNTED( dev ) ) { build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); } else { switch(errno) { case EIO: if(STS_EOT(dev)) build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); else build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); break; case ENOSPC: build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); break; default: build_senseX(TAPE_BSENSE_ITFERROR,dev,unitstat,code); break; } } return -1; } /* end function fsf_scsitape */ /*-------------------------------------------------------------------*/ /* Backspace to previous file of SCSI tape device */ /* */ /* If successful, the return value is zero, and the current file */ /* number in the device block is decremented. */ /* If error, return value is -1 and unitstat is set to CE+DE+UC */ /*-------------------------------------------------------------------*/ int bsf_scsitape (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; int save_errno; struct mtop opblk; /* PROGRAMMING NOTE: There is currently no way to distinguish ** between a "normal" backspace-file error and a "backspaced- ** into-loadpoint" i/o error, since the only error indication ** we get [in response to a backspace file attempt] is simply ** 'EIO'. (Interrogating the status AFTER the fact (to see if ** we're positioned at loadpoint) doesn't tell us whether we ** were already positioned at loadpoint *before* the error was ** was encountered or whether we're only positioned ar load- ** point because we *did* in fact backspace over a BOT tape- ** mark on the tape (and are thus now, after the fact, sitting ** at loadpoint because we *did* backspace over a tape-mark ** but it just got an error for some reason). ** ** Thus, we have absolutely no choice here but to retrieve the ** status BEFORE we attempt the i/o to see if we're ALREADY at ** loadpoint. If we are, then we immediately return an error ** ("backspaced-into-loadpoint") *without* even attemting the ** i/o at all. If we're *not* already sitting at loadpoint how- ** ever, then we go ahead an attempt the i/o and then check for ** an error afterwards. */ /* Obtain tape status before backward space... (no choice!) */ int_scsi_status_update( dev, 0 ); /* Unit check if already at start of tape */ if ( STS_BOT( dev ) ) { dev->eotwarning = 0; build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } /* Attempt the backspace i/o...*/ opblk.mt_op = MTBSF; opblk.mt_count = 1; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); /* Since we have no idea how many blocks we've skipped over (as a result of doing the back-space file), we now have no clue as to what the proper current blockid should be. */ dev->blockid = -1; // (actual position now unknown!) if ( rc >= 0 ) { dev->curfilen--; return 0; } /* Handle error condition */ dev->fenced = 1; // (actual position now unknown!) save_errno = errno; { logmsg (_("HHCTA338E Backspace file error on %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); } errno = save_errno; if ( STS_NOT_MOUNTED( dev ) ) build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); else { if ( EIO == errno && STS_BOT(dev) ) { dev->eotwarning = 0; build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); } else build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); } return -1; } /* end function bsf_scsitape */ /*-------------------------------------------------------------------*/ /* Rewind an SCSI tape device */ /*-------------------------------------------------------------------*/ int rewind_scsitape(DEVBLK *dev,BYTE *unitstat,BYTE code) { int rc; /* int save_errno; */ struct mtop opblk; // opblk.mt_op = MTLOAD; // (not sure which is more correct) opblk.mt_op = MTREW; opblk.mt_count = 1; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); if ( rc >= 0 ) { dev->sstat |= GMT_BOT( -1 ); // (forced) dev->blockid = 0; dev->curfilen = 0; dev->fenced = 0; return 0; } dev->fenced = 1; // (because the rewind failed) dev->blockid = -1; // (because the rewind failed) dev->curfilen = -1; // (because the rewind failed) logmsg (_("HHCTA373E Error rewinding %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); if ( STS_NOT_MOUNTED( dev ) ) build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); else build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code); return -1; } /* end function rewind_scsitape */ /*-------------------------------------------------------------------*/ /* Rewind Unload a SCSI tape device (and CLOSE it too!) */ /*-------------------------------------------------------------------*/ void int_scsi_rewind_unload(DEVBLK *dev, BYTE *unitstat, BYTE code ) { int rc; struct mtop opblk; // opblk.mt_op = MTUNLOAD; // (not sure which is more correct) opblk.mt_op = MTOFFL; opblk.mt_count = 1; rc = ioctl_tape (dev->fd, MTIOCTOP, (char*)&opblk); if ( rc >= 0 ) { dev->fenced = 0; if ( dev->ccwtrace || dev->ccwstep ) logmsg (_("HHCTA377I Tape %u:%4.4X unloaded\n"), SSID_TO_LCSS(dev->ssid), dev->devnum); // PR# tape/88: no sense with 'close_scsitape' // attempting a rewind if the tape is unloaded! dev->stape_close_rewinds = 0; // (skip rewind attempt) close_scsitape( dev ); // (required for REW UNLD) return; } dev->fenced = 1; // (because the rewind-unload failed) dev->curfilen = -1; // (because the rewind-unload failed) dev->blockid = -1; // (because the rewind-unload failed) logmsg ( _("HHCTA376E Error unloading %u:%4.4X=%s; errno=%d: %s\n" ), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror( errno ) ); if ( STS_NOT_MOUNTED( dev ) ) build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code); else build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code); } /* end function int_scsi_rewind_unload */ /*-------------------------------------------------------------------*/ /* Erase Gap */ /*-------------------------------------------------------------------*/ int erg_scsitape( DEVBLK *dev, BYTE *unitstat, BYTE code ) { #if defined( OPTION_SCSI_ERASE_GAP ) int rc; if (!dev->stape_no_erg) { struct mtop opblk; opblk.mt_op = MTERASE; opblk.mt_count = 0; // (zero means "short" erase-gap) rc = ioctl_tape( dev->fd, MTIOCTOP, (char*)&opblk ); #if defined( _MSVC_ ) if (errno == ENOSPC) dev->eotwarning = 1; #endif if ( rc < 0 ) { /* LINUX EOM BEHAVIOUR WHEN WRITING When the end of medium early warning is encountered, the current write is finished and the number of bytes is returned. The next write returns -1 and errno is set to ENOSPC. To enable writing a trailer, the next write is allowed to proceed and, if successful, the number of bytes is returned. After this, -1 and the number of bytes are alternately returned until the physical end of medium (or some other error) occurs. */ if (errno == ENOSPC) { int_scsi_status_update( dev, 0 ); opblk.mt_op = MTERASE; opblk.mt_count = 0; // (zero means "short" erase-gap) if ( (rc = ioctl_tape( dev->fd, MTIOCTOP, (char*)&opblk )) >= 0 ) dev->eotwarning = 1; } if ( rc < 0) { logmsg (_("HHCTA380E Erase Gap error on %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } } } return 0; // (success) #else // !defined( OPTION_SCSI_ERASE_GAP ) UNREFERENCED ( dev ); UNREFERENCED ( code ); UNREFERENCED ( unitstat ); return 0; // (treat as nop) #endif // defined( OPTION_SCSI_ERASE_GAP ) } /* end function erg_scsitape */ /*-------------------------------------------------------------------*/ /* Data Security Erase */ /*-------------------------------------------------------------------*/ int dse_scsitape( DEVBLK *dev, BYTE *unitstat, BYTE code ) { #if defined( OPTION_SCSI_ERASE_TAPE ) struct mtop opblk; opblk.mt_op = MTERASE; opblk.mt_count = 1; // (one means "long" erase-tape) if ( ioctl_tape( dev->fd, MTIOCTOP, (char*)&opblk ) < 0 ) { logmsg (_("HHCTA381E Data Security Erase error on %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } return 0; // (success) #else // !defined( OPTION_SCSI_ERASE_TAPE ) UNREFERENCED ( dev ); UNREFERENCED ( code ); UNREFERENCED ( unitstat ); return 0; // (treat as nop) #endif // defined( OPTION_SCSI_ERASE_TAPE ) } /* end function dse_scsitape */ /*-------------------------------------------------------------------*/ /* readblkid_scsitape */ /*-------------------------------------------------------------------*/ /* Output values are returned in BIG-ENDIAN guest format... */ /*-------------------------------------------------------------------*/ int readblkid_scsitape ( DEVBLK* dev, BYTE* logical, BYTE* physical ) { // ZZ FIXME: The two blockid fields that READ BLOCK ID // are returning are the "Channel block ID" and "Device // block ID" fields, which correspond directly to the // SCSI "First block location" and "Last block location" // fields (as returned by a READ POSITION scsi command), // so we really SHOULD be doing our own direct scsi i/o // for ourselves so we can retrieve BOTH of those values // directly from the real/actual physical device itself, // but until we can add code to Herc to do that, we must // return the same value for each since ioctl(MTIOCPOS) // only returns us one value (the logical position) and // not both that we really prefer... // (And for the record, we want the "Channel block ID" // value, also known as the SCSI "First block location" // value, also known as the >>LOGICAL<< value and *NOT* // the absolute/physical device-relative value) struct mtpos mtpos; BYTE blockid[4]; if (ioctl_tape( dev->fd, MTIOCPOS, (char*) &mtpos ) < 0 ) { /* Informative ERROR message if tracing */ int save_errno = errno; { if ( dev->ccwtrace || dev->ccwstep ) logmsg(_("HHCTA382W ioctl_tape(MTIOCPOS=MTTELL) failed on %4.4X = %s: %s\n") ,dev->devnum ,dev->filename ,strerror(errno) ); } errno = save_errno; return -1; // (errno should already be set) } // Convert MTIOCPOS value to guest BIG-ENDIAN format... mtpos.mt_blkno = CSWAP32( mtpos.mt_blkno ); // (guest <- host) // Handle emulated vs. physical tape-device block-id format issue... blockid_actual_to_emulated( dev, (BYTE*)&mtpos.mt_blkno, blockid ); // Until we can add code to Herc to do direct SCSI i/o (so that // we can retrieve BOTH values directly from the device itself), // we have no choice but to return the same value for each since // the ioctl(MTIOCPOS) call only returns the logical value and // not also the physical value that we wish it would... if (logical) memcpy( logical, &blockid[0], 4 ); if (physical) memcpy( physical, &blockid[0], 4 ); return 0; // (success) } /* end function readblkid_scsitape */ /*-------------------------------------------------------------------*/ /* locateblk_scsitape */ /*-------------------------------------------------------------------*/ /* Input value is passed in little-endian host format... */ /*-------------------------------------------------------------------*/ int locateblk_scsitape ( DEVBLK* dev, U32 blockid, BYTE *unitstat, BYTE code ) { int rc; struct mtop mtop; UNREFERENCED( unitstat ); // (not used) UNREFERENCED( code ); // (not used) // Convert the passed host-format blockid value into the proper // 32-bit vs. 22-bit guest-format the physical device expects ... blockid = CSWAP32( blockid ); // (guest <- host) blockid_emulated_to_actual( dev, (BYTE*)&blockid, (BYTE*)&mtop.mt_count ); mtop.mt_count = CSWAP32( mtop.mt_count ); // (host <- guest) mtop.mt_op = MTSEEK; // Ask the actual hardware to do an actual physical locate... if ((rc = ioctl_tape( dev->fd, MTIOCTOP, (char*)&mtop )) < 0) { int save_errno = errno; { if ( dev->ccwtrace || dev->ccwstep ) logmsg(_("HHCTA383W ioctl_tape(MTIOCTOP=MTSEEK) failed on %4.4X = %s: %s\n") ,dev->devnum ,dev->filename ,strerror(errno) ); } errno = save_errno; } return rc; } /*********************************************************************/ /** **/ /** BLOCK-ID ADJUSTMENT FUNCTIONS **/ /** **/ /*********************************************************************/ /* The following conversion functions compensate for the fact that the emulated device type might actually be completely different from the actual real [SCSI] device being used for the emulation. That is to say, the actual SCSI device being used may actually be a 3590 type device but is defined in Hercules as a 3480 (or vice-versa). Thus while the device actually behaves as a 3590, we need to emulate 3480 functionality instead (and vice-versa). For 3480/3490 devices, the block ID has the following format: __________ ________________________________________________ | Bit | Description | |__________|________________________________________________| | 0 | Direction Bit | | | | | | 0 Wrap 1 | | | 1 Wrap 2 | |__________|________________________________________________| | 1-7 | Segment Number | |__________|________________________________________________| | 8-9 | Format Mode | | | | | | 00 3480 format | | | 01 3480-2 XF format | | | 10 3480 XF format | | | 11 Reserved | | | | | | Note: The 3480 format does not support IDRC. | |__________|________________________________________________| | 10-31 | Logical Block Number | |__________|________________________________________________| For 3480's and 3490's, first block recorded on the tape has a block ID value of X'01000000', whereas for 3590 devices the block ID is a full 32 bits and the first block on the tape is block ID x'00000000'. For the 32-bit to 22-bit (and vice versa) conversion, we're relying on (hoping really!) that an actual 32-bit block-id value will never actually exceed 30 bits (1-bit wrap + 7-bit segment# + 22-bit block-id) since we perform the conversion by simply splitting the low-order 30 bits of a 32-bit block-id into a sep- arate 8-bit (wrap and segment#) and 22-bit (block-id) fields, and then shifting them into their appropriate position (and of course combining/appending them for the opposite conversion). As such, this of course implies that we are thus treating the wrap bit and 7-bit segment number values of a 3480/3490 "22-bit format" blockid as simply the high-order 8 bits of an actual 30-bit physical blockid (which may or may not work properly on actual SCSI hardware depending on how[*] it handles inaccurate blockid values). ----------------- [*] Most(?) [SCSI] devices treat the blockid value used in a Locate CCW as simply an "approximate location" of where the block in question actually resides on the physical tape, and will, after positioning itself to the *approximate* physical location of where the block is *believed* to reside, proceed to then perform the final positioning at low-speed based on its reading of its actual internally-recorded blockid values. Thus, even when the supplied Locate block-id value is wrong, the Locate should still succeed, albeit less efficiently since it may be starting at a physical position quite distant from where the actual block is actually physically located on the actual media. */ /*-------------------------------------------------------------------*/ /* blockid_emulated_to_actual */ /*-------------------------------------------------------------------*/ /* Locate CCW helper: convert guest-supplied 3480 or 3590 blockid */ /* to the actual SCSI hardware blockid format */ /* Both I/P AND O/P are presumed to be in BIG-ENDIAN guest format */ /*-------------------------------------------------------------------*/ void blockid_emulated_to_actual ( DEVBLK *dev, // ptr to Hercules device BYTE *emu_blkid, // ptr to i/p 4-byte block-id in guest storage BYTE *act_blkid // ptr to o/p 4-byte block-id for actual SCSI i/o ) { if ( TAPEDEVT_SCSITAPE != dev->tapedevt ) { memcpy( act_blkid, emu_blkid, 4 ); return; } #if defined(OPTION_SCSI_TAPE) if (0x3590 == dev->devtype) { // 3590 being emulated; guest block-id is full 32-bits... if (dev->stape_blkid_32) { // SCSI using full 32-bit block-ids too. Just copy as-is... memcpy( act_blkid, emu_blkid, 4 ); } else { // SCSI using 22-bit block-ids. Use low-order 30 bits // of 32-bit guest-supplied blockid and convert it // into a "22-bit format" blockid value for SCSI... blockid_32_to_22 ( emu_blkid, act_blkid ); } } else // non-3590 being emulated; guest block-id is 22-bits... { if (dev->stape_blkid_32) { // SCSI using full 32-bit block-ids. Extract the wrap, // segment# and 22-bit blockid bits from the "22-bit // format" guest-supplied blockid value and combine // (append) them into a contiguous low-order 30 bits // of a 32-bit blockid value for SCSI to use... blockid_22_to_32 ( emu_blkid, act_blkid ); } else { // SCSI using 22-bit block-ids too. Just copy as-is... memcpy( act_blkid, emu_blkid, 4 ); } } #endif /* defined(OPTION_SCSI_TAPE) */ } /* end function blockid_emulated_to_actual */ /*-------------------------------------------------------------------*/ /* blockid_actual_to_emulated */ /*-------------------------------------------------------------------*/ /* Read Block Id CCW helper: convert an actual SCSI block-id */ /* to guest emulated 3480/3590 format */ /* Both i/p and o/p are presumed to be in big-endian guest format */ /*-------------------------------------------------------------------*/ void blockid_actual_to_emulated ( DEVBLK *dev, // ptr to Hercules device (for 'devtype') BYTE *act_blkid, // ptr to i/p 4-byte block-id from actual SCSI i/o BYTE *emu_blkid // ptr to o/p 4-byte block-id in guest storage ) { if ( TAPEDEVT_SCSITAPE != dev->tapedevt ) { memcpy( emu_blkid, act_blkid, 4 ); return; } #if defined(OPTION_SCSI_TAPE) if (dev->stape_blkid_32) { // SCSI using full 32-bit block-ids... if (0x3590 == dev->devtype) { // Emulated device is a 3590 too. Just copy as-is... memcpy( emu_blkid, act_blkid, 4 ); } else { // Emulated device using 22-bit format. Convert... blockid_32_to_22 ( act_blkid, emu_blkid ); } } else { // SCSI using 22-bit format block-ids... if (0x3590 == dev->devtype) { // Emulated device using full 32-bit format. Convert... blockid_22_to_32 ( act_blkid, emu_blkid ); } else { // Emulated device using 22-bit format too. Just copy as-is... memcpy( emu_blkid, act_blkid, 4 ); } } #endif /* defined(OPTION_SCSI_TAPE) */ } /* end function blockid_actual_to_emulated */ /*-------------------------------------------------------------------*/ /* blockid_32_to_22 */ /*-------------------------------------------------------------------*/ /* Convert a 3590 32-bit blockid into 3480 "22-bit format" blockid */ /* Both i/p and o/p are presumed to be in big-endian guest format */ /*-------------------------------------------------------------------*/ void blockid_32_to_22 ( BYTE *in_32blkid, BYTE *out_22blkid ) { out_22blkid[0] = ((in_32blkid[0] << 2) & 0xFC) | ((in_32blkid[1] >> 6) & 0x03); out_22blkid[1] = in_32blkid[1] & 0x3F; out_22blkid[2] = in_32blkid[2]; out_22blkid[3] = in_32blkid[3]; } /*-------------------------------------------------------------------*/ /* blockid_22_to_32 */ /*-------------------------------------------------------------------*/ /* Convert a 3480 "22-bit format" blockid into a 3590 32-bit blockid */ /* Both i/p and o/p are presumed to be in big-endian guest format */ /*-------------------------------------------------------------------*/ void blockid_22_to_32 ( BYTE *in_22blkid, BYTE *out_32blkid ) { out_32blkid[0] = (in_22blkid[0] >> 2) & 0x3F; out_32blkid[1] = ((in_22blkid[0] << 6) & 0xC0) | (in_22blkid[1] & 0x3F); out_32blkid[2] = in_22blkid[2]; out_32blkid[3] = in_22blkid[3]; } /*********************************************************************/ /** **/ /** INTERNAL STATUS & AUTOMOUNT FUNCTIONS **/ /** **/ /*********************************************************************/ /* Forward references... */ static int int_scsi_status_wait ( DEVBLK* dev, int usecs ); static void* get_stape_status_thread ( void* notused ); /*-------------------------------------------------------------------*/ /* get_stape_status_thread */ /*-------------------------------------------------------------------*/ static void* get_stape_status_thread( void* notused ) { LIST_ENTRY* pListEntry; STSTATRQ* req; DEVBLK* dev = NULL; struct mtget mtget; int timeout; UNREFERENCED(notused); logmsg (_("HHCTA300I SCSI-Tape status monitoring thread started; " "tid="TIDPAT", pri=%d, pid=%d\n"), thread_id(), getpriority(PRIO_PROCESS,0), getpid()); // PROGRAMMING NOTE: it is EXTREMELY IMPORTANT that the status- // retrieval thread (i.e. ourselves) be set to a priority that // is AT LEAST one priority slot ABOVE what the device-threads // are currently set to in order to prevent their request for // new/updated status from erroneously timing out (thereby mis- // leading them to mistakenly believe no tape is mounted when // in acuality there is!). The issue is, the caller only waits // for so long for us to return the status to them so we better // ensure we return it to them in a timely fashion else they be // mislead to believe there's no tape mounted (since, by virtue // of their request having timed out, they presume no tape is // mounted since the retrieval took too long (which only occurs // whenever (duh!) there's no tape mounted!)). Thus, if there // *is* a tape mounted, we better be DARN sure to return them // the status as quickly as possible in order to prevent their // wait from timing out. We ensure this by setting our own pri- // ority HIGHER than theirs. // PROGRAMMING NOTE: currently, it looks like each priority slot // differs from each other priority slot by '8' units, which is // why we use the value '10' here (to ensure OUR priority gets // set to the next higher slot). If this ever changes then the // below code will need to be adjusted appropriately. -- Fish SETMODE( ROOT ); { setpriority( PRIO_PROCESS, 0, (sysblk.devprio - 10) ); } SETMODE( USER ); obtain_lock( &sysblk.stape_lock ); do { sysblk.stape_getstat_busy = 1; broadcast_condition( &sysblk.stape_getstat_cond ); // Process all work items currently in our queue... while (!IsListEmpty( &sysblk.stape_status_link ) && !sysblk.shutdown) { pListEntry = RemoveListHead( &sysblk.stape_status_link ); InitializeListLink( pListEntry ); req = CONTAINING_RECORD( pListEntry, STSTATRQ, link ); dev = req->dev; // Status queries limited GLOBALLY to one per second, // since there's no way of knowing whether a drive is // on the same or different bus as the other drive(s). for ( timeout = 0 ; 1 && !sysblk.shutdown && sysblk.stape_query_status_tod.tv_sec && !(timeout = timed_wait_condition_relative_usecs ( &sysblk.stape_getstat_cond, &sysblk.stape_lock, MAX_GSTAT_FREQ_USECS, &sysblk.stape_query_status_tod )) ; ); if (!sysblk.shutdown) { // Query drive status... // Since this may take quite a while to do if there's no tape // mounted, we release the lock before attempting to retrieve // the status and then re-acquire it afterwards... release_lock( &sysblk.stape_lock ); { define_BOT_pos( dev ); // (always before MTIOCGET) // NOTE: the following may take up to *>10<* seconds to // complete on Windows whenever there's no tape mounted, // but apparently only with certain hardware. On a fast // quad-cpu Windows 2003 Server system with an Adaptec // AHA2944UW SCSI control for example, it completes right // away (i.e. IMMEDIATELY), whereas on a medium dual-proc // Windows 2000 Server system with TEKRAM SCSI controller // it takes *>> 10 <<* seconds!... if (0 == ioctl_tape( dev->fd, MTIOCGET, (char*)&mtget )) { memcpy( &dev->mtget, &mtget, sizeof( mtget )); } } obtain_lock( &sysblk.stape_lock ); broadcast_condition( &dev->stape_sstat_cond ); gettimeofday( &sysblk.stape_query_status_tod, NULL ); } } // end while (!IsListEmpty)... if (!sysblk.shutdown) { // Sleep until more/new work arrives... sysblk.stape_getstat_busy = 0; broadcast_condition( &sysblk.stape_getstat_cond ); wait_condition( &sysblk.stape_getstat_cond, &sysblk.stape_lock ); } } while (!sysblk.shutdown); // (discard all work items since we're going away) while (!IsListEmpty( &sysblk.stape_status_link )) { pListEntry = RemoveListHead( &sysblk.stape_status_link ); InitializeListLink( pListEntry ); } logmsg (_("HHCTA301I SCSI-Tape status monitoring thread ended; " "tid="TIDPAT", pri=%d, pid=%d\n"), thread_id(), getpriority(PRIO_PROCESS,0), getpid()); sysblk.stape_getstat_busy = 0; sysblk.stape_getstat_tid = 0; broadcast_condition( &sysblk.stape_getstat_cond ); release_lock( &sysblk.stape_lock ); return NULL; } /* end function get_stape_status_thread */ /*-------------------------------------------------------------------*/ /* int_scsi_status_wait */ /*-------------------------------------------------------------------*/ static int int_scsi_status_wait( DEVBLK* dev, int usecs ) { int rc; if (unlikely( dev->fd < 0 )) // (has drive been opened yet?) return -1; // (cannot proceed until it is) obtain_lock( &sysblk.stape_lock ); // Create the status retrieval thread if it hasn't been yet. // We do the actual retrieval of the status in a worker thread // because retrieving the status from a drive that doesn't have // a tape mounted may take a long time (at least on Windows). if (unlikely( !sysblk.stape_getstat_tid )) { VERIFY ( create_thread ( &sysblk.stape_getstat_tid, JOINABLE, get_stape_status_thread, NULL, "get_stape_status_thread" ) == 0 ); } // Add our request to its work queue if needed... if (!dev->stape_statrq.link.Flink) { InsertListTail( &sysblk.stape_status_link, &dev->stape_statrq.link ); } // Wake up the status retrieval thread (if needed)... if (!sysblk.stape_getstat_busy) { broadcast_condition( &sysblk.stape_getstat_cond ); } // Wait only so long for the status to be updated... rc = timed_wait_condition_relative_usecs ( &dev->stape_sstat_cond, // ptr to condition to wait on &sysblk.stape_lock, // ptr to controlling lock (must be held!) usecs, // max #of microseconds to wait NULL // [OPTIONAL] ptr to tod value (may be NULL) ); release_lock( &sysblk.stape_lock ); return rc; } /* end function int_scsi_status_wait */ /*-------------------------------------------------------------------*/ /* Check if a SCSI tape is positioned past the EOT reflector or not */ /*-------------------------------------------------------------------*/ int passedeot_scsitape( DEVBLK *dev ) { return dev->eotwarning; // (1==past EOT reflector; 0==not) } /*-------------------------------------------------------------------*/ /* Determine if the tape is Ready (tape drive door status) */ /* Returns: true/false: 1 = ready, 0 = NOT ready */ /*-------------------------------------------------------------------*/ int is_tape_mounted_scsitape( DEVBLK *dev, BYTE *unitstat, BYTE code ) { UNREFERENCED(unitstat); UNREFERENCED(code); /* Update tape mounted status */ int_scsi_status_update( dev, 1 ); // (safe/fast internal call) return ( STS_MOUNTED( dev ) ); } /* end function driveready_scsitape */ /*-------------------------------------------------------------------*/ /* Force a manual status refresh/update (DANGEROUS!) */ /*-------------------------------------------------------------------*/ int update_status_scsitape( DEVBLK *dev ) // (external tmh call) { // * * WARNING! * * // PROGRAMMING NOTE: do NOT call this function indiscriminately, // as doing so COULD cause improper functioning of the guest o/s! // How? Simple: if there's already a tape job running on the guest // using the tape drive and we just so happen to request a status // update at the precise moment a guest i/o encounters a tapemark, // it's possible for US to receive the "tapemark" status and thus // cause the guest to end up NOT SEEING the tapemark! Therefore, // you should ONLY call this function whenever the current status // indicates there's no tape mounted. If the current status says // there *is* a tape mounted, you must NOT call this function! // If the current status says there's a tape mounted and the user // knows this to be untrue (e.g. they manually unloaded it maybe) // then to kick off the auto-scsi-mount thread they must manually // issue the 'devinit' command themselves. We CANNOT presume that // a "mounted" status is bogus. We can ONLY safely presume that a // "UNmounted" status may possibly be bogus. Thus we only ask for // a status refresh if the current status is "not mounted" but we // purposely do NOT force a refresh if the status is "mounted"!! if ( STS_NOT_MOUNTED( dev ) ) // (if no tape mounted) int_scsi_status_update( dev, 0 ); // (then probably safe) return 0; } /* end function update_status_scsitape */ /*-------------------------------------------------------------------*/ /* Update SCSI tape status (and display it if CCW tracing is active) */ /*-------------------------------------------------------------------*/ void int_scsi_status_update( DEVBLK* dev, int mountstat_only ) { create_automount_thread( dev ); // (only if needed of course) // PROGRAMMING NOTE: only normal i/o requests (as well as the // scsi_tapemountmon_thread thread whenever AUTO_SCSI_MOUNT is // enabled and active) ever actually call us with mountstat_only // set to zero (in order to update our actual status value). // // Thus if we're called with a non-zero mountstat_only argument // (meaning all the caller is interested in is whether or not // there's a tape mounted on the drive (which only the panel // and GUI threads normally do (and which they do continuously // whenever they do do it!))) then we simply return immediately // so as to cause the caller to continue using whatever status // happens to already be set for the drive (which should always // be accurate). // // This prevents us from continuously "banging on the drive" // asking for the status when in reality the status we already // have should already be accurate (since it is updated after // every i/o or automatically by the auto-mount thread) if (likely(mountstat_only)) // (if only want mount status) return; // (then current should be ok) // Update status... if (likely(STS_MOUNTED( dev ))) { // According to our current status value there is a tape mounted, // so we should wait for a full/complete/accurate status update, // regardless of however long that may take... int rc; while (ETIMEDOUT == (rc = int_scsi_status_wait( dev, MAX_GSTAT_FREQ_USECS + (2 * SLOW_UPDATE_STATUS_TIMEOUT) ))) { if ( dev->ccwtrace || dev->ccwstep ) { logmsg (_("HHCTA343W %u:%4.4X Tape status retrieval timeout\n"), SSID_TO_LCSS(dev->ssid), dev->devnum); } } } else { // No tape is mounted (or so we believe). Attempt to retrieve // an updated tape status value, but if we cannot do so within // a reasonable period of time (SLOW_UPDATE_STATUS_TIMEOUT), // then continue using whatever our current tape status is... int_scsi_status_wait( dev, SLOW_UPDATE_STATUS_TIMEOUT ); } create_automount_thread( dev ); // (in case status changed) /* Display tape status if tracing is active */ if (unlikely( dev->ccwtrace || dev->ccwstep )) { char buf[256]; snprintf ( buf, sizeof(buf), "%u:%4.4X filename=%s (%s), sstat=0x%8.8lX: %s %s" ,SSID_TO_LCSS(dev->ssid) ,dev->devnum ,( (dev->filename[0]) ? (dev->filename) : ("(undefined)") ) ,( (dev->fd < 0 ) ? ("closed") : ( "opened" ) ) ,dev->sstat ,STS_ONLINE(dev) ? "ON-LINE" : "OFF-LINE" ,STS_MOUNTED(dev) ? "READY" : "NO-TAPE" ); if ( STS_TAPEMARK(dev) ) strlcat ( buf, " TAPE-MARK" , sizeof(buf) ); if ( STS_EOF (dev) ) strlcat ( buf, " END-OF-FILE" , sizeof(buf) ); if ( STS_BOT (dev) ) strlcat ( buf, " LOAD-POINT" , sizeof(buf) ); if ( STS_EOT (dev) ) strlcat ( buf, " END-OF-TAPE" , sizeof(buf) ); if ( STS_EOD (dev) ) strlcat ( buf, " END-OF-DATA" , sizeof(buf) ); if ( STS_WR_PROT (dev) ) strlcat ( buf, " WRITE-PROTECT", sizeof(buf) ); if ( STS_BOT(dev) ) dev->eotwarning = 0; logmsg ( _("HHCTA323I %s\n"), buf ); } } /* end function int_scsi_status_update */ /*-------------------------------------------------------------------*/ /* ASYNCHRONOUS TAPE OPEN */ /* SCSI tape tape-mount monitoring thread (monitors for tape mounts) */ /* Auto-started by 'int_scsi_status_update' when it notices there is */ /* no tape mounted on whatever device it's checking the status of, */ /* or by the ReqAutoMount function for unsatisfied mount requests. */ /*-------------------------------------------------------------------*/ void create_automount_thread( DEVBLK* dev ) { // AUTO-SCSI-MOUNT // // If no tape is currently mounted on this device, // kick off the tape mount monitoring thread that // will monitor for tape mounts (if it doesn't al- // ready still exist)... obtain_lock( &sysblk.stape_lock ); // Is scsimount enabled? if (likely( sysblk.auto_scsi_mount_secs )) { // Create thread if needed... if (unlikely( !sysblk.stape_mountmon_tid )) { int rc; VERIFY ( (rc = create_thread ( &sysblk.stape_mountmon_tid, DETACHED, scsi_tapemountmon_thread, NULL, "scsi_tapemountmon_thread" )) == 0 ); } // Enable it for our drive if needed... if (STS_NOT_MOUNTED( dev )) { if (!dev->stape_mntdrq.link.Flink) { InsertListTail( &sysblk.stape_mount_link, &dev->stape_mntdrq.link ); } } } release_lock( &sysblk.stape_lock ); } /*-------------------------------------------------------------------*/ /* ASYNCHRONOUS TAPE OPEN */ /*-------------------------------------------------------------------*/ /* AUTO_SCSI_MOUNT thread... */ /*-------------------------------------------------------------------*/ void *scsi_tapemountmon_thread( void *notused ) { struct timeval now; int timeout, fd; LIST_ENTRY* pListEntry; STMNTDRQ* req; DEVBLK* dev = NULL; UNREFERENCED(notused); logmsg ( _( "HHCTA300I SCSI-Tape mount-monitoring thread started;\n" " dev=%u:%4.4X, tid="TIDPAT", pri=%d, pid=%d\n" ) ,SSID_TO_LCSS(dev->ssid) ,dev->devnum ,thread_id() ,getpriority(PRIO_PROCESS,0) ,getpid() ); obtain_lock( &sysblk.stape_lock ); while (sysblk.auto_scsi_mount_secs && !sysblk.shutdown) { // Wait for automount interval to expire... gettimeofday( &now, NULL ); for ( timeout = 0 ; 1 && !sysblk.shutdown && sysblk.auto_scsi_mount_secs && !(timeout = timed_wait_condition_relative_usecs ( &sysblk.stape_getstat_cond, &sysblk.stape_lock, sysblk.auto_scsi_mount_secs * 1000000, &now )) ; ); if (sysblk.auto_scsi_mount_secs && !sysblk.shutdown) { // Process all work items... pListEntry = sysblk.stape_mount_link.Flink; while (pListEntry != &sysblk.stape_mount_link) { req = CONTAINING_RECORD( pListEntry, STMNTDRQ, link ); dev = req->dev; pListEntry = pListEntry->Flink; // Open drive if needed... if ((fd = dev->fd) < 0) { dev->readonly = 0; fd = open_tape( dev->filename, O_RDWR | O_BINARY | O_NONBLOCK ); if (fd < 0 && EROFS == errno ) { dev->readonly = 1; fd = open_tape( dev->filename, O_RDONLY | O_BINARY | O_NONBLOCK ); } // Check for successful open if (fd < 0) { logmsg (_("HHCTA324E Error opening SCSI device %u:%4.4X=%s; errno=%d: %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, errno, strerror(errno)); continue; // (go on to next drive) } define_BOT_pos( dev ); // (always after successful open) dev->fd = fd; // (so far so good) } // Retrieve the current status... // PLEASE NOTE that we must do this WITHOUT holding the stape_lock // since the 'int_scsi_status_update' and sub-functions all expect // the lock to NOT be held so that THEY can then attempt to acquire // it when needed... release_lock( &sysblk.stape_lock ); { int_scsi_status_update( dev, 0 ); } obtain_lock( &sysblk.stape_lock ); // (check again for shutdown) if (sysblk.shutdown || !sysblk.auto_scsi_mount_secs) break; // Has a tape [finally] been mounted yet?? if (STS_NOT_MOUNTED( dev )) { #if !defined( _MSVC_ ) dev->fd = -1; close_tape( fd ); #endif continue; // (go on to next drive) } // Yes, remove completed work item... RemoveListEntry( &dev->stape_mntdrq.link ); InitializeListLink( &dev->stape_mntdrq.link ); // Finish the open drive process (set drive to variable length // block processing mode, etc)... // PLEASE NOTE that we must do this WITHOUT holding the stape_lock // since the 'finish_scsitape_open' and sub-functions all expect // the lock to NOT be held so that THEY can then attempt to acquire // it when needed... release_lock( &sysblk.stape_lock ); { if ( finish_scsitape_open( dev, NULL, 0 ) == 0 ) { // Notify the guest that the tape has now been loaded by // presenting an unsolicited device attention interrupt... device_attention( dev, CSW_DE ); } } obtain_lock( &sysblk.stape_lock ); } // end for (all work items)... } // end if (sysblk.auto_scsi_mount_secs && !sysblk.shutdown) } // end while (sysblk.auto_scsi_mount_secs && !sysblk.shutdown) // (discard all work items since we're going away) while (!IsListEmpty( &sysblk.stape_mount_link )) { pListEntry = RemoveListHead( &sysblk.stape_mount_link ); InitializeListLink( pListEntry ); // (remove from the STATUS thread's work queue too!) req = CONTAINING_RECORD( pListEntry, STMNTDRQ, link ); dev = req->dev; if ( dev->stape_statrq.link.Flink) { RemoveListEntry( &dev->stape_statrq.link ); InitializeListLink( &dev->stape_statrq.link ); } } logmsg ( _( "HHCTA301I SCSI-Tape mount-monitoring thread ended;\n" " dev=%u:%4.4X, tid="TIDPAT", pid=%d\n" ) ,SSID_TO_LCSS(dev->ssid) ,dev->devnum ,thread_id() ,getpid() ); sysblk.stape_mountmon_tid = 0; // (we're going away) release_lock( &sysblk.stape_lock ); return NULL; } /* end function scsi_tapemountmon_thread */ /*-------------------------------------------------------------------*/ /* Tell driver (if needed) what a BOT position looks like... */ /*-------------------------------------------------------------------*/ void define_BOT_pos( DEVBLK *dev ) { #ifdef _MSVC_ // PROGRAMMING NOTE: Need to tell 'w32stape.c' here the // information it needs to detect physical BOT (load-point). // This is not normally needed as most drivers determine // it for themselves based on the type (manufacturer/model) // of tape drive being used, but since I haven't added the // code to 'w32stape.c' to do that yet (involves talking // directly to the SCSI device itself) we thus, for now, // need to pass that information directly to 'w32stape.c' // ourselves... U32 msk = 0xFF3FFFFF; // (3480/3490 default) U32 bot = 0x01000000; // (3480/3490 default) if ( dev->stape_blkid_32 ) { msk = 0xFFFFFFFF; // (3590 default) bot = 0x00000000; // (3590 default) } VERIFY( 0 == w32_define_BOT( dev->fd, msk, bot ) ); #else UNREFERENCED(dev); #endif // _MSVC_ } #endif // defined(OPTION_SCSI_TAPE) hercules-3.12/w32stape.c0000664000175000017500000011644312564723224012030 00000000000000//////////////////////////////////////////////////////////////////////////////////// // W32STAPE.C -- Hercules Win32 SCSI Tape handling module // // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under // the Q Public License (http://www.hercules-390.org/herclic.html) // as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// // // This module contains only WIN32 support for SCSI tapes. // Primary SCSI Tape support is in module 'scsitape.c'... // // PROGRAMMING NOTE: we rely on the known fact that // 'NO_ERROR' == 0 and 'INVALID_HANDLE_VALUE' == -1. // //////////////////////////////////////////////////////////////////////////////////// #include "hstdinc.h" #define _W32STAPE_C_ #define _HTAPE_DLL_ #include "hercules.h" #include "w32stape.h" #include "tapedev.h" // (need IS_TAPE_BLKID_BOT) #ifdef _MSVC_ //////////////////////////////////////////////////////////////////////////////////// // Global data... #define W32STAPE_MAX_FDNUMS (32) // (admitedly low, but easily increased) typedef int ifd_t; // (internal fd) typedef int ufd_t; // (user fd) #define W32STAPE_IFD2UFD( ifd ) ((ufd_t)( (ifd) | 0x7F000000 )) #define W32STAPE_UFD2IFD( ufd ) ((ifd_t)( (ufd) & ~0x7F000000 )) static BYTE g_ifds [ W32STAPE_MAX_FDNUMS ] = {0}; // (0 == avail, 0xFF == used) static HANDLE g_handles [ W32STAPE_MAX_FDNUMS ] = {0}; // (WIN32 handles) static char* g_fnames [ W32STAPE_MAX_FDNUMS ] = {0}; // (for posterity) static U32 g_fstats [ W32STAPE_MAX_FDNUMS ] = {0}; // (running status) static U32 g_BOTmsk [ W32STAPE_MAX_FDNUMS ] = {0}; // (BOT block-id mask) static U32 g_BOTbot [ W32STAPE_MAX_FDNUMS ] = {0}; // (BOT block-id value) static TAPE_GET_DRIVE_PARAMETERS g_drive_parms [ W32STAPE_MAX_FDNUMS ] = {0}; // (drive parameters) static LOCK g_lock; // (master global access lock) #define lock() obtain_w32stape_lock() #define unlock() release_lock( &g_lock ) static void obtain_w32stape_lock() { static int bDidInit = 0; static int bInitBusy = 1; if (!bDidInit) { bDidInit = 1; initialize_lock ( &g_lock ); memset( g_ifds, 0x00, sizeof ( g_ifds ) ); memset( g_handles, 0x00, sizeof ( g_handles ) ); memset( g_fnames, 0x00, sizeof ( g_fnames ) ); memset( g_fstats, 0x00, sizeof ( g_fstats ) ); memset( g_BOTmsk, 0xFF, sizeof ( g_BOTmsk ) ); memset( g_BOTbot, 0x00, sizeof ( g_BOTbot ) ); bInitBusy = 0; } while (bInitBusy) Sleep(10); obtain_lock ( &g_lock ); } //////////////////////////////////////////////////////////////////////////////////// // Allocate an internal fd number... static ifd_t w32_alloc_ifd() { ifd_t ifd = -1; errno = EMFILE; lock(); { BYTE* pifd_slot = memchr( g_ifds, 0, W32STAPE_MAX_FDNUMS ); if (pifd_slot) { int n = (int) (pifd_slot - g_ifds); if ( n >= 0 && n < W32STAPE_MAX_FDNUMS ) { *pifd_slot = 1; errno = 0; ifd = n; } } } unlock(); return ifd; } //////////////////////////////////////////////////////////////////////////////////// // Release an internal fd number... static int w32_free_ifd( ifd_t ifd ) { int rc = 0; errno = 0; lock(); { if ( ifd >= 0 && ifd < W32STAPE_MAX_FDNUMS ) g_ifds [ ifd ] = 0; else { rc = -1; errno = EBADF; } } unlock(); return rc; } //////////////////////////////////////////////////////////////////////////////////// // Retrieve the status of the tape drive... static DWORD w32_get_tape_status ( HANDLE hFile ) { // *************************************************************** // PROGRAMMING NOTE: it is THIS LOOP (retrieving the status // of the tape drive) that takes UP TO *10* SECONDS TO COMPLETE // if there is no tape mounted on the drive whereas it completes // immediately when there IS a tape mounted! I have no idea why // Windows behave so unusually/inefficiently in this way! - Fish // *************************************************************** DWORD dwTapeStatus; // (NOTE: see also: KB 111837: "ERROR_BUS_RESET May Be Benign") do dwTapeStatus = GetTapeStatus( hFile ); while (ERROR_BUS_RESET == dwTapeStatus); return dwTapeStatus; } //////////////////////////////////////////////////////////////////////////////////// // Open tape device... DLL_EXPORT ufd_t w32_open_tape ( const char* path, int oflag, ... ) { ifd_t ifd; HANDLE hFile; char szTapeDeviceName[10]; const char* pszTapeDevNum; DWORD dwDesiredAccess, dwSizeofDriveParms, dwRetCode; // Reserve an fd number right away and bail if none available... if ( (ifd = w32_alloc_ifd()) < 0 ) return -1; // If they specified a Windows device name, // use it as-is. if (1 && strnfilenamecmp( path, "\\\\.\\", 4 ) == 0 && path [4] != 0 ) { strlcpy( szTapeDeviceName, path, sizeof(szTapeDeviceName) ); } else // (not a Windows device name) { // The device name is a Cygwin/*nix device name. // Name must be either "/dev/nst0" or "/dev/st0" if (1 && strnfilenamecmp( path, "/dev/", 5 ) == 0 && ( strnfilenamecmp( (pszTapeDevNum=path+8)-3, "nst", 3 ) == 0 || strnfilenamecmp( (pszTapeDevNum=path+7)-2, "st", 2 ) == 0 ) && strlen(pszTapeDevNum) == 1 && isdigit(*pszTapeDevNum) ) { // Change it to a Windows device name (e.g. \\.\Tape0) strlcpy( szTapeDeviceName, WIN32_TAPE_DEVICE_NAME, sizeof(szTapeDeviceName) ); szTapeDeviceName[8] = *pszTapeDevNum; szTapeDeviceName[9] = 0; // PROGRAMMING NOTE: the "rewind at close" option (implied by // virtue of the filename being "/dev/st0" and not "/dev/nst0") // was handled (detected/remembered) by the higher-level caller. } else { VERIFY( w32_free_ifd( ifd ) == 0 ); errno = EINVAL; // (bad device name) return -1; // (open failure) } } // We only support O_BINARY with either O_RDWR or O_RDONLY if (1 && (( O_BINARY | O_RDWR ) != oflag) && (( O_BINARY | O_RDONLY) != oflag) ) { VERIFY( w32_free_ifd( ifd ) == 0 ); errno = EINVAL; // (invalid open flags) return -1; // (open failure) } // Set desired access dwDesiredAccess = GENERIC_READ; if ( oflag & O_RDWR ) dwDesiredAccess |= GENERIC_WRITE; // Open the tape drive... hFile = CreateFile ( szTapeDeviceName, // filename dwDesiredAccess, // desired access 0, // share mode (0 == exclusive) NULL, // security == default OPEN_EXISTING, // "file" (device actually) must already exist 0, // no special access flags needed NULL // not using template ); if ( INVALID_HANDLE_VALUE == hFile ) { int save_errno = w32_trans_w32error( GetLastError() ); VERIFY( w32_free_ifd( ifd ) == 0 ); errno = save_errno; return -1; } // Save drive parameters for later... memset( &g_drive_parms[ifd], 0, sizeof(TAPE_GET_DRIVE_PARAMETERS) ); dwSizeofDriveParms = sizeof(TAPE_GET_DRIVE_PARAMETERS); do { dwRetCode = GetTapeParameters ( hFile, GET_TAPE_DRIVE_INFORMATION, &dwSizeofDriveParms, &g_drive_parms[ifd] ); } while ((NO_ERROR != dwRetCode) // (if not normal completion, && // check for retry conditions) (0 || ERROR_MEDIA_CHANGED == dwRetCode // (likely but unimportant; retry) || ERROR_BUS_RESET == dwRetCode // (unlikely but possible; retry) )); // Did that work? if (NO_ERROR != dwRetCode) { int save_errno = w32_trans_w32error( GetLastError() ); CloseHandle( hFile ); VERIFY( w32_free_ifd( ifd ) == 0 ); errno = save_errno; return -1; } ASSERT( NO_ERROR == dwRetCode ); ASSERT( sizeof(TAPE_GET_DRIVE_PARAMETERS) == dwSizeofDriveParms ); // Save control info & return their file descriptor... g_handles [ ifd ] = hFile; // (WIN32 handle) g_fnames [ ifd ] = strdup( path ); // (for posterity) g_fstats [ ifd ] = GMT_ONLINE (0xFFFFFFFF); // (initial status) g_BOTmsk [ ifd ] = 0xFFFFFFFF; // (BOT block-id mask) g_BOTbot [ ifd ] = 0x00000000; // (BOT block-id value) return W32STAPE_IFD2UFD( ifd ); // (user fd result) } //////////////////////////////////////////////////////////////////////////////////// // Define physical BOT block-id mask / value... // PROGRAMMING NOTE: For the time being, we require 'tapedev.c' to provide to us // the information we need in order to detect physical BOT (load-point). This is // only until such time as I can add SCSI PassThru support to Hercules so that we // can talk SCSI directly to the device ourselves (to determine such things as // what type of device (manufacturer/model) we're dealing with, etc). DLL_EXPORT int w32_define_BOT ( ufd_t ufd, U32 msk, U32 bot ) { ifd_t ifd = W32STAPE_UFD2IFD( ufd ); lock(); if (0 || ifd < 0 || ifd >= W32STAPE_MAX_FDNUMS || g_ifds[ ifd ] == 0 ) { unlock(); errno = EBADF; return -1; } g_BOTmsk [ ifd ] = msk; // (BOT block-id mask) g_BOTbot [ ifd ] = bot; // (BOT block-id value) unlock(); return 0; } //////////////////////////////////////////////////////////////////////////////////// // Post-process a tape i/o return code... // // Examine 'errno' (which should have been manually set to the return // code from the current i/o) and update the internal status appropriately, // depending on what type of error it was (tapemark, etc)... // // ------------------------------------------------------------- // *** THIS FUNCTION SHOULD BE CALLED AFTER EVERY TAPE I/O *** // ------------------------------------------------------------- // // An errno of 'EINTR' means the error was spurious (media changed, etc) // and that the caller should try the same i/o again (retry their i/o). // // EXAMPLE: // // do // { // errno = SetTapePosition( ... ); // errno = w32_internal_rc ( pStat ); // } // while ( EINTR == errno ); // return errno ? -1 : 0; // //////////////////////////////////////////////////////////////////////////////////// // *** THIS FUNCTION SHOULD BE CALLED AFTER EVERY TAPE I/O *** static int w32_internal_rc ( U32* pStat ) { ASSERT( pStat ); // (sanity check) // PROGRAMMING NOTE: the 'door open' (no tape in drive) and the // 'write protected' statuses are "sticky" in that they never change // until a new/different tape is mounted. All the other statuses // however, change dynamically as one does i/o to the tape... if (0 || ERROR_BUS_RESET == errno // (See KB 111837: "ERROR_BUS_RESET May Be Benign") || ERROR_MEDIA_CHANGED == errno || ERROR_DEVICE_NOT_CONNECTED == errno // (shouldn't occur but we'll check anyway) || ERROR_DEV_NOT_EXIST == errno // (shouldn't occur but we'll check anyway) || ERROR_FILE_NOT_FOUND == errno // (shouldn't occur but we'll check anyway) ) { *pStat &= ~GMT_DR_OPEN (0xFFFFFFFF); *pStat &= ~GMT_WR_PROT (0xFFFFFFFF); } // (see PROGRAMMING NOTE above) *pStat &= ~GMT_BOT (0xFFFFFFFF); *pStat &= ~GMT_SM (0xFFFFFFFF); *pStat &= ~GMT_EOF (0xFFFFFFFF); *pStat &= ~GMT_EOT (0xFFFFFFFF); *pStat &= ~GMT_EOD (0xFFFFFFFF); if (0 || ERROR_BUS_RESET == errno // (spurious error; retry) || ERROR_MEDIA_CHANGED == errno // (spurious error; retry) // || ERROR_DEVICE_NOT_CONNECTED == errno // (PERM ERROR! NO RETRY!) // || ERROR_DEV_NOT_EXIST == errno // (PERM ERROR! NO RETRY!) // || ERROR_FILE_NOT_FOUND == errno // (PERM ERROR! NO RETRY!) ) { return EINTR; // (Interrupted system call; Retry) } // (see PROGRAMMING NOTE further above) switch (errno) { default: break; // (leave errno set to whatever it already is) case NO_ERROR: errno = 0; break; // (normal expected i/o result) case ERROR_BEGINNING_OF_MEDIA: *pStat |= GMT_BOT (0xFFFFFFFF); errno = EIO; break; case ERROR_END_OF_MEDIA: *pStat |= GMT_EOT (0xFFFFFFFF); errno = ENOSPC; break; // "ERROR_END_OF_MEDIA" // // Msg: "The physical end of the tape has been reached." // // The EOT warning reflector has been reached or passed (i.e. you're // now/still in the "EOT Warning Zone" area). Writing additional data // and/or tapemarks may still be possible depending on the size of the // EOT Warning Zone (as set by a SetTapeParameters call with a non-zero // EOTWarningZoneSize value (if supported; see further below)) and // how much data you've already written to the EOT Warning Zone area // (i.e. once you're in the warning area, this "error" occurs after // EACH and EVERY I/O [in the warning zone area] until the ABSOLUTE // physical end-of-tape (ERROR_EOM_OVERFLOW) is reached; see below). // // // *********************** // ** IMPORTANT NOTE! ** // *********************** // // This is NOT actually an "error"!!! // // // When this "error" occurs, your "ReadFile" and/or "WriteFile" call // returns 'FALSE' even though ALL of your requested data was actually // written successfully!! This can be verified by checking to ensure // the returned "number of bytes written" actually matches the amount // you asked to be written. If they're the same (and they ALWAYS will // be for this specific "error" code), then it means this "error" is // NOT actually an error at all, but rather just a WARNING instead!! // (Had it been an actual i/o error, the error code would have been // some other DIFFERENT error code value instead!!) // // // *********************** // ** ALSO IMPORTANT! ** // *********************** // See also: // // http://fixunix.com/storage/205622-bug-dlttape-sys-no-eot-warning.html // // for ADDITIONAL IMPORTANT INFORMATION regarding always having to // specifically request that this "error" code be returned to you: // // Even when a drive reports it does not support the setting of the // the 'EOTWarningZoneSize' value (i.e. the FeaturesLow field of the // GetTapeParameters call returns '0' for TAPE_DRIVE_SET_EOT_WZ_SIZE // field), it may still be possible for "ERROR_END_OF_MEDIA" warnings // to be generated anyway by simply calling SetTapeParameters with a // non-zero 'EOTWarningZoneSize' value anyway. // // The reason for this is because some drives may not allow CHANGING // the value (thus the reason for it reporting that setting the value // is not supported), but may nevertheless still support the ENABLING // of their own hard-coded internal value. That is to say, while the // size of the warning zone may not be modifiable (as it may be hard- // coded and thus unchangeable), the drive may still have the ability // to REPORT reaching the EOT Warning zone IF SPECIFICALLY REQUESTED // TO DO SO! (which is presumably what requesting a non-zero Warning // Zone size would end up doing: i.e. even though such calls APPEAR // to fail, they actually DO succeed in accomplishing SOMETHING, just // not what you originally/specifically requested). // // Thus calling SetTapeParameters with a non-zero 'EOTWarningZoneSize' // value might very well succeed anyway even though GetTapeParameters // reports that doing so is not supported, and by so doing, may cause // the drive to begin reporting of "ERROR_END_OF_MEDIA" (whereas not // attempting to do so would end up leaving the drive in its default // non-reporting mode. That is to say, you should ALWAYS try setting // a non-zero 'EOTWarningZoneSize' value, ignoring any "unsupported" // error code that may be returned from such a call.) case ERROR_EOM_OVERFLOW: *pStat |= GMT_EOT (0xFFFFFFFF); errno = EIO; break; // "ERROR_EOM_OVERFLOW" // // Msg: "Physical end of tape encountered." // // This error code means that the actual physical end-of-media has been // reached, and no more data can be written to the tape. This includes // tapemarks as well. // // *********************** // ** IMPORTANT NOTE! ** // *********************** // // This is a HARD (UNRECOVERABLE) error!! // // To be programmatically informed of when you are coming close to the // physical end-of-the-tape (such that you could be assured room still // remained to write logical end-of-volume labels for example), simply // call SetTapeParameters with a non-zero 'EOTWarningZoneSize' value // and treat any "ERROR_END_OF_MEDIA" "errors" received when writing // as warnings instead. (See prior discussion of "ERROR_END_OF_MEDIA" // return code further above) case ERROR_NO_DATA_DETECTED: *pStat |= GMT_EOD (0xFFFFFFFF); errno = EIO; break; case ERROR_FILEMARK_DETECTED: *pStat |= GMT_EOF (0xFFFFFFFF); errno = EIO; break; case ERROR_SETMARK_DETECTED: *pStat |= GMT_SM (0xFFFFFFFF); errno = EIO; break; case ERROR_NOT_READY: *pStat |= GMT_DR_OPEN (0xFFFFFFFF); errno = ENOMEDIUM; break; case ERROR_NO_MEDIA_IN_DRIVE: *pStat |= GMT_DR_OPEN (0xFFFFFFFF); errno = ENOMEDIUM; break; case ERROR_WRITE_PROTECT: *pStat |= GMT_WR_PROT (0xFFFFFFFF); errno = EROFS; break; } return errno; } //////////////////////////////////////////////////////////////////////////////////// // (forward references for private helper functions) int w32_internal_mtop ( HANDLE hFile, U32* pStat, struct mtop* mtop, ifd_t ifd ); int w32_internal_mtget ( HANDLE hFile, U32* pStat, struct mtget* mtget, ifd_t ifd ); int w32_internal_mtpos ( HANDLE hFile, U32* pStat, DWORD* pdwLogPos, DWORD* pdwAbsPos, ifd_t ifd ); //////////////////////////////////////////////////////////////////////////////////// // Close tape device... DLL_EXPORT int w32_close_tape ( ufd_t ufd ) { ifd_t ifd = W32STAPE_UFD2IFD( ufd ); int rc = -1; errno = EBADF; lock(); if (1 && ifd >= 0 && ifd < W32STAPE_MAX_FDNUMS && g_ifds[ ifd ] != 0 ) { // Deallocate resources HANDLE hFile = g_handles[ ifd ]; char* pName = g_fnames [ ifd ]; g_handles[ ifd ] = NULL; g_fnames [ ifd ] = NULL; g_fstats [ ifd ] = GMT_DR_OPEN (0xFFFFFFFF); g_BOTmsk [ ifd ] = 0xFFFFFFFF; g_BOTbot [ ifd ] = 0x00000000; VERIFY( w32_free_ifd( ifd ) == 0 ); // Close the file... free( pName ); errno = CloseHandle( hFile ) ? 0 : w32_trans_w32error( GetLastError() ); rc = errno ? -1 : 0; } unlock(); return rc; } //////////////////////////////////////////////////////////////////////////////////// // Read tape... DLL_EXPORT ssize_t w32_read_tape ( ufd_t ufd, void* buf, size_t nbyte ) { BOOL bSuccess; DWORD dwBytesRead; DWORD dwLastError; ifd_t ifd = W32STAPE_UFD2IFD( ufd ); U32* pStat = NULL; HANDLE hFile; if (!buf) { errno = EINVAL; return -1; } lock(); if (0 || ifd < 0 || ifd >= W32STAPE_MAX_FDNUMS || g_ifds[ ifd ] == 0 ) { unlock(); errno = EBADF; return -1; } unlock(); hFile = g_handles[ ifd ]; pStat = &g_fstats[ ifd ]; // Do the i/o, save results, update device status // (based on the results), then check results... do { dwBytesRead = 0; bSuccess = ReadFile( hFile, buf, (DWORD)nbyte, &dwBytesRead, NULL ); errno = (dwLastError = GetLastError()); errno = w32_internal_rc ( pStat ); } while ( !bSuccess && EINTR == errno ); // Success? (see: "ERROR_END_OF_MEDIA" in function 'w32_internal_rc') if (bSuccess || ERROR_END_OF_MEDIA == dwLastError) { ASSERT( bSuccess || ENOSPC == errno ); return ( (ssize_t) dwBytesRead ); } ASSERT( !bSuccess && ERROR_END_OF_MEDIA != dwLastError && ENOSPC != errno ); // The i/o "failed". Check to see if it was just a tapemark... if ( EIO == errno && GMT_EOF( *pStat ) ) { ASSERT( ERROR_FILEMARK_DETECTED == dwLastError ); return 0; // (tapemark) } // EIO != errno || !GMT_EOF( *pStat ) --> bona fide i/o error... ASSERT( ERROR_FILEMARK_DETECTED != dwLastError ); return -1; } //////////////////////////////////////////////////////////////////////////////////// // Write tape... DLL_EXPORT ssize_t w32_write_tape ( ufd_t ufd, const void* buf, size_t nbyte ) { BOOL bSuccess; DWORD dwBytesWritten; DWORD dwLastError; ifd_t ifd = W32STAPE_UFD2IFD( ufd ); U32* pStat = NULL; HANDLE hFile; if (!buf) { errno = EINVAL; return -1; } lock(); if (0 || ifd < 0 || ifd >= W32STAPE_MAX_FDNUMS || g_ifds[ ifd ] == 0 ) { unlock(); errno = EBADF; return -1; } unlock(); hFile = g_handles[ ifd ]; pStat = &g_fstats[ ifd ]; // Do the i/o, save results, update device status // (based on the results), then check results... do { dwBytesWritten = 0; bSuccess = WriteFile( hFile, buf, (DWORD)nbyte, &dwBytesWritten, NULL ); errno = (dwLastError = GetLastError()); errno = w32_internal_rc ( pStat ); } while ( !bSuccess && EINTR == errno ); // Success? (see: "ERROR_END_OF_MEDIA" in function 'w32_internal_rc') if (bSuccess || ERROR_END_OF_MEDIA == dwLastError) { ASSERT( bSuccess || ENOSPC == errno ); ASSERT( ((size_t)dwBytesWritten) == nbyte ); // (MUST be true!!) return ( (ssize_t) dwBytesWritten ); } // I/O error... ASSERT( !bSuccess && ERROR_END_OF_MEDIA != dwLastError && ENOSPC != errno ); return -1; } //////////////////////////////////////////////////////////////////////////////////// // ioctl... (perform some type of control function, e.g. fsf, rewind, etc) DLL_EXPORT int w32_ioctl_tape ( ufd_t ufd, int request, ... ) { va_list vl; void* ptr = NULL; int rc = 0; ifd_t ifd = W32STAPE_UFD2IFD( ufd ); U32* pStat = NULL; HANDLE hFile; lock(); if (0 || ifd < 0 || ifd >= W32STAPE_MAX_FDNUMS || g_ifds[ ifd ] == 0 ) { unlock(); errno = EBADF; return -1; } unlock(); hFile = g_handles[ ifd ]; pStat = &g_fstats[ ifd ]; va_start ( vl, request ); ptr = va_arg( vl, void* ); if ( !ptr ) { errno = EINVAL; return -1; } switch (request) { case MTIOCTOP: // (perform tape operation) { struct mtop* mtop = ptr; rc = w32_internal_mtop ( hFile, pStat, mtop, ifd ); } break; case MTIOCGET: // (retrieve tape status) { struct mtget* mtget = ptr; memset( mtget, 0, sizeof(*mtget) ); rc = w32_internal_mtget ( hFile, pStat, mtget, ifd ); } break; case MTIOCPOS: // (retrieve tape position) { struct mtpos* mtpos = ptr; memset( mtpos, 0, sizeof(*mtpos) ); rc = w32_internal_mtpos( hFile, pStat, &mtpos->mt_blkno, NULL, ifd ); } break; default: // (invalid/unsupported ioctl code) { errno = EINVAL; rc = -1; } break; } return rc; } //////////////////////////////////////////////////////////////////////////////////// // Private internal helper function... return 0 == success, -1 == failure static int w32_internal_mtop ( HANDLE hFile, U32* pStat, struct mtop* mtop, ifd_t ifd ) { int rc = 0; ASSERT( pStat && mtop ); // (sanity check) // General technique: do the i/o, save results, update the // device status (based on the results), then check results... switch ( mtop->mt_op ) { case MTLOAD: // (load media) { if ( 1 != mtop->mt_count ) { errno = EINVAL; rc = -1; } else { do { errno = PrepareTape( hFile, TAPE_LOAD, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } } break; case MTUNLOAD: // (unload media) case MTOFFL: // (make media offline (same as unload)) { if ( 1 != mtop->mt_count ) { errno = EINVAL; rc = -1; } else { do { errno = PrepareTape( hFile, TAPE_UNLOAD, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } } break; case MTSEEK: // (position media) { do { errno = SetTapePosition( hFile, TAPE_LOGICAL_BLOCK, 0, mtop->mt_count, 0, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } break; case MTREW: // (rewind) { if ( 1 != mtop->mt_count ) { errno = EINVAL; rc = -1; } else { do { errno = SetTapePosition( hFile, TAPE_REWIND, 0, 0, 0, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } } break; case MTFSF: // (FORWARD space FILE) case MTBSF: // (BACKWARD space FILE) { if ( !mtop->mt_count ) { errno = EINVAL; rc = -1; } else { LARGE_INTEGER liCount; liCount.QuadPart = mtop->mt_count; if ( MTBSF == mtop->mt_op ) liCount.QuadPart = -liCount.QuadPart; // (negative == backwards) do { errno = SetTapePosition( hFile, TAPE_SPACE_FILEMARKS, 0, liCount.LowPart, liCount.HighPart, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } } break; case MTFSR: // (FORWARD space BLOCK) case MTBSR: // (BACKWARD space BLOCK) { if ( !mtop->mt_count ) { errno = EINVAL; rc = -1; } else { LARGE_INTEGER liCount; liCount.QuadPart = mtop->mt_count; if ( MTBSR == mtop->mt_op ) liCount.QuadPart = -liCount.QuadPart; // (negative == backwards) do { errno = SetTapePosition( hFile, TAPE_SPACE_RELATIVE_BLOCKS, 0, liCount.LowPart, liCount.HighPart, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } } break; case MTSETBLK: // (set blocksize) { TAPE_SET_MEDIA_PARAMETERS media_parms; media_parms.BlockSize = mtop->mt_count; do { errno = SetTapeParameters( hFile, SET_TAPE_MEDIA_INFORMATION, &media_parms ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } break; case MTEOTWARN: // (set EOT Warning Zone size in bytes) { TAPE_SET_DRIVE_PARAMETERS set_drive_parms; set_drive_parms.ECC = g_drive_parms[ifd].ECC; set_drive_parms.Compression = g_drive_parms[ifd].Compression; set_drive_parms.DataPadding = g_drive_parms[ifd].DataPadding; set_drive_parms.ReportSetmarks = g_drive_parms[ifd].ReportSetmarks; set_drive_parms.EOTWarningZoneSize = mtop->mt_count; do { errno = SetTapeParameters( hFile, SET_TAPE_DRIVE_INFORMATION, &set_drive_parms ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } break; case MTWEOF: // (write TAPEMARK) { if ( mtop->mt_count < 0 ) { errno = EINVAL; rc = -1; } else { // PROGRAMMING NOTE: We prefer "long" filemarks over any other type // because, according to the SDK documentaion: // // "A short filemark contains a short erase gap that cannot be // overwritten unless the write operation is performed from the // beginning of the partition or from an earlier long filemark." // // "A long filemark contains a long erase gap that allows an // application to position the tape at the beginning of the filemark // and to overwrite the filemark and the erase gap." // // Thus if TAPE_LONG_FILEMARKS is not supported we try ONLY the generic // TAPE_FILEMARKS variety and return an error if that fails; we do NOT // ever attempt the TAPE_SHORT_FILEMARKS or TAPE_SETMARKS variety. DWORD dwTapemarkType = TAPE_LONG_FILEMARKS; if ( !( g_drive_parms[ifd].FeaturesHigh & TAPE_DRIVE_WRITE_LONG_FMKS ) ) dwTapemarkType = TAPE_FILEMARKS; do { errno = WriteTapemark( hFile, dwTapemarkType, mtop->mt_count, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } } break; case MTERASE: // (write erase gap or erase entire tape (data security erase)) { if (1 && 0 != mtop->mt_count // (0 == write erase gap at current position) && 1 != mtop->mt_count // (1 == erases the remainder of entire tape) ) { errno = EINVAL; rc = -1; } else { DWORD dwEraseType = mtop->mt_count ? TAPE_ERASE_LONG : TAPE_ERASE_SHORT; do { errno = EraseTape( hFile, dwEraseType, FALSE ); errno = w32_internal_rc ( pStat ); } while ( EINTR == errno ); } } break; case MTNOP: // (no operation) { errno = 0; rc = 0; } break; default: // (invalid/unsupported tape operation) { errno = EINVAL; rc = -1; } break; } return (rc = (0 == errno || ENOSPC == errno) ? 0 : /* errno != 0 && errno != ENOSPC */ -1); } //////////////////////////////////////////////////////////////////////////////////// // Private internal helper function... return 0 == success, -1 == failure static int w32_internal_mtget ( HANDLE hFile, U32* pStat, struct mtget* mtget, ifd_t ifd ) { TAPE_GET_MEDIA_PARAMETERS media_parms; DWORD dwRetCode, dwSize, dwLogicalPosition; ASSERT( pStat && mtget ); mtget->mt_resid = 0; // (unknown/unsupported) mtget->mt_erreg = 0; // (unknown/unsupported) mtget->mt_fileno = -1; // (unknown/unsupported) mtget->mt_blkno = -1; // (unknown as of yet; set further below) mtget->mt_type = MT_ISSCSI2; // "Generic ANSI SCSI-2 tape unit" mtget->mt_gstat = -1; // (purposely invalid; set correctly below) // Reset the mounted status; it will get set further below... *pStat &= ~GMT_DR_OPEN (0xFFFFFFFF); // Attempt to retrieve the status of the tape-drive... dwRetCode = w32_get_tape_status( hFile ); // Windows returns 'ERROR_NOT_READY' if no tape is mounted // instead of the usual expected 'ERROR_NO_MEDIA_IN_DRIVE' if ( ERROR_NOT_READY == dwRetCode ) dwRetCode = ERROR_NO_MEDIA_IN_DRIVE; // If there is not tape mounted OR a new tape was mounted, // then the following status bits are now unknown/obsolete if (0 || ERROR_NO_MEDIA_IN_DRIVE == dwRetCode || ERROR_MEDIA_CHANGED == dwRetCode ) { // (these statuse are now obsolete) *pStat &= ~GMT_WR_PROT (0xFFFFFFFF); *pStat &= ~GMT_BOT (0xFFFFFFFF); *pStat &= ~GMT_EOT (0xFFFFFFFF); *pStat &= ~GMT_EOD (0xFFFFFFFF); *pStat &= ~GMT_EOF (0xFFFFFFFF); *pStat &= ~GMT_SM (0xFFFFFFFF); } // There's no sense trying to get media parameters // unless there's some media loaded on the drive! if ( ERROR_NO_MEDIA_IN_DRIVE == dwRetCode ) { *pStat |= GMT_DR_OPEN (0xFFFFFFFF); // (no tape mounted in drive) mtget->mt_gstat = *pStat; // (return current status) return 0; // (nothing more we can do) } // A tape appears to be mounted on the drive... // Retrieve the media parameters information... dwSize = sizeof(media_parms); memset( &media_parms, 0, dwSize ); dwRetCode = GetTapeParameters( hFile, GET_TAPE_MEDIA_INFORMATION, &dwSize, &media_parms ); ASSERT( sizeof(media_parms) == dwSize ); if ( NO_ERROR == dwRetCode ) { mtget->mt_dsreg = media_parms.BlockSize; if (media_parms.WriteProtected) *pStat |= GMT_WR_PROT (0xFFFFFFFF); else *pStat &= ~GMT_WR_PROT (0xFFFFFFFF); } else mtget->mt_dsreg = 0; // (unknown; variable blocks presumed) // Lastly, attempt to determine if we are at BOT (i.e. load-point)... if ( 0 != ( errno = w32_internal_mtpos( hFile, pStat, &dwLogicalPosition, NULL, ifd ) ) ) { mtget->mt_gstat = *pStat; return -1; } mtget->mt_blkno = dwLogicalPosition; if ( ( dwLogicalPosition & g_BOTmsk[ ifd ] ) == g_BOTbot[ ifd ] ) *pStat |= GMT_BOT (0xFFFFFFFF); else *pStat &= ~GMT_BOT (0xFFFFFFFF); mtget->mt_gstat = *pStat; return 0; } //////////////////////////////////////////////////////////////////////////////////// // Private internal helper function... return 0 == success, -1 == failure static int w32_internal_mtpos ( HANDLE hFile, U32* pStat, DWORD* pdwLogPos, DWORD* pdwAbsPos, ifd_t ifd ) { DWORD dwDummyPartition, dwDummyPositionHigh; ASSERT( pStat && pdwLogPos ); // (sanity check) // PROGRAMMING NOTE: the SDK docs state that for the 'lpdwOffsetHigh' // parameter (i.e. dwDummyPositionHigh, the 5th paramater): // // "This parameter can be NULL if the // high-order bits are not required." // // But it LIES! Simple expirical observation reveals that ALL parameters // are in fact required. If any are NULL then 'GetTapePosition' crashes // and burns (which is unusual since usually when you pass invalid args // to an API it usually just returns an error code, but in this case it // doesn't. It actually crashes) do { U32 dummy_stat = 0; errno = GetTapePosition ( hFile, TAPE_LOGICAL_POSITION, &dwDummyPartition, pdwLogPos, &dwDummyPositionHigh ); errno = w32_internal_rc ( &dummy_stat ); } while ( EINTR == errno ); if (errno) return -1; if (pdwAbsPos) // (may be NULL if they're not interested in it) { do { U32 dummy_stat = 0; errno = GetTapePosition ( hFile, TAPE_ABSOLUTE_POSITION, &dwDummyPartition, pdwAbsPos, &dwDummyPositionHigh ); errno = w32_internal_rc ( &dummy_stat ); } while ( EINTR == errno ); if (errno) return -1; } // PROGRAMMING NOTE: the Windows 'GetTapePosition' API returns either // a LOGICAL position value or an ABSOLUTE position value. Based on // trial and error it was determined the LOGICAL position corresponds // to the SCSI "READ POSITION" command's "first block location" value, // and the ABSOLUTE tape position appears to correspond to the SCSI // "last block location". // Since what we want is what IBM calls the "Channel block ID" (which // itself appears to correspond to what the SCSI documentation refers // to as the "First block location"), then what we want here is what // Windows refers to as the LOGICAL position, not the ABSOLUTE (i.e. // device-relative) position I originally thought we needed/wanted. if ( ( *pdwLogPos & g_BOTmsk[ ifd ] ) == g_BOTbot[ ifd ] ) *pStat |= GMT_BOT (0xFFFFFFFF); else *pStat &= ~GMT_BOT (0xFFFFFFFF); return 0; } //////////////////////////////////////////////////////////////////////////////////// #endif /* _MSVC_ */ hercules-3.12/cardrdr.c0000664000175000017500000007101312564723224011772 00000000000000/* CARDRDR.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Card Reader Device Handler */ /*-------------------------------------------------------------------*/ /* This module contains device handling functions for emulated */ /* card reader devices. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "sockdev.h" #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) SYSBLK *psysblk; #define sysblk (*psysblk) #endif /*-------------------------------------------------------------------*/ /* ISW 2003/03/07 */ /* 3505 Byte 1 Sense Codes */ /*-------------------------------------------------------------------*/ #define SENSE1_RDR_PERM 0x80 /* Permanent Err key depressed */ #define SENSE1_RDR_AUTORETRY 0x40 /* Don't know */ #define SENSE1_RDR_MOTIONMF 0x20 /* Motion Malfunction */ #define SENSE1_RDR_RAIC 0x10 /* Retry After Intreq Cleared */ /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ #define CARD_SIZE 80 #define HEX40 ((BYTE)0x40) /*-------------------------------------------------------------------*/ /* Initialize the device handler */ /*-------------------------------------------------------------------*/ static int cardrdr_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { int i; /* Array subscript */ int fc; /* File counter */ int sockdev = 0; if (dev->bs) { if (!unbind_device(dev)) { // (error message already issued) return -1; } } /* Initialize device dependent fields */ dev->fd = -1; dev->fh = NULL; dev->multifile = 0; dev->ebcdic = 0; dev->ascii = 0; dev->trunc = 0; dev->cardpos = 0; dev->cardrem = 0; dev->autopad = 0; if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x2501; fc = 0; if (dev->more_files) free (dev->more_files); dev->more_files = malloc(sizeof(char*) * (fc + 1)); if (!dev->more_files) { logmsg (_("HHCRD001E Out of memory\n")); return -1; } dev->more_files[fc] = NULL; /* Process the driver arguments starting with the SECOND argument. (The FIRST argument is the filename and is checked later further below.) */ for (i = 1; i < argc; i++) { /* sockdev means the device file is actually a connected socket instead of a disk file. The file name is the socket_spec (host:port) to listen for connections on. */ if (strcasecmp(argv[i], "sockdev") == 0) { sockdev = 1; continue; } /* multifile means to automatically open the next i/p file if multiple i/p files are defined. */ if (strcasecmp(argv[i], "multifile") == 0) { dev->multifile = 1; continue; } /* eof means that unit exception will be returned at end of file, instead of intervention required */ if (strcasecmp(argv[i], "eof") == 0) { dev->rdreof = 1; continue; } /* intrq means that intervention required will be returned at end of file, instead of unit exception */ if (strcasecmp(argv[i], "intrq") == 0) { dev->rdreof = 0; continue; } /* ebcdic means that the card image file consists of fixed length 80-byte EBCDIC card images with no line-end delimiters */ if (strcasecmp(argv[i], "ebcdic") == 0) { dev->ebcdic = 1; continue; } /* ascii means that the card image file consists of variable length ASCII records delimited by either line-feed or carriage-return line-feed sequences */ if (strcasecmp(argv[i], "ascii") == 0) { dev->ascii = 1; continue; } /* trunc means that records longer than 80 bytes will be silently truncated to 80 bytes when processing a variable length ASCII file. The default behaviour is to present a data check if an overlength record is encountered. The trunc option is ignored except when processing an ASCII card image file. */ if (strcasecmp(argv[i], "trunc") == 0) { dev->trunc = 1; continue; } /* autopad means that if reading fixed sized records * (ebcdic) and end of file is reached in the middle of * a record, the record is automatically padded to 80 bytes. */ if (strcasecmp(argv[i], "autopad") == 0) { dev->autopad = 1; continue; } // add additional file arguments if (strlen(argv[i]) > sizeof(dev->filename)-1) { logmsg (_("HHCRD002E File name too long (max=%ud): \"%s\"\n"), (unsigned int)sizeof(dev->filename)-1,argv[i]); return -1; } if (access(argv[i], R_OK | F_OK) != 0) { logmsg (_("HHCRD003E Unable to access file \"%s\": %s\n"), argv[i], strerror(errno)); return -1; } dev->more_files[fc++] = strdup(argv[i]); dev->more_files = realloc(dev->more_files, sizeof(char*) * (fc + 1)); if (!dev->more_files) { logmsg (_("HHCRD004E Out of memory\n")); return -1; } dev->more_files[fc] = NULL; } dev->current_file = dev->more_files; /* Check for conflicting arguments */ if (dev->ebcdic && dev->ascii) { logmsg (_("HHCRD005E Specify 'ascii' or 'ebcdic' (or neither) but" " not both\n")); return -1; } if (sockdev) { if (fc) { logmsg (_("HHCRD006E Only one filename (sock_spec) allowed for" " socket devices\n")); return -1; } // If neither ascii nor ebcdic is specified, default to ascii. // This is required for socket devices because the open logic, // if neither is specified, attempts to determine whether the data // is actually ascii or ebcdic by reading the 1st 160 bytes of // data and then rewinding to the beginning of the file afterwards. // Since you can't "rewind" a socket, we must therefore default // to one of them. if (!dev->ebcdic && !dev->ascii) { logmsg (_("HHCRD007I Defaulting to 'ascii' for socket device" " %4.4X\n"),dev->devnum); dev->ascii = 1; } } if (dev->multifile && !fc) { logmsg (_("HHCRD008W 'multifile' option ignored: only one file" " specified\n")); dev->multifile = 0; } /* The first argument is the file name */ if (argc > 0) { /* Check for valid file name */ if (strlen(argv[0]) > sizeof(dev->filename)-1) { logmsg (_("HHCRD009E File name too long (max=%ud): \"%s\"\n"), (unsigned int)sizeof(dev->filename)-1,argv[0]); return -1; } if (!sockdev) { /* Check for specification of no file mounted on reader */ if (argv[0][0] == '*') { dev->filename[0] = '\0'; } else if (access(argv[0], R_OK | F_OK) != 0) { logmsg (_("HHCRD010E Unable to access file \"%s\": %s\n"), argv[0], strerror(errno)); return -1; } } /* Save the file name in the device block */ strcpy (dev->filename, argv[0]); } else { dev->filename[0] = '\0'; } /* Set size of i/o buffer */ dev->bufsize = CARD_SIZE; /* Set number of sense bytes */ /* ISW 20030307 : Empirical knowledge : DOS/VS R34 Erep */ /* indicates 4 bytes in 3505 sense */ dev->numsense = 4; /* Initialize the device identifier bytes */ dev->devid[0] = 0xFF; dev->devid[1] = 0x28; /* Control unit type is 2821-1 */ dev->devid[2] = 0x21; dev->devid[3] = 0x01; dev->devid[4] = dev->devtype >> 8; dev->devid[5] = dev->devtype & 0xFF; dev->devid[6] = 0x01; dev->numdevid = 7; // If socket device, create a listening socket // to accept connections on. if (sockdev && !bind_device(dev,dev->filename)) { // (error message already issued) return -1; } return 0; } /* end function cardrdr_init_handler */ /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ static void cardrdr_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "RDR", dev, class, buflen, buffer ); snprintf (buffer, buflen, "%s%s%s%s%s%s%s%s", ((dev->filename[0] == '\0') ? "*" : (char *)dev->filename), (dev->bs ? " sockdev" : ""), (dev->multifile ? " multifile" : ""), (dev->ascii ? " ascii" : ""), (dev->ebcdic ? " ebcdic" : ""), (dev->autopad ? " autopad" : ""), ((dev->ascii && dev->trunc) ? " trunc" : ""), (dev->rdreof ? " eof" : " intrq")); } /* end function cardrdr_query_device */ /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ static int cardrdr_close_device ( DEVBLK *dev ) { /* Close the device file */ if (0 || ( dev->bs && dev->fd >= 0 && close_socket( dev->fd ) < 0 ) || ( !dev->bs && dev->fh != NULL && fclose( dev->fh ) != 0 ) ) { int errnum = dev->bs ? get_HSO_errno() : errno; logmsg (_("HHCRD011E Close error on file \"%s\": %s\n"), dev->filename, strerror(errnum)); dev->fd = -1; dev->fh = NULL; return -1; } if (dev->bs && (dev->bs->clientip || dev->bs->clientname)) { logmsg (_("HHCRD012I %s (%s) disconnected from device %4.4X (%s)\n"), dev->bs->clientip, dev->bs->clientname, dev->devnum, dev->bs->spec); } dev->fd = -1; dev->fh = NULL; return 0; } /* end function cardrdr_close_device */ /*-------------------------------------------------------------------*/ /* Clear the card reader */ /*-------------------------------------------------------------------*/ static int clear_cardrdr ( DEVBLK *dev ) { /* Close the card image file */ if (cardrdr_close_device(dev) != 0) return -1; if (dev->bs) return 0; /* Clear the file name */ dev->filename[0] = '\0'; /* If next file is available, open it */ if (dev->current_file && *(dev->current_file)) { strcpy(dev->filename, *(dev->current_file++)); } else { /* Reset the device dependent flags */ dev->multifile = 0; dev->ascii = 0; dev->ebcdic = 0; // dev->rdreof = 0; dev->trunc = 0; dev->autopad = 0; } return 0; } /* end function clear_cardrdr */ /*-------------------------------------------------------------------*/ /* Open the card image file */ /*-------------------------------------------------------------------*/ static int open_cardrdr ( DEVBLK *dev, BYTE *unitstat ) { int rc; /* Return code */ int i; /* Array subscript */ int len; /* Length of data */ BYTE buf[160]; /* Auto-detection buffer */ char pathname[MAX_PATH]; /* file path in host format */ *unitstat = 0; // Socket device? if (dev->bs) { // Intervention required if no one has connected yet if (dev->fd == -1) { if(dev->rdreof) { *unitstat=CSW_CE|CSW_DE|CSW_UX; return -1; } dev->sense[0] = SENSE_IR; dev->sense[1] = SENSE1_RDR_RAIC; /* Retry when IntReq Cleared */ *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } return 0; } /* Intervention required if device has no file name */ if (dev->filename[0] == '\0') { if(dev->rdreof) { *unitstat=CSW_CE|CSW_DE|CSW_UX; return -1; } dev->sense[0] = SENSE_IR; dev->sense[1] = SENSE1_RDR_RAIC; /* Retry when IntReq Cleared */ *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Open the device file */ hostpath(pathname, dev->filename, sizeof(pathname)); rc = hopen(pathname, O_RDONLY | O_BINARY); if (rc < 0) { /* Handle open failure */ logmsg (_("HHCRD013E Error opening file %s: %s\n"), dev->filename, strerror(errno)); /* Set unit check with equipment check */ dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Save the file descriptor in the device block */ dev->fd = rc; dev->fh = fdopen(dev->fd, "rb"); /* If neither EBCDIC nor ASCII was specified, attempt to detect the format by inspecting the first 160 bytes */ if (dev->ebcdic == 0 && dev->ascii == 0) { /* Read first 160 bytes of file into the buffer */ len = fread(buf, 1, sizeof(buf), dev->fh); if (len < 0) { /* Handle read error condition */ logmsg (_("HHCRD014E Error reading file %s: %s\n"), dev->filename, strerror(errno)); /* Close the file */ fclose(dev->fh); dev->fd = -1; dev->fh = NULL; /* Set unit check with equipment check */ dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Assume ASCII format if first 160 bytes contain only ASCII characters, carriage return, line feed, tab, or EOF */ for (i = 0, dev->ascii = 1; i < len && buf[i] != '\x1A'; i++) { if ((buf[i] < 0x20 || buf[i] > 0x7F) && buf[i] != '\r' && buf[i] != '\n' && buf[i] != '\t') { dev->ascii = 0; dev->ebcdic = 1; break; } } /* end for(i) */ /* Rewind to start of file */ rc = fseek (dev->fh, 0, SEEK_SET); if (rc < 0) { /* Handle seek error condition */ logmsg (_("HHCRD015E Seek error in file %s: %s\n"), dev->filename, strerror(errno)); /* Close the file */ fclose (dev->fh); dev->fd = -1; dev->fh = NULL; /* Set unit check with equipment check */ dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } } /* end if(auto-detect) */ ASSERT(dev->fd != -1 && dev->fh); return 0; } /* end function open_cardrdr */ /*-------------------------------------------------------------------*/ /* Read an 80-byte EBCDIC card image into the device buffer */ /*-------------------------------------------------------------------*/ static int read_ebcdic ( DEVBLK *dev, BYTE *unitstat ) { int rc; /* Return code */ /* Read 80 bytes of card image data into the device buffer */ if (dev->bs) rc = read_socket( dev->fd, dev->buf, CARD_SIZE ); else rc = fread(dev->buf, 1, CARD_SIZE, dev->fh); if ((rc > 0) && (rc < CARD_SIZE) && dev->autopad) { memset(&dev->buf[rc], 0, CARD_SIZE - rc); rc = CARD_SIZE; } else if /* Check for End of file */ (0 || ( dev->bs && rc <= 0) || (!dev->bs && feof(dev->fh)) ) { /* Return unit exception or intervention required */ if (dev->rdreof) { *unitstat = CSW_CE | CSW_DE | CSW_UX; } else { dev->sense[0] = SENSE_IR; dev->sense[1] = SENSE1_RDR_RAIC; /* Retry when IntReq Cleared */ *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* Close the file and clear the file name and flags */ if (clear_cardrdr(dev) != 0) { /* Set unit check with equipment check */ dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } return -2; } /* Handle read error condition */ if (rc < CARD_SIZE) { if (rc < 0) logmsg (_("HHCRD016E Error reading file %s: %s\n"), dev->filename, strerror(errno)); else logmsg (_("HHCRD017E Unexpected end of file on %s\n"), dev->filename); /* Set unit check with equipment check */ dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } return 0; } /* end function read_ebcdic */ /*-------------------------------------------------------------------*/ /* Read a variable length ASCII card image into the device buffer */ /*-------------------------------------------------------------------*/ static int read_ascii ( DEVBLK *dev, BYTE *unitstat ) { int rc; /* Return code */ int i; /* Array subscript */ BYTE c = 0; /* Input character */ /* Prefill the card image with EBCDIC blanks */ memset (dev->buf, HEX40, CARD_SIZE); /* Read up to 80 bytes into device buffer */ for (i = 0; ; ) { /* Read next byte of card image */ if (dev->bs) { BYTE b; rc = read_socket( dev->fd, &b, 1 ); if (rc <= 0) rc = EOF; else c = b; } else { rc = getc(dev->fh); c = (BYTE)rc; } /* Handle end-of-file condition */ if (rc == EOF || c == '\x1A') { /* End of record if there is any data in buffer */ if (i > 0) break; /* Return unit exception or intervention required */ if (dev->rdreof) { *unitstat = CSW_CE | CSW_DE | CSW_UX; } else { dev->sense[0] = SENSE_IR; dev->sense[1] = SENSE1_RDR_RAIC; /* Retry when IntReq Cleared */ *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* Close the file and clear the file name and flags */ if (clear_cardrdr(dev) != 0) { /* Set unit check with equipment check */ dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } return -2; } /* Handle read error condition */ if (rc < 0) { logmsg (_("HHCRD018E Error reading file %s: %s\n"), dev->filename, strerror(errno)); /* Set unit check with equipment check */ dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Ignore carriage return */ if (c == '\r') continue; /* Line-feed indicates end of variable length record */ if (c == '\n') break; /* Expand tabs to spaces */ if (c == '\t') { do {i++;} while ((i & 7) && (i < CARD_SIZE)); continue; } /* Test for overlength record */ if (i >= CARD_SIZE) { /* Ignore excess characters if trunc option specified */ if (dev->trunc) continue; logmsg (_("HHCRD019E Card image exceeds %d bytes in file %s\n"), CARD_SIZE, dev->filename); /* Set unit check with data check */ dev->sense[0] = SENSE_DC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Convert character to EBCDIC and store in device buffer */ dev->buf[i++] = host_to_guest(c); } /* end for(i) */ return 0; } /* end function read_ascii */ /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ static void cardrdr_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { int rc; /* Return code */ int num; /* Number of bytes to move */ UNREFERENCED(flags); UNREFERENCED(prevcode); UNREFERENCED(ccwseq); /* Open the device file if necessary */ if ( !IS_CCW_SENSE(code) && (dev->fd < 0 || (!dev->bs && !dev->fh))) { rc = open_cardrdr (dev, unitstat); if (rc) return; } /* Turn all read/feed commands into read, feed, select stacker 1 */ if ((code & 0x17) == 0x02) code = 0x02; /* Turn all feed-only commands into NOP. This is ugly, and should really be thought out more. --JRM */ if ((code & 0x37) == 0x23) code = 0x03; /* Process depending on CCW opcode */ switch (code) { case 0x02: /*---------------------------------------------------------------*/ /* READ */ /*---------------------------------------------------------------*/ /* Read next card if not data-chained from previous CCW */ if ((chained & CCW_FLAGS_CD) == 0) { for (;;) { /* Read ASCII or EBCDIC card image */ if (dev->ascii) rc = read_ascii (dev, unitstat); else rc = read_ebcdic (dev, unitstat); if (0 || rc != -2 || !dev->multifile || open_cardrdr (dev, unitstat) != 0 ) break; } /* Return error status if read was unsuccessful */ if (rc) break; /* Initialize number of bytes in current card */ dev->cardpos = 0; dev->cardrem = CARD_SIZE; } /* end if(!data-chained) */ /* Calculate number of bytes to read and set residual count */ num = (count < dev->cardrem) ? count : dev->cardrem; *residual = count - num; if (count < dev->cardrem) *more = 1; /* Copy data from card image buffer into channel buffer */ memcpy (iobuf, dev->buf + dev->cardpos, num); /* Update number of bytes remaining in card image buffer */ dev->cardpos += num; dev->cardrem -= num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x03: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ *residual = 0; *unitstat = CSW_CE | CSW_DE; break; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* If sense is clear AND filename = "" OR sockdev and fd=-1 */ /* Put an IR sense - so that an unsolicited sense can see the intreq */ if(dev->sense[0]==0) { if(dev->filename[0]==0x00 || (dev->bs && dev->fd==-1)) { dev->sense[0] = SENSE_IR; dev->sense[1] = SENSE1_RDR_RAIC; /* Retry when IntReq Cleared */ } } /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ } /* end function cardrdr_execute_ccw */ #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND cardrdr_device_hndinfo = { &cardrdr_init_handler, /* Device Initialisation */ &cardrdr_execute_ccw, /* Device CCW execute */ &cardrdr_close_device, /* Device Close */ &cardrdr_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt3505_LTX_hdl_ddev #define hdl_depc hdt3505_LTX_hdl_depc #define hdl_reso hdt3505_LTX_hdl_reso #define hdl_init hdt3505_LTX_hdl_init #define hdl_fini hdt3505_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); } END_DEPENDENCY_SECTION #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR( psysblk, sysblk ); } END_RESOLVER_SECTION #endif HDL_DEVICE_SECTION; { HDL_DEVICE(1442, cardrdr_device_hndinfo ); HDL_DEVICE(2501, cardrdr_device_hndinfo ); HDL_DEVICE(3505, cardrdr_device_hndinfo ); } END_DEVICE_SECTION #endif hercules-3.12/cardpch.c0000664000175000017500000003063012564723224011755 00000000000000/* CARDPCH.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Card Punch Device Handler */ /*-------------------------------------------------------------------*/ /* This module contains device handling functions for emulated */ /* System/370 card punch devices. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ #define CARD_LENGTH 80 #define HEX40 ((BYTE)0x40) /*-------------------------------------------------------------------*/ /* Subroutine to write data to the card punch */ /*-------------------------------------------------------------------*/ static void write_buffer (DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Write data to the output file */ rc = write (dev->fd, buf, len); /* Equipment check if error writing to output file */ if (rc < len) { logmsg (_("HHCPU004E Error writing to %s: %s\n"), dev->filename, (errno == 0 ? "incomplete": strerror(errno))); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } } /* end function write_buffer */ /*-------------------------------------------------------------------*/ /* Initialize the device handler */ /*-------------------------------------------------------------------*/ static int cardpch_init_handler (DEVBLK *dev, int argc, char *argv[]) { int i; /* Array subscript */ /* The first argument is the file name */ if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1) { logmsg (_("HHCPU001E File name missing or invalid\n")); return -1; } /* Save the file name in the device block */ strcpy (dev->filename, argv[0]); /* Initialize device dependent fields */ dev->fd = -1; dev->ascii = 0; dev->crlf = 0; dev->cardpos = 0; dev->cardrem = CARD_LENGTH; dev->notrunc = 0; if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x3525; /* Process the driver arguments */ for (i = 1; i < argc; i++) { if (strcasecmp(argv[i], "ascii") == 0) { dev->ascii = 1; continue; } if (strcasecmp(argv[i], "ebcdic") == 0) { dev->ascii = 0; continue; } if (strcasecmp(argv[i], "crlf") == 0) { dev->crlf = 1; continue; } if (strcasecmp(argv[i], "noclear") == 0) { dev->notrunc = 1; continue; } logmsg (_("HHCPU002E Invalid argument: %s\n"), argv[i]); return -1; } /* Set length of buffer */ dev->bufsize = CARD_LENGTH + 2; /* Set number of sense bytes */ dev->numsense = 1; /* Initialize the device identifier bytes */ dev->devid[0] = 0xFF; dev->devid[1] = 0x28; /* Control unit type is 2821-1 */ dev->devid[2] = 0x21; dev->devid[3] = 0x01; dev->devid[4] = dev->devtype >> 8; dev->devid[5] = dev->devtype & 0xFF; dev->devid[6] = 0x01; dev->numdevid = 7; /* Activate I/O tracing */ // dev->ccwtrace = 1; return 0; } /* end function cardpch_init_handler */ /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ static void cardpch_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "PCH", dev, class, buflen, buffer ); snprintf (buffer, buflen, "%s%s%s%s", dev->filename, (dev->ascii ? " ascii" : " ebcdic"), ((dev->ascii && dev->crlf) ? " crlf" : ""), (dev->notrunc ? " notrunc" : "")); } /* end function cardpch_query_device */ /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ static int cardpch_close_device ( DEVBLK *dev ) { /* Close the device file */ if (dev->fd >= 0) close (dev->fd); dev->fd = -1; return 0; } /* end function cardpch_close_device */ /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ static void cardpch_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual) { int rc; /* Return code */ int i; /* Loop counter */ int num; /* Number of bytes to move */ int open_flags; /* File open flags */ BYTE c; /* Output character */ char pathname[MAX_PATH]; /* file path in host format */ UNREFERENCED(prevcode); UNREFERENCED(ccwseq); /* Open the device file if necessary */ if (dev->fd < 0 && !IS_CCW_SENSE(code)) { hostpath(pathname, dev->filename, sizeof(pathname)); open_flags = O_WRONLY | O_CREAT /* | O_SYNC */ | O_BINARY; if (dev->notrunc != 1) { open_flags |= O_TRUNC; } rc = hopen(pathname, open_flags, S_IRUSR | S_IWUSR | S_IRGRP); if (rc < 0) { /* Handle open failure */ logmsg (_("HHCPU003E Error opening file %s: %s\n"), dev->filename, strerror(errno)); /* Set unit check with intervention required */ dev->sense[0] = SENSE_IR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } dev->fd = rc; } /* Process depending on CCW opcode */ switch (code) { case 0x01: case 0x41: case 0x81: /*---------------------------------------------------------------*/ /* WRITE, FEED, SELECT STACKER */ /*---------------------------------------------------------------*/ /* Start a new record if not data-chained from previous CCW */ if ((chained & CCW_FLAGS_CD) == 0) { dev->cardpos = 0; dev->cardrem = CARD_LENGTH; } /* end if(!data-chained) */ /* Calculate number of bytes to write and set residual count */ num = (count < dev->cardrem) ? count : dev->cardrem; *residual = count - num; /* Copy data from channel buffer to card buffer */ for (i = 0; i < num; i++) { c = iobuf[i]; if (dev->ascii) { c = guest_to_host(c); if (!isprint(c)) c = SPACE; } dev->buf[dev->cardpos] = c; dev->cardpos++; dev->cardrem--; } /* end for(i) */ /* Perform end of record processing if not data-chaining */ if ((flags & CCW_FLAGS_CD) == 0) { if (dev->ascii) { /* Truncate trailing blanks from card buffer */ for (i = dev->cardpos; i > 0; i--) if (dev->buf[i-1] != SPACE) break; /* Append carriage return and line feed */ if (dev->crlf) dev->buf[i++] = '\r'; dev->buf[i++] = '\n'; } else { /* Pad card image with blanks */ for (i = dev->cardpos; i < CARD_LENGTH; i++) dev->buf[i] = HEX40; } /* Write card image */ write_buffer (dev, dev->buf, i, unitstat); if (*unitstat != 0) break; } /* end if(!data-chaining) */ /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x03: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ *unitstat = CSW_CE | CSW_DE; break; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ } /* end function cardpch_execute_ccw */ #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND cardpch_device_hndinfo = { &cardpch_init_handler, /* Device Initialisation */ &cardpch_execute_ccw, /* Device CCW execute */ &cardpch_close_device, /* Device Close */ &cardpch_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt3525_LTX_hdl_ddev #define hdl_depc hdt3525_LTX_hdl_depc #define hdl_reso hdt3525_LTX_hdl_reso #define hdl_init hdt3525_LTX_hdl_init #define hdl_fini hdt3525_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); } END_DEPENDENCY_SECTION HDL_DEVICE_SECTION; { HDL_DEVICE(3525, cardpch_device_hndinfo ); } END_DEVICE_SECTION #endif hercules-3.12/comm3705.c0000664000175000017500000024602312564723224011630 00000000000000/* COMM3705.C (c) Copyright Max H. Parke, 2007-2012 */ /* Hercules 3705 communications controller */ /* running NCP */ /***********************************************************************/ /* */ /* comm3705.c - (C) Copyright 2007 by MHP */ /* */ /* Loosely based on commadpt.c by Ivan Warren */ /* */ /* This module appears to the "host" as a 3705 communications */ /* controller running NCP. It does not attempt to provide an emulated */ /* execution environment for native 3705 code. */ /* */ /* Experimental release 0.02 Oct. 15, 2007 */ /* */ /* A very minimalistic SNA engine is implemented. All received SNA */ /* requests are responded to with a positive response. Also, there's */ /* enough code to enable a single SNA session to logon in LU1 (TTY) */ /* mode. */ /* */ /* FID1 is the only SNA header type supported. */ /* */ /* A large amount of required SNA functionality is not present in this */ /* release. There are no "state machines", "layers", "services", */ /* chaining*, pacing, brackets, etc.etc.etc. There are */ /* probably more bugs than working functions... Enjoy ;-) */ /* */ /* A better implementation might be to separate the SNA functions out */ /* into an independent process, with communications over a full-duplex */ /* TCP/IP socket... We might also get rid of all the magic constants...*/ /* */ /* New in release 0.02 - */ /* - VTAM switched (dial) support */ /* - New remote NCP capability */ /* - SNA 3270 (LU2) support (*with RU chaining) */ /* - fixes for some bugs in 0.01 */ /* New in release 0.03 - */ /* - don't process TTY lines until CR received */ /* New in release 0.04 - */ /* - make debug messages optional */ /* */ /* 73 DE KA1RBI */ /***********************************************************************/ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "parser.h" #include "comm3705.h" #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) SYSBLK *psysblk; #define sysblk (*psysblk) #endif #if !defined(min) #define min(a,b) (((a) <= (b)) ? (a) : (b)) #endif static void make_sna_requests2(COMMADPT*); static void make_sna_requests3(COMMADPT*); static void make_sna_requests4(COMMADPT*, int, BYTE); static void make_sna_requests5(COMMADPT*); static unsigned char R010201[3] = {0x01, 0x02, 0x01}; static unsigned char R010202[3] = {0x01, 0x02, 0x02}; static unsigned char R010203[3] = {0x01, 0x02, 0x03}; static unsigned char R010204[3] = {0x01, 0x02, 0x04}; static unsigned char R010205[3] = {0x01, 0x02, 0x05}; static unsigned char R01020A[3] = {0x01, 0x02, 0x0A}; static unsigned char R01020B[3] = {0x01, 0x02, 0x0B}; static unsigned char R01020F[3] = {0x01, 0x02, 0x0F}; static unsigned char R010211[3] = {0x01, 0x02, 0x11}; static unsigned char R010216[3] = {0x01, 0x02, 0x16}; static unsigned char R010217[3] = {0x01, 0x02, 0x17}; static unsigned char R010219[3] = {0x01, 0x02, 0x19}; static unsigned char R01021A[3] = {0x01, 0x02, 0x1A}; static unsigned char R01021B[3] = {0x01, 0x02, 0x1B}; static unsigned char R010280[3] = {0x01, 0x02, 0x80}; static unsigned char R010281[3] = {0x01, 0x02, 0x81}; static unsigned char R010284[3] = {0x01, 0x02, 0x84}; #define BUFPD 0x1C static BYTE commadpt_immed_command[256]= { 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /*---------------------------------------------------------------*/ /* PARSER TABLES */ /*---------------------------------------------------------------*/ static PARSER ptab[]={ {"lport","%s"}, {"lhost","%s"}, {"rport","%s"}, {"rhost","%s"}, {"dial","%s"}, {"rto","%s"}, {"pto","%s"}, {"eto","%s"}, {"switched","%s"}, {"lnctl","%s"}, {"debug","%s"}, {"emu3791","%s"}, {"locsuba","%s"}, {"rmtsuba","%s"}, {"locncpnm","%s"}, {"rmtncpnm","%s"}, {"idblk","%s"}, {"idnum","%s"}, {"unitsz","%s"}, {"ackspeed","%s"}, {NULL,NULL} }; enum { COMMADPT_KW_LPORT=1, COMMADPT_KW_LHOST, COMMADPT_KW_RPORT, COMMADPT_KW_RHOST, COMMADPT_KW_DIAL, COMMADPT_KW_READTO, COMMADPT_KW_POLLTO, COMMADPT_KW_ENABLETO, COMMADPT_KW_SWITCHED, COMMADPT_KW_LNCTL, COMMADPT_KW_DEBUG, COMMADPT_KW_EMU3791, COMMADPT_KW_LOCSUBA, COMMADPT_KW_RMTSUBA, COMMADPT_KW_LOCNCPNM, COMMADPT_KW_RMTNCPNM, COMMADPT_KW_IDBLK, COMMADPT_KW_IDNUM, COMMADPT_KW_UNITSZ, COMMADPT_KW_ACKSPEED } comm3705_kw; ////////////////////////////////////////////////////////////////////// // some code copied from console.c static HOST_INFO cons_hostinfo; /* Host info for this system */ /*-------------------------------------------------------------------*/ /* Telnet command definitions */ /*-------------------------------------------------------------------*/ #define BINARY 0 /* Binary Transmission */ #define IS 0 /* Used by terminal-type negotiation */ #define SEND 1 /* Used by terminal-type negotiation */ #define ECHO_OPTION 1 /* Echo option */ #define SUPPRESS_GA 3 /* Suppress go-ahead option */ #define TIMING_MARK 6 /* Timing mark option */ #define TERMINAL_TYPE 24 /* Terminal type option */ #define NAWS 31 /* Negotiate About Window Size */ #define EOR 25 /* End of record option */ #define EOR_MARK 239 /* End of record marker */ #define SE 240 /* End of subnegotiation parameters */ #define NOP 241 /* No operation */ #define DATA_MARK 242 /* The data stream portion of a Synch. This should always be accompanied by a TCP Urgent notification */ #define BRK 243 /* Break character */ #define IP 244 /* Interrupt Process */ #define AO 245 /* Abort Output */ #define AYT 246 /* Are You There */ #define EC 247 /* Erase character */ #define EL 248 /* Erase Line */ #define GA 249 /* Go ahead */ #define SB 250 /* Subnegotiation of indicated option */ #define WILL 251 /* Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option */ #define WONT 252 /* Indicates the refusal to perform, or continue performing, the indicated option */ #define DO 253 /* Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option */ #define DONT 254 /* Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option */ #define IAC 255 /* Interpret as Command */ /*-------------------------------------------------------------------*/ /* 3270 definitions */ /*-------------------------------------------------------------------*/ /* 3270 remote commands */ #define R3270_EAU 0x6F /* Erase All Unprotected */ #define R3270_EW 0xF5 /* Erase/Write */ #define R3270_EWA 0x7E /* Erase/Write Alternate */ #define R3270_RB 0xF2 /* Read Buffer */ #define R3270_RM 0xF6 /* Read Modified */ #define R3270_RMA 0x6E /* Read Modified All */ #define R3270_WRT 0xF1 /* Write */ #define R3270_WSF 0xF3 /* Write Structured Field */ /* 3270 orders */ #define O3270_SBA 0x11 /* Set Buffer Address */ #define O3270_SF 0x1D /* Start Field */ #define O3270_SFE 0x29 /* Start Field Extended */ #define O3270_SA 0x28 /* Set Attribute */ #define O3270_IC 0x13 /* Insert Cursor */ #define O3270_MF 0x2C /* Modify Field */ #define O3270_PT 0x05 /* Program Tab */ #define O3270_RA 0x3C /* Repeat to Address */ #define O3270_EUA 0x12 /* Erase Unprotected to Addr */ #define O3270_GE 0x08 /* Graphic Escape */ /* Inbound structured fields */ #define SF3270_AID 0x88 /* Aid value of inbound SF */ #define SF3270_3270DS 0x80 /* SFID of 3270 datastream SF*/ /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ /* DEBUG_LVL: 0 = none 1 = status 2 = headers 3 = buffers */ #define DEBUG_LVL 0 #if DEBUG_LVL == 0 #define TNSDEBUG1 1 ? ((void)0) : logmsg #define TNSDEBUG2 1 ? ((void)0) : logmsg #define TNSDEBUG3 1 ? ((void)0) : logmsg #endif #if DEBUG_LVL == 1 #define TNSDEBUG1 logmsg #define TNSDEBUG2 1 ? ((void)0) : logmsg #define TNSDEBUG3 1 ? ((void)0) : logmsg #endif #if DEBUG_LVL == 2 #define TNSDEBUG1 logmsg #define TNSDEBUG2 logmsg #define TNSDEBUG3 1 ? ((void)0) : logmsg #endif #if DEBUG_LVL == 3 #define TNSDEBUG1 logmsg #define TNSDEBUG2 logmsg #define TNSDEBUG3 logmsg #endif #define TNSERROR logmsg #define BUFLEN_3270 65536 /* 3270 Send/Receive buffer */ #define BUFLEN_1052 150 /* 1052 Send/Receive buffer */ #undef FIX_QWS_BUG_FOR_MCS_CONSOLES /*-------------------------------------------------------------------*/ /* SUBROUTINE TO TRACE THE CONTENTS OF AN ASCII MESSAGE PACKET */ /*-------------------------------------------------------------------*/ #if DEBUG_LVL == 3 static void packet_trace(BYTE *addr, int len) { int i, offset; BYTE c; BYTE print_chars[17]; for (offset=0; offset < len; ) { memset(print_chars,0,sizeof(print_chars)); logmsg("+%4.4X ", offset); for (i=0; i < 16; i++) { c = *addr++; if (offset < len) { logmsg("%2.2X", c); print_chars[i] = '.'; if (isprint(c)) print_chars[i] = c; c = guest_to_host(c); if (isprint(c)) print_chars[i] = c; } else { logmsg(" "); } offset++; if ((offset & 3) == 0) { logmsg(" "); } } /* end for(i) */ logmsg(" %s\n", print_chars); } /* end for(offset) */ } /* end function packet_trace */ #else #define packet_trace( _addr, _len) #endif #if 1 struct sockaddr_in * get_inet_socket(char *host_serv) { char *host = NULL; char *serv; struct sockaddr_in *sin; if((serv = strchr(host_serv,':'))) { *serv++ = '\0'; if(*host_serv) host = host_serv; } else serv = host_serv; if(!(sin = malloc(sizeof(struct sockaddr_in)))) return sin; sin->sin_family = AF_INET; if(host) { struct hostent *hostent; hostent = gethostbyname(host); if(!hostent) { logmsg(_("HHCGI001I Unable to determine IP address from %s\n"), host); free(sin); return NULL; } memcpy(&sin->sin_addr,*hostent->h_addr_list,sizeof(sin->sin_addr)); } else sin->sin_addr.s_addr = INADDR_ANY; if(serv) { if(!isdigit(*serv)) { struct servent *servent; servent = getservbyname(serv, "tcp"); if(!servent) { logmsg(_("HHCGI002I Unable to determine port number from %s\n"), host); free(sin); return NULL; } sin->sin_port = servent->s_port; } else sin->sin_port = htons(atoi(serv)); } else { logmsg(_("HHCGI003E Invalid parameter: %s\n"), host_serv); free(sin); return NULL; } return sin; } #endif /*-------------------------------------------------------------------*/ /* SUBROUTINE TO DOUBLE UP ANY IAC BYTES IN THE DATA STREAM */ /* Returns the new length after inserting extra IAC bytes */ /*-------------------------------------------------------------------*/ static int double_up_iac (BYTE *buf, int len) { int m, n, x, newlen; /* Count the number of IAC bytes in the data */ for (x=0, n=0; n < len; n++) if (buf[n] == IAC) x++; /* Exit if nothing to do */ if (x == 0) return len; /* Insert extra IAC bytes backwards from the end of the buffer */ newlen = len + x; TNSDEBUG3("console: DBG002: %d IAC bytes added, newlen=%d\n", x, newlen); for (n=newlen, m=len; n > m; ) { buf[--n] = buf[--m]; if (buf[n] == IAC) buf[--n] = IAC; } packet_trace (buf, newlen); return newlen; } /* end function double_up_iac */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO TRANSLATE A NULL-TERMINATED STRING TO EBCDIC */ /*-------------------------------------------------------------------*/ static BYTE * translate_to_ebcdic (char *str) { int i; /* Array subscript */ BYTE c; /* Character work area */ for (i = 0; str[i] != '\0'; i++) { c = str[i]; str[i] = (isprint(c) ? host_to_guest(c) : SPACE); } return (BYTE *)str; } /* end function translate_to_ebcdic */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO SEND A DATA PACKET TO THE CLIENT */ /*-------------------------------------------------------------------*/ static int send_packet (int csock, BYTE *buf, int len, char *caption) { int rc; /* Return code */ if (caption != NULL) { TNSDEBUG2("console: DBG003: Sending %s\n", caption); packet_trace (buf, len); } rc = send (csock, buf, len, 0); if (rc < 0) { TNSERROR("console: DBG021: send: %s\n", strerror(HSO_errno)); return -1; } /* end if(rc) */ return 0; } /* end function send_packet */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO RECEIVE A DATA PACKET FROM THE CLIENT */ /* This subroutine receives bytes from the client. It stops when */ /* the receive buffer is full, or when the last two bytes received */ /* consist of the IAC character followed by a specified delimiter. */ /* If zero bytes are received, this means the client has closed the */ /* connection, and this is treated as an error. */ /* Input: */ /* csock is the socket number */ /* buf points to area to receive data */ /* reqlen is the number of bytes requested */ /* delim is the delimiter character (0=no delimiter) */ /* Output: */ /* buf is updated with data received */ /* The return value is the number of bytes received, or */ /* -1 if an error occurred. */ /*-------------------------------------------------------------------*/ static int recv_packet (int csock, BYTE *buf, int reqlen, BYTE delim) { int rc=0; /* Return code */ int rcvlen=0; /* Length of data received */ while (rcvlen < reqlen) { rc = recv (csock, buf + rcvlen, reqlen - rcvlen, 0); if (rc < 0) { TNSERROR("console: DBG022: recv: %s\n", strerror(HSO_errno)); return -1; } if (rc == 0) { TNSDEBUG1("console: DBG004: Connection closed by client\n"); return -1; } rcvlen += rc; if (delim != '\0' && rcvlen >= 2 && buf[rcvlen-2] == IAC && buf[rcvlen-1] == delim) break; } TNSDEBUG2("console: DBG005: Packet received length=%d\n", rcvlen); packet_trace (buf, rcvlen); return rcvlen; } /* end function recv_packet */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO RECEIVE A PACKET AND COMPARE WITH EXPECTED VALUE */ /*-------------------------------------------------------------------*/ static int expect (int csock, BYTE *expected, int len, char *caption) { int rc; /* Return code */ BYTE buf[512]; /* Receive buffer */ #if 1 /* TCP/IP for MVS returns the server sequence rather then the client sequence during bin negotiation 19/06/00 Jan Jaeger */ static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY }; static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY }; #endif UNREFERENCED(caption); rc = recv_packet (csock, buf, len, 0); if (rc < 0) return -1; #if 1 /* TCP/IP FOR MVS DOES NOT COMPLY TO RFC 1576 THIS IS A BYPASS */ if(memcmp(buf, expected, len) != 0 && !(len == sizeof(will_bin) && memcmp(expected, will_bin, len) == 0 && memcmp(buf, do_bin, len) == 0) ) #else if (memcmp(buf, expected, len) != 0) #endif { TNSDEBUG2("console: DBG006: Expected %s\n", caption); return -1; } TNSDEBUG2("console: DBG007: Received %s\n", caption); return 0; } /* end function expect */ /*-------------------------------------------------------------------*/ /* SUBROUTINE TO NEGOTIATE TELNET PARAMETERS */ /* This subroutine negotiates the terminal type with the client */ /* and uses the terminal type to determine whether the client */ /* is to be supported as a 3270 display console or as a 1052/3215 */ /* printer-keyboard console. */ /* */ /* Valid display terminal types are "IBM-NNNN", "IBM-NNNN-M", and */ /* "IBM-NNNN-M-E", where NNNN is 3270, 3277, 3278, 3279, 3178, 3179, */ /* or 3180, M indicates the screen size (2=25x80, 3=32x80, 4=43x80, */ /* 5=27x132, X=determined by Read Partition Query command), and */ /* -E is an optional suffix indicating that the terminal supports */ /* extended attributes. Displays are negotiated into tn3270 mode. */ /* An optional device number suffix (example: IBM-3270@01F) may */ /* be specified to request allocation to a specific device number. */ /* Valid 3270 printer type is "IBM-3287-1" */ /* */ /* Terminal types whose first four characters are not "IBM-" are */ /* handled as printer-keyboard consoles using telnet line mode. */ /* */ /* Input: */ /* csock Socket number for client connection */ /* Output: */ /* class D=3270 display console, K=printer-keyboard console */ /* P=3270 printer */ /* model 3270 model indicator (2,3,4,5,X) */ /* extatr 3270 extended attributes (Y,N) */ /* devn Requested device number, or FFFF=any device number */ /* Return value: */ /* 0=negotiation successful, -1=negotiation error */ /*-------------------------------------------------------------------*/ static int negotiate(int csock, BYTE *class, BYTE *model, BYTE *extatr, U16 *devn,char *group) { int rc; /* Return code */ char *termtype; /* Pointer to terminal type */ char *s; /* String pointer */ BYTE c; /* Trailing character */ U16 devnum; /* Requested device number */ BYTE buf[512]; /* Telnet negotiation buffer */ static BYTE do_term[] = { IAC, DO, TERMINAL_TYPE }; static BYTE will_term[] = { IAC, WILL, TERMINAL_TYPE }; static BYTE req_type[] = { IAC, SB, TERMINAL_TYPE, SEND, IAC, SE }; static BYTE type_is[] = { IAC, SB, TERMINAL_TYPE, IS }; static BYTE do_eor[] = { IAC, DO, EOR, IAC, WILL, EOR }; static BYTE will_eor[] = { IAC, WILL, EOR, IAC, DO, EOR }; static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY }; static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY }; #if 0 static BYTE do_tmark[] = { IAC, DO, TIMING_MARK }; static BYTE will_tmark[] = { IAC, WILL, TIMING_MARK }; static BYTE wont_sga[] = { IAC, WONT, SUPPRESS_GA }; static BYTE dont_sga[] = { IAC, DONT, SUPPRESS_GA }; #endif static BYTE wont_echo[] = { IAC, WONT, ECHO_OPTION }; static BYTE dont_echo[] = { IAC, DONT, ECHO_OPTION }; static BYTE will_naws[] = { IAC, WILL, NAWS }; /* Perform terminal-type negotiation */ rc = send_packet (csock, do_term, sizeof(do_term), "IAC DO TERMINAL_TYPE"); if (rc < 0) return -1; rc = expect (csock, will_term, sizeof(will_term), "IAC WILL TERMINAL_TYPE"); if (rc < 0) return -1; /* Request terminal type */ rc = send_packet (csock, req_type, sizeof(req_type), "IAC SB TERMINAL_TYPE SEND IAC SE"); if (rc < 0) return -1; rc = recv_packet (csock, buf, sizeof(buf)-2, SE); if (rc < 0) return -1; /* Ignore Negotiate About Window Size */ if (rc >= (int)sizeof(will_naws) && memcmp (buf, will_naws, sizeof(will_naws)) == 0) { memmove(buf, &buf[sizeof(will_naws)], (rc - sizeof(will_naws))); rc -= sizeof(will_naws); } if (rc < (int)(sizeof(type_is) + 2) || memcmp(buf, type_is, sizeof(type_is)) != 0 || buf[rc-2] != IAC || buf[rc-1] != SE) { TNSDEBUG2("console: DBG008: Expected IAC SB TERMINAL_TYPE IS\n"); return -1; } buf[rc-2] = '\0'; termtype = (char *)(buf + sizeof(type_is)); TNSDEBUG2("console: DBG009: Received IAC SB TERMINAL_TYPE IS %s IAC SE\n", termtype); /* Check terminal type string for device name suffix */ s = strchr (termtype, '@'); if(s!=NULL) { if(strlen(s)<16) { strlcpy(group,&s[1],16); } } else { group[0]=0; } if (s != NULL && sscanf (s, "@%hx%c", &devnum,&c) == 1) { *devn = devnum; group[0]=0; } else { *devn = 0xFFFF; } /* Test for non-display terminal type */ if (memcmp(termtype, "IBM-", 4) != 0) { #if 0 /* Perform line mode negotiation */ rc = send_packet (csock, do_tmark, sizeof(do_tmark), "IAC DO TIMING_MARK"); if (rc < 0) return -1; rc = expect (csock, will_tmark, sizeof(will_tmark), "IAC WILL TIMING_MARK"); if (rc < 0) return 0; rc = send_packet (csock, wont_sga, sizeof(wont_sga), "IAC WONT SUPPRESS_GA"); if (rc < 0) return -1; rc = expect (csock, dont_sga, sizeof(dont_sga), "IAC DONT SUPPRESS_GA"); if (rc < 0) return -1; #endif if (memcmp(termtype, "ANSI", 4) == 0) { rc = send_packet (csock, wont_echo, sizeof(wont_echo), "IAC WONT ECHO"); if (rc < 0) return -1; rc = expect (csock, dont_echo, sizeof(dont_echo), "IAC DONT ECHO"); if (rc < 0) return -1; } /* Return printer-keyboard terminal class */ *class = 'K'; *model = '-'; *extatr = '-'; return 0; } /* Determine display terminal model */ if (memcmp(termtype+4,"DYNAMIC",7) == 0) { *model = 'X'; *extatr = 'Y'; } else { if (!(memcmp(termtype+4, "3277", 4) == 0 || memcmp(termtype+4, "3270", 4) == 0 || memcmp(termtype+4, "3178", 4) == 0 || memcmp(termtype+4, "3278", 4) == 0 || memcmp(termtype+4, "3179", 4) == 0 || memcmp(termtype+4, "3180", 4) == 0 || memcmp(termtype+4, "3287", 4) == 0 || memcmp(termtype+4, "3279", 4) == 0)) return -1; *model = '2'; *extatr = 'N'; if (termtype[8]=='-') { if (termtype[9] < '1' || termtype[9] > '5') return -1; *model = termtype[9]; if (memcmp(termtype+4, "328",3) == 0) *model = '2'; if (memcmp(termtype+10, "-E", 2) == 0) *extatr = 'Y'; } } /* Perform end-of-record negotiation */ rc = send_packet (csock, do_eor, sizeof(do_eor), "IAC DO EOR IAC WILL EOR"); if (rc < 0) return -1; rc = expect (csock, will_eor, sizeof(will_eor), "IAC WILL EOR IAC DO EOR"); if (rc < 0) return -1; /* Perform binary negotiation */ rc = send_packet (csock, do_bin, sizeof(do_bin), "IAC DO BINARY IAC WILL BINARY"); if (rc < 0) return -1; rc = expect (csock, will_bin, sizeof(will_bin), "IAC WILL BINARY IAC DO BINARY"); if (rc < 0) return -1; /* Return display terminal class */ if (memcmp(termtype+4,"3287",4)==0) *class='P'; else *class = 'D'; return 0; } /* end function negotiate */ /*-------------------------------------------------------------------*/ /* NEW CLIENT CONNECTION */ /*-------------------------------------------------------------------*/ static int connect_client (int *csockp) /* returns 1 if 3270, else 0 */ { int rc; /* Return code */ size_t len; /* Data length */ int csock; /* Socket for conversation */ struct sockaddr_in client; /* Client address structure */ socklen_t namelen; /* Length of client structure*/ char *clientip; /* Addr of client ip address */ U16 devnum; /* Requested device number */ BYTE class; /* D=3270, P=3287, K=3215/1052 */ BYTE model; /* 3270 model (2,3,4,5,X) */ BYTE extended; /* Extended attributes (Y,N) */ char buf[256]; /* Message buffer */ char conmsg[256]; /* Connection message */ char devmsg[25]; /* Device message */ char hostmsg[256]; /* Host ID message */ char num_procs[16]; /* #of processors string */ char group[16]; /* Console group */ /* Load the socket address from the thread parameter */ csock = *csockp; /* Obtain the client's IP address */ namelen = sizeof(client); rc = getpeername (csock, (struct sockaddr *)&client, &namelen); /* Log the client's IP address and hostname */ clientip = strdup(inet_ntoa(client.sin_addr)); #if 0 // The following isn't really needed and hangs under unusual // network configuration settings and thus has been removed. { struct hostent* pHE; /* Addr of hostent structure */ char* clientname; /* Addr of client hostname */ pHE = gethostbyaddr ((unsigned char*)(&client.sin_addr), sizeof(client.sin_addr), AF_INET); if (pHE != NULL && pHE->h_name != NULL && pHE->h_name[0] != '\0') { clientname = (char*) pHE->h_name; } else { clientname = "host name unknown"; } TNSDEBUG1("console: DBG018: Received connection from %s (%s)\n", clientip, clientname); } #else TNSDEBUG1("console: DBG018: Received connection from %s\n", clientip ); #endif /* Negotiate telnet parameters */ rc = negotiate (csock, &class, &model, &extended, &devnum, group); if (rc != 0) { close_socket (csock); if (clientip) free(clientip); return 0; } /* Build connection message for client */ if ( cons_hostinfo.num_procs > 1 ) snprintf( num_procs, sizeof(num_procs), "MP=%d", cons_hostinfo.num_procs ); else strlcpy( num_procs, "UP", sizeof(num_procs) ); snprintf ( hostmsg, sizeof(hostmsg), "running on %s (%s-%s.%s %s %s)" ,cons_hostinfo.nodename ,cons_hostinfo.sysname ,cons_hostinfo.release ,cons_hostinfo.version ,cons_hostinfo.machine ,num_procs ); snprintf (conmsg, sizeof(conmsg), "Hercules version %s built on %s %s", VERSION, __DATE__, __TIME__); { snprintf (devmsg, sizeof(devmsg), "Connected to device %4.4X", 0); } logmsg (_("HHCTE009I Client %s connected to %4.4X device %4.4X\n"), clientip, 0x3270, 0); /* Send connection message to client */ if (class != 'K') { len = snprintf (buf, sizeof(buf), "\xF5\x40\x11\x40\x40\x1D\x60%s" "\x11\xC1\x50\x1D\x60%s" "\x11\xC2\x60\x1D\x60%s", translate_to_ebcdic(conmsg), translate_to_ebcdic(hostmsg), translate_to_ebcdic(devmsg)); if (len < sizeof(buf)) { buf[len++] = IAC; } else { ASSERT(FALSE); } if (len < sizeof(buf)) { buf[len++] = EOR_MARK; } else { ASSERT(FALSE); } } else { len = snprintf (buf, sizeof(buf), "%s\r\n%s\r\n%s\r\n", conmsg, hostmsg, devmsg); } if (class != 'P') /* do not write connection resp on 3287 */ { rc = send_packet (csock, (BYTE *)buf, len, "CONNECTION RESPONSE"); } return (class == 'D') ? 1 : 0; /* return 1 if 3270 */ } /* end function connect_client */ static void logdump(char *txt,DEVBLK *dev,BYTE *bfr,size_t sz) { size_t i; if(!dev->ccwtrace) { return; } logmsg(_("HHCCA300D %4.4X:%s\n"), dev->devnum, txt); logmsg(_("HHCCA300D %4.4X:%s : Dump of %d (%x) byte(s)\n"),dev->devnum,txt,sz,sz); for(i=0;idevnum,txt,i); } if(i%4==0) { logmsg(" "); } logmsg("%2.2X",bfr[i]); } logmsg("\nHHCCA300D "); for(i=0;iunitsz+16+4; ca->poolarea = (BYTE*)calloc (numbufs, bufsize); if (!ca->poolarea) { return; } areap = ca->poolarea; for (i1 = 0; i1 < numbufs; i1++) { put_bufpool(&ca->freeq, areap); areap += (bufsize); } } static void free_bufpool(COMMADPT *ca) { ca->sendq = 0; ca->freeq = 0; if (ca->poolarea) { free(ca->poolarea); ca->poolarea = 0; } } /*-------------------------------------------------------------------*/ /* Free all private structures and buffers */ /*-------------------------------------------------------------------*/ static void commadpt_clean_device(DEVBLK *dev) { if(dev->commadpt!=NULL) { free(dev->commadpt); dev->commadpt=NULL; if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:clean : Control block freed\n"), dev->devnum); } } else { if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:clean : Control block not freed : not allocated\n"),dev->devnum); } } return; } /*-------------------------------------------------------------------*/ /* Allocate initial private structures */ /*-------------------------------------------------------------------*/ static int commadpt_alloc_device(DEVBLK *dev) { dev->commadpt=malloc(sizeof(COMMADPT)); if(dev->commadpt==NULL) { logmsg(_("HHCCA020E %4.4X:Memory allocation failure for main control block\n"), dev->devnum); return -1; } memset(dev->commadpt,0,sizeof(COMMADPT)); dev->commadpt->dev=dev; return 0; } /*-------------------------------------------------------------------*/ /* Parsing utilities */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* commadpt_getport : returns a port number or -1 */ /*-------------------------------------------------------------------*/ static int commadpt_getport(char *txt) { int pno; struct servent *se; pno=atoi(txt); if(pno==0) { se=getservbyname(txt,"tcp"); if(se==NULL) { return -1; } pno=se->s_port; } return(pno); } /*-------------------------------------------------------------------*/ /* commadpt_getaddr : set an in_addr_t if ok, else return -1 */ /*-------------------------------------------------------------------*/ static int commadpt_getaddr(in_addr_t *ia,char *txt) { struct hostent *he; he=gethostbyname(txt); if(he==NULL) { return(-1); } memcpy(ia,he->h_addr_list[0],4); return(0); } static void connect_message(int sfd, int na, int flag) { int rc; struct sockaddr_in client; socklen_t namelen; char *ipaddr; char msgtext[256]; if (!sfd) return; namelen = sizeof(client); rc = getpeername (sfd, (struct sockaddr *)&client, &namelen); ipaddr = inet_ntoa(client.sin_addr); if (flag == 0) sprintf(msgtext, "%s:%d VTAM CONNECTION ACCEPTED - NETWORK NODE= %4.4X", ipaddr, (int)ntohs(client.sin_port), na); else sprintf(msgtext, "%s:%d VTAM CONNECTION TERMINATED", ipaddr, (int)ntohs(client.sin_port)); logmsg( _("%s\n"), msgtext); write(sfd, msgtext, strlen(msgtext)); write(sfd, "\r\n", 2); } static void commadpt_read_tty(COMMADPT *ca, BYTE * bfr, int len) // everything has been tortured to now do 3270 also { BYTE bfr3[3]; BYTE c; int i1; int eor=0; logdump("RECV",ca->dev, bfr,len); /* If there is a complete data record already in the buffer then discard it before reading more data For TTY, allow data to accumulate until CR is received */ if (ca->is_3270) { if (ca->inpbufl) { ca->rlen3270 = 0; ca->inpbufl = 0; } } for (i1 = 0; i1 < len; i1++) { c = (unsigned char) bfr[i1]; if (ca->telnet_opt) { ca->telnet_opt = 0; if(ca->dev->ccwtrace) logmsg(_("HHCCA300D %4.4X: Received TELNET CMD 0x%02x 0x%02x\n"), ca->dev->devnum, ca->telnet_cmd, c); bfr3[0] = 0xff; /* IAC */ /* set won't/don't for all received commands */ bfr3[1] = (ca->telnet_cmd == 0xfd) ? 0xfc : 0xfe; bfr3[2] = c; if (ca->sfd > 0) { write_socket(ca->sfd,bfr3,3); } if(ca->dev->ccwtrace) logmsg(_("HHCCA300D %4.4X: Sending TELNET CMD 0x%02x 0x%02x\n"), ca->dev->devnum, bfr3[1], bfr3[2]); continue; } if (ca->telnet_iac) { ca->telnet_iac = 0; if(ca->dev->ccwtrace) logmsg(_("HHCCA300D %4.4X: Received TELNET IAC 0x%02x\n"), ca->dev->devnum, c); switch (c) { case 0xFB: /* TELNET WILL option cmd */ case 0xFD: /* TELNET DO option cmd */ ca->telnet_opt = 1; ca->telnet_cmd = c; break; case 0xF4: /* TELNET interrupt */ if (!ca->telnet_int) { ca->telnet_int = 1; } break; case EOR_MARK: eor = 1; break; case 0xFF: /* IAC IAC */ ca->inpbuf[ca->rlen3270++] = 0xFF; break; } continue; } if (c == 0xFF) { /* TELNET IAC */ ca->telnet_iac = 1; continue; } else { ca->telnet_iac = 0; } if (!ca->is_3270) { if (c == 0x0D) // CR in TTY mode ? ca->eol_flag = 1; c = host_to_guest(c); // translate ASCII to EBCDIC for tty } ca->inpbuf[ca->rlen3270++] = c; } /* received data (rlen3270 > 0) is sufficient for 3270, but for TTY, eol_flag must also be set */ if ((ca->eol_flag || ca->is_3270) && ca->rlen3270) { ca->eol_flag = 0; if (ca->is_3270) { if (eor) { ca->inpbufl = ca->rlen3270; ca->rlen3270 = 0; /* for next msg */ } } else { ca->inpbufl = ca->rlen3270; ca->rlen3270 = 0; /* for next msg */ } if(ca->dev->ccwtrace) logmsg(_("%4.4X: posted %d input bytes\n"),ca->dev->devnum,ca->inpbufl); } } static void *telnet_thread(void *vca) { COMMADPT *ca; int devnum; /* device number copy for convenience*/ int sockopt; /* Used for setsocketoption */ int ca_shutdown=0; /* Thread shutdown internal flag */ int rc; /* return code from various rtns */ struct sockaddr_in sin; /* bind socket address structure */ BYTE bfr[256]; ca=(COMMADPT*)vca; /* get a work copy of devnum (for messages) */ ca->sfd = 0; devnum=ca->devnum; ca->lfd=socket(AF_INET,SOCK_STREAM,0); if(!socket_is_socket(ca->lfd)) { logmsg(_("HHCCA003E %4.4X:Cannot obtain socket for incoming calls : %s\n"),devnum,strerror(HSO_errno)); ca->have_cthread=0; release_lock(&ca->lock); return NULL; } /* Reuse the address regardless of any */ /* spurious connection on that port */ sockopt=1; setsockopt(ca->lfd,SOL_SOCKET,SO_REUSEADDR,(GETSET_SOCKOPT_T*)&sockopt,sizeof(sockopt)); /* Bind the socket */ sin.sin_family=AF_INET; sin.sin_addr.s_addr=ca->lhost; sin.sin_port=htons(ca->lport); while(1) { rc=bind(ca->lfd,(struct sockaddr *)&sin,sizeof(sin)); if(rc<0) { logmsg(_("HHCCA018E %4.4X:Bind failed : %s\n"),devnum,strerror(HSO_errno)); ca_shutdown=1; break; } else { break; } } /* Start the listen */ if(!ca_shutdown) { listen(ca->lfd,10); logmsg(_("HHCCA005I %4.4X:Listening on port %d for incoming TCP connections\n"), devnum, ca->lport); } for (;;) { ca->sfd = 0; ca->sfd=accept(ca->lfd,NULL,0); if (ca->sfd < 1) continue; if (connect_client(&ca->sfd)) { ca->is_3270 = 1; } else { ca->is_3270 = 0; } socket_set_blocking_mode(ca->sfd,0); // set to non-blocking mode if (ca->emu3791 == 0) {make_sna_requests4(ca, 0, (ca->is_3270) ? 0x02 : 0x01);} // send REQCONT ca->hangup = 0; for (;;) { usleep(50000); if (ca->hangup) break; /* read_socket has changed from 3.04 to 3.06 - we need old way */ #ifdef _MSVC_ rc=recv(ca->sfd,bfr,ca->unitsz-BUFPD,0); #else rc=read(ca->sfd,bfr,ca->unitsz-BUFPD); #endif if (rc < 0) { if(0 #ifndef WIN32 || EAGAIN == errno #endif || HSO_EWOULDBLOCK == HSO_errno ) { continue; } break; // make_sna_requests4(ca, 1); // send REQDISCONT if (ca->emu3791 == 0) {make_sna_requests5(ca);} } if (rc == 0) { // make_sna_requests4(ca, 1); // send REQDISCONT if (ca->emu3791 == 0) {make_sna_requests5(ca);} break; } commadpt_read_tty(ca,bfr,rc); } close_socket(ca->sfd); ca->sfd = 0; } } /*-------------------------------------------------------------------*/ /* Communication Thread main loop */ /*-------------------------------------------------------------------*/ static void *commadpt_thread(void *vca) { COMMADPT *ca; /* Work CA Control Block Pointer */ int devnum; /* device number copy for convenience*/ int delay; /* unacknowledged attention delay */ int rc; /* return code from various rtns */ int ca_shutdown; /* Thread shutdown internal flag */ int init_signaled; /* Thread initialisation signaled */ /*---------------------END OF DECLARES---------------------------*/ /* fetch the commadpt structure */ ca=(COMMADPT *)vca; /* Obtain the CA lock */ obtain_lock(&ca->lock); /* get a work copy of devnum (for messages) */ devnum=ca->devnum; /* reset shutdown flag */ ca_shutdown=0; init_signaled=0; logmsg(_("HHCCA002I %4.4X:3705 Communication thread "TIDPAT" started\n"),devnum,thread_id()); for (;;) { release_lock(&ca->lock); if(ca->ackspeed == 0) delay = 50000 + (ca->unack_attn_count * 100000); /* Max's reliable algorithm */ else delay = (ca->unack_attn_count * ca->unack_attn_count + 1) * ca->ackspeed; /* much faster but TCAM hates it */ usleep(min(1000000,delay)); /* go to sleep, max. 1 second */ obtain_lock(&ca->lock); make_sna_requests2(ca); make_sna_requests3(ca); if (ca->sendq // attempt to fix hot i/o bug && ca->unack_attn_count < 10 ) { ca->unack_attn_count++; rc = device_attention(ca->dev, CSW_ATTN); if(ca->dev->ccwtrace) logmsg(_("%4.4X: Raised attention rc = %d\n"), ca->dev->devnum, rc); } } logmsg(_("HHCCA009I %4.4X:3705 utility thread terminated\n"),ca->devnum); release_lock(&ca->lock); return NULL; } /*-------------------------------------------------------------------*/ /* Halt currently executing I/O command */ /*-------------------------------------------------------------------*/ static void commadpt_halt(DEVBLK *dev) { if(!dev->busy) { return; } } /* The following 3 MSG functions ensure only 1 (one) */ /* hardcoded instance exist for the same numbered msg */ /* that is issued on multiple situations */ static void msg013e(DEVBLK *dev,char *kw,char *kv) { logmsg(_("HHCCA013E %4.4X:Incorrect %s specification %s\n"),dev->devnum,kw,kv); } /*-------------------------------------------------------------------*/ /* Device Initialisation */ /*-------------------------------------------------------------------*/ static int commadpt_init_handler (DEVBLK *dev, int argc, char *argv[]) { char thread_name[32]; char thread_name2[32]; int i; int rc; int pc; /* Parse code */ int errcnt; struct in_addr in_temp; union { int num; char text[80]; } res; dev->devtype=0x3705; if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Initialisation starting\n"),dev->devnum); } if(dev->commadpt!=NULL) { commadpt_clean_device(dev); } rc=commadpt_alloc_device(dev); if(rc<0) { logmsg(_("HHCCA010I %4.4X:initialisation not performed\n"), dev->devnum); return(-1); } if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Initialisation : Control block allocated\n"),dev->devnum); } errcnt=0; /* * Initialise ports & hosts */ dev->commadpt->sfd=-1; dev->commadpt->lport=0; dev->commadpt->debug_sna=0; dev->commadpt->emu3791=0; dev->commadpt->locsuba = 0x3800; /* local subarea = 7 (maxsuba=31) */ dev->commadpt->rmtsuba = 0x4000; /* remote subarea = 8 (maxsuba=31) */ strcpy(dev->commadpt->locncpnm,"MHP3705 "); /* local NCP name */ strcpy(dev->commadpt->rmtncpnm,"MHPRMT1 "); /* remote NCP name */ translate_to_ebcdic(dev->commadpt->locncpnm); /* convert to EBCDIC */ translate_to_ebcdic(dev->commadpt->rmtncpnm); /* convert to EBCDIC */ dev->commadpt->idblk = 0x17; /* IDBLK of switched PU (default=0x017) */ dev->commadpt->idnum = 0x17; /* IDNUM of switched PU (default=0x00017) */ dev->commadpt->unitsz = 256; /* I/O blocksize (must equal RRT KEYLN) */ /* unitsz=256 is invalid for TCAM and */ /* instable for VTAM. Default retained */ /* for compatibility with previous */ /* versions only. */ dev->commadpt->ackspeed = 0; /* choose Max's original attn algorithm */ for(i=0;idevnum,argv[i]); errcnt++; continue; } if(pc==0) { logmsg(_("HHCCA012E %4.4X:Unrecognized parameter %s\n"),dev->devnum,argv[i]); errcnt++; continue; } switch(pc) { case COMMADPT_KW_DEBUG: if (res.text[0] == 'y' || res.text[0] == 'Y') dev->commadpt->debug_sna = 1; else dev->commadpt->debug_sna = 0; break; case COMMADPT_KW_LPORT: rc=commadpt_getport(res.text); if(rc<0) { errcnt++; msg013e(dev,"LPORT",res.text); break; } dev->commadpt->lport=rc; break; case COMMADPT_KW_LHOST: if(strcmp(res.text,"*")==0) { dev->commadpt->lhost=INADDR_ANY; break; } rc=commadpt_getaddr(&dev->commadpt->lhost,res.text); if(rc!=0) { msg013e(dev,"LHOST",res.text); errcnt++; } break; case COMMADPT_KW_EMU3791: if(strcasecmp(res.text,"yes")==0 || strcmp(res.text,"1")) dev->commadpt->emu3791=1; break; case COMMADPT_KW_LOCSUBA: dev->commadpt->locsuba = (atoi(res.text)<<11); /* (maxsuba=31) */ break; case COMMADPT_KW_RMTSUBA: dev->commadpt->rmtsuba = (atoi(res.text)<<11); /* (maxsuba=31) */ break; case COMMADPT_KW_LOCNCPNM: strcpy(dev->commadpt->locncpnm," "); strcpy(dev->commadpt->locncpnm,res.text); memcpy(&dev->commadpt->locncpnm[strlen(res.text)]," ",1); translate_to_ebcdic(dev->commadpt->locncpnm); break; case COMMADPT_KW_RMTNCPNM: strcpy(dev->commadpt->rmtncpnm," "); strcpy(dev->commadpt->rmtncpnm,res.text); memcpy(&dev->commadpt->rmtncpnm[strlen(res.text)]," ",1); translate_to_ebcdic(dev->commadpt->rmtncpnm); break; case COMMADPT_KW_IDBLK: sscanf(res.text,"%3x",&dev->commadpt->idblk); break; case COMMADPT_KW_IDNUM: sscanf(res.text,"%5x",&dev->commadpt->idnum); break; case COMMADPT_KW_UNITSZ: dev->commadpt->unitsz = atoi(res.text); break; case COMMADPT_KW_ACKSPEED: dev->commadpt->ackspeed = atoi(res.text); break; default: break; } } if(errcnt>0) { logmsg(_("HHCCA021I %4.4X:Initialisation failed due to previous errors\n"),dev->devnum); return -1; } in_temp.s_addr=dev->commadpt->lhost; dev->bufsize=dev->commadpt->unitsz; dev->numsense=2; memset(dev->sense,0,sizeof(dev->sense)); init_bufpool(dev->commadpt); dev->commadpt->devnum=dev->devnum; /* Initialize the CA lock */ initialize_lock(&dev->commadpt->lock); /* Initialise thread->I/O & halt initiation EVB */ initialize_condition(&dev->commadpt->ipc); initialize_condition(&dev->commadpt->ipc_halt); /* Allocate I/O -> Thread signaling pipe */ create_pipe(dev->commadpt->pipe); /* Point to the halt routine for HDV/HIO/HSCH handling */ dev->halt_device=commadpt_halt; /* Obtain the CA lock */ obtain_lock(&dev->commadpt->lock); /* Start the telnet worker thread */ /* Set thread-name for debugging purposes */ snprintf(thread_name2,sizeof(thread_name2), "commadpt %4.4X thread2",dev->devnum); thread_name2[sizeof(thread_name2)-1]=0; if(create_thread(&dev->commadpt->tthread,&sysblk.detattr,telnet_thread,dev->commadpt,thread_name2)) { logmsg(D_("HHCCA022E create_thread: %s\n"),strerror(errno)); release_lock(&dev->commadpt->lock); return -1; } /* Start the async worker thread */ /* Set thread-name for debugging purposes */ snprintf(thread_name,sizeof(thread_name), "commadpt %4.4X thread",dev->devnum); thread_name[sizeof(thread_name)-1]=0; if(create_thread(&dev->commadpt->cthread,&sysblk.detattr,commadpt_thread,dev->commadpt,thread_name)) { logmsg(D_("HHCCA022E create_thread: %s\n"),strerror(errno)); release_lock(&dev->commadpt->lock); return -1; } dev->commadpt->have_cthread=1; /* Release the CA lock */ release_lock(&dev->commadpt->lock); /* Indicate succesfull completion */ return 0; } /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ static void commadpt_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "LINE", dev, class, buflen, buffer ); snprintf(buffer,buflen,"Read count=%d, Write count=%d", dev->commadpt->read_ccw_count, dev->commadpt->write_ccw_count); } /*-------------------------------------------------------------------*/ /* Close the device */ /* Invoked by HERCULES shutdown & DEVINIT processing */ /*-------------------------------------------------------------------*/ static int commadpt_close_device ( DEVBLK *dev ) { if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Closing down\n"),dev->devnum); } /* Obtain the CA lock */ obtain_lock(&dev->commadpt->lock); /* Terminate current I/O thread if necessary */ if(dev->busy) { commadpt_halt(dev); } free_bufpool(dev->commadpt); /* release the CA lock */ release_lock(&dev->commadpt->lock); /* Free all work storage */ commadpt_clean_device(dev); /* Indicate to hercules the device is no longer opened */ dev->fd=-1; if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:Closed down\n"),dev->devnum); } return 0; } void make_seq (COMMADPT * ca, BYTE * reqptr) { if (reqptr[4] == (ca->locsuba >> 8)) { /* local NCP */ reqptr[6] = (unsigned char)(++ca->ncpa_sscp_seqn >> 8) & 0xff; reqptr[7] = (unsigned char)( ca->ncpa_sscp_seqn ) & 0xff; } else if (reqptr[4] == (ca->rmtsuba >> 8)){ /* remote NCP */ reqptr[6] = (unsigned char)(++ca->ncpb_sscp_seqn >> 8) & 0xff; reqptr[7] = (unsigned char)( ca->ncpb_sscp_seqn ) & 0xff; } } static void format_sna (BYTE * requestp, char * tag, int devnum) { char fmtbuf[32]; char fmtbuf2[32]; char fmtbuf3[32]; char fmtbuf4[32]; char fmtbuf5[256]; char fmtbuf6[32]; char *ru_type=""; int len; sprintf(fmtbuf, "%02X%02X %02X%02X %02X%02X %02X%02X %02X%02X", requestp[0], requestp[1], requestp[2], requestp[3], requestp[4], requestp[5], requestp[6], requestp[7], requestp[8], requestp[9]); sprintf(fmtbuf2, "%02X%02X%02X", requestp[10], requestp[11], requestp[12]); len = (requestp[8] << 8) + requestp[9]; len -= 3; /* for len of ru only */ sprintf(fmtbuf3, "%02X", requestp[13]); sprintf(fmtbuf4, "%02X", requestp[14]); if (len > 1) strcat(fmtbuf3, fmtbuf4); sprintf(fmtbuf4, "%02X", requestp[15]); if (len > 2) strcat(fmtbuf3, fmtbuf4); if (requestp[13] == 0x11) ru_type = "ACTPU"; if (requestp[13] == 0x0D) ru_type = "ACTLU"; if (requestp[13] == 0x0E) ru_type = "DACTLU"; if (requestp[13] == 0x12) ru_type = "DACTPU"; if (requestp[13] == 0xA0) ru_type = "SDT"; if (requestp[13] == 0x31) ru_type = "BIND"; if (requestp[13] == 0x32) ru_type = "UNBIND"; if (!memcmp(&requestp[13], R010201, 3)) ru_type = "CONTACT"; if (!memcmp(&requestp[13], R010202, 3)) ru_type = "DISCONTACT"; if (!memcmp(&requestp[13], R010203, 3)) ru_type = "IPLINIT"; if (!memcmp(&requestp[13], R010204, 3)) ru_type = "IPLTEXT"; if (!memcmp(&requestp[13], R010205, 3)) ru_type = "IPLFINAL"; if (!memcmp(&requestp[13], R01020A, 3)) ru_type = "ACTLINK"; if (!memcmp(&requestp[13], R01020B, 3)) ru_type = "DACTLINK"; if (!memcmp(&requestp[13], R010211, 3)) { sprintf(fmtbuf6, "%s[%02x]", "SETCV", requestp[18]); ru_type = fmtbuf6; if ((requestp[10] & 0x80) != 0) ru_type = "SETCV"; } if (!memcmp(&requestp[13], R010280, 3)) ru_type = "CONTACTED"; if (!memcmp(&requestp[13], R010281, 3)) ru_type = "INOP"; if (!memcmp(&requestp[13], R010284, 3)) ru_type = "REQCONT"; if (!memcmp(&requestp[13], R01021B, 3)) ru_type = "REQDISCONT"; if (!memcmp(&requestp[13], R01021A, 3)) ru_type = "FNA"; if (!memcmp(&requestp[13], R01020F, 3)) ru_type = "ABCONN"; if (!memcmp(&requestp[13], R010219, 3)) ru_type = "ANA"; if (!memcmp(&requestp[13], R010216, 3)) ru_type = "ACTCONNIN"; if (!memcmp(&requestp[13], R010217, 3)) ru_type = "DACTCONNIN"; if ((requestp[10] & 0x08) == 0) ru_type = ""; sprintf(fmtbuf5, "%4.4X: %s: %s %s %-6.6s %s\n", devnum, tag, fmtbuf, fmtbuf2, fmtbuf3, ru_type); logmsg(fmtbuf5); } static void make_sna_requests2 (COMMADPT *ca) { BYTE *respbuf; BYTE *ru_ptr; int ru_size; void *eleptr; int bufp = 0; while (ca->inpbufl > 0) { eleptr = get_bufpool(&ca->freeq); if (!eleptr) { logmsg("no buffers trying to send SNA request2\n"); return; } respbuf = SIZEOF_INT_P + (BYTE*)eleptr; /* first do the ten-byte FID1 TH */ respbuf[0] = 0x1C; respbuf[1] = 0x00; respbuf[2] = ca->tso_addr0; // daf respbuf[3] = ca->tso_addr1; respbuf[4] = ca->lu_addr0; // oaf respbuf[5] = ca->lu_addr1; // oaf respbuf[6] = (unsigned char)(++ca->lu_lu_seqn >> 8) & 0xff; respbuf[7] = (unsigned char)( ca->lu_lu_seqn ) & 0xff; /* do RH */ respbuf[10] = 0x00; if (!bufp) { respbuf[10] |= 0x02; /* set first in chain */ } respbuf[11] = 0x90; respbuf[12] = 0x00; /* do RU */ // FIXME - max. ru_size should be based on BIND settings // A true fix would also require code changes to READ CCW processing // including possibly (gasp) segmenting long PIUs into multiple BTUs // JW: still not fixed but unitsz is now an external parameter // to allow easier modification ru_size = min(ca->unitsz-(BUFPD+10+3),ca->inpbufl); ru_ptr = &respbuf[13]; if (!ca->bindflag) { // send as character-coded logon to SSCP if (ru_size > 0 && (ca->inpbuf[ca->inpbufl-1] == 0x0d || ca->inpbuf[ca->inpbufl-1] == 0x25)) { ru_size--; } if (ru_size > 0 && (ca->inpbuf[ca->inpbufl-1] == 0x0d || ca->inpbuf[ca->inpbufl-1] == 0x25)) { ru_size--; } respbuf[2] = ca->sscp_addr0; respbuf[3] = ca->sscp_addr1; respbuf[11] = 0x80; respbuf[12] = 0x00; } memcpy(ru_ptr, &ca->inpbuf[bufp], ru_size); bufp += ru_size; ca->inpbufl -= ru_size; if (!ca->is_3270) { ca->inpbufl = 0; } if (!ca->inpbufl) { respbuf[10] |= 0x01; /* set last in chain */ if (ca->bindflag) { respbuf[12] |= 0x20; /* set CD */ } } /* set length field in TH */ ru_size += 3; /* for RH */ respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff; respbuf[9] = (unsigned char)(ru_size ) & 0xff; put_bufpool(&ca->sendq, eleptr); } /* end of while (ca->inpbufl > 0) */ } static void make_sna_requests3 (COMMADPT *ca) { BYTE *respbuf; BYTE *ru_ptr; int ru_size; void *eleptr; if (!ca->telnet_int) return; eleptr = get_bufpool(&ca->freeq); if (!eleptr) { logmsg("no buffers trying to send SNA request3\n"); return; } respbuf = SIZEOF_INT_P + (BYTE*)eleptr; /* first do the ten-byte FID1 TH */ respbuf[0] = 0x1D; respbuf[1] = 0x00; respbuf[2] = ca->tso_addr0; // daf respbuf[3] = ca->tso_addr1; respbuf[4] = ca->lu_addr0; // oaf respbuf[5] = ca->lu_addr1; // oaf respbuf[6] = 0x11; respbuf[7] = 0x11; /* do RH */ respbuf[10] = 0x4B; respbuf[11] = 0x80; respbuf[12] = 0x00; /* do RU */ ru_size = 0; ru_ptr = &respbuf[13]; ru_ptr[ru_size++] = 0xc9; // SIG ru_ptr[ru_size++] = 0x00; ru_ptr[ru_size++] = 0x01; ru_size += 3; /* for RH */ respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff; respbuf[9] = (unsigned char)(ru_size ) & 0xff; put_bufpool(&ca->sendq, eleptr); ca->telnet_int = 0; } static void make_sna_requests4 (COMMADPT *ca, int flag, BYTE pu_type) { /* send type flag: 0=REQCONT 1=REQDISCONT */ BYTE *respbuf; BYTE *ru_ptr; int ru_size; U32 stids; void *eleptr; eleptr = get_bufpool(&ca->freeq); if (!eleptr) { logmsg("no buffers trying to send SNA request4\n"); return; } respbuf = SIZEOF_INT_P + (BYTE*)eleptr; /* first do the ten-byte FID1 TH */ respbuf[0] = 0x1C; respbuf[1] = 0x00; respbuf[2] = ca->sscp_addr0; // daf respbuf[3] = ca->sscp_addr1; // set oaf if (flag == 0) { respbuf[4] = ca->ncp_addr0; respbuf[5] = ca->ncp_addr1; make_seq(ca, respbuf); } else { respbuf[4] = ca->pu_addr0; respbuf[5] = ca->pu_addr1; respbuf[6] = 0x00; respbuf[7] = 0x01; } /* do RH */ respbuf[10] = 0x0b; respbuf[11] = 0x00; respbuf[12] = 0x00; /* do RU */ ru_size = 0; ru_ptr = &respbuf[13]; if (flag == 0) { ru_ptr[ru_size++] = 0x01; // REQCONT (REQUEST CONTACT) ru_ptr[ru_size++] = 0x02; ru_ptr[ru_size++] = 0x84; ru_ptr[ru_size++] = (ca->rmtsuba >> 8); // network address of link ru_ptr[ru_size++] = 0x01; ru_ptr[ru_size++] = pu_type; // PU type ru_ptr[ru_size++] = 0x00; stids = ((ca->idblk << 20) & 0xfff00000) | (ca->idnum & 0x000fffff); // 12 bit IDBLK, 20 bit IDNUM ru_ptr[ru_size++] = (stids >> 24) &0xff; ru_ptr[ru_size++] = (stids >> 16) &0xff; ru_ptr[ru_size++] = (stids >> 8) &0xff; ru_ptr[ru_size++] = stids &0xff; } else { ru_ptr[ru_size++] = 0x01; // REQDISCONT (REQUEST DISCONTACT) ru_ptr[ru_size++] = 0x02; ru_ptr[ru_size++] = 0x1B; ru_ptr[ru_size++] = 0x00; } ru_size += 3; /* for RH */ respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff; respbuf[9] = (unsigned char)(ru_size ) & 0xff; put_bufpool(&ca->sendq, eleptr); ca->telnet_int = 0; } static void make_sna_requests5 (COMMADPT *ca) { BYTE *respbuf; BYTE *ru_ptr; int ru_size; void *eleptr; eleptr = get_bufpool(&ca->freeq); if (!eleptr) { logmsg("no buffers trying to send SNA request5\n"); return; } respbuf = SIZEOF_INT_P + (BYTE*)eleptr; /* first do the ten-byte FID1 TH */ respbuf[0] = 0x1C; respbuf[1] = 0x00; respbuf[2] = ca->sscp_addr0; // daf respbuf[3] = ca->sscp_addr1; respbuf[4] = ca->ncp_addr0; // oaf respbuf[5] = ca->ncp_addr1; // set seq no. make_seq(ca, respbuf); /* do RH */ respbuf[10] = 0x0B; respbuf[11] = 0x00; respbuf[12] = 0x00; /* do RU */ ru_size = 0; ru_ptr = &respbuf[13]; ru_ptr[ru_size++] = 0x01; // INOP ru_ptr[ru_size++] = 0x02; ru_ptr[ru_size++] = 0x81; ru_ptr[ru_size++] = ca->pu_addr0; ru_ptr[ru_size++] = ca->pu_addr1; ru_ptr[ru_size++] = 0x01; // format/reason ru_size += 3; /* for RH */ respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff; respbuf[9] = (unsigned char)(ru_size ) & 0xff; put_bufpool(&ca->sendq, eleptr); } void make_sna_requests (BYTE * requestp, COMMADPT *ca) { BYTE *respbuf; BYTE *ru_ptr; int ru_size; void *eleptr; if (memcmp(&requestp[13], R010201, 3)) return; // we only want to process CONTACT eleptr = get_bufpool(&ca->freeq); if (!eleptr) { logmsg("no buffers trying to send SNA request\n"); return; } respbuf = SIZEOF_INT_P + (BYTE*)eleptr; /* first do the ten-byte FID1 TH */ // respbuf[0] = requestp[0]; // respbuf[1] = requestp[1]; respbuf[0] = 0x1c; respbuf[1] = 0x00; respbuf[2] = requestp[4]; // daf respbuf[3] = requestp[5]; respbuf[4] = requestp[2]; // oaf respbuf[5] = requestp[3]; make_seq(ca, respbuf); /* do RH */ respbuf[10] = requestp[10]; respbuf[11] = requestp[11]; respbuf[11] = 0x00; respbuf[12] = requestp[12]; /* make a CONTACTED RU */ ru_size = 0; ru_ptr = &respbuf[13]; ru_ptr[ru_size++] = 0x01; ru_ptr[ru_size++] = 0x02; ru_ptr[ru_size++] = 0x80; ru_ptr[ru_size++] = requestp[16]; ru_ptr[ru_size++] = requestp[17]; ru_ptr[ru_size++] = 0x01; /* set length field in TH */ ru_size += 3; /* for RH */ respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff; respbuf[9] = (unsigned char)(ru_size ) & 0xff; put_bufpool(&ca->sendq, eleptr); } void make_sna_response (BYTE * requestp, COMMADPT *ca) { BYTE *respbuf; BYTE *ru_ptr; int ru_size; void *eleptr; BYTE obuf[4096]; BYTE buf[BUFLEN_3270]; int amt; int i1; if ((requestp[10] & 0x80) != 0) return; // disregard if this is a resp. if ((requestp[10] & (unsigned char)0xfc) == 0x00 && requestp[2] == ca->lu_addr0 && requestp[3] == ca->lu_addr1 && ca->sfd > 0) { /* if type=data, and DAF matches up, and socket exists */ amt = (requestp[8] << 8) + requestp[9]; amt -= 3; if (ca->is_3270) { memcpy(buf, &requestp[13], amt); /* Double up any IAC bytes in the data */ amt = double_up_iac (buf, amt); /* Append telnet EOR marker at end of data */ if ((requestp[10] & 0x01) == 0x01) { /* if last-in-chain is set */ buf[amt++] = IAC; buf[amt++] = EOR_MARK; } /* Send the data to the client */ logdump ("SEND", ca->dev, buf, amt); write_socket(ca->sfd,buf,amt); } else { // convert data portion to ASCII and write to remote user if (amt > 0) { memcpy(obuf, &requestp[13], amt); for (i1=0; i1dev, obuf, amt); write_socket(ca->sfd,obuf,amt); } } } if ((requestp[11] & 0xf0) != 0x80) return; // disregard if not DR1 requested eleptr = get_bufpool(&ca->freeq); if (!eleptr) { logmsg("no buffers trying to send SNA response\n"); return; } respbuf = SIZEOF_INT_P + (BYTE*)eleptr; /* first do the ten-byte FID1 TH */ respbuf[0] = requestp[0]; respbuf[1] = requestp[1]; respbuf[2] = requestp[4]; // daf respbuf[3] = requestp[5]; respbuf[4] = requestp[2]; // oaf respbuf[5] = requestp[3]; respbuf[6] = requestp[6]; // seq # respbuf[7] = requestp[7]; /* do RH */ respbuf[10] = requestp[10]; respbuf[10] |= 0x83; // indicate this is a resp. respbuf[11] = requestp[11]; // respbuf[12] = requestp[12]; respbuf[12] = 0x00; /* do RU */ ru_size = 0; ru_ptr = &respbuf[13]; if ((requestp[10] & 0x08) != 0) ru_ptr[ru_size++] = requestp[13]; if (requestp[13] == 0x11 && requestp[14] == 0x02) { /* ACTPU (NCP)*/ ca->ncp_addr0 = requestp[2]; ca->ncp_addr1 = requestp[3]; // ca->ncp_sscp_seqn = 0; ru_ptr[ru_size++] = 0x02; if (requestp[2] == (ca->rmtsuba >> 8)){ /* remote NCP */ memcpy(&ru_ptr[ru_size],ca->rmtncpnm,8); /* load mod name */ ru_size += 8; ca->ncpb_sscp_seqn = 0; } else if (requestp[2] == (ca->locsuba >> 8)){ /* local NCP */ memcpy(&ru_ptr[ru_size],ca->locncpnm,8); /* load mod name */ ru_size += 8; ca->ncpa_sscp_seqn = 0; } } if (requestp[13] == 0x11 && requestp[14] == 0x01) { /* ACTPU (PU)*/ ru_ptr[ru_size++] = 0x01; /* save daf as our own net addr */ ca->pu_addr0 = requestp[2]; ca->pu_addr1 = requestp[3]; } if (requestp[13] == 0x01) { /* 01XXXX Network Services */ ru_ptr[ru_size++] = requestp[14]; ru_ptr[ru_size++] = requestp[15]; } if (!memcmp(&requestp[13], R010219, 3) && ca->sfd > 0) { /* ANA */ if (!ca->is_3270) { connect_message(ca->sfd, (requestp[20] << 8) + requestp[21], 0); } } if (requestp[13] == 0x0D) { /* ACTLU */ /* save daf as our own net addr */ ca->lu_addr0 = requestp[2]; ca->lu_addr1 = requestp[3]; /* save oaf as our sscp net addr */ ca->sscp_addr0 = requestp[4]; ca->sscp_addr1 = requestp[5]; ca->lu_sscp_seqn = 0; ca->bindflag = 0; } if (requestp[13] == 0x0E || !memcmp(&requestp[13], R01020F, 3)) { // DACTLU or ABCONN if (!ca->is_3270) { connect_message(ca->sfd, 0, 1); } ca->hangup = 1; } if (requestp[13] == 0x31) { /* BIND */ /* save oaf from BIND request */ ca->tso_addr0 = requestp[4]; ca->tso_addr1 = requestp[5]; ca->lu_lu_seqn = 0; ca->bindflag = 1; } if (requestp[13] == 0x32 && requestp[14] != 0x02) { /* BIND */ ca->bindflag = 0; } #if 0 if (requestp[13] == 0x32 && requestp[14] == 0x01 && ca->sfd > 0) { /* UNBIND */ close_socket(ca->sfd); ca->sfd=-1; } #endif /* set length field in TH */ ru_size += 3; /* for RH */ respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff; respbuf[9] = (unsigned char)(ru_size ) & 0xff; put_bufpool(&ca->sendq, eleptr); } enum fid_remap { MAP_FID1_FID2, MAP_FID2_FID1 }; static void th_remap(enum fid_remap r, BYTE * thptr, U16 locsuba) { /* for 3791 support, remaps SNA FID1 <--> FID2 TH headers */ int thmpf; int thm2; int thdaf; int thoaf; int thsnf; int len; if (r == MAP_FID1_FID2) { thmpf = thptr[0]; thm2 = thptr[1]; thdaf = (thptr[2] << 8) + thptr[3]; thoaf = (thptr[4] << 8) + thptr[5]; thsnf = (thptr[6] << 8) + thptr[7]; len = (thptr[8] << 8) + thptr[9]; len += 10; thptr[0] = (len >> 8) & 0xff; thptr[1] = len & 0xff; thptr[2] = 0x00; thptr[3] = 0x00; thptr[4] = 0x20 | (thmpf & 0x0f); thptr[5] = thm2; thptr[6] = thdaf & 0xff; thptr[7] = thoaf & 0xff; thptr[8] = (thsnf >> 8) & 0xff; thptr[9] = thsnf & 0xff; } else { /* map fid2 to fid1 */ len = (thptr[0] << 8) + thptr[1]; thmpf = thptr[4]; thm2 = thptr[5]; thdaf = thptr[6]; thoaf = thptr[7]; thsnf = (thptr[8] << 8) + thptr[9]; thdaf |= locsuba; thoaf |= 0x0800; /* SSCP subarea = 1 (maxsuba=31) */ len -= 10; thptr[0] = 0x10 | (thmpf & 0x0f); thptr[1] = thm2; thptr[2] = (thdaf >> 8) & 0xff; thptr[3] = thdaf & 0xff; thptr[4] = (thoaf >> 8) & 0xff; thptr[5] = thoaf & 0xff; thptr[6] = (thsnf >> 8) & 0xff; thptr[7] = thsnf & 0xff; thptr[8] = (len >> 8) & 0xff; thptr[9] = len & 0xff; } } /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ static void commadpt_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual) { U32 num; /* Work : Actual CCW transfer count */ BYTE *piudata; int piusize; void *eleptr; int llsize; UNREFERENCED(flags); UNREFERENCED(chained); UNREFERENCED(prevcode); UNREFERENCED(ccwseq); *residual = 0; /* * Obtain the COMMADPT lock */ if(dev->ccwtrace) { logmsg(_("HHCCA300D %4.4X:CCW Exec - Entry code = %x\n"),dev->devnum,code); } obtain_lock(&dev->commadpt->lock); switch (code) { /*---------------------------------------------------------------*/ /* BASIC SENSE */ /*---------------------------------------------------------------*/ case 0x04: dev->commadpt->unack_attn_count = 0; num=countnumsense?count:dev->numsense; *more=countnumsense?1:0; memcpy(iobuf,dev->sense,num); *residual=count-num; *unitstat=CSW_CE|CSW_DE; break; /*---------------------------------------------------------------*/ /* READ type CCWs */ /*---------------------------------------------------------------*/ case 0x02: /* READ */ dev->commadpt->read_ccw_count++; dev->commadpt->unack_attn_count = 0; *more = 0; make_sna_requests2(dev->commadpt); make_sna_requests3(dev->commadpt); eleptr = get_bufpool(&dev->commadpt->sendq); *residual=count; if (eleptr) { piudata = SIZEOF_INT_P + (BYTE*)eleptr; piusize = (piudata[8] << 8) + piudata[9]; piusize += 10; // for FID1 TH iobuf[0] = BUFPD; memcpy (&iobuf[BUFPD], piudata, piusize); if (dev->commadpt->emu3791) { llsize = piusize + BUFPD; iobuf[0] = (llsize >> 8) & 0xff; iobuf[1] = llsize & 0xff; th_remap(MAP_FID1_FID2, &iobuf[BUFPD], dev->commadpt->locsuba); } *residual=count - (piusize + BUFPD); logdump("READ", dev, &iobuf[BUFPD], piusize); if (dev->commadpt->debug_sna) format_sna(piudata, "RD", dev->devnum); put_bufpool(&dev->commadpt->freeq, eleptr); } *unitstat=CSW_CE|CSW_DE; #if 0 if (dev->commadpt->sendq) { *unitstat|=CSW_ATTN; } #endif *unitstat|=CSW_UX; break; /*---------------------------------------------------------------*/ /* 3791 WRITE BLOCK */ /*---------------------------------------------------------------*/ case 0x05: logdump("WRITE BLOCK", dev, iobuf, count); *residual=0; *unitstat=CSW_CE|CSW_DE; break; /*---------------------------------------------------------------*/ /* WRITE type CCWs */ /*---------------------------------------------------------------*/ case 0x09: /* WRITE BREAK */ case 0x01: /* WRITE */ dev->commadpt->write_ccw_count++; dev->commadpt->unack_attn_count = 0; logdump("WRITE", dev, iobuf, count); if (dev->commadpt->emu3791 && (iobuf[4] & 0xf0) == 0x20) th_remap(MAP_FID2_FID1, iobuf, dev->commadpt->locsuba); if ((iobuf[0] & 0xf0) == 0x10) { // if FID1 if (dev->commadpt->debug_sna) format_sna(iobuf, "WR", dev->devnum); make_sna_response(iobuf, dev->commadpt); make_sna_requests(iobuf, dev->commadpt); } *residual=0; *unitstat=CSW_CE|CSW_DE; #if 0 if (dev->commadpt->sendq) { *unitstat|=CSW_ATTN; *unitstat|=CSW_UX|CSW_ATTN; } #endif break; /*---------------------------------------------------------------*/ /* CCWs to be treated as NOPs */ /*---------------------------------------------------------------*/ case 0x03: /* NOP */ case 0x93: /* RESTART */ case 0x31: /* WS0 */ case 0x51: /* WS1 */ case 0x32: /* RS0 */ case 0x52: /* RS1 */ *residual=count; *unitstat=CSW_CE|CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ *unitstat=CSW_CE+CSW_DE+CSW_UC; dev->sense[0]=SENSE_CR; break; } release_lock(&dev->commadpt->lock); } /*---------------------------------------------------------------*/ /* DEVICE FUNCTION POINTERS */ /*---------------------------------------------------------------*/ #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND com3705_device_hndinfo = { &commadpt_init_handler, /* Device Initialisation */ &commadpt_execute_ccw, /* Device CCW execute */ &commadpt_close_device, /* Device Close */ &commadpt_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ commadpt_immed_command, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdt3705_LTX_hdl_ddev #define hdl_depc hdt3705_LTX_hdl_depc #define hdl_reso hdt3705_LTX_hdl_reso #define hdl_init hdt3705_LTX_hdl_init #define hdl_fini hdt3705_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); } END_DEPENDENCY_SECTION; #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR( psysblk, sysblk ); } END_RESOLVER_SECTION; #endif HDL_DEVICE_SECTION; { HDL_DEVICE(3705, com3705_device_hndinfo ); } END_DEVICE_SECTION; #endif hercules-3.12/hdteq.c0000664000175000017500000000531512564723224011460 00000000000000/* HDTEQ.C (c) Copyright Jan Jaeger, 2003-2009 */ /* Hercules Dynamic Loader */ #include "hstdinc.h" #include "hercules.h" typedef struct _DTEQ { char *alias; char *name; } DTEQ; static DTEQ dteq[] = { /* This table provides aliases for device types, such that various device types may be mapped to a common loadable module. The only purpose of this table is to associate the right loadable module with a specific device type, before the device type in question has been registered. This table will not be searched for registered device types or if the specific loadable module exists. device type requested | | base device support | | V V */ // { "3390", "3990" }, // { "3380", "3990" }, { "1052", "3270" }, { "3215", "3270" }, { "3287", "3270" }, { "SYSG", "3270" }, { "1052-C", "1052c" }, { "3215-C", "1052c" }, { "1442", "3505" }, { "2501", "3505" }, { "3211", "1403" }, { "3410", "3420" }, { "3411", "3420" }, // { "3420", "3420" }, { "3480", "3420" }, { "3490", "3420" }, { "3590", "3420" }, { "9347", "3420" }, { "9348", "3420" }, { "8809", "3420" }, { "3422", "3420" }, { "3430", "3420" }, { "LCS", "3088" }, { "CTCI", "3088" }, { "CTCT", "3088" }, { "CTCE", "3088" }, { "VMNET", "3088" }, { "HCHAN", "2880" }, // { "2880", "2880" }, { "2870", "2880" }, { "2860", "2880" }, { "9032", "2880" }, { NULL, NULL } }; #if defined(OPTION_DYNAMIC_LOAD) static char *hdt_device_type_equates(char *typname) { DTEQ *device_type; char *(*nextcall)(char *); for(device_type = dteq; device_type->name; device_type++) if(!strcasecmp(device_type->alias, typname)) return device_type->name; if((nextcall = HDL_FINDNXT(hdt_device_type_equates))) return nextcall(typname); return NULL; } /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ /* for use in DLREOPEN case only */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdteq_LTX_hdl_ddev #define hdl_depc hdteq_LTX_hdl_depc #define hdl_reso hdteq_LTX_hdl_reso #define hdl_init hdteq_LTX_hdl_init #define hdl_fini hdteq_LTX_hdl_fini #endif HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); } END_DEPENDENCY_SECTION HDL_REGISTER_SECTION; { HDL_REGISTER(hdl_device_type_equates,hdt_device_type_equates); } END_REGISTER_SECTION #endif hercules-3.12/qeth.c0000664000175000017500000003016212564723224011312 00000000000000/* QETH.C (c) Copyright Jan Jaeger, 2004-2009 */ /* OSA Express */ /* This module contains device handling functions for the */ /* OSA Express emulated card */ /* Device module hdtqeth.dll devtype QETH (config) */ /* hercules.cnf: */ /* 0A00-0A02 QETH */ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) SYSBLK *psysblk; #define sysblk (*psysblk) #endif static BYTE sense_id_bytes[] = { 0xff, 0x17, 0x31, 0x01, /* D/T */ 0x17, 0x32, 0x01, /* CU/T */ 0x00, 0x40, 0xfa, 0x01, 0x00, /* RCD CIW */ 0x03, 0xfc, 0x01, 0x00, /*Ena Q CIW */ 0x04, 0xfd, 0x01, 0x00 /* Act Q CIW */ }; /*-------------------------------------------------------------------*/ /* Initialize the device handler */ /*-------------------------------------------------------------------*/ static int qeth_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { UNREFERENCED(argc); UNREFERENCED(argv); logmsg(D_("dev(%4.4x) experimental driver\n"),dev->devnum); dev->numdevid = sizeof(sense_id_bytes); logmsg(D_("senseidnum=%d\n"),dev->numdevid); memcpy(dev->devid, sense_id_bytes, sizeof(sense_id_bytes)); dev->devtype = dev->devid[1] << 8 | dev->devid[2]; dev->pmcw.flag4 |= PMCW4_Q; if(!group_device(dev,3)) { logmsg(D_("group device(%4.4x) pending\n"),dev->devnum); return 0; } else { int i; logmsg(D_("group = ( ")); for(i = 0; i < dev->group->acount; i++) logmsg("%4.4x ",dev->group->memdev[i]->devnum); logmsg(") complete\n"); } return 0; } /* end function qeth_init_handler */ /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ static void qeth_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "QETH", dev, class, buflen, buffer ); snprintf (buffer, buflen, "\n"); } /* end function qeth_query_device */ /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ static int qeth_close_device ( DEVBLK *dev ) { UNREFERENCED(dev); /* Close the device file */ return 0; } /* end function qeth_close_device */ /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ static void qeth_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { int rc = 0; /* Return code */ int num; /* Number of bytes to move */ int blocksize = 1024; #define CONFIG_DATA_SIZE 1024 UNREFERENCED(flags); UNREFERENCED(prevcode); UNREFERENCED(ccwseq); UNREFERENCED(chained); UNREFERENCED(rc); UNREFERENCED(blocksize); /* Process depending on CCW opcode */ switch (code) { case 0x01: /*---------------------------------------------------------------*/ /* WRITE */ /*---------------------------------------------------------------*/ logmsg(D_("Write dev(%4.4x)\n"),dev->devnum); #define WR_SIZE 0x22 /* Calculate number of bytes to read and set residual count */ num = (count < WR_SIZE) ? count : WR_SIZE; *residual = count - num; if (count < WR_SIZE) *more = 1; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x02: /*---------------------------------------------------------------*/ /* READ */ /*---------------------------------------------------------------*/ logmsg(D_("Read dev(%4.4x)\n"),dev->devnum); #define RD_SIZE 0x22 /* Calculate number of bytes to read and set residual count */ num = (count < RD_SIZE) ? count : RD_SIZE; *residual = count - num; if (count < RD_SIZE) *more = 1; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x03: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ logmsg(D_("NOP dev(%4.4x)\n"),dev->devnum); *residual = 0; *unitstat = CSW_CE | CSW_DE; break; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ logmsg(D_("Sense dev(%4.4x)\n"),dev->devnum); /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ logmsg(D_("Sense ID dev(%4.4x)\n"),dev->devnum); /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xFA: /*---------------------------------------------------------------*/ /* READ CONFIGURATION DATA */ /*---------------------------------------------------------------*/ logmsg(D_("Read Configuration Data dev(%4.4x)\n"),dev->devnum); /* Calculate residual byte count */ num = (count < CONFIG_DATA_SIZE) ? count : CONFIG_DATA_SIZE; *residual = count - num; if (count < CONFIG_DATA_SIZE) *more = 1; /* Clear the configuration data area */ memset (iobuf, 0x00, CONFIG_DATA_SIZE); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xFC: /*---------------------------------------------------------------*/ /* ESTABLISH QUEUES */ /*---------------------------------------------------------------*/ logmsg(D_("Establish Queues dev(%4.4x)\n"),dev->devnum); /* Calculate residual byte count */ num = (count < CONFIG_DATA_SIZE) ? count : CONFIG_DATA_SIZE; *residual = count - num; if (count < CONFIG_DATA_SIZE) *more = 1; memset (iobuf, 0x00, CONFIG_DATA_SIZE); /* INCOMPLETE ZZ * QUEUES MUST BE SETUP HERE */ /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xFD: /*---------------------------------------------------------------*/ /* ACTIVATE QUEUES */ /*---------------------------------------------------------------*/ logmsg(D_("Activate Queues dev(%4.4x)\n"),dev->devnum); /* Calculate residual byte count */ num = (count < CONFIG_DATA_SIZE) ? count : CONFIG_DATA_SIZE; *residual = count - num; if (count < CONFIG_DATA_SIZE) *more = 1; memset (iobuf, 0x00, CONFIG_DATA_SIZE); /* INCOMPLETE ZZ * QUEUES MUST BE HANDLED HERE, THIS CCW WILL ONLY EXIT * IN CASE OF AN ERROR OR A HALT, CLEAR OR CANCEL SIGNAL */ /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ logmsg(D_("Unkown CCW dev(%4.4x) code(%2.2x)\n"),dev->devnum,code); /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ } /* end function qeth_execute_ccw */ /*-------------------------------------------------------------------*/ /* Signal Adapter Initiate Input */ /*-------------------------------------------------------------------*/ static int qeth_initiate_input(DEVBLK *dev, U32 qmask) { UNREFERENCED(qmask); logmsg(D_("SIGA-r dev(%4.4x) qmask(%8.8x)\n"),dev->devnum); return 0; } /*-------------------------------------------------------------------*/ /* Signal Adapter Initiate Output */ /*-------------------------------------------------------------------*/ static int qeth_initiate_output(DEVBLK *dev, U32 qmask) { UNREFERENCED(qmask); logmsg(D_("SIGA-w dev(%4.4x) qmask(%8.8x)\n"),dev->devnum); return 0; } #if defined(OPTION_DYNAMIC_LOAD) static #endif DEVHND qeth_device_hndinfo = { &qeth_init_handler, /* Device Initialisation */ &qeth_execute_ccw, /* Device CCW execute */ &qeth_close_device, /* Device Close */ &qeth_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ NULL, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ NULL, /* Device Suspend channel pgm */ NULL, /* Device Read */ NULL, /* Device Write */ NULL, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ &qeth_initiate_input, /* Signal Adapter Input */ &qeth_initiate_output, /* Signal Adapter Output */ NULL, /* Hercules suspend */ NULL /* Hercules resume */ }; /* Libtool static name colision resolution */ /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */ #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL) #define hdl_ddev hdtqeth_LTX_hdl_ddev #define hdl_depc hdtqeth_LTX_hdl_depc #define hdl_reso hdtqeth_LTX_hdl_reso #define hdl_init hdtqeth_LTX_hdl_init #define hdl_fini hdtqeth_LTX_hdl_fini #endif #if defined(OPTION_DYNAMIC_LOAD) HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); } END_DEPENDENCY_SECTION #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_) #undef sysblk HDL_RESOLVER_SECTION; { HDL_RESOLVE_PTRVAR( psysblk, sysblk ); } END_RESOLVER_SECTION #endif HDL_DEVICE_SECTION; { HDL_DEVICE(QETH, qeth_device_hndinfo ); } END_DEVICE_SECTION #endif hercules-3.12/hconsole.c0000664000175000017500000010465212564723224012171 00000000000000/* HCONSOLE.C (c) Copyright "Fish" (David B. Trout), 2005-2009 */ /* Hercules console panel support functions */ ////////////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. ////////////////////////////////////////////////////////////////////////////////////////// #include "hstdinc.h" #include "hercules.h" #include "hconsole.h" ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// #if defined( _MSVC_ ) ////////////////////////////////////////////////////////////////////////////////////////// // 'save_and_set' = 1 --> just what it says; 0 --> restore from saved value. static DWORD g_dwConsoleInputMode = 0; // (saved value so we can later restore it) static DWORD g_dwConsoleOutputMode = 0; // (saved value so we can later restore it) static WORD g_wDefaultAttrib = 0; // (saved value so we can later restore it) static WORD default_FG_color() { return g_wDefaultAttrib & 0x0F; } static WORD default_BG_color() { return (g_wDefaultAttrib >> 4) & 0x0F; } int set_or_reset_console_mode( int keybrd_fd, short save_and_set ) { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hStdIn, hStdErr; DWORD dwNewInputMode; DWORD dwNewOutputMode; if ( ! _isatty( keybrd_fd ) ) { errno = EBADF; return -1; } hStdIn = (HANDLE) _get_osfhandle( keybrd_fd ); ASSERT( hStdIn && INVALID_HANDLE_VALUE != hStdIn ); hStdErr = GetStdHandle( STD_ERROR_HANDLE ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); if ( save_and_set ) { VERIFY( GetConsoleMode( hStdIn, &g_dwConsoleInputMode ) ); VERIFY( GetConsoleMode( hStdErr, &g_dwConsoleOutputMode ) ); VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) ); g_wDefaultAttrib = csbi.wAttributes; dwNewInputMode = 0; dwNewOutputMode = 0; } else // (restore/reset) { VERIFY( SetConsoleTextAttribute( hStdErr, g_wDefaultAttrib ) ); dwNewInputMode = g_dwConsoleInputMode; dwNewOutputMode = g_dwConsoleOutputMode; } VERIFY( SetConsoleMode( hStdIn, dwNewInputMode ) ); VERIFY( SetConsoleMode( hStdErr, dwNewOutputMode ) ); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // Translate Herc color to Win32 color... #define W32_FOREGROUND_COLOR( w32_color ) ( ( w32_color ) ) #define W32_BACKGROUND_COLOR( w32_color ) ( ( w32_color ) << 4 ) #define W32_COLOR_BLACK ( 0 ) #define W32_COLOR_RED ( FOREGROUND_RED ) #define W32_COLOR_GREEN ( FOREGROUND_GREEN ) #define W32_COLOR_BLUE ( FOREGROUND_BLUE ) #define W32_COLOR_CYAN ( FOREGROUND_GREEN | FOREGROUND_BLUE ) #define W32_COLOR_MAGENTA ( FOREGROUND_RED | FOREGROUND_BLUE ) #define W32_COLOR_YELLOW ( FOREGROUND_RED | FOREGROUND_GREEN ) #define W32_COLOR_LIGHT_GREY ( FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE ) #define W32_COLOR_DARK_GREY ( FOREGROUND_INTENSITY | W32_COLOR_BLACK ) #define W32_COLOR_LIGHT_RED ( FOREGROUND_INTENSITY | W32_COLOR_RED ) #define W32_COLOR_LIGHT_GREEN ( FOREGROUND_INTENSITY | W32_COLOR_GREEN ) #define W32_COLOR_LIGHT_BLUE ( FOREGROUND_INTENSITY | W32_COLOR_BLUE ) #define W32_COLOR_LIGHT_CYAN ( FOREGROUND_INTENSITY | W32_COLOR_CYAN ) #define W32_COLOR_LIGHT_MAGENTA ( FOREGROUND_INTENSITY | W32_COLOR_MAGENTA ) #define W32_COLOR_LIGHT_YELLOW ( FOREGROUND_INTENSITY | W32_COLOR_YELLOW ) #define W32_COLOR_WHITE ( FOREGROUND_INTENSITY | W32_COLOR_LIGHT_GREY ) static WORD W32_COLOR( short herc_color ) { switch ( herc_color ) { case COLOR_BLACK: return W32_COLOR_BLACK; case COLOR_RED: return W32_COLOR_RED; case COLOR_GREEN: return W32_COLOR_GREEN; case COLOR_BLUE: return W32_COLOR_BLUE; case COLOR_CYAN: return W32_COLOR_CYAN; case COLOR_MAGENTA: return W32_COLOR_MAGENTA; case COLOR_YELLOW: return W32_COLOR_YELLOW; case COLOR_DARK_GREY: return W32_COLOR_DARK_GREY; case COLOR_LIGHT_GREY: return W32_COLOR_LIGHT_GREY; case COLOR_LIGHT_RED: return W32_COLOR_LIGHT_RED; case COLOR_LIGHT_GREEN: return W32_COLOR_LIGHT_GREEN; case COLOR_LIGHT_BLUE: return W32_COLOR_LIGHT_BLUE; case COLOR_LIGHT_CYAN: return W32_COLOR_LIGHT_CYAN; case COLOR_LIGHT_MAGENTA: return W32_COLOR_LIGHT_MAGENTA; case COLOR_LIGHT_YELLOW: return W32_COLOR_LIGHT_YELLOW; case COLOR_WHITE: return W32_COLOR_WHITE; case COLOR_DEFAULT_BG: return default_BG_color(); case COLOR_DEFAULT_FG: return default_FG_color(); case COLOR_DEFAULT_LIGHT: return default_FG_color() | FOREGROUND_INTENSITY; default: return default_FG_color(); } } ////////////////////////////////////////////////////////////////////////////////////////// int set_screen_color ( FILE* confp, short herc_fore, short herc_back ) { HANDLE hStdErr; WORD wColor; int cons_fd; if ( !confp ) { errno = EINVAL; return -1; } if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } hStdErr = (HANDLE) _get_osfhandle( cons_fd ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); wColor = 0 | W32_FOREGROUND_COLOR( W32_COLOR( herc_fore ) ) | W32_BACKGROUND_COLOR( W32_COLOR( herc_back ) ) ; VERIFY( SetConsoleTextAttribute( hStdErr, wColor ) ); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // screen positions are 1-based; row 1 == top line; col 1 == leftmost column int set_screen_pos( FILE* confp, short rowY1, short colX1 ) { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hStdErr; COORD ptConsole; int cons_fd; if ( !confp ) { errno = EINVAL; return -1; } if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } hStdErr = (HANDLE) _get_osfhandle( cons_fd ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) ); // Note: ANSI escape codes are 1-based, whereas // SetConsoleCursorPosition values are 0-based... if (0 || colX1 < 1 || colX1 > csbi.dwSize.X || rowY1 < 1 || rowY1 > csbi.dwSize.Y ) { errno = EINVAL; return -1; } ptConsole.X = colX1 - 1; ptConsole.Y = rowY1 - 1; VERIFY( SetConsoleCursorPosition( hStdErr, ptConsole ) ); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // (From KB article 99261) int clear_screen( FILE* confp ) { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hStdErr; DWORD dwNumCells, dwCellsWritten; COORD ptConsole = { 0, 0 }; int cons_fd; if ( !confp ) { errno = EINVAL; return -1; } if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } hStdErr = (HANDLE) _get_osfhandle( cons_fd ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) ); dwNumCells = csbi.dwSize.X * csbi.dwSize.Y; VERIFY( FillConsoleOutputCharacter( hStdErr, ' ', dwNumCells, ptConsole, &dwCellsWritten ) ); VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) ); VERIFY( FillConsoleOutputAttribute( hStdErr, csbi.wAttributes, dwNumCells, ptConsole, &dwCellsWritten ) ); VERIFY( SetConsoleCursorPosition ( hStdErr, ptConsole ) ); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// int erase_to_eol( FILE* confp ) { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hStdErr; DWORD dwCellsWritten; COORD ptConsole; int cons_fd; if ( !confp ) { errno = EINVAL; return -1; } if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } hStdErr = (HANDLE) _get_osfhandle( cons_fd ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); VERIFY( GetConsoleScreenBufferInfo( hStdErr, &csbi ) ); ptConsole = csbi.dwCursorPosition; VERIFY( FillConsoleOutputAttribute( hStdErr, csbi.wAttributes, csbi.dwSize.X - ptConsole.X, ptConsole, &dwCellsWritten ) ); VERIFY( FillConsoleOutputCharacter( hStdErr, ' ', csbi.dwSize.X - ptConsole.X, ptConsole, &dwCellsWritten ) ); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // Handles key presses that result in TWO characters being generated... void translate_keystroke( char kbbuf[], int* pkblen ) { BYTE ch = kbbuf[0]; // (move char to work var) switch ( ch ) // Check if special key pressed... { case 0x0D: // enter key kbbuf[0] = '\n'; // change to newline character // fall thru to default case default: // no further translation needed break; // accept the keystroke as-is // translate special key (escape sequence)... case 0x00: // 1st char of special key press case 0xE0: // 1st char of special key press { BYTE orig_ch, ch2; if ( !kbhit() ) // if not two chars generated, break; // then not special key press orig_ch = ch; // save original keystroke ch = '\x1B'; // change it to an escape char ch2 = getch(); // get second keystroke of pair switch ( ch2 ) // generate ANSI escape sequence { case 0x47: strcpy( kbbuf, KBD_HOME ); break; case 0x52: strcpy( kbbuf, KBD_INSERT ); break; case 0x53: strcpy( kbbuf, KBD_DELETE ); break; case 0x4F: strcpy( kbbuf, KBD_END ); break; case 0x49: strcpy( kbbuf, KBD_PAGE_UP ); break; case 0x51: strcpy( kbbuf, KBD_PAGE_DOWN ); break; case 0x48: strcpy( kbbuf, KBD_UP_ARROW ); break; case 0x50: strcpy( kbbuf, KBD_DOWN_ARROW ); break; case 0x4D: strcpy( kbbuf, KBD_RIGHT_ARROW ); break; case 0x4B: strcpy( kbbuf, KBD_LEFT_ARROW ); break; case 0x77: strcpy( kbbuf, KBD_CTRL_HOME ); break; case 0x75: strcpy( kbbuf, KBD_CTRL_END ); break; case 0x8D: strcpy( kbbuf, KBD_CTRL_UP_ARROW ); break; case 0x91: strcpy( kbbuf, KBD_CTRL_DOWN_ARROW ); break; case 0x98: strcpy( kbbuf, KBD_ALT_UP_ARROW ); break; case 0xA0: strcpy( kbbuf, KBD_ALT_DOWN_ARROW ); break; case 0x9D: strcpy( kbbuf, KBD_ALT_RIGHT_ARROW ); break; case 0x9B: strcpy( kbbuf, KBD_ALT_LEFT_ARROW ); break; default: { #if 0 kbbuf[0] = '\x1B'; kbbuf[1] = ch2; kbbuf[2] = 0; #else /* EAT IT */ kbbuf[0] = 0; kbbuf[1] = 0; kbbuf[2] = 0; #endif break; } // end default } // end switch( ch2 ) *pkblen = strlen( kbbuf ); // inform caller #of chars break; } // end case: 0x00, 0xE0 } // end switch( ch ) } ////////////////////////////////////////////////////////////////////////////////////////// int console_beep( FILE* confp ) { int cons_fd; if ( !confp ) { errno = EINVAL; return -1; } if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } MessageBeep(-1); return 0; } ////////////////////////////////////////////////////////////////////////////////////////// #ifdef OPTION_EXTCURS int get_cursor_pos( int keybrd_fd, FILE* confp, short* row, short* col ) { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hStdErr; int cons_fd; UNREFERENCED( keybrd_fd ); if ( !confp || !row || !col ) { errno = EINVAL; return -1; } if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } hStdErr = (HANDLE) _get_osfhandle( cons_fd ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); if ( !GetConsoleScreenBufferInfo( hStdErr, &csbi ) ) { errno = EIO; return -1; } *row = 1 + csbi.dwCursorPosition.Y; *col = 1 + csbi.dwCursorPosition.X; return 0; } #endif // OPTION_EXTCURS ////////////////////////////////////////////////////////////////////////////////////////// int get_console_dim( FILE* confp, int* rows, int* cols ) { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hStdErr; int cons_fd; if ( !confp || !rows || !cols ) { errno = EINVAL; return -1; } *rows = *cols = 0; if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } hStdErr = (HANDLE) _get_osfhandle( cons_fd ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); if ( !GetConsoleScreenBufferInfo( hStdErr, &csbi ) ) { errno = EIO; return -1; } *rows = 1 + csbi.srWindow.Bottom - csbi.srWindow.Top; *cols = 1 + csbi.srWindow.Right - csbi.srWindow.Left; return 0; } ////////////////////////////////////////////////////////////////////////////////////////// int set_console_cursor_shape( FILE* confp, int ins ) { CONSOLE_CURSOR_INFO ci; HANDLE hStdErr; int cons_fd; if ( !confp ) { errno = EINVAL; return -1; } if ( ! _isatty( cons_fd = fileno( confp ) ) ) { errno = EBADF; return -1; } hStdErr = (HANDLE) _get_osfhandle( cons_fd ); ASSERT( hStdErr && INVALID_HANDLE_VALUE != hStdErr ); ci.bVisible = TRUE; ci.dwSize = ins ? 20 : 100; // (note: values are percent of cell height) if ( !SetConsoleCursorInfo( hStdErr, &ci ) ) { errno = EIO; return -1; } return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // From KB article 124103: "How To Obtain a Console Window Handle (HWND)" // http://support.microsoft.com/?kbid=124103 #define MAX_WINDOW_TITLE_LEN (256) // (purely arbitrary) static TCHAR g_szOriginalTitle[ MAX_WINDOW_TITLE_LEN ] = {0}; int w32_set_console_title( char* pszTitle ) { TCHAR szNewTitleBuff [ MAX_WINDOW_TITLE_LEN ]; LPCTSTR pszNewTitle = NULL; if (!g_szOriginalTitle[0]) VERIFY(GetConsoleTitle( g_szOriginalTitle, MAX_WINDOW_TITLE_LEN )); if (pszTitle) { _sntprintf( szNewTitleBuff, MAX_WINDOW_TITLE_LEN-1, _T("%hs"), pszTitle ); szNewTitleBuff[MAX_WINDOW_TITLE_LEN-1]=0; pszNewTitle = szNewTitleBuff; } else pszNewTitle = g_szOriginalTitle; if (!SetConsoleTitle( pszNewTitle )) { errno = GetLastError(); return -1; } return 0; } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// #else // !defined( WIN32 ) #ifdef HAVE_TERMIOS_H static struct termios saved_kbattr; // (saved value so we can later restore it) #endif // 'save_and_set' = 1 --> just what it says; 0 --> restore from saved value. int set_or_reset_console_mode( int keybrd_fd, short save_and_set ) { #ifdef HAVE_TERMIOS_H struct termios kbattr; if ( save_and_set ) { // Put the terminal into cbreak mode tcgetattr( keybrd_fd, &saved_kbattr ); // (save for later restore) kbattr = saved_kbattr; // (make copy) kbattr.c_lflag &= ~(ECHO | ICANON); // (set desired values...) kbattr.c_cc[VMIN] = 0; kbattr.c_cc[VTIME] = 0; tcsetattr( keybrd_fd, TCSANOW, &kbattr ); } else { // Restore the terminal mode tcsetattr( STDIN_FILENO, TCSANOW, &saved_kbattr ); // (restore prev value) } #else UNREFERENCED( keybrd_fd ); UNREFERENCED( save_and_set ); #endif return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // screen positions are 1-based; row 1 == top line; col 1 == leftmost column int set_screen_pos( FILE* confp, short rowY1, short colX1 ) { #define ANSI_POSITION_CURSOR "\x1B[%d;%dH" return ( fprintf( confp, ANSI_POSITION_CURSOR, rowY1, colX1 ) ? 0 : -1 ); } ////////////////////////////////////////////////////////////////////////////////////////// int erase_to_eol( FILE* confp ) { #define ANSI_ERASE_EOL "\x1B[K" return ( fprintf( confp, ANSI_ERASE_EOL ) ? 0 : -1 ); } ////////////////////////////////////////////////////////////////////////////////////////// int clear_screen( FILE* confp ) { #define ANSI_ERASE_SCREEN "\x1B[2J" return ( fprintf( confp, ANSI_ERASE_SCREEN ) ? 0 : -1 ); } ////////////////////////////////////////////////////////////////////////////////////////// /* From: (http://www.vtt.fi/tte/EuroBridge/Xew/iso6429.html) CSI (Control Sequence Introducer) = "\033[" or "\233" SGR (Select Graphic Rendition) = CSI Ps1;Ps2;... m SGR (Select Graphic Rendition): CSI Ps ... 0x6d (Note: 0x6d = ASCII 'm') SGR is used to establish one or more graphic rendition aspects for subsequent text. The established aspects remain in effect until the next occurrence of SGR in the data stream, depending on the setting of the GRAPHIC RENDITION COMBINATION MODE (GRCM). The implementation assumes the GRCM = CUMULATIVE (that is, each aspect will be in effect until explicitly cancelled by another SGR). -------------------------------------------------------------------------- Ps Description -------------------------------------------------------------------------- 0 default rendition; cancel all preceding occurrences of SGR; invoke primary font. 1 bold or increased intensity 2 faint <------<<< Fish: non-standard, but apparently anyway (based on other documents I've seen) 3 italicized 4 underlined 7 negative image 9 crossed out 10 primary (default) font 11-19 first to ninth alternative fonts (see also fonts) 21 doubly underlined 22 normal intensity (neither bold nor faint) 23 not italicized 24 not underlined (neither singly or doubly) 27 positive image 29 not crossed out 30-37 foreground color of the text; 30=black, 31=red, 32=green, 33=yellow, 34=blue, 35=magenta, 36=cyan, 37=white. 39 default foreground text color (foreground color of the widget) 40-47 background color of the text; 40=black, 41=red, 42=green, 43=yellow, 44=blue, 45=magenta, 46=cyan, 47=white. 49 default background text color (background color of the widget) 51 framed (see FrameRendition) 53 overlined [not implemented yet] 54 not framed, not encircled 55 not overlined [not implemented yet] -------------------------------------------------------------------------- "\033[m" Reset "\033[0m" Reset "\033[1m" Bold "\033[2m" Faint <------<<< Fish: non-standard, but apparently anyway (based on other documents I've seen) "\033[3m" Italic "\033[4m" Underline "\033[7m" Inverse "\033[9m" Crossed out "\033[10m" primary font "\033[11m" 1st alternate font "\033[12m" 2nd alternate font "\033[13m" 3rd alternate font "\033[14m" 4th alternate font "\033[15m" 5th alternate font "\033[16m" 6th alternate font "\033[17m" 7th alternate font "\033[18m" 8th alternate font "\033[19m" 9th alternate font "\033[21m" Double underline "\033[22m" Bold off "\033[23m" Italic off "\033[24m" Underline off (double or single) "\033[27m" Inverse off "\033[29m" Crossed out off "\033[30m" Black foreground "\033[31m" Red foreground "\033[32m" Green foreground "\033[33m" Yellow foreground "\033[34m" Blue foreground "\033[35m" Magenta foreground "\033[36m" Cyan foreground "\033[37m" White foreground "\033[39m" Default foreground "\033[40m" Black background "\033[41m" Red background "\033[42m" Green background "\033[43m" Yellow background "\033[44m" Blue background "\033[45m" Magenta background "\033[46m" Cyan background "\033[47m" White background "\033[49m" Default background "\033[51m" Framed on "\033[54m" Framed off */ ////////////////////////////////////////////////////////////////////////////////////////// // Translate Herc color to ANSI/ISO-6429 (ECMA-48) color... // High-order byte is attribute (0=normal, 1=bold), low-order byte is color. #define ISO_COLOR_BLACK ( 30 ) #define ISO_COLOR_RED ( 31 ) #define ISO_COLOR_GREEN ( 32 ) #define ISO_COLOR_YELLOW ( 33 ) #define ISO_COLOR_BLUE ( 34 ) #define ISO_COLOR_MAGENTA ( 35 ) #define ISO_COLOR_CYAN ( 36 ) #define ISO_COLOR_WHITE ( 37 ) #define ISO_COLOR_DEFAULT ( 39 ) #define ISO_NORMAL( iso_color ) ( ( 0x0000 ) | ( (uint16_t)( iso_color ) ) ) #define ISO_BRIGHT( iso_color ) ( ( 0x0100 ) | ( (uint16_t)( iso_color ) ) ) #define ISO_IS_ISO_BRIGHT( iso_color ) ( ( ( iso_color ) >> 8 ) & 0x01 ) // PROGRAMMING NOTE: the '2' (faint/dim) and '22' (bold-off) // attribute codes are UNRELIABLE. They are apparently rarely // implemented properly on many platforms (Cygwin included). // Thus we prefer to use the more reliable (but programmatically // bothersome) '0' (reset) attribute instead [whenever we wish // to paint a 'dim/faint' (non-bold) color]. As a result however, // we need to be careful to paint the foregoround/background // colors in the proper sequence/order and in the proper manner. // See the below 'set_screen_color' function for details. (Fish) //#define ISO_NORMAL_OR_BRIGHT( iso_color ) ISO_IS_ISO_BRIGHT( iso_color ) ? 1 : 22 //#define ISO_NORMAL_OR_BRIGHT( iso_color ) ISO_IS_ISO_BRIGHT( iso_color ) ? 1 : 2 #define ISO_NORMAL_OR_BRIGHT( iso_color ) ISO_IS_ISO_BRIGHT( iso_color ) ? 1 : 0 #define ISO_FOREGROUND_COLOR( iso_color ) ( ( ( iso_color ) & 0x00FF ) ) #define ISO_BACKGROUND_COLOR( iso_color ) ( ( ( iso_color ) & 0x00FF ) + 10 ) static uint16_t ISO_COLOR( short herc_color ) { switch ( herc_color ) { case COLOR_BLACK: return ISO_NORMAL( ISO_COLOR_BLACK ); case COLOR_RED: return ISO_NORMAL( ISO_COLOR_RED ); case COLOR_GREEN: return ISO_NORMAL( ISO_COLOR_GREEN ); case COLOR_BLUE: return ISO_NORMAL( ISO_COLOR_BLUE ); case COLOR_CYAN: return ISO_NORMAL( ISO_COLOR_CYAN ); case COLOR_MAGENTA: return ISO_NORMAL( ISO_COLOR_MAGENTA ); case COLOR_YELLOW: return ISO_NORMAL( ISO_COLOR_YELLOW ); case COLOR_DARK_GREY: return ISO_BRIGHT( ISO_COLOR_BLACK ); case COLOR_LIGHT_GREY: return ISO_NORMAL( ISO_COLOR_WHITE ); case COLOR_LIGHT_RED: return ISO_BRIGHT( ISO_COLOR_RED ); case COLOR_LIGHT_GREEN: return ISO_BRIGHT( ISO_COLOR_GREEN ); case COLOR_LIGHT_BLUE: return ISO_BRIGHT( ISO_COLOR_BLUE ); case COLOR_LIGHT_CYAN: return ISO_BRIGHT( ISO_COLOR_CYAN ); case COLOR_LIGHT_MAGENTA: return ISO_BRIGHT( ISO_COLOR_MAGENTA ); case COLOR_LIGHT_YELLOW: return ISO_BRIGHT( ISO_COLOR_YELLOW ); case COLOR_WHITE: return ISO_BRIGHT( ISO_COLOR_WHITE ); case COLOR_DEFAULT_FG: return ISO_NORMAL( ISO_COLOR_DEFAULT ); case COLOR_DEFAULT_BG: return ISO_NORMAL( ISO_COLOR_DEFAULT ); case COLOR_DEFAULT_LIGHT: return ISO_BRIGHT( ISO_COLOR_DEFAULT ); default: return ISO_NORMAL( ISO_COLOR_DEFAULT ); } } ////////////////////////////////////////////////////////////////////////////////////////// // Translate Herc color to ANSI/ISO-6429 (ECMA-48) SGR terminal escape sequence... int set_screen_color( FILE* confp, short herc_fore, short herc_back ) { uint16_t iso_fore, iso_back; uint16_t iso_bold_color, iso_dim_color; int rc; // Translate Herc color to ANSI (ISO) color... iso_fore = ISO_COLOR( herc_fore ); iso_back = ISO_COLOR( herc_back ); // PROGRAMMING NOTE: Because the only means we have to RELIABLY // set non-bold (faint/dim) color attributes across ALL platforms // is to use the '0' (reset) escape code (which of course has the // unfortunate(?) side-effect of resetting BOTH the background // AND foreground colors to dim/faint instead of just one or the // other), we need to be careful to always set the dim (NON-bold) // color attribute FIRST (which will of course reset both the fore- // ground AND the backgound colors to non-bold/faint/dim as well), // and then to, AFTERWARDS, set the BOLD color attribute. This is // the ONLY way I've been able to discover (empirically via trial // and error) how to RELIABLY set bold/faint foreground/background // color attributes across all(?) supported platforms. (Fish) if ( ISO_IS_ISO_BRIGHT(iso_fore) == ISO_IS_ISO_BRIGHT(iso_back) ) { // BOTH the foreground color AND the background colors // are either BOTH bold or BOTH dim/faint (normal)... rc = fprintf ( confp, // Set the bold/dim attribute FIRST and then // BOTH foreground/background colors afterwards... "\x1B[%d;%d;%dm" ,ISO_NORMAL_OR_BRIGHT( iso_back ) ,ISO_BACKGROUND_COLOR( iso_back ) ,ISO_FOREGROUND_COLOR( iso_fore ) ); } else // ( ISO_IS_ISO_BRIGHT(iso_fore) != ISO_IS_ISO_BRIGHT(iso_back) ) { // ONE of either the foreground OR background colors // is bold, but the OTHER one is dim/faint (normal)... if ( ISO_IS_ISO_BRIGHT(iso_fore) ) { // The foregound color is the bright/bold one... iso_bold_color = ISO_FOREGROUND_COLOR( iso_fore ); iso_dim_color = ISO_BACKGROUND_COLOR( iso_back ); } else // ( !ISO_IS_ISO_BRIGHT(iso_fore) ) { // The background color is the bright/bold one... iso_bold_color = ISO_BACKGROUND_COLOR( iso_back ); iso_dim_color = ISO_FOREGROUND_COLOR( iso_fore ); } // Set whichever is the DIM color attribute FIRST // and then AFTERWARDS whichever one is the BOLD... rc = fprintf ( confp, "\x1B[0;%d;1;%dm" // (reset, dim-color, bold, bold-color) ,iso_dim_color ,iso_bold_color ); } return rc < 0 ? -1 : 0; } ////////////////////////////////////////////////////////////////////////////////////////// void translate_keystroke( char kbbuf[], int* pkblen ) { UNREFERENCED( kbbuf ); UNREFERENCED( pkblen ); return; } ////////////////////////////////////////////////////////////////////////////////////////// int console_beep( FILE* confp ) { return fprintf( confp, "\a" ) < 0 ? -1 : 0; } ////////////////////////////////////////////////////////////////////////////////////////// int get_console_dim( FILE* confp, int* rows, int* cols ) { char* env; #if defined(TIOCGWINSZ) struct winsize winsize; #else UNREFERENCED( confp ); #endif if ( !rows || !cols ) { errno = EINVAL; return -1; } #if defined(TIOCGWINSZ) if (ioctl(fileno(confp), TIOCGWINSZ, &winsize) >= 0) { *rows = winsize.ws_row; *cols = winsize.ws_col; } else #endif { if (!(env = getenv( "LINES" ))) *rows = 24; else *rows = atoi(env); if (!(env = getenv( "COLUMNS" ))) *cols = 80; else *cols = atoi(env); } if (!*rows || !*cols) { errno = EIO; return -1; } return 0; } ////////////////////////////////////////////////////////////////////////////////////////// #ifdef OPTION_EXTCURS int get_cursor_pos( int keybrd_fd, FILE* confp, short* row, short* col ) { struct timeval tv; /* Select timeout structure */ fd_set readset; /* Select file descriptors */ char kbbuf[16]; /* Keyboard i/p buffer */ char* semi; /* Index of semicolon */ int kblen; /* Number of chars in kbbuf */ int maxfd; /* Highest file descriptor */ int rc; /* Return code */ char c; /* Work for scanf */ /* Request the CPR (Cursor Position Report) */ if ( fprintf( confp, KBD_ASK_CURSOR_POS ) < 0 ) return -1; /* Read the CPR from the keyboard i/p buffer */ while (1) { FD_ZERO (&readset); FD_SET (keybrd_fd, &readset); maxfd = keybrd_fd; tv.tv_sec = 0; tv.tv_usec = 50 * 1000; // (PLENTY long enough!) /* Wait for CPR to arrive in our i/p buffer */ rc = select (maxfd + 1, &readset, NULL, NULL, &tv); if (rc < 0 ) { if (errno == EINTR) continue; errno = EIO; break; } /* If keyboard input has arrived then process it */ if (!FD_ISSET(keybrd_fd, &readset)) continue; /* Read character(s) from the keyboard */ kblen = read (keybrd_fd, kbbuf, sizeof(kbbuf)-1); if (kblen < 0) { errno = EIO; break; } kbbuf[kblen] = 0; // The returned CPR is the string "\x1B[n;mR" // where n = decimal row, m = decimal column. // Note: we expect the entire the CPR to have // been read on our first i/o (i.e. for it to // have arrived all at once in one piece) and // not piecemeal requiring several i/o's... if (0 || kblen < 6 || kbbuf[ 0 ] != '\x1B' || kbbuf[ 1 ] != '[' || kbbuf[kblen-1] != 'R' || (semi = memchr( kbbuf, ';', kblen )) == NULL || (semi - kbbuf) < 3 || sscanf( &kbbuf[2], "%hu%c", row, &c ) != 2 || c != ';' || sscanf( semi+1, "%hu%c", col, &c ) != 2 || c != 'R' ) { errno = EIO; rc = -1; break; } /* Success! */ rc = 0; break } return rc; } #endif // OPTION_EXTCURS ////////////////////////////////////////////////////////////////////////////////////////// /* From: (http://groups-beta.google.com/group/comp.protocols.kermit.misc/msg/1cc3ec6f0bfc0084) VGA-softcursor.txt, from the 2.2 kernel Software cursor for VGA by Pavel Machek ======================= and Martin Mares Linux now has some ability to manipulate cursor appearance. Normally, you can set the size of hardware cursor (and also work around some ugly bugs in those miserable Trident cards--see #define TRIDENT_GLITCH in drivers/video/ vgacon.c). You can now play a few new tricks: you can make your cursor look like a non-blinking red block, make it inverse background of the character it's over or to highlight that character and still choose whether the original hardware cursor should remain visible or not. There may be other things I have never thought of. The cursor appearance is controlled by a "[?1;2;3c" escape sequence where 1, 2 and 3 are parameters described below. If you omit any of them, they will default to zeroes. Parameter 1 specifies cursor size (0=default, 1=invisible, 2=underline, ..., 8=full block) + 16 if you want the software cursor to be applied + 32 if you want to always change the background color + 64 if you dislike having the background the same as the foreground. Highlights are ignored for the last two flags. The second parameter selects character attribute bits you want to change (by simply XORing them with the value of this parameter). On standard VGA, the high four bits specify background and the low four the foreground. In both groups, low three bits set color (as in normal color codes used by the console) and the most significant one turns on highlight (or sometimes blinking--it depends on the configuration of your VGA). The third parameter consists of character attribute bits you want to set. Bit setting takes place before bit toggling, so you can simply clear a bit by including it in both the set mask and the toggle mask. Examples: ========= To get normal blinking underline, use: echo -e '\033[?2c' To get blinking block, use: echo -e '\033[?6c' To get red non-blinking block, use: echo -e '\033[?17;0;64c' */ int set_console_cursor_shape( FILE* confp, int ins ) { #if SET_CONSOLE_CURSOR_SHAPE_METHOD == CURSOR_SHAPE_NOT_SUPPORTED UNREFERENCED( confp ); UNREFERENCED( ins ); return 0; #elif SET_CONSOLE_CURSOR_SHAPE_METHOD == CURSOR_SHAPE_VIA_SPECIAL_LINUX_ESCAPE #define LINUX_UNDER_BLINK_CURSOR "\x1B[?2c" #define LINUX_BLINK_BLOCK_CURSOR "\x1B[?6c" return fprintf( confp, ins ? LINUX_UNDER_BLINK_CURSOR : LINUX_BLINK_BLOCK_CURSOR ); #else #error Invalid #defined SET_CONSOLE_CURSOR_SHAPE_METHOD value return -1; #endif } ////////////////////////////////////////////////////////////////////////////////////////// #endif // defined( WIN32 ) ////////////////////////////////////////////////////////////////////////////////////////// hercules-3.12/w32util.c0000664000175000017500000031311712564723224011666 00000000000000////////////////////////////////////////////////////////////////////////////////////////// // w32util.c Windows porting functions ////////////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. ////////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT PROGRAMMING NOTE! // // Please see the "VERY IMPORTANT SPECIAL NOTE" comments accompanying the // select, fdopen, etc, #undef's in the Windows Socket Handling section!! // ////////////////////////////////////////////////////////////////////////////////////////// #include "hstdinc.h" #define _W32UTIL_C_ #define _HUTIL_DLL_ #include "hercules.h" #if defined( _MSVC_ ) /////////////////////////////////////////////////////////////////////////////// // Support for disabling of CRT Invalid Parameter Handler... #if defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) static void DummyCRTInvalidParameterHandler ( const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved ) { // Do nothing to cause CRT to simply ignore the invalid parameter // and to instead just pass back the return code to the caller. } static _invalid_parameter_handler old_iph = NULL; static int prev_rm = 0; // This function's sole purpose is to bypass Microsoft's default handling of // invalid parameters being passed to CRT functions, which ends up causing // two completely different assertion dialogs to appear for each problem DLL_EXPORT void DisableInvalidParameterHandling() { if ( old_iph ) return; old_iph = _set_invalid_parameter_handler( DummyCRTInvalidParameterHandler ); #if defined(DEBUG) || defined(_DEBUG) prev_rm = _CrtSetReportMode( _CRT_ASSERT, 0 ); #endif } DLL_EXPORT void EnableInvalidParameterHandling() { if ( !old_iph ) return; _set_invalid_parameter_handler( old_iph ); old_iph = NULL; #if defined(DEBUG) || defined(_DEBUG) _CrtSetReportMode( _CRT_ASSERT, prev_rm ); #endif } #endif // defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) ////////////////////////////////////////////////////////////////////////////////////////// struct ERRNOTAB { DWORD dwLastError; // Win32 error from GetLastError() int nErrNo; // corresponding 'errno' value }; typedef struct ERRNOTAB ERRNOTAB; // PROGRAMMING NOTE: we only need to translate values which // are in the same range as existing defined errno values. If // the Win32 GetLastError() value is outside the defined errno // value range, then we just use the raw GetLastError() value. // The current 'errno' value range is 0 - 43, so only those // GetLastError() values (defined in winerror.h) which are 43 // or less need to be remapped. ERRNOTAB w32_errno_tab[] = { { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, { ERROR_ACCESS_DENIED, EACCES }, { ERROR_INVALID_HANDLE, EBADF }, { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, { ERROR_OUTOFMEMORY, ENOMEM }, { ERROR_INVALID_DRIVE, ENOENT }, { ERROR_WRITE_PROTECT, EACCES }, { ERROR_NOT_READY, EIO }, { ERROR_CRC, EIO }, { ERROR_WRITE_FAULT, EIO }, { ERROR_READ_FAULT, EIO }, { ERROR_GEN_FAILURE, EIO }, { ERROR_SHARING_VIOLATION, EACCES }, }; #define NUM_ERRNOTAB_ENTRIES (sizeof(w32_errno_tab)/sizeof(w32_errno_tab[0])) ////////////////////////////////////////////////////////////////////////////////////////// // Translates a Win32 '[WSA]GetLastError()' value into a 'errno' value (if possible // and/or if needed) that can then be used in the below 'w32_strerror' string function... DLL_EXPORT int w32_trans_w32error( const DWORD dwLastError ) { int i; for ( i=0; i < NUM_ERRNOTAB_ENTRIES; i++ ) if ( dwLastError == w32_errno_tab[i].dwLastError ) return w32_errno_tab[i].nErrNo; return (int) dwLastError; } ////////////////////////////////////////////////////////////////////////////////////////// // ("unsafe" version -- use "safer" 'w32_strerror_r' instead if possible) DLL_EXPORT char* w32_strerror( int errnum ) { static char szMsgBuff[ 256 ]; // (s/b plenty big enough) w32_strerror_r( errnum, szMsgBuff, sizeof(szMsgBuff) ); return szMsgBuff; } ////////////////////////////////////////////////////////////////////////////////////////// // Handles both regular 'errno' values as well as [WSA]GetLastError() values too... DLL_EXPORT int w32_strerror_r( int errnum, char* buffer, size_t buffsize ) { // Route all 'errno' values outside the normal CRT (C Runtime) error // message table range to the Win32 'w32_w32errmsg' function instead. // Otherwise simply use the CRT's error message table directly... if ( !buffer || !buffsize ) return -1; if ( errnum >= 0 && errnum < _sys_nerr ) { // Use CRT's error message table directly... strlcpy( buffer, _sys_errlist[ errnum ], buffsize ); } else { // 'errno' value is actually a Win32 [WSA]GetLastError value... w32_w32errmsg( errnum, buffer, buffsize ); } return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // Return Win32 error message text associated with an error number value // as returned by a call to either GetLastError() or WSAGetLastError()... DLL_EXPORT char* w32_w32errmsg( int errnum, char* pszBuffer, size_t nBuffSize ) { DWORD dwBytesReturned = 0; DWORD dwBuffSize = (DWORD)nBuffSize; ASSERT( pszBuffer && nBuffSize ); dwBytesReturned = FormatMessageA ( 0 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , NULL, errnum, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), pszBuffer, dwBuffSize, NULL ); ASSERT( dwBytesReturned ); // (remove trailing whitespace) { char* p = pszBuffer + dwBytesReturned - 1; while ( p >= pszBuffer && isspace(*p) ) p--; *++p = 0; } return pszBuffer; } ////////////////////////////////////////////////////////////////////////////////////////// // Large File Support... #if (_MSC_VER < 1400) //---------------------------------------------------------------------------------------- #if defined( _POSIX_ ) // (promote/demote long to/from __int64) #define FPOS_T_TO_INT64(pos) ((__int64)(pos)) #define INT64_TO_FPOS_T(i64,pos) ((pos) = (long)(i64)) #if _INTEGRAL_MAX_BITS < 64 #pragma message( MSVC_MESSAGE_LINENUM "warning: fseek/ftell use offset arguments of insufficient size" ) #endif #else #if !__STDC__ && _INTEGRAL_MAX_BITS >= 64 // (already __int64!) #define FPOS_T_TO_INT64(pos) (pos) #define INT64_TO_FPOS_T(i64,pos) ((pos) = (i64)) #else // (construct an __int64 from fpos_t structure members and vice-versa) #define FPOS_T_TO_INT64(pos) ((__int64)(((unsigned __int64)(pos).hipart << 32) | \ (unsigned __int64)(pos).lopart)) #define INT64_TO_FPOS_T(i64,pos) ((pos).hipart = (int)((i64) >> 32), \ (pos).lopart = (unsigned int)(i64)) #endif #endif //---------------------------------------------------------------------------------------- DLL_EXPORT __int64 w32_ftelli64 ( FILE* stream ) { fpos_t pos; if ( fgetpos( stream, &pos ) != 0 ) return -1; else return FPOS_T_TO_INT64( pos ); } //---------------------------------------------------------------------------------------- DLL_EXPORT int w32_fseeki64 ( FILE* stream, __int64 offset, int origin ) { __int64 offset_from_beg; fpos_t pos; if (SEEK_CUR == origin) { if ( (offset_from_beg = w32_ftelli64( stream )) < 0 ) return -1; offset_from_beg += offset; } else if (SEEK_END == origin) { struct stat fst; if ( fstat( fileno( stream ), &fst ) != 0 ) return -1; offset_from_beg = (__int64)fst.st_size + offset; } else if (SEEK_SET == origin) { offset_from_beg = offset; } else { errno = EINVAL; return -1; } INT64_TO_FPOS_T( offset_from_beg, pos ); return fsetpos( stream, &pos ); } //---------------------------------------------------------------------------------------- DLL_EXPORT int w32_ftrunc64 ( int fd, __int64 new_size ) { HANDLE hFile; int rc = 0, save_errno; __int64 old_pos, old_size; if ( new_size < 0 ) { errno = EINVAL; return -1; } hFile = (HANDLE) _get_osfhandle( fd ); if ( (HANDLE) -1 == hFile ) { errno = EBADF; // (probably not a valid opened file descriptor) return -1; } // The value of the seek pointer shall not be modified by a call to ftruncate(). if ( ( old_pos = _telli64( fd ) ) < 0 ) return -1; // PROGRAMMING NOTE: from here on, all errors // need to goto error_return to restore the original // seek pointer... if ( ( old_size = _lseeki64( fd, 0, SEEK_END ) ) < 0 ) { rc = -1; goto error_return; } // pad with zeros out to new_size if needed rc = 0; // (think positively) if ( new_size > old_size ) { #define ZEROPAD_BUFFSIZE ( 128 * 1024 ) BYTE zeros[ZEROPAD_BUFFSIZE]; size_t write_amount = sizeof(zeros); memset( zeros, 0, sizeof(zeros) ); do { write_amount = min( sizeof(zeros), ( new_size - old_size ) ); if ( !WriteFile( hFile, zeros, write_amount, NULL, NULL ) ) { errno = (int) GetLastError(); rc = -1; break; } } while ( ( old_size += write_amount ) < new_size ); save_errno = errno; ASSERT( old_size == new_size || rc < 0 ); errno = save_errno; } if ( rc < 0 ) goto error_return; // set the new file size (eof) if ( _lseeki64( fd, new_size, SEEK_SET ) < 0 ) { rc = -1; goto error_return; } if ( !SetEndOfFile( hFile ) ) { errno = (int) GetLastError(); rc = -1; goto error_return; } rc = 0; // success! error_return: // restore the original seek pointer and return save_errno = errno; _lseeki64( fd, old_pos, SEEK_SET ); errno = save_errno; return rc; } #endif // (_MSC_VER < 1400) ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( HAVE_FORK ) DLL_EXPORT pid_t fork( void ) { errno = ENOTSUP; return -1; // *** NOT SUPPORTED *** } #endif ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( HAVE_SCHED_YIELD ) DLL_EXPORT int sched_yield ( void ) { Sleep(0); return 0; } #endif ////////////////////////////////////////////////////////////////////////////////////////// // Win32's runtime library functions are reentrant as long as you link // with one of the multi-threaded libraries (i.e. LIBCMT, MSVCRT, etc.) #if !defined( HAVE_STRTOK_R ) DLL_EXPORT char* strtok_r ( char* s, const char* sep, char** lasts ) { UNREFERENCED( lasts ); return strtok( s, sep ); } #endif ////////////////////////////////////////////////////////////////////////////////////////// // Can't use "HAVE_SLEEP" since Win32's "Sleep" causes HAVE_SLEEP to // be erroneously #defined due to autoconf AC_CHECK_FUNCS case issues... //#if !defined( HAVE_SLEEP ) DLL_EXPORT unsigned sleep ( unsigned seconds ) { Sleep( seconds * 1000 ); return 0; } //#endif ////////////////////////////////////////////////////////////////////////////////////////// // high resolution sleep #if !defined( HAVE_NANOSLEEP ) || !defined( HAVE_USLEEP ) static int w32_nanosleep ( const struct timespec* rqtp ) { /* DESCRIPTION The nanosleep() function shall cause the current thread to be suspended from execution until either the time interval specified by the rqtp argument has elapsed or a signal is delivered to the calling thread, and its action is to invoke a signal-catching function or to terminate the process. The suspension time may be longer than requested because the argument value is rounded up to an integer multiple of the sleep resolution or because of the scheduling of other activity by the system. But, except for the case of being interrupted by a signal, the suspension time shall not be less than the time specified by rqtp, as measured by the system clock CLOCK_REALTIME. The use of the nanosleep() function has no effect on the action or blockage of any signal. RETURN VALUE If the nanosleep() function returns because the requested time has elapsed, its return value shall be zero. If the nanosleep() function returns because it has been interrupted by a signal, it shall return a value of -1 and set errno to indicate the interruption. If the rmtp argument is non-NULL, the timespec structure referenced by it is updated to contain the amount of time remaining in the interval (the requested time minus the time actually slept). If the rmtp argument is NULL, the remaining time is not returned. If nanosleep() fails, it shall return a value of -1 and set errno to indicate the error. ERRORS The nanosleep() function shall fail if: [EINTR] The nanosleep() function was interrupted by a signal. [EINVAL] The rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million. */ static BOOL bDidInit = FALSE; static HANDLE hTimer = NULL; LARGE_INTEGER liDueTime; // Create the waitable timer if needed... if (unlikely( !bDidInit )) { bDidInit = TRUE; VERIFY( ( hTimer = CreateWaitableTimer( NULL, TRUE, NULL ) ) != NULL ); } // Check passed parameters... if (unlikely(!rqtp || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000 )) { errno = EINVAL; return -1; } // Note: Win32 waitable timers: parameter is #of 100-nanosecond intervals. // Positive values indicate absolute UTC time. Negative values indicate // relative time. The actual timer accuracy depends on the capability // of your hardware. liDueTime.QuadPart = -( // (negative means relative) (((__int64)rqtp->tv_sec * 10000000)) + (((__int64)rqtp->tv_nsec + 99) / 100) ); // Set the waitable timer... VERIFY( SetWaitableTimer( hTimer, &liDueTime, 0, NULL, NULL, FALSE ) ); // Wait for the waitable timer to expire... VERIFY( WaitForSingleObject( hTimer, INFINITE ) == WAIT_OBJECT_0 ); return 0; } #endif ////////////////////////////////////////////////////////////////////////////////////////// // nanosleep - high resolution sleep #if !defined( HAVE_NANOSLEEP ) DLL_EXPORT int nanosleep ( const struct timespec* rqtp, struct timespec* rmtp ) { if (unlikely(rmtp)) { rmtp->tv_sec = 0; rmtp->tv_nsec = 0; } return w32_nanosleep ( rqtp ); } #endif ////////////////////////////////////////////////////////////////////////////////////////// // usleep - suspend execution for an interval #if !defined( HAVE_USLEEP ) DLL_EXPORT int usleep ( useconds_t useconds ) { // "The useconds argument shall be less than one million. If the value of // useconds is 0, then the call has no effect." // "Implementations may place limitations on the granularity of timer values. // For each interval timer, if the requested timer value requires a finer // granularity than the implementation supports, the actual timer value shall // be rounded up to the next supported value." // "Upon successful completion, usleep() shall return 0; otherwise, it shall // return -1 and set errno to indicate the error." // "The usleep() function may fail if: // // [EINVAL] The time interval specified // one million or more microseconds" struct timespec rqtp; if (unlikely( useconds < 0 || useconds >= 1000000 )) { errno = EINVAL; return -1; } rqtp.tv_sec = 0; rqtp.tv_nsec = useconds * 1000; return w32_nanosleep ( &rqtp ); } #endif ////////////////////////////////////////////////////////////////////////////////////////// // gettimeofday... #if !defined( HAVE_GETTIMEOFDAY ) // Number of 100-nanosecond units from 1 Jan 1601 to 1 Jan 1970 #define EPOCH_BIAS 116444736000000000ULL // Helper function to convert Windows system-time value to microseconds... static LARGE_INTEGER FileTimeToMicroseconds( const FILETIME* pFT ) { LARGE_INTEGER liWork; // (work area) // Copy value to be converted to work area liWork.HighPart = pFT->dwHighDateTime; liWork.LowPart = pFT->dwLowDateTime; // Convert to 100-nanosecond units since 1 Jan 1970 liWork.QuadPart -= EPOCH_BIAS; // Convert to microseconds since 1 Jan 1970 liWork.QuadPart /= (LONGLONG) 10; return liWork; } DLL_EXPORT int gettimeofday ( struct timeval* pTV, void* pTZ ) { LARGE_INTEGER liCurrentHPCValue; // (high-performance-counter tick count) static LARGE_INTEGER liStartingHPCValue; // (high-performance-counter tick count) static LARGE_INTEGER liStartingSystemTime; // (time of last resync in microseconds) static struct timeval tvPrevSyncVal = {0,0}; // (time of last resync as timeval) static struct timeval tvPrevRetVal = {0,0}; // (previously returned value) static double dHPCTicksPerMicrosecond; // (just what it says) static BOOL bInSync = FALSE; // (work flag) UNREFERENCED(pTZ); // One-time (and periodic!) initialization... if (unlikely( !bInSync )) { FILETIME ftStartingSystemTime; LARGE_INTEGER liHPCTicksPerSecond; // The "GetSystemTimeAsFileTime" function obtains the current system date // and time. The information is in Coordinated Universal Time (UTC) format. GetSystemTimeAsFileTime( &ftStartingSystemTime ); VERIFY( QueryPerformanceCounter( &liStartingHPCValue ) ); VERIFY( QueryPerformanceFrequency( &liHPCTicksPerSecond ) ); dHPCTicksPerMicrosecond = (double) liHPCTicksPerSecond.QuadPart / 1000000.0; liStartingSystemTime = FileTimeToMicroseconds( &ftStartingSystemTime ); tvPrevSyncVal.tv_sec = 0; // (to force init further below) tvPrevSyncVal.tv_usec = 0; // (to force init further below) bInSync = TRUE; } // The following check for user error must FOLLOW the above initialization // code block so the above initialization code block ALWAYS gets executed! if (unlikely( !pTV )) return EFAULT; // Query current high-performance counter value... VERIFY( QueryPerformanceCounter( &liCurrentHPCValue ) ); // Calculate elapsed HPC ticks... liCurrentHPCValue.QuadPart -= liStartingHPCValue.QuadPart; // Convert to elapsed microseconds... liCurrentHPCValue.QuadPart = (LONGLONG) ( (double) liCurrentHPCValue.QuadPart / dHPCTicksPerMicrosecond ); // Add to starting system time... liCurrentHPCValue.QuadPart += liStartingSystemTime.QuadPart; // Build results... pTV->tv_sec = (long)(liCurrentHPCValue.QuadPart / 1000000); pTV->tv_usec = (long)(liCurrentHPCValue.QuadPart % 1000000); // Re-sync to system clock every so often to prevent clock drift // since high-performance timer updated independently from clock. #define RESYNC_GTOD_EVERY_SECS 30 // (initialize time of previous 'sync') if (unlikely( !tvPrevSyncVal.tv_sec )) { tvPrevSyncVal.tv_sec = pTV->tv_sec; tvPrevSyncVal.tv_usec = pTV->tv_usec; } // (is is time to resync again?) if (unlikely( (pTV->tv_sec - tvPrevSyncVal.tv_sec ) > RESYNC_GTOD_EVERY_SECS )) { bInSync = FALSE; // (force resync) return gettimeofday( pTV, NULL ); } // Ensure that each call returns a unique, ever-increasing value... if (unlikely( !tvPrevRetVal.tv_sec )) { tvPrevRetVal.tv_sec = pTV->tv_sec; tvPrevRetVal.tv_usec = pTV->tv_usec; } if (unlikely (0 || pTV->tv_sec < tvPrevRetVal.tv_sec || (1 && pTV->tv_sec == tvPrevRetVal.tv_sec && pTV->tv_usec <= tvPrevRetVal.tv_usec ) )) { pTV->tv_sec = tvPrevRetVal.tv_sec; pTV->tv_usec = tvPrevRetVal.tv_usec + 1; if (unlikely(pTV->tv_usec >= 1000000)) { pTV->tv_sec += pTV->tv_usec / 1000000; pTV->tv_usec = pTV->tv_usec % 1000000; } } // Save previously returned value for next time... tvPrevRetVal.tv_sec = pTV->tv_sec; tvPrevRetVal.tv_usec = pTV->tv_usec; // Done! return 0; // (always unless user error) } #endif ////////////////////////////////////////////////////////////////////////////////////////// // scandir... #if !defined( HAVE_SCANDIR ) // (fishfix: fix benign "passing incompatible pointer type" compiler warning..) typedef int (*PFN_QSORT_COMPARE_FUNC)( const void* elem1, const void* elem2 ); // Found the following on Koders.com ... (http://www.koders.com/) ... /* Copyright (c) 2000 Petter Reinholdtsen 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. */ DLL_EXPORT int scandir ( const char *dir, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **) ) { WIN32_FIND_DATA file_data; HANDLE handle; int count, pos; struct dirent **names; char *pattern; /* 3 for "*.*", 1 for "\", 1 for zero termination */ pattern = (char*)malloc(strlen(dir) + 3 +1 +1); strcpy(pattern, dir); if (pattern[ strlen(pattern) - 1] != '\\') strcat(pattern, "\\"); strcat(pattern, "*.*"); /* 1st pass thru is just to count them */ handle = FindFirstFile(pattern, &file_data); if (handle == INVALID_HANDLE_VALUE) { free(pattern); return -1; } count = 0; while (1) { count++; if (!FindNextFile(handle, &file_data)) break; } FindClose(handle); /* Now we know how many, we can alloc & make 2nd pass to copy them */ names = (struct dirent**)malloc(sizeof(struct dirent*) * count); memset(names, 0, sizeof(*names)); handle = FindFirstFile(pattern, &file_data); if (handle == INVALID_HANDLE_VALUE) { free(pattern); free(names); return -1; } /* Now let caller filter them if requested */ pos = 0; while (1) { int rtn; struct dirent current; strcpy(current.d_name, file_data.cFileName); if (!filter || filter(¤t)) { struct dirent *copyentry = malloc(sizeof(struct dirent)); strcpy(copyentry->d_name, current.d_name); names[pos] = copyentry; pos++; } rtn = FindNextFile(handle, &file_data); if (!rtn || rtn==ERROR_NO_MORE_FILES) break; } free(pattern); /* Now sort them */ if (compar) // (fishfix: fix benign "passing incompatible pointer type" compiler warning..) qsort(names, pos, sizeof(names[0]), (PFN_QSORT_COMPARE_FUNC)compar); *namelist = names; return pos; } #endif ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( HAVE_ALPHASORT ) DLL_EXPORT int alphasort ( const struct dirent **a, const struct dirent **b ) { return strfilenamecmp ( (*a)->d_name, (*b)->d_name ); } #endif ////////////////////////////////////////////////////////////////////////////////////////// // "Poor man's" getrusage... #if !defined(HAVE_SYS_RESOURCE_H) static int DoGetRUsage( HANDLE hProcess, struct rusage* r_usage ) { FILETIME ftCreation; // When the process was created(*) FILETIME ftExit; // When the process exited(*) // (*) Windows standard FILETIME format: date/time expressed as the // amount of time that has elapsed since midnight January 1, 1601. FILETIME ftKernel; // CPU time spent in kernel mode (in #of 100-nanosecond units) FILETIME ftUser; // CPU time spent in user mode (in #of 100-nanosecond units) LARGE_INTEGER liWork; // (work area) if ( !GetProcessTimes( hProcess, &ftCreation, &ftExit, &ftKernel, &ftUser ) ) { ftCreation.dwHighDateTime = ftCreation.dwLowDateTime = 0; ftExit .dwHighDateTime = ftExit .dwLowDateTime = 0; ftKernel .dwHighDateTime = ftKernel .dwLowDateTime = 0; ftUser .dwHighDateTime = ftUser .dwLowDateTime = 0; } // Kernel time... liWork.HighPart = ftKernel.dwHighDateTime; liWork.LowPart = ftKernel.dwLowDateTime; liWork.QuadPart /= 10; // (convert to microseconds) r_usage->ru_stime.tv_sec = (long)(liWork.QuadPart / 1000000); r_usage->ru_stime.tv_usec = (long)(liWork.QuadPart % 1000000); // User time... liWork.HighPart = ftUser.dwHighDateTime; liWork.LowPart = ftUser.dwLowDateTime; liWork.QuadPart /= 10; // (convert to microseconds) r_usage->ru_utime.tv_sec = (long)(liWork.QuadPart / 1000000); r_usage->ru_utime.tv_usec = (long)(liWork.QuadPart % 1000000); return 0; } DLL_EXPORT int getrusage ( int who, struct rusage* r_usage ) { if ( !r_usage ) { errno = EFAULT; return -1; } if ( RUSAGE_SELF == who ) return DoGetRUsage( GetCurrentProcess(), r_usage ); if ( RUSAGE_CHILDREN != who ) { errno = EINVAL; return -1; } // RUSAGE_CHILDREN ... { DWORD dwOurProcessId = GetCurrentProcessId(); HANDLE hProcessSnap = NULL; PROCESSENTRY32 pe32; HANDLE hChildProcess; struct rusage child_usage; memset( &pe32, 0, sizeof(pe32) ); // Take a snapshot of all active processes... hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if ( INVALID_HANDLE_VALUE == hProcessSnap ) return DoGetRUsage( INVALID_HANDLE_VALUE, r_usage ); pe32.dwSize = sizeof( PROCESSENTRY32 ); // Walk the snapshot... if ( !Process32First( hProcessSnap, &pe32 ) ) { CloseHandle( hProcessSnap ); return DoGetRUsage( INVALID_HANDLE_VALUE, r_usage ); } r_usage->ru_stime.tv_sec = r_usage->ru_stime.tv_usec = 0; r_usage->ru_utime.tv_sec = r_usage->ru_utime.tv_usec = 0; // Locate all children of the current process // and accumulate their process times together... do { if ( pe32.th32ParentProcessID != dwOurProcessId ) continue; hChildProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID ); DoGetRUsage( hChildProcess, &child_usage ); CloseHandle( hChildProcess ); VERIFY( timeval_add( &child_usage.ru_stime, &r_usage->ru_stime ) == 0 ); VERIFY( timeval_add( &child_usage.ru_utime, &r_usage->ru_utime ) == 0 ); } while ( Process32Next( hProcessSnap, &pe32 ) ); VERIFY( CloseHandle( hProcessSnap ) ); } return 0; } #endif ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( HAVE_GETLOGIN_R ) DLL_EXPORT int getlogin_r ( char* name, size_t namesize ) { DWORD dwSize = (DWORD)namesize; if ( !name ) return EFAULT; if ( namesize < 2 || namesize > ( LOGIN_NAME_MAX + 1 ) ) return EINVAL; return ( GetUserName( name, &dwSize ) ? 0 : ERANGE ); } #endif ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( HAVE_GETLOGIN ) DLL_EXPORT char* getlogin ( void ) { static char login_name [ LOGIN_NAME_MAX + 1 ]; int rc; if ( ( rc = getlogin_r ( login_name, sizeof(login_name) ) ) == 0 ) return login_name; errno = rc; return NULL; } #endif ////////////////////////////////////////////////////////////////////////////////////////// #if !defined( HAVE_REALPATH ) DLL_EXPORT char* realpath ( const char* file_name, char* resolved_name ) { char* retval; if ( !file_name || !resolved_name ) { errno = EINVAL; return NULL; } // PROGRAMMING NOTE: unfortunately there's no possible way to implement an accurate // Win32 port of realpath in regard to the errno values returned whenever there's an // error. The errno values that are set whenever realpath fails are quite precise, // telling you exactly what went wrong (name too long, invalid directory component, // etc), whereas _fullpath only returns success/failure with absolutely no indication // as to WHY it failed. To further complicate matters, there's no real "generic" type // of errno value we can choose to return to the caller should _fullpath fail either, // so for this implementation we purposely return EIO (i/o error) if _fullpath fails // for any reason. That may perhaps be somewhat misleading (since the actual cause of // the failure was probably not because of an i/o error), but returning any of the // OTHER possible realpath errno values would be even MORE misleading in my opinion. if ( !(retval = _fullpath( resolved_name, file_name, PATH_MAX ) ) ) errno = EIO; return retval; } #endif ////////////////////////////////////////////////////////////////////////////////////////// // Returns outpath as a host filesystem compatible filename path. // This is a Cygwin-to-MSVC transitional period helper function. // On non-Windows platforms it simply copies inpath to outpath. // On Windows it converts inpath of the form "/cygdrive/x/foo.bar" // to outpath in the form "x:/foo.bar" for Windows compatibility. DLL_EXPORT BYTE *hostpath( BYTE *outpath, const BYTE *inpath, size_t buffsize ) { // The possibilities: // a. Linux/Cygwin absolute: // /dir/foo.bar // b. Linux/Cygwin relative: // ../dir/foo.bar // ./dir/foo.bar // ../../.././dir/foo.bar // (etc) // c. Windows relative: // ./dir\foo.bar // ../dir\foo.bar // ..\dir\foo.bar // .\dir\foo.bar // ..\dir/foo.bar // .\dir/foo.bar // ../..\../.\dir/foo.bar // (etc) // d. Windows absolute // x:/dir/foo.bar // x:\dir\foo.bar // x:/dir\foo.bar // x:\dir/foo.bar // For case a we check for special Cygwin format "/cygdrive/x/..." // and convert it to "normalized" (forward-slash) case d format. // (Note that the slashes in this case MUST be forward slashes // or else the special Cygwin path format will not be detected!) // Case b we treat the same as case c. // For case c we simply convert all backslashes to forward slashes // since Windows supports both. // For case d we do nothing since it is already a Windows path // (other than normalize all backward slashes to forward slashes // since Windows supports both) // NOTE that we do NOT attempt to convert relative paths to absolute // paths! The caller is responsible for doing that themselves after // calling this function if so desired. if (outpath && buffsize) *outpath = 0; if (inpath && *inpath && outpath && buffsize > 1) { size_t inlen = strlen(inpath); if (1 && inlen >= 11 && strncasecmp(inpath,"/cygdrive/",10) == 0 && isalpha(inpath[10]) ) { *outpath++ = inpath[10]; buffsize--; if (buffsize > 1) { *outpath++ = ':'; buffsize--; } inpath += 11; } while (*inpath && --buffsize) { BYTE c = *inpath++; if (c == '\\') c = '/'; *outpath++ = c; } *outpath = 0; } return outpath; } ////////////////////////////////////////////////////////////////////////////////////////// // Poor man's "fcntl( fd, F_GETFL )"... // (only returns access-mode flags and not any others) DLL_EXPORT int get_file_accmode_flags( int fd ) { // PROGRAMMING NOTE: we unfortunately CANNOT use Microsoft's "_fstat" here // since it seems to always return the actual file's ATTRIBUTE permissions // and not the ACCESS MODE permissions specified when the file was opened! HANDLE hFile; BOOL bCanRead; BOOL bCanWrite; DWORD dwNumBytesToReadOrWrite; DWORD dwNumBytesReadOrWritten; char read_write_buffer; // TECHNIQUE: check whether or not we can "read" and/or "write" to the file // and return appropriate access-mode flags accordingly. Note that we do not // actually read nor write from/to the file per se, since we specify ZERO BYTES // for our "number of bytes to read/write" argument. This is valid under Win32 // and does not modify the file position and so is safe to do. All it does is // return the appropriate success/failure return code (e.g. ERROR_ACCESS_DENIED) // depending on whether the file was opened with the proper access permissions. hFile = (HANDLE) _get_osfhandle( fd ); if ( (HANDLE) -1 == hFile ) { errno = EBADF; // (probably not a valid opened file descriptor) return -1; } dwNumBytesToReadOrWrite = 0; // ZERO!!! (we don't wish to modify the file!) VERIFY( ( bCanRead = ReadFile ( hFile, &read_write_buffer, dwNumBytesToReadOrWrite, &dwNumBytesReadOrWritten, NULL ) ) || ERROR_ACCESS_DENIED == GetLastError() ); VERIFY( ( bCanWrite = WriteFile ( hFile, &read_write_buffer, dwNumBytesToReadOrWrite, &dwNumBytesReadOrWritten, NULL ) ) || ERROR_ACCESS_DENIED == GetLastError() ); // For reference, 'fcntl.h' defines the flags as follows: // // #define _O_RDONLY 0 // #define _O_WRONLY 1 // #define _O_RDWR 2 if ( bCanRead && bCanWrite ) return _O_RDWR; if ( bCanRead && !bCanWrite ) return _O_RDONLY; if ( !bCanRead && bCanWrite ) return _O_WRONLY; ASSERT( FALSE ); // (HUH?! Can neither read NOR write to the file?!) errno = EBADF; // (maybe they closed it before we could test it??) return -1; // (oh well) } ////////////////////////////////////////////////////////////////////////////////////////// // Retrieve directory where process was loaded from... // (returns >0 == success, 0 == failure) DLL_EXPORT int get_process_directory( char* dirbuf, size_t bufsiz ) { char process_exec_dirbuf[MAX_PATH]; char* p; DWORD dwDirBytes = GetModuleFileName(GetModuleHandle(NULL),process_exec_dirbuf,MAX_PATH); if (!dwDirBytes || dwDirBytes >= MAX_PATH) return 0; p = strrchr(process_exec_dirbuf,'\\'); if (p) *(p+1) = 0; strlcpy(dirbuf,process_exec_dirbuf,bufsiz); return strlen(dirbuf) ? 1 : 0; } ////////////////////////////////////////////////////////////////////////////////////////// // Expand environment variables... (e.g. %SystemRoot%, etc); 0==success DLL_EXPORT int expand_environ_vars( const char* inbuff, char* outbuff, DWORD outbufsiz ) { // If the function succeeds, the return value is the number of TCHARs // stored in the destination buffer, including the terminating null character. // If the destination buffer is too small to hold the expanded string, the // return value is the required buffer size, in TCHARs. If the function fails, // the return value is zero. DWORD dwOutLen = ExpandEnvironmentStrings( inbuff, outbuff, outbufsiz ); return ( ( dwOutLen && dwOutLen < outbufsiz ) ? 0 : -1 ); } ////////////////////////////////////////////////////////////////////////////////////////// // Initialize Hercules HOSTINFO structure DLL_EXPORT void w32_init_hostinfo( HOST_INFO* pHostInfo ) { CRITICAL_SECTION cs; OSVERSIONINFO vi; SYSTEM_INFO si; char* psz; DWORD dw; dw = sizeof(pHostInfo->nodename)-1; GetComputerName( pHostInfo->nodename, &dw ); pHostInfo->nodename[sizeof(pHostInfo->nodename)-1] = 0; vi.dwOSVersionInfoSize = sizeof(vi); VERIFY( GetVersionEx( &vi ) ); switch ( vi.dwPlatformId ) { case VER_PLATFORM_WIN32_WINDOWS: psz = "9X"; break; case VER_PLATFORM_WIN32_NT: psz = "NT"; break; default: psz = "??"; break; } #if defined(__MINGW32_VERSION) #define HWIN32_SYSNAME "MINGW32" #else #define HWIN32_SYSNAME "Windows" #endif _snprintf( pHostInfo->sysname, sizeof( pHostInfo->sysname)-1, HWIN32_SYSNAME "_%s", psz ); pHostInfo->sysname[ sizeof( pHostInfo->sysname)-1] = 0; _snprintf( pHostInfo->release, sizeof( pHostInfo->release)-1, "%d", vi.dwMajorVersion ); pHostInfo->release[ sizeof( pHostInfo->release)-1] = 0; _snprintf( pHostInfo->version, sizeof( pHostInfo->version)-1, "%d", vi.dwMinorVersion ); pHostInfo->version[ sizeof( pHostInfo->version)-1] = 0; GetSystemInfo( &si ); switch ( si.wProcessorArchitecture ) { case PROCESSOR_ARCHITECTURE_INTEL: { int n; if ( si.wProcessorLevel < 3 ) n = 3; else if ( si.wProcessorLevel > 9 ) n = 6; else n = si.wProcessorLevel; _snprintf( pHostInfo->machine, sizeof( pHostInfo->machine)-1, "i%d86", n ); pHostInfo->machine[ sizeof( pHostInfo->machine)-1] = 0; } break; // The following are missing from MinGW's supplied version of #define PROCESSOR_ARCHITECTURE_MSIL 8 #define PROCESSOR_ARCHITECTURE_AMD64 9 #define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 case PROCESSOR_ARCHITECTURE_IA64: strlcpy( pHostInfo->machine, "IA64" , sizeof(pHostInfo->machine) ); break; case PROCESSOR_ARCHITECTURE_AMD64: strlcpy( pHostInfo->machine, "AMD64" , sizeof(pHostInfo->machine) ); break; case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: strlcpy( pHostInfo->machine, "IA32_ON_WIN64" , sizeof(pHostInfo->machine) ); break; case PROCESSOR_ARCHITECTURE_ALPHA: strlcpy( pHostInfo->machine, "ALPHA" , sizeof(pHostInfo->machine) ); break; case PROCESSOR_ARCHITECTURE_MIPS: strlcpy( pHostInfo->machine, "MIPS" , sizeof(pHostInfo->machine) ); break; default: strlcpy( pHostInfo->machine, "???" , sizeof(pHostInfo->machine) ); break; } pHostInfo->num_procs = si.dwNumberOfProcessors; InitializeCriticalSection( &cs ); if ( !TryEnterCriticalSection( &cs ) ) pHostInfo->trycritsec_avail = 0; else { pHostInfo->trycritsec_avail = 1; LeaveCriticalSection( &cs ); } DeleteCriticalSection( &cs ); } ////////////////////////////////////////////////////////////////////////////////////////// // The function that creates us is responsible for initializing the below values // (as well as de-initialzing them too!) static DWORD dwThreadId = 0; // (Win32 thread-id of below thread) static HANDLE hThread = NULL; // (Win32 handle of below thread) static HANDLE hGotStdIn = NULL; // (signaled to get next char) static HANDLE hStdInAvailable = NULL; // (signaled when char avail) static HANDLE hStdIn = NULL; // (Win32 stdin handle) static char chStdIn = 0; // (the next char read from stdin) // Win32 worker thread that reads from stdin. It needs to be a thread because the // "ReadFile" on stdin 'hangs' (blocks) until there's actually some data to read // or the handle is closed, whichever comes first. Note that we only read one char // at a time. This may perhaps be slightly inefficient but it makes for a simpler // implementation and besides, we don't really expect huge gobs of data coming in. static DWORD WINAPI ReadStdInW32Thread( LPVOID lpParameter ) { DWORD dwBytesRead = 0; UNREFERENCED( lpParameter ); SET_THREAD_NAME ("ReadStdInW32Thread"); for (;;) { WaitForSingleObject( hGotStdIn, INFINITE ); if ( !ReadFile( hStdIn, &chStdIn, 1, &dwBytesRead, NULL ) ) { char szErrMsg[256]; DWORD dwLastError = GetLastError(); if ( ERROR_BROKEN_PIPE == dwLastError || sysblk.shutdown ) break; // (shutting down; time to exit) w32_w32errmsg( dwLastError, szErrMsg, sizeof(szErrMsg) ); logmsg ( _("HHCDG008W ReadFile(hStdIn) failed! dwLastError=%d (0x%08.8X): %s\n") ,dwLastError ,dwLastError ,szErrMsg ); continue; } ASSERT( 1 == dwBytesRead ); ResetEvent( hGotStdIn ); SetEvent( hStdInAvailable ); } return 0; } ////////////////////////////////////////////////////////////////////////////////////////// // Function to read the next character from stdin. Similar to 'getch' but allows // one to specify a maximum timeout value and thus doesn't block forever. Returns // 0 or 1: 0 == timeout (zero characters read), 1 == success (one character read), // or -1 == error (pCharBuff NULL). The worker thread is created on the 1st call. DLL_EXPORT int w32_get_stdin_char( char* pCharBuff, int wait_millisecs ) { if ( !pCharBuff ) { errno = EINVAL; return -1; } *pCharBuff = 0; if ( !dwThreadId ) { hStdIn = GetStdHandle( STD_INPUT_HANDLE ); hStdInAvailable = CreateEvent(NULL,TRUE,FALSE,NULL); hGotStdIn = CreateEvent(NULL,TRUE,TRUE,NULL); // (initially signaled) hThread = (HANDLE) _beginthreadex ( NULL, // pointer to security attributes 64*1024, // initial thread stack size in bytes ReadStdInW32Thread, // pointer to thread function NULL, // argument for new thread 0, // creation flags &dwThreadId // pointer to receive thread ID ); ASSERT(1 && hStdIn && INVALID_HANDLE_VALUE != hStdIn && hStdInAvailable && INVALID_HANDLE_VALUE != hStdInAvailable && hGotStdIn && INVALID_HANDLE_VALUE != hGotStdIn && hThread && INVALID_HANDLE_VALUE != hThread ); } if ( WAIT_TIMEOUT == WaitForSingleObject( hStdInAvailable, wait_millisecs ) ) return 0; *pCharBuff = chStdIn; // (save the next char right away) ResetEvent( hStdInAvailable ); // (reset OUR flag for next time) SetEvent( hGotStdIn ); // (allow thread to read next char) return 1; } /****************************************************************************************\ * * * (BEGIN) S O C K E T H A N D L I N G F U N C T I O N S (BEGIN) * * * \****************************************************************************************/ // ***** VERY IMPORTANT SPECIAL NOTE! ***** // Because "hmacros.h" #defines 'xxxx' to 'w32_xxxx' (to route the call to us), // we now need to #undef it here to allow us to call the actual 'xxxx' function // if we need to. All xxxx calls from here on will call the true Windows version. // To call the w32_xxxx function instead, simply call it directly yourself. #undef socket // (so we can call the actual Windows version if we need to) #undef select // (so we can call the actual Windows version if we need to) #undef fdopen // (so we can call the actual Windows version if we need to) #undef fwrite // (so we can call the actual Windows version if we need to) #undef fprintf // (so we can call the actual Windows version if we need to) #undef fclose // (so we can call the actual Windows version if we need to) ////////////////////////////////////////////////////////////////////////////////////////// /* INITIALIZE / DE-INITIALIZE SOCKETS PACKAGE The WSAStartup function must be the first Windows Sockets function called by an application or DLL. It allows an application or DLL to specify the version of Windows Sockets required and retrieve details of the specific Windows Sockets implementation. The application or DLL can only issue further Windows Sockets functions after successfully calling WSAStartup. Once an application or DLL has made a successful WSAStartup call, it can proceed to make other Windows Sockets calls as needed. When it has finished using the services of the WS2_32.DLL, the application or DLL must call WSACleanup to allow the WS2_32.DLL to free any resources for the application. *** IMPORTANT *** An application must call one WSACleanup call for every successful WSAStartup call to allow third-party DLLs to make use of a WS2_32.DLL on behalf of an application. This means, for example, that if an application calls WSAStartup three times, it must call WSACleanup three times. The first two calls to WSACleanup do nothing except decrement an internal counter; the final WSACleanup call for the task does all necessary resource deallocation for the task. */ DLL_EXPORT int socket_init ( void ) { /* In order to support future Windows Sockets implementations and applications that can have functionality differences from the current version of Windows Sockets, a negotiation takes place in WSAStartup. The caller of WSAStartup and the WS2_32.DLL indicate to each other the highest version that they can support, and each confirms that the other's highest version is acceptable. Upon entry to WSAStartup, the WS2_32.DLL examines the version requested by the application. If this version is equal to or higher than the lowest version supported by the DLL, the call succeeds and the DLL returns in wHighVersion the highest version it supports and in wVersion the minimum of its high version and wVersionRequested. The WS2_32.DLL then assumes that the application will use wVersion If the wVersion parameter of the WSADATA structure is unacceptable to the caller, it should call WSACleanup and either search for another WS2_32.DLL or fail to initialize. */ WSADATA sSocketPackageInfo; WORD wVersionRequested = MAKEWORD(1,1); return ( WSAStartup( wVersionRequested, &sSocketPackageInfo ) == 0 ? 0 : -1 ); } ////////////////////////////////////////////////////////////////////////////////////////// // De-initialize Windows Sockets package... DLL_EXPORT int socket_deinit ( void ) { // PROGRAMMING NOTE: regardless of the comments in the socket_init function above // regarding the need to always call WSACleanup for every WSAStartup call, it's not // really necessary in our particular case because we're not designed to continue // running after shutting down socket handling (which is really what the WSACleanup // function is designed for). That is to say, the WSACleanup function is designed // so a program can inform the operating system that it's finished using the socket // DLL (thus allowing it to free up all of the resources currently being used by // the process and allow the DLL to be unmapped from the process'es address space) // but not exit (i.e. continue running). In our case however, our entire process // is exiting (i.e. we're NOT going to continue running), and when a process exits, // all loaded DLLs are automatically notified by the operating system to allow them // to automatically free all resources for the process in question. Thus since we // are exiting we don't really need to call WSACleanup since whatever "cleanup" it // would do is going to get done *anyway* by virtue of our going away. Besides that, // WSACleanup appears to "hang" when it's called while socket resources are still // being used (which is true in our case since we're not designed (yet!) to cleanly // shutdown all of our socket-using threads before exiting). THUS (sorry to ramble) // we in fact probably SHOULDN'T be calling WSACleanup here (and besides, bypassing // it seems to resolve our hangs at shutdown whenever there's still a thread running // that doing sockets shit). #if 0 // (see above) return ( WSACleanup() == 0 ? 0 : -1 ); #else return 0; // (not needed? see PROGRAMING NOTE above!) #endif } ////////////////////////////////////////////////////////////////////////////////////////// // Retrieve unique host id DLL_EXPORT long gethostid( void ) { char szHostName[ WSADESCRIPTION_LEN ]; struct hostent* pHostent = NULL; return (gethostname( szHostName, sizeof(szHostName) ) == 0 && (pHostent = gethostbyname( szHostName )) != NULL) ? (long)(*(pHostent->h_addr)) : 0; } ////////////////////////////////////////////////////////////////////////////////////////// DLL_EXPORT int w32_socket( int af, int type, int protocol ) { /////////////////////////////////////////////////////////////////////////////// // // PROGRAMMING NOTE // // We need to request that all sockets we create [via the 'socket()' API] // be created WITHOUT the "OVERLAPPED" attribute so that our 'fgets()', etc, // calls (which end up calling the "ReadFile()", etc, Win32 API) work as // expected. // // Note that the "overlapped" attribute for a socket is completely different // from its non-blocking vs. blocking mode. All sockets are created, by default, // as blocking mode sockets, but WITH the "overlapped" attribute set. Thus all // sockets are actually asynchonous by default. (The winsock DLL(s) handle the // blocking mode separately programmatically internally even though the socket // is actually an asynchronous Win32 "file"). // // Thus we need to specifically request that our [blocking mode] sockets be // created WITHOUT the Win32 "OVERLAPPED" attribute (so that when we call the // C runtime read/write/etc functions, the C runtime's ReadFile/WriteFile calls // work (which they don't (they fail with error 87 ERROR_INVALID_PARAMETER) // when called on a Win32 "file" handle created with the OVERLAPPED attribute // but without an OVERLAPPED structure pased in the ReadFile/WriteFile call // (which the C runtime functions don't use)). You follow?). // // See KB (Knowledge Base) article 181611 for more information: // // "Socket overlapped I/O versus blocking/non-blocking mode" // (http://support.microsoft.com/?kbid=181611) // // --------------------------------------------------------------------- // "However, you can call the setsockopt API with SO_OPENTYPE option // on any socket handle -- including an INVALID_SOCKET -- to change // the overlapped attributes for all successive socket calls in the // same thread. The default SO_OPENTYPE option value is 0, which sets // the overlapped attribute. All non-zero option values make the socket // synchronous and make it so that you cannot use a completion function." // --------------------------------------------------------------------- // // The documentation for the "SOL_SOCKET" SO_OPENTYPE socket option contains // the folowing advice/warning however: // // // "Once set, subsequent sockets created will be non-overlapped. // This option should not be used; use WSASocket and leave the // WSA_FLAG_OVERLAPPED turned off." // // // So we'll use WSASocket instead as suggested. // /////////////////////////////////////////////////////////////////////////////// // The last parameter is where one would normally specify the WSA_FLAG_OVERLAPPED // option, but we're specifying '0' because we want our sockets to be synchronous // and not asynchronous so the C runtime functions can successfully perform ReadFile // and WriteFile on them... SOCKET sock = WSASocket( af, type, protocol, NULL, 0, 0 ); if ( INVALID_SOCKET == sock ) { errno = WSAGetLastError(); sock = (SOCKET) -1; } return ( (int) sock ); } ////////////////////////////////////////////////////////////////////////////////////////// // Determine whether a file descriptor is a socket or not... // (returns 1==true if it's a socket, 0==false otherwise) DLL_EXPORT int socket_is_socket( int sfd ) { u_long dummy; return WSAHtonl( (SOCKET) sfd, 666, &dummy ) == 0 ? 1 : 0; } ////////////////////////////////////////////////////////////////////////////////////////// // Set the SO_KEEPALIVE option and timeout values for a // socket connection to detect when client disconnects */ DLL_EXPORT void socket_keepalive( int sfd, int idle_time, int probe_interval, int probe_count ) { DWORD dwBytesReturned; // (not used) struct tcp_keepalive ka; ka.onoff = TRUE; ka.keepalivetime = idle_time * 1000; ka.keepaliveinterval = probe_interval * 1000; UNREFERENCED(probe_count); // It either works or it doesn't // PROGRAMMING NOTE: the 'dwBytesReturned' value must apparently always be // specified in order for this call to work at all. If you don't specify it, // even though the call succeeds (does not return an error), the automatic // keep-alive polling does not occur! if (0 != WSAIoctl ( (SOCKET)sfd, // [in] Descriptor identifying a socket SIO_KEEPALIVE_VALS, // [in] Control code of operation to perform &ka, // [in] Pointer to the input buffer sizeof(ka), // [in] Size of the input buffer, in bytes NULL, // [out] Pointer to the output buffer 0, // [in] Size of the output buffer, in bytes &dwBytesReturned, // [out] Pointer to actual number of bytes of output NULL, // [in] Pointer to a WSAOVERLAPPED structure // (ignored for nonoverlapped sockets) NULL // [in] Pointer to the completion routine called // when the operation has been completed // (ignored for nonoverlapped sockets) )) { DWORD dwLastError = WSAGetLastError(); TRACE("*** WSAIoctl(SIO_KEEPALIVE_VALS) failed; rc %d: %s\n", dwLastError, w32_strerror(dwLastError) ); ASSERT(1); // (in case we're debugging) } } ////////////////////////////////////////////////////////////////////////////////////////// // The inet_aton() function converts the specified string, // in the Internet standard dot notation, to a network address, // and stores the address in the structure provided. // // The inet_aton() function returns 1 if the address is successfully converted, // or 0 if the conversion failed. #if !defined( HAVE_INET_ATON ) DLL_EXPORT int inet_aton( const char* cp, struct in_addr* addr ) { // Return success as long as both args are not NULL *and* // the result is not INADDR_NONE (0xFFFFFFFF), -OR- if it // is [INADDR_NONE], [we return success] if that is the // actual expected value of the conversion... return ( (1 && cp // (must not be NULL) && addr // (must not be NULL) && (0 || INADDR_NONE != ( addr->s_addr = inet_addr( cp ) ) || strcmp( cp, "255.255.255.255" ) == 0 ) ) ? 1 : 0 // 1 == success, 0 == failure ); } #endif // !defined( HAVE_INET_ATON ) ////////////////////////////////////////////////////////////////////////////////////////// // All internal calls to Windows's 'FD_ISSET' or 'FD_SET' macros MUST use the below // macros instead and NOT the #defined 'FD_ISSET' or 'FD_SET' macros! The #defined // 'FD_ISSET' and 'FD_SET' macros are coded (in hmacros.h) to route the calls to the // internal 'w32_FD_SET' and 'w32_FD_ISSET' functions further below! #define ORIGINAL_FD_ISSET __WSAFDIsSet #define ORIGINAL_FD_SET( fd, pSet ) \ do \ { \ unsigned int i; \ for (i=0; i < ((fd_set*)(pSet))->fd_count; i++) \ if (((fd_set*)(pSet))->fd_array[i] == (fd)) \ break; \ if (i == ((fd_set*)(pSet))->fd_count \ && ((fd_set*)(pSet))->fd_count < FD_SETSIZE) \ { \ ((fd_set*)(pSet))->fd_array[i] = (fd); \ ((fd_set*)(pSet))->fd_count++; \ } \ } \ while (0) ////////////////////////////////////////////////////////////////////////////////////////// // FD_SET: ( FD_SET(fd,pSet) ) // // Will need to override and route to "w32_FD_SET" // // Do '_get_osfhandle'. // // If '_get_osfhandle' error, then it's either already a HANDLE (SOCKET probably), // or else a bona fide invalid file descriptor or invalid SOCKET handle, so do a // normal FD_SET. // // Otherwise ('_get_osfhandle' success), then it WAS a file descriptor // but we now have it's HANDLE, so do the FD_SET on the returned HANDLE. // // Thus we ensure all entries added to set are HANDLES // (or SOCKETS which are considered to be HANDLES too) DLL_EXPORT void w32_FD_SET( int fd, fd_set* pSet ) { SOCKET hSocket; if (0 || socket_is_socket( fd ) || (SOCKET) -1 == ( hSocket = (SOCKET) _get_osfhandle( fd ) ) ) hSocket = (SOCKET) fd; ORIGINAL_FD_SET( hSocket, pSet ); // (add HANDLE/SOCKET to specified set) } ////////////////////////////////////////////////////////////////////////////////////////// // FD_ISSET: ( FD_ISSET(fd,pSet) ) // // Will need to override and route to "w32_FD_ISSET". // // (Note: all entries in sets should already be HANDLES // due to previously mentioned FD_SET override) // // If socket, do normal FD_ISSET. // Otherwise do our IsEventSet(). DLL_EXPORT int w32_FD_ISSET( int fd, fd_set* pSet ) { int i; HANDLE hFile; if ( socket_is_socket( fd ) ) // (is it already a SOCKET?) return ORIGINAL_FD_ISSET( (SOCKET)fd, pSet ); // (yes, do normal FD_ISSET) hFile = (HANDLE) _get_osfhandle( fd ); for ( i=0; i < (int)pSet->fd_count; i++ ) if ( pSet->fd_array[i] == (SOCKET) hFile ) // (is this the file?) return IsEventSet( hFile ); // (yes, return whether ready (signaled) or not) return 0; // (file not a member of the specified set) } ////////////////////////////////////////////////////////////////////////////////////////// // Win32 "socketpair()" and "pipe()" functionality... #if !defined( HAVE_SOCKETPAIR ) DLL_EXPORT int socketpair( int domain, int type, int protocol, int socket_vector[2] ) { // PROGRAMMING NOTE: we do NOT support type AF_UNIX socketpairs on Win32. // we *ONLY* support AF_INET, IPPROTO_IP, SOCK_STREAM. SOCKET temp_listen_socket; struct sockaddr_in localhost_addr; int len = sizeof(localhost_addr); /* FIXME ISW ? In some situations, it seems the sockaddr_in structure */ /* returned by getsockname() isn't appropriate for use */ /* by connect(). We therefore use another sockaddr_in for the */ /* sole purpose of fetching the automatic port number issued */ /* during the bind() operation. */ /* NOTE : This is a workaround. The actual root cause for this */ /* problem is presently unknown because it is hard to reproduce*/ struct sockaddr_in tempaddr; int talen = sizeof(tempaddr); // Technique: create a pair of sockets bound to each other by first creating a // temporary listening socket bound to the localhost loopback address (127.0.0.1) // and then having the other socket connect to it... // "Upon successful completion, 0 shall be returned; otherwise, // -1 shall be returned and errno set to indicate the error." if ( AF_INET != domain ) { errno = WSAEAFNOSUPPORT; return -1; } if ( SOCK_STREAM != type ) { errno = WSAEPROTONOSUPPORT; return -1; } if ( IPPROTO_IP != protocol ) { errno = WSAEPROTOTYPE; return -1; } socket_vector[0] = socket_vector[1] = INVALID_SOCKET; if ( INVALID_SOCKET == (temp_listen_socket = socket( AF_INET, SOCK_STREAM, 0 )) ) { errno = (int)WSAGetLastError(); return -1; } memset( &localhost_addr, 0, len ); memset( &tempaddr, 0, talen ); localhost_addr.sin_family = AF_INET; localhost_addr.sin_port = htons( 0 ); localhost_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); if (0 || SOCKET_ERROR == bind( temp_listen_socket, (SOCKADDR*) &localhost_addr, len ) || SOCKET_ERROR == listen( temp_listen_socket, 1 ) || SOCKET_ERROR == getsockname( temp_listen_socket, (SOCKADDR*) &tempaddr, &talen ) || INVALID_SOCKET == (SOCKET)( socket_vector[1] = socket( AF_INET, SOCK_STREAM, 0 ) ) ) { int nLastError = (int)WSAGetLastError(); closesocket( temp_listen_socket ); errno = nLastError; return -1; } /* Get the temporary port number assigned automatically */ /* by bind(127.0.0.1/0) */ localhost_addr.sin_port = tempaddr.sin_port; if (0 || SOCKET_ERROR == connect( socket_vector[1], (SOCKADDR*) &localhost_addr, len ) || INVALID_SOCKET == (SOCKET)( socket_vector[0] = accept( temp_listen_socket, (SOCKADDR*) &localhost_addr, &len ) ) ) { int nLastError = (int)WSAGetLastError(); closesocket( socket_vector[1] ); socket_vector[1] = INVALID_SOCKET; closesocket( temp_listen_socket ); errno = nLastError; return -1; } closesocket( temp_listen_socket ); return 0; } #endif // !defined( HAVE_SOCKETPAIR ) ////////////////////////////////////////////////////////////////////////////////////////// // Set socket to blocking or non-blocking mode... DLL_EXPORT int socket_set_blocking_mode( int sfd, int blocking_mode ) { u_long non_blocking_option = !blocking_mode; if ( SOCKET_ERROR != ioctlsocket( sfd, FIONBIO, &non_blocking_option) ) return 0; switch (WSAGetLastError()) { case WSAENETDOWN: errno = ENETDOWN; break; case WSAENOTSOCK: errno = ENOTSOCK; break; case WSAEFAULT: errno = EFAULT; break; default: errno = ENOSYS; break; } return -1; } ////////////////////////////////////////////////////////////////////////////////////////// // select: // // Will need to override and route to "w32_select" // // w32_select: // // Check if all entries (in all sets) are sockets or not // // (Note: all entries in sets should already be HANDLES // due to previously mentioned FD_SET override) // // If all sockets, then do normal 'select'. // // If all non-sockets, then do 'WaitForMultipleObjects' instead. // // if mixed, then EBADF (one or more bad file descriptors) static void SelectSet // (helper function) ( fd_set* pSet, BOOL* pbSocketFound, BOOL* pbNonSocketFound, DWORD* pdwHandles, HANDLE* parHandles ); DLL_EXPORT int w32_select ( int nfds, fd_set* pReadSet, fd_set* pWriteSet, fd_set* pExceptSet, const struct timeval* pTimeVal, const char* pszSourceFile, int nLineNumber ) { HANDLE arHandles[ 2 * FD_SETSIZE ]; // (max read + write set size) DWORD dwHandles = 0; BOOL bSocketFound = FALSE; BOOL bNonSocketFound = FALSE; BOOL bExceptSetSocketFound = FALSE; BOOL bExceptSetNonSocketFound = FALSE; DWORD dwWaitMilliSeconds = 0; DWORD dwWaitRetCode = 0; UNREFERENCED( nfds ); // Quick check for 'timer.c' call wherein all passed fd_set pointers are NULL... if ( !pReadSet && !pWriteSet && !pExceptSet ) { ASSERT( pTimeVal ); // (why else would we be called?!) if ( !pTimeVal ) { logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): NULL args\n", pszSourceFile, nLineNumber ); errno = EINVAL; return -1; } // Sleep for the specified time period... if ( !pTimeVal->tv_sec && !pTimeVal->tv_usec ) sched_yield(); else { if ( pTimeVal->tv_sec ) sleep( pTimeVal->tv_sec ); if ( pTimeVal->tv_usec ) usleep( pTimeVal->tv_usec ); } return 0; } // Check for mixed sets and build HANDLE array... // (Note: we don't support except sets for non-sockets) SelectSet( pReadSet, &bSocketFound, &bNonSocketFound, &dwHandles, arHandles ); SelectSet( pWriteSet, &bSocketFound, &bNonSocketFound, &dwHandles, arHandles ); SelectSet( pExceptSet, &bExceptSetSocketFound, &bExceptSetNonSocketFound, NULL, NULL ); if (0 || ( bSocketFound && ( bNonSocketFound || bExceptSetNonSocketFound ) ) || ( bNonSocketFound && ( bSocketFound || bExceptSetSocketFound ) ) ) { logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): mixed set(s)\n", pszSourceFile, nLineNumber ); errno = EBADF; return -1; } if ( bExceptSetNonSocketFound ) { logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): non-socket except set\n", pszSourceFile, nLineNumber ); errno = EBADF; return -1; } // If all SOCKETs, do a normal 'select'... if ( bSocketFound ) return select( nfds, pReadSet, pWriteSet, pExceptSet, pTimeVal ); // Otherwise they're all HANDLEs, so do a WaitForMultipleObjects... if ( !pTimeVal ) dwWaitMilliSeconds = INFINITE; else { dwWaitMilliSeconds = ( pTimeVal->tv_sec * 1000 ); dwWaitMilliSeconds += ( ( pTimeVal->tv_usec + 500 ) / 1000 ); } if ( !dwHandles ) { // Just sleep for the specified interval... Sleep( dwWaitMilliSeconds ); return 0; // (timeout) } dwWaitRetCode = WaitForMultipleObjects( dwHandles, arHandles, FALSE, dwWaitMilliSeconds ); if ( WAIT_TIMEOUT == dwWaitRetCode ) return 0; // NOTE: we don't support returning the actual total number of handles // that are ready; instead, we return 1 as long as ANY handle is ready... if ( dwWaitRetCode >= WAIT_OBJECT_0 && dwWaitRetCode < ( WAIT_OBJECT_0 + dwHandles ) ) return 1; // Something went wrong... ASSERT( FALSE ); // (in case this is a debug build) errno = ENOSYS; // (system call failure) return -1; } ////////////////////////////////////////////////////////////////////////////////////////// // internal helper function to pre-process a 'select' set... static void SelectSet ( fd_set* pSet, BOOL* pbSocketFound, BOOL* pbNonSocketFound, DWORD* pdwHandles, HANDLE* parHandles ) { unsigned int i; if ( !pSet ) return; for (i=0; i < pSet->fd_count && i < FD_SETSIZE; i++) { if ( socket_is_socket( pSet->fd_array[i] ) ) { *pbSocketFound = TRUE; continue; } *pbNonSocketFound = TRUE; // If parHandles is NULL, then we're // only interested in the BOOLean flags... if ( !parHandles ) continue; ASSERT( *pdwHandles < ( 2 * FD_SETSIZE ) ); *( parHandles + *pdwHandles ) = (HANDLE) pSet->fd_array[i]; *pdwHandles++; } } ////////////////////////////////////////////////////////////////////////////////////////// struct MODE_TRANS { const char* old_mode; const char* new_mode; int new_flags; }; typedef struct MODE_TRANS MODE_TRANS; DLL_EXPORT FILE* w32_fdopen( int their_fd, const char* their_mode ) { int new_fd, new_flags = 0; const char* new_mode = NULL; MODE_TRANS* pModeTransTab; MODE_TRANS mode_trans_tab[] = { { "r", "rbc", _O_RDONLY | _O_BINARY }, { "r+", "r+bc", _O_RDWR | _O_BINARY }, { "r+b", "r+bc", _O_RDWR | _O_BINARY }, { "rb+", "r+bc", _O_RDWR | _O_BINARY }, { "w", "wbc", _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY }, { "w+", "w+bc", _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY }, { "w+b", "w+bc", _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY }, { "wb+", "w+bc", _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY }, { "a", "abc", _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY }, { "a+", "a+bc", _O_RDWR | _O_CREAT | _O_APPEND | _O_BINARY }, { "a+b", "a+bc", _O_RDWR | _O_CREAT | _O_APPEND | _O_BINARY }, { "ab+", "a+bc", _O_RDWR | _O_CREAT | _O_APPEND | _O_BINARY }, { NULL, NULL, 0 } }; ASSERT( their_mode ); // (we're only interested in socket calls) if ( !socket_is_socket( their_fd ) ) return _fdopen( their_fd, their_mode ); // The passed "file descriptor" is actually a SOCKET handle... // Translate their original mode to our new mode // and determine what flags we should use in our // call to _open_osfhandle()... if ( their_mode ) for (pModeTransTab = mode_trans_tab; pModeTransTab->old_mode; pModeTransTab++) if ( strcmp( their_mode, pModeTransTab->old_mode ) == 0 ) { new_mode = pModeTransTab->new_mode; new_flags = pModeTransTab->new_flags; break; } if ( !new_mode ) { errno = EINVAL; return NULL; } // Allocate a CRT file descriptor integer for this SOCKET... if ( ( new_fd = _open_osfhandle( their_fd, new_flags ) ) < 0 ) return NULL; // (errno already set) // Now we should be able to do the actual fdopen... return _fdopen( new_fd, new_mode ); } ////////////////////////////////////////////////////////////////////////////////////////// // fwrite DLL_EXPORT size_t w32_fwrite ( const void* buff, size_t size, size_t count, FILE* stream ) { int rc; SOCKET sock; ASSERT( buff && (size * count) && stream ); { int sd = fileno( stream ); if ( !socket_is_socket( sd ) ) return fwrite( buff, size, count, stream ); sock = (SOCKET) _get_osfhandle( sd ); } if ( ( rc = send( sock, buff, (int)(size * count), 0 ) ) == SOCKET_ERROR ) { errno = WSAGetLastError(); return -1; } return ( rc / size ); } ////////////////////////////////////////////////////////////////////////////////////////// // fprintf DLL_EXPORT int w32_fprintf( FILE* stream, const char* format, ... ) { char* buff = NULL; int bytes = 0, rc; va_list vl; SOCKET sock; ASSERT( stream && format ); va_start( vl, format ); { int sd = fileno( stream ); if ( !socket_is_socket( sd ) ) return vfprintf( stream, format, vl ); sock = (SOCKET) _get_osfhandle( sd ); } do { free( buff ); if ( !( buff = malloc( bytes += 1000 ) ) ) { errno = ENOMEM; return -1; } } while ( ( rc = vsnprintf( buff, bytes, format, vl ) ) < 0 ); rc = send( sock, buff, bytes = rc, 0 ); free( buff ); if ( SOCKET_ERROR == rc ) { errno = WSAGetLastError(); return -1; } return rc; } ////////////////////////////////////////////////////////////////////////////////////////// // fclose DLL_EXPORT int w32_fclose ( FILE* stream ) { int sd, rc, err; SOCKET sock; ASSERT( stream ); sd = fileno( stream ); if ( !socket_is_socket( sd ) ) return fclose( stream ); // (SOCKETs get special handling) sock = (SOCKET) _get_osfhandle( sd ); // Flush the data, close the socket, then deallocate // the crt's file descriptor for it by calling fclose. // Note that the fclose will fail since the closesocket // has already closed the o/s handle, but we don't care; // all we care about is the crt deallocating its file // descriptor for it... fflush( stream ); // (flush buffers) shutdown( sock, SD_BOTH); // (try to be graceful) rc = closesocket( sock ); // (close socket) err = WSAGetLastError(); // (save retcode) fclose( stream ); // (ignore likely error) if ( SOCKET_ERROR == rc ) // (closesocket error?) { errno = err; // (yes, return error) return EOF; // (failed) } return 0; // (success) } /****************************************************************************************\ (END) (Socket Handling Functions) (END) \****************************************************************************************/ // Create a child process with redirected standard file HANDLEs... // // For more information, see KB article 190351 "HOWTO: Spawn Console Processes // with Redirected Standard Handles" http://support.microsoft.com/?kbid=190351 #define PIPEBUFSIZE (1024) // SHOULD be big enough!! #define HOLDBUFSIZE (PIPEBUFSIZE*2) // twice pipe buffer size #define PIPE_THREAD_STACKSIZE (64*1024) // 64K should be plenty!! #define MSG_TRUNCATED_MSG "...(truncated)\n" char* buffer_overflow_msg = NULL; // used to trim received message size_t buffer_overflow_msg_len = 0; // length of above truncation msg ////////////////////////////////////////////////////////////////////////////////////////// // Fork control... typedef struct _PIPED_PROCESS_CTL { char* pszBuffer; // ptr to current logmsgs buffer size_t nAllocSize; // allocated size of logmsgs buffer size_t nStrLen; // amount used - 1 (because of NULL) CRITICAL_SECTION csLock; // lock for accessing above buffer } PIPED_PROCESS_CTL; typedef struct _PIPED_THREAD_CTL { HANDLE hStdXXX; // stdout or stderr handle PIPED_PROCESS_CTL* pPipedProcessCtl; // ptr to process control } PIPED_THREAD_CTL; ////////////////////////////////////////////////////////////////////////////////////////// // "Poor man's" fork... UINT WINAPI w32_read_piped_process_stdxxx_output_thread ( void* pThreadParm ); // (fwd ref) DLL_EXPORT pid_t w32_poor_mans_fork ( char* pszCommandLine, int* pnWriteToChildStdinFD ) { HANDLE hChildReadFromStdin; // child's stdin pipe HANDLE (inherited from us) HANDLE hChildWriteToStdout; // child's stdout pipe HANDLE (inherited from us) HANDLE hChildWriteToStderr; // child's stderr pipe HANDLE (inherited from us) HANDLE hOurWriteToStdin; // our HANDLE to write-end of child's stdin pipe HANDLE hOurReadFromStdout; // our HANDLE to read-end of child's stdout pipe HANDLE hOurReadFromStderr; // our HANDLE to read-end of child's stderr pipe HANDLE hOurProcess; // (temporary for creating pipes) HANDLE hPipeReadHandle; // (temporary for creating pipes) HANDLE hPipeWriteHandle; // (temporary for creating pipes) HANDLE hWorkerThread; // (worker thread to monitor child's pipe) DWORD dwThreadId; // (worker thread to monitor child's pipe) STARTUPINFO siStartInfo; // (info passed to CreateProcess) PROCESS_INFORMATION piProcInfo; // (info returned by CreateProcess) SECURITY_ATTRIBUTES saAttr; // (suckurity? we dunt need no stinkin suckurity!) char* pszNewCommandLine; // (because we build pvt copy for CreateProcess) BOOL bSuccess; // (work) int rc; // (work) size_t len; // (work) PIPED_PROCESS_CTL* pPipedProcessCtl = NULL; PIPED_THREAD_CTL* pPipedStdOutThreadCtl = NULL; PIPED_THREAD_CTL* pPipedStdErrThreadCtl = NULL; ////////////////////////////////////////////////// // Initialize fields... buffer_overflow_msg = MSG_TRUNCATED_MSG; buffer_overflow_msg_len = strlen( buffer_overflow_msg ); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.lpSecurityDescriptor = NULL; // (we dunt need no stinkin suckurity!) saAttr.bInheritHandle = TRUE; // (allows our inheritable HANDLEs // to be inherited by child) hOurProcess = GetCurrentProcess(); // (for creating pipes) ////////////////////////////////////////////////// // Only create a stdin pipe if caller will be providing the child's stdin data... if (!pnWriteToChildStdinFD) // (will caller be providing child's stdin?) { // PROGRAMMING NOTE: KB article 190351 "HOWTO: Spawn Console Processes with // Redirected Standard Handles" http://support.microsoft.com/?kbid=190351 // is WRONG! (or at the very least quite misleading!) // It states that for those stdio handles you do NOT wish to redirect, you // should use "GetStdHandle(STD_xxx_HANDLE)", but that ONLY works when you // have a console to begin with! (which Hercules would NOT have when started // via HercGUI for example (since it specifies "DETACHED_PROCESS" (i.e. no // console) whenever it starts it via its own CreateProcess call). // If you wish to only redirect *some* (but NOT *all*) stdio handles in your // CreateProcess call, the ONLY way to properly do so (regardless of whether // you have a console or not) is by specifying NULL. Specifying NULL for your // stdio handle tells CreateProcess to use the default value for that HANDLE. hChildReadFromStdin = NULL; // (no stdin redirection; use default) } else { // Create Stdin pipe for sending data to child... VERIFY(CreatePipe(&hChildReadFromStdin, &hPipeWriteHandle, &saAttr, PIPEBUFSIZE)); // Create non-inheritable duplcate of pipe handle for our own private use... VERIFY(DuplicateHandle ( hOurProcess, hPipeWriteHandle, // (handle to be duplicated) hOurProcess, &hOurWriteToStdin, // (non-inheritable duplicate) 0, FALSE, // (prevents child from inheriting it) DUPLICATE_SAME_ACCESS )); VERIFY(CloseHandle(hPipeWriteHandle)); // (MUST close so child won't hang!) } ////////////////////////////////////////////////// // Pipe child's Stdout output back to us... VERIFY(CreatePipe(&hPipeReadHandle, &hChildWriteToStdout, &saAttr, PIPEBUFSIZE)); // Create non-inheritable duplcate of pipe handle for our own private use... VERIFY(DuplicateHandle ( hOurProcess, hPipeReadHandle, // (handle to be duplicated) hOurProcess, &hOurReadFromStdout, // (non-inheritable duplicate) 0, FALSE, // (prevents child from inheriting it) DUPLICATE_SAME_ACCESS )); VERIFY(CloseHandle(hPipeReadHandle)); // (MUST close so child won't hang!) ////////////////////////////////////////////////// // Pipe child's Stderr output back to us... VERIFY(CreatePipe(&hPipeReadHandle, &hChildWriteToStderr, &saAttr, PIPEBUFSIZE)); // Create non-inheritable duplcate of pipe handle for our own private use... VERIFY(DuplicateHandle ( hOurProcess, hPipeReadHandle, // (handle to be duplicated) hOurProcess, &hOurReadFromStderr, // (non-inheritable duplicate) 0, FALSE, // (prevents child from inheriting it) DUPLICATE_SAME_ACCESS )); VERIFY(CloseHandle(hPipeReadHandle)); // (MUST close so child won't hang!) ////////////////////////////////////////////////// // Prepare for creation of child process... ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO )); siStartInfo.cb = sizeof(STARTUPINFO); // (size of structure) siStartInfo.dwFlags = STARTF_USESTDHANDLES; // (use redirected std HANDLEs) siStartInfo.hStdInput = hChildReadFromStdin; // (use redirected std HANDLEs) siStartInfo.hStdOutput = hChildWriteToStdout; // (use redirected std HANDLEs) siStartInfo.hStdError = hChildWriteToStderr; // (use redirected std HANDLEs) // Build the command-line for the system to create the child process with... len = strlen(pszCommandLine) + 1; pszNewCommandLine = malloc( len ); strlcpy( pszNewCommandLine, pszCommandLine, len ); ////////////////////////////////////////////////// // Now actually create the child process... ////////////////////////////////////////////////// bSuccess = CreateProcess ( NULL, // name of executable module = from command-line pszNewCommandLine, // command line with arguments NULL, // process security attributes = use defaults NULL, // primary thread security attributes = use defaults TRUE, // HANDLE inheritance flag = allow // (required when STARTF_USESTDHANDLES flag is used) 0, // NOTE! >>>---> // UNDOCUMENTED SECRET! MUST BE ZERO! Can't be "CREATE_NO_WINDOW" // nor "DETACHED_PROCESS", etc, or else it sometimes doesn't work // or else a console window appears! ("ipconfig" being one such // example). THIS IS NOT DOCUMENTED *ANYWHERE* IN ANY MICROSOFT // DOCUMENTATION THAT I COULD FIND! I only stumbled across it by // sheer good fortune in a news group post after some intensive // Googling and have experimentally verified it works as desired. NULL, // environment block ptr = make a copy from parent's NULL, // initial working directory = same as parent's &siStartInfo, // input STARTUPINFO pointer &piProcInfo // output PROCESS_INFORMATION ); rc = GetLastError(); // (save return code) // Close the HANDLEs we don't need... if (pnWriteToChildStdinFD) VERIFY(CloseHandle(hChildReadFromStdin)); // (MUST close so child won't hang!) VERIFY(CloseHandle(hChildWriteToStdout)); // (MUST close so child won't hang!) VERIFY(CloseHandle(hChildWriteToStderr)); // (MUST close so child won't hang!) CloseHandle(piProcInfo.hThread); // (we don't need this one) free(pszNewCommandLine); // (not needed anymore) // Check results... if (!bSuccess) { TRACE("*** CreateProcess() failed! rc = %d : %s\n", rc,w32_strerror(rc)); if (pnWriteToChildStdinFD) VERIFY(CloseHandle(hOurWriteToStdin)); VERIFY(CloseHandle(hOurReadFromStdout)); VERIFY(CloseHandle(hOurReadFromStderr)); errno = rc; return -1; } // Allocate/intialize control blocks for piped process/thread control... // If we were passed a pnWriteToChildStdinFD pointer, then the caller // is in charge of the process and will handle message capturing/logging // (such as is done with the print-to-pipe facility). // Otherwise (pnWriteToChildStdinFD is NULL) the caller wishes for us // to capture the piped process's o/p, so we pass a PIPED_PROCESS_CTL // structure to the stdout/stderr monitoring threads. This structure // contains a pointer to a buffer where they can accumulate messages. // Then once the process exits WE will then issue the "logmsg". This // is necessary in order to "capture" the process's o/p since the logmsg // capture facility is designed to capture o/p for a specific thread, // where that thread is US! (else if we let the monitoring thread issue // the logmsg's, they'll never get captured since they don't have the // same thread-id as the thread that started the capture, which was us! // (actually it was the caller, but we're the same thread as they are!)). pPipedStdOutThreadCtl = malloc( sizeof(PIPED_THREAD_CTL) ); pPipedStdErrThreadCtl = malloc( sizeof(PIPED_THREAD_CTL) ); pPipedStdOutThreadCtl->hStdXXX = hOurReadFromStdout; pPipedStdErrThreadCtl->hStdXXX = hOurReadFromStderr; if ( !pnWriteToChildStdinFD ) { pPipedProcessCtl = malloc( sizeof(PIPED_PROCESS_CTL) ); pPipedStdOutThreadCtl->pPipedProcessCtl = pPipedProcessCtl; pPipedStdErrThreadCtl->pPipedProcessCtl = pPipedProcessCtl; InitializeCriticalSection( &pPipedProcessCtl->csLock ); pPipedProcessCtl->nAllocSize = 1; // (purposely small for debugging) pPipedProcessCtl->pszBuffer = malloc( 1 ); // (purposely small for debugging) *pPipedProcessCtl->pszBuffer = 0; // (null terminate string buffer) pPipedProcessCtl->nStrLen = 0; // (no msgs yet) } else { pPipedStdOutThreadCtl->pPipedProcessCtl = NULL; pPipedStdErrThreadCtl->pPipedProcessCtl = NULL; } ////////////////////////////////////////////////// // Create o/p pipe monitoring worker threads... ////////////////////////////////////////////////// // Stdout... hWorkerThread = (HANDLE) _beginthreadex ( NULL, // pointer to security attributes = use defaults PIPE_THREAD_STACKSIZE, // initial thread stack size w32_read_piped_process_stdxxx_output_thread, pPipedStdOutThreadCtl, // thread argument 0, // special creation flags = none needed &dwThreadId // pointer to receive thread ID ); rc = GetLastError(); // (save return code) if (!hWorkerThread || INVALID_HANDLE_VALUE == hWorkerThread) { TRACE("*** _beginthreadex() failed! rc = %d : %s\n", rc,w32_strerror(rc)); if (pnWriteToChildStdinFD) VERIFY(CloseHandle(hOurWriteToStdin)); VERIFY(CloseHandle(hOurReadFromStdout)); VERIFY(CloseHandle(hOurReadFromStderr)); if ( !pnWriteToChildStdinFD ) { DeleteCriticalSection( &pPipedProcessCtl->csLock ); free( pPipedProcessCtl->pszBuffer ); free( pPipedProcessCtl ); } free( pPipedStdOutThreadCtl ); free( pPipedStdErrThreadCtl ); errno = rc; return -1; } else VERIFY(CloseHandle(hWorkerThread)); // (not needed anymore) SET_THREAD_NAME_ID(dwThreadId,"w32_read_piped_process_stdOUT_output_thread"); ////////////////////////////////////////////////// // Stderr... hWorkerThread = (HANDLE) _beginthreadex ( NULL, // pointer to security attributes = use defaults PIPE_THREAD_STACKSIZE, // initial thread stack size w32_read_piped_process_stdxxx_output_thread, pPipedStdErrThreadCtl, // thread argument 0, // special creation flags = none needed &dwThreadId // pointer to receive thread ID ); rc = GetLastError(); // (save return code) if (!hWorkerThread || INVALID_HANDLE_VALUE == hWorkerThread) { TRACE("*** _beginthreadex() failed! rc = %d : %s\n", rc,w32_strerror(rc)); if (pnWriteToChildStdinFD) VERIFY(CloseHandle(hOurWriteToStdin)); VERIFY(CloseHandle(hOurReadFromStdout)); VERIFY(CloseHandle(hOurReadFromStderr)); if ( !pnWriteToChildStdinFD ) { DeleteCriticalSection( &pPipedProcessCtl->csLock ); free( pPipedProcessCtl->pszBuffer ); free( pPipedProcessCtl ); } free( pPipedStdOutThreadCtl ); free( pPipedStdErrThreadCtl ); errno = rc; return -1; } else VERIFY(CloseHandle(hWorkerThread)); // (not needed anymore) SET_THREAD_NAME_ID(dwThreadId,"w32_read_piped_process_stdERR_output_thread"); // Piped process capture handling... if ( !pnWriteToChildStdinFD ) { // We're in control of the process... // Wait for it to exit... WaitForSingleObject( piProcInfo.hProcess, INFINITE ); CloseHandle( piProcInfo.hProcess ); // Now print ALL captured messages AT ONCE (if any)... while (pPipedProcessCtl->nStrLen && isspace( pPipedProcessCtl->pszBuffer[ pPipedProcessCtl->nStrLen - 1 ] )) pPipedProcessCtl->nStrLen--; if (pPipedProcessCtl->nStrLen) { pPipedProcessCtl->pszBuffer[ pPipedProcessCtl->nStrLen ] = 0; // (null terminate) logmsg( "%s", pPipedProcessCtl->pszBuffer ); } // Free resources... DeleteCriticalSection( &pPipedProcessCtl->csLock ); free( pPipedProcessCtl->pszBuffer ); free( pPipedProcessCtl ); } else { // Caller is in control of the process... CloseHandle( piProcInfo.hProcess ); // Return a C run-time file descriptor // for the write-to-child-stdin HANDLE... *pnWriteToChildStdinFD = _open_osfhandle( (intptr_t) hOurWriteToStdin, 0 ); } // Success! return piProcInfo.dwProcessId; // (return process-id to caller) } ////////////////////////////////////////////////////////////////////////////////////////// // Thread to read message data from the child process's stdxxx o/p pipe... void w32_parse_piped_process_stdxxx_data ( PIPED_PROCESS_CTL* pPipedProcessCtl, char* holdbuff, int* pnHoldAmount ); UINT WINAPI w32_read_piped_process_stdxxx_output_thread ( void* pThreadParm ) { PIPED_THREAD_CTL* pPipedStdXXXThreadCtl = NULL; PIPED_PROCESS_CTL* pPipedProcessCtl = NULL; HANDLE hOurReadFromStdxxx = NULL; DWORD nAmountRead = 0; int nHoldAmount = 0; BOOL oflow = FALSE; unsigned nRetcode = 0; char readbuff [ PIPEBUFSIZE ]; char holdbuff [ HOLDBUFSIZE ]; // Extract parms pPipedStdXXXThreadCtl = (PIPED_THREAD_CTL*) pThreadParm; pPipedProcessCtl = pPipedStdXXXThreadCtl->pPipedProcessCtl; hOurReadFromStdxxx = pPipedStdXXXThreadCtl->hStdXXX; free( pPipedStdXXXThreadCtl ); // (prevent memory leak) // Begin work... for (;;) { if (!ReadFile(hOurReadFromStdxxx, readbuff, PIPEBUFSIZE-1, &nAmountRead, NULL)) { if (ERROR_BROKEN_PIPE == (nRetcode = GetLastError())) nRetcode = 0; // (else keep value returned from GetLastError()) break; } *(readbuff+nAmountRead) = 0; if (!nAmountRead) break; // (pipe closed (i.e. broken pipe); time to exit) if ((nHoldAmount + nAmountRead) >= (HOLDBUFSIZE-1)) { // OVERFLOW! append "truncated" string and force end-of-msg... oflow = TRUE; memcpy( holdbuff + nHoldAmount, readbuff, HOLDBUFSIZE - nHoldAmount); strcpy( readbuff, buffer_overflow_msg); nAmountRead = (DWORD)buffer_overflow_msg_len; nHoldAmount = HOLDBUFSIZE - nAmountRead - 1; } // Append new data to end of hold buffer... memcpy(holdbuff+nHoldAmount,readbuff,nAmountRead); nHoldAmount += nAmountRead; *(holdbuff+nHoldAmount) = 0; // Pass all existing data to parsing function... w32_parse_piped_process_stdxxx_data( pPipedProcessCtl, holdbuff, &nHoldAmount ); if (oflow) ASSERT(!nHoldAmount); oflow = FALSE; } // Finish up... CloseHandle( hOurReadFromStdxxx ); // (prevent HANDLE leak) return nRetcode; } ////////////////////////////////////////////////////////////////////////////////////////// // Parse piped child's stdout/stderr o/p data into individual newline delimited // messages for displaying on the Hercules hardware console... void w32_parse_piped_process_stdxxx_data ( PIPED_PROCESS_CTL* pPipedProcessCtl, char* holdbuff, int* pnHoldAmount ) { // This function executes in the context of the worker thread that calls it. char* pbeg; // ptr to start of message char* pend; // find end of message (MUST NOT BE MODIFIED!) char* pmsgend; // work ptr to end of message // 'pend' variable MUST NOT BE MODIFIED int nlen; // work length of one message int ntotlen; // accumulated length of all parsed messages // A worker thread that monitors a child's Stdout o/p has received a message // and is calling this function to determine what, if anything, to do with it. // (Note: the worker thread that calls us ensures holdbuff is null terminated) pbeg = holdbuff; // ptr to start of message pend = strchr(pbeg,'\n'); // find end of message (MUST NOT BE MODIFIED!) if (!pend) return; // we don't we have a complete message yet ntotlen = 0; // accumulated length of all parsed messages // Parse the message... do { nlen = (pend-pbeg); // get length of THIS message ntotlen += nlen + 1; // keep track of all that we see // Remove trailing newline character and any other trailing blanks... // (Note: we MUST NOT MODIFY the 'pend' variable. It should always // point to where the newline character was found so we can start // looking for the next message (if there is one) where this message // ended). *pend = 0; // (change newline character to null) pmsgend = pend; // (start removing blanks from here) while (--pmsgend >= pbeg && isspace(*pmsgend)) {*pmsgend = 0; --nlen;} // If we were passed a PIPED_PROCESS_CTL pointer, then the root thread // wants us to just capture the o/p and IT will issue the logmsg within // its own thread. Otherwise root thread isn't interested in capturing // and thus we must issue the individual logmsg's ourselves... if (!pPipedProcessCtl) { logmsg("%s\n",pbeg); // send all child's msgs to Herc console } else { size_t nNewStrLen, nAllocSizeNeeded; // (work) EnterCriticalSection( &pPipedProcessCtl->csLock ); nNewStrLen = strlen( pbeg ); nAllocSizeNeeded = ((((pPipedProcessCtl->nStrLen + nNewStrLen + 2) / 4096) + 1) * 4096); if ( nAllocSizeNeeded > pPipedProcessCtl->nAllocSize ) { pPipedProcessCtl->nAllocSize = nAllocSizeNeeded; pPipedProcessCtl->pszBuffer = realloc( pPipedProcessCtl->pszBuffer, nAllocSizeNeeded ); ASSERT( pPipedProcessCtl->pszBuffer ); } if (nNewStrLen) { memcpy( pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen, pbeg, nNewStrLen ); pPipedProcessCtl->nStrLen += nNewStrLen; } *(pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen) = '\n'; pPipedProcessCtl->nStrLen++; *(pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen) = '\0'; ASSERT( pPipedProcessCtl->nStrLen <= pPipedProcessCtl->nAllocSize ); LeaveCriticalSection( &pPipedProcessCtl->csLock ); } // 'pend' should still point to the end of this message (where newline was) pbeg = (pend + 1); // point to beg of next message (if any) if (pbeg >= (holdbuff + *pnHoldAmount)) // past end of data? { pbeg = pend; // re-point back to our null ASSERT(*pbeg == 0); // sanity check break; // we're done with this batch } pend = strchr(pbeg,'\n'); // is there another message? } while (pend); // while messages remain... if (ntotlen > *pnHoldAmount) // make sure we didn't process too much { TRACE("*** ParseStdxxxMsg logic error! ***\n"); ASSERT(FALSE); // oops! } // 'Remove' the messages that we parsed from the caller's hold buffer by // sliding the remainder to the left (i.e. left justifying the remainder // in their hold buffer) and then telling them how much data now remains // in their hold buffer. // IMPORTANT PROGRAMMING NOTE! We must use memmove here and not strcpy! // strcpy doesn't work correctly for overlapping source and destination. // If there's 100 bytes remaining and we just want to slide it left by 1 // byte (just as an illustrative example), strcpy screws up. This is more // than likely because strcpy is trying to be as efficient as possible and // is grabbing multiple bytes at a time from the source string and plonking // them down into the destination string, thus wiping out part of our source // string. Thus, we MUST use memmove here and NOT strcpy. if ((*pnHoldAmount = (int)strlen(pbeg)) > 0) // new amount of data remaining memmove(holdbuff,pbeg,*pnHoldAmount); // slide left justify remainder } ////////////////////////////////////////////////////////////////////////////////////////// // The following is documented in Microsoft's Visual Studio developer documentation... #define MS_VC_EXCEPTION 0x406D1388 // (special value) typedef struct tagTHREADNAME_INFO { DWORD dwType; // must be 0x1000 LPCSTR pszName; // pointer to name (in same addr space) DWORD dwThreadID; // thread ID (-1 caller thread) DWORD dwFlags; // reserved for future use, must be zero } THREADNAME_INFO; DLL_EXPORT void w32_set_thread_name( TID tid, char* name ) { THREADNAME_INFO info; if (!name) return; // (ignore premature calls) info.dwType = 0x1000; info.pszName = name; // (should really be LPCTSTR) info.dwThreadID = tid; // (-1 == current thread, else tid) info.dwFlags = 0; __try { RaiseException( MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (const ULONG_PTR*)&info ); } __except ( EXCEPTION_CONTINUE_EXECUTION ) { /* (do nothing) */ } } ////////////////////////////////////////////////////////////////////////////////////////// // Hercules file open // w32_hopen is called instead of hopen in MSVC environment (see hercwind.h) // Its purpose is to prevent a file from being opened for output by two // Hercules instances at the same time. // _SH_DENYRW prevents all access to the file from other processes; // _SH_DENYWR permits other processes to read the file but not to write; // _SH_SECURE opens the file in _SH_DENYRW mode if oflag specifies write // access, or _SH_DENYWR mode if oflag specifies read-only. DLL_EXPORT int w32_hopen( const char* path, int oflag, ... ) { int shflag = (oflag & _O_RDWR) ? _SH_DENYRW : _SH_DENYWR; int pmode = 0; if (oflag & _O_CREAT) { va_list vargs; va_start( vargs, oflag ); pmode = va_arg( vargs, int ); } return _sopen( path, oflag, shflag, pmode ); } ////////////////////////////////////////////////////////////////////////////////////////// #endif // defined( _MSVC_ ) hercules-3.12/strsignal.c0000664000175000017500000002444312564723224012364 00000000000000/* strsignal.c -- implement strsignal() for architectures without it Written by Fred Fish. fnf@cygnus.com This file is in the public domain. */ #include "hstdinc.h" #include "hercules.h" #if !defined(HAVE_STRSIGNAL) /* We need to declare sys_siglist, because even if the system provides it we can't assume that it is declared in (for example, SunOS provides sys_siglist, but it does not declare it in any header file). fHowever, we can't declare sys_siglist portably, because on some systems it is declared with const and on some systems it is declared without const. If we were using autoconf, we could work out the right declaration. Until, then we just ignore any declaration in the system header files, and always declare it ourselves. With luck, this will always work. */ #define sys_siglist no_such_symbol /* Routines imported from standard C runtime libraries. */ #ifdef __STDC__ #include extern void *malloc (size_t size); /* 4.10.3.3 */ extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */ #else /* !__STDC__ */ extern char *malloc (); /* Standard memory allocater */ extern char *memset (); #endif /* __STDC__ */ /* Undefine the macro we used to hide the definition of sys_siglist found in the system header files. */ #undef sys_siglist #ifndef NULL # ifdef __STDC__ # define NULL (void *) 0 # else # define NULL 0 # endif #endif #ifndef MAX # define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif /* Translation table for signal values. Note that this table is generally only accessed when it is used at runtime to initialize signal name and message tables that are indexed by signal value. Not all of these signals will exist on all systems. This table is the only thing that should have to be updated as new signal numbers are introduced. It's sort of ugly, but at least its portable. */ struct signal_info { int value; /* The numeric value from */ const char *name; /* The equivalent symbolic value */ #ifndef HAVE_SYS_SIGLIST const char *msg; /* Short message about this value */ #endif }; #ifndef HAVE_SYS_SIGLIST # define ENTRY(value, name, msg) {value, name, msg} #else # define ENTRY(value, name, msg) {value, name} #endif static const struct signal_info signal_table[] = { #if defined (SIGHUP) ENTRY(SIGHUP, "SIGHUP", "Hangup"), #endif #if defined (SIGINT) ENTRY(SIGINT, "SIGINT", "Interrupt"), #endif #if defined (SIGQUIT) ENTRY(SIGQUIT, "SIGQUIT", "Quit"), #endif #if defined (SIGILL) ENTRY(SIGILL, "SIGILL", "Illegal instruction"), #endif #if defined (SIGTRAP) ENTRY(SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"), #endif /* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */ #if defined (SIGIOT) ENTRY(SIGIOT, "SIGIOT", "IOT trap"), #endif #if defined (SIGABRT) ENTRY(SIGABRT, "SIGABRT", "Aborted"), #endif #if defined (SIGEMT) ENTRY(SIGEMT, "SIGEMT", "Emulation trap"), #endif #if defined (SIGFPE) ENTRY(SIGFPE, "SIGFPE", "Arithmetic exception"), #endif #if defined (SIGKILL) ENTRY(SIGKILL, "SIGKILL", "Killed"), #endif #if defined (SIGBUS) ENTRY(SIGBUS, "SIGBUS", "Bus error"), #endif #if defined (SIGSEGV) ENTRY(SIGSEGV, "SIGSEGV", "Segmentation fault"), #endif #if defined (SIGSYS) ENTRY(SIGSYS, "SIGSYS", "Bad system call"), #endif #if defined (SIGPIPE) ENTRY(SIGPIPE, "SIGPIPE", "Broken pipe"), #endif #if defined (SIGALRM) ENTRY(SIGALRM, "SIGALRM", "Alarm clock"), #endif #if defined (SIGTERM) ENTRY(SIGTERM, "SIGTERM", "Terminated"), #endif #if defined (SIGUSR1) ENTRY(SIGUSR1, "SIGUSR1", "User defined signal 1"), #endif #if defined (SIGUSR2) ENTRY(SIGUSR2, "SIGUSR2", "User defined signal 2"), #endif /* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD overrides SIGCLD. SIGCHLD is in POXIX.1 */ #if defined (SIGCLD) ENTRY(SIGCLD, "SIGCLD", "Child status changed"), #endif #if defined (SIGCHLD) ENTRY(SIGCHLD, "SIGCHLD", "Child status changed"), #endif #if defined (SIGPWR) ENTRY(SIGPWR, "SIGPWR", "Power fail/restart"), #endif #if defined (SIGWINCH) ENTRY(SIGWINCH, "SIGWINCH", "Window size changed"), #endif #if defined (SIGURG) ENTRY(SIGURG, "SIGURG", "Urgent I/O condition"), #endif #if defined (SIGIO) /* "I/O pending" has also been suggested, but is misleading since the signal only happens when the process has asked for it, not everytime I/O is pending. */ ENTRY(SIGIO, "SIGIO", "I/O possible"), #endif #if defined (SIGPOLL) ENTRY(SIGPOLL, "SIGPOLL", "Pollable event occurred"), #endif #if defined (SIGSTOP) ENTRY(SIGSTOP, "SIGSTOP", "Stopped (signal)"), #endif #if defined (SIGTSTP) ENTRY(SIGTSTP, "SIGTSTP", "Stopped (user)"), #endif #if defined (SIGCONT) ENTRY(SIGCONT, "SIGCONT", "Continued"), #endif #if defined (SIGTTIN) ENTRY(SIGTTIN, "SIGTTIN", "Stopped (tty input)"), #endif #if defined (SIGTTOU) ENTRY(SIGTTOU, "SIGTTOU", "Stopped (tty output)"), #endif #if defined (SIGVTALRM) ENTRY(SIGVTALRM, "SIGVTALRM", "Virtual timer expired"), #endif #if defined (SIGPROF) ENTRY(SIGPROF, "SIGPROF", "Profiling timer expired"), #endif #if defined (SIGXCPU) ENTRY(SIGXCPU, "SIGXCPU", "CPU time limit exceeded"), #endif #if defined (SIGXFSZ) ENTRY(SIGXFSZ, "SIGXFSZ", "File size limit exceeded"), #endif #if defined (SIGWIND) ENTRY(SIGWIND, "SIGWIND", "SIGWIND"), #endif #if defined (SIGPHONE) ENTRY(SIGPHONE, "SIGPHONE", "SIGPHONE"), #endif #if defined (SIGLOST) ENTRY(SIGLOST, "SIGLOST", "Resource lost"), #endif #if defined (SIGWAITING) ENTRY(SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"), #endif #if defined (SIGLWP) ENTRY(SIGLWP, "SIGLWP", "Signal LWP"), #endif #if defined (SIGDANGER) ENTRY(SIGDANGER, "SIGDANGER", "Swap space dangerously low"), #endif #if defined (SIGGRANT) ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"), #endif #if defined (SIGRETRACT) ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"), #endif #if defined (SIGMSG) ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"), #endif #if defined (SIGSOUND) ENTRY(SIGSOUND, "SIGSOUND", "Sound completed"), #endif #if defined (SIGSAK) ENTRY(SIGSAK, "SIGSAK", "Secure attention"), #endif ENTRY(0, NULL, NULL) }; /* Translation table allocated and initialized at runtime. Indexed by the signal value to find the equivalent symbolic value. */ static const char **signal_names; static int num_signal_names = 0; /* Translation table allocated and initialized at runtime, if it does not already exist in the host environment. Indexed by the signal value to find the descriptive string. We don't export it for use in other modules because even though it has the same name, it differs from other implementations in that it is dynamically initialized rather than statically initialized. */ #ifndef HAVE_SYS_SIGLIST static int sys_nsig; static const char **sys_siglist; #else #ifdef NSIG static int sys_nsig = NSIG; #else #ifdef _NSIG static int sys_nsig = _NSIG; #endif #endif extern const char * const sys_siglist[]; #endif #ifndef HAVE_SYS_SIGLIST /* NAME init_signal_tables -- initialize the name and message tables SYNOPSIS static void init_signal_tables (); DESCRIPTION Using the signal_table, which is initialized at compile time, generate the signal_names and the sys_siglist (if needed) tables, which are indexed at runtime by a specific signal value. BUGS The initialization of the tables may fail under low memory conditions, in which case we don't do anything particularly useful, but we don't bomb either. Who knows, it might succeed at a later point if we free some memory in the meantime. In any case, the other routines know how to deal with lack of a table after trying to initialize it. This may or may not be considered to be a bug, that we don't specifically warn about this particular failure mode. */ static void init_signal_tables () { const struct signal_info *eip; int nbytes; /* If we haven't already scanned the signal_table once to find the maximum signal value, then go find it now. */ if (num_signal_names == 0) { for (eip = signal_table; eip -> name != NULL; eip++) { if (eip -> value >= num_signal_names) { num_signal_names = eip -> value + 1; } } } /* Now attempt to allocate the sys_siglist table, zero it out, and then initialize it from the statically initialized signal_table. */ if (sys_siglist == NULL) { nbytes = num_signal_names * sizeof (char *); if ((sys_siglist = (const char **) malloc (nbytes)) != NULL) { memset (sys_siglist, 0, nbytes); sys_nsig = num_signal_names; for (eip = signal_table; eip -> name != NULL; eip++) { sys_siglist[eip -> value] = eip -> msg; } } } } #endif /* NAME strsignal -- map a signal number to a signal message string SYNOPSIS const char *strsignal (int signo) DESCRIPTION Maps an signal number to an signal message string, the contents of which are implementation defined. On systems which have the external variable sys_siglist, these strings will be the same as the ones used by psignal(). If the supplied signal number is within the valid range of indices for the sys_siglist, but no message is available for the particular signal number, then returns the string "Signal NUM", where NUM is the signal number. If the supplied signal number is not a valid index into sys_siglist, returns NULL. The returned string is only guaranteed to be valid only until the next call to strsignal. */ const char * strsignal (signo) int signo; { const char *msg; static char buf[32]; #ifndef HAVE_SYS_SIGLIST if (signal_names == NULL) { init_signal_tables (); } #endif if ((signo < 0) || (signo >= sys_nsig)) { /* Out of range, just return NULL */ msg = NULL; } else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL)) { /* In range, but no sys_siglist or no entry at this index. */ sprintf (buf, "Signal %d", signo); msg = (const char *) buf; } else { /* In range, and a valid message. Just return the message. */ msg = (const char *) sys_siglist[signo]; } return (msg); } #endif // !defined(HAVE_STRSIGNAL) hercules-3.12/impl.c0000664000175000017500000005361512564723224011322 00000000000000/* IMPL.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Initialization Module */ /*-------------------------------------------------------------------*/ /* This module initializes the Hercules S/370 or ESA/390 emulator. */ /* It builds the system configuration blocks, creates threads for */ /* central processors, HTTP server, logger task and activates the */ /* control panel which runs under the main thread when in foreground */ /* mode. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _IMPL_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "opcode.h" #include "devtype.h" #include "herc_getopt.h" #include "hostinfo.h" #include "history.h" /* (delayed_exit function defined in config.c) */ extern void delayed_exit (int exit_code); /* forward define process_script_file (ISW20030220-3) */ int process_script_file(char *,int); static LOGCALLBACK log_callback=NULL; /*-------------------------------------------------------------------*/ /* Register a LOG callback */ /*-------------------------------------------------------------------*/ DLL_EXPORT void registerLogCallback(LOGCALLBACK lcb) { log_callback=lcb; } /*-------------------------------------------------------------------*/ /* Signal handler for SIGINT signal */ /*-------------------------------------------------------------------*/ static void sigint_handler (int signo) { // logmsg ("impl.c: sigint handler entered for thread %lu\n",/*debug*/ // thread_id()); /*debug*/ UNREFERENCED(signo); signal(SIGINT, sigint_handler); /* Ignore signal unless presented on console thread */ if ( !equal_threads( thread_id(), sysblk.cnsltid ) ) return; /* Exit if previous SIGINT request was not actioned */ if (sysblk.sigintreq) { /* Release the configuration */ release_config(); delayed_exit(1); } /* Set SIGINT request pending flag */ sysblk.sigintreq = 1; /* Activate instruction stepping */ sysblk.inststep = 1; SET_IC_TRACE; return; } /* end function sigint_handler */ /*-------------------------------------------------------------------*/ /* Signal handler for SIGTERM signal */ /*-------------------------------------------------------------------*/ static void sigterm_handler (int signo) { // logmsg ("impl.c: sigterm handler entered for thread %lu\n",/*debug*/ // thread_id()); /*debug*/ UNREFERENCED(signo); signal(SIGTERM, sigterm_handler); /* Ignore signal unless presented on main program (impl) thread */ if ( !equal_threads( thread_id(), sysblk.impltid ) ) return; /* Initiate system shutdown */ do_shutdown(); return; } /* end function sigterm_handler */ #if defined( _MSVC_ ) /*-------------------------------------------------------------------*/ /* Signal handler for Windows signals */ /*-------------------------------------------------------------------*/ BOOL WINAPI console_ctrl_handler (DWORD signo) { int i; SetConsoleCtrlHandler(console_ctrl_handler, FALSE); // turn handler off while processing switch ( signo ) { case CTRL_BREAK_EVENT: logmsg(_("HHCIN050ICtrl-Break intercepted. Interrupt Key depressed simulated.\n")); OBTAIN_INTLOCK(NULL); ON_IC_INTKEY; /* Signal waiting CPUs that an interrupt is pending */ WAKEUP_CPUS_MASK (sysblk.waiting_mask); RELEASE_INTLOCK(NULL); SetConsoleCtrlHandler(console_ctrl_handler, TRUE); // reset handler return TRUE; break; case CTRL_C_EVENT: logmsg(_("HHCIN022I Ctrl-C intercepted\n")); SetConsoleCtrlHandler(console_ctrl_handler, TRUE); // reset handler return TRUE; break; case CTRL_CLOSE_EVENT: case CTRL_SHUTDOWN_EVENT: case CTRL_LOGOFF_EVENT: if ( !sysblk.shutdown ) // (system shutdown not initiated) { logmsg(_("HHCIN021ICLOSE Event received, SHUTDOWN Immediate starting...\n")); sysblk.shutimmed = TRUE; do_shutdown(); // logmsg("%s(%d): return from shutdown\n", __FILE__, __LINE__ ); /* debug */ for ( i = 0; i < 120; i++ ) { if ( sysblk.shutdown && sysblk.shutfini ) { // logmsg("%s(%d): %d shutdown completed\n", /* debug */ // __FILE__, __LINE__, i ); /* debug */ sleep(1); break; } else { // logmsg("%s(%d): %d waiting for shutdown to complete\n", /* debug */ // __FILE__, __LINE__, i ); /* debug */ sleep(1); } } socket_deinit(); } else { logmsg(_("HHCIN023W CLOSE Event received, SHUTDOWN previously requested...\n")); } usleep(10000); return FALSE; break; default: return FALSE; } } /* end function console_ctrl_handler */ #endif #if !defined(NO_SIGABEND_HANDLER) static void *watchdog_thread(void *arg) { S64 savecount[MAX_CPU_ENGINES]; int i; UNREFERENCED(arg); /* Set watchdog priority just below cpu priority such that it will not invalidly detect an inoperable cpu */ if(sysblk.cpuprio >= 0) setpriority(PRIO_PROCESS, 0, sysblk.cpuprio+1); for (i = 0; i < MAX_CPU_ENGINES; i ++) savecount[i] = -1; while(!sysblk.shutdown) { for (i = 0; i < MAX_CPU; i++) { // obtain_lock (&sysblk.cpulock[i]); if (IS_CPU_ONLINE(i) && sysblk.regs[i]->cpustate == CPUSTATE_STARTED && (!WAITSTATE(&sysblk.regs[i]->psw) #if defined(_FEATURE_WAITSTATE_ASSIST) && !(sysblk.regs[i]->sie_active && WAITSTATE(&sysblk.regs[i]->guestregs->psw)) #endif )) { /* If the cpu is running but not executing instructions then it must be malfunctioning */ if((INSTCOUNT(sysblk.regs[i]) == (U64)savecount[i]) && !HDC1(debug_watchdog_signal, sysblk.regs[i]) ) { /* Send signal to looping CPU */ signal_thread(sysblk.cputid[i], SIGUSR1); savecount[i] = -1; } else /* Save current instcount */ savecount[i] = INSTCOUNT(sysblk.regs[i]); } else /* mark savecount invalid as CPU not in running state */ savecount[i] = -1; // release_lock (&sysblk.cpulock[i]); } /* Sleep for 20 seconds */ SLEEP(20); } return NULL; } #endif /*!defined(NO_SIGABEND_HANDLER)*/ void *log_do_callback(void *dummy) { char *msgbuf; int msgcnt = -1,msgnum; UNREFERENCED(dummy); while(msgcnt) { if((msgcnt = log_read(&msgbuf, &msgnum, LOG_BLOCK))) { log_callback(msgbuf,msgcnt); } } return(NULL); } DLL_EXPORT COMMANDHANDLER getCommandHandler(void) { return(panel_command); } /*-------------------------------------------------------------------*/ /* Process .RC file thread */ /*-------------------------------------------------------------------*/ void* process_rc_file (void* dummy) { char *rcname; /* hercules.rc name pointer */ int is_default_rc = 0; /* 1 == default name used */ int numcpu = 0; /* #of ONLINE & STOPPED CPUs */ int i; /* (work) */ UNREFERENCED(dummy); /* Wait for all installed/configured CPUs to come ONLINE and enter the STOPPED state */ OBTAIN_INTLOCK(NULL); for (;;) { numcpu = 0; for (i = 0; i < MAX_CPU_ENGINES; i++) if (IS_CPU_ONLINE(i) && CPUSTATE_STOPPED == sysblk.regs[i]->cpustate) numcpu++; if (numcpu == sysblk.numcpu) break; RELEASE_INTLOCK(NULL); usleep( 10 * 1000 ); OBTAIN_INTLOCK(NULL); } RELEASE_INTLOCK(NULL); /* Wait for panel thread to engage */ while (!sysblk.panel_init) usleep( 10 * 1000 ); /* Obtain the name of the hercules.rc file or default */ if (!(rcname = getenv("HERCULES_RC"))) { rcname = "hercules.rc"; is_default_rc = 1; } #if defined(OPTION_HAO) /* Initialize the Hercules Automatic Operator */ if ( !hao_initialize() ) logmsg(_("HHCIN004S Cannot create HAO thread: %s\n"), strerror(errno)); #endif /* defined(OPTION_HAO) */ /* Run the script processor for this file */ if (process_script_file(rcname,1) != 0) if (ENOENT == errno) if (!is_default_rc) logmsg(_("HHCPN995E .RC file \"%s\" not found.\n"), rcname); // (else error message already issued) return NULL; } /*-------------------------------------------------------------------*/ /* IMPL main entry point */ /*-------------------------------------------------------------------*/ DLL_EXPORT int impl(int argc, char *argv[]) { char *cfgfile; /* -> Configuration filename */ int c; /* Work area for getopt */ int arg_error = 0; /* 1=Invalid arguments */ char *msgbuf; /* */ int msgnum; /* */ int msgcnt; /* */ TID rctid; /* RC file thread identifier */ TID logcbtid; /* RC file thread identifier */ SET_THREAD_NAME("impl"); /* Initialize 'hostinfo' BEFORE display_version is called */ init_hostinfo( &hostinfo ); #ifdef _MSVC_ /* Initialize sockets package */ VERIFY( socket_init() == 0 ); #endif /* Ensure hdl_shut is called in case of shutdown hdl_shut will ensure entries are only called once */ atexit(hdl_shut); set_codepage(NULL); /* Clear the system configuration block */ memset (&sysblk, 0, sizeof(SYSBLK)); /* Save thread ID of main program */ sysblk.impltid = thread_id(); /* Save TOD of when we were first IMPL'ed */ time( &sysblk.impltime ); #ifdef OPTION_MSGHLD /* Set the default timeout value */ sysblk.keep_timeout_secs = 120; #endif /* Initialize thread creation attributes so all of hercules can use them at any time when they need to create_thread */ initialize_detach_attr (DETACHED); initialize_join_attr (JOINABLE); /* Copy length for regs */ sysblk.regs_copy_len = (int)((uintptr_t)&sysblk.dummyregs.regs_copy_end - (uintptr_t)&sysblk.dummyregs); /* Set the daemon_mode flag indicating whether we running in background/daemon mode or not (meaning both stdout/stderr are redirected to a non-tty device). Note that this flag needs to be set before logger_init gets called since the logger_logfile_write function relies on its setting. */ sysblk.daemon_mode = !isatty(STDERR_FILENO) && !isatty(STDOUT_FILENO); /* Initialize the logmsg pipe and associated logger thread. This causes all subsequent logmsg's to be redirected to the logger facility for handling by virtue of stdout/stderr being redirected to the logger facility. */ logger_init(); /* Now display the version information again after logger_init has been called so that either the panel display thread or the external gui can see the version which was previously possibly only displayed to the actual physical screen the first time we did it further above (depending on whether we're running in daemon_mode (external gui mode) or not). This it the call that the panel thread or the one the external gui actually "sees". The first call further above wasn't seen by either since it was issued before logger_init was called and thus got written directly to the physical screen whereas this one will be inter- cepted and handled by the logger facility thereby allowing the panel thread or external gui to "see" it and thus display it. */ display_version (stdout, "Hercules ", TRUE); #if defined(OPTION_DYNAMIC_LOAD) /* Initialize the hercules dynamic loader */ hdl_main(); #endif /* defined(OPTION_DYNAMIC_LOAD) */ #ifdef EXTERNALGUI /* Set GUI flag if specified as final argument */ if (argc >= 1 && strncmp(argv[argc-1],"EXTERNALGUI",11) == 0) { #if defined(OPTION_DYNAMIC_LOAD) if (hdl_load("dyngui",HDL_LOAD_DEFAULT) != 0) { usleep(10000); /* (give logger thread time to issue preceding HHCHD007E message) */ logmsg(_("HHCIN008S DYNGUI.DLL load failed; Hercules terminated.\n")); delayed_exit(1); } #endif /* defined(OPTION_DYNAMIC_LOAD) */ argc--; } #endif /*EXTERNALGUI*/ #if !defined(WIN32) && !defined(HAVE_STRERROR_R) strerror_r_init(); #endif #if defined(OPTION_SCSI_TAPE) initialize_lock (&sysblk.stape_lock); initialize_condition (&sysblk.stape_getstat_cond); InitializeListHead (&sysblk.stape_mount_link); InitializeListHead (&sysblk.stape_status_link); #endif /* defined(OPTION_SCSI_TAPE) */ /* Get name of configuration file or default to hercules.cnf */ if(!(cfgfile = getenv("HERCULES_CNF"))) cfgfile = "hercules.cnf"; /* Process the command line options */ while ((c = getopt(argc, argv, "f:p:l:db:")) != EOF) { switch (c) { case 'f': cfgfile = optarg; break; #if defined(OPTION_DYNAMIC_LOAD) case 'p': if(optarg) hdl_setpath(strdup(optarg)); break; case 'l': { char *dllname, *strtok_str; for(dllname = strtok_r(optarg,", ",&strtok_str); dllname; dllname = strtok_r(NULL,", ",&strtok_str)) hdl_load(dllname, HDL_LOAD_DEFAULT); } break; #endif /* defined(OPTION_DYNAMIC_LOAD) */ case 'b': sysblk.logofile=optarg; break; case 'd': sysblk.daemon_mode = 1; break; default: arg_error = 1; } /* end switch(c) */ } /* end while */ if (optind < argc) arg_error = 1; /* Terminate if invalid arguments were detected */ if (arg_error) { logmsg("usage: %s [-f config-filename] [-d] [-b logo-filename]" #if defined(OPTION_DYNAMIC_LOAD) " [-p dyn-load-dir] [[-l dynmod-to-load]...]" #endif /* defined(OPTION_DYNAMIC_LOAD) */ " [> logfile]\n", argv[0]); delayed_exit(1); } /* Register the SIGINT handler */ if ( signal (SIGINT, sigint_handler) == SIG_ERR ) { logmsg(_("HHCIN001S Cannot register SIGINT handler: %s\n"), strerror(errno)); delayed_exit(1); } /* Register the SIGTERM handler */ if ( signal (SIGTERM, sigterm_handler) == SIG_ERR ) { logmsg(_("HHCIN009S Cannot register SIGTERM handler: %s\n"), strerror(errno)); delayed_exit(1); } #if defined( _MSVC_ ) /* Register the Window console ctrl handlers */ if (SetConsoleCtrlHandler(console_ctrl_handler, TRUE) == FALSE) { logmsg(_("HHCIN010S Cannot register ConsoleCtrl handler: %s\n"), strerror(errno)); delayed_exit(1); } #endif #if defined(HAVE_DECL_SIGPIPE) && HAVE_DECL_SIGPIPE /* Ignore the SIGPIPE signal, otherwise Hercules may terminate with Broken Pipe error if the printer driver writes to a closed pipe */ if ( signal (SIGPIPE, SIG_IGN) == SIG_ERR ) { logmsg(_("HHCIN002E Cannot suppress SIGPIPE signal: %s\n"), strerror(errno)); } #endif #if defined( OPTION_WAKEUP_SELECT_VIA_PIPE ) { int fds[2]; initialize_lock(&sysblk.cnslpipe_lock); initialize_lock(&sysblk.sockpipe_lock); sysblk.cnslpipe_flag=0; sysblk.sockpipe_flag=0; VERIFY( create_pipe(fds) >= 0 ); sysblk.cnslwpipe=fds[1]; sysblk.cnslrpipe=fds[0]; VERIFY( create_pipe(fds) >= 0 ); sysblk.sockwpipe=fds[1]; sysblk.sockrpipe=fds[0]; } #endif // defined( OPTION_WAKEUP_SELECT_VIA_PIPE ) #if !defined(NO_SIGABEND_HANDLER) { struct sigaction sa; sa.sa_sigaction = (void*)&sigabend_handler; #ifdef SA_NODEFER sa.sa_flags = SA_NODEFER; #else sa.sa_flags = 0; #endif if( sigaction(SIGILL, &sa, NULL) || sigaction(SIGFPE, &sa, NULL) || sigaction(SIGSEGV, &sa, NULL) || sigaction(SIGBUS, &sa, NULL) || sigaction(SIGUSR1, &sa, NULL) || sigaction(SIGUSR2, &sa, NULL) ) { logmsg(_("HHCIN003S Cannot register SIGILL/FPE/SEGV/BUS/USR " "handler: %s\n"), strerror(errno)); delayed_exit(1); } } #endif /*!defined(NO_SIGABEND_HANDLER)*/ /* Build system configuration */ build_config (cfgfile); /* System initialisation time */ sysblk.todstart = hw_clock() << 8; #ifdef OPTION_MIPS_COUNTING /* Initialize "maxrates" command reporting intervals */ curr_int_start_time = time( NULL ); prev_int_start_time = curr_int_start_time; #endif #if !defined(NO_SIGABEND_HANDLER) /* Start the watchdog */ if ( create_thread (&sysblk.wdtid, DETACHED, watchdog_thread, NULL, "watchdog_thread") ) { logmsg(_("HHCIN004S Cannot create watchdog thread: %s\n"), strerror(errno)); delayed_exit(1); } #endif /*!defined(NO_SIGABEND_HANDLER)*/ #ifdef OPTION_SHARED_DEVICES /* Start the shared server */ if (sysblk.shrdport) if ( create_thread (&sysblk.shrdtid, DETACHED, shared_server, NULL, "shared_server") ) { logmsg(_("HHCIN006S Cannot create shared_server thread: %s\n"), strerror(errno)); delayed_exit(1); } /* Retry pending connections */ { DEVBLK *dev; TID tid; for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if (dev->connecting) if ( create_thread (&tid, DETACHED, *dev->hnd->init, dev, "device connecting thread") ) { logmsg(_("HHCIN007S Cannot create %4.4X connection thread: %s\n"), dev->devnum, strerror(errno)); delayed_exit(1); } } #endif /* Start up the RC file processing thread */ create_thread(&rctid,DETACHED, process_rc_file,NULL,"process_rc_file"); if(log_callback) { // 'herclin' called us. IT'S in charge. Create its requested // logmsg intercept callback function and return back to it. create_thread(&logcbtid,DETACHED, log_do_callback,NULL,"log_do_callback"); return(0); } //--------------------------------------------------------------- // The below functions will not return until Hercules is shutdown //--------------------------------------------------------------- /* Activate the control panel */ if(!sysblk.daemon_mode) panel_display (); else { #if defined(OPTION_DYNAMIC_LOAD) if(daemon_task) daemon_task (); else #endif /* defined(OPTION_DYNAMIC_LOAD) */ { /* Tell RC file and HAO threads they may now proceed */ sysblk.panel_init = 1; /* Retrieve messages from logger and write to stderr */ while (1) if((msgcnt = log_read(&msgbuf, &msgnum, LOG_BLOCK))) if(isatty(STDERR_FILENO)) fwrite(msgbuf,msgcnt,1,stderr); } } // ----------------------------------------------------- // *** Hercules has been shutdown (PAST tense) *** // ----------------------------------------------------- ASSERT( sysblk.shutdown ); // (why else would we be here?!) #ifdef _MSVC_ SetConsoleCtrlHandler(console_ctrl_handler, FALSE); socket_deinit(); #endif #ifdef DEBUG fprintf(stdout, _("IMPL EXIT\n")); #endif fprintf(stdout, _("HHCIN099I Hercules terminated\n")); fflush(stdout); usleep(10000); return 0; } /* end function main */ /*-------------------------------------------------------------------*/ /* System cleanup */ /*-------------------------------------------------------------------*/ DLL_EXPORT void system_cleanup (void) { // logmsg("HHCIN950I Begin system cleanup\n"); /* Currently only called by hdlmain,c's HDL_FINAL_SECTION after the main 'hercules' module has been unloaded, but that could change at some time in the future. The above and below logmsg's are commented out since this function currently doesn't do anything yet. Once it DOES something, they should be uncommented. */ // logmsg("HHCIN959I System cleanup complete\n"); } hercules-3.12/config.c0000664000175000017500000012257112564723224011624 00000000000000/* CONFIG.C (c) Copyright Jan Jaeger, 2000-2009 */ /* Device configuration functions */ /*-------------------------------------------------------------------*/ /* The original configuration builder is now called bldcfg.c */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _CONFIG_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "opcode.h" #if !defined(_GEN_ARCH) #if defined(_ARCHMODE3) #define _GEN_ARCH _ARCHMODE3 #include "config.c" #undef _GEN_ARCH #endif #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "config.c" #undef _GEN_ARCH #endif #if defined(OPTION_FISHIO) #include "w32chan.h" #endif // defined(OPTION_FISHIO) /*-------------------------------------------------------------------*/ /* Function to terminate all CPUs and devices */ /*-------------------------------------------------------------------*/ void release_config() { DEVBLK *dev; int cpu; /* Deconfigure all CPU's */ OBTAIN_INTLOCK(NULL); for (cpu = 0; cpu < MAX_CPU_ENGINES; cpu++) if(IS_CPU_ONLINE(cpu)) deconfigure_cpu(cpu); RELEASE_INTLOCK(NULL); #if defined(OPTION_SHARED_DEVICES) /* Terminate the shared device listener thread */ if (sysblk.shrdtid) signal_thread (sysblk.shrdtid, SIGUSR2); #endif /* Detach all devices */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if (dev->allocated) detach_subchan(SSID_TO_LCSS(dev->ssid), dev->subchan); #if !defined(OPTION_FISHIO) /* Terminate device threads */ obtain_lock (&sysblk.ioqlock); sysblk.devtwait=0; broadcast_condition (&sysblk.ioqcond); release_lock (&sysblk.ioqlock); #endif } /* end function release_config */ /*-------------------------------------------------------------------*/ /* Function to start a new CPU thread */ /* Caller MUST own the intlock */ /*-------------------------------------------------------------------*/ int configure_cpu(int cpu) { int i; char thread_name[16]; if(IS_CPU_ONLINE(cpu)) return -1; snprintf(thread_name,sizeof(thread_name),"cpu%d thread",cpu); thread_name[sizeof(thread_name)-1]=0; if ( create_thread (&sysblk.cputid[cpu], DETACHED, cpu_thread, &cpu, thread_name) ) { logmsg(_("HHCCF040E Cannot create CPU%4.4X thread: %s\n"), cpu, strerror(errno)); return -1; } /* Find out if we are a cpu thread */ for (i = 0; i < MAX_CPU_ENGINES; i++) if (sysblk.cputid[i] == thread_id()) break; if (i < MAX_CPU_ENGINES) sysblk.regs[i]->intwait = 1; /* Wait for CPU thread to initialize */ wait_condition (&sysblk.cpucond, &sysblk.intlock); if (i < MAX_CPU_ENGINES) sysblk.regs[i]->intwait = 0; return 0; } /* end function configure_cpu */ /*-------------------------------------------------------------------*/ /* Function to remove a CPU from the configuration */ /* This routine MUST be called with the intlock held */ /*-------------------------------------------------------------------*/ int deconfigure_cpu(int cpu) { int i; /* Find out if we are a cpu thread */ for (i = 0; i < MAX_CPU_ENGINES; i++) if (sysblk.cputid[i] == thread_id()) break; /* If we're NOT trying to deconfigure ourselves */ if (cpu != i) { if (!IS_CPU_ONLINE(cpu)) return -1; /* Deconfigure CPU */ sysblk.regs[cpu]->configured = 0; sysblk.regs[cpu]->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(sysblk.regs[cpu]); /* Wake up CPU as it may be waiting */ WAKEUP_CPU (sysblk.regs[cpu]); /* (if we're a cpu thread) */ if (i < MAX_CPU_ENGINES) sysblk.regs[i]->intwait = 1; /* Wait for CPU thread to terminate */ wait_condition (&sysblk.cpucond, &sysblk.intlock); /* (if we're a cpu thread) */ if (i < MAX_CPU_ENGINES) sysblk.regs[i]->intwait = 0; join_thread (sysblk.cputid[cpu], NULL); detach_thread( sysblk.cputid[cpu] ); } else { /* Else we ARE trying to deconfigure ourselves */ sysblk.regs[cpu]->configured = 0; sysblk.regs[cpu]->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(sysblk.regs[cpu]); } sysblk.cputid[cpu] = 0; return 0; } /* end function deconfigure_cpu */ /* 4 next functions used for fast device lookup cache management */ #if defined(OPTION_FAST_DEVLOOKUP) static void AddDevnumFastLookup(DEVBLK *dev,U16 lcss,U16 devnum) { unsigned int Channel; if(sysblk.devnum_fl==NULL) { sysblk.devnum_fl=(DEVBLK ***)malloc(sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX); memset(sysblk.devnum_fl,0,sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX); } Channel=(devnum & 0xff00)>>8 | ((lcss & (FEATURE_LCSS_MAX-1))<<8); if(sysblk.devnum_fl[Channel]==NULL) { sysblk.devnum_fl[Channel]=(DEVBLK **)malloc(sizeof(DEVBLK *)*256); memset(sysblk.devnum_fl[Channel],0,sizeof(DEVBLK *)*256); } sysblk.devnum_fl[Channel][devnum & 0xff]=dev; } static void AddSubchanFastLookup(DEVBLK *dev,U16 ssid, U16 subchan) { unsigned int schw; #if 0 logmsg(D_("DEBUG : ASFL Adding %d\n"),subchan); #endif if(sysblk.subchan_fl==NULL) { sysblk.subchan_fl=(DEVBLK ***)malloc(sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX); memset(sysblk.subchan_fl,0,sizeof(DEVBLK **)*256*FEATURE_LCSS_MAX); } schw=((subchan & 0xff00)>>8)|(SSID_TO_LCSS(ssid)<<8); if(sysblk.subchan_fl[schw]==NULL) { sysblk.subchan_fl[schw]=(DEVBLK **)malloc(sizeof(DEVBLK *)*256); memset(sysblk.subchan_fl[schw],0,sizeof(DEVBLK *)*256); } sysblk.subchan_fl[schw][subchan & 0xff]=dev; } static void DelDevnumFastLookup(U16 lcss,U16 devnum) { unsigned int Channel; if(sysblk.devnum_fl==NULL) { return; } Channel=(devnum & 0xff00)>>8 | ((lcss & (FEATURE_LCSS_MAX-1))<<8); if(sysblk.devnum_fl[Channel]==NULL) { return; } sysblk.devnum_fl[Channel][devnum & 0xff]=NULL; } static void DelSubchanFastLookup(U16 ssid, U16 subchan) { unsigned int schw; #if 0 logmsg(D_("DEBUG : DSFL Removing %d\n"),subchan); #endif if(sysblk.subchan_fl==NULL) { return; } schw=((subchan & 0xff00)>>8)|(SSID_TO_LCSS(ssid) << 8); if(sysblk.subchan_fl[schw]==NULL) { return; } sysblk.subchan_fl[schw][subchan & 0xff]=NULL; } #endif DEVBLK *get_devblk(U16 lcss, U16 devnum) { DEVBLK *dev; DEVBLK**dvpp; if(lcss >= FEATURE_LCSS_MAX) lcss = 0; for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if (!(dev->allocated) && dev->ssid == LCSS_TO_SSID(lcss)) break; if(!dev) { if (!(dev = (DEVBLK*)malloc(sizeof(DEVBLK)))) { logmsg (_("HHCCF043E Cannot obtain device block\n"), strerror(errno)); return NULL; } memset (dev, 0, sizeof(DEVBLK)); /* Initialize the device lock and conditions */ initialize_lock (&dev->lock); initialize_condition (&dev->resumecond); initialize_condition (&dev->iocond); #if defined(OPTION_SCSI_TAPE) initialize_condition (&dev->stape_sstat_cond); InitializeListLink (&dev->stape_statrq.link); InitializeListLink (&dev->stape_mntdrq.link); dev->stape_statrq.dev = dev; dev->stape_mntdrq.dev = dev; dev->sstat = GMT_DR_OPEN(-1); #endif /* Search for the last device block on the chain */ for (dvpp = &(sysblk.firstdev); *dvpp != NULL; dvpp = &((*dvpp)->nextdev)); /* Add the new device block to the end of the chain */ *dvpp = dev; dev->ssid = LCSS_TO_SSID(lcss); dev->subchan = sysblk.highsubchan[lcss]++; } /* Initialize the device block */ obtain_lock (&dev->lock); dev->group = NULL; dev->member = 0; dev->cpuprio = sysblk.cpuprio; dev->devprio = sysblk.devprio; dev->hnd = NULL; dev->devnum = devnum; dev->chanset = lcss; dev->fd = -1; dev->syncio = 0; dev->ioint.dev = dev; dev->ioint.pending = 1; dev->pciioint.dev = dev; dev->pciioint.pcipending = 1; dev->attnioint.dev = dev; dev->attnioint.attnpending = 1; dev->oslinux = sysblk.pgminttr == OS_LINUX; /* Initialize storage view */ dev->mainstor = sysblk.mainstor; dev->storkeys = sysblk.storkeys; dev->mainlim = sysblk.mainsize - 1; /* Initialize the path management control word */ memset (&dev->pmcw, 0, sizeof(PMCW)); dev->pmcw.devnum[0] = dev->devnum >> 8; dev->pmcw.devnum[1] = dev->devnum & 0xFF; dev->pmcw.lpm = 0x80; dev->pmcw.pim = 0x80; dev->pmcw.pom = 0xFF; dev->pmcw.pam = 0x80; dev->pmcw.chpid[0] = dev->devnum >> 8; #if defined(OPTION_SHARED_DEVICES) dev->shrdwait = -1; #endif /*defined(OPTION_SHARED_DEVICES)*/ #ifdef _FEATURE_CHANNEL_SUBSYSTEM /* Indicate a CRW is pending for this device */ #if defined(_370) if (sysblk.arch_mode != ARCH_370) #endif /*defined(_370)*/ dev->crwpending = 1; #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/ #ifdef EXTERNALGUI if ( !dev->pGUIStat ) { dev->pGUIStat = malloc( sizeof(GUISTAT) ); dev->pGUIStat->pszOldStatStr = dev->pGUIStat->szStatStrBuff1; dev->pGUIStat->pszNewStatStr = dev->pGUIStat->szStatStrBuff2; *dev->pGUIStat->pszOldStatStr = 0; *dev->pGUIStat->pszNewStatStr = 0; } #endif /*EXTERNALGUI*/ /* Mark device valid */ dev->pmcw.flag5 |= PMCW5_V; dev->allocated = 1; return dev; } void ret_devblk(DEVBLK *dev) { /* Mark device invalid */ dev->allocated = 0; dev->pmcw.flag5 &= ~PMCW5_V; // compat ZZ deprecated release_lock(&dev->lock); } /*-------------------------------------------------------------------*/ /* Function to build a device configuration block */ /*-------------------------------------------------------------------*/ int attach_device (U16 lcss, U16 devnum, const char *type, int addargc, char *addargv[]) { DEVBLK *dev; /* -> Device block */ int rc; /* Return code */ int i; /* Loop index */ /* Check whether device number has already been defined */ if (find_device_by_devnum(lcss,devnum) != NULL) { logmsg (_("HHCCF041E Device %d:%4.4X already exists\n"), lcss,devnum); return 1; } /* obtain device block */ dev = get_devblk(lcss,devnum); if(!(dev->hnd = hdl_ghnd(type))) { logmsg (_("HHCCF042E Device type %s not recognized\n"), type); ret_devblk(dev); return 1; } dev->typname = strdup(type); /* Copy the arguments */ dev->argc = addargc; if (addargc) { dev->argv = malloc ( addargc * sizeof(BYTE *) ); for (i = 0; i < addargc; i++) if (addargv[i]) dev->argv[i] = strdup(addargv[i]); else dev->argv[i] = NULL; } else dev->argv = NULL; /* Call the device handler initialization function */ rc = (dev->hnd->init)(dev, addargc, addargv); if (rc < 0) { logmsg (_("HHCCF044E Initialization failed for device %4.4X\n"), devnum); for (i = 0; i < dev->argc; i++) if (dev->argv[i]) free(dev->argv[i]); if (dev->argv) free(dev->argv); free(dev->typname); ret_devblk(dev); return 1; } /* Obtain device data buffer */ if (dev->bufsize != 0) { dev->buf = malloc (dev->bufsize); if (dev->buf == NULL) { logmsg (_("HHCCF045E Cannot obtain buffer " "for device %4.4X: %s\n"), dev->devnum, strerror(errno)); for (i = 0; i < dev->argc; i++) if (dev->argv[i]) free(dev->argv[i]); if (dev->argv) free(dev->argv); free(dev->typname); ret_devblk(dev); return 1; } } /* Release device lock */ release_lock(&dev->lock); #ifdef _FEATURE_CHANNEL_SUBSYSTEM /* Signal machine check */ #if defined(_370) if (sysblk.arch_mode != ARCH_370) #endif machine_check_crwpend(); #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/ /* if(lcss!=0 && sysblk.arch_mode==ARCH_370) { logmsg(_("HHCCF078W %d:%4.4X : Only devices on CSS 0 are usable in S/370 mode\n"),lcss,devnum); } */ return 0; } /* end function attach_device */ /*-------------------------------------------------------------------*/ /* Function to delete a device configuration block */ /*-------------------------------------------------------------------*/ static int detach_devblk (DEVBLK *dev) { int i; /* Loop index */ /* Obtain the device lock */ obtain_lock(&dev->lock); #if defined(OPTION_FAST_DEVLOOKUP) DelSubchanFastLookup(dev->ssid, dev->subchan); if(dev->pmcw.flag5 & PMCW5_V) DelDevnumFastLookup(SSID_TO_LCSS(dev->ssid),dev->devnum); #endif /* Close file or socket */ if ((dev->fd > 2) || dev->console) /* Call the device close handler */ (dev->hnd->close)(dev); for (i = 0; i < dev->argc; i++) if (dev->argv[i]) free(dev->argv[i]); if (dev->argv) free(dev->argv); free(dev->typname); #ifdef _FEATURE_CHANNEL_SUBSYSTEM /* Indicate a CRW is pending for this device */ #if defined(_370) if (sysblk.arch_mode != ARCH_370) #endif /*defined(_370)*/ dev->crwpending = 1; #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/ // detach all devices in group if(dev->group) { int i; dev->group->memdev[dev->member] = NULL; if(dev->group->members) { dev->group->members = 0; for(i = 0; i < dev->group->acount; i++) { if(dev->group->memdev[i] && dev->group->memdev[i]->allocated) { detach_devblk(dev->group->memdev[i]); } } free(dev->group); } dev->group = NULL; } ret_devblk(dev); /* Zeroize the PMCW */ memset (&dev->pmcw, 0, sizeof(PMCW)); #ifdef _FEATURE_CHANNEL_SUBSYSTEM /* Signal machine check */ #if defined(_370) if (sysblk.arch_mode != ARCH_370) #endif machine_check_crwpend(); #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/ return 0; } /* end function detach_devblk */ /*-------------------------------------------------------------------*/ /* Function to delete a device configuration block by subchannel */ /*-------------------------------------------------------------------*/ int detach_subchan (U16 lcss, U16 subchan) { DEVBLK *dev; /* -> Device block */ int rc; /* Find the device block */ dev = find_device_by_subchan ((LCSS_TO_SSID(lcss)<<16)|subchan); if (dev == NULL) { logmsg (_("HHCCF046E Subchannel %d:%4.4X does not exist\n"), lcss, subchan); return 1; } rc = detach_devblk( dev ); if(!rc) logmsg (_("HHCCF047I Subchannel %d:%4.4X detached\n"), lcss, subchan); return rc; } /*-------------------------------------------------------------------*/ /* Function to delete a device configuration block by device number */ /*-------------------------------------------------------------------*/ int detach_device (U16 lcss,U16 devnum) { DEVBLK *dev; /* -> Device block */ int rc; /* Find the device block */ dev = find_device_by_devnum (lcss,devnum); if (dev == NULL) { logmsg (_("HHCCF046E Device %d:%4.4X does not exist\n"), lcss, devnum); return 1; } rc = detach_devblk( dev ); if(!rc) logmsg (_("HHCCF047I Device %4.4X detached\n"), devnum); return rc; } /*-------------------------------------------------------------------*/ /* Function to rename a device configuration block */ /*-------------------------------------------------------------------*/ int define_device (U16 lcss, U16 olddevn,U16 newdevn) { DEVBLK *dev; /* -> Device block */ /* Find the device block */ dev = find_device_by_devnum (lcss, olddevn); if (dev == NULL) { logmsg (_("HHCCF048E Device %d:%4.4X does not exist\n"), lcss, olddevn); return 1; } /* Check that new device number does not already exist */ if (find_device_by_devnum(lcss, newdevn) != NULL) { logmsg (_("HHCCF049E Device %d:%4.4X already exists\n"), lcss, newdevn); return 1; } /* Obtain the device lock */ obtain_lock(&dev->lock); /* Update the device number in the DEVBLK */ dev->devnum = newdevn; /* Update the device number in the PMCW */ dev->pmcw.devnum[0] = newdevn >> 8; dev->pmcw.devnum[1] = newdevn & 0xFF; /* Disable the device */ dev->pmcw.flag5 &= ~PMCW5_E; #if defined(OPTION_FAST_DEVLOOKUP) DelDevnumFastLookup(lcss,olddevn); DelDevnumFastLookup(lcss,newdevn); #endif #ifdef _FEATURE_CHANNEL_SUBSYSTEM /* Indicate a CRW is pending for this device */ #if defined(_370) if (sysblk.arch_mode != ARCH_370) #endif /*defined(_370)*/ dev->crwpending = 1; #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/ /* Release device lock */ release_lock(&dev->lock); #ifdef _FEATURE_CHANNEL_SUBSYSTEM /* Signal machine check */ #if defined(_370) if (sysblk.arch_mode != ARCH_370) #endif machine_check_crwpend(); #endif /*_FEATURE_CHANNEL_SUBSYSTEM*/ // logmsg (_("HHCCF050I Device %4.4X defined as %4.4X\n"), // olddevn, newdevn); return 0; } /* end function define_device */ /*-------------------------------------------------------------------*/ /* Function to group devblk's belonging to one device (eg OSA, LCS) */ /* */ /* group_device is intended to be called from within a device */ /* initialisation routine to group 1 or more devices to a logical */ /* device group. */ /* */ /* group_device will return true for the device that completes */ /* the device group. (ie the last device to join the group) */ /* */ /* when no group exists, and device group is called with a device */ /* count of zero, then no group will be created. Otherwise */ /* a new group will be created and the currently attaching device */ /* will be the first in the group. */ /* */ /* when a device in a group is detached, all devices in the group */ /* will be detached. The first device to be detached will enter */ /* its close routine with the group intact. Subsequent devices */ /* being detached will no longer have access to previously detached */ /* devices. */ /* */ /* Example of a fixed count device group: */ /* */ /* device_init(dev) */ /* { */ /* if( !device_group(dev, 2) ) */ /* return 0; */ /* */ /* ... all devices in the group have been attached, */ /* ... group initialisation may proceed. */ /* */ /* } */ /* */ /* */ /* Variable device group example: */ /* */ /* device_init(dev) */ /* { */ /* if( !group_device(dev, 0) && dev->group ) */ /* return 0; */ /* */ /* if( !device->group ) */ /* { */ /* ... process parameters to determine number of devices */ /* */ /* // Create group */ /* if( !group_device(dev, variable_count) ) */ /* return 0; */ /* } */ /* */ /* ... all devices in the group have been attached, */ /* ... group initialisation may proceed. */ /* } */ /* */ /* */ /* dev->group : pointer to DEVGRP structure or NULL */ /* dev->member : index into memdev array in DEVGRP structure for */ /* : current DEVBLK */ /* group->members : number of members in group */ /* group->acount : number active members in group */ /* group->memdev[] : array of DEVBLK pointers of member devices */ /* */ /* */ /* members will be equal to acount for a complete group */ /* */ /* */ /* Always: (for grouped devices) */ /* dev->group->memdev[dev->member] == dev */ /* */ /* */ /* Jan Jaeger, 23 Apr 2004 */ /*-------------------------------------------------------------------*/ DLL_EXPORT int group_device(DEVBLK *dev, int members) { DEVBLK *tmp; // Find a compatible group that is incomplete for (tmp = sysblk.firstdev; tmp != NULL && (!tmp->allocated // not allocated || !tmp->group // not a group device || strcmp(tmp->typname,dev->typname) // unequal type || (tmp->group->members == tmp->group->acount) ); // complete tmp = tmp->nextdev) ; if(tmp) { // Join Group dev->group = tmp->group; dev->member = dev->group->acount++; dev->group->memdev[dev->member] = dev; } else if(members) { // Allocate a new Group when requested dev->group = malloc(sizeof(DEVGRP) + members * sizeof(DEVBLK *)); dev->group->members = members; dev->group->acount = 1; dev->group->memdev[0] = dev; dev->member = 0; } return (dev->group && (dev->group->members == dev->group->acount)); } /*-------------------------------------------------------------------*/ /* Function to find a device block given the device number */ /*-------------------------------------------------------------------*/ DLL_EXPORT DEVBLK *find_device_by_devnum (U16 lcss,U16 devnum) { DEVBLK *dev; #if defined(OPTION_FAST_DEVLOOKUP) DEVBLK **devtab; int Chan; Chan=(devnum & 0xff00)>>8 | ((lcss & (FEATURE_LCSS_MAX-1))<<8); if(sysblk.devnum_fl!=NULL) { devtab=sysblk.devnum_fl[Chan]; if(devtab!=NULL) { dev=devtab[devnum & 0xff]; if(dev && dev->allocated && dev->pmcw.flag5 & PMCW5_V && dev->devnum==devnum) { return dev; } else { DelDevnumFastLookup(lcss,devnum); } } } #endif for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if (dev->allocated && dev->devnum == devnum && lcss==SSID_TO_LCSS(dev->ssid) && dev->pmcw.flag5 & PMCW5_V) break; #if defined(OPTION_FAST_DEVLOOKUP) if(dev) { AddDevnumFastLookup(dev,lcss,devnum); } #endif return dev; } /* end function find_device_by_devnum */ /*-------------------------------------------------------------------*/ /* Function to find a device block given the subchannel number */ /*-------------------------------------------------------------------*/ DEVBLK *find_device_by_subchan (U32 ioid) { U16 subchan = ioid & 0xFFFF; DEVBLK *dev; #if defined(OPTION_FAST_DEVLOOKUP) unsigned int schw = ((subchan & 0xff00)>>8)|(IOID_TO_LCSS(ioid)<<8); #if 0 logmsg(D_("DEBUG : FDBS FL Looking for %d\n"),subchan); #endif if(sysblk.subchan_fl && sysblk.subchan_fl[schw] && sysblk.subchan_fl[schw][subchan & 0xff]) return sysblk.subchan_fl[schw][subchan & 0xff]; #endif #if 0 logmsg(D_("DEBUG : FDBS SL Looking for %8.8x\n"),ioid); #endif for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if (dev->ssid == IOID_TO_SSID(ioid) && dev->subchan == subchan) break; #if defined(OPTION_FAST_DEVLOOKUP) if(dev) { AddSubchanFastLookup(dev, IOID_TO_SSID(ioid), subchan); } else { DelSubchanFastLookup(IOID_TO_SSID(ioid), subchan); } #endif return dev; } /* end function find_device_by_subchan */ /*-------------------------------------------------------------------*/ /* Returns a CPU register context for the device, or else NULL */ /*-------------------------------------------------------------------*/ REGS *devregs(DEVBLK *dev) { /* If a register context already exists then use it */ if (dev->regs) return dev->regs; /* Otherwise attempt to determine what it should be */ { int i; TID tid = thread_id(); /* Our own thread id */ for (i=0; i < MAX_CPU; i++) if (tid == sysblk.cputid[i]) /* Are we a cpu thread? */ return sysblk.regs[i]; /* yes, use its context */ } return NULL; /* Not CPU thread. Return NULL register context */ } /*-------------------------------------------------------------------*/ /* Internal device parsing structures */ /*-------------------------------------------------------------------*/ typedef struct _DEVARRAY { U16 cuu1; U16 cuu2; } DEVARRAY; typedef struct _DEVNUMSDESC { BYTE lcss; DEVARRAY *da; } DEVNUMSDESC; /*-------------------------------------------------------------------*/ /* Function to Parse a LCSS specification in a device number spec */ /* Syntax : [lcss:]Anything... */ /* Function args : */ /* const char * spec : Parsed string */ /* char **rest : Rest of string (or original str) */ /* Returns : */ /* int : 0 if not specified, 0<=nFEATURE_LCSS_MAX) { if(verbose) { logmsg(_("HHCCF077E Logical Channel Subsystem Identification %d exceeds maximum of %d\n"),lcssid,FEATURE_LCSS_MAX-1); } free(wrk); return -1; } *rest=malloc(strlen(r)+1); strcpy(*rest,r); free(wrk); return lcssid; } static int parse_single_devnum__INTERNAL(const char *spec, U16 *p_lcss, U16 *p_devnum, int verbose) { int rc; U16 lcss; char *r; char *strptr; rc=parse_lcss(spec,&r,verbose); if(rc<0) { return -1; } lcss=rc; rc=strtoul(r,&strptr,16); if(rc<0 || rc>0xffff || *strptr!=0) { if(verbose) { logmsg(_("HHCCF055E Incorrect device address specification near character %c\n"),*strptr); } free(r); return -1; } *p_devnum=rc; *p_lcss=lcss; return 0; } DLL_EXPORT int parse_single_devnum(const char *spec, U16 *lcss, U16 *devnum) { return parse_single_devnum__INTERNAL(spec,lcss,devnum,1); } int parse_single_devnum_silent(const char *spec, U16 *lcss, U16 *devnum) { return parse_single_devnum__INTERNAL(spec,lcss,devnum,0); } /*-------------------------------------------------------------------*/ /* Function to Parse compound device numbers */ /* Syntax : [lcss:]CCUU[-CUU][,CUU..][.nn][...] */ /* Examples : 200-23F */ /* 200,201 */ /* 200.16 */ /* 200-23F,280.8 */ /* etc... */ /* : is the LCSS id separator (only 0 or 1 allowed and it must be 1st*/ /* - is the range specification (from CUU to CUU) */ /* , is the separator */ /* . is the count indicator (nn is decimal) */ /* 1st parm is the specification string as specified above */ /* 2nd parm is the address of an array of DEVARRAY */ /* Return value : 0 - Parsing error, etc.. */ /* >0 - Size of da */ /* */ /* NOTE : A basic validity check is made for the following : */ /* All CUUs must belong on the same channel */ /* (this check is to eventually pave the way to a formal */ /* channel/cu/device architecture) */ /* no 2 identical CCUUs */ /* ex : 200,300 : WRONG */ /* 200.12,200.32 : WRONG */ /* 2FF.2 : WRONG */ /* NOTE : caller should free the array returned in da if the return */ /* value is not 0 */ /*-------------------------------------------------------------------*/ static size_t parse_devnums(const char *spec,DEVNUMSDESC *dd) { size_t gcount; /* Group count */ size_t i; /* Index runner */ char *grps; /* Pointer to current devnum group */ char *sc; /* Specification string copy */ DEVARRAY *dgrs; /* Device groups */ U16 cuu1,cuu2; /* CUUs */ char *strptr; /* strtoul ptr-ptr */ int basechan=0; /* Channel for all CUUs */ int duplicate; /* duplicated CUU indicator */ int badcuu; /* offending CUU */ int rc; /* Return code work var */ rc=parse_lcss(spec,&sc,1); if(rc<0) { return 0; } dd->lcss=rc; /* Split by ',' groups */ gcount=0; grps=strtok(sc,","); dgrs=NULL; while(grps!=NULL) { if(dgrs==NULL) { dgrs=malloc(sizeof(DEVARRAY)); } else { dgrs=realloc(dgrs,(sizeof(DEVARRAY))*(gcount+1)); } cuu1=strtoul(grps,&strptr,16); switch(*strptr) { case 0: /* Single CUU */ cuu2=cuu1; break; case '-': /* CUU Range */ cuu2=strtoul(&strptr[1],&strptr,16); if(*strptr!=0) { logmsg(_("HHCCF053E Incorrect second device number in device range near character %c\n"),*strptr); free(dgrs); free(sc); return(0); } break; case '.': /* CUU Count */ cuu2=cuu1+strtoul(&strptr[1],&strptr,10); cuu2--; if(*strptr!=0) { logmsg(_("HHCCF054E Incorrect Device count near character %c\n"),*strptr); free(dgrs); free(sc); return(0); } break; default: logmsg(_("HHCCF055E Incorrect device address specification near character %c\n"),*strptr); free(dgrs); free(sc); return(0); } /* Check cuu1 <= cuu2 */ if(cuu1>cuu2) { logmsg(_("HHCCF056E Incorrect device address range. %4.4X < %4.4X\n"),cuu2,cuu1); free(dgrs); free(sc); return(0); } if(gcount==0) { basechan=(cuu1 >> 8) & 0xff; } badcuu=-1; if(((cuu1 >> 8) & 0xff) != basechan) { badcuu=cuu1; } else { if(((cuu2 >> 8) & 0xff) != basechan) { badcuu=cuu2; } } if(badcuu>=0) { logmsg(_("HHCCF057E %4.4X is on wrong channel (1st device defined on channel %2.2X)\n"),badcuu,basechan); free(dgrs); free(sc); return(0); } /* Check for duplicates */ duplicate=0; for(i=0;i=dgrs[i].cuu1 && cuu1<=dgrs[i].cuu2) { duplicate=1; break; } /* check 2nd cuu not within existing range */ if(cuu2>=dgrs[i].cuu1 && cuu1<=dgrs[i].cuu2) { duplicate=1; break; } /* check current range doesn't completelly overlap existing range */ if(cuu1dgrs[i].cuu2) { duplicate=1; break; } } if(duplicate) { logmsg(_("HHCCF058E Some or all devices in %4.4X-%4.4X duplicate devices already defined\n"),cuu1,cuu2); free(dgrs); free(sc); return(0); } dgrs[gcount].cuu1=cuu1; dgrs[gcount].cuu2=cuu2; gcount++; grps=strtok(NULL,","); } free(sc); dd->da=dgrs; return(gcount); } int parse_and_attach_devices(const char *sdevnum, const char *sdevtype, int addargc, char **addargv) { DEVNUMSDESC dnd; int baddev; size_t devncount; DEVARRAY *da; int i; U16 devnum; int rc; #if defined(OPTION_CONFIG_SYMBOLS) int j; char **newargv; char **orig_newargv; #endif devncount=parse_devnums(sdevnum,&dnd); if(devncount==0) { return -2; } #if defined(OPTION_CONFIG_SYMBOLS) newargv=malloc(MAX_ARGS*sizeof(char *)); orig_newargv=malloc(MAX_ARGS*sizeof(char *)); #endif /* #if defined(OPTION_CONFIG_SYMBOLS) */ for(baddev=0,i=0;i<(int)devncount;i++) { da=dnd.da; for(devnum=da[i].cuu1;devnum<=da[i].cuu2;devnum++) { #if defined(OPTION_CONFIG_SYMBOLS) char wrkbfr[16]; snprintf(wrkbfr,sizeof(wrkbfr),"%3.3x",devnum); set_symbol("cuu",wrkbfr); snprintf(wrkbfr,sizeof(wrkbfr),"%4.4x",devnum); set_symbol("ccuu",wrkbfr); snprintf(wrkbfr,sizeof(wrkbfr),"%3.3X",devnum); set_symbol("CUU",wrkbfr); snprintf(wrkbfr,sizeof(wrkbfr),"%4.4X",devnum); set_symbol("CCUU",wrkbfr); snprintf(wrkbfr,sizeof(wrkbfr),"%d",dnd.lcss); set_symbol("CSS",wrkbfr); for(j=0;jMAX_LOGO_LINES) { break; } } fclose(lf); sysblk.herclogo=data; return 0; } DLL_EXPORT int parse_conkpalv(char* s, int* idle, int* intv, int* cnt ) { size_t n; char *p1, *p2, *p3, c; ASSERT(s && *s && idle && intv && cnt); if (!s || !*s || !idle || !intv || !cnt) return -1; // Format: "(idle,intv,cnt)". All numbers. No spaces. if (0 || (n = strlen(s)) < 7 || s[0] != '(' || s[n-1] != ')' ) return -1; // 1st sub-operand if (!(p1 = strchr(s+1, ','))) return -1; c = *p1; *p1 = 0; if ( strspn( s+1, "0123456789" ) != strlen(s+1) ) { *p1 = c; return -1; } *p1 = c; // 2nd sub-operand if (!(p2 = strchr(p1+1, ','))) return -1; c = *p2; *p2 = 0; if ( strspn( p1+1, "0123456789" ) != strlen(p1+1) ) { *p2 = c; return -1; } *p2 = c; // 3rd sub-operand if (!(p3 = strchr(p2+1, ')'))) return -1; c = *p3; *p3 = 0; if ( strspn( p2+1, "0123456789" ) != strlen(p2+1) ) { *p3 = c; return -1; } *p3 = c; // convert each to number c = *p1; *p1 = 0; *idle = atoi(s+1); *p1 = c; c = *p2; *p2 = 0; *intv = atoi(p1+1); *p2 = c; c = *p3; *p3 = 0; *cnt = atoi(p2+1); *p3 = c; // check results if (*idle <= 0 || INT_MAX == *idle) return -1; if (*intv <= 0 || INT_MAX == *intv) return -1; if (*cnt <= 0 || INT_MAX == *cnt ) return -1; return 0; } #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/bldcfg.c0000664000175000017500000017731312564723224011604 00000000000000/* BLDCFG.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Configuration Builder */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module builds the configuration tables for the Hercules */ /* ESA/390 emulator. It reads information about the processors */ /* and I/O devices from a configuration file. It allocates */ /* main storage and expanded storage, initializes control blocks, */ /* and creates detached threads to handle console attention */ /* requests and to maintain the TOD clock and CPU timers. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* TOD clock offset contributed by Jay Maynard */ /* Dynamic device attach/detach by Jan Jaeger */ /* OSTAILOR parameter by Jay Maynard */ /* PANRATE parameter by Reed H. Petty */ /* CPUPRIO parameter by Jan Jaeger */ /* HERCPRIO, TODPRIO, DEVPRIO parameters by Mark L. Gaubatz */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /* $(DEFSYM) symbol substitution support by Ivan Warren */ /* Patch for ${var=def} symbol substitution (hax #26), */ /* and INCLUDE support (modified hax #27), */ /* contributed by Enrico Sorichetti based on */ /* original patches by "Hackules" */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_BLDCFG_C_) #define _BLDCFG_C_ #endif #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "hostinfo.h" #if defined(OPTION_FISHIO) #include "w32chan.h" #endif // defined(OPTION_FISHIO) #if defined( OPTION_TAPE_AUTOMOUNT ) #include "tapedev.h" #endif #if !defined(_GEN_ARCH) #if defined(_ARCHMODE3) #define _GEN_ARCH _ARCHMODE3 #include "bldcfg.c" #undef _GEN_ARCH #endif #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "bldcfg.c" #undef _GEN_ARCH #endif typedef struct _DEVARRAY { U16 cuu1; U16 cuu2; } DEVARRAY; typedef struct _DEVNUMSDESC { BYTE lcss; DEVARRAY *da; } DEVNUMSDESC; /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ #define MAX_INC_LEVEL 8 /* Maximum nest level */ static int inc_level; /* Current nesting level */ // following commented out ISW 20061009 : Not referenced anywhere. // static int inc_fname[MAX_INC_LEVEL]; /* filename (base or incl) */ static int inc_stmtnum[MAX_INC_LEVEL]; /* statement number */ static int inc_ignore_errors = 0; /* 1==ignore include errors */ #ifdef EXTERNALGUI static char buf[1024]; /* Config statement buffer */ #else /*!EXTERNALGUI*/ static char buf[256]; /* Config statement buffer */ #endif /*EXTERNALGUI*/ static char *keyword; /* -> Statement keyword */ static char *operand; /* -> First argument */ static int addargc; /* Number of additional args */ static char *addargv[MAX_ARGS]; /* Additional argument array */ /*-------------------------------------------------------------------*/ /* Subroutine to parse an argument string. The string that is passed */ /* is modified in-place by inserting null characters at the end of */ /* each argument found. The returned array of argument pointers */ /* then points to each argument found in the original string. Any */ /* argument that begins with '#' comment indicator causes early */ /* termination of the parsing and is not included in the count. Any */ /* argument found that starts with a quote or apostrophe causes */ /* all characters up to the next quote or apostrophe to be */ /* included as part of that argument. The quotes/apostrophes them- */ /* selves are not considered part of any argument and are ignored. */ /* p Points to string to be parsed. */ /* maxargc Maximum allowable number of arguments. (Prevents */ /* overflowing the pargv array) */ /* pargv Pointer to buffer for argument pointer array. */ /* pargc Pointer to number of arguments integer result. */ /* Returns number of arguments found. (same value as at *pargc) */ /*-------------------------------------------------------------------*/ DLL_EXPORT int parse_args (char* p, int maxargc, char** pargv, int* pargc) { for (*pargc = 0; *pargc < MAX_ARGS; ++*pargc) addargv[*pargc] = NULL; *pargc = 0; *pargv = NULL; while (*p && *pargc < maxargc) { while (*p && isspace(*p)) p++; if (!*p) break; // find start of arg if (*p == '#') break; // stop on comments *pargv = p; ++*pargc; // count new arg while (*p && !isspace(*p) && *p != '\"' && *p != '\'') p++; if (!*p) break; // find end of arg if (*p == '\"' || *p == '\'') { char delim = *p; if (p == *pargv) *pargv = p+1; while (*++p && *p != delim) {}; if (!*p) break; // find end of quoted string } *p++ = 0; // mark end of arg pargv++; // next arg ptr } return *pargc; } void delayed_exit (int exit_code) { /* Delay exiting is to give the system * time to display the error message. */ fflush(stderr); fflush(stdout); usleep(100000); // hdl_shut(); do_shutdown(); fflush(stderr); fflush(stdout); usleep(100000); exit(exit_code); } /* storage configuration routine. To be moved *JJ */ static void config_storage(unsigned mainsize, unsigned xpndsize) { int off; /* Obtain main storage */ sysblk.mainsize = mainsize * 1024 * 1024ULL; sysblk.mainstor = calloc((size_t)(sysblk.mainsize + 8192), 1); if (sysblk.mainstor != NULL) sysblk.main_clear = 1; else sysblk.mainstor = malloc((size_t)(sysblk.mainsize + 8192)); if (sysblk.mainstor == NULL) { logmsg(_("HHCCF031S Cannot obtain %dMB main storage: %s\n"), mainsize, strerror(errno)); delayed_exit(1); } /* Trying to get mainstor aligned to the next 4K boundary - Greg */ off = (uintptr_t)sysblk.mainstor & 0xFFF; sysblk.mainstor += off ? 4096 - off : 0; /* Obtain main storage key array */ sysblk.storkeys = calloc((size_t)(sysblk.mainsize / STORAGE_KEY_UNITSIZE), 1); if (sysblk.storkeys == NULL) { sysblk.main_clear = 0; sysblk.storkeys = malloc((size_t)(sysblk.mainsize / STORAGE_KEY_UNITSIZE)); } if (sysblk.storkeys == NULL) { logmsg(_("HHCCF032S Cannot obtain storage key array: %s\n"), strerror(errno)); delayed_exit(1); } /* Initial power-on reset for main storage */ storage_clear(); #if 0 /*DEBUG-JJ-20/03/2000*/ /* Mark selected frames invalid for debugging purposes */ for (i = 64 ; i < (sysblk.mainsize / STORAGE_KEY_UNITSIZE); i += 2) if (i < (sysblk.mainsize / STORAGE_KEY_UNITSIZE) - 64) sysblk.storkeys[i] = STORKEY_BADFRM; else sysblk.storkeys[i++] = STORKEY_BADFRM; #endif if (xpndsize != 0) { #ifdef _FEATURE_EXPANDED_STORAGE /* Obtain expanded storage */ sysblk.xpndsize = xpndsize * (1024*1024 / XSTORE_PAGESIZE); sysblk.xpndstor = calloc(sysblk.xpndsize, XSTORE_PAGESIZE); if (sysblk.xpndstor) sysblk.xpnd_clear = 1; else sysblk.xpndstor = malloc((size_t)sysblk.xpndsize * XSTORE_PAGESIZE); if (sysblk.xpndstor == NULL) { logmsg(_("HHCCF033S Cannot obtain %dMB expanded storage: " "%s\n"), xpndsize, strerror(errno)); delayed_exit(1); } /* Initial power-on reset for expanded storage */ xstorage_clear(); #else /*!_FEATURE_EXPANDED_STORAGE*/ logmsg(_("HHCCF034W Expanded storage support not installed\n")); #endif /*!_FEATURE_EXPANDED_STORAGE*/ } /* end if(sysblk.xpndsize) */ } #if defined( OPTION_TAPE_AUTOMOUNT ) /*-------------------------------------------------------------------*/ /* Add directory to AUTOMOUNT allowed/disallowed directories list */ /* */ /* Input: tamdir pointer to work character array of at least */ /* MAX_PATH size containing an allowed/disallowed */ /* directory specification, optionally prefixed */ /* with the '+' or '-' indicator. */ /* */ /* ppTAMDIR address of TAMDIR ptr that upon successful */ /* completion is updated to point to the TAMDIR */ /* entry that was just successfully added. */ /* */ /* Output: upon success, ppTAMDIR is updated to point to the TAMDIR */ /* entry just added. Upon error, ppTAMDIR is set to NULL and */ /* the original input character array is set to the inter- */ /* mediate value being processed when the error occurred. */ /* */ /* Returns: 0 == success */ /* 1 == unresolvable path */ /* 2 == path inaccessible */ /* 3 == conflict w/previous */ /* 4 == duplicates previous */ /* 5 == out of memory */ /* */ /*-------------------------------------------------------------------*/ DLL_EXPORT int add_tamdir( char *tamdir, TAMDIR **ppTAMDIR ) { int rc, rej = 0; char dirwrk[ MAX_PATH ] = {0}; *ppTAMDIR = NULL; if (*tamdir == '-') { rej = 1; memmove (tamdir, tamdir+1, MAX_PATH); } else if (*tamdir == '+') { rej = 0; memmove (tamdir, tamdir+1, MAX_PATH); } /* Convert tamdir to absolute path ending with a slash */ #if defined(_MSVC_) /* (expand any embedded %var% environment variables) */ rc = expand_environ_vars( tamdir, dirwrk, MAX_PATH ); if (rc == 0) strlcpy (tamdir, dirwrk, MAX_PATH); #endif if (!realpath( tamdir, dirwrk )) return (1); /* ("unresolvable path") */ strlcpy (tamdir, dirwrk, MAX_PATH); /* Verify that the path is valid */ if (access( tamdir, R_OK | W_OK ) != 0) return (2); /* ("path inaccessible") */ /* Append trailing path separator if needed */ rc = strlen( tamdir ); if (tamdir[rc-1] != *PATH_SEP) strlcat (tamdir, PATH_SEP, MAX_PATH); /* Check for duplicate/conflicting specification */ for (*ppTAMDIR = sysblk.tamdir; *ppTAMDIR; *ppTAMDIR = (*ppTAMDIR)->next) { if (strfilenamecmp( tamdir, (*ppTAMDIR)->dir ) == 0) { if ((*ppTAMDIR)->rej != rej) return (3); /* ("conflict w/previous") */ else return (4); /* ("duplicates previous") */ } } /* Allocate new AUTOMOUNT directory entry */ *ppTAMDIR = malloc( sizeof(TAMDIR) ); if (!*ppTAMDIR) return (5); /* ("out of memory") */ /* Fill in the new entry... */ (*ppTAMDIR)->dir = strdup (tamdir); (*ppTAMDIR)->len = strlen (tamdir); (*ppTAMDIR)->rej = rej; (*ppTAMDIR)->next = NULL; /* Add new entry to end of existing list... */ if (sysblk.tamdir == NULL) sysblk.tamdir = *ppTAMDIR; else { TAMDIR *pTAMDIR = sysblk.tamdir; while (pTAMDIR->next) pTAMDIR = pTAMDIR->next; pTAMDIR->next = *ppTAMDIR; } /* Use first allowable dir as default */ if (rej == 0 && sysblk.defdir == NULL) sysblk.defdir = (*ppTAMDIR)->dir; return (0); /* ("success") */ } #endif /* OPTION_TAPE_AUTOMOUNT */ /*-------------------------------------------------------------------*/ /* Subroutine to read a statement from the configuration file */ /* The statement is then parsed into keyword, operand, and */ /* additional arguments. The output values are: */ /* keyword Points to first word of statement */ /* operand Points to second word of statement */ /* addargc Contains number of additional arguments */ /* addargv An array of pointers to each additional argument */ /* Returns 0 if successful, -1 if end of file */ /*-------------------------------------------------------------------*/ static int read_config (char *fname, FILE *fp) { int i; /* Array subscript */ int c; /* Character work area */ int stmtlen; /* Statement length */ #if defined( OPTION_ENHANCED_CONFIG_SYMBOLS ) int inc_dollar; /* >=0 Ndx of dollar */ int inc_lbrace; /* >=0 Ndx of lbrace + 1 */ int inc_colon; /* >=0 Ndx of colon */ int inc_equals; /* >=0 Ndx of equals */ char *inc_envvar; /* ->Environment variable */ #endif // defined( OPTION_ENHANCED_CONFIG_SYMBOLS ) int lstarted; /* Indicate if non-whitespace*/ /* has been seen yet in line */ char *cnfline; /* Pointer to copy of buffer */ #if defined(OPTION_CONFIG_SYMBOLS) char *buf1; /* Pointer to resolved buffer*/ #endif /*defined(OPTION_CONFIG_SYMBOLS)*/ #if defined( OPTION_ENHANCED_CONFIG_SYMBOLS ) inc_dollar = -1; inc_lbrace = -1; inc_colon = -1; inc_equals = -1; #endif // defined( OPTION_ENHANCED_CONFIG_SYMBOLS ) while (1) { /* Increment statement number */ inc_stmtnum[inc_level]++; /* Read next statement from configuration file */ for (stmtlen = 0, lstarted = 0; ;) { /* Read character from configuration file */ c = fgetc(fp); /* Check for I/O error */ if (ferror(fp)) { logmsg(_("HHCCF001S Error reading file %s line %d: %s\n"), fname, inc_stmtnum[inc_level], strerror(errno)); delayed_exit(1); } /* Check for end of file */ if (stmtlen == 0 && (c == EOF || c == '\x1A')) return -1; /* Check for end of line */ if (c == '\n' || c == EOF || c == '\x1A') break; /* Ignore nulls and carriage returns */ if (c == '\0' || c == '\r') continue; /* Check if it is a white space and no other character yet */ if(!lstarted && isspace(c)) continue; lstarted=1; /* Check that statement does not overflow buffer */ if (stmtlen >= (int)(sizeof(buf) - 1)) { logmsg(_("HHCCF002S File %s line %d is too long\n"), fname, inc_stmtnum[inc_level]); delayed_exit(1); } #if defined( OPTION_ENHANCED_CONFIG_SYMBOLS ) /* inc_dollar already processed? */ if (inc_dollar >= 0) { /* Left brace already processed? */ if (inc_lbrace >= 0) { /* End of variable spec? */ if (c == '}') { /* Terminate it */ buf[stmtlen] = '\0'; /* Terminate var name if we have a inc_colon specifier */ if (inc_colon >= 0) { buf[inc_colon] = '\0'; } /* Terminate var name if we have a default value */ if (inc_equals >= 0) { buf[inc_equals] = '\0'; } /* Reset statement index to start of variable */ stmtlen = inc_dollar; /* Get variable value */ inc_envvar = getenv (&buf[inc_lbrace]); /* Variable unset? */ if (inc_envvar == NULL) { /* Substitute default if specified */ if (inc_equals >= 0) { inc_envvar = &buf[inc_equals+1]; } } else // (environ variable defined) { /* Have ":=" specification? */ if (/*inc_colon >= 0 && */inc_equals >= 0) { /* Substitute default if value is NULL */ if (strlen (inc_envvar) == 0) { inc_envvar = &buf[inc_equals+1]; } } } /* Have a value? (environment or default) */ if (inc_envvar != NULL) { /* Check that statement does not overflow buffer */ if (stmtlen+strlen(inc_envvar) >= sizeof(buf) - 1) { logmsg(_("HHCCF002S File %s line %d is too long\n"), fname, inc_stmtnum[inc_level]); delayed_exit(1); } /* Copy to buffer and update index */ stmtlen += sprintf (&buf[stmtlen], "%s", inc_envvar); } /* Reset indexes */ inc_equals = -1; inc_colon = -1; inc_lbrace = -1; inc_dollar = -1; continue; } else if (c == ':' && inc_colon < 0 && inc_equals < 0) { /* Remember possible start of default specifier */ inc_colon = stmtlen; } else if (c == '=' && inc_equals < 0) { /* Remember possible start of default specifier */ inc_equals = stmtlen; } } else // (inc_lbrace < 0) { /* Remember start of variable name */ if (c == '{') { inc_lbrace = stmtlen + 1; } else { /* Reset inc_dollar specifier if immediately following character is not a left brace */ inc_dollar = -1; } } } else // (inc_dollar < 0) { /* Enter variable substitution state */ if (c == '$') { inc_dollar = stmtlen; } } #endif // defined( OPTION_ENHANCED_CONFIG_SYMBOLS ) /* Append character to buffer */ buf[stmtlen++] = c; } /* end for(stmtlen) */ /* Remove trailing blanks and tabs */ while (stmtlen > 0 && (buf[stmtlen-1] == SPACE || buf[stmtlen-1] == '\t')) stmtlen--; buf[stmtlen] = '\0'; /* Ignore comments and null statements */ if (stmtlen == 0 || buf[0] == '*' || buf[0] == '#') continue; cnfline = strdup(buf); /* Parse the statement just read */ #if defined(OPTION_CONFIG_SYMBOLS) /* Perform variable substitution */ /* First, set some 'dynamic' symbols to their own values */ set_symbol("CUU","$(CUU)"); set_symbol("cuu","$(cuu)"); set_symbol("CCUU","$(CCUU)"); set_symbol("ccuu","$(ccuu)"); buf1=resolve_symbol_string(buf); if(buf1!=NULL) { if(strlen(buf1)>=sizeof(buf)) { logmsg(_("HHCCF002S File %s line %d is too long\n"), fname, inc_stmtnum[inc_level]); free(buf1); delayed_exit(1); } strcpy(buf,buf1); } #endif /*defined(OPTION_CONFIG_SYMBOLS)*/ parse_args (buf, MAX_ARGS, addargv, &addargc); #if defined(OPTION_DYNAMIC_LOAD) if(config_command) { if( config_command(addargc, (char**)addargv, cnfline) ) { free(cnfline); continue; } } #endif /*defined(OPTION_DYNAMIC_LOAD)*/ if( !ProcessConfigCommand (addargc, (char**)addargv, cnfline) ) { free(cnfline); continue; } free(cnfline); /* Move the first two arguments to separate variables */ keyword = addargv[0]; operand = addargv[1]; addargc = (addargc > 2) ? (addargc-2) : (0); for (i = 0; i < MAX_ARGS; i++) { if (i < (MAX_ARGS-2)) addargv[i] = addargv[i+2]; else addargv[i] = NULL; } break; } /* end while */ return 0; } /* end function read_config */ static inline S64 lyear_adjust(int epoch) { int year, leapyear; U64 tod = hw_clock(); if(tod >= TOD_YEAR) { tod -= TOD_YEAR; year = (tod / TOD_4YEARS * 4) + 1; tod %= TOD_4YEARS; if((leapyear = tod / TOD_YEAR) == 4) year--; year += leapyear; } else year = 0; if(epoch > 0) return (((year % 4) != 0) && (((year % 4) - (epoch % 4)) <= 0)) ? -TOD_DAY : 0; else return (((year % 4) == 0 && (-epoch % 4) != 0) || ((year % 4) + (-epoch % 4) > 4)) ? TOD_DAY : 0; } DLL_EXPORT char *config_cnslport = "3270"; /*-------------------------------------------------------------------*/ /* Function to build system configuration */ /*-------------------------------------------------------------------*/ void build_config (char *fname) { int rc; /* Return code */ int i; /* Array subscript */ int scount; /* Statement counter */ int cpu; /* CPU number */ int count; /* Counter */ FILE *inc_fp[MAX_INC_LEVEL]; /* Configuration file pointer*/ char *sserial; /* -> CPU serial string */ char *smodel; /* -> CPU model string */ char *sversion; /* -> CPU version string */ char *smainsize; /* -> Main size string */ char *sxpndsize; /* -> Expanded size string */ char *smaxcpu; /* -> Maximum number of CPUs */ char *snumcpu; /* -> Number of CPUs */ char *snumvec; /* -> Number of VFs */ char *sengines; /* -> Processor engine types */ char *ssysepoch; /* -> System epoch */ char *syroffset; /* -> System year offset */ char *stzoffset; /* -> System timezone offset */ char *shercprio; /* -> Hercules base priority */ char *stodprio; /* -> Timer thread priority */ char *scpuprio; /* -> CPU thread priority */ char *sdevprio; /* -> Device thread priority */ char *slogofile; /* -> 3270 logo file */ #if defined(_FEATURE_ECPSVM) char *secpsvmlevel; /* -> ECPS:VM Keyword */ char *secpsvmlvl; /* -> ECPS:VM level (or 'no')*/ int ecpsvmac; /* -> ECPS:VM add'l arg cnt */ #endif /*defined(_FEATURE_ECPSVM)*/ #if defined(OPTION_SHARED_DEVICES) char *sshrdport; /* -> Shared device port nbr */ #endif /*defined(OPTION_SHARED_DEVICES)*/ U16 version = 0x00; /* CPU version code */ int dfltver = 1; /* Default version code */ U32 serial; /* CPU serial number */ U16 model; /* CPU model number */ unsigned mainsize; /* Main storage size (MB) */ unsigned xpndsize; /* Expanded storage size (MB)*/ U16 maxcpu; /* Maximum number of CPUs */ U16 numcpu; /* Number of CPUs */ U16 numvec; /* Number of VFs */ #if defined(OPTION_SHARED_DEVICES) U16 shrdport; /* Shared device port number */ #endif /*defined(OPTION_SHARED_DEVICES)*/ S32 sysepoch; /* System epoch year */ S32 tzoffset; /* System timezone offset */ S32 yroffset; /* System year offset */ S64 ly1960; /* Leap offset for 1960 epoch*/ int hercprio; /* Hercules base priority */ int todprio; /* Timer thread priority */ int cpuprio; /* CPU thread priority */ int devprio; /* Device thread priority */ DEVBLK *dev; /* -> Device Block */ char *sdevnum; /* -> Device number string */ char *sdevtype; /* -> Device type string */ int devtmax; /* Max number device threads */ #if defined(_FEATURE_ECPSVM) int ecpsvmavail; /* ECPS:VM Available flag */ int ecpsvmlevel; /* ECPS:VM declared level */ #endif /*defined(_FEATURE_ECPSVM)*/ BYTE c; /* Work area for sscanf */ char *styp; /* -> Engine type string */ char *styp_values[] = {"CP","CF","AP","IL","??","IP"}; /* type values */ BYTE ptyp; /* Processor engine type */ #ifdef OPTION_SELECT_KLUDGE int dummyfd[OPTION_SELECT_KLUDGE]; /* Dummy file descriptors -- this allows the console to get a low fd when the msg pipe is opened... prevents cygwin from thrashing in select(). sigh */ #endif char hlogofile[FILENAME_MAX+1] = ""; /* File name from HERCLOGO */ char pathname[MAX_PATH]; /* file path in host format */ /* Initialize SETMODE and set user authority */ SETMODE(INIT); #ifdef OPTION_SELECT_KLUDGE /* Reserve some fd's to be used later for the message pipes */ for (i = 0; i < OPTION_SELECT_KLUDGE; i++) dummyfd[i] = dup(fileno(stderr)); #endif /* Open the base configuration file */ hostpath(pathname, fname, sizeof(pathname)); inc_level = 0; inc_fp[inc_level] = fopen (pathname, "r"); if (inc_fp[inc_level] == NULL) { logmsg(_("HHCCF003S Open error file %s: %s\n"), fname, strerror(errno)); delayed_exit(1); } inc_stmtnum[inc_level] = 0; /* Set the default system parameter values */ serial = 0x000001; model = 0x0586; mainsize = 2; xpndsize = 0; maxcpu = 0; numcpu = 0; numvec = MAX_CPU_ENGINES; sysepoch = 1900; yroffset = 0; tzoffset = 0; #if defined(_390) sysblk.arch_mode = ARCH_390; #else sysblk.arch_mode = ARCH_370; #endif #if defined(_900) sysblk.arch_z900 = ARCH_900; #endif sysblk.pgminttr = OS_NONE; sysblk.timerint = DEFAULT_TIMER_REFRESH_USECS; #if defined( HTTP_SERVER_CONNECT_KLUDGE ) sysblk.http_server_kludge_msecs = 10; #endif // defined( HTTP_SERVER_CONNECT_KLUDGE ) hercprio = DEFAULT_HERCPRIO; todprio = DEFAULT_TOD_PRIO; cpuprio = DEFAULT_CPU_PRIO; devprio = DEFAULT_DEV_PRIO; devtmax = MAX_DEVICE_THREADS; sysblk.kaidle = KEEPALIVE_IDLE_TIME; sysblk.kaintv = KEEPALIVE_PROBE_INTERVAL; sysblk.kacnt = KEEPALIVE_PROBE_COUNT; #if defined(_FEATURE_ECPSVM) ecpsvmavail = 0; ecpsvmlevel = 20; #endif /*defined(_FEATURE_ECPSVM)*/ #if defined(OPTION_SHARED_DEVICES) shrdport = 0; #endif /*defined(OPTION_SHARED_DEVICES)*/ #if defined(_FEATURE_ASN_AND_LX_REUSE) sysblk.asnandlxreuse = 0; /* ASN And LX Reuse is defaulted to DISABLE */ #endif #ifdef PANEL_REFRESH_RATE sysblk.panrate = PANEL_REFRESH_RATE_SLOW; #endif /* Initialize locks, conditions, and attributes */ initialize_lock (&sysblk.todlock); initialize_lock (&sysblk.mainlock); sysblk.mainowner = LOCK_OWNER_NONE; initialize_lock (&sysblk.intlock); initialize_lock (&sysblk.iointqlk); sysblk.intowner = LOCK_OWNER_NONE; initialize_lock (&sysblk.sigplock); // initialize_detach_attr (&sysblk.detattr); // (moved to impl.c) // initialize_join_attr (&sysblk.joinattr); // (moved to impl.c) initialize_condition (&sysblk.cpucond); for (i = 0; i < MAX_CPU_ENGINES; i++) initialize_lock (&sysblk.cpulock[i]); initialize_condition (&sysblk.sync_cond); initialize_condition (&sysblk.sync_bc_cond); #if defined(OPTION_INSTRUCTION_COUNTING) initialize_lock (&sysblk.icount_lock); #endif #ifdef OPTION_PTTRACE ptt_trace_init (0, 1); #endif #if defined(_FEATURE_MESSAGE_SECURITY_ASSIST) /* Initialize the wrapping key registers lock */ initialize_lock(&sysblk.wklock); #endif /*defined(_FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(OPTION_FISHIO) InitIOScheduler // initialize i/o scheduler... ( sysblk.arch_mode, // (for calling execute_ccw_chain) &sysblk.devprio, // (ptr to device thread priority) MAX_DEVICE_THREAD_IDLE_SECS, // (maximum device thread wait time) devtmax // (maximum #of device threads allowed) ); #else // !defined(OPTION_FISHIO) initialize_lock (&sysblk.ioqlock); initialize_condition (&sysblk.ioqcond); /* Set max number device threads */ sysblk.devtmax = devtmax; sysblk.devtwait = sysblk.devtnbr = sysblk.devthwm = sysblk.devtunavail = 0; #endif // defined(OPTION_FISHIO) /* Default the licence setting */ losc_set(PGM_PRD_OS_RESTRICTED); /* Default CPU type CP */ for (i = 0; i < MAX_CPU_ENGINES; i++) sysblk.ptyp[i] = SCCB_PTYP_CP; /* Cap the default priorities at zero if setuid not available */ #if !defined(NO_SETUID) if (sysblk.suid != 0) { #endif /*!defined(NO_SETUID)*/ if (hercprio < 0) hercprio = 0; if (todprio < 0) todprio = 0; if (cpuprio < 0) cpuprio = 0; if (devprio < 0) devprio = 0; #if !defined(NO_SETUID) } #endif /*!defined(NO_SETUID)*/ /*****************************************************************/ /* Parse configuration file system parameter statements... */ /*****************************************************************/ for (scount = 0; ; scount++) { /* Read next record from the configuration file */ while (inc_level >= 0 && read_config (fname, inc_fp[inc_level])) { fclose (inc_fp[inc_level--]); } if (inc_level < 0) { logmsg(_("HHCCF004S No device records in file %s\n"), fname); delayed_exit(1); } #if defined( OPTION_ENHANCED_CONFIG_INCLUDE ) if (strcasecmp (keyword, "ignore") == 0) { if (strcasecmp (operand, "include_errors") == 0) { logmsg( _("HHCCF081I %s Will ignore include errors .\n"), fname); inc_ignore_errors = 1 ; } continue ; } /* Check for include statement */ if (strcasecmp (keyword, "include") == 0) { if (++inc_level >= MAX_INC_LEVEL) { logmsg(_( "HHCCF082S Error in %s line %d: " "Maximum nesting level (%d) reached\n"), fname, inc_stmtnum[inc_level-1], MAX_INC_LEVEL); delayed_exit(1); } logmsg( _("HHCCF083I %s Including %s at %d.\n"), fname, operand, inc_stmtnum[inc_level-1]); hostpath(pathname, operand, sizeof(pathname)); inc_fp[inc_level] = fopen (pathname, "r"); if (inc_fp[inc_level] == NULL) { inc_level--; if ( inc_ignore_errors == 1 ) { logmsg(_("HHCCF084W %s Open error ignored file %s: %s\n"), fname, operand, strerror(errno)); continue ; } else { logmsg(_("HHCCF085S %s Open error file %s: %s\n"), fname, operand, strerror(errno)); delayed_exit(1); } } inc_stmtnum[inc_level] = 0; continue; } #endif // defined( OPTION_ENHANCED_CONFIG_INCLUDE ) /* Exit loop if first device statement found */ if (strlen(keyword) <= 4 && sscanf(keyword, "%x%c", &rc, &c) == 1) break; /* ISW */ /* Also exit if keyword contains '-', ',' or '.' */ /* Added because device statements may now be a compound device number specification */ if(strchr(keyword,'-')) { break; } if(strchr(keyword,'.')) { break; } if(strchr(keyword,',')) { break; } /* Also exit if keyword contains ':' (added by Harold Grovesteen jan2008) */ /* Added because device statements may now contain channel set or LCSS id */ if(strchr(keyword,':')) { break; } /* Clear the operand value pointers */ sserial = NULL; smodel = NULL; sversion = NULL; smainsize = NULL; sxpndsize = NULL; smaxcpu = NULL; snumcpu = NULL; snumvec = NULL; sengines = NULL; ssysepoch = NULL; syroffset = NULL; stzoffset = NULL; shercprio = NULL; stodprio = NULL; scpuprio = NULL; sdevprio = NULL; slogofile = NULL; #if defined(_FEATURE_ECPSVM) secpsvmlevel = NULL; secpsvmlvl = NULL; ecpsvmac = 0; #endif /*defined(_FEATURE_ECPSVM)*/ #if defined(OPTION_SHARED_DEVICES) sshrdport = NULL; #endif /*defined(OPTION_SHARED_DEVICES)*/ /* Check for old-style CPU statement */ if (scount == 0 && addargc == 5 && strlen(keyword) == 6 && sscanf(keyword, "%x%c", &rc, &c) == 1) { sserial = keyword; smodel = operand; smainsize = addargv[0]; sxpndsize = addargv[1]; config_cnslport = strdup(addargv[2]); snumcpu = addargv[3]; set_loadparm(addargv[4]); } else { if (strcasecmp (keyword, "cpuserial") == 0) { sserial = operand; } else if (strcasecmp (keyword, "cpumodel") == 0) { smodel = operand; } else if (strcasecmp (keyword, "mainsize") == 0) { smainsize = operand; } else if (strcasecmp (keyword, "xpndsize") == 0) { sxpndsize = operand; } else if (strcasecmp (keyword, "cnslport") == 0) { config_cnslport = strdup(operand); } else if (strcasecmp (keyword, "maxcpu") == 0) { smaxcpu = operand; } else if (strcasecmp (keyword, "numcpu") == 0) { snumcpu = operand; } else if (strcasecmp (keyword, "numvec") == 0) { snumvec = operand; } else if (strcasecmp (keyword, "engines") == 0) { sengines = operand; } else if (strcasecmp (keyword, "sysepoch") == 0) { ssysepoch = operand; if (addargc > 0) { syroffset = addargv[0]; addargc--; } } else if (strcasecmp (keyword, "yroffset") == 0) { syroffset = operand; } else if (strcasecmp (keyword, "tzoffset") == 0) { stzoffset = operand; } else if (strcasecmp (keyword, "cpuverid") == 0) { sversion = operand; } else if (strcasecmp (keyword, "hercprio") == 0) { shercprio = operand; } else if (strcasecmp (keyword, "todprio") == 0) { stodprio = operand; } else if (strcasecmp (keyword, "cpuprio") == 0) { scpuprio = operand; } else if (strcasecmp (keyword, "devprio") == 0) { sdevprio = operand; } else if (strcasecmp (keyword, "logofile") == 0) { logmsg(_("HHCCF061W Warning in %s line %d: " "LOGOFILE statement deprecated. Use HERCLOGO instead\n"), fname, inc_stmtnum[inc_level]); slogofile=operand; } else if (strcasecmp (keyword, "herclogo") == 0) { slogofile=operand; } #if defined(_FEATURE_ECPSVM) /* ECPS:VM support */ else if(strcasecmp(keyword, "ecps:vm") == 0) { secpsvmlevel=operand; secpsvmlvl=addargv[0]; ecpsvmac=addargc; logmsg(_("HHCCF061W Warning in %s line %d: " "ECPS:VM Statement deprecated. Use ECPSVM instead\n"), fname, inc_stmtnum[inc_level]); addargc=0; } else if(strcasecmp(keyword, "ecpsvm") == 0) { secpsvmlevel=operand; secpsvmlvl=addargv[0]; ecpsvmac=addargc; addargc=0; } #endif /*defined(_FEATURE_ECPSVM)*/ #if defined(OPTION_SHARED_DEVICES) else if (strcasecmp (keyword, "shrdport") == 0) { sshrdport = operand; } #endif /*defined(OPTION_SHARED_DEVICES)*/ else { logmsg( _("HHCCF008E Error in %s line %d: " "Syntax error: %s\n"), fname, inc_stmtnum[inc_level], keyword); operand = ""; addargc = 0; } /* Check for one and only one operand */ if (operand == NULL || addargc != 0) { logmsg( _("HHCCF009E Error in %s line %d: " "Incorrect number of operands\n"), fname, inc_stmtnum[inc_level]); } } /* end else (not old-style CPU statement) */ /* Parse CPU version number operand */ if (sversion != NULL) { if (strlen(sversion) != 2 || sscanf(sversion, "%hx%c", &version, &c) != 1 || version>255) { logmsg(_("HHCCF012S Error in %s line %d: " "%s is not a valid CPU version code\n"), fname, inc_stmtnum[inc_level], sversion); delayed_exit(1); } dfltver = 0; } /* Parse CPU serial number operand */ if (sserial != NULL) { if (strlen(sserial) != 6 || sscanf(sserial, "%x%c", &serial, &c) != 1) { logmsg(_("HHCCF051S Error in %s line %d: " "%s is not a valid serial number\n"), fname, inc_stmtnum[inc_level], sserial); delayed_exit(1); } } /* Parse CPU model number operand */ if (smodel != NULL) { if (strlen(smodel) != 4 || sscanf(smodel, "%hx%c", &model, &c) != 1) { logmsg(_("HHCCF012S Error in %s line %d: " "%s is not a valid CPU model\n"), fname, inc_stmtnum[inc_level], smodel); delayed_exit(1); } } /* Parse main storage size operand */ if (smainsize != NULL) { if (sscanf(smainsize, "%u%c", &mainsize, &c) != 1 || mainsize < 2 || (mainsize > 4095 && sizeof(sysblk.mainsize) < 8) || (mainsize > 4095 && sizeof(size_t) < 8)) { logmsg(_("HHCCF013S Error in %s line %d: " "Invalid main storage size %s\n"), fname, inc_stmtnum[inc_level], smainsize); delayed_exit(1); } } /* Parse expanded storage size operand */ if (sxpndsize != NULL) { if (sscanf(sxpndsize, "%u%c", &xpndsize, &c) != 1 || xpndsize > (0x100000000ULL / XSTORE_PAGESIZE) - 1 || (xpndsize > 4095 && sizeof(size_t) < 8)) { logmsg(_("HHCCF014S Error in %s line %d: " "Invalid expanded storage size %s\n"), fname, inc_stmtnum[inc_level], sxpndsize); delayed_exit(1); } } /* Parse Hercules priority operand */ if (shercprio != NULL) if (sscanf(shercprio, "%d%c", &hercprio, &c) != 1) { logmsg(_("HHCCF016S Error in %s line %d: " "Invalid Hercules process group thread priority %s\n"), fname, inc_stmtnum[inc_level], shercprio); delayed_exit(1); } #if !defined(NO_SETUID) if(sysblk.suid != 0 && hercprio < 0) { logmsg(_("HHCCF017W Hercules is not running as setuid root, " "cannot raise Hercules process group thread priority\n")); hercprio = 0; /* Set priority to Normal */ } #endif /*!defined(NO_SETUID)*/ sysblk.hercprio = hercprio; /* Parse TOD Clock priority operand */ if (stodprio != NULL) if (sscanf(stodprio, "%d%c", &todprio, &c) != 1) { logmsg(_("HHCCF016S Error in %s line %d: " "Invalid TOD Clock thread priority %s\n"), fname, inc_stmtnum[inc_level], stodprio); delayed_exit(1); } #if !defined(NO_SETUID) if(sysblk.suid != 0 && todprio < 0) { logmsg(_("HHCCF017W Hercules is not running as setuid root, " "cannot raise TOD Clock thread priority\n")); todprio = 0; /* Set priority to Normal */ } #endif /*!defined(NO_SETUID)*/ sysblk.todprio = todprio; /* Parse CPU thread priority operand */ if (scpuprio != NULL) if (sscanf(scpuprio, "%d%c", &cpuprio, &c) != 1) { logmsg(_("HHCCF016S Error in %s line %d: " "Invalid CPU thread priority %s\n"), fname, inc_stmtnum[inc_level], scpuprio); delayed_exit(1); } #if !defined(NO_SETUID) if(sysblk.suid != 0 && cpuprio < 0) { logmsg(_("HHCCF017W Hercules is not running as setuid root, " "cannot raise CPU priority\n")); cpuprio = 0; /* Set priority to Normal */ } #endif /*!defined(NO_SETUID)*/ sysblk.cpuprio = cpuprio; /* Parse Device thread priority operand */ if (sdevprio != NULL) if (sscanf(sdevprio, "%d%c", &devprio, &c) != 1) { logmsg(_("HHCCF016S Error in %s line %d: " "Invalid device thread priority %s\n"), fname, inc_stmtnum[inc_level], sdevprio); delayed_exit(1); } #if !defined(NO_SETUID) if(sysblk.suid != 0 && devprio < 0) logmsg(_("HHCCF017W Hercules is not running as setuid root, " "cannot raise device thread priority\n")); #endif /*!defined(NO_SETUID)*/ sysblk.devprio = devprio; /* Parse Device thread priority operand */ if (sdevprio != NULL) if (sscanf(sdevprio, "%d%c", &devprio, &c) != 1) { logmsg(_("HHCCF016S Error in %s line %d: " "Invalid device thread priority %s\n"), fname, inc_stmtnum[inc_level], sdevprio); delayed_exit(1); } #if !defined(NO_SETUID) if(sysblk.suid != 0 && devprio < 0) logmsg(_("HHCCF017W Hercules is not running as setuid root, " "cannot raise device thread priority\n")); #endif /*!defined(NO_SETUID)*/ sysblk.devprio = devprio; /* Parse maximum number of CPUs operand */ if (smaxcpu != NULL) { if (sscanf(smaxcpu, "%hu%c", &maxcpu, &c) != 1 || maxcpu < 1 || maxcpu > MAX_CPU_ENGINES) { fprintf(stderr, _("HHCCF021S Error in %s line %d: " "Invalid maximum number of CPUs %s\n"), fname, inc_stmtnum[inc_level], smaxcpu); delayed_exit(1); } } /* Parse number of CPUs operand */ if (snumcpu != NULL) { if (sscanf(snumcpu, "%hu%c", &numcpu, &c) != 1 || numcpu > MAX_CPU_ENGINES) { logmsg(_("HHCCF018S Error in %s line %d: " "Invalid number of CPUs %s\n"), fname, inc_stmtnum[inc_level], snumcpu); delayed_exit(1); } } sysblk.numcpu = numcpu ? numcpu : 1; /* Parse number of VFs operand */ if (snumvec != NULL) { #ifdef _FEATURE_VECTOR_FACILITY if (sscanf(snumvec, "%hu%c", &numvec, &c) != 1 || numvec > MAX_CPU_ENGINES) { logmsg(_("HHCCF019S Error in %s line %d: " "Invalid number of VFs %s\n"), fname, inc_stmtnum[inc_level], snumvec); delayed_exit(1); } #else /*!_FEATURE_VECTOR_FACILITY*/ logmsg(_("HHCCF020W Vector Facility support not configured\n")); #endif /*!_FEATURE_VECTOR_FACILITY*/ } sysblk.numvec = numvec; /* Parse processor engine types operand */ /* example: ENGINES 4*CP,AP,2*IP */ if (sengines != NULL) { styp = strtok(sengines,","); for (cpu = 0; styp != NULL; ) { count = 1; if (isdigit(styp[0])) { if (sscanf(styp, "%d%c", &count, &c) != 2 || c != '*' || count < 1) { logmsg(_("HHCCF074S Error in %s line %d: " "Invalid engine syntax %s\n"), fname, inc_stmtnum[inc_level], styp); delayed_exit(1); break; } styp = strchr(styp,'*') + 1; } if (strcasecmp(styp,"cp") == 0) ptyp = SCCB_PTYP_CP; else if (strcasecmp(styp,"cf") == 0) ptyp = SCCB_PTYP_ICF; else if (strcasecmp(styp,"il") == 0) ptyp = SCCB_PTYP_IFL; else if (strcasecmp(styp,"ap") == 0) ptyp = SCCB_PTYP_IFA; else if (strcasecmp(styp,"ip") == 0) ptyp = SCCB_PTYP_SUP; else { logmsg(_("HHCCF075S Error in %s line %d: " "Invalid engine type %s\n"), fname, inc_stmtnum[inc_level], styp); delayed_exit(1); break; } while (count-- > 0 && cpu < MAX_CPU_ENGINES) { logmsg("HHCCF077I Engine %d set to type %d (%s)\n", cpu, ptyp, styp_values[ptyp]); sysblk.ptyp[cpu++] = ptyp; } styp = strtok(NULL,","); } } /* Parse system epoch operand */ if (ssysepoch != NULL) { if (strlen(ssysepoch) != 4 || sscanf(ssysepoch, "%d%c", &sysepoch, &c) != 1 || sysepoch <= 1800 || sysepoch >= 2100) { logmsg(_("HHCCF022S Error in %s line %d: " "%s is not a valid system epoch.\n" " The only valid values are " "1801-2099\n"), fname, inc_stmtnum[inc_level], ssysepoch); delayed_exit(1); } } /* Parse year offset operand */ if (syroffset != NULL) { if (sscanf(syroffset, "%d%c", &yroffset, &c) != 1 || (yroffset < -142) || (yroffset > 142)) { logmsg(_("HHCCF070S Error in %s line %d: " "%s is not a valid year offset\n"), fname, inc_stmtnum[inc_level], syroffset); delayed_exit(1); } } /* Parse timezone offset operand */ if (stzoffset != NULL) { if (strlen(stzoffset) != 5 || sscanf(stzoffset, "%d%c", &tzoffset, &c) != 1 || (tzoffset < -2359) || (tzoffset > 2359)) { logmsg(_("HHCCF023S Error in %s line %d: " "%s is not a valid timezone offset\n"), fname, inc_stmtnum[inc_level], stzoffset); delayed_exit(1); } } /* Parse terminal logo option */ if (slogofile != NULL) { strncpy(hlogofile, slogofile, sizeof(hlogofile)-1); hlogofile[sizeof(hlogofile)-1] = '\0'; } #if defined(_FEATURE_ECPSVM) /* Parse ECPS:VM level */ if(secpsvmlevel != NULL) { while(1) /* Dummy while loop for break support */ { ecpsvmavail=0; ecpsvmlevel=0; if(strcasecmp(secpsvmlevel,"no")==0) { ecpsvmavail=0; break; } if(strcasecmp(secpsvmlevel,"yes")==0) { ecpsvmavail=1; ecpsvmlevel=20; break; } if(strcasecmp(secpsvmlevel,"level")==0) { ecpsvmavail=1; if(ecpsvmac==0) { logmsg(_("HHCCF062W Warning in %s line %d: " "Missing ECPSVM level value. 20 Assumed\n"), fname, inc_stmtnum[inc_level]); ecpsvmavail=1; ecpsvmlevel=20; break; } if (sscanf(secpsvmlvl, "%d%c", &ecpsvmlevel, &c) != 1) { logmsg(_("HHCCF051W Warning in %s line %d: " "Invalid ECPSVM level value : %s. 20 Assumed\n"), fname, inc_stmtnum[inc_level], secpsvmlevel); ecpsvmavail=1; ecpsvmlevel=20; break; } break; } ecpsvmavail=1; if (sscanf(secpsvmlevel, "%d%c", &ecpsvmlevel, &c) != 1) { logmsg(_("HHCCF051W Error in %s line %d: " "Invalid ECPSVM keyword : %s. NO Assumed\n"), fname, inc_stmtnum[inc_level], secpsvmlevel); ecpsvmavail=0; ecpsvmlevel=0; break; } else { logmsg(_("HHCCF063W Warning in %s line %d: " "Specifying ECPSVM level directly is deprecated. Use the 'LEVEL' keyword instead.\n"), fname, inc_stmtnum[inc_level]); break; } break; } sysblk.ecpsvm.available=ecpsvmavail; sysblk.ecpsvm.level=ecpsvmlevel; } #endif /*defined(_FEATURE_ECPSVM)*/ #if defined(OPTION_SHARED_DEVICES) /* Parse shared device port number operand */ if (sshrdport != NULL) { if (sscanf(sshrdport, "%hu%c", &shrdport, &c) != 1 || shrdport < 1024 ) { logmsg(_("HHCCF029S Error in %s line %d: " "Invalid SHRDPORT port number %s\n"), fname, inc_stmtnum[inc_level], sshrdport); delayed_exit(1); } } #endif /*defined(OPTION_SHARED_DEVICES)*/ } /* end for(scount) (end of configuration file statement loop) */ /* Read the logofile */ if (sysblk.logofile == NULL) /* LogoFile NOT passed in command line */ { if (hlogofile[0] != '\0') /* LogoFile SET in hercules config */ { readlogo(hlogofile); } else /* Try to Read Logo File using Default FileName */ { slogofile=getenv("HERCLOGO"); if (slogofile==NULL) { readlogo("herclogo.txt"); } else { readlogo(slogofile); } } /* Otherwise Use Internal LOGO */ } else /* LogoFile passed in command line */ { readlogo(sysblk.logofile); } #if defined( OPTION_TAPE_AUTOMOUNT ) /* Define default AUTOMOUNT directory if needed */ if (sysblk.tamdir && sysblk.defdir == NULL) { char cwd[ MAX_PATH ]; TAMDIR *pNewTAMDIR = malloc( sizeof(TAMDIR) ); if (!pNewTAMDIR) { logmsg( _("HHCCF900S Out of memory!\n")); delayed_exit(1); } VERIFY( getcwd( cwd, sizeof(cwd) ) != NULL ); rc = strlen( cwd ); if (cwd[rc-1] != *PATH_SEP) strlcat (cwd, PATH_SEP, sizeof(cwd)); pNewTAMDIR->dir = strdup (cwd); pNewTAMDIR->len = strlen (cwd); pNewTAMDIR->rej = 0; pNewTAMDIR->next = sysblk.tamdir; sysblk.tamdir = pNewTAMDIR; sysblk.defdir = pNewTAMDIR->dir; logmsg(_("HHCCF090I Default Allowed AUTOMOUNT directory = \"%s\"\n"), sysblk.defdir); } #endif /* OPTION_TAPE_AUTOMOUNT */ /* Set root mode in order to set priority */ SETMODE(ROOT); /* Set Hercules base priority */ if (setpriority(PRIO_PGRP, 0, hercprio)) logmsg (_("HHCCF064W Hercules set priority %d failed: %s\n"), hercprio, strerror(errno)); /* Back to user mode */ SETMODE(USER); /* Display Hercules thread information on control panel */ logmsg (_("HHCCF065I Hercules: tid="TIDPAT", pid=%d, pgid=%d, " "priority=%d\n"), thread_id(), getpid(), getpgrp(), getpriority(PRIO_PGRP,0)); #if defined(OPTION_SHARED_DEVICES) sysblk.shrdport = shrdport; #endif /*defined(OPTION_SHARED_DEVICES)*/ #if defined(_370) || defined(_390) if(dfltver) version = #if defined(_900) (sysblk.arch_mode == ARCH_900) ? 0x00 : #endif 0xFD; #endif /* Build CPU identifier */ sysblk.cpuid = ((U64)version << 56) | ((U64)serial << 32) | ((U64)model << 16); /* Reset the clock steering registers */ csr_reset(); /* Set up the system TOD clock offset: compute the number of * microseconds offset to 0000 GMT, 1 January 1900 */ if(sysepoch != 1900 && sysepoch != 1960) { if(sysepoch < 1960) logmsg(_("HHCCF072W SYSEPOCH %04d is deprecated. " "Please specify \"SYSEPOCH 1900 %s%d\".\n"), sysepoch, 1900-sysepoch > 0 ? "+" : "", 1900-sysepoch); else logmsg(_("HHCCF073W SYSEPOCH %04d is deprecated. " "Please specify \"SYSEPOCH 1960 %s%d\".\n"), sysepoch, 1960-sysepoch > 0 ? "+" : "", 1960-sysepoch); } if(sysepoch == 1960 || sysepoch == 1988) ly1960 = TOD_DAY; else ly1960 = 0; sysepoch -= 1900 + yroffset; set_tod_epoch(((sysepoch*365+(sysepoch/4))*-TOD_DAY)+lyear_adjust(sysepoch)+ly1960); sysblk.sysepoch = sysepoch; /* Set the timezone offset */ adjust_tod_epoch((tzoffset/100*3600+(tzoffset%100)*60)*16000000LL); /* Gabor Hoffer (performance option) */ copy_opcode_tables(); /*****************************************************************/ /* Parse configuration file device statements... */ /*****************************************************************/ while(1) { /* First two fields are device number and device type */ sdevnum = keyword; sdevtype = operand; if (sdevnum == NULL || sdevtype == NULL) { logmsg(_("HHCCF035S Error in %s line %d: " "Missing device number or device type\n"), fname, inc_stmtnum[inc_level]); delayed_exit(1); } /* Parse devnum */ rc=parse_and_attach_devices(sdevnum,sdevtype,addargc,addargv); if(rc==-2) { logmsg(_("HHCCF036S Error in %s line %d: " "%s is not a valid device number(s) specification\n"), fname, inc_stmtnum[inc_level], sdevnum); delayed_exit(1); } /* Read next device record from the configuration file */ #if defined( OPTION_ENHANCED_CONFIG_INCLUDE ) while (1) { while (inc_level >= 0 && read_config (fname, inc_fp[inc_level]) ) { fclose (inc_fp[inc_level--]); } if (inc_level < 0 || strcasecmp (keyword, "include") != 0) break; if (++inc_level >= MAX_INC_LEVEL) { logmsg(_( "HHCCF082S Error in %s line %d: " "Maximum nesting level (%d) reached\n"), fname, inc_stmtnum[inc_level-1], MAX_INC_LEVEL); delayed_exit(1); } logmsg( _("HHCCF083I %s Including %s at %d .\n"), fname, operand, inc_stmtnum[inc_level-1]); hostpath(pathname, operand, sizeof(pathname)); inc_fp[inc_level] = fopen (pathname, "r"); if (inc_fp[inc_level] == NULL) { inc_level--; if ( inc_ignore_errors == 1 ) { logmsg(_("HHCCF084W %s Open error ignored file %s: %s\n"), fname, operand, strerror(errno)); continue ; } else { logmsg(_("HHCCF085E %s Open error file %s: %s\n"), fname, operand, strerror(errno)); delayed_exit(1); } } inc_stmtnum[inc_level] = 0; continue; } if (inc_level < 0) #else // !defined( OPTION_ENHANCED_CONFIG_INCLUDE ) if (read_config (fname, inc_fp[inc_level])) #endif // defined( OPTION_ENHANCED_CONFIG_INCLUDE ) break; } /* end while(1) */ #if !defined( OPTION_ENHANCED_CONFIG_INCLUDE ) /* close configuration file */ rc = fclose(inc_fp[inc_level]); #endif // !defined( OPTION_ENHANCED_CONFIG_INCLUDE ) /* Now configure storage. We do this after processing the device * statements so the fork()ed hercifc process won't require as much * virtual storage. We will need to update all the devices too. */ config_storage(mainsize, xpndsize); for (dev = sysblk.firstdev; dev; dev = dev->nextdev) { dev->mainstor = sysblk.mainstor; dev->storkeys = sysblk.storkeys; dev->mainlim = sysblk.mainsize - 1; } #if defined(_FEATURE_REGION_RELOCATE) /* Initialize base zone storage view (SIE compat) */ for(i = 0; i < FEATURE_SIE_MAXZONES; i++) { sysblk.zpb[i].mso = 0; sysblk.zpb[i].msl = (sysblk.mainsize - 1) >> 20; if(sysblk.xpndsize) { sysblk.zpb[i].eso = 0; sysblk.zpb[i].esl = ((size_t)sysblk.xpndsize * XSTORE_PAGESIZE - 1) >> 20; } else { sysblk.zpb[i].eso = -1; sysblk.zpb[i].esl = -1; } } #endif /* Initialize dummy regs. * Dummy regs are used by the panel or gui when the target cpu * (sysblk.pcpu) is not configured (ie cpu_thread not started). */ sysblk.dummyregs.mainstor = sysblk.mainstor; sysblk.dummyregs.psa = (PSA*)sysblk.mainstor; sysblk.dummyregs.storkeys = sysblk.storkeys; sysblk.dummyregs.mainlim = sysblk.mainsize - 1; sysblk.dummyregs.dummy = 1; initial_cpu_reset (&sysblk.dummyregs); sysblk.dummyregs.arch_mode = sysblk.arch_mode; sysblk.dummyregs.hostregs = &sysblk.dummyregs; #ifdef OPTION_SELECT_KLUDGE /* Release the dummy file descriptors */ for (i = 0; i < OPTION_SELECT_KLUDGE; i++) close(dummyfd[i]); #endif /* Set default maximum number of CPUs */ #ifdef _FEATURE_CPU_RECONFIG sysblk.maxcpu = sysblk.arch_mode == ARCH_370 ? numcpu : MAX_CPU_ENGINES; #else sysblk.maxcpu = numcpu; #endif /*_FEATURE_CPU_RECONFIG*/ /* Set maximum number of CPUs to specified value */ if (maxcpu > 0) { sysblk.maxcpu = maxcpu; } /* Check that numcpu does not exceed maxcpu */ if (sysblk.numcpu > sysblk.maxcpu) { logmsg(_("HHCCF086S Error in %s: NUMCPU %d must not exceed MAXCPU %d\n"), fname, sysblk.numcpu, sysblk.maxcpu); delayed_exit(1); } /* Start the CPUs */ OBTAIN_INTLOCK(NULL); for(i = 0; i < numcpu; i++) configure_cpu(i); RELEASE_INTLOCK(NULL); } /* end function build_config */ #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/panel.c0000664000175000017500000031665312564723224011464 00000000000000/* PANEL.C (c) Copyright Roger Bowler, 1999-2010 */ /* Hercules Control Panel Commands */ /* Modified for New Panel Display =NP= */ /*-------------------------------------------------------------------*/ /* This module is the control panel for the ESA/390 emulator. */ /* It provides a command interface into hercules, and it displays */ /* messages that are issued by various hercules components. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* breakpoint command contributed by Dan Horak */ /* devinit command contributed by Jay Maynard */ /* New Panel Display contributed by Dutch Owen */ /* HMC system console commands contributed by Jan Jaeger */ /* Set/reset bad frame indicator command by Jan Jaeger */ /* attach/detach/define commands by Jan Jaeger */ /* Panel refresh rate triva by Reed H. Petty */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2007 */ /* 64-bit address support by Roger Bowler */ /* Display subchannel command by Nobumichi Kozawa */ /* External GUI logic contributed by "Fish" (David B. Trout) */ /* Socket Devices originally designed by Malcolm Beattie; */ /* actual implementation by "Fish" (David B. Trout). */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _PANEL_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "history.h" // #include "inline.h" #include "fillfnam.h" #include "hconsole.h" #define DISPLAY_INSTRUCTION_OPERANDS #define PANEL_MAX_ROWS (256) #define PANEL_MAX_COLS (256) int redraw_msgs; /* 1=Redraw message area */ int redraw_cmd; /* 1=Redraw command line */ int redraw_status; /* 1=Redraw status line */ /*=NP================================================================*/ /* Global data for new panel display */ /* (Note: all NPD mods are identified by the string =NP= */ /*===================================================================*/ static int NPDup = 0; /* 1 = new panel is up */ static int NPDinit = 0; /* 1 = new panel initialized */ static int NPhelpup = 0; /* 1 = help panel showing */ static int NPhelppaint = 1; /* 1 = help pnl s/b painted */ static int NPhelpdown = 0; /* 1 = help pnl coming down */ static int NPregdisp = 0; /* which regs are displayed: */ /* 0=gpr, 1=cr, 2=ar, 3=fpr */ static int NPcmd = 0; /* 1 = NP in command mode */ static int NPdataentry = 0; /* 1 = NP in data-entry mode */ static int NPdevsel = 0; /* 1 = device being selected */ static char NPpending; /* pending data entry cmd */ static char NPentered[256]; /* Data which was entered */ static char NPprompt1[40]; /* Left bottom screen prompt */ static char NPoldprompt1[40]; /* Left bottom screen prompt */ static char NPprompt2[40]; /* Right bottom screen prompt*/ static char NPoldprompt2[40]; /* Right bottom screen prompt*/ static char NPsel2; /* dev sel part 2 cmd letter */ static char NPdevice; /* Which device is selected */ static int NPasgn; /* Index to dev being init'ed*/ static int NPlastdev; /* Number of devices */ static int NPcpugraph_ncpu; /* Number of CPUs to display */ static char *NPregnum[] = {" 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7", " 8"," 9","10","11","12","13","14","15" }; static char *NPregnum64[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" }; /* Boolean fields; redraw the corresponding data field if false */ static int NPcpunum_valid, NPcpupct_valid, NPpsw_valid, NPpswstate_valid, NPregs_valid, NPaddr_valid, NPdata_valid, #ifdef OPTION_MIPS_COUNTING NPmips_valid, NPsios_valid, #endif // OPTION_MIPS_COUNTING NPdevices_valid, NPcpugraph_valid; /* Current CPU states */ static U16 NPcpunum; static int NPcpupct; static int NPpswmode; static int NPpswzhost; static QWORD NPpsw; static char NPpswstate[16]; static int NPregmode; static int NPregzhost; static U64 NPregs64[16]; static U32 NPregs[16]; static U32 NPaddress; static U32 NPdata; #ifdef OPTION_MIPS_COUNTING static U32 NPmips; static U32 NPsios; #else static U64 NPinstcount; #endif // OPTION_MIPS_COUNTING static int NPcpugraph; static int NPcpugraphpct[MAX_CPU_ENGINES]; /* Current device states */ #define NP_MAX_DEVICES (PANEL_MAX_ROWS - 3) static int NPonline[NP_MAX_DEVICES]; static U16 NPdevnum[NP_MAX_DEVICES]; static int NPbusy[NP_MAX_DEVICES]; static U16 NPdevtype[NP_MAX_DEVICES]; static int NPopen[NP_MAX_DEVICES]; static char NPdevnam[NP_MAX_DEVICES][128]; static short NPcurrow, NPcurcol; static int NPcolorSwitch; static short NPcolorFore; static short NPcolorBack; static int NPdatalen; static char *NPhelp[] = { "All commands consist of one character keypresses. The various commands are", "highlighted onscreen by bright white versus the gray of other lettering.", " ", "Press the escape key to terminate the control panel and go to command mode.", " ", "Display Controls: G - General purpose regs C - Control regs", " A - Access registers F - Floating Point regs", " I - Display main memory at 'ADDRESS'", "CPU controls: L - IPL S - Start CPU", " E - External interrupt P - Stop CPU", " W - Exit Hercules T - Restart interrupt", "Storage update: R - Enter ADDRESS to be updated", " D - Enter DATA to be updated at ADDRESS", " O - place DATA value at ADDRESS", " ", "Peripherals: N - enter a new name for the device file assignment", " U - send an I/O attention interrupt", " ", "In the display of devices, a green device letter means the device is online,", "a lighted device address means the device is busy, and a green model number", "means the attached file is open to the device", " ", " Press Escape to return to control panel operations", "" }; /////////////////////////////////////////////////////////////////////// #define MSG_SIZE PANEL_MAX_COLS /* Size of one message */ #define MAX_MSGS 2048 /* Number of slots in buffer */ //#define MAX_MSGS 300 /* (for testing scrolling) */ #define MSG_LINES (cons_rows - 2) /* #lines in message area */ #define SCROLL_LINES (MSG_LINES - numkept) /* #of scrollable lines */ #define CMD_SIZE 256 /* cmdline buffer size */ /////////////////////////////////////////////////////////////////////// static int cons_rows = 0; /* console height in lines */ static int cons_cols = 0; /* console width in chars */ static short cur_cons_row = 0; /* current console row */ static short cur_cons_col = 0; /* current console column */ static char *cons_term = NULL; /* TERM env value */ static char cmdins = 1; /* 1==insert mode, 0==overlay*/ static char cmdline[CMD_SIZE+1]; /* Command line buffer */ static int cmdlen = 0; /* cmdline data len in bytes */ static int cmdoff = 0; /* cmdline buffer cursor pos */ static int cursor_on_cmdline = 1; /* bool: cursor on cmdline */ static char saved_cmdline[CMD_SIZE+1]; /* Saved command */ static int saved_cmdlen = 0; /* Saved cmdline data len */ static int saved_cmdoff = 0; /* Saved cmdline buffer pos */ static short saved_cons_row = 0; /* Saved console row */ static short saved_cons_col = 0; /* Saved console column */ static int cmdcols = 0; /* visible cmdline width cols*/ static int cmdcol = 0; /* cols cmdline scrolled righ*/ static FILE *confp = NULL; /* Console file pointer */ /////////////////////////////////////////////////////////////////////// #define CMD_PREFIX_STR "Command ==> " /* Keep same len as below! */ #ifdef OPTION_CMDTGT #define CMD_PREFIX_STR1 "SCP ======> " /* Keep same len as above! */ #define CMD_PREFIX_STR2 "PrioSCP ==> " /* Keep same len as above! */ #endif // OPTION_CMDTGT #define CMD_PREFIX_LEN (strlen(CMD_PREFIX_STR)) #define CMDLINE_ROW ((short)(cons_rows-1)) #define CMDLINE_COL ((short)(CMD_PREFIX_LEN+1)) /////////////////////////////////////////////////////////////////////// #define ADJ_SCREEN_SIZE() \ do { \ int rows, cols; \ get_dim (&rows, &cols); \ if (rows != cons_rows || cols != cons_cols) { \ cons_rows = rows; \ cons_cols = cols; \ cmdcols = cons_cols - CMDLINE_COL; \ redraw_msgs = redraw_cmd = redraw_status = 1; \ NPDinit = 0; \ clr_screen(); \ } \ } while (0) #define ADJ_CMDCOL() /* (called after modifying cmdoff) */ \ do { \ if (cmdoff-cmdcol > cmdcols) { /* past right edge of screen */ \ cmdcol = cmdoff-cmdcols; \ } else if (cmdoff < cmdcol) { /* past left edge of screen */ \ cmdcol = cmdoff; \ } \ } while (0) #define PUTC_CMDLINE() \ do { \ ASSERT(cmdcol <= cmdlen); \ for (i=0; cmdcol+i < cmdlen && i < cmdcols; i++) \ draw_char (cmdline[cmdcol+i]); \ } while (0) /////////////////////////////////////////////////////////////////////// typedef struct _PANMSG /* Panel message control block structure */ { struct _PANMSG* next; /* --> next entry in chain */ struct _PANMSG* prev; /* --> prev entry in chain */ int msgnum; /* msgbuf 0-relative entry# */ char msg[MSG_SIZE]; /* text of panel message */ #if defined(OPTION_MSGCLR) short fg; /* text color */ short bg; /* screen background color */ #if defined(OPTION_MSGHLD) int keep:1; /* sticky flag */ struct timeval expiration; /* when to unstick if sticky */ #endif // defined(OPTION_MSGHLD) #endif // defined(OPTION_MSGCLR) } PANMSG; /* Panel message control block structure */ static PANMSG* msgbuf; /* Circular message buffer */ static PANMSG* topmsg; /* message at top of screen */ static PANMSG* curmsg; /* newest message */ static int wrapped = 0; /* wrapped-around flag */ static int numkept = 0; /* count of kept messages */ static int npquiet = 0; /* screen updating flag */ /////////////////////////////////////////////////////////////////////// static char *lmsbuf = NULL; /* xxx */ static int lmsndx = 0; /* xxx */ static int lmsnum = -1; /* xxx */ static int lmscnt = -1; /* xxx */ static int lmsmax = LOG_DEFSIZE/2; /* xxx */ static int keybfd = -1; /* Keyboard file descriptor */ static REGS copyregs, copysieregs; /* Copied regs */ /////////////////////////////////////////////////////////////////////// #if defined(OPTION_MSGCLR) /* -- Message coloring build option -- */ #if defined(OPTION_MSGHLD) /* -- Sticky messages build option -- */ #define KEEP_TIMEOUT_SECS 120 /* #seconds kept msgs expire */ static PANMSG* keptmsgs; /* start of keep chain */ static PANMSG* lastkept; /* last entry in keep chain */ /*-------------------------------------------------------------------*/ /* Remove and Free a keep chain entry from the keep chain */ /*-------------------------------------------------------------------*/ static void unkeep( PANMSG* pk ) { if (pk->prev) pk->prev->next = pk->next; if (pk->next) pk->next->prev = pk->prev; if (pk == keptmsgs) keptmsgs = pk->next; if (pk == lastkept) lastkept = pk->prev; free( pk ); numkept--; } /*-------------------------------------------------------------------*/ /* Allocate and Add a new kept message to the keep chain */ /*-------------------------------------------------------------------*/ static void keep( PANMSG* p ) { PANMSG* pk; ASSERT( p->keep ); pk = malloc( sizeof(PANMSG) ); memcpy( pk, p, sizeof(PANMSG) ); if (!keptmsgs) keptmsgs = pk; pk->next = NULL; pk->prev = lastkept; if (lastkept) lastkept->next = pk; lastkept = pk; numkept++; /* Must ensure we always have at least 2 scrollable lines */ while (SCROLL_LINES < 2) { /* Permanently unkeep oldest kept message */ msgbuf[keptmsgs->msgnum].keep = 0; unkeep( keptmsgs ); } } /*-------------------------------------------------------------------*/ /* Remove a kept message from the kept chain */ /*-------------------------------------------------------------------*/ static void unkeep_by_keepnum( int keepnum, int perm ) { PANMSG* pk; int i; /* Validate call */ if (!numkept || keepnum < 0 || keepnum > numkept-1) { ASSERT(FALSE); // bad 'keepnum' passed! return; } /* Chase keep chain to find kept message to be unkept */ for (i=0, pk=keptmsgs; pk && i != keepnum; pk = pk->next, i++); /* If kept message found, unkeep it */ if (pk) { if (perm) { msgbuf[pk->msgnum].keep = 0; #if defined(_DEBUG) || defined(DEBUG) msgbuf[pk->msgnum].fg = COLOR_YELLOW; #endif // defined(_DEBUG) || defined(DEBUG) } unkeep(pk); } } #endif // defined(OPTION_MSGHLD) #endif // defined(OPTION_MSGCLR) #if defined(OPTION_MSGHLD) /*-------------------------------------------------------------------*/ /* unkeep messages once expired */ /*-------------------------------------------------------------------*/ void expire_kept_msgs(int unconditional) { struct timeval now; PANMSG *pk = keptmsgs; int i; gettimeofday(&now, NULL); while (pk) { for (i=0, pk=keptmsgs; pk; i++, pk = pk->next) { if (unconditional || now.tv_sec >= pk->expiration.tv_sec) { unkeep_by_keepnum(i,1); // remove message from chain break; // start over again from the beginning } } } } #endif // defined(OPTION_MSGHLD) #if defined(OPTION_MSGCLR) /* -- Message coloring build option -- */ /*-------------------------------------------------------------------*/ /* Get the color name from a string */ /*-------------------------------------------------------------------*/ #define CHECKCOLOR(s, cs, c, cc) if(!strncasecmp(s, cs, sizeof(cs) - 1)) { *c = cc; return(sizeof(cs) - 1); } int get_color(char *string, short *color) { CHECKCOLOR(string, "black", color, COLOR_BLACK) else CHECKCOLOR(string, "cyan", color, COLOR_CYAN) else CHECKCOLOR(string, "blue", color, COLOR_BLUE) else CHECKCOLOR(string, "darkgrey", color, COLOR_DARK_GREY) else CHECKCOLOR(string, "green", color, COLOR_GREEN) else CHECKCOLOR(string, "lightblue", color, COLOR_LIGHT_BLUE) else CHECKCOLOR(string, "lightcyan", color, COLOR_LIGHT_CYAN) else CHECKCOLOR(string, "lightgreen", color, COLOR_LIGHT_GREEN) else CHECKCOLOR(string, "lightgrey", color, COLOR_LIGHT_GREY) else CHECKCOLOR(string, "lightmagenta", color, COLOR_LIGHT_MAGENTA) else CHECKCOLOR(string, "lightred", color, COLOR_LIGHT_RED) else CHECKCOLOR(string, "lightyellow", color, COLOR_LIGHT_YELLOW) else CHECKCOLOR(string, "magenta", color, COLOR_MAGENTA) else CHECKCOLOR(string, "red", color, COLOR_RED) else CHECKCOLOR(string, "white", color, COLOR_WHITE) else CHECKCOLOR(string, "yellow", color, COLOR_YELLOW) else return(0); } /*-------------------------------------------------------------------*/ /* Read, process and remove the "" colorizing message prefix */ /* Syntax: */ /* */ /* Mandatory prefix "" */ /* Valid tokens: */ /* color(fg, bg) specifies the message's color */ /* keep keeps message on screen until removed */ /*-------------------------------------------------------------------*/ void colormsg(PANMSG *p) { int i = 0; // current message text index int len; // length of color-name token if(!strncasecmp(p->msg, "" panel command(s) i += 4; while(p->msg[i] == ',') { i += 1; // skip , if(!strncasecmp(&p->msg[i], "color(", 6)) { // inspect color command i += 6; // skip color( len = get_color(&p->msg[i], &p->fg); if(!len) break; // no valid color found i += len; // skip colorname if(p->msg[i] != ',') break; // no , i++; // skip , len = get_color(&p->msg[i], &p->bg); if(!len) break; // no valid color found i += len; // skip colorname if(p->msg[i] != ')') break; // no ) i++; // skip ) } else if(!strncasecmp(&p->msg[i], "keep", 4)) { #if defined(OPTION_MSGHLD) p->keep = 1; gettimeofday(&p->expiration, NULL); p->expiration.tv_sec += sysblk.keep_timeout_secs; #endif // defined(OPTION_MSGHLD) i += 4; // skip keep } else break; // rubbish } if(p->msg[i] == '>') { // Remove "" string from message i += 1; memmove(p->msg, &p->msg[i], MSG_SIZE - i); memset(&p->msg[MSG_SIZE - i], SPACE, i); return; } } /* rubbish or no panel command */ p->fg = COLOR_DEFAULT_FG; p->bg = COLOR_DEFAULT_BG; #if defined(OPTION_MSGHLD) p->keep = 0; #endif // defined(OPTION_MSGHLD) } #endif // defined(OPTION_MSGCLR) /*-------------------------------------------------------------------*/ /* Screen manipulation primitives */ /*-------------------------------------------------------------------*/ static void beep() { console_beep( confp ); } static PANMSG* oldest_msg() { return (wrapped) ? curmsg->next : msgbuf; } static PANMSG* newest_msg() { return curmsg; } static int lines_scrolled() { /* return # of lines 'up' from current line that we're scrolled. */ if (topmsg->msgnum <= curmsg->msgnum) return curmsg->msgnum - topmsg->msgnum; return MAX_MSGS - (topmsg->msgnum - curmsg->msgnum); } static int visible_lines() { return (lines_scrolled() + 1); } static int is_currline_visible() { return (visible_lines() <= SCROLL_LINES); } static int lines_remaining() { return (SCROLL_LINES - visible_lines()); } static void scroll_up_lines( int numlines, int doexpire ) { int i; #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) for (i=0; i < numlines && topmsg != oldest_msg(); i++) { topmsg = topmsg->prev; #if defined(OPTION_MSGHLD) // If new topmsg is simply the last entry in the keep chain // then we didn't really backup a line (all we did was move // our topmsg ptr), so if that's the case then we need to // continue backing up until we reach a non-kept message. // Only then is the screen actually scrolled up one line. while (1 && topmsg->keep && lastkept && lastkept->msgnum == topmsg->msgnum ) { unkeep( lastkept ); if (topmsg == oldest_msg()) break; topmsg = topmsg->prev; } #endif // defined(OPTION_MSGHLD) } } static void scroll_down_lines( int numlines, int doexpire ) { int i; #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) for (i=0; i < numlines && topmsg != newest_msg(); i++) { #if defined(OPTION_MSGHLD) // If the topmsg should be kept and is not already in our // keep chain, then adding it to our keep chain before // setting topmsg to the next entry does not really scroll // the screen any (all it does is move the topmsg ptr), // so if that's the case then we need to keep doing that // until we eventually find the next non-kept message. // Only then is the screen really scrolled down one line. while (1 && topmsg->keep && (!lastkept || topmsg->msgnum != lastkept->msgnum) ) { keep( topmsg ); topmsg = topmsg->next; if (topmsg == newest_msg()) break; } #endif // defined(OPTION_MSGHLD) if (topmsg != newest_msg()) topmsg = topmsg->next; } } static void page_up( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) scroll_up_lines( SCROLL_LINES - 1, 0 ); } static void page_down( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) scroll_down_lines( SCROLL_LINES - 1, 0 ); } static void scroll_to_top_line( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) topmsg = oldest_msg(); #if defined(OPTION_MSGHLD) while (keptmsgs) unkeep( keptmsgs ); #endif // defined(OPTION_MSGHLD) } static void scroll_to_bottom_line( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) while (topmsg != newest_msg()) scroll_down_lines( 1, 0 ); } static void scroll_to_bottom_screen( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) scroll_to_bottom_line( 0 ); page_up( 0 ); } static void do_panel_command( void* cmd ) { if (!is_currline_visible()) scroll_to_bottom_screen( 1 ); if (cmd != (void*)cmdline) strlcpy( cmdline, cmd, sizeof(cmdline) ); panel_command( cmdline ); cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); } static void do_prev_history() { if (history_prev() != -1) { strcpy(cmdline, historyCmdLine); cmdlen = strlen(cmdline); cmdoff = cmdlen < cmdcols ? cmdlen : 0; ADJ_CMDCOL(); } } static void do_next_history() { if (history_next() != -1) { strcpy(cmdline, historyCmdLine); cmdlen = strlen(cmdline); cmdoff = cmdlen < cmdcols ? cmdlen : 0; ADJ_CMDCOL(); } } static void clr_screen () { clear_screen (confp); } static void get_dim (int *y, int *x) { get_console_dim( confp, y, x); if (*y > PANEL_MAX_ROWS) *y = PANEL_MAX_ROWS; if (*x > PANEL_MAX_COLS) *x = PANEL_MAX_COLS; #if defined(WIN32) && !defined( _MSVC_ ) /* If running from a cygwin command prompt we do * better with one less row. */ if (!cons_term || strcmp(cons_term, "xterm")) (*y)--; #endif // defined(WIN32) && !defined( _MSVC_ ) } #if defined(OPTION_EXTCURS) static int get_keepnum_by_row( int row ) { // PROGRAMMING NOTE: right now all of our kept messages are // always placed at the very top of the screen (starting on // line 1), but should we at some point in the future decide // to use the very top line of the screen for something else // (such as a title or status line for example), then all we // need to do is modify the below variable and the code then // adjusts itself automatically. (I try to avoid hard-coded // constants whenever possible). -- Fish static int keep_beg_row = 1; // screen 1-relative line# of first kept msg if (0 || row < keep_beg_row || row > (keep_beg_row + numkept - 1) ) return -1; return (row - keep_beg_row); } #endif /*defined(OPTION_EXTCURS)*/ static void set_color (short fg, short bg) { set_screen_color (confp, fg, bg); } static void set_pos (short y, short x) { cur_cons_row = y; cur_cons_col = x; y = y < 1 ? 1 : y > cons_rows ? cons_rows : y; x = x < 1 ? 1 : x > cons_cols ? cons_cols : x; set_screen_pos (confp, y, x); } static int is_cursor_on_cmdline() { #if defined(OPTION_EXTCURS) get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); cursor_on_cmdline = (1 && cur_cons_row == CMDLINE_ROW && cur_cons_col >= CMDLINE_COL && cur_cons_col <= CMDLINE_COL + cmdcols ); #else // !defined(OPTION_EXTCURS) cursor_on_cmdline = 1; #endif // defined(OPTION_EXTCURS) return cursor_on_cmdline; } static void cursor_cmdline_home() { cmdoff = 0; ADJ_CMDCOL(); set_pos( CMDLINE_ROW, CMDLINE_COL ); } static void cursor_cmdline_end() { cmdoff = cmdlen; ADJ_CMDCOL(); set_pos( CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol ); } static void save_command_line() { memcpy( saved_cmdline, cmdline, sizeof(saved_cmdline) ); saved_cmdlen = cmdlen; saved_cmdoff = cmdoff; saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; } static void restore_command_line() { memcpy( cmdline, saved_cmdline, sizeof(cmdline) ); cmdlen = saved_cmdlen; cmdoff = saved_cmdoff; cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } static void draw_text (char *text) { int len; char *short_text; if (cur_cons_row < 1 || cur_cons_row > cons_rows || cur_cons_col < 1 || cur_cons_col > cons_cols) return; len = strlen(text); if ((cur_cons_col + len - 1) <= cons_cols) fprintf (confp, "%s", text); else { len = cons_cols - cur_cons_col + 1; if ((short_text = strdup(text)) == NULL) return; short_text[len] = '\0'; fprintf (confp, "%s", short_text); free (short_text); } cur_cons_col += len; } static void write_text (char *text, int size) { if (cur_cons_row < 1 || cur_cons_row > cons_rows || cur_cons_col < 1 || cur_cons_col > cons_cols) return; if (cons_cols - cur_cons_col + 1 < size) size = cons_cols - cur_cons_col + 1; fwrite (text, size, 1, confp); cur_cons_col += size; } static void draw_char (int c) { if (cur_cons_row < 1 || cur_cons_row > cons_rows || cur_cons_col < 1 || cur_cons_col > cons_cols) return; fputc (c, confp); cur_cons_col++; } static void draw_fw (U32 fw) { char buf[9]; sprintf (buf, "%8.8X", fw); draw_text (buf); } static void draw_dw (U64 dw) { char buf[17]; sprintf (buf, "%16.16"I64_FMT"X", dw); draw_text (buf); } static void fill_text (char c, short x) { char buf[PANEL_MAX_COLS+1]; int len; if (x > PANEL_MAX_COLS) x = PANEL_MAX_COLS; len = x + 1 - cur_cons_col; if (len <= 0) return; memset (buf, c, len); buf[len] = '\0'; draw_text (buf); } static void draw_button (short bg, short fg, short hfg, char *left, char *mid, char *right) { set_color (fg, bg); draw_text (left); set_color (hfg, bg); draw_text (mid); set_color (fg, bg); draw_text (right); } static void set_console_title () { if (!sysblk.pantitle) return; #if defined( _MSVC_ ) w32_set_console_title(sysblk.pantitle); #else /*!defined(_MSVC_) */ /* For Unix systems we set the window title by sending a special escape sequence (depends on terminal type) to the console. See http://www.faqs.org/docs/Linux-mini/Xterm-Title.html */ if (!cons_term) return; if (strcmp(cons_term,"xterm")==0 || strcmp(cons_term,"rxvt")==0 || strcmp(cons_term,"dtterm")==0 || strcmp(cons_term,"screen")==0) { fprintf(confp,"%c]0;%s%c",'\033',sysblk.pantitle,'\007'); } #endif /*!defined(_MSVC_) */ } /*=NP================================================================*/ /* Initialize the NP data */ /*===================================================================*/ static void NP_init() { NPdataentry = 0; strcpy(NPprompt1, ""); strcpy(NPprompt2, ""); } /*=NP================================================================*/ /* This draws the initial screen template */ /*===================================================================*/ static void NP_screen_redraw (REGS *regs) { int i, line; char buf[1024]; /* Force all data to be redrawn */ NPcpunum_valid = NPcpupct_valid = NPpsw_valid = NPpswstate_valid = NPregs_valid = NPaddr_valid = NPdata_valid = NPdevices_valid = NPcpugraph_valid = 0; #if defined(OPTION_MIPS_COUNTING) NPmips_valid = NPsios_valid = 0; #endif /*defined(OPTION_MIPS_COUNTING)*/ #if defined(_FEATURE_SIE) if(regs->sie_active) regs = regs->guestregs; #endif /*defined(_FEATURE_SIE)*/ /* * Draw the static parts of the NP screen */ set_color (COLOR_LIGHT_GREY, COLOR_BLACK ); clr_screen (); /* Line 1 - title line */ set_color (COLOR_WHITE, COLOR_BLUE ); set_pos (1, 1); draw_text (" Hercules CPU : %"); fill_text (' ', 30); draw_text ((char *)get_arch_mode_string(NULL)); fill_text (' ', 38); set_color (COLOR_LIGHT_GREY, COLOR_BLUE ); draw_text ("| "); set_color (COLOR_WHITE, COLOR_BLUE ); /* Center "Peripherals" on the right-hand-side */ if (cons_cols > 52) fill_text (' ', 40 + (cons_cols - 52) / 2); draw_text ("Peripherals"); fill_text (' ', (short)cons_cols); /* Line 2 - peripheral headings */ set_pos (2, 41); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('U'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text(" Addr Modl Type Assig"); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('n'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text("ment"); /* 4th line - PSW */ NPpswmode = (regs->arch_mode == ARCH_900); NPpswzhost = #if defined(_FEATURE_SIE) !NPpswmode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900; #else 0; #endif /*defined(_FEATURE_SIE)*/ set_pos (4, NPpswmode || NPpswzhost ? 19 : 10); draw_text ("PSW"); /* Lines 6 .. 13 : register area */ set_color (COLOR_LIGHT_GREY, COLOR_BLACK); NPregmode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); NPregzhost = #if defined(_FEATURE_SIE) (regs->arch_mode != ARCH_900 && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); #else 0; #endif /*defined(_FEATURE_SIE)*/ if (NPregmode == 1 || NPregzhost) { for (i = 0; i < 8; i++) { set_pos (i+6, 1); draw_text (NPregnum64[i*2]); set_pos (i+6, 20); draw_text (NPregnum64[i*2+1]); } } else { for (i = 0; i < 4; i++) { set_pos (i*2+7,9); draw_text (NPregnum[i*4]); set_pos (i*2+7,18); draw_text (NPregnum[i*4+1]); set_pos (i*2+7,27); draw_text (NPregnum[i*4+2]); set_pos (i*2+7,36); draw_text (NPregnum[i*4+3]); } } /* Line 14 : register selection */ set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (14, 6); draw_text ("GPR"); set_pos (14, 14); draw_text ("CR"); set_pos (14, 22); draw_text ("AR"); set_pos (14, 30); draw_text ("FPR"); /* Line 16 .. 17 : Address and data */ set_pos (16, 2); draw_text ("ADD"); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('R'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text ("ESS:"); set_pos (16, 22); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('D'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text ("ATA:"); /* Line 18 : separator */ set_pos (18, 1); fill_text ('-', 38); /* Lines 19 .. 23 : buttons */ set_pos (19, 16); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " ST", "O", " " ); set_pos (19, 24); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " D", "I", "S " ); set_pos (19, 32); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " RS", "T", " " ); #if defined(OPTION_MIPS_COUNTING) set_pos (20, 3); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text ("MIPS"); set_pos (20, 9); draw_text ("SIO/s"); #endif /*defined(OPTION_MIPS_COUNTING)*/ set_pos (22, 2); draw_button(COLOR_GREEN, COLOR_LIGHT_GREY, COLOR_WHITE, " ", "S", "TR "); set_pos (22, 9); draw_button(COLOR_RED, COLOR_LIGHT_GREY, COLOR_WHITE, " ST", "P", " " ); set_pos (22, 16); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " ", "E", "XT "); set_pos (22, 24); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " IP", "L", " " ); set_pos (22, 32); draw_button(COLOR_RED, COLOR_LIGHT_GREY, COLOR_WHITE, " P", "W", "R " ); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); /* CPU busy graph */ line = 24; NPcpugraph_ncpu = MIN(cons_rows - line - 2, HI_CPU); if (HI_CPU > 0) { NPcpugraph = 1; NPcpugraph_valid = 0; set_pos (line++, 1); fill_text ('-', 38); set_pos (line++, 1); draw_text ("CPU"); for (i = 0; i < NPcpugraph_ncpu; i++) { sprintf (buf, "%02X ", i); set_pos (line++, 1); draw_text (buf); } } else NPcpugraph = 0; /* Vertical separators */ for (i = 2; i <= cons_rows; i++) { set_pos (i , 39); draw_char ('|'); } /* Last line : horizontal separator */ if (cons_rows >= 24) { set_pos (cons_rows, 1); fill_text ('-', 38); draw_char ('|'); fill_text ('-', cons_cols); } /* positions the cursor */ set_pos (cons_rows, cons_cols); } /*=NP================================================================*/ /* This refreshes the screen with new data every cycle */ /*===================================================================*/ static void NP_update(REGS *regs) { int i, n; int mode, zhost; QWORD curpsw; U32 addr, aaddr; DEVBLK *dev; int online, busy, open; char *devclass; char devnam[128]; char buf[1024]; if (NPhelpup == 1) { if (NPhelpdown == 1) { NP_init(); NP_screen_redraw(regs); NPhelpup = 0; NPhelpdown = 0; NPhelppaint = 1; } else { if (NPhelppaint) { set_color (COLOR_LIGHT_GREY, COLOR_BLACK); clr_screen (); for (i = 0; strcmp(NPhelp[i], ""); i++) { set_pos (i+1, 1); draw_text (NPhelp[i]); } NPhelppaint = 0; } return; } } #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) regs = regs->hostregs; #endif /*defined(_FEATURE_SIE)*/ /* line 1 : cpu number and percent busy */ if (!NPcpunum_valid || NPcpunum != regs->cpuad) { set_color (COLOR_WHITE, COLOR_BLUE); set_pos (1, 16); sprintf (buf, "%4.4X:",regs->cpuad); draw_text (buf); NPcpunum_valid = 1; NPcpunum = regs->cpuad; } #if defined(OPTION_MIPS_COUNTING) if (!NPcpupct_valid || NPcpupct != regs->cpupct) { set_color (COLOR_WHITE, COLOR_BLUE); set_pos (1, 22); sprintf(buf, "%3d", regs->cpupct); draw_text (buf); NPcpupct_valid = 1; NPcpupct = regs->cpupct; } #else // !defined(OPTION_MIPS_COUNTING) if (!NPcpupct_valid) { set_color (COLOR_WHITE, COLOR_BLUE); set_pos (1, 21); draw_text (" "); NPcpupct_valid = 1; } #endif /*defined(OPTION_MIPS_COUNTING)*/ #if defined(_FEATURE_SIE) if(regs->sie_active) regs = regs->guestregs; #endif /*defined(_FEATURE_SIE)*/ mode = (regs->arch_mode == ARCH_900); zhost = #if defined(_FEATURE_SIE) !mode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900; #else // !defined(_FEATURE_SIE) 0; #endif // defined(_FEATURE_SIE) /* Redraw the psw template if the mode changed */ if (NPpswmode != mode || NPpswzhost != zhost) { NPpswmode = mode; NPpswzhost = zhost; NPpsw_valid = NPpswstate_valid = 0; set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (3, 1); fill_text (' ',38); set_pos (4, 1); fill_text (' ', 38); set_pos (4, NPpswmode || NPpswzhost ? 19 : 10); draw_text ("PSW"); } /* Display the psw */ memset (curpsw, 0, sizeof(QWORD)); copy_psw (regs, curpsw); if (!NPpsw_valid || memcmp(NPpsw, curpsw, sizeof(QWORD))) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (3, 3); if (mode) { draw_dw (fetch_dw(curpsw)); set_pos (3, 22); draw_dw (fetch_dw(curpsw+8)); } else if (zhost) { draw_fw (fetch_fw(curpsw)); // draw_fw (0); draw_fw (fetch_fw(curpsw+4)); /* *JJ */ set_pos (3, 22); // draw_fw (fetch_fw(curpsw+4) & 0x80000000 ? 0x80000000 : 0); // draw_fw (fetch_fw(curpsw+4) & 0x7fffffff); draw_text("----------------"); /* *JJ */ } else { draw_fw (fetch_fw(curpsw)); set_pos (3, 12); draw_fw (fetch_fw(curpsw+4)); } NPpsw_valid = 1; memcpy (NPpsw, curpsw, sizeof(QWORD)); } /* Display psw state */ sprintf (buf, "%2d%c%c%c%c%c%c%c%c", regs->psw.amode64 ? 64 : regs->psw.amode ? 31 : 24, regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.', sysblk.inststep ? 'T' : '.', WAITSTATE (®s->psw) ? 'W' : '.', regs->loadstate ? 'L' : '.', regs->checkstop ? 'C' : '.', PROBSTATE(®s->psw) ? 'P' : '.', SIE_MODE(regs) ? 'S' : '.', mode ? 'Z' : '.'); if (!NPpswstate_valid || strcmp(NPpswstate, buf)) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK ); set_pos (mode || zhost ? 4 : 3, 28); draw_text (buf); NPpswstate_valid = 1; strcpy (NPpswstate, buf); } /* Redraw the register template if the regmode switched */ mode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); zhost = #if defined(_FEATURE_SIE) (regs->arch_mode != ARCH_900 && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); #else // !defined(_FEATURE_SIE) 0; #endif /*defined(_FEATURE_SIE)*/ if (NPregmode != mode || NPregzhost != zhost) { NPregmode = mode; NPregzhost = zhost; NPregs_valid = 0; set_color (COLOR_LIGHT_GREY, COLOR_BLACK); if (NPregmode || NPregzhost) { /* 64 bit registers */ for (i = 0; i < 8; i++) { set_pos (i+6, 1); fill_text (' ', 38); set_pos (i+6, 1); draw_text (NPregnum64[i*2]); set_pos (i+6, 20); draw_text (NPregnum64[i*2+1]); } } else { /* 32 bit registers */ for (i = 0; i < 4; i++) { set_pos (i*2+6,1); fill_text (' ', 38); set_pos (i*2+7,1); fill_text (' ', 38); set_pos (i*2+7,9); draw_text (NPregnum[i*4]); set_pos (i*2+7,18); draw_text (NPregnum[i*4+1]); set_pos (i*2+7,27); draw_text (NPregnum[i*4+2]); set_pos (i*2+7,36); draw_text (NPregnum[i*4+3]); } } } /* Display register values */ set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK ); if (NPregmode) { /* 64 bit registers */ for (i = 0; i < 16; i++) { switch (NPregdisp) { case 0: if (!NPregs_valid || NPregs64[i] != regs->GR_G(i)) { set_pos (6 + i/2, 3 + (i%2)*19); draw_dw (regs->GR_G(i)); NPregs64[i] = regs->GR_G(i); } break; case 1: if (!NPregs_valid || NPregs64[i] != regs->CR_G(i)) { set_pos (6 + i/2, 3 + (i%2)*19); draw_dw (regs->CR_G(i)); NPregs64[i] = regs->CR_G(i); } break; } } } else if (NPregzhost) { /* 32 bit registers on 64 bit template */ for (i = 0; i < 16; i++) { switch (NPregdisp) { case 0: if (!NPregs_valid || NPregs[i] != regs->GR_L(i)) { set_pos (6 + i/2, 3 + (i%2)*19); // draw_fw (0); draw_text("--------"); draw_fw (regs->GR_L(i)); NPregs[i] = regs->GR_L(i); } break; case 1: if (!NPregs_valid || NPregs[i] != regs->CR_L(i)) { set_pos (6 + i/2, 3 + (i%2)*19); // draw_fw (0); draw_text("--------"); draw_fw (regs->CR_L(i)); NPregs[i] = regs->CR_L(i); } break; } } } else { /* 32 bit registers */ addr = NPaddress; for (i = 0; i < 16; i++) { switch (NPregdisp) { default: case 0: if (!NPregs_valid || NPregs[i] != regs->GR_L(i)) { set_pos (6 + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->GR_L(i)); NPregs[i] = regs->GR_L(i); } break; case 1: if (!NPregs_valid || NPregs[i] != regs->CR_L(i)) { set_pos (6 + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->CR_L(i)); NPregs[i] = regs->CR_L(i); } break; case 2: if (!NPregs_valid || NPregs[i] != regs->AR(i)) { set_pos (6 + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->AR(i)); NPregs[i] = regs->AR(i); } break; case 3: if (!NPregs_valid || NPregs[i] != regs->fpr[i]) { set_pos (6 + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->fpr[i]); NPregs[i] = regs->fpr[i]; } break; case 4: aaddr = APPLY_PREFIXING (addr, regs->PX); addr += 4; if (aaddr + 3 > regs->mainlim) break; if (!NPregs_valid || NPregs[i] != fetch_fw(regs->mainstor + aaddr)) { set_pos (6 + (i/4)*2, 3 + (i%4)*9); draw_fw (fetch_fw(regs->mainstor + aaddr)); NPregs[i] = fetch_fw(regs->mainstor + aaddr); } break; } } } /* Update register selection indicator */ if (!NPregs_valid) { set_pos (14, 6); set_color (NPregdisp == 0 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('G'); set_pos (14, 14); set_color (NPregdisp == 1 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('C'); set_pos (14, 22); set_color (NPregdisp == 2 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('A'); set_pos (14, 30); set_color (NPregdisp == 3 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('F'); } NPregs_valid = 1; /* Address & Data */ if (!NPaddr_valid) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (16, 12); draw_fw (NPaddress); NPaddr_valid = 1; } if (!NPdata_valid) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (16, 30); draw_fw (NPdata); NPdata_valid = 1; } /* Rates */ #ifdef OPTION_MIPS_COUNTING if (!NPmips_valid || sysblk.mipsrate != NPmips) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (19, 1); sprintf(buf, "%3.1d.%2.2d", sysblk.mipsrate / 1000000, (sysblk.mipsrate % 1000000) / 10000); draw_text (buf); NPmips = sysblk.mipsrate; NPmips_valid = 1; } if (!NPsios_valid || NPsios != sysblk.siosrate) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (19, 7); sprintf(buf, "%7d", sysblk.siosrate); draw_text (buf); NPsios = sysblk.siosrate; NPsios_valid = 1; } #endif /* OPTION_MIPS_COUNTING */ /* Optional cpu graph */ if (NPcpugraph) { for (i = 0; i < NPcpugraph_ncpu; i++) { if (!IS_CPU_ONLINE(i)) { if (!NPcpugraph_valid || NPcpugraphpct[i] != -2.0) { set_color (COLOR_RED, COLOR_BLACK); set_pos (26+i, 4); draw_text ("OFFLINE"); fill_text (' ', 38); NPcpugraphpct[i] = -2.0; } } else if (sysblk.regs[i]->cpustate != CPUSTATE_STARTED) { if (!NPcpugraph_valid || NPcpugraphpct[i] != -1.0) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (26+i, 4); draw_text ("STOPPED"); fill_text (' ', 38); NPcpugraphpct[i] = -1.0; } } else if (!NPcpugraph_valid || NPcpugraphpct[i] != sysblk.regs[i]->cpupct) { n = (34 * sysblk.regs[i]->cpupct) / 100; if (n == 0 && sysblk.regs[i]->cpupct > 0) n = 1; else if (n > 34) n = 34; set_color (n > 17 ? COLOR_WHITE : COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (26+i, 4); fill_text ('*', n+3); fill_text (' ', 38); NPcpugraphpct[i] = sysblk.regs[i]->cpupct; } set_color (COLOR_LIGHT_GREY, COLOR_BLACK); } NPcpugraph_valid = 1; } /* Process devices */ for (i = 0, dev = sysblk.firstdev; dev != NULL; i++, dev = dev->nextdev) { if (i >= cons_rows - 3) break; if (!dev->allocated) continue; online = (dev->console && dev->connected) || strlen(dev->filename) > 0; busy = dev->busy != 0 || IOPENDING(dev) != 0; open = dev->fd > 2; /* device identifier */ if (!NPdevices_valid || online != NPonline[i]) { set_pos (i+3, 41); set_color (online ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK); draw_char (i < 26 ? 'A' + i : '.'); NPonline[i] = online; } /* device number */ if (!NPdevices_valid || dev->devnum != NPdevnum[i] || NPbusy[i] != busy) { set_pos (i+3, 43); set_color (busy ? COLOR_LIGHT_YELLOW : COLOR_LIGHT_GREY, COLOR_BLACK); sprintf (buf, "%4.4X", dev->devnum); draw_text (buf); NPdevnum[i] = dev->devnum; NPbusy[i] = busy; } /* device type */ if (!NPdevices_valid || dev->devtype != NPdevtype[i] || open != NPopen[i]) { set_pos (i+3, 48); set_color (open ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK); sprintf (buf, "%4.4X", dev->devtype); draw_text (buf); NPdevtype[i] = dev->devtype; NPopen[i] = open; } /* device class and name */ (dev->hnd->query)(dev, &devclass, sizeof(devnam), devnam); if (!NPdevices_valid || strcmp(NPdevnam[i], devnam)) { set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (i+3, 53); sprintf (buf, "%-4.4s", devclass); draw_text (buf); /* Draw device name only if they're NOT assigning a new one */ if (0 || NPdataentry != 1 || NPpending != 'n' || NPasgn != i ) { set_pos (i+3, 58); draw_text (devnam); fill_text (' ', PANEL_MAX_COLS); } } } /* Complete the device state table */ if (!NPdevices_valid) { NPlastdev = i > 26 ? 26 : i - 1; for ( ; i < NP_MAX_DEVICES; i++) { NPonline[i] = NPdevnum[i] = NPbusy[i] = NPdevtype[i] = NPopen[i] = 0; strcpy (NPdevnam[i], ""); } NPdevices_valid = 1; } /* Prompt 1 */ if (strcmp(NPprompt1, NPoldprompt1)) { strcpy(NPoldprompt1, NPprompt1); if (strlen(NPprompt1) > 0) { set_color (COLOR_WHITE, COLOR_BLUE); set_pos (cons_rows, (40 - strlen(NPprompt1)) / 2); draw_text (NPprompt1); } else if (cons_rows >= 24) { set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (cons_rows, 1); fill_text ('-', 38); } } /* Prompt 2 */ if (strcmp(NPprompt2, NPoldprompt2)) { strcpy(NPoldprompt2, NPprompt2); if (strlen(NPprompt2) > 0) { set_color (COLOR_WHITE, COLOR_BLUE); set_pos (cons_rows, 41); draw_text (NPprompt2); } else if (cons_rows >= 24) { set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (cons_rows, 41); fill_text ('-', cons_cols); } } /* Data entry field */ if (NPdataentry && redraw_cmd) { set_pos (NPcurrow, NPcurcol); if (NPcolorSwitch) set_color (NPcolorFore, NPcolorBack); fill_text (' ', NPcurcol + NPdatalen - 1); set_pos (NPcurrow, NPcurcol); PUTC_CMDLINE(); redraw_cmd = 0; } else /* Position the cursor to the bottom right */ set_pos(cons_rows, cons_cols); } /* ============== End of the main NP block of code =============*/ static void panel_cleanup(void *unused); // (forward reference) #ifdef OPTION_MIPS_COUNTING /////////////////////////////////////////////////////////////////////// // "maxrates" command support... #define DEF_MAXRATES_RPT_INTVL ( 1440 ) DLL_EXPORT U32 curr_high_mips_rate = 0; // (high water mark for current interval) DLL_EXPORT U32 curr_high_sios_rate = 0; // (high water mark for current interval) DLL_EXPORT U32 prev_high_mips_rate = 0; // (saved high water mark for previous interval) DLL_EXPORT U32 prev_high_sios_rate = 0; // (saved high water mark for previous interval) DLL_EXPORT time_t curr_int_start_time = 0; // (start time of current interval) DLL_EXPORT time_t prev_int_start_time = 0; // (start time of previous interval) DLL_EXPORT U32 maxrates_rpt_intvl = DEF_MAXRATES_RPT_INTVL; DLL_EXPORT void update_maxrates_hwm() // (update high-water-mark values) { time_t current_time = 0; U32 elapsed_secs = 0; if (curr_high_mips_rate < sysblk.mipsrate) curr_high_mips_rate = sysblk.mipsrate; if (curr_high_sios_rate < sysblk.siosrate) curr_high_sios_rate = sysblk.siosrate; // Save high water marks for current interval... time( ¤t_time ); elapsed_secs = current_time - curr_int_start_time; if ( elapsed_secs >= ( maxrates_rpt_intvl * 60 ) ) { prev_high_mips_rate = curr_high_mips_rate; prev_high_sios_rate = curr_high_sios_rate; curr_high_mips_rate = 0; curr_high_sios_rate = 0; prev_int_start_time = curr_int_start_time; curr_int_start_time = current_time; } } #endif // OPTION_MIPS_COUNTING /////////////////////////////////////////////////////////////////////// REGS *copy_regs(int cpu) { REGS *regs; if (cpu < 0 || cpu >= MAX_CPU_ENGINES) cpu = 0; obtain_lock (&sysblk.cpulock[cpu]); if ((regs = sysblk.regs[cpu]) == NULL) { release_lock(&sysblk.cpulock[cpu]); return &sysblk.dummyregs; } memcpy (©regs, regs, sysblk.regs_copy_len); if (copyregs.hostregs == NULL) { release_lock(&sysblk.cpulock[cpu]); return &sysblk.dummyregs; } #if defined(_FEATURE_SIE) if (regs->sie_active) { memcpy (©sieregs, regs->guestregs, sysblk.regs_copy_len); copyregs.guestregs = ©sieregs; copysieregs.hostregs = ©regs; regs = ©sieregs; } else #endif // defined(_FEATURE_SIE) regs = ©regs; SET_PSW_IA(regs); release_lock(&sysblk.cpulock[cpu]); return regs; } static char *format_int(uint64_t ic) { static char obfr[32]; /* Enough for displaying 2^64-1 */ char grps[7][4]; /* 7 groups of 3 digits */ int maxg=0; int i; strcpy(grps[0],"0"); while(ic>0) { int grp; grp=ic%1000; ic/=1000; if(ic==0) { sprintf(grps[maxg],"%u",grp); } else { sprintf(grps[maxg],"%3.3u",grp); } maxg++; } if(maxg) maxg--; obfr[0]=0; for(i=maxg;i>=0;i--) { strcat(obfr,grps[i]); if(i) { strcat(obfr,","); } } return obfr; } /*-------------------------------------------------------------------*/ /* Panel display thread */ /* */ /* This function runs on the main thread. It receives messages */ /* from the log task and displays them on the screen. It accepts */ /* panel commands from the keyboard and executes them. It samples */ /* the PSW periodically and displays it on the screen status line. */ /*-------------------------------------------------------------------*/ #if defined(OPTION_DYNAMIC_LOAD) void panel_display_r (void) #else void panel_display (void) #endif // defined(OPTION_DYNAMIC_LOAD) { #ifndef _MSVC_ int rc; /* Return code */ int maxfd; /* Highest file descriptor */ fd_set readset; /* Select file descriptors */ struct timeval tv; /* Select timeout structure */ #endif // _MSVC_ int i; /* Array subscripts */ int len; /* Length */ REGS *regs; /* -> CPU register context */ QWORD curpsw; /* Current PSW */ QWORD prvpsw; /* Previous PSW */ BYTE prvstate = 0xFF; /* Previous stopped state */ U64 prvicount = 0; /* Previous instruction count*/ #if defined(OPTION_MIPS_COUNTING) U64 prvtcount = 0; /* Previous total count */ #endif /*defined(OPTION_MIPS_COUNTING)*/ int prvcpupct = 0; /* Previous cpu percentage */ #if defined(OPTION_SHARED_DEVICES) U32 prvscount = 0; /* Previous shrdcount */ #endif // defined(OPTION_SHARED_DEVICES) char readbuf[MSG_SIZE]; /* Message read buffer */ int readoff = 0; /* Number of bytes in readbuf*/ BYTE c; /* Character work area */ size_t kbbufsize = CMD_SIZE; /* Size of keyboard buffer */ char *kbbuf = NULL; /* Keyboard input buffer */ int kblen; /* Number of chars in kbbuf */ U32 aaddr; /* Absolute address for STO */ char buf[1024]; /* Buffer workarea */ SET_THREAD_NAME("panel_display"); /* Display thread started message on control panel */ logmsg (_("HHCPN001I Control panel thread started: " "tid="TIDPAT", pid=%d\n"), thread_id(), getpid()); /* Notify logger_thread we're in control */ sysblk.panel_init = 1; hdl_adsc("panel_cleanup",panel_cleanup, NULL); history_init(); /* Set up the input file descriptors */ confp = stderr; keybfd = STDIN_FILENO; /* Initialize screen dimensions */ cons_term = getenv ("TERM"); get_dim (&cons_rows, &cons_cols); /* Clear the command-line buffer */ memset (cmdline, 0, sizeof(cmdline)); cmdcols = cons_cols - CMDLINE_COL; /* Obtain storage for the keyboard buffer */ if (!(kbbuf = malloc (kbbufsize))) { logmsg(_("HHCPN002S Cannot obtain keyboard buffer: %s\n"), strerror(errno)); return; } /* Obtain storage for the circular message buffer */ msgbuf = malloc (MAX_MSGS * sizeof(PANMSG)); if (msgbuf == NULL) { fprintf (stderr, _("HHCPN003S Cannot obtain message buffer: %s\n"), strerror(errno)); return; } /* Initialize circular message buffer */ for (curmsg = msgbuf, i=0; i < MAX_MSGS; curmsg++, i++) { curmsg->next = curmsg + 1; curmsg->prev = curmsg - 1; curmsg->msgnum = i; memset(curmsg->msg,SPACE,MSG_SIZE); #if defined(OPTION_MSGCLR) curmsg->bg = COLOR_DEFAULT_FG; curmsg->fg = COLOR_DEFAULT_BG; #if defined(OPTION_MSGHLD) curmsg->keep = 0; memset( &curmsg->expiration, 0, sizeof(curmsg->expiration)); #endif // defined(OPTION_MSGHLD) #endif // defined(OPTION_MSGCLR) } /* Complete the circle */ msgbuf->prev = msgbuf + MAX_MSGS - 1; msgbuf->prev->next = msgbuf; /* Indicate "first-time" state */ curmsg = topmsg = NULL; wrapped = 0; numkept = 0; #if defined(OPTION_MSGHLD) keptmsgs = lastkept = NULL; #endif // defined(OPTION_MSGHLD) /* Set screen output stream to NON-buffered */ setvbuf (confp, NULL, _IONBF, 0); /* Put the terminal into cbreak mode */ set_or_reset_console_mode( keybfd, 1 ); /* Set console title */ set_console_title(); /* Clear the screen */ set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); clr_screen (); redraw_msgs = redraw_cmd = redraw_status = 1; /* Process messages and commands */ while ( 1 ) { #if defined(OPTION_MIPS_COUNTING) update_maxrates_hwm(); // (update high-water-mark values) #endif // defined(OPTION_MIPS_COUNTING) #if defined( _MSVC_ ) /* Wait for keyboard input */ #define WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS (20) for (i=sysblk.panrate/WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS; i && !kbhit(); i--) Sleep(WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS); ADJ_SCREEN_SIZE(); /* If keyboard input has [finally] arrived, then process it */ if ( kbhit() ) { /* Read character(s) from the keyboard */ kbbuf[0] = getch(); kbbuf[kblen=1] = '\0'; translate_keystroke( kbbuf, &kblen ); #else // !defined( _MSVC_ ) /* Set the file descriptors for select */ FD_ZERO (&readset); FD_SET (keybfd, &readset); maxfd = keybfd; /* Wait for a message to arrive, a key to be pressed, or the inactivity interval to expire */ tv.tv_sec = sysblk.panrate / 1000; tv.tv_usec = (sysblk.panrate * 1000) % 1000000; rc = select (maxfd + 1, &readset, NULL, NULL, &tv); if (rc < 0 ) { if (errno == EINTR) continue; fprintf (stderr, _("HHCPN004E select: %s\n"), strerror(errno)); break; } ADJ_SCREEN_SIZE(); /* If keyboard input has arrived then process it */ if (FD_ISSET(keybfd, &readset)) { /* Read character(s) from the keyboard */ kblen = read (keybfd, kbbuf, kbbufsize-1); if (kblen < 0) { fprintf (stderr, _("HHCPN005E keyboard read: %s\n"), strerror(errno)); break; } kbbuf[kblen] = '\0'; #endif // defined( _MSVC_ ) /* =NP= : Intercept NP commands & process */ if (NPDup == 1) { if (NPdevsel == 1) { NPdevsel = 0; NPdevice = kbbuf[0]; /* save the device selected */ kbbuf[0] = NPsel2; /* setup for 2nd part of rtn */ } if (NPdataentry == 0 && kblen == 1) { /* We are in command mode */ if (NPhelpup == 1) { if (kbbuf[0] == 0x1b) NPhelpdown = 1; kbbuf[0] = '\0'; redraw_status = 1; } cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); switch(kbbuf[0]) { case 0x1B: /* ESC */ NPDup = 0; restore_command_line(); ADJ_CMDCOL(); redraw_msgs = redraw_cmd = redraw_status = 1; npquiet = 0; // (forced for one paint cycle) break; case '?': NPhelpup = 1; redraw_status = 1; break; case 'S': /* START */ case 's': do_panel_command("herc startall"); break; case 'P': /* STOP */ case 'p': do_panel_command("herc stopall"); break; case 'O': /* Store */ case 'o': regs = copy_regs(sysblk.pcpu); aaddr = APPLY_PREFIXING (NPaddress, regs->PX); if (aaddr > regs->mainlim) break; store_fw (regs->mainstor + aaddr, NPdata); redraw_status = 1; break; case 'I': /* Display */ case 'i': NPregdisp = 4; NPregs_valid = 0; redraw_status = 1; break; case 'g': /* display GPR */ case 'G': NPregdisp = 0; NPregs_valid = 0; redraw_status = 1; break; case 'a': /* Display AR */ case 'A': NPregdisp = 2; NPregs_valid = 0; redraw_status = 1; break; case 'c': case 'C': /* Case CR */ NPregdisp = 1; NPregs_valid = 0; redraw_status = 1; break; case 'f': /* Case FPR */ case 'F': NPregdisp = 3; NPregs_valid = 0; redraw_status = 1; break; case 'r': /* Enter address */ case 'R': NPdataentry = 1; redraw_cmd = 1; NPpending = 'r'; NPcurrow = 16; NPcurcol = 12; NPdatalen = 8; NPcolorSwitch = 1; NPcolorFore = COLOR_WHITE; NPcolorBack = COLOR_BLUE; strcpy(NPentered, ""); strcpy(NPprompt1, "Enter Address"); redraw_status = 1; break; case 'd': /* Enter data */ case 'D': NPdataentry = 1; redraw_cmd = 1; NPpending = 'd'; NPcurrow = 16; NPcurcol = 30; NPdatalen = 8; NPcolorSwitch = 1; NPcolorFore = COLOR_WHITE; NPcolorBack = COLOR_BLUE; strcpy(NPentered, ""); strcpy(NPprompt1, "Enter Data Value"); redraw_status = 1; break; case 'l': /* IPL */ case 'L': NPdevsel = 1; NPsel2 = 1; strcpy(NPprompt2, "Select Device for IPL"); redraw_status = 1; break; case 1: /* IPL - 2nd part */ i = toupper(NPdevice) - 'A'; if (i < 0 || i > NPlastdev) { strcpy(NPprompt2, ""); redraw_status = 1; break; } sprintf (cmdline, "herc ipl %4.4x", NPdevnum[i]); do_panel_command(cmdline); strcpy(NPprompt2, ""); redraw_status = 1; break; case 'u': /* Device interrupt */ case 'U': NPdevsel = 1; NPsel2 = 2; strcpy(NPprompt2, "Select Device for Interrupt"); redraw_status = 1; break; case 2: /* Device int: part 2 */ i = toupper(NPdevice) - 'A'; if (i < 0 || i > NPlastdev) { strcpy(NPprompt2, ""); redraw_status = 1; break; } sprintf (cmdline, "herc i %4.4x", NPdevnum[i]); do_panel_command(cmdline); strcpy(NPprompt2, ""); redraw_status = 1; break; case 'n': /* Device Assignment */ case 'N': NPdevsel = 1; NPsel2 = 3; strcpy(NPprompt2, "Select Device to Reassign"); redraw_status = 1; break; case 3: /* Device asgn: part 2 */ i = toupper(NPdevice) - 'A'; if (i < 0 || i > NPlastdev) { strcpy(NPprompt2, ""); redraw_status = 1; break; } NPdataentry = 1; redraw_cmd = 1; NPpending = 'n'; NPasgn = i; NPcurrow = 3 + i; NPcurcol = 58; NPdatalen = cons_cols - 57; NPcolorSwitch = 1; NPcolorFore = COLOR_DEFAULT_LIGHT; NPcolorBack = COLOR_BLUE; strcpy(NPentered, ""); strcpy(NPprompt2, "New Name, or [enter] to Reload"); redraw_status = 1; break; case 'W': /* POWER */ case 'w': NPdevsel = 1; NPsel2 = 4; strcpy(NPprompt1, "Confirm Powerdown Y or N"); redraw_status = 1; break; case 4: /* POWER - 2nd part */ if (NPdevice == 'y' || NPdevice == 'Y') do_panel_command("herc quit"); strcpy(NPprompt1, ""); redraw_status = 1; break; case 'T': /* Restart */ case 't': NPdevsel = 1; NPsel2 = 5; strcpy(NPprompt1, "Confirm Restart Y or N"); redraw_status = 1; break; case 5: /* Restart - part 2 */ if (NPdevice == 'y' || NPdevice == 'Y') do_panel_command("herc restart"); strcpy(NPprompt1, ""); redraw_status = 1; break; case 'E': /* Ext int */ case 'e': NPdevsel = 1; NPsel2 = 6; strcpy(NPprompt1, "Confirm External Interrupt Y or N"); redraw_status = 1; break; case 6: /* External - part 2 */ if (NPdevice == 'y' || NPdevice == 'Y') do_panel_command("herc ext"); strcpy(NPprompt1, ""); redraw_status = 1; break; default: break; } NPcmd = 1; } else { /* We are in data entry mode */ if (kbbuf[0] == 0x1B) { /* Switch back to command mode */ NPdataentry = 0; NPaddr_valid = 0; NPdata_valid = 0; strcpy(NPprompt1, ""); strcpy(NPprompt2, ""); NPcmd = 1; } else NPcmd = 0; } if (NPcmd == 1) kblen = 0; /* don't process as command */ } /* =NP END= */ /* Process characters in the keyboard buffer */ for (i = 0; i < kblen; ) { /* Test for HOME */ if (strcmp(kbbuf+i, KBD_HOME) == 0) { if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) { cursor_cmdline_home(); redraw_cmd = 1; } else { scroll_to_top_line( 1 ); redraw_msgs = 1; } break; } /* Test for END */ if (strcmp(kbbuf+i, KBD_END) == 0) { if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) { cursor_cmdline_end(); redraw_cmd = 1; } else { scroll_to_bottom_screen( 1 ); redraw_msgs = 1; } break; } /* Test for CTRL+HOME */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_HOME) == 0) { scroll_to_top_line( 1 ); redraw_msgs = 1; break; } /* Test for CTRL+END */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_END) == 0) { scroll_to_bottom_line( 1 ); redraw_msgs = 1; break; } /* Process UPARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_UP_ARROW) == 0) { do_prev_history(); redraw_cmd = 1; break; } /* Process DOWNARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_DOWN_ARROW) == 0) { do_next_history(); redraw_cmd = 1; break; } #if defined(OPTION_EXTCURS) /* Process ALT+UPARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_UP_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_row <= 1) cur_cons_row = cons_rows + 1; set_pos( --cur_cons_row, cur_cons_col ); break; } /* Process ALT+DOWNARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_DOWN_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_row >= cons_rows) cur_cons_row = 1 - 1; set_pos( ++cur_cons_row, cur_cons_col ); break; } #endif // defined(OPTION_EXTCURS) /* Test for PAGEUP */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_UP) == 0) { page_up( 1 ); redraw_msgs = 1; break; } /* Test for PAGEDOWN */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_DOWN) == 0) { page_down( 1 ); redraw_msgs = 1; break; } /* Test for CTRL+UPARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_UP_ARROW) == 0) { scroll_up_lines(1,1); redraw_msgs = 1; break; } /* Test for CTRL+DOWNARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_DOWN_ARROW) == 0) { scroll_down_lines(1,1); redraw_msgs = 1; break; } /* Process BACKSPACE */ if (kbbuf[i] == '\b' || kbbuf[i] == '\x7F') { if (NPDup == 0 && !is_cursor_on_cmdline()) beep(); else { if (cmdoff > 0) { int j; for (j = cmdoff-1; j 0) cmdoff--; ADJ_CMDCOL(); i++; redraw_cmd = 1; break; } /* Process RIGHTARROW */ if (strcmp(kbbuf+i, KBD_RIGHT_ARROW) == 0) { if (cmdoff < cmdlen) cmdoff++; ADJ_CMDCOL(); i++; redraw_cmd = 1; break; } #if defined(OPTION_EXTCURS) /* Process ALT+LEFTARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_LEFT_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_col <= 1) { cur_cons_row--; cur_cons_col = cons_cols + 1; } if (cur_cons_row < 1) cur_cons_row = cons_rows; set_pos( cur_cons_row, --cur_cons_col ); break; } /* Process ALT+RIGHTARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_RIGHT_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_col >= cons_cols) { cur_cons_row++; cur_cons_col = 0; } if (cur_cons_row > cons_rows) cur_cons_row = 1; set_pos( cur_cons_row, ++cur_cons_col ); break; } #endif // defined(OPTION_EXTCURS) /* Process INSERT */ if (strcmp(kbbuf+i, KBD_INSERT) == 0 ) { cmdins = !cmdins; set_console_cursor_shape( confp, cmdins ); i++; break; } /* Process ESCAPE */ if (kbbuf[i] == '\x1B') { /* If data on cmdline, erase it */ if ((NPDup == 1 || is_cursor_on_cmdline()) && cmdlen) { cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); redraw_cmd = 1; } else { /* =NP= : Switch to new panel display */ save_command_line(); NP_init(); NPDup = 1; /* =END= */ } break; } /* Process TAB */ if (kbbuf[i] == '\t' || kbbuf[i] == '\x7F') { if (NPDup == 1 || !is_cursor_on_cmdline()) { cursor_cmdline_home(); redraw_cmd = 1; } else { tab_pressed(cmdline, &cmdoff); cmdlen = strlen(cmdline); ADJ_CMDCOL(); i++; redraw_cmd = 1; } break; } #if defined(OPTION_EXTCURS) /* ENTER key special handling */ if (NPDup == 0 && kbbuf[i] == '\n') { /* Get cursor pos and check if on cmdline */ if (!is_cursor_on_cmdline()) { int keepnum = get_keepnum_by_row( cur_cons_row ); if (keepnum >= 0) { #if defined(OPTION_MSGHLD) /* ENTER pressed on kept msg; remove msg */ unkeep_by_keepnum( keepnum, 1 ); #endif // defined(OPTION_MSGHLD) redraw_msgs = 1; break; } /* ENTER pressed NOT on cmdline */ beep(); break; } /* ENTER pressed on cmdline; fall through for normal ENTER keypress handling... */ } #endif // defined(OPTION_EXTCURS) /* Process the command when the ENTER key is pressed */ if (kbbuf[i] == '\n') { if (cmdlen == 0 && NPDup == 0 && !sysblk.inststep && sysblk.cmdtgt == 0) { history_show(); } else { cmdline[cmdlen] = '\0'; /* =NP= create_thread replaced with: */ if (NPDup == 0) { if ('#' == cmdline[0] || '*' == cmdline[0]) { if (!is_currline_visible()) scroll_to_bottom_screen( 1 ); history_requested = 0; do_panel_command(cmdline); redraw_cmd = 1; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); redraw_cmd = 1; } else { history_requested = 0; do_panel_command(cmdline); redraw_cmd = 1; if (history_requested == 1) { strcpy(cmdline, historyCmdLine); cmdlen = strlen(cmdline); cmdoff = cmdlen; ADJ_CMDCOL(); NPDup = 0; NPDinit = 1; } } } else { NPdataentry = 0; NPcurrow = cons_rows; NPcurcol = cons_cols; NPcolorSwitch = 0; switch (NPpending) { case 'r': sscanf(cmdline, "%x", &NPaddress); NPaddr_valid = 0; strcpy(NPprompt1, ""); break; case 'd': sscanf(cmdline, "%x", &NPdata); NPdata_valid = 0; strcpy(NPprompt1, ""); break; case 'n': if (strlen(cmdline) < 1) { strcpy(cmdline, NPdevnam[NPasgn]); } strcpy(NPdevnam[NPasgn], ""); sprintf (NPentered, "herc devinit %4.4x %s", NPdevnum[NPasgn], cmdline); do_panel_command(NPentered); strcpy(NPprompt2, ""); break; default: break; } redraw_status = 1; cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); } /* =END= */ redraw_cmd = 1; } break; } /* end if (kbbuf[i] == '\n') */ /* Ignore non-printable characters */ if (!isprint(kbbuf[i])) { beep(); i++; continue; } /* Ignore all other keystrokes not on cmdline */ if (NPDup == 0 && !is_cursor_on_cmdline()) { beep(); break; } /* Append the character to the command buffer */ ASSERT(cmdlen <= CMD_SIZE-1 && cmdoff <= cmdlen); if (0 || (cmdoff >= CMD_SIZE-1) || (cmdins && cmdlen >= CMD_SIZE-1) ) { /* (no more room!) */ beep(); } else /* (there's still room) */ { ASSERT(cmdlen < CMD_SIZE-1 || (!cmdins && cmdoff < cmdlen)); if (cmdoff >= cmdlen) { /* Append to end of buffer */ ASSERT(!(cmdoff > cmdlen)); // (sanity check) cmdline[cmdoff++] = kbbuf[i]; cmdline[cmdoff] = '\0'; cmdlen++; } else { ASSERT(cmdoff < cmdlen); if (cmdins) { /* Insert: make room by sliding all following chars right one position */ int j; for (j=cmdlen-1; j>=cmdoff; j--) cmdline[j+1] = cmdline[j]; cmdline[cmdoff++] = kbbuf[i]; cmdlen++; } else { /* Overlay: replace current position */ cmdline[cmdoff++] = kbbuf[i]; } } ADJ_CMDCOL(); redraw_cmd = 1; } i++; } /* end for(i) */ } /* end if keystroke */ FinishShutdown: // If we finished processing all of the message data // the last time we were here, then get some more... if ( lmsndx >= lmscnt ) // (all previous data processed?) { lmscnt = log_read( &lmsbuf, &lmsnum, LOG_NOBLOCK ); lmsndx = 0; } else if ( lmsndx >= lmsmax ) { lmsbuf += lmsndx; // pick up where we left off at... lmscnt -= lmsndx; // pick up where we left off at... lmsndx = 0; } // Process all message data or until limit reached... // (limiting the amount of data we process a console message flood // from preventing keyboard from being read since we need to break // out of the below message data processing loop to loop back up // to read the keyboard again...) /* Read message bytes until newline... */ while ( lmsndx < lmscnt && lmsndx < lmsmax ) { /* Initialize the read buffer */ if (!readoff || readoff >= MSG_SIZE) { memset (readbuf, SPACE, MSG_SIZE); readoff = 0; } /* Read message bytes and copy into read buffer until we either encounter a newline character or our buffer is completely filled with data. */ while ( lmsndx < lmscnt && lmsndx < lmsmax ) { /* Read a byte from the message pipe */ c = *(lmsbuf + lmsndx); lmsndx++; /* Break to process received message whenever a newline is encountered */ if (c == '\n' || c == '\r') { readoff = 0; /* (for next time) */ break; } /* Handle tab character */ if (c == '\t') { readoff += 8; readoff &= 0xFFFFFFF8; /* Messages longer than one screen line will be continued on the very next screen line */ if (readoff >= MSG_SIZE) break; else continue; } /* Eliminate non-displayable characters */ if (!isgraph(c)) c = SPACE; /* Stuff byte into message processing buffer */ readbuf[readoff++] = c; /* Messages longer than one screen line will be continued on the very next screen line */ if (readoff >= MSG_SIZE) break; } /* end while ( lmsndx < lmscnt && lmsndx < lmsmax ) */ /* If we have a message to be displayed (or a complete part of one), then copy it to the circular buffer. */ if (!readoff || readoff >= MSG_SIZE) { /* First-time here? */ if (curmsg == NULL) { curmsg = topmsg = msgbuf; } else { /* Perform autoscroll if needed */ if (is_currline_visible()) { while (lines_remaining() < 1) scroll_down_lines(1,1); /* Set the display update indicator */ redraw_msgs = 1; } /* Go on to next available msg buffer */ curmsg = curmsg->next; /* Updated wrapped indicator */ if (curmsg == msgbuf) wrapped = 1; } /* Copy message into next available PANMSG slot */ memcpy( curmsg->msg, readbuf, MSG_SIZE ); #if defined(OPTION_MSGCLR) /* Colorize and/or keep new message if needed */ colormsg(curmsg); #endif // defined(OPTION_MSGCLR) } /* end if (!readoff || readoff >= MSG_SIZE) */ } /* end Read message bytes until newline... */ /* Don't read or otherwise process any input once system shutdown has been initiated */ if ( sysblk.shutdown ) { if ( sysblk.shutfini ) break; /* wait for system to finish shutting down */ usleep(10000); lmsmax = INT_MAX; goto FinishShutdown; } /* =NP= : Reinit traditional panel if NP is down */ if (NPDup == 0 && NPDinit == 1) { redraw_msgs = redraw_status = redraw_cmd = 1; set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); clr_screen (); } /* =END= */ /* Obtain the PSW for target CPU */ regs = copy_regs(sysblk.pcpu); memset (curpsw, 0x00, sizeof(curpsw)); copy_psw (regs, curpsw); /* Set the display update indicator if the PSW has changed or if the instruction counter has changed, or if the CPU stopped state has changed */ if (memcmp(curpsw, prvpsw, sizeof(curpsw)) != 0 || prvicount != INSTCOUNT(regs) || prvcpupct != regs->cpupct #if defined(OPTION_SHARED_DEVICES) || prvscount != sysblk.shrdcount #endif // defined(OPTION_SHARED_DEVICES) || prvstate != regs->cpustate #if defined(OPTION_MIPS_COUNTING) || (NPDup && NPcpugraph && prvtcount != sysblk.instcount) #endif /*defined(OPTION_MIPS_COUNTING)*/ ) { redraw_status = 1; memcpy (prvpsw, curpsw, sizeof(prvpsw)); prvicount = INSTCOUNT(regs); prvcpupct = regs->cpupct; prvstate = regs->cpustate; #if defined(OPTION_SHARED_DEVICES) prvscount = sysblk.shrdcount; #endif // defined(OPTION_SHARED_DEVICES) #if defined(OPTION_MIPS_COUNTING) prvtcount = sysblk.instcount; #endif /*defined(OPTION_MIPS_COUNTING)*/ } /* =NP= : Display the screen - traditional or NP */ /* Note: this is the only code block modified rather */ /* than inserted. It makes the block of 3 ifs in the */ /* original code dependent on NPDup == 0, and inserts */ /* the NP display as an else after those ifs */ if (NPDup == 0) { /* Rewrite the screen if display update indicators are set */ if (redraw_msgs && !npquiet) { /* Display messages in scrolling area */ PANMSG* p; /* Save cursor location */ saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; #if defined(OPTION_MSGHLD) /* Unkeep kept messages if needed */ expire_kept_msgs(0); #endif // defined(OPTION_MSGHLD) i = 0; #if defined(OPTION_MSGHLD) /* Draw kept messages first */ for (p=keptmsgs; i < (SCROLL_LINES + numkept) && p; i++, p = p->next) { set_pos (i+1, 1); #if defined(OPTION_MSGCLR) set_color (p->fg, p->bg); #else // !defined(OPTION_MSGCLR) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); #endif // defined(OPTION_MSGCLR) write_text (p->msg, MSG_SIZE); } #endif // defined(OPTION_MSGHLD) /* Then draw current screen */ for (p=topmsg; i < (SCROLL_LINES + numkept) && (p != curmsg->next || p == topmsg); i++, p = p->next) { set_pos (i+1, 1); #if defined(OPTION_MSGCLR) set_color (p->fg, p->bg); #else // !defined(OPTION_MSGCLR) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); #endif // defined(OPTION_MSGCLR) write_text (p->msg, MSG_SIZE); } /* Pad remainder of screen with blank lines */ for (; i < (SCROLL_LINES + numkept); i++) { set_pos (i+1, 1); set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); erase_to_eol( confp ); } /* Display the scroll indicators */ if (topmsg != oldest_msg()) { /* More messages precede top line */ set_pos (1, cons_cols); set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG); draw_text ("+"); } if (!is_currline_visible()) { /* More messages follow bottom line */ set_pos (cons_rows-2, cons_cols); set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG); draw_text ("V"); } /* restore cursor location */ cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } /* end if(redraw_msgs) */ if (redraw_cmd) { /* Save cursor location */ saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; /* Display the command line */ set_pos (CMDLINE_ROW, 1); set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG); #if defined(OPTION_CMDTGT) switch(sysblk.cmdtgt) { case 0: // cmdtgt herc { draw_text(CMD_PREFIX_STR); break; } case 1: // cmdtgt scp { draw_text(CMD_PREFIX_STR1); break; } case 2: // cmdtgt pscp { draw_text(CMD_PREFIX_STR2); break; } } #else // !defined(OPTION_CMDTGT) draw_text (CMD_PREFIX_STR); #endif // defined(OPTION_CMDTGT) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); PUTC_CMDLINE (); fill_text (' ',cons_cols); /* restore cursor location */ cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } /* end if(redraw_cmd) */ if (redraw_status && !npquiet) { /* Save cursor location */ saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; memset (buf, ' ', cons_cols); len = sprintf (buf, "CPU%4.4X ", sysblk.pcpu); if (IS_CPU_ONLINE(sysblk.pcpu)) { char ibuf[64]; len += sprintf(buf+len, "PSW=%8.8X%8.8X ", fetch_fw(curpsw), fetch_fw(curpsw+4)); if (regs->arch_mode == ARCH_900) len += sprintf (buf+len, "%16.16"I64_FMT"X ", fetch_dw (curpsw+8)); #if defined(_FEATURE_SIE) else if( SIE_MODE(regs) ) { for(i = 0;i < 16;i++) buf[len++] = '-'; buf[len++] = ' '; } #endif /*defined(_FEATURE_SIE)*/ len += sprintf (buf+len, "%2d%c%c%c%c%c%c%c%c", regs->psw.amode64 ? 64 : regs->psw.amode ? 31 : 24, regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.', sysblk.inststep ? 'T' : '.', WAITSTATE(®s->psw) ? 'W' : '.', regs->loadstate ? 'L' : '.', regs->checkstop ? 'C' : '.', PROBSTATE(®s->psw) ? 'P' : '.', SIE_MODE(regs) ? 'S' : '.', regs->arch_mode == ARCH_900 ? 'Z' : '.'); buf[len++] = ' '; sprintf (ibuf, "instcount=%s", format_int(INSTCOUNT(regs))); if (len + (int)strlen(ibuf) < cons_cols) len = cons_cols - strlen(ibuf); strcpy (buf + len, ibuf); } else { len += sprintf (buf+len,"%s", "Offline"); buf[len++] = ' '; } buf[cons_cols] = '\0'; set_pos (cons_rows, 1); set_color (COLOR_LIGHT_YELLOW, COLOR_RED); draw_text (buf); /* restore cursor location */ cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } /* end if(redraw_status) */ /* Flush screen buffer and reset display update indicators */ if (redraw_msgs || redraw_cmd || redraw_status) { set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); if (NPDup == 0 && NPDinit == 1) { NPDinit = 0; restore_command_line(); set_pos (cur_cons_row, cur_cons_col); } else if (redraw_cmd) set_pos (CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol); else set_pos (cur_cons_row, cur_cons_col); fflush (confp); redraw_msgs = redraw_cmd = redraw_status = 0; } } else { /* (NPDup == 1) */ if (redraw_status || (NPDinit == 0 && NPDup == 1) || (redraw_cmd && NPdataentry == 1)) { if (NPDinit == 0) { NPDinit = 1; NP_screen_redraw(regs); NP_update(regs); fflush (confp); } } /* Update New Panel every panrate interval */ if (!npquiet) { NP_update(regs); fflush (confp); } redraw_msgs = redraw_cmd = redraw_status = 0; } /* =END= */ /* Force full screen repaint if needed */ if (!sysblk.npquiet && npquiet) redraw_msgs = redraw_cmd = redraw_status = 1; npquiet = sysblk.npquiet; } /* end while */ ASSERT( sysblk.shutdown ); // (why else would we be here?!) } /* end function panel_display */ static void panel_cleanup(void *unused) { int i; PANMSG* p; UNREFERENCED(unused); log_wakeup(NULL); set_screen_color( stderr, COLOR_DEFAULT_FG, COLOR_DEFAULT_BG ); clear_screen( stderr ); /* Scroll to last full screen's worth of messages */ scroll_to_bottom_screen( 1 ); /* Display messages in scrolling area */ for (i=0, p = topmsg; i < SCROLL_LINES && p != curmsg->next; i++, p = p->next) { set_pos (i+1, 1); #if defined(OPTION_MSGCLR) set_color (p->fg, p->bg); #else // !defined(OPTION_MSGCLR) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); #endif // defined(OPTION_MSGCLR) write_text (p->msg, MSG_SIZE); } /* Restore the terminal mode */ set_or_reset_console_mode( keybfd, 0 ); /* Position to next line */ fwrite("\n",1,1,stderr); /* Read and display any msgs still remaining in the system log */ while((lmscnt = log_read(&lmsbuf, &lmsnum, LOG_NOBLOCK))) fwrite(lmsbuf,lmscnt,1,stderr); fflush(stderr); } hercules-3.12/history.c0000664000175000017500000001240312564723224012050 00000000000000/* HISTORY.C (c) Copyright Volker Bandke, 2003-2009 */ /* Hercules Command History Processor */ #include "hstdinc.h" #include "hercules.h" #include "history.h" #define HISTORY_MAX 10 #define CMD_SIZE 256 /* 32767 is way toooooo much */ typedef struct history { int number; char *cmdline; struct history *prev; struct history *next; } HISTORY; BYTE history_count; /* for line numbering */ HISTORY *history_lines; /* points to the beginning of history list (oldest command) */ HISTORY *history_lines_end; /* points to the end of history list (most recent command) */ HISTORY *history_ptr; /* points to last command retrieved by key press */ HISTORY *backup; /* used for backuping last removed command */ /* these 2 are used in panel.c to see if there was history command requested and returns that command */ char *historyCmdLine; int history_requested = 0; void copy_to_historyCmdLine(char* cmdline) { if (historyCmdLine) free(historyCmdLine); historyCmdLine = malloc(strlen(cmdline)+1); strcpy(historyCmdLine, cmdline); } /* initialize environment */ int history_init() { history_lines = NULL; history_lines_end = NULL; historyCmdLine = (char *) malloc(255); history_requested = 0; backup = NULL; history_count = 0; history_ptr = NULL; return(0); } /* add commandline to history list */ int history_add(char *cmdline) { HISTORY *tmp; /* if there is some backup line remaining, remove it */ if (backup != NULL) { free(backup->cmdline); free(backup); backup = NULL; } /* If last line is exactly the same as this line ignore and return to caller */ if (history_lines != NULL && !strcmp(cmdline,history_lines_end->cmdline)) { history_ptr = NULL; return 0; } /* allocate space and copy string */ tmp = (HISTORY*) malloc(sizeof(HISTORY)); tmp->cmdline = (char*) malloc(strlen(cmdline) + 1); strcpy(tmp->cmdline, cmdline); tmp->next = NULL; tmp->prev = NULL; tmp->number = ++history_count; if (history_lines == NULL) { /* first in list */ history_lines = tmp; history_lines_end = tmp; } else { tmp->prev = history_lines_end; history_lines_end->next = tmp; history_lines_end = tmp; } history_ptr = NULL; if (history_count > HISTORY_MAX) { /* if we are over maximum number of lines in history list, oldest one should be deleted but we don't know whether history_remove will not be called, so oldest line is backuped and not removed */ backup = history_lines; history_lines = history_lines->next; backup->next = NULL; history_lines->prev = NULL; } return(0); } /* show list of lines in history */ int history_show() { HISTORY *tmp; tmp = history_lines; while (tmp != NULL) { logmsg("%4d %s\n", tmp->number, tmp->cmdline); tmp = tmp->next; } return(0); } /* remove last line from history list (called only when history command was invoked) */ int history_remove() { HISTORY *tmp; if (history_lines == NULL) return(0); if (history_lines == history_lines_end) { ASSERT(history_lines->next == NULL); ASSERT(history_count == 1); free(history_lines->cmdline); free(history_lines); history_lines = NULL; history_lines_end = NULL; history_count--; return(0); } tmp = history_lines_end->prev; tmp->next = NULL; free(history_lines_end->cmdline); free(history_lines_end); history_count--; history_lines_end = tmp; if (backup != NULL) { backup->next = history_lines; history_lines->prev = backup; history_lines = backup; backup = NULL; } return(0); } int history_relative_line(int x) { HISTORY *tmp = history_lines_end; if (-x > HISTORY_MAX) { logmsg("History limited to last %d commands\n", HISTORY_MAX); return (-1); } if (-x > history_count) { logmsg("only %d commands in history\n", history_count); return (-1); } while (x<-1) { tmp = tmp->prev; x++; } copy_to_historyCmdLine(tmp->cmdline); history_ptr = NULL; return(0); } int history_absolute_line(int x) { HISTORY *tmp = history_lines_end; int lowlimit; if (history_count == 0) { logmsg("history empty\n"); return -1; } lowlimit = history_count - HISTORY_MAX; if (x > history_count || x <= lowlimit) { logmsg("only commands %d-%d are in history\n", lowlimit<0? 1 : lowlimit + 1, history_count); return (-1); } while (tmp->number != x) tmp = tmp->prev; copy_to_historyCmdLine(tmp->cmdline); history_ptr = NULL; return(0); } int history_next() { if (history_ptr == NULL) { history_ptr = history_lines_end; if (history_ptr == NULL) return(-1); copy_to_historyCmdLine(history_ptr->cmdline); return(0); } if (history_ptr->next == NULL) history_ptr = history_lines; else history_ptr = history_ptr->next; copy_to_historyCmdLine(history_ptr->cmdline); return(0); } int history_prev() { if (history_ptr == NULL) { history_ptr = history_lines_end; if (history_ptr == NULL) return(-1); copy_to_historyCmdLine(history_ptr->cmdline); return(0); } if (history_ptr->prev == NULL) history_ptr = history_lines_end; else history_ptr = history_ptr->prev; copy_to_historyCmdLine(history_ptr->cmdline); return(0); } hercules-3.12/fillfnam.c0000664000175000017500000001446312564723224012147 00000000000000/* FILLFNAM.C (c) Copyright Volker Bandke, 2003-2006 */ /* Hercules filename completion functions */ #include "hstdinc.h" #include "hercules.h" #include "fillfnam.h" /* On Solaris 2.9 (SunOS 5.9) and earlier, there is no scandir and alphasort function. In this case fillfnam does nothing and the tab command is effectively a no-operation */ #if !(defined(HAVE_SCANDIR) && defined(HAVE_ALPHASORT)) && !defined(_MSVC_) int tab_pressed(char *cmdlinefull, int *cmdoffset) { UNREFERENCED(cmdlinefull); UNREFERENCED(cmdoffset); return 0; } #else char *filterarray; int filter(const struct dirent *ent) { if (filterarray == NULL) return(1); if (strncmp(ent->d_name, filterarray, strlen(filterarray)) == 0) return(1); return(0); } /* tab can be pressed anywhere in the command line, so I have to split command line for example: attach 0a00 3390 volu_ sf=volume1.shadow will be divided part1 = "attach 0a00 " part2 = "volu" part3 = " sf=volume1.shadow" only part2 can be changed and it must be divided into path and filename */ int tab_pressed(char *cmdlinefull, int *cmdoffset) { struct dirent **namelist; int n, i, j, len, len1, len2; int cmdoff = *(cmdoffset); /* for easy reading of source code */ char *part1, *part2, *part3; char *buff; char *filename, *path, *tmp; char result[1024]; char pathname[MAX_PATH]; #ifdef _MSVC_ int within_quoted_string = 0; int quote_pos; #endif /* part3 goes from cursor position to the end of line */ part3 = cmdlinefull + cmdoff; /* looking for ' ','@' or '=' backward, starting from cursor offset I am not aware of any other delimiters which can be used in hercules */ /* (except for '"' (double quote) for the MSVC version of herc - Fish) */ #ifdef _MSVC_ /* determine if tab was pressed within a quoted string */ for (i=0; i < cmdoff; i++) if ('\"' == cmdlinefull[i]) { within_quoted_string = !within_quoted_string; quote_pos = i; /* (save position of quote immediately preceding cmdoff) */ } if (within_quoted_string) i = quote_pos; /* (the quote is our delimiter) */ else #endif for (i = cmdoff-1; i>=0; i--) if (cmdlinefull[i] == ' ' || cmdlinefull[i] == '@' || cmdlinefull[i] == '=') break; /* part1 is from beginning to found delimiter (including delimiter itself) */ part1 = (char*) malloc(i+2); strncpy(part1, cmdlinefull, i+1); part1[i+1]= '\0'; /* part2 is the interesting one */ part2 = (char*)malloc(cmdoff - i); strncpy(part2, cmdlinefull + i + 1, cmdoff - i - 1); part2[cmdoff - i - 1] = '\0'; len = strlen(part2); /* 3 characters minimum needed, for ./\0 in path. */ /* (or 4 chars for MSVC if within quoted string, for \"./\0 - Fish) */ #ifdef _MSVC_ if (within_quoted_string) { if (len < 3) len = 3; } else #endif if (len < 2) len = 2; path = (char*)malloc(len + 1); *path = '\0'; filename = part2; /* is it pure filename or is there whole path ? */ tmp = strrchr(part2, '/'); #ifdef _MSVC_ if (!tmp) tmp = strrchr(part2, '\\'); #endif if (tmp != NULL) { filename = tmp + 1; strncpy(path, part2, strlen(part2)-strlen(filename)); path[strlen(part2)-strlen(filename)] = '\0'; tmp[0] = '\0'; } else { #ifdef _MSVC_ if (within_quoted_string) strcpy(path,"\"./"); else #endif strcpy(path,"./"); } /* this is used in filter function to include only relevant filenames */ filterarray = filename; n = scandir(path, &namelist, filter, alphasort); if (n > 0) { for (i=0; id_name contains filtered filenames, check if they are directories with stat(), before that create whole path */ if (tmp != NULL) sprintf(fullfilename, "%s%s", path, namelist[i]->d_name); else sprintf(fullfilename, "%s", namelist[i]->d_name); #ifdef _MSVC_ if (within_quoted_string) strlcat(fullfilename,"\"",sizeof(fullfilename)); #endif /* if it is a directory, add '/' to the end so it can be seen on screen*/ hostpath(pathname, fullfilename, sizeof(pathname)); if (stat(pathname,&buf) == 0) if (buf.st_mode & S_IFDIR) { // strcat(namelist[i]->d_name,"/"); // Don't write past end of d_name // Problem debugged by bb5ch39t namelist[i] = realloc(namelist[i], sizeof(struct dirent) + strlen(namelist[i]->d_name) + 2); if (namelist[i]) strcat(namelist[i]->d_name,"/"); } } /* now check, if filenames have something in common, after a cycle buff contains maximal intersection of names */ buff = (char*)malloc(strlen(namelist[0]->d_name) + 1); /* first one */ strcpy(buff, namelist[0]->d_name); for (i = 1; i < n; i++) { len1 = strlen(buff); len2 = strlen(namelist[i]->d_name); /* check number of characters in shorter one */ len = len1 > len2 ? len2 : len1; for (j = 0; j < len; j++) if (buff[j] != namelist[i]->d_name[j]) { buff[j] = '\0'; /* end the string where characters are not equal */ break; } } /* if maximal intersection of filenames is longer then original filename */ if (strlen(buff) > strlen(filename)) { char *fullfilename; fullfilename = (char*)malloc(strlen(path) + strlen(buff) + 1); /* this test is not useless as path contains './' if there was no path in original filename. it is because of scandir function, which needs path portion */ if (tmp != NULL) sprintf(fullfilename, "%s%s", path, buff); else sprintf(fullfilename, "%s", buff); /* construct command line */ sprintf(result, "%s%s%s", part1, fullfilename, part3); /* move cursor */ *(cmdoffset) = strlen(part1) + strlen(fullfilename); strcpy(cmdlinefull, result); free(fullfilename); } else { /* display all alternatives */ for (i = 0; i< n; i++) logmsg("%s\n", namelist[i]->d_name); } /* free everything */ free(buff); for (i = 0; i< n; i++) free(namelist[i]); free(namelist); } free(part1); free(part2); free(path); return(0); } #endif /*(HAVE_SCANDIR && HAVE_ALPHASORT) || _MSVC_*/ hercules-3.12/ipl.c0000664000175000017500000005036512564723224011144 00000000000000/* IPL.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Initial Program Loader */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements the Initial Program Load (IPL) function of */ /* the S/370, ESA/390 and z/Architectures, described in the manuals: */ /* */ /* GA22-7000 System/370 Principles of Operation */ /* SA22-7201 ESA/390 Principles of Operation */ /* SA22-7832 z/Architecture Principles of Operation. */ /* */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _IPL_C #define _HENGINE_DLL_ #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(OPTION_FISHIO) #include "w32chan.h" #endif // defined(OPTION_FISHIO) #if defined(_FEATURE_MESSAGE_SECURITY_ASSIST) #include "hexterns.h" #endif /*-------------------------------------------------------------------*/ /* Function to perform System Reset (either 'normal' or 'clear') */ /*-------------------------------------------------------------------*/ int ARCH_DEP(system_reset) (int cpu, int clear) { int rc = 0; REGS *regs; /* Configure the cpu if it is not online */ if (!IS_CPU_ONLINE(cpu)) { if (configure_cpu(cpu) != 0) { /* ZZ FIXME: we should probably present a machine-check if we encounter any errors during the reset (rc != 0) */ return -1; } ASSERT(IS_CPU_ONLINE(cpu)); } regs = sysblk.regs[cpu]; HDC1(debug_cpu_state, regs); /* Perform system-reset-normal or system-reset-clear function */ if (!clear) { /* Reset external interrupts */ OFF_IC_SERVSIG; OFF_IC_INTKEY; /* Reset all CPUs in the configuration */ for (cpu = 0; cpu < MAX_CPU; cpu++) if (IS_CPU_ONLINE(cpu)) if (ARCH_DEP(cpu_reset) (sysblk.regs[cpu])) rc = -1; /* Perform I/O subsystem reset */ io_reset (); } else { /* Reset external interrupts */ OFF_IC_SERVSIG; OFF_IC_INTKEY; /* Reset all CPUs in the configuration */ for (cpu = 0; cpu < MAX_CPU; cpu++) { if (IS_CPU_ONLINE(cpu)) { regs=sysblk.regs[cpu]; if (ARCH_DEP(initial_cpu_reset) (regs)) { rc = -1; } /* Clear all the registers (AR, GPR, FPR, VR) as part of the CPU CLEAR RESET operation */ memset (regs->ar,0,sizeof(regs->ar)); memset (regs->gr,0,sizeof(regs->gr)); memset (regs->fpr,0,sizeof(regs->fpr)); #if defined(_FEATURE_VECTOR_FACILITY) memset (regs->vf->vr,0,sizeof(regs->vf->vr)); #endif /*defined(_FEATURE_VECTOR_FACILITY)*/ } } /* Perform I/O subsystem reset */ io_reset (); #if defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY) /* Clear the program-parameter register */ sysblk.program_parameter = 0; #endif /*defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY)*/ /* Clear storage */ sysblk.main_clear = sysblk.xpnd_clear = 0; storage_clear(); xstorage_clear(); } #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) /* Set horizontal polarization */ sysblk.topology = TOPOLOGY_HORIZ; /* Clear topology-change-report-pending condition */ sysblk.topchnge = 0; #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ /* ZZ FIXME: we should probably present a machine-check if we encounter any errors during the reset (rc != 0) */ return rc; } /* end function system_reset */ /*-------------------------------------------------------------------*/ /* LOAD (aka IPL) functions... */ /*-------------------------------------------------------------------*/ /* Performing an Initial Program Load (aka IPL) involves three */ /* distinct phases: in phase 1 the system is reset (registers */ /* and, for load-clear, storage), and in phase two the actual */ /* Initial Program Loading from the IPL device takes place. Finally,*/ /* in phase three, the IPL PSW is loaded and the CPU is started. */ /*-------------------------------------------------------------------*/ int orig_arch_mode; /* Saved architecture mode */ PSW captured_zpsw; /* Captured z/Arch PSW */ /*-------------------------------------------------------------------*/ /* Common LOAD (IPL) begin: system-reset (register/storage clearing) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(common_load_begin) (int cpu, int clear) { REGS *regs; /* Save the original architecture mode for later */ orig_arch_mode = sysblk.dummyregs.arch_mode = sysblk.arch_mode; #if defined(OPTION_FISHIO) ios_arch_mode = sysblk.arch_mode; #endif // defined(OPTION_FISHIO) /* Perform system-reset-normal or system-reset-clear function */ if (ARCH_DEP(system_reset(cpu,clear)) != 0) return -1; regs = sysblk.regs[cpu]; if (sysblk.arch_mode == ARCH_900) { /* Switch architecture mode to ESA390 mode for z/Arch IPL */ sysblk.arch_mode = ARCH_390; /* Capture the z/Arch PSW if this is a Load-normal IPL */ if (!clear) captured_zpsw = regs->psw; } /* Load-clear does a clear-reset (which does an initial-cpu-reset) on all cpus in the configuration, but Load-normal does an initial- cpu-reset only for the IPL CPU and a regular cpu-reset for all other CPUs in the configuration. Thus if the above system_reset call did a system-normal-reset for us, then we need to manually do a clear-reset (initial-cpu-reset) on the IPL CPU... */ if (!clear) { /* Perform initial reset on the IPL CPU */ if (ARCH_DEP(initial_cpu_reset) (regs) != 0) return -1; /* Save our captured-z/Arch-PSW if this is a Load-normal IPL since the initial_cpu_reset call cleared it to zero. */ if (orig_arch_mode == ARCH_900) regs->captured_zpsw = captured_zpsw; } /* The actual IPL (load) now begins... */ regs->loadstate = 1; return 0; } /* end function common_load_begin */ /*-------------------------------------------------------------------*/ /* Function to run initial CCW chain from IPL device and load IPLPSW */ /* Returns 0 if successful, -1 if error */ /* intlock MUST be held on entry */ /*-------------------------------------------------------------------*/ int ARCH_DEP(load_ipl) (U16 lcss, U16 devnum, int cpu, int clear) { REGS *regs; /* -> Regs */ DEVBLK *dev; /* -> Device control block */ int i; /* Array subscript */ BYTE unitstat; /* IPL device unit status */ BYTE chanstat; /* IPL device channel status */ /* Get started */ if (ARCH_DEP(common_load_begin) (cpu, clear) != 0) return -1; /* The actual IPL proper starts here... */ regs = sysblk.regs[cpu]; /* Point to IPL CPU's registers */ /* Point to the device block for the IPL device */ dev = find_device_by_devnum (lcss,devnum); if (dev == NULL) { logmsg (_("HHCCP027E Device %4.4X not in configuration%s\n"), devnum, (sysblk.arch_mode == ARCH_370 ? " or not conneceted to channelset" : "")); HDC1(debug_cpu_state, regs); return -1; } #if defined(OPTION_IPLPARM) if(sysblk.haveiplparm) { for(i=0;i<16;i++) { regs->GR_L(i)=fetch_fw(&sysblk.iplparmstring[i*4]); } sysblk.haveiplparm=0; } #endif /* Set Main Storage Reference and Update bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); sysblk.main_clear = sysblk.xpnd_clear = 0; /* Build the IPL CCW at location 0 */ regs->psa->iplpsw[0] = 0x02; /* CCW command = Read */ regs->psa->iplpsw[1] = 0; /* Data address = zero */ regs->psa->iplpsw[2] = 0; regs->psa->iplpsw[3] = 0; regs->psa->iplpsw[4] = CCW_FLAGS_CC | CCW_FLAGS_SLI; /* CCW flags */ regs->psa->iplpsw[5] = 0; /* Reserved byte */ regs->psa->iplpsw[6] = 0; /* Byte count = 24 */ regs->psa->iplpsw[7] = 24; /* Enable the subchannel for the IPL device */ dev->pmcw.flag5 |= PMCW5_E; /* Build the operation request block */ /*@IWZ*/ memset (&dev->orb, 0, sizeof(ORB)); /*@IWZ*/ dev->busy = 1; RELEASE_INTLOCK(NULL); /* Execute the IPL channel program */ ARCH_DEP(execute_ccw_chain) (dev); OBTAIN_INTLOCK(NULL); /* Clear the interrupt pending and device busy conditions */ obtain_lock (&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->attnioint); release_lock(&sysblk.iointqlk); dev->busy = 0; dev->scsw.flag2 = 0; dev->scsw.flag3 = 0; /* Check that load completed normally */ #ifdef FEATURE_S370_CHANNEL unitstat = dev->csw[4]; chanstat = dev->csw[5]; #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM unitstat = dev->scsw.unitstat; chanstat = dev->scsw.chanstat; #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) { logmsg (_("HHCCP029E %s mode IPL failed: CSW status=%2.2X%2.2X\n" " Sense="), get_arch_mode_string(regs), unitstat, chanstat); for (i=0; i < (int)dev->numsense; i++) { logmsg ("%2.2X", dev->sense[i]); if ((i & 3) == 3) logmsg(" "); } logmsg ("\n"); HDC1(debug_cpu_state, regs); return -1; } #ifdef FEATURE_S370_CHANNEL /* Test the EC mode bit in the IPL PSW */ if (regs->psa->iplpsw[1] & 0x08) { /* In EC mode, store device address at locations 184-187 */ STORE_FW(regs->psa->ioid, dev->devnum); } else { /* In BC mode, store device address at locations 2-3 */ STORE_HW(regs->psa->iplpsw + 2, dev->devnum); } #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Set LPUM */ dev->pmcw.lpum = 0x80; STORE_FW(regs->psa->ioid, (dev->ssid<<16)|dev->subchan); /* Store zeroes at locations 188-191 */ memset (regs->psa->ioparm, 0, 4); #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Save IPL device number, cpu number and lcss */ sysblk.ipldev = devnum; sysblk.iplcpu = regs->cpuad; sysblk.ipllcss = lcss; /* Finish up... */ return ARCH_DEP(common_load_finish) (regs); } /* end function load_ipl */ /*-------------------------------------------------------------------*/ /* Common LOAD (IPL) finish: load IPL PSW and start CPU */ /*-------------------------------------------------------------------*/ int ARCH_DEP(common_load_finish) (REGS *regs) { /* Zeroize the interrupt code in the PSW */ regs->psw.intcode = 0; /* Load IPL PSW from PSA+X'0' */ if (ARCH_DEP(load_psw) (regs, regs->psa->iplpsw) != 0) { logmsg (_("HHCCP030E %s mode IPL failed: Invalid IPL PSW: " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n"), get_arch_mode_string(regs), regs->psa->iplpsw[0], regs->psa->iplpsw[1], regs->psa->iplpsw[2], regs->psa->iplpsw[3], regs->psa->iplpsw[4], regs->psa->iplpsw[5], regs->psa->iplpsw[6], regs->psa->iplpsw[7]); HDC1(debug_cpu_state, regs); return -1; } /* Set the CPU into the started state */ regs->opinterv = 0; regs->cpustate = CPUSTATE_STARTED; /* The actual IPL (load) is now completed... */ regs->loadstate = 0; /* Signal the CPU to retest stopped indicator */ WAKEUP_CPU (regs); HDC1(debug_cpu_state, regs); return 0; } /* end function common_load_finish */ /*-------------------------------------------------------------------*/ /* Function to perform CPU Reset */ /*-------------------------------------------------------------------*/ int ARCH_DEP(cpu_reset) (REGS *regs) { int i; /* Array subscript */ regs->ip = regs->inst; /* Clear indicators */ regs->loadstate = 0; regs->checkstop = 0; regs->sigpreset = 0; regs->extccpu = 0; for (i = 0; i < MAX_CPU; i++) regs->emercpu[i] = 0; regs->instinvalid = 1; regs->instcount = regs->prevcount = 0; /* Clear interrupts */ SET_IC_INITIAL_MASK(regs); SET_IC_INITIAL_STATE(regs); /* Clear the translation exception identification */ regs->EA_G = 0; regs->excarid = 0; /* Clear monitor code */ regs->MC_G = 0; /* Purge the lookaside buffers */ ARCH_DEP(purge_tlb) (regs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (regs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ if(regs->host) { /* Put the CPU into the stopped state */ regs->opinterv = 0; regs->cpustate = CPUSTATE_STOPPED; ON_IC_INTERRUPT(regs); } #ifdef FEATURE_INTERVAL_TIMER ARCH_DEP(store_int_timer_nolock) (regs); #endif if(regs->host && regs->guestregs) { ARCH_DEP(cpu_reset)(regs->guestregs); /* CPU state of SIE copy cannot be controlled */ regs->guestregs->opinterv = 0; regs->guestregs->cpustate = CPUSTATE_STARTED; } return 0; } /* end function cpu_reset */ /*-------------------------------------------------------------------*/ /* Function to perform Initial CPU Reset */ /*-------------------------------------------------------------------*/ int ARCH_DEP(initial_cpu_reset) (REGS *regs) { /* Clear reset pending indicators */ regs->sigpireset = regs->sigpreset = 0; /* Clear the registers */ memset ( ®s->psw, 0, sizeof(regs->psw) ); memset ( ®s->captured_zpsw, 0, sizeof(regs->captured_zpsw) ); memset ( regs->cr, 0, sizeof(regs->cr) ); regs->fpc = 0; regs->PX = 0; regs->psw.AMASK_G = AMASK24; /* * ISW20060125 : Since we reset the prefix, we must also adjust * the PSA ptr */ regs->psa = (PSA_3XX *)regs->mainstor; /* Perform a CPU reset (after setting PSA) */ ARCH_DEP(cpu_reset) (regs); regs->todpr = 0; regs->clkc = 0; set_cpu_timer(regs, 0); #ifdef _FEATURE_INTERVAL_TIMER set_int_timer(regs, 0); #endif /* The breaking event address register is initialised to 1 */ regs->bear = 1; /* Initialize external interrupt masks in control register 0 */ regs->CR(0) = CR0_XM_ITIMER | CR0_XM_INTKEY | CR0_XM_EXTSIG; #ifdef FEATURE_S370_CHANNEL /* For S/370 initialize the channel masks in CR2 */ regs->CR(2) = 0xFFFFFFFF; #endif /*FEATURE_S370_CHANNEL*/ regs->chanset = #if defined(FEATURE_CHANNEL_SWITCHING) regs->cpuad < FEATURE_LCSS_MAX ? regs->cpuad : #endif /*defined(FEATURE_CHANNEL_SWITCHING)*/ 0xFFFF; /* Initialize the machine check masks in control register 14 */ regs->CR(14) = CR14_CHKSTOP | CR14_SYNCMCEL | CR14_XDMGRPT; #ifndef FEATURE_LINKAGE_STACK /* For S/370 initialize the MCEL address in CR15 */ regs->CR(15) = 512; #endif /*!FEATURE_LINKAGE_STACK*/ if(regs->host && regs->guestregs) ARCH_DEP(initial_cpu_reset)(regs->guestregs); #if defined(_FEATURE_MESSAGE_SECURITY_ASSIST) renew_wrapping_keys(); #endif /*defined(_FEATURE_MESSAGE_SECURITY_ASSIST)*/ return 0; } /* end function initial_cpu_reset */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "ipl.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "ipl.c" #endif /*********************************************************************/ /* Externally Initiated Functions... */ /*********************************************************************/ /*-------------------------------------------------------------------*/ /* Load / IPL (Load Normal -or- Load Clear) */ /*-------------------------------------------------------------------*/ int load_ipl (U16 lcss, U16 devnum, int cpu, int clear) { switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: return s370_load_ipl (lcss, devnum, cpu, clear); #endif #if defined(_390) case ARCH_390: return s390_load_ipl (lcss, devnum, cpu, clear); #endif #if defined(_900) case ARCH_900: /* z/Arch always starts out in ESA390 mode */ return s390_load_ipl (lcss, devnum, cpu, clear); #endif } return -1; } /*-------------------------------------------------------------------*/ /* Initial CPU Reset */ /*-------------------------------------------------------------------*/ int initial_cpu_reset (REGS *regs) { int rc = -1; switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: rc = s370_initial_cpu_reset (regs); break; #endif #if defined(_390) case ARCH_390: rc = s390_initial_cpu_reset (regs); break; #endif #if defined(_900) case ARCH_900: /* z/Arch always starts out in ESA390 mode */ rc = s390_initial_cpu_reset (regs); break; #endif } regs->arch_mode = sysblk.arch_mode; return rc; } /*-------------------------------------------------------------------*/ /* System Reset ( Normal reset or Clear reset ) */ /*-------------------------------------------------------------------*/ int system_reset (int cpu, int clear) { switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: return s370_system_reset (cpu, clear); #endif #if defined(_390) case ARCH_390: return s390_system_reset (cpu, clear); #endif #if defined(_900) case ARCH_900: /* z/Arch always starts out in ESA390 mode */ return s390_system_reset (cpu, clear); #endif } return -1; } /*-------------------------------------------------------------------*/ /* ordinary CPU Reset (no clearing takes place) */ /*-------------------------------------------------------------------*/ int cpu_reset (REGS *regs) { switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: return s370_cpu_reset (regs); #endif #if defined(_390) case ARCH_390: return s390_cpu_reset (regs); #endif #if defined(_900) case ARCH_900: /* z/Arch always starts out in ESA390 mode */ return s390_cpu_reset (regs); #endif } return -1; } /*-------------------------------------------------------------------*/ /* Function to clear main storage */ /*-------------------------------------------------------------------*/ void storage_clear() { if (!sysblk.main_clear) { memset(sysblk.mainstor,0,sysblk.mainsize); memset(sysblk.storkeys,0,sysblk.mainsize / STORAGE_KEY_UNITSIZE); sysblk.main_clear = 1; } } /*-------------------------------------------------------------------*/ /* Function to clear expanded storage */ /*-------------------------------------------------------------------*/ void xstorage_clear() { if(sysblk.xpndsize && !sysblk.xpnd_clear) { memset(sysblk.xpndstor,0,(size_t)sysblk.xpndsize * XSTORE_PAGESIZE); sysblk.xpnd_clear = 1; } } #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/assist.c0000664000175000017500000005711512564723224011666 00000000000000/* ASSIST.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 MVS Assist Routines */ /*-------------------------------------------------------------------*/ /* This module contains routines which process the MVS Assist */ /* instructions described in the manual GA22-7079-01. */ /*-------------------------------------------------------------------*/ /* Instruction decode rework - Jan Jaeger */ /* Correct address wraparound - Jan Jaeger */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /* Add dummy assist instruction - Jay Maynard, */ /* suggested by Brandon Hill */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_ASSIST_C_) #define _ASSIST_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if !defined(_ASSIST_C) #define _ASSIST_C /*-------------------------------------------------------------------*/ /* Control block offsets fixed by architecture */ /*-------------------------------------------------------------------*/ /* Prefixed storage area offsets */ #define PSALCPUA 0x2F4 /* Logical CPU address */ #define PSAHLHI 0x2F8 /* Locks held indicators */ /* Bit settings for PSAHLHI */ #define PSACMSLI 0x00000002 /* CMS lock held indicator */ #define PSALCLLI 0x00000001 /* Local lock held indicator */ /* Address space control block offsets */ #define ASCBLOCK 0x080 /* Local lock */ #define ASCBLSWQ 0x084 /* Local lock suspend queue */ /* Lock interface table offsets */ #define LITOLOC (-16) /* Obtain local error exit */ #define LITRLOC (-12) /* Release local error exit */ #define LITOCMS (-8) /* Obtain CMS error exit */ #define LITRCMS (-4) /* Release CMS error exit */ #endif /*!defined(_ASSIST_C)*/ #if !defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E502 - Page Fix [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(fix_page) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); PTT(PTT_CL_ERR,"*E502 PGFIX",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE*/ } #endif /*!defined(FEATURE_S390_DAT) && !defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* E503 - SVC assist [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(svc_assist) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); PTT(PTT_CL_ERR,"*E503 SVCA",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE: NO ACTION IS TAKEN, THE SVC IS UNASSISTED AND MVS WILL HAVE TO HANDLE THE SITUATION*/ } /*-------------------------------------------------------------------*/ /* E504 - Obtain Local Lock [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(obtain_local_lock) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ VADR ascb_addr; /* Virtual address of ASCB */ VADR lock_addr; /* Virtual addr of ASCBLOCK */ U32 hlhi_word; /* Highest lock held word */ VADR lit_addr; /* Virtual address of lock interface table */ U32 lock; /* Lock value */ U32 lcpa; /* Logical CPU address */ VADR newia; /* Unsuccessful branch addr */ int acc_mode = 0; /* access mode to use */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PERFORM_SERIALIZATION(regs); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); if (ACCESS_REGISTER_MODE(®s->psw)) acc_mode = USE_PRIMARY_SPACE; /* Load ASCB address from first operand location */ ascb_addr = ARCH_DEP(vfetch4) ( effective_addr1, acc_mode, regs ); /* Load locks held bits from second operand location */ hlhi_word = ARCH_DEP(vfetch4) ( effective_addr2, acc_mode, regs ); /* Fetch our logical CPU address from PSALCPUA */ lcpa = ARCH_DEP(vfetch4) ( effective_addr2 - 4, acc_mode, regs ); lock_addr = (ascb_addr + ASCBLOCK) & ADDRESS_MAXWRAP(regs); /* Fetch the local lock from the ASCB */ lock = ARCH_DEP(vfetch4) ( lock_addr, acc_mode, regs ); /* Obtain the local lock if not already held by any CPU */ if (lock == 0 && (hlhi_word & PSALCLLI) == 0) { /* Store the unchanged value into the second operand to ensure suppression in the event of an access exception */ ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Store our logical CPU address in ASCBLOCK */ ARCH_DEP(vstore4) ( lcpa, lock_addr, acc_mode, regs ); /* Set the local lock held bit in the second operand */ hlhi_word |= PSALCLLI; ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Set register 13 to zero to indicate lock obtained */ regs->GR_L(13) = 0; } else { /* Fetch the lock interface table address from the second word of the second operand, and load the new instruction address and amode from LITOLOC */ lit_addr = ARCH_DEP(vfetch4) ( effective_addr2 + 4, acc_mode, regs ) + LITOLOC; lit_addr &= ADDRESS_MAXWRAP(regs); newia = ARCH_DEP(vfetch4) ( lit_addr, acc_mode, regs ); /* Save the link information in register 12 */ regs->GR_L(12) = PSW_IA(regs, 0); /* Copy LITOLOC into register 13 to signify obtain failure */ regs->GR_L(13) = newia; /* Update the PSW instruction address */ UPD_PSW_IA(regs, newia); } /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); PERFORM_SERIALIZATION(regs); } /* end function obtain_local_lock */ /*-------------------------------------------------------------------*/ /* E505 - Release Local Lock [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(release_local_lock) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ VADR ascb_addr; /* Virtual address of ASCB */ VADR lock_addr; /* Virtual addr of ASCBLOCK */ VADR susp_addr; /* Virtual addr of ASCBLSWQ */ U32 hlhi_word; /* Highest lock held word */ VADR lit_addr; /* Virtual address of lock interface table */ U32 lock; /* Lock value */ U32 susp; /* Lock suspend queue */ U32 lcpa; /* Logical CPU address */ VADR newia; /* Unsuccessful branch addr */ int acc_mode = 0; /* access mode to use */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); if (ACCESS_REGISTER_MODE(®s->psw)) acc_mode = USE_PRIMARY_SPACE; /* Load ASCB address from first operand location */ ascb_addr = ARCH_DEP(vfetch4) ( effective_addr1, acc_mode, regs ); /* Load locks held bits from second operand location */ hlhi_word = ARCH_DEP(vfetch4) ( effective_addr2, acc_mode, regs ); /* Fetch our logical CPU address from PSALCPUA */ lcpa = ARCH_DEP(vfetch4) ( effective_addr2 - 4, acc_mode, regs ); /* Fetch the local lock and the suspend queue from the ASCB */ lock_addr = (ascb_addr + ASCBLOCK) & ADDRESS_MAXWRAP(regs); susp_addr = (ascb_addr + ASCBLSWQ) & ADDRESS_MAXWRAP(regs); lock = ARCH_DEP(vfetch4) ( lock_addr, acc_mode, regs ); susp = ARCH_DEP(vfetch4) ( susp_addr, acc_mode, regs ); /* Test if this CPU holds the local lock, and does not hold any CMS lock, and the local lock suspend queue is empty */ if (lock == lcpa && (hlhi_word & (PSALCLLI | PSACMSLI)) == PSALCLLI && susp == 0) { /* Store the unchanged value into the second operand to ensure suppression in the event of an access exception */ ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Set the local lock to zero */ ARCH_DEP(vstore4) ( 0, lock_addr, acc_mode, regs ); /* Clear the local lock held bit in the second operand */ hlhi_word &= ~PSALCLLI; ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Set register 13 to zero to indicate lock released */ regs->GR_L(13) = 0; } else { /* Fetch the lock interface table address from the second word of the second operand, and load the new instruction address and amode from LITRLOC */ lit_addr = ARCH_DEP(vfetch4) ( effective_addr2 + 4, acc_mode, regs ) + LITRLOC; lit_addr &= ADDRESS_MAXWRAP(regs); newia = ARCH_DEP(vfetch4) ( lit_addr, acc_mode, regs ); /* Save the link information in register 12 */ regs->GR_L(12) = PSW_IA(regs, 0); /* Copy LITRLOC into register 13 to signify release failure */ regs->GR_L(13) = newia; /* Update the PSW instruction address */ UPD_PSW_IA(regs, newia); } /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); } /* end function release_local_lock */ /*-------------------------------------------------------------------*/ /* E506 - Obtain CMS Lock [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(obtain_cms_lock) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ VADR ascb_addr; /* Virtual address of ASCB */ U32 hlhi_word; /* Highest lock held word */ VADR lit_addr; /* Virtual address of lock interface table */ VADR lock_addr; /* Lock address */ int lock_arn; /* Lock access register */ U32 lock; /* Lock value */ VADR newia; /* Unsuccessful branch addr */ int acc_mode = 0; /* access mode to use */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PERFORM_SERIALIZATION(regs); /* General register 11 contains the lock address */ lock_addr = regs->GR_L(11) & ADDRESS_MAXWRAP(regs); lock_arn = 11; /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); if (ACCESS_REGISTER_MODE(®s->psw)) acc_mode = USE_PRIMARY_SPACE; /* Load ASCB address from first operand location */ ascb_addr = ARCH_DEP(vfetch4) ( effective_addr1, acc_mode, regs ); /* Load locks held bits from second operand location */ hlhi_word = ARCH_DEP(vfetch4) ( effective_addr2, acc_mode, regs ); /* Fetch the lock addressed by general register 11 */ lock = ARCH_DEP(vfetch4) ( lock_addr, acc_mode, regs ); /* Obtain the lock if not held by any ASCB, and if this CPU holds the local lock and does not hold a CMS lock */ if (lock == 0 && (hlhi_word & (PSALCLLI | PSACMSLI)) == PSALCLLI) { /* Store the unchanged value into the second operand to ensure suppression in the event of an access exception */ ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Store the ASCB address in the CMS lock */ ARCH_DEP(vstore4) ( ascb_addr, lock_addr, acc_mode, regs ); /* Set the CMS lock held bit in the second operand */ hlhi_word |= PSACMSLI; ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Set register 13 to zero to indicate lock obtained */ regs->GR_L(13) = 0; } else { /* Fetch the lock interface table address from the second word of the second operand, and load the new instruction address and amode from LITOCMS */ lit_addr = ARCH_DEP(vfetch4) ( effective_addr2 + 4, acc_mode, regs ) + LITOCMS; lit_addr &= ADDRESS_MAXWRAP(regs); newia = ARCH_DEP(vfetch4) ( lit_addr, acc_mode, regs ); /* Save the link information in register 12 */ regs->GR_L(12) = PSW_IA(regs, 0); /* Copy LITOCMS into register 13 to signify obtain failure */ regs->GR_L(13) = newia; /* Update the PSW instruction address */ UPD_PSW_IA(regs, newia); } /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); PERFORM_SERIALIZATION(regs); } /* end function obtain_cms_lock */ /*-------------------------------------------------------------------*/ /* E507 - Release CMS Lock [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(release_cms_lock) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ VADR ascb_addr; /* Virtual address of ASCB */ U32 hlhi_word; /* Highest lock held word */ VADR lit_addr; /* Virtual address of lock interface table */ VADR lock_addr; /* Lock address */ int lock_arn; /* Lock access register */ U32 lock; /* Lock value */ U32 susp; /* Lock suspend queue */ VADR newia; /* Unsuccessful branch addr */ int acc_mode = 0; /* access mode to use */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* General register 11 contains the lock address */ lock_addr = regs->GR_L(11) & ADDRESS_MAXWRAP(regs); lock_arn = 11; /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); if (ACCESS_REGISTER_MODE(®s->psw)) acc_mode = USE_PRIMARY_SPACE; /* Load ASCB address from first operand location */ ascb_addr = ARCH_DEP(vfetch4) ( effective_addr1, acc_mode, regs ); /* Load locks held bits from second operand location */ hlhi_word = ARCH_DEP(vfetch4) ( effective_addr2, acc_mode, regs ); /* Fetch the CMS lock and the suspend queue word */ lock = ARCH_DEP(vfetch4) ( lock_addr, acc_mode, regs ); susp = ARCH_DEP(vfetch4) ( lock_addr + 4, acc_mode, regs ); /* Test if current ASCB holds this lock, the locks held indicators show a CMS lock is held, and the lock suspend queue is empty */ if (lock == ascb_addr && (hlhi_word & PSACMSLI) && susp == 0) { /* Store the unchanged value into the second operand to ensure suppression in the event of an access exception */ ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Set the CMS lock to zero */ ARCH_DEP(vstore4) ( 0, lock_addr, acc_mode, regs ); /* Clear the CMS lock held bit in the second operand */ hlhi_word &= ~PSACMSLI; ARCH_DEP(vstore4) ( hlhi_word, effective_addr2, acc_mode, regs ); /* Set register 13 to zero to indicate lock released */ regs->GR_L(13) = 0; } else { /* Fetch the lock interface table address from the second word of the second operand, and load the new instruction address and amode from LITRCMS */ lit_addr = ARCH_DEP(vfetch4) ( effective_addr2 + 4, acc_mode, regs ) + LITRCMS; lit_addr &= ADDRESS_MAXWRAP(regs); newia = ARCH_DEP(vfetch4) ( lit_addr, acc_mode, regs ); /* Save the link information in register 12 */ regs->GR_L(12) = PSW_IA(regs, 0); /* Copy LITRCMS into register 13 to signify release failure */ regs->GR_L(13) = newia; /* Update the PSW instruction address */ UPD_PSW_IA(regs, newia); } /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); } /* end function release_cms_lock */ #if !defined(FEATURE_TRACING) /*-------------------------------------------------------------------*/ /* E508 - Trace SVC Interruption [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(trace_svc_interruption) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PTT(PTT_CL_ERR,"*E508 TRSVC",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE: NO TRACE ENTRY IS GENERATED*/ } /*-------------------------------------------------------------------*/ /* E509 - Trace Program Interruption [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(trace_program_interruption) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PTT(PTT_CL_ERR,"*E509 TRPGM",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE: NO TRACE ENTRY IS GENERATED*/ } /*-------------------------------------------------------------------*/ /* E50A - Trace Initial SRB Dispatch [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(trace_initial_srb_dispatch) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PTT(PTT_CL_ERR,"*E50A TRSRB",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE: NO TRACE ENTRY IS GENERATED*/ } /*-------------------------------------------------------------------*/ /* E50B - Trace I/O Interruption [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(trace_io_interruption) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PTT(PTT_CL_ERR,"*E50B TRIO",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE: NO TRACE ENTRY IS GENERATED*/ } /*-------------------------------------------------------------------*/ /* E50C - Trace Task Dispatch [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(trace_task_dispatch) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PTT(PTT_CL_ERR,"*E50C TRTSK",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE: NO TRACE ENTRY IS GENERATED*/ } /*-------------------------------------------------------------------*/ /* E50D - Trace SVC Return [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(trace_svc_return) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); /* Specification exception if operands are not on word boundary */ if ((effective_addr1 & 0x00000003) || (effective_addr2 & 0x00000003)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); PTT(PTT_CL_ERR,"*E50D TRRTN",effective_addr1,effective_addr2,regs->psw.IA_L); /*INCOMPLETE: NO TRACE ENTRY IS GENERATED*/ } #endif /*!defined(FEATURE_TRACING)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "assist.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "assist.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/dat.c0000664000175000017500000000130612564723224011117 00000000000000/* DAT.C (c) Copyright Roger Bowler, 1999-2012 */ /* Hercules Supported DAT Functions */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #include "hstdinc.h" #include "hercules.h" #if defined(OPTION_NO_INLINE_DAT) || defined(OPTION_NO_INLINE_LOGICAL) #define _DAT_C #include "opcode.h" #include "inline.h" #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "dat.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "dat.c" #endif #endif /*!defined(_GEN_ARCH)*/ #endif /*!defined(OPTION_NO_INLINE_DAT) || defined(OPTION_NO_INLINE_LOGICAL)*/ hercules-3.12/stack.c0000664000175000017500000016003512564723224011461 00000000000000/* STACK.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Linkage Stack Operations */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements the linkage stack functions of ESA/390 */ /* described in SA22-7201-04 ESA/390 Principles of Operation. */ /* The numbers in square brackets refer to sections in the manual. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Fix CR15 corruption in form_stack_entry Jan Jaeger */ /* Fix nullification in form_stack_entry Jan Jaeger */ /* Fix nullification in unstack_registers Jan Jaeger */ /* Modifications for Interpretive Execution (SIE) Jan Jaeger */ /* ESAME low-address protection v208d Roger Bowler */ /* ESAME linkage stack operations v208e Roger Bowler */ /* TRAP support added Jan Jaeger */ /* Correction to stack types in ESAME mode Jan Jaeger */ /* ASN-and-LX-reuse facility June 2004 Roger Bowler */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" // #define STACK_DEBUG #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_STACK_C_) #define _STACK_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" /*-------------------------------------------------------------------*/ /* Linkage stack macro definitions */ /*-------------------------------------------------------------------*/ #undef CR15_LSEA #undef LSEA_WRAP #undef LSSE_SIZE #undef LSSE_REGSIZE #undef FETCH_BSEA #undef STORE_BSEA #undef LSHE_BSEA #undef LSHE_RESV #undef LSHE_BVALID #undef FETCH_FSHA #undef LSTE_FSHA #undef LSTE_RESV #undef LSTE_FVALID #if defined(FEATURE_ESAME) #define CR15_LSEA CR15_LSEA_900 /* Bit mask for ESAME linkage stack entry addr in CR15 */ #define LSEA_WRAP(_lsea) /* No address wrap for ESAME */ #define LSSE_SIZE 296 /* Size of an ESAME linkage stack state entry */ #define LSSE_REGSIZE 8 /* Size of a general register in ESAME state entry */ /* ESAME linkage stack header entry */ /* LSHE words 1 and 2 contain the backward stack entry address */ #define FETCH_BSEA(_bsea,_lshe) FETCH_DW(_bsea,_lshe) #define STORE_BSEA(_lshe,_bsea) STORE_DW(_lshe,_bsea) #define LSHE_BSEA 0xFFFFFFFFFFFFFFF8ULL /* Backward address */ #define LSHE_RESV 0x06 /* Reserved bits - must be 0 */ #define LSHE_BVALID 0x01 /* Backward address is valid */ /* LSHE words 2 and 3 contain a linkage stack entry descriptor */ /* ESAME linkage stack trailer entry */ /* LSTE words 1 and 2 contain the forward section header address */ #define FETCH_FSHA(_fsha,_lste) FETCH_DW(_fsha,_lste) #define LSTE_FSHA 0xFFFFFFFFFFFFFFF8ULL /* Forward address */ #define LSTE_RESV 0x06 /* Reserved bits - must be 0 */ #define LSTE_FVALID 0x01 /* Forward address is valid */ /* LSTE words 2 and 3 contain a linkage stack entry descriptor */ #else /*!defined(FEATURE_ESAME)*/ #define CR15_LSEA CR15_LSEA_390 /* Bit mask for ESA/390 linkage stack entry addr in CR15 */ #define LSEA_WRAP(_lsea) \ _lsea &= 0x7FFFFFFF /* Wrap linkage stack address*/ #define LSSE_SIZE 168 /* Size of an ESA/390 linkage stack state entry */ #define LSSE_REGSIZE 4 /* Size of a general register in ESA/390 state entry */ /* ESA/390 linkage stack header entry */ /* LSHE word 0 is reserved for control program use */ /* LSHE word 1 contains the backward stack entry address */ #define FETCH_BSEA(_bsea,_lshe) FETCH_FW(_bsea,(_lshe)+4) #define STORE_BSEA(_lshe,_bsea) STORE_FW((_lshe)+4,_bsea) #define LSHE_BVALID 0x80000000 /* Backward address is valid */ #define LSHE_BSEA 0x7FFFFFF8 /* Backward stack entry addr */ #define LSHE_RESV 0x00000007 /* Reserved bits - must be 0 */ /* LSHE words 2 and 3 contain a linkage stack entry descriptor */ /* ESA/390 linkage stack trailer entry */ /* LSTE word 0 is reserved for control program use */ /* LSTE word 1 contains the forward section header address */ #define FETCH_FSHA(_fsha,_lste) FETCH_FW(_fsha,(_lste)+4) #define LSTE_FVALID 0x80000000 /* Forward address is valid */ #define LSTE_FSHA 0x7FFFFFF8 /* Forward section hdr addr */ #define LSTE_RESV 0x00000007 /* Reserved bits - must be 0 */ /* LSTE words 2 and 3 contain a linkage stack entry descriptor */ #endif /*!defined(FEATURE_ESAME)*/ #if defined(FEATURE_LINKAGE_STACK) static inline RADR ARCH_DEP(abs_stack_addr) (VADR vaddr, REGS *regs, int acctype) { return MADDR(vaddr, USE_HOME_SPACE, regs, acctype, 0) - regs->mainstor; } static inline RADR ARCH_DEP(abs_trap_addr) (VADR vaddr, REGS *regs, int acctype) { return MADDR(vaddr, USE_HOME_SPACE, regs, acctype, regs->psw.pkey) - regs->mainstor; } /*-------------------------------------------------------------------*/ /* Subroutine called by the TRAP2 and TRAP4 instructions */ /* */ /* Input: */ /* trap4 0=TRAP2 instruction, 1=TRAP4 instruction */ /* regs Pointer to the CPU register context */ /* operand Effective address if TRAP4 */ /*-------------------------------------------------------------------*/ void ARCH_DEP(trap_x) (int trap_is_trap4, REGS *regs, U32 trap_operand) { RADR ducto; U32 duct11; U32 tcba; RADR atcba; #if defined(FEATURE_ESAME) U32 tcba0; #endif /*defined(FEATURE_ESAME)*/ U32 tsao; RADR tsaa1, tsaa2; VADR lastbyte; U32 trap_ia; U32 trap_flags; QWORD trap_psw; int i; if(SIE_STATB(regs, MX, XC)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIAL_OPERATION_EXCEPTION); if ( REAL_MODE(®s->psw) || !(PRIMARY_SPACE_MODE(®s->psw) || ACCESS_REGISTER_MODE(®s->psw)) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Obtain the DUCT origin from control register 2 */ ducto = regs->CR(2) & CR2_DUCTO; /* Program check if DUCT origin address is invalid */ if (ducto > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch DUCT bytes 44-47 */ duct11 = ARCH_DEP(fetch_fullword_absolute) (ducto + 44, regs); if(!(duct11 & DUCT11_TE)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Isolate the Trap Control Block Address */ tcba = duct11 & DUCT11_TCBA; #if defined(FEATURE_ESAME) /* Fetch word 0 of the TCB */ atcba = ARCH_DEP(abs_trap_addr) (tcba, regs, ACCTYPE_READ); FETCH_FW(tcba0, regs->mainstor + atcba); #endif /*defined(FEATURE_ESAME)*/ /* Advance to offset +12 */ tcba += 12; atcba = ARCH_DEP(abs_trap_addr) (tcba, regs, ACCTYPE_READ); /* Fetch word 3 of the TCB */ FETCH_FW(tsao, regs->mainstor + atcba); tsao &= 0x7FFFFFF8; /* Advance to offset +20 */ tcba += 8; atcba += 8; if((atcba & PAGEFRAME_BYTEMASK) < 8) atcba = ARCH_DEP(abs_trap_addr) (tcba, regs, ACCTYPE_READ); /* Fetch word 5 of the TCB */ FETCH_FW(trap_ia, regs->mainstor + atcba); trap_ia &= 0x7FFFFFFF; /* Calculate last byte stored */ lastbyte = tsao + 95 #if defined(FEATURE_ESAME) + ((tcba0 & TCB0_R) ? 64 : 0) #endif /*defined(FEATURE_ESAME)*/ ; /* Use abs_trap_addr as it conforms to trap save area access */ tsaa1 = tsaa2 = ARCH_DEP(abs_trap_addr) (tsao, regs, ACCTYPE_WRITE); if((tsaa1 & PAGEFRAME_PAGEMASK) != (lastbyte & PAGEFRAME_PAGEMASK)) { tsao = lastbyte & PAGEFRAME_PAGEMASK; tsaa2 = ARCH_DEP(abs_trap_addr) (tsao, regs, ACCTYPE_WRITE); } STORAGE_KEY(tsaa1, regs) |= STORKEY_CHANGE; if (tsaa1 != tsaa2) STORAGE_KEY(tsaa2, regs) |= STORKEY_CHANGE; #if defined(FEATURE_ESAME) /* Special operation exception if P == 0 and EA == 1 */ if(!(tcba0 & TCB0_P) && regs->psw.amode64) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif /*defined(FEATURE_ESAME)*/ #ifdef FEATURE_TRACING if (regs->CR(12) & CR12_BRTRACE) regs->CR(12) = ARCH_DEP(trace_br) (1, trap_ia, regs); #endif /*FEATURE_TRACING*/ PER_SB(regs, trap_ia); trap_flags = REAL_ILC(regs) << 16; if(regs->execflag) trap_flags |= TRAP0_EXECUTE; if(trap_is_trap4) trap_flags |= TRAP0_TRAP4; /* Trap flags at offset +0 */ STORE_FW(regs->mainstor + tsaa1, trap_flags); /* Reserved zero's stored at offset +4 */ STORE_FW(regs->mainstor + tsaa1 + 4, 0); tsaa1 += 8; if((tsaa1 & PAGEFRAME_BYTEMASK) == 0) tsaa1 = tsaa2; /* Bits 33-63 of Second-Op address of TRAP4 at offset +8 */ STORE_FW(regs->mainstor + tsaa1, trap_operand); /* Access register 15 at offset +12 */ STORE_FW(regs->mainstor + tsaa1 + 4, regs->AR(15)); tsaa1 += 8; if((tsaa1 & PAGEFRAME_BYTEMASK) == 0) tsaa1 = tsaa2; #if defined(FEATURE_ESAME) /* If the P bit is one then store the PSW in esame format */ if(tcba0 & TCB0_P) ARCH_DEP(store_psw) (regs, trap_psw); else #endif /*defined(FEATURE_ESAME)*/ { s390_store_psw(regs, trap_psw); #if defined(FEATURE_ESAME) /* Set the notesame mode bit for a esa/390 psw */ trap_psw[1] |= 0x08; #endif /*defined(FEATURE_ESAME)*/ } /* bits 0-63 of PSW at offset +16 */ memcpy(regs->mainstor + tsaa1, trap_psw, 8); tsaa1 += 8; if((tsaa1 & PAGEFRAME_BYTEMASK) == 0) { tsaa1 = tsaa2; } #if defined(FEATURE_ESAME) /* If the P bit is one then store the PSW in esame format */ /* bits 64-127 of PSW at offset +24 */ if(tcba0 & TCB0_P) { memcpy(regs->mainstor + tsaa1, trap_psw + 8, 8); } else { #endif /*defined(FEATURE_ESAME)*/ memset(regs->mainstor + tsaa1, 0, 8); #if defined(FEATURE_ESAME) } #endif /*defined(FEATURE_ESAME)*/ tsaa1 += 8; if((tsaa1 & PAGEFRAME_BYTEMASK) == 0) tsaa1 = tsaa2; #if defined(FEATURE_ESAME) /* General registers at offset +32 */ if(tcba0 & TCB0_R) for(i = 0; i < 16; i++) { STORE_DW(regs->mainstor + tsaa1, regs->GR_G(i)); tsaa1 += 8; if((tsaa1 & PAGEFRAME_BYTEMASK) == 0) tsaa1 = tsaa2; } else #endif /*defined(FEATURE_ESAME)*/ for(i = 0; i < 16; i++) { STORE_FW(regs->mainstor + tsaa1, regs->GR_L(i)); tsaa1 += 4; if((tsaa1 & PAGEFRAME_BYTEMASK) == 0) tsaa1 = tsaa2; } /* Load the Trap Control Block Address in gr15 */ #if defined(FEATURE_ESAME) if(regs->psw.amode64) regs->GR(15) = duct11 & DUCT11_TCBA & 0x00000000FFFFFFFF; else #endif /*defined(FEATURE_ESAME)*/ regs->GR_L(15) = duct11 & DUCT11_TCBA; /* Ensure psw.IA is set */ SET_PSW_IA(regs); /* Set the Breaking Event Address Register */ SET_BEAR_REG(regs, regs->ip - (trap_is_trap4 ? 4 : regs->execflag ? regs->exrl ? 6 : 4 : 2)); regs->psw.amode = 1; regs->psw.AMASK = AMASK31; UPD_PSW_IA(regs, trap_ia); /* set PSW to primary space */ regs->psw.asc = 0; SET_AEA_MODE(regs); } /*-------------------------------------------------------------------*/ /* Form a new entry on the linkage stack */ /* */ /* Input: */ /* etype Linkage stack entry type (LSED_UET_PC/BAKR) */ /* retna Return amode and instruction address to be stored */ /* in the saved PSW in the new stack entry */ /* calla Called amode and instruction address (for BAKR) */ /* csi 32-bit called-space identification (for PC) */ /* pcnum Called PC number (for PC) */ /* regs Pointer to the CPU register context */ /* */ /* This function performs the stacking process for the */ /* Branch and Stack (BAKR) and Program Call (PC) instructions. */ /* */ /* For ESAME, bit 63 of retna/calla indicate a 64-bit address, */ /* otherwise bit 32 indicates a 31-bit address. */ /* For ESA/390, bit 0 of retna/calla indicate a 31-bit address. */ /* */ /* For ESAME, bit 0 of pcnum indicates resulting 64-bit mode. */ /* */ /* In the event of any stack error, this function generates */ /* a program check and does not return. */ /*-------------------------------------------------------------------*/ void ARCH_DEP(form_stack_entry) (BYTE etype, VADR retna, VADR calla, U32 csi, U32 pcnum, REGS *regs) { QWORD currpsw; /* Current PSW */ VADR lsea; /* Linkage stack entry addr */ VADR lseaold; /* Linkage stack old addr */ RADR abs, abs2 = 0; /* Absolute addr new entry */ RADR absold; /* Absolute addr old entry */ LSED lsed; /* Linkage stack entry desc. */ LSED lsed2; /* New entry descriptor */ U16 rfs; /* Remaining free space */ VADR fsha; /* Forward section hdr addr */ VADR bsea = 0; /* Backward stack entry addr */ RADR absea = 0; /* Absolute address of bsea */ int i; /* Array subscript */ /* [5.12.3.1] Locate space for a new linkage stack entry */ /* Obtain the virtual address of the current entry from CR15 */ lsea = regs->CR(15) & CR15_LSEA; /* Fetch the entry descriptor of the current entry */ absold = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); memcpy (&lsed, regs->mainstor+absold, sizeof(LSED)); lseaold = lsea; #ifdef STACK_DEBUG logmsg (_("stack: Current stack entry at " F_VADR "\n"), lsea); logmsg (_("stack: et=%2.2X si=%2.2X rfs=%2.2X%2.2X nes=%2.2X%2.2X\n"), lsed.uet, lsed.si, lsed.rfs[0], lsed.rfs[1], lsed.nes[0], lsed.nes[1]); #endif /*STACK_DEBUG*/ /* Check whether the current linkage stack section has enough remaining free space to contain the new stack entry */ FETCH_HW(rfs,lsed.rfs); if (rfs < LSSE_SIZE) { /* Program check if remaining free space not a multiple of 8 */ if ((rfs & 0x07) != 0) ARCH_DEP(program_interrupt) (regs, PGM_STACK_SPECIFICATION_EXCEPTION); /* Not enough space, so fetch the forward section header addr from the trailer entry of current linkage stack section */ lsea += sizeof(LSED) + rfs; LSEA_WRAP(lsea); abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); FETCH_FSHA(fsha, regs->mainstor + abs); #ifdef STACK_DEBUG logmsg (_("stack: Forward section header addr " F_VADR "\n"), fsha); #endif /*STACK_DEBUG*/ /* Stack full exception if forward address is not valid */ if ((fsha & LSTE_FVALID) == 0) ARCH_DEP(program_interrupt) (regs, PGM_STACK_FULL_EXCEPTION); /* Extract the forward section header address, which points to the entry descriptor (words 2-3) of next section's header */ fsha &= LSTE_FSHA; /* Fetch the entry descriptor of the next section's header */ absold = ARCH_DEP(abs_stack_addr) (fsha, regs, ACCTYPE_READ); memcpy (&lsed, regs->mainstor+absold, sizeof(LSED)); lseaold = fsha; #ifdef STACK_DEBUG logmsg (_("stack: et=%2.2X si=%2.2X rfs=%2.2X%2.2X " "nes=%2.2X%2.2X\n"), lsed.uet, lsed.si, lsed.rfs[0], lsed.rfs[1], lsed.nes[0], lsed.nes[1]); #endif /*STACK_DEBUG*/ /* Program check if the next linkage stack section does not have enough free space to contain the new stack entry */ FETCH_HW(rfs,lsed.rfs); if (rfs < LSSE_SIZE) ARCH_DEP(program_interrupt) (regs, PGM_STACK_SPECIFICATION_EXCEPTION); /* Calculate the virtual address of the new section's header entry, which is 8 bytes before the entry descriptor */ lsea = fsha - 8; LSEA_WRAP(lsea); /* Form the backward stack entry address */ bsea = LSHE_BVALID | (regs->CR(15) & CR15_LSEA); absea = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_WRITE); /* Use the virtual address of the entry descriptor of the new section's header entry as the current entry address */ lsea = fsha; } /* end if(rfsmainstor + absea, bsea); /* Store general registers 0-15 in bytes 0-63 (ESA/390) or bytes 0-127 (ESAME) of the new state entry */ for (i = 0; i < 16; i++) { #if defined(FEATURE_ESAME) /* Store the 64-bit general register in the stack entry */ STORE_DW(regs->mainstor + abs, regs->GR_G(i)); #ifdef STACK_DEBUG logmsg (_("stack: GPR%d=" F_GREG " stored at V:" F_VADR " A:" F_RADR "\n"), i, regs->GR_G(i), lsea, abs); #endif /*STACK_DEBUG*/ #else /*!defined(FEATURE_ESAME)*/ /* Store the 32-bit general register in the stack entry */ STORE_FW(regs->mainstor + abs, regs->GR_L(i)); #ifdef STACK_DEBUG logmsg (_("stack: GPR%d=" F_GREG " stored at V:" F_VADR " A:" F_RADR "\n"), i, regs->GR_L(i), lsea, abs); #endif /*STACK_DEBUG*/ #endif /*!defined(FEATURE_ESAME)*/ /* Update the virtual and absolute addresses */ lsea += LSSE_REGSIZE; LSEA_WRAP(lsea); abs += LSSE_REGSIZE; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; } /* end for(i) */ #if !defined(FEATURE_ESAME) /* For ESA/390, store access registers 0-15 in bytes 64-127 */ for (i = 0; i < 16; i++) { /* Store the access register in the stack entry */ STORE_FW(regs->mainstor + abs, regs->AR(i)); #ifdef STACK_DEBUG logmsg (_("stack: AR%d=" F_AREG " stored at V:" F_VADR " A:" F_RADR "\n"), i, regs->AR(i), lsea, abs); #endif /*STACK_DEBUG*/ /* Update the virtual and absolute addresses */ lsea += 4; LSEA_WRAP(lsea); abs += 4; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; } /* end for(i) */ #endif /*!defined(FEATURE_ESAME)*/ /* Store the PKM, SASN, EAX, and PASN in bytes 128-135 */ STORE_FW(regs->mainstor + abs, regs->CR_L(3)); STORE_HW(regs->mainstor + abs + 4, regs->CR_LHH(8)); STORE_HW(regs->mainstor + abs + 6, regs->CR_LHL(4)); #ifdef STACK_DEBUG logmsg (_("stack: PKM=%2.2X%2.2X SASN=%2.2X%2.2X " "EAX=%2.2X%2.2X PASN=%2.2X%2.2X \n" "stored at V:" F_VADR " A:" F_RADR "\n"), regs->mainstor[abs], regs->mainstor[abs+1], regs->mainstor[abs+2], regs->mainstor[abs+3], regs->mainstor[abs+4], regs->mainstor[abs+5], regs->mainstor[abs+6], regs->mainstor[abs+7], lsea, abs); #endif /*STACK_DEBUG*/ /* Update virtual and absolute addresses to point to byte 136 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; /* Store bits 0-63 of the current PSW in bytes 136-143 */ ARCH_DEP(store_psw) (regs, currpsw); memcpy (regs->mainstor + abs, currpsw, 8); #if defined(FEATURE_ESAME) /* For ESAME, use the addressing mode bits from the return address to set bits 31 and 32 of bytes 136-143 */ if (retna & 0x01) { /* For a 64-bit return address, set bits 31 and 32 */ regs->mainstor[abs+3] |= 0x01; regs->mainstor[abs+4] |= 0x80; retna &= 0xFFFFFFFFFFFFFFFEULL; } else if (retna & 0x80000000) { /* For a 31-bit return address, clear bit 31 and set bit 32 */ regs->mainstor[abs+3] &= 0xFE; regs->mainstor[abs+4] |= 0x80; retna &= 0x7FFFFFFF; } else { /* For a 24-bit return address, clear bits 31 and 32 */ regs->mainstor[abs+3] &= 0xFE; regs->mainstor[abs+4] &= 0x7F; retna &= 0x00FFFFFF; } #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390, replace bytes 140-143 by the return address, with the high-order bit indicating the addressing mode */ STORE_FW(regs->mainstor + abs + 4, retna); #endif /*!defined(FEATURE_ESAME)*/ #ifdef STACK_DEBUG logmsg (_("stack: PSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "stored at V:" F_VADR " A:" F_RADR "\n"), regs->mainstor[abs], regs->mainstor[abs+1], regs->mainstor[abs+2], regs->mainstor[abs+3], regs->mainstor[abs+4], regs->mainstor[abs+5], regs->mainstor[abs+6], regs->mainstor[abs+7], lsea, abs); #endif /*STACK_DEBUG*/ /* Update virtual and absolute addresses to point to byte 144 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; /* Store bytes 144-151 according to PC or BAKR */ if (etype == LSED_UET_PC) { #if defined(FEATURE_CALLED_SPACE_IDENTIFICATION) /* Store the called-space identification in bytes 144-147 */ STORE_FW(regs->mainstor + abs, csi); #endif /*defined(FEATURE_CALLED_SPACE_IDENTIFICATION)*/ /* Store the PC number in bytes 148-151 */ STORE_FW(regs->mainstor + abs + 4, pcnum); } else { #if defined(FEATURE_ESAME) /* Store the called address and amode in bytes 144-151 */ STORE_DW(regs->mainstor + abs, calla); #else /*!defined(FEATURE_ESAME)*/ /* Store the called address and amode in bytes 148-151 */ STORE_FW(regs->mainstor + abs + 4, calla); #endif /*!defined(FEATURE_ESAME)*/ } /* Update virtual and absolute addresses to point to byte 152 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; /* Store zeroes in bytes 152-159 */ memset (regs->mainstor+abs, 0, 8); /* Update virtual and absolute addresses to point to byte 160 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; #if defined(FEATURE_ESAME) /* For ESAME, store zeroes in bytes 160-167 */ memset (regs->mainstor+abs, 0, 8); /* Update virtual and absolute addresses to point to byte 168 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; /* For ESAME, store the return address in bytes 168-175 */ STORE_DW (regs->mainstor + abs, retna); #ifdef STACK_DEBUG logmsg (_("stack: PSW2=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "stored at V:" F_VADR " A:" F_RADR "\n"), regs->mainstor[abs], regs->mainstor[abs+1], regs->mainstor[abs+2], regs->mainstor[abs+3], regs->mainstor[abs+4], regs->mainstor[abs+5], regs->mainstor[abs+6], regs->mainstor[abs+7], lsea, abs); #endif /*STACK_DEBUG*/ /* Update virtual and absolute addresses to point to byte 176 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; /* If ASN-and-LX-reuse is installed and active, store the SASTEIN (CR3 bits 0-31) in bytes 176-179, and store the PASTEIN (CR4 bits 0-31) in bytes 180-183 */ if (ASN_AND_LX_REUSE_ENABLED(regs)) { STORE_FW(regs->mainstor + abs, regs->CR_H(3)); STORE_FW(regs->mainstor + abs + 4, regs->CR_H(4)); #ifdef STACK_DEBUG logmsg (_("stack: SASTEIN=%2.2X%2.2X%2.2X%2.2X " "PASTEIN=%2.2X%2.2X%2.2X%2.2X \n" "stored at V:" F_VADR " A:" F_RADR "\n"), regs->mainstor[abs], regs->mainstor[abs+1], regs->mainstor[abs+2], regs->mainstor[abs+3], regs->mainstor[abs+4], regs->mainstor[abs+5], regs->mainstor[abs+6], regs->mainstor[abs+7], lsea, abs); #endif /*STACK_DEBUG*/ } /* end if(ASN_AND_LX_REUSE_ENABLED) */ /* Skip bytes 176-223 of the new stack entry */ lsea += 48; LSEA_WRAP(lsea); abs += 48; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) < 48) abs = abs2 | (lsea & PAGEFRAME_BYTEMASK); /* For ESAME, store access registers 0-15 in bytes 224-287 */ for (i = 0; i < 16; i++) { /* Store the access register in the stack entry */ STORE_FW(regs->mainstor + abs, regs->AR(i)); #ifdef STACK_DEBUG logmsg (_("stack: AR%d=" F_AREG " stored at V:" F_VADR " A:" F_RADR "\n"), i, regs->AR(i), lsea, abs); #endif /*STACK_DEBUG*/ /* Update the virtual and absolute addresses */ lsea += 4; LSEA_WRAP(lsea); abs += 4; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; } /* end for(i) */ #endif /*defined(FEATURE_ESAME)*/ /* Build the new linkage stack entry descriptor */ memset (&lsed2, 0, sizeof(LSED)); lsed2.uet = etype & LSED_UET_ET; lsed2.si = lsed.si; rfs -= LSSE_SIZE; STORE_HW(lsed2.rfs,rfs); /* Store the linkage stack entry descriptor in the last eight bytes of the new state entry (bytes 160-167 for ESA/390, or bytes 288-295 for ESAME) */ memcpy (regs->mainstor+abs, &lsed2, sizeof(LSED)); #ifdef STACK_DEBUG logmsg (_("stack: New stack entry at " F_VADR "\n"), lsea); logmsg (_("stack: et=%2.2X si=%2.2X rfs=%2.2X%2.2X nes=%2.2X%2.2X\n"), lsed2.uet, lsed2.si, lsed2.rfs[0], lsed2.rfs[1], lsed2.nes[0], lsed2.nes[1]); #endif /*STACK_DEBUG*/ /* [5.12.3.3] Update the current entry */ STORE_HW(lsed.nes, LSSE_SIZE); absold = ARCH_DEP(abs_stack_addr) (lseaold, regs, ACCTYPE_WRITE); memcpy (regs->mainstor+absold, &lsed, sizeof(LSED)); #ifdef STACK_DEBUG logmsg (_("stack: Previous stack entry updated at A:" F_RADR "\n"), absold); logmsg (_("stack: et=%2.2X si=%2.2X rfs=%2.2X%2.2X nes=%2.2X%2.2X\n"), lsed.uet, lsed.si, lsed.rfs[0], lsed.rfs[1], lsed.nes[0], lsed.nes[1]); #endif /*STACK_DEBUG*/ /* [5.12.3.4] Update control register 15 */ regs->CR(15) = lsea & CR15_LSEA; #ifdef STACK_DEBUG logmsg (_("stack: CR15=" F_CREG "\n"), regs->CR(15)); #endif /*STACK_DEBUG*/ } /* end function ARCH_DEP(form_stack_entry) */ /*-------------------------------------------------------------------*/ /* Locate the current linkage stack entry */ /* */ /* Input: */ /* prinst 1=PR instruction, 0=EREG/EREGG/ESTA/MSTA instruction */ /* lsedptr Pointer to an LSED structure */ /* regs Pointer to the CPU register context */ /* Output: */ /* The entry descriptor for the current state entry in the */ /* linkage stack is copied into the LSED structure. */ /* The home virtual address of the entry descriptor is */ /* returned as the function return value. */ /* */ /* This function performs the first part of the unstacking */ /* process for the Program Return (PR), Extract Stacked */ /* Registers (EREG/EREGG), Extract Stacked State (ESTA), */ /* and Modify Stacked State (MSTA) instructions. */ /* */ /* In the event of any stack error, this function generates */ /* a program check and does not return. */ /*-------------------------------------------------------------------*/ VADR ARCH_DEP(locate_stack_entry) (int prinst, LSED *lsedptr, REGS *regs) { VADR lsea; /* Linkage stack entry addr */ RADR abs; /* Absolute address */ VADR bsea; /* Backward stack entry addr */ /* [5.12.4] Special operation exception if ASF is not enabled, or if DAT is off, or if in secondary-space mode */ if (!ASF_ENABLED(regs) || REAL_MODE(®s->psw) || SECONDARY_SPACE_MODE(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Special operation exception if home space mode PR instruction */ if (prinst && HOME_SPACE_MODE(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* [5.12.4.1] Locate current entry and process header entry */ /* Obtain the virtual address of the current entry from CR15 */ lsea = regs->CR(15) & CR15_LSEA; /* Fetch the entry descriptor of the current entry */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); memcpy (lsedptr, regs->mainstor+abs, sizeof(LSED)); #ifdef STACK_DEBUG logmsg (_("stack: Stack entry located at " F_VADR "\n"), lsea); logmsg (_("stack: et=%2.2X si=%2.2X rfs=%2.2X%2.2X nes=%2.2X%2.2X\n"), lsedptr->uet, lsedptr->si, lsedptr->rfs[0], lsedptr->rfs[1], lsedptr->nes[0], lsedptr->nes[1]); #endif /*STACK_DEBUG*/ /* Check for a header entry */ if ((lsedptr->uet & LSED_UET_ET) == LSED_UET_HDR) { /* For PR instruction only, generate stack operation exception if the unstack suppression bit in the header entry is set */ if (prinst && (lsedptr->uet & LSED_UET_U)) ARCH_DEP(program_interrupt) (regs, PGM_STACK_OPERATION_EXCEPTION); /* Calculate the virtual address of the header entry, which is 8 bytes before the entry descriptor */ lsea -= 8; LSEA_WRAP(lsea); /* Fetch the backward stack entry address from the header */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); FETCH_BSEA(bsea,regs->mainstor + abs); #ifdef STACK_DEBUG logmsg (_("stack: Stack entry located at " F_VADR "\n"), bsea); #endif /*STACK_DEBUG*/ /* Stack empty exception if backward address is not valid */ if ((bsea & LSHE_BVALID) == 0) ARCH_DEP(program_interrupt) (regs, PGM_STACK_EMPTY_EXCEPTION); /* Extract the virtual address of the entry descriptor of the last entry in the previous section */ lsea = bsea & LSHE_BSEA; /* Fetch the entry descriptor of the designated entry */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); memcpy (lsedptr, regs->mainstor+abs, sizeof(LSED)); #ifdef STACK_DEBUG logmsg (_("stack: et=%2.2X si=%2.2X rfs=%2.2X%2.2X " "nes=%2.2X%2.2X\n"), lsedptr->uet, lsedptr->si, lsedptr->rfs[0], lsedptr->rfs[1], lsedptr->nes[0], lsedptr->nes[1]); #endif /*STACK_DEBUG*/ /* Stack specification exception if this is also a header */ if ((lsedptr->uet & LSED_UET_ET) == LSED_UET_HDR) ARCH_DEP(program_interrupt) (regs, PGM_STACK_SPECIFICATION_EXCEPTION); } /* end if(LSED_UET_HDR) */ /* [5.12.4.2] Check for a state entry */ /* Stack type exception if this is not a state entry */ if ((lsedptr->uet & LSED_UET_ET) != LSED_UET_BAKR && (lsedptr->uet & LSED_UET_ET) != LSED_UET_PC) ARCH_DEP(program_interrupt) (regs, PGM_STACK_TYPE_EXCEPTION); /* [5.12.4.3] For PR instruction only, stack operation exception if the unstack suppression bit in the state entry is set */ if (prinst && (lsedptr->uet & LSED_UET_U)) ARCH_DEP(program_interrupt) (regs, PGM_STACK_OPERATION_EXCEPTION); /* Return the virtual address of the entry descriptor */ return lsea; } /* end function ARCH_DEP(locate_stack_entry) */ /*-------------------------------------------------------------------*/ /* Stack modify */ /* */ /* Input: */ /* lsea Virtual address of linkage stack entry descriptor */ /* m1 Left 32 bits to be stored in state entry */ /* m2 Right 32 bits to be stored in state entry */ /* regs Pointer to the CPU register context */ /* */ /* This function places eight bytes of information into the */ /* modifiable area of a state entry in the linkage stack. It */ /* is called by the Modify Stacked State (MSTA) instruction */ /* after it has located the current state entry. */ /* */ /* If a translation exception occurs when accessing the stack */ /* entry, then a program check will be generated by the */ /* abs_stack_addr subroutine, and the function will not return. */ /*-------------------------------------------------------------------*/ void ARCH_DEP(stack_modify) (VADR lsea, U32 m1, U32 m2, REGS *regs) { RADR abs; /* Absolute address */ /* Point back to byte 152 of the state entry */ lsea -= LSSE_SIZE - sizeof(LSED); lsea += 152; LSEA_WRAP(lsea); /* Store the modify values into the state entry */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_WRITE); STORE_FW(regs->mainstor + abs, m1); STORE_FW(regs->mainstor + abs + 4, m2); } /* end function ARCH_DEP(stack_modify) */ /*-------------------------------------------------------------------*/ /* Stack extract */ /* */ /* Input: */ /* lsea Virtual address of linkage stack entry descriptor */ /* r1 The number of an even-odd pair of registers */ /* code A code indicating which bytes are to be extracted: */ /* 0 = Bytes 128-135 (PKN/SASN/EAX/PASN) */ /* 1 = ESA/390: Bytes 136-143 (PSW) */ /* ESAME: Bytes 136-139, 140.0, 168-175.33-63 */ /* (ESA/390-format PSW) */ /* 2 = Bytes 144-151 (Branch address or PC number) */ /* 3 = Bytes 152-159 (Modifiable area) */ /* 4 = Bytes 136-143 and 168-175 (ESAME-format PSW) */ /* 5 = Bytes 176-183 (SASTEIN,PASTEIN) */ /* regs Pointer to the CPU register context */ /* */ /* This function extracts 64 or 128 bits of information from */ /* the status area of a state entry in the linkage stack. It */ /* is called by the Extract Stacked State (ESTA) instruction */ /* after it has located the current state entry. */ /* */ /* For codes 0 through 3, the rightmost 32 bits of the R1 and */ /* R1+1 registers are updated (the leftmost 32 bits remain */ /* unchanged for ESAME). For code 4, which is valid only for */ /* ESAME, all 64 bits of the R1 and R1+1 registers are loaded. */ /* For code 5 (valid only if the ASN-and-LX-reuse facility is */ /* installed), the leftmost 32 bits of the R1 and R1+1 regs */ /* are updated, and the rightmost 32 bits remain unchanged. */ /* */ /* If a translation exception occurs when accessing the stack */ /* entry, then a program check will be generated by the */ /* abs_stack_addr subroutine, and the function will not return. */ /*-------------------------------------------------------------------*/ void ARCH_DEP(stack_extract) (VADR lsea, int r1, int code, REGS *regs) { RADR abs; /* Absolute address */ /* Point back to byte 128 of the state entry */ lsea -= LSSE_SIZE - sizeof(LSED); lsea += 128; #if defined(FEATURE_ESAME) /* For codes 1 and 4, extract bytes 136-143 and 168-175 */ if (code == 1 || code == 4) { U64 psw1, psw2; /* Point to byte 136 of the state entry */ lsea += 8; LSEA_WRAP(lsea); /* Load bits 0-63 of ESAME PSW from bytes 136-143 */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); FETCH_DW(psw1, regs->mainstor + abs); /* Point to byte 168 of the state entry */ lsea += 32; abs += 32; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) < 32) abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); /* Load bits 64-127 of ESAME PSW from bytes 168-175 */ FETCH_DW(psw2, regs->mainstor + abs); /* For code 4, return ESAME PSW in general register pair */ if (code == 4) { regs->GR_G(r1) = psw1; regs->GR_G(r1+1) = psw2; return; } /* For code 1, convert ESAME PSW to ESA/390 format */ regs->GR_L(r1) = (psw1 >> 32) | 0x00080000; regs->GR_L(r1+1) = (psw1 & 0x80000000) | (psw2 & 0x7FFFFFFF); /* Set low-order bit of R1+1 if IA exceeds 31-bit address */ if (psw2 > 0x7FFFFFFF) regs->GR_L(r1+1) |= 0x01; return; } /* if(code==1||code==4) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ASN_AND_LX_REUSE) /* For code 5, extract bytes 176-183 */ if (code == 5) { /* Point to byte 176 of the state entry */ lsea += 48; LSEA_WRAP(lsea); /* Load the SASTEIN, PASTEIN from bytes 176-179, 180-183*/ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); FETCH_FW(regs->GR_H(r1), regs->mainstor + abs); FETCH_FW(regs->GR_H(r1+1), regs->mainstor + abs + 4); return; } /* if(code==5) */ #endif /*defined(FEATURE_ASN_AND_LX_REUSE)*/ /* For codes 0,2,3 in ESAME, and codes 0,1,2,3 in ESA/390 */ /* Point to byte 128, 136, 144, or 152 depending on the code */ lsea += code * 8; LSEA_WRAP(lsea); /* Load the general register pair from the state entry */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); FETCH_FW(regs->GR_L(r1), regs->mainstor + abs); FETCH_FW(regs->GR_L(r1+1), regs->mainstor + abs + 4); } /* end function ARCH_DEP(stack_extract) */ /*-------------------------------------------------------------------*/ /* Unstack registers */ /* */ /* Input: */ /* gtype 0=EREG instruction, 1=EREGG or PR instruction */ /* lsea Virtual address of linkage stack entry descriptor */ /* r1 The number of the first register to be loaded */ /* r2 The number of the last register to be loaded */ /* regs Pointer to the CPU register context */ /* */ /* This function loads a range of general registers and */ /* access registers from the specified linkage stack entry. */ /* It is called by the Extract Stacked Registers (EREG/EREGG) */ /* and Program Return (PR) instructions after they have located */ /* the current state entry in the linkage stack. */ /* */ /* If a translation exception occurs when accessing the stack */ /* entry, then a program check will be generated by the */ /* abs_stack_addr subroutine, and the function will not return. */ /* Since the stack entry can only span at most two pages, and */ /* the caller will have already successfully accessed the */ /* entry descriptor which is at the end of the stack entry, */ /* the only place a translation exception can occur is when */ /* attempting to load the first register, in which case the */ /* operation is nullified with all registers unchanged. */ /*-------------------------------------------------------------------*/ void ARCH_DEP(unstack_registers) (int gtype, VADR lsea, int r1, int r2, REGS *regs) { RADR abs, abs2 = 0; /* Absolute address */ VADR firstbyte, /* First byte to be fetched */ lastbyte; /* Last byte to be fetched */ int i; /* Array subscript */ UNREFERENCED(gtype); /* Point back to byte 0 of the state entry */ lsea -= LSSE_SIZE - sizeof(LSED); LSEA_WRAP(lsea); /* Determine first and last byte to fetch from the state entry */ firstbyte = lsea + ((r1 > r2) ? 0 : r1) * LSSE_REGSIZE; lastbyte = lsea + (LSSE_SIZE - 69) + (((r1 > r2) ? 15 : r2) * 4); lsea = firstbyte; /* Obtain absolute address of the state entry */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); /* If the state entry crosses a page boundary, obtain the absolute address of the second page of the stack entry */ if( (firstbyte & PAGEFRAME_PAGEMASK) != (lastbyte & PAGEFRAME_PAGEMASK)) abs2 = ARCH_DEP(abs_stack_addr) (lastbyte & PAGEFRAME_PAGEMASK, regs, ACCTYPE_READ); #ifdef STACK_DEBUG logmsg (_("stack: Unstacking registers %d-%d from " F_VADR "\n"), r1, r2, lsea); #endif /*STACK_DEBUG*/ /* Load general registers from bytes 0-63 (for ESA/390), or bytes 0-127 (for ESAME) of the state entry */ for (i = ((r1 > r2) ? 0 : r1); i <= 15; i++) { /* Load the general register from the stack entry */ if ((r1 <= r2 && i >= r1 && i <= r2) || (r1 > r2 && (i >= r1 || i <= r2))) { #if defined(FEATURE_ESAME) if (gtype) { /* For ESAME PR and EREGG instructions, load all 64 bits of the register */ FETCH_DW(regs->GR_G(i), regs->mainstor + abs); } else { /* For ESAME EREG instruction, load bits 32-63 of the register, and leave bits 0-31 unchanged */ FETCH_FW(regs->GR_L(i), regs->mainstor + abs + 4); } #ifdef STACK_DEBUG logmsg (_("stack: GPR%d=" F_GREG " loaded from V:" F_VADR " A:" F_RADR "\n"), i, regs->GR(i), lsea, abs); #endif /*STACK_DEBUG*/ #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390, load a 32-bit general register */ FETCH_FW(regs->GR_L(i), regs->mainstor + abs); #ifdef STACK_DEBUG logmsg (_("stack: GPR%d=" F_GREG " loaded from V:" F_VADR " A:" F_RADR "\n"), i, regs->GR(i), lsea, abs); #endif /*STACK_DEBUG*/ #endif /*!defined(FEATURE_ESAME)*/ } /* Update the virtual and absolute addresses */ lsea += LSSE_REGSIZE; LSEA_WRAP(lsea); abs += LSSE_REGSIZE; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; } /* end for(i) */ #if defined(FEATURE_ESAME) /* For ESAME, skip the next 96 bytes of the state entry */ lsea += 96; abs += 96; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) < 96) abs = abs2 | (lsea & PAGEFRAME_BYTEMASK); #endif /*defined(FEATURE_ESAME)*/ /* Load access registers from bytes 64-127 (for ESA/390), or bytes 224-280 (for ESAME) of the state entry */ for (i = 0; i <= ((r1 > r2) ? 15 : r2); i++) { /* Load the access register from the stack entry */ if ((r1 <= r2 && i >= r1 && i <= r2) || (r1 > r2 && (i >= r1 || i <= r2))) { FETCH_FW(regs->AR(i),regs->mainstor + abs); SET_AEA_AR(regs, i); #ifdef STACK_DEBUG logmsg (_("stack: AR%d=" F_AREG " loaded from V:" F_VADR " A:" F_RADR "\n"), i, regs->AR(i), lsea, abs); #endif /*STACK_DEBUG*/ } /* Update the virtual and absolute addresses */ lsea += 4; LSEA_WRAP(lsea); abs += 4; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = abs2; } /* end for(i) */ } /* end function ARCH_DEP(unstack_registers) */ /*-------------------------------------------------------------------*/ /* Program return unstack */ /* */ /* Input: */ /* regs Pointer to a copy of the CPU register context */ /* Output: */ /* lsedap The absolute address of the entry descriptor of */ /* the new current entry on the linkage stack. */ /* rc Return code from load_psw, checked later for PIC 06 */ /* Return value: */ /* The type of entry unstacked: LSED_UET_BAKR or LSED_UET_PC */ /* */ /* This function performs the restoring and updating parts */ /* of the unstacking process for the Program Return (PR) */ /* instruction. If a program exception occurs during the PR */ /* instruction (either during or after the unstack), then the */ /* effects of the instruction must be nullified or suppressed. */ /* This is achieved by updating a copy of the CPU register */ /* context instead of the actual register context. */ /* The current register context is replaced by the copy */ /* only on successful completion of the PR instruction. */ /* */ /* In the event of any stack error, this function generates */ /* a program check and does not return. */ /*-------------------------------------------------------------------*/ int ARCH_DEP(program_return_unstack) (REGS *regs, RADR *lsedap, int *rc) { QWORD newpsw; /* New PSW */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ RADR abs; /* Absolute address */ int permode; /* 1=PER mode is set in PSW */ U16 pkm; /* PSW key mask */ U16 sasn; /* Secondary ASN */ U16 eax; /* Extended AX */ U16 pasn; /* Primary ASN */ VADR lsep; /* Virtual addr of entry desc. of previous stack entry */ /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (1, &lsed, regs); /* [5.12.4.3] Restore information from stack entry */ /* Load registers 2-14 from the stack entry */ ARCH_DEP(unstack_registers) (1, lsea, 2, 14, regs); /* Point back to the entry descriptor of previous stack entry */ lsep = lsea - LSSE_SIZE; LSEA_WRAP(lsep); /* Point back to byte 128 of the current state entry */ lsea -= LSSE_SIZE - sizeof(LSED); lsea += 128; LSEA_WRAP(lsea); /* Translate virtual address to absolute address */ abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); /* For a call state entry, replace the PKM, SASN, EAX, and PASN */ if ((lsed.uet & LSED_UET_ET) == LSED_UET_PC) { /* Fetch the PKM from bytes 128-129 of the stack entry */ FETCH_HW(pkm,regs->mainstor + abs); /* Fetch the SASN from bytes 130-131 of the stack entry */ FETCH_HW(sasn,regs->mainstor + abs + 2); /* Fetch the EAX from bytes 132-133 of the stack entry */ FETCH_HW(eax,regs->mainstor + abs + 4); /* Fetch the PASN from bytes 134-135 of the stack entry */ FETCH_HW(pasn,regs->mainstor + abs + 6); #ifdef STACK_DEBUG logmsg (_("stack: PKM=%2.2X%2.2X SASN=%2.2X%2.2X " "EAX=%2.2X%2.2X PASN=%2.2X%2.2X \n" "loaded from V:" F_VADR " A:" F_RADR "\n"), regs->mainstor[abs], regs->mainstor[abs+1], regs->mainstor[abs+2], regs->mainstor[abs+3], regs->mainstor[abs+4], regs->mainstor[abs+5], regs->mainstor[abs+6], regs->mainstor[abs+7], lsea, abs); #endif /*STACK_DEBUG*/ /* Load PKM into CR3 bits 0-15 (32-47) */ regs->CR_LHH(3) = pkm; /* Load SASN into CR3 bits 16-31 (48-63) */ regs->CR_LHL(3) = sasn; /* Load EAX into CR8 bits 0-15 (32-47) */ regs->CR_LHH(8) = eax; /* Load PASN into CR4 bits 16-31 (48-63) */ regs->CR_LHL(4) = pasn; } /* end if(LSED_UET_PC) */ /* Update virtual and absolute addresses to point to byte 136 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); /* Save the PER mode bit from the current PSW */ permode = (regs->psw.sysmask & PSW_PERMODE) ? 1 : 0; #ifdef STACK_DEBUG logmsg (_("stack: PSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "loaded from V:" F_VADR " A:" F_RADR "\n"), regs->mainstor[abs], regs->mainstor[abs+1], regs->mainstor[abs+2], regs->mainstor[abs+3], regs->mainstor[abs+4], regs->mainstor[abs+5], regs->mainstor[abs+6], regs->mainstor[abs+7], lsea, abs); #endif /*STACK_DEBUG*/ /* Copy PSW bits 0-63 from bytes 136-143 of the stack entry */ memcpy (newpsw, regs->mainstor + abs, 8); #if defined(FEATURE_ESAME) /* For ESAME, advance to byte 168 of the stack entry */ lsea += 32; LSEA_WRAP(lsea); abs += 32; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) < 32) abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); /* Copy ESAME PSW bits 64-127 from bytes 168-175 */ memcpy (newpsw + 8, regs->mainstor + abs, 8); /* Update virtual and absolute addresses to point to byte 176 */ lsea += 8; LSEA_WRAP(lsea); abs += 8; /* Recalculate absolute address if page boundary crossed */ if ((lsea & PAGEFRAME_BYTEMASK) == 0x000) abs = ARCH_DEP(abs_stack_addr) (lsea, regs, ACCTYPE_READ); /* For a call state entry only, if ASN-and-LX-reuse is installed and active, load the SASTEIN (high word of CR3) from bytes 176-179, and load the PASTEIN (high word of CR4) from bytes 180-183 */ if ((lsed.uet & LSED_UET_ET) == LSED_UET_PC && ASN_AND_LX_REUSE_ENABLED(regs)) { FETCH_FW(regs->CR_H(3), regs->mainstor + abs); FETCH_FW(regs->CR_H(4), regs->mainstor + abs + 4); #ifdef STACK_DEBUG logmsg (_("stack: SASTEIN=%2.2X%2.2X%2.2X%2.2X " "PASTEIN=%2.2X%2.2X%2.2X%2.2X \n" "loaded from V:" F_VADR " A:" F_RADR "\n"), regs->mainstor[abs], regs->mainstor[abs+1], regs->mainstor[abs+2], regs->mainstor[abs+3], regs->mainstor[abs+4], regs->mainstor[abs+5], regs->mainstor[abs+6], regs->mainstor[abs+7], lsea, abs); #endif /*STACK_DEBUG*/ } /* end if(LSED_UET_PC && ASN_AND_LX_REUSE_ENABLED) */ #endif /*defined(FEATURE_ESAME)*/ /* [5.12.4.4] Pass back the absolute address of the entry descriptor of the preceding linkage stack entry. The next entry size field of this entry will be cleared on successful completion of the PR instruction */ *lsedap = ARCH_DEP(abs_stack_addr) (lsep, regs, ACCTYPE_WRITE); /* [5.12.4.5] Update CR15 to point to the previous entry */ regs->CR(15) = lsep & CR15_LSEA; /* Load new PSW using the bytes extracted from the stack entry */ /* The rc will be checked by calling routine for PIC 06 */ *rc = ARCH_DEP(load_psw) (regs, newpsw); /* Restore the PER mode bit from the current PSW */ if (permode) regs->psw.sysmask |= PSW_PERMODE; else regs->psw.sysmask &= ~PSW_PERMODE; /* restore PER masks which could have been wiped out by load_psw */ SET_IC_MASK(regs); #ifdef STACK_DEBUG logmsg (_("stack: CR15=" F_CREG "\n"), regs->CR(15)); #endif /*STACK_DEBUG*/ /* Return the entry type of the unstacked state entry */ return (lsed.uet & LSED_UET_ET); } /* end function ARCH_DEP(program_return_unstack) */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "stack.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "stack.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/cpu.c0000664000175000017500000020712612564723224011146 00000000000000/* CPU.C (c) Copyright Roger Bowler, 1994-2009 */ /* ESA/390 CPU Emulator */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements the CPU instruction execution function of */ /* the S/370 and ESA/390 architectures, as described in the manuals */ /* GA22-7000-03 System/370 Principles of Operation */ /* SA22-7201-06 ESA/390 Principles of Operation */ /* SA22-7832-00 z/Architecture Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Nullification corrections by Jan Jaeger */ /* Set priority by Reed H. Petty from an idea by Steve Gay */ /* Corrections to program check by Jan Jaeger */ /* Light optimization on critical path by Valery Pogonchenko */ /* OSTAILOR parameter by Jay Maynard */ /* CPU timer and clock comparator interrupt improvements by */ /* Jan Jaeger, after a suggestion by Willem Konynenberg */ /* Instruction decode rework - Jan Jaeger */ /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */ /* Basic FP extensions support - Peter Kuschnerus v209*/ /* ASN-and-LX-reuse facility - Roger Bowler, June 2004 @ALR*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_CPU_C_) #define _CPU_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" /*-------------------------------------------------------------------*/ /* Put a CPU in check-stop state */ /* Must hold the system intlock */ /*-------------------------------------------------------------------*/ void ARCH_DEP(checkstop_cpu)(REGS *regs) { regs->cpustate=CPUSTATE_STOPPING; regs->checkstop=1; ON_IC_INTERRUPT(regs); } /*-------------------------------------------------------------------*/ /* Put all the CPUs in the configuration in check-stop state */ /*-------------------------------------------------------------------*/ void ARCH_DEP(checkstop_config)(void) { int i; for(i=0;ipsw.zeroilc) SET_PSW_IA(regs); #if defined(FEATURE_BCMODE) if ( ECMODE(®s->psw) ) { #endif /*defined(FEATURE_BCMODE)*/ #if !defined(FEATURE_ESAME) STORE_FW ( addr, ( (regs->psw.sysmask << 24) | ((regs->psw.pkey | regs->psw.states) << 16) | ( ( (regs->psw.asc) | (regs->psw.cc << 4) | (regs->psw.progmask) ) << 8 ) | regs->psw.zerobyte ) ); if(unlikely(regs->psw.zeroilc)) STORE_FW ( addr + 4, regs->psw.IA | (regs->psw.amode ? 0x80000000 : 0) ); else STORE_FW ( addr + 4, ( (regs->psw.IA & ADDRESS_MAXWRAP(regs)) | (regs->psw.amode ? 0x80000000 : 0) ) ); #endif /*!defined(FEATURE_ESAME)*/ #if defined(FEATURE_BCMODE) } else { STORE_FW ( addr, ( (regs->psw.sysmask << 24) | ((regs->psw.pkey | regs->psw.states) << 16) | (regs->psw.intcode) ) ); if(unlikely(regs->psw.zeroilc)) STORE_FW ( addr + 4, ( ( (REAL_ILC(regs) << 5) | (regs->psw.cc << 4) | regs->psw.progmask ) << 24 ) | regs->psw.IA ); else STORE_FW ( addr + 4, ( ( (REAL_ILC(regs) << 5) | (regs->psw.cc << 4) | regs->psw.progmask ) << 24 ) | (regs->psw.IA & ADDRESS_MAXWRAP(regs)) ); } #elif defined(FEATURE_ESAME) STORE_FW ( addr, ( (regs->psw.sysmask << 24) | ((regs->psw.pkey | regs->psw.states) << 16) | ( ( (regs->psw.asc) | (regs->psw.cc << 4) | (regs->psw.progmask) ) << 8 ) | (regs->psw.amode64 ? 0x01 : 0) | regs->psw.zerobyte ) ); STORE_FW ( addr + 4, ( (regs->psw.amode ? 0x80000000 : 0 ) | regs->psw.zeroword ) ); STORE_DW ( addr + 8, regs->psw.IA_G ); #endif /*defined(FEATURE_ESAME)*/ } /* end function ARCH_DEP(store_psw) */ /*-------------------------------------------------------------------*/ /* Load current PSW from a specified address in main storage */ /* Returns 0 if valid, 0x0006 if specification exception */ /*-------------------------------------------------------------------*/ int ARCH_DEP(load_psw) (REGS *regs, BYTE *addr) { INVALIDATE_AIA(regs); regs->psw.zeroilc = 1; regs->psw.sysmask = addr[0]; regs->psw.pkey = (addr[1] & 0xF0); regs->psw.states = (addr[1] & 0x0F); #if defined(FEATURE_BCMODE) if ( ECMODE(®s->psw) ) { #endif /*defined(FEATURE_BCMODE)*/ SET_IC_ECMODE_MASK(regs); /* Processing for EC mode PSW */ regs->psw.intcode = 0; regs->psw.asc = (addr[2] & 0xC0); regs->psw.cc = (addr[2] & 0x30) >> 4; regs->psw.progmask = (addr[2] & 0x0F); regs->psw.amode = (addr[4] & 0x80) ? 1 : 0; #if defined(FEATURE_ESAME) regs->psw.zerobyte = addr[3] & 0xFE; regs->psw.amode64 = addr[3] & 0x01; regs->psw.zeroword = fetch_fw(addr+4) & 0x7FFFFFFF; regs->psw.IA = fetch_dw (addr + 8); regs->psw.AMASK = regs->psw.amode64 ? AMASK64 : regs->psw.amode ? AMASK31 : AMASK24; #else /*!defined(FEATURE_ESAME)*/ regs->psw.zerobyte = addr[3]; regs->psw.amode64 = 0; regs->psw.IA = fetch_fw(addr + 4) & 0x7FFFFFFF; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; #endif /*!defined(FEATURE_ESAME)*/ /* Bits 0 and 2-4 of system mask must be zero */ if ((addr[0] & 0xB8) != 0) return PGM_SPECIFICATION_EXCEPTION; #if defined(FEATURE_ESAME) /* For ESAME, bit 12 must be zero */ if (NOTESAME(®s->psw)) return PGM_SPECIFICATION_EXCEPTION; /* Bits 24-30 must be zero */ if (regs->psw.zerobyte) return PGM_SPECIFICATION_EXCEPTION; /* Bits 33-63 must be zero */ if ( regs->psw.zeroword ) return PGM_SPECIFICATION_EXCEPTION; #else /*!defined(FEATURE_ESAME)*/ /* Bits 24-31 must be zero */ if ( regs->psw.zerobyte ) return PGM_SPECIFICATION_EXCEPTION; /* For ESA/390, bit 12 must be one */ if (!ECMODE(®s->psw)) return PGM_SPECIFICATION_EXCEPTION; #endif /*!defined(FEATURE_ESAME)*/ #ifndef FEATURE_DUAL_ADDRESS_SPACE /* If DAS feature not installed then bit 16 must be zero */ if (SPACE_BIT(®s->psw)) return PGM_SPECIFICATION_EXCEPTION; #endif /*!FEATURE_DUAL_ADDRESS_SPACE*/ #ifndef FEATURE_ACCESS_REGISTERS /* If not ESA/370 or ESA/390 then bit 17 must be zero */ if (AR_BIT(®s->psw)) return PGM_SPECIFICATION_EXCEPTION; #endif /*!FEATURE_ACCESS_REGISTERS*/ /* Check validity of amode and instruction address */ #if defined(FEATURE_ESAME) /* For ESAME, bit 32 cannot be zero if bit 31 is one */ if (regs->psw.amode64 && !regs->psw.amode) return PGM_SPECIFICATION_EXCEPTION; /* If bit 32 is zero then IA cannot exceed 24 bits */ if (!regs->psw.amode && regs->psw.IA > 0x00FFFFFF) return PGM_SPECIFICATION_EXCEPTION; /* If bit 31 is zero then IA cannot exceed 31 bits */ if (!regs->psw.amode64 && regs->psw.IA > 0x7FFFFFFF) return PGM_SPECIFICATION_EXCEPTION; #else /*!defined(FEATURE_ESAME)*/ #ifdef FEATURE_BIMODAL_ADDRESSING /* For 370-XA, ESA/370, and ESA/390, if amode=24, bits 33-39 must be zero */ if (!regs->psw.amode && regs->psw.IA > 0x00FFFFFF) return PGM_SPECIFICATION_EXCEPTION; #else /*!FEATURE_BIMODAL_ADDRESSING*/ /* For S/370, bits 32-39 must be zero */ if (addr[4] != 0x00) return PGM_SPECIFICATION_EXCEPTION; #endif /*!FEATURE_BIMODAL_ADDRESSING*/ #endif /*!defined(FEATURE_ESAME)*/ #if defined(FEATURE_BCMODE) } else { SET_IC_BCMODE_MASK(regs); /* Processing for S/370 BC mode PSW */ regs->psw.intcode = fetch_hw (addr + 2); regs->psw.cc = (addr[4] & 0x30) >> 4; regs->psw.progmask = (addr[4] & 0x0F); FETCH_FW(regs->psw.IA, addr + 4); regs->psw.IA &= 0x00FFFFFF; regs->psw.AMASK = AMASK24; regs->psw.zerobyte = 0; regs->psw.asc = 0; regs->psw.amode64 = regs->psw.amode = 0; } #endif /*defined(FEATURE_BCMODE)*/ #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Bits 5 and 16 must be zero in XC mode */ if( SIE_STATB(regs, MX, XC) && ( (regs->psw.sysmask & PSW_DATMODE) || SPACE_BIT(®s->psw)) ) return PGM_SPECIFICATION_EXCEPTION; #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ regs->psw.zeroilc = 0; /* Check for wait state PSW */ if (WAITSTATE(®s->psw) && CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP043I Wait state PSW loaded: ")); display_psw (regs); } TEST_SET_AEA_MODE(regs); return 0; } /* end function ARCH_DEP(load_psw) */ /*-------------------------------------------------------------------*/ /* Load program interrupt new PSW */ /*-------------------------------------------------------------------*/ void (ATTR_REGPARM(2) ARCH_DEP(program_interrupt)) (REGS *regs, int pcode) { PSA *psa; /* -> Prefixed storage area */ REGS *realregs; /* True regs structure */ RADR px; /* host real address of pfx */ int code; /* pcode without PER ind. */ int ilc; /* instruction length */ #if defined(FEATURE_ESAME) /** FIXME : SEE ISW20090110-1 */ void *zmoncode=NULL; /* special reloc for z/Arch */ /* FIXME : zmoncode not being initialized here raises a potentially non-initialized warning in GCC.. can't find why. ISW 2009/02/04 */ /* mon call SIE intercept */ #endif #if defined(FEATURE_INTERPRETIVE_EXECUTION) int sie_ilc=0; /* SIE instruction length */ #endif #if defined(_FEATURE_SIE) int nointercept; /* True for virtual pgmint */ #endif /*defined(_FEATURE_SIE)*/ #if defined(OPTION_FOOTPRINT_BUFFER) U32 n; #endif /*defined(OPTION_FOOTPRINT_BUFFER)*/ char dxcstr[8]={0}; /* " DXC=xx" if data excptn */ static char *pgmintname[] = { /* 01 */ "Operation exception", /* 02 */ "Privileged-operation exception", /* 03 */ "Execute exception", /* 04 */ "Protection exception", /* 05 */ "Addressing exception", /* 06 */ "Specification exception", /* 07 */ "Data exception", /* 08 */ "Fixed-point-overflow exception", /* 09 */ "Fixed-point-divide exception", /* 0A */ "Decimal-overflow exception", /* 0B */ "Decimal-divide exception", /* 0C */ "HFP-exponent-overflow exception", /* 0D */ "HFP-exponent-underflow exception", /* 0E */ "HFP-significance exception", /* 0F */ "HFP-floating-point-divide exception", /* 10 */ "Segment-translation exception", /* 11 */ "Page-translation exception", /* 12 */ "Translation-specification exception", /* 13 */ "Special-operation exception", /* 14 */ "Pseudo-page-fault exception", /* 15 */ "Operand exception", /* 16 */ "Trace-table exception", /* 17 */ "ASN-translation exception", /* 18 */ "Page access exception", /* 19 */ "Vector/Crypto operation exception", /* 1A */ "Page state exception", /* 1B */ "Page transition exception", /* 1C */ "Space-switch event", /* 1D */ "Square-root exception", /* 1E */ "Unnormalized-operand exception", /* 1F */ "PC-translation specification exception", /* 20 */ "AFX-translation exception", /* 21 */ "ASX-translation exception", /* 22 */ "LX-translation exception", /* 23 */ "EX-translation exception", /* 24 */ "Primary-authority exception", /* 25 */ "Secondary-authority exception", /* 26 */ "LFX-translation exception", /*@ALR*/ /* 27 */ "LSX-translation exception", /*@ALR*/ /* 28 */ "ALET-specification exception", /* 29 */ "ALEN-translation exception", /* 2A */ "ALE-sequence exception", /* 2B */ "ASTE-validity exception", /* 2C */ "ASTE-sequence exception", /* 2D */ "Extended-authority exception", /* 2E */ "LSTE-sequence exception", /*@ALR*/ /* 2F */ "ASTE-instance exception", /*@ALR*/ /* 30 */ "Stack-full exception", /* 31 */ "Stack-empty exception", /* 32 */ "Stack-specification exception", /* 33 */ "Stack-type exception", /* 34 */ "Stack-operation exception", /* 35 */ "Unassigned exception", /* 36 */ "Unassigned exception", /* 37 */ "Unassigned exception", /* 38 */ "ASCE-type exception", /* 39 */ "Region-first-translation exception", /* 3A */ "Region-second-translation exception", /* 3B */ "Region-third-translation exception", /* 3C */ "Unassigned exception", /* 3D */ "Unassigned exception", /* 3E */ "Unassigned exception", /* 3F */ "Unassigned exception", /* 40 */ "Monitor event" }; /* 26 */ /* was "Page-fault-assist exception", */ /* 27 */ /* was "Control-switch exception", */ /* If called with ghost registers (ie from hercules command then ignore all interrupt handling and report the error to the caller */ if(regs->ghostregs) longjmp(regs->progjmp, pcode); PTT(PTT_CL_PGM,"*PROG",pcode,(U32)(regs->TEA & 0xffffffff),regs->psw.IA_L); /* program_interrupt() may be called with a shadow copy of the regs structure, realregs is the pointer to the real structure which must be used when loading/storing the psw, or backing up the instruction address in case of nullification */ #if defined(_FEATURE_SIE) realregs = SIE_MODE(regs) ? sysblk.regs[regs->cpuad]->guestregs : sysblk.regs[regs->cpuad]; #else /*!defined(_FEATURE_SIE)*/ realregs = sysblk.regs[regs->cpuad]; #endif /*!defined(_FEATURE_SIE)*/ /* Prevent machine check when in (almost) interrupt loop */ realregs->instcount++; /* Release any locks */ if (sysblk.intowner == realregs->cpuad) RELEASE_INTLOCK(realregs); if (sysblk.mainowner == realregs->cpuad) RELEASE_MAINLOCK(realregs); /* Ensure psw.IA is set and aia invalidated */ INVALIDATE_AIA(realregs); #if defined(FEATURE_INTERPRETIVE_EXECUTION) if(realregs->sie_active) INVALIDATE_AIA(realregs->guestregs); #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ /* Set instruction length (ilc) */ ilc = realregs->psw.zeroilc ? 0 : REAL_ILC(realregs); if (realregs->psw.ilc == 0 && !realregs->psw.zeroilc) { /* This can happen if BALR, BASR, BASSM or BSM program checks during trace */ ilc = realregs->execflag ? realregs->exrl ? 6 : 4 : 2; realregs->ip += ilc; realregs->psw.IA += ilc; realregs->psw.ilc = ilc; } #if defined(FEATURE_INTERPRETIVE_EXECUTION) if(realregs->sie_active) { sie_ilc = realregs->guestregs->psw.zeroilc ? 0 : REAL_ILC(realregs->guestregs); if (realregs->guestregs->psw.ilc == 0 && !realregs->guestregs->psw.zeroilc) { sie_ilc = realregs->guestregs->execflag ? realregs->guestregs->exrl ? 6 : 4 : 2; realregs->guestregs->psw.IA += sie_ilc; /* IanWorthington regression restored from 20081205 */ realregs->guestregs->psw.ilc = sie_ilc; } } #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ /* Set `execflag' to 0 in case EXecuted instruction program-checked */ realregs->execflag = 0; #if defined(FEATURE_INTERPRETIVE_EXECUTION) if(realregs->sie_active) realregs->guestregs->execflag = 0; #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ /* Unlock the main storage lock if held */ if (realregs->cpuad == sysblk.mainowner) RELEASE_MAINLOCK(realregs); /* Remove PER indication from program interrupt code such that interrupt code specific tests may be done. The PER indication will be stored in the PER handling code */ code = pcode & ~PGM_PER_EVENT; /* If this is a concurrent PER event then we must add the PER bit to the interrupts code */ if( OPEN_IC_PER(realregs) ) pcode |= PGM_PER_EVENT; /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (realregs); PERFORM_CHKPT_SYNC (realregs); #if defined(FEATURE_INTERPRETIVE_EXECUTION) /* Host protection and addressing exceptions must be reflected to the guest */ if(realregs->sie_active && (code == PGM_PROTECTION_EXCEPTION || code == PGM_ADDRESSING_EXCEPTION #if defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) || code == PGM_ALET_SPECIFICATION_EXCEPTION || code == PGM_ALEN_TRANSLATION_EXCEPTION || code == PGM_ALE_SEQUENCE_EXCEPTION || code == PGM_EXTENDED_AUTHORITY_EXCEPTION #endif /*defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ) { #if defined(SIE_DEBUG) logmsg(_("program_int() passing to guest code=%4.4X\n"),pcode); #endif /*defined(SIE_DEBUG)*/ realregs->guestregs->TEA = realregs->TEA; realregs->guestregs->excarid = realregs->excarid; realregs->guestregs->opndrid = realregs->opndrid; #if defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL) realregs->guestregs->hostint = 1; #endif /*defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL)*/ (realregs->guestregs->program_interrupt) (realregs->guestregs, pcode); } #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ /* Back up the PSW for exceptions which cause nullification, unless the exception occurred during instruction fetch */ if ((code == PGM_PAGE_TRANSLATION_EXCEPTION || code == PGM_SEGMENT_TRANSLATION_EXCEPTION #if defined(FEATURE_ESAME) || code == PGM_ASCE_TYPE_EXCEPTION || code == PGM_REGION_FIRST_TRANSLATION_EXCEPTION || code == PGM_REGION_SECOND_TRANSLATION_EXCEPTION || code == PGM_REGION_THIRD_TRANSLATION_EXCEPTION #endif /*defined(FEATURE_ESAME)*/ || code == PGM_TRACE_TABLE_EXCEPTION || code == PGM_AFX_TRANSLATION_EXCEPTION || code == PGM_ASX_TRANSLATION_EXCEPTION || code == PGM_LX_TRANSLATION_EXCEPTION || code == PGM_LFX_TRANSLATION_EXCEPTION /*@ALR*/ || code == PGM_LSX_TRANSLATION_EXCEPTION /*@ALR*/ || code == PGM_LSTE_SEQUENCE_EXCEPTION /*@ALR*/ || code == PGM_EX_TRANSLATION_EXCEPTION || code == PGM_PRIMARY_AUTHORITY_EXCEPTION || code == PGM_SECONDARY_AUTHORITY_EXCEPTION || code == PGM_ALEN_TRANSLATION_EXCEPTION || code == PGM_ALE_SEQUENCE_EXCEPTION || code == PGM_ASTE_VALIDITY_EXCEPTION || code == PGM_ASTE_SEQUENCE_EXCEPTION || code == PGM_ASTE_INSTANCE_EXCEPTION /*@ALR*/ || code == PGM_EXTENDED_AUTHORITY_EXCEPTION || code == PGM_STACK_FULL_EXCEPTION || code == PGM_STACK_EMPTY_EXCEPTION || code == PGM_STACK_SPECIFICATION_EXCEPTION || code == PGM_STACK_TYPE_EXCEPTION || code == PGM_STACK_OPERATION_EXCEPTION || code == PGM_VECTOR_OPERATION_EXCEPTION) && !realregs->instinvalid) { realregs->psw.IA -= ilc; realregs->psw.IA &= ADDRESS_MAXWRAP(realregs); #if defined(FEATURE_INTERPRETIVE_EXECUTION) /* When in SIE mode the guest instruction causing this host exception must also be nullified */ if(realregs->sie_active && !realregs->guestregs->instinvalid) { realregs->guestregs->psw.IA -= sie_ilc; realregs->guestregs->psw.IA &= ADDRESS_MAXWRAP(realregs->guestregs); } #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ } /* The OLD PSW must be incremented on the following exceptions during instfetch */ if(realregs->instinvalid && ( code == PGM_PROTECTION_EXCEPTION || code == PGM_ADDRESSING_EXCEPTION || code == PGM_SPECIFICATION_EXCEPTION || code == PGM_TRANSLATION_SPECIFICATION_EXCEPTION )) { realregs->psw.IA += ilc; realregs->psw.IA &= ADDRESS_MAXWRAP(realregs); } /* Store the interrupt code in the PSW */ realregs->psw.intcode = pcode; /* Call debugger if active */ HDC2(debug_program_interrupt, regs, pcode); /* Trace program checks other then PER event */ if(code && (CPU_STEPPING_OR_TRACING(realregs, ilc) || sysblk.pgminttr & ((U64)1 << ((code - 1) & 0x3F)))) { BYTE *ip; #if defined(OPTION_FOOTPRINT_BUFFER) if(!(sysblk.insttrace || sysblk.inststep)) for(n = sysblk.footprptr[realregs->cpuad] + 1 ; n != sysblk.footprptr[realregs->cpuad]; n++, n &= OPTION_FOOTPRINT_BUFFER - 1) ARCH_DEP(display_inst) (&sysblk.footprregs[realregs->cpuad][n], sysblk.footprregs[realregs->cpuad][n].inst); #endif /*defined(OPTION_FOOTPRINT_BUFFER)*/ logmsg(_("HHCCP014I ")); #if defined(_FEATURE_SIE) if(SIE_MODE(realregs)) logmsg(_("SIE: ")); #endif /*defined(_FEATURE_SIE)*/ #if defined(SIE_DEBUG) logmsg (MSTRING(_GEN_ARCH) " "); #endif /*defined(SIE_DEBUG)*/ if (code == PGM_DATA_EXCEPTION) sprintf(dxcstr, " DXC=%2.2X", regs->dxc); logmsg (_("CPU%4.4X: %s CODE=%4.4X ILC=%d%s\n"), realregs->cpuad, pgmintname[ (code - 1) & 0x3F], pcode, ilc, dxcstr); /* Calculate instruction pointer */ ip = realregs->instinvalid ? NULL : (realregs->ip - ilc < realregs->aip) ? realregs->inst : realregs->ip - ilc; ARCH_DEP(display_inst) (realregs, ip); } realregs->instinvalid = 0; #if defined(FEATURE_INTERPRETIVE_EXECUTION) /* If this is a host exception in SIE state then leave SIE */ if(realregs->sie_active) ARCH_DEP(sie_exit) (realregs, SIE_HOST_PGMINT); #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ /* Absolute address of prefix page */ px = realregs->PX; /* If under SIE use translated to host absolute prefix */ #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) px = regs->sie_px; #endif #if defined(_FEATURE_SIE) if(!SIE_MODE(regs) || /* Interception is mandatory for the following exceptions */ ( #if defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL) !(code == PGM_PROTECTION_EXCEPTION && (!SIE_FEATB(regs, EC2, PROTEX) || realregs->hostint)) #else /*!defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL)*/ code != PGM_PROTECTION_EXCEPTION #endif /*!defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL)*/ #if defined (_FEATURE_PER2) && !((pcode & PGM_PER_EVENT) && SIE_FEATB(regs, M, GPE)) #endif /* defined (_FEATURE_PER2) */ && code != PGM_ADDRESSING_EXCEPTION && code != PGM_SPECIFICATION_EXCEPTION && code != PGM_SPECIAL_OPERATION_EXCEPTION #ifdef FEATURE_VECTOR_FACILITY && code != PGM_VECTOR_OPERATION_EXCEPTION #endif /*FEATURE_VECTOR_FACILITY*/ #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) && !(code == PGM_ALEN_TRANSLATION_EXCEPTION && SIE_FEATB(regs, MX, XC)) && !(code == PGM_ALE_SEQUENCE_EXCEPTION && SIE_FEATB(regs, MX, XC)) && !(code == PGM_EXTENDED_AUTHORITY_EXCEPTION && SIE_FEATB(regs, MX, XC)) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* And conditional for the following exceptions */ && !(code == PGM_OPERATION_EXCEPTION && SIE_FEATB(regs, IC0, OPEREX)) && !(code == PGM_PRIVILEGED_OPERATION_EXCEPTION && SIE_FEATB(regs, IC0, PRIVOP)) #ifdef FEATURE_BASIC_FP_EXTENSIONS && !(code == PGM_DATA_EXCEPTION && (regs->dxc == 1 || regs->dxc == 2) && (regs->CR(0) & CR0_AFP) && !(regs->hostregs->CR(0) & CR0_AFP)) #endif /*FEATURE_BASIC_FP_EXTENSIONS*/ /* Or all exceptions if requested as such */ && !SIE_FEATB(regs, IC0, PGMALL) ) ) { #endif /*defined(_FEATURE_SIE)*/ /* Set the main storage reference and change bits */ STORAGE_KEY(px, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Point to PSA in main storage */ psa = (void*)(regs->mainstor + px); #if defined(_FEATURE_SIE) #if defined(FEATURE_ESAME) /** FIXME : SEE ISW20090110-1 */ if(code == PGM_MONITOR_EVENT) { zmoncode=psa->moncode; } #endif nointercept = 1; } else { /* This is a guest interruption interception so point to the interruption parm area in the state descriptor rather then the PSA, except for the operation exception */ if(code != PGM_OPERATION_EXCEPTION) { psa = (void*)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_IP_PSA_OFFSET); /* Set the main storage reference and change bits */ STORAGE_KEY(SIE_STATE(regs), regs->hostregs) |= (STORKEY_REF | STORKEY_CHANGE); #if defined(FEATURE_ESAME) /** FIXME : SEE ISW20090110-1 */ if(code == PGM_MONITOR_EVENT) { PSA *_psa; _psa=(void *)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_II_PSA_OFFSET); zmoncode=_psa->ioid; } #endif } else { /* Point to PSA in main storage */ psa = (void*)(regs->mainstor + px); /* Set the main storage reference and change bits */ STORAGE_KEY(px, regs) |= (STORKEY_REF | STORKEY_CHANGE); } nointercept = 0; } #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_PER) /* Handle PER or concurrent PER event */ /* Throw out Stor Alter PER if merged with nullified/suppressed rupt */ if ( IS_IC_PER_SA(realregs) && !IS_IC_PER_STURA(realregs) && (realregs->ip[0] != 0x0E) && !(code == 0x00 || code == 0x06 || code == 0x08 || code == 0x0A || code == 0x0C || code == 0x0D || code == 0x0E || code == 0x1C || code == 0x40) ) OFF_IC_PER_SA(realregs); if( OPEN_IC_PER(realregs) ) { if( CPU_STEPPING_OR_TRACING(realregs, ilc) ) logmsg(_("HHCCP015I CPU%4.4X PER event: code=%4.4X perc=%2.2X " "addr=" F_VADR "\n"), regs->cpuad, pcode, IS_IC_PER(realregs) >> 16, (realregs->psw.IA - ilc) & ADDRESS_MAXWRAP(realregs) ); realregs->perc |= OPEN_IC_PER(realregs) >> ((32 - IC_CR9_SHIFT) - 16); /* Positions 14 and 15 contain zeros if a storage alteration event was not indicated */ //FIXME: is this right?? if( !(OPEN_IC_PER_SA(realregs)) || (OPEN_IC_PER_STURA(realregs)) ) realregs->perc &= 0xFFFC; STORE_HW(psa->perint, realregs->perc); STORE_W(psa->peradr, realregs->peradr); if( IS_IC_PER_SA(realregs) && ACCESS_REGISTER_MODE(&realregs->psw) ) psa->perarid = realregs->peraid; #if defined(_FEATURE_SIE) /* Reset PER pending indication */ if(nointercept) OFF_IC_PER(realregs); #endif } else { pcode &= 0xFF7F; } #endif /*defined(_FEATURE_PER)*/ #if defined(FEATURE_BCMODE) /* For ECMODE, store extended interrupt information in PSA */ if ( ECMODE(&realregs->psw) ) #endif /*defined(FEATURE_BCMODE)*/ { /* Store the program interrupt code at PSA+X'8C' */ psa->pgmint[0] = 0; psa->pgmint[1] = ilc; STORE_HW(psa->pgmint + 2, pcode); /* Store the exception access identification at PSA+160 */ if ( code == PGM_PAGE_TRANSLATION_EXCEPTION || code == PGM_SEGMENT_TRANSLATION_EXCEPTION #if defined(FEATURE_ESAME) || code == PGM_ASCE_TYPE_EXCEPTION || code == PGM_REGION_FIRST_TRANSLATION_EXCEPTION || code == PGM_REGION_SECOND_TRANSLATION_EXCEPTION || code == PGM_REGION_THIRD_TRANSLATION_EXCEPTION #endif /*defined(FEATURE_ESAME)*/ || code == PGM_ALEN_TRANSLATION_EXCEPTION || code == PGM_ALE_SEQUENCE_EXCEPTION || code == PGM_ASTE_VALIDITY_EXCEPTION || code == PGM_ASTE_SEQUENCE_EXCEPTION || code == PGM_ASTE_INSTANCE_EXCEPTION /*@ALR*/ || code == PGM_EXTENDED_AUTHORITY_EXCEPTION #ifdef FEATURE_SUPPRESSION_ON_PROTECTION || code == PGM_PROTECTION_EXCEPTION #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ) { psa->excarid = regs->excarid; if(regs->TEA | TEA_MVPG) psa->opndrid = regs->opndrid; realregs->opndrid = 0; } #if defined(FEATURE_ESAME) /* Store the translation exception address at PSA+168 */ if ( code == PGM_PAGE_TRANSLATION_EXCEPTION || code == PGM_SEGMENT_TRANSLATION_EXCEPTION || code == PGM_ASCE_TYPE_EXCEPTION || code == PGM_REGION_FIRST_TRANSLATION_EXCEPTION || code == PGM_REGION_SECOND_TRANSLATION_EXCEPTION || code == PGM_REGION_THIRD_TRANSLATION_EXCEPTION #ifdef FEATURE_SUPPRESSION_ON_PROTECTION || code == PGM_PROTECTION_EXCEPTION #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ) { STORE_DW(psa->TEA_G, regs->TEA); } /* Store the translation exception address at PSA+172 */ if ( code == PGM_AFX_TRANSLATION_EXCEPTION || code == PGM_ASX_TRANSLATION_EXCEPTION || code == PGM_PRIMARY_AUTHORITY_EXCEPTION || code == PGM_SECONDARY_AUTHORITY_EXCEPTION || code == PGM_SPACE_SWITCH_EVENT || code == PGM_LX_TRANSLATION_EXCEPTION || code == PGM_LFX_TRANSLATION_EXCEPTION /*@ALR*/ || code == PGM_LSX_TRANSLATION_EXCEPTION /*@ALR*/ || code == PGM_LSTE_SEQUENCE_EXCEPTION /*@ALR*/ || code == PGM_EX_TRANSLATION_EXCEPTION) { STORE_FW(psa->TEA_L, regs->TEA); } #else /*!defined(FEATURE_ESAME)*/ /* Store the translation exception address at PSA+144 */ if ( code == PGM_PAGE_TRANSLATION_EXCEPTION || code == PGM_SEGMENT_TRANSLATION_EXCEPTION || code == PGM_AFX_TRANSLATION_EXCEPTION || code == PGM_ASX_TRANSLATION_EXCEPTION || code == PGM_PRIMARY_AUTHORITY_EXCEPTION || code == PGM_SECONDARY_AUTHORITY_EXCEPTION || code == PGM_SPACE_SWITCH_EVENT || code == PGM_LX_TRANSLATION_EXCEPTION || code == PGM_EX_TRANSLATION_EXCEPTION #ifdef FEATURE_SUPPRESSION_ON_PROTECTION || code == PGM_PROTECTION_EXCEPTION #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ) { STORE_FW(psa->tea, regs->TEA); } #endif /*!defined(FEATURE_ESAME)*/ realregs->TEA = 0; /* Store Data exception code in PSA */ if (code == PGM_DATA_EXCEPTION) { STORE_FW(psa->DXC, regs->dxc); #ifdef FEATURE_BASIC_FP_EXTENSIONS /* Load data exception code into FPC register byte 2 */ if(regs->CR(0) & CR0_AFP) { regs->fpc &= ~(FPC_DXC); regs->fpc |= ((regs->dxc << 8)) & FPC_DXC; } #endif /*FEATURE_BASIC_FP_EXTENSIONS*/ } /* Store the monitor class and event code */ if (code == PGM_MONITOR_EVENT) { STORE_HW(psa->monclass, regs->monclass); /* Store the monitor code word at PSA+156 */ /* or doubleword at PSA+176 */ /* ISW20090110-1 ZSIEMCFIX */ /* In the event of a z/Arch guest being */ /* intercepted during a succesful Monitor */ /* call, the monitor code is not stored */ /* at psa->moncode (which is beyond sie2bk->ip */ /* but rather at the same location as an */ /* I/O interrupt would store the SSID */ /* zmoncode points to this location */ /* **** FIXME **** FIXME *** FIXME *** */ /* ---- The determination of the location */ /* of the z/Sie Intercept moncode */ /* should be made more flexible */ /* and should be put somewhere in */ /* esa390.h */ /* **** FIXME **** FIXME *** FIXME *** */ #if defined(FEATURE_ESAME) STORE_DW(zmoncode, regs->MONCODE); #else STORE_W(psa->moncode, regs->MONCODE); #endif } #if defined(FEATURE_PER3) /* Store the breaking event address register in the PSA */ SET_BEAR_REG(regs, regs->bear_ip); STORE_W(psa->bea, regs->bear); #endif /*defined(FEATURE_PER3)*/ } /* end if(ECMODE) */ #if defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL) realregs->hostint = 0; #endif /*defined(_FEATURE_PROTECTION_INTERCEPTION_CONTROL)*/ #if defined(_FEATURE_SIE) if(nointercept) { #endif /*defined(_FEATURE_SIE)*/ //FIXME: Why are we getting intlock here?? // OBTAIN_INTLOCK(realregs); /* Store current PSW at PSA+X'28' or PSA+X'150' for ESAME */ ARCH_DEP(store_psw) (realregs, psa->pgmold); /* Load new PSW from PSA+X'68' or PSA+X'1D0' for ESAME */ if ( (code = ARCH_DEP(load_psw) (realregs, psa->pgmnew)) ) { #if defined(_FEATURE_SIE) if(SIE_MODE(realregs)) { // RELEASE_INTLOCK(realregs); longjmp(realregs->progjmp, pcode); } else #endif /*defined(_FEATURE_SIE)*/ { logmsg (_("HHCCP016I CPU%4.4X: Program interrupt loop: "), realregs->cpuad); display_psw (realregs); OBTAIN_INTLOCK(realregs); realregs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(realregs); RELEASE_INTLOCK(realregs); } } // RELEASE_INTLOCK(realregs); longjmp(realregs->progjmp, SIE_NO_INTERCEPT); #if defined(_FEATURE_SIE) } longjmp (realregs->progjmp, pcode); #endif /*defined(_FEATURE_SIE)*/ } /* end function ARCH_DEP(program_interrupt) */ /*-------------------------------------------------------------------*/ /* Load restart new PSW */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(restart_interrupt) (REGS *regs) { int rc; /* Return code */ PSA *psa; /* -> Prefixed storage area */ PTT(PTT_CL_INF,"*RESTART",regs->cpuad,regs->cpustate,regs->psw.IA_L); /* Set the main storage reference and change bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Zeroize the interrupt code in the PSW */ regs->psw.intcode = 0; /* Point to PSA in main storage */ psa = (PSA*)(regs->mainstor + regs->PX); /* Store current PSW at PSA+X'8' or PSA+X'120' for ESAME */ ARCH_DEP(store_psw) (regs, psa->RSTOLD); /* Load new PSW from PSA+X'0' or PSA+X'1A0' for ESAME */ rc = ARCH_DEP(load_psw) (regs, psa->RSTNEW); if ( rc == 0) { regs->opinterv = 0; regs->cpustate = CPUSTATE_STARTED; } RELEASE_INTLOCK(regs); if ( rc ) regs->program_interrupt(regs, rc); longjmp (regs->progjmp, SIE_INTERCEPT_RESTART); } /* end function restart_interrupt */ /*-------------------------------------------------------------------*/ /* Perform I/O interrupt if pending */ /* Note: The caller MUST hold the interrupt lock (sysblk.intlock) */ /*-------------------------------------------------------------------*/ void ARCH_DEP(perform_io_interrupt) (REGS *regs) { int rc; /* Return code */ int icode; /* Intercept code */ PSA *psa; /* -> Prefixed storage area */ U32 ioparm; /* I/O interruption parameter*/ U32 ioid; /* I/O interruption address */ U32 iointid; /* I/O interruption ident */ RADR pfx; /* Prefix */ DBLWRD csw; /* CSW for S/370 channels */ /* Test and clear pending I/O interrupt */ icode = ARCH_DEP(present_io_interrupt) (regs, &ioid, &ioparm, &iointid, csw); /* Exit if no interrupt was presented */ if (icode == 0) return; PTT(PTT_CL_IO,"*IOINT",ioid,ioparm,iointid); #if defined(_FEATURE_IO_ASSIST) if(SIE_MODE(regs) && icode != SIE_NO_INTERCEPT) { /* Point to SIE copy of PSA in state descriptor */ psa = (void*)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_II_PSA_OFFSET); STORAGE_KEY(SIE_STATE(regs), regs->hostregs) |= (STORKEY_REF | STORKEY_CHANGE); } else #endif { /* Point to PSA in main storage */ pfx = #if defined(_FEATURE_SIE) SIE_MODE(regs) ? regs->sie_px : #endif regs->PX; psa = (void*)(regs->mainstor + pfx); STORAGE_KEY(pfx, regs) |= (STORKEY_REF | STORKEY_CHANGE); } #ifdef FEATURE_S370_CHANNEL /* Store the channel status word at PSA+X'40' */ memcpy (psa->csw, csw, 8); /* Set the interrupt code to the I/O device address */ regs->psw.intcode = ioid; /* For ECMODE, store the I/O device address at PSA+X'B8' */ if (ECMODE(®s->psw)) STORE_FW(psa->ioid, ioid); /* Trace the I/O interrupt */ if (CPU_STEPPING_OR_TRACING(regs, 0)) logmsg (_("HHCCP044I I/O interrupt code=%4.4X " "CSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n"), regs->psw.intcode, csw[0], csw[1], csw[2], csw[3], csw[4], csw[5], csw[6], csw[7]); #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Store X'0001' + subchannel number at PSA+X'B8' */ STORE_FW(psa->ioid, ioid); /* Store the I/O interruption parameter at PSA+X'BC' */ STORE_FW(psa->ioparm, ioparm); #if defined(FEATURE_ESAME) || defined(_FEATURE_IO_ASSIST) /* Store the I/O interruption identification word at PSA+X'C0' */ STORE_FW(psa->iointid, iointid); #endif /*defined(FEATURE_ESAME)*/ /* Trace the I/O interrupt */ if (CPU_STEPPING_OR_TRACING(regs, 0)) #if !defined(FEATURE_ESAME) && !defined(_FEATURE_IO_ASSIST) logmsg (_("HHCCP045I I/O interrupt code=%8.8X parm=%8.8X\n"), ioid, ioparm); #else /*defined(FEATURE_ESAME)*/ logmsg (_("HHCCP046I I/O interrupt code=%8.8X parm=%8.8X id=%8.8X\n"), ioid, ioparm, iointid); #endif /*defined(FEATURE_ESAME)*/ #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ #if defined(_FEATURE_IO_ASSIST) if(icode == SIE_NO_INTERCEPT) #endif { /* Store current PSW at PSA+X'38' or PSA+X'170' for ESAME */ ARCH_DEP(store_psw) ( regs, psa->iopold ); /* Load new PSW from PSA+X'78' or PSA+X'1F0' for ESAME */ rc = ARCH_DEP(load_psw) ( regs, psa->iopnew ); if ( rc ) { RELEASE_INTLOCK(regs); regs->program_interrupt (regs, rc); } } RELEASE_INTLOCK(regs); longjmp(regs->progjmp, icode); } /* end function perform_io_interrupt */ /*-------------------------------------------------------------------*/ /* Perform Machine Check interrupt if pending */ /* Note: The caller MUST hold the interrupt lock (sysblk.intlock) */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(perform_mck_interrupt) (REGS *regs) { int rc; /* Return code */ PSA *psa; /* -> Prefixed storage area */ U64 mcic; /* Mach.check interrupt code */ U32 xdmg; /* External damage code */ RADR fsta; /* Failing storage address */ /* Test and clear pending machine check interrupt */ rc = ARCH_DEP(present_mck_interrupt) (regs, &mcic, &xdmg, &fsta); /* Exit if no machine check was presented */ if (rc == 0) return; /* Set the main storage reference and change bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Point to the PSA in main storage */ psa = (void*)(regs->mainstor + regs->PX); /* Store registers in machine check save area */ ARCH_DEP(store_status) (regs, regs->PX); #if !defined(FEATURE_ESAME) // ZZ /* Set the extended logout area to zeros */ memset(psa->storepsw, 0, 16); #endif /* Store the machine check interrupt code at PSA+232 */ STORE_DW(psa->mckint, mcic); /* Trace the machine check interrupt */ if (CPU_STEPPING_OR_TRACING(regs, 0)) logmsg (_("HHCCP022I Machine Check code=%16.16" I64_FMT "u\n"), (long long)mcic); /* Store the external damage code at PSA+244 */ STORE_FW(psa->xdmgcode, xdmg); #if defined(FEATURE_ESAME) /* Store the failing storage address at PSA+248 */ STORE_DW(psa->mcstorad, fsta); #else /*!defined(FEATURE_ESAME)*/ /* Store the failing storage address at PSA+248 */ STORE_FW(psa->mcstorad, fsta); #endif /*!defined(FEATURE_ESAME)*/ /* Store current PSW at PSA+X'30' */ ARCH_DEP(store_psw) ( regs, psa->mckold ); /* Load new PSW from PSA+X'70' */ rc = ARCH_DEP(load_psw) ( regs, psa->mcknew ); RELEASE_INTLOCK(regs); if ( rc ) regs->program_interrupt (regs, rc); longjmp (regs->progjmp, SIE_INTERCEPT_MCK); } /* end function perform_mck_interrupt */ #if !defined(_GEN_ARCH) REGS *s370_run_cpu (int cpu, REGS *oldregs); REGS *s390_run_cpu (int cpu, REGS *oldregs); REGS *z900_run_cpu (int cpu, REGS *oldregs); static REGS *(* run_cpu[GEN_MAXARCH]) (int cpu, REGS *oldregs) = { #if defined(_370) s370_run_cpu, #endif #if defined(_390) s390_run_cpu, #endif #if defined(_900) z900_run_cpu #endif }; /*-------------------------------------------------------------------*/ /* CPU instruction execution thread */ /*-------------------------------------------------------------------*/ void *cpu_thread (int *ptr) { REGS *regs = NULL; int cpu = *ptr; OBTAIN_INTLOCK(NULL); /* Signal cpu has started */ signal_condition (&sysblk.cpucond); /* Increment number of CPUs online */ sysblk.cpus++; /* Set hi CPU */ if (cpu >= sysblk.hicpu) sysblk.hicpu = cpu + 1; /* Start the TOD clock and CPU timer thread */ if (!sysblk.todtid) { if ( create_thread (&sysblk.todtid, DETACHED, timer_update_thread, NULL, "timer_update_thread") ) { logmsg (_("HHCCP006S Cannot create timer thread: %s\n"), strerror(errno)); RELEASE_INTLOCK(NULL); return NULL; } } /* Set root mode in order to set priority */ SETMODE(ROOT); /* Set CPU thread priority */ if (setpriority(PRIO_PROCESS, 0, sysblk.cpuprio)) logmsg (_("HHCCP001W CPU%4.4X thread set priority %d failed: %s\n"), cpu, sysblk.cpuprio, strerror(errno)); /* Back to user mode */ SETMODE(USER); /* Display thread started message on control panel */ logmsg (_("HHCCP002I CPU%4.4X thread started: tid="TIDPAT", pid=%d, " "priority=%d\n"), cpu, thread_id(), getpid(), getpriority(PRIO_PROCESS,0)); /* Execute the program in specified mode */ do { regs = run_cpu[sysblk.arch_mode] (cpu, regs); } while (regs); /* Decrement number of CPUs online */ sysblk.cpus--; /* Reset hi cpu */ if (cpu + 1 >= sysblk.hicpu) { int i; for (i = MAX_CPU_ENGINES - 1; i >= 0; i--) if (IS_CPU_ONLINE(i)) break; sysblk.hicpu = i + 1; } /* Signal cpu has terminated */ signal_condition (&sysblk.cpucond); /* Display thread ended message on control panel */ logmsg (_("HHCCP008I CPU%4.4X thread ended: tid="TIDPAT", pid=%d\n"), cpu, thread_id(), getpid()); RELEASE_INTLOCK(NULL); return NULL; } void s370_set_jump_pointers(REGS *regs, int jump); void s390_set_jump_pointers(REGS *regs, int jump); void z900_set_jump_pointers(REGS *regs, int jump); /*-------------------------------------------------------------------*/ /* Initialize a CPU */ /*-------------------------------------------------------------------*/ int cpu_init (int cpu, REGS *regs, REGS *hostregs) { int i; obtain_lock (&sysblk.cpulock[cpu]); regs->cpuad = cpu; regs->cpubit = CPU_BIT(cpu); regs->arch_mode = sysblk.arch_mode; regs->mainstor = sysblk.mainstor; regs->sysblk = &sysblk; /* * ISW20060125 : LINE REMOVED : This is the job of * the INITIAL CPU RESET */ #if 0 regs->psa = (PSA*)regs->mainstor; #endif regs->storkeys = sysblk.storkeys; regs->mainlim = sysblk.mainsize - 1; regs->tod_epoch = get_tod_epoch(); initialize_condition (®s->intcond); regs->cpulock = &sysblk.cpulock[cpu]; #if defined(_FEATURE_VECTOR_FACILITY) regs->vf = &sysblk.vf[cpu]; regs->vf->online = (cpu < sysblk.numvec); #endif /*defined(_FEATURE_VECTOR_FACILITY)*/ initial_cpu_reset(regs); if (hostregs == NULL) { regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); regs->hostregs = regs; regs->host = 1; sysblk.regs[cpu] = regs; sysblk.config_mask |= regs->cpubit; sysblk.started_mask |= regs->cpubit; } else { hostregs->guestregs = regs; regs->hostregs = hostregs; regs->guestregs = regs; regs->guest = 1; regs->sie_mode = 1; regs->opinterv = 0; regs->cpustate = CPUSTATE_STARTED; } /* Initialize accelerated lookup fields */ regs->CR_G(CR_ASD_REAL) = TLB_REAL_ASD; for(i = 0; i < 16; i++) regs->aea_ar[i] = CR_ASD_REAL; regs->aea_ar[USE_INST_SPACE] = CR_ASD_REAL; regs->aea_ar[USE_REAL_ADDR] = CR_ASD_REAL; regs->aea_ar[USE_PRIMARY_SPACE] = 1; regs->aea_ar[USE_SECONDARY_SPACE] = 7; regs->aea_ar[USE_HOME_SPACE] = 13; /* Initialize opcode table pointers */ set_opcode_pointers (regs); /* Set multi-byte jump code pointers */ #if defined(_370) s370_set_jump_pointers(regs, 0); #endif #if defined(_390) s390_set_jump_pointers(regs, 0); #endif #if defined(_900) z900_set_jump_pointers(regs, 0); #endif regs->configured = 1; release_lock (&sysblk.cpulock[cpu]); #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) /* Set topology-change-report-pending condition */ sysblk.topchnge = 1; #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ return 0; } /*-------------------------------------------------------------------*/ /* Uninitialize a CPU */ /*-------------------------------------------------------------------*/ void *cpu_uninit (int cpu, REGS *regs) { if (regs->host) { obtain_lock (&sysblk.cpulock[cpu]); if (regs->guestregs) { cpu_uninit (cpu, regs->guestregs); free (regs->guestregs); } } destroy_condition(®s->intcond); if (regs->host) { #ifdef FEATURE_VECTOR_FACILITY /* Mark Vector Facility offline */ regs->vf->online = 0; #endif /*FEATURE_VECTOR_FACILITY*/ /* Remove CPU from all CPU bit masks */ sysblk.config_mask &= ~CPU_BIT(cpu); sysblk.started_mask &= ~CPU_BIT(cpu); sysblk.waiting_mask &= ~CPU_BIT(cpu); sysblk.regs[cpu] = NULL; release_lock (&sysblk.cpulock[cpu]); } #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) /* Set topology-change-report-pending condition */ sysblk.topchnge = 1; #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ return NULL; } #endif /*!defined(_GEN_ARCH)*/ /*-------------------------------------------------------------------*/ /* Process interrupt */ /*-------------------------------------------------------------------*/ void (ATTR_REGPARM(1) ARCH_DEP(process_interrupt))(REGS *regs) { /* Process PER program interrupts */ if( OPEN_IC_PER(regs) ) regs->program_interrupt (regs, PGM_PER_EVENT); /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); OFF_IC_INTERRUPT(regs); regs->tracing = (sysblk.inststep || sysblk.insttrace); /* Ensure psw.IA is set and invalidate the aia */ INVALIDATE_AIA(regs); /* Perform invalidation */ if (unlikely(regs->invalidate)) ARCH_DEP(invalidate_tlbe)(regs, regs->invalidate_main); /* Take interrupts if CPU is not stopped */ if (likely(regs->cpustate == CPUSTATE_STARTED)) { /* Process machine check interrupt */ if ( OPEN_IC_MCKPENDING(regs) ) { PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); ARCH_DEP (perform_mck_interrupt) (regs); } /* Process external interrupt */ if ( OPEN_IC_EXTPENDING(regs) ) { PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); ARCH_DEP (perform_external_interrupt) (regs); } /* Process I/O interrupt */ if (IS_IC_IOPENDING) { if ( OPEN_IC_IOPENDING(regs) ) { PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); ARCH_DEP (perform_io_interrupt) (regs); } else WAKEUP_CPU_MASK(sysblk.waiting_mask); } } /*CPU_STARTED*/ /* If CPU is stopping, change status to stopped */ if (unlikely(regs->cpustate == CPUSTATE_STOPPING)) { /* Change CPU status to stopped */ regs->opinterv = 0; regs->cpustate = CPUSTATE_STOPPED; /* Thread exit (note - intlock still held) */ if (!regs->configured) longjmp(regs->exitjmp, SIE_NO_INTERCEPT); /* If initial CPU reset pending then perform reset */ if (regs->sigpireset) { PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); ARCH_DEP (initial_cpu_reset) (regs); RELEASE_INTLOCK(regs); longjmp(regs->progjmp, SIE_NO_INTERCEPT); } /* If a CPU reset is pending then perform the reset */ if (regs->sigpreset) { PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); ARCH_DEP(cpu_reset) (regs); RELEASE_INTLOCK(regs); longjmp(regs->progjmp, SIE_NO_INTERCEPT); } /* Store status at absolute location 0 if requested */ if (IS_IC_STORSTAT(regs)) { OFF_IC_STORSTAT(regs); ARCH_DEP(store_status) (regs, 0); logmsg (_("HHCCP010I CPU%4.4X store status completed.\n"), regs->cpuad); /* ISW 20071102 : Do not return via longjmp here. */ /* process_interrupt needs to finish putting the */ /* CPU in its manual state */ /* RELEASE_INTLOCK(regs); longjmp(regs->progjmp, SIE_NO_INTERCEPT); */ } } /*CPUSTATE_STOPPING*/ /* Perform restart interrupt if pending */ if ( IS_IC_RESTART(regs) ) { PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); OFF_IC_RESTART(regs); ARCH_DEP(restart_interrupt) (regs); } /* end if(restart) */ /* This is where a stopped CPU will wait */ if (unlikely(regs->cpustate == CPUSTATE_STOPPED)) { S64 saved_timer = cpu_timer(regs); regs->ints_state = IC_INITIAL_STATE; sysblk.started_mask ^= regs->cpubit; sysblk.intowner = LOCK_OWNER_NONE; /* Wait while we are STOPPED */ wait_condition (®s->intcond, &sysblk.intlock); /* Wait while SYNCHRONIZE_CPUS is in progress */ while (sysblk.syncing) wait_condition (&sysblk.sync_bc_cond, &sysblk.intlock); sysblk.intowner = regs->cpuad; sysblk.started_mask |= regs->cpubit; regs->ints_state |= sysblk.ints_state; set_cpu_timer(regs,saved_timer); ON_IC_INTERRUPT(regs); /* Purge the lookaside buffers */ ARCH_DEP(purge_tlb) (regs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (regs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /* If the architecture mode has changed we must adapt */ if(sysblk.arch_mode != regs->arch_mode) longjmp(regs->archjmp,SIE_NO_INTERCEPT); RELEASE_INTLOCK(regs); longjmp(regs->progjmp, SIE_NO_INTERCEPT); } /*CPUSTATE_STOPPED*/ /* Test for wait state */ if (WAITSTATE(®s->psw)) { #ifdef OPTION_MIPS_COUNTING regs->waittod = host_tod(); #endif /* Test for disabled wait PSW and issue message */ if( IS_IC_DISABLED_WAIT_PSW(regs) ) { logmsg (_("HHCCP011I CPU%4.4X: Disabled wait state\n" " "), regs->cpuad); display_psw (regs); regs->cpustate = CPUSTATE_STOPPING; RELEASE_INTLOCK(regs); longjmp(regs->progjmp, SIE_NO_INTERCEPT); } /* Indicate we are giving up intlock */ sysblk.intowner = LOCK_OWNER_NONE; sysblk.waiting_mask |= regs->cpubit; /* Wait for interrupt */ wait_condition (®s->intcond, &sysblk.intlock); /* Wait while SYNCHRONIZE_CPUS is in progress */ while (sysblk.syncing) wait_condition (&sysblk.sync_bc_cond, &sysblk.intlock); /* Indicate we now own intlock */ sysblk.waiting_mask ^= regs->cpubit; sysblk.intowner = regs->cpuad; #ifdef OPTION_MIPS_COUNTING /* Calculate the time we waited */ regs->waittime += host_tod() - regs->waittod; regs->waittod = 0; #endif RELEASE_INTLOCK(regs); longjmp(regs->progjmp, SIE_NO_INTERCEPT); } /* end if(wait) */ /* Release the interrupt lock */ RELEASE_INTLOCK(regs); return; } /* process_interrupt */ /*-------------------------------------------------------------------*/ /* Run CPU */ /*-------------------------------------------------------------------*/ REGS *ARCH_DEP(run_cpu) (int cpu, REGS *oldregs) { BYTE *ip; REGS regs; if (oldregs) { memcpy (®s, oldregs, sizeof(REGS)); free (oldregs); regs.hostregs = ®s; if (regs.guestregs) regs.guestregs->hostregs = ®s; sysblk.regs[cpu] = ®s; release_lock(&sysblk.cpulock[cpu]); logmsg (_("HHCCP007I CPU%4.4X architecture mode set to %s\n"), cpu, get_arch_mode_string(®s)); } else { memset (®s, 0, sizeof(REGS)); if (cpu_init (cpu, ®s, NULL)) return NULL; logmsg (_("HHCCP003I CPU%4.4X architecture mode %s\n"), cpu, get_arch_mode_string(®s)); #ifdef FEATURE_VECTOR_FACILITY if (regs->vf->online) logmsg (_("HHCCP004I CPU%4.4X Vector Facility online\n"), cpu); #endif /*FEATURE_VECTOR_FACILITY*/ } regs.program_interrupt = &ARCH_DEP(program_interrupt); #if defined(FEATURE_TRACING) regs.trace_br = (func)&ARCH_DEP(trace_br); #endif regs.tracing = (sysblk.inststep || sysblk.insttrace); regs.ints_state |= sysblk.ints_state; /* Establish longjmp destination for cpu thread exit */ if (setjmp(regs.exitjmp)) return cpu_uninit(cpu, ®s); /* Establish longjmp destination for architecture switch */ setjmp(regs.archjmp); /* Switch architecture mode if appropriate */ if(sysblk.arch_mode != regs.arch_mode) { PTT(PTT_CL_INF,"*SETARCH",regs.arch_mode,sysblk.arch_mode,cpu); regs.arch_mode = sysblk.arch_mode; oldregs = malloc (sizeof(REGS)); if (oldregs) { memcpy(oldregs, ®s, sizeof(REGS)); obtain_lock(&sysblk.cpulock[cpu]); } else { logmsg (_("HHCCP080E CPU%4.4X malloc failed for archjmp regs: %s\n"), cpu, strerror(errno)); cpu_uninit (cpu, ®s); } return oldregs; } RELEASE_INTLOCK(®s); /* Establish longjmp destination for program check */ setjmp(regs.progjmp); /* Set `execflag' to 0 in case EXecuted instruction did a longjmp() */ regs.execflag = 0; do { if (INTERRUPT_PENDING(®s)) ARCH_DEP(process_interrupt)(®s); ip = INSTRUCTION_FETCH(®s, 0); regs.instcount++; EXECUTE_INSTRUCTION(ip, ®s); do { UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); regs.instcount += 12; UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); UNROLLED_EXECUTE(®s); } while (!INTERRUPT_PENDING(®s)); } while (1); /* Never reached */ return NULL; } /* end function cpu_thread */ /*-------------------------------------------------------------------*/ /* Process Trace */ /*-------------------------------------------------------------------*/ void ARCH_DEP(process_trace)(REGS *regs) { int shouldtrace = 0; /* 1=Trace instruction */ int shouldstep = 0; /* 1=Wait for start command */ /* Test for trace */ if (CPU_TRACING(regs, 0)) shouldtrace = 1; /* Test for step */ if (CPU_STEPPING(regs, 0)) shouldstep = 1; /* Display the instruction */ if (shouldtrace || shouldstep) { BYTE *ip = regs->ip < regs->aip ? regs->inst : regs->ip; ARCH_DEP(display_inst) (regs, ip); } /* Stop the CPU */ if (shouldstep) { REGS *hostregs = regs->hostregs; S64 saved_timer[2]; OBTAIN_INTLOCK(hostregs); #ifdef OPTION_MIPS_COUNTING hostregs->waittod = host_tod(); #endif /* The CPU timer is not decremented for a CPU that is in the manual state (e.g. stopped in single step mode) */ saved_timer[0] = cpu_timer(regs); saved_timer[1] = cpu_timer(hostregs); hostregs->cpustate = CPUSTATE_STOPPED; sysblk.started_mask &= ~hostregs->cpubit; hostregs->stepwait = 1; sysblk.intowner = LOCK_OWNER_NONE; while (hostregs->cpustate == CPUSTATE_STOPPED) { wait_condition (&hostregs->intcond, &sysblk.intlock); } sysblk.intowner = hostregs->cpuad; hostregs->stepwait = 0; sysblk.started_mask |= hostregs->cpubit; set_cpu_timer(regs,saved_timer[0]); set_cpu_timer(hostregs,saved_timer[1]); #ifdef OPTION_MIPS_COUNTING hostregs->waittime += host_tod() - hostregs->waittod; hostregs->waittod = 0; #endif RELEASE_INTLOCK(hostregs); } } /* process_trace */ /*-------------------------------------------------------------------*/ /* Set Jump Pointers */ /* */ /* For supported architectures and certain multi-byte instructions, */ /* EXECUTE_INSTRUCTION and UNROLLED_EXECUTE call a label in this */ /* function which does a jump to the real instruction. */ /* */ /* The reason why we use labels instead of individual pointers is */ /* that if -fomit-frame-pointer is omitted then the backframe */ /* isn't pushed onto the stack. */ /* */ /* The reason why this routine is in cpu.c is an attempt to provide */ /* locality with the corresponding run_cpu function. */ /* */ /* This routine is called from cpu_init */ /* */ /*-------------------------------------------------------------------*/ void ARCH_DEP(set_jump_pointers) (REGS *regs, int jump) { #if defined(MULTI_BYTE_ASSIST) /* Use `switch' to confuse smart-ass optimizing compilers */ switch (jump) { #if defined(MULTI_BYTE_ASSIST_IA32) case 0xa7: jump_a7xx: __asm__ ( "movzbl 1(%%eax),%%ecx\n\t" "jmp *%c0(%%edx,%%ecx,4)" : : "i" (offsetof(REGS,ARCH_DEP(opcode_a7xx))) ); return; case 0xb2: jump_b2xx: __asm__ ( "movzbl 1(%%eax),%%ecx\n\t" "jmp *%c0(%%edx,%%ecx,4)" : : "i" (offsetof(REGS,ARCH_DEP(opcode_b2xx))) ); return; case 0xb9: jump_b9xx: __asm__ ( "movzbl 1(%%eax),%%ecx\n\t" "jmp *%c0(%%edx,%%ecx,4)" : : "i" (offsetof(REGS,ARCH_DEP(opcode_b9xx))) ); return; #if defined(FEATURE_ESAME) || defined(FEATURE_ESAME_N3_ESA390) case 0xc0: jump_c0xx: __asm__ ( "movzbl 1(%%eax),%%ecx\n\t" "jmp *%c0(%%edx,%%ecx,4)" : : "i" (offsetof(REGS,ARCH_DEP(opcode_c0xx))) ); return; case 0xe3: jump_e3xx: __asm__ ( "movzbl 5(%%eax),%%ecx\n\t" "jmp *%c0(%%edx,%%ecx,4)" : : "i" (offsetof(REGS,ARCH_DEP(opcode_e3xx))) ); return; case 0xeb: #endif /* defined(FEATURE_ESAME) || defined(FEATURE_ESAME_N3_ESA390) */ jump_ebxx: __asm__ ( "movzbl 5(%%eax),%%ecx\n\t" "jmp *%c0(%%edx,%%ecx,4)" : : "i" (offsetof(REGS,ARCH_DEP(opcode_ebxx))) ); return; #endif /* defined(MULTI_BYTE_ASSIST_IA32) */ } /* switch(jump) */ regs->ARCH_DEP(opcode_table)[0xa7] = &&jump_a7xx; regs->ARCH_DEP(opcode_table)[0xb2] = &&jump_b2xx; regs->ARCH_DEP(opcode_table)[0xb9] = &&jump_b9xx; #if defined(FEATURE_ESAME) || defined(FEATURE_ESAME_N3_ESA390) regs->ARCH_DEP(opcode_table)[0xc0] = &&jump_c0xx; regs->ARCH_DEP(opcode_table)[0xe3] = &&jump_e3xx; #endif /* defined(FEATURE_ESAME) || defined(FEATURE_ESAME_N3_ESA390) */ regs->ARCH_DEP(opcode_table)[0xeb] = &&jump_ebxx; #else /* !defined(MULTI_BYTE_ASSIST) */ UNREFERENCED(regs); UNREFERENCED(jump); #endif /* !defined(MULTI_BYTE_ASSIST) */ } #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "cpu.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "cpu.c" #endif /*-------------------------------------------------------------------*/ /* Copy program status word */ /*-------------------------------------------------------------------*/ DLL_EXPORT void copy_psw (REGS *regs, BYTE *addr) { REGS cregs; int arch_mode; memcpy(&cregs, regs, sysblk.regs_copy_len); /* Use the architecture mode from SYSBLK if load indicator shows IPL in process, otherwise use archmode from REGS */ if (cregs.loadstate) { arch_mode = sysblk.arch_mode; } else { arch_mode = cregs.arch_mode; } /* Call the appropriate store_psw routine based on archmode */ switch(arch_mode) { #if defined(_370) case ARCH_370: s370_store_psw(&cregs, addr); break; #endif #if defined(_390) case ARCH_390: s390_store_psw(&cregs, addr); break; #endif #if defined(_900) case ARCH_900: z900_store_psw(&cregs, addr); break; #endif } } /* end function copy_psw */ /*-------------------------------------------------------------------*/ /* Display program status word */ /*-------------------------------------------------------------------*/ void display_psw (REGS *regs) { QWORD qword; /* quadword work area */ int arch_mode; /* architecture mode */ memset(qword, 0, sizeof(qword)); /* Use the architecture mode from SYSBLK if load indicator shows IPL in process, otherwise use archmode from REGS */ if (regs->loadstate) { arch_mode = sysblk.arch_mode; } else { arch_mode = regs->arch_mode; } if( arch_mode != ARCH_900 ) { copy_psw (regs, qword); logmsg (_("PSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n"), qword[0], qword[1], qword[2], qword[3], qword[4], qword[5], qword[6], qword[7]); } else { copy_psw (regs, qword); logmsg (_("PSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X\n"), qword[0], qword[1], qword[2], qword[3], qword[4], qword[5], qword[6], qword[7], qword[8], qword[9], qword[10], qword[11], qword[12], qword[13], qword[14], qword[15]); } } /* end function display_psw */ const char* arch_name[GEN_MAXARCH] = { #if defined(_370) _ARCH_370_NAME, #endif #if defined(_390) _ARCH_390_NAME, #endif #if defined(_900) _ARCH_900_NAME #endif }; const char* get_arch_mode_string(REGS* regs) { if (!regs) return arch_name[sysblk.arch_mode]; else return arch_name[regs->arch_mode]; } #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/vstore.c0000664000175000017500000000136712564723224011700 00000000000000/* VSTORE.C (c) Copyright Roger Bowler, 2000-2009 */ /* ESA/390 Virtual Storage Functions */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #include "hstdinc.h" #include "hercules.h" #if defined(OPTION_NO_INLINE_VSTORE) | defined(OPTION_NO_INLINE_IFETCH) #define _VSTORE_C #include "opcode.h" #include "inline.h" #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "vstore.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "vstore.c" #endif #endif /*!defined(_GEN_ARCH)*/ #endif /*!defined(OPTION_NO_INLINE_VSTORE)*/ hercules-3.12/general1.c0000664000175000017500000050260012564723224012050 00000000000000/* GENERAL1.C (c) Copyright Roger Bowler, 1994-2009 */ /* ESA/390 CPU Emulator */ /* Instructions A-M */ /* (c) Copyright Peter Kuschnerus, 1999-2009 (UPT & CFC)*/ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements general instructions A-M of the */ /* S/370 and ESA/390 architectures, as described in the manuals */ /* GA22-7000-03 System/370 Principles of Operation */ /* SA22-7201-06 ESA/390 Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Corrections to shift instructions by Jay Maynard, Jan Jaeger */ /* Branch tracing by Jan Jaeger */ /* Instruction decode by macros - Jan Jaeger */ /* Prevent TOD from going backwards in time - Jan Jaeger */ /* Fix STCKE instruction - Bernard van der Helm */ /* Instruction decode rework - Jan Jaeger */ /* Make STCK update the TOD clock - Jay Maynard */ /* Fix address wraparound in MVO - Jan Jaeger */ /* PLO instruction - Jan Jaeger */ /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */ /* Clear TEA on data exception - Peter Kuschnerus v209*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_GENERAL1_C_) #define _GENERAL1_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "clock.h" /*-------------------------------------------------------------------*/ /* 1A AR - Add Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_register) { int r1, r2; /* Values of R fields */ RR(inst, regs, r1, r2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r1), regs->GR_L(r2)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /*-------------------------------------------------------------------*/ /* 5A A - Add [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(add) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r1), n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /*-------------------------------------------------------------------*/ /* 4A AH - Add Halfword [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(add_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load 2 bytes from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r1), (U32)n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7xA AHI - Add Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(add_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit immediate op */ RI(inst, regs, r1, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r1), (S16)i2); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ /*-------------------------------------------------------------------*/ /* 1E ALR - Add Logical Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Add signed operands and set condition code */ regs->psw.cc = add_logical (&(regs->GR_L(r1)), regs->GR_L(r1), regs->GR_L(r2)); } /*-------------------------------------------------------------------*/ /* 5E AL - Add Logical [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_logical (&(regs->GR_L(r1)), regs->GR_L(r1), n); } /*-------------------------------------------------------------------*/ /* 14 NR - And Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(and_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* AND second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) &= regs->GR_L(r2) ) ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 54 N - And [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(and) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* AND second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) &= n ) ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 94 NI - And Immediate [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate) { BYTE i2; /* Immediate byte of opcode */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE *dest; /* Pointer to target byte */ SI(inst, regs, i2, b1, effective_addr1); /* Get byte mainstor address */ dest = MADDR (effective_addr1, b1, regs, ACCTYPE_WRITE, regs->psw.pkey ); /* AND byte with immediate operand, setting condition code */ regs->psw.cc = ((*dest &= i2) != 0); /* Update interval timer if necessary */ ITIMER_UPDATE(effective_addr1,4-1,regs); } /*-------------------------------------------------------------------*/ /* D4 NC - And Character [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(and_character) { int len, len2, len3; /* Lengths to copy */ int b1, b2; /* Base register numbers */ VADR addr1, addr2; /* Virtual addresses */ BYTE *dest1, *dest2; /* Destination addresses */ BYTE *source1, *source2; /* Source addresses */ BYTE *sk1, *sk2; /* Storage key addresses */ int i; /* Loop counter */ int cc = 0; /* Condition code */ SS_L(inst, regs, len, b1, addr1, b2, addr2); ITIMER_SYNC(addr2,len,regs); ITIMER_SYNC(addr1,len,regs); /* Quick out for 1 byte (no boundary crossed) */ if (unlikely(len == 0)) { source1 = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); dest1 = MADDR (addr1, b1, regs, ACCTYPE_WRITE, regs->psw.pkey); *dest1 &= *source1; regs->psw.cc = (*dest1 != 0); ITIMER_UPDATE(addr1,0,regs); return; } /* There are several scenarios (in optimal order): * (1) dest boundary and source boundary not crossed * (2) dest boundary not crossed and source boundary crossed * (3) dest boundary crossed and source boundary not crossed * (4) dest boundary and source boundary are crossed * (a) dest and source boundary cross at the same time * (b) dest boundary crossed first * (c) source boundary crossed first */ /* Translate addresses of leftmost operand bytes */ dest1 = MADDRL (addr1, len+1, b1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk1 = regs->dat.storkey; source1 = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if ( NOCROSS2K(addr1,len ) ) { if ( NOCROSS2K(addr2,len) ) { /* (1) - No boundaries are crossed */ for (i = 0; i <= len; i++) if (*dest1++ &= *source1++) cc = 1; } else { /* (2) - Second operand crosses a boundary */ len2 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len2) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); for ( i = 0; i < len2; i++) if (*dest1++ &= *source1++) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if (*dest1++ &= *source2++) cc = 1; } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); } else { /* First operand crosses a boundary */ len2 = 0x800 - (addr1 & 0x7FF); dest2 = MADDR ((addr1 + len2) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk2 = regs->dat.storkey; if ( NOCROSS2K(addr2,len )) { /* (3) - First operand crosses a boundary */ for ( i = 0; i < len2; i++) if (*dest1++ &= *source1++) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if (*dest2++ &= *source1++) cc = 1; } else { /* (4) - Both operands cross a boundary */ len3 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len3) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); if (len2 == len3) { /* (4a) - Both operands cross at the same time */ for ( i = 0; i < len2; i++) if (*dest1++ &= *source1++) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if (*dest2++ &= *source2++) cc = 1; } else if (len2 < len3) { /* (4b) - First operand crosses first */ for ( i = 0; i < len2; i++) if (*dest1++ &= *source1++) cc = 1; len2 = len3 - len2; for ( i = 0; i < len2; i++) if (*dest2++ &= *source1++) cc = 1; len2 = len - len3; for ( i = 0; i <= len2; i++) if (*dest2++ &= *source2++) cc = 1; } else { /* (4c) - Second operand crosses first */ for ( i = 0; i < len3; i++) if (*dest1++ &= *source1++) cc = 1; len3 = len2 - len3; for ( i = 0; i < len3; i++) if (*dest1++ &= *source2++) cc = 1; len3 = len - len2; for ( i = 0; i <= len3; i++) if (*dest2++ &= *source2++) cc = 1; } } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); *sk2 |= (STORKEY_REF | STORKEY_CHANGE); } ITIMER_UPDATE(addr1,len,regs); regs->psw.cc = cc; } /*-------------------------------------------------------------------*/ /* 05 BALR - Branch and Link Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_link_register) { int r1, r2; /* Values of R fields */ VADR newia; /* New instruction address */ RR_B(inst, regs, r1, r2); #if defined(FEATURE_TRACING) /* Add a branch trace entry to the trace table */ if ((regs->CR(12) & CR12_BRTRACE) && (r2 != 0)) { regs->psw.ilc = 0; // indicates regs->ip not updated regs->CR(12) = ((ARCH_DEP(trace_br_func))regs->trace_br) (regs->psw.amode, regs->GR_L(r2), regs); regs->psw.ilc = 2; // reset if trace didn't pgm check } #endif /*defined(FEATURE_TRACING)*/ /* Compute the branch address from the R2 operand */ newia = regs->GR(r2); /* Save the link information in the R1 operand */ #if defined(FEATURE_ESAME) if( regs->psw.amode64 ) regs->GR_G(r1) = PSW_IA64(regs, 2); else #endif regs->GR_L(r1) = ( regs->psw.amode ) ? (0x80000000 | PSW_IA31(regs, 2)) : (((!regs->execflag ? 2 : regs->exrl ? 6 : 4) << 29) | (regs->psw.cc << 28) | (regs->psw.progmask << 24) | PSW_IA24(regs, 2)); /* Execute the branch unless R2 specifies register 0 */ if ( r2 != 0 ) SUCCESSFUL_BRANCH(regs, newia, 2); else INST_UPDATE_PSW(regs, 2, 0); } /* end DEF_INST(branch_and_link_register) */ /*-------------------------------------------------------------------*/ /* 45 BAL - Branch and Link [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_link) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX_B(inst, regs, r1, b2, effective_addr2); /* Save the link information in the R1 operand */ #if defined(FEATURE_ESAME) if( regs->psw.amode64 ) regs->GR_G(r1) = PSW_IA64(regs, 4); else #endif regs->GR_L(r1) = ( regs->psw.amode ) ? (0x80000000 | PSW_IA31(regs, 4)) : ((4 << 29) | (regs->psw.cc << 28) | (regs->psw.progmask << 24) | PSW_IA24(regs, 4)); SUCCESSFUL_BRANCH(regs, effective_addr2, 4); } /* end DEF_INST(branch_and_link) */ /*-------------------------------------------------------------------*/ /* 0D BASR - Branch and Save Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_save_register) { int r1, r2; /* Values of R fields */ VADR newia; /* New instruction address */ RR_B(inst, regs, r1, r2); #if defined(FEATURE_TRACING) /* Add a branch trace entry to the trace table */ if ((regs->CR(12) & CR12_BRTRACE) && (r2 != 0)) { regs->psw.ilc = 0; // indcates regs->ip not updated regs->CR(12) = ((ARCH_DEP(trace_br_func))regs->trace_br) (regs->psw.amode, regs->GR_L(r2), regs); regs->psw.ilc = 2; // reset if trace didn't pgm check } #endif /*defined(FEATURE_TRACING)*/ /* Compute the branch address from the R2 operand */ newia = regs->GR(r2); /* Save the link information in the R1 operand */ #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) regs->GR_G(r1) = PSW_IA64(regs, 2); else #endif if ( regs->psw.amode ) regs->GR_L(r1) = 0x80000000 | PSW_IA31(regs, 2); else regs->GR_L(r1) = PSW_IA24(regs, 2); /* Execute the branch unless R2 specifies register 0 */ if ( r2 != 0 ) SUCCESSFUL_BRANCH(regs, newia, 2); else INST_UPDATE_PSW(regs, 2, 0); } /* end DEF_INST(branch_and_save_register) */ /*-------------------------------------------------------------------*/ /* 4D BAS - Branch and Save [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_save) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX_B(inst, regs, r1, b2, effective_addr2); /* Save the link information in the R1 register */ #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) regs->GR_G(r1) = PSW_IA64(regs, 4); else #endif if ( regs->psw.amode ) regs->GR_L(r1) = 0x80000000 | PSW_IA31(regs, 4); else regs->GR_L(r1) = PSW_IA24(regs, 4); SUCCESSFUL_BRANCH(regs, effective_addr2, 4); } /* end DEF_INST(branch_and_save) */ #if defined(FEATURE_BIMODAL_ADDRESSING) /*-------------------------------------------------------------------*/ /* 0C BASSM - Branch and Save and Set Mode [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_save_and_set_mode) { int r1, r2; /* Values of R fields */ VADR newia; /* New instruction address */ int xmode; /* 64 or 31 mode of target */ #if defined(FEATURE_ESAME) BYTE *ipsav; /* save for ip */ #endif /*defined(FEATURE_ESAME)*/ RR_B(inst, regs, r1, r2); /* Compute the branch address from the R2 operand */ newia = regs->GR(r2); #if defined(FEATURE_TRACING) #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && (r2 != 0) && (regs->psw.amode64 != (newia & 1))) { /* save ip and update it for mode switch trace */ ipsav = regs->ip; INST_UPDATE_PSW(regs, 2, 0); regs->psw.ilc = 2; regs->CR(12) = ARCH_DEP(trace_ms) (regs->CR(12) & CR12_BRTRACE ? 1 : 0, newia & ~0x01, regs); regs->ip = ipsav; } else #endif /*defined(FEATURE_ESAME)*/ /* Add a branch trace entry to the trace table */ if ((regs->CR(12) & CR12_BRTRACE) && (r2 != 0)) { regs->psw.ilc = 0; // indicates regs->ip not updated #if defined(FEATURE_ESAME) if (newia & 0x01) xmode = 1; else #endif /*defined(FEATURE_ESAME)*/ xmode = newia & 0x80000000 ? 1 : 0; regs->CR(12) = ARCH_DEP(trace_br) (xmode, newia & ~0x01, regs); regs->psw.ilc = 2; // reset if trace didn't pgm check } #endif /*defined(FEATURE_TRACING)*/ /* Save the link information in the R1 operand */ #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) regs->GR_G(r1) = PSW_IA64(regs, 3); // low bit on else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) regs->GR_L(r1) = 0x80000000 | PSW_IA31(regs, 2); else regs->GR_L(r1) = PSW_IA24(regs, 2); /* Set mode and branch to address specified by R2 operand */ if ( r2 != 0 ) { SET_ADDRESSING_MODE(regs, newia); SUCCESSFUL_BRANCH(regs, newia, 2); } else INST_UPDATE_PSW(regs, 2, 0); } /* end DEF_INST(branch_and_save_and_set_mode) */ #endif /*defined(FEATURE_BIMODAL_ADDRESSING)*/ #if defined(FEATURE_BIMODAL_ADDRESSING) /*-------------------------------------------------------------------*/ /* 0B BSM - Branch and Set Mode [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_set_mode) { int r1, r2; /* Values of R fields */ VADR newia; /* New instruction address */ RR_B(inst, regs, r1, r2); /* Compute the branch address from the R2 operand */ newia = regs->GR(r2); #if defined(FEATURE_TRACING) #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && (r2 != 0) && (regs->psw.amode64 != (newia & 1))) { INST_UPDATE_PSW(regs, 2, 0); regs->psw.ilc = 2; regs->CR(12) = ARCH_DEP(trace_ms) (0, 0, regs); } #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_TRACING)*/ /* Insert addressing mode into bit 0 of R1 operand */ if ( r1 != 0 ) { #if defined(FEATURE_ESAME) /* Z/Pops seems to be in error about this */ // regs->GR_LHLCL(r1) &= 0xFE; if ( regs->psw.amode64 ) regs->GR_LHLCL(r1) |= 0x01; else #endif { if ( regs->psw.amode ) regs->GR_L(r1) |= 0x80000000; else regs->GR_L(r1) &= 0x7FFFFFFF; } } /* Set mode and branch to address specified by R2 operand */ if ( r2 != 0 ) { SET_ADDRESSING_MODE(regs, newia); SUCCESSFUL_BRANCH(regs, newia, 2); } else INST_UPDATE_PSW(regs, 2, 0); } /* end DEF_INST(branch_and_set_mode) */ #endif /*defined(FEATURE_BIMODAL_ADDRESSING)*/ /*-------------------------------------------------------------------*/ /* 07 BCR - Branch on Condition Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_condition_register) { //int r1, r2; /* Values of R fields */ // RR(inst, regs, r1, r2); /* Branch if R1 mask bit is set and R2 is not register 0 */ if ((inst[1] & 0x0F) != 0 && (inst[1] & (0x80 >> regs->psw.cc))) SUCCESSFUL_BRANCH(regs, regs->GR(inst[1] & 0x0F), 2); else { INST_UPDATE_PSW(regs, 2, 0); /* Perform serialization and checkpoint synchronization if the mask is all ones and R2 is register 0 */ if ( inst[1] == 0xF0 ) { PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } #if defined(FEATURE_FAST_BCR_SERIALIZATION_FACILITY) /*810*/ /* Perform serialization without checkpoint synchronization the mask is B'1110' and R2 is register 0 */ else if (inst[1] == 0xE0) { PERFORM_SERIALIZATION (regs); } #endif /*defined(FEATURE_FAST_BCR_SERIALIZATION_FACILITY)*/ } } /* end DEF_INST(branch_on_condition_register) */ /*-------------------------------------------------------------------*/ /* 47 BC - Branch on Condition [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_condition) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ /* Branch to operand address if r1 mask bit is set */ if ((0x80 >> regs->psw.cc) & inst[1]) { RX_BC(inst, regs, b2, effective_addr2); SUCCESSFUL_BRANCH(regs, effective_addr2, 4); } else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_on_condition) */ /*-------------------------------------------------------------------*/ /* 06 BCTR - Branch on Count Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_count_register) { int r1, r2; /* Values of R fields */ VADR newia; /* New instruction address */ RR_B(inst, regs, r1, r2); /* Compute the branch address from the R2 operand */ newia = regs->GR(r2); /* Subtract 1 from the R1 operand and branch if result is non-zero and R2 operand is not register zero */ if ( --(regs->GR_L(r1)) && r2 != 0 ) SUCCESSFUL_BRANCH(regs, newia, 2); else INST_UPDATE_PSW(regs, 2, 0); } /* end DEF_INST(branch_on_count_register) */ /*-------------------------------------------------------------------*/ /* 46 BCT - Branch on Count [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_count) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX_B(inst, regs, r1, b2, effective_addr2); /* Subtract 1 from the R1 operand and branch if non-zero */ if ( --(regs->GR_L(r1)) ) SUCCESSFUL_BRANCH(regs, effective_addr2, 4); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_on_count) */ /*-------------------------------------------------------------------*/ /* 86 BXH - Branch on Index High [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_index_high) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ S32 i, j; /* Integer work areas */ RS_B(inst, regs, r1, r3, b2, effective_addr2); /* Load the increment value from the R3 register */ i = (S32)regs->GR_L(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S32)regs->GR_L(r3) : (S32)regs->GR_L(r3+1); /* Add the increment value to the R1 register */ regs->GR_L(r1) = (S32)regs->GR_L(r1) + i; /* Branch if result compares high */ if ( (S32)regs->GR_L(r1) > j ) SUCCESSFUL_BRANCH(regs, effective_addr2, 4); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_on_index_high) */ /*-------------------------------------------------------------------*/ /* 87 BXLE - Branch on Index Low or Equal [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_index_low_or_equal) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ S32 i, j; /* Integer work areas */ RS_B(inst, regs, r1, r3, b2, effective_addr2); /* Load the increment value from the R3 register */ i = regs->GR_L(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S32)regs->GR_L(r3) : (S32)regs->GR_L(r3+1); /* Add the increment value to the R1 register */ regs->GR_L(r1) = (S32)regs->GR_L(r1) + i; /* Branch if result compares low or equal */ if ( (S32)regs->GR_L(r1) <= j ) SUCCESSFUL_BRANCH(regs, effective_addr2, 4); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_on_index_low_or_equal) */ #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7x4 BRC - Branch Relative on Condition [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_condition) { //int r1; /* Register number */ U16 i2; /* 16-bit operand values */ // RI(inst, regs, r1, i2); /* Branch if R1 mask bit is set */ if (inst[1] & (0x80 >> regs->psw.cc)) { i2 = fetch_fw(inst) & 0xFFFF; SUCCESSFUL_RELATIVE_BRANCH(regs, 2*(S16)i2, 4); } else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_relative_on_condition) */ #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7x5 BRAS - Branch Relative And Save [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_and_save) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI_B(inst, regs, r1, i2); /* Save the link information in the R1 operand */ #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) regs->GR_G(r1) = PSW_IA64(regs, 4); else #endif if ( regs->psw.amode ) regs->GR_L(r1) = 0x80000000 | PSW_IA31(regs, 4); else regs->GR_L(r1) = PSW_IA24(regs, 4); SUCCESSFUL_RELATIVE_BRANCH(regs, 2*(S16)i2, 4); } /* end DEF_INST(branch_relative_and_save) */ #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7x6 BRCT - Branch Relative on Count [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_count) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI_B(inst, regs, r1, i2); /* Subtract 1 from the R1 operand and branch if non-zero */ if ( --(regs->GR_L(r1)) ) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*(S16)i2, 4); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_relative_on_count) */ #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* 84 BRXH - Branch Relative on Index High [RSI] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_index_high) { int r1, r3; /* Register numbers */ U16 i2; /* 16-bit operand */ S32 i,j; /* Integer workareas */ RSI_B(inst, regs, r1, r3, i2); /* Load the increment value from the R3 register */ i = (S32)regs->GR_L(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S32)regs->GR_L(r3) : (S32)regs->GR_L(r3+1); /* Add the increment value to the R1 register */ regs->GR_L(r1) = (S32)regs->GR_L(r1) + i; /* Branch if result compares high */ if ( (S32)regs->GR_L(r1) > j ) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*(S16)i2, 4); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_relative_on_index_high) */ #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* 85 BRXLE - Branch Relative on Index Low or Equal [RSI] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_index_low_or_equal) { int r1, r3; /* Register numbers */ U16 i2; /* 16-bit operand */ S32 i,j; /* Integer workareas */ RSI_B(inst, regs, r1, r3, i2); /* Load the increment value from the R3 register */ i = (S32)regs->GR_L(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S32)regs->GR_L(r3) : (S32)regs->GR_L(r3+1); /* Add the increment value to the R1 register */ regs->GR_L(r1) = (S32)regs->GR_L(r1) + i; /* Branch if result compares low or equal */ if ( (S32)regs->GR_L(r1) <= j ) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*(S16)i2, 4); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_relative_on_index_low_or_equal) */ #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if defined(FEATURE_CHECKSUM_INSTRUCTION) /*-------------------------------------------------------------------*/ /* B241 CKSM - Checksum [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(checksum) { int r1, r2; /* Values of R fields */ VADR addr2; /* Address of second operand */ GREG len; /* Operand length */ int i, j; /* Loop counters */ int cc = 0; /* Condition code */ U32 n; /* Word loaded from operand */ U64 dreg; /* Checksum accumulator */ RRE(inst, regs, r1, r2); ODD_CHECK(r2, regs); /* Obtain the second operand address and length from R2, R2+1 */ addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); len = GR_A(r2+1, regs); /* Initialize the checksum from the first operand register */ dreg = regs->GR_L(r1); /* Process each fullword of second operand */ for ( i = 0; len > 0 ; i++ ) { /* If 1024 words have been processed, exit with cc=3 */ if ( i >= 1024 ) { cc = 3; break; } /* Fetch fullword from second operand */ if (len >= 4) { n = ARCH_DEP(vfetch4) ( addr2, r2, regs ); addr2 += 4; addr2 &= ADDRESS_MAXWRAP(regs); len -= 4; } else { /* Fetch final 1, 2, or 3 bytes and pad with zeroes */ for (j = 0, n = 0; j < 4; j++) { n <<= 8; if (len > 0) { n |= ARCH_DEP(vfetchb) ( addr2, r2, regs ); addr2++; addr2 &= ADDRESS_MAXWRAP(regs); len--; } } /* end for(j) */ } /* Accumulate the fullword into the checksum */ dreg += n; /* Carry 32 bit overflow into bit 31 */ if (dreg > 0xFFFFFFFFULL) { dreg &= 0xFFFFFFFFULL; dreg++; } } /* end for(i) */ /* Load the updated checksum into the R1 register */ regs->GR_L(r1) = dreg; /* Update the operand address and length registers */ SET_GR_A(r2, regs,addr2); SET_GR_A(r2+1, regs,len); /* Set condition code 0 or 3 */ regs->psw.cc = cc; } #endif /*defined(FEATURE_CHECKSUM_INSTRUCTION)*/ /*-------------------------------------------------------------------*/ /* 19 CR - Compare Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < (S32)regs->GR_L(r2) ? 1 : (S32)regs->GR_L(r1) > (S32)regs->GR_L(r2) ? 2 : 0; } /*-------------------------------------------------------------------*/ /* 59 C - Compare [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(compare) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < (S32)n ? 1 : (S32)regs->GR_L(r1) > (S32)n ? 2 : 0; } /*-------------------------------------------------------------------*/ /* B21A CFC - Compare and Form Codeword [S] */ /* (c) Copyright Peter Kuschnerus, 1999-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2005-2009 */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_form_codeword) { int b2; /* Base of effective addr */ int rc; /* memcmp() return code */ int i; /* (work var) */ VADR op2_effective_addr; /* (op2 effective address) */ VADR op1_addr, op3_addr; /* (op1 & op3 fetch addr) */ GREG work_reg; /* (register work area) */ U16 index, max_index; /* (operand index values) */ BYTE op1[CFC_MAX_OPSIZE]; /* (work field) */ BYTE op3[CFC_MAX_OPSIZE]; /* (work field) */ BYTE tmp[CFC_MAX_OPSIZE]; /* (work field) */ BYTE descending; /* (sort-order control bit) */ #if defined(FEATURE_ESAME) BYTE a64 = regs->psw.amode64; /* ("64-bit mode" flag) */ #endif BYTE op_size = CFC_OPSIZE; /* (work constant; uses a64) */ BYTE gr2_shift = CFC_GR2_SHIFT; /* (work constant; uses a64) */ GREG gr2_high_bit = CFC_HIGH_BIT; /* (work constant; uses a64) */ S(inst, regs, b2, op2_effective_addr); /* All operands must be halfword aligned */ if (0 || GR_A(1,regs) & 1 || GR_A(2,regs) & 1 || GR_A(3,regs) & 1 ) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Initialize "end-of-operand-data" index value... */ max_index = op2_effective_addr & 0x7FFE; /* Loop until we either locate where the two operands differ from one another or until we reach the end of the operand data... */ do { /* Exit w/cc0 (op1==op3) when end of operands are reached */ index = GR_A(2,regs) & 0xFFFF; if ( index > max_index ) { regs->psw.cc = 0; // (operands are equal to each other) SET_GR_A( 2, regs, GR_A(3,regs) | gr2_high_bit ); return; } /* Fetch next chunk of operand data... */ op1_addr = ( regs->GR(1) + index ) & ADDRESS_MAXWRAP(regs); op3_addr = ( regs->GR(3) + index ) & ADDRESS_MAXWRAP(regs); ARCH_DEP( vfetchc )( op1, op_size - 1, op1_addr, AR1, regs ); ARCH_DEP( vfetchc )( op3, op_size - 1, op3_addr, AR1, regs ); /* Update GR2 operand index value... (Note: we must do this AFTER we fetch the operand data in case of storage access exceptions) */ SET_GR_A( 2, regs, GR_A(2,regs) + op_size ); /* Compare operands; continue while still equal... */ } while ( !( rc = memcmp( op1, op3, op_size ) ) ); /* Operands are NOT equal (we found an inequality). Set the condition code, form our codeword, and then exit */ ASSERT( rc != 0 ); // (we shouldn't be here unless this is true!) /* Check to see which sequence the operands should be sorted into so we can know whether or not we need to form our codeword using either the inverse of the higher operand's data (if doing an ascending sort), or the lower operand's data AS-IS (if doing a descending sort). This thus causes either the lower (or higher) operand values (depending on which type of sort we're doing, ascending or descending) to bubble to the top (beginning) of the tree that the UPT (Update Tree) instruction ultimately/eventually updates (which gets built from our codewords). */ descending = op2_effective_addr & 1; // (0==ascending, 1==descending) if ( rc < 0 ) // (operand-1 < operand-3) { if ( !descending ) // (ascending; in sequence) { regs->psw.cc = 1; // (cc1 == in sequence) /* Ascending sort: use inverse of higher operand's data */ for ( i=0; i < op_size; i++ ) tmp[i] = ~op3[i]; } else // (descending; out-of-sequence) { regs->psw.cc = 2; // (cc2 == out-of-sequence) /* Descending sort: use lower operand's data as-is */ memcpy( tmp, op1, op_size ); /* Swap GR1 & GR3 because out-of-sequence */ work_reg = GR_A(1,regs); SET_GR_A( 1, regs, GR_A(3,regs) ); SET_GR_A( 3, regs, work_reg ); } } else // (operand-1 > operand-3) { if ( !descending ) // (ascending; out-of-sequence) { regs->psw.cc = 2; // (cc2 == out-of-sequence) /* Ascending sort: use inverse of higher operand's data */ for ( i=0; i < op_size; i++ ) tmp[i] = ~op1[i]; /* Swap GR1 & GR3 because out-of-sequence */ work_reg = GR_A(1,regs); SET_GR_A( 1, regs, GR_A(3,regs) ); SET_GR_A( 3, regs, work_reg ); } else // (descending; in sequence) { regs->psw.cc = 1; // (cc1 == in sequence) /* Descending sort: use lower operand's data as-is */ memcpy( tmp, op3, op_size ); } } /* Form a sort/merge codeword to be used to sort the two operands into their proper sequence consisting of a combination of both the index position where the inequality was found (current GR2 value) and either the one's complement inverse of the higher operand's data (if doing an ascending sort) or the lower oper- and's data as-is (if doing a descending sort)... */ for ( work_reg=0, i=0; i < op_size; i++ ) work_reg = ( work_reg << 8 ) | tmp[i]; SET_GR_A( 2, regs, ( GR_A(2,regs) << gr2_shift ) | work_reg ); } /*-------------------------------------------------------------------*/ /* BA CS - Compare and Swap [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_swap) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR addr2; /* effective address */ BYTE *main2; /* mainstor address */ U32 old; /* old value */ RS(inst, regs, r1, r3, b2, addr2); FW_CHECK(addr2, regs); ITIMER_SYNC(addr2,4-1,regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Get mainstor address */ main2 = MADDRL (addr2, 4, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); old = CSWAP32(regs->GR_L(r1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg4 (&old, CSWAP32(regs->GR_L(r3)), main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); if (regs->psw.cc == 1) { PTT(PTT_CL_CSF,"*CS",regs->GR_L(r1),regs->GR_L(r3),(U32)(addr2 & 0xffffffff)); regs->GR_L(r1) = CSWAP32(old); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC0, CS1)) { if( !OPEN_IC_PER(regs) ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else longjmp(regs->progjmp, SIE_INTERCEPT_INSTCOMP); } else #endif /*defined(_FEATURE_SIE)*/ if (sysblk.cpus > 1) sched_yield(); } else { ITIMER_UPDATE(addr2,4-1,regs); } } /*-------------------------------------------------------------------*/ /* BB CDS - Compare Double and Swap [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_double_and_swap) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR addr2; /* effective address */ BYTE *main2; /* mainstor address */ U64 old, new; /* old, new values */ RS(inst, regs, r1, r3, b2, addr2); ODD2_CHECK(r1, r3, regs); DW_CHECK(addr2, regs); ITIMER_SYNC(addr2,8-1,regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Get operand absolute address */ main2 = MADDRL (addr2, 8, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get old, new values */ old = CSWAP64(((U64)(regs->GR_L(r1)) << 32) | regs->GR_L(r1+1)); new = CSWAP64(((U64)(regs->GR_L(r3)) << 32) | regs->GR_L(r3+1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg8 (&old, new, main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); if (regs->psw.cc == 1) { PTT(PTT_CL_CSF,"*CDS",regs->GR_L(r1),regs->GR_L(r3),(U32)(addr2 & 0xffffffff)); regs->GR_L(r1) = CSWAP64(old) >> 32; regs->GR_L(r1+1) = CSWAP64(old) & 0xffffffff; #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC0, CS1)) { if( !OPEN_IC_PER(regs) ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else longjmp(regs->progjmp, SIE_INTERCEPT_INSTCOMP); } else #endif /*defined(_FEATURE_SIE)*/ if (sysblk.cpus > 1) sched_yield(); } else { ITIMER_UPDATE(addr2,8-1,regs); } } #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE) #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) #define MAX_CSST_FC 2 #define MAX_CSST_SC 4 #else #define MAX_CSST_FC 1 #define MAX_CSST_SC 3 #endif /*-------------------------------------------------------------------*/ /* C8x2 CSST - Compare and Swap and Store [SSF] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_swap_and_store) { int r3; /* Value of R3 field */ int b1, b2; /* Base registers */ const int rp=1; /* Parameter list register */ VADR addr1, addr2; /* Effective addresses */ VADR addrp; /* Parameter list address */ BYTE *main1; /* Mainstor address of op1 */ int ln2; /* Second operand length - 1 */ U64 old16l=0, old16h=0, new16l=0, new16h=0; /* swap values for cmpxchg16 */ U64 old8=0, new8=0; /* Swap values for cmpxchg8 */ U32 old4=0, new4=0; /* Swap values for cmpxchg4 */ U64 stv16h=0,stv16l=0; /* 16-byte store value pair */ U64 stv8=0; /* 8-byte store value */ U32 stv4=0; /* 4-byte store value */ U16 stv2=0; /* 2-byte store value */ BYTE stv1=0; /* 1-byte store value */ BYTE fc; /* Function code */ BYTE sc; /* Store characteristic */ SSF(inst, regs, b1, addr1, b2, addr2, r3); /* Extract function code from register 0 bits 56-63 */ fc = regs->GR_LHLCL(0); /* Extract store characteristic from register 0 bits 48-55 */ sc = regs->GR_LHLCH(0); /* Program check if function code is not 0 or 1 */ if (fc > MAX_CSST_FC) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if store characteristic is not 0, 1, 2, or 3 */ if (sc > MAX_CSST_SC) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Calculate length minus 1 of second operand */ ln2 = (1 << sc) - 1; /* Program check if first operand is not on correct boundary */ switch(fc) { case 0: FW_CHECK(addr1, regs); break; case 1: DW_CHECK(addr1, regs); break; #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) case 2: QW_CHECK(addr1, regs); break; #endif } #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) if(r3 & 1) { regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } #endif /* Program check if second operand is not on correct boundary */ switch(sc) { case 1: HW_CHECK(addr2, regs); break; case 2: FW_CHECK(addr2, regs); break; case 3: DW_CHECK(addr2, regs); break; #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) case 4: QW_CHECK(addr2, regs); break; #endif } /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Obtain parameter list address from register 1 bits 0-59 */ addrp = regs->GR(rp) & 0xFFFFFFFFFFFFFFF0ULL & ADDRESS_MAXWRAP(regs); /* Obtain main storage address of first operand */ main1 = MADDRL (addr1, 4, b1, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Ensure second operand storage is writable */ ARCH_DEP(validate_operand) (addr2, b2, ln2, ACCTYPE_WRITE_SKP, regs); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Load the compare value from the r3 register and also */ /* load replacement value from bytes 0-3, 0-7 or 0-15 of parameter list */ switch(fc) { case 0: old4 = CSWAP32(regs->GR_L(r3)); new4 = ARCH_DEP(vfetch4) (addrp, rp, regs); new4 = CSWAP32(new4); break; case 1: old8 = CSWAP64(regs->GR_G(r3)); new8 = ARCH_DEP(vfetch8) (addrp, rp, regs); new8 = CSWAP64(new8); break; #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) case 2: old16h = CSWAP64(regs->GR_G(r3)); old16l = CSWAP64(regs->GR_G(r3+1)); new16h = ARCH_DEP(vfetch8) (addrp, rp, regs); new16l = ARCH_DEP(vfetch8) (addrp+8, rp, regs); new16h = CSWAP64(new16h); new16l = CSWAP64(new16l); break; #endif } /* Load the store value from bytes 16-23 of parameter list */ addrp += 16; addrp = addrp & ADDRESS_MAXWRAP(regs); switch(sc) { case 0: stv1 = ARCH_DEP(vfetchb) (addrp, rp, regs); break; case 1: stv2 = ARCH_DEP(vfetch2) (addrp, rp, regs); break; case 2: stv4 = ARCH_DEP(vfetch4) (addrp, rp, regs); break; case 3: stv8 = ARCH_DEP(vfetch8) (addrp, rp, regs); break; #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) case 4: stv16h = ARCH_DEP(vfetch8) (addrp, rp, regs); stv16l = ARCH_DEP(vfetch8) (addrp+8, rp, regs); break; #endif } switch(fc) { case 0: regs->psw.cc = cmpxchg4 (&old4, new4, main1); break; case 1: regs->psw.cc = cmpxchg8 (&old8, new8, main1); break; #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) case 2: regs->psw.cc = cmpxchg16 (&old16h, &old16l, new16h, new16l, main1); break; #endif } if (regs->psw.cc == 0) { /* Store the store value into the second operand location */ switch(sc) { case 0: ARCH_DEP(vstoreb) (stv1, addr2, b2, regs); break; case 1: ARCH_DEP(vstore2) (stv2, addr2, b2, regs); break; case 2: ARCH_DEP(vstore4) (stv4, addr2, b2, regs); break; case 3: ARCH_DEP(vstore8) (stv8, addr2, b2, regs); break; #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) case 4: ARCH_DEP(vstore8) (stv16h, addr2, b2, regs); ARCH_DEP(vstore8) (stv16l, addr2+8, b2, regs); break; #endif } } else { switch(fc) { case 0: regs->GR_L(r3) = CSWAP32(old4); break; case 1: regs->GR_G(r3) = CSWAP64(old8); break; #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) case 2: regs->GR_G(r3) = CSWAP64(old16h); regs->GR_G(r3+1) = CSWAP64(old16l); break; #endif } } /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); } /* end DEF_INST(compare_and_swap_and_store) */ #endif /*defined(FEATURE_COMPARE_AND_SWAP_AND_STORE)*/ /*-------------------------------------------------------------------*/ /* 49 CH - Compare Halfword [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load rightmost 2 bytes of comparand from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < n ? 1 : (S32)regs->GR_L(r1) > n ? 2 : 0; } #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7xE CHI - Compare Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit operand */ RI0(inst, regs, r1, i2); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < (S16)i2 ? 1 : (S32)regs->GR_L(r1) > (S16)i2 ? 2 : 0; } #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ /*-------------------------------------------------------------------*/ /* 15 CLR - Compare Logical Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_L(r1) < regs->GR_L(r2) ? 1 : regs->GR_L(r1) > regs->GR_L(r2) ? 2 : 0; } /*-------------------------------------------------------------------*/ /* 55 CL - Compare Logical [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_L(r1) < n ? 1 : regs->GR_L(r1) > n ? 2 : 0; } /*-------------------------------------------------------------------*/ /* 95 CLI - Compare Logical Immediate [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate) { BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE cbyte; /* Compare byte */ SI(inst, regs, i2, b1, effective_addr1); /* Fetch byte from operand address */ cbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* Compare with immediate operand and set condition code */ regs->psw.cc = (cbyte < i2) ? 1 : (cbyte > i2) ? 2 : 0; } /*-------------------------------------------------------------------*/ /* D5 CLC - Compare Logical Character [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_character) { unsigned int len, len1, len2; /* Lengths */ int rc; /* memcmp() return code */ int b1, b2; /* Base registers */ VADR ea1, ea2; /* Effective addresses */ BYTE *m1, *m2; /* Mainstor addresses */ SS_L(inst, regs, len, b1, ea1, b2, ea2); ITIMER_SYNC(ea1,len,regs); ITIMER_SYNC(ea2,len,regs); /* Translate addresses of leftmost operand bytes */ m1 = MADDR (ea1, b1, regs, ACCTYPE_READ, regs->psw.pkey); m2 = MADDR (ea2, b2, regs, ACCTYPE_READ, regs->psw.pkey); /* Quick out if comparing just 1 byte */ if (unlikely(len == 0)) { rc = *m1 - *m2; regs->psw.cc = ( rc == 0 ? 0 : ( rc < 0 ? 1 : 2 ) ); return; } /* There are several scenarios (in optimal order): * (1) dest boundary and source boundary not crossed * (a) halfword compare * (b) fullword compare * (c) doubleword compare (64-bit machines) * (d) other * (2) dest boundary not crossed and source boundary crossed * (3) dest boundary crossed and source boundary not crossed * (4) dest boundary and source boundary are crossed * (a) dest and source boundary cross at the same time * (b) dest boundary crossed first * (c) source boundary crossed first */ if ( (ea1 & 0x7FF) <= 0x7FF - len ) { if ( (ea2 & 0x7FF) <= 0x7FF - len ) { /* (1) - No boundaries are crossed */ switch(len) { case 1: /* (1a) - halfword compare */ { U16 v1, v2; v1 = fetch_hw(m1); v2 = fetch_hw(m2); regs->psw.cc = ( v1 == v2 ? 0 : ( v1 < v2 ? 1 : 2 ) ); return; } break; case 3: /* (1b) - fullword compare */ { U32 v1, v2; v1 = fetch_fw(m1); v2 = fetch_fw(m2); regs->psw.cc = ( v1 == v2 ? 0 : ( v1 < v2 ? 1 : 2 ) ); return; } break; case 7: /* (1c) - doubleword compare (64-bit machines) */ if (sizeof(unsigned int) >= 8) { U64 v1, v2; v1 = fetch_dw(m1); v2 = fetch_dw(m2); regs->psw.cc = ( v1 == v2 ? 0 : ( v1 < v2 ? 1 : 2 ) ); return; } default: /* (1d) - other compare */ rc = memcmp(m1, m2, len + 1); break; } } else { /* (2) - Second operand crosses a boundary */ len2 = 0x800 - (ea2 & 0x7FF); rc = memcmp(m1, m2, len2); if (rc == 0) { m2 = MADDR ((ea2 + len2) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); rc = memcmp(m1 + len2, m2, len - len2 + 1); } } } else { /* First operand crosses a boundary */ len1 = 0x800 - (ea1 & 0x7FF); if ( (ea2 & 0x7FF) <= 0x7FF - len ) { /* (3) - First operand crosses a boundary */ rc = memcmp(m1, m2, len1); if (rc == 0) { m1 = MADDR ((ea1 + len1) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_READ, regs->psw.pkey); rc = memcmp(m1, m2 + len1, len - len1 + 1); } } else { /* (4) - Both operands cross a boundary */ len2 = 0x800 - (ea2 & 0x7FF); if (len1 == len2) { /* (4a) - Both operands cross at the same time */ rc = memcmp(m1, m2, len1); if (rc == 0) { m1 = MADDR ((ea1 + len1) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_READ, regs->psw.pkey); m2 = MADDR ((ea2 + len1) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); rc = memcmp(m1, m2, len - len1 +1); } } else if (len1 < len2) { /* (4b) - First operand crosses first */ rc = memcmp(m1, m2, len1); if (rc == 0) { m1 = MADDR ((ea1 + len1) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_READ, regs->psw.pkey); rc = memcmp (m1, m2 + len1, len2 - len1); } if (rc == 0) { m2 = MADDR ((ea2 + len2) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); rc = memcmp (m1 + len2 - len1, m2, len - len2 + 1); } } else { /* (4c) - Second operand crosses first */ rc = memcmp(m1, m2, len2); if (rc == 0) { m2 = MADDR ((ea2 + len2) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); rc = memcmp (m1 + len2, m2, len1 - len2); } if (rc == 0) { m1 = MADDR ((ea1 + len1) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_READ, regs->psw.pkey); rc = memcmp (m1, m2 + len1 - len2, len - len1 + 1); } } } } regs->psw.cc = ( rc == 0 ? 0 : ( rc < 0 ? 1 : 2 ) ); } /*-------------------------------------------------------------------*/ /* BD CLM - Compare Logical Characters under Mask [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_characters_under_mask) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, j; /* Integer work areas */ int cc = 0; /* Condition code */ BYTE rbyte[4], /* Register bytes */ vbyte; /* Virtual storage byte */ RS(inst, regs, r1, r3, b2, effective_addr2); /* Set register bytes by mask */ i = 0; if (r3 & 0x8) rbyte[i++] = (regs->GR_L(r1) >> 24) & 0xFF; if (r3 & 0x4) rbyte[i++] = (regs->GR_L(r1) >> 16) & 0xFF; if (r3 & 0x2) rbyte[i++] = (regs->GR_L(r1) >> 8) & 0xFF; if (r3 & 0x1) rbyte[i++] = (regs->GR_L(r1) ) & 0xFF; /* Perform access check if mask is 0 */ if (!r3) ARCH_DEP(vfetchb) (effective_addr2, b2, regs); /* Compare byte by byte */ for (j = 0; j < i && !cc; j++) { effective_addr2 &= ADDRESS_MAXWRAP(regs); vbyte = ARCH_DEP(vfetchb) (effective_addr2++, b2, regs); if (rbyte[j] != vbyte) cc = rbyte[j] < vbyte ? 1 : 2; } regs->psw.cc = cc; } /*-------------------------------------------------------------------*/ /* 0F CLCL - Compare Logical Long [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_character_long) { int r1, r2; /* Values of R fields */ int cc = 0; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ U32 len1, len2; /* Operand lengths */ BYTE byte1, byte2; /* Operand bytes */ BYTE pad; /* Padding byte */ RR(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Load padding byte from bits 0-7 of R2+1 register */ pad = regs->GR_LHHCH(r2+1); /* Load operand lengths from bits 8-31 of R1+1 and R2+1 */ len1 = regs->GR_LA24(r1+1); len2 = regs->GR_LA24(r2+1); /* Process operands from left to right */ while (len1 > 0 || len2 > 0) { /* Fetch a byte from each operand, or use padding byte */ byte1 = (len1 > 0) ? ARCH_DEP(vfetchb) (addr1, r1, regs) : pad; byte2 = (len2 > 0) ? ARCH_DEP(vfetchb) (addr2, r2, regs) : pad; /* Compare operand bytes, set condition code if unequal */ if (byte1 != byte2) { cc = (byte1 < byte2) ? 1 : 2; break; } /* end if */ /* Update the first operand address and length */ if (len1 > 0) { addr1++; addr1 &= ADDRESS_MAXWRAP(regs); len1--; } /* Update the second operand address and length */ if (len2 > 0) { addr2++; addr2 &= ADDRESS_MAXWRAP(regs); len2--; } /* Update Regs if cross half page - may get access rupt */ if ((addr1 & 0x7ff) == 0 || (addr2 & 0x7ff) == 0) { SET_GR_A(r1, regs, addr1); SET_GR_A(r2, regs, addr2); regs->GR_LA24(r1+1) = len1; regs->GR_LA24(r2+1) = len2; } /* The instruction can be interrupted when a CPU determined number of bytes have been processed. The instruction address will be backed up, and the instruction will be re-executed. This is consistent with operation under a hypervisor such as LPAR or VM. *JJ */ if ((len1 + len2 > 255) && !((addr1 - len2) & 0xFFF)) { UPD_PSW_IA (regs, PSW_IA(regs, -REAL_ILC(regs))); break; } } /* end while(len1||len2) */ /* Update the registers */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); regs->GR_LA24(r1+1) = len1; regs->GR_LA24(r2+1) = len2; regs->psw.cc = cc; } #if defined(FEATURE_COMPARE_AND_MOVE_EXTENDED) /*-------------------------------------------------------------------*/ /* A9 CLCLE - Compare Logical Long Extended [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_long_extended) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Loop counter */ int cc = 0; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ GREG len1, len2; /* Operand lengths */ BYTE byte1, byte2; /* Operand bytes */ BYTE pad; /* Padding byte */ RS(inst, regs, r1, r3, b2, effective_addr2); ODD2_CHECK(r1, r3, regs); /* Load padding byte from bits 24-31 of effective address */ pad = effective_addr2 & 0xFF; /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r3) & ADDRESS_MAXWRAP(regs); /* Load operand lengths from bits 0-31 of R1+1 and R3+1 */ len1 = GR_A(r1+1, regs); len2 = GR_A(r3+1, regs); /* Process operands from left to right */ for (i = 0; len1 > 0 || len2 > 0 ; i++) { /* If 4096 bytes have been compared, exit with cc=3 */ if (i >= 4096) { cc = 3; break; } /* Fetch a byte from each operand, or use padding byte */ byte1 = (len1 > 0) ? ARCH_DEP(vfetchb) (addr1, r1, regs) : pad; byte2 = (len2 > 0) ? ARCH_DEP(vfetchb) (addr2, r3, regs) : pad; /* Compare operand bytes, set condition code if unequal */ if (byte1 != byte2) { cc = (byte1 < byte2) ? 1 : 2; break; } /* end if */ /* Update the first operand address and length */ if (len1 > 0) { addr1++; addr1 &= ADDRESS_MAXWRAP(regs); len1--; } /* Update the second operand address and length */ if (len2 > 0) { addr2++; addr2 &= ADDRESS_MAXWRAP(regs); len2--; } } /* end for(i) */ /* Update the registers */ SET_GR_A(r1, regs,addr1); SET_GR_A(r1+1, regs,len1); SET_GR_A(r3, regs,addr2); SET_GR_A(r3+1, regs,len2); regs->psw.cc = cc; } #endif /*defined(FEATURE_COMPARE_AND_MOVE_EXTENDED)*/ #if defined(FEATURE_STRING_INSTRUCTION) /*-------------------------------------------------------------------*/ /* B25D CLST - Compare Logical String [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_string) { int r1, r2; /* Values of R fields */ int i; /* Loop counter */ int cc; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ BYTE byte1, byte2; /* Operand bytes */ BYTE termchar; /* Terminating character */ RRE(inst, regs, r1, r2); /* Program check if bits 0-23 of register 0 not zero */ if ((regs->GR_L(0) & 0xFFFFFF00) != 0) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Load string terminating character from register 0 bits 24-31 */ termchar = regs->GR_LHLCL(0); /* Determine the operand addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Initialize the condition code to 3 */ cc = 3; /* Compare up to 4096 bytes until terminating character */ for (i = 0; i < 4096; i++) { /* Fetch a byte from each operand */ byte1 = ARCH_DEP(vfetchb) ( addr1, r1, regs ); byte2 = ARCH_DEP(vfetchb) ( addr2, r2, regs ); /* If both bytes are the terminating character then the strings are equal so return condition code 0 and leave the R1 and R2 registers unchanged */ if (byte1 == termchar && byte2 == termchar) { regs->psw.cc = 0; return; } /* If first operand byte is the terminating character, or if the first operand byte is lower than the second operand byte, then return condition code 1 */ if (byte1 == termchar || ((byte1 < byte2) && (byte2 != termchar))) { cc = 1; break; } /* If second operand byte is the terminating character, or if the first operand byte is higher than the second operand byte, then return condition code 2 */ if (byte2 == termchar || byte1 > byte2) { cc = 2; break; } /* Increment operand addresses */ addr1++; addr1 &= ADDRESS_MAXWRAP(regs); addr2++; addr2 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ /* Set R1 and R2 to point to current character of each operand */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); /* Set condition code */ regs->psw.cc = cc; } /* end DEF_INST(compare_logical_string) */ #endif /*defined(FEATURE_STRING_INSTRUCTION)*/ #if defined(FEATURE_STRING_INSTRUCTION) /*-------------------------------------------------------------------*/ /* B257 CUSE - Compare Until Substring Equal [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_until_substring_equal) { int r1, r2; /* Values of R fields */ int i; /* Loop counter */ int cc = 0; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ BYTE byte1, byte2; /* Operand bytes */ BYTE pad; /* Padding byte */ BYTE sublen; /* Substring length */ BYTE equlen = 0; /* Equal byte counter */ VADR eqaddr1, eqaddr2; /* Address of equal substring*/ #if defined(FEATURE_ESAME) S64 len1, len2; /* Operand lengths */ S64 remlen1, remlen2; /* Lengths remaining */ #else /*!defined(FEATURE_ESAME)*/ S32 len1, len2; /* Operand lengths */ S32 remlen1, remlen2; /* Lengths remaining */ #endif /*!defined(FEATURE_ESAME)*/ RRE(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); /* Load substring length from bits 24-31 of register 0 */ sublen = regs->GR_LHLCL(0); /* Load padding byte from bits 24-31 of register 1 */ pad = regs->GR_LHLCL(1); /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* update regs so unused bits zeroed */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); /* Load signed operand lengths from R1+1 and R2+1 */ len1 = #if defined(FEATURE_ESAME) regs->psw.amode64 ? (S64)(regs->GR_G(r1+1)) : #endif /*defined(FEATURE_ESAME)*/ (S32)(regs->GR_L(r1+1)); len2 = #if defined(FEATURE_ESAME) regs->psw.amode64 ? (S64)(regs->GR_G(r2+1)) : #endif /*defined(FEATURE_ESAME)*/ (S32)(regs->GR_L(r2+1)); /* Initialize equal string addresses and lengths */ eqaddr1 = addr1; eqaddr2 = addr2; remlen1 = len1; remlen2 = len2; /* If substring length is zero, exit with condition code 0 */ if (sublen == 0) { regs->psw.cc = 0; return; } /* If both operand lengths are zero, exit with condition code 2 */ if (len1 <= 0 && len2 <= 0) { regs->psw.cc = 2; return; } /* If r1=r2, exit with condition code 0 or 1*/ if (r1 == r2) { regs->psw.cc = (len1 < sublen) ? 1 : 0; return; } /* Process operands from left to right */ for (i = 0; len1 > 0 || len2 > 0 ; i++) { /* If 4096 bytes have been compared, and the last bytes compared were unequal, exit with condition code 3 */ if (equlen == 0 && i >= 4096) { cc = 3; break; } /* Fetch byte from first operand, or use padding byte */ if (len1 > 0) byte1 = ARCH_DEP(vfetchb) ( addr1, r1, regs ); else byte1 = pad; /* Fetch byte from second operand, or use padding byte */ if (len2 > 0) byte2 = ARCH_DEP(vfetchb) ( addr2, r2, regs ); else byte2 = pad; /* Test if bytes compare equal */ if (byte1 == byte2) { /* If this is the first equal byte, save the start of substring addresses and remaining lengths */ if (equlen == 0) { eqaddr1 = addr1; eqaddr2 = addr2; remlen1 = len1; remlen2 = len2; } /* Count the number of equal bytes */ equlen++; /* Set condition code 1 */ cc = 1; } else { /* Reset equal byte count and set condition code 2 */ equlen = 0; cc = 2; } /* Update the first operand address and length */ if (len1 > 0) { addr1++; addr1 &= ADDRESS_MAXWRAP(regs); len1--; } /* Update the second operand address and length */ if (len2 > 0) { addr2++; addr2 &= ADDRESS_MAXWRAP(regs); len2--; } /* update GPRs if we just crossed half page - could get rupt */ if ((addr1 & 0x7FF) == 0 || (addr2 & 0x7FF) == 0) { /* Update R1 and R2 to point to next bytes to compare */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); /* Set R1+1 and R2+1 to remaining operand lengths */ SET_GR_A(r1+1, regs,len1); SET_GR_A(r2+1, regs,len2); } /* If equal byte count has reached substring length exit with condition code zero */ if (equlen == sublen) { cc = 0; break; } } /* end for(i) */ /* Update the registers */ if (cc < 2) { /* Update R1 and R2 to point to the equal substring */ SET_GR_A(r1, regs,eqaddr1); SET_GR_A(r2, regs,eqaddr2); /* Set R1+1 and R2+1 to length remaining in each operand after the start of the substring */ SET_GR_A(r1+1, regs,remlen1); SET_GR_A(r2+1, regs,remlen2); } else { /* Update R1 and R2 to point to next bytes to compare */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); /* Set R1+1 and R2+1 to remaining operand lengths */ SET_GR_A(r1+1, regs,len1); SET_GR_A(r2+1, regs,len2); } /* Set condition code */ regs->psw.cc = cc; } /* end DEF_INST(compare_until_substring_equal) */ #endif /*defined(FEATURE_STRING_INSTRUCTION)*/ #ifdef FEATURE_EXTENDED_TRANSLATION /*-------------------------------------------------------------------*/ /* B2A6 CU21 (CUUTF) - Convert Unicode to UTF-8 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_utf16_to_utf8) { int r1, r2; /* Register numbers */ int i; /* Loop counter */ int cc = 0; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ GREG len1, len2; /* Operand lengths */ VADR naddr2; /* Next operand 2 addr */ GREG nlen2; /* Next operand 2 length */ U16 uvwxy; /* Unicode work area */ U16 unicode1; /* Unicode character */ U16 unicode2; /* Unicode low surrogate */ GREG n; /* Number of UTF-8 bytes - 1 */ BYTE utf[4]; /* UTF-8 bytes */ #if defined(FEATURE_ETF3_ENHANCEMENT) int wfc; /* Well-Formedness-Checking */ #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ // NOTE: it's faster to decode with RRE format // and then to handle the 'wfc' flag separately... // RRF_M(inst, regs, r1, r2, wfc); RRE(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) /* Set WellFormednessChecking */ if(inst[2] & 0x10) wfc = 1; else wfc = 0; #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Load operand lengths from bits 0-31 of R1+1 and R2+1 */ len1 = GR_A(r1+1, regs); len2 = GR_A(r2+1, regs); if (len1 == 0 && len2 > 1) cc = 1; /* Process operands from left to right */ for (i = 0; len1 > 0 && len2 > 0; i++) { /* If 4096 characters have been converted, exit with cc=3 */ if (i >= 4096) { cc = 3; break; } /* Exit if fewer than 2 bytes remain in source operand */ if (len2 < 2) break; /* Fetch two bytes from source operand */ unicode1 = ARCH_DEP(vfetch2) ( addr2, r2, regs ); naddr2 = addr2 + 2; naddr2 &= ADDRESS_MAXWRAP(regs); nlen2 = len2 - 2; /* Convert Unicode to UTF-8 */ if (unicode1 < 0x0080) { /* Convert Unicode 0000-007F to one UTF-8 byte */ utf[0] = (BYTE)unicode1; n = 0; } else if (unicode1 < 0x0800) { /* Convert Unicode 0080-07FF to two UTF-8 bytes */ utf[0] = (BYTE)0xC0 | (BYTE)(unicode1 >> 6); utf[1] = (BYTE)0x80 | (BYTE)(unicode1 & 0x003F); n = 1; } else if (unicode1 < 0xD800 || unicode1 >= 0xDC00) { /* Convert Unicode 0800-D7FF or DC00-FFFF to three UTF-8 bytes */ utf[0] = (BYTE)0xE0 | (BYTE)(unicode1 >> 12); utf[1] = (BYTE)0x80 | (BYTE)((unicode1 & 0x0FC0) >> 6); utf[2] = (BYTE)0x80 | (BYTE)(unicode1 & 0x003F); n = 2; } else { /* Exit if fewer than 2 bytes remain in source operand */ if (nlen2 < 2) break; /* Fetch the Unicode low surrogate */ unicode2 = ARCH_DEP(vfetch2) ( naddr2, r2, regs ); naddr2 += 2; naddr2 &= ADDRESS_MAXWRAP(regs); nlen2 -= 2; #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormdnessChecking */ if(wfc) { if(unicode2 < 0xdc00 || unicode2 > 0xdf00) { regs->psw.cc = 2; return; } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Convert Unicode surrogate pair to four UTF-8 bytes */ uvwxy = ((unicode1 & 0x03C0) >> 6) + 1; utf[0] = (BYTE)0xF0 | (BYTE)(uvwxy >> 2); utf[1] = (BYTE)0x80 | (BYTE)((uvwxy & 0x0003) << 4) | (BYTE)((unicode1 & 0x003C) >> 2); utf[2] = (BYTE)0x80 | (BYTE)((unicode1 & 0x0003) << 4) | (BYTE)((unicode2 & 0x03C0) >> 6); utf[3] = (BYTE)0x80 | (BYTE)(unicode2 & 0x003F); n = 3; } /* Exit cc=1 if too few bytes remain in destination operand */ if (len1 <= n) { cc = 1; break; } /* Store the result bytes in the destination operand */ ARCH_DEP(vstorec) ( utf, n, addr1, r1, regs ); addr1 += n + 1; addr1 &= ADDRESS_MAXWRAP(regs); len1 -= n + 1; /* Update operand 2 address and length */ addr2 = naddr2; len2 = nlen2; /* Update the registers */ SET_GR_A(r1, regs,addr1); SET_GR_A(r1+1, regs,len1); SET_GR_A(r2, regs,addr2); SET_GR_A(r2+1, regs,len2); if (len1 == 0 && len2 != 0) cc = 1; } /* end for(i) */ regs->psw.cc = cc; } /* end convert_utf16_to_utf8 */ /*-------------------------------------------------------------------*/ /* B2A7 CU12 (CUTFU) - Convert UTF-8 to Unicode [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_utf8_to_utf16) { int r1, r2; /* Register numbers */ int i; /* Loop counter */ int cc = 0; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ GREG len1, len2; /* Operand lengths */ int pair; /* 1=Store Unicode pair */ U16 uvwxy; /* Unicode work area */ U16 unicode1; /* Unicode character */ U16 unicode2 = 0; /* Unicode low surrogate */ GREG n; /* Number of UTF-8 bytes - 1 */ BYTE utf[4]; /* UTF-8 bytes */ #if defined(FEATURE_ETF3_ENHANCEMENT) int wfc; /* WellFormednessChecking */ #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ // NOTE: it's faster to decode with RRE format // and then to handle the 'wfc' flag separately... // RRF_M(inst, regs, r1, r2, wfc); RRE(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) /* Set WellFormednessChecking */ if(inst[2] & 0x10) wfc = 1; else wfc = 0; #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Load operand lengths from bits 0-31 of R1+1 and R2+1 */ len1 = GR_A(r1+1, regs); len2 = GR_A(r2+1, regs); if (len1 == 0 && len2 > 0) cc = 1; /* Process operands from left to right */ for (i = 0; len1 > 0 && len2 > 0; i++) { /* If 4096 characters have been converted, exit with cc=3 */ if (i >= 4096) { cc = 3; break; } /* Fetch first UTF-8 byte from source operand */ utf[0] = ARCH_DEP(vfetchb) ( addr2, r2, regs ); /* Convert UTF-8 to Unicode */ if (utf[0] < (BYTE)0x80) { /* Convert 00-7F to Unicode 0000-007F */ n = 0; unicode1 = utf[0]; pair = 0; } else if ((utf[0] & 0xE0) == 0xC0) { #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormdnessChecking */ if(wfc) { if(utf[0] <= 0xc1) { regs->psw.cc = 2; return; } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Exit if fewer than 2 bytes remain in source operand */ n = 1; if (len2 <= n) break; /* Fetch two UTF-8 bytes from source operand */ ARCH_DEP(vfetchc) ( utf, n, addr2, r2, regs ); #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormednessChecking */ if(wfc) { if(utf[1] < 0x80 || utf[1] > 0xbf) { regs->psw.cc = 2; return; } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Convert C0xx-DFxx to Unicode */ unicode1 = ((U16)(utf[0] & 0x1F) << 6) | ((U16)(utf[1] & 0x3F)); pair = 0; } else if ((utf[0] & 0xF0) == 0xE0) { /* Exit if fewer than 3 bytes remain in source operand */ n = 2; if (len2 <= n) break; /* Fetch three UTF-8 bytes from source operand */ ARCH_DEP(vfetchc) ( utf, n, addr2, r2, regs ); #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormdnessChecking */ if(wfc) { if(utf[0] == 0xe0) { if(utf[1] < 0xa0 || utf[1] > 0xbf || utf[2] < 0x80 || utf[2] > 0xbf) { regs->psw.cc = 2; return; } } if((utf[0] >= 0xe1 && utf[0] <= 0xec) || (utf[0] >= 0xee && utf[0] < 0xef)) { if(utf[1] < 0x80 || utf[1] > 0xbf || utf[2] < 0x80 || utf[2] > 0xbf) { regs->psw.cc = 2; return; } } if(utf[0] == 0xed) { if(utf[1] < 0x80 || utf[1] > 0x9f || utf[2] < 0x80 || utf[2] > 0xbf) { regs->psw.cc = 2; return; } } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Convert E0xxxx-EFxxxx to Unicode */ unicode1 = ((U16)(utf[0]) << 12) | ((U16)(utf[1] & 0x3F) << 6) | ((U16)(utf[2] & 0x3F)); pair = 0; } else if ((utf[0] & 0xF8) == 0xF0) { /* Exit if fewer than 4 bytes remain in source operand */ n = 3; if (len2 <= n) break; /* Fetch four UTF-8 bytes from source operand */ ARCH_DEP(vfetchc) ( utf, n, addr2, r2, regs ); #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormdnessChecking */ if(wfc) { if(utf[0] == 0xf0) { if(utf[1] < 0x90 || utf[1] > 0xbf || utf[2] < 0x80 || utf[2] > 0xbf || utf[3] < 0x80 || utf[3] > 0xbf) { regs->psw.cc = 2; return; } } if(utf[0] >= 0xf1 && utf[0] <= 0xf3) { if(utf[1] < 0x80 || utf[1] > 0xbf || utf[2] < 0x80 || utf[2] > 0xbf || utf[3] < 0x80 || utf[3] > 0xbf) { regs->psw.cc = 2; return; } } if(utf[0] == 0xf4) { if(utf[1] < 0x80 || utf[1] > 0x8f || utf[2] < 0x80 || utf[2] > 0xbf || utf[3] < 0x80 || utf[3] > 0xbf) { regs->psw.cc = 2; return; } } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Convert F0xxxxxx-F7xxxxxx to Unicode surrogate pair */ uvwxy = ((((U16)(utf[0] & 0x07) << 2) | ((U16)(utf[1] & 0x30) >> 4)) - 1) & 0x0F; unicode1 = 0xD800 | (uvwxy << 6) | ((U16)(utf[1] & 0x0F) << 2) | ((U16)(utf[2] & 0x30) >> 4); unicode2 = 0xDC00 | ((U16)(utf[2] & 0x0F) << 6) | ((U16)(utf[3] & 0x3F)); pair = 1; } else { /* Invalid UTF-8 byte 80-BF or F8-FF, exit with cc=2 */ cc = 2; break; } /* Store the result bytes in the destination operand */ if (pair) { /* Exit if fewer than 4 bytes remain in destination */ if (len1 < 4) { cc = 1; break; } /* Store Unicode surrogate pair in destination */ ARCH_DEP(vstore4) ( ((U32)unicode1 << 16) | (U32)unicode2, addr1, r1, regs ); addr1 += 4; addr1 &= ADDRESS_MAXWRAP(regs); len1 -= 4; } else { /* Exit if fewer than 2 bytes remain in destination */ if (len1 < 2) { cc = 1; break; } /* Store Unicode character in destination */ ARCH_DEP(vstore2) ( unicode1, addr1, r1, regs ); addr1 += 2; addr1 &= ADDRESS_MAXWRAP(regs); len1 -= 2; } /* Update operand 2 address and length */ addr2 += n + 1; addr2 &= ADDRESS_MAXWRAP(regs); len2 -= n + 1; /* Update the registers */ SET_GR_A(r1, regs,addr1); SET_GR_A(r1+1, regs,len1); SET_GR_A(r2, regs,addr2); SET_GR_A(r2+1, regs,len2); if (len1 == 0 && len2 != 0) cc = 1; } /* end for(i) */ regs->psw.cc = cc; } /* end convert_utf8_to_utf16 */ #endif /*FEATURE_EXTENDED_TRANSLATION*/ /*-------------------------------------------------------------------*/ /* 4F CVB - Convert to Binary [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_to_binary) { U64 dreg; /* 64-bit result accumulator */ int r1; /* Value of R1 field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int ovf; /* 1=overflow */ int dxf; /* 1=data exception */ BYTE dec[8]; /* Packed decimal operand */ RX(inst, regs, r1, b2, effective_addr2); /* Fetch 8-byte packed decimal operand */ ARCH_DEP(vfetchc) (dec, 8-1, effective_addr2, b2, regs); /* Convert 8-byte packed decimal to 64-bit signed binary */ packed_to_binary (dec, 8-1, &dreg, &ovf, &dxf); /* Data exception if invalid digits or sign */ if (dxf) { regs->dxc = DXC_DECIMAL; regs->program_interrupt (regs, PGM_DATA_EXCEPTION); } /* Overflow if result exceeds 31 bits plus sign */ if ((S64)dreg < -2147483648LL || (S64)dreg > 2147483647LL) ovf = 1; /* Store low-order 32 bits of result into R1 register */ regs->GR_L(r1) = dreg & 0xFFFFFFFF; /* Program check if overflow (R1 contains rightmost 32 bits) */ if (ovf) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); } /* end DEF_INST(convert_to_binary) */ /*-------------------------------------------------------------------*/ /* 4E CVD - Convert to Decimal [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_to_decimal) { S64 bin; /* 64-bit signed binary value*/ int r1; /* Value of R1 field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE dec[16]; /* Packed decimal result */ RX(inst, regs, r1, b2, effective_addr2); /* Load value of register and sign-extend to 64 bits */ bin = (S64)((S32)(regs->GR_L(r1))); /* Convert to 16-byte packed decimal number */ binary_to_packed (bin, dec); /* Store low 8 bytes of result at operand address */ ARCH_DEP(vstorec) ( dec+8, 8-1, effective_addr2, b2, regs ); } /* end DEF_INST(convert_to_decimal) */ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* B24D CPYA - Copy Access [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(copy_access) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy R2 access register to R1 access register */ regs->AR(r1) = regs->AR(r2); SET_AEA_AR(regs, r1); } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* 1D DR - Divide Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_register) { int r1; /* Values of R fields */ int r2; /* Values of R fields */ int divide_overflow; /* 1=divide overflow */ RR(inst, regs, r1, r2); ODD_CHECK(r1, regs); /* Divide r1::r1+1 by r2, remainder in r1, quotient in r1+1 */ divide_overflow = div_signed (&(regs->GR_L(r1)),&(regs->GR_L(r1+1)), regs->GR_L(r1), regs->GR_L(r1+1), regs->GR_L(r2)); /* Program check if overflow */ if ( divide_overflow ) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); } /*-------------------------------------------------------------------*/ /* 5D D - Divide [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(divide) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ int divide_overflow; /* 1=divide overflow */ RX(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Divide r1::r1+1 by n, remainder in r1, quotient in r1+1 */ divide_overflow = div_signed (&(regs->GR_L(r1)), &(regs->GR_L(r1+1)), regs->GR_L(r1), regs->GR_L(r1+1), n); /* Program check if overflow */ if ( divide_overflow ) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); } /*-------------------------------------------------------------------*/ /* 17 XR - Exclusive Or Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* XOR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) ^= regs->GR_L(r2) ) ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 57 X - Exclusive Or [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* XOR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) ^= n ) ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 97 XI - Exclusive Or Immediate [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_immediate) { BYTE i2; /* Immediate operand */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE *dest; /* Pointer to target byte */ SI(inst, regs, i2, b1, effective_addr1); ITIMER_SYNC(effective_addr1,1,regs); /* Get byte mainstor address */ dest = MADDR (effective_addr1, b1, regs, ACCTYPE_WRITE, regs->psw.pkey ); /* XOR byte with immediate operand, setting condition code */ regs->psw.cc = ((*dest ^= i2) != 0); ITIMER_UPDATE(effective_addr1,0,regs); } /*-------------------------------------------------------------------*/ /* D7 XC - Exclusive Or Character [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_character) { int len, len2, len3; /* Lengths to copy */ int b1, b2; /* Base register numbers */ VADR addr1, addr2; /* Virtual addresses */ BYTE *dest1, *dest2; /* Destination addresses */ BYTE *source1, *source2; /* Source addresses */ BYTE *sk1, *sk2; /* Storage key addresses */ int i; /* Loop counter */ int cc = 0; /* Condition code */ SS_L(inst, regs, len, b1, addr1, b2, addr2); ITIMER_SYNC(addr1,len,regs); ITIMER_SYNC(addr2,len,regs); /* Quick out for 1 byte (no boundary crossed) */ if (unlikely(len == 0)) { source1 = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); dest1 = MADDR (addr1, b1, regs, ACCTYPE_WRITE, regs->psw.pkey); if (*dest1 ^= *source1) cc = 1; regs->psw.cc = cc; return; } /* There are several scenarios (in optimal order): * (1) dest boundary and source boundary not crossed * (a) dest and source are the same, set dest to zeroes * (b) dest and source are not the same * (2) dest boundary not crossed and source boundary crossed * (3) dest boundary crossed and source boundary not crossed * (4) dest boundary and source boundary are crossed * (a) dest and source boundary cross at the same time * (b) dest boundary crossed first * (c) source boundary crossed first */ /* Translate addresses of leftmost operand bytes */ dest1 = MADDRL (addr1, len, b1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk1 = regs->dat.storkey; source1 = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if ( NOCROSS2K(addr1,len)) { if ( NOCROSS2K(addr2,len)) { /* (1) - No boundaries are crossed */ if (dest1 == source1) { /* (1a) - Dest and source are the same */ memset(dest1, 0, len + 1); } else { /* (1b) - Dest and source are not the sam */ for (i = 0; i <= len; i++) if (*dest1++ ^= *source1++) cc = 1; } } else { /* (2) - Second operand crosses a boundary */ len2 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len2) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); for ( i = 0; i < len2; i++) if (*dest1++ ^= *source1++) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if (*dest1++ ^= *source2++) cc = 1; } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); } else { /* First operand crosses a boundary */ len2 = 0x800 - (addr1 & 0x7FF); dest2 = MADDR ((addr1 + len2) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk2 = regs->dat.storkey; if ( NOCROSS2K(addr2,len)) { /* (3) - First operand crosses a boundary */ for ( i = 0; i < len2; i++) if (*dest1++ ^= *source1++) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if (*dest2++ ^= *source1++) cc = 1; } else { /* (4) - Both operands cross a boundary */ len3 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len3) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); if (len2 == len3) { /* (4a) - Both operands cross at the same time */ for ( i = 0; i < len2; i++) if (*dest1++ ^= *source1++) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if (*dest2++ ^= *source2++) cc = 1; } else if (len2 < len3) { /* (4b) - First operand crosses first */ for ( i = 0; i < len2; i++) if (*dest1++ ^= *source1++) cc = 1; len2 = len3 - len2; for ( i = 0; i < len2; i++) if (*dest2++ ^= *source1++) cc = 1; len2 = len - len3; for ( i = 0; i <= len2; i++) if (*dest2++ ^= *source2++) cc = 1; } else { /* (4c) - Second operand crosses first */ for ( i = 0; i < len3; i++) if (*dest1++ ^= *source1++) cc = 1; len3 = len2 - len3; for ( i = 0; i < len3; i++) if (*dest1++ ^= *source2++) cc = 1; len3 = len - len2; for ( i = 0; i <= len3; i++) if (*dest2++ ^= *source2++) cc = 1; } } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); *sk2 |= (STORKEY_REF | STORKEY_CHANGE); } regs->psw.cc = cc; ITIMER_UPDATE(addr1,len,regs); } /*-------------------------------------------------------------------*/ /* 44 EX - Execute [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(execute) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ BYTE *ip; /* -> executed instruction */ RX(inst, regs, r1, b2, regs->ET); ODD_CHECK(regs->ET, regs); #if defined(_FEATURE_SIE) /* Ensure that the instruction field is zero, such that zeros are stored in the interception parm field, if the interrupt is intercepted */ memset(regs->exinst, 0, 8); #endif /*defined(_FEATURE_SIE)*/ /* Fetch target instruction from operand address */ ip = INSTRUCTION_FETCH(regs, 1); if (ip != regs->exinst) memcpy (regs->exinst, ip, 8); /* Program check if recursive execute */ if ( regs->exinst[0] == 0x44 #if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) || (regs->exinst[0] == 0xc6 && !(regs->exinst[1] & 0x0f)) #endif /*defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/ ) regs->program_interrupt (regs, PGM_EXECUTE_EXCEPTION); /* Or 2nd byte of instruction with low-order byte of R1 */ regs->exinst[1] |= r1 ? regs->GR_LHLCL(r1) : 0; /* * Turn execflag on indicating this instruction is EXecuted. * psw.ip is backed up by the EXecuted instruction length to * be incremented back by the instruction decoder. */ regs->execflag = 1; regs->exrl = 0; regs->ip -= ILC(regs->exinst[0]); EXECUTE_INSTRUCTION (regs->exinst, regs); /* Leave execflag on if pending PER so ILC will reflect EX */ if (!OPEN_IC_PER(regs)) regs->execflag = 0; } #if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) /*-------------------------------------------------------------------*/ /* C6x0 EXRL - Execute Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(execute_relative_long) { int r1; /* Register number */ BYTE *ip; /* -> executed instruction */ RIL_A(inst, regs, r1, regs->ET); #if defined(_FEATURE_SIE) /* Ensure that the instruction field is zero, such that zeros are stored in the interception parm field, if the interrupt is intercepted */ memset(regs->exinst, 0, 8); #endif /*defined(_FEATURE_SIE)*/ /* Fetch target instruction from operand address */ ip = INSTRUCTION_FETCH(regs, 1); if (ip != regs->exinst) memcpy (regs->exinst, ip, 8); #if 1 /* Display target instruction if stepping or tracing */ if (CPU_STEPPING_OR_TRACING(regs, 6)) { int n, ilc; char buf[256]; #if defined(FEATURE_ESAME) n = sprintf (buf, "EXRL target ADDR="F_VADR" ", regs->ET); #else n = sprintf (buf, "EXRL ADDR="F_VADR" ", regs->ET); #endif ilc = ILC(ip[0]); n += sprintf (buf+n, " INST=%2.2X%2.2X", ip[0], ip[1]); if (ilc > 2) n += sprintf (buf+n, "%2.2X%2.2X", ip[2], ip[3]); if (ilc > 4) n += sprintf (buf+n, "%2.2X%2.2X", ip[4], ip[5]); logmsg ("%s %s", buf,(ilc<4) ? " " : (ilc<6) ? " " : ""); DISASM_INSTRUCTION(ip,buf); logmsg ("%s\n", buf); } #endif /* Program check if recursive execute */ if ( regs->exinst[0] == 0x44 || (regs->exinst[0] == 0xc6 && !(regs->exinst[1] & 0x0f)) ) regs->program_interrupt (regs, PGM_EXECUTE_EXCEPTION); /* Or 2nd byte of instruction with low-order byte of R1 */ regs->exinst[1] |= r1 ? regs->GR_LHLCL(r1) : 0; /* * Turn execflag on indicating this instruction is EXecuted. * psw.ip is backed up by the EXecuted instruction length to * be incremented back by the instruction decoder. */ regs->execflag = 1; regs->exrl = 1; regs->ip -= ILC(regs->exinst[0]); EXECUTE_INSTRUCTION (regs->exinst, regs); /* Leave execflag on if pending PER so ILC will reflect EXRL */ if (!OPEN_IC_PER(regs)) regs->execflag = 0; } #endif /* defined(FEATURE_EXECUTE_EXTENSION_FACILITY) */ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* B24F EAR - Extract Access Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_access_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy R2 access register to R1 general register */ regs->GR_L(r1) = regs->AR(r2); } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* 43 IC - Insert Character [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_character) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX(inst, regs, r1, b2, effective_addr2); /* Insert character in r1 register */ regs->GR_LHLCL(r1) = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* BF ICM - Insert Characters under Mask [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_characters_under_mask) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Integer work area */ BYTE vbyte[4]; /* Fetched storage bytes */ U32 n; /* Fetched value */ static const int /* Length-1 to fetch by mask */ icmlen[16] = {0, 0, 0, 1, 0, 1, 1, 2, 0, 1, 1, 2, 1, 2, 2, 3}; static const unsigned int /* Turn reg bytes off by mask*/ icmmask[16] = {0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFFFF0000, 0xFF00FFFF, 0xFF00FF00, 0xFF0000FF, 0xFF000000, 0x00FFFFFF, 0x00FFFF00, 0x00FF00FF, 0x00FF0000, 0x0000FFFF, 0x0000FF00, 0x000000FF, 0x00000000}; RS(inst, regs, r1, r3, b2, effective_addr2); switch (r3) { case 7: /* Optimized case */ vbyte[0] = 0; ARCH_DEP(vfetchc) (vbyte + 1, 2, effective_addr2, b2, regs); n = fetch_fw (vbyte); regs->GR_L(r1) = (regs->GR_L(r1) & 0xFF000000) | n; regs->psw.cc = n ? n & 0x00800000 ? 1 : 2 : 0; break; case 15: /* Optimized case */ regs->GR_L(r1) = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); regs->psw.cc = regs->GR_L(r1) ? regs->GR_L(r1) & 0x80000000 ? 1 : 2 : 0; break; default: memset (vbyte, 0, 4); ARCH_DEP(vfetchc)(vbyte, icmlen[r3], effective_addr2, b2, regs); /* If mask was 0 then we still had to fetch, according to POP. If so, set the fetched byte to 0 to force zero cc */ if (!r3) vbyte[0] = 0; n = fetch_fw (vbyte); regs->psw.cc = n ? n & 0x80000000 ? 1 : 2 : 0; /* Turn off the reg bytes we are going to set */ regs->GR_L(r1) &= icmmask[r3]; /* Set bytes one at a time according to the mask */ i = 0; if (r3 & 0x8) regs->GR_L(r1) |= vbyte[i++] << 24; if (r3 & 0x4) regs->GR_L(r1) |= vbyte[i++] << 16; if (r3 & 0x2) regs->GR_L(r1) |= vbyte[i++] << 8; if (r3 & 0x1) regs->GR_L(r1) |= vbyte[i]; break; } /* switch (r3) */ } /*-------------------------------------------------------------------*/ /* B222 IPM - Insert Program Mask [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_program_mask) { int r1, unused; /* Value of R field */ RRE0(inst, regs, r1, unused); /* Insert condition code in R1 bits 2-3, program mask in R1 bits 4-7, and set R1 bits 0-1 to zero */ regs->GR_LHHCH(r1) = (regs->psw.cc << 4) | regs->psw.progmask; } /*-------------------------------------------------------------------*/ /* 58 L - Load [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ #if 0 U32 *p; /* Mainstor pointer */ #endif RX(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_L(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); } /* end DEF_INST(load) */ /*-------------------------------------------------------------------*/ /* 18 LR - Load Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Copy second operand to first operand */ regs->GR_L(r1) = regs->GR_L(r2); } #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* 9A LAM - Load Access Multiple [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(load_access_multiple) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2 = NULL; /* Mainstor pointers */ RS(inst, regs, r1, r3, b2, effective_addr2); FW_CHECK(effective_addr2, regs); /* Calculate number of regs to fetch */ n = ((r3 - r1) & 0xF) + 1; /* Calculate number of words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 2; /* Address of operand beginning */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely (m < n)) p2 = (U32*)MADDR(effective_addr2 + (m*4), b2, regs, ACCTYPE_READ, regs->psw.pkey); else m = n; /* Copy from operand beginning */ for (i = 0; i < m; i++, p1++) { regs->AR((r1 + i) & 0xF) = fetch_fw (p1); SET_AEA_AR (regs, (r1 + i) & 0xF); } /* Copy from next page */ for ( ; i < n; i++, p2++) { regs->AR((r1 + i) & 0xF) = fetch_fw (p2); SET_AEA_AR (regs, (r1 + i) & 0xF); } } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* 41 LA - Load Address [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load_address) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX0(inst, regs, r1, b2, effective_addr2); /* Load operand address into register */ SET_GR_A(r1, regs, effective_addr2); } #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* 51 LAE - Load Address Extended [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load_address_extended) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX0(inst, regs, r1, b2, effective_addr2); /* Load operand address into register */ SET_GR_A(r1, regs,effective_addr2); /* Load corresponding value into access register */ if ( PRIMARY_SPACE_MODE(&(regs->psw)) ) regs->AR(r1) = ALET_PRIMARY; else if ( SECONDARY_SPACE_MODE(&(regs->psw)) ) regs->AR(r1) = ALET_SECONDARY; else if ( HOME_SPACE_MODE(&(regs->psw)) ) regs->AR(r1) = ALET_HOME; else /* ACCESS_REGISTER_MODE(&(regs->psw)) */ regs->AR(r1) = (b2 == 0) ? 0 : regs->AR(b2); SET_AEA_AR(regs, r1); } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* 12 LTR - Load and Test Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Copy second operand and set condition code */ regs->GR_L(r1) = regs->GR_L(r2); regs->psw.cc = (S32)regs->GR_L(r1) < 0 ? 1 : (S32)regs->GR_L(r1) > 0 ? 2 : 0; } /*-------------------------------------------------------------------*/ /* 13 LCR - Load Complement Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_register) { int r1, r2; /* Values of R fields */ RR(inst, regs, r1, r2); /* Condition code 3 and program check if overflow */ if ( regs->GR_L(r2) == 0x80000000 ) { regs->GR_L(r1) = regs->GR_L(r2); regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Load complement of second operand and set condition code */ regs->GR_L(r1) = -((S32)regs->GR_L(r2)); regs->psw.cc = (S32)regs->GR_L(r1) < 0 ? 1 : (S32)regs->GR_L(r1) > 0 ? 2 : 0; } /*-------------------------------------------------------------------*/ /* 48 LH - Load Halfword [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX(inst, regs, r1, b2, effective_addr2); /* Load rightmost 2 bytes of register from operand address */ regs->GR_L(r1) = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); } #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7x8 LHI - Load Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(load_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); /* Load operand into register */ regs->GR_L(r1) = (S16)i2; } #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ /*-------------------------------------------------------------------*/ /* 98 LM - Load Multiple [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(load_multiple) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2; /* Mainstor pointers */ BYTE *bp1; /* Unaligned maintstor ptr */ RS(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to load */ n = (((r3 - r1) & 0xF) + 1) << 2; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Address of operand beginning */ bp1 = (BYTE*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); p1=(U32*)bp1; if (likely(n <= m)) { /* Boundary not crossed */ n >>= 2; #if defined(OPTION_STRICT_ALIGNMENT) if(likely(!(((uintptr_t)effective_addr2)&0x03))) { #endif for (i = 0; i < n; i++, p1++) regs->GR_L((r1 + i) & 0xF) = fetch_fw (p1); #if defined(OPTION_STRICT_ALIGNMENT) } else { for (i = 0; i < n; i++, bp1+=4) regs->GR_L((r1 + i) & 0xF) = fetch_fw (bp1); } #endif } else { /* Boundary crossed, get 2nd page address */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if (likely((m & 0x3) == 0)) { /* Addresses are word aligned */ m >>= 2; for (i = 0; i < m; i++, p1++) regs->GR_L((r1 + i) & 0xF) = fetch_fw (p1); n >>= 2; for ( ; i < n; i++, p2++) regs->GR_L((r1 + i) & 0xF) = fetch_fw (p2); } else { /* Worst case */ U32 rwork[16]; BYTE *b1, *b2; b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b1++ = *b2++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b1++ = *b2++; n >>= 2; for (i = 0; i < n; i++) regs->GR_L((r1 + i) & 0xF) = CSWAP32(rwork[i]); } } } /* end DEF_INST(load_multiple) */ /*-------------------------------------------------------------------*/ /* 11 LNR - Load Negative Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Load negative value of second operand and set cc */ regs->GR_L(r1) = (S32)regs->GR_L(r2) > 0 ? -((S32)regs->GR_L(r2)) : (S32)regs->GR_L(r2); regs->psw.cc = (S32)regs->GR_L(r1) == 0 ? 0 : 1; } /*-------------------------------------------------------------------*/ /* 10 LPR - Load Positive Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_register) { int r1, r2; /* Values of R fields */ RR(inst, regs, r1, r2); /* Condition code 3 and program check if overflow */ if ( regs->GR_L(r2) == 0x80000000 ) { regs->GR_L(r1) = regs->GR_L(r2); regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Load positive value of second operand and set cc */ regs->GR_L(r1) = (S32)regs->GR_L(r2) < 0 ? -((S32)regs->GR_L(r2)) : (S32)regs->GR_L(r2); regs->psw.cc = (S32)regs->GR_L(r1) == 0 ? 0 : 2; } /*-------------------------------------------------------------------*/ /* AF MC - Monitor Call [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(monitor_call) { BYTE i2; /* Monitor class */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ CREG n; /* Work */ SI(inst, regs, i2, b1, effective_addr1); /* Program check if monitor class exceeds 15 */ if ( i2 > 0x0F ) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Ignore if monitor mask in control register 8 is zero */ n = (regs->CR(8) & CR8_MCMASK) << i2; if ((n & 0x00008000) == 0) return; #if defined(FEATURE_ENHANCED_MONITOR_FACILITY) /* Perform Monitor Event Counting Operation if enabled */ if (((regs->CR_H(8) & CR8_MCMASK) << i2) & 0x00008000) { PSA *psa; /* -> Prefixed storage area */ RADR cao; /* Enhanced Monitor Counter Array Origin */ U32 cal; /* Enhanced Monitor Counter Array Length */ U32 ec; /* Enhanced Montior Counter Exception Count */ RADR ceh; /* HW Counter Entry address */ RADR cew; /* FW Counter Entry address */ RADR px; int unavailable; U16 hwc; U32 fwc; px = regs->PX; SIE_TRANSLATE(&px, ACCTYPE_WRITE, regs); /* Point to PSA in main storage */ psa = (void*)(regs->mainstor + px); /* Set the main storage reference bit */ STORAGE_KEY(px, regs) |= STORKEY_REF; /* Fetch Counter Array Origin and Size from PSA */ FETCH_DW(cao, psa->cao); FETCH_W(cal, psa->cal); /* DW boundary, ignore last 3 bits */ cao &= ~7ULL; if(!(unavailable = (effective_addr1 >= cal))) { /* Point to the virtual address of the HW entry */ ceh = cao + (effective_addr1 << 1); if(!(unavailable = ARCH_DEP(translate_addr) (ceh, USE_HOME_SPACE, regs, ACCTYPE_EMC))) { /* Convert real address to absolute address */ ceh = APPLY_PREFIXING (regs->dat.raddr, regs->PX); /* Ensure absolute address is available */ if (!(unavailable = (ceh >= regs->mainlim ))) { SIE_TRANSLATE(&ceh, ACCTYPE_WRITE, regs); /* Update counter */ FETCH_HW(hwc, ceh + regs->mainstor); STORAGE_KEY(ceh, regs) |= STORKEY_REF; if(++hwc) { STORE_HW(ceh + regs->mainstor, hwc); STORAGE_KEY(ceh, regs) |= (STORKEY_REF | STORKEY_CHANGE); } else { /* Point to the virtual address of the FW entry */ cew = cao + (cal << 1) + (effective_addr1 << 2); if(!(unavailable = ARCH_DEP(translate_addr) (cew, USE_HOME_SPACE, regs, ACCTYPE_EMC))) { /* Convert real address to absolute address */ cew = APPLY_PREFIXING (regs->dat.raddr, regs->PX); /* Ensure absolute address is available */ if (!(unavailable = (cew >= regs->mainlim ))) { SIE_TRANSLATE(&cew, ACCTYPE_WRITE, regs); /* Update both counters */ FETCH_W(fwc, cew + regs->mainstor); fwc++; STORE_W(cew + regs->mainstor, fwc); STORAGE_KEY(cew, regs) |= (STORKEY_REF | STORKEY_CHANGE); STORE_HW(ceh + regs->mainstor, hwc); STORAGE_KEY(ceh, regs) |= (STORKEY_REF | STORKEY_CHANGE); } } } } } } /* Update the Enhance Monitor Exception Counter if the array could not be updated */ if(unavailable) { FETCH_W(ec,psa->ec); ec++; /* Set the main storage reference and change bits */ STORAGE_KEY(px, regs) |= (STORKEY_REF | STORKEY_CHANGE); STORE_W(psa->ec,ec); } return; } #endif /*defined(FEATURE_ENHANCED_MONITOR_FACILITY)*/ regs->monclass = i2; regs->MONCODE = effective_addr1; /* Generate a monitor event program interruption */ regs->program_interrupt (regs, PGM_MONITOR_EVENT); } /*-------------------------------------------------------------------*/ /* 92 MVI - Move Immediate [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(move_immediate) { BYTE i2; /* Immediate operand */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ SI(inst, regs, i2, b1, effective_addr1); /* Store immediate operand at operand address */ ARCH_DEP(vstoreb) ( i2, effective_addr1, b1, regs ); } /*-------------------------------------------------------------------*/ /* D2 MVC - Move Character [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_character) { BYTE l; /* Length byte */ int b1, b2; /* Values of base fields */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SS_L(inst, regs, l, b1, effective_addr1, b2, effective_addr2); /* Move characters using current addressing mode and key */ ARCH_DEP(move_chars) (effective_addr1, b1, regs->psw.pkey, effective_addr2, b2, regs->psw.pkey, l, regs); } /*-------------------------------------------------------------------*/ /* E8 MVCIN - Move Inverse [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_inverse) { BYTE l; /* Lenght byte */ int b1, b2; /* Base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ VADR n; /* 32-bit operand values */ BYTE tbyte; /* Byte work areas */ int i; /* Integer work areas */ SS_L(inst, regs, l, b1, effective_addr1, b2, effective_addr2); /* If operand 1 crosses a page, make sure both pages are accessable */ if((effective_addr1 & PAGEFRAME_PAGEMASK) != ((effective_addr1 + l) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr1, b1, l, ACCTYPE_WRITE_SKP, regs); /* If operand 2 crosses a page, make sure both pages are accessable */ n = (effective_addr2 - l) & ADDRESS_MAXWRAP(regs); if((n & PAGEFRAME_PAGEMASK) != ((n + l) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (n, b2, l, ACCTYPE_READ, regs); /* Process the destination operand from left to right, and the source operand from right to left */ for ( i = 0; i <= l; i++ ) { /* Fetch a byte from the source operand */ tbyte = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); /* Store the byte in the destination operand */ ARCH_DEP(vstoreb) ( tbyte, effective_addr1, b1, regs ); /* Increment destination operand address */ effective_addr1++; effective_addr1 &= ADDRESS_MAXWRAP(regs); /* Decrement source operand address */ effective_addr2--; effective_addr2 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ } /*-------------------------------------------------------------------*/ /* 0E MVCL - Move Long [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(move_long) { int r1, r2; /* Values of R fields */ VADR addr1, addr2; /* Operand addresses */ int len1, len2; /* Operand lengths */ int len, len3, len4; /* Work lengths */ VADR n; /* Work area */ BYTE *dest, *source; /* Mainstor addresses */ BYTE pad; /* Padding byte */ #if defined(FEATURE_INTERVAL_TIMER) int orglen1; /* Original dest length */ #endif RR(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Load padding byte from bits 0-7 of R2+1 register */ pad = regs->GR_LHHCH(r2+1); /* Load operand lengths from bits 8-31 of R1+1 and R2+1 */ len1 = regs->GR_LA24(r1+1); len2 = regs->GR_LA24(r2+1); #if defined(FEATURE_INTERVAL_TIMER) orglen1=len1; #endif ITIMER_SYNC(addr2,len2,regs); /* Test for destructive overlap */ if ( len2 > 1 && len1 > 1 && (!ACCESS_REGISTER_MODE(&(regs->psw)) || (r1 == 0 ? 0 : regs->AR(r1)) == (r2 == 0 ? 0 : regs->AR(r2)))) { n = addr2 + ((len2 < len1) ? len2 : len1) - 1; n &= ADDRESS_MAXWRAP(regs); if ((n > addr2 && (addr1 > addr2 && addr1 <= n)) || (n <= addr2 && (addr1 > addr2 || addr1 <= n))) { SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); regs->psw.cc = 3; #if 0 logmsg (_("MVCL destructive overlap: ")); ARCH_DEP(display_inst) (regs, inst); #endif return; } } /* Initialize source and dest addresses */ if (len1) { if (len2) { source = MADDR (addr2, r2, regs, ACCTYPE_READ, regs->psw.pkey); } else { source=NULL; } dest = MADDRL (addr1, len1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey); } else { /* FIXME : We shouldn't have to do that - just to prevent potentially uninitialized variable warning in GCC.. Can't see where it is getting this diagnostic from. ISW 2009/02/04 */ source=NULL; dest=NULL; } /* Set the condition code according to the lengths */ regs->psw.cc = (len1 < len2) ? 1 : (len1 > len2) ? 2 : 0; /* Set the registers *after* translating - so that the instruction is properly nullified when there is an access exception on the 1st unit of operation */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); while (len1) { /* Clear or copy memory */ if (len2 == 0) { len = NOCROSS2KL(addr1,len1) ? len1 : (int)(0x800 - (addr1 & 0x7FF)); memset (dest, pad, len); } else { len3 = NOCROSS2KL(addr1,len1) ? len1 : (int)(0x800 - (addr1 & 0x7FF)); len4 = NOCROSS2KL(addr2,len2) ? len2 : (int)(0x800 - (addr2 & 0x7FF)); len = len3 < len4 ? len3 : len4; /* Use concpy to ensure Concurrent block update consistency */ concpy (regs, dest, source, len); } /* No longer required because it is handled during MADDRL */ #if 0 /* Check for storage alteration PER event */ #if defined(FEATURE_PER) if ( EN_IC_PER_SA(regs) #if defined(FEATURE_PER2) && ( REAL_MODE(®s->psw) || ARCH_DEP(check_sa_per2) (r1, ACCTYPE_WRITE, regs) ) #endif /*defined(FEATURE_PER2)*/ && PER_RANGE_CHECK2(addr1, addr1+len, regs->CR(10), regs->CR(11)) ) ON_IC_PER_SA(regs); #endif /*defined(FEATURE_PER)*/ #endif /* Adjust lengths and virtual addresses */ len1 -= len; addr1 = (addr1 + len) & ADDRESS_MAXWRAP(regs); if (len2) { len2 -= len; addr2 = (addr2 + len) & ADDRESS_MAXWRAP(regs); } /* Update regs (since interrupt may occur) */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); regs->GR_LA24(r1+1) = len1; regs->GR_LA24(r2+1) = len2; /* Check for pending interrupt */ if ( len1 > 256 && (OPEN_IC_EXTPENDING(regs) || OPEN_IC_IOPENDING(regs)) ) { UPD_PSW_IA (regs, PSW_IA(regs, -REAL_ILC(regs))); break; } /* Translate next source and dest addresses */ if (len1) { if (len2) { if (addr2 & 0x7FF) source += len; else source = MADDR (addr2, r2, regs, ACCTYPE_READ, regs->psw.pkey); } if (addr1 & 0x7FF) dest += len; else dest = MADDRL (addr1, len1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey); } } /* while (len1) */ ITIMER_UPDATE(addr1,orglen1,regs); /* If len1 is non-zero then we were interrupted */ if (len1) RETURN_INTCHECK(regs); } #if defined(FEATURE_COMPARE_AND_MOVE_EXTENDED) /*-------------------------------------------------------------------*/ /* A8 MVCLE - Move Long Extended [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_long_extended) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int cc; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ GREG len1, len2; /* Operand lengths */ BYTE pad; /* Padding byte */ size_t cpu_length; /* cpu determined length */ size_t copylen; /* Length to copy */ BYTE *dest; /* Maint storage pointers */ size_t dstlen,srclen; /* Page wide src/dst lengths */ RS(inst, regs, r1, r3, b2, effective_addr2); ODD2_CHECK(r1, r3, regs); /* Load padding byte from bits 24-31 of effective address */ pad = effective_addr2 & 0xFF; /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r3) & ADDRESS_MAXWRAP(regs); /* Load operand lengths from bits 0-31 of R1+1 and R3+1 */ len1 = GR_A(r1+1, regs); len2 = GR_A(r3+1, regs); /* set cpu_length as shortest distance to new page */ if ((addr1 & 0xFFF) > (addr2 & 0xFFF)) cpu_length = 0x1000 - (addr1 & 0xFFF); else cpu_length = 0x1000 - (addr2 & 0xFFF); dstlen=MIN(cpu_length,len1); srclen=MIN(cpu_length,len2); copylen=MIN(dstlen,srclen); /* Set the condition code according to the lengths */ cc = (len1 < len2) ? 1 : (len1 > len2) ? 2 : 0; /* Obtain destination pointer */ if(len1==0) { /* bail out if nothing to do */ regs->psw.cc = cc; return; } dest = MADDRL (addr1, len1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey); if(copylen!=0) { /* here if we need to copy data */ BYTE *source; /* get source frame and copy concurrently */ source = MADDR (addr2, r3, regs, ACCTYPE_READ, regs->psw.pkey); concpy(regs,dest,source,copylen); /* Adjust operands */ addr2+=copylen; len2-=copylen; addr1+=copylen; len1-=copylen; /* Adjust length & pointers for this cycle */ dest+=copylen; dstlen-=copylen; srclen-=copylen; } if(srclen==0 && dstlen!=0) { /* here if we need to pad the destination */ memset(dest,pad,dstlen); /* Adjust destination operands */ addr1+=dstlen; len1-=dstlen; } /* Update the registers */ SET_GR_A(r1, regs,addr1); SET_GR_A(r1+1, regs,len1); SET_GR_A(r3, regs,addr2); SET_GR_A(r3+1, regs,len2); /* if len1 != 0 then set CC to 3 to indicate we have reached end of CPU dependent length */ if(len1>0) cc=3; regs->psw.cc = cc; } #endif /*defined(FEATURE_COMPARE_AND_MOVE_EXTENDED)*/ #define MOVE_NUMERIC_BUMP(_d,_s) \ do { \ *(_d)=( *(_d) & 0xF0) | ( *(_s) & 0x0F); \ _d++; \ _s++; \ } while(0) /*-------------------------------------------------------------------*/ /* D1 MVN - Move Numerics [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_numerics) { VADR addr1, addr2; /* Operand virtual addresses */ int len, arn1, arn2; /* Operand values */ BYTE *dest1, *dest2; /* Destination addresses */ BYTE *source1, *source2; /* Source addresses */ BYTE *sk1, *sk2; /* Storage key addresses */ int len2, len3; /* Lengths to copy */ int i; /* Loop counter */ SS_L(inst, regs, len, arn1, addr1, arn2, addr2); ITIMER_SYNC(addr2,len,regs); /* Translate addresses of leftmost operand bytes */ dest1 = MADDRL (addr1, len+1, arn1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk1 = regs->dat.storkey; source1 = MADDR (addr2, arn2, regs, ACCTYPE_READ, regs->psw.pkey); /* There are several scenarios (in optimal order): * (1) dest boundary and source boundary not crossed * (2) dest boundary not crossed and source boundary crossed * (3) dest boundary crossed and source boundary not crossed * (4) dest boundary and source boundary are crossed * (a) dest and source boundary cross at the same time * (b) dest boundary crossed first * (c) source boundary crossed first */ if ( NOCROSS2K(addr1,len)) { if ( NOCROSS2K(addr2,len)) { /* (1) - No boundaries are crossed */ for ( i = 0; i <= len; i++) MOVE_NUMERIC_BUMP(dest1,source1); } else { /* (2) - Second operand crosses a boundary */ len2 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len2) & ADDRESS_MAXWRAP(regs), arn2, regs, ACCTYPE_READ, regs->psw.pkey); for ( i = 0; i < len2; i++) MOVE_NUMERIC_BUMP(dest1,source1); len2 = len - len2; for ( i = 0; i <= len2; i++) MOVE_NUMERIC_BUMP(dest1,source2); } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); } else { /* First operand crosses a boundary */ len2 = 0x800 - (addr1 & 0x7FF); dest2 = MADDR ((addr1 + len2) & ADDRESS_MAXWRAP(regs), arn1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk2 = regs->dat.storkey; if ( NOCROSS2K(addr2,len) ) { /* (3) - First operand crosses a boundary */ for ( i = 0; i < len2; i++) MOVE_NUMERIC_BUMP(dest1,source1); len2 = len - len2; for ( i = 0; i <= len2; i++) MOVE_NUMERIC_BUMP(dest2,source1); } else { /* (4) - Both operands cross a boundary */ len3 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len3) & ADDRESS_MAXWRAP(regs), arn2, regs, ACCTYPE_READ, regs->psw.pkey); if (len2 == len3) { /* (4a) - Both operands cross at the same time */ for ( i = 0; i < len2; i++) MOVE_NUMERIC_BUMP(dest1,source1); len2 = len - len2; for ( i = 0; i <= len2; i++) MOVE_NUMERIC_BUMP(dest2,source2); } else if (len2 < len3) { /* (4b) - First operand crosses first */ for ( i = 0; i < len2; i++) MOVE_NUMERIC_BUMP(dest1,source1); len2 = len3 - len2; for ( i = 0; i < len2; i++) MOVE_NUMERIC_BUMP(dest2,source1); len2 = len - len3; for ( i = 0; i <= len2; i++) MOVE_NUMERIC_BUMP(dest2,source2); } else { /* (4c) - Second operand crosses first */ for ( i = 0; i < len3; i++) MOVE_NUMERIC_BUMP(dest1,source1); len3 = len2 - len3; for ( i = 0; i < len3; i++) MOVE_NUMERIC_BUMP(dest1,source2); len3 = len - len2; for ( i = 0; i <= len3; i++) MOVE_NUMERIC_BUMP(dest2,source2); } } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); *sk2 |= (STORKEY_REF | STORKEY_CHANGE); } ITIMER_UPDATE(addr1,len,regs); } #if defined(FEATURE_STRING_INSTRUCTION) /*-------------------------------------------------------------------*/ /* B255 MVST - Move String [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(move_string) { int r1, r2; /* Values of R fields */ int i; /* Loop counter */ VADR addr1, addr2; /* Operand addresses */ BYTE sbyte; /* String character */ BYTE termchar; /* Terminating character */ int cpu_length; /* length to next page */ RRE(inst, regs, r1, r2); /* Program check if bits 0-23 of register 0 not zero */ if ((regs->GR_L(0) & 0xFFFFFF00) != 0) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Load string terminating character from register 0 bits 24-31 */ termchar = regs->GR_LHLCL(0); /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* set cpu_length as shortest distance to new page */ if ((addr1 & 0xFFF) > (addr2 & 0xFFF)) cpu_length = 0x1000 - (addr1 & 0xFFF); else cpu_length = 0x1000 - (addr2 & 0xFFF); /* Move up to 4096 bytes until terminating character */ for (i = 0; i < cpu_length; i++) { /* Fetch a byte from the source operand */ sbyte = ARCH_DEP(vfetchb) ( addr2, r2, regs ); /* Store the byte in the destination operand */ ARCH_DEP(vstoreb) ( sbyte, addr1, r1, regs ); /* Check if string terminating character was moved */ if (sbyte == termchar) { /* Set r1 to point to terminating character */ SET_GR_A(r1, regs,addr1); /* Set condition code 1 */ regs->psw.cc = 1; return; } /* Increment operand addresses */ addr1++; addr1 &= ADDRESS_MAXWRAP(regs); addr2++; addr2 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ /* Set R1 and R2 to point to next character of each operand */ SET_GR_A(r1, regs,addr1); SET_GR_A(r2, regs,addr2); /* Set condition code 3 */ regs->psw.cc = 3; } /* end DEF_INST(move_string) */ #endif /*defined(FEATURE_STRING_INSTRUCTION)*/ /*-------------------------------------------------------------------*/ /* F1 MVO - Move with Offset [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_offset) { int l1, l2; /* Lenght values */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int i, j; /* Loop counters */ BYTE sbyte; /* Source operand byte */ BYTE dbyte; /* Destination operand byte */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* If operand 1 crosses a page, make sure both pages are accessable */ if((effective_addr1 & PAGEFRAME_PAGEMASK) != ((effective_addr1 + l1) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr1, b1, l1, ACCTYPE_WRITE_SKP, regs); /* If operand 2 crosses a page, make sure both pages are accessable */ if((effective_addr2 & PAGEFRAME_PAGEMASK) != ((effective_addr2 + l2) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr2, b2, l2, ACCTYPE_READ, regs); /* Fetch the rightmost byte from the source operand */ effective_addr2 += l2; effective_addr2 &= ADDRESS_MAXWRAP(regs); sbyte = ARCH_DEP(vfetchb) ( effective_addr2--, b2, regs ); /* Fetch the rightmost byte from the destination operand */ effective_addr1 += l1; effective_addr1 &= ADDRESS_MAXWRAP(regs); dbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* Move low digit of source byte to high digit of destination */ dbyte &= 0x0F; dbyte |= sbyte << 4; ARCH_DEP(vstoreb) ( dbyte, effective_addr1--, b1, regs ); /* Process remaining bytes from right to left */ for (i = l1, j = l2; i > 0; i--) { /* Move previous high digit to destination low digit */ dbyte = sbyte >> 4; /* Fetch next byte from second operand */ if ( j-- > 0 ) { effective_addr2 &= ADDRESS_MAXWRAP(regs); sbyte = ARCH_DEP(vfetchb) ( effective_addr2--, b2, regs ); } else sbyte = 0x00; /* Move low digit to destination high digit */ dbyte |= sbyte << 4; effective_addr1 &= ADDRESS_MAXWRAP(regs); ARCH_DEP(vstoreb) ( dbyte, effective_addr1--, b1, regs ); } /* end for(i) */ } #define MOVE_ZONE_BUMP(_d,_s) \ do { \ *(_d)=( *(_d) & 0x0F) | ( *(_s) & 0xF0); \ _d++; \ _s++; \ } while(0) /*-------------------------------------------------------------------*/ /* D3 MVZ - Move Zones [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_zones) { VADR addr1, addr2; /* Operand virtual addresses */ int len, arn1, arn2; /* Operand values */ BYTE *dest1, *dest2; /* Destination addresses */ BYTE *source1, *source2; /* Source addresses */ BYTE *sk1, *sk2; /* Storage key addresses */ int len2, len3; /* Lengths to copy */ int i; /* Loop counter */ SS_L(inst, regs, len, arn1, addr1, arn2, addr2); ITIMER_SYNC(addr2,len,regs); /* Translate addresses of leftmost operand bytes */ dest1 = MADDRL (addr1, len+1, arn1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk1 = regs->dat.storkey; source1 = MADDR (addr2, arn2, regs, ACCTYPE_READ, regs->psw.pkey); /* There are several scenarios (in optimal order): * (1) dest boundary and source boundary not crossed * (2) dest boundary not crossed and source boundary crossed * (3) dest boundary crossed and source boundary not crossed * (4) dest boundary and source boundary are crossed * (a) dest and source boundary cross at the same time * (b) dest boundary crossed first * (c) source boundary crossed first */ if ( NOCROSS2K(addr1,len) ) { if ( NOCROSS2K(addr2,len) ) { /* (1) - No boundaries are crossed */ for ( i = 0; i <= len; i++) MOVE_ZONE_BUMP(dest1,source1); } else { /* (2) - Second operand crosses a boundary */ len2 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len2) & ADDRESS_MAXWRAP(regs), arn2, regs, ACCTYPE_READ, regs->psw.pkey); for ( i = 0; i < len2; i++) MOVE_ZONE_BUMP(dest1,source1); len2 = len - len2; for ( i = 0; i <= len2; i++) MOVE_ZONE_BUMP(dest1,source2); } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); } else { /* First operand crosses a boundary */ len2 = 0x800 - (addr1 & 0x7FF); dest2 = MADDR ((addr1 + len2) & ADDRESS_MAXWRAP(regs), arn1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk2 = regs->dat.storkey; if ( NOCROSS2K(addr2,len) ) { /* (3) - First operand crosses a boundary */ for ( i = 0; i < len2; i++) MOVE_ZONE_BUMP(dest1,source1); len2 = len - len2; for ( i = 0; i <= len2; i++) MOVE_ZONE_BUMP(dest2,source1); } else { /* (4) - Both operands cross a boundary */ len3 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len3) & ADDRESS_MAXWRAP(regs), arn2, regs, ACCTYPE_READ, regs->psw.pkey); if (len2 == len3) { /* (4a) - Both operands cross at the same time */ for ( i = 0; i < len2; i++) MOVE_ZONE_BUMP(dest1,source1); len2 = len - len2; for ( i = 0; i <= len2; i++) MOVE_ZONE_BUMP(dest2,source2); } else if (len2 < len3) { /* (4b) - First operand crosses first */ for ( i = 0; i < len2; i++) MOVE_ZONE_BUMP(dest1,source1); len2 = len3 - len2; for ( i = 0; i < len2; i++) MOVE_ZONE_BUMP(dest2,source1); len2 = len - len3; for ( i = 0; i <= len2; i++) MOVE_ZONE_BUMP(dest2,source2); } else { /* (4c) - Second operand crosses first */ for ( i = 0; i < len3; i++) MOVE_ZONE_BUMP(dest1,source1); len3 = len2 - len3; for ( i = 0; i < len3; i++) MOVE_ZONE_BUMP(dest1,source2); len3 = len - len2; for ( i = 0; i <= len3; i++) MOVE_ZONE_BUMP(dest2,source2); } } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); *sk2 |= (STORKEY_REF | STORKEY_CHANGE); } ITIMER_UPDATE(addr1,len,regs); } /*-------------------------------------------------------------------*/ /* 1C MR - Multiply Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_register) { int r1, r2; /* Values of R fields */ RR(inst, regs, r1, r2); ODD_CHECK(r1, regs); /* Multiply r1+1 by r2 and place result in r1 and r1+1 */ mul_signed (&(regs->GR_L(r1)),&(regs->GR_L(r1+1)), regs->GR_L(r1+1), regs->GR_L(r2)); } /*-------------------------------------------------------------------*/ /* 5C M - Multiply [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Multiply r1+1 by n and place result in r1 and r1+1 */ mul_signed (&(regs->GR_L(r1)), &(regs->GR_L(r1+1)), regs->GR_L(r1+1), n); } /*-------------------------------------------------------------------*/ /* 4C MH - Multiply Halfword [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load 2 bytes from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Multiply R1 register by n, ignore leftmost 32 bits of result, and place rightmost 32 bits in R1 register */ mul_signed ((U32 *)&n, &(regs->GR_L(r1)), regs->GR_L(r1), n); } #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7xC MHI - Multiply Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit operand */ RI0(inst, regs, r1, i2); /* Multiply register by operand ignoring overflow */ regs->GR_L(r1) = (S32)regs->GR_L(r1) * (S16)i2; } /* end DEF_INST(multiply_halfword_immediate) */ /*-------------------------------------------------------------------*/ /* B252 MSR - Multiply Single Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Multiply signed registers ignoring overflow */ regs->GR_L(r1) = (S32)regs->GR_L(r1) * (S32)regs->GR_L(r2); } /* end DEF_INST(multiply_single_register) */ /*-------------------------------------------------------------------*/ /* 71 MS - Multiply Single [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Multiply signed operands ignoring overflow */ regs->GR_L(r1) = (S32)regs->GR_L(r1) * (S32)n; } /* end DEF_INST(multiply_single) */ #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "general1.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "general1.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/general2.c0000664000175000017500000027736512564723224012072 00000000000000/* GENERAL2.C (c) Copyright Roger Bowler, 1994-2009 */ /* ESA/390 CPU Emulator */ /* Instructions N-Z */ /* (c) Copyright Peter Kuschnerus, 1999-2009 (UPT & CFC)*/ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements general instructions N-Z of the */ /* S/370 and ESA/390 architectures, as described in the manuals */ /* GA22-7000-03 System/370 Principles of Operation */ /* SA22-7201-06 ESA/390 Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Corrections to shift instructions by Jay Maynard, Jan Jaeger */ /* Branch tracing by Jan Jaeger */ /* Instruction decode by macros - Jan Jaeger */ /* Prevent TOD from going backwards in time - Jan Jaeger */ /* Fix STCKE instruction - Bernard van der Helm */ /* Instruction decode rework - Jan Jaeger */ /* Make STCK update the TOD clock - Jay Maynard */ /* Fix address wraparound in MVO - Jan Jaeger */ /* PLO instruction - Jan Jaeger */ /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */ /* Clear TEA on data exception - Peter Kuschnerus v209*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_GENERAL2_C_) #define _GENERAL2_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "clock.h" /*-------------------------------------------------------------------*/ /* 16 OR - Or Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(or_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* OR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) |= regs->GR_L(r2) ) ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 56 O - Or [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(or) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* OR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) |= n ) ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 96 OI - Or Immediate [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate) { BYTE i2; /* Immediate operand byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE *dest; /* Pointer to target byte */ SI(inst, regs, i2, b1, effective_addr1); ITIMER_SYNC(effective_addr1,1,regs); /* Get byte mainstor address */ dest = MADDR (effective_addr1, b1, regs, ACCTYPE_WRITE, regs->psw.pkey ); /* OR byte with immediate operand, setting condition code */ regs->psw.cc = ((*dest |= i2) != 0); ITIMER_UPDATE(effective_addr1,1,regs); } /*-------------------------------------------------------------------*/ /* D6 OC - Or Characters [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(or_character) { int len, len2, len3; /* Lengths to copy */ int b1, b2; /* Base register numbers */ VADR addr1, addr2; /* Virtual addresses */ BYTE *dest1, *dest2; /* Destination addresses */ BYTE *source1, *source2; /* Source addresses */ BYTE *sk1, *sk2; /* Storage key addresses */ int i; /* Loop counter */ int cc = 0; /* Condition code */ SS_L(inst, regs, len, b1, addr1, b2, addr2); ITIMER_SYNC(addr1,len,regs); ITIMER_SYNC(addr2,len,regs); /* Quick out for 1 byte (no boundary crossed) */ if (unlikely(len == 0)) { source1 = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); dest1 = MADDR (addr1, b1, regs, ACCTYPE_WRITE, regs->psw.pkey); *dest1 |= *source1; regs->psw.cc = (*dest1 != 0); ITIMER_UPDATE(addr1,len,regs); return; } /* There are several scenarios (in optimal order): * (1) dest boundary and source boundary not crossed * (2) dest boundary not crossed and source boundary crossed * (3) dest boundary crossed and source boundary not crossed * (4) dest boundary and source boundary are crossed * (a) dest and source boundary cross at the same time * (b) dest boundary crossed first * (c) source boundary crossed first */ /* Translate addresses of leftmost operand bytes */ dest1 = MADDRL (addr1, len+1, b1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk1 = regs->dat.storkey; source1 = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if ( NOCROSS2K(addr1,len) ) { if ( NOCROSS2K(addr2,len) ) { /* (1) - No boundaries are crossed */ for (i = 0; i <= len; i++) if ((*dest1++ |= *source1++)) cc = 1; } else { /* (2) - Second operand crosses a boundary */ len2 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len2) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); for ( i = 0; i < len2; i++) if ((*dest1++ |= *source1++)) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if ((*dest1++ |= *source2++)) cc = 1; } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); } else { /* First operand crosses a boundary */ len2 = 0x800 - (addr1 & 0x7FF); dest2 = MADDR ((addr1 + len2) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_WRITE_SKP, regs->psw.pkey); sk2 = regs->dat.storkey; if ( NOCROSS2K(addr2,len) ) { /* (3) - First operand crosses a boundary */ for ( i = 0; i < len2; i++) if ((*dest1++ |= *source1++)) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if ((*dest2++ |= *source1++)) cc = 1; } else { /* (4) - Both operands cross a boundary */ len3 = 0x800 - (addr2 & 0x7FF); source2 = MADDR ((addr2 + len3) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); if (len2 == len3) { /* (4a) - Both operands cross at the same time */ for ( i = 0; i < len2; i++) if ((*dest1++ |= *source1++)) cc = 1; len2 = len - len2; for ( i = 0; i <= len2; i++) if ((*dest2++ |= *source2++)) cc = 1; } else if (len2 < len3) { /* (4b) - First operand crosses first */ for ( i = 0; i < len2; i++) if ((*dest1++ |= *source1++)) cc = 1; len2 = len3 - len2; for ( i = 0; i < len2; i++) if ((*dest2++ |= *source1++)) cc = 1; len2 = len - len3; for ( i = 0; i <= len2; i++) if ((*dest2++ |= *source2++)) cc = 1; } else { /* (4c) - Second operand crosses first */ for ( i = 0; i < len3; i++) if ((*dest1++ |= *source1++)) cc = 1; len3 = len2 - len3; for ( i = 0; i < len3; i++) if ((*dest1++ |= *source2++)) cc = 1; len3 = len - len2; for ( i = 0; i <= len3; i++) if ((*dest2++ |= *source2++)) cc = 1; } } *sk1 |= (STORKEY_REF | STORKEY_CHANGE); *sk2 |= (STORKEY_REF | STORKEY_CHANGE); } regs->psw.cc = cc; ITIMER_UPDATE(addr1,len,regs); } /* end DEF_INST(or_character) */ /*-------------------------------------------------------------------*/ /* F2 PACK - Pack [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(pack) { int l1, l2; /* Lenght values */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int i, j; /* Loop counters */ BYTE sbyte; /* Source operand byte */ BYTE dbyte; /* Destination operand byte */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* If operand 1 crosses a page, make sure both pages are accessable */ if((effective_addr1 & PAGEFRAME_PAGEMASK) != ((effective_addr1 + l1) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr1, b1, l1, ACCTYPE_WRITE_SKP, regs); /* If operand 2 crosses a page, make sure both pages are accessable */ if((effective_addr2 & PAGEFRAME_PAGEMASK) != ((effective_addr2 + l2) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr2, b2, l2, ACCTYPE_READ, regs); /* Exchange the digits in the rightmost byte */ effective_addr1 += l1; effective_addr2 += l2; sbyte = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); dbyte = (sbyte << 4) | (sbyte >> 4); ARCH_DEP(vstoreb) ( dbyte, effective_addr1, b1, regs ); /* Process remaining bytes from right to left */ for (i = l1, j = l2; i > 0; i--) { /* Fetch source bytes from second operand */ if (j-- > 0) { sbyte = ARCH_DEP(vfetchb) ( --effective_addr2, b2, regs ); dbyte = sbyte & 0x0F; if (j-- > 0) { effective_addr2 &= ADDRESS_MAXWRAP(regs); sbyte = ARCH_DEP(vfetchb) ( --effective_addr2, b2, regs ); dbyte |= sbyte << 4; } } else { dbyte = 0; } /* Store packed digits at first operand address */ ARCH_DEP(vstoreb) ( dbyte, --effective_addr1, b1, regs ); /* Wraparound according to addressing mode */ effective_addr1 &= ADDRESS_MAXWRAP(regs); effective_addr2 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ } #if defined(FEATURE_PERFORM_LOCKED_OPERATION) /*-------------------------------------------------------------------*/ /* EE PLO - Perform Locked Operation [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(perform_locked_operation) { int r1, r3; /* Lenght values */ int b2, b4; /* Values of base registers */ VADR effective_addr2, effective_addr4; /* Effective addresses */ SS(inst, regs, r1, r3, b2, effective_addr2, b4, effective_addr4); if(regs->GR_L(0) & PLO_GPR0_RESV) regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION); if(regs->GR_L(0) & PLO_GPR0_T) switch(regs->GR_L(0) & PLO_GPR0_FC) { case PLO_CL: case PLO_CLG: case PLO_CS: case PLO_CSG: case PLO_DCS: case PLO_DCSG: case PLO_CSST: case PLO_CSSTG: case PLO_CSDST: case PLO_CSDSTG: case PLO_CSTST: case PLO_CSTSTG: #if defined(FEATURE_ESAME) case PLO_CLGR: case PLO_CLX: case PLO_CSGR: case PLO_CSX: case PLO_DCSGR: case PLO_DCSX: case PLO_CSSTGR: case PLO_CSSTX: case PLO_CSDSTGR: case PLO_CSDSTX: case PLO_CSTSTGR: case PLO_CSTSTX: #endif /*defined(FEATURE_ESAME)*/ /* Indicate function supported */ regs->psw.cc = 0; break; default: PTT(PTT_CL_ERR,"*PLO",regs->GR_L(0),regs->GR_L(r1),regs->psw.IA_L); /* indicate function not supported */ regs->psw.cc = 3; break; } else { /* gpr1/ar1 indentify the program lock token, which is used to select a lock from the model dependent number of locks in the configuration. We simply use 1 lock which is the main storage access lock which is also used by CS, CDS and TS. *JJ */ OBTAIN_MAINLOCK(regs); switch(regs->GR_L(0) & PLO_GPR0_FC) { case PLO_CL: regs->psw.cc = ARCH_DEP(plo_cl) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CLG: regs->psw.cc = ARCH_DEP(plo_clg) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CS: regs->psw.cc = ARCH_DEP(plo_cs) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSG: regs->psw.cc = ARCH_DEP(plo_csg) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_DCS: regs->psw.cc = ARCH_DEP(plo_dcs) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_DCSG: regs->psw.cc = ARCH_DEP(plo_dcsg) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSST: regs->psw.cc = ARCH_DEP(plo_csst) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSSTG: regs->psw.cc = ARCH_DEP(plo_csstg) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSDST: regs->psw.cc = ARCH_DEP(plo_csdst) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSDSTG: regs->psw.cc = ARCH_DEP(plo_csdstg) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSTST: regs->psw.cc = ARCH_DEP(plo_cstst) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSTSTG: regs->psw.cc = ARCH_DEP(plo_cststg) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; #if defined(FEATURE_ESAME) case PLO_CLGR: regs->psw.cc = ARCH_DEP(plo_clgr) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CLX: regs->psw.cc = ARCH_DEP(plo_clx) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSGR: regs->psw.cc = ARCH_DEP(plo_csgr) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSX: regs->psw.cc = ARCH_DEP(plo_csx) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_DCSGR: regs->psw.cc = ARCH_DEP(plo_dcsgr) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_DCSX: regs->psw.cc = ARCH_DEP(plo_dcsx) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSSTGR: regs->psw.cc = ARCH_DEP(plo_csstgr) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSSTX: regs->psw.cc = ARCH_DEP(plo_csstx) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSDSTGR: regs->psw.cc = ARCH_DEP(plo_csdstgr) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSDSTX: regs->psw.cc = ARCH_DEP(plo_csdstx) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSTSTGR: regs->psw.cc = ARCH_DEP(plo_cststgr) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; case PLO_CSTSTX: regs->psw.cc = ARCH_DEP(plo_cststx) (r1, r3, effective_addr2, b2, effective_addr4, b4, regs); break; #endif /*defined(FEATURE_ESAME)*/ default: regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION); } /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); if(regs->psw.cc && sysblk.cpus > 1) { PTT(PTT_CL_CSF,"*PLO",regs->GR_L(0),regs->GR_L(r1),regs->psw.IA_L); sched_yield(); } } } #endif /*defined(FEATURE_PERFORM_LOCKED_OPERATION)*/ #if defined(FEATURE_STRING_INSTRUCTION) /*-------------------------------------------------------------------*/ /* B25E SRST - Search String [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(search_string) { int r1, r2; /* Values of R fields */ int i; /* Loop counter */ VADR addr1, addr2; /* End/start addresses */ BYTE sbyte; /* String character */ BYTE termchar; /* Terminating character */ RRE(inst, regs, r1, r2); /* Program check if bits 0-23 of register 0 not zero */ if ((regs->GR_L(0) & 0xFFFFFF00) != 0) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Load string terminating character from register 0 bits 24-31 */ termchar = regs->GR_LHLCL(0); /* Determine the operand end and start addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Search up to 256 bytes or until end of operand */ for (i = 0; i < 0x100; i++) { /* If operand end address has been reached, return condition code 2 and leave the R1 and R2 registers unchanged */ if (addr2 == addr1) { regs->psw.cc = 2; return; } /* Fetch a byte from the operand */ sbyte = ARCH_DEP(vfetchb) ( addr2, r2, regs ); /* If the terminating character was found, return condition code 1 and load the address of the character into R1 */ if (sbyte == termchar) { SET_GR_A(r1, regs, addr2); regs->psw.cc = 1; return; } /* Increment operand address */ addr2++; addr2 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ /* Set R2 to point to next character of operand */ SET_GR_A(r2, regs, addr2); /* Return condition code 3 */ regs->psw.cc = 3; } /* end DEF_INST(search_string) */ #endif /*defined(FEATURE_STRING_INSTRUCTION)*/ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* B24E SAR - Set Access Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(set_access_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy R2 general register to R1 access register */ regs->AR(r1) = regs->GR_L(r2); SET_AEA_AR(regs, r1); } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* 04 SPM - Set Program Mask [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(set_program_mask) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Set condition code from bits 2-3 of R1 register */ regs->psw.cc = ( regs->GR_L(r1) & 0x30000000 ) >> 28; /* Set program mask from bits 4-7 of R1 register */ regs->psw.progmask = ( regs->GR_L(r1) >> 24) & PSW_PROGMASK; } /*-------------------------------------------------------------------*/ /* 8F SLDA - Shift Left Double [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_double) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n; /* 32-bit operand values */ U64 dreg; /* Double register work area */ U32 h, i, j, m; /* Integer work areas */ RS(inst, regs, r1, r3, b2, effective_addr2); ODD_CHECK(r1, regs); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Load the signed value from the R1 and R1+1 registers */ dreg = (U64)regs->GR_L(r1) << 32 | regs->GR_L(r1+1); m = ((S64)dreg < 0) ? 1 : 0; /* Shift the numeric portion of the value */ for (i = 0, j = 0; i < n; i++) { /* Shift bits 1-63 left one bit position */ dreg <<= 1; /* Overflow if bit shifted out is unlike the sign bit */ h = ((S64)dreg < 0) ? 1 : 0; if (h != m) j = 1; } /* Load updated value into the R1 and R1+1 registers */ regs->GR_L(r1) = (dreg >> 32) & 0x7FFFFFFF; if (m) regs->GR_L(r1) |= 0x80000000; regs->GR_L(r1+1) = dreg & 0xFFFFFFFF; /* Condition code 3 and program check if overflow occurred */ if (j) { regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Set the condition code */ regs->psw.cc = (S64)dreg > 0 ? 2 : (S64)dreg < 0 ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 8D SLDL - Shift Left Double Logical [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_double_logical) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n; /* 32-bit operand values */ U64 dreg; /* Double register work area */ RS(inst, regs, r1, r3, b2, effective_addr2); ODD_CHECK(r1, regs); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the R1 and R1+1 registers */ dreg = (U64)regs->GR_L(r1) << 32 | regs->GR_L(r1+1); dreg <<= n; regs->GR_L(r1) = dreg >> 32; regs->GR_L(r1+1) = dreg & 0xFFFFFFFF; } /*-------------------------------------------------------------------*/ /* 8B SLA - Shift Left Single [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_single) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n, n1, n2; /* 32-bit operand values */ U32 i, j; /* Integer work areas */ RS(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Fast path if no possible overflow */ if (regs->GR_L(r1) < 0x10000 && n < 16) { regs->GR_L(r1) <<= n; regs->psw.cc = regs->GR_L(r1) ? 2 : 0; return; } /* Load the numeric and sign portions from the R1 register */ n1 = regs->GR_L(r1) & 0x7FFFFFFF; n2 = regs->GR_L(r1) & 0x80000000; /* Shift the numeric portion left n positions */ for (i = 0, j = 0; i < n; i++) { /* Shift bits 1-31 left one bit position */ n1 <<= 1; /* Overflow if bit shifted out is unlike the sign bit */ if ((n1 & 0x80000000) != n2) j = 1; } /* Load the updated value into the R1 register */ regs->GR_L(r1) = (n1 & 0x7FFFFFFF) | n2; /* Condition code 3 and program check if overflow occurred */ if (j) { regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Set the condition code */ regs->psw.cc = (S32)regs->GR_L(r1) > 0 ? 2 : (S32)regs->GR_L(r1) < 0 ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 89 SLL - Shift Left Single Logical [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_single_logical) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n; /* Integer work areas */ RS0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the R1 register */ regs->GR_L(r1) = n > 31 ? 0 : regs->GR_L(r1) << n; } /*-------------------------------------------------------------------*/ /* 8E SRDA - Shift Right Double [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_double) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n; /* 32-bit operand values */ U64 dreg; /* Double register work area */ RS(inst, regs, r1, r3, b2, effective_addr2); ODD_CHECK(r1, regs); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the R1 and R1+1 registers */ dreg = (U64)regs->GR_L(r1) << 32 | regs->GR_L(r1+1); dreg = (U64)((S64)dreg >> n); regs->GR_L(r1) = dreg >> 32; regs->GR_L(r1+1) = dreg & 0xFFFFFFFF; /* Set the condition code */ regs->psw.cc = (S64)dreg > 0 ? 2 : (S64)dreg < 0 ? 1 : 0; } /*-------------------------------------------------------------------*/ /* 8C SRDL - Shift Right Double Logical [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_double_logical) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n; /* 32-bit operand values */ U64 dreg; /* Double register work area */ RS(inst, regs, r1, r3, b2, effective_addr2); ODD_CHECK(r1, regs); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the R1 and R1+1 registers */ dreg = (U64)regs->GR_L(r1) << 32 | regs->GR_L(r1+1); dreg >>= n; regs->GR_L(r1) = dreg >> 32; regs->GR_L(r1+1) = dreg & 0xFFFFFFFF; } /*-------------------------------------------------------------------*/ /* 8A SRA - Shift Right Single [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_single) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n; /* Integer work areas */ RS0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the signed value of the R1 register */ regs->GR_L(r1) = n > 30 ? ((S32)regs->GR_L(r1) < 0 ? -1 : 0) : (S32)regs->GR_L(r1) >> n; /* Set the condition code */ regs->psw.cc = ((S32)regs->GR_L(r1) > 0) ? 2 : (((S32)regs->GR_L(r1) < 0) ? 1 : 0); } /*-------------------------------------------------------------------*/ /* 88 SRL - Shift Right Single Logical [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_single_logical) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U32 n; /* Integer work areas */ RS0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the R1 register */ regs->GR_L(r1) = n > 31 ? 0 : regs->GR_L(r1) >> n; } /*-------------------------------------------------------------------*/ /* 50 ST - Store [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(store) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ #if 0 U32 *p; /* Mainstor pointer */ #endif RX(inst, regs, r1, b2, effective_addr2); /* Store register contents at operand address */ /* FOLLOWING BLOCK COMMENTED OUT ISW 20060119 */ #if 0 if ((effective_addr2 & 3) == 0) { p = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); STORE_FW (p, regs->GR_L(r1)); ITIMER_UPDATE(effective_addr2, 4-1, regs); } else #endif ARCH_DEP(vstore4) ( regs->GR_L(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store) */ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* 9B STAM - Store Access Multiple [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(store_access_multiple) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work area */ U32 *p1, *p2 = NULL; /* Mainstor pointers */ RS(inst, regs, r1, r3, b2, effective_addr2); FW_CHECK(effective_addr2, regs); /* Calculate number of regs to store */ n = ((r3 - r1) & 0xF) + 1; /* Calculate number of words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 2; /* Address of operand beginning */ p1 = (U32*)MADDRL(effective_addr2, n, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely (m < n)) p2 = (U32*)MADDR(effective_addr2 + (m*4), b2, regs, ACCTYPE_WRITE, regs->psw.pkey); else m = n; /* Store to first page */ for (i = 0; i < m; i++) store_fw (p1++, regs->AR((r1 + i) & 0xF)); /* Store to next page */ for ( ; i < n; i++) store_fw (p2++, regs->AR((r1 + i) & 0xF)); } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* 42 STC - Store Character [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(store_character) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX(inst, regs, r1, b2, effective_addr2); /* Store rightmost byte of R1 register at operand address */ ARCH_DEP(vstoreb) ( regs->GR_LHLCL(r1), effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* BE STCM - Store Characters under Mask [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(store_characters_under_mask) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Integer work area */ BYTE rbyte[4]; /* Byte work area */ RS(inst, regs, r1, r3, b2, effective_addr2); switch (r3) { case 7: /* Optimized case */ store_fw(rbyte, regs->GR_L(r1)); ARCH_DEP(vstorec) (rbyte+1, 2, effective_addr2, b2, regs); break; case 15: /* Optimized case */ ARCH_DEP(vstore4) (regs->GR_L(r1), effective_addr2, b2, regs); break; default: /* Extract value from register by mask */ i = 0; if (r3 & 0x8) rbyte[i++] = (regs->GR_L(r1) >> 24) & 0xFF; if (r3 & 0x4) rbyte[i++] = (regs->GR_L(r1) >> 16) & 0xFF; if (r3 & 0x2) rbyte[i++] = (regs->GR_L(r1) >> 8) & 0xFF; if (r3 & 0x1) rbyte[i++] = (regs->GR_L(r1) ) & 0xFF; if (i) ARCH_DEP(vstorec) (rbyte, i-1, effective_addr2, b2, regs); #if defined(MODEL_DEPENDENT_STCM) /* If the mask is all zero, we nevertheless access one byte from the storage operand, because POP states that an access exception may be recognized on the first byte */ else ARCH_DEP(validate_operand) (effective_addr2, b2, 0, ACCTYPE_WRITE, regs); #endif break; } /* switch (r3) */ } /*-------------------------------------------------------------------*/ /* B205 STCK - Store Clock [S] */ /* B27C STCKF - Store Clock Fast [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_clock) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word work area */ S(inst, regs, b2, effective_addr2); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC2, STCK)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ #if defined(FEATURE_STORE_CLOCK_FAST) if(inst[1] == 0x05) // STCK only #endif /*defined(FEATURE_STORE_CLOCK_FAST)*/ /* Perform serialization before fetching clock */ PERFORM_SERIALIZATION (regs); /* Retrieve the TOD clock value and shift out the epoch */ dreg = tod_clock(regs) << 8; #if defined(FEATURE_STORE_CLOCK_FAST) if(inst[1] == 0x05) // STCK only #endif /*defined(FEATURE_STORE_CLOCK_FAST)*/ /* Insert the cpu address to ensure a unique value */ dreg |= regs->cpuad; // /*debug*/logmsg("Store TOD clock=%16.16" I64_FMT "X\n", dreg); /* Store TOD clock value at operand address */ ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); #if defined(FEATURE_STORE_CLOCK_FAST) if(inst[1] == 0x05) // STCK only #endif /*defined(FEATURE_STORE_CLOCK_FAST)*/ /* Perform serialization after storing clock */ PERFORM_SERIALIZATION (regs); /* Set condition code zero */ regs->psw.cc = 0; } #if defined(FEATURE_EXTENDED_TOD_CLOCK) /*-------------------------------------------------------------------*/ /* B278 STCKE - Store Clock Extended [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_clock_extended) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word work area */ S(inst, regs, b2, effective_addr2); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC2, STCK)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before fetching clock */ PERFORM_SERIALIZATION (regs); /* Retrieve the TOD epoch, clock bits 0-51, and 4 zeroes */ dreg = 0x00ffffffffffffffULL & tod_clock(regs); /* Check that all 16 bytes of the operand are accessible */ ARCH_DEP(validate_operand) (effective_addr2, b2, 15, ACCTYPE_WRITE, regs); // /*debug*/logmsg("Store TOD clock extended: +0=%16.16" I64_FMT "X\n", // /*debug*/ dreg); /* Store the 8 bit TOD epoch, clock bits 0-51, and bits 20-23 of the TOD uniqueness value at operand address */ ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); // /*debug*/logmsg("Store TOD clock extended: +8=%16.16" I64_FMT "X\n", // /*debug*/ dreg); /* Store second doubleword value at operand+8 */ effective_addr2 += 8; effective_addr2 &= ADDRESS_MAXWRAP(regs); /* Store nonzero value in pos 72 to 111 */ dreg = 0x0000000001000000ULL | (regs->cpuad << 16) | regs->todpr; ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); /* Perform serialization after storing clock */ PERFORM_SERIALIZATION (regs); /* Set condition code zero */ regs->psw.cc = 0; } #endif /*defined(FEATURE_EXTENDED_TOD_CLOCK)*/ /*-------------------------------------------------------------------*/ /* 40 STH - Store Halfword [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(store_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX(inst, regs, r1, b2, effective_addr2); /* Store rightmost 2 bytes of R1 register at operand address */ ARCH_DEP(vstore2) ( regs->GR_LHL(r1), effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* 90 STM - Store Multiple [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(store_multiple) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2; /* Mainstor pointers */ BYTE *bp1; /* Unaligned mainstor ptr */ RS(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to store */ n = (((r3 - r1) & 0xF) + 1) << 2; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Get address of first page */ bp1 = (BYTE*)MADDRL(effective_addr2, n, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); p1 = (U32*)bp1; if (likely(n <= m)) { /* boundary not crossed */ n >>= 2; #if defined(OPTION_STRICT_ALIGNMENT) if(likely(!(((uintptr_t)effective_addr2)&0x03))) { #endif for (i = 0; i < n; i++) store_fw (p1++, regs->GR_L((r1 + i) & 0xF)); #if defined(OPTION_STRICT_ALIGNMENT) } else { for (i = 0; i < n; i++,bp1+=4) store_fw (bp1, regs->GR_L((r1 + i) & 0xF)); } #endif ITIMER_UPDATE(effective_addr2,(n*4)-1,regs); } else { /* boundary crossed, get address of the 2nd page */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); if (likely((m & 0x3) == 0)) { /* word aligned */ m >>= 2; for (i = 0; i < m; i++) store_fw (p1++, regs->GR_L((r1 + i) & 0xF)); n >>= 2; for ( ; i < n; i++) store_fw (p2++, regs->GR_L((r1 + i) & 0xF)); } else { /* worst case */ U32 rwork[16]; BYTE *b1, *b2; for (i = 0; i < (n >> 2); i++) rwork[i] = CSWAP32(regs->GR_L((r1 + i) & 0xF)); b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b2++ = *b1++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b2++ = *b1++; } } } /* end DEF_INST(store_multiple) */ /*-------------------------------------------------------------------*/ /* 1B SR - Subtract Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_register) { int r1, r2; /* Values of R fields */ RR(inst, regs, r1, r2); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_L(r1)), regs->GR_L(r1), regs->GR_L(r2)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /*-------------------------------------------------------------------*/ /* 5B S - Subtract [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_L(r1)), regs->GR_L(r1), n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /*-------------------------------------------------------------------*/ /* 4B SH - Subtract Halfword [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load 2 bytes from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_L(r1)), regs->GR_L(r1), n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /*-------------------------------------------------------------------*/ /* 1F SLR - Subtract Logical Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_register) { int r1, r2; /* Values of R fields */ RR0(inst, regs, r1, r2); /* Subtract unsigned operands and set condition code */ if (likely(r1 == r2)) { regs->psw.cc = 2; regs->GR_L(r1) = 0; } else regs->psw.cc = sub_logical (&(regs->GR_L(r1)), regs->GR_L(r1), regs->GR_L(r2)); } /*-------------------------------------------------------------------*/ /* 5F SL - Subtract Logical [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RX(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical (&(regs->GR_L(r1)), regs->GR_L(r1), n); } /*-------------------------------------------------------------------*/ /* 0A SVC - Supervisor Call [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(supervisor_call) { BYTE i; /* Instruction byte 1 */ PSA *psa; /* -> prefixed storage area */ RADR px; /* prefix */ int rc; /* Return code */ RR_SVC(inst, regs, i); #if defined(FEATURE_ECPSVM) if(ecpsvm_dosvc(regs,i)==0) { return; } #endif #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && ( (regs->siebk->svc_ctl[0] & SIE_SVC0_ALL) || ( (regs->siebk->svc_ctl[0] & SIE_SVC0_1N) && regs->siebk->svc_ctl[1] == i) || ( (regs->siebk->svc_ctl[0] & SIE_SVC0_2N) && regs->siebk->svc_ctl[2] == i) || ( (regs->siebk->svc_ctl[0] & SIE_SVC0_3N) && regs->siebk->svc_ctl[3] == i) )) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ px = regs->PX; SIE_TRANSLATE(&px, ACCTYPE_WRITE, regs); /* Set the main storage reference and change bits */ STORAGE_KEY(px, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Use the I-byte to set the SVC interruption code */ regs->psw.intcode = i; /* Point to PSA in main storage */ psa = (void*)(regs->mainstor + px); #if defined(FEATURE_BCMODE) /* For ECMODE, store SVC interrupt code at PSA+X'88' */ if ( ECMODE(®s->psw) ) #endif /*defined(FEATURE_BCMODE)*/ { psa->svcint[0] = 0; psa->svcint[1] = REAL_ILC(regs); psa->svcint[2] = 0; psa->svcint[3] = i; } /* Store current PSW at PSA+X'20' */ ARCH_DEP(store_psw) ( regs, psa->svcold ); /* Load new PSW from PSA+X'60' */ if ( (rc = ARCH_DEP(load_psw) ( regs, psa->svcnew ) ) ) regs->program_interrupt (regs, rc); /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* 93 TS - Test and Set [S] */ /*-------------------------------------------------------------------*/ DEF_INST(test_and_set) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE *main2; /* Mainstor address */ BYTE old; /* Old value */ S(inst, regs, b2, effective_addr2); ITIMER_SYNC(effective_addr2,0,regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Get operand absolute address */ main2 = MADDR (effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Get old value */ old = *main2; /* Attempt to exchange the values */ while (cmpxchg1(&old, 255, main2)); regs->psw.cc = old >> 7; /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); if (regs->psw.cc == 1) { #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC0, TS1)) { if( !OPEN_IC_PER(regs) ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else longjmp(regs->progjmp, SIE_INTERCEPT_INSTCOMP); } else #endif /*defined(_FEATURE_SIE)*/ if (sysblk.cpus > 1) sched_yield(); } else { ITIMER_UPDATE(effective_addr2,0,regs); } } /*-------------------------------------------------------------------*/ /* 91 TM - Test under Mask [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(test_under_mask) { BYTE i2; /* Immediate operand */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE tbyte; /* Work byte */ SI(inst, regs, i2, b1, effective_addr1); /* Fetch byte from operand address */ tbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* AND with immediate operand mask */ tbyte &= i2; /* Set condition code according to result */ regs->psw.cc = ( tbyte == 0 ) ? 0 : /* result all zeroes */ ( tbyte == i2) ? 3 : /* result all ones */ 1 ; /* result mixed */ } #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7x0 TMH - Test under Mask High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(test_under_mask_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ U16 h1; /* 16-bit operand values */ U16 h2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); /* AND register bits 0-15 with immediate operand */ h1 = i2 & regs->GR_LHH(r1); /* Isolate leftmost bit of immediate operand */ for ( h2 = 0x8000; h2 != 0 && (h2 & i2) == 0; h2 >>= 1 ); /* Set condition code according to result */ regs->psw.cc = ( h1 == 0 ) ? 0 : /* result all zeroes */ ( h1 == i2) ? 3 : /* result all ones */ ((h1 & h2) == 0) ? 1 : /* leftmost bit zero */ 2; /* leftmost bit one */ } #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if defined(FEATURE_IMMEDIATE_AND_RELATIVE) /*-------------------------------------------------------------------*/ /* A7x1 TML - Test under Mask Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(test_under_mask_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ U16 h1; /* 16-bit operand values */ U16 h2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); /* AND register bits 16-31 with immediate operand */ h1 = i2 & regs->GR_LHL(r1); /* Isolate leftmost bit of immediate operand */ for ( h2 = 0x8000; h2 != 0 && (h2 & i2) == 0; h2 >>= 1 ); /* Set condition code according to result */ regs->psw.cc = ( h1 == 0 ) ? 0 : /* result all zeroes */ ( h1 == i2) ? 3 : /* result all ones */ ((h1 & h2) == 0) ? 1 : /* leftmost bit zero */ 2; /* leftmost bit one */ } #endif /*defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ /*-------------------------------------------------------------------*/ /* DC TR - Translate [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(translate) { int len, len2 = -1; /* Lengths */ int b1, b2; /* Values of base field */ int i, b, n; /* Work variables */ VADR addr1, addr2; /* Effective addresses */ BYTE *dest, *dest2 = NULL, *tab, *tab2; /* Mainstor pointers */ SS_L(inst, regs, len, b1, addr1, b2, addr2); /* Get destination pointer */ dest = MADDRL (addr1, len+1, b1, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get pointer to next page if destination crosses a boundary */ if (CROSS2K (addr1, len)) { len2 = len; len = 0x7FF - (addr1 & 0x7FF); len2 -= (len + 1); dest2 = MADDR ((addr1+len+1) & ADDRESS_MAXWRAP(regs), b1, regs, ACCTYPE_WRITE, regs->psw.pkey); } /* Fast path if table does not cross a boundary */ if (NOCROSS2K (addr2, 255)) { tab = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); /* Perform translate function */ for (i = 0; i <= len; i++) dest[i] = tab[dest[i]]; for (i = 0; i <= len2; i++) dest2[i] = tab[dest2[i]]; } else { n = 0x800 - (addr2 & 0x7FF); b = dest[0]; /* Referenced part of the table may or may not span boundary */ if (b < n) { tab = MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); for (i = 1; i <= len && b < n; i++) b = dest[i]; for (i = 0; i <= len2 && b < n; i++) b = dest2[i]; tab2 = b < n ? NULL : MADDR ((addr2+n) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); } else { tab2 = MADDR ((addr2+n) & ADDRESS_MAXWRAP(regs), b2, regs, ACCTYPE_READ, regs->psw.pkey); for (i = 1; i <= len && b >= n; i++) b = dest[i]; for (i = 0; i <= len2 && b >= n; i++) b = dest2[i]; tab = b >= n ? NULL : MADDR (addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); } /* Perform translate function */ for (i = 0; i <= len; i++) dest[i] = dest[i] < n ? tab[dest[i]] : tab2[dest[i]-n]; for (i = 0; i <= len2; i++) dest2[i] = dest2[i] < n ? tab[dest2[i]] : tab2[dest2[i]-n]; } /* Translate table spans a boundary */ } /*-------------------------------------------------------------------*/ /* DD TRT - Translate and Test [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_and_test) { int l; /* Lenght byte */ int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc = 0; /* Condition code */ BYTE sbyte; /* Byte work areas */ BYTE dbyte; /* Byte work areas */ int i; /* Integer work areas */ SS_L(inst, regs, l, b1, effective_addr1, b2, effective_addr2); /* Process first operand from left to right */ for ( i = 0; i <= l; i++ ) { /* Fetch argument byte from first operand */ dbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* Fetch function byte from second operand */ sbyte = ARCH_DEP(vfetchb) ( (effective_addr2 + dbyte) & ADDRESS_MAXWRAP(regs), b2, regs ); /* Test for non-zero function byte */ if (sbyte != 0) { /* Store address of argument byte in register 1 */ #if defined(FEATURE_ESAME) if(regs->psw.amode64) regs->GR_G(1) = effective_addr1; else #endif if ( regs->psw.amode ) regs->GR_L(1) = effective_addr1; else regs->GR_LA24(1) = effective_addr1; /* Store function byte in low-order byte of reg.2 */ regs->GR_LHLCL(2) = sbyte; /* Set condition code 2 if argument byte was last byte of first operand, otherwise set condition code 1 */ cc = (i == l) ? 2 : 1; /* Terminate the operation at this point */ break; } /* end if(sbyte) */ /* Increment first operand address */ effective_addr1++; effective_addr1 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ /* Update the condition code */ regs->psw.cc = cc; } #ifdef FEATURE_EXTENDED_TRANSLATION /*-------------------------------------------------------------------*/ /* B2A5 TRE - Translate Extended [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_extended) { int r1, r2; /* Values of R fields */ int i; /* Loop counter */ int cc = 0; /* Condition code */ VADR addr1, addr2; /* Operand addresses */ GREG len1; /* Operand length */ BYTE byte1, byte2; /* Operand bytes */ BYTE tbyte; /* Test byte */ BYTE trtab[256]; /* Translate table */ RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); /* Load the test byte from bits 24-31 of register 0 */ tbyte = regs->GR_LHLCL(0); /* Load the operand addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Load first operand length from R1+1 */ len1 = GR_A(r1+1, regs); /* Fetch second operand into work area. [7.5.101] Access exceptions for all 256 bytes of the second operand may be recognized, even if not all bytes are used */ ARCH_DEP(vfetchc) ( trtab, 255, addr2, r2, regs ); /* Process first operand from left to right */ for (i = 0; len1 > 0; i++) { /* If 4096 bytes have been compared, exit with condition code 3 */ if (i >= 4096) { cc = 3; break; } /* Fetch byte from first operand */ byte1 = ARCH_DEP(vfetchb) ( addr1, r1, regs ); /* If equal to test byte, exit with condition code 1 */ if (byte1 == tbyte) { cc = 1; break; } /* Load indicated byte from translate table */ byte2 = trtab[byte1]; /* Store result at first operand address */ ARCH_DEP(vstoreb) ( byte2, addr1, r1, regs ); addr1++; addr1 &= ADDRESS_MAXWRAP(regs); len1--; /* Update the registers */ SET_GR_A(r1, regs, addr1); SET_GR_A(r1+1, regs, len1); } /* end for(i) */ /* Set condition code */ regs->psw.cc = cc; } /* end translate_extended */ #endif /*FEATURE_EXTENDED_TRANSLATION*/ /*-------------------------------------------------------------------*/ /* F3 UNPK - Unpack [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(unpack) { int l1, l2; /* Register numbers */ int b1, b2; /* Base registers */ VADR effective_addr1, effective_addr2; /* Effective addressES */ int i, j; /* Loop counters */ BYTE sbyte; /* Source operand byte */ BYTE rbyte; /* Right result byte of pair */ BYTE lbyte; /* Left result byte of pair */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* If operand 1 crosses a page, make sure both pages are accessable */ if((effective_addr1 & PAGEFRAME_PAGEMASK) != ((effective_addr1 + l1) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr1, b1, l1, ACCTYPE_WRITE_SKP, regs); /* If operand 2 crosses a page, make sure both pages are accessable */ if((effective_addr2 & PAGEFRAME_PAGEMASK) != ((effective_addr2 + l2) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr2, b2, l2, ACCTYPE_READ, regs); /* Exchange the digits in the rightmost byte */ effective_addr1 += l1; effective_addr2 += l2; sbyte = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); rbyte = (sbyte << 4) | (sbyte >> 4); ARCH_DEP(vstoreb) ( rbyte, effective_addr1, b1, regs ); /* Process remaining bytes from right to left */ for (i = l1, j = l2; i > 0; i--) { /* Fetch source byte from second operand */ if (j-- > 0) { sbyte = ARCH_DEP(vfetchb) ( --effective_addr2, b2, regs ); rbyte = (sbyte & 0x0F) | 0xF0; lbyte = (sbyte >> 4) | 0xF0; } else { rbyte = 0xF0; lbyte = 0xF0; } /* Store unpacked bytes at first operand address */ ARCH_DEP(vstoreb) ( rbyte, --effective_addr1, b1, regs ); if (--i > 0) { effective_addr1 &= ADDRESS_MAXWRAP(regs); ARCH_DEP(vstoreb) ( lbyte, --effective_addr1, b1, regs ); } /* Wraparound according to addressing mode */ effective_addr1 &= ADDRESS_MAXWRAP(regs); effective_addr2 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ } /*-------------------------------------------------------------------*/ /* 0102 UPT - Update Tree [E] */ /* (c) Copyright Peter Kuschnerus, 1999-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2005-2009 */ /*-------------------------------------------------------------------*/ DEF_INST(update_tree) { GREG index; /* tree index */ GREG nodecode; /* current node's codeword */ GREG nodedata; /* current node's other data */ VADR nodeaddr; /* work addr of current node */ #if defined(FEATURE_ESAME) BYTE a64 = regs->psw.amode64; /* 64-bit mode flag */ #endif E(inst, regs); /* ** GR0, GR1 node values (codeword and other data) of node ** with "highest encountered codeword value" ** GR2, GR3 node values (codeword and other data) from whichever ** node we happened to have encountered that had a code- ** word value equal to our current "highest encountered ** codeword value" (e.g. GR0) (cc0 only) ** GR4 pointer to one node BEFORE the beginning of the tree ** GR5 current node index (tree displacement to current node) */ /* Check GR4, GR5 for proper alignment */ if (0 || ( GR_A(4,regs) & UPT_ALIGN_MASK ) || ( GR_A(5,regs) & UPT_ALIGN_MASK ) ) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Bubble the tree by moving successively higher nodes towards the front (beginning) of the tree, only stopping whenever we either: 1. reach the beginning of the tree, -OR- 2. encounter a node with a negative codeword value, -OR- 3. encounter a node whose codeword is equal to our current "highest encountered codeword". Thus, when we're done, GR0 & GR1 will then contain the node values of the node with the highest encountered codeword value, and all other traversed nodes will have been reordered into descending code- word sequence (i.e. from highest codeword value to lowest codeword value; this is after all an instruction used for sorting/merging). */ for (;;) { /* Calculate index value of next node to be examined (half as far from beginning of tree to where we currently are) */ index = (GR_A(5,regs) >> 1) & UPT_SHIFT_MASK; /* Exit with cc1 when we've gone as far as we can go */ if ( !index ) { regs->psw.cc = 1; break; } /* Exit with cc3 when we encounter a negative codeword value (i.e. any codeword value with its highest-order bit on) */ if ( GR_A(0,regs) & UPT_HIGH_BIT ) { regs->psw.cc = 3; break; } /* Retrieve this node's values for closer examination... */ nodeaddr = regs->GR(4) + index; #if defined(FEATURE_ESAME) if ( a64 ) { nodecode = ARCH_DEP(vfetch8) ( (nodeaddr+0) & ADDRESS_MAXWRAP(regs), AR4, regs ); nodedata = ARCH_DEP(vfetch8) ( (nodeaddr+8) & ADDRESS_MAXWRAP(regs), AR4, regs ); } else #endif { nodecode = ARCH_DEP(vfetch4) ( (nodeaddr+0) & ADDRESS_MAXWRAP(regs), AR4, regs ); nodedata = ARCH_DEP(vfetch4) ( (nodeaddr+4) & ADDRESS_MAXWRAP(regs), AR4, regs ); } /* GR5 must remain UNCHANGED if the execution of a unit of operation is nullified or suppressed! Thus it must ONLY be updated/committed AFTER we've successfully retrieved the node data (since the storage access could cause a program-check thereby nullifying/suppressing the instruction's "current unit of operation") */ SET_GR_A(5,regs,index); // (do AFTER node data is accessed!) /* Exit with cc0 whenever we reach a node whose codeword is equal to our current "highest encountered" codeword value (i.e. any node whose codeword matches our current "highest" (GR0) value) */ if ( nodecode == GR_A(0,regs) ) { /* Load GR2 and GR3 with the equal codeword node's values */ SET_GR_A(2,regs,nodecode); SET_GR_A(3,regs,nodedata); regs->psw.cc = 0; return; } /* Keep resequencing the tree's nodes, moving successively higher nodes to the front (beginning of tree)... */ if ( nodecode < GR_A(0,regs) ) continue; /* This node has a codeword value higher than our currently saved highest encountered codeword value (GR0). Swap our GR0/1 values with this node's values, such that GR0/1 always hold the values from the node with the highest encountered codeword value... */ /* Store obsolete GR0 and GR1 values into this node's entry */ #if defined(FEATURE_ESAME) if ( a64 ) { ARCH_DEP(vstore8) ( GR_A(0,regs), (nodeaddr+0) & ADDRESS_MAXWRAP(regs), AR4, regs ); ARCH_DEP(vstore8) ( GR_A(1,regs), (nodeaddr+8) & ADDRESS_MAXWRAP(regs), AR4, regs ); } else #endif { ARCH_DEP(vstore4) ( GR_A(0,regs), (nodeaddr+0) & ADDRESS_MAXWRAP(regs), AR4, regs ); ARCH_DEP(vstore4) ( GR_A(1,regs), (nodeaddr+4) & ADDRESS_MAXWRAP(regs), AR4, regs ); } /* Update GR0 and GR1 with the new "highest encountered" values */ SET_GR_A(0,regs,nodecode); SET_GR_A(1,regs,nodedata); } /* Commit GR5 with the actual index value we stopped on */ SET_GR_A(5,regs,index); } /* end DEF_INST(update_tree) */ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_3) /*-------------------------------------------------------------------*/ /* B9B0 CU14 - Convert UTF-8 to UTF-32 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_utf8_to_utf32) { VADR dest; /* Destination address */ GREG destlen; /* Destination length */ int r1; int r2; int read; /* Bytes read */ VADR srce; /* Source address */ GREG srcelen; /* Source length */ BYTE utf32[4]; /* utf32 character(s) */ BYTE utf8[4]; /* utf8 character(s) */ #if defined(FEATURE_ETF3_ENHANCEMENT) int wfc; /* Well-Formedness-Checking (W) */ #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ int xlated; /* characters translated */ // NOTE: it's faster to decode with RRE format // and then to handle the 'wfc' flag separately... //RRF_M(inst, regs, r1, r2, wfc); RRE(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); /* Get paramaters */ dest = regs->GR(r1) & ADDRESS_MAXWRAP(regs); destlen = GR_A(r1 + 1, regs); srce = regs->GR(r2) & ADDRESS_MAXWRAP(regs); srcelen = GR_A(r2 + 1, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) if(inst[2] & 0x10) wfc = 1; else wfc = 0; #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Every valid utf-32 starts with 0x00 */ utf32[0] = 0x00; /* Initialize number of translated charachters */ xlated = 0; while(xlated < 4096) { /* Check end of source or destination */ if(srcelen < 1) { regs->psw.cc = 0; return; } if(destlen < 4) { regs->psw.cc = 1; return; } /* Fetch a byte */ utf8[0] = ARCH_DEP(vfetchb)(srce, r2, regs); if(utf8[0] < 0x80) { /* xlate range 00-7f */ /* 0jklmnop -> 00000000 00000000 00000000 0jklmnop */ utf32[1] = 0x00; utf32[2] = 0x00; utf32[3] = utf8[0]; read = 1; } else if(utf8[0] >= 0xc0 && utf8[0] <= 0xdf) { #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormednessChecking */ if(wfc) { if(utf8[0] <= 0xc1) { regs->psw.cc = 2; return; } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Check end of source */ if(srcelen < 2) { regs->psw.cc = 0; /* Strange but stated in POP */ return; } /* Get the next byte */ utf8[1] = ARCH_DEP(vfetchb)(srce + 1, r2, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormednessChecking */ if(wfc) { if(utf8[1] < 0x80 || utf8[1] > 0xbf) { regs->psw.cc = 2; return; } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* xlate range c000-dfff */ /* 110fghij 10klmnop -> 00000000 00000000 00000fgh ijklmnop */ utf32[1] = 0x00; utf32[2] = (utf8[0] & 0x1c) >> 2; utf32[3] = (utf8[0] << 6) | (utf8[1] & 0x3f); read = 2; } else if(utf8[0] >= 0xe0 && utf8[0] <= 0xef) { /* Check end of source */ if(srcelen < 3) { regs->psw.cc = 0; /* Strange but stated in POP */ return; } /* Get the next 2 bytes */ ARCH_DEP(vfetchc)(&utf8[1], 1, srce + 1, r2, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellformednessChecking */ if(wfc) { if(utf8[0] == 0xe0) { if(utf8[1] < 0xa0 || utf8[1] > 0xbf || utf8[2] < 0x80 || utf8[2] > 0xbf) { regs->psw.cc = 2; return; } } if((utf8[0] >= 0xe1 && utf8[0] <= 0xec) || (utf8[0] >= 0xee && utf8[0] <= 0xef)) { if(utf8[1] < 0x80 || utf8[1] > 0xbf || utf8[2] < 0x80 || utf8[2] > 0xbf) { regs->psw.cc = 2; return; } } if(utf8[0] == 0xed) { if(utf8[1] < 0x80 || utf8[1] > 0x9f || utf8[2] < 0x80 || utf8[2] > 0xbf) { regs->psw.cc = 2; return; } } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* xlate range e00000-efffff */ /* 1110abcd 10efghij 10klmnop -> 00000000 00000000 abcdefgh ijklmnop */ utf32[1] = 0x00; utf32[2] = (utf8[0] << 4) | ((utf8[1] & 0x3c) >> 2); utf32[3] = (utf8[1] << 6) | (utf8[2] & 0x3f); read = 3; } else if(utf8[0] >= 0xf0 && utf8[0] <= 0xf7) { #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormednessChecking */ if(wfc) { if(utf8[0] > 0xf4) { regs->psw.cc = 2; return; } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Check end of source */ if(srcelen < 4) { regs->psw.cc = 0; /* Strange but stated in POP */ return; } /* Get the next 3 bytes */ ARCH_DEP(vfetchc)(&utf8[1], 2, srce + 1, r2, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormdnessChecking */ if(wfc) { if(utf8[0] == 0xf0) { if(utf8[1] < 0x90 || utf8[1] > 0xbf || utf8[2] < 0x80 || utf8[2] > 0xbf || utf8[3] < 0x80 || utf8[3] > 0xbf) { regs->psw.cc = 2; return; } } if(utf8[0] >= 0xf1 && utf8[0] <= 0xf3) { if(utf8[1] < 0x80 || utf8[1] > 0xbf || utf8[2] < 0x80 || utf8[2] > 0xbf || utf8[3] < 0x80 || utf8[3] > 0xbf) { regs->psw.cc = 2; return; } } if(utf8[0] == 0xf4) { if(utf8[1] < 0x80 || utf8[1] > 0x8f || utf8[2] < 0x80 || utf8[2] > 0xbf || utf8[3] < 0x80 || utf8[3] > 0xbf) { regs->psw.cc = 2; return; } } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* xlate range f0000000-f7000000 */ /* 1110uvw 10xyefgh 10ijklmn 10opqrst -> 00000000 000uvwxy efghijkl mnopqrst */ utf32[1] = ((utf8[0] & 0x07) << 2) | ((utf8[1] & 0x30) >> 4); utf32[2] = (utf8[1] << 4) | ((utf8[2] & 0x3c) >> 2); utf32[3] = (utf8[2] << 6) | (utf8[3] & 0x3f); read = 4; } else { regs->psw.cc = 2; return; } /* Write and commit registers */ ARCH_DEP(vstorec)(utf32, 3, dest, r1, regs); SET_GR_A(r1, regs, (dest + 4) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r1 + 1, regs, destlen - 4); SET_GR_A(r2, regs, (srce + read) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r2 + 1, regs, srcelen - read); xlated += read; } /* CPU determined number of characters reached */ regs->psw.cc = 3; } /*-------------------------------------------------------------------*/ /* B9B1 CU24 - Convert UTF-16 to UTF-32 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_utf16_to_utf32) { VADR dest; /* Destination address */ GREG destlen; /* Destination length */ int r1; int r2; int read; /* Bytes read */ VADR srce; /* Source address */ GREG srcelen; /* Source length */ BYTE utf16[4]; /* utf16 character(s) */ BYTE utf32[4]; /* utf328 character(s) */ BYTE uvwxy; /* Work value */ #if defined(FEATURE_ETF3_ENHANCEMENT) int wfc; /* Well-Formedness-Checking (W) */ #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ int xlated; /* characters translated */ // NOTE: it's faster to decode with RRE format // and then to handle the 'wfc' flag separately... //RRF_M(inst, regs, r1, r2, wfc); RRE(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); /* Get paramaters */ dest = regs->GR(r1) & ADDRESS_MAXWRAP(regs); destlen = GR_A(r1 + 1, regs); srce = regs->GR(r2) & ADDRESS_MAXWRAP(regs); srcelen = GR_A(r2 + 1, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) if(inst[2] & 0x10) wfc = 1; else wfc = 0; #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* Every valid utf-32 starts with 0x00 */ utf32[0] = 0x00; /* Initialize number of translated charachters */ xlated = 0; while(xlated < 4096) { /* Check end of source or destination */ if(srcelen < 2) { regs->psw.cc = 0; return; } if(destlen < 4) { regs->psw.cc = 1; return; } /* Fetch 2 bytes */ ARCH_DEP(vfetchc)(utf16, 1, srce, r2, regs); if(utf16[0] <= 0xd7 || utf16[0] >= 0xdc) { /* xlate range 0000-d7fff and dc00-ffff */ /* abcdefgh ijklmnop -> 00000000 00000000 abcdefgh ijklmnop */ utf32[1] = 0x00; utf32[2] = utf16[0]; utf32[3] = utf16[1]; read = 2; } else { /* Check end of source */ if(srcelen < 4) { regs->psw.cc = 0; /* Strange but stated in POP */ return; } /* Fetch another 2 bytes */ ARCH_DEP(vfetchc)(&utf16[2], 1, srce, r2, regs); #if defined(FEATURE_ETF3_ENHANCEMENT) /* WellFormednessChecking */ if(wfc) { if(utf16[2] < 0xdc && utf16[2] > 0xdf) { regs->psw.cc = 2; return; } } #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ /* xlate range d800-dbff */ /* 110110ab cdefghij 110111kl mnopqrst -> 00000000 000uvwxy efghijkl mnopqrst */ /* 000uvwxy = 0000abcde + 1 */ uvwxy = (((utf16[0] & 0x03) << 2) | (utf16[1] >> 6)) + 1; utf32[1] = uvwxy; utf32[2] = (utf16[1] << 2) | (utf16[2] & 0x03); utf32[3] = utf16[3]; read = 4; } /* Write and commit registers */ ARCH_DEP(vstorec)(utf32, 3, dest, r1, regs); SET_GR_A(r1, regs, (dest + 4) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r1 + 1, regs, destlen - 4); SET_GR_A(r2, regs, (srce + read) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r2 + 1, regs, srcelen - read); xlated += read; } /* CPU determined number of characters reached */ regs->psw.cc = 3; } /*-------------------------------------------------------------------*/ /* B9B2 CU41 - Convert UTF-32 to UTF-8 [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_utf32_to_utf8) { VADR dest; /* Destination address */ GREG destlen; /* Destination length */ int r1; int r2; VADR srce; /* Source address */ GREG srcelen; /* Source length */ BYTE utf32[4]; /* utf32 character(s) */ BYTE utf8[4]; /* utf8 character(s) */ int write; /* Bytes written */ int xlated; /* characters translated */ RRE(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); /* Get paramaters */ dest = regs->GR(r1) & ADDRESS_MAXWRAP(regs); destlen = GR_A(r1 + 1, regs); srce = regs->GR(r2) & ADDRESS_MAXWRAP(regs); srcelen = GR_A(r2 + 1, regs); /* Initialize number of translated charachters */ xlated = 0; write = 0; while(xlated < 4096) { /* Check end of source or destination */ if(srcelen < 4) { regs->psw.cc = 0; return; } if(destlen < 1) { regs->psw.cc = 1; return; } /* Get 4 bytes */ ARCH_DEP(vfetchc)(utf32, 3, srce, r2, regs); if(utf32[0] != 0x00) { regs->psw.cc = 2; return; } else if(utf32[1] == 0x00) { if(utf32[2] == 0x00) { if(utf32[3] <= 0x7f) { /* xlate range 00000000-0000007f */ /* 00000000 00000000 00000000 0jklmnop -> 0jklmnop */ utf8[0] = utf32[3]; write = 1; } } else if(utf32[2] <= 0x07) { /* Check destination length */ if(destlen < 2) { regs->psw.cc = 1; return; } /* xlate range 00000080-000007ff */ /* 00000000 00000000 00000fgh ijklmnop -> 110fghij 10klmnop */ utf8[0] = 0xc0 | (utf32[2] << 2) | (utf32[2] >> 6); utf8[1] = 0x80 | (utf32[2] & 0x3f); write = 2; } else if(utf32[2] <= 0xd7 || utf32[2] > 0xdc) { /* Check destination length */ if(destlen < 3) { regs->psw.cc = 1; return; } /* xlate range 00000800-0000d7ff and 0000dc00-0000ffff */ /* 00000000 00000000 abcdefgh ijklnmop -> 1110abcd 10efghij 10klmnop */ utf8[0] = 0xe0 | (utf32[2] >> 4); utf8[1] = 0x80 | ((utf32[2] & 0x0f) << 2) | (utf32[3] >> 6); utf8[2] = 0x80 | (utf32[3] & 0x3f); write = 3; } else { regs->psw.cc = 2; return; } } else if(utf32[1] >= 0x01 && utf32[1] <= 0x10) { /* Check destination length */ if(destlen < 4) { regs->psw.cc = 1; return; } /* xlate range 00010000-0010ffff */ /* 00000000 000uvwxy efghijkl mnopqrst -> 11110uvw 10xyefgh 10ijklmn 10opqrst */ utf8[0] = 0xf0 | (utf32[1] >> 2); utf8[1] = 0x80 | ((utf32[1] & 0x03) << 4) | (utf32[2] >> 4); utf8[2] = 0x80 | ((utf32[2] & 0x0f) << 2) | (utf32[3] >> 6); utf8[3] = 0x80 | (utf32[3] & 0x3f); write = 4; } else { regs->psw.cc = 2; return; } /* Write and commit registers */ ARCH_DEP(vstorec)(utf8, write - 1, dest, r1, regs); SET_GR_A(r1, regs, (dest + write) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r1 + 1, regs, destlen - write); SET_GR_A(r2, regs, (srce + 4) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r2 + 1, regs, srcelen - 4); xlated += 4; } /* CPU determined number of characters reached */ regs->psw.cc = 3; } /*-------------------------------------------------------------------*/ /* B9B3 CU42 - Convert UTF-32 to UTF-16 [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_utf32_to_utf16) { VADR dest; /* Destination address */ GREG destlen; /* Destination length */ int r1; int r2; VADR srce; /* Source address */ GREG srcelen; /* Source length */ BYTE utf16[4]; /* utf16 character(s) */ BYTE utf32[4]; /* utf32 character(s) */ int write; /* Bytes written */ int xlated; /* characters translated */ BYTE zabcd; /* Work value */ RRE(inst, regs, r1, r2); ODD2_CHECK(r1, r2, regs); /* Get paramaters */ dest = regs->GR(r1) & ADDRESS_MAXWRAP(regs); destlen = GR_A(r1 + 1, regs); srce = regs->GR(r2) & ADDRESS_MAXWRAP(regs); srcelen = GR_A(r2 + 1, regs); /* Initialize number of translated charachters */ xlated = 0; while(xlated < 4096) { /* Check end of source or destination */ if(srcelen < 4) { regs->psw.cc = 0; return; } if(destlen < 2) { regs->psw.cc = 1; return; } /* Get 4 bytes */ ARCH_DEP(vfetchc)(utf32, 3, srce, r2, regs); if(utf32[0] != 0x00) { regs->psw.cc = 2; return; } else if(utf32[1] == 0x00 && (utf32[2] <= 0xd7 || utf32[2] >= 0xdc)) { /* xlate range 00000000-0000d7ff and 0000dc00-0000ffff */ /* 00000000 00000000 abcdefgh ijklmnop -> abcdefgh ijklmnop */ utf16[0] = utf32[2]; utf16[1] = utf32[3]; write = 2; } else if(utf32[1] >= 0x01 && utf32[1] <= 0x10) { /* Check end of destination */ if(destlen < 4) { regs->psw.cc = 1; return; } /* xlate range 00010000-0010ffff */ /* 00000000 000uvwxy efghijkl mnopqrst -> 110110ab cdefghij 110111kl mnopqrst */ /* 000zabcd = 000uvwxy - 1 */ zabcd = (utf32[1] - 1) & 0x0f; utf16[0] = 0xd8 | (zabcd >> 2); utf16[1] = (zabcd << 6) | (utf32[2] >> 2); utf16[2] = 0xdc | (utf32[2] & 0x03); utf16[3] = utf32[3]; write = 4; } else { regs->psw.cc = 2; return; } /* Write and commit registers */ ARCH_DEP(vstorec)(utf16, write - 1, dest, r1, regs); SET_GR_A(r1, regs, (dest + write) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r1 + 1, regs, destlen - write); SET_GR_A(r2, regs, (srce + 4) & ADDRESS_MAXWRAP(regs)); SET_GR_A(r2 + 1, regs, srcelen - 4); xlated += 4; } /* CPU determined number of characters reached */ regs->psw.cc = 3; } /*-------------------------------------------------------------------*/ /* B9BE SRSTU - Search String Unicode [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(search_string_unicode) { VADR addr1, addr2; /* End/start addresses */ int i; /* Loop counter */ int r1, r2; /* Values of R fields */ U16 sbyte; /* String character */ U16 termchar; /* Terminating character */ RRE(inst, regs, r1, r2); /* Program check if bits 0-15 of register 0 not zero */ if(regs->GR_L(0) & 0xFFFF0000) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Load string terminating character from register 0 bits 16-31 */ termchar = (U16) regs->GR(0); /* Determine the operand end and start addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Search up to 256 bytes or until end of operand */ for(i = 0; i < 0x100; i++) { /* If operand end address has been reached, return condition code 2 and leave the R1 and R2 registers unchanged */ if(addr2 == addr1) { regs->psw.cc = 2; return; } /* Fetch 2 bytes from the operand */ sbyte = ARCH_DEP(vfetch2)(addr2, r2, regs ); /* If the terminating character was found, return condition code 1 and load the address of the character into R1 */ if(sbyte == termchar) { SET_GR_A(r1, regs, addr2); regs->psw.cc = 1; return; } /* Increment operand address */ addr2 += 2; addr2 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ /* Set R2 to point to next character of operand */ SET_GR_A(r2, regs, addr2); /* Return condition code 3 */ regs->psw.cc = 3; } /*-------------------------------------------------------------------*/ /* D0 TRTR - Translate and Test Reverse [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_and_test_reverse) { int b1, b2; /* Values of base field */ int cc = 0; /* Condition code */ BYTE dbyte; /* Byte work areas */ VADR effective_addr1; VADR effective_addr2; /* Effective addresses */ int i; /* Integer work areas */ int l; /* Lenght byte */ BYTE sbyte; /* Byte work areas */ SS_L(inst, regs, l, b1, effective_addr1, b2, effective_addr2); /* Process first operand from right to left*/ for(i = 0; i <= l; i++) { /* Fetch argument byte from first operand */ dbyte = ARCH_DEP(vfetchb)(effective_addr1, b1, regs); /* Fetch function byte from second operand */ sbyte = ARCH_DEP(vfetchb)((effective_addr2 + dbyte) & ADDRESS_MAXWRAP(regs), b2, regs); /* Test for non-zero function byte */ if(sbyte != 0) { /* Store address of argument byte in register 1 */ #if defined(FEATURE_ESAME) if(regs->psw.amode64) regs->GR_G(1) = effective_addr1; else #endif if(regs->psw.amode) { /* Note: TRTR differs from TRT in 31 bit mode. TRTR leaves bit 32 unchanged, TRT clears bit 32 */ regs->GR_L(1) &= 0x80000000; regs->GR_L(1) |= effective_addr1; } else regs->GR_LA24(1) = effective_addr1; /* Store function byte in low-order byte of reg.2 */ regs->GR_LHLCL(2) = sbyte; /* Set condition code 2 if argument byte was last byte of first operand, otherwise set condition code 1 */ cc = (i == l) ? 2 : 1; /* Terminate the operation at this point */ break; } /* end if(sbyte) */ /* Decrement first operand address */ effective_addr1--; /* Another difference with TRT */ effective_addr1 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ /* Update the condition code */ regs->psw.cc = cc; } #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_3)*/ #ifdef FEATURE_PARSING_ENHANCEMENT_FACILITY /*-------------------------------------------------------------------*/ /* B9BF TRTE - Translate and Test Extended [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_and_test_extended) { int a_bit; /* Argument-Character Control (A) */ U32 arg_ch; /* Argument character */ VADR buf_addr; /* first argument address */ GREG buf_len; /* First argument length */ int f_bit; /* Function-Code Control (F) */ U32 fc; /* Function-Code */ VADR fct_addr; /* Function-code table address */ int l_bit; /* Argument-Character Limit (L) */ int m3; int processed; /* # bytes processed */ int r1; int r2; RRF_M(inst, regs, r1, r2, m3); a_bit = ((m3 & 0x08) ? 1 : 0); f_bit = ((m3 & 0x04) ? 1 : 0); l_bit = ((m3 & 0x02) ? 1 : 0); buf_addr = regs->GR(r1) & ADDRESS_MAXWRAP(regs); buf_len = GR_A(r1 + 1, regs); fct_addr = regs->GR(1) & ADDRESS_MAXWRAP(regs); if(unlikely((a_bit && (buf_len % 1)) || r1 & 0x01)) regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION); fc = 0; processed = 0; while(buf_len && !fc && processed < 16384) { if(a_bit) { arg_ch = ARCH_DEP(vfetch2)(buf_addr, r1, regs); } else { arg_ch = ARCH_DEP(vfetchb)(buf_addr, r1, regs); } if(l_bit && arg_ch > 255) fc = 0; else { if(f_bit) fc = ARCH_DEP(vfetch2)((fct_addr + (arg_ch * 2)) & ADDRESS_MAXWRAP(regs), 1, regs); else fc = ARCH_DEP(vfetchb)((fct_addr + arg_ch) & ADDRESS_MAXWRAP(regs), 1, regs); } if(!fc) { if(a_bit) { buf_len -= 2; processed += 2; buf_addr = (buf_addr + 2) & ADDRESS_MAXWRAP(regs); } else { buf_len--; processed++; buf_addr = (buf_addr + 1) & ADDRESS_MAXWRAP(regs); } } } /* Commit registers */ SET_GR_A(r1, regs, buf_addr); SET_GR_A(r1 + 1, regs, buf_len); /* Check if CPU determined number of bytes have been processed */ if(buf_len && !fc) { regs->psw.cc = 3; return; } /* Set function code */ if(likely(r2 != r1 && r2 != r1 + 1)) SET_GR_A(r2, regs, fc); /* Set condition code */ if(fc) regs->psw.cc = 1; else regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* B9BD TRTRE - Translate and Test Reverse Extended [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_and_test_reverse_extended) { int a_bit; /* Argument-Character Control (A) */ U32 arg_ch; /* Argument character */ VADR buf_addr; /* first argument address */ GREG buf_len; /* First argument length */ int f_bit; /* Function-Code Control (F) */ U32 fc; /* Function-Code */ VADR fct_addr; /* Function-code table address */ int l_bit; /* Argument-Character Limit (L) */ int m3; int processed; /* # bytes processed */ int r1; int r2; RRF_M(inst, regs, r1, r2, m3); a_bit = ((m3 & 0x08) ? 1 : 0); f_bit = ((m3 & 0x04) ? 1 : 0); l_bit = ((m3 & 0x02) ? 1 : 0); buf_addr = regs->GR(r1) & ADDRESS_MAXWRAP(regs); buf_len = GR_A(r1 + 1, regs); fct_addr = regs->GR(1) & ADDRESS_MAXWRAP(regs); if(unlikely((a_bit && (buf_len % 1)) || r1 & 0x01)) regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION); fc = 0; processed = 0; while(buf_len && !fc && processed < 16384) { if(a_bit) { arg_ch = ARCH_DEP(vfetch2)(buf_addr, r1, regs); } else { arg_ch = ARCH_DEP(vfetchb)(buf_addr, r1, regs); } if(l_bit && arg_ch > 255) fc = 0; else { if(f_bit) fc = ARCH_DEP(vfetch2)((fct_addr + (arg_ch * 2)) & ADDRESS_MAXWRAP(regs), 1, regs); else fc = ARCH_DEP(vfetchb)((fct_addr + arg_ch) & ADDRESS_MAXWRAP(regs), 1, regs); } if(!fc) { if(a_bit) { buf_len -= 2; processed += 2; buf_addr = (buf_addr - 2) & ADDRESS_MAXWRAP(regs); } else { buf_len--; processed++; buf_addr = (buf_addr - 1) & ADDRESS_MAXWRAP(regs); } } } /* Commit registers */ SET_GR_A(r1, regs, buf_addr); SET_GR_A(r1 + 1, regs, buf_len); /* Check if CPU determined number of bytes have been processed */ if(buf_len && !fc) { regs->psw.cc = 3; return; } /* Set function code */ if(likely(r2 != r1 && r2 != r1 + 1)) SET_GR_A(r2, regs, fc); /* Set condition code */ if(fc) regs->psw.cc = 1; else regs->psw.cc = 0; } #endif /* FEATURE_PARSING_ENHANCEMENT_FACILITY */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "general2.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "general2.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/general3.c0000664000175000017500000045252512564723224012064 00000000000000/* GENERAL3.C (c) Copyright Roger Bowler, 2009 */ /* Additional General Instructions */ /*-------------------------------------------------------------------*/ /* This module implements additional general instructions introduced */ /* as later extensions to z/Architecture and described in the manual */ /* SA22-7832-06 z/Architecture Principles of Operation */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_GENERAL3_C_) #define _GENERAL3_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY) #if defined(FEATURE_INTERLOCKED_ACCESS_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* Perform Interlocked Storage Immediate Operation */ /* Subroutine called by ASI and ALSI instructions */ /*-------------------------------------------------------------------*/ DEF_INST(perform_interlocked_storage_immediate) /*810*/ { BYTE opcode; /* 2nd byte of opcode */ BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR addr1; /* Effective address */ BYTE *m1; /* Mainstor address */ U32 n; /* 32-bit operand value */ U32 result; /* Result value */ U32 old, new; /* Values for cmpxchg4 */ int cc; /* Condition code */ int rc; /* Return code */ SIY(inst, regs, i2, b1, addr1); /* Extract second byte of instruction opcode */ opcode = inst[5]; /* Get mainstor address of storage operand */ m1 = MADDRL (addr1, 4, b1, regs, ACCTYPE_WRITE, regs->psw.pkey); do { /* Load 32-bit operand from operand address */ n = ARCH_DEP(vfetch4) (addr1, b1, regs); switch (opcode) { case 0x6A: /* Add Storage Immediate */ /* Add signed operands and set condition code */ cc = add_signed (&result, n, (S32)(S8)i2); break; case 0x6E: /* Add Logical Storage with Signed Immediate */ /* Add operands and set condition code */ cc = (S8)i2 < 0 ? sub_logical (&result, n, (S32)(-(S8)i2)) : add_logical (&result, n, (S32)(S8)i2); break; default: /* To prevent compiler warnings */ result = 0; cc = 0; } /* end switch(opcode) */ /* Regular store if operand is not on a fullword boundary */ if ((addr1 & 0x03) != 0) { ARCH_DEP(vstore4) (result, addr1, b1, regs); break; } /* Interlocked exchange if operand is on a fullword boundary */ old = CSWAP32(n); new = CSWAP32(result); rc = cmpxchg4(&old, new, m1); } while (rc != 0); /* Set condition code in PSW */ regs->psw.cc = cc; } /* end DEF_INST(perform_interlocked_storage_immediate) */ /*-------------------------------------------------------------------*/ /* Perform Interlocked Long Storage Immediate Operation */ /* Subroutine called by AGSI and ALGSI instructions */ /*-------------------------------------------------------------------*/ DEF_INST(perform_interlocked_long_storage_immediate) /*810*/ { BYTE opcode; /* 2nd byte of opcode */ BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR addr1; /* Effective address */ BYTE *m1; /* Mainstor address */ U64 n; /* 64-bit operand value */ U64 result; /* Result value */ U64 old, new; /* Values for cmpxchg4 */ int cc; /* Condition code */ int rc; /* Return code */ SIY(inst, regs, i2, b1, addr1); /* Extract second byte of instruction opcode */ opcode = inst[5]; /* Get mainstor address of storage operand */ m1 = MADDRL (addr1, 8, b1, regs, ACCTYPE_WRITE, regs->psw.pkey); do { /* Load 64-bit operand from operand address */ n = ARCH_DEP(vfetch8) (addr1, b1, regs); switch (opcode) { case 0x7A: /* Add Long Storage Immediate */ /* Add signed operands and set condition code */ cc = add_signed_long (&result, n, (S64)(S8)i2); break; case 0x7E: /* Add Logical Long Storage with Signed Immediate */ /* Add operands and set condition code */ cc = (S8)i2 < 0 ? sub_logical_long (&result, n, (S64)(-(S8)i2)) : add_logical_long (&result, n, (S64)(S8)i2); break; default: /* To prevent compiler warnings */ result = 0; cc = 0; } /* end switch(opcode) */ /* Regular store if operand is not on a doubleword boundary */ if ((addr1 & 0x07) != 0) { ARCH_DEP(vstore8) (result, addr1, b1, regs); break; } /* Interlocked exchange if operand is on doubleword boundary */ old = CSWAP64(n); new = CSWAP64(result); rc = cmpxchg8(&old, new, m1); } while (rc != 0); /* Set condition code in PSW */ regs->psw.cc = cc; } /* end DEF_INST(perform_interlocked_long_storage_immediate) */ #endif /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ /*-------------------------------------------------------------------*/ /* EB6A ASI - Add Immediate Storage [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_immediate_storage) { #if !defined(FEATURE_INTERLOCKED_ACCESS_FACILITY) /*810*/ BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ U32 n; /* 32-bit operand value */ int cc; /* Condition Code */ SIY(inst, regs, i2, b1, effective_addr1); /* Load 32-bit operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr1, b1, regs ); /* Add signed operands and set condition code */ cc = add_signed (&n, n, (S32)(S8)i2); /* Store 32-bit operand at operand address */ ARCH_DEP(vstore4) ( n, effective_addr1, b1, regs ); /* Update Condition Code */ regs->psw.cc = cc; #else /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ ARCH_DEP(perform_interlocked_storage_immediate) (inst, regs); #endif /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_immediate_storage) */ /*-------------------------------------------------------------------*/ /* EB7A AGSI - Add Immediate Long Storage [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_immediate_long_storage) { #if !defined(FEATURE_INTERLOCKED_ACCESS_FACILITY) /*810*/ BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ U64 n; /* 64-bit operand value */ int cc; /* Condition Code */ SIY(inst, regs, i2, b1, effective_addr1); /* Load 64-bit operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); /* Add signed operands and set condition code */ cc = add_signed_long (&n, n, (S64)(S8)i2); /* Store 64-bit value at operand address */ ARCH_DEP(vstore8) ( n, effective_addr1, b1, regs ); /* Update Condition Code */ regs->psw.cc = cc; #else /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ ARCH_DEP(perform_interlocked_long_storage_immediate) (inst, regs); #endif /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_immediate_long_storage) */ /*-------------------------------------------------------------------*/ /* EB6E ALSI - Add Logical with Signed Immediate [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_with_signed_immediate) { #if !defined(FEATURE_INTERLOCKED_ACCESS_FACILITY) /*810*/ BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ U32 n; /* 32-bit operand value */ int cc; /* Condition Code */ SIY(inst, regs, i2, b1, effective_addr1); /* Load 32-bit operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr1, b1, regs ); /* Add operands and set condition code */ cc = (S8)i2 < 0 ? sub_logical (&n, n, (S32)(-(S8)i2)) : add_logical (&n, n, (S32)(S8)i2); /* Store 32-bit operand at operand address */ ARCH_DEP(vstore4) ( n, effective_addr1, b1, regs ); /* Update Condition Code */ regs->psw.cc = cc; #else /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ ARCH_DEP(perform_interlocked_storage_immediate) (inst, regs); #endif /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ } /* end DEF_INST(add_logical_with_signed_immediate) */ /*-------------------------------------------------------------------*/ /* EB7E ALGSI - Add Logical with Signed Immediate Long [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_with_signed_immediate_long) { #if !defined(FEATURE_INTERLOCKED_ACCESS_FACILITY) /*810*/ BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ U64 n; /* 64-bit operand value */ int cc; /* Condition Code */ SIY(inst, regs, i2, b1, effective_addr1); /* Load 64-bit operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); /* Add operands and set condition code */ cc = (S8)i2 < 0 ? sub_logical_long (&n, n, (S64)(-(S8)i2)) : add_logical_long (&n, n, (S64)(S8)i2); /* Store 64-bit value at operand address */ ARCH_DEP(vstore8) ( n, effective_addr1, b1, regs ); /* Update Condition Code */ regs->psw.cc = cc; #else /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ ARCH_DEP(perform_interlocked_long_storage_immediate) (inst, regs); #endif /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ } /* end DEF_INST(add_logical_with_signed_immediate_long) */ /*-------------------------------------------------------------------*/ /* ECF6 CRB - Compare and Branch Register [RRS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_branch_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ RRS_B(inst, regs, r1, r2, m3, b4, effective_addr4); /* Compare signed operands and set comparison result */ cc = (S32)regs->GR_L(r1) < (S32)regs->GR_L(r2) ? 1 : (S32)regs->GR_L(r1) > (S32)regs->GR_L(r2) ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_and_branch_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* ECE4 CGRB - Compare and Branch Long Register [RRS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_branch_long_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ RRS_B(inst, regs, r1, r2, m3, b4, effective_addr4); /* Compare signed operands and set comparison result */ cc = (S64)regs->GR_G(r1) < (S64)regs->GR_G(r2) ? 1 : (S64)regs->GR_G(r1) > (S64)regs->GR_G(r2) ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_and_branch_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EC76 CRJ - Compare and Branch Relative Register [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_branch_relative_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RRIM_B(inst, regs, r1, r2, i4, m3); /* Compare signed operands and set comparison result */ cc = (S32)regs->GR_L(r1) < (S32)regs->GR_L(r2) ? 1 : (S32)regs->GR_L(r1) > (S32)regs->GR_L(r2) ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_and_branch_relative_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC64 CGRJ - Compare and Branch Relative Long Register [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_branch_relative_long_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RRIM_B(inst, regs, r1, r2, i4, m3); /* Compare signed operands and set comparison result */ cc = (S64)regs->GR_G(r1) < (S64)regs->GR_G(r2) ? 1 : (S64)regs->GR_G(r1) > (S64)regs->GR_G(r2) ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_and_branch_relative_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* B972 CRT - Compare and Trap Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_trap_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int cc; /* Comparison result */ RRF_M(inst, regs, r1, r2, m3); /* Compare signed operands and set comparison result */ cc = (S32)regs->GR_L(r1) < (S32)regs->GR_L(r2) ? 1 : (S32)regs->GR_L(r1) > (S32)regs->GR_L(r2) ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_and_trap_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B960 CGRT - Compare and Trap Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_trap_long_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int cc; /* Comparison result */ RRF_M(inst, regs, r1, r2, m3); /* Compare signed operands and set comparison result */ cc = (S64)regs->GR_G(r1) < (S64)regs->GR_G(r2) ? 1 : (S64)regs->GR_G(r1) > (S64)regs->GR_G(r2) ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_and_trap_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* E554 CHHSI - Compare Halfword Immediate Halfword Storage [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_immediate_halfword_storage) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ S16 i2; /* 16-bit immediate value */ S16 n; /* 16-bit storage value */ SIL(inst, regs, i2, b1, effective_addr1); /* Load 16-bit value from first operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr1, b1, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = n < i2 ? 1 : n > i2 ? 2 : 0; } /* end DEF_INST(compare_halfword_immediate_halfword_storage) */ /*-------------------------------------------------------------------*/ /* E558 CGHSI - Compare Halfword Immediate Long Storage [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_immediate_long_storage) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ S16 i2; /* 16-bit immediate value */ S64 n; /* 64-bit storage value */ SIL(inst, regs, i2, b1, effective_addr1); /* Load 64-bit value from first operand address */ n = (S64)ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = n < i2 ? 1 : n > i2 ? 2 : 0; } /* end DEF_INST(compare_halfword_immediate_long_storage) */ /*-------------------------------------------------------------------*/ /* E55C CHSI - Compare Halfword Immediate Storage [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_immediate_storage) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ S16 i2; /* 16-bit immediate value */ S32 n; /* 32-bit storage value */ SIL(inst, regs, i2, b1, effective_addr1); /* Load 32-bit value from first operand address */ n = (S32)ARCH_DEP(vfetch4) ( effective_addr1, b1, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = n < i2 ? 1 : n > i2 ? 2 : 0; } /* end DEF_INST(compare_halfword_immediate_storage) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E334 CGH - Compare Halfword Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S64 n; /* 64-bit operand value */ RXY(inst, regs, r1, b2, effective_addr2); /* Load rightmost 2 bytes of comparand from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < n ? 1 : (S64)regs->GR_G(r1) > n ? 2 : 0; } /* end DEF_INST(compare_halfword_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* C6x5 CHRL - Compare Halfword Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < (S16)n ? 1 : (S32)regs->GR_L(r1) > (S16)n ? 2 : 0; } /* end DEF_INST(compare_halfword_relative_long) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C6x4 CGHRL - Compare Halfword Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_relative_long_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S16)n ? 1 : (S64)regs->GR_G(r1) > (S16)n ? 2 : 0; } /* end DEF_INST(compare_halfword_relative_long_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* ECFE CIB - Compare Immediate and Branch [RIS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_immediate_and_branch) { int r1; /* Register number */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ BYTE i2; /* Immediate value */ RIS_B(inst, regs, r1, i2, m3, b4, effective_addr4); /* Compare signed operands and set comparison result */ cc = (S32)regs->GR_L(r1) < (S32)(S8)i2 ? 1 : (S32)regs->GR_L(r1) > (S32)(S8)i2 ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_immediate_and_branch) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* ECFC CGIB - Compare Immediate and Branch Long [RIS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_immediate_and_branch_long) { int r1; /* Register number */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ BYTE i2; /* Immediate value */ RIS_B(inst, regs, r1, i2, m3, b4, effective_addr4); /* Compare signed operands and set comparison result */ cc = (S64)regs->GR_G(r1) < (S64)(S8)i2 ? 1 : (S64)regs->GR_G(r1) > (S64)(S8)i2 ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_immediate_and_branch_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EC7E CIJ - Compare Immediate and Branch Relative [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_immediate_and_branch_relative) { int r1; /* Register numbers */ int m3; /* Mask bits */ BYTE i2; /* Immediate operand value */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RMII_B(inst, regs, r1, i2, m3, i4); /* Compare signed operands and set comparison result */ cc = (S32)regs->GR_L(r1) < (S32)(S8)i2 ? 1 : (S32)regs->GR_L(r1) > (S32)(S8)i2 ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_immediate_and_branch_relative) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC7C CGIJ - Compare Immediate and Branch Relative Long [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_immediate_and_branch_relative_long) { int r1; /* Register numbers */ int m3; /* Mask bits */ BYTE i2; /* Immediate operand value */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RMII_B(inst, regs, r1, i2, m3, i4); /* Compare signed operands and set comparison result */ cc = (S64)regs->GR_G(r1) < (S64)(S8)i2 ? 1 : (S64)regs->GR_G(r1) > (S64)(S8)i2 ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_immediate_and_branch_relative_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EC72 CIT - Compare Immediate and Trap [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_immediate_and_trap) { int r1; /* Register number */ int m3; /* Mask bits */ int cc; /* Comparison result */ U16 i2; /* 16-bit immediate value */ RIE_RIM(inst, regs, r1, i2, m3); /* Compare signed operands and set comparison result */ cc = (S32)regs->GR_L(r1) < (S32)(S16)i2 ? 1 : (S32)regs->GR_L(r1) > (S32)(S16)i2 ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_immediate_and_trap) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC70 CGIT - Compare Immediate and Trap Long [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_immediate_and_trap_long) { int r1; /* Register number */ int m3; /* Mask bits */ int cc; /* Comparison result */ U16 i2; /* 16-bit immediate value */ RIE_RIM(inst, regs, r1, i2, m3); /* Compare signed operands and set comparison result */ cc = (S64)regs->GR_G(r1) < (S64)(S16)i2 ? 1 : (S64)regs->GR_G(r1) > (S64)(S16)i2 ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_immediate_and_trap_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* ECF7 CLRB - Compare Logical and Branch Register [RRS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_branch_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ RRS_B(inst, regs, r1, r2, m3, b4, effective_addr4); /* Compare unsigned operands and set comparison result */ cc = regs->GR_L(r1) < regs->GR_L(r2) ? 1 : regs->GR_L(r1) > regs->GR_L(r2) ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_and_branch_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* ECE5 CLGRB - Compare Logical and Branch Long Register [RRS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_branch_long_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ RRS_B(inst, regs, r1, r2, m3, b4, effective_addr4); /* Compare unsigned operands and set comparison result */ cc = regs->GR_G(r1) < regs->GR_G(r2) ? 1 : regs->GR_G(r1) > regs->GR_G(r2) ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_and_branch_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EC77 CLRJ - Compare Logical and Branch Relative Register [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_branch_relative_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RRIM_B(inst, regs, r1, r2, i4, m3); /* Compare unsigned operands and set comparison result */ cc = regs->GR_L(r1) < regs->GR_L(r2) ? 1 : regs->GR_L(r1) > regs->GR_L(r2) ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_and_branch_relative_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC65 CLGRJ - Compare Logical and Branch Relative Long Reg [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_branch_relative_long_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RRIM_B(inst, regs, r1, r2, i4, m3); /* Compare unsigned operands and set comparison result */ cc = regs->GR_G(r1) < regs->GR_G(r2) ? 1 : regs->GR_G(r1) > regs->GR_G(r2) ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_and_branch_relative_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* B973 CLRT - Compare Logical and Trap Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_trap_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int cc; /* Comparison result */ RRF_M(inst, regs, r1, r2, m3); /* Compare unsigned operands and set comparison result */ cc = regs->GR_L(r1) < regs->GR_L(r2) ? 1 : regs->GR_L(r1) > regs->GR_L(r2) ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_logical_and_trap_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B961 CLGRT - Compare Logical and Trap Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_trap_long_register) { int r1, r2; /* Register numbers */ int m3; /* Mask bits */ int cc; /* Comparison result */ RRF_M(inst, regs, r1, r2, m3); /* Compare unsigned operands and set comparison result */ cc = regs->GR_G(r1) < regs->GR_G(r2) ? 1 : regs->GR_G(r1) > regs->GR_G(r2) ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_logical_and_trap_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* ECFF CLIB - Compare Logical Immediate and Branch [RIS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_and_branch) { int r1; /* Register number */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ BYTE i2; /* Immediate value */ RIS_B(inst, regs, r1, i2, m3, b4, effective_addr4); /* Compare unsigned operands and set comparison result */ cc = regs->GR_L(r1) < i2 ? 1 : regs->GR_L(r1) > i2 ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_immediate_and_branch) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* ECFD CLGIB - Compare Logical Immediate and Branch Long [RIS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_and_branch_long) { int r1; /* Register number */ int m3; /* Mask bits */ int b4; /* Base of effective addr */ VADR effective_addr4; /* Effective address */ int cc; /* Comparison result */ BYTE i2; /* Immediate value */ RIS_B(inst, regs, r1, i2, m3, b4, effective_addr4); /* Compare unsigned operands and set comparison result */ cc = regs->GR_G(r1) < i2 ? 1 : regs->GR_G(r1) > i2 ? 2 : 0; /* Branch to operand address if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_BRANCH(regs, effective_addr4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_immediate_and_branch_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EC7F CLIJ - Compare Logical Immediate and Branch Relative [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_and_branch_relative) { int r1; /* Register number */ int m3; /* Mask bits */ BYTE i2; /* Immediate operand value */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RMII_B(inst, regs, r1, i2, m3, i4); /* Compare unsigned operands and set comparison result */ cc = regs->GR_L(r1) < i2 ? 1 : regs->GR_L(r1) > i2 ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_immediate_and_branch_relative) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC7D CLGIJ - Compare Logical Immed and Branch Relative Long [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_and_branch_relative_long) { int r1; /* Register number */ int m3; /* Mask bits */ BYTE i2; /* Immediate operand value */ S16 i4; /* 16-bit immediate offset */ int cc; /* Comparison result */ RIE_RMII_B(inst, regs, r1, i2, m3, i4); /* Compare unsigned operands and set comparison result */ cc = regs->GR_G(r1) < i2 ? 1 : regs->GR_G(r1) > i2 ? 2 : 0; /* Branch to immediate offset if m3 mask bit is set */ if ((0x8 >> cc) & m3) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i4, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(compare_logical_immediate_and_branch_relative_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EC73 CLFIT - Compare Logical Immediate and Trap Fullword [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_and_trap_fullword) { int r1; /* Register number */ int m3; /* Mask bits */ int cc; /* Comparison result */ U16 i2; /* 16-bit immediate value */ RIE_RIM(inst, regs, r1, i2, m3); /* Compare unsigned operands and set comparison result */ cc = regs->GR_L(r1) < i2 ? 1 : regs->GR_L(r1) > i2 ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_logical_immediate_and_trap_fullword) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC71 CLGIT - Compare Logical Immediate and Trap Long [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_and_trap_long) { int r1; /* Register number */ int m3; /* Mask bits */ int cc; /* Comparison result */ U16 i2; /* 16-bit immediate value */ RIE_RIM(inst, regs, r1, i2, m3); /* Compare unsigned operands and set comparison result */ cc = regs->GR_G(r1) < i2 ? 1 : regs->GR_G(r1) > i2 ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_logical_immediate_and_trap_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* E55D CLFHSI - Compare Logical Immediate Fullword Storage [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_fullword_storage) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ U16 i2; /* 16-bit immediate value */ U32 n; /* 32-bit storage value */ SIL(inst, regs, i2, b1, effective_addr1); /* Load 32-bit value from first operand address */ n = ARCH_DEP(vfetch4) ( effective_addr1, b1, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = n < i2 ? 1 : n > i2 ? 2 : 0; } /* end DEF_INST(compare_logical_immediate_fullword_storage) */ /*-------------------------------------------------------------------*/ /* E555 CLHHSI - Compare Logical Immediate Halfword Storage [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_halfword_storage) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ U16 i2; /* 16-bit immediate value */ U16 n; /* 16-bit storage value */ SIL(inst, regs, i2, b1, effective_addr1); /* Load 16-bit value from first operand address */ n = ARCH_DEP(vfetch2) ( effective_addr1, b1, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = n < i2 ? 1 : n > i2 ? 2 : 0; } /* end DEF_INST(compare_logical_immediate_halfword_storage) */ /*-------------------------------------------------------------------*/ /* E559 CLGHSI - Compare Logical Immediate Long Storage [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_long_storage) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ U16 i2; /* 16-bit immediate value */ U64 n; /* 64-bit storage value */ SIL(inst, regs, i2, b1, effective_addr1); /* Load 64-bit value from first operand address */ n = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = n < i2 ? 1 : n > i2 ? 2 : 0; } /* end DEF_INST(compare_logical_immediate_long_storage) */ /*-------------------------------------------------------------------*/ /* C6xF CLRL - Compare Logical Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U32 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch4) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = regs->GR_L(r1) < n ? 1 : regs->GR_L(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_relative_long) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C6xA CLGRL - Compare Logical Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_relative_long_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U64 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on doubleword boundary */ DW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch8) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < n ? 1 : regs->GR_G(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_relative_long_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C6xE CLGFRL - Compare Logical Relative Long Long Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_relative_long_long_fullword) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U32 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch4) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < n ? 1 : regs->GR_G(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_relative_long_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* C6x7 CLHRL - Compare Logical Halfword Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_relative_long_halfword) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = regs->GR_L(r1) < n ? 1 : regs->GR_L(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_relative_long_halfword) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C6x6 CLGHRL - Compare Logical Halfword Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_relative_long_long_halfword) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < n ? 1 : regs->GR_G(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_relative_long_long_halfword) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* C6xD CRL - Compare Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U32 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch4) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < (S32)n ? 1 : (S32)regs->GR_L(r1) > (S32)n ? 2 : 0; } /* end DEF_INST(compare_relative_long) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C6x8 CGRL - Compare Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_relative_long_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U64 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on doubleword boundary */ DW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch8) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S64)n ? 1 : (S64)regs->GR_G(r1) > (S64)n ? 2 : 0; } /* end DEF_INST(compare_relative_long_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C6xC CGFRL - Compare Relative Long Long Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_relative_long_long_fullword) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U32 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch4) ( addr2, USE_INST_SPACE, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S32)n ? 1 : (S64)regs->GR_G(r1) > (S32)n ? 2 : 0; } /* end DEF_INST(compare_relative_long_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB4C ECAG - Extract Cache Attribute [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_cache_attribute) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int ai, li, ti; /* Operand address subfields */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Address bit 63 contains the Type Indication (TI) */ ti = effective_addr2 & 0x1; /* Address bits 60-62 contain the Level Indication (LI) */ li = (effective_addr2 >> 1) & 0x7; /* Address bits 56-59 contain the Attribute Indication (AI) */ ai = (effective_addr2 >> 4) & 0xF; //logmsg ("ECAG ai=%d li=%d ti=%d\n", ai, li, ti); /* If reserved bits 40-55 are not zero then set r1 to all ones */ if ((effective_addr2 & 0xFFFF00) != 0) { regs->GR(r1) = 0xFFFFFFFFFFFFFFFFULL; return; } /* If AI=0 (topology summary) is requested, set register r1 to indicate that cache level 0 is private to this CPU and that cache levels 1-7 are not implemented */ if (ai == 0) { regs->GR_H(r1) = 0x04000000; regs->GR_L(r1) = 0x00000000; return; } /* If cache level is not 0, set register r1 to all ones which indicates that the requested cache level is not implemented */ if (li > 0) { regs->GR(r1) = 0xFFFFFFFFFFFFFFFFULL; return; } /* If AI=1 (cache line size) is requested for cache level 0 set register r1 to indicate a fictitious cache line size */ if (ai == 1 && li == 0) { regs->GR(r1) = 256; return; } /* If AI=2 (total cache size) is requested for cache level 0 set register r1 to indicate a fictitious total cache size */ if (ai == 2 && li == 0) { regs->GR(r1) = 256 * 2048; return; } /* Set register r1 to all ones indicating that the requested attribute indication is reserved */ regs->GR(r1) = 0xFFFFFFFFFFFFFFFFULL; } /* end DEF_INST(extract_cache_attribute) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* E375 LAEY - Load Address Extended (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_address_extended_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY0(inst, regs, r1, b2, effective_addr2); /* Load operand address into register */ SET_GR_A(r1, regs,effective_addr2); /* Load corresponding value into access register */ if ( PRIMARY_SPACE_MODE(&(regs->psw)) ) regs->AR(r1) = ALET_PRIMARY; else if ( SECONDARY_SPACE_MODE(&(regs->psw)) ) regs->AR(r1) = ALET_SECONDARY; else if ( HOME_SPACE_MODE(&(regs->psw)) ) regs->AR(r1) = ALET_HOME; else /* ACCESS_REGISTER_MODE(&(regs->psw)) */ regs->AR(r1) = (b2 == 0) ? 0 : regs->AR(b2); SET_AEA_AR(regs, r1); } /* end DEF_INST(load_address_extended_y) */ #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E332 LTGF - Load and Test Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_long_fullword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* Second operand value */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from sign-extended second operand */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); regs->GR_G(r1) = (S64)(S32)n; /* Set condition code according to value loaded */ regs->psw.cc = (S64)regs->GR_G(r1) < 0 ? 1 : (S64)regs->GR_G(r1) > 0 ? 2 : 0; } /* end DEF_INST(load_and_test_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* C4x5 LHRL - Load Halfword Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_halfword_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Sign-extend operand value and load into R1 register */ regs->GR_L(r1) = (S32)(S16)n; } /* end DEF_INST(load_halfword_relative_long) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C4x4 LGHRL - Load Halfword Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_halfword_relative_long_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Sign-extend operand value and load into R1 register */ regs->GR_G(r1) = (S64)(S16)n; } /* end DEF_INST(load_halfword_relative_long_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* C4x2 LLHRL - Load Logical Halfword Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_halfword_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Zero-extend operand value and load into R1 register */ regs->GR_L(r1) = n; } /* end DEF_INST(load_logical_halfword_relative_long) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C4x6 LLGHRL - Load Logical Halfword Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_halfword_relative_long_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U16 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch2) ( addr2, USE_INST_SPACE, regs ); /* Zero-extend operand value and load into R1 register */ regs->GR_G(r1) = n; } /* end DEF_INST(load_logical_halfword_relative_long_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C4xE LLGFRL - Load Logical Relative Long Long Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_relative_long_long_fullword) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U32 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch4) ( addr2, USE_INST_SPACE, regs ); /* Zero-extend operand value and load into R1 register */ regs->GR_G(r1) = n; } /* end DEF_INST(load_logical_relative_long_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* C4xD LRL - Load Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U32 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch4) ( addr2, USE_INST_SPACE, regs ); /* Load operand value into R1 register */ regs->GR_L(r1) = n; } /* end DEF_INST(load_relative_long) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C4x8 LGRL - Load Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_relative_long_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U64 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on doubleword boundary */ DW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch8) ( addr2, USE_INST_SPACE, regs ); /* Load operand value into R1 register */ regs->GR_G(r1) = n; } /* end DEF_INST(load_relative_long_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C4xC LGFRL - Load Relative Long Long Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_relative_long_long_fullword) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ U32 n; /* Relative operand value */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Load relative operand from instruction address space */ n = ARCH_DEP(vfetch4) ( addr2, USE_INST_SPACE, regs ); /* Sign-extend operand value and load into R1 register */ regs->GR_G(r1) = (S64)(S32)n; } /* end DEF_INST(load_relative_long_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* E54C MVHI - Move Fullword from Halfword Immediate [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(move_fullword_from_halfword_immediate) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ S16 i2; /* 16-bit immediate value */ S32 n; /* Sign-extended value of i2 */ SIL(inst, regs, i2, b1, effective_addr1); /* Sign-extend 16-bit immediate value to 32 bits */ n = i2; /* Store 4-byte value at operand address */ ARCH_DEP(vstore4) ( n, effective_addr1, b1, regs ); } /* end DEF_INST(move_fullword_from_halfword_immediate) */ /*-------------------------------------------------------------------*/ /* E544 MVHHI - Move Halfword from Halfword Immediate [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(move_halfword_from_halfword_immediate) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ S16 i2; /* 16-bit immediate value */ SIL(inst, regs, i2, b1, effective_addr1); /* Store 16-bit immediate value at operand address */ ARCH_DEP(vstore2) ( i2, effective_addr1, b1, regs ); } /* end DEF_INST(move_halfword_from_halfword_immediate) */ /*-------------------------------------------------------------------*/ /* E548 MVGHI - Move Long from Halfword Immediate [SIL] */ /*-------------------------------------------------------------------*/ DEF_INST(move_long_from_halfword_immediate) { int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ S16 i2; /* 16-bit immediate value */ S64 n; /* Sign-extended value of i2 */ SIL(inst, regs, i2, b1, effective_addr1); /* Sign-extend 16-bit immediate value to 64 bits */ n = i2; /* Store 8-byte value at operand address */ ARCH_DEP(vstore8) ( n, effective_addr1, b1, regs ); } /* end DEF_INST(move_long_from_halfword_immediate) */ /*-------------------------------------------------------------------*/ /* E37C MHY - Multiply Halfword (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_halfword_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load 2 bytes from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Multiply R1 register by n, ignore leftmost 32 bits of result, and place rightmost 32 bits in R1 register */ mul_signed ((U32 *)&n, &(regs->GR_L(r1)), regs->GR_L(r1), n); } /* end DEF_INST(multiply_halfword_y) */ /*-------------------------------------------------------------------*/ /* C2x1 MSFI - Multiply Single Immediate Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_immediate_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL(inst, regs, r1, opcd, i2); /* Multiply signed operands ignoring overflow */ regs->GR_L(r1) = (S32)regs->GR_L(r1) * (S32)i2; } /* end DEF_INST(multiply_single_immediate_fullword) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C2x0 MSGFI - Multiply Single Immediate Long Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_immediate_long_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL(inst, regs, r1, opcd, i2); /* Multiply signed operands ignoring overflow */ regs->GR_G(r1) = (S64)regs->GR_G(r1) * (S32)i2; } /* end DEF_INST(multiply_single_immediate_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* E35C MFY - Multiply (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Multiply r1+1 by n and place result in r1 and r1+1 */ mul_signed (&(regs->GR_L(r1)), &(regs->GR_L(r1+1)), regs->GR_L(r1+1), n); } /* end DEF_INST(multiply_y) */ /*-------------------------------------------------------------------*/ /* E336 PFD - Prefetch Data [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(prefetch_data) { int m1; /* Mask value */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, m1, b2, effective_addr2); /* The Prefetch Data instruction acts as a no-op */ } /* end DEF_INST(prefetch_data) */ /*-------------------------------------------------------------------*/ /* C6x2 PFDRL - Prefetch Data Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(prefetch_data_relative_long) { int m1; /* Mask value */ VADR addr2; /* Relative operand address */ RIL_A(inst, regs, m1, addr2); /* The Prefetch Data instruction acts as a no-op */ } /* end DEF_INST(prefetch_data_relative_long) */ #endif /*defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY)*/ #if defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY) \ || defined(FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY) /*912*/ \ || defined(FEATURE_HIGH_WORD_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* Rotate Then Perform Operation On Selected Bits Long Register */ /* Subroutine is called by RNSBG,RISBG,ROSBG,RXSBG instructions */ /* and also by the RISBHG,RISBLG instructions */ /*810*/ /* and by the RISBGN instruction */ /*912*/ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_xxx_selected_bits_long_reg) { int r1, r2; /* Register numbers */ int start, end; /* Start and end bit number */ U64 mask, rota, resu; /* 64-bit work areas */ int n; /* Number of bits to shift */ int t_bit = 0; /* Test-results indicator */ int z_bit = 0; /* Zero-remaining indicator */ int i; /* Loop counter */ BYTE i3, i4, i5; /* Immediate values */ BYTE opcode; /* 2nd byte of opcode */ RIE_RRIII(inst, regs, r1, r2, i3, i4, i5); /* Extract second byte of instruction opcode */ opcode = inst[5]; /* Extract parameters from immediate fields */ start = i3 & 0x3F; end = i4 & 0x3F; n = i5 & 0x3F; if ((opcode & 0xFC) == 0x50 /*Low*/ ) { /*810*/ start |= 0x20; /*810*/ end |= 0x20; /*810*/ } /*810*/ if ((opcode & 0xFC) == 0x5C /*High*/ ) { /*810*/ start &= 0x1F; /*810*/ end &= 0x1F; /*810*/ } /*810*/ if ((opcode & 0x03) == 0x01 /*Insert*/ ) /*810*/ z_bit = i4 >> 7; else t_bit = i3 >> 7; /* Copy value from R2 register and rotate left n bits */ rota = (regs->GR_G(r2) << n) | ((n == 0) ? 0 : (regs->GR_G(r2) >> (64 - n))); /* Construct mask for selected bits */ for (i=0, mask=0; i < 64; i++) { mask <<= 1; if (start <= end) { if (i >= start && i <= end) mask |= 1; } else { if (i <= end || i >= start) mask |= 1; } } /* end for(i) */ /* Isolate selected bits of rotated second operand */ rota &= mask; /* Isolate selected bits of first operand */ resu = regs->GR_G(r1) & mask; /* Perform operation on selected bits */ switch (opcode) { case 0x54: /* And */ resu &= rota; break; case 0x51: /* Insert Low */ /*810*/ case 0x55: /* Insert */ case 0x5D: /* Insert High */ /*810*/ resu = rota; break; case 0x56: /* Or */ resu |= rota; break; case 0x57: /* Exclusive Or */ resu ^= rota; break; } /* end switch(opcode) */ /* And/Or/Xor set condition code according to result bits*/ /*810*/ if ((opcode & 0x03) != 0x01 /*Insert*/ ) /*810*/ regs->psw.cc = (resu == 0) ? 0 : 1; /* Insert result bits into R1 register */ if (t_bit == 0) { if (z_bit == 0) regs->GR_G(r1) = (regs->GR_G(r1) & ~mask) | resu; else if ((opcode & 0xFC) == 0x50 /*Low*/ ) /*810*/ regs->GR_L(r1) = (U32)resu; /*810*/ else if ((opcode & 0xFC) == 0x5C /*High*/ ) /*810*/ regs->GR_H(r1) = (U32)(resu >> 32); /*810*/ else regs->GR_G(r1) = resu; } /* end if(t_bit==0) */ /* For RISBG set condition code according to signed result */ if (opcode == 0x55) regs->psw.cc = (S64)regs->GR_G(r1) < 0 ? 1 : (S64)regs->GR_G(r1) > 0 ? 2 : 0; /* For RISBHG,RISBLG the condition code remains unchanged*/ /*810*/ /* For RISBGN the condition code remains unchanged */ /*912*/ } /* end DEF_INST(rotate_then_xxx_selected_bits_long_reg) */ #endif /*defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY)*/ /*|| defined(FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY)*/ /*912*/ /*|| defined(FEATURE_HIGH_WORD_FACILITY)*/ /*810*/ #if defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY) #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC54 RNSBG - Rotate Then And Selected Bits [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_and_selected_bits_long_reg) { ARCH_DEP(rotate_then_xxx_selected_bits_long_reg) (inst, regs); } /* end DEF_INST(rotate_then_and_selected_bits_long_reg) */ /*-------------------------------------------------------------------*/ /* EC55 RISBG - Rotate Then Insert Selected Bits [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_insert_selected_bits_long_reg) { ARCH_DEP(rotate_then_xxx_selected_bits_long_reg) (inst, regs); } /* end DEF_INST(rotate_then_insert_selected_bits_long_reg) */ /*-------------------------------------------------------------------*/ /* EC56 ROSBG - Rotate Then Or Selected Bits [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_or_selected_bits_long_reg) { ARCH_DEP(rotate_then_xxx_selected_bits_long_reg) (inst, regs); } /* end DEF_INST(rotate_then_or_selected_bits_long_reg) */ /*-------------------------------------------------------------------*/ /* EC57 RXSBG - Rotate Then Exclusive Or Selected Bits [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_exclusive_or_selected_bits_long_reg) { ARCH_DEP(rotate_then_xxx_selected_bits_long_reg) (inst, regs); } /* end DEF_INST(rotate_then_exclusive_or_selected_bits_long_reg) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* C4x7 STHRL - Store Halfword Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(store_halfword_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ RIL_A(inst, regs, r1, addr2); /* Store low 2 bytes of R1 register in instruction address space */ ARCH_DEP(vstore2) ( regs->GR_LHL(r1), addr2, USE_INST_SPACE, regs ); } /* end DEF_INST(store_halfword_relative_long) */ /*-------------------------------------------------------------------*/ /* C4xF STRL - Store Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(store_relative_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on fullword boundary */ FW_CHECK(addr2, regs); /* Store low 4 bytes of R1 register in instruction address space */ ARCH_DEP(vstore4) ( regs->GR_L(r1), addr2, USE_INST_SPACE, regs ); } /* end DEF_INST(store_relative_long) */ /*-------------------------------------------------------------------*/ /* C4xB STGRL - Store Relative Long Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(store_relative_long_long) { int r1; /* Register number */ VADR addr2; /* Relative operand address */ RIL_A(inst, regs, r1, addr2); /* Program check if operand not on doubleword boundary */ DW_CHECK(addr2, regs); /* Store R1 register in instruction address space */ ARCH_DEP(vstore8) ( regs->GR_G(r1), addr2, USE_INST_SPACE, regs ); } /* end DEF_INST(store_relative_long_long) */ #endif /*defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY)*/ #if defined(FEATURE_HIGH_WORD_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B9C8 AHHHR - Add High High High Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_high_high_high_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_H(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_high_high_high_register) */ /*-------------------------------------------------------------------*/ /* B9D8 AHHLR - Add High High Low Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_high_high_low_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_L(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_high_high_low_register) */ /*-------------------------------------------------------------------*/ /* CCx8 AIH - Add High Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(add_high_immediate) /*810*/ { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL(inst, regs, r1, opcd, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_H(r1)), regs->GR_H(r1), (S32)i2); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_high_immediate) */ /*-------------------------------------------------------------------*/ /* B9CA ALHHHR - Add Logical High High High Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_high_high_high_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Add signed operands and set condition code */ regs->psw.cc = add_logical (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_H(r3)); } /* end DEF_INST(add_logical_high_high_high_register) */ /*-------------------------------------------------------------------*/ /* B9DA ALHHLR - Add Logical High High Low Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_high_high_low_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Add signed operands and set condition code */ regs->psw.cc = add_logical (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_L(r3)); } /* end DEF_INST(add_logical_high_high_low_register) */ /*-------------------------------------------------------------------*/ /* CCxA ALSIH - Add Logical with Signed Immediate High [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_with_signed_immediate_high) /*810*/ { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Add operands and set condition code */ regs->psw.cc = (S32)i2 < 0 ? sub_logical (&(regs->GR_H(r1)), regs->GR_H(r1), -(S32)i2) : add_logical (&(regs->GR_H(r1)), regs->GR_H(r1), i2); } /* end DEF_INST(add_logical_with_signed_immediate_high) */ /*-------------------------------------------------------------------*/ /* CCxB ALSIHN - Add Logical with Signed Immediate High No CC [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_with_signed_immediate_high_n) /*810*/ { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Add operands without setting condition code */ if ((S32)i2 < 0) { sub_logical (&(regs->GR_H(r1)), regs->GR_H(r1), -(S32)i2); } else { add_logical (&(regs->GR_H(r1)), regs->GR_H(r1), i2); } } /* end DEF_INST(add_logical_with_signed_immediate_high_n) */ /*-------------------------------------------------------------------*/ /* CCx6 BRCTH - Branch Relative on Count High [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_count_high) /*810*/ { int r1; /* Register number */ int opcd; /* Opcode */ S32 i2; /* 32-bit operand value */ RIL_B(inst, regs, r1, opcd, i2); /* Subtract 1 from the R1 operand and branch if non-zero */ if ( --(regs->GR_H(r1)) ) SUCCESSFUL_RELATIVE_BRANCH_LONG(regs, 2LL*i2); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(branch_relative_on_count_high) */ /*-------------------------------------------------------------------*/ /* B9CD CHHR - Compare High High Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_high_high_register) /*810*/ { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_H(r1) < (S32)regs->GR_H(r2) ? 1 : (S32)regs->GR_H(r1) > (S32)regs->GR_H(r2) ? 2 : 0; } /* DEF_INST(compare_high_high_register) */ /*-------------------------------------------------------------------*/ /* B9DD CHLR - Compare High Low Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_high_low_register) /*810*/ { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_H(r1) < (S32)regs->GR_L(r2) ? 1 : (S32)regs->GR_H(r1) > (S32)regs->GR_L(r2) ? 2 : 0; } /* DEF_INST(compare_high_low_register) */ /*-------------------------------------------------------------------*/ /* E3CD CHF - Compare High Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_high_fullword) /*810*/ { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_H(r1) < (S32)n ? 1 : (S32)regs->GR_H(r1) > (S32)n ? 2 : 0; } /* DEF_INST(compare_high_fullword) */ /*-------------------------------------------------------------------*/ /* CCxD CIH - Compare High Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_high_immediate) /*810*/ { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_H(r1) < (S32)i2 ? 1 : (S32)regs->GR_H(r1) > (S32)i2 ? 2 : 0; } /* end DEF_INST(compare_high_immediate) */ /*-------------------------------------------------------------------*/ /* B9CF CLHHR - Compare Logical High High Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_high_high_register) /*810*/ { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_H(r1) < regs->GR_H(r2) ? 1 : regs->GR_H(r1) > regs->GR_H(r2) ? 2 : 0; } /* end DEF_INST(compare_logical_high_high_register) */ /*-------------------------------------------------------------------*/ /* B9DF CLHLR - Compare Logical High Low Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_high_low_register) /*810*/ { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_H(r1) < regs->GR_L(r2) ? 1 : regs->GR_H(r1) > regs->GR_L(r2) ? 2 : 0; } /* end DEF_INST(compare_logical_high_low_register) */ /*-------------------------------------------------------------------*/ /* E3CF CLHF - Compare Logical High Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_high_fullword) /*810*/ { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_H(r1) < n ? 1 : regs->GR_H(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_high_fullword) */ /*-------------------------------------------------------------------*/ /* CCxF CLIH - Compare Logical High Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_high_immediate) /*810*/ { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_H(r1) < i2 ? 1 : regs->GR_H(r1) > i2 ? 2 : 0; } /* end DEF_INST(compare_logical_high_immediate) */ /*-------------------------------------------------------------------*/ /* E3C0 LBH - Load Byte High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_byte_high) /*810*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load sign-extended byte from operand address */ regs->GR_H(r1) = (S8)ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_byte_high) */ /*-------------------------------------------------------------------*/ /* E3CA LFH - Load Fullword High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fullword_high) /*810*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register bits 0-31 from second operand */ regs->GR_H(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_fullword_high) */ /*-------------------------------------------------------------------*/ /* E3C4 LHH - Load Halfword High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_halfword_high) /*810*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load sign-extended halfword from operand address */ regs->GR_H(r1) = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_halfword_high) */ /*-------------------------------------------------------------------*/ /* E3C2 LLCH - Load Logical Character High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_character_high) /*810*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load byte into R1 register bits 24-31 and clear bits 0-23 */ regs->GR_H(r1) = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_logical_character_high) */ /*-------------------------------------------------------------------*/ /* E3C6 LLHH - Load Logical Halfword High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_halfword_high) /*810*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load halfword into R1 register bits 16-31 and clear bits 0-15 */ regs->GR_H(r1) = ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_logical_halfword_high) */ /*-------------------------------------------------------------------*/ /* EC5D RISBHG - Rotate Then Insert Selected Bits High [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_insert_selected_bits_high_long_reg) /*810*/ { ARCH_DEP(rotate_then_xxx_selected_bits_long_reg) (inst, regs); } /* end DEF_INST(rotate_then_insert_selected_bits_high_long_reg) */ /*-------------------------------------------------------------------*/ /* EC51 RISBLG - Rotate Then Insert Selected Bits Low [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_insert_selected_bits_low_long_reg) /*810*/ { ARCH_DEP(rotate_then_xxx_selected_bits_long_reg) (inst, regs); } /* end DEF_INST(rotate_then_insert_selected_bits_low_long_reg) */ /*-------------------------------------------------------------------*/ /* E3C3 STCH - Store Character High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_character_high) /*810*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store bits 24-31 of R1 register at operand address */ ARCH_DEP(vstoreb) ( regs->GR_HHLCL(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store_character_high) */ /*-------------------------------------------------------------------*/ /* E3CB STFH - Store Fullword High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_fullword_high) /*810*/ { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store bits 0-31 of R1 register at operand address */ ARCH_DEP(vstore4) ( regs->GR_H(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store_fullword_high) */ /*-------------------------------------------------------------------*/ /* E3C7 STHH - Store Halfword High [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_halfword_high) /*810*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store bits 16-31 of R1 register at operand address */ ARCH_DEP(vstore2) ( regs->GR_HHL(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store_halfword_high) */ /*-------------------------------------------------------------------*/ /* B9C9 SHHHR - Subtract High High High Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_high_high_high_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_H(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_high_high_high_register) */ /*-------------------------------------------------------------------*/ /* B9D9 SHHLR - Subtract High High Low Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_high_high_low_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_L(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_high_high_low_register) */ /*-------------------------------------------------------------------*/ /* B9CB SLHHHR - Subtract Logical High High High Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_high_high_high_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_H(r3)); } /* end DEF_INST(subtract_logical_high_high_high_register) */ /*-------------------------------------------------------------------*/ /* B9DB SLHHLR - Subtract Logical High High Low Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_high_high_low_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical (&(regs->GR_H(r1)), regs->GR_H(r2), regs->GR_L(r3)); } /* end DEF_INST(subtract_logical_high_high_low_register) */ #endif /*defined(FEATURE_HIGH_WORD_FACILITY)*/ /*810*/ #if defined(FEATURE_INTERLOCKED_ACCESS_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* Load and Perform Interlocked Access Operation */ /* Subroutine called by LAA,LAAL,LAN,LAX,LAO instructions */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_perform_interlocked_access) /*810*/ { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR addr2; /* Effective address */ BYTE *m2; /* Mainstor address */ U32 v2, v3; /* Operand values */ U32 result; /* Result value */ U32 old, new; /* Values for cmpxchg4 */ int cc; /* Condition code */ int rc; /* Return code */ BYTE opcode; /* 2nd byte of opcode */ RSY(inst, regs, r1, r3, b2, addr2); /* Extract second byte of instruction opcode */ opcode = inst[5]; /* Obtain third operand value from R3 register */ v3 = regs->GR_L(r3); /* Get mainstor address of storage operand */ m2 = MADDRL (addr2, 4, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); do { /* Load storage operand value from operand address */ v2 = ARCH_DEP(vfetch4) ( addr2, b2, regs ); switch (opcode) { case 0xF4: /* Load and And */ /* AND operand values and set condition code */ result = v2 & v3; cc = result ? 1 : 0; break; case 0xF6: /* Load and Or */ /* OR operand values and set condition code */ result = v2 | v3; cc = result ? 1 : 0; break; case 0xF7: /* Load and Exclusive Or */ /* XOR operand values and set condition code */ result = v2 ^ v3; cc = result ? 1 : 0; break; case 0xF8: /* Load and Add */ /* Add signed operands and set condition code */ cc = add_signed (&result, v2, v3); break; case 0xFA: /* Load and Add Logical */ /* Add unsigned operands and set condition code */ cc = add_logical (&result, v2, v3); break; default: /* To prevent compiler warnings */ result = 0; cc = 0; } /* end switch(opcode) */ /* Interlocked exchange to storage location */ old = CSWAP32(v2); new = CSWAP32(result); rc = cmpxchg4 (&old, new, m2); } while (rc != 0); /* Load original storage operand value into R1 register */ regs->GR_L(r1) = v2; /* Set condition code in PSW */ regs->psw.cc = cc; } /* end DEF_INST(load_and_perform_interlocked_access) */ /*-------------------------------------------------------------------*/ /* Load and Perform Interlocked Access Operation Long */ /* Subroutine called by LAAG,LAALG,LANG,LAXG,LAOG instructions */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_perform_interlocked_access_long) /*810*/ { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR addr2; /* Effective address */ BYTE *m2; /* Mainstor address */ U64 v2, v3; /* Operand values */ U64 result; /* Result value */ U64 old, new; /* Values for cmpxchg4 */ int cc; /* Condition code */ int rc; /* Return code */ BYTE opcode; /* 2nd byte of opcode */ RSY(inst, regs, r1, r3, b2, addr2); /* Extract second byte of instruction opcode */ opcode = inst[5]; /* Obtain third operand value from R3 register */ v3 = regs->GR_G(r3); /* Get mainstor address of storage operand */ m2 = MADDRL (addr2, 8, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); do { /* Load storage operand value from operand address */ v2 = ARCH_DEP(vfetch8) ( addr2, b2, regs ); switch (opcode) { case 0xE4: /* Load and And Long */ /* AND operand values and set condition code */ result = v2 & v3; cc = result ? 1 : 0; break; case 0xE6: /* Load and Or Long */ /* OR operand values and set condition code */ result = v2 | v3; cc = result ? 1 : 0; break; case 0xE7: /* Load and Exclusive Or Long */ /* XOR operand values and set condition code */ result = v2 ^ v3; cc = result ? 1 : 0; break; case 0xE8: /* Load and Add Long */ /* Add signed operands and set condition code */ cc = add_signed_long (&result, v2, v3); break; case 0xEA: /* Load and Add Logical Long */ /* Add unsigned operands and set condition code */ cc = add_logical_long (&result, v2, v3); break; default: /* To prevent compiler warnings */ result = 0; cc = 0; } /* end switch(opcode) */ /* Interlocked exchange to storage location */ old = CSWAP64(v2); new = CSWAP64(result); rc = cmpxchg8 (&old, new, m2); } while (rc != 0); /* Load original storage operand value into R1 register */ regs->GR_G(r1) = v2; /* Set condition code in PSW */ regs->psw.cc = cc; } /* end DEF_INST(load_and_perform_interlocked_access_long) */ /*-------------------------------------------------------------------*/ /* EBF8 LAA - Load and Add [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_add) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access) (inst, regs); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(load_and_add) */ /*-------------------------------------------------------------------*/ /* EBE8 LAAG - Load and Add Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_add_long) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access_long) (inst, regs); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(load_and_add_long) */ /*-------------------------------------------------------------------*/ /* EBFA LAAL - Load and Add Logical [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_add_logical) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access) (inst, regs); } /* end DEF_INST(load_and_add_logical) */ /*-------------------------------------------------------------------*/ /* EBEA LAALG - Load and Add Logical Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_add_logical_long) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access_long) (inst, regs); } /* end DEF_INST(load_and_add_logical_long) */ /*-------------------------------------------------------------------*/ /* EBF4 LAN - Load and And [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_and) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access) (inst, regs); } /* end DEF_INST(load_and_and) */ /*-------------------------------------------------------------------*/ /* EBE4 LANG - Load and And Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_and_long) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access_long) (inst, regs); } /* end DEF_INST(load_and_and_long) */ /*-------------------------------------------------------------------*/ /* EBF7 LAX - Load and Exclusive Or [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_exclusive_or) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access) (inst, regs); } /* end DEF_INST(load_and_exclusive_or) */ /*-------------------------------------------------------------------*/ /* EBE7 LAXG - Load and Exclusive Or Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_exclusive_or_long) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access_long) (inst, regs); } /* end DEF_INST(load_and_exclusive_or_long) */ /*-------------------------------------------------------------------*/ /* EBF6 LAO - Load and Or [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_or) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access) (inst, regs); } /* end DEF_INST(load_and_or) */ /*-------------------------------------------------------------------*/ /* EBE6 LAOG - Load and Or Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_or_long) /*810*/ { ARCH_DEP(load_and_perform_interlocked_access_long) (inst, regs); } /* end DEF_INST(load_and_or_long) */ /*-------------------------------------------------------------------*/ /* C8x4 LPD - Load Pair Disjoint [SSF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_pair_disjoint) /*810*/ { int r3; /* Register number */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ U32 v1, v2; /* Operand values */ U32 w1, w2; /* Refetched values */ SSF(inst, regs, b1, effective_addr1, b2, effective_addr2, r3); ODD_CHECK(r3, regs); /* Fetch the values of the storage operands */ v1 = ARCH_DEP(vfetch4) ( effective_addr1, b1, regs ); v2 = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Fetch operands again to check for alteration by another CPU */ w1 = ARCH_DEP(vfetch4) ( effective_addr1, b1, regs ); w2 = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Load R3 register from first storage operand */ regs->GR_L(r3) = v1; /* Load R3+1 register from second storage operand */ regs->GR_L(r3+1) = v2; /* Set condition code 0 if operands unaltered, or 3 if altered */ regs->psw.cc = (v1 == w1 && v2 == w2) ? 0 : 3; } /* end DEF_INST(load_pair_disjoint) */ /*-------------------------------------------------------------------*/ /* C8x5 LPDG - Load Pair Disjoint Long [SSF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_pair_disjoint_long) /*810*/ { int r3; /* Register number */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ U64 v1, v2; /* Operand values */ U64 w1, w2; /* Refetched values */ SSF(inst, regs, b1, effective_addr1, b2, effective_addr2, r3); ODD_CHECK(r3, regs); /* Fetch the values of the storage operands */ v1 = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); v2 = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Fetch operands again to check for alteration by another CPU */ w1 = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); w2 = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Load R3 register from first storage operand */ regs->GR_G(r3) = v1; /* Load R3+1 register from second storage operand */ regs->GR_G(r3+1) = v2; /* Set condition code 0 if operands unaltered, or 3 if altered */ regs->psw.cc = (v1 == w1 && v2 == w2) ? 0 : 3; } /* end DEF_INST(load_pair_disjoint_long) */ #endif /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ #if defined(FEATURE_LOAD_STORE_ON_CONDITION_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B9F2 LOCR - Load on Condition Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_on_condition_register) /*810*/ { int r1, r2; /* Values of R fields */ int m3; /* Value of M field */ RRF_M(inst, regs, r1, r2, m3); /* Test M3 mask bit corresponding to condition code */ if (m3 & (0x8 >> regs->psw.cc)) { /* Copy R2 register bits 32-63 to R1 register */ regs->GR_L(r1) = regs->GR_L(r2); } } /* end DEF_INST(load_on_condition_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9E2 LOCGR - Load on Condition Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_on_condition_long_register) /*810*/ { int r1, r2; /* Values of R fields */ int m3; /* Value of M field */ RRF_M(inst, regs, r1, r2, m3); /* Test M3 mask bit corresponding to condition code */ if (m3 & (0x8 >> regs->psw.cc)) { /* Copy R2 register bits 0-63 to R1 register */ regs->GR_G(r1) = regs->GR_G(r2); } } /* end DEF_INST(load_on_condition_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EBF2 LOC - Load on Condition [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_on_condition) /*810*/ { int r1; /* Value of R field */ int m3; /* Value of M field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RSY(inst, regs, r1, m3, b2, effective_addr2); /* Test M3 mask bit corresponding to condition code */ if (m3 & (0x8 >> regs->psw.cc)) { /* Load R1 register bits 32-63 from second operand */ regs->GR_L(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); } } /* end DEF_INST(load_on_condition) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EBE2 LOCG - Load on Condition Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_on_condition_long) /*810*/ { int r1; /* Value of R field */ int m3; /* Value of M field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RSY(inst, regs, r1, m3, b2, effective_addr2); /* Test M3 mask bit corresponding to condition code */ if (m3 & (0x8 >> regs->psw.cc)) { /* Load R1 register bits 0-63 from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); } } /* end DEF_INST(load_on_condition_long) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EBF3 STOC - Store on Condition [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_on_condition) /*810*/ { int r1; /* Value of R field */ int m3; /* Value of M field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RSY(inst, regs, r1, m3, b2, effective_addr2); /* Test M3 mask bit corresponding to condition code */ if (m3 & (0x8 >> regs->psw.cc)) { /* Store R1 register bits 32-63 at operand address */ ARCH_DEP(vstore4) ( regs->GR_L(r1), effective_addr2, b2, regs ); } } /* end DEF_INST(store_on_condition) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EBE3 STOCG - Store on Condition Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_on_condition_long) /*810*/ { int r1; /* Value of R field */ int m3; /* Value of M field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RSY(inst, regs, r1, m3, b2, effective_addr2); /* Test M3 mask bit corresponding to condition code */ if (m3 & (0x8 >> regs->psw.cc)) { /* Store R1 register bits 0-63 at operand address */ ARCH_DEP(vstore8) ( regs->GR_G(r1), effective_addr2, b2, regs ); } } /* end DEF_INST(store_on_condition_long) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_LOAD_STORE_ON_CONDITION_FACILITY)*/ /*810*/ #if defined(FEATURE_DISTINCT_OPERANDS_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B9F8 ARK - Add Distinct Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_distinct_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r2), regs->GR_L(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_distinct_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9E8 AGRK - Add Distinct Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_distinct_long_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long(&(regs->GR_G(r1)), regs->GR_G(r2), regs->GR_G(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_distinct_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* ECD8 AHIK - Add Distinct Halfword Immediate [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_distinct_halfword_immediate) /*810*/ { int r1, r3; /* Values of R fields */ U16 i2; /* 16-bit immediate operand */ RIE(inst, regs, r1, r3, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), (S16)i2, regs->GR_L(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_distinct_halfword_immediate) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* ECD9 AGHIK - Add Distinct Long Halfword Immediate [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_distinct_long_halfword_immediate) /*810*/ { int r1, r3; /* Values of R fields */ U16 i2; /* 16-bit immediate operand */ RIE(inst, regs, r1, r3, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long(&(regs->GR_G(r1)), (S16)i2, regs->GR_G(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_distinct_long_halfword_immediate) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* B9FA ALRK - Add Logical Distinct Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_distinct_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Add signed operands and set condition code */ regs->psw.cc = add_logical (&(regs->GR_L(r1)), regs->GR_L(r2), regs->GR_L(r3)); } /* end DEF_INST(add_logical_distinct_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9EA ALGRK - Add Logical Distinct Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_distinct_long_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r2), regs->GR_G(r3)); } /* end DEF_INST(add_logical_distinct_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* ECDA ALHSIK - Add Logical Distinct with Signed Halfword Imm [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_distinct_signed_halfword_immediate) /*810*/ { int r1, r3; /* Values of R fields */ U16 i2; /* 16-bit immediate operand */ RIE0(inst, regs, r1, r3, i2); /* Add operands and set condition code */ regs->psw.cc = (S16)i2 < 0 ? sub_logical (&(regs->GR_L(r1)), regs->GR_L(r3), (S32)(-(S16)i2)) : add_logical (&(regs->GR_L(r1)), regs->GR_L(r3), (S32)(S16)i2); } /* end DEF_INST(add_logical_distinct_signed_halfword_immediate) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* ECDB ALGHSIK - Add Logical Distinct Long with Signed Hw Imm [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_distinct_long_signed_halfword_immediate) /*810*/ { int r1, r3; /* Values of R fields */ U16 i2; /* 16-bit immediate operand */ RIE0(inst, regs, r1, r3, i2); /* Add operands and set condition code */ regs->psw.cc = (S16)i2 < 0 ? sub_logical_long (&(regs->GR_G(r1)), regs->GR_G(r3), (S64)(-(S16)i2)) : add_logical_long (&(regs->GR_G(r1)), regs->GR_G(r3), (S64)(S16)i2); } /* end DEF_INST(add_logical_distinct_long_signed_halfword_immediate) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* B9F4 NRK - And Distinct Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(and_distinct_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* AND second and third operands and put result in first operand */ regs->GR_L(r1) = regs->GR_L(r2) & regs->GR_L(r3); /* Set condition code 1 if result is non-zero, otherwise 0 */ regs->psw.cc = (regs->GR_L(r1)) ? 1 : 0; } /* end DEF_INST(and_distinct_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9E4 NGRK - And Distinct Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(and_distinct_long_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* AND second and third operands and put result in first operand */ regs->GR_G(r1) = regs->GR_G(r2) & regs->GR_G(r3); /* Set condition code 1 if result is non-zero, otherwise 0 */ regs->psw.cc = (regs->GR_G(r1)) ? 1 : 0; } /* end DEF_INST(and_distinct_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* B9F7 XRK - Exclusive Or Distinct Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_distinct_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* XOR second and third operands and put result in first operand */ regs->GR_L(r1) = regs->GR_L(r2) ^ regs->GR_L(r3); /* Set condition code 1 if result is non-zero, otherwise 0 */ regs->psw.cc = (regs->GR_L(r1)) ? 1 : 0; } /* end DEF_INST(exclusive_or_distinct_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9E7 XGRK - Exclusive Or Distinct Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_distinct_long_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* XOR second and third operands and put result in first operand */ regs->GR_G(r1) = regs->GR_G(r2) ^ regs->GR_G(r3); /* Set condition code 1 if result is non-zero, otherwise 0 */ regs->psw.cc = (regs->GR_G(r1)) ? 1 : 0; } /* end DEF_INST(exclusive_or_distinct_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* B9F6 ORK - Or Distinct Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(or_distinct_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* OR second and third operands and put result in first operand */ regs->GR_L(r1) = regs->GR_L(r2) | regs->GR_L(r3); /* Set condition code 1 if result is non-zero, otherwise 0 */ regs->psw.cc = (regs->GR_L(r1)) ? 1 : 0; } /* end DEF_INST(or_distinct_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9E6 OGRK - Or Distinct Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(or_distinct_long_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* OR second and third operands and put result in first operand */ regs->GR_G(r1) = regs->GR_G(r2) | regs->GR_G(r3); /* Set condition code 1 if result is non-zero, otherwise 0 */ regs->psw.cc = (regs->GR_G(r1)) ? 1 : 0; } /* end DEF_INST(or_distinct_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* EBDC SRAK - Shift Right Single Distinct [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_single_distinct) /*810*/ { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* Integer work area */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift signed value of the R3 register, result in R1 register */ regs->GR_L(r1) = n > 30 ? ((S32)regs->GR_L(r3) < 0 ? -1 : 0) : (S32)regs->GR_L(r3) >> n; /* Set the condition code */ regs->psw.cc = ((S32)regs->GR_L(r1) > 0) ? 2 : (((S32)regs->GR_L(r1) < 0) ? 1 : 0); } /* end DEF_INST(shift_right_single_distinct) */ /*-------------------------------------------------------------------*/ /* EBDD SLAK - Shift Left Single Distinct [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_single_distinct) /*810*/ { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n, n1, n2; /* 32-bit operand values */ U32 i, j; /* Integer work areas */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Fast path if no possible overflow */ if (regs->GR_L(r3) < 0x10000 && n < 16) { regs->GR_L(r1) = regs->GR_L(r3) << n; regs->psw.cc = regs->GR_L(r1) ? 2 : 0; return; } /* Load the numeric and sign portions from the R3 register */ n1 = regs->GR_L(r3) & 0x7FFFFFFF; n2 = regs->GR_L(r3) & 0x80000000; /* Shift the numeric portion left n positions */ for (i = 0, j = 0; i < n; i++) { /* Shift bits 1-31 left one bit position */ n1 <<= 1; /* Overflow if bit shifted out is unlike the sign bit */ if ((n1 & 0x80000000) != n2) j = 1; } /* Load the updated value into the R1 register */ regs->GR_L(r1) = (n1 & 0x7FFFFFFF) | n2; /* Condition code 3 and program check if overflow occurred */ if (j) { regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Set the condition code */ regs->psw.cc = (S32)regs->GR_L(r1) > 0 ? 2 : (S32)regs->GR_L(r1) < 0 ? 1 : 0; } /* end DEF_INST(shift_left_single_distinct) */ /*-------------------------------------------------------------------*/ /* EBDE SRLK - Shift Right Single Logical Distinct [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_single_logical_distinct) /*810*/ { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* Integer work area */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the R3 register and place the result in the R1 register */ regs->GR_L(r1) = n > 31 ? 0 : regs->GR_L(r3) >> n; } /* end DEF_INST(shift_right_single_logical_distinct) */ /*-------------------------------------------------------------------*/ /* EBDF SLLK - Shift Left Single Logical Distinct [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_single_logical_distinct) /*810*/ { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* Integer work area */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Shift the R3 register and place the result in the R1 register */ regs->GR_L(r1) = n > 31 ? 0 : regs->GR_L(r3) << n; } /* end DEF_INST(shift_left_single_logical_distinct) */ /*-------------------------------------------------------------------*/ /* B9F9 SRK - Subtract Distinct Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_distinct_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_L(r1)), regs->GR_L(r2), regs->GR_L(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_distinct_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9E9 SGRK - Subtract Distinct Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_distinct_long_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR(inst, regs, r1, r2, r3); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed_long(&(regs->GR_G(r1)), regs->GR_G(r2), regs->GR_G(r3)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_distinct_long_register) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* B9FB SLRK - Subtract Logical Distinct Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_distinct_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical (&(regs->GR_L(r1)), regs->GR_L(r2), regs->GR_L(r3)); } /* end DEF_INST(subtract_logical_distinct_register) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B9EB SLGRK - Subtract Logical Distinct Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_distinct_long_register) /*810*/ { int r1, r2, r3; /* Values of R fields */ RRR0(inst, regs, r1, r2, r3); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r2), regs->GR_G(r3)); } /* end DEF_INST(subtract_logical_distinct_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_DISTINCT_OPERANDS_FACILITY)*/ /*810*/ #if defined(FEATURE_POPULATION_COUNT_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B9E1 POPCNT - Population Count [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(population_count) /*810*/ { int r1, r2; /* Values of R fields */ int i; /* Loop counter */ U64 n; /* Contents of R2 register */ U64 result; /* Result counter */ U64 mask = 0x0101010101010101ULL; /* Bit mask */ RRE0(inst, regs, r1, r2); /* Load the value to be counted from the R2 register */ n = regs->GR_G(r2); /* Count the number of 1 bits in each byte */ for (i = 0, result = 0; i < 8; i++) { result += n & mask; n >>= 1; } /* Load the result into the R1 register */ regs->GR_G(r1) = result; /* Set condition code 0 if result is zero, or 1 if non-zero */ regs->psw.cc = (result == 0) ? 0 : 1; } /* end DEF_INST(population_count) */ #endif /*defined(FEATURE_POPULATION_COUNT_FACILITY)*/ /*810*/ #if defined(FEATURE_LOAD_AND_TRAP_FACILITY) /*912*/ /*-------------------------------------------------------------------*/ /* E39F LAT - Load and Trap [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_trap) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_L(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Raise data exception if result is zero */ if (regs->GR_L(r1) == 0) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_and_trap) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E385 LGAT - Load Long and Trap [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_and_trap) /*912*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Raise data exception if result is zero */ if (regs->GR_G(r1) == 0) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_long_and_trap) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E3C8 LFHAT - Load Fullword High and Trap [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fullword_high_and_trap) /*912*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register bits 0-31 from second operand */ regs->GR_H(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Raise data exception if result is zero */ if (regs->GR_H(r1) == 0) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_fullword_high_and_trap) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E39D LLGFAT - Load Logical Long Fullword and Trap [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_fullword_and_trap) /*912*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Raise data exception if result is zero */ if (regs->GR_G(r1) == 0) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_logical_long_fullword_and_trap) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E39C LLGTAT - Load Logical Long Thirtyone and Trap [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_thirtyone_and_trap) /*912*/ { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ) & 0x7FFFFFFF; /* Raise data exception if result is zero */ if (regs->GR_G(r1) == 0) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_logical_long_thirtyone_and_trap) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_LOAD_AND_TRAP_FACILITY)*/ /*912*/ #if defined(FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY) /*912*/ /*-------------------------------------------------------------------*/ /* EB23 CLT - Compare Logical and Trap [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_trap) /*912*/ { int r1; /* Register number */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand value */ int m3; /* Mask bits */ int cc; /* Comparison result */ RSY(inst, regs, r1, m3, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare unsigned operands and set comparison result */ cc = regs->GR_L(r1) < n ? 1 : regs->GR_L(r1) > n ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_logical_and_trap) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB2B CLGT - Compare Logical and Trap Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_and_trap_long) /*912*/ { int r1; /* Register number */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand value */ int m3; /* Mask bits */ int cc; /* Comparison result */ RSY(inst, regs, r1, m3, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Compare unsigned operands and set comparison result */ cc = regs->GR_G(r1) < n ? 1 : regs->GR_G(r1) > n ? 2 : 0; /* Raise data exception if m3 mask bit is set */ if ((0x8 >> cc) & m3) { regs->dxc = DXC_COMPARE_AND_TRAP; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_logical_and_trap_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC59 RISBGN - Rotate Then Insert Selected Bits No CC [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_then_insert_selected_bits_long_reg_n) { ARCH_DEP(rotate_then_xxx_selected_bits_long_reg) (inst, regs); } /* end DEF_INST(rotate_then_insert_selected_bits_long_reg_n) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY)*/ #if defined(FEATURE_EXECUTION_HINT_FACILITY) /*912*/ /*-------------------------------------------------------------------*/ /* C7 BPP - Branch Prediction Preload [SMI] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_prediction_preload) /*912*/ { VADR addr2, addr3; /* Effective addresses */ int b3; /* Base of effective address */ int m1; /* Mask value */ SMI_A0(inst, regs, m1, addr2, b3, addr3); /* Depending on the model, the CPU may not implement all of the branch-attribute codes. For codes that are not recognized by the CPU, and for reserved codes, the BPP instruction acts as a no-operation */ } /* end DEF_INST(branch_prediction_preload) */ /*-------------------------------------------------------------------*/ /* C5 BPRP - Branch Prediction Relative Preload [MII] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_prediction_relative_preload) /*912*/ { VADR addr2, addr3; /* Effective addresses */ int m1; /* Mask value */ MII_A0(inst, regs, m1, addr2, addr3); /* Depending on the model, the CPU may not implement all of the branch-attribute codes. For codes that are not recognized by the CPU, and for reserved codes, the BPRP instruction acts as a no-operation */ } /* end DEF_INST(branch_prediction_relative_preload) */ /*-------------------------------------------------------------------*/ /* B2FA NIAI - Next Instruction Access Intent [IE] */ /*-------------------------------------------------------------------*/ DEF_INST(next_instruction_access_intent) /*912*/ { BYTE i1, i2; /* Immediate fields */ IE0(inst, regs, i1, i2); /* Depending on the model, the CPU may not recognize all of the access intents. For access intents that are not recognized by the CPU, the NIAI instruction acts as a no-operation */ } /* end DEF_INST(next_instruction_access_intent) */ #endif /*defined(FEATURE_EXECUTION_HINT_FACILITY)*/ /*912*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "general3.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "general3.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/pfpo.c0000664000175000017500000002770612564723224011327 00000000000000/* PFPO.C (c) Copyright Roger Bowler, 2007 */ /* Perform Floating Point Operation instruction */ /* (c) Copyright Bernard van der Helm, 2009 */ /* Noordwijkerhout, The Netherlands */ /*-------------------------------------------------------------------*/ /* This module implements the Perform Floating Point Operation */ /* instruction described in the manual SA22-7832-05. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_PFPO_C_) #define _PFPO_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "decimal128.h" #include "decimal64.h" #include "decimal32.h" #include "decPacked.h" #if defined(FEATURE_PFPO) #define CLASS_ZERO 1 #define CLASS_SUBNORMAL 2 #define CLASS_INFINITY 3 #define CLASS_QNAN 4 #define CLASS_SNAN 5 #define CLASS_NORMAL 6 #define INFINITYSTR "Infinity" #define QNANSTR "NaN" #define SNANSTR "sNaN" typedef struct { unsigned base; unsigned class; char str[256]; } PFPO_FLOAT; #if 0 // PFPO not yet implemented /*-------------------------------------------------------------------*/ /* Binary floating point routines */ /*-------------------------------------------------------------------*/ static void BFPshortGet(PFPO_FLOAT *f, U32 r) { unsigned exp; U32 frac; unsigned i; U32 mask; unsigned sign; sign = r & 0x80000000 ? 1 : 0; exp = (r & 0x7f800000) >> 23; frac = r & 0x007fffff; if(exp == 127) { if(!frac) f->class = CLASS_ZERO; else f->class = CLASS_SUBNORMAL; } else if(exp == 0xff) { if(!frac) f->class = CLASS_INFINITY; else { if(frac & 0x80000000) f->class = CLASS_QNAN; else f->class = CLASS_SNAN; } } else f->class = CLASS_NORMAL; f->base = 2; switch(f->class) { case CLASS_ZERO: strcpy(f->str, "0"); break; case CLASS_INFINITY: if(sign) strcpy(f->str, "-" INFINITYSTR); else strcpy(f->str, INFINITYSTR); break; case CLASS_QNAN: strcpy(f->str, QNANSTR); break; case CLASS_SNAN: strcpy(f->str, SNANSTR); break; case CLASS_NORMAL: case CLASS_SUBNORMAL: if(sign) strcpy(f->str, "-0."); else strcpy(f->str, "0."); if(f->class == CLASS_NORMAL) strcat(f->str, "1"); else strcat(f->str, "0"); mask = 0x00400000; for(i = 0; i < 23; i++) { if(frac & mask) strcat(f->str, "1"); else strcat(f->str, "0"); mask >>= 1; } strcat(f->str, "@"); if(f->class == CLASS_NORMAL) sprintf(&f->str[strlen(f->str)], "%d", exp - 127); else strcat(f->str, "1"); break; } } static void BFPlongGet(PFPO_FLOAT *f, U64 r) { unsigned exp; U64 frac; unsigned i; U64 mask; unsigned sign; sign = r & 0x8000000000000000 ? 1 : 0; exp = (r & 0x7ff0000000000000) >> 52; frac = r & 0x000fffffffffffff; if(exp == 1023) { if(!frac) f->class = CLASS_ZERO; else f->class = CLASS_SUBNORMAL; } else if(exp == 0x7ff) { if(!frac) f->class = CLASS_INFINITY; else { if(frac & 0x8000000000000000) f->class = CLASS_QNAN; else f->class = CLASS_SNAN; } } else f->class = CLASS_NORMAL; f->base = 2; switch(f->class) { case CLASS_ZERO: strcpy(f->str, "0"); break; case CLASS_INFINITY: if(sign) strcpy(f->str, "-" INFINITYSTR); else strcpy(f->str, INFINITYSTR); break; case CLASS_QNAN: strcpy(f->str, QNANSTR); break; case CLASS_SNAN: strcpy(f->str, SNANSTR); break; case CLASS_NORMAL: case CLASS_SUBNORMAL: if(sign) strcpy(f->str, "-0."); else strcpy(f->str, "0."); if(f->class == CLASS_NORMAL) strcat(f->str, "1"); else strcat(f->str, "0"); mask = 0x0008000000000000; for(i = 0; i < 52; i++) { if(frac & mask) strcat(f->str, "1"); else strcat(f->str, "0"); mask >>= 1; } strcat(f->str, "@"); if(f->class == CLASS_NORMAL) sprintf(&f->str[strlen(f->str)], "%d", exp - 1023); else strcat(f->str, "1"); break; } } static void BFPextGet(PFPO_FLOAT *f, U64 h, U64 l) { unsigned exp; U64 frach; U64 fracl; unsigned i; U64 mask; unsigned sign; sign = h & 0x8000000000000000 ? 1 : 0; exp = (h & 0x7fff000000000000) >> 48; frach = h & 0x0000ffffffffffff; fracl = l; if(exp == 16383) { if(!frach && !fracl) f->class = CLASS_ZERO; else f->class = CLASS_SUBNORMAL; } else if(exp == 0x7fff) { if(!frach && !fracl) f->class = CLASS_INFINITY; else { if(frach & 0x8000000000000000) f->class = CLASS_QNAN; else f->class = CLASS_SNAN; } } else f->class = CLASS_NORMAL; f->base = 2; switch(f->class) { case CLASS_ZERO: strcpy(f->str, "0"); break; case CLASS_INFINITY: if(sign) strcpy(f->str, "-" INFINITYSTR); else strcpy(f->str, INFINITYSTR); break; case CLASS_QNAN: strcpy(f->str, QNANSTR); break; case CLASS_SNAN: strcpy(f->str, SNANSTR); break; case CLASS_NORMAL: case CLASS_SUBNORMAL: if(sign) strcpy(f->str, "-0."); else strcpy(f->str, "0."); if(f->class == CLASS_NORMAL) strcat(f->str, "1"); else strcat(f->str, "0"); mask = 0x0000800000000000; for(i = 0; i < 48; i++) { if(frach & mask) strcat(f->str, "1"); else strcat(f->str, "0"); mask >>= 1; } mask = 0x8000000000000000; for(i = 0; i < 64; i++) { if(fracl & mask) strcat(f->str, "1"); else strcat(f->str, "0"); mask >>= 1; } strcat(f->str, "@"); if(f->class == CLASS_NORMAL) sprintf(&f->str[strlen(f->str)], "%d", exp - 16383); else strcat(f->str, "1"); break; } } /*-------------------------------------------------------------------*/ /* Decimal floating point routines */ /*-------------------------------------------------------------------*/ static void DFPshortGet(PFPO_FLOAT *f, U32 r) { decimal32 dec32; unsigned i; U32 temp; temp = r; for(i = 0; i < 4; i++) { dec32.bytes[i] = temp & 0xff; temp >>= 8; } decimal32ToString(&dec32, f->str); f->base = 10; if(!strncmp(f->str, "-0E", 2) || !strncmp(f->str, "0E", 2)) f->class = CLASS_ZERO; else if(strstr(f->str, "E0")) f->class = CLASS_SUBNORMAL; else if(!strcmp(f->str, "Ininity")) f->class = CLASS_INFINITY; else if(!strcmp(f->str, "NaN")) f->class = CLASS_QNAN; else if(!strcmp(f->str, "sNaN")) f->class = CLASS_SNAN; else f->class = CLASS_NORMAL; } static void DFPlongGet(PFPO_FLOAT *f, U64 r) { decimal64 dec64; unsigned i; U64 temp; temp = r; for(i = 0; i < 8; i++) { dec64.bytes[i] = temp & 0xff; temp >>= 8; } decimal64ToString(&dec64, f->str); f->base = 10; if(!strncmp(f->str, "-0E", 2) || !strncmp(f->str, "0E", 2)) f->class = CLASS_ZERO; else if(strstr(f->str, "E0")) f->class = CLASS_SUBNORMAL; else if(!strcmp(f->str, "Ininity")) f->class = CLASS_INFINITY; else if(!strcmp(f->str, "NaN")) f->class = CLASS_QNAN; else if(!strcmp(f->str, "sNaN")) f->class = CLASS_SNAN; else f->class = CLASS_NORMAL; } static void DFPextGet(PFPO_FLOAT *f, U64 h, U64 l) { decimal128 dec128; unsigned i; U64 temph; U64 templ; temph = h; templ = l; for(i = 0; i < 8; i++) { dec128.bytes[i] = templ & 0xff; dec128.bytes[i + 8] = temph & 0xff; templ >>= 8; temph >>= 8; } decimal128ToString(&dec128, f->str); f->base = 10; if(!strncmp(f->str, "-0E", 2) || !strncmp(f->str, "0E", 2)) f->class = CLASS_ZERO; else if(strstr(f->str, "E0")) f->class = CLASS_SUBNORMAL; else if(!strcmp(f->str, "Ininity")) f->class = CLASS_INFINITY; else if(!strcmp(f->str, "NaN")) f->class = CLASS_QNAN; else if(!strcmp(f->str, "sNaN")) f->class = CLASS_SNAN; else f->class = CLASS_NORMAL; } /*-------------------------------------------------------------------*/ /* Hexadecimal floating point routines */ /*-------------------------------------------------------------------*/ static void HFPshortGet(PFPO_FLOAT *f, U32 r) { unsigned exp; U32 frac; unsigned i; U32 mask; unsigned sign; sign = r & 0x80000000 ? 1 : 0; exp = (r & 0x7f000000) >> 24; frac = r & 0x00ffffff; if(!frac) f->class = CLASS_ZERO; else f->class = CLASS_NORMAL; f->base = 16; switch(f->class) { case CLASS_ZERO: strcpy(f->str, "0"); break; case CLASS_NORMAL: if(sign) strcpy(f->str, "-0."); else strcpy(f->str, "0."); mask = 0x00ff0000; for(i = 0; i < 3; i++) { sprintf(&f->str[strlen(f->str)], "%02x", (r & mask) >> (16 - (i * 8))); mask >>= 8; } strcat(f->str, "@"); sprintf(&f->str[strlen(f->str)], "%d", exp - 64); break; } } static void HFPlongGet(PFPO_FLOAT *f, U64 r) { unsigned exp; U64 frac; unsigned i; U64 mask; unsigned sign; sign = r & 0x8000000000000000 ? 1 : 0; exp = (r & 0x7f00000000000000) >> 56; frac = r & 0x00ffffffffffffff; if(!frac) f->class = CLASS_ZERO; else f->class = CLASS_NORMAL; f->base = 16; switch(f->class) { case CLASS_ZERO: strcpy(f->str, "0"); break; case CLASS_NORMAL: if(sign) strcpy(f->str, "-0."); else strcpy(f->str, "0."); mask = 0x00ff000000000000; for(i = 0; i < 7; i++) { sprintf(&f->str[strlen(f->str)], "%02"I64_FMT"x", (r & mask) >> (48 - (i * 8))); mask >>= 8; } strcat(f->str, "@"); sprintf(&f->str[strlen(f->str)], "%d", exp - 64); break; } } static void HFPextGet(PFPO_FLOAT *f, U64 h, U64 l) { unsigned exp; U64 frach; U64 fracl; unsigned i; U64 mask; unsigned sign; sign = h & 0x8000000000000000 ? 1 : 0; exp = (h & 0x7f00000000000000) >> 56; frach = h & 0x00ffffffffffffff; fracl = l & 0x00ffffffffffffff; if(!frach && !fracl) f->class = CLASS_ZERO; else f->class = CLASS_NORMAL; f->base = 16; switch(f->class) { case CLASS_ZERO: strcpy(f->str, "0"); break; case CLASS_NORMAL: if(sign) strcpy(f->str, "-0."); else strcpy(f->str, "0."); mask = 0x00ff000000000000; for(i = 0; i < 7; i++) { sprintf(&f->str[strlen(f->str)], "%02"I64_FMT"x", (h & mask) >> (48 - (i * 8))); mask >>= 8; } mask = 0x00ff000000000000; for(i = 0; i < 7; i++) { sprintf(&f->str[strlen(f->str)], "%02"I64_FMT"x", (l & mask) >> (48 - (i * 8))); mask >>= 8; } strcat(f->str, "@"); sprintf(&f->str[strlen(f->str)], "%d", exp - 64); break; } } #endif // PFPO not yet implemented /*-------------------------------------------------------------------*/ /* 010A PFPO - Perform Floating Point Operation [E] */ /*-------------------------------------------------------------------*/ DEF_INST(perform_floating_point_operation) { E(inst, regs); ARCH_DEP(program_interrupt)(regs, PGM_OPERATION_EXCEPTION); } /* end DEF_INST(perform_floating_point_operation) */ #endif /*defined(FEATURE_PFPO)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "pfpo.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "pfpo.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/plo.c0000664000175000017500000013405612564723224011152 00000000000000/* PLO.C (c) Copyright Jan Jaeger, 2000-2009 */ /* Perform Locked Operation functions codes */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_PLO_C_) #define _PLO_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_PERFORM_LOCKED_OPERATION) int ARCH_DEP(plo_cl) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U32 op2, op4; FW_CHECK(effective_addr2, regs); FW_CHECK(effective_addr4, regs); /* Load second operand from operand address */ op2 = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); if(regs->GR_L(r1) == op2) { op4 = ARCH_DEP(vfetch4) ( effective_addr4, b4, regs ); regs->GR_L(r3) = op4; return 0; } else { regs->GR_L(r1) = op2; return 1; } } int ARCH_DEP(plo_clg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op1c, op2, op4; U32 op4alet = 0; VADR op4addr; UNREFERENCED(r1); DW_CHECK(effective_addr4, regs); DW_CHECK(effective_addr2, regs); /* load second operand */ op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); /* load 1st op. compare value */ op1c = ARCH_DEP(wfetch8)(effective_addr4 + 8, b4, regs); if(op1c == op2) { /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ #if defined(FEATURE_ESAME) op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); #else op4addr = ARCH_DEP(wfetch4)(effective_addr4 + 76, b4, regs); #endif op4addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op4addr, regs); /* Load operand 4, using ar3 when in ar mode */ op4 = ARCH_DEP(vfetch8)(op4addr, r3, regs); /* replace the 3rd operand with the 4th operand */ ARCH_DEP(wstore8)(op4, effective_addr4 + 40, b4, regs); return 0; } else { /* replace the first op compare value with 2nd op */ ARCH_DEP(wstore8)(op2, effective_addr4 + 8, b4, regs); return 1; } } #if defined(FEATURE_ESAME) int ARCH_DEP(plo_clgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op2, op4; DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); /* Load second operand from operand address */ op2 = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); if(regs->GR_G(r1) == op2) { op4 = ARCH_DEP(vfetch8) ( effective_addr4, b4, regs ); regs->GR_G(r3) = op4; return 0; } else { regs->GR_G(r1) = op2; return 1; } } #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) int ARCH_DEP(plo_clx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { BYTE op1c[16], op2[16], op4[16]; U32 op4alet = 0; VADR op4addr; UNREFERENCED(r1); DW_CHECK(effective_addr4, regs); QW_CHECK(effective_addr2, regs); /* load second operand */ ARCH_DEP(vfetchc) ( op2, 16-1, effective_addr2, b2, regs ); /* load 1st op. compare value */ ARCH_DEP(vfetchc) ( op1c, 16-1, effective_addr4 + 0, b4, regs ); if(memcmp(op1c,op2,16) == 0) { /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); op4addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op4addr, regs); /* Load operand 4, using ar3 when in ar mode */ ARCH_DEP(vfetchc) ( op4, 16-1, op4addr, r3, regs ); /* replace the 3rd operand with the 4th operand */ ARCH_DEP(wstorec) ( op4, 16-1, effective_addr4 + 32, b4, regs ); return 0; } else { /* replace the first op compare value with 2nd op */ ARCH_DEP(vstorec) ( op2, 16-1, effective_addr4 + 0, b4, regs ); return 1; } } #endif /*defined(FEATURE_ESAME)*/ int ARCH_DEP(plo_cs) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U32 op2; UNREFERENCED(r3); UNREFERENCED(effective_addr4); UNREFERENCED(b4); ODD_CHECK(r1, regs); FW_CHECK(effective_addr2, regs); /* Load second operand from operand address */ op2 = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare operand with R1 register contents */ if ( regs->GR_L(r1) == op2 ) { /* If equal, store R1+1 at operand loc and set cc=0 */ ARCH_DEP(vstore4) ( regs->GR_L(r1+1), effective_addr2, b2, regs ); return 0; } else { /* If unequal, load R1 from operand and set cc=1 */ regs->GR_L(r1) = op2; return 1; } } int ARCH_DEP(plo_csg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op1c, op1r, op2; UNREFERENCED(r1); UNREFERENCED(r3); DW_CHECK(effective_addr4, regs); DW_CHECK(effective_addr2, regs); /* Load first op compare value */ op1c = ARCH_DEP(wfetch8)(effective_addr4 + 8, b4, regs); /* Load 2nd operand */ op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); if(op1c == op2) { /* Load 1st op replacement value */ op1r = ARCH_DEP(wfetch8)(effective_addr4 + 24, b4, regs); /* Store at 2nd operand location */ ARCH_DEP(vstore8)(op1r, effective_addr2, b2, regs); return 0; } else { /* Replace 1st op comp value by 2nd op */ ARCH_DEP(wstore8)(op2, effective_addr4 + 8, b4, regs); return 1; } } #if defined(FEATURE_ESAME) int ARCH_DEP(plo_csgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op2; UNREFERENCED(r3); UNREFERENCED(effective_addr4); UNREFERENCED(b4); ODD_CHECK(r1, regs); DW_CHECK(effective_addr2, regs); /* Load second operand from operand address */ op2 = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Compare operand with R1 register contents */ if ( regs->GR_G(r1) == op2 ) { /* If equal, store R1+1 at operand loc and set cc=0 */ ARCH_DEP(vstore8) ( regs->GR_G(r1+1), effective_addr2, b2, regs ); return 0; } else { /* If unequal, load R1 from operand and set cc=1 */ regs->GR_G(r1) = op2; return 1; } } #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) int ARCH_DEP(plo_csx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { BYTE op1c[16], op1r[16], op2[16]; UNREFERENCED(r1); UNREFERENCED(r3); DW_CHECK(effective_addr4, regs); QW_CHECK(effective_addr2, regs); /* Load first op compare value */ ARCH_DEP(vfetchc) ( op1c, 16-1, effective_addr4 + 0, b4, regs ); /* Load 2nd operand */ ARCH_DEP(vfetchc) ( op2, 16-1, effective_addr2, b2, regs ); if(memcmp(op1c,op2,16) == 0) { /* Load 1st op replacement value */ ARCH_DEP(wfetchc) ( op1r, 16-1, effective_addr4 + 16, b4, regs ); /* Store at 2nd operand location */ ARCH_DEP(vstorec) ( op1r, 16-1, effective_addr2, b2, regs ); return 0; } else { /* Replace 1st op comp value by 2nd op */ ARCH_DEP(vstorec) ( op2, 16-1, effective_addr4 + 0, b4, regs ); return 1; } } #endif /*defined(FEATURE_ESAME)*/ int ARCH_DEP(plo_dcs) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U32 op2, op4; ODD2_CHECK(r1, r3, regs); FW_CHECK(effective_addr2, regs); FW_CHECK(effective_addr4, regs); /* Load second operands from operand addresses */ op2 = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); if(regs->GR_L(r1) != op2) { regs->GR_L(r1) = op2; return 1; } else { op4 = ARCH_DEP(vfetch4) ( effective_addr4, b4, regs ); /* Compare operand with register contents */ if (regs->GR_L(r3) != op4) { /* If unequal, load r3 from op and set cc=2 */ regs->GR_L(r3) = op4; return 2; } else { /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 4-1, ACCTYPE_WRITE_SKP, regs); /* If equal, store replacement and set cc=0 */ ARCH_DEP(vstore4) ( regs->GR_L(r3+1), effective_addr4, b4, regs ); ARCH_DEP(vstore4) ( regs->GR_L(r1+1), effective_addr2, b2, regs ); return 0; } } } int ARCH_DEP(plo_dcsg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op1c, op1r, op2, op3c, op3r, op4; U32 op4alet = 0; VADR op4addr; UNREFERENCED(r1); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); /* load 1st op compare value from the pl */ op1c = ARCH_DEP(wfetch8)(effective_addr4 + 8, b4, regs); /* load 2nd operand */ op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); if(op1c != op2) { /* replace the 1st op compare value with 2nd op */ ARCH_DEP(wstore8)(op2, effective_addr4 + 8, b4, regs); return 1; } else { /* Load 3rd op compare value */ op3c = ARCH_DEP(wfetch8)(effective_addr4 + 40, b4, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ #if defined(FEATURE_ESAME) op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); #else op4addr = ARCH_DEP(wfetch4)(effective_addr4 + 76, b4, regs); #endif op4addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op4addr, regs); /* Load operand 4, using ar3 when in ar mode */ op4 = ARCH_DEP(vfetch8)(op4addr, r3, regs); if(op3c != op4) { ARCH_DEP(wstore8)(op4, effective_addr4 + 40, b4, regs); return 2; } else { /* load replacement values */ op1r = ARCH_DEP(wfetch8)(effective_addr4 + 24, b4, regs); op3r = ARCH_DEP(wfetch8)(effective_addr4 + 56, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE_SKP, regs); /* Store 3rd op replacement at 4th op */ ARCH_DEP(vstore8)(op3r, op4addr, r3, regs); /* Store 1st op replacement at 2nd op */ ARCH_DEP(vstore8)(op1r, effective_addr2, b2, regs); return 0; } } } #if defined(FEATURE_ESAME) int ARCH_DEP(plo_dcsgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op2, op4; ODD2_CHECK(r1, r3, regs); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); /* Load second operands from operand addresses */ op2 = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); if(regs->GR_G(r1) != op2) { regs->GR_G(r1) = op2; return 1; } else { op4 = ARCH_DEP(vfetch8) ( effective_addr4, b4, regs ); /* Compare operand with register contents */ if (regs->GR_G(r3) != op4) { /* If unequal, load r3 from op and set cc=2 */ regs->GR_G(r3) = op4; return 2; } else { /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 4-1, ACCTYPE_WRITE_SKP, regs); /* If equal, store replacement and set cc=0 */ ARCH_DEP(vstore8) ( regs->GR_G(r3+1), effective_addr4, b4, regs ); ARCH_DEP(vstore8) ( regs->GR_G(r1+1), effective_addr2, b2, regs ); return 0; } } } #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) int ARCH_DEP(plo_dcsx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { BYTE op1c[16], op1r[16], op2[16], op3c[16], op3r[16], op4[16]; U32 op4alet = 0; VADR op4addr; UNREFERENCED(r1); QW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); /* load 1st op compare value from the pl */ ARCH_DEP(vfetchc) ( op1c, 16-1, effective_addr4 + 0, b4, regs ); /* load 2nd operand */ ARCH_DEP(vfetchc) ( op2, 16-1, effective_addr2, b2, regs ); if(memcmp(op1c,op2,16) != 0) { /* replace the 1st op compare value with 2nd op */ ARCH_DEP(vstorec) ( op2, 16-1, effective_addr4 + 0, b4, regs ); return 1; } else { /* Load 3rd op compare value */ ARCH_DEP(wfetchc) ( op3c, 16-1, effective_addr4 + 32, b4, regs ); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); op4addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op4addr, regs); /* Load operand 4, using ar3 when in ar mode */ ARCH_DEP(vfetchc) ( op4, 16-1, op4addr, r3, regs ); if(memcmp(op3c,op4,16) != 0) { ARCH_DEP(wstorec) ( op4, 16-1, effective_addr4 + 32, b4, regs ); return 2; } else { /* load replacement values */ ARCH_DEP(wfetchc) ( op1r, 16-1, effective_addr4 + 16, b4, regs ); ARCH_DEP(wfetchc) ( op3r, 16-1, effective_addr4 + 48, b4, regs ); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 16-1, ACCTYPE_WRITE_SKP, regs); /* Store 3rd op replacement at 4th op */ ARCH_DEP(vstorec) ( op3r, 16-1, op4addr, r3, regs); /* Store 1st op replacement at 2nd op */ ARCH_DEP(vstorec) ( op1r, 16-1, effective_addr2, b2, regs); return 0; } } } #endif /*defined(FEATURE_ESAME)*/ int ARCH_DEP(plo_csst) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U32 op2; ODD_CHECK(r1, regs); FW_CHECK(effective_addr2, regs); FW_CHECK(effective_addr4, regs); /* Load second operand from operand address */ op2 = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare operand with register contents */ if ( regs->GR_L(r1) == op2) { /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 4-1, ACCTYPE_WRITE_SKP, regs); /* If equal, store replacement and set cc=0 */ ARCH_DEP(vstore4) ( regs->GR_L(r3), effective_addr4, b4, regs ); ARCH_DEP(vstore4) ( regs->GR_L(r1+1), effective_addr2, b2, regs ); return 0; } else { regs->GR_L(r1) = op2; return 1; } } int ARCH_DEP(plo_csstg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op1c, op1r, op2, op3; U32 op4alet = 0; VADR op4addr; UNREFERENCED(r1); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); op1c = ARCH_DEP(wfetch8)(effective_addr4 + 8, b4, regs); op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); if(op1c == op2) { op1r = ARCH_DEP(wfetch8)(effective_addr4 + 24, b4, regs); op3 = ARCH_DEP(wfetch8)(effective_addr4 + 56, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ #if defined(FEATURE_ESAME) op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); #else op4addr = ARCH_DEP(wfetch4)(effective_addr4 + 76, b4, regs); #endif op4addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op4addr, regs); ARCH_DEP(vstore8)(op3, op4addr, r3, regs); ARCH_DEP(vstore8)(op1r, effective_addr2, b2, regs); return 0; } else { /* Store 2nd op at 1st op comare value */ ARCH_DEP(wstore8)(op2, effective_addr4 + 8, b4, regs); return 1; } } #if defined(FEATURE_ESAME) int ARCH_DEP(plo_csstgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op2; ODD_CHECK(r1, regs); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); /* Load second operand from operand address */ op2 = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Compare operand with register contents */ if ( regs->GR_G(r1) == op2) { /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE_SKP, regs); /* If equal, store replacement and set cc=0 */ ARCH_DEP(vstore8) ( regs->GR_G(r3), effective_addr4, b4, regs ); ARCH_DEP(vstore8) ( regs->GR_G(r1+1), effective_addr2, b2, regs ); return 0; } else { regs->GR_G(r1) = op2; return 1; } } #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) int ARCH_DEP(plo_csstx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { BYTE op1c[16], op1r[16], op2[16], op3[16]; U32 op4alet = 0; VADR op4addr; UNREFERENCED(r1); QW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); ARCH_DEP(vfetchc) ( op1c, 16-1, effective_addr4 + 0, b4, regs ); ARCH_DEP(vfetchc) ( op2, 16-1, effective_addr2, b2, regs ); if(memcmp(op1c,op2,16) == 0) { ARCH_DEP(wfetchc) ( op1r, 16-1, effective_addr4 + 16, b4, regs ); ARCH_DEP(wfetchc) ( op3, 16-1, effective_addr4 + 48, b4, regs ); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 16-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); op4addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op4addr, regs); ARCH_DEP(vstorec)(op3, 16-1, op4addr, r3, regs); ARCH_DEP(vstorec)(op1r, 16-1, effective_addr2, b2, regs); return 0; } else { /* Store 2nd op at 1st op comare value */ ARCH_DEP(vstorec)(op2, 16-1, effective_addr4 + 0, b4, regs); return 1; } } #endif /*defined(FEATURE_ESAME)*/ int ARCH_DEP(plo_csdst) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U32 op2, op3, op4alet = 0, op5, op6alet = 0; VADR op4addr, op6addr; ODD_CHECK(r1, regs); FW_CHECK(effective_addr2, regs); FW_CHECK(effective_addr4, regs); op2 = ARCH_DEP(vfetch4)(effective_addr2, b2, regs); op3 = ARCH_DEP(wfetch4)(effective_addr4 + 60, b4, regs); op5 = ARCH_DEP(wfetch4)(effective_addr4 + 92, b4, regs); if(regs->GR_L(r1) == op2) { /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 4-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ #if defined(FEATURE_ESAME) op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); #else op4addr = ARCH_DEP(wfetch4)(effective_addr4 + 76, b4, regs); #endif op4addr &= ADDRESS_MAXWRAP(regs); FW_CHECK(op4addr, regs); /* Load address of operand 6 */ #if defined(FEATURE_ESAME) op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); #else op6addr = ARCH_DEP(wfetch4)(effective_addr4 + 108, b4, regs); #endif op6addr &= ADDRESS_MAXWRAP(regs); FW_CHECK(op6addr, regs); /* Verify access to 6th operand */ ARCH_DEP(validate_operand) (op6addr, r3, 4-1,ACCTYPE_WRITE_SKP, regs); /* Store 3th op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore4)(op3, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore4)(op5, op6addr, r3, regs); /* Store 1st op at 2nd op */ ARCH_DEP(vstore4)(regs->GR_L(r1+1), effective_addr2, b2, regs); return 0; } else { regs->GR_L(r1) = op2; return 1; } } int ARCH_DEP(plo_csdstg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op1c, op1r, op2, op3, op5; U32 op4alet = 0, op6alet = 0; VADR op4addr, op6addr; UNREFERENCED(r1); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); op1c = ARCH_DEP(wfetch8)(effective_addr4 + 8, b4, regs); op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); if(op1c == op2) { op1r = ARCH_DEP(wfetch8)(effective_addr4 + 24, b4, regs); op3 = ARCH_DEP(wfetch8)(effective_addr4 + 56, b4, regs); op5 = ARCH_DEP(wfetch8)(effective_addr4 + 88, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ #if defined(FEATURE_ESAME) op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); #else op4addr = ARCH_DEP(wfetch4)(effective_addr4 + 76, b4, regs); #endif op4addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op4addr, regs); /* Load address of operand 6 */ #if defined(FEATURE_ESAME) op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); #else op6addr = ARCH_DEP(wfetch4)(effective_addr4 + 108, b4, regs); #endif op6addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op6addr, regs); /* Verify access to 6th operand */ ARCH_DEP(validate_operand) (op6addr, r3, 8-1, ACCTYPE_WRITE_SKP, regs); /* Store 3th op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op3, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op5, op6addr, r3, regs); /* Store 1st op replacement at 2nd op */ ARCH_DEP(vstore8)(op1r, effective_addr2, b2, regs); return 0; } else { ARCH_DEP(wstore8)(op2, effective_addr4 + 8, b4, regs); return 1; } } #if defined(FEATURE_ESAME) int ARCH_DEP(plo_csdstgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op2, op3, op5; U32 op4alet = 0, op6alet = 0; VADR op4addr, op6addr; ODD_CHECK(r1, regs); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); if(regs->GR_G(r1) == op2) { op3 = ARCH_DEP(wfetch8)(effective_addr4 + 56, b4, regs); op5 = ARCH_DEP(wfetch8)(effective_addr4 + 88, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); op4addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op4addr, regs); /* Load address of operand 6 */ op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); op6addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op6addr, regs); /* Verify access to 6th operand */ ARCH_DEP(validate_operand) (op6addr, r3, 8-1,ACCTYPE_WRITE_SKP, regs); /* Store 3th op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op3, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op5, op6addr, r3, regs); /* Store 1st op at 2nd op */ ARCH_DEP(vstore8)(regs->GR_G(r1+1), effective_addr2, b2, regs); return 0; } else { regs->GR_G(r1) = op2; return 1; } } #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) int ARCH_DEP(plo_csdstx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { BYTE op1c[16], op1r[16], op2[16], op3[16], op5[16]; U32 op4alet = 0, op6alet = 0; VADR op4addr, op6addr; UNREFERENCED(r1); QW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); ARCH_DEP(vfetchc)(op1c, 16-1, effective_addr4 + 0, b4, regs); ARCH_DEP(vfetchc)(op2, 16-1, effective_addr2, b2, regs); if(memcmp(op1c,op2,16) == 0) { ARCH_DEP(wfetchc)(op1r, 16-1, effective_addr4 + 16, b4, regs); ARCH_DEP(wfetchc)(op3, 16-1, effective_addr4 + 48, b4, regs); ARCH_DEP(wfetchc)(op5, 16-1, effective_addr4 + 80, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 16-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); op4addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op4addr, regs); /* Load address of operand 6 */ op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); op6addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op6addr, regs); /* Verify access to 6th operand */ ARCH_DEP(validate_operand) (op6addr, r3, 16-1,ACCTYPE_WRITE_SKP, regs); /* Store 3th op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstorec)(op3, 16-1, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstorec)(op5, 16-1, op6addr, r3, regs); /* Store 1st op replacement at 2nd op */ ARCH_DEP(vstorec)(op1r, 16-1, effective_addr2, b2, regs); return 0; } else { ARCH_DEP(vstorec)(op2, 16-1, effective_addr4 + 0, b4, regs); return 1; } } #endif /*defined(FEATURE_ESAME)*/ int ARCH_DEP(plo_cstst) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U32 op2, op3, op4alet = 0, op5, op6alet = 0, op7, op8alet = 0; VADR op4addr, op6addr, op8addr; ODD_CHECK(r1, regs); FW_CHECK(effective_addr2, regs); FW_CHECK(effective_addr4, regs); op2 = ARCH_DEP(vfetch4)(effective_addr2, b2, regs); op3 = ARCH_DEP(wfetch4)(effective_addr4 + 60, b4, regs); op5 = ARCH_DEP(wfetch4)(effective_addr4 + 92, b4, regs); op7 = ARCH_DEP(wfetch4)(effective_addr4 + 124, b4, regs); if(regs->GR_L(r1) == op2) { /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 4-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); op8alet = ARCH_DEP(wfetch4)(effective_addr4 + 132, b4, regs); regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ #if defined(FEATURE_ESAME) op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); #else op4addr = ARCH_DEP(wfetch4)(effective_addr4 + 76, b4, regs); #endif op4addr &= ADDRESS_MAXWRAP(regs); FW_CHECK(op4addr, regs); /* Load address of operand 6 */ #if defined(FEATURE_ESAME) op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); #else op6addr = ARCH_DEP(wfetch4)(effective_addr4 + 108, b4, regs); #endif op6addr &= ADDRESS_MAXWRAP(regs); FW_CHECK(op6addr, regs); /* Load address of operand 8 */ #if defined(FEATURE_ESAME) op8addr = ARCH_DEP(wfetch8)(effective_addr4 + 136, b4, regs); #else op8addr = ARCH_DEP(wfetch4)(effective_addr4 + 140, b4, regs); #endif op8addr &= ADDRESS_MAXWRAP(regs); FW_CHECK(op8addr, regs); /* Verify access to 8th operand */ ARCH_DEP(validate_operand) (op8addr, r3, 4-1,ACCTYPE_WRITE_SKP, regs); /* Verify access to 6th operand */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(validate_operand) (op6addr, r3, 4-1, ACCTYPE_WRITE_SKP, regs); /* Store 3rd op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore4)(op3, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore4)(op5, op6addr, r3, regs); /* Store 7th op at 8th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore4)(op7, op8addr, r3, regs); /* Store 1st op replacement at 2nd op */ ARCH_DEP(vstore4)(regs->GR_L(r1+1), effective_addr2, b2, regs); return 0; } else { regs->GR_L(r1) = op2; return 1; } } int ARCH_DEP(plo_cststg) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op1c, op1r, op2, op3, op5, op7; U32 op4alet = 0, op6alet = 0, op8alet = 0; VADR op4addr, op6addr, op8addr; UNREFERENCED(r1); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); op1c = ARCH_DEP(wfetch8)(effective_addr4 + 8, b4, regs); op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); if(op1c == op2) { op1r = ARCH_DEP(wfetch8)(effective_addr4 + 24, b4, regs); op3 = ARCH_DEP(wfetch8)(effective_addr4 + 56, b4, regs); op5 = ARCH_DEP(wfetch8)(effective_addr4 + 88, b4, regs); op7 = ARCH_DEP(wfetch8)(effective_addr4 + 120, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); op8alet = ARCH_DEP(wfetch4)(effective_addr4 + 132, b4, regs); regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ #if defined(FEATURE_ESAME) op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); #else op4addr = ARCH_DEP(wfetch4)(effective_addr4 + 76, b4, regs); #endif op4addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op4addr, regs); /* Load address of operand 6 */ #if defined(FEATURE_ESAME) op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); #else op6addr = ARCH_DEP(wfetch4)(effective_addr4 + 108, b4, regs); #endif op6addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op6addr, regs); /* Load address of operand 8 */ #if defined(FEATURE_ESAME) op8addr = ARCH_DEP(wfetch8)(effective_addr4 + 136, b4, regs); #else op8addr = ARCH_DEP(wfetch4)(effective_addr4 + 140, b4, regs); #endif op8addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op8addr, regs); /* Verify access to 8th operand */ ARCH_DEP(validate_operand) (op8addr, r3, 8-1,ACCTYPE_WRITE_SKP, regs); /* Verify access to 6th operand */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(validate_operand) (op6addr, r3, 8-1,ACCTYPE_WRITE_SKP, regs); /* Store 3th op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op3, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op5, op6addr, r3, regs); /* Store 7th op at 8th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op7, op8addr, r3, regs); /* Store 1st op replacement value at 2nd op */ ARCH_DEP(vstore8)(op1r, effective_addr2, b2, regs); return 0; } else { ARCH_DEP(wstore8)(op2, effective_addr4 + 8, b4, regs); return 1; } } #if defined(FEATURE_ESAME) int ARCH_DEP(plo_cststgr) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { U64 op2, op3, op5, op7; U32 op4alet = 0, op6alet = 0, op8alet = 0; VADR op4addr, op6addr, op8addr; ODD_CHECK(r1, regs); DW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); op2 = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); if(regs->GR_G(r1) == op2) { op3 = ARCH_DEP(wfetch8)(effective_addr4 + 56, b4, regs); op5 = ARCH_DEP(wfetch8)(effective_addr4 + 88, b4, regs); op7 = ARCH_DEP(wfetch8)(effective_addr4 + 120, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); op8alet = ARCH_DEP(wfetch4)(effective_addr4 + 132, b4, regs); regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); op4addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op4addr, regs); /* Load address of operand 6 */ op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); op6addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op6addr, regs); /* Load address of operand 8 */ op8addr = ARCH_DEP(wfetch8)(effective_addr4 + 136, b4, regs); op8addr &= ADDRESS_MAXWRAP(regs); DW_CHECK(op8addr, regs); /* Verify access to 8th operand */ ARCH_DEP(validate_operand) (op8addr, r3, 8-1,ACCTYPE_WRITE_SKP, regs); /* Verify access to 6th operand */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(validate_operand) (op6addr, r3, 8-1,ACCTYPE_WRITE_SKP, regs); /* Store 3rd op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op3, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op5, op6addr, r3, regs); /* Store 7th op at 8th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstore8)(op7, op8addr, r3, regs); /* Store 1st op replacement at 2nd op */ ARCH_DEP(vstore8)(regs->GR_G(r1+1), effective_addr2, b2, regs); return 0; } else { regs->GR_G(r1) = op2; return 1; } } #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) int ARCH_DEP(plo_cststx) (int r1, int r3, VADR effective_addr2, int b2, VADR effective_addr4, int b4, REGS *regs) { BYTE op1c[16], op1r[16], op2[16], op3[16], op5[16], op7[16]; U32 op4alet = 0, op6alet = 0, op8alet = 0; VADR op4addr, op6addr, op8addr; UNREFERENCED(r1); QW_CHECK(effective_addr2, regs); DW_CHECK(effective_addr4, regs); ARCH_DEP(vfetchc)(op1c, 16-1, effective_addr4 + 0, b4, regs); ARCH_DEP(vfetchc)(op2, 16-1, effective_addr2, b2, regs); if(memcmp(op1c,op2,16) == 0) { ARCH_DEP(wfetchc)(op1r, 16-1, effective_addr4 + 16, b4, regs); ARCH_DEP(wfetchc)(op3, 16-1, effective_addr4 + 48, b4, regs); ARCH_DEP(wfetchc)(op5, 16-1, effective_addr4 + 80, b4, regs); ARCH_DEP(wfetchc)(op7, 16-1, effective_addr4 + 112, b4, regs); /* Verify access to 2nd operand */ ARCH_DEP(validate_operand) (effective_addr2, b2, 16-1, ACCTYPE_WRITE_SKP, regs); /* When in ar mode, ar3 is used to access the operand. The alet is fetched from the pl */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { if(r3 == 0) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); op4alet = ARCH_DEP(wfetch4)(effective_addr4 + 68, b4, regs); op6alet = ARCH_DEP(wfetch4)(effective_addr4 + 100, b4, regs); op8alet = ARCH_DEP(wfetch4)(effective_addr4 + 132, b4, regs); regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } /* Load address of operand 4 */ op4addr = ARCH_DEP(wfetch8)(effective_addr4 + 72, b4, regs); op4addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op4addr, regs); /* Load address of operand 6 */ op6addr = ARCH_DEP(wfetch8)(effective_addr4 + 104, b4, regs); op6addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op6addr, regs); /* Load address of operand 8 */ op8addr = ARCH_DEP(wfetch8)(effective_addr4 + 136, b4, regs); op8addr &= ADDRESS_MAXWRAP(regs); QW_CHECK(op8addr, regs); /* Verify access to 8th operand */ ARCH_DEP(validate_operand) (op8addr, r3, 16-1,ACCTYPE_WRITE_SKP, regs); /* Verify access to 6th operand */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(validate_operand) (op6addr, r3, 16-1, ACCTYPE_WRITE_SKP, regs); /* Store 3th op at 4th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op4alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstorec)(op3, 16-1, op4addr, r3, regs); /* Store 5th op at 6th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op6alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstorec)(op5, 16-1, op6addr, r3, regs); /* Store 7th op at 8th op */ if(!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { regs->AR(r3) = op8alet; SET_AEA_AR(regs, r3); } ARCH_DEP(vstorec)(op7, 16-1, op8addr, r3, regs); /* Store 1st op replacement value at 2nd op */ ARCH_DEP(vstorec)(op1r, 16-1, effective_addr2, b2, regs); return 0; } else { ARCH_DEP(vstorec)(op2, 16-1, effective_addr4 + 0, b4, regs); return 1; } } #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_PERFORM_LOCKED_OPERATION)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "plo.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "plo.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/control.c0000664000175000017500000101563612564723224012043 00000000000000/* CONTROL.C (c) Copyright Roger Bowler, 1994-2010 */ /* ESA/390 CPU Emulator */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements all control instructions of the */ /* S/370 and ESA/390 architectures, as described in the manuals */ /* GA22-7000-03 System/370 Principles of Operation */ /* SA22-7201-06 ESA/390 Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Bad frame support by Jan Jaeger */ /* Branch tracing by Jan Jaeger */ /* CSP instructions by Jan Jaeger */ /* Instruction decode by macros - Jan Jaeger */ /* Prevent TOD from going backwards in time - Jan Jaeger */ /* Instruction decode rework - Jan Jaeger */ /* PR may lose pending interrupts - Jan Jaeger */ /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */ /* ESAME low-address protection - Roger Bowler */ /* ESAME linkage stack operations - Roger Bowler */ /* ESAME BSA instruction - Roger Bowler v209c*/ /* ASN-and-LX-reuse facility - Roger Bowler June 2004*/ /* SIGP orders 11,12.2,13,15 - Fish Oct 2005*/ /* Configuration topology facility fixes by PaoloG Oct 2013*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_CONTROL_C_) #define _CONTROL_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(OPTION_FISHIO) #include "w32chan.h" #endif // defined(OPTION_FISHIO) /* Temporary debug */ extern int ipending_cmd(int,void *,void *); #if defined(FEATURE_BRANCH_AND_SET_AUTHORITY) /*-------------------------------------------------------------------*/ /* B25A BSA - Branch and Set Authority [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_set_authority) { int r1, r2; /* Values of R fields */ U32 ducto; /* DUCT origin */ U32 duct_pkrp; /* DUCT PKM/Key/RA/P word */ RADR duct_reta; /* DUCT return address/amode */ BYTE key; /* New PSW key */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ RRE(inst, regs, r1, r2); /* Special operation exception if ASF is not enabled */ if (!ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, BSA)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Load real address of dispatchable unit control table */ ducto = regs->CR(2) & CR2_DUCTO; /* Apply low-address protection to stores into the DUCT */ if (ARCH_DEP(is_low_address_protected) (ducto, regs)) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = (ducto & STORAGE_KEY_PAGEMASK); regs->excarid = 0; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION); } /* Convert DUCT real address to absolute address */ ducto = APPLY_PREFIXING (ducto, regs->PX); /* Program check if DUCT origin address is invalid */ if (ducto > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(FEATURE_ESAME) /* For ESAME, load the PKM/Key/RA/P from DUCT word 5, and load the return address and amode from DUCT words 8 and 9 (note: the DUCT cannot cross a page boundary) */ duct_pkrp = ARCH_DEP(fetch_fullword_absolute) (ducto+20, regs); duct_reta = ARCH_DEP(fetch_doubleword_absolute) (ducto+32, regs); #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390, load the PKM/Key/RA/P from DUCT word 9, and load the return address and amode from DUCT word 8 (note: the DUCT cannot cross a page boundary) */ duct_pkrp = ARCH_DEP(fetch_fullword_absolute) (ducto+36, regs); duct_reta = ARCH_DEP(fetch_fullword_absolute) (ducto+32, regs); #endif /*!defined(FEATURE_ESAME)*/ /* Perform base authority or reduced authority operation */ if ((duct_pkrp & DUCT_RA) == 0) { /* In base authority state R2 cannot specify register zero */ if (r2 == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #ifdef FEATURE_TRACING /* Perform tracing */ if (regs->CR(12) & CR12_BRTRACE) newcr12 = ARCH_DEP(trace_br) (regs->GR_L(r2) & 0x80000000, regs->GR_L(r2), regs); #endif /*FEATURE_TRACING*/ /* Obtain the new PSW key from R1 register bits 24-27 */ key = regs->GR_L(r1) & 0x000000F0; /* Privileged operation exception if in problem state and current PSW key mask does not permit new key value */ if (PROBSTATE(®s->psw) && ((regs->CR(3) << (key >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Save current PSW amode and instruction address */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { duct_reta = PSW_IA(regs, 0); } else #endif /*!defined(FEATURE_ESAME)*/ { duct_reta = PSW_IA(regs, 0) & DUCT_IA31; if (regs->psw.amode) duct_reta |= DUCT_AM31; } /* Save current PSW key mask, PSW key, and problem state */ duct_pkrp = (regs->CR(3) & CR3_KEYMASK) | regs->psw.pkey; if (PROBSTATE(®s->psw)) duct_pkrp |= DUCT_PROB; /* Set the reduced authority bit */ duct_pkrp |= DUCT_RA; #if defined(FEATURE_ESAME) /* For ESAME, store the PKM/Key/RA/P into DUCT word 5, and store the return address and amode into DUCT words 8 and 9 (note: the DUCT cannot cross a page boundary) */ ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+20, regs); ARCH_DEP(store_doubleword_absolute) (duct_reta, ducto+32, regs); #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390, store the PKM/Key/RA/P into DUCT word 9, and store the return address and amode into DUCT word 8 (note: the DUCT cannot cross a page boundary) */ ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+36, regs); ARCH_DEP(store_fullword_absolute) (duct_reta, ducto+32, regs); #endif /*!defined(FEATURE_ESAME)*/ /* Load new PSW key and PSW key mask from R1 register */ regs->psw.pkey = key; regs->CR_LHH(3) &= regs->GR_LHH(r1); /* Set the problem state bit in the current PSW */ regs->psw.states |= BIT(PSW_PROB_BIT); /* Set the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); /* Set PSW instruction address and amode from R2 register */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { UPD_PSW_IA(regs, regs->GR_G(r2)); } else #endif /*defined(FEATURE_ESAME)*/ if (regs->GR_L(r2) & 0x80000000) { #if defined(FEATURE_ESAME) regs->psw.amode64 = 0; #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode = 1; regs->psw.AMASK = AMASK31; UPD_PSW_IA(regs, regs->GR_L(r2)); } else { #if defined(FEATURE_ESAME) regs->psw.amode64 = #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode = 0; regs->psw.AMASK = AMASK24; UPD_PSW_IA(regs, regs->GR_L(r2)); } } /* end if(BSA-ba) */ else { /* BSA-ra */ /* In reduced authority state R2 must specify register zero */ if (r2 != 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #ifdef FEATURE_TRACING /* Perform tracing */ if (regs->CR(12) & CR12_BRTRACE) newcr12 = ARCH_DEP(trace_br) (duct_reta & DUCT_AM31, duct_reta &DUCT_IA31, regs); #endif /*FEATURE_TRACING*/ /* Set the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); /* If R1 is non-zero, save the current PSW addressing mode and instruction address in the R1 register */ if (r1 != 0) { #if defined(FEATURE_ESAME) if (regs->psw.amode64) { regs->GR_G(r1) = PSW_IA(regs, 0); } else #endif /*defined(FEATURE_ESAME)*/ { regs->GR_L(r1) = PSW_IA(regs, 0); if (regs->psw.amode) regs->GR_L(r1) |= 0x80000000; } } /* Restore PSW amode and instruction address from the DUCT */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { UPD_PSW_IA(regs, duct_reta); } else #endif /*defined(FEATURE_ESAME)*/ { regs->psw.amode = (duct_reta & DUCT_AM31) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; UPD_PSW_IA(regs, duct_reta & DUCT_IA31); } /* Restore the PSW key mask from the DUCT */ regs->CR_L(3) &= 0x0000FFFF; regs->CR_L(3) |= duct_pkrp & DUCT_PKM; /* Restore the PSW key from the DUCT */ regs->psw.pkey = duct_pkrp & DUCT_KEY; /* Restore the problem state bit from the DUCT */ if (duct_pkrp & DUCT_PROB) regs->psw.states |= BIT(PSW_PROB_BIT); else regs->psw.states &= ~BIT(PSW_PROB_BIT); /* Reset the reduced authority bit in the DUCT */ duct_pkrp &= ~DUCT_RA; #if defined(FEATURE_ESAME) ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+20, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(store_fullword_absolute) (duct_pkrp, ducto+36, regs); #endif /*!defined(FEATURE_ESAME)*/ /* Specification exception if the PSW is now invalid. */ /* (Since UPD_PSW_IA used above masks off inval bits */ /* in psw.IA, test duct_reta for invalid bits). */ if ((duct_reta & 1) #if defined(FEATURE_ESAME) || (regs->psw.amode64 == 0 && regs->psw.amode == 0 && (duct_reta & 0x7F000000))) #else /*!defined(FEATURE_ESAME)*/ || (regs->psw.amode == 0 && duct_reta > 0x00FFFFFF)) #endif /*!defined(FEATURE_ESAME)*/ { /* program_interrupt will invoke INVALIDATE_AIA which */ /* will apply address mask to psw.IA if aie valid. */ regs->aie = NULL; regs->psw.IA = duct_reta; regs->psw.zeroilc = 1; ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } } /* end if(BSA-ra) */ #ifdef FEATURE_TRACING /* Update trace table address if branch tracing is on */ if (regs->CR(12) & CR12_BRTRACE) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ /* Check for Successful Branch PER event */ PER_SB(regs, regs->psw.IA); } /* end DEF_INST(branch_and_set_authority) */ #endif /*defined(FEATURE_BRANCH_AND_SET_AUTHORITY)*/ #if defined(FEATURE_SUBSPACE_GROUP) /*-------------------------------------------------------------------*/ /* B258 BSG - Branch in Subspace Group [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_in_subspace_group) { int r1, r2; /* Values of R fields */ U32 alet; /* Destination subspace ALET */ U32 dasteo=0; /* Destination ASTE origin */ U32 daste[16]; /* ASN second table entry */ RADR ducto; /* DUCT origin */ U32 duct0; /* DUCT word 0 */ U32 duct1; /* DUCT word 1 */ U32 duct3; /* DUCT word 3 */ RADR abs; /* Absolute address */ BYTE *mn; /* Mainstor address */ VADR newia; /* New instruction address */ U16 xcode; /* Exception code */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ CREG inst_cr; /* Instruction CR */ RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); /* Special operation exception if DAT is off or ASF not enabled */ if (REAL_MODE(&(regs->psw)) || !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); inst_cr = regs->CR(regs->aea_ar[USE_INST_SPACE]); #ifdef FEATURE_TRACING /* Perform tracing */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_bsg) ((r2 == 0) ? 0 : regs->AR(r2), regs->GR_L(r2), regs); else if (regs->CR(12) & CR12_BRTRACE) newcr12 = ARCH_DEP(trace_br) (regs->GR_L(r2) & 0x80000000, regs->GR_L(r2), regs); #endif /*FEATURE_TRACING*/ /* Load real address of dispatchable unit control table */ ducto = regs->CR(2) & CR2_DUCTO; /* Apply low-address protection to stores into the DUCT */ if (ARCH_DEP(is_low_address_protected) (ducto, regs)) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = (ducto & STORAGE_KEY_PAGEMASK); regs->excarid = 0; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION); } /* Convert DUCT real address to absolute address */ ducto = APPLY_PREFIXING (ducto, regs->PX); /* Program check if DUCT origin address is invalid */ if (ducto > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch DUCT words 0, 1, and 3 from absolute storage (note: the DUCT cannot cross a page boundary) */ mn = FETCH_MAIN_ABSOLUTE (ducto, regs, 16); duct0 = fetch_fw (mn); duct1 = fetch_fw (mn+4); duct3 = fetch_fw (mn+12); /* Special operation exception if the current primary ASTE origin is not the same as the base ASTE for the dispatchable unit */ if ((regs->CR_L(5) & CR5_PASTEO) != (duct0 & DUCT0_BASTEO)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Obtain the destination ALET from the R2 access register, except that register zero means destination ALET is zero */ alet = (r2 == 0) ? 0 : regs->AR(r2); /* Perform special ALET translation to obtain destination ASTE */ switch (alet) { case ALET_PRIMARY: /* Branch to base space */ /* Load the base space ASTE origin from the DUCT */ dasteo = duct0 & DUCT0_BASTEO; /* Convert the ASTE origin to an absolute address */ abs = APPLY_PREFIXING (dasteo, regs->PX); /* Program check if ASTE origin address is invalid */ if (abs > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch destination ASTE words 2 and 3 from absolute storage (note: the ASTE cannot cross a page boundary) */ mn = FETCH_MAIN_ABSOLUTE (abs, regs, 16); daste[2] = fetch_fw (mn+8); daste[3] = fetch_fw (mn+12); break; case ALET_SECONDARY: /* Branch to last-used subspace */ /* Load the subspace ASTE origin from the DUCT */ dasteo = duct1 & DUCT1_SSASTEO; /* Special operation exception if SSASTEO is zero */ if (dasteo == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Convert the ASTE origin to an absolute address */ abs = APPLY_PREFIXING (dasteo, regs->PX); /* Program check if ASTE origin address is invalid */ if (abs > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch subspace ASTE words 0, 2, 3, and 5 from absolute storage (note: the ASTE cannot cross a page boundary) */ mn = FETCH_MAIN_ABSOLUTE (abs, regs, 24); daste[0] = fetch_fw (mn); daste[2] = fetch_fw (mn+8); daste[3] = fetch_fw (mn+12); daste[5] = fetch_fw (mn+20); /* ASTE validity exception if ASTE invalid bit is one */ if (daste[0] & ASTE0_INVALID) { regs->excarid = r2; ARCH_DEP(program_interrupt) (regs, PGM_ASTE_VALIDITY_EXCEPTION); } /* ASTE sequence exception if the subspace ASTE sequence number does not match the sequence number in the DUCT */ if ((daste[5] & ASTE5_ASTESN) != (duct3 & DUCT3_SSASTESN)) { regs->excarid = r2; ARCH_DEP(program_interrupt) (regs, PGM_ASTE_SEQUENCE_EXCEPTION); } break; default: /* ALET not 0 or 1 */ /* Perform special ART to obtain destination ASTE */ xcode = ARCH_DEP(translate_alet) (alet, 0, ACCTYPE_BSG, regs, &dasteo, daste); /* Program check if ALET translation error */ if (xcode != 0) { regs->excarid = r2; ARCH_DEP(program_interrupt) (regs, xcode); } /* Special operation exception if the destination ASTE is the base space of a different subspace group */ if (dasteo != (duct0 & DUCT0_BASTEO) && ((ASTE_AS_DESIGNATOR(daste) & SSGROUP_BIT) == 0 || (daste[0] & ASTE0_BASE) )) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* end switch(alet) */ /* Update the primary STD (or ASCE) from the destination ASTE */ if ((dasteo == (duct0 & DUCT0_BASTEO)) && (alet != ALET_SECONDARY)) { /* When the destination ASTE is the base space, replace the primary STD (or ASCE) by the STD (or ASCE) in the ASTE */ regs->CR(1) = ASTE_AS_DESIGNATOR(daste); } else { /* When the destination ASTE is a subspace, replace the primary STD or ASCE by the STD or ASTE in the ASTE, except for the space-switch event and storage alteration event bits, which remain unchanged */ regs->CR(1) &= (SSEVENT_BIT | SAEVENT_BIT); regs->CR(1) |= (ASTE_AS_DESIGNATOR(daste) & ~((RADR)(SSEVENT_BIT | SAEVENT_BIT))); } /* Compute the branch address from the R2 operand */ newia = regs->GR(r2); /* If R1 is non-zero, save the current PSW addressing mode and instruction address in the R1 register */ if (r1 != 0) { #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_G(r1) = PSW_IA(regs, 0); else #endif /*!defined(FEATURE_ESAME)*/ regs->GR_L(r1) = PSW_IA(regs, 0) | (regs->psw.amode ? 0x80000000 : 0); } /* Update the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); #if defined(FEATURE_ESAME) if (regs->psw.amode64 == 0 && (newia & 0x80000000)) #else /*!defined(FEATURE_ESAME)*/ if (newia & 0x80000000) #endif /*!defined(FEATURE_ESAME)*/ { regs->psw.amode = 1; regs->psw.AMASK = AMASK31; } else { regs->psw.amode = 0; regs->psw.AMASK = AMASK24; } /* Set mode and branch to address specified by R2 operand */ UPD_PSW_IA(regs, newia); /* Set the SSTD (or SASCE) equal to PSTD (or PASCE) */ regs->CR(7) = regs->CR(1); /* Set SASN equal to PASN */ regs->CR_LHL(3) = regs->CR_LHL(4); /* When ASN-and-LX-reuse is installed and enabled by CR0, set the SASTEIN in CR3 equal to the PASTEIN in CR4 */ if (ASN_AND_LX_REUSE_ENABLED(regs)) { regs->CR_H(3) = regs->CR_H(4); } /* end if (ASN_AND_LX_REUSE_ENABLED) */ /* Reset the subspace fields in the DUCT */ if (alet == ALET_SECONDARY) { /* When the destination ASTE specifies a subspace by means of ALET 1, set the subspace active bit in the DUCT */ duct1 |= DUCT1_SA; ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs); } else if (dasteo == (duct0 & DUCT0_BASTEO)) { /* When the destination ASTE is the base space, reset the subspace active bit in the DUCT */ duct1 &= ~DUCT1_SA; ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs); } else { /* When the destination ASTE specifies a subspace by means of an ALET other than ALET 1, set the subspace active bit and store the subspace ASTE origin in the DUCT */ duct1 = DUCT1_SA | dasteo; ARCH_DEP(store_fullword_absolute) (duct1, ducto+4, regs); /* Set the subspace ASTE sequence number in the DUCT equal to the destination ASTE sequence number */ duct3 = daste[5]; ARCH_DEP(store_fullword_absolute) (duct3, ducto+12, regs); } #ifdef FEATURE_TRACING /* Update trace table address if ASN tracing or branch tracing */ if (regs->CR(12) & (CR12_ASNTRACE | CR12_BRTRACE)) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ SET_AEA_COMMON(regs); if (inst_cr != regs->CR(regs->aea_ar[USE_INST_SPACE])) INVALIDATE_AIA(regs); /* Check for Successful Branch PER event */ PER_SB(regs, regs->psw.IA); } /* end DEF_INST(branch_in_subspace_group) */ #endif /*defined(FEATURE_SUBSPACE_GROUP)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B240 BAKR - Branch and Stack Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_and_stack) { int r1, r2; /* Values of R fields */ VADR n1, n2; /* Operand values */ #ifdef FEATURE_TRACING VADR n = 0; /* Work area */ #endif /*FEATURE_TRACING*/ RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, BAKR)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* [5.12.3]/ Fig 10-2 Special operation exception if ASF is not enabled, or if DAT is off, or if not primary-space mode or AR-mode */ if (!ASF_ENABLED(regs) || REAL_MODE(®s->psw) || SPACE_BIT(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Obtain the return address and addressing mode from the R1 register, or use updated PSW if R1 is zero */ if ( r1 != 0 ) { n1 = regs->GR(r1); #if defined(FEATURE_ESAME) if ( (n1 & 0x01) == 0 ) n1 &= (n1 & 0x80000000) ? 0xFFFFFFFF : 0x00FFFFFF; #else /*!defined(FEATURE_ESAME)*/ if ( (n1 & 0x80000000) == 0 ) n1 &= 0x00FFFFFF; #endif /*!defined(FEATURE_ESAME)*/ } else { n1 = PSW_IA(regs, 0); #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) n1 |= 0x01; else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) n1 |= 0x80000000; } /* Obtain the branch address from the R2 register, or use the updated PSW instruction address if R2 is zero */ n2 = (r2 != 0) ? regs->GR(r2) : PSW_IA(regs, 0); n2 &= ADDRESS_MAXWRAP(regs); /* Set the addressing mode bit in the branch address */ #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) n2 |= 0x01; else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) n2 |= 0x80000000; #ifdef FEATURE_TRACING /* Form the branch trace entry */ if((regs->CR(12) & CR12_BRTRACE) && (r2 != 0)) n = ARCH_DEP(trace_br)(regs->psw.amode, regs->GR_L(r2), regs); #endif /*FEATURE_TRACING*/ /* Form the linkage stack entry */ ARCH_DEP(form_stack_entry) (LSED_UET_BAKR, n1, n2, 0, 0, regs); #ifdef FEATURE_TRACING /* Update CR12 to reflect the new branch trace entry */ if((regs->CR(12) & CR12_BRTRACE) && (r2 != 0)) regs->CR(12) = n; #endif /*FEATURE_TRACING*/ /* Execute the branch unless R2 specifies register 0 */ if ( r2 != 0 ) { UPDATE_BEAR(regs, -4); UPD_PSW_IA(regs, regs->GR(r2)); PER_SB(regs, regs->psw.IA); } } /* end DEF_INST(branch_and_stack) */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_BROADCASTED_PURGING) /*-------------------------------------------------------------------*/ /* B250 CSP - Compare and Swap and Purge [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_swap_and_purge) { int r1, r2; /* Values of R fields */ U64 n2; /* virtual address of op2 */ BYTE *main2; /* mainstor address of op2 */ U32 old; /* old value */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); ODD_CHECK(r1, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs,IC0, IPTECSP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && regs->sie_scao) { STORAGE_KEY(regs->sie_scao, regs) |= STORKEY_REF; if(regs->mainstor[regs->sie_scao] & 0x80) longjmp(regs->progjmp, SIE_INTERCEPT_INST); } #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Obtain 2nd operand address from r2 */ n2 = regs->GR(r2) & 0xFFFFFFFFFFFFFFFCULL & ADDRESS_MAXWRAP(regs); main2 = MADDR (n2, r2, regs, ACCTYPE_WRITE, regs->psw.pkey); old = CSWAP32 (regs->GR_L(r1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg4 (&old, CSWAP32(regs->GR_L(r1+1)), main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); if (regs->psw.cc == 0) { /* Perform requested funtion specified as per request code in r2 */ if (regs->GR_L(r2) & 3) { OBTAIN_INTLOCK(regs); SYNCHRONIZE_CPUS(regs); if (regs->GR_L(r2) & 1) ARCH_DEP(purge_tlb_all)(); if (regs->GR_L(r2) & 2) ARCH_DEP(purge_alb_all)(); RELEASE_INTLOCK(regs); } } else { PTT(PTT_CL_CSF,"*CSP",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); /* Otherwise yield */ regs->GR_L(r1) = CSWAP32(old); if (sysblk.cpus > 1) sched_yield(); } /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); } /* end DEF_INST(compare_and_swap_and_purge) */ #endif /*defined(FEATURE_BROADCASTED_PURGING)*/ /*-------------------------------------------------------------------*/ /* 83 DIAG - Diagnose [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(diagnose) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RS(inst, regs, r1, r3, b2, effective_addr2); #if defined(FEATURE_ECPSVM) if(ecpsvm_dodiag(regs,r1,r3,b2,effective_addr2)==0) { return; } #endif #ifdef FEATURE_HERCULES_DIAGCALLS if ( #if defined(_FEATURE_SIE) !SIE_MODE(regs) && #endif /* defined(_FEATURE_SIE) */ effective_addr2 != 0xF08) #endif PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_INF,"DIAG",regs->GR_L(r1),regs->GR_L(r3),(U32)(effective_addr2 & 0xffffff)); /* Process diagnose instruction */ ARCH_DEP(diagnose_call) (effective_addr2, b2, r1, r3, regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); #ifdef FEATURE_HERCULES_DIAGCALLS RETURN_INTCHECK(regs); #endif } /* end DEF_INST(diagnose) */ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B226 EPAR - Extract Primary ASN [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_primary_asn) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( PROBSTATE(®s->psw) && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load R1 bits 48-63 with PASN from control register 4 bits 48-63 and zeroize R1 bits 32-47 */ regs->GR_L(r1) = regs->CR_LHL(4); } /* end DEF_INST(extract_primary_asn) */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_ASN_AND_LX_REUSE) /*-------------------------------------------------------------------*/ /* B99A EPAIR - Extract Primary ASN and Instance [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_primary_asn_and_instance) { int r1, r2; /* Values of R fields */ /* Operation exception if ASN-and-LX-reuse is not enabled */ if(!sysblk.asnandlxreuse) { ARCH_DEP(operation_exception)(inst,regs); } RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( PROBSTATE(®s->psw) && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load R1 bits 48-63 with PASN from control register 4 bits 48-63 and zeroize R1 bits 32-47 */ regs->GR_L(r1) = regs->CR_LHL(4); /* Load R1 bits 0-31 with PASTEIN from control register 4 bits 0-31 */ regs->GR_H(r1) = regs->CR_H(4); } /* end DEF_INST(extract_primary_asn_and_instance) */ #endif /*defined(FEATURE_ASN_AND_LX_REUSE)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B227 ESAR - Extract Secondary ASN [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_secondary_asn) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( PROBSTATE(®s->psw) && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load R1 bits 48-63 with SASN from control register 3 bits 48-63 and zeroize R1 bits 32-47 */ regs->GR_L(r1) = regs->CR_LHL(3); } /* end DEF_INST(extract_secondary_asn) */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_ASN_AND_LX_REUSE) /*-------------------------------------------------------------------*/ /* B99B ESAIR - Extract Secondary ASN and Instance [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_secondary_asn_and_instance) { int r1, r2; /* Values of R fields */ /* Operation exception if ASN-and-LX-reuse is not enabled */ if(!sysblk.asnandlxreuse) { ARCH_DEP(operation_exception)(inst,regs); } RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( PROBSTATE(®s->psw) && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load R1 bits 48-63 with SASN from control register 3 bits 48-63 and zeroize R1 bits 32-47 */ regs->GR_L(r1) = regs->CR_LHL(3); /* Load R1 bits 0-31 with SASTEIN from control register 3 bits 0-31 */ regs->GR_H(r1) = regs->CR_H(3); } /* end DEF_INST(extract_secondary_asn_and_instance) */ #endif /*defined(FEATURE_ASN_AND_LX_REUSE)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B249 EREG - Extract Stacked Registers [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_stacked_registers) { int r1, r2; /* Values of R fields */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs); /* Load registers from the stack entry */ ARCH_DEP(unstack_registers) (0, lsea, r1, r2, regs); } #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B24A ESTA - Extract Stacked State [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_stacked_state) { int r1, r2; /* Values of R fields */ BYTE code; /* Extraction code */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ int max_esta_code; RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); if (REAL_MODE(®s->psw) || SECONDARY_SPACE_MODE(®s->psw) || !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load the extraction code from low-order byte of R2 register */ code = regs->GR_LHLCL(r2); #if defined(FEATURE_ASN_AND_LX_REUSE) max_esta_code=sysblk.asnandlxreuse?5:4; #elif defined(FEATURE_ESAME) max_esta_code=4; #else /*!defined(FEATURE_ESAME)*/ max_esta_code=3; #endif /*!defined(FEATURE_ESAME)*/ /* Program check if r1 is odd, or if extraction code is invalid */ if ((r1 & 1) || code > max_esta_code) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs); /* Load general register pair from state entry */ ARCH_DEP(stack_extract) (lsea, r1, code, regs); /* Set condition code depending on entry type */ regs->psw.cc = ((lsed.uet & LSED_UET_ET) == LSED_UET_PC) ? 1 : 0; } #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B224 IAC - Insert Address Space Control [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_address_space_control) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); /* Special operation exception if DAT is off */ if ( REAL_MODE(&(regs->psw)) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Except in XC mode */ && !SIE_STATB(regs, MX, XC) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( PROBSTATE(®s->psw) && !(regs->CR(0) & CR0_EXT_AUTH) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Ignore extraction control in XC mode */ && !SIE_STATB(regs, MX, XC) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Extract the address-space control bits from the PSW */ regs->psw.cc = (AR_BIT(®s->psw) << 1) | SPACE_BIT(®s->psw); /* Insert address-space mode into register bits 22-23 */ regs->GR_LHLCH(r1) = regs->psw.cc; } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* B20B IPK - Insert PSW Key [S] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_psw_key) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( PROBSTATE(®s->psw) && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Insert PSW key into bits 24-27 of general register 2 and set bits 28-31 of general register 2 to zero */ regs->GR_LHLCL(2) = regs->psw.pkey & 0xF0; } #if defined(FEATURE_BASIC_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* 09 ISK - Insert Storage Key [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_storage_key) { int r1, r2; /* Values of R fields */ RADR n; /* Absolute storage addr */ #if defined(_FEATURE_SIE) BYTE storkey; #endif /*defined(_FEATURE_SIE)*/ RR(inst, regs, r1, r2); PRIV_CHECK(regs); #if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE) if( #if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS) SIE_MODE(regs) && #endif !(regs->CR(0) & CR0_STORKEY_4K) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif /* Program check if R2 bits 28-31 are not zeroes */ if ( regs->GR_L(r2) & 0x0000000F ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Load 2K block address from R2 register */ n = regs->GR_L(r2) & 0x00FFF800; /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { if(SIE_STATB(regs, IC2, ISKE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) && SIE_STATB(regs, RCPO2, RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE; #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { RADR rcpa; BYTE rcpkey; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA)) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* The reference and change byte is located directly beyond the page table and is located at offset 1 in the entry. S/370 mode cannot be emulated in ESAME mode, so no provision is made for ESAME mode tables */ rcpa += 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; STORAGE_KEY(rcpa, regs) |= STORKEY_REF; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE); /* guest absolute to host real */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) #if defined(_FEATURE_STORAGE_KEY_ASSIST) { /* In case of storage key assist obtain the key and fetch bit from the PGSTE */ if(SIE_STATB(regs, RCPO0, SKA)) regs->GR_LHLCL(r1) = storkey | (regs->mainstor[rcpa-1] & (STORKEY_KEY | STORKEY_FETCH)); else longjmp(regs->progjmp, SIE_INTERCEPT_INST); } else #else /*!defined(_FEATURE_STORAGE_KEY_ASSIST)*/ longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = storkey | (STORAGE_KEY(n, regs) & 0xFE); #else regs->GR_LHLCL(r1) = storkey | ((STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE); #endif } } } else /* !sie_pref */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE; #endif } else /* !SIE_MODE */ #endif /*defined(_FEATURE_SIE)*/ /* Insert the storage key into R1 register bits 24-31 */ #if defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE; #endif /* In BC mode, clear bits 29-31 of R1 register */ if ( !ECMODE(®s->psw) ) regs->GR_LHLCL(r1) &= 0xF8; // /*debug*/logmsg("ISK storage block %8.8X key %2.2X\n", // regs->GR_L(r2), regs->GR_L(r1) & 0xFE); } #endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/ #if defined(FEATURE_EXTENDED_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B229 ISKE - Insert Storage Key Extended [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_storage_key_extended) { int r1, r2; /* Values of R fields */ RADR n; /* Workarea */ #if defined(_FEATURE_SIE) BYTE storkey; #endif /*defined(_FEATURE_SIE)*/ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* Load 4K block address from R2 register */ n = regs->GR(r2) & ADDRESS_MAXWRAP_E(regs); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { if(SIE_STATB(regs, IC2, ISKE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && SIE_STATB(regs, RCPO2, RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE; #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { RADR rcpa; BYTE rcpkey; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(SIE_STATB(regs, MX, XC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; STORAGE_KEY(rcpa, regs) |= STORKEY_REF; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE); /* guest absolute to host real */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) #if defined(_FEATURE_STORAGE_KEY_ASSIST) { /* In case of storage key assist obtain the key and fetch bit from the PGSTE */ if(SIE_STATB(regs, RCPO0, SKA)) regs->GR_LHLCL(r1) = storkey | (regs->mainstor[rcpa-1] & (STORKEY_KEY | STORKEY_FETCH)); else longjmp(regs->progjmp, SIE_INTERCEPT_INST); } else #else /*!defined(_FEATURE_STORAGE_KEY_ASSIST)*/ longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = storkey | (STORAGE_KEY(n, regs) & 0xFE); #else regs->GR_LHLCL(r1) = storkey | ((STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE); #endif } } } else /* sie_pref */ /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE; #endif } else /* !SIE_MODE */ #endif /*defined(_FEATURE_SIE)*/ /* Insert the storage key into R1 register bits 24-31 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xFE; #else regs->GR_LHLCL(r1) = (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) & 0xFE; #endif } /* end DEF_INST(insert_storage_key_extended) */ #endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B223 IVSK - Insert Virtual Storage Key [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_virtual_storage_key) { int r1, r2; /* Values of R fields */ VADR effective_addr; /* Virtual storage addr */ RADR n; /* 32-bit operand values */ #if defined(_FEATURE_STORAGE_KEY_ASSIST) int sr; /* SIE_TRANSLATE_ADDR rc */ #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ RRE(inst, regs, r1, r2); /* Special operation exception if DAT is off */ if ( (regs->psw.sysmask & PSW_DATMODE) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and the extraction-authority control bit is zero */ if ( PROBSTATE(®s->psw) && (regs->CR(0) & CR0_EXT_AUTH) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load virtual storage address from R2 register */ effective_addr = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Translate virtual address to real address */ if (ARCH_DEP(translate_addr) (effective_addr, r2, regs, ACCTYPE_IVSK)) ARCH_DEP(program_interrupt) (regs, regs->dat.xcode); /* Convert real address to absolute address */ n = APPLY_PREFIXING (regs->dat.raddr, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_STORAGE_KEY_ASSIST) /* When running under SIE, and the guest absolute address is paged out, then obtain the storage key from the SPGTE rather then causing a host page fault. */ if(SIE_MODE(regs) && !regs->sie_pref && (SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && !SIE_FEATB(regs, RCPO2, RCPBY)) { /* guest absolute to host absolute addr or PTE addr in case of rc2 */ sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE); n = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); if(sr != 0 && sr != 2) ARCH_DEP(program_interrupt) (regs->hostregs, regs->hostregs->dat.xcode); if(sr == 2) { /* For ESA/390 the RCP byte entry is at offset 0 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ n += regs->hostregs->arch_mode == ARCH_900 ? 2048 : 1024; /* Insert PGSTE key bits 0-4 into R1 register bits 56-60 and set bits 61-63 to zeroes */ regs->GR_LHLCL(r1) = regs->mainstor[n] & 0xF8; } else /* Insert storage key bits 0-4 into R1 register bits 56-60 and set bits 61-63 to zeroes */ regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xF8; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); /* Insert storage key bits 0-4 into R1 register bits 56-60 and set bits 61-63 to zeroes */ regs->GR_LHLCL(r1) = STORAGE_KEY(n, regs) & 0xF8; } } /* end DEF_INST(insert_virtual_storage_key) */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* B221 IPTE - Invalidate Page Table Entry [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(invalidate_page_table_entry) { int r1, r2; /* Values of R fields */ RADR op1; U32 op2; #if defined(FEATURE_IPTE_RANGE_FACILITY) int r3; int op3; #endif /*defined(FEATURE_IPTE_RANGE_FACILITY)*/ #if defined(FEATURE_IPTE_RANGE_FACILITY) RRR(inst, regs, r1, r2, r3); #else /*defined(FEATURE_IPTE_RANGE_FACILITY)*/ RRE(inst, regs, r1, r2); #endif /*defined(FEATURE_IPTE_RANGE_FACILITY)*/ PRIV_CHECK(regs); op1 = regs->GR(r1); op2 = regs->GR_L(r2); #if defined(FEATURE_IPTE_RANGE_FACILITY) if (r3) { op3 = regs->GR_LHLCL(r3); if(op3 + ((op2 >> 12) & 0xFF) > 0xFF) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } else op3 = 0; #endif /*defined(FEATURE_IPTE_RANGE_FACILITY)*/ #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC0, IPTECSP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before operation */ PERFORM_SERIALIZATION (regs); OBTAIN_INTLOCK(regs); SYNCHRONIZE_CPUS(regs); #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && regs->sie_scao) { STORAGE_KEY(regs->sie_scao, regs) |= STORKEY_REF; if(regs->mainstor[regs->sie_scao] & 0x80) { RELEASE_INTLOCK(regs); longjmp(regs->progjmp, SIE_INTERCEPT_INST); } regs->mainstor[regs->sie_scao] |= 0x80; STORAGE_KEY(regs->sie_scao, regs) |= (STORKEY_REF|STORKEY_CHANGE); } #endif /*defined(_FEATURE_SIE)*/ #if defined(FEATURE_IPTE_RANGE_FACILITY) /* Invalidate the additional ptes as specfied by op3 */ for( ; op3; op3--, op2 += 0x1000) ARCH_DEP(invalidate_pte) (inst[1], op1, op2, regs); #endif /*defined(FEATURE_IPTE_RANGE_FACILITY)*/ /* Invalidate page table entry */ ARCH_DEP(invalidate_pte) (inst[1], op1, op2, regs); #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && regs->sie_scao) { regs->mainstor[regs->sie_scao] &= 0x7F; STORAGE_KEY(regs->sie_scao, regs) |= (STORKEY_REF|STORKEY_CHANGE); } #endif /*defined(_FEATURE_SIE)*/ RELEASE_INTLOCK(regs); } /* DEF_INST(invalidate_page_table_entry) */ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* E500 LASP - Load Address Space Parameters [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_address_space_parameters) { int b1, b2; /* Values of base field */ VADR effective_addr1, effective_addr2; /* Effective addresses */ U64 dreg; U32 sastein_d = 0; /* Designated SASTEIN */ U32 pastein_d = 0; /* Designated PASTEIN */ U32 sastein_new = 0; /* New SASTEIN */ U32 pastein_new = 0; /* New PASTEIN */ U16 pkm_d; /* Designated PKM */ U16 sasn_d; /* Designated SASN */ U16 ax_d; /* Designated AX */ U16 pasn_d; /* Designated PASN */ U32 aste[16]; /* ASN second table entry */ RADR pstd; /* Primary STD */ RADR sstd; /* Secondary STD */ U32 ltd; /* Linkage table designation */ U32 pasteo=0; /* Primary ASTE origin */ U32 sasteo=0; /* Secondary ASTE origin */ U16 ax; /* Authorisation index */ #ifdef FEATURE_SUBSPACE_GROUP U16 xcode; /* Exception code */ #endif /*FEATURE_SUBSPACE_GROUP*/ CREG inst_cr; /* Instruction CR */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); SIE_XC_INTERCEPT(regs); PRIV_CHECK(regs); /* Special operation exception if ASN translation control (bit 12 of control register 14) is zero */ if ( (regs->CR(14) & CR14_ASN_TRAN) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); DW_CHECK(effective_addr1, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC2, LASP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ inst_cr = regs->CR(regs->aea_ar[USE_INST_SPACE]); /* Fetch LASP parameters from first operand location (note that the storage-operand references for LASP may be multiple-access references) */ if (ASN_AND_LX_REUSE_ENABLED(regs)) { /* When ASN-and-LX-reuse is installed and enabled by CR0, the first operand consists of two doublewords */ /* The first doubleword contains the SASTEIN-d (32 bits), PKM-d (16 bits), and SASN-d (16 bits) */ dreg = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); sastein_d = (dreg >> 32); pkm_d = (dreg >> 16) & 0xFFFF; sasn_d = dreg & 0xFFFF; /* The second doubleword contains the PASTEIN-d (32 bits), AX-d (16 bits), and PASN-d (16 bits) */ effective_addr1 += 8; effective_addr1 &= ADDRESS_MAXWRAP(regs); dreg = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); pastein_d = (dreg >> 32); ax_d = (dreg >> 16) & 0xFFFF; pasn_d = dreg & 0xFFFF; } else /* !ASN_AND_LX_REUSE_ENABLED */ { /* When ASN-and-LX-reuse is not installed or not enabled, the first operand is one doubleword containing the PKM-d, SASN-d, AX-d, and PASN-d (16 bits each) */ dreg = ARCH_DEP(vfetch8) ( effective_addr1, b1, regs ); pkm_d = (dreg >> 48) & 0xFFFF; sasn_d = (dreg >> 32) & 0xFFFF; ax_d = (dreg >> 16) & 0xFFFF; pasn_d = dreg & 0xFFFF; } /* end else !ASN_AND_LX_REUSE_ENABLED */ /* PASN translation */ /* Perform PASN translation if PASN not equal to current PASN, or if LASP function bit 29 is set */ if ((effective_addr2 & 0x00000004) || pasn_d != regs->CR_LHL(4) ) { /* Translate PASN and return condition code 1 if AFX- or ASX-translation exception condition */ if (ARCH_DEP(translate_asn) (pasn_d, regs, &pasteo, aste)) { regs->psw.cc = 1; return; } /* When ASN-and-LX-reuse is installed and enabled by CR0, condition code 1 is also set if the PASTEIN-d does not equal the ASTEIN in word 11 of the ASTE */ if (ASN_AND_LX_REUSE_ENABLED(regs) && pastein_d != aste[11]) { regs->psw.cc = 1; return; } /* end if(ASN_AND_LX_REUSE_ENABLED && pastein_d!=aste[11]) */ /* Obtain new PSTD and LTD from ASTE */ pstd = ASTE_AS_DESIGNATOR(aste); ltd = ASTE_LT_DESIGNATOR(aste); ax = (aste[1] & ASTE1_AX) >> 16; /* When ASN-and-LX-reuse is installed and enabled by CR0, set the new PASTEIN equal to the PASTEIN-d */ if (ASN_AND_LX_REUSE_ENABLED(regs)) pastein_new = pastein_d; #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, &xcode, regs); /* Return with condition code 1 if ASTE exception recognized */ if (xcode != 0) { regs->psw.cc = 1; return; } #endif /*FEATURE_SUBSPACE_GROUP*/ /* Return with condition code 3 if either current STD or new STD indicates a space switch event */ if ((regs->CR(1) & SSEVENT_BIT) || (ASTE_AS_DESIGNATOR(aste) & SSEVENT_BIT)) { regs->psw.cc = 3; return; } } else { /* Load current PSTD and LTD or PASTEO */ pstd = regs->CR(1); ltd = regs->CR_L(5); /* ZZZ1 NOT SURE ABOUT THE MEANING OF THIS CODE: REFER TO ZZZ2 */ pasteo = regs->CR_L(5); /* ZZZ1 NOT SURE ABOUT THE MEANING OF THIS CODE: REFER TO ZZZ2 */ ax = (regs->CR(4) & CR4_AX) >> 16; /* When ASN-and-LX-reuse is installed and enabled by CR0, load the current PASTEIN */ if (ASN_AND_LX_REUSE_ENABLED(regs)) pastein_new = regs->CR_H(4); } /* If bit 30 of the LASP function bits is zero, use the current AX instead of the AX specified in the first operand */ if ((effective_addr2 & 0x00000002)) ax = ax_d; /* SASN translation */ /* If new SASN = new PASN then set new SSTD = new PSTD, also set the new SASTEIN equal to new PASTEIN when ASN-and-LX-reuse is installed and enabled by CR0 */ if (sasn_d == pasn_d) { sstd = pstd; if (ASN_AND_LX_REUSE_ENABLED(regs)) sastein_new = pastein_new; } else { /* If new SASN = current SASN, and bit 29 of the LASP function bits is 0, and bit 31 of the LASP function bits is 1, use current SSTD/SASCE in control register 7, also use current SASTEIN if ASN-and-LX-reuse is installed and enabled by CR0 */ if (!(effective_addr2 & 0x00000004) && (effective_addr2 & 0x00000001) && (sasn_d == regs->CR_LHL(3))) { sstd = regs->CR(7); if (ASN_AND_LX_REUSE_ENABLED(regs)) sastein_new = regs->CR_H(3); } else { /* Translate SASN and return condition code 2 if AFX- or ASX-translation exception condition */ if (ARCH_DEP(translate_asn) (sasn_d, regs, &sasteo, aste)) { regs->psw.cc = 2; return; } /* When ASN-and-LX-reuse is installed and enabled by CR0, condition code 2 is also set if the SASTEIN-d does not equal the ASTEIN in word 11 of the ASTE */ if (ASN_AND_LX_REUSE_ENABLED(regs) && sastein_d != aste[11]) { regs->psw.cc = 2; return; } /* end if(ASN_AND_LX_REUSE_ENABLED && sastein_d!=aste[11]) */ /* Obtain new SSTD or SASCE from secondary ASTE */ sstd = ASTE_AS_DESIGNATOR(aste); /* When ASN-and-LX-reuse is installed and enabled by CR0, set the new SASTEIN equal to the SASTEIN-d */ if (ASN_AND_LX_REUSE_ENABLED(regs)) sastein_new = sastein_d; #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new SSTD */ sstd = ARCH_DEP(subspace_replace) (sstd, sasteo, &xcode, regs); /* Return condition code 2 if ASTE exception recognized */ if (xcode != 0) { regs->psw.cc = 2; return; } #endif /*FEATURE_SUBSPACE_GROUP*/ /* Perform SASN authorization if bit 31 of the LASP function bits is 0 */ if (!(effective_addr2 & 0x00000001)) { /* Condition code 2 if SASN authorization fails */ if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY, regs)) { regs->psw.cc = 2; return; } } /* end if(SASN authorization) */ } /* end if(SASN translation) */ } /* end if(SASN = PASN) */ /* Perform control-register loading */ regs->CR(1) = pstd; regs->CR_LHH(3) = pkm_d; regs->CR_LHL(3) = sasn_d; regs->CR_LHH(4) = ax; regs->CR_LHL(4) = pasn_d; regs->CR_L(5) = ASF_ENABLED(regs) ? pasteo : ltd; /* ZZZ2 NOT SURE ABOUT THE MEANING OF THIS CODE: REFER TO ZZZ1 */ regs->CR(7) = sstd; if (ASN_AND_LX_REUSE_ENABLED(regs)) { regs->CR_H(3) = sastein_new; regs->CR_H(4) = pastein_new; } /* end if(ASN_AND_LX_REUSE_ENABLED) */ SET_AEA_COMMON(regs); if (inst_cr != regs->CR(regs->aea_ar[USE_INST_SPACE])) INVALIDATE_AIA(regs); /* Return condition code zero */ regs->psw.cc = 0; } /* end DEF_INST(load_address_space_parameters) */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* B7 LCTL - Load Control [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(load_control) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2 = NULL; /* Mainstor pointers */ U16 updated = 0; /* Updated control regs */ RS(inst, regs, r1, r3, b2, effective_addr2); #if defined(FEATURE_ECPSVM) if(ecpsvm_dolctl(regs,r1,r3,b2,effective_addr2)==0) { return; } #endif PRIV_CHECK(regs); FW_CHECK(effective_addr2, regs); /* Calculate number of regs to load */ n = ((r3 - r1) & 0xF) + 1; ITIMER_SYNC(effective_addr2,(n*4)-1,regs); #if defined(_FEATURE_SIE) if (SIE_MODE(regs)) { U16 cr_mask = fetch_hw (regs->siebk->lctl_ctl); for (i = 0; i < n; i++) if (cr_mask & BIT(15 - ((r1 + i) & 0xF))) longjmp(regs->progjmp, SIE_INTERCEPT_INST); } #endif /*defined(_FEATURE_SIE)*/ /* Calculate number of words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 2; /* Address of operand beginning */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely (m < n)) p2 = (U32*)MADDR(effective_addr2 + (m*4), b2, regs, ACCTYPE_READ, regs->psw.pkey); else m = n; /* Copy from operand beginning */ for (i = 0; i < m; i++, p1++) { regs->CR_L((r1 + i) & 0xF) = fetch_fw (p1); updated |= BIT((r1 + i) & 0xF); } /* Copy from next page */ for ( ; i < n; i++, p2++) { regs->CR_L((r1 + i) & 0xF) = fetch_fw (p2); updated |= BIT((r1 + i) & 0xF); } /* Actions based on updated control regs */ SET_IC_MASK(regs); #if __GEN_ARCH == 370 if (updated & BIT(1)) { SET_AEA_COMMON(regs); INVALIDATE_AIA(regs); } #else if (updated & (BIT(1) | BIT(7) | BIT(13))) SET_AEA_COMMON(regs); if (updated & BIT(regs->aea_ar[USE_INST_SPACE])) INVALIDATE_AIA(regs); #endif if (updated & BIT(9)) { OBTAIN_INTLOCK(regs); SET_IC_PER(regs); RELEASE_INTLOCK(regs); if (EN_IC_PER_SA(regs)) ARCH_DEP(invalidate_tlb)(regs,~(ACC_WRITE|ACC_CHECK)); } RETURN_INTCHECK(regs); } /* end DEF_INST(load_control) */ /*-------------------------------------------------------------------*/ /* 82 LPSW - Load Program Status Word [S] */ /*-------------------------------------------------------------------*/ DEF_INST(load_program_status_word) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ DBLWRD dword; int rc; #if defined(FEATURE_ESAME) int amode64; #endif /*defined(FEATURE_ESAME)*/ S(inst, regs, b2, effective_addr2); #if defined(FEATURE_ECPSVM) if(ecpsvm_dolpsw(regs,b2,effective_addr2)==0) { return; } #endif PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, LPSW)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Fetch new PSW from operand address */ STORE_DW ( dword, ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ) ); /* Set the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); /* Load updated PSW (ESA/390 Format in ESAME mode) */ #if !defined(FEATURE_ESAME) if ((rc = ARCH_DEP(load_psw) ( regs, dword ))) ARCH_DEP(program_interrupt) (regs, rc); #else /*defined(FEATURE_ESAME)*/ /* Make the PSW valid for ESA/390 mode after first saving our amode64 flag */ amode64 = dword[3] & 0x01; dword[3] &= ~0x01; /* Now call 's390_load_psw' to load our ESA/390 PSW for us */ rc = s390_load_psw ( regs, dword ); /* PROGRAMMING NOTE: z/Arch (ESAME) only supports the loading of ESA/390 mode (Extended Control mode (i.e. EC mode)) PSWs via the LPSW instruction. Thus the above 's390_load_psw' call has already checked to make sure bit 12 -- the EC mode bit (otherwise also known as the 'NOTESAME' bit) -- was set when the PSW was loaded (otherwise it would not have even returned and instead would have thrown a PGM_SPECIFICATION_EXCEPTION). Since we're actually executing in z/Arch (ESAME) mode though we now need to turn that bit off (since it's not supposed to be on for z/Arch (ESAME) mode) as explained in the Principles of Operations manual for the LPSW instruction. */ regs->psw.states &= ~BIT(PSW_NOTESAME_BIT); /* Restore the amode64 flag setting and set the actual correct AMASK value according to it (if we need to) since we had to force non-amode64 further above to get the 's390_load_psw' function to work right without erroneously program-checking. */ if((regs->psw.amode64 = amode64)) { regs->psw.AMASK = AMASK64; /* amode31 bit must be set when amode64 is set */ if(!regs->psw.amode) { regs->psw.zeroilc = 1; ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } } else /* Clear the high word of the address mask since the 's390_load_psw' function didn't do that for us */ regs->psw.AMASK_H = 0; /* Check for Load PSW success/failure */ if (rc) ARCH_DEP(program_interrupt) (regs, rc); /* Clear the high word of the instruction address since the 's390_load_psw' function didn't do that for us */ regs->psw.IA_H = 0; #endif /*defined(FEATURE_ESAME)*/ /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); RETURN_INTCHECK(regs); } /* end DEF_INST(load_program_status_word) */ /*-------------------------------------------------------------------*/ /* B1 LRA - Load Real Address [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load_real_address) { int r1; /* Register number */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX(inst, regs, r1, b2, effective_addr2); ARCH_DEP(load_real_address_proc) (regs, r1, b2, effective_addr2); } /* end DEF_INST(load_real_address) */ /*-------------------------------------------------------------------*/ /* Common processing routine for the LRA and LRAY instructions */ /*-------------------------------------------------------------------*/ void ARCH_DEP(load_real_address_proc) (REGS *regs, int r1, int b2, VADR effective_addr2) { int cc; /* Condition code */ SIE_XC_INTERCEPT(regs); PRIV_CHECK(regs); /* Translate the effective address to a real address */ cc = ARCH_DEP(translate_addr) (effective_addr2, b2, regs, ACCTYPE_LRA); /* If ALET exception or ASCE-type or region translation exception, set exception code in R1 bits 48-63, set bit 32 of R1, and set condition code 3 */ if (cc > 3) { regs->GR_L(r1) = 0x80000000 | regs->dat.xcode; cc = 3; } else { /* Set r1 and condition code as returned by translate_addr */ #if defined(FEATURE_ESAME) if (regs->psw.amode64 && cc != 3) { regs->GR_G(r1) = regs->dat.raddr; } else { if (regs->dat.raddr <= 0x7FFFFFFF) { regs->GR_L(r1) = regs->dat.raddr; } else { /* Special handling if in 24-bit or 31-bit mode and the returned address exceeds 2GB, or if cc=3 and the returned address exceeds 2GB */ if (cc == 0) { /* Real address exceeds 2GB */ ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* Condition code is 1, 2, or 3, and the returned table entry address exceeds 2GB. Convert to condition code 3 and return the exception code which will be X'0010' or X'0011' */ regs->GR_L(r1) = 0x80000000 | regs->dat.xcode; cc = 3; } /* end else(regs->dat.raddr) */ } /* end else(amode) */ #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(r1) = regs->dat.raddr; #endif /*!defined(FEATURE_ESAME)*/ } /* end else(cc) */ regs->psw.cc = cc; } /* end ARCH_DEP(load_real_address_proc) */ /*-------------------------------------------------------------------*/ /* B24B LURA - Load Using Real Address [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_using_real_address) { int r1, r2; /* Values of R fields */ RADR n; /* Unsigned work */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* R2 register contains operand real storage address */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Program check if operand not on fullword boundary */ FW_CHECK(n, regs); /* Load R1 register from second operand */ regs->GR_L(r1) = ARCH_DEP(vfetch4) ( n, USE_REAL_ADDR, regs ); } #if defined(FEATURE_LOCK_PAGE) /*-------------------------------------------------------------------*/ /* B262 LKPG - Lock Page [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(lock_page) { int r1, r2; /* Values of R fields */ VADR n2; /* effective addr of r2 */ RADR rpte; /* PTE real address */ CREG pte; /* Page Table Entry */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); if(REAL_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); if(regs->GR_L(0) & LKPG_GPR0_RESV) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); n2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Access to PTE must be serialized */ OBTAIN_MAINLOCK(regs); /* Return condition code 3 if translation exception */ if (ARCH_DEP(translate_addr) (n2, r2, regs, ACCTYPE_PTE) == 0) { rpte = APPLY_PREFIXING (regs->dat.raddr, regs->PX); pte = #if defined(FEATURE_ESAME) ARCH_DEP(fetch_doubleword_absolute) (rpte, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(fetch_fullword_absolute) (rpte, regs); #endif /*!defined(FEATURE_ESAME)*/ if(regs->GR_L(0) & LKPG_GPR0_LOCKBIT) { /* Lock request */ if(!(pte & PAGETAB_PGLOCK)) { /* Return condition code 3 if translation exception */ if(ARCH_DEP(translate_addr) (n2, r2, regs, ACCTYPE_LRA)) { regs->psw.cc = 3; RELEASE_MAINLOCK(regs); return; } pte |= PAGETAB_PGLOCK; #if defined(FEATURE_ESAME) ARCH_DEP(store_doubleword_absolute) (pte, rpte, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(store_fullword_absolute) (pte, rpte, regs); #endif /*!defined(FEATURE_ESAME)*/ regs->GR(r1) = regs->dat.raddr; regs->psw.cc = 0; } else regs->psw.cc = 1; } else { /* Unlock reguest */ if(pte & PAGETAB_PGLOCK) { pte &= ~((U64)PAGETAB_PGLOCK); #if defined(FEATURE_ESAME) ARCH_DEP(store_doubleword_absolute) (pte, rpte, regs); #else /*!defined(FEATURE_ESAME)*/ ARCH_DEP(store_fullword_absolute) (pte, rpte, regs); #endif /*!defined(FEATURE_ESAME)*/ regs->psw.cc = 0; } else regs->psw.cc = 1; } } else regs->psw.cc = 3; RELEASE_MAINLOCK(regs); } /* end DEF_INST(lock_page) */ #endif /*defined(FEATURE_LOCK_PAGE)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B247 MSTA - Modify Stacked State [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(modify_stacked_state) { int r1, unused; /* Values of R fields */ U32 m1, m2; /* Modify values */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ RRE(inst, regs, r1, unused); SIE_XC_INTERCEPT(regs); if (REAL_MODE(®s->psw) || SECONDARY_SPACE_MODE(®s->psw) || !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); ODD_CHECK(r1, regs); /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs); /* Load values from rightmost 32 bits of R1 and R1+1 registers */ m1 = regs->GR_L(r1); m2 = regs->GR_L(r1+1); /* Store two 32-bit values into modifiable area of state entry */ ARCH_DEP(stack_modify) (lsea, m1, m2, regs); } #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* DA MVCP - Move to Primary [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_to_primary) { int r1, r3; /* Register numbers */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ int k; /* Integer workarea */ GREG l; /* Unsigned workarea */ SS(inst, regs, r1, r3, b1, effective_addr1, b2, effective_addr2); SIE_XC_INTERCEPT(regs); /* Program check if secondary space control (CR0 bit 5) is 0, or if DAT is off, or if in AR mode or home-space mode */ if ((regs->CR(0) & CR0_SEC_SPACE) == 0 || REAL_MODE(®s->psw) || AR_BIT(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load true length from R1 register */ l = GR_A(r1,regs); /* If the true length does not exceed 256, set condition code zero, otherwise set cc=3 and use effective length of 256 */ if (l <= 256) cc = 0; else { cc = 3; l = 256; } /* Load secondary space key from R3 register bits 24-27 */ k = regs->GR_L(r3) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( PROBSTATE(®s->psw) && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters from secondary address space to primary address space using secondary key for second operand */ if (l > 0) ARCH_DEP(move_chars) (effective_addr1, USE_PRIMARY_SPACE, regs->psw.pkey, effective_addr2, USE_SECONDARY_SPACE, k, l-1, regs); /* Set condition code */ regs->psw.cc = cc; } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* DB MVCS - Move to Secondary [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_to_secondary) { int r1, r3; /* Register numbers */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ int k; /* Integer workarea */ GREG l; /* Unsigned workarea */ SS(inst, regs, r1, r3, b1, effective_addr1, b2, effective_addr2); SIE_XC_INTERCEPT(regs); /* Program check if secondary space control (CR0 bit 5) is 0, or if DAT is off, or if in AR mode or home-space mode */ if ((regs->CR(0) & CR0_SEC_SPACE) == 0 || REAL_MODE(®s->psw) || AR_BIT(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load true length from R1 register */ l = GR_A(r1,regs); /* If the true length does not exceed 256, set condition code zero, otherwise set cc=3 and use effective length of 256 */ if (l <= 256) cc = 0; else { cc = 3; l = 256; } /* Load secondary space key from R3 register bits 24-27 */ k = regs->GR_L(r3) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( PROBSTATE(®s->psw) && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters from primary address space to secondary address space using secondary key for first operand */ if (l > 0) ARCH_DEP(move_chars) (effective_addr1, USE_SECONDARY_SPACE, k, effective_addr2, USE_PRIMARY_SPACE, regs->psw.pkey, l-1, regs); /* Set condition code */ regs->psw.cc = cc; } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* E50F MVCDK - Move with Destination Key [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_destination_key) { int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int k, l; /* Integer workarea */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); /* Load operand length-1 from register 0 bits 24-31 */ l = regs->GR_L(0) & 0xFF; /* Load destination key from register 1 bits 24-27 */ k = regs->GR_L(1) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( PROBSTATE(®s->psw) && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters using destination key for operand 1 */ ARCH_DEP(move_chars) (effective_addr1, b1, k, effective_addr2, b2, regs->psw.pkey, l, regs); } #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* D9 MVCK - Move with Key [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_key) { int r1, r3; /* Register numbers */ int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ int k; /* Integer workarea */ GREG l; /* Unsigned workarea */ SS(inst, regs, r1, r3, b1, effective_addr1, b2, effective_addr2); /* Load true length from R1 register */ l = GR_A(r1,regs); /* If the true length does not exceed 256, set condition code zero, otherwise set cc=3 and use effective length of 256 */ if (l <= 256) cc = 0; else { cc = 3; l = 256; } /* Load source key from R3 register bits 24-27 */ k = regs->GR_L(r3) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( PROBSTATE(®s->psw) && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters using source key for second operand */ if (l > 0) ARCH_DEP(move_chars) (effective_addr1, b1, regs->psw.pkey, effective_addr2, b2, k, l-1, regs); /* Set condition code */ regs->psw.cc = cc; } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS) /*-------------------------------------------------------------------*/ /* C8x0 MVCOS - Move with Optional Specifications [SSF] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_optional_specifications) { int r3; /* Register number */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int kbit1, kbit2, abit1, abit2; /* Key and AS validity bits */ int key1, key2; /* Access keys in bits 0-3 */ int asc1, asc2; /* AS controls (same as PSW) */ int cc; /* Condition code */ GREG len; /* Effective length */ int space1, space2; /* Address space modifiers */ SSF(inst, regs, b1, effective_addr1, b2, effective_addr2, r3); SIE_XC_INTERCEPT(regs); /* Program check if DAT is off */ if (REAL_MODE(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Extract the access key and address-space control for operand 1 */ abit1 = regs->GR_LHH(0) & 0x0001; kbit1 = (regs->GR_LHH(0) & 0x0002) >> 1; asc1 = regs->GR_LHH(0) & 0x00C0; key1 = (regs->GR_LHH(0) & 0xF000) >> 8; /* Extract the access key and address-space control for operand 2 */ abit2 = regs->GR_LHL(0) & 0x0001; kbit2 = (regs->GR_LHL(0) & 0x0002) >> 1; asc2 = regs->GR_LHL(0) & 0x00C0; key2 = (regs->GR_LHL(0) & 0xF000) >> 8; /* Use PSW address-space control for operand 1 if A bit is zero */ if (abit1 == 0) asc1 = regs->psw.asc; /* Use PSW address-space control for operand 2 if A bit is zero */ if (abit2 == 0) asc2 = regs->psw.asc; /* Use PSW key for operand 1 if K bit is zero */ if (kbit1 == 0) key1 = regs->psw.pkey; /* Use PSW key for operand 2 if K bit is zero */ if (kbit2 == 0) key2 = regs->psw.pkey; /* Program check if home-space mode is specified for operand 1 and PSW indicates problem state */ if (abit1 && asc1 == PSW_HOME_SPACE_MODE && PROBSTATE(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Program check if secondary space control (CR0 bit 5/37) is 0, and secondary space mode is specified or implied for either operand */ if ((regs->CR(0) & CR0_SEC_SPACE) == 0 && (asc1 == PSW_SECONDARY_SPACE_MODE || asc2 == PSW_SECONDARY_SPACE_MODE)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Program check if in problem state and the key mask in CR3 is zero for the specified or implied access key for either operand */ if (PROBSTATE(®s->psw) && ( ((regs->CR(3) << (key1 >> 4)) & 0x80000000) == 0 || ((regs->CR(3) << (key2 >> 4)) & 0x80000000) == 0 )) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Load true length from R3 register */ len = GR_A(r3,regs); /* If the true length does not exceed 4096, set condition code zero, otherwise set cc=3 and use effective length of 4096 */ if (len <= 4096) cc = 0; else { cc = 3; len = 4096; } /* Set the address space modifier for operand 1 */ space1 = (asc1 == PSW_PRIMARY_SPACE_MODE) ? USE_PRIMARY_SPACE : (asc1 == PSW_SECONDARY_SPACE_MODE) ? USE_SECONDARY_SPACE : (asc1 == PSW_ACCESS_REGISTER_MODE) ? USE_ARMODE | b1 : (asc1 == PSW_HOME_SPACE_MODE) ? USE_HOME_SPACE : 0; /* Set the address space modifier for operand 2 */ space2 = (asc2 == PSW_PRIMARY_SPACE_MODE) ? USE_PRIMARY_SPACE : (asc2 == PSW_SECONDARY_SPACE_MODE) ? USE_SECONDARY_SPACE : (asc2 == PSW_ACCESS_REGISTER_MODE) ? USE_ARMODE | b2 : (asc2 == PSW_HOME_SPACE_MODE) ? USE_HOME_SPACE : 0; /* Perform the move */ ARCH_DEP(move_charx) (effective_addr1, space1, key1, effective_addr2, space2, key2, len, regs); /* Set the condition code */ regs->psw.cc = cc; } /* end DEF_INST(move_with_optional_specifications) */ #endif /*defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS)*/ /*-------------------------------------------------------------------*/ /* E50E MVCSK - Move with Source Key [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(move_with_source_key) { int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int k, l; /* Integer workarea */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); /* Load operand length-1 from register 0 bits 24-31 */ l = regs->GR_L(0) & 0xFF; /* Load source key from register 1 bits 24-27 */ k = regs->GR_L(1) & 0xF0; /* Program check if in problem state and key mask in CR3 bits 0-15 is not 1 for the specified key */ if ( PROBSTATE(®s->psw) && ((regs->CR(3) << (k >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Move characters using source key for second operand */ ARCH_DEP(move_chars) (effective_addr1, b1, regs->psw.pkey, effective_addr2, b2, k, l, regs); } #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B218 PC - Program Call [S] */ /*-------------------------------------------------------------------*/ DEF_INST(program_call) { int b2; /* Base of effective addr */ U32 pcnum; /* Program call number */ U32 pctea; /* TEA in case of program chk*/ VADR effective_addr2; /* Effective address */ RADR abs; /* Absolute address */ BYTE *mn; /* Mainstor address */ RADR pstd; /* Primary STD or ASCE */ U32 oldpstd; /* Old Primary STD or ASCE */ U32 ltdesig; /* Linkage table designation (LTD or LFTD) */ U32 pasteo=0; /* Primary ASTE origin */ RADR lto; /* Linkage table origin */ U32 ltl; /* Linkage table length */ U32 lte; /* Linkage table entry */ RADR lfto; /* Linkage first table origin*/ U32 lftl; /* Linkage first table length*/ U32 lfte; /* Linkage first table entry */ RADR lsto; /* Linkage second table orig */ U32 lste[2]; /* Linkage second table entry*/ RADR eto; /* Entry table origin */ U32 etl; /* Entry table length */ U32 ete[8]; /* Entry table entry */ int numwords; /* ETE size (4 or 8 words) */ int i; /* Array subscript */ int ssevent = 0; /* 1=space switch event */ U32 aste[16]; /* ASN second table entry */ U32 akm; /* Bits 0-15=AKM, 16-31=zero */ U16 xcode; /* Exception code */ U16 pasn; /* Primary ASN */ U16 oldpasn; /* Old Primary ASN */ #if defined(FEATURE_LINKAGE_STACK) U32 csi; /* Called-space identifier */ VADR retn; /* Return address and amode */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ #if defined(FEATURE_ESAME) CREG savecr12 = 0; /* CR12 save */ #endif /*FEATURE_ESAME*/ S(inst, regs, b2, effective_addr2); SIE_XC_INTERCEPT(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC2, PC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Load the PC number from the operand address */ if (!ASN_AND_LX_REUSE_ENABLED(regs)) { /* When ASN-and-LX-reuse is not installed or not enabled, the PC number is the low-order 20 bits of the operand address and the translation exception identification is the 20-bit PC number with 12 high order zeroes appended to the left */ pcnum = effective_addr2 & (PC_LX | PC_EX); pctea = pcnum; } else /* ASN_AND_LX_REUSE_ENABLED */ { /* When ASN-and-LX-reuse is installed and enabled by CR0, the PC number is loaded from the low-order 20 bits of the operand address (bits 44-63) if bit 44 is zero, otherwise a 31-bit PC number is constructed using bits 32-43 (LFX1) of the operand address concatenated with bits 45-63 (LFX2, LSX,EX) of the operand address. The translation exception identification is either the 20 bit PC number with 12 high order zeroes, or, if bit 44 is one, is the entire 32 bits of the effective address including the 1 in bit 44 */ if ((effective_addr2 & PC_BIT44) == 0) { pcnum = effective_addr2 & (PC_LFX2 | PC_LSX | PC_EX); pctea = pcnum; } else { pcnum = ((effective_addr2 & PC_LFX1) >> 1) | (effective_addr2 & (PC_LFX2 | PC_LSX | PC_EX)); pctea = effective_addr2 & 0xFFFFFFFF; } } /* end ASN_AND_LX_REUSE_ENABLED */ /* Special operation exception if DAT is off, or if in secondary space mode or home space mode */ if (REAL_MODE(&(regs->psw)) || SPACE_BIT(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Save CR4 and CR1 in case of space switch */ oldpasn = regs->CR(4) & CR4_PASN; oldpstd = regs->CR(1); /* [5.5.3.1] Load the linkage table designation */ if (!ASF_ENABLED(regs)) { /* Special operation exception if in AR mode */ if (ACCESS_REGISTER_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Obtain the LTD from control register 5 */ ltdesig = regs->CR_L(5); } else { /* Obtain the primary ASTE origin from control register 5 */ pasteo = regs->CR_L(5) & CR5_PASTEO; /* Convert the PASTE origin to an absolute address */ abs = APPLY_PREFIXING (pasteo, regs->PX); /* Program check if PASTE is outside main storage */ if (abs > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch primary ASTE words 3 or 6 from absolute storage (note: the ASTE cannot cross a page boundary) */ #if !defined(FEATURE_ESAME) aste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs); #else /*defined(FEATURE_ESAME)*/ aste[6] = ARCH_DEP(fetch_fullword_absolute) (abs+24, regs); #endif /*defined(FEATURE_ESAME)*/ /* Load LTD or LFTD from primary ASTE word 3 or 6 */ ltdesig = ASTE_LT_DESIGNATOR(aste); } /* Note: When ASN-and-LX-reuse is installed and enabled by CR0, ltdesig is an LFTD, otherwise it is an LTD */ /* Special operation exception if subsystem linkage control bit in linkage table designation is zero */ if ((ltdesig & LTD_SSLINK) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #ifdef FEATURE_TRACING /* Form trace entry if ASN tracing is active */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_pc) (pctea, regs); #endif /*FEATURE_TRACING*/ /* [5.5.3.2] Linkage table lookup */ if (!ASN_AND_LX_REUSE_ENABLED(regs)) { /* Extract the linkage table origin and length from the LTD */ lto = ltdesig & LTD_LTO; ltl = ltdesig & LTD_LTL; /* Program check if linkage index outside the linkage table */ if (ltl < ((pcnum & PC_LX) >> 13)) { regs->TEA = pctea; ARCH_DEP(program_interrupt) (regs, PGM_LX_TRANSLATION_EXCEPTION); } /* Calculate the address of the linkage table entry */ lto += (pcnum & PC_LX) >> 6; lto &= 0x7FFFFFFF; /* Program check if linkage table entry outside real storage */ if (lto > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch linkage table entry from real storage. All bytes must be fetched concurrently as observed by other CPUs */ lto = APPLY_PREFIXING (lto, regs->PX); lte = ARCH_DEP(fetch_fullword_absolute)(lto, regs); /* Program check if the LX invalid bit is set */ if (lte & LTE_INVALID) { regs->TEA = pctea; ARCH_DEP(program_interrupt) (regs, PGM_LX_TRANSLATION_EXCEPTION); } /* Extract the entry table origin and length from the LTE */ eto = lte & LTE_ETO; etl = lte & LTE_ETL; } else /* ASN_AND_LX_REUSE_ENABLED */ { /* Extract linkage first table origin and length from LFTD */ lfto = ltdesig & LFTD_LFTO; lftl = ltdesig & LFTD_LFTL; /* If the linkage first index exceeds the length of the linkage first table, then generate a program check. The index exceeds the table length if the LFX1 (which is now in bits 1-12 of the 32-bit PC number) exceeds the LFTL. Since the LFTL is only 8 bits, this also implies that the first 4 bits of the LFX1 (originally bits 32-35 of the operand address) must always be 0. The LFX1 was loaded from bits 32-43 of the operand address if bit 44 of the operand address was 1, otherwise LFX1 is zero. However, when bit 44 of the effective address is zero, the LFTL (Linkage-First-Table Length) is ignored. */ if ((effective_addr2 & PC_BIT44) && lftl < (pcnum >> 19)) { regs->TEA = pctea; ARCH_DEP(program_interrupt) (regs, PGM_LFX_TRANSLATION_EXCEPTION); } /* Calculate the address of the linkage first table entry (it is always a 31-bit address even in ESAME) */ lfto += (pcnum & ((PC_LFX1>>1)|PC_LFX2)) >> (13-2); lfto &= 0x7FFFFFFF; /* Program check if the LFTE address is outside real storage */ if (lfto > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch linkage first table entry from real storage. All bytes must be fetched concurrently as observed by other CPUs */ lfto = APPLY_PREFIXING (lfto, regs->PX); lfte = ARCH_DEP(fetch_fullword_absolute)(lfto, regs); /* Program check if the LFX invalid bit is set */ if (lfte & LFTE_INVALID) { regs->TEA = pctea; ARCH_DEP(program_interrupt) (regs, PGM_LFX_TRANSLATION_EXCEPTION); } /* Extract the linkage second table origin from the LFTE */ lsto = lfte & LFTE_LSTO; /* Calculate the address of the linkage second table entry (it is always a 31-bit address even in ESAME) */ lsto += (pcnum & PC_LSX) >> (8-3); lsto &= 0x7FFFFFFF; /* Program check if the LSTE address is outside real storage */ if (lsto > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch the linkage second table entry from real storage. The LSTE is 2 fullwords and cannot cross a page boundary. All 8 bytes of the LSTE must be fetched concurrently as observed by other CPUs */ abs = APPLY_PREFIXING (lsto, regs->PX); mn = FETCH_MAIN_ABSOLUTE (abs, regs, 2 * 4); lste[0] = fetch_fw (mn); lste[1] = fetch_fw (mn + 4); /* Program check if the LSX invalid bit is set */ if (lste[0] & LSTE0_INVALID) { regs->TEA = pctea; ARCH_DEP(program_interrupt) (regs, PGM_LSX_TRANSLATION_EXCEPTION); } /* Program check if the LSTESN in word 1 of the LSTE is non-zero and not equal to bits 0-31 of register 15 */ if (lste[1] != 0 && regs->GR_H(15) != lste[1]) { regs->TEA = pctea; ARCH_DEP(program_interrupt) (regs, PGM_LSTE_SEQUENCE_EXCEPTION); } /* Extract the entry table origin and length from the LSTE */ eto = lste[0] & LSTE0_ETO; etl = lste[0] & LSTE0_ETL; } /* end ASN_AND_LX_REUSE_ENABLED */ /* [5.5.3.3] Entry table lookup */ /* Program check if entry index is outside the entry table */ if (etl < ((pcnum & PC_EX) >> (8-6))) { regs->TEA = pctea; ARCH_DEP(program_interrupt) (regs, PGM_EX_TRANSLATION_EXCEPTION); } /* Calculate the starting address of the entry table entry (it is always a 31-bit address even in ESAME) */ eto += (pcnum & PC_EX) << (ASF_ENABLED(regs) ? 5 : 4); eto &= 0x7FFFFFFF; /* Determine the size of the entry table entry */ numwords = ASF_ENABLED(regs) ? 8 : 4; /* Program check if entry table entry is outside main storage */ abs = APPLY_PREFIXING (eto, regs->PX); if (abs > regs->mainlim - (numwords * 4)) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch the 4- or 8-word entry table entry from real storage. Each fullword of the ETE must be fetched concurrently as observed by other CPUs. The entry table entry cannot cross a page boundary. */ mn = FETCH_MAIN_ABSOLUTE (abs, regs, numwords * 4); for (i = 0; i < numwords; i++) { ete[i] = fetch_fw (mn); mn += 4; } /* Clear remaining words if fewer than 8 words were loaded */ while (i < 8) ete[i++] = 0; /* Program check if basic program call in AR mode */ if ((ete[4] & ETE4_T) == 0 && AR_BIT(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #if defined(FEATURE_ESAME) /* Program check if basic program call is attempting to switch into or out of 64-bit addressing mode */ if ((ete[4] & ETE4_T) == 0 && ((ete[4] & ETE4_G) ? 1 : 0) != regs->psw.amode64) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif /*defined(FEATURE_ESAME)*/ /* Program check if resulting addressing mode is 24 and the entry instruction address is not a 24-bit address */ if ((ete[1] & ETE1_AMODE) == 0 #if defined(FEATURE_ESAME) && (ete[4] & ETE4_G) == 0 #endif /*defined(FEATURE_ESAME)*/ && (ete[1] & ETE1_EIA) > 0x00FFFFFF) ARCH_DEP(program_interrupt) (regs, PGM_PC_TRANSLATION_SPECIFICATION_EXCEPTION); /* Obtain the authorization key mask from the entry table */ #if defined(FEATURE_ESAME) akm = ete[2] & ETE2_AKM; #else /*!defined(FEATURE_ESAME)*/ akm = ete[0] & ETE0_AKM; #endif /*!defined(FEATURE_ESAME)*/ /* Program check if in problem state and the PKM in control register 3 produces zero when ANDed with the AKM in the ETE */ if (PROBSTATE(®s->psw) && ((regs->CR(3) & CR3_KEYMASK) & akm) == 0) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Obtain the new primary ASN from the entry table */ #if defined(FEATURE_ESAME) pasn = ete[2] & ETE2_ASN; #else /*!defined(FEATURE_ESAME)*/ pasn = ete[0] & ETE0_ASN; #endif /*!defined(FEATURE_ESAME)*/ /* Obtain the ASTE if ASN is non-zero */ if (pasn != 0) { /* Program check if ASN translation control is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* For ESA/390 when ASF control is not enabled, the ASTE is obtained by ASN translation. For ESAME, and for ESA/390 when ASF control is enabled, the ASTE is loaded using the ASTE real address from the entry table */ if (!ASF_ENABLED(regs)) { /* Perform ASN translation to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (pasn, regs, &pasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (regs, xcode); } else { /* Load the ASTE origin from the entry table */ pasteo = ete[5] & ETE5_ASTE; /* Convert the ASTE origin to an absolute address */ abs = APPLY_PREFIXING (pasteo, regs->PX); /* Program check if ASTE origin address is invalid */ if (abs > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch the 16-word ASTE from absolute storage (note: the ASTE cannot cross a page boundary) */ mn = FETCH_MAIN_ABSOLUTE (abs, regs, 64); for (i = 0; i < 16; i++) { aste[i] = fetch_fw (mn); mn += 4; } /* ASX translation exception if ASTE invalid bit is one */ if (aste[0] & ASTE0_INVALID) { regs->TEA = pasn; ARCH_DEP(program_interrupt) (regs, PGM_ASX_TRANSLATION_EXCEPTION); } } /* Obtain the new PSTD or PASCE from the ASTE */ pstd = ASTE_AS_DESIGNATOR(aste); #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, NULL, regs); #endif /*FEATURE_SUBSPACE_GROUP*/ } /* end if(PC-ss) */ else { /* PC-cp */ /* For PC to current primary, load current primary STD */ pstd = regs->CR(1); } /* end if(PC-cp) */ /* Perform basic or stacking program call */ if ((ete[4] & ETE4_T) == 0) { /* For basic PC, load linkage info into general register 14 */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_G(14) = PSW_IA(regs, 0) | PROBSTATE(®s->psw); else regs->GR_L(14) = (regs->psw.amode ? 0x80000000 : 0) | PSW_IA(regs, 0) | PROBSTATE(®s->psw); #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(14) = (regs->psw.amode ? 0x80000000 : 0) | PSW_IA(regs, 0) | PROBSTATE(®s->psw); #endif /*!defined(FEATURE_ESAME)*/ /* Set the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); /* Update the PSW from the entry table */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) UPD_PSW_IA(regs , ((U64)(ete[0]) << 32) | (U64)(ete[1] & 0xFFFFFFFE)); else { regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; UPD_PSW_IA(regs, ete[1] & ETE1_EIA); } #else /*!defined(FEATURE_ESAME)*/ regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; UPD_PSW_IA(regs, ete[1] & ETE1_EIA); #endif /*!defined(FEATURE_ESAME)*/ if (ete[1] & ETE1_PROB) regs->psw.states |= BIT(PSW_PROB_BIT); else regs->psw.states &= ~BIT(PSW_PROB_BIT); /* Load the current PKM and PASN into general register 3 */ regs->GR_L(3) = (regs->CR(3) & CR3_KEYMASK) | (regs->CR(4) & CR4_PASN); /* OR the EKM into the current PKM */ regs->CR(3) |= (ete[3] & ETE3_EKM); /* Load the entry parameter into general register 4 */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_H(4) = ete[6]; regs->GR_L(4) = ete[7]; #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(4) = ete[2]; #endif /*!defined(FEATURE_ESAME)*/ } /* end if(basic PC) */ else #if defined(FEATURE_LINKAGE_STACK) { /* stacking PC */ /* ESA/390 POP Fig 10-17 8.B.11 */ if (!ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #ifdef FEATURE_TRACING #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && (regs->psw.amode64 != ((ete[4] & ETE4_G) ? 1 : 0))) { /* since ASN trace might be made already, need to save current CR12 and use newcr12 for this second entry */ if (!newcr12) newcr12 = regs->CR(12); savecr12 = regs->CR(12); regs->CR(12) = newcr12; newcr12 = ARCH_DEP(trace_ms) (0, 0, regs); regs->CR(12) = savecr12; } #endif /*defined(FEATURE_ESAME)*/ #endif /*FEATURE_TRACING*/ /* Set the called-space identification */ if (pasn == 0) csi = 0; else if (ASN_AND_LX_REUSE_ENABLED(regs)) csi = pasn << 16 | (aste[11] & 0x0000FFFF); else csi = pasn << 16 | (aste[5] & 0x0000FFFF); /* Set the addressing mode bits in the return address */ retn = PSW_IA(regs, 0); #if defined(FEATURE_ESAME) if ( regs->psw.amode64 ) retn |= 0x01; else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) retn |= 0x80000000; #if defined(FEATURE_ESAME) /* Set the high-order bit of the PC number if the resulting addressing mode is 64-bit */ if (ete[4] & ETE4_G) pcnum |= 0x80000000; #endif /*defined(FEATURE_ESAME)*/ /* Perform the stacking process */ ARCH_DEP(form_stack_entry) (LSED_UET_PC, retn, 0, csi, pcnum, regs); /* Set the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); /* Update the PSW from the entry table */ #if defined(FEATURE_ESAME) if (ete[4] & ETE4_G) { regs->psw.amode64 = 1; regs->psw.amode = 1; regs->psw.AMASK = AMASK64; UPD_PSW_IA(regs, ((U64)(ete[0]) << 32) | (U64)(ete[1] & 0xFFFFFFFE)); } else { regs->psw.amode64 = 0; regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; UPD_PSW_IA(regs, ete[1] & ETE1_EIA); } #else /*!defined(FEATURE_ESAME)*/ regs->psw.amode = (ete[1] & ETE1_AMODE) ? 1 : 0; regs->psw.AMASK = regs->psw.amode ? AMASK31 : AMASK24; UPD_PSW_IA(regs, ete[1] & ETE1_EIA); #endif /*!defined(FEATURE_ESAME)*/ if (ete[1] & ETE1_PROB) regs->psw.states |= BIT(PSW_PROB_BIT); else regs->psw.states &= ~BIT(PSW_PROB_BIT); /* Replace the PSW key by the entry key if the K bit is set */ if (ete[4] & ETE4_K) { regs->psw.pkey = (ete[4] & ETE4_EK) >> 16; } /* Replace the PSW key mask by the EKM if the M bit is set, otherwise OR the EKM into the current PSW key mask */ if (ete[4] & ETE4_M) regs->CR_LHH(3) = 0; regs->CR(3) |= (ete[3] & ETE3_EKM); /* Replace the EAX key by the EEAX if the E bit is set */ if (ete[4] & ETE4_E) { regs->CR_LHH(8) = (ete[4] & ETE4_EEAX); } /* Set the access mode according to the C bit */ if (ete[4] & ETE4_C) regs->psw.asc |= BIT(PSW_AR_BIT); else regs->psw.asc &= ~BIT(PSW_AR_BIT); /* Load the entry parameter into general register 4 */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_H(4) = ete[6]; regs->GR_L(4) = ete[7]; #else /*!defined(FEATURE_ESAME)*/ regs->GR_L(4) = ete[2]; #endif /*!defined(FEATURE_ESAME)*/ } /* end if(stacking PC) */ #else /*!defined(FEATURE_LINKAGE_STACK)*/ ARCH_DEP(program_interrupt) (regs, PGM_PC_TRANSLATION_SPECIFICATION_EXCEPTION); #endif /*!defined(FEATURE_LINKAGE_STACK)*/ /* If new ASN is zero, perform program call to current primary */ if (pasn == 0) { /* Set SASN equal to PASN */ regs->CR_LHL(3) = regs->CR_LHL(4); /* Set SSTD equal to PSTD */ regs->CR(7) = regs->CR(1); /* When ASN-and-LX-reuse is installed and enabled, set the SASTEIN equal to the PASTEIN */ if (ASN_AND_LX_REUSE_ENABLED(regs)) regs->CR_H(3) = regs->CR_H(4); } /* end if(PC-cp) */ else { /* Program call with space switching */ /* Set SASN and SSTD equal to current PASN and PSTD */ regs->CR_LHL(3) = regs->CR_LHL(4); regs->CR(7) = regs->CR(1); /* When ASN-and-LX-reuse is installed and enabled, set the SASTEIN equal to the current PASTEIN */ if (ASN_AND_LX_REUSE_ENABLED(regs)) regs->CR_H(3) = regs->CR_H(4); /* Set flag if either the current or new PSTD indicates a space switch event */ if ((regs->CR(1) & SSEVENT_BIT) || (pstd & SSEVENT_BIT) ) { /* Indicate space-switch event required */ ssevent = 1; } /* Obtain new AX from the ASTE and new PASN from the ET */ regs->CR_L(4) = (aste[1] & ASTE1_AX) | pasn; /* When ASN-and-LX-reuse is installed and enabled, obtain the new PASTEIN from the new primary ASTE */ if (ASN_AND_LX_REUSE_ENABLED(regs)) regs->CR_H(4) = aste[11]; /* Load the new primary STD or ASCE */ regs->CR(1) = pstd; /* Update control register 5 with the new PASTEO or LTD */ regs->CR_L(5) = ASF_ENABLED(regs) ? pasteo : ASTE_LT_DESIGNATOR(aste); #if defined(FEATURE_LINKAGE_STACK) /* For stacking PC when the S-bit in the entry table is one, set SASN and SSTD equal to new PASN and PSTD */ if ((ete[4] & ETE4_T) && (ete[4] & ETE4_S)) { regs->CR_LHL(3) = regs->CR_LHL(4); regs->CR(7) = regs->CR(1); /* When ASN-and-LX-reuse is installed and enabled, also set the SASTEIN equal to the new PASTEIN */ if (ASN_AND_LX_REUSE_ENABLED(regs)) regs->CR_H(3) = regs->CR_H(4); } #endif /*defined(FEATURE_LINKAGE_STACK)*/ } /* end if(PC-ss) */ #ifdef FEATURE_TRACING /* Update trace table address if ASN or Mode switch made trace entry */ if (newcr12) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ /* Update cpu states */ SET_IC_MASK(regs); SET_AEA_MODE(regs); // psw.asc may be updated SET_AEA_COMMON(regs); // cr[1], cr[7] may be updated INVALIDATE_AIA(regs); /* Check for Successful Branch PER event */ PER_SB(regs, regs->psw.IA); /* Generate space switch event if required */ if ( ssevent || (pasn != 0 && IS_IC_PER(regs)) ) { /* [6.5.2.34] Set the translation exception address equal to the old primary ASN, with the high-order bit set if the old primary space-switch-event control bit is one */ regs->TEA = oldpasn; if (oldpstd & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; ARCH_DEP(program_interrupt) (regs, PGM_SPACE_SWITCH_EVENT); } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* end DEF_INST(program_call) */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* 0101 PR - Program Return [E] */ /*-------------------------------------------------------------------*/ DEF_INST(program_return) { REGS newregs; /* Copy of CPU registers */ int etype; /* Entry type unstacked */ int ssevent = 0; /* 1=space switch event */ RADR alsed; /* Absolute addr of LSED of previous stack entry */ LSED *lsedp; /* -> LSED in main storage */ U32 aste[16]; /* ASN second table entry */ U32 pasteo=0; /* Primary ASTE origin */ U32 sasteo=0; /* Secondary ASTE origin */ U16 oldpasn; /* Original primary ASN */ U32 oldpstd; /* Original primary STD */ U16 pasn = 0; /* New primary ASN */ U16 sasn; /* New secondary ASN */ U16 ax; /* Authorization index */ U16 xcode; /* Exception code */ int rc; /* return code from load_psw */ E(inst, regs); SIE_XC_INTERCEPT(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, PR)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); INVALIDATE_AIA(regs); /* Create a working copy of the CPU registers... */ memcpy( &newregs, regs, sysblk.regs_copy_len ); /* Now INVALIDATE ALL TLB ENTRIES in our working copy.. */ memset( &newregs.tlb.vaddr, 0, TLBN * sizeof(DW) ); newregs.tlbID = 1; /* Set the breaking event address register in the copy */ SET_BEAR_REG(&newregs, newregs.ip - (newregs.execflag ? newregs.exrl ? 6 : 4 : 2)); /* Save the primary ASN (CR4) and primary STD (CR1) */ oldpasn = regs->CR_LHL(4); oldpstd = regs->CR(1); /* Perform the unstacking process */ etype = ARCH_DEP(program_return_unstack) (&newregs, &alsed, &rc); #ifdef FEATURE_TRACING #if defined(FEATURE_ESAME) /* If unstacked entry was a BAKR: */ /* Add a mode trace entry when switching in/out of 64 bit mode */ if((etype == LSED_UET_BAKR) && (regs->CR(12) & CR12_MTRACE) && (regs->psw.amode64 != newregs.psw.amode64)) newregs.CR(12) = ARCH_DEP(trace_ms) (0, 0, regs); #endif /*defined(FEATURE_ESAME)*/ #endif /*FEATURE_TRACING*/ /* Perform PR-cp or PR-ss if unstacked entry was a program call */ if (etype == LSED_UET_PC) { /* Extract the new primary ASN from CR4 bits 16-31 */ pasn = newregs.CR_LHL(4); #ifdef FEATURE_TRACING /* Perform tracing if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) newregs.CR(12) = ARCH_DEP(trace_pr) (&newregs, regs); #if defined(FEATURE_ESAME) else /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && (regs->psw.amode64 != newregs.psw.amode64)) newregs.CR(12) = ARCH_DEP(trace_ms) (0, 0, regs); #endif /*defined(FEATURE_ESAME)*/ #endif /*FEATURE_TRACING*/ /* Perform PASN translation if new PASN not equal old PASN */ if (pasn != oldpasn) { /* Special operation exception if ASN translation control (control register 14 bit 12) is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (&newregs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Translate new primary ASN to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (pasn, &newregs, &pasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (&newregs, xcode); /* When ASN-and-LX-reuse is installed and enabled by CR0, the PASTEIN previously loaded from the state entry (by the program_return_unstack procedure) into the high word of CR4 must equal the ASTEIN in word 11 of the ASTE */ if (ASN_AND_LX_REUSE_ENABLED(regs)) { if (newregs.CR_H(4) != aste[11]) { /* Set bit 2 of the exception access identification to indicate that the program check occurred during PASN translation in a PR instruction */ newregs.excarid = 0x20; ARCH_DEP(program_interrupt) (&newregs, PGM_ASTE_INSTANCE_EXCEPTION); } } /* end if(ASN_AND_LX_REUSE_ENABLED) */ /* Obtain new PSTD (or PASCE) and AX from the ASTE */ newregs.CR(1) = ASTE_AS_DESIGNATOR(aste); newregs.CR_LHH(4) = 0; newregs.CR_L(4) |= aste[1] & ASTE1_AX; /* Load CR5 with the primary ASTE origin address */ newregs.CR_L(5) = pasteo; #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ newregs.CR(1) = ARCH_DEP(subspace_replace) (newregs.CR(1), pasteo, NULL, &newregs); #endif /*FEATURE_SUBSPACE_GROUP*/ /* Space switch if either current PSTD or new PSTD space-switch-event control bit is set to 1 */ if ((regs->CR(1) & SSEVENT_BIT) || (newregs.CR(1) & SSEVENT_BIT)) { /* Indicate space-switch event required */ ssevent = 1; } else { /* space-switch event maybe - if PER event */ ssevent = 2; } } /* end if(pasn!=oldpasn) */ /* Extract the new secondary ASN from CR3 bits 16-31 */ sasn = newregs.CR_LHL(3); /* Set SSTD = PSTD if new SASN is equal to new PASN */ if (sasn == pasn) { newregs.CR(7) = newregs.CR(1); } else /* sasn != pasn */ { /* Perform SASN translation */ /* Special operation exception if ASN translation control (control register 14 bit 12) is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (&newregs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Translate new secondary ASN to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (sasn, &newregs, &sasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (&newregs, xcode); /* When ASN-and-LX-reuse is installed and enabled by CR0, the SASTEIN previously loaded from the state entry (by the program_return_unstack procedure) into the high word of CR3 must equal the ASTEIN in word 11 of the ASTE */ if (ASN_AND_LX_REUSE_ENABLED(regs)) { if (newregs.CR_H(3) != aste[11]) { /* Set bit 3 of the exception access identification to indicate that the program check occurred during SASN translation in a PR instruction */ newregs.excarid = 0x10; ARCH_DEP(program_interrupt) (&newregs, PGM_ASTE_INSTANCE_EXCEPTION); } } /* end if(ASN_AND_LX_REUSE_ENABLED) */ /* Obtain new SSTD or SASCE from secondary ASTE */ newregs.CR(7) = ASTE_AS_DESIGNATOR(aste); /* Perform SASN authorization using new AX */ ax = newregs.CR_LHH(4); if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY, &newregs)) { newregs.TEA = sasn; ARCH_DEP(program_interrupt) (&newregs, PGM_SECONDARY_AUTHORITY_EXCEPTION); } #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new SSTD */ newregs.CR(7) = ARCH_DEP(subspace_replace) (newregs.CR(7), sasteo, NULL, &newregs); #endif /*FEATURE_SUBSPACE_GROUP*/ } /* end else(sasn!=pasn) */ } /* end if(LSED_UET_PC) */ /* Update the updated CPU registers from the working copy */ memcpy(&(regs->psw), &(newregs.psw), sizeof(newregs.psw)); memcpy(regs->gr, newregs.gr, sizeof(newregs.gr)); memcpy(regs->cr, newregs.cr, sizeof(newregs.cr)); memcpy(regs->ar, newregs.ar, sizeof(newregs.ar)); regs->bear = newregs.bear; /* Set the main storage reference and change bits */ STORAGE_KEY(alsed, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* [5.12.4.4] Clear the next entry size field of the linkage stack entry now pointed to by control register 15 */ lsedp = (LSED*)(regs->mainstor + alsed); lsedp->nes[0] = 0; lsedp->nes[1] = 0; #if defined(FEATURE_PER) /* Copy PER info from working copy to real copy of registers */ if (IS_IC_PER_SA(&newregs)) { ON_IC_PER_SA(regs); regs->perc = newregs.perc; } PER_SB(regs, regs->psw.IA); #endif /*defined(FEATURE_PER)*/ /* Update cpu states */ SET_IC_MASK(regs); SET_AEA_MODE(regs); // psw has been updated SET_AEA_COMMON(regs); // control regs been updated /* Generate space switch event if required */ if ( ssevent == 1 || (ssevent == 2 && IS_IC_PER(regs)) ) { /* [6.5.2.34] Set translation exception address equal to old primary ASN, and set high-order bit if old primary space-switch-event control bit is one */ regs->TEA = oldpasn; if (oldpstd & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; ARCH_DEP(program_interrupt) (regs, PGM_SPACE_SWITCH_EVENT); } if (rc) /* if new psw has bad format */ { ARCH_DEP(program_interrupt) (regs, rc); } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); RETURN_INTCHECK(regs); } /* end DEF_INST(program_return) */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* Common processing routine for the PT and PTI instructions */ /*-------------------------------------------------------------------*/ void ARCH_DEP(program_transfer_proc) (REGS *regs, int r1, int r2, int pti_instruction) { U16 pkm; /* New program key mask */ U16 pasn; /* New primary ASN */ U16 oldpasn; /* Old primary ASN */ int amode; /* New amode */ VADR ia; /* New instruction address */ int prob; /* New problem state bit */ RADR abs; /* Absolute address */ U32 ltd; /* Linkage table designation */ U32 pasteo=0; /* Primary ASTE origin */ U32 aste[16]; /* ASN second table entry */ CREG pstd; /* Primary STD */ U32 oldpstd; /* Old Primary STD */ U16 ax; /* Authorization index */ U16 xcode; /* Exception code */ int ssevent = 0; /* 1=space switch event */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ SIE_XC_INTERCEPT(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC2, PT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Special operation exception if DAT is off, or not in primary space mode */ if (REAL_MODE(&(regs->psw)) || !PRIMARY_SPACE_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Special operation exception if subsystem linkage control bit in CR5 is zero (when ASF is off)*/ if (!ASF_ENABLED(regs) && !(regs->CR_L(5) & LTD_SSLINK)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Save the primary ASN (CR4) and primary STD (CR1) */ oldpasn = regs->CR_LHL(4); oldpstd = regs->CR(1); /* Extract the PSW key mask from R1 register bits 0-15 */ pkm = regs->GR_LHH(r1); /* Extract the ASN from R1 register bits 16-31 */ pasn = regs->GR_LHL(r1); #ifdef FEATURE_TRACING /* Build trace entry if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_pt) (pti_instruction, pasn, regs->GR(r2), regs); #endif /*FEATURE_TRACING*/ /* Determine instruction address, amode, and problem state */ #if defined(FEATURE_ESAME) if (regs->psw.amode64) { /* In 64-bit address mode, extract instruction address from R2 register bits 0-62, and leave address mode unchanged */ ia = regs->GR_G(r2) & 0xFFFFFFFFFFFFFFFEULL; amode = regs->psw.amode; } else #endif /*defined(FEATURE_ESAME)*/ { /* In 31- or 24-bit mode, extract new amode from R2 bit 0 */ amode = (regs->GR_L(r2) & 0x80000000) ? 1 : 0; /* Extract the instruction address from R2 bits 1-30 */ ia = regs->GR_L(r2) & 0x7FFFFFFE; } /* Extract the problem state bit from R2 register bit 31 */ prob = regs->GR_L(r2) & 0x00000001; /* [5.5.3.1] Load the linkage table designation */ if (!ASF_ENABLED(regs)) { /* Obtain the LTD from control register 5 */ ltd = regs->CR_L(5); } else { /* Obtain the primary ASTE origin from control register 5 */ pasteo = regs->CR_L(5) & CR5_PASTEO; /* Convert the PASTE origin to an absolute address */ abs = APPLY_PREFIXING (pasteo, regs->PX); /* Program check if PASTE is outside main storage */ if (abs > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Fetch primary ASTE words 3 and 6 from absolute storage (note: the ASTE cannot cross a page boundary) */ #if !defined(FEATURE_ESAME) aste[3] = ARCH_DEP(fetch_fullword_absolute) (abs+12, regs); #else /*defined(FEATURE_ESAME)*/ aste[6] = ARCH_DEP(fetch_fullword_absolute) (abs+24, regs); #endif /*defined(FEATURE_ESAME)*/ /* Load LTD from primary ASTE word 3 or 6 */ ltd = ASTE_LT_DESIGNATOR(aste); } /* Special operation exception if subsystem linkage control bit in linkage table designation is zero */ if ((ltd & LTD_SSLINK) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if in problem state and problem bit indicates a change to supervisor state */ if (PROBSTATE(®s->psw) && prob == 0) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Specification exception if new amode is 24-bit and new instruction address is not a 24-bit address */ if (amode == 0 && ia > 0x00FFFFFF) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Space switch if ASN not equal to current PASN */ if ( pasn != regs->CR_LHL(4) ) { /* Special operation exception if ASN translation control (control register 14 bit 12) is zero */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Translate ASN and generate program check if AFX- or ASX-translation exception condition */ xcode = ARCH_DEP(translate_asn) (pasn, regs, &pasteo, aste); if (xcode != 0) ARCH_DEP(program_interrupt) (regs, xcode); /* For PT-ss only, generate a special operation exception if ASN-and-LX-reuse is enabled and the reusable-ASN bit in the ASTE is one */ if (pti_instruction == 0 && ASN_AND_LX_REUSE_ENABLED(regs) && (aste[1] & ASTE1_RA) != 0) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* end if (PT && ASN_AND_LX_REUSE_ENABLED && ASTE1_RA) */ /* For PTI-ss only, generate a special operation exception if the controlled-ASN bit in the ASTE is one and the CPU was in problem state at the beginning of the operation */ if (pti_instruction && (aste[1] & ASTE1_CA) != 0 && PROBSTATE(®s->psw)) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* end if (PT && ASTE1_CA && PROBSTATE) */ /* For PTI-ss only, generate an ASTE instance exception if the ASTEIN in bits 0-31 of the R1 register does not equal the ASTEIN in the ASTE*/ if (pti_instruction && aste[11] != regs->GR_H(r1)) { /* Set bit 2 of the exception access identification to indicate that the program check occurred during PASN translation in a PTI instruction */ regs->excarid = 0x20; ARCH_DEP(program_interrupt) (regs, PGM_ASTE_INSTANCE_EXCEPTION); } /* end if (PT && ASTE11_ASTEIN != GR_H(r1)) */ /* Perform primary address space authorization using current authorization index */ ax = regs->CR_LHH(4); if (ARCH_DEP(authorize_asn) (ax, aste, ATE_PRIMARY, regs)) { regs->TEA = pasn; ARCH_DEP(program_interrupt) (regs, PGM_PRIMARY_AUTHORITY_EXCEPTION); } /* Obtain new primary STD or ASCE from the ASTE */ pstd = ASTE_AS_DESIGNATOR(aste); #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new PSTD */ pstd = ARCH_DEP(subspace_replace) (pstd, pasteo, NULL, regs); #endif /*FEATURE_SUBSPACE_GROUP*/ /* Space switch if either current PSTD or new PSTD space-switch-event control bit is set to 1 */ if ((regs->CR(1) & SSEVENT_BIT) || (pstd & SSEVENT_BIT)) { /* Indicate space-switch event required */ ssevent = 1; } else { ssevent = 2; /* maybe, if PER is pending */ } /* Load new primary STD or ASCE into control register 1 */ regs->CR(1) = pstd; /* Load new AX and PASN into control register 4 */ regs->CR_L(4) = (aste[1] & ASTE1_AX) | pasn; /* Load new PASTEO or LTD into control register 5 */ regs->CR_L(5) = ASF_ENABLED(regs) ? pasteo : ASTE_LT_DESIGNATOR(aste); /* For PTI-ss, and for PT-ss when ASN-and-LX-reuse is enabled, load the new PASTEIN into CR4 from ASTE11_ASTEIN */ if (pti_instruction || ASN_AND_LX_REUSE_ENABLED(regs)) { regs->CR_H(4) = aste[11]; } /* end if (PTI || ASN_AND_LX_REUSE_ENABLED) */ } /* end if(PT-ss or PTI-ss) */ else { /* For PT-cp or PTI-cp use current primary STD or ASCE */ pstd = regs->CR(1); } #ifdef FEATURE_TRACING /* Update trace table address if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ /* Check for Successful Branch PER event */ PER_SB(regs, ia); /* Set the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); /* Replace PSW amode, instruction address, and problem state bit */ regs->psw.amode = amode; UPD_PSW_IA(regs, ia); if (prob) regs->psw.states |= BIT(PSW_PROB_BIT); else regs->psw.states &= ~BIT(PSW_PROB_BIT); regs->psw.AMASK = #if defined(FEATURE_ESAME) regs->psw.amode64 ? AMASK64 : #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode ? AMASK31 : AMASK24; /* AND control register 3 bits 0-15 with the supplied PKM value and replace the SASN in CR3 bits 16-31 with new PASN */ regs->CR_LHH(3) &= pkm; regs->CR_LHL(3) = pasn; /* For PTI, and also for PT when ASN-and-LX-reuse is enabled, set the SASTEIN in CR3 equal to the new PASTEIN in CR4 */ if (pti_instruction || ASN_AND_LX_REUSE_ENABLED(regs)) { regs->CR_H(3) = regs->CR_H(4); } /* end if (PTI || ASN_AND_LX_REUSE_ENABLED) */ /* Set secondary STD or ASCE equal to new primary STD or ASCE */ regs->CR(7) = pstd; /* Update cpu states */ SET_IC_MASK(regs); SET_AEA_COMMON(regs); INVALIDATE_AIA(regs); /* Generate space switch event if required */ if ( ssevent == 1 || (ssevent == 2 && IS_IC_PER(regs)) ) { /* [6.5.2.34] Set the translation exception address equal to the old primary ASN, with the high-order bit set if the old primary space-switch-event control bit is one */ regs->TEA = oldpasn; if (oldpstd & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; ARCH_DEP(program_interrupt) (regs, PGM_SPACE_SWITCH_EVENT); } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* end ARCH_DEP(program_transfer_proc) */ /*-------------------------------------------------------------------*/ /* B228 PT - Program Transfer [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(program_transfer) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); ARCH_DEP(program_transfer_proc) (regs, r1, r2, 0); } /* end DEF_INST(program_transfer) */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_ASN_AND_LX_REUSE) /*-------------------------------------------------------------------*/ /* B99E PTI - Program Transfer with Instance [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(program_transfer_with_instance) { int r1, r2; /* Values of R fields */ if(!sysblk.asnandlxreuse) { ARCH_DEP(operation_exception)(inst,regs); } RRE(inst, regs, r1, r2); ARCH_DEP(program_transfer_proc) (regs, r1, r2, 1); } /* end DEF_INST(program_transfer_with_instance) */ #endif /*defined(FEATURE_ASN_AND_LX_REUSE)*/ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* B248 PALB - Purge ALB [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(purge_accesslist_lookaside_buffer) { int r1, r2; /* Register values (unused) */ RRE(inst, regs, r1, r2); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* This instruction is executed as a no-operation in XC mode */ if(SIE_STATB(regs, MX, XC)) return; #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, PXLB)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Purge the ART lookaside buffer for this CPU */ ARCH_DEP(purge_alb) (regs); } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /*-------------------------------------------------------------------*/ /* B20D PTLB - Purge TLB [S] */ /*-------------------------------------------------------------------*/ DEF_INST(purge_translation_lookaside_buffer) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* This instruction is executed as a no-operation in XC mode */ if(SIE_STATB(regs, MX, XC)) return; #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, PXLB)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Purge the translation lookaside buffer for this CPU */ ARCH_DEP(purge_tlb) (regs); } #if defined(FEATURE_BASIC_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B213 RRB - Reset Reference Bit [S] */ /*-------------------------------------------------------------------*/ DEF_INST(reset_reference_bit) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RADR n; /* Absolute storage addr */ BYTE storkey; /* Storage key */ S(inst, regs, b2, effective_addr2); #if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE) if( #if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS) SIE_MODE(regs) && #endif !(regs->CR(0) & CR0_STORKEY_4K) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif PRIV_CHECK(regs); /* Load 2K block real address from operand address */ n = effective_addr2 & 0x00FFF800; /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { if(SIE_STATB(regs, IC2, RRBE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) && SIE_STATB(regs, RCPO2, RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs); #endif /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { BYTE rcpkey, realkey; RADR ra; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA)) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* The reference and change byte is located directly beyond the page table and is located at offset 1 in the entry. S/370 mode cannot be emulated in ESAME mode, so no provision is made for ESAME mode tables */ rcpa += 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; STORAGE_KEY(rcpa, regs) |= STORKEY_REF; if (!SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) { ra = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); #if !defined(_FEATURE_2K_STORAGE_KEYS) realkey = STORAGE_KEY(ra, regs) #else realkey = (STORAGE_KEY1(ra, regs) | STORAGE_KEY2(ra, regs)) #endif & (STORKEY_REF | STORKEY_CHANGE); /* Reset reference and change bits in storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(ra, regs) &= ~(STORKEY_REF | STORKEY_CHANGE); #else STORAGE_KEY1(ra, regs) &= ~(STORKEY_REF | STORKEY_CHANGE); STORAGE_KEY2(ra, regs) &= ~(STORKEY_REF | STORKEY_CHANGE); #endif } else realkey = 0; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = realkey | (rcpkey & (STORKEY_REF | STORKEY_CHANGE)); /* or with host set */ rcpkey |= realkey << 4; /* Put storage key in guest set */ rcpkey |= storkey; /* reset the reference bit */ rcpkey &= ~(STORKEY_REF); regs->mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa, regs) |= (STORKEY_REF|STORKEY_CHANGE); } } else /* regs->sie_perf */ { #if defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs); #endif /* Reset the reference bit in the storage key */ #if defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs); #endif /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } /* Set the condition code according to the original state of the reference and change bits in the storage key */ regs->psw.cc = ((storkey & STORKEY_REF) ? 2 : 0) | ((storkey & STORKEY_CHANGE) ? 1 : 0); /* If the storage key had the REF bit on then perform * accelerated lookup invalidations on all CPUs * so that the REF bit will be set when referenced next. */ if (storkey & STORKEY_REF) STORKEY_INVALIDATE(regs, n); } #endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/ #if defined(FEATURE_EXTENDED_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B22A RRBE - Reset Reference Bit Extended [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(reset_reference_bit_extended) { int r1, r2; /* Register values */ RADR n; /* Abs frame addr stor key */ BYTE storkey; /* Storage key */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* Load 4K block address from R2 register */ n = regs->GR(r2) & ADDRESS_MAXWRAP_E(regs); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { if(SIE_STATB(regs, IC2, RRBE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && SIE_STATB(regs, RCPO2, RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | (STORAGE_KEY2(n, regs) & (STORKEY_REF|STORKEY_CHANGE)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { BYTE rcpkey, realkey; RADR ra; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(SIE_STATB(regs, MX, XC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; STORAGE_KEY(rcpa, regs) |= STORKEY_REF; if (!SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) { ra = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); #if !defined(_FEATURE_2K_STORAGE_KEYS) realkey = STORAGE_KEY(ra, regs) & (STORKEY_REF | STORKEY_CHANGE); #else realkey = (STORAGE_KEY1(ra, regs) | STORAGE_KEY2(ra, regs)) & (STORKEY_REF | STORKEY_CHANGE); #endif /* Reset the reference and change bits in the real machine storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(ra, regs) &= ~(STORKEY_REF | STORKEY_CHANGE); #else STORAGE_KEY1(ra, regs) &= ~(STORKEY_REF | STORKEY_CHANGE); STORAGE_KEY2(ra, regs) &= ~(STORKEY_REF | STORKEY_CHANGE); #endif } else realkey = 0; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = realkey | (rcpkey & (STORKEY_REF | STORKEY_CHANGE)); /* or with host set */ rcpkey |= realkey << 4; /* Put storage key in guest set */ rcpkey |= storkey; /* reset the reference bit */ rcpkey &= ~(STORKEY_REF); regs->mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa, regs) |= (STORKEY_REF|STORKEY_CHANGE); } } else { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | (STORAGE_KEY2(n, regs) & (STORKEY_REF|STORKEY_CHANGE)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | (STORAGE_KEY2(n, regs) & (STORKEY_REF|STORKEY_CHANGE)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } /* Set the condition code according to the original state of the reference and change bits in the storage key */ regs->psw.cc = ((storkey & STORKEY_REF) ? 2 : 0) | ((storkey & STORKEY_CHANGE) ? 1 : 0); /* If the storage key had the REF bit on then perform * accelerated looup invalidations on all CPUs * so that the REF bit will be set when referenced next. */ if (storkey & STORKEY_REF) STORKEY_INVALIDATE(regs, n); } /* end DEF_INST(reset_reference_bit_extended) */ #endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* B219 SAC - Set Address Space Control [S] */ /* B279 SACF - Set Address Space Control Fast [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_address_space_control) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE mode; /* New addressing mode */ BYTE oldmode; /* Current addressing mode */ int ssevent = 0; /* 1=space switch event */ S(inst, regs, b2, effective_addr2); #if defined(FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST) if(inst[1] == 0x19) // SAC only #endif /*defined(FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST)*/ { /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* Isolate bits 20-23 of effective address */ mode = (effective_addr2 & 0x00000F00) >> 8; /* Special operation exception if DAT is off or secondary-space control bit is zero */ if ((REAL_MODE(&(regs->psw)) || (regs->CR(0) & CR0_SEC_SPACE) == 0) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) && !SIE_STATB(regs, MX, XC) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged operation exception if setting home-space mode while in problem state */ if (mode == 3 && PROBSTATE(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Special operation exception if setting AR mode and address-space function control bit is zero */ if (mode == 2 && !ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Specification exception if mode is invalid */ if (mode > 3 #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Secondary and Home space mode are not supported in XC mode */ || ( SIE_STATB(regs, MX, XC) && (mode == 1 || mode == 3) ) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Save the current address-space control bits */ oldmode = (AR_BIT(®s->psw) << 1) | SPACE_BIT(®s->psw); /* Reset the address-space control bits in the PSW */ if (mode & 1) regs->psw.asc |= BIT(PSW_SPACE_BIT); else regs->psw.asc &= ~BIT(PSW_SPACE_BIT); if (mode & 2) regs->psw.asc |= BIT(PSW_AR_BIT); else regs->psw.asc &= ~BIT(PSW_AR_BIT); TEST_SET_AEA_MODE(regs); /* If switching into or out of home-space mode, and also: primary space-switch-event control bit is set; or home space-switch-event control bit is set; or PER event is to be indicated then indicate a space-switch-event */ if (((oldmode != 3 && mode == 3) || (oldmode == 3 && mode != 3)) && (regs->CR(1) & SSEVENT_BIT || regs->CR(13) & SSEVENT_BIT || OPEN_IC_PER(regs) )) { /* Indicate space-switch event required */ ssevent = 1; /* [6.5.2.34] Set the translation exception address */ if (mode == 3) { /* When switching into home-space mode, set the translation exception address equal to the primary ASN, with the high-order bit set equal to the value of the primary space-switch-event control bit */ regs->TEA = regs->CR_LHL(4); if (regs->CR(1) & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; } else { /* When switching out of home-space mode, set the translation exception address equal to zero, with the high-order bit set equal to the value of the home space-switch-event control bit */ regs->TEA = 0; if (regs->CR(13) & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; } } /* Generate a space-switch-event if indicated */ if (ssevent) ARCH_DEP(program_interrupt) (regs, PGM_SPACE_SWITCH_EVENT); #if defined(FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST) if(inst[1] == 0x19) // SAC only #endif /*defined(FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST)*/ { /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } } #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ /*-------------------------------------------------------------------*/ /* B204 SCK - Set Clock [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_clock) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Clock value */ S(inst, regs, b2, effective_addr2); SIE_INTERCEPT(regs); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); /* Fetch new TOD clock value from operand address */ dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs); /* Set the clock epoch register */ set_tod_clock(dreg >> 8); /* reset the clock comparator pending flag according to the setting of the tod clock */ OBTAIN_INTLOCK(regs); if( tod_clock(regs) > regs->clkc ) ON_IC_CLKC(regs); else OFF_IC_CLKC(regs); RELEASE_INTLOCK(regs); /* Return condition code zero */ regs->psw.cc = 0; RETURN_INTCHECK(regs); // /*debug*/logmsg("Set TOD clock=%16.16" I64_FMT "X\n", dreg); } /*-------------------------------------------------------------------*/ /* B206 SCKC - Set Clock Comparator [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_clock_comparator) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Clock value */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, SCKC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Fetch clock comparator value from operand location */ dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); // /*debug*/logmsg("Set clock comparator=%16.16" I64_FMT "X\n", dreg); dreg >>= 8; OBTAIN_INTLOCK(regs); regs->clkc = dreg; /* reset the clock comparator pending flag according to the setting of the tod clock */ if( tod_clock(regs) > dreg ) ON_IC_CLKC(regs); else OFF_IC_CLKC(regs); RELEASE_INTLOCK(regs); RETURN_INTCHECK(regs); } #if defined(FEATURE_EXTENDED_TOD_CLOCK) /*-------------------------------------------------------------------*/ /* 0107 SCKPF - Set Clock Programmable Field [E] */ /*-------------------------------------------------------------------*/ DEF_INST(set_clock_programmable_field) { E(inst, regs); PRIV_CHECK(regs); /* Program check if register 0 bits 0-15 are not zeroes */ if ( regs->GR_LHH(0) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Set TOD programmable register from register 0 */ regs->todpr = regs->GR_LHL(0); } /* end DEF_INST(set_clock_programmable_field) */ #endif /*defined(FEATURE_EXTENDED_TOD_CLOCK)*/ /*-------------------------------------------------------------------*/ /* B208 SPT - Set CPU Timer [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_cpu_timer) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S64 dreg; /* Timer value */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, SPT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Fetch the CPU timer value from operand location */ dreg = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); OBTAIN_INTLOCK(regs); set_cpu_timer(regs, dreg); /* reset the cpu timer pending flag according to its value */ if( CPU_TIMER(regs) < 0 ) ON_IC_PTIMER(regs); else OFF_IC_PTIMER(regs); RELEASE_INTLOCK(regs); // /*debug*/logmsg("Set CPU timer=%16.16" I64_FMT "X\n", dreg); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B210 SPX - Set Prefix [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_prefix) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RADR n; /* Prefix value */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); FW_CHECK(effective_addr2, regs); /* Perform serialization before fetching the operand */ PERFORM_SERIALIZATION (regs); /* Load new prefix value from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Isolate bits 1-19 for ESA/390 or 1-18 for ESAME of new prefix value */ n &= PX_MASK; /* Program check if prefix is invalid absolute address */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Load new value into prefix register */ regs->PX = n; /* Set pointer to active PSA structure */ regs->psa = (PSA_3XX*)(regs->mainstor + regs->PX); /* Invalidate the ALB and TLB */ ARCH_DEP(purge_tlb) (regs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (regs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /* Perform serialization after completing the operation */ PERFORM_SERIALIZATION (regs); } /*-------------------------------------------------------------------*/ /* B20A SPKA - Set PSW Key from Address [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_psw_key_from_address) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int n; /* Storage key workarea */ BYTE pkey; /* Original key */ S(inst, regs, b2, effective_addr2); pkey = regs->psw.pkey; /* Isolate the key from bits 24-27 of effective address */ n = effective_addr2 & 0x000000F0; /* Privileged operation exception if in problem state and the corresponding PSW key mask bit is zero */ if ( PROBSTATE(®s->psw) && ((regs->CR(3) << (n >> 4)) & 0x80000000) == 0 ) ARCH_DEP(program_interrupt) (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* Set PSW key */ regs->psw.pkey = n; INVALIDATE_AIA(regs); } #if defined(FEATURE_DUAL_ADDRESS_SPACE) /*-------------------------------------------------------------------*/ /* Common processing routine for the SSAR and SSAIR instructions */ /*-------------------------------------------------------------------*/ void ARCH_DEP(set_secondary_asn_proc) (REGS *regs, int r1, int r2, int ssair_instruction) { U16 sasn; /* New Secondary ASN */ RADR sstd; /* Secondary STD */ U32 sasteo=0; /* Secondary ASTE origin */ U32 aste[16]; /* ASN second table entry */ U32 sastein; /* New Secondary ASTEIN */ U16 xcode; /* Exception code */ U16 ax; /* Authorization index */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ UNREFERENCED(r2); SIE_XC_INTERCEPT(regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Special operation exception if ASN translation control (bit 12 of control register 14) is zero or DAT is off */ if ((regs->CR(14) & CR14_ASN_TRAN) == 0 || REAL_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Load the new ASN from R1 register bits 16-31 */ sasn = regs->GR_LHL(r1); #ifdef FEATURE_TRACING /* Form trace entry if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) newcr12 = ARCH_DEP(trace_ssar) (ssair_instruction, sasn, regs); #endif /*FEATURE_TRACING*/ /* Test for SSAR/SSAIR to current primary */ if ( sasn == regs->CR_LHL(4) ) { /* Set new secondary STD equal to primary STD */ sstd = regs->CR(1); /* Set new secondary ASTEIN equal to primary ASTEIN */ sastein = regs->CR_H(4); } /* end if(SSAR-cp or SSAIR-cp) */ else { /* SSAR/SSAIR with space-switch */ /* Perform ASN translation to obtain ASTE */ xcode = ARCH_DEP(translate_asn) (sasn, regs, &sasteo, aste); /* Program check if ASN translation exception */ if (xcode != 0) ARCH_DEP(program_interrupt) (regs, xcode); /* For SSAR-ss only, generate a special operation exception if ASN-and-LX-reuse is enabled and the reusable-ASN bit in the ASTE is one */ if (ssair_instruction == 0 && ASN_AND_LX_REUSE_ENABLED(regs) && (aste[1] & ASTE1_RA) != 0) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* end if (SSAR && ASN_AND_LX_REUSE_ENABLED && ASTE1_RA) */ /* For SSAIR-ss only, generate a special operation exception if the controlled-ASN bit in the ASTE is one and the CPU is in problem state */ if (ssair_instruction && (aste[1] & ASTE1_CA) != 0 && PROBSTATE(®s->psw)) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); } /* end if (SSAIR && ASTE1_CA && PROBSTATE) */ /* For SSAIR-ss only, generate an ASTE instance exception if the ASTEIN in bits 0-31 of the R1 register does not equal the ASTEIN in the ASTE */ if (ssair_instruction && aste[11] != regs->GR_H(r1)) { /* Set bit 3 of the exception access identification to indicate that the program check occurred during SASN translation in a SSAIR instruction */ regs->excarid = 0x10; ARCH_DEP(program_interrupt) (regs, PGM_ASTE_INSTANCE_EXCEPTION); } /* end if (SSAIR && ASTE11_ASTEIN != GR_H(r1)) */ /* Perform ASN authorization using current AX */ ax = regs->CR_LHH(4); if (ARCH_DEP(authorize_asn) (ax, aste, ATE_SECONDARY, regs)) { regs->TEA = sasn; ARCH_DEP(program_interrupt) (regs, PGM_SECONDARY_AUTHORITY_EXCEPTION); } /* Load new secondary STD or ASCE from the ASTE */ sstd = ASTE_AS_DESIGNATOR(aste); /* Load new secondary ASTEIN from the ASTE */ sastein = aste[11]; #ifdef FEATURE_SUBSPACE_GROUP /* Perform subspace replacement on new SSTD */ sstd = ARCH_DEP(subspace_replace) (sstd, sasteo, NULL, regs); #endif /*FEATURE_SUBSPACE_GROUP*/ } /* end if(SSAR-ss or SSAIR-ss) */ #ifdef FEATURE_TRACING /* Update trace table address if ASN tracing is on */ if (regs->CR(12) & CR12_ASNTRACE) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ /* Load the new secondary ASN into control register 3 */ regs->CR_LHL(3) = sasn; /* Load the new secondary STD into control register 7 */ regs->CR(7) = sstd; /* For SSAIR, and for SSAR when ASN-and-LX-reuse is enabled, load the new secondary ASTEIN into control register 3 */ if (ssair_instruction || ASN_AND_LX_REUSE_ENABLED(regs)) { regs->CR_H(3) = sastein; } /* end if (SSAIR || ASN_AND_LX_REUSE_ENABLED) */ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* end ARCH_DEP(set_secondary_asn_proc) */ /*-------------------------------------------------------------------*/ /* B225 SSAR - Set Secondary ASN [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(set_secondary_asn) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); ARCH_DEP(set_secondary_asn_proc) (regs, r1, r2, 0); } /* end DEF_INST(set_secondary_asn) */ #endif /*defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if defined(FEATURE_ASN_AND_LX_REUSE) /*-------------------------------------------------------------------*/ /* B99F SSAIR - Set Secondary ASN with Instance [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(set_secondary_asn_with_instance) { int r1, r2; /* Values of R fields */ if(!sysblk.asnandlxreuse) { ARCH_DEP(operation_exception)(inst,regs); } RRE(inst, regs, r1, r2); ARCH_DEP(set_secondary_asn_proc) (regs, r1, r2, 1); } /* end DEF_INST(set_secondary_asn_with_instance) */ #endif /*defined(FEATURE_ASN_AND_LX_REUSE)*/ #if defined(FEATURE_BASIC_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* 08 SSK - Set Storage Key [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(set_storage_key) { int r1, r2; /* Values of R fields */ RADR n; /* Absolute storage addr */ RR(inst, regs, r1, r2); PRIV_CHECK(regs); #if defined(FEATURE_4K_STORAGE_KEYS) || defined(_FEATURE_SIE) if( #if defined(_FEATURE_SIE) && !defined(FEATURE_4K_STORAGE_KEYS) SIE_MODE(regs) && #endif !(regs->CR(0) & CR0_STORKEY_4K) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif /* Program check if R2 bits 28-31 are not zeroes */ if ( regs->GR_L(r2) & 0x0000000F ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Load 2K block address from R2 register */ n = regs->GR_L(r2) & 0x00FFF800; /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { if(SIE_STATB(regs, IC2, SSKE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) && SIE_STATB(regs, RCPO2, RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { int sr; BYTE realkey, rcpkey; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA)) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* The reference and change byte is located directly beyond the page table and is located at offset 1 in the entry. S/370 mode cannot be emulated in ESAME mode, so no provision is made for ESAME mode tables */ rcpa += 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* guest absolute to host real */ sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE); if (sr #if defined(_FEATURE_STORAGE_KEY_ASSIST) && !SIE_FEATB(regs, RCPO0, SKA) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #if defined(_FEATURE_STORAGE_KEY_ASSIST) if (sr) realkey = 0; else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); realkey = #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) #else (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) #endif & (STORKEY_REF | STORKEY_CHANGE); } /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; STORAGE_KEY(rcpa, regs) |= STORKEY_REF; /* or with host set */ rcpkey |= realkey << 4; /* or new settings with guest set */ rcpkey &= ~(STORKEY_REF | STORKEY_CHANGE); rcpkey |= regs->GR_L(r1) & (STORKEY_REF | STORKEY_CHANGE); regs->mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa, regs) |= (STORKEY_REF|STORKEY_CHANGE); #if defined(_FEATURE_STORAGE_KEY_ASSIST) /* Insert key in new storage key */ if(SIE_STATB(regs, RCPO0, SKA)) regs->mainstor[rcpa-1] = regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); if(!sr) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= STORKEY_BADFRM; STORAGE_KEY(n, regs) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); #else STORAGE_KEY1(n, regs) &= STORKEY_BADFRM; STORAGE_KEY1(n, regs) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); STORAGE_KEY2(n, regs) &= STORKEY_BADFRM; STORAGE_KEY2(n, regs) |= regs->GR_LHLCL(r1) & (STORKEY_KEY | STORKEY_FETCH); #endif } } } else { /* Update the storage key from R1 register bits 24-30 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= STORKEY_BADFRM; STORAGE_KEY(n, regs) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n, regs) &= STORKEY_BADFRM; STORAGE_KEY1(n, regs) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); STORAGE_KEY2(n, regs) &= STORKEY_BADFRM; STORAGE_KEY2(n, regs) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { /* Update the storage key from R1 register bits 24-30 */ #if defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= STORKEY_BADFRM; STORAGE_KEY(n, regs) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n, regs) &= STORKEY_BADFRM; STORAGE_KEY1(n, regs) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); STORAGE_KEY2(n, regs) &= STORKEY_BADFRM; STORAGE_KEY2(n, regs) |= regs->GR_LHLCL(r1) & ~(STORKEY_BADFRM); #endif } STORKEY_INVALIDATE(regs, n); // /*debug*/logmsg("SSK storage block %8.8X key %2.2X\n", // /*debug*/ regs->GR_L(r2), regs->GR_LHLCL(r1) & 0xFE); } /* end DEF_INST(set_storage_key) */ #endif /*defined(FEATURE_BASIC_STORAGE_KEYS)*/ #if defined(FEATURE_EXTENDED_STORAGE_KEYS) #if defined(FEATURE_CONDITIONAL_SSKE) /*-------------------------------------------------------------------*/ /* SUBROUTINE TO PERFORM CONDITIONAL SSKE PROCESSING */ /* Input: */ /* regs Register context */ /* r1 Register number field from SSKE instruction */ /* m3 Mask field from SSKE instruction */ /* skey Contents of storage key before modification */ /* r1key New storage key to be set (R1 bits 56-63) */ /* Output (when conditional SSKE is not indicated): */ /* r1 register and condition code remain unchanged; */ /* The function return value is 0. */ /* Output (when conditional SSKE is indicated): */ /* r1 register bits 48-55 contain original storage key; */ /* - if storage key is to be updated, the condition code */ /* is set to 1 and the function return value is 0; */ /* - if storage key update is to be bypassed, the condition */ /* code is set to 0 and the function return value is 1; */ /*-------------------------------------------------------------------*/ static inline int ARCH_DEP(conditional_sske_procedure) (REGS *regs, int r1, int m3, BYTE skey, BYTE r1key) { /* Perform normal SSKE if MR and MC bits are both zero */ if ((m3 & (SSKE_MASK_MR | SSKE_MASK_MC)) == 0) return 0; /* Perform conditional SSKE if either MR or MC bits are set */ /* Ignore Bad Frame indicator */ skey &= ~(STORKEY_BADFRM); /* Insert storage key into R1 register bits 48-55 */ regs->GR_LHLCH(r1) = skey; /* If storage key and fetch bit do not equal new values in R1 register bits 56-60 then set condition code 1 and return to SSKE to update storage key */ if ((skey & (STORKEY_KEY | STORKEY_FETCH)) != (r1key & (STORKEY_KEY | STORKEY_FETCH))) { regs->psw.cc = 1; return 0; } /* If both MR and MC mask bits are one then set condition code 0 and leave storage key unchanged */ if ((m3 & (SSKE_MASK_MR | SSKE_MASK_MC)) == (SSKE_MASK_MR | SSKE_MASK_MC)) { regs->psw.cc = 0; return 1; } /* If MR bit is zero and reference bit is equal to bit 61 of R1 register then set condition code 0 and leave storage key unchanged */ if ((m3 & SSKE_MASK_MR) == 0 && ((skey & STORKEY_REF) == (r1key & STORKEY_REF))) { regs->psw.cc = 0; return 1; } /* If MC bit is zero and the change bit is equal to bit 62 of R1 register then set condition code 0 and leave storage key unchanged */ if ((m3 & SSKE_MASK_MC) == 0 && ((skey & STORKEY_CHANGE) == (r1key & STORKEY_CHANGE))) { regs->psw.cc = 0; return 1; } /* Set condition code 1 and let SSKE update storage key */ regs->psw.cc = 1; return 0; } /* end function conditional_sske_procedure */ #endif /*defined(FEATURE_CONDITIONAL_SSKE)*/ #endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ #if defined(FEATURE_EXTENDED_STORAGE_KEYS) /*-------------------------------------------------------------------*/ /* B22B SSKE - Set Storage Key extended [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(set_storage_key_extended) { int r1, r2; /* Register numbers */ int m3; /* Mask field */ RADR a,n; /* Abs frame addr stor key */ #if defined(FEATURE_ENHANCED_DAT_FACILITY) int fc; /* Frame Count */ #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ BYTE r1key; /* New key (R1 bits 56-63) */ RRF_M(inst, regs, r1, r2, m3); PRIV_CHECK(regs); /* Load 4K block address from R2 register */ a = regs->GR(r2) & ADDRESS_MAXWRAP_E(regs); /* Key to be applied */ r1key = regs->GR_LHLCL(r1); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); #if defined(FEATURE_ENHANCED_DAT_FACILITY) if ((m3 & SSKE_MASK_MB)) fc = 0x100 - ((a & 0xFF000) >> PAGEFRAME_PAGESHIFT); else fc = 1; for( ; fc--; ) { if ((m3 & SSKE_MASK_MB)) /* r2 contains an absolute address when multiple block control is one */ n = a; else #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ /* Convert real address to absolute address */ n = APPLY_PREFIXING (a, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { if(SIE_STATB(regs, IC2, SSKE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if ((SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && SIE_STATB(regs, RCPO2, RCPBY)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { int sr; BYTE realkey, rcpkey, protkey; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(SIE_STATB(regs, MX, XC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* guest absolute to host real */ sr = SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE); if (sr #if defined(_FEATURE_STORAGE_KEY_ASSIST) && !(SIE_FEATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; /* set the reference bit in the RCP key */ STORAGE_KEY(rcpa, regs) |= STORKEY_REF; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(sr) { realkey = 0; protkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE); /* rcpa-1 is correct here - would have been SIE Intercepted otherwise */ protkey |= regs->mainstor[rcpa-1] & (STORKEY_KEY | STORKEY_FETCH); } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); protkey = #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) #else (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) #endif ; realkey = protkey & (STORKEY_REF | STORKEY_CHANGE); } #if defined(FEATURE_CONDITIONAL_SSKE) /* Perform conditional SSKE procedure */ if (ARCH_DEP(conditional_sske_procedure)(regs, r1, m3, protkey, r1key)) return; #endif /*defined(FEATURE_CONDITIONAL_SSKE)*/ /* or with host set */ rcpkey |= realkey << 4; /* insert new settings of the guest set */ rcpkey &= ~(STORKEY_REF | STORKEY_CHANGE); rcpkey |= r1key & (STORKEY_REF | STORKEY_CHANGE); regs->mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa, regs) |= (STORKEY_REF|STORKEY_CHANGE); #if defined(_FEATURE_STORAGE_KEY_ASSIST) /* Insert key in new storage key */ if(SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) regs->mainstor[rcpa-1] = r1key & (STORKEY_KEY | STORKEY_FETCH); if(!sr) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= STORKEY_BADFRM; STORAGE_KEY(n, regs) |= r1key & (STORKEY_KEY | STORKEY_FETCH); #else STORAGE_KEY1(n, regs) &= STORKEY_BADFRM; STORAGE_KEY1(n, regs) |= r1key & (STORKEY_KEY | STORKEY_FETCH); STORAGE_KEY2(n, regs) &= STORKEY_BADFRM; STORAGE_KEY2(n, regs) |= r1key & (STORKEY_KEY | STORKEY_FETCH); #endif } } } else { #if defined(FEATURE_CONDITIONAL_SSKE) /* Perform conditional SSKE procedure */ if (ARCH_DEP(conditional_sske_procedure)(regs, r1, m3, #if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs), #else (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)), #endif r1key)) return; #endif /*defined(FEATURE_CONDITIONAL_SSKE)*/ /* Update the storage key from R1 register bits 24-30 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= STORKEY_BADFRM; STORAGE_KEY(n, regs) |= r1key & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n, regs) &= STORKEY_BADFRM; STORAGE_KEY1(n, regs) |= r1key & ~(STORKEY_BADFRM); STORAGE_KEY2(n, regs) &= STORKEY_BADFRM; STORAGE_KEY2(n, regs) |= r1key & ~(STORKEY_BADFRM); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { #if defined(FEATURE_CONDITIONAL_SSKE) /* Perform conditional SSKE procedure */ if (ARCH_DEP(conditional_sske_procedure)(regs, r1, m3, #if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs), #else (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)), #endif r1key)) return; #endif /*defined(FEATURE_CONDITIONAL_SSKE)*/ /* Update the storage key from R1 register bits 24-30 */ #if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= STORKEY_BADFRM; STORAGE_KEY(n, regs) |= r1key & ~(STORKEY_BADFRM); #else STORAGE_KEY1(n, regs) &= STORKEY_BADFRM; STORAGE_KEY1(n, regs) |= r1key & ~(STORKEY_BADFRM); STORAGE_KEY2(n, regs) &= STORKEY_BADFRM; STORAGE_KEY2(n, regs) |= r1key & ~(STORKEY_BADFRM); #endif } /* Invalidate AIA/AEA so that the REF and CHANGE bits will be set when referenced next */ STORKEY_INVALIDATE(regs, n); #if defined(FEATURE_ENHANCED_DAT_FACILITY) /* Update r2 in the case of a multiple page update */ if ((m3 & SSKE_MASK_MB)) { /* Advance r2 to the next page */ a += PAGEFRAME_PAGESIZE; if(regs->psw.amode64) regs->GR_G(r2) = a & ADDRESS_MAXWRAP(regs); else regs->GR_L(r2) = a & ADDRESS_MAXWRAP(regs); } } #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* end DEF_INST(set_storage_key_extended) */ #endif /*defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ /*-------------------------------------------------------------------*/ /* 80 SSM - Set System Mask [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_system_mask) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); /* * ECPS:VM - Before checking for prob/priv * Check CR6 to see if S-ASSIST is requested * * If we can process it, then do it */ #if defined(FEATURE_ECPSVM) if(ecpsvm_dossm(regs,b2,effective_addr2)==0) { return; } #endif PRIV_CHECK(regs); /* Special operation exception if SSM-suppression is active */ if ( (regs->CR(0) & CR0_SSM_SUPP) #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* SSM-suppression is ignored in XC mode */ && !SIE_STATB(regs, MX, XC) #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, SSM)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Load new system mask value from operand address */ regs->psw.sysmask = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* DAT must be off in XC mode */ if(SIE_STATB(regs, MX, XC) && (regs->psw.sysmask & PSW_DATMODE) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* For ECMODE, bits 0 and 2-4 of system mask must be zero */ if ((regs->psw.sysmask & 0xB8) != 0 #if defined(FEATURE_BCMODE) && ECMODE(®s->psw) #endif /*defined(FEATURE_BCMODE)*/ ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); SET_IC_MASK(regs); TEST_SET_AEA_MODE(regs); RETURN_INTCHECK(regs); } /* end DEF_INST(set_system_mask) */ /*-------------------------------------------------------------------*/ /* AE SIGP - Signal Processor [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(signal_processor) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ REGS *tregs; /* -> Target CPU registers */ GREG parm; /* Signal parameter */ GREG status = 0; /* Signal status */ RADR abs; /* Absolute address */ U16 cpad; /* Target CPU address */ BYTE order; /* SIGP order code */ #if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS) int cpu; /* cpu number */ int set_arch = 0; /* Need to switch mode */ #endif /*defined(_900) || defined(FEATURE_ESAME)*/ size_t log_sigp = 0; /* Log SIGP instruction flag */ char log_buf[128]; /* Log buffer */ static char *ordername[] = { /* 0x00 */ "Unassigned", /* 0x01 SIGP_SENSE */ "Sense", /* 0x02 SIGP_EXTCALL */ "External call", /* 0x03 SIGP_EMERGENCY */ "Emergency signal", /* 0x04 SIGP_START */ "Start", /* 0x05 SIGP_STOP */ "Stop", /* 0x06 SIGP_RESTART */ "Restart", /* 0x07 SIGP_IPR */ "Initial program reset", /* 0x08 SIGP_PR */ "Program reset", /* 0x09 SIGP_STOPSTORE */ "Stop and store status", /* 0x0A SIGP_IMPL */ "Initial microprogram load", /* 0x0B SIGP_INITRESET */ "Initial CPU reset", /* 0x0C SIGP_RESET */ "CPU reset", /* 0x0D SIGP_SETPREFIX */ "Set prefix", /* 0x0E SIGP_STORE */ "Store status", /* 0x0F */ "Unassigned", /* 0x10 */ "Unassigned", /* 0x11 SIGP_STOREX */ "Store extended status at address", /* 0x12 SIGP_SETARCH */ "Set architecture mode", /* 0x13 SIGP_COND_EMERGENCY */ "Conditional emergency", /* 0x14 */ "Unassigned", /* 0x15 SIGP_SENSE_RUNNING_STATE */ "Sense running state" }; RS(inst, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_SIG,"SIGP",regs->GR_L(r1),regs->GR_L(r3),(U32)(effective_addr2 & 0xffffffff)); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Load the order code from operand address bits 24-31 */ order = effective_addr2 & 0xFF; /* Load the target CPU address from R3 bits 16-31 */ cpad = (order != SIGP_SETARCH) ? regs->GR_LHL(r3) : regs->cpuad; /* Load the parameter from R1 (if R1 odd), or R1+1 (if even) */ parm = (r1 & 1) ? regs->GR_L(r1) : regs->GR_L(r1+1); /* Return condition code 3 if target CPU does not exist */ if (cpad >= MAX_CPU) { PTT(PTT_CL_ERR,"*SIGP",regs->GR_L(r1),regs->GR_L(r3),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; return; } /* Issuing Sense to an offline CPU that is >= numcpu or HI_CPU is not now considered unusual especially since we have increased the default max CPU number to 8 */ if (order == SIGP_SENSE && !IS_CPU_ONLINE(cpad) && cpad >= sysblk.numcpu && cpad >= HI_CPU) { PTT(PTT_CL_ERR,"*SIGP",regs->GR_L(r1),regs->GR_L(r3),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; return; } /* Trace SIGP unless Sense, External Call, Emergency Signal, Sense Running State, or the target CPU is configured offline */ if ((order > LOG_SIGPORDER && order != SIGP_SENSE_RUNNING_STATE) || !IS_CPU_ONLINE(cpad)) { log_sigp = snprintf ( log_buf, sizeof(log_buf), "CPU%4.4X: SIGP %s (%2.2X) CPU%4.4X, PARM "F_GREG, regs->cpuad, order >= sizeof(ordername) / sizeof(ordername[0]) ? "Unassigned" : ordername[order], order, cpad, parm); } /* [4.9.2.1] Claim the use of the CPU signaling and response facility, and return condition code 2 if the facility is busy. The sigplock is held while the facility is in use by any CPU. */ if(try_obtain_lock (&sysblk.sigplock)) { regs->psw.cc = 2; if (log_sigp) logmsg("%s: CC 2\n",log_buf); return; } /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); /* If the cpu is not part of the configuration then return cc3 Initial CPU reset may IML a processor that is currently not part of the configuration, ie configure the cpu implicitly online */ if (order != SIGP_INITRESET #if defined(FEATURE_S370_CHANNEL) && order != SIGP_IMPL #endif /*defined(FEATURE_S370_CHANNEL)*/ && !IS_CPU_ONLINE(cpad)) { RELEASE_INTLOCK(regs); release_lock(&sysblk.sigplock); regs->psw.cc = 3; if (log_sigp) logmsg("%s: CC 3\n",log_buf); return; } /* Point to the target CPU -- may be NULL if INITRESET or IMPL */ tregs = sysblk.regs[cpad]; /* Except for the reset orders, return condition code 2 if the target CPU is executing a previous start, stop, restart, stop and store status, set prefix, or store status order */ if ((order != SIGP_RESET #if defined(FEATURE_S370_CHANNEL) && order != SIGP_IMPL && order != SIGP_IPR #endif /*defined(FEATURE_S370_CHANNEL)*/ && order != SIGP_INITRESET) && (tregs) && (tregs->cpustate == CPUSTATE_STOPPING || IS_IC_RESTART(tregs))) { RELEASE_INTLOCK(regs); release_lock(&sysblk.sigplock); regs->psw.cc = 2; if (log_sigp) logmsg("%s: CC 2\n",log_buf); sched_yield(); return; } /* The operator-intervening condition, when present, can be indicated in response to all orders, and is indicated in response to sense if it precludes the acceptance of any of the installed orders (which is always true in our case), but cannot arise as a result of a SIGP instruction executed by a CPU addressing itself. */ if (1 && order != SIGP_SENSE // if this isn't a sense, && cpad != regs->cpuad // and we're not addressing ourselves, && (tregs) && tregs->opinterv // and operator intervening condition... ) { // ...then we cannot proceed status |= SIGP_STATUS_OPERATOR_INTERVENING; } else /* (order == SIGP_SENSE || cpad == regs->cpuad || ((tregs) && !tregs->opinterv)) */ /* Process signal according to order code */ switch (order) { case SIGP_SENSE: /* Set status bit 24 if external call interrupt pending */ if (IS_IC_EXTCALL(tregs)) status |= SIGP_STATUS_EXTERNAL_CALL_PENDING; /* Set status bit 25 if target CPU is stopped */ if (tregs->cpustate != CPUSTATE_STARTED) status |= SIGP_STATUS_STOPPED; /* Test for checkstop state */ if(tregs->checkstop) status |= SIGP_STATUS_CHECK_STOP; /* Test for operator intervening state */ if(cpad != regs->cpuad && tregs->opinterv) status |= SIGP_STATUS_OPERATOR_INTERVENING; break; case SIGP_EXTCALL: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Exit with status bit 24 set if a previous external call interrupt is still pending in the target CPU */ if (IS_IC_EXTCALL(tregs)) { status |= SIGP_STATUS_EXTERNAL_CALL_PENDING; break; } /* Raise an external call interrupt pending condition */ ON_IC_EXTCALL(tregs); tregs->extccpu = regs->cpuad; break; #if defined(_900) || defined(FEATURE_ESAME) case SIGP_COND_EMERGENCY: /* Test for checkstop state */ if(tregs->checkstop) status |= SIGP_STATUS_CHECK_STOP; else { U16 check_asn = (parm & 0xFFFF); SET_PSW_IA(tregs); if (0 /* PSW disabled for external interruptions, I/O interruptions, or both */ || (!(tregs->psw.sysmask & PSW_EXTMASK) || !(tregs->psw.sysmask & PSW_IOMASK)) /* CPU in wait state and the PSW instruction address not zero */ || ( WAITSTATE( &tregs->psw ) && tregs->psw.IA ) /* CPU not in wait state and check_asn value equals an ASN of the CPU (primary, secondary or both) -- regardless of the setting of PSW bits 16-17 */ || (1 && !WAITSTATE( &tregs->psw ) && (check_asn == tregs->CR_LHL(3) || check_asn == tregs->CR_LHL(4)) ) ) { /* Raise an emergency signal interrupt pending condition */ tregs->emercpu[regs->cpuad] = 1; ON_IC_EMERSIG(tregs); } else status |= SIGP_STATUS_INCORRECT_STATE; } break; #endif /* defined(_900) || defined(FEATURE_ESAME) */ case SIGP_EMERGENCY: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Raise an emergency signal interrupt pending condition */ ON_IC_EMERSIG(tregs); tregs->emercpu[regs->cpuad] = 1; break; case SIGP_START: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Restart the target CPU if it is in the stopped state */ tregs->cpustate = CPUSTATE_STARTED; break; case SIGP_STOP: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Put the the target CPU into the stopping state */ tregs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(tregs); break; case SIGP_RESTART: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Make restart interrupt pending in the target CPU */ ON_IC_RESTART(tregs); /* Set cpustate to stopping. If the restart is successful, then the cpustate will be set to started in cpu.c */ if(tregs->cpustate == CPUSTATE_STOPPED) tregs->cpustate = CPUSTATE_STOPPING; break; case SIGP_STOPSTORE: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Indicate store status is required when stopped */ ON_IC_STORSTAT(tregs); /* Put the the target CPU into the stopping state */ tregs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(tregs); break; #if defined(FEATURE_S370_CHANNEL) case SIGP_IMPL: case SIGP_IPR: #endif /* defined(FEATURE_S370_CHANNEL) */ case SIGP_INITRESET: if (!IS_CPU_ONLINE(cpad)) { configure_cpu(cpad); if (!IS_CPU_ONLINE(cpad)) { status |= SIGP_STATUS_OPERATOR_INTERVENING; break; } tregs = sysblk.regs[cpad]; } #if defined(FEATURE_S370_CHANNEL) if (order == SIGP_IMPL || order == SIGP_IPR) channelset_reset(tregs); #endif /* defined(FEATURE_S370_CHANNEL) */ /* Signal initial CPU reset function */ tregs->sigpireset = 1; tregs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(tregs); break; #if defined(FEATURE_S370_CHANNEL) case SIGP_PR: channelset_reset(tregs); /* fallthrough*/ #endif /* defined(FEATURE_S370_CHANNEL) */ case SIGP_RESET: /* Signal CPU reset function */ tregs->sigpreset = 1; tregs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(tregs); break; case SIGP_SETPREFIX: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Exit with operator intervening if the status is stopping, such that a retry can be attempted */ if(tregs->cpustate == CPUSTATE_STOPPING) { status |= SIGP_STATUS_OPERATOR_INTERVENING; break; } /* Exit with status bit 22 set if CPU is not stopped */ if (tregs->cpustate != CPUSTATE_STOPPED) { status |= SIGP_STATUS_INCORRECT_STATE; break; } /* Obtain new prefix from parameter register bits 1-19 or bits 1-18 in ESAME mode */ abs = parm & PX_MASK; /* Exit with status bit 23 set if new prefix is invalid */ if (abs > regs->mainlim) { status |= SIGP_STATUS_INVALID_PARAMETER; break; } /* Load new value into prefix register of target CPU */ tregs->PX = abs; /* Set pointer to active PSA structure */ tregs->psa = (PSA_3XX*)(tregs->mainstor + tregs->PX); /* Invalidate the ALB and TLB of the target CPU */ ARCH_DEP(purge_tlb) (tregs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (tregs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ /* Perform serialization and checkpoint-sync on target CPU */ // perform_serialization (tregs); // perform_chkpt_sync (tregs); break; case SIGP_STORE: /* Test for checkstop state */ if(tregs->checkstop) { status |= SIGP_STATUS_CHECK_STOP; break; } /* Exit with operator intervening if the status is stopping, such that a retry can be attempted */ if(tregs->cpustate == CPUSTATE_STOPPING) { status |= SIGP_STATUS_OPERATOR_INTERVENING; break; } /* Exit with status bit 22 set if CPU is not stopped */ if (tregs->cpustate != CPUSTATE_STOPPED) { status |= SIGP_STATUS_INCORRECT_STATE; break; } /* Obtain status address from parameter register bits 1-22 */ abs = parm & 0x7FFFFE00; /* Exit with status bit 23 set if status address invalid */ if (abs > regs->mainlim) { status |= SIGP_STATUS_INVALID_PARAMETER; break; } /* Store status at specified main storage address */ ARCH_DEP(store_status) (tregs, abs); /* Perform serialization and checkpoint-sync on target CPU */ // perform_serialization (tregs); // perform_chkpt_sync (tregs); break; #if defined(_390) case SIGP_STOREX: { #if !defined(FEATURE_BASIC_FP_EXTENSIONS) status |= SIGP_STATUS_INVALID_ORDER; #else /* defined(FEATURE_BASIC_FP_EXTENSIONS) */ RADR absx; /* abs addr of extended save area */ /* Test for checkstop state */ if(tregs->checkstop) status |= SIGP_STATUS_CHECK_STOP; /* Check if CPU is not stopped */ if (tregs->cpustate != CPUSTATE_STOPPED) status |= SIGP_STATUS_INCORRECT_STATE; /* Only proceed if no conditions exist to preclude the acceptance of this signal-processor order */ if (!status) { /* Obtain status address from parameter register bits 1-22 */ abs = parm & 0x7FFFFE00; /* Exit with status bit 23 set if status address invalid */ if (abs > regs->mainlim) status |= SIGP_STATUS_INVALID_PARAMETER; else { /* Fetch the address of the extended save area */ absx = ARCH_DEP(fetch_fullword_absolute) (abs+212, tregs); absx &= 0x7FFFF000; /* Invalid parameter if extended save area address invalid */ if (absx > regs->mainlim) status |= SIGP_STATUS_INVALID_PARAMETER; else { int i; // (work) /* Store status at specified main storage address */ ARCH_DEP(store_status) (tregs, abs ); /* Store extended status at specified main storage address */ for (i = 0; i < 32; i++) STORE_FW( tregs->mainstor + absx + (i*4), tregs->fpr[i] ); STORE_FW( tregs->mainstor + absx + 128, tregs->fpc ); STORE_FW( tregs->mainstor + absx + 132, 0 ); STORE_FW( tregs->mainstor + absx + 136, 0 ); STORE_FW( tregs->mainstor + absx + 140, 0 ); /* Perform serialization and checkpoint-sync on target CPU */ // perform_serialization (tregs); // perform_chkpt_sync (tregs); } } } #endif /* defined(FEATURE_BASIC_FP_EXTENSIONS) */ } break; #endif /* defined(_390) */ #if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS) case SIGP_SETARCH: /* CPU must have ESAME support */ if(!sysblk.arch_z900) status = SIGP_STATUS_INVALID_ORDER; PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); for (cpu = 0; cpu < MAX_CPU; cpu++) if (IS_CPU_ONLINE(cpu) && sysblk.regs[cpu]->cpustate != CPUSTATE_STOPPED && sysblk.regs[cpu]->cpuad != regs->cpuad) status |= SIGP_STATUS_INCORRECT_STATE; if(!status) { switch(parm & 0xFF) { #if defined(_900) || defined(FEATURE_ESAME) case 0: // from: -- z/Arch --to--> 390 if(sysblk.arch_mode == ARCH_390) status = SIGP_STATUS_INVALID_PARAMETER; else { sysblk.arch_mode = ARCH_390; set_arch = 1; INVALIDATE_AIA(regs); regs->captured_zpsw = regs->psw; regs->psw.states |= BIT(PSW_NOTESAME_BIT); regs->PX_L &= 0x7FFFE000; for (cpu = 0; cpu < MAX_CPU; cpu++) { if (IS_CPU_ONLINE(cpu) && sysblk.regs[cpu]->cpuad != regs->cpuad) { INVALIDATE_AIA(sysblk.regs[cpu]); sysblk.regs[cpu]->captured_zpsw = sysblk.regs[cpu]->psw; sysblk.regs[cpu]->psw.states |= BIT(PSW_NOTESAME_BIT); sysblk.regs[cpu]->PX_L &= 0x7FFFE000; } } } break; case 1: // from: -- 390 --to--> z/Arch if(sysblk.arch_mode == ARCH_900) status = SIGP_STATUS_INVALID_PARAMETER; else { sysblk.arch_mode = ARCH_900; set_arch = 1; INVALIDATE_AIA(regs); regs->psw.states &= ~BIT(PSW_NOTESAME_BIT); regs->psw.IA_H = 0; regs->PX_G &= 0x7FFFE000; for (cpu = 0; cpu < MAX_CPU; cpu++) { if (IS_CPU_ONLINE(cpu) && sysblk.regs[cpu]->cpuad != regs->cpuad) { INVALIDATE_AIA(sysblk.regs[cpu]); sysblk.regs[cpu]->psw.states &= ~BIT(PSW_NOTESAME_BIT); sysblk.regs[cpu]->psw.IA_H = 0; sysblk.regs[cpu]->PX_G &= 0x7FFFE000; } } } break; case 2: // restore CAPTURED z/Arch PSW... if(sysblk.arch_mode == ARCH_900) status = SIGP_STATUS_INVALID_PARAMETER; else { sysblk.arch_mode = ARCH_900; set_arch = 1; INVALIDATE_AIA(regs); regs->psw.states &= ~BIT(PSW_NOTESAME_BIT); regs->psw.IA_H = 0; regs->PX_G &= 0x7FFFE000; for (cpu = 0; cpu < MAX_CPU; cpu++) { if (IS_CPU_ONLINE(cpu) && sysblk.regs[cpu]->cpuad != regs->cpuad) { INVALIDATE_AIA(sysblk.regs[cpu]); sysblk.regs[cpu]->psw = sysblk.regs[cpu]->captured_zpsw; sysblk.regs[cpu]->PX_G &= 0x7FFFE000; } } } break; #endif // defined(_900) || defined(FEATURE_ESAME) #if defined(FEATURE_HERCULES_DIAGCALLS) case 37: if(sysblk.arch_mode == ARCH_370) status = SIGP_STATUS_INVALID_PARAMETER; else { sysblk.arch_mode = ARCH_370; set_arch = 1; } break; #endif /*defined(FEATURE_HERCULES_DIAGCALLS)*/ default: PTT(PTT_CL_ERR,"*SIGP",regs->GR_L(r1),regs->GR_L(r3),(U32)(effective_addr2 & 0xffffffff)); status |= SIGP_STATUS_INVALID_PARAMETER; } /* end switch(parm & 0xFF) */ } /* end if(!status) */ sysblk.dummyregs.arch_mode = sysblk.arch_mode; #if defined(OPTION_FISHIO) ios_arch_mode = sysblk.arch_mode; #endif // defined(OPTION_FISHIO) /* Invalidate the ALB and TLB */ ARCH_DEP(purge_tlb) (regs); #if defined(FEATURE_ACCESS_REGISTERS) ARCH_DEP(purge_alb) (tregs); #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); break; #endif /*defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS)*/ #if defined(FEATURE_SENSE_RUNNING_STATUS) case SIGP_SENSE_RUNNING_STATE: if (tregs->cpustate != CPUSTATE_STARTED) status = SIGP_STATUS_NOT_RUNNING; break; #endif /*defined(FEATURE_SENSE_RUNNING_STATUS)*/ default: PTT(PTT_CL_ERR,"*SIGP",regs->GR_L(r1),regs->GR_L(r3),(U32)(effective_addr2 & 0xffffffff)); status = SIGP_STATUS_INVALID_ORDER; } /* end switch(order) */ /* Release the use of the signalling and response facility */ release_lock(&sysblk.sigplock); /* Wake up the target CPU */ if (IS_CPU_ONLINE(cpad)) WAKEUP_CPU (sysblk.regs[cpad]); /* Release the interrupt lock */ RELEASE_INTLOCK(regs); /* If status is non-zero, load the status word into the R1 register and return condition code 1 */ if (status != 0) { regs->GR_L(r1) = status; regs->psw.cc = 1; } else regs->psw.cc = 0; /* Log the results if we're interested in this particular SIGP */ if (log_sigp) { if (regs->psw.cc == 0) logmsg("%s: CC 0\n",log_buf); else logmsg("%s: CC 1 STATUS %8.8X\n",log_buf, (U32)status); } /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); #if defined(_900) || defined(FEATURE_ESAME) || defined(FEATURE_HERCULES_DIAGCALLS) if(set_arch) { OBTAIN_INTLOCK(regs); longjmp(regs->archjmp, 0); } #endif /*defined(_900) || defined(FEATURE_ESAME)*/ RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B207 STCKC - Store Clock Comparator [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_clock_comparator) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Clock value */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, SCKC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); /* Save clock comparator value */ dreg = regs->clkc; /* reset the clock comparator pending flag according to the setting of the tod clock */ if( tod_clock(regs) > dreg ) { ON_IC_CLKC(regs); /* Roll back the instruction and take the timer interrupt if we have a pending CPU timer and we are enabled for such interrupts *JJ */ if( OPEN_IC_CLKC(regs) ) { RELEASE_INTLOCK(regs); UPD_PSW_IA(regs, PSW_IA(regs, -4)); RETURN_INTCHECK(regs); } } else OFF_IC_CLKC(regs); RELEASE_INTLOCK(regs); /* Store clock comparator value at operand location */ ARCH_DEP(vstore8) ((dreg << 8), effective_addr2, b2, regs ); // /*debug*/logmsg("Store clock comparator=%16.16" I64_FMT "X\n", dreg); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B6 STCTL - Store Control [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(store_control) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2 = NULL; /* Mainstor pointers */ RS(inst, regs, r1, r3, b2, effective_addr2); #if defined(FEATURE_ECPSVM) if(ecpsvm_dostctl(regs,r1,r3,b2,effective_addr2)==0) { return; } #endif PRIV_CHECK(regs); FW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, STCTL)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Calculate number of regs to store */ n = ((r3 - r1) & 0xF) + 1; /* Calculate number of words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 2; /* Address of operand beginning */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely (m < n)) p2 = (U32*)MADDR(effective_addr2 + (m*4), b2, regs, ACCTYPE_WRITE, regs->psw.pkey); else m = n; /* Store at operand beginning */ for (i = 0; i < m; i++) store_fw (p1++, regs->CR_L((r1 + i) & 0xF)); /* Store on next page */ for ( ; i < n; i++) store_fw (p2++, regs->CR_L((r1 + i) & 0xF)); ITIMER_UPDATE(effective_addr2,(n*4)-1,regs); } /* end DEF_INST(store_control) */ /*-------------------------------------------------------------------*/ /* B212 STAP - Store CPU Address [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_cpu_address) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); ODD_CHECK(effective_addr2, regs); /* Store CPU address at operand address */ ARCH_DEP(vstore2) ( regs->cpuad, effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* B202 STIDP - Store CPU ID [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_cpu_id) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word workarea */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); DW_CHECK(effective_addr2, regs); /* Load the CPU ID */ dreg = sysblk.cpuid; /* If LPARNUM is two digits, build a format 1 CPU ID */ if (sysblk.lparnuml == 2) { /* Overlay first two digits of CPU ID by LPARNUM */ dreg &= 0xFF00FFFFFFFFFFFFULL; dreg |= ((U64)(sysblk.lparnum & 0xFF) << 48); /* Indicate format 1 CPU ID */ dreg |= 0x8000ULL; } /* If LPARNUM is one digit, build a format 0 CPU ID */ else if (sysblk.lparnuml == 1) { /* Overlay first digit of CPU ID by processor id and overlay second digit of CPU ID by LPARNUM */ dreg &= 0xFF00FFFFFFFFFFFFULL; dreg |= ((U64)(regs->cpuad & 0x0F) << 52) | ((U64)(sysblk.lparnum & 0x0F) << 48); } /* If LPARNUM is not specified, build basic mode CPU ID */ else { /* If first digit of serial is zero, insert processor id */ if ((dreg & 0x00F0000000000000ULL) == 0) dreg |= (U64)(regs->cpuad & 0x0F) << 52; } #if defined(FEATURE_ESAME) /* For ESAME, set version code in CPU ID bits 0-7 to zero */ dreg &= 0x00FFFFFFFFFFFFFFULL; #endif /*defined(FEATURE_ESAME)*/ /* Store CPU ID at operand address */ ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* B209 STPT - Store CPU Timer [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_cpu_timer) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S64 dreg; /* Double word workarea */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, SPT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ OBTAIN_INTLOCK(regs); /* Save the CPU timer value */ dreg = cpu_timer(regs); /* reset the cpu timer pending flag according to its value */ if( CPU_TIMER(regs) < 0 ) { ON_IC_PTIMER(regs); /* Roll back the instruction and take the timer interrupt if we have a pending CPU timer and we are enabled for such interrupts *JJ */ if( OPEN_IC_PTIMER(regs) ) { RELEASE_INTLOCK(regs); UPD_PSW_IA(regs, PSW_IA(regs, -4)); RETURN_INTCHECK(regs); } } else OFF_IC_PTIMER(regs); RELEASE_INTLOCK(regs); /* Store CPU timer value at operand location */ ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); // /*debug*/logmsg("Store CPU timer=%16.16" I64_FMT "X\n", dreg); RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B211 STPX - Store Prefix [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_prefix) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); FW_CHECK(effective_addr2, regs); /* Store prefix register at operand address */ ARCH_DEP(vstore4) ( regs->PX, effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* Calculate CPU capability indicator for STSI instruction */ /* */ /* The CPU capability indicator is 32-bit value which is calculated */ /* dynamically. A lower value indicates a faster CPU. The value may */ /* be either an unsigned binary integer or a floating point number. */ /* If bits 0-8 are zero, it is an integer in the range 0 to 2**23-1. */ /* If bits 0-8 are nonzero, is is a 32-bit short BFP number. */ /*-------------------------------------------------------------------*/ #if !defined(_STSI_CAPABILITY) #define _STSI_CAPABILITY static inline U32 stsi_capability (REGS *regs) { U64 dreg; /* work doubleword */ struct rusage usage; /* RMF type data */ #define SUSEC_PER_MIPS 48 /* One MIPS eq 48 SU */ getrusage(RUSAGE_SELF,&usage); dreg = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec); dreg = (dreg * 1000000) + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec); dreg = INSTCOUNT(regs) / (dreg ? dreg : 1); dreg *= SUSEC_PER_MIPS; return 0x800000 / (dreg ? dreg : 1); } /* end function stsi_capability */ #endif /*!defined(_STSI_CAPABILITY)*/ #ifdef FEATURE_STORE_SYSTEM_INFORMATION /*-------------------------------------------------------------------*/ /* B27D STSI - Store System Information [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_system_information) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE *m; /* Mainstor address */ int i; U16 offset; /* Offset into control block */ SYSIB111 *sysib111; /* Basic machine conf */ SYSIB121 *sysib121; /* Basic machine CPU */ SYSIB122 *sysib122; /* Basic machine CPUs */ SYSIB221 *sysib221; /* LPAR CPU */ SYSIB222 *sysib222; /* LPAR CPUs */ #if 0 SYSIB322 *sysib322; /* VM CPUs */ SYSIBVMDB *sysib322; /* VM description block */ #endif #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) SYSIB1512 *sysib1512; /* Configuration Topology */ BYTE *tle; /* Pointer to next TLE */ TLECNTNR *tlecntnr; /* Container TLE pointer */ TLECPU *tlecpu; /* CPU TLE Type */ U64 cpumask; /* work */ int cputype; /* work */ U16 cpuad; /* CPU address */ BYTE cntnrid; /* Container ID */ #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ /* "0 1 2 3 4 5 6 7" */ static BYTE hexebcdic[16] = { 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7, /* "8 9 A B C D E F" */ 0xF8,0xF9,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6 }; #define STSI_CAPABILITY stsi_capability(regs) S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_INF,"STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); #if defined(DEBUG_STSI) logmsg("control.c: STSI %d.%d.%d ia="F_VADR" sysib="F_VADR"\n", (regs->GR_L(0) & STSI_GPR0_FC_MASK) >> 28, regs->GR_L(0) & STSI_GPR0_SEL1_MASK, regs->GR_L(1) & STSI_GPR1_SEL2_MASK, PSW_IA(regs,-4), effective_addr2); #endif /*DEBUG_STSI*/ /* Check function code */ if((regs->GR_L(0) & STSI_GPR0_FC_MASK) > STSI_GPR0_FC_LPAR #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) && (regs->GR_L(0) & STSI_GPR0_FC_MASK) != STSI_GPR0_FC_CURRINFO #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ ) { PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); #ifdef DEBUG_STSI logmsg("control.c: STSI cc=3 function code invalid\n"); #endif /*DEBUG_STSI*/ regs->psw.cc = 3; return; } /* Program check if reserved bits not zero */ if(regs->GR_L(0) & STSI_GPR0_RESERVED || regs->GR_L(1) & STSI_GPR1_RESERVED) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Return current level if function code is zero */ if((regs->GR_L(0) & STSI_GPR0_FC_MASK) == STSI_GPR0_FC_CURRNUM) { regs->GR_L(0) |= STSI_GPR0_FC_LPAR; #ifdef DEBUG_STSI logmsg("control.c: STSI cc=0 R0=%8.8X\n", regs->GR_L(0)); #endif /*DEBUG_STSI*/ regs->psw.cc = 0; return; } /* Program check if operand not on a page boundary */ if ( effective_addr2 & 0x00000FFF ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc3 if selector codes invalid */ /* Func- tion Selec- Selec- Code tor 1 tor 2 Information Requested about ---- ----- ----- ---------------------------- 1 1 1 Basic-machine configuration 1 2 1 Basic-machine CPU 1 2 2 Basic-machine CPUs 2 2 1 Logical-partition CPU 2 2 2 Logical-partition CPUs 3 2 2 Virtual-machine CPUs 15 1 2 Topology information of current configuration */ if (0 || ((regs->GR_L(0) & STSI_GPR0_FC_MASK) == STSI_GPR0_FC_BASIC && (0 || (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) == 0 || (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) > 2 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) == 0 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) > 2 ) ) || ((regs->GR_L(0) & STSI_GPR0_FC_MASK) == STSI_GPR0_FC_LPAR && (0 || (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) != 2 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) == 0 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) > 2 ) ) || ((regs->GR_L(0) & STSI_GPR0_FC_MASK) == STSI_GPR0_FC_VM && (0 || (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) != 2 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) != 2 ) ) #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) || ((regs->GR_L(0) & STSI_GPR0_FC_MASK) == STSI_GPR0_FC_CURRINFO && (0 || (regs->GR_L(0) & STSI_GPR0_SEL1_MASK) != 1 || (regs->GR_L(1) & STSI_GPR1_SEL2_MASK) != 2 ) ) #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ ) { PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); #ifdef DEBUG_STSI logmsg("control.c: STSI cc=3 selector codes invalid\n"); #endif /*DEBUG_STSI*/ regs->psw.cc = 3; return; } /* Obtain absolute address of main storage block, check protection, and set reference and change bits */ m = MADDR (effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); switch(regs->GR_L(0) & STSI_GPR0_FC_MASK) { case STSI_GPR0_FC_BASIC: switch(regs->GR_L(0) & STSI_GPR0_SEL1_MASK) { case 1: switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) { case 1: /* Basic-machine configuration */ sysib111 = (SYSIB111*)(m); memset(sysib111, 0x00, MAX(sizeof(SYSIB111),64*4)); sysib111->flag1 |= SYSIB111_PFLAG; get_manufacturer(sysib111->manufact); get_model(sysib111->model); for(i = 0; i < 4; i++) sysib111->type[i] = hexebcdic[(sysblk.cpuid >> (28 - (i*4))) & 0x0F]; get_modelcapa(sysib111->modcapaid); if (sysib111->modcapaid[0] == '\0') memcpy(sysib111->modcapaid, sysib111->model, sizeof(sysib111->model)); get_modelperm(sysib111->mpci); get_modeltemp(sysib111->mtci); memset(sysib111->seqc,0xF0,sizeof(sysib111->seqc)); for(i = 0; i < 6; i++) sysib111->seqc[(sizeof(sysib111->seqc) - 6) + i] = hexebcdic[(sysblk.cpuid >> (52 - (i*4))) & 0x0F]; get_plant(sysib111->plant); STORE_FW(sysib111->mcaprating, STSI_CAPABILITY); STORE_FW(sysib111->mpcaprating, STSI_CAPABILITY); STORE_FW(sysib111->mtcaprating, STSI_CAPABILITY); for(i=0;i<5;i++) { sysib111->typepct[i] = 100; } regs->psw.cc = 0; break; default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* selector 2 */ break; case 2: switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) { case 1: /* Basic-machine Current CPU */ sysib121 = (SYSIB121*)(m); memset(sysib121, 0x00, MAX(sizeof(SYSIB121),64*4)); memset(sysib121->seqc,0xF0,sizeof(sysib121->seqc)); for(i = 0; i < 6; i++) sysib121->seqc[(sizeof(sysib121->seqc) - 6) + i] = hexebcdic[sysblk.cpuid >> (52 - (i*4)) & 0x0F]; get_plant(sysib121->plant); STORE_HW(sysib121->cpuad,regs->cpuad); regs->psw.cc = 0; break; case 2: /* Basic-machine All CPUs */ sysib122 = (SYSIB122*)(m); memset(sysib122, 0x00, MAX(sizeof(SYSIB122),64*4)); sysib122->format = 1; offset = (U16)(sysib122->accap - (BYTE*)sysib122); STORE_HW(sysib122->accoff, offset); STORE_FW(sysib122->sccap, STSI_CAPABILITY); STORE_FW(sysib122->cap, STSI_CAPABILITY); STORE_HW(sysib122->totcpu, MAX_CPU); STORE_HW(sysib122->confcpu, sysblk.cpus); STORE_HW(sysib122->sbcpu, MAX_CPU - sysblk.cpus); get_mpfactors((BYTE*)sysib122->mpfact); STORE_FW(sysib122->accap, STSI_CAPABILITY); get_mpfactors((BYTE*)sysib122->ampfact); regs->psw.cc = 0; break; default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* selector 2 */ break; default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* selector 1 */ break; case STSI_GPR0_FC_LPAR: switch(regs->GR_L(0) & STSI_GPR0_SEL1_MASK) { case 2: switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) { case 1: /* Logical-partition Current CPU */ sysib221 = (SYSIB221 *)(m); memset(sysib221, 0x00, MAX(sizeof(SYSIB221),64*4)); memset(sysib221->seqc,0xF0,sizeof(sysib111->seqc)); for(i = 0; i < 6; i++) sysib221->seqc[(sizeof(sysib221->seqc) - 6) + i] = hexebcdic[(sysblk.cpuid >> (52 - (i*4))) & 0x0F]; get_plant(sysib221->plant); STORE_HW(sysib221->lcpuid,regs->cpuad); STORE_HW(sysib221->cpuad,regs->cpuad); regs->psw.cc = 0; break; case 2: /* Logical-partition All CPUs */ sysib222 = (SYSIB222 *)(m); memset(sysib222, 0x00, MAX(sizeof(SYSIB222),64*4)); STORE_HW(sysib222->lparnum,1); sysib222->lcpuc = SYSIB222_LCPUC_SHARED; STORE_HW(sysib222->totcpu,MAX_CPU); STORE_HW(sysib222->confcpu,sysblk.cpus); STORE_HW(sysib222->sbcpu,MAX_CPU - sysblk.cpus); get_lparname(sysib222->lparname); STORE_FW(sysib222->lparcaf,1000); /* Full capability factor */ STORE_FW(sysib222->mdep[0],1000); /* ZZ nonzero value */ STORE_FW(sysib222->mdep[1],1000); /* ZZ nonzero value */ STORE_HW(sysib222->shrcpu,sysblk.cpus); regs->psw.cc = 0; break; default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* selector 2 */ break; default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* selector 1 */ break; #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) case STSI_GPR0_FC_CURRINFO: switch(regs->GR_L(0) & STSI_GPR0_SEL1_MASK) { case 1: switch(regs->GR_L(1) & STSI_GPR1_SEL2_MASK) { case 2: /* Topology information of current configuration */ sysib1512 = (SYSIB1512 *)(m); memset(sysib1512, 0x00, sizeof(SYSIB1512)); sysib1512->mnest = 2; sysib1512->mag[4] = 1; /*added by PaoloG 25-10-13*/ sysib1512->mag[5] = MAX_CPU; tle = sysib1512->tles; cntnrid = 1; cpuad = 0; /* Build a container TLE */ tlecntnr = (TLECNTNR *)tle; memset(tlecntnr, 0x00, sizeof(TLECNTNR)); tlecntnr->nl = 1; tlecntnr->cntnrid = cntnrid; tle += sizeof(TLECNTNR); /* For each type of CPU */ for (cputype = 0; cputype <= SCCB_PTYP_MAX; cputype++) { tlecpu = (TLECPU *)tle; /* For each CPU of this type */ cpumask = 0; for (i=0; i < sysblk.hicpu; i++) { if (1 && sysblk.regs[i] && sysblk.regs[i]->configured && sysblk.ptyp[i] == cputype ) { /* Initialize new TLE for this type */ if (!cpumask) { memset(tlecpu, 0x00, sizeof(TLECPU)); tlecpu->nl = 0; if (sysblk.topology == TOPOLOGY_VERT) { tlecpu->flags = CPUTLE_FLAG_VERTMED; } else { tlecpu->flags = CPUTLE_FLAG_HORIZ; } tlecpu->cpuadorg = cpuad; tlecpu->cputype = cputype; } /* Update CPU mask field for this type */ cpumask |= 0x8000000000000000ULL >> sysblk.regs[i]->cpuad; } } /* Bump to next TLE */ if (cpumask) { STORE_DW( &tlecpu->cpumask, cpumask ); tle += sizeof(TLECPU); } } /* Save the length of this System Information Block */ STORE_HW(sysib1512->len,(U16)(tle - (BYTE*)sysib1512)); /* Successful completion */ regs->psw.cc = 0; /* Clear topology-change-report-pending condition */ OBTAIN_INTLOCK(regs); sysblk.topchnge = 0; RELEASE_INTLOCK(regs); break; default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* selector 2 */ break; default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* selector 1 */ break; #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ default: PTT(PTT_CL_ERR,"*STSI",regs->GR_L(0),regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff)); regs->psw.cc = 3; } /* function code */ #ifdef DEBUG_STSI /* Display results of STSI */ logmsg("control.c: STSI cc=%d\n", regs->psw.cc); for (i=0; i<256; i+=16, m+=16) { BYTE c, s[17]; int j; for (j=0; j<16; j++) { c = guest_to_host(m[j]); s[j] = isprint(c) ? c : '.'; } s[j] = '\0'; logmsg("+%2.2X %2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X *%s*\n", i,m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7], m[8],m[9],m[10],m[11],m[12],m[13],m[14],m[15],s); } #endif /*DEBUG_STSI*/ } /* end DEF_INST(store_system_information) */ #endif /*FEATURE_STORE_SYSTEM_INFORMATION*/ /*-------------------------------------------------------------------*/ /* AC STNSM - Store Then And Systen Mask [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(store_then_and_system_mask) { BYTE i2; /* Immediate byte of opcode */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ SI(inst, regs, i2, b1, effective_addr1); #ifdef FEATURE_ECPSVM if(ecpsvm_dostnsm(regs,b1,effective_addr1,i2)==0) { return; } #endif PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, STNSM)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Store current system mask value into storage operand */ ARCH_DEP(vstoreb) ( regs->psw.sysmask, effective_addr1, b1, regs ); /* AND system mask with immediate operand */ regs->psw.sysmask &= i2; SET_IC_MASK(regs); TEST_SET_AEA_MODE(regs); RETURN_INTCHECK(regs); } /* end DEF_INST(store_then_and_system_mask) */ /*-------------------------------------------------------------------*/ /* AD STOSM - Store Then Or Systen Mask [SI] */ /*-------------------------------------------------------------------*/ DEF_INST(store_then_or_system_mask) { BYTE i2; /* Immediate byte of opcode */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ SI(inst, regs, i2, b1, effective_addr1); #ifdef FEATURE_ECPSVM if(ecpsvm_dostosm(regs,b1,effective_addr1,i2)==0) { return; } #endif PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC1, STOSM)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Store current system mask value into storage operand */ ARCH_DEP(vstoreb) ( regs->psw.sysmask, effective_addr1, b1, regs ); /* OR system mask with immediate operand */ regs->psw.sysmask |= i2; #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* DAT must be off in XC mode */ if(SIE_STATB(regs, MX, XC) && (regs->psw.sysmask & PSW_DATMODE) ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* For ECMODE, bits 0 and 2-4 of system mask must be zero */ if ( #if defined(FEATURE_BCMODE) ECMODE(®s->psw) && #endif /*defined(FEATURE_BCMODE)*/ (regs->psw.sysmask & 0xB8) != 0) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); SET_IC_MASK(regs); TEST_SET_AEA_MODE(regs); RETURN_INTCHECK(regs); } /* end DEF_INST(store_then_or_system_mask) */ /*-------------------------------------------------------------------*/ /* B246 STURA - Store Using Real Address [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(store_using_real_address) { int r1, r2; /* Values of R fields */ RADR n; /* Unsigned work */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* R2 register contains operand real storage address */ n = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Program check if operand not on fullword boundary */ FW_CHECK(n, regs); /* Store R1 register at second operand location */ ARCH_DEP(vstore4) (regs->GR_L(r1), n, USE_REAL_ADDR, regs ); #if defined(FEATURE_PER2) /* Storage alteration must be enabled for STURA to be recognised */ if( EN_IC_PER_SA(regs) && EN_IC_PER_STURA(regs) ) { ON_IC_PER_SA(regs) ; ON_IC_PER_STURA(regs) ; regs->perc &= 0xFFFC; /* zero STD ID part of PER code */ } #endif /*defined(FEATURE_PER2)*/ } /* end DEF_INST(store_using_real_address) */ #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* B24C TAR - Test Access [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_access) { int r1, r2; /* Values of R fields */ U32 asteo; /* Real address of ASTE */ U32 aste[16]; /* ASN second table entry */ RRE(inst, regs, r1, r2); /* Program check if ASF control bit is zero */ if (!ASF_ENABLED(regs)) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Set condition code 0 if ALET value is 0 */ if (regs->AR(r1) == ALET_PRIMARY) { regs->psw.cc = 0; return; } /* Set condition code 3 if ALET value is 1 */ if (regs->AR(r1) == ALET_SECONDARY) { regs->psw.cc = 3; return; } /* Perform ALET translation using EAX value from register R2 bits 0-15, and set condition code 3 if exception */ if (ARCH_DEP(translate_alet) (regs->AR(r1), regs->GR_LHH(r2), ACCTYPE_TAR, #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) SIE_STATB(regs, MX, XC) ? regs->hostregs : #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ regs, &asteo, aste)) { regs->psw.cc = 3; return; } /* Set condition code 1 or 2 according to whether the ALET designates the DUCT or the PASTE */ regs->psw.cc = (regs->AR(r1) & ALET_PRI_LIST) ? 2 : 1; } #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ #if defined(FEATURE_TEST_BLOCK) /*-------------------------------------------------------------------*/ /* B22C TB - Test Block [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_block) { int r1, r2; /* Values of R fields */ RADR n; /* Real address */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); #if defined(FEATURE_REGION_RELOCATE) if(SIE_STATNB(regs, MX, RRF) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); /* Load 4K block address from R2 register */ n = regs->GR(r2) & ADDRESS_MAXWRAP_E(regs); n &= XSTORE_PAGEMASK; /* 4K boundary */ /* Perform serialization */ PERFORM_SERIALIZATION (regs); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Protection exception if low-address protection is set */ if (ARCH_DEP(is_low_address_protected) (n, regs)) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = (n & STORAGE_KEY_PAGEMASK); regs->excarid = 0; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION); } /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Clear the 4K block to zeroes */ memset (regs->mainstor + n, 0x00, PAGEFRAME_PAGESIZE); /* Set condition code 0 if storage usable, 1 if unusable */ if (STORAGE_KEY(n, regs) & STORKEY_BADFRM) regs->psw.cc = 1; else regs->psw.cc = 0; /* Perform serialization */ PERFORM_SERIALIZATION (regs); /* Clear general register 0 */ SET_GR_A(0, regs, 0); } #endif /*defined(FEATURE_TEST_BLOCK)*/ /*-------------------------------------------------------------------*/ /* E501 TPROT - Test Protection [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_protection) { int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ RADR aaddr; /* Absolute address */ BYTE skey; /* Storage key */ BYTE akey; /* Access key */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC2, TPROT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Convert logical address to real address */ if (REAL_MODE(®s->psw)) { regs->dat.protect = 0; regs->dat.raddr = effective_addr1; } else { /* Return condition code 3 if translation exception */ if (ARCH_DEP(translate_addr) (effective_addr1, b1, regs, ACCTYPE_TPROT)) { regs->psw.cc = 3; return; } } /* Convert real address to absolute address */ aaddr = APPLY_PREFIXING (regs->dat.raddr, regs->PX); /* Program check if absolute address is outside main storage */ if (aaddr > regs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && !regs->sie_pref) { /* Under SIE TPROT also indicates if the host is using page protection */ /* Translate to real address - eventually using an access register if the guest is in XC mode */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + aaddr, b1>0 && MULTIPLE_CONTROLLED_DATA_SPACE(regs) ? b1 : USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert host real address to host absolute address */ aaddr = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); if (aaddr > regs->hostregs->mainlim) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); } #endif /*defined(_FEATURE_SIE)*/ /* Load access key from operand 2 address bits 24-27 */ akey = effective_addr2 & 0xF0; /* Load the storage key for the absolute address */ skey = STORAGE_KEY(aaddr, regs); /* Return condition code 2 if location is fetch protected */ if (ARCH_DEP(is_fetch_protected) (effective_addr1, skey, akey, regs)) regs->psw.cc = 2; else /* Return condition code 1 if location is store protected */ if (ARCH_DEP(is_store_protected) (effective_addr1, skey, akey, regs)) regs->psw.cc = 1; else /* Return condition code 0 if location is not protected */ regs->psw.cc = 0; } #if defined(FEATURE_TRACING) /*-------------------------------------------------------------------*/ /* 99 TRACE - Trace [RS] */ /*-------------------------------------------------------------------*/ DEF_INST(trace) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ #if defined(FEATURE_TRACING) U32 op; /* Operand */ #endif /*defined(FEATURE_TRACING)*/ RS(inst, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); FW_CHECK(effective_addr2, regs); #if defined(FEATURE_TRACING) /* Exit if explicit tracing (control reg 12 bit 31) is off */ if ( (regs->CR(12) & CR12_EXTRACE) == 0 ) return; /* Fetch the trace operand */ op = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Exit if bit zero of the trace operand is one */ if ( (op & 0x80000000) ) return; /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); regs->CR(12) = ARCH_DEP(trace_tr) (r1, r3, op, regs); #endif /*defined(FEATURE_TRACING)*/ /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } #endif /*defined(FEATURE_TRACING)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "control.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "control.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/crypto.c0000664000175000017500000002175012564723224011674 00000000000000/* CRYPTO.C (c) Copyright Jan Jaeger, 2000-2010 */ /* Cryptographic instructions */ #include "hstdinc.h" #define _CRYPTO_C_ #define _HENGINE_DLL_ #include "hercules.h" #if defined(FEATURE_MESSAGE_SECURITY_ASSIST) #include "opcode.h" #define CRYPTO_EXTERN #include "crypto.h" /*----------------------------------------------------------------------------*/ /* B93E KIMD - Compute Intermediate Message Digest [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(compute_intermediate_message_digest_r) { if( ARCH_DEP(compute_intermediate_message_digest) ) ARCH_DEP(compute_intermediate_message_digest) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } /*----------------------------------------------------------------------------*/ /* B93F KLMD - Compute Last Message Digest [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(compute_last_message_digest_r) { if( ARCH_DEP(compute_last_message_digest) ) ARCH_DEP(compute_last_message_digest) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } /*----------------------------------------------------------------------------*/ /* B92E KM - Cipher Message [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_r) { if( ARCH_DEP(cipher_message) ) ARCH_DEP(cipher_message) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } /*----------------------------------------------------------------------------*/ /* B91E KMAC - Compute Message Authentication Code [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(compute_message_authentication_code_r) { if( ARCH_DEP(compute_message_authentication_code) ) ARCH_DEP(compute_message_authentication_code) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } /*----------------------------------------------------------------------------*/ /* B92F KMC - Cipher Message with Chaining [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_chaining_r) { if( ARCH_DEP(cipher_message_with_chaining) ) ARCH_DEP(cipher_message_with_chaining) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } #endif /*defined(FEATURE_MESSAGE_SECURITY_ASSIST)*/ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* B92D KMCTR - Cipher message with counter [RRF] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_counter_r) { if( ARCH_DEP(cipher_message_with_counter) ) ARCH_DEP(cipher_message_with_counter) (inst, regs); else { int r1, r2, r3; /* register values */ RRF_M(inst, regs, r1, r2, r3); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } /*----------------------------------------------------------------------------*/ /* B92A KMF - Cipher message with cipher feedback [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_cipher_feedback_r) { if( ARCH_DEP(cipher_message_with_cipher_feedback) ) ARCH_DEP(cipher_message_with_cipher_feedback) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } /*----------------------------------------------------------------------------*/ /* B92B KMO - Cipher message with output feedback [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_output_feedback_r) { if( ARCH_DEP(cipher_message_with_output_feedback) ) ARCH_DEP(cipher_message_with_output_feedback) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } /*----------------------------------------------------------------------------*/ /* B92C PCC - Perform cryptographic computation [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(perform_cryptographic_computation_r) { if( ARCH_DEP(perform_cryptographic_computation) ) ARCH_DEP(perform_cryptographic_computation) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } #endif /* FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /*----------------------------------------------------------------------------*/ /* B928 PCKMO - Perform cryptographic key management operation [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(perform_cryptographic_key_management_operation_r) { if( ARCH_DEP(perform_cryptographic_key_management_operation) ) ARCH_DEP(perform_cryptographic_key_management_operation) (inst, regs); else { int r1, r2; /* register values */ RRE(inst, regs, r1, r2); ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); } } #ifndef __WK__ #define __WK__ /*----------------------------------------------------------------------------*/ /* Function: renew_wrapping_keys */ /* */ /* Each time a clear reset is performed, a new set of wrapping keys and their */ /* associated verification patterns are generated. The contents of the two */ /* wrapping-key registers are kept internal to the model so that no program, */ /* including the operating system, can directly observe their clear value. */ /*----------------------------------------------------------------------------*/ void renew_wrapping_keys(void) { int i; BYTE lparname[8]; U64 cpuid; BYTE byte; obtain_lock(&sysblk.wklock); for(i = 0; i < 0x100; i++) srandom(random() * host_tod()); /* Randomize related to time */ for(i = 0; i < 32; i++) sysblk.wkaes_reg[i] = random(); for(i = 0; i < 24; i++) sysblk.wkdea_reg[i] = random(); /* We set the verification pattern to */ /* cpuid (8 bytes) */ /* lpar name (8 bytes) */ /* lparnum (1 byte) */ /* random number 8 bytes at the end) */ memset(sysblk.wkvpaes_reg, 0, 32); memset(sysblk.wkvpdea_reg, 0, 24); cpuid = sysblk.cpuid; for(i = 0; i < 8; i++) { sysblk.wkvpaes_reg[7 - i] = cpuid; sysblk.wkvpdea_reg[7 - i] = cpuid; cpuid >>= 8; } get_lparname(lparname); memcpy(&sysblk.wkvpaes_reg[8], lparname, 8); memcpy(&sysblk.wkvpdea_reg[8], lparname, 8); sysblk.wkvpaes_reg[16] = sysblk.lparnum; sysblk.wkvpdea_reg[16] = sysblk.lparnum; for(i = 0; i < 8; i++) { byte = random(); sysblk.wkvpaes_reg[31 - i] = byte; sysblk.wkvpdea_reg[23 - i] = byte; } release_lock(&sysblk.wklock); #if 0 logmsg("AES wrapping key: "); for(i = 0; i < 32; i++) logmsg("%02X", sysblk.wkaes_reg[i]); logmsg("\nAES wrapping key verification pattern: "); for(i = 0; i < 32; i++) logmsg("%02X", sysblk.wkvpaes_reg[i]); logmsg("\nDEA wrapping key: "); for(i = 0; i < 24; i++) logmsg("%02X", sysblk.wkdea_reg[i]); logmsg("\nDEA wrapping key verification pattern: "); for(i = 0; i < 24; i++) logmsg("%02X", sysblk.wkvpdea_reg[i]); logmsg("\n"); #endif } #endif #endif /* FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "crypto.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "crypto.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/io.c0000664000175000017500000011314712564723224010765 00000000000000/* IO.C (c) Copyright Roger Bowler, 1994-2009 */ /* ESA/390 CPU Emulator */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements all I/O instructions of the */ /* S/370 and ESA/390 architectures, as described in the manuals */ /* GA22-7000-03 System/370 Principles of Operation */ /* SA22-7201-06 ESA/390 Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* STCPS and SCHM instructions by Jan Jaeger */ /* STCRW instruction by Jan Jaeger */ /* Instruction decode by macros - Jan Jaeger */ /* Instruction decode rework - Jan Jaeger */ /* Correct nullification of TIO and TSCH - Jan Jaeger */ /* Lock device during MSCH update - Jan Jaeger */ /* SIE support - Jan Jaeger */ /* SAL instruction added - Jan Jaeger */ /* RCHP instruction added - Jan Jaeger */ /* CONCS instruction added - Jan Jaeger */ /* DISCS instruction added - Jan Jaeger */ /* TPI fix - Jay Maynard, found by Greg Smith */ /* STCRW instruction nullification correction - Jan Jaeger */ /* I/O rate counter - Valery Pogonchenko */ /* 64-bit IDAW support - Roger Bowler v209 @IWZ*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_IO_C_) #define _IO_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #undef PTIO #if defined(FEATURE_CHANNEL_SUBSYSTEM) #define PTIO(_class, _name) \ PTT(PTT_CL_ ## _class,_name,regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L) #else #define PTIO(_class, _name) \ PTT(PTT_CL_ ## _class,_name,(U32)(effective_addr2 & 0xffffffff),0,regs->psw.IA_L) #endif #if defined(FEATURE_CHANNEL_SUBSYSTEM) /*-------------------------------------------------------------------*/ /* B230 CSCH - Clear Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(clear_subchannel) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"CSCH"); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, or is not enabled */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0) { PTIO(ERR,"*CSCH"); #if defined(_FEATURE_IO_ASSIST) SIE_INTERCEPT(regs); #endif regs->psw.cc = 3; return; } /* Perform clear subchannel and set condition code zero */ clear_subchan (regs, dev); regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* B231 HSCH - Halt Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(halt_subchannel) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"HSCH"); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, or is not enabled */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0) { PTIO(ERR,"*HSCH"); #if defined(_FEATURE_IO_ASSIST) SIE_INTERCEPT(regs); #endif regs->psw.cc = 3; return; } /* Perform halt subchannel and set condition code */ regs->psw.cc = halt_subchan (regs, dev); } /*-------------------------------------------------------------------*/ /* B232 MSCH - Modify Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(modify_subchannel) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ PMCW pmcw; /* Path management ctl word */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"MSCH"); FW_CHECK(effective_addr2, regs); /* Fetch the updated path management control word */ ARCH_DEP(vfetchc) ( &pmcw, sizeof(PMCW)-1, effective_addr2, b2, regs ); /* Program check if reserved bits are not zero */ if ((pmcw.flag4 & PMCW4_RESV) || (pmcw.flag5 & PMCW5_LM) == PMCW5_LM_RESV #if !defined(_FEATURE_IO_ASSIST) || (pmcw.flag4 & PMCW4_A) || (pmcw.zone != 0) || (pmcw.flag25 & PMCW25_VISC) || (pmcw.flag27 & PMCW27_I) #endif || (pmcw.flag26 != 0) || (pmcw.flag27 & PMCW27_RESV)) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist */ if (dev == NULL) { PTIO(ERR,"*MSCH"); regs->psw.cc = 3; return; } /* If the subchannel is invalid then return cc0 */ if (!(dev->pmcw.flag5 & PMCW5_V)) { PTIO(ERR,"*MSCH"); regs->psw.cc = 0; return; } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Obtain the device lock */ obtain_lock (&dev->lock); /* Condition code 1 if subchannel is status pending with other than intermediate status */ if ((dev->scsw.flag3 & SCSW3_SC_PEND) && !(dev->scsw.flag3 & SCSW3_SC_INTER)) { PTIO(ERR,"*MSCH"); regs->psw.cc = 1; release_lock (&dev->lock); return; } /* Condition code 2 if subchannel is busy */ if (dev->busy || IOPENDING(dev)) { PTIO(ERR,"*MSCH"); regs->psw.cc = 2; release_lock (&dev->lock); return; } /* Update the enabled (E), limit mode (LM), and measurement mode (MM), and multipath (D) bits */ dev->pmcw.flag5 &= ~(PMCW5_E | PMCW5_LM | PMCW5_MM | PMCW5_D); dev->pmcw.flag5 |= (pmcw.flag5 & (PMCW5_E | PMCW5_LM | PMCW5_MM | PMCW5_D)); /* Update the measurement block index */ memcpy (dev->pmcw.mbi, pmcw.mbi, sizeof(HWORD)); /* Update the interruption parameter */ memcpy (dev->pmcw.intparm, pmcw.intparm, sizeof(FWORD)); /* Update the ISC and A fields */ dev->pmcw.flag4 &= ~(PMCW4_ISC | PMCW4_A); dev->pmcw.flag4 |= (pmcw.flag4 & (PMCW4_ISC | PMCW4_A)); /* Update the path management (LPM and POM) fields */ dev->pmcw.lpm = pmcw.lpm; dev->pmcw.pom = pmcw.pom; /* Update zone, VISC, I and S bit */ dev->pmcw.zone = pmcw.zone; dev->pmcw.flag25 &= ~(PMCW25_VISC); dev->pmcw.flag25 |= (pmcw.flag25 & PMCW25_VISC); dev->pmcw.flag26 = pmcw.flag26; dev->pmcw.flag27 = pmcw.flag27; #if defined(_FEATURE_IO_ASSIST) /* Relate the device storage view to the requested zone */ { RADR mso, msl; mso = sysblk.zpb[dev->pmcw.zone].mso << 20; msl = (sysblk.zpb[dev->pmcw.zone].msl << 20) | 0xFFFFF; /* Ensure channel program checks on incorrect zone defs */ if(mso > (sysblk.mainsize-1) || msl > (sysblk.mainsize-1) || mso > msl) mso = msl = 0; dev->mainstor = &(sysblk.mainstor[mso]); dev->mainlim = msl - mso; dev->storkeys = &(STORAGE_KEY(mso, &sysblk)); } #endif /*defined(_FEATURE_IO_ASSIST)*/ /* Set device priority from the interruption subclass bits */ dev->priority = (dev->pmcw.flag4 & PMCW4_ISC) >> 3; release_lock (&dev->lock); /* Set condition code 0 */ regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* B23B RCHP - Reset Channel Path [S] */ /*-------------------------------------------------------------------*/ DEF_INST(reset_channel_path) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE chpid; S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"RCHP"); /* Program check if reg 1 bits 0-23 not zero */ if(regs->GR_L(1) & 0xFFFFFF00) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); chpid = regs->GR_L(1) & 0xFF; if( !(regs->psw.cc = chp_reset(regs, chpid)) ) { OBTAIN_INTLOCK(regs); sysblk.chp_reset[chpid/32] |= 0x80000000 >> (chpid % 32); ON_IC_CHANRPT; WAKEUP_CPUS_MASK (sysblk.waiting_mask); RELEASE_INTLOCK(regs); } RETURN_INTCHECK(regs); } /*-------------------------------------------------------------------*/ /* B238 RSCH - Resume Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(resume_subchannel) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"RSCH"); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, or is not enabled */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0) { PTIO(ERR,"*RSCH"); #if defined(_FEATURE_IO_ASSIST) SIE_INTERCEPT(regs); #endif regs->psw.cc = 3; return; } /* Perform resume subchannel and set condition code */ regs->psw.cc = resume_subchan (regs, dev); regs->siocount++; } /*-------------------------------------------------------------------*/ /* B237 SAL - Set Address Limit [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_address_limit) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"SAL"); if(regs->GR_L(1) & 0x8000FFFF) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); else sysblk.addrlimval = regs->GR_L(1); } /*-------------------------------------------------------------------*/ /* B23C SCHM - Set Channel Monitor [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_channel_monitor) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"SCHM"); /* Reserved bits in gpr1 must be zero */ if (regs->GR_L(1) & CHM_GPR1_RESV) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); /* Program check if M bit one and gpr2 address not on a 32 byte boundary or highorder bit set in ESA/390 mode */ if ((regs->GR_L(1) & CHM_GPR1_M) && (regs->GR_L(2) & CHM_GPR2_RESV)) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); #if defined(_FEATURE_IO_ASSIST) /* Virtual use of I/O Assist features must be intercepted */ if(SIE_MODE(regs) && ( (regs->GR_L(1) & CHM_GPR1_ZONE) || (regs->GR_L(1) & CHM_GPR1_A) )) SIE_INTERCEPT(regs); /* Zone must be a valid zone number */ if (((regs->GR_L(1) & CHM_GPR1_ZONE) >> 16) >= FEATURE_SIE_MAXZONES) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); if(regs->GR_L(1) & CHM_GPR1_A) #endif /*defined(_FEATURE_IO_ASSIST)*/ { /* Set the measurement block origin address */ if (regs->GR_L(1) & CHM_GPR1_M) { sysblk.mbo = regs->GR(2); sysblk.mbk = (regs->GR_L(1) & CHM_GPR1_MBK) >> 24; sysblk.mbm = 1; } else sysblk.mbm = 0; sysblk.mbd = regs->GR_L(1) & CHM_GPR1_D; } #if defined(_FEATURE_IO_ASSIST) else { int zone = SIE_MODE(regs) ? regs->siebk->zone : ((regs->GR_L(1) & CHM_GPR1_ZONE) >> 16); /* Set the measurement block origin address */ if (regs->GR_L(1) & CHM_GPR1_M) { sysblk.zpb[zone].mbo = regs->GR(2); sysblk.zpb[zone].mbk = (regs->GR_L(1) & CHM_GPR1_MBK) >> 24; sysblk.zpb[zone].mbm = 1; } else sysblk.zpb[zone].mbm = 0; sysblk.zpb[zone].mbd = regs->GR_L(1) & CHM_GPR1_D; } #endif /*defined(_FEATURE_IO_ASSIST)*/ } /*-------------------------------------------------------------------*/ /* B233 SSCH - Start Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(start_subchannel) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ ORB orb; /* Operation request block */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"SSCH"); FW_CHECK(effective_addr2, regs); /* Fetch the operation request block */ ARCH_DEP(vfetchc) ( &orb, sizeof(ORB)-1, effective_addr2, b2, regs ); /* Program check if reserved bits are not zero */ if (orb.flag5 & ORB5_RESV || orb.flag7 & ORB7_RESV || orb.ccwaddr[0] & 0x80) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); #if !defined(FEATURE_INCORRECT_LENGTH_INDICATION_SUPPRESSION) /* Program check if incorrect length suppression */ if (orb.flag7 & ORB7_L) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); #endif /*!defined(FEATURE_INCORRECT_LENGTH_INDICATION_SUPPRESSION)*/ #if !defined(FEATURE_MIDAW) /*@MW*/ /* Program check if modified indirect data addressing requested */ if (orb.flag7 & ORB7_D) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); #endif /*!defined(FEATURE_MIDAW)*/ /*@MW*/ /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, is not enabled, or no path available */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0 || (orb.lpm & dev->pmcw.pam) == 0) { PTIO(ERR,"*SSCH"); #if defined(_FEATURE_IO_ASSIST) SIE_INTERCEPT(regs); #endif regs->psw.cc = 3; return; } /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Clear the path not operational mask */ dev->pmcw.pnom = 0; /* Copy the logical path mask */ dev->pmcw.lpm = orb.lpm; /* Start the channel program and set the condition code */ regs->psw.cc = ARCH_DEP(startio) (regs, dev, &orb); /*@IWZ*/ regs->siocount++; /* Set the last path used mask */ if (regs->psw.cc == 0) dev->pmcw.lpum = 0x80; } /*-------------------------------------------------------------------*/ /* B23A STCPS - Store Channel Path Status [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_channel_path_status) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ BYTE work[32]; /* Work area */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"STCPS"); /* Program check if operand not on 32 byte boundary */ if ( effective_addr2 & 0x0000001F ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /*INCOMPLETE, SET TO ALL ZEROS*/ memset(work,0x00,32); /* Store channel path status word at operand address */ ARCH_DEP(vstorec) ( work, 32-1, effective_addr2, b2, regs ); } /*-------------------------------------------------------------------*/ /* B239 STCRW - Store Channel Report Word [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_channel_report_word) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ U32 n; /* Integer work area */ S(inst, regs, b2, effective_addr2); PTIO(IO,"STCRW"); PRIV_CHECK(regs); SIE_INTERCEPT(regs); FW_CHECK(effective_addr2, regs); /* Validate write access to operand before taking any pending channel report word off the queue */ ARCH_DEP(validate_operand) (effective_addr2, b2, 0, ACCTYPE_WRITE, regs); /* Obtain any pending channel report */ n = channel_report(regs); /* Store channel report word at operand address */ ARCH_DEP(vstore4) ( n, effective_addr2, b2, regs ); /* Indicate if channel report or zeros were stored */ regs->psw.cc = (n == 0) ? 1 : 0; } /*-------------------------------------------------------------------*/ /* B234 STSCH - Store Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_subchannel) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ SCHIB schib; /* Subchannel information blk*/ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"STSCH"); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Set condition code 3 if subchannel does not exist */ if (dev == NULL) { PTIO(ERR,"*STSCH"); regs->psw.cc = 3; return; } FW_CHECK(effective_addr2, regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Build the subchannel information block */ schib.pmcw = dev->pmcw; obtain_lock (&dev->lock); if (dev->pciscsw.flag3 & SCSW3_SC_PEND) schib.scsw = dev->pciscsw; else schib.scsw = dev->scsw; release_lock (&dev->lock); memset (schib.moddep, 0x00, sizeof(schib.moddep)); /* Store the subchannel information block */ ARCH_DEP(vstorec) ( &schib, sizeof(SCHIB)-1, effective_addr2, b2, regs ); /* Set condition code 0 */ regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* B236 TPI - Test Pending Interruption [S] */ /*-------------------------------------------------------------------*/ DEF_INST(test_pending_interruption) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ PSA *psa; /* -> Prefixed storage area */ U64 dreg; /* Double register work area */ U32 ioid; /* I/O interruption address */ U32 ioparm; /* I/O interruption parameter*/ U32 iointid; /* I/O interruption ident */ int icode; /* Intercept code */ RADR pfx; /* Prefix */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"TPI"); FW_CHECK(effective_addr2, regs); /* validate operand before taking any action */ if ( effective_addr2 != 0 ) ARCH_DEP(validate_operand) (effective_addr2, b2, 8-1, ACCTYPE_WRITE, regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); if( IS_IC_IOPENDING ) { /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); /* Test and clear pending interrupt, set condition code */ icode = ARCH_DEP(present_io_interrupt) (regs, &ioid, &ioparm, &iointid, NULL); /* Release the interrupt lock */ RELEASE_INTLOCK(regs); /* Store the SSID word and I/O parameter if an interrupt was pending */ if (icode) { if ( effective_addr2 == 0 #if defined(_FEATURE_IO_ASSIST) || icode != SIE_NO_INTERCEPT #endif ) { #if defined(_FEATURE_IO_ASSIST) if(icode != SIE_NO_INTERCEPT) { /* Point to SIE copy of PSA in state descriptor */ psa = (void*)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_II_PSA_OFFSET); STORAGE_KEY(SIE_STATE(regs), regs->hostregs) |= (STORKEY_REF | STORKEY_CHANGE); } else #endif { /* Point to PSA in main storage */ pfx = regs->PX; SIE_TRANSLATE(&pfx, ACCTYPE_SIE, regs); psa = (void*)(regs->mainstor + pfx); STORAGE_KEY(pfx, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* If operand address is zero, store in PSA */ STORE_FW(psa->ioid,ioid); STORE_FW(psa->ioparm,ioparm); #if defined(FEATURE_ESAME) || defined(_FEATURE_IO_ASSIST) STORE_FW(psa->iointid,iointid); #endif /*defined(FEATURE_ESAME)*/ #if defined(_FEATURE_IO_ASSIST) if(icode != SIE_NO_INTERCEPT) longjmp(regs->progjmp,SIE_INTERCEPT_IOINST); #endif } else { /* Otherwise store at operand location */ dreg = ((U64)ioid << 32) | ioparm; ARCH_DEP(vstore8) ( dreg, effective_addr2, b2, regs ); } } } else { #if defined(_FEATURE_IO_ASSIST) /* If no I/O assisted devices have pending interrupts then we must intercept */ SIE_INTERCEPT(regs); #endif icode = 0; } regs->psw.cc = (icode == 0) ? 0 : 1; } /*-------------------------------------------------------------------*/ /* B235 TSCH - Test Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(test_subchannel) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ IRB irb; /* Interruption response blk */ int cc; /* Condition Code */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"TSCH"); FW_CHECK(effective_addr2, regs); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, or is not enabled */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0) { PTIO(ERR,"*TSCH"); #if defined(_FEATURE_IO_ASSIST) SIE_INTERCEPT(regs); #endif regs->psw.cc = 3; return; } /* validate operand before taking any action */ ARCH_DEP(validate_operand) (effective_addr2, b2, sizeof(IRB)-1, ACCTYPE_WRITE_SKP, regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Test and clear pending status, set condition code */ cc = test_subchan (regs, dev, &irb); /* Store the interruption response block */ ARCH_DEP(vstorec) ( &irb, sizeof(IRB)-1, effective_addr2, b2, regs ); regs->psw.cc = cc; } #if defined(FEATURE_CANCEL_IO_FACILITY) /*-------------------------------------------------------------------*/ /* B276 XSCH - Cancel Subchannel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(cancel_subchannel) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_IO_ASSIST) if(SIE_STATNB(regs, EC0, IOA) && !regs->sie_pref) #endif SIE_INTERCEPT(regs); PTIO(IO,"XSCH"); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, or is not enabled */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0) { PTIO(ERR,"*XSCH"); #if defined(_FEATURE_IO_ASSIST) SIE_INTERCEPT(regs); #endif regs->psw.cc = 3; return; } /* Perform cancel subchannel and set condition code */ regs->psw.cc = cancel_subchan (regs, dev); } #endif /*defined(FEATURE_CANCEL_IO_FACILITY)*/ #endif /*defined(FEATURE_CHANNEL_SUBSYSTEM)*/ #if defined(FEATURE_S370_CHANNEL) /*-------------------------------------------------------------------*/ /* 9C00 SIO - Start I/O [S] */ /* 9C01 SIOF - Start I/O Fast Release [S] */ /* 9C02 RIO - Resume I/O - ZZ INCOMPLETE [S] */ /*-------------------------------------------------------------------*/ DEF_INST(start_io) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ PSA *psa; /* -> prefixed storage area */ DEVBLK *dev; /* -> device block for SIO */ ORB orb; /* Operation request blk @IZW*/ VADR ccwaddr; /* CCW address for start I/O */ BYTE ccwkey; /* Bits 0-3=key, 4=7=zeroes */ S(inst, regs, b2, effective_addr2); #if defined(FEATURE_ECPSVM) if((inst[1])!=0x02) { if(ecpsvm_dosio(regs,b2,effective_addr2)==0) { return; } } #endif PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"SIO"); /* Locate the device block */ if(regs->chanset == 0xFFFF || !(dev = find_device_by_devnum (regs->chanset,effective_addr2)) ) { PTIO(ERR,"*SIO"); regs->psw.cc = 3; return; } /* Fetch key and CCW address from the CAW at PSA+X'48' */ psa = (PSA*)(regs->mainstor + regs->PX); ccwkey = psa->caw[0] & 0xF0; ccwaddr = (psa->caw[1] << 16) | (psa->caw[2] << 8) | psa->caw[3]; /* Build the I/O operation request block */ /*@IZW*/ memset (&orb, 0, sizeof(ORB)); /*@IZW*/ orb.flag4 = ccwkey & ORB4_KEY; /*@IZW*/ STORE_FW(orb.ccwaddr,ccwaddr); /*@IZW*/ /* Start the channel program and set the condition code */ regs->psw.cc = ARCH_DEP(startio) (regs, dev, &orb); /*@IZW*/ regs->siocount++; } /*-------------------------------------------------------------------*/ /* 9D00 TIO - Test I/O [S] */ /* 9D01 CLRIO - Clear I/O [S] */ /*-------------------------------------------------------------------*/ DEF_INST(test_io) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block for SIO */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"TIO"); /* Locate the device block */ if(regs->chanset == 0xFFFF || !(dev = find_device_by_devnum (regs->chanset,effective_addr2)) ) { PTIO(ERR,"*TIO"); regs->psw.cc = 3; return; } /* Test the device and set the condition code */ regs->psw.cc = testio (regs, dev, inst[1]); /* Yield time slice so that device handler may get some time */ /* to possibly complete an I/O - to prevent a TIO Busy Loop */ if(regs->psw.cc == 2) { sched_yield(); } } /*-------------------------------------------------------------------*/ /* 9E00 HIO - Halt I/O [S] */ /* 9E01 HDV - Halt Device [S] */ /*-------------------------------------------------------------------*/ DEF_INST(halt_io) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ DEVBLK *dev; /* -> device block for SIO */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"HIO"); /* Locate the device block */ if(regs->chanset == 0xFFFF || !(dev = find_device_by_devnum (regs->chanset,effective_addr2)) ) { PTIO(ERR,"*HIO"); regs->psw.cc = 3; return; } /* Test the device and set the condition code */ regs->psw.cc = haltio (regs, dev, inst[1]); } /*-------------------------------------------------------------------*/ /* 9F00 TCH - Test Channel [S] */ /*-------------------------------------------------------------------*/ DEF_INST(test_channel) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ #if defined(_FEATURE_SIE) BYTE channelid; U16 tch_ctl; #endif /*defined(_FEATURE_SIE)*/ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); PTIO(IO,"TCH"); #if defined(_FEATURE_SIE) if(!SIE_MODE(regs)) { #endif /*defined(_FEATURE_SIE)*/ /* Test for pending interrupt and set condition code */ regs->psw.cc = testch (regs, effective_addr2 & 0xFF00); #if defined(_FEATURE_SIE) } else { channelid = (effective_addr2 >> 8) & 0xFF; FETCH_HW(tch_ctl,((SIEBK*)(regs->siebk))->tch_ctl); if((channelid > 15) || ((0x8000 >> channelid) & tch_ctl)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else regs->psw.cc = 0; } #endif /*defined(_FEATURE_SIE)*/ } /*-------------------------------------------------------------------*/ /* B203 STIDC - Store Channel ID [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_channel_id) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"STIDC"); /* Store Channel ID and set condition code */ regs->psw.cc = stchan_id (regs, effective_addr2 & 0xFF00); } #if defined(FEATURE_CHANNEL_SWITCHING) /*-------------------------------------------------------------------*/ /* B200 CONCS - Connect Channel Set [S] */ /*-------------------------------------------------------------------*/ DEF_INST(connect_channel_set) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i; S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"CONCS"); effective_addr2 &= 0xFFFF; /* Hercules has as many channelsets as CSS's */ if(effective_addr2 >= FEATURE_LCSS_MAX) { PTIO(ERR,"*CONCS"); regs->psw.cc = 3; return; } /* If the addressed channel set is currently connected then return with cc0 */ if(regs->chanset == effective_addr2) { regs->psw.cc = 0; return; } /* Disconnect channel set */ regs->chanset = 0xFFFF; OBTAIN_INTLOCK(regs); /* If the addressed channelset is connected to another CPU then return with cc1 */ for (i = 0; i < MAX_CPU; i++) { if (IS_CPU_ONLINE(i) && sysblk.regs[i]->chanset == effective_addr2) { RELEASE_INTLOCK(regs); regs->psw.cc = 1; return; } } /* Set channel set connected to current CPU */ regs->chanset = effective_addr2; /* Interrupts may be pending on this channelset */ ON_IC_IOPENDING; RELEASE_INTLOCK(regs); regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* B201 DISCS - Disconnect Channel Set [S] */ /*-------------------------------------------------------------------*/ DEF_INST(disconnect_channel_set) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i; S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"DISCS"); /* Hercules has as many channelsets as CSS's */ if(effective_addr2 >= FEATURE_LCSS_MAX) { PTIO(ERR,"*DISCS"); regs->psw.cc = 3; return; } /* If the addressed channel set is currently connected then disconect channel set and return with cc0 */ if(regs->chanset == effective_addr2 && regs->chanset != 0xFFFF) { regs->chanset = 0xFFFF; regs->psw.cc = 0; return; } OBTAIN_INTLOCK(regs); /* If the addressed channelset is connected to another CPU then return with cc0 */ for(i = 0; i < MAX_CPU; i++) { if (IS_CPU_ONLINE(i) && sysblk.regs[i]->chanset == effective_addr2) { if(sysblk.regs[i]->cpustate != CPUSTATE_STARTED) { sysblk.regs[i]->chanset = 0xFFFF; regs->psw.cc = 0; } else regs->psw.cc = 1; RELEASE_INTLOCK(regs); return; } } RELEASE_INTLOCK(regs); /* The channel set is not connected, no operation is performed */ regs->psw.cc = 0; } #endif /*defined(FEATURE_CHANNEL_SWITCHING)*/ #endif /*defined(FEATURE_S370_CHANNEL)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "io.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "io.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/decimal.c0000664000175000017500000015331112564723224011751 00000000000000/* DECIMAL.C (c) Copyright Roger Bowler, 1991-2009 */ /* ESA/390 Packed Decimal Routines */ /*-------------------------------------------------------------------*/ /* This module contains packed decimal subroutines for ESA/390. */ /* */ /* Acknowledgements: */ /* The lowest level string-math functions are modelled on */ /* algorithms in D.E.Knuth's 'The Art of Computer Programming */ /* Vol.2', and on C.E.Burton's algorithms in DDJ #89. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Complete rework for reworked instruction decode/execution code */ /* Jan Jaeger 01/07/00 */ /* Add trialrun to ED and EDMK Jan Jaeger 19/07/00 */ /* Fix random MP bug - Mario Bezzi */ /* Clear DXC on data exception - Peter Kuschnerus V209*/ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /* TP instruction - Roger Bowler 08/02/01 */ /* packed_to_binary subroutine - Roger Bowler 29/06/03 */ /* binary_to_packed subroutine - Roger Bowler 02jul2003 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_DECIMAL_C_) #define _DECIMAL_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if !defined(_DECIMAL_C) #define _DECIMAL_C /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ #define MAX_DECIMAL_LENGTH 16 #define MAX_DECIMAL_DIGITS (((MAX_DECIMAL_LENGTH)*2)-1) /*-------------------------------------------------------------------*/ /* Convert packed decimal number to binary */ /* */ /* This subroutine is called by the CVB/CVBY/CVBG instructions. */ /* It performs the conversion of a 8-byte or 16-byte packed */ /* decimal number into a 64-bit SIGNED binary result. */ /* This routine is not architecture-dependent; all of its operands */ /* are contained in work areas passed by the architecture-dependent */ /* instruction routines which handle all main-storage accesses and */ /* possible program checks. */ /* */ /* Input: */ /* dec An 8 or 16 byte area containing a copy of the */ /* packed decimal storage operand. */ /* len Length-1 (in bytes) of the packed decimal input */ /* (7 for CVB/CVBY or 15 for CVBG). */ /* Output: */ /* result Points to an U64 field which will receive the */ /* result as a 64-bit SIGNED binary number. */ /* ovf Points to an int field which will be set to 1 if */ /* the result overflows 63 bits plus sign, else 0. */ /* If overflow occurs, the result field will contain */ /* the rightmost 64 bits of the result. */ /* dxf Points to an int field which will be set to 1 if */ /* invalid digits or sign were detected, else 0. */ /* The result field is not set if the dxf is set to 1. */ /*-------------------------------------------------------------------*/ void packed_to_binary (BYTE *dec, int len, U64 *result, int *ovf, int *dxf) { U64 dreg; /* 64-bit result accumulator */ int i; /* Loop counter */ int h, d=0; /* Decimal digits */ U64 inter_u64max_div10; int inter_u64max_rem10; U64 pos_u64max = 9223372036854775807ULL; // (LLONG_MAX) U64 neg_u64max = 9223372036854775808ULL; // (LLONG_MIN) /* Initialize result flags */ *ovf = 0; *dxf = 0; /* Initialize 64-bit result accumulator */ dreg = 0; /* Initialize max unsigned intermediate value for overflow check */ if ((dec[len] & 0x0F) == 0x0B || (dec[len] & 0x0F) == 0x0D) { inter_u64max_div10 = (neg_u64max / 10); inter_u64max_rem10 = (int) (neg_u64max % 10); } else if ((dec[len] & 0x0F) < 0x0A) { *dxf = 1; return; } else { inter_u64max_div10 = (pos_u64max / 10); inter_u64max_rem10 = (int) (pos_u64max % 10); } /* Convert decimal digits to binary */ for (i = 0; i <= len; i++) { /* Isolate high-order and low-order digits */ h = (dec[i] & 0xF0) >> 4; d = dec[i] & 0x0F; /* Data exception if high-order digit is invalid */ if (h > 9) { *dxf = 1; return; } /* Check for overflow before accumulating */ if ( dreg > inter_u64max_div10 || (dreg == inter_u64max_div10 && h > inter_u64max_rem10)) // (NOTE: 'h', not 'd') { *ovf = 1; } /* Accumulate high-order digit into result */ dreg *= 10; dreg += h; /* Check for valid low-order digit or sign */ if (i < len) { /* Data exception if low-order digit is invalid */ if (d > 9) { *dxf = 1; return; } /* Check for overflow before accumulating */ if ( dreg > inter_u64max_div10 || (dreg == inter_u64max_div10 && d > inter_u64max_rem10)) // (NOTE: 'd', not 'h') { *ovf = 1; } /* Accumulate low-order digit into result */ dreg *= 10; dreg += d; } else { /* Data exception if sign is invalid */ if (d < 10) { *dxf = 1; return; } } } /* end for(i) */ /* Result is negative if sign is X'B' or X'D' */ if (d == 0x0B || d == 0x0D) { /* Check for UNDERflow (less than min negative) */ if ( dreg > neg_u64max ) *ovf = 1; else dreg = -((S64)dreg); } else { /* Check for OVERflow (greater than max positive) */ if ( dreg > pos_u64max ) *ovf = 1; } /* Set result field and return */ *result = dreg; } /* end function packed_to_binary */ /*-------------------------------------------------------------------*/ /* Convert binary number to packed decimal */ /* */ /* This subroutine is called by the CVD/CVDY/CVDG instructions. */ /* It performs the conversion of a 64-bit signed binary number */ /* to a 16-byte packed decimal result. Since the maximum 63 bit */ /* number is less than 31 decimal digits, overflow cannot occur. */ /* Similarly, the maximum 31 bit number is less than 15 decimal */ /* digits, therefore CVD/CVDY can safely use the rightmost eight */ /* bytes of the packed decimal result without risk of overflow. */ /* */ /* This routine is not architecture-dependent; all of its operands */ /* are contained in work areas passed by the architecture-dependent */ /* instruction routines which handle all main-storage accesses and */ /* possible program checks. */ /* */ /* Input: */ /* bin Binary number (63 bits plus sign) */ /* Output: */ /* result Points to a 16-byte field which will receive the */ /* result as a packed decimal number (31 digits + sign) */ /*-------------------------------------------------------------------*/ void binary_to_packed (S64 bin, BYTE *result) { int i; /* Array subscript */ int d; /* Decimal digit or sign */ /* Special case when input is maximum negative value */ if ((U64)bin == 0x8000000000000000ULL) { memcpy (result, "\x00\x00\x00\x00\x00\x00\x92\x23" "\x37\x20\x36\x85\x47\x75\x80\x8D", 16); } else { /* Load absolute value and generate sign */ if ((U64)bin < 0x8000000000000000ULL) { /* Value is positive */ d = 0x0C; } else { /* Value is negative */ bin = -bin; d = 0x0D; } /* Store sign and decimal digits from right to left */ memset (result, 0, 16); for (i = 16 - 1; d != 0 || bin != 0; i--) { result[i] = d; d = bin % 10; bin /= 10; result[i] |= (d << 4); d = bin % 10; bin /= 10; } } } /* end function(binary_to_packed) */ /*-------------------------------------------------------------------*/ /* Add two decimal byte strings as unsigned decimal numbers */ /* */ /* Input: */ /* dec1 A 31-byte area containing the decimal digits of */ /* the first operand. Each byte contains one decimal */ /* digit in the low-order 4 bits of the byte. */ /* dec2 A 31-byte area containing the decimal digits of */ /* the second operand. Each byte contains one decimal */ /* digit in the low-order 4 bits of the byte. */ /* Output: */ /* result Points to a 31-byte area to contain the result */ /* digits. One decimal digit is placed in the low-order */ /* 4 bits of each byte. */ /* count Points to an integer to receive the number of */ /* digits in the result excluding leading zeroes. */ /* This field is set to zero if the result is all zero, */ /* or to MAX_DECIMAL_DIGITS+1 if overflow occurred. */ /*-------------------------------------------------------------------*/ static void add_decimal (BYTE *dec1, BYTE *dec2, BYTE *result, int *count) { int d; /* Decimal digit */ int i; /* Array subscript */ int n = 0; /* Significant digit counter */ int carry = 0; /* Carry indicator */ /* Add digits from right to left */ for (i = MAX_DECIMAL_DIGITS - 1; i >= 0; i--) { /* Add digits from first and second operands */ d = dec1[i] + dec2[i] + carry; /* Check for carry into next digit */ if (d > 9) { d -= 10; carry = 1; } else { carry = 0; } /* Check for significant digit */ if (d != 0) n = MAX_DECIMAL_DIGITS - i; /* Store digit in result */ result[i] = d; } /* end for */ /* Check for carry out of leftmost digit */ if (carry) n = MAX_DECIMAL_DIGITS + 1; /* Return significant digit counter */ *count = n; } /* end function add_decimal */ /*-------------------------------------------------------------------*/ /* Subtract two decimal byte strings as unsigned decimal numbers */ /* */ /* Input: */ /* dec1 A 31-byte area containing the decimal digits of */ /* the first operand. Each byte contains one decimal */ /* digit in the low-order 4 bits of the byte. */ /* dec2 A 31-byte area containing the decimal digits of */ /* the second operand. Each byte contains one decimal */ /* digit in the low-order 4 bits of the byte. */ /* Output: */ /* result Points to a 31-byte area to contain the result */ /* digits. One decimal digit is placed in the low-order */ /* 4 bits of each byte. */ /* count Points to an integer to receive the number of */ /* digits in the result excluding leading zeroes. */ /* This field is set to zero if the result is all zero. */ /* sign -1 if the result is negative (operand2 > operand1) */ /* +1 if the result is positive (operand2 <= operand1) */ /*-------------------------------------------------------------------*/ static void subtract_decimal (BYTE *dec1, BYTE *dec2, BYTE *result, int *count, int *sign) { int d; /* Decimal digit */ int i; /* Array subscript */ int n = 0; /* Significant digit counter */ int borrow = 0; /* Borrow indicator */ int rc; /* Return code */ BYTE *higher; /* -> Higher value operand */ BYTE *lower; /* -> Lower value operand */ /* Compare digits to find which operand has higher numeric value */ rc = memcmp (dec1, dec2, MAX_DECIMAL_DIGITS); /* Return positive zero result if both operands are equal */ if (rc == 0) { memset (result, 0, MAX_DECIMAL_DIGITS); *count = 0; *sign = +1; return; } /* Point to higher and lower value operands and set sign */ if (rc > 0) { higher = dec1; lower = dec2; *sign = +1; } else { lower = dec1; higher = dec2; *sign = -1; } /* Subtract digits from right to left */ for (i = MAX_DECIMAL_DIGITS - 1; i >= 0; i--) { /* Subtract lower operand digit from higher operand digit */ d = higher[i] - lower[i] - borrow; /* Check for borrow from next digit */ if (d < 0) { d += 10; borrow = 1; } else { borrow = 0; } /* Check for significant digit */ if (d != 0) n = MAX_DECIMAL_DIGITS - i; /* Store digit in result */ result[i] = d; } /* end for */ /* Return significant digit counter */ *count = n; } /* end function subtract_decimal */ /*-------------------------------------------------------------------*/ /* Divide two decimal byte strings as unsigned decimal numbers */ /* */ /* Input: */ /* dec1 A 31-byte area containing the decimal digits of */ /* the dividend. Each byte contains one decimal */ /* digit in the low-order 4 bits of the byte. */ /* count1 The number of significant digits in the dividend. */ /* dec2 A 31-byte area containing the decimal digits of */ /* the divisor. Each byte contains one decimal */ /* digit in the low-order 4 bits of the byte. */ /* count2 The number of significant digits in the divisor. */ /* Output: */ /* quot Points to a 31-byte area to contain the quotient */ /* digits. One decimal digit is placed in the low-order */ /* 4 bits of each byte. */ /* rem Points to a 31-byte area to contain the remainder */ /* digits. One decimal digit is placed in the low-order */ /* 4 bits of each byte. */ /* Restrictions: */ /* It is assumed that the caller has already verified that */ /* divide overflow cannot occur, that the divisor is not zero, */ /* and that the dividend has at least one high order zero. */ /*-------------------------------------------------------------------*/ static void divide_decimal (BYTE *dec1, int count1, BYTE *dec2, int count2, BYTE *quot, BYTE *rem) { BYTE *num1; /* -> dividend digits */ BYTE *num2; /* -> divisor digits */ int div, flag, scale; /* Work areas for algorithm */ int index, index1, index2; /* Work areas for algorithm */ int indexq, indexr, temp1, temp2; /* Work areas for algorithm */ int temp3, temp4, temp5, qtest; /* Work areas for algorithm */ /* Clear the result fields */ memset (quot, 0, MAX_DECIMAL_DIGITS); memset (rem, 0, MAX_DECIMAL_DIGITS); /* If dividend is zero then return zero quotient and remainder */ if (count1 == 0) return; /* If dividend is less than divisor then return zero quotient and set remainder equal to dividend */ if (memcmp (dec1, dec2, MAX_DECIMAL_DIGITS) < 0) { memcpy (rem, dec1, MAX_DECIMAL_DIGITS); return; } /* Adjust dividend digit count to give one leading zero */ count1++; /* Point to significant digits of dividend with leading zero */ num1 = dec1 + MAX_DECIMAL_DIGITS - count1; /* Point to significant digits of divisor */ num2 = dec2 + MAX_DECIMAL_DIGITS - count2; scale = 10 / (num2[0] + 1); if (scale > 1) { for (index1 = count1-1, flag = 0; index1 >= 0; index1--) { div = flag + scale*num1[index1]; num1[index1] = div % 10; flag = div / 10; } /* end for(index1) */ for (index2 = count2-1, flag = 0; index2 >= 0; index2--) { div = flag + scale*num2[index2]; num2[index2] = div % 10; flag = div / 10; } /* end for(index2) */ } /* end if(scale>1) */ for (index1 = 0; index1 < count1-count2; index1++) { if (num2[0] == num1[index1]) qtest = 9; else { temp2 = (index1+1 < count1) ? num1[index1+1] : 0; qtest = (10*num1[index1] + temp2) / num2[0]; } temp2 = num1[index1]; temp4 = num2[0]; temp1 = (count2 >= 2) ? num2[1] : 0; if (index1+1 < count1) { temp3 = num1[index1+1]; temp5 = (index1+2 < count1) ? num1[index1+2] : 0; } else { temp3 = 0; temp5 = 0; } while (qtest*temp1 > (10*(10*temp2 + temp3 - qtest*temp4) + temp5)) --qtest; for (index = index1+count2, index2 = count2-1, flag = 0; index >= index1; index--, index2--) { if (index2 >= 0) flag -= qtest*num2[index2]; div = flag + num1[index]; if (div < 0) { flag = div / 10; div %= 10; if (div < 0) { div += 10; --flag; } } else flag = 0; num1[index] = div; } /* end for(index) */ indexq = MAX_DECIMAL_DIGITS - (count1-count2) + index1; if (flag != 0) { quot[indexq] = qtest - 1; for (index = index1+count2, index2 = count2-1, flag = 0; index >= index1; index--, index2--) { if (index2 >= 0) flag += num2[index2]; div = flag + num1[index]; if (div > 9) { div -= 10; flag = 1; } else flag = 0; num1[index] = div; } /* end for(index) */ } else quot[indexq] = qtest; } /* end for(index1) */ for (index1 = count1-count2, indexr = MAX_DECIMAL_DIGITS-count2, flag = 0; index1 < count1; index1++, indexr++) { div = num1[index1] + 10*flag; rem[indexr] = div / scale; flag = div % scale; } /* end for(index1) */ for (index2 = 0, flag = 0; index2 < count2; index2++) { div = num2[index2] + 10*flag; num2[index2] = div / scale; flag = div % scale; } /* end for(index2) */ } /* end function divide_decimal */ #endif /*!defined(_DECIMAL_C)*/ /*-------------------------------------------------------------------*/ /* Load a packed decimal storage operand into a decimal byte string */ /* */ /* Input: */ /* addr Logical address of packed decimal storage operand */ /* len Length minus one of storage operand (range 0-15) */ /* arn Access register number associated with operand */ /* regs CPU register context */ /* Output: */ /* result Points to a 31-byte area into which the decimal */ /* digits are loaded. One decimal digit is loaded */ /* into the low-order 4 bits of each byte, and the */ /* result is padded to the left with high-order zeroes */ /* if the storage operand contains less than 31 digits. */ /* count Points to an integer to receive the number of */ /* digits in the result excluding leading zeroes. */ /* This field is set to zero if the result is all zero. */ /* sign Points to an integer which will be set to -1 if a */ /* negative sign was loaded from the operand, or +1 if */ /* a positive sign was loaded from the operand. */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, or if the operand causes a data exception */ /* because of invalid decimal digits or sign. */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(load_decimal) (VADR addr, int len, int arn, REGS *regs, BYTE *result, int *count, int *sign) { int h; /* Hexadecimal digit */ int i, j; /* Array subscripts */ int n; /* Significant digit counter */ BYTE pack[MAX_DECIMAL_LENGTH]; /* Packed decimal work area */ /* Fetch the packed decimal operand into work area */ memset (pack, 0, sizeof(pack)); ARCH_DEP(vfetchc) (pack+sizeof(pack)-len-1, len, addr, arn, regs); /* Unpack digits into result */ for (i=0, j=0, n=0; i < MAX_DECIMAL_DIGITS; i++) { /* Load source digit */ if (i & 1) h = pack[j++] & 0x0F; else h = pack[j] >> 4; /* Check for valid numeric */ if (h > 9) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); return; } /* Count significant digits */ if (n > 0 || h != 0) n++; /* Store decimal digit in result */ result[i] = h; } /* end for */ /* Check for valid sign */ h = pack[MAX_DECIMAL_LENGTH-1] & 0x0F; if (h < 0x0A) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); return; } /* Set number of significant digits */ *count = n; /* Set sign of operand */ *sign = (h == 0x0B || h == 0x0D) ? -1 : 1; } /* end function ARCH_DEP(load_decimal) */ /*-------------------------------------------------------------------*/ /* Store decimal byte string into packed decimal storage operand */ /* */ /* Input: */ /* addr Logical address of packed decimal storage operand */ /* len Length minus one of storage operand (range 0-15) */ /* arn Access register number associated with operand */ /* regs CPU register context */ /* dec A 31-byte area containing the decimal digits to be */ /* stored. Each byte contains one decimal digit in */ /* the low-order 4 bits of the byte. */ /* sign -1 if a negative sign is to be stored, or +1 if a */ /* positive sign is to be stored. */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or protection exception. */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(store_decimal) (VADR addr, int len, int arn, REGS *regs, BYTE *dec, int sign) { int i, j; /* Array subscripts */ BYTE pack[MAX_DECIMAL_LENGTH]; /* Packed decimal work area */ /* if operand crosses page, make sure both pages are accessable */ if((addr & PAGEFRAME_PAGEMASK) != ((addr + len) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (addr, arn, len, ACCTYPE_WRITE_SKP, regs); /* Pack digits into packed decimal work area */ for (i=0, j=0; i < MAX_DECIMAL_DIGITS; i++) { if (i & 1) pack[j++] |= dec[i]; else pack[j] = dec[i] << 4; } /* end for */ /* Pack the sign into low-order digit of work area */ pack[MAX_DECIMAL_LENGTH-1] |= (sign < 0 ? 0x0D : 0x0C); /* Store the result at the operand location */ ARCH_DEP(vstorec) (pack+sizeof(pack)-len-1, len, addr, arn, regs); } /* end function ARCH_DEP(store_decimal) */ /*-------------------------------------------------------------------*/ /* FA AP - Add Decimal [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(add_decimal) { int l1, l2; /* Length values */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ BYTE dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */ BYTE dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */ BYTE dec3[MAX_DECIMAL_DIGITS]; /* Work area for result */ int count1, count2, count3; /* Significant digit counters*/ int sign1, sign2, sign3; /* Sign of operands & result */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* Load operands into work areas */ ARCH_DEP(load_decimal) (effective_addr1, l1, b1, regs, dec1, &count1, &sign1); ARCH_DEP(load_decimal) (effective_addr2, l2, b2, regs, dec2, &count2, &sign2); /* Add or subtract operand values */ if (count2 == 0) { /* If second operand is zero then result is first operand */ memcpy (dec3, dec1, MAX_DECIMAL_DIGITS); count3 = count1; sign3 = sign1; } else if (count1 == 0) { /* If first operand is zero then result is second operand */ memcpy (dec3, dec2, MAX_DECIMAL_DIGITS); count3 = count2; sign3 = sign2; } else if (sign1 == sign2) { /* If signs are equal then add operands */ add_decimal (dec1, dec2, dec3, &count3); sign3 = sign1; } else { /* If signs are opposite then subtract operands */ subtract_decimal (dec1, dec2, dec3, &count3, &sign3); if (sign1 < 0) sign3 = -sign3; } /* Set condition code */ cc = (count3 == 0) ? 0 : (sign3 < 1) ? 1 : 2; /* Overflow if result exceeds first operand length */ if (count3 > (l1+1) * 2 - 1) cc = 3; /* Set positive sign if result is zero */ if (count3 == 0) sign3 = 1; /* Store result into first operand location */ ARCH_DEP(store_decimal) (effective_addr1, l1, b1, regs, dec3, sign3); /* Set condition code */ regs->psw.cc = cc; /* Program check if overflow and PSW program mask is set */ if (cc == 3 && DOMASK(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_decimal) */ /*-------------------------------------------------------------------*/ /* F9 CP - Compare Decimal [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_decimal) { int l1, l2; /* Length values */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ BYTE dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */ BYTE dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */ int count1, count2; /* Significant digit counters*/ int sign1, sign2; /* Sign of each operand */ int rc; /* Return code */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* Load operands into work areas */ ARCH_DEP(load_decimal) (effective_addr1, l1, b1, regs, dec1, &count1, &sign1); ARCH_DEP(load_decimal) (effective_addr2, l2, b2, regs, dec2, &count2, &sign2); /* Result is equal if both operands are zero */ if (count1 == 0 && count2 == 0) { regs->psw.cc = 0; return; } /* Result is low if operand 1 is -ve and operand 2 is +ve */ if (sign1 < 0 && sign2 > 0) { regs->psw.cc = 1; return; } /* Result is high if operand 1 is +ve and operand 2 is -ve */ if (sign1 > 0 && sign2 < 0) { regs->psw.cc = 2; return; } /* If signs are equal then compare the digits */ rc = memcmp (dec1, dec2, MAX_DECIMAL_DIGITS); /* Return low or high (depending on sign) if digits are unequal */ if (rc < 0) regs->psw.cc = (sign1 > 0) ? 1 : 2; else if (rc > 0) regs->psw.cc = (sign1 > 0) ? 2 : 1; else regs->psw.cc = 0; } /* end DEF_INST(compare_decimal) */ /*-------------------------------------------------------------------*/ /* FD DP - Divide Decimal [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_decimal) { int l1, l2; /* Length values */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ BYTE dec1[MAX_DECIMAL_DIGITS]; /* Operand 1 (dividend) */ BYTE dec2[MAX_DECIMAL_DIGITS]; /* Operand 2 (divisor) */ BYTE quot[MAX_DECIMAL_DIGITS]; /* Quotient */ BYTE rem[MAX_DECIMAL_DIGITS]; /* Remainder */ int count1, count2; /* Significant digit counters*/ int sign1, sign2; /* Sign of operands */ int signq, signr; /* Sign of quotient/remainder*/ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* Program check if the second operand length exceeds 15 digits or is equal to or greater than the first operand length */ if (l2 > 7 || l2 >= l1) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Load operands into work areas */ ARCH_DEP(load_decimal) (effective_addr1, l1, b1, regs, dec1, &count1, &sign1); ARCH_DEP(load_decimal) (effective_addr2, l2, b2, regs, dec2, &count2, &sign2); /* Program check if second operand value is zero */ if (count2 == 0) ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_DIVIDE_EXCEPTION); /* Perform trial comparison to determine potential overflow. The leftmost digit of the divisor is aligned one digit to the right of the leftmost dividend digit. When the divisor, so aligned, is less than or equal to the dividend, ignoring signs, a divide exception is indicated. As a result of this comparison, it is also certain that the leftmost digit of the dividend must be zero, and that the divisor cannot be zero */ if (memcmp(dec2 + (MAX_DECIMAL_DIGITS - l2*2 - 2), dec1 + (MAX_DECIMAL_DIGITS - l1*2 - 1), l2*2 + 2) <= 0) ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_DIVIDE_EXCEPTION); /* Perform decimal division */ divide_decimal (dec1, count1, dec2, count2, quot, rem); /* Quotient is positive if operand signs are equal, and negative if operand signs are opposite, even if quotient is zero */ signq = (sign1 == sign2) ? 1 : -1; /* Remainder sign is same as dividend, even if remainder is zero */ signr = sign1; /* Store remainder into entire first operand location. The entire field will be filled in order to check for store protection. Subsequently the quotient will be stored in the leftmost bytes of the first operand location, overwriting high order zeroes */ ARCH_DEP(store_decimal) (effective_addr1, l1, b1, regs, rem, signr); /* Store quotient in leftmost bytes of first operand location */ ARCH_DEP(store_decimal) (effective_addr1, l1-l2-1, b1, regs, quot, signq); } /* end DEF_INST(divide_decimal) */ /*-------------------------------------------------------------------*/ /* DE ED - Edit [SS] */ /* DF EDMK - Edit and Mark [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(edit_x_edit_and_mark) { int l; /* Length value */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2, /* Effective addresses */ addr1, addr2; int cc = 0; /* Condition code */ int sig = 0; /* Significance indicator */ int trial_run; /* 1=trial run */ int i; /* Loop counter */ int d; /* 1=Use right source digit */ int h; /* Hexadecimal digit */ BYTE sbyte; /* Source operand byte */ BYTE fbyte; /* Fill byte */ BYTE pbyte; /* Pattern byte */ BYTE rbyte; /* Result byte */ SS_L(inst, regs, l, b1, effective_addr1, b2, effective_addr2); /* If addr1 crosses page, make sure both pages are accessable */ if((effective_addr1 & PAGEFRAME_PAGEMASK) != ((effective_addr1 + l) & PAGEFRAME_PAGEMASK)) ARCH_DEP(validate_operand) (effective_addr1, b1, l, ACCTYPE_WRITE_SKP, regs); /* If addr2 might cross page, do a trial run to catch possible access rupts */ if((effective_addr2 & PAGEFRAME_PAGEMASK) != ((effective_addr2 + l) & PAGEFRAME_PAGEMASK)) trial_run = 1; else trial_run = 0; for(;trial_run >= 0; trial_run--) { /* Initialize variables */ addr1 = effective_addr1; addr2 = effective_addr2; cc = 0; sig = 0; sbyte = 0; fbyte = 0; /* Process first operand from left to right */ for (i = 0, d = 0; i < l+1; i++) { /* Fetch pattern byte from first operand */ pbyte = ARCH_DEP(vfetchb) ( addr1, b1, regs ); /* The first pattern byte is also the fill byte */ if (i == 0) fbyte = pbyte; /* If pattern byte is digit selector (X'20') or significance starter (X'21') then fetch next hexadecimal digit from the second operand */ if (pbyte == 0x20 || pbyte == 0x21) { if (d == 0) { /* Fetch source byte and extract left digit */ sbyte = ARCH_DEP(vfetchb) ( addr2, b2, regs ); h = sbyte >> 4; sbyte &= 0x0F; d = 1; /* Increment second operand address */ addr2++; addr2 &= ADDRESS_MAXWRAP(regs); /* Program check if left digit is not numeric */ if (h > 9) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } else { /* Use right digit of source byte */ h = sbyte; d = 0; } /* For the EDMK instruction only, insert address of result byte into general register 1 if the digit is non-zero and significance indicator was off */ if (!trial_run && (inst[0] == 0xDF) && h > 0 && sig == 0) { #if defined(FEATURE_ESAME) if (regs->psw.amode64) regs->GR_G(1) = addr1; else #endif if ( regs->psw.amode ) regs->GR_L(1) = addr1; else regs->GR_LA24(1) = addr1; } /* Replace the pattern byte by the fill character or by a zoned decimal digit */ rbyte = (sig == 0 && h == 0) ? fbyte : (0xF0 | h); if(!trial_run) ARCH_DEP(vstoreb) ( rbyte, addr1, b1, regs ); else ARCH_DEP(validate_operand) (addr1, b1, 0, ACCTYPE_WRITE_SKP, regs); /* Set condition code 2 if digit is non-zero */ if (h > 0) cc = 2; /* Turn on significance indicator if pattern byte is significance starter or if source digit is non-zero */ if (pbyte == 0x21 || h > 0) sig = 1; /* Examine right digit for sign code */ if (d == 1 && sbyte > 9) { /* Turn off the significance indicator if the right digit is a plus sign code */ if (sbyte != 0x0B && sbyte != 0x0D) sig = 0; /* Take next digit from next source byte */ d = 0; } } /* If pattern byte is field separator (X'22') then replace it by the fill character, turn off the significance indicator, and zeroize conditon code */ else if (pbyte == 0x22) { if(!trial_run) ARCH_DEP(vstoreb) ( fbyte, addr1, b1, regs ); else ARCH_DEP(validate_operand) (addr1, b1, 0, ACCTYPE_WRITE_SKP, regs); sig = 0; cc = 0; } /* If pattern byte is a message byte (anything other than X'20', X'21', or X'22') then replace it by the fill byte if the significance indicator is off */ else { if (sig == 0) { if (!trial_run) ARCH_DEP(vstoreb) ( fbyte, addr1, b1, regs ); else ARCH_DEP(validate_operand) (addr1, b1, 0, ACCTYPE_WRITE_SKP, regs); } else /* store message byte */ { if (!trial_run) ARCH_DEP(vstoreb) ( pbyte, addr1, b1, regs ); else ARCH_DEP(validate_operand) (addr1, b1, 0, ACCTYPE_WRITE_SKP, regs); } } /* Increment first operand address */ addr1++; addr1 &= ADDRESS_MAXWRAP(regs); } /* end for(i) */ } /* end for(trial_run) */ /* Replace condition code 2 by condition code 1 if the significance indicator is on at the end of editing */ if (sig && cc == 2) cc = 1; /* Set condition code */ regs->psw.cc = cc; } /* end DEF_INST(edit_x_edit_and_mark) */ /*-------------------------------------------------------------------*/ /* FC MP - Multiply Decimal [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_decimal) { int l1, l2; /* Length values */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ BYTE dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */ BYTE dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */ BYTE dec3[MAX_DECIMAL_DIGITS]; /* Work area for result */ int count1, count2; /* Significant digit counters*/ int sign1, sign2, sign3; /* Sign of operands & result */ int d; /* Decimal digit */ int i1, i2, i3; /* Array subscripts */ int carry; /* Carry indicator */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* Program check if the second operand length exceeds 15 digits or is equal to or greater than the first operand length */ if (l2 > 7 || l2 >= l1) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Load operands into work areas */ ARCH_DEP(load_decimal) (effective_addr1, l1, b1, regs, dec1, &count1, &sign1); ARCH_DEP(load_decimal) (effective_addr2, l2, b2, regs, dec2, &count2, &sign2); /* Program check if the number of bytes in the second operand is less than the number of bytes of high-order zeroes in the first operand; this ensures that overflow cannot occur */ if (l2 > l1 - (count1/2 + 1)) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Clear the result field */ memset (dec3, 0, MAX_DECIMAL_DIGITS); /* Perform decimal multiplication */ for (i2 = MAX_DECIMAL_DIGITS-1; i2 >= 0; i2--) { if (dec2[i2] != 0) { for (i1 = MAX_DECIMAL_DIGITS - 1, i3 = i2, carry = 0; i3 >= 0; i1--, i3--) { d = carry + dec1[i1]*dec2[i2] + dec3[i3]; dec3[i3] = d % 10; carry = d / 10; } } } /* end for(i2) */ /* Result is positive if operand signs are equal, and negative if operand signs are opposite, even if result is zero */ sign3 = (sign1 == sign2) ? 1 : -1; /* Store result into first operand location */ ARCH_DEP(store_decimal) (effective_addr1, l1, b1, regs, dec3, sign3); } /* end DEF_INST(multiply_decimal) */ /*-------------------------------------------------------------------*/ /* F0 SRP - Shift and Round Decimal [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_and_round_decimal) { int l1, i3; /* Length and rounding */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ BYTE dec[MAX_DECIMAL_DIGITS]; /* Work area for operand */ int count; /* Significant digit counter */ int sign; /* Sign of operand/result */ int i, j; /* Array subscripts */ int d; /* Decimal digit */ int carry; /* Carry indicator */ SS(inst, regs, l1, i3, b1, effective_addr1, b2, effective_addr2); /* Load operand into work area */ ARCH_DEP(load_decimal) (effective_addr1, l1, b1, regs, dec, &count, &sign); /* Program check if rounding digit is invalid */ if (i3 > 9) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Isolate low-order six bits of shift count */ effective_addr2 &= 0x3F; /* Shift count 0-31 means shift left, 32-63 means shift right */ if (effective_addr2 < 32) { /* Set condition code according to operand sign */ cc = (count == 0) ? 0 : (sign < 0) ? 1 : 2; /* Set cc=3 if non-zero digits will be lost on left shift */ if (count > 0 && effective_addr2 > (VADR)((l1+1)*2 - 1 - count)) cc = 3; /* Shift operand left */ for (i=0, j=effective_addr2; i < MAX_DECIMAL_DIGITS; i++, j++) dec[i] = (j < MAX_DECIMAL_DIGITS) ? dec[j] : 0; } else { /* Calculate number of digits (1-32) to shift right */ effective_addr2 = 64 - effective_addr2; /* Add the rounding digit to the leftmost of the digits to be shifted out and propagate the carry to the left */ carry = (effective_addr2 > MAX_DECIMAL_DIGITS) ? 0 : (dec[MAX_DECIMAL_DIGITS - effective_addr2] + i3) / 10; count = 0; /* Shift operand right */ for (i=MAX_DECIMAL_DIGITS-1, j=MAX_DECIMAL_DIGITS-1-effective_addr2; i >= 0; i--, j--) { d = (j >= 0) ? dec[j] : 0; d += carry; carry = d / 10; d %= 10; dec[i] = d; if (d != 0) count = MAX_DECIMAL_DIGITS - i; } /* Set condition code according to operand sign */ cc = (count == 0) ? 0 : (sign < 0) ? 1 : 2; } /* Make sign positive if result is zero */ if (cc == 0) sign = +1; /* Store result into operand location */ ARCH_DEP(store_decimal) (effective_addr1, l1, b1, regs, dec, sign); /* Set condition code */ regs->psw.cc = cc; /* Program check if overflow and PSW program mask is set */ if (cc == 3 && DOMASK(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_OVERFLOW_EXCEPTION); } /* end DEF_INST(shift_and_round_decimal) */ /*-------------------------------------------------------------------*/ /* FB SP - Subtract Decimal [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_decimal) { int l1, l2; /* Length values */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ BYTE dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */ BYTE dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */ BYTE dec3[MAX_DECIMAL_DIGITS]; /* Work area for result */ int count1, count2, count3; /* Significant digit counters*/ int sign1, sign2, sign3; /* Sign of operands & result */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* Load operands into work areas */ ARCH_DEP(load_decimal) (effective_addr1, l1, b1, regs, dec1, &count1, &sign1); ARCH_DEP(load_decimal) (effective_addr2, l2, b2, regs, dec2, &count2, &sign2); /* Add or subtract operand values */ if (count2 == 0) { /* If second operand is zero then result is first operand */ memcpy (dec3, dec1, MAX_DECIMAL_DIGITS); count3 = count1; sign3 = sign1; } else if (count1 == 0) { /* If first operand is zero then result is -second operand */ memcpy (dec3, dec2, MAX_DECIMAL_DIGITS); count3 = count2; sign3 = -sign2; } else if (sign1 != sign2) { /* If signs are opposite then add operands */ add_decimal (dec1, dec2, dec3, &count3); sign3 = sign1; } else { /* If signs are equal then subtract operands */ subtract_decimal (dec1, dec2, dec3, &count3, &sign3); if (sign1 < 0) sign3 = -sign3; } /* Set condition code */ cc = (count3 == 0) ? 0 : (sign3 < 1) ? 1 : 2; /* Overflow if result exceeds first operand length */ if (count3 > (l1+1) * 2 - 1) cc = 3; /* Set positive sign if result is zero */ if (count3 == 0) sign3 = 1; /* Store result into first operand location */ ARCH_DEP(store_decimal) (effective_addr1, l1, b1, regs, dec3, sign3); /* Return condition code */ regs->psw.cc = cc; /* Program check if overflow and PSW program mask is set */ if (cc == 3 && DOMASK(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_decimal) */ /*-------------------------------------------------------------------*/ /* F8 ZAP - Zero and Add [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(zero_and_add) { int l1, l2; /* Length values */ int b1, b2; /* Base register numbers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ int cc; /* Condition code */ BYTE dec[MAX_DECIMAL_DIGITS]; /* Work area for operand */ int count; /* Significant digit counter */ int sign; /* Sign */ SS(inst, regs, l1, l2, b1, effective_addr1, b2, effective_addr2); /* Load second operand into work area */ ARCH_DEP(load_decimal) (effective_addr2, l2, b2, regs, dec, &count, &sign); /* Set condition code */ cc = (count == 0) ? 0 : (sign < 1) ? 1 : 2; /* Overflow if result exceeds first operand length */ if (count > (l1+1) * 2 - 1) cc = 3; /* Set positive sign if result is zero */ if (count == 0) sign = +1; /* Store result into first operand location */ ARCH_DEP(store_decimal) (effective_addr1, l1, b1, regs, dec, sign); /* Return condition code */ regs->psw.cc = cc; /* Program check if overflow and PSW program mask is set */ if (cc == 3 && DOMASK(®s->psw)) ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_OVERFLOW_EXCEPTION); } /* end DEF_INST(zero_and_add) */ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* EBC0 TP - Test Decimal [RSL] */ /*-------------------------------------------------------------------*/ DEF_INST(test_decimal) { int l1; /* Length value */ int b1; /* Base register number */ VADR effective_addr1; /* Effective address */ int i; /* Array subscript */ int cc = 0; /* Condition code */ BYTE pack[MAX_DECIMAL_LENGTH]; /* Packed decimal work area */ RSL(inst, regs, l1, b1, effective_addr1); /* Fetch the packed decimal operand into the work area */ ARCH_DEP(vfetchc) (pack, l1, effective_addr1, b1, regs); /* Test each byte of the operand */ for (i=0; ; i++) { /* Test the high-order digit of the byte */ if ((pack[i] & 0xF0) > 0x90) cc = 2; /* Exit if this is the last byte */ if (i == l1) break; /* Test the low-order digit of the byte */ if ((pack[i] & 0x0F) > 0x09) cc = 2; } /* Test the sign in the last byte */ if ((pack[i] & 0x0F) < 0x0A) cc |= 1; /* Return condition code */ regs->psw.cc = cc; } /* end DEF_INST(test_decimal) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "decimal.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "decimal.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/service.c0000664000175000017500000021013112625667132012010 00000000000000/* SERVICE.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Service Processor */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements service processor functions */ /* for the Hercules ESA/390 emulator. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Corrections contributed by Jan Jaeger */ /* HMC system console functions by Jan Jaeger 2000-02-08 */ /* Expanded storage support by Jan Jaeger */ /* Dynamic CPU reconfiguration - Jan Jaeger */ /* Suppress superflous HHC701I/HHC702I messages - Jan Jaeger */ /* Break syscons output if too long - Jan Jaeger */ /* Added CPI - Control Program Information ev. - JJ 2001-11-19 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_SERVICE_C_) #define _SERVICE_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "sr.h" #if !defined(_SERVICE_C) #define _SERVICE_C /*-------------------------------------------------------------------*/ /* Service processor state data */ /*-------------------------------------------------------------------*/ static U32 servc_cp_recv_mask; /* Syscons CP receive mask */ static U32 servc_cp_send_mask; /* Syscons CP send mask */ static U32 servc_attn_pending; /* Attention pending mask */ static char servc_scpcmdstr[123+1]; /* Operator command string */ static U16 servc_signal_quiesce_count; static BYTE servc_signal_quiesce_unit; static BYTE servc_sysg_cmdcode; /* Pending SYSG read command */ #define SCLP_RECV_ENABLED(_type) \ (servc_cp_recv_mask & (0x80000000 >> ((_type)-1))) /*-------------------------------------------------------------------*/ /* Reset the service processor to its initial state */ /*-------------------------------------------------------------------*/ void sclp_reset() { servc_cp_recv_mask = 0; servc_cp_send_mask = 0; servc_attn_pending = 0; servc_signal_quiesce_count = 0; servc_signal_quiesce_unit = 0; servc_sysg_cmdcode = 0; sysblk.servparm = 0; } // #ifdef FEATURE_SYSTEM_CONSOLE /*-------------------------------------------------------------------*/ /* Raise service signal external interrupt */ /* (the caller is expected to hold the interrupt lock) */ /*-------------------------------------------------------------------*/ void sclp_attention(U16 type) { /* Set pending mask */ servc_attn_pending |= 0x80000000 >> (type -1); /* Ignore request if already pending */ if (!(IS_IC_SERVSIG && (sysblk.servparm & SERVSIG_PEND))) { /* Set event pending flag in service parameter */ sysblk.servparm |= SERVSIG_PEND; /* Set service signal interrupt pending for read event data */ ON_IC_SERVSIG; WAKEUP_CPUS_MASK (sysblk.waiting_mask); } } void sclp_attn_thread(U16 *type) { OBTAIN_INTLOCK(NULL); // The VM boys appear to have made an error in not // allowing for asyncronous attentions to be merged // with pending interrupts as such we will wait here // until a pending interrupt has been cleared. *JJ while(IS_IC_SERVSIG) { RELEASE_INTLOCK(NULL); sched_yield(); OBTAIN_INTLOCK(NULL); } sclp_attention(*type); free(type); RELEASE_INTLOCK(NULL); } void sclp_attn_async(U16 type) { if(!IS_IC_SERVSIG) sclp_attention(type); else { TID sclp_attn_tid; U16 *typ; typ=malloc(sizeof(U16)); *typ=type; create_thread(&sclp_attn_tid, &sysblk.detattr, sclp_attn_thread, typ, "attn_thread"); } } static U32 sclp_attn_pending(U16 type) { U32 pending; if(type) { pending = servc_attn_pending & (0x80000000 >> (type -1)); servc_attn_pending &= ~pending; return pending; } else return servc_attn_pending; } /*-------------------------------------------------------------------*/ /* Issue SCP command */ /* */ /* This function is called from the control panel when the operator */ /* enters an HMC system console SCP command or SCP priority message. */ /* The command is queued for processing by the SCLP_READ_EVENT_DATA */ /* service call, and a service signal interrupt is made pending. */ /* */ /* Input: */ /* command Null-terminated ASCII command string */ /* priomsg 0=SCP command, 1=SCP priority message */ /*-------------------------------------------------------------------*/ void scp_command (char *command, int priomsg) { /* Error if disabled for priority messages */ if (priomsg && !SCLP_RECV_ENABLED(SCCB_EVD_TYPE_PRIOR)) { logmsg (_("HHCCP036E SCP not receiving priority messages\n")); return; } /* Error if disabled for commands */ if (!priomsg && !SCLP_RECV_ENABLED(SCCB_EVD_TYPE_OPCMD)) { logmsg (_("HHCCP037E SCP not receiving commands\n")); return; } /* Error if command string is missing */ if (strlen(command) < 1) { logmsg (_("HHCCP038E No SCP command\n")); return; } /* Obtain the interrupt lock */ OBTAIN_INTLOCK(NULL); /* Save command string and message type for read event data */ strncpy (servc_scpcmdstr, command, sizeof(servc_scpcmdstr)); /* Ensure termination of the command string */ servc_scpcmdstr[sizeof(servc_scpcmdstr)-1] = '\0'; /* Raise attention service signal */ sclp_attention( priomsg ? SCCB_EVD_TYPE_PRIOR : SCCB_EVD_TYPE_OPCMD ); /* Release the interrupt lock */ RELEASE_INTLOCK(NULL); } /* end function scp_command */ static void sclp_opcmd_event(SCCB_HEADER *sccb, U16 type) { static BYTE const1_template[] = { 0x13,0x10, /* MDS message unit */ 0x00,0x25,0x13,0x11, /* MDS routine info */ 0x0E,0x81, /* origin location name */ 0x03,0x01,0x00, /* Net ID */ 0x03,0x02,0x00, /* NAU Name */ 0x06,0x03,0x00,0x00,0x00,0x00, /* Appl id */ 0x0E,0x82, /* Destinition location name */ 0x03,0x01,0x00, /* Net ID */ 0x03,0x02,0x00, /* NAU Name */ 0x06,0x03,0x00,0x00,0x00,0x00, /* Appl id */ 0x05,0x90,0x00,0x00,0x00, /* Flags (MDS type = req) */ 0x00,0x0C,0x15,0x49, /* Agent unit-of-work */ 0x08,0x01, /* Requestor loc name */ 0x03,0x01,0x00, /* Requestor Net ID */ 0x03,0x02,0x00 /* Requestor Node ID */ }; static BYTE const2_template[] = { 0x12,0x12, /* CP-MSU */ 0x00,0x12,0x15,0x4D, /* RTI */ 0x0E,0x06, /* Name List */ 0x06,0x10,0x00,0x03,0x00,0x00, /* Cascaded resource list */ 0x06,0x60,0xD6,0xC3,0xC6,0xC1, /* OAN (C'OCFA') */ 0x00,0x04,0x80,0x70 /* Operate request */ }; static BYTE const3_template[] = { 0x13,0x20 /* Text data */ }; static BYTE const4_template = { 0x31 /* Self-defining */ }; static BYTE const5_template = { 0x30 /* Text data */ }; U16 sccb_len; U16 evd_len; int event_msglen; int i; SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1); SCCB_EVD_BK *evd_bk = (SCCB_EVD_BK*)(evd_hdr+1); BYTE *event_msg = (BYTE*)(evd_bk+1); /* Get SCCB length */ FETCH_HW(sccb_len, sccb->length); /* Command length */ event_msglen = strlen(servc_scpcmdstr); /* Calculate required EVD length */ evd_len = event_msglen + sizeof(SCCB_EVD_HDR) + sizeof(SCCB_EVD_BK); /* Set response code X'75F0' if SCCB length exceeded */ if ((evd_len + sizeof(SCCB_HEADER)) > sccb_len) { sccb->reas = SCCB_REAS_EXCEEDS_SCCB; sccb->resp = SCCB_RESP_EXCEEDS_SCCB; return; } /* Zero all fields */ memset (evd_hdr, 0, evd_len); /* Update SCCB length field if variable request */ if (sccb->type & SCCB_TYPE_VARIABLE) { /* Set new SCCB length */ sccb_len = evd_len + sizeof(SCCB_HEADER); STORE_HW(sccb->length, sccb_len); sccb->type &= ~SCCB_TYPE_VARIABLE; } /* Set length in event header */ STORE_HW(evd_hdr->totlen, evd_len); /* Set type in event header */ evd_hdr->type = type; /* Set message length in event data block */ i = evd_len - sizeof(SCCB_EVD_HDR); STORE_HW(evd_bk->msglen, i); memcpy (evd_bk->const1, const1_template, sizeof(const1_template)); i -= sizeof(const1_template) + 2; STORE_HW(evd_bk->cplen, i); memcpy (evd_bk->const2, const2_template, sizeof(const2_template)); i -= sizeof(const2_template) + 2; STORE_HW(evd_bk->tdlen, i); memcpy (evd_bk->const3, const3_template, sizeof(const3_template)); i -= sizeof(const3_template) + 2; evd_bk->sdtlen = i; evd_bk->const4 = const4_template; i -= 2; evd_bk->tmlen = i; evd_bk->const5 = const5_template; /* Copy and translate command */ for (i = 0; i < event_msglen; i++) event_msg[i] = host_to_guest(servc_scpcmdstr[i]); /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } void sclp_cpident(SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb + 1); SCCB_CPI_BK *cpi_bk = (SCCB_CPI_BK*)(evd_hdr + 1); int i; char systype[9], sysname[9], sysplex[9]; U64 syslevel; if(*(cpi_bk->system_type)) set_systype(cpi_bk->system_type); if(*(cpi_bk->system_name)) set_sysname(cpi_bk->system_name); if(*(cpi_bk->sysplex_name)) set_sysplex(cpi_bk->sysplex_name); for(i = 0; i < 8; i++) { systype[i] = guest_to_host(cpi_bk->system_type[i]); sysname[i] = guest_to_host(cpi_bk->system_name[i]); sysplex[i] = guest_to_host(cpi_bk->sysplex_name[i]); } systype[8] = sysname[8] = sysplex[8] = 0; FETCH_DW(syslevel,cpi_bk->system_level); #if 1 logmsg(_("HHCCP040I CPI: System Type: %s Name: %s " "Sysplex: %s\n"), systype,sysname,sysplex); #else logmsg(_("HHC770I Control Program Information:\n")); logmsg(_("HHC771I System Type = %s\n",systype)); logmsg(_("HHC772I System Name = %s\n",sysname)); logmsg(_("HHC773I Sysplex Name = %s\n",sysplex)); logmsg(_("HHC774I System Level = %16.16" I64_FMT "X\n"),syslevel); #endif losc_check(systype); /* Indicate Event Processed */ evd_hdr->flag |= SCCB_EVD_FLAG_PROC; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } /*-------------------------------------------------------------------*/ /* Test whether SCP is enabled for QUIESCE signal */ /* */ /* This function tests whether the SCP is willing to be notified */ /* of a system shutdown via the SCLP_READ_EVENT_DATA service call. */ /* */ /* Return code: */ /* Zero = SCP not receiving quiesce event notification */ /* Non-zero = SCP ready to receive quiesce event notification */ /*-------------------------------------------------------------------*/ int can_signal_quiesce() { return SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SIGQ); } /*-------------------------------------------------------------------*/ /* Send QUIESCE signal to SCP */ /* */ /* This function is called during system shutdown to notify the SCP */ /* that a shutdown event is occurring. The shutdown event is queued */ /* for processing by the SCLP_READ_EVENT_DATA service call, and a */ /* service signal interrupt is made pending. */ /* */ /* Input: */ /* count and unit values to be returned by SCLP_READ_EVENT_DATA */ /*-------------------------------------------------------------------*/ int signal_quiesce (U16 count, BYTE unit) { /* Error if disabled for commands */ if (!SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SIGQ)) { logmsg (_("HHCCP081E SCP not receiving quiesce signals\n")); return -1; } /* Obtain the interrupt lock */ OBTAIN_INTLOCK(NULL); /* Save delay values for signal shutdown event read */ servc_signal_quiesce_count = count; servc_signal_quiesce_unit = unit; sclp_attention(SCCB_EVD_TYPE_SIGQ); /* Release the interrupt lock */ RELEASE_INTLOCK(NULL); return 0; } /* end function signal_quiesce */ static void sclp_sigq_event(SCCB_HEADER *sccb) { U16 sccb_len; U16 evd_len; SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1); SCCB_SGQ_BK *sgq_bk = (SCCB_SGQ_BK*)(evd_hdr+1); FETCH_HW(sccb_len, sccb->length); evd_len = sizeof(SCCB_EVD_HDR) + sizeof(SCCB_SGQ_BK); /* Set response code X'75F0' if SCCB length exceeded */ if ((evd_len + sizeof(SCCB_HEADER)) > sccb_len) { sccb->reas = SCCB_REAS_EXCEEDS_SCCB; sccb->resp = SCCB_RESP_EXCEEDS_SCCB; return; } /* Zero all fields */ memset (evd_hdr, 0, evd_len); /* Update SCCB length field if variable request */ if (sccb->type & SCCB_TYPE_VARIABLE) { /* Set new SCCB length */ sccb_len = evd_len + sizeof(SCCB_HEADER); STORE_HW(sccb->length, sccb_len); sccb->type &= ~SCCB_TYPE_VARIABLE; } /* Set length in event header */ STORE_HW(evd_hdr->totlen, evd_len); /* Set type in event header */ evd_hdr->type = SCCB_EVD_TYPE_SIGQ; STORE_HW(sgq_bk->count, servc_signal_quiesce_count); sgq_bk->unit = servc_signal_quiesce_unit; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } #if defined(_FEATURE_INTEGRATED_3270_CONSOLE) /*-------------------------------------------------------------------*/ /* Write data to the SYSG console */ /* */ /* The datastream to be written to the SYSG console is in the SCCB */ /* immediately following the Event Data Header. It consists of a */ /* one-byte local 3270 CCW command code, followed by a 3270 WCC, */ /* followed by 3270 orders and data. */ /* */ /* Input: */ /* sccb Address of SCCB */ /* evd_hdr Address of event data header within SCCB */ /* Output: */ /* Reason and response codes are set in the SCCB */ /* */ /*-------------------------------------------------------------------*/ void sclp_sysg_write(SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1); U16 evd_len; /* SCCB event data length */ U16 sysg_len; /* SYSG output data length */ DEVBLK *dev; /* -> SYSG console devblk */ BYTE *sysg_data; /* -> SYSG output data */ BYTE unitstat; /* Unit status */ BYTE more = 0; /* Flag for device handler */ U16 residual; /* Residual data count */ BYTE cmdcode; /* 3270 read/write command */ /* Calculate the address and length of the 3270 datastream */ FETCH_HW(evd_len,evd_hdr->totlen); sysg_data = (BYTE*)(evd_hdr+1); sysg_len = evd_len - sizeof(SCCB_EVD_HDR); /* The first data byte is the 3270 command code */ cmdcode = *sysg_data; /* Look for the SYSG console device block */ dev = sysblk.sysgdev; if (dev == NULL) { PTT(PTT_CL_ERR,"*SERVC",(U32)cmdcode,(U32)sysg_len,0); /* Set response code X'05F0' in SCCB header */ sccb->reas = SCCB_REAS_IMPROPER_RSC; sccb->resp = SCCB_RESP_REJECT; return; } /* If it is a read CCW then save the command until READ_EVENT_DATA */ if (IS_CCW_READ(cmdcode)) { servc_sysg_cmdcode = cmdcode; /* Indicate Event Processed */ evd_hdr->flag |= SCCB_EVD_FLAG_PROC; /* Generate a service call interrupt to trigger READ_EVENT_DATA */ sclp_attn_async(SCCB_EVD_TYPE_SYSG); /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; return; } else { servc_sysg_cmdcode = 0x00; /* Execute the 3270 command in data block */ /* dev->hnd->exec points to loc3270_execute_ccw */ (dev->hnd->exec) (dev, /*ccw opcode*/ cmdcode, /*flags*/ CCW_FLAGS_SLI, /*chained*/0, /*count*/ sysg_len - 1, /*prevcode*/ 0, /*ccwseq*/ 0, /*iobuf*/ sysg_data+1, &more, &unitstat, &residual); /* Indicate Event Processed */ evd_hdr->flag |= SCCB_EVD_FLAG_PROC; /* If unit check occured, set response code X'0040' */ if (unitstat & CSW_UC) { PTT(PTT_CL_ERR,"*SERVC",(U32)more,(U32)unitstat,residual); /* Set response code X'0040' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_BACKOUT; return; } /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } } /*-------------------------------------------------------------------*/ /* Read data from the SYSG console */ /* */ /* If the SYSG console has data to send, copy it into the SCCB */ /* immediately following the Event Data Header. The data consists */ /* of a 3270 AID byte, followed by a two-byte 3270 cursor address, */ /* followed by 3270 orders and data. */ /* */ /* Output: */ /* Data, reason and response codes are set in the SCCB */ /* */ /*-------------------------------------------------------------------*/ void sclp_sysg_poll(SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1); U16 sccblen; /* SCCB total length */ U16 evd_len; /* SCCB event data length */ U16 sysg_len; /* SYSG input data length */ DEVBLK *dev; /* -> SYSG console devblk */ BYTE *sysg_data; /* -> SYSG input data */ BYTE *sysg_cmd; /* -> SYSG input data */ BYTE unitstat; /* Unit status */ BYTE more = 0; /* Flag for device handler */ U16 residual; /* Residual data count */ dev = sysblk.sysgdev; if (dev != NULL) { /* Zeroize the event data header */ memset (evd_hdr, 0, sizeof(SCCB_EVD_HDR)); /* Calculate maximum data length */ FETCH_HW(sccblen, sccb->length); evd_len = sccblen - sizeof(SCCB_HEADER); sysg_data = (BYTE*)(evd_hdr+1); sysg_len = evd_len - sizeof(SCCB_EVD_HDR); /* Insert flag byte before the 3270 input data */ sysg_cmd = sysg_data; sysg_len-=1; sysg_data+=1; /* Execute previously saved 3270 read command */ if (servc_sysg_cmdcode) { *sysg_cmd = 0x00; /* Execute a 3270 read-modified command */ /* dev->hnd->exec points to loc3270_execute_ccw */ (dev->hnd->exec) (dev, /*ccw opcode*/ servc_sysg_cmdcode, /*flags*/ CCW_FLAGS_SLI, /*chained*/0, /*count*/ sysg_len, /*prevcode*/ 0, /*ccwseq*/ 0, /*iobuf*/ sysg_data, &more, &unitstat, &residual); servc_sysg_cmdcode = 0; /* Set response code X'0040' if unit check occurred */ if (unitstat & CSW_UC) { PTT(PTT_CL_ERR,"*SERVC",(U32)more,(U32)unitstat,residual); /* Set response code X'0040' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_BACKOUT; return; } /* Set response code X'75F0' if SCCB length exceeded */ if (more) { PTT(PTT_CL_ERR,"*SERVC",(U32)more,(U32)unitstat,residual); sccb->reas = SCCB_REAS_EXCEEDS_SCCB; sccb->resp = SCCB_RESP_EXCEEDS_SCCB; return; } /* Calculate actual length read */ sysg_len -= residual; evd_len = sizeof(SCCB_EVD_HDR) + sysg_len + 1; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } else { evd_len = sizeof(SCCB_EVD_HDR) + 1; *sysg_cmd = 0x80; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } /* Update SCCB length field if variable request */ if (sccb->type & SCCB_TYPE_VARIABLE) { /* Set new SCCB length */ sccblen = evd_len + sizeof(SCCB_HEADER); STORE_HW(sccb->length, sccblen); sccb->type &= ~SCCB_TYPE_VARIABLE; } /* Set length in event header */ STORE_HW(evd_hdr->totlen, evd_len); /* Set type in event header */ evd_hdr->type = SCCB_EVD_TYPE_SYSG; } } /*-------------------------------------------------------------------*/ /* Handle attention interrupt from the SYSG console */ /* */ /* This function is called by console.c when it receives input */ /* from the SYSG console. It sets the SYSG read flag and raises */ /* a service signal external interrupt, which should prompt the */ /* SCP to issue a SCLP_READ_EVENT_DATA service call to retrieve */ /* the input data. */ /*-------------------------------------------------------------------*/ SERV_DLL_IMPORT void sclp_sysg_attention() { OBTAIN_INTLOCK(NULL); sclp_attn_async(SCCB_EVD_TYPE_SYSG); RELEASE_INTLOCK(NULL); } #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/ #if defined(_FEATURE_INTEGRATED_ASCII_CONSOLE) int sclp_sysa_write(SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1); U16 evd_len; U16 sysa_len; BYTE *sysa_data; int i; logmsg(D_("SYSA write:")); FETCH_HW(evd_len,evd_hdr->totlen); sysa_data = (BYTE*)(evd_hdr+1); sysa_len = evd_len - sizeof(SCCB_EVD_HDR); for(i = 0; i < sysa_len; i++) { if(!(i & 15)) logmsg("\n %4.4X:", i); logmsg(" %2.2X", sysa_data[i]); } if(i & 15) logmsg("\n"); /* Indicate Event Processed */ evd_hdr->flag |= SCCB_EVD_FLAG_PROC; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; // maybe this needs to be INFO //sclp_attention(SCCB_EVD_TYPE_VT220); return 0; // write ok } int sclp_sysa_poll(SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb+1); UNREFERENCED(sccb); UNREFERENCED(evd_hdr); logmsg(D_("VT220 poll\n")); } #endif /*defined(_FEATURE_INTEGRATED_ASCII_CONSOLE)*/ /*-------------------------------------------------------------------*/ /* Suspend and resume functions */ /*-------------------------------------------------------------------*/ #define SR_SYS_SERVC_RECVMASK ( SR_SYS_SERVC | 0x001 ) #define SR_SYS_SERVC_SENDMASK ( SR_SYS_SERVC | 0x002 ) #define SR_SYS_SERVC_PENDING ( SR_SYS_SERVC | 0x003 ) #define SR_SYS_SERVC_SCPCMD ( SR_SYS_SERVC | 0x004 ) #define SR_SYS_SERVC_SQC ( SR_SYS_SERVC | 0x005 ) #define SR_SYS_SERVC_SQU ( SR_SYS_SERVC | 0x006 ) #define SR_SYS_SERVC_PARM ( SR_SYS_SERVC | 0x007 ) int servc_hsuspend(void *file) { SR_WRITE_VALUE(file, SR_SYS_SERVC_RECVMASK, servc_cp_recv_mask, sizeof(servc_cp_recv_mask)); SR_WRITE_VALUE(file, SR_SYS_SERVC_SENDMASK, servc_cp_send_mask, sizeof(servc_cp_send_mask)); SR_WRITE_VALUE(file, SR_SYS_SERVC_PENDING, servc_attn_pending, sizeof(servc_attn_pending)); SR_WRITE_STRING(file, SR_SYS_SERVC_SCPCMD, servc_scpcmdstr); SR_WRITE_VALUE(file, SR_SYS_SERVC_SQC, servc_signal_quiesce_count, sizeof(servc_signal_quiesce_count)); SR_WRITE_VALUE(file, SR_SYS_SERVC_SQU, servc_signal_quiesce_unit, sizeof(servc_signal_quiesce_unit)); SR_WRITE_VALUE(file, SR_SYS_SERVC_PARM, sysblk.servparm, sizeof(sysblk.servparm)); return 0; } int servc_hresume(void *file) { size_t key, len; sclp_reset(); do { SR_READ_HDR(file, key, len); switch (key) { case SR_SYS_SERVC_RECVMASK: SR_READ_VALUE(file, len, &servc_cp_recv_mask, sizeof(servc_cp_recv_mask)); break; case SR_SYS_SERVC_SENDMASK: SR_READ_VALUE(file, len, &servc_cp_send_mask, sizeof(servc_cp_send_mask)); break; case SR_SYS_SERVC_PENDING: SR_READ_VALUE(file, len, &servc_attn_pending, sizeof(servc_attn_pending)); break; case SR_SYS_SERVC_SCPCMD: if ( len <= sizeof(servc_scpcmdstr) ) SR_READ_STRING(file, servc_scpcmdstr, sizeof(servc_scpcmdstr)); else SR_READ_SKIP(file, len); break; case SR_SYS_SERVC_SQC: SR_READ_VALUE(file, len, &servc_signal_quiesce_count, sizeof(servc_signal_quiesce_count)); break; case SR_SYS_SERVC_SQU: SR_READ_VALUE(file, len, &servc_signal_quiesce_unit, sizeof(servc_signal_quiesce_unit)); break; case SR_SYS_SERVC_PARM: SR_READ_VALUE(file, len, &sysblk.servparm, sizeof(sysblk.servparm)); break; default: SR_READ_SKIP(file, len); break; } } while ((key & SR_SYS_MASK) == SR_SYS_SERVC); return 0; } #endif /*!defined(_SERVICE_C)*/ // #endif /*FEATURE_SYSTEM_CONSOLE*/ #if defined(FEATURE_SERVICE_PROCESSOR) /*-------------------------------------------------------------------*/ /* Architecture-dependent service processor bit strings */ /*-------------------------------------------------------------------*/ BYTE ARCH_DEP(scpinfo_ifm)[8] = { 0 | SCCB_IFM0_CHANNEL_PATH_INFORMATION | SCCB_IFM0_CHANNEL_PATH_SUBSYSTEM_COMMAND // | SCCB_IFM0_CHANNEL_PATH_RECONFIG // | SCCB_IFM0_CPU_INFORMATION #ifdef FEATURE_CPU_RECONFIG | SCCB_IFM0_CPU_RECONFIG #endif /*FEATURE_CPU_RECONFIG*/ , 0 // | SCCB_IFM1_SIGNAL_ALARM // | SCCB_IFM1_WRITE_OPERATOR_MESSAGE // | SCCB_IFM1_STORE_STATUS_ON_LOAD // | SCCB_IFM1_RESTART_REASONS // | SCCB_IFM1_INSTRUCTION_ADDRESS_TRACE_BUFFER | SCCB_IFM1_LOAD_PARAMETER , 0 // | SCCB_IFM2_REAL_STORAGE_INCREMENT_RECONFIG // | SCCB_IFM2_REAL_STORAGE_ELEMENT_INFO // | SCCB_IFM2_REAL_STORAGE_ELEMENT_RECONFIG // | SCCB_IFM2_COPY_AND_REASSIGN_STORAGE #ifdef FEATURE_EXPANDED_STORAGE | SCCB_IFM2_EXTENDED_STORAGE_USABILITY_MAP #endif /*FEATURE_EXPANDED_STORAGE*/ // | SCCB_IFM2_EXTENDED_STORAGE_ELEMENT_INFO // | SCCB_IFM2_EXTENDED_STORAGE_ELEMENT_RECONFIG , 0 #if defined(FEATURE_VECTOR_FACILITY) && defined(FEATURE_CPU_RECONFIG) | SCCB_IFM3_VECTOR_FEATURE_RECONFIG #endif /*FEATURE_VECTOR_FACILITY*/ #ifdef FEATURE_SYSTEM_CONSOLE | SCCB_IFM3_READ_WRITE_EVENT_FEATURE #endif /*FEATURE_SYSTEM_CONSOLE*/ // | SCCB_IFM3_READ_RESOURCE_GROUP_INFO , 0, 0, 0, 0 }; BYTE ARCH_DEP(scpinfo_cfg)[6] = { 0 #if defined(FEATURE_HYPERVISOR) | SCCB_CFG0_LOGICALLY_PARTITIONED #endif /*defined(FEATURE_HYPERVISOR)*/ #ifdef FEATURE_SUPPRESSION_ON_PROTECTION | SCCB_CFG0_SUPPRESSION_ON_PROTECTION #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ // | SCCB_CFG0_INITIATE_RESET #if defined(FEATURE_CHSC) | SCCB_CFG0_STORE_CHANNEL_SUBSYS_CHARACTERISTICS #endif /*defined(FEATURE_CHSC)*/ #if defined(FEATURE_MOVE_PAGE_FACILITY_2) | SCCB_CFG0_MVPG_FOR_ALL_GUESTS #endif /*defined(FEATURE_MOVE_PAGE_FACILITY_2)*/ #if defined(FEATURE_FAST_SYNC_DATA_MOVER) /* The Fast Sync Data Mover facility is simply a flag which indicates that the MVPG instruction performs faster than the Asynchronous Data Mover facility (see GA22-1030-03) */ | SCCB_CFG0_FAST_SYNCHRONOUS_DATA_MOVER #endif /*defined(FEATURE_FAST_SYNC_DATA_MOVER)*/ , 0 // | SCCB_CFG1_CSLO , 0 // | SCCB_CFG2_DEVICE_ACTIVE_ONLY_MEASUREMENT #ifdef FEATURE_CALLED_SPACE_IDENTIFICATION | SCCB_CFG2_CALLED_SPACE_IDENTIFICATION #endif /*FEATURE_CALLED_SPACE_IDENTIFICATION*/ #ifdef FEATURE_CHECKSUM_INSTRUCTION | SCCB_CFG2_CHECKSUM_INSTRUCTION #endif /*FEATURE_CHECKSUM_INSTRUCTION*/ , 0 #if defined(FEATURE_RESUME_PROGRAM) | SCCB_CFG3_RESUME_PROGRAM #endif /*defined(FEATURE_RESUME_PROGRAM)*/ #if defined(FEATURE_PERFORM_LOCKED_OPERATION) | SCCB_CFG3_PERFORM_LOCKED_OPERATION #endif /*defined(FEATURE_PERFORM_LOCKED_OPERATION)*/ #ifdef FEATURE_IMMEDIATE_AND_RELATIVE | SCCB_CFG3_IMMEDIATE_AND_RELATIVE #endif /*FEATURE_IMMEDIATE_AND_RELATIVE*/ #ifdef FEATURE_COMPARE_AND_MOVE_EXTENDED | SCCB_CFG3_COMPARE_AND_MOVE_EXTENDED #endif /*FEATURE_COMPARE_AND_MOVE_EXTENDED*/ #ifdef FEATURE_BRANCH_AND_SET_AUTHORITY | SCCB_CFG3_BRANCH_AND_SET_AUTHORITY #endif /*FEATURE_BRANCH_AND_SET_AUTHORITY*/ #if defined(FEATURE_BASIC_FP_EXTENSIONS) | SCCB_CFG3_EXTENDED_FLOATING_POINT #endif /*defined(FEATURE_BASIC_FP_EXTENSIONS)*/ /*ZZ*/ | SCCB_CFG3_EXTENDED_LOGICAL_COMPUTATION_FACILITY , 0 #ifdef FEATURE_EXTENDED_TOD_CLOCK | SCCB_CFG4_EXTENDED_TOD_CLOCK #endif /*FEATURE_EXTENDED_TOD_CLOCK*/ #if defined(FEATURE_EXTENDED_TRANSLATION) | SCCB_CFG4_EXTENDED_TRANSLATION #endif /*defined(FEATURE_EXTENDED_TRANSLATION)*/ #if defined(FEATURE_LOAD_REVERSED) | SCCB_CFG4_LOAD_REVERSED_FACILITY #endif /*defined(FEATURE_LOAD_REVERSED)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) | SCCB_CFG4_EXTENDED_TRANSLATION_FACILITY2 #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_STORE_SYSTEM_INFORMATION) | SCCB_CFG4_STORE_SYSTEM_INFORMATION #endif /*FEATURE_STORE_SYSTEM_INFORMATION*/ // | SCCB_CFG4_LPAR_CLUSTERING | SCCB_CFG4_IFA_FACILITY , 0 #if defined(FEATURE_SENSE_RUNNING_STATUS) | SCCB_CFG5_SENSE_RUNNING_STATUS #endif /*FEATURE_SENSE_RUNNING_STATUS*/ }; BYTE ARCH_DEP(scpinfo_cfg11) = 0 #if defined(FEATURE_PER3) | SCCB_CFGB_PER_3 #endif | SCCB_CFGB_LIST_DIRECTED_IPL; BYTE ARCH_DEP(scpinfo_cpf)[12] = { 0 #if defined(FEATURE_INTERPRETIVE_EXECUTION) #if defined(_370) && !defined(FEATURE_ESAME) | SCCB_CPF0_SIE_370_MODE #endif /*defined(_370) && !defined(FEATURE_ESAME)*/ | SCCB_CPF0_SIE_XA_MODE #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ // | SCCB_CPF0_SIE_SET_II_370_MODE #if defined(FEATURE_IO_ASSIST) | SCCB_CPF0_SIE_SET_II_XA_MODE #endif /*defined(FEATURE_IO_ASSIST)*/ #if defined(FEATURE_INTERPRETIVE_EXECUTION) | SCCB_CPF0_SIE_NEW_INTERCEPT_FORMAT #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ #if defined(FEATURE_STORAGE_KEY_ASSIST) | SCCB_CPF0_STORAGE_KEY_ASSIST #endif /*defined(FEATURE_STORAGE_KEY_ASSIST)*/ #if defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) | SCCB_CPF0_MULTIPLE_CONTROLLED_DATA_SPACE #endif /*defined(_FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ , 0 #if defined(FEATURE_IO_ASSIST) | SCCB_CPF1_IO_INTERPRETATION_LEVEL_2 #endif /*defined(FEATURE_IO_ASSIST)*/ #if defined(FEATURE_INTERPRETIVE_EXECUTION) | SCCB_CPF1_GUEST_PER_ENHANCED #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ // | SCCB_CPF1_SIGP_INTERPRETATION_ASSIST #if defined(FEATURE_STORAGE_KEY_ASSIST) | SCCB_CPF1_RCP_BYPASS_FACILITY #endif /*defined(FEATURE_STORAGE_KEY_ASSIST)*/ #if defined(FEATURE_REGION_RELOCATE) | SCCB_CPF1_REGION_RELOCATE_FACILITY #endif /*defined(FEATURE_REGION_RELOCATE)*/ #if defined(FEATURE_EXPEDITED_SIE_SUBSET) | SCCB_CPF1_EXPEDITE_TIMER_PROCESSING #endif /*defined(FEATURE_EXPEDITED_SIE_SUBSET)*/ , 0 #if defined(FEATURE_CRYPTO) | SCCB_CPF2_CRYPTO_FEATURE_ACCESSED #endif /*defined(FEATURE_CRYPTO)*/ #if defined(FEATURE_EXPEDITED_SIE_SUBSET) | SCCB_CPF2_EXPEDITE_RUN_PROCESSING #endif /*defined(FEATURE_EXPEDITED_SIE_SUBSET)*/ , 0 #ifdef FEATURE_PRIVATE_SPACE | SCCB_CPF3_PRIVATE_SPACE_FEATURE | SCCB_CPF3_FETCH_ONLY_BIT #endif /*FEATURE_PRIVATE_SPACE*/ #if defined(FEATURE_PER2) | SCCB_CPF3_PER2_INSTALLED #endif /*defined(FEATURE_PER2)*/ , 0 #if defined(FEATURE_PER2) | SCCB_CPF4_OMISION_GR_ALTERATION_370 #endif /*defined(FEATURE_PER2)*/ , 0 #if defined(FEATURE_WAITSTATE_ASSIST) | SCCB_CPF5_GUEST_WAIT_STATE_ASSIST #endif /*defined(FEATURE_WAITSTATE_ASSIST)*/ , 0, 0, 0, 0, 0, 0 } ; U32 ARCH_DEP(sclp_recv_mask) = (0x80000000 >> (SCCB_EVD_TYPE_MSG-1)) | (0x80000000 >> (SCCB_EVD_TYPE_PRIOR-1)) | #if defined(FEATURE_SCEDIO) (0x80000000 >> (SCCB_EVD_TYPE_SCEDIO-1)) | #endif /*defined(FEATURE_SCEDIO)*/ #if defined(FEATURE_INTEGRATED_ASCII_CONSOLE) (0x80000000 >> (SCCB_EVD_TYPE_VT220-1)) | #endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/ #if defined(FEATURE_INTEGRATED_3270_CONSOLE) (0x80000000 >> (SCCB_EVD_TYPE_SYSG-1)) | #endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/ (0x80000000 >> (SCCB_EVD_TYPE_CPIDENT-1)) ; U32 ARCH_DEP(sclp_send_mask) = (0x80000000 >> (SCCB_EVD_TYPE_OPCMD-1)) | (0x80000000 >> (SCCB_EVD_TYPE_STATECH-1)) | (0x80000000 >> (SCCB_EVD_TYPE_PRIOR-1)) | (0x80000000 >> (SCCB_EVD_TYPE_SIGQ-1)) | #if defined(FEATURE_SCEDIO) (0x80000000 >> (SCCB_EVD_TYPE_SCEDIO-1)) | #endif /*defined(FEATURE_SCEDIO)*/ #if defined(FEATURE_INTEGRATED_ASCII_CONSOLE) (0x80000000 >> (SCCB_EVD_TYPE_VT220-1)) | #endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/ #if defined(FEATURE_INTEGRATED_3270_CONSOLE) (0x80000000 >> (SCCB_EVD_TYPE_SYSG-1)) | #endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/ (0x80000000 >> (SCCB_EVD_TYPE_CPCMD-1)) ; /*-------------------------------------------------------------------*/ /* B220 SERVC - Service Call [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(service_call) { U32 r1, r2; /* Values of R fields */ U32 sclp_command; /* SCLP command code */ U32 sccb_real_addr; /* SCCB real address */ int i; /* Array subscripts */ U32 realinc; /* Storage size in increments*/ U32 incsizemb; /* Increment size in MB */ U32 sccb_absolute_addr; /* Absolute address of SCCB */ U32 sccblen; /* Length of SCCB */ SCCB_HEADER *sccb; /* -> SCCB header */ SCCB_SCP_INFO *sccbscp; /* -> SCCB SCP information */ SCCB_CPU_INFO *sccbcpu; /* -> SCCB CPU information */ #if defined(FEATURE_MPF_INFO) SCCB_MPF_INFO *sccbmpf; /* -> SCCB MPF information */ #endif /*defined(FEATURE_MPF_INFO)*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM SCCB_CHP_INFO *sccbchp; /* -> SCCB channel path info */ #else SCCB_CHSET_INFO *sccbchp; /* -> SCCB channel path info */ #endif SCCB_CSI_INFO *sccbcsi; /* -> SCCB channel subsys inf*/ U16 offset; /* Offset from start of SCCB */ #ifdef FEATURE_CHANNEL_SUBSYSTEM DEVBLK *dev; /* Used to find CHPIDs */ U32 chpbyte; /* Offset to byte for CHPID */ U32 chpbit; /* Bit number for CHPID */ #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ #ifdef FEATURE_SYSTEM_CONSOLE SCCB_EVENT_MASK*evd_mask; /* Event mask */ SCCB_EVD_HDR *evd_hdr; /* Event header */ U16 evd_len; /* Length of event data */ SCCB_MCD_BK *mcd_bk; /* Message Control Data */ U16 mcd_len; /* Length of MCD */ SCCB_OBJ_HDR *obj_hdr; /* Object Header */ U16 obj_len; /* Length of Object */ U16 obj_type; /* Object type */ SCCB_MTO_BK *mto_bk; /* Message Text Object */ BYTE *event_msg; /* Message Text pointer */ int event_msglen; /* Message Text length */ BYTE message[4089]; /* Maximum event data buffer length plus one for \0 */ U32 masklen; /* Length of event mask */ U32 old_cp_recv_mask; /* Masks before write event */ U32 old_cp_send_mask; /* mask command */ #endif /*FEATURE_SYSTEM_CONSOLE*/ #ifdef FEATURE_EXPANDED_STORAGE SCCB_XST_MAP *sccbxmap; /* Xstore usability map */ U32 xstincnum; /* Number of expanded storage increments */ U32 xstblkinc; /* Number of expanded storage blocks per increment */ BYTE *xstmap; /* Xstore bitmap, zero means available */ #endif /*FEATURE_EXPANDED_STORAGE*/ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_INF,"SERVC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); /* R1 is SCLP command word */ sclp_command = regs->GR_L(r1); /* R2 is real address of service call control block */ sccb_real_addr = regs->GR_L(r2); /* Obtain the absolute address of the SCCB */ sccb_absolute_addr = APPLY_PREFIXING(sccb_real_addr, regs->PX); /* Program check if SCCB is not on a doubleword boundary */ if ( sccb_absolute_addr & 0x00000007 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if SCCB is outside main storage */ if ( sccb_absolute_addr > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Point to service call control block */ sccb = (SCCB_HEADER*)(regs->mainstor + sccb_absolute_addr); /* Load SCCB length from header */ FETCH_HW(sccblen, sccb->length); /* Set the main storage reference bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_REF; /* Program check if end of SCCB falls outside main storage */ if ( sccb_absolute_addr + sccblen > regs->mainlim + 1) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Obtain lock if immediate response is not requested */ if (!(sccb->flag & SCCB_FLAG_SYNC) || (sclp_command & SCLP_COMMAND_CLASS) == 0x01) { /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); /* If a service signal is pending then return condition code 2 to indicate that service processor is busy */ if (IS_IC_SERVSIG && (sysblk.servparm & SERVSIG_ADDR)) { RELEASE_INTLOCK(regs); regs->psw.cc = 2; return; } } /* Test SCLP command word */ switch (sclp_command & SCLP_COMMAND_MASK) { case SCLP_READ_IFL_INFO: /* READ_IFL_INFO is only valid for processor type IFL */ if(sysblk.ptyp[regs->cpuad] != SCCB_PTYP_IFL) goto invalidcmd; else goto read_scpinfo; case SCLP_READ_SCP_INFO: /* READ_SCP_INFO is only valid for processor type CP */ if(sysblk.ptyp[regs->cpuad] != SCCB_PTYP_CP) { #ifdef OPTION_MSGCLR logmsg(""); #endif logmsg("HHCCP090W The configuration has been placed into a system check-stop state because of an incompatible service call\n\n"); goto docheckstop; /* * Replace the following 2 lines with * goto invalidcmd * if this behavior is not satisfactory * ISW 20081221 */ } read_scpinfo: /* Set the main storage change bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set response code X'0100' if SCCB crosses a page boundary */ if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) != ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK)) { sccb->reas = SCCB_REAS_NOT_PGBNDRY; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Set response code X'0300' if SCCB length is insufficient to contain SCP info */ if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_SCP_INFO) + (sizeof(SCCB_CPU_INFO) * MAX_CPU)) { sccb->reas = SCCB_REAS_TOO_SHORT; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Point to SCCB data area following SCCB header */ sccbscp = (SCCB_SCP_INFO*)(sccb+1); memset (sccbscp, 0, sizeof(SCCB_SCP_INFO)); /* Set main storage size in SCCB */ incsizemb = (sysblk.mainsize + (0xFFFF00000ULL - 1)) / 0xFFFF00000ULL; realinc = sysblk.mainsize / (incsizemb << 20); STORE_HW(sccbscp->realinum, realinc); sccbscp->realiszm = (incsizemb & 0xFF); sccbscp->realbszk = 4; STORE_HW(sccbscp->realiint, 1); #if defined(_900) || defined(FEATURE_ESAME) /* SIE supports the full address range */ sccbscp->maxvm = 0; /* realiszm is valid */ STORE_FW(sccbscp->grzm, 0); /* Number of storage increments installed in esame mode */ STORE_DW(sccbscp->grnmx, realinc); #endif /*defined(_900) || defined(FEATURE_ESAME)*/ #ifdef FEATURE_EXPANDED_STORAGE /* Set expanded storage size in SCCB */ xstincnum = sysblk.xpndsize / (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT); STORE_FW(sccbscp->xpndinum, xstincnum); xstblkinc = XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT; STORE_FW(sccbscp->xpndsz4K, xstblkinc); #endif /*FEATURE_EXPANDED_STORAGE*/ #ifdef FEATURE_VECTOR_FACILITY /* Set the Vector section size in the SCCB */ STORE_HW(sccbscp->vectssiz, VECTOR_SECTION_SIZE); /* Set the Vector partial sum number in the SCCB */ STORE_HW(sccbscp->vectpsum, VECTOR_PARTIAL_SUM_NUMBER); #endif /*FEATURE_VECTOR_FACILITY*/ /* Set CPU array count and offset in SCCB */ STORE_HW(sccbscp->numcpu, MAX_CPU); offset = sizeof(SCCB_HEADER) + sizeof(SCCB_SCP_INFO); STORE_HW(sccbscp->offcpu, offset); #if defined(FEATURE_MPF_INFO) /* Set MPF array count and offset in SCCB */ STORE_HW(sccbscp->nummpf, MAX_CPU-1); #endif /*defined(FEATURE_MPF_INFO)*/ offset += sizeof(SCCB_CPU_INFO) * MAX_CPU; STORE_HW(sccbscp->offmpf, offset); /* Set HSA array count and offset in SCCB */ STORE_HW(sccbscp->numhsa, 0); #if defined(FEATURE_MPF_INFO) offset += sizeof(SCCB_MPF_INFO) * MAX_CPU-1; #endif /*defined(FEATURE_MPF_INFO)*/ STORE_HW(sccbscp->offhsa, offset); /* Build the MPF information array after the CPU info */ /* Move IPL load parameter to SCCB */ get_loadparm (sccbscp->loadparm); /* Set installed features bit mask in SCCB */ memcpy(sccbscp->ifm, ARCH_DEP(scpinfo_ifm), sizeof(sccbscp->ifm)); memcpy(sccbscp->cfg, ARCH_DEP(scpinfo_cfg), sizeof(sccbscp->cfg)); /* sccbscp->cfg11 = ARCH_DEP(scpinfo_cfg11); */ #if defined(_900) || defined(FEATURE_ESAME) if(sysblk.arch_z900) sccbscp->cfg[5] |= SCCB_CFG5_ESAME; #endif /*defined(_900) || defined(FEATURE_ESAME)*/ ; /* Build the CPU information array after the SCP info */ sccbcpu = (SCCB_CPU_INFO*)(sccbscp+1); for (i = 0; i < MAX_CPU; i++, sccbcpu++) { memset (sccbcpu, 0, sizeof(SCCB_CPU_INFO)); sccbcpu->cpa = i; sccbcpu->tod = 0; memcpy(sccbcpu->cpf, ARCH_DEP(scpinfo_cpf), sizeof(sccbcpu->cpf)); sccbcpu->ptyp = sysblk.ptyp[i]; #if defined(FEATURE_CRYPTO) // sccbcpu->ksid = SCCB_KSID_CRYPTO_UNIT_ID; #endif /*defined(FEATURE_CRYPTO)*/ #ifdef FEATURE_VECTOR_FACILITY if(IS_CPU_ONLINE(i) && sysblk.regs[i]->vf->online) sccbcpu->cpf[2] |= SCCB_CPF2_VECTOR_FEATURE_INSTALLED; if(IS_CPU_ONLINE(i) && sysblk.regs[i]->vf->online) sccbcpu->cpf[2] |= SCCB_CPF2_VECTOR_FEATURE_CONNECTED; if(!IS_CPU_ONLINE(i)) sccbcpu->cpf[2] |= SCCB_CPF2_VECTOR_FEATURE_STANDBY_STATE; #endif /*FEATURE_VECTOR_FACILITY*/ } #if defined(FEATURE_MPF_INFO) /* Define machine capacity */ STORE_FW(sccbscp->rcci, 10000); /* Fill in the MP Factors array */ sccbmpf = (SCCB_MPF_INFO*)(sccbcpu); get_mpfactors((BYTE*)sccbmpf); #endif /*defined(FEATURE_MPF_INFO)*/ /* Set response code X'0010' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_INFO; break; docheckstop: ARCH_DEP(checkstop_config)(); RELEASE_INTLOCK(regs); longjmp(regs->progjmp,SIE_NO_INTERCEPT); break; case SCLP_READ_CHP_INFO: /* Set the main storage change bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set response code X'0100' if SCCB crosses a page boundary */ if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) != ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK)) { sccb->reas = SCCB_REAS_NOT_PGBNDRY; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Set response code X'0300' if SCCB length is insufficient to contain channel path info */ if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_CHP_INFO)) { sccb->reas = SCCB_REAS_TOO_SHORT; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } #ifdef FEATURE_S370_CHANNEL /* Point to SCCB data area following SCCB header */ sccbchp = (SCCB_CHSET_INFO*)(sccb+1); memset (sccbchp, 0, sizeof(SCCB_CHSET_INFO)); #else /* Point to SCCB data area following SCCB header */ sccbchp = (SCCB_CHP_INFO*)(sccb+1); memset (sccbchp, 0, sizeof(SCCB_CHP_INFO)); #endif #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Identify CHPIDs installed, standby, and online */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { chpbyte = dev->devnum >> 11; chpbit = (dev->devnum >> 8) & 7; sccbchp->installed[chpbyte] |= 0x80 >> chpbit; if (dev->pmcw.flag5 & PMCW5_V) sccbchp->online[chpbyte] |= 0x80 >> chpbit; else sccbchp->standby[chpbyte] |= 0x80 >> chpbit; } #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ #ifdef FEATURE_S370_CHANNEL /* For S/370, initialize identifiers for channel set 0A */ for (i = 0; i < 16; i++) { sccbchp->chanset0a[2*i] = 0x80; sccbchp->chanset0a[2*i+1] = i; } /* end for(i) */ /* Set the channel set configuration byte */ sccbchp->csconfig = 0xC0; #endif /*FEATURE_S370_CHANNEL*/ /* Set response code X'0010' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_INFO; break; case SCLP_READ_CSI_INFO: /* Set the main storage change bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set response code X'0100' if SCCB crosses a page boundary */ if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) != ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK)) { sccb->reas = SCCB_REAS_NOT_PGBNDRY; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Set response code X'0300' if SCCB length is insufficient to contain channel path info */ if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_CSI_INFO)) { sccb->reas = SCCB_REAS_TOO_SHORT; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Point to SCCB data area following SCCB header */ sccbcsi = (SCCB_CSI_INFO*)(sccb+1); memset (sccbcsi, 0, sizeof(SCCB_CSI_INFO)); sccbcsi->csif[0] = 0 #if defined(FEATURE_CANCEL_IO_FACILITY) | SCCB_CSI0_CANCEL_IO_REQUEST_FACILITY #endif /*defined(FEATURE_CANCEL_IO_FACILITY)*/ | SCCB_CSI0_CONCURRENT_SENSE_FACILITY ; /* Set response code X'0010' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_INFO; break; #ifdef FEATURE_SYSTEM_CONSOLE case SCLP_WRITE_EVENT_DATA: /* Set the main storage change bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set response code X'0100' if SCCB crosses a page boundary */ if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) != ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK)) { sccb->reas = SCCB_REAS_NOT_PGBNDRY; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Point to SCCB data area following SCCB header */ evd_hdr = (SCCB_EVD_HDR*)(sccb+1); FETCH_HW(evd_len,evd_hdr->totlen); switch(evd_hdr->type) { case SCCB_EVD_TYPE_MSG: case SCCB_EVD_TYPE_PRIOR: /* Point to the Message Control Data Block */ mcd_bk = (SCCB_MCD_BK*)(evd_hdr+1); FETCH_HW(mcd_len,mcd_bk->length); obj_hdr = (SCCB_OBJ_HDR*)(mcd_bk+1); while (mcd_len > sizeof(SCCB_MCD_BK)) { FETCH_HW(obj_len,obj_hdr->length); if (obj_len == 0) { sccb->reas = SCCB_REAS_BUFF_LEN_ERR; sccb->resp = SCCB_RESP_BUFF_LEN_ERR; break; } FETCH_HW(obj_type,obj_hdr->type); if (obj_type == SCCB_OBJ_TYPE_MESSAGE) { mto_bk = (SCCB_MTO_BK*)(obj_hdr+1); event_msg = (BYTE*)(mto_bk+1); event_msglen = obj_len - (sizeof(SCCB_OBJ_HDR) + sizeof(SCCB_MTO_BK)); if (event_msglen < 0) { sccb->reas = SCCB_REAS_BUFF_LEN_ERR; sccb->resp = SCCB_RESP_BUFF_LEN_ERR; break; } /* Print line unless it is a response prompt */ if (!(mto_bk->ltflag[0] & SCCB_MTO_LTFLG0_PROMPT)) { for (i = 0; i < event_msglen; i++) { message[i] = isprint(guest_to_host(event_msg[i])) ? guest_to_host(event_msg[i]) : 0x20; } message[i] = '\0'; #ifdef OPTION_MSGCLR if(evd_hdr->type == SCCB_EVD_TYPE_MSG) { if(mto_bk->presattr[3] == SCCB_MTO_PRATTR3_HIGH) logmsg("%s\n", message); else logmsg ("%s\n", message); } else logmsg ("%s\n", message); #else logmsg ("%s\n", message); #endif } } mcd_len -= obj_len; obj_hdr=(SCCB_OBJ_HDR *)((BYTE*)obj_hdr + obj_len); } /* Indicate Event Processed */ evd_hdr->flag |= SCCB_EVD_FLAG_PROC; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; break; case SCCB_EVD_TYPE_CPIDENT: sclp_cpident(sccb); break; #if defined(FEATURE_SCEDIO) case SCCB_EVD_TYPE_SCEDIO: ARCH_DEP(sclp_scedio_request)(sccb); break; #endif /*defined(FEATURE_SCEDIO)*/ #if defined(FEATURE_INTEGRATED_3270_CONSOLE) case SCCB_EVD_TYPE_SYSG: sclp_sysg_write(sccb); break; #endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/ #if defined(FEATURE_INTEGRATED_ASCII_CONSOLE) case SCCB_EVD_TYPE_VT220: sclp_sysa_write(sccb); break; #endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/ default: PTT(PTT_CL_ERR,"*SERVC",regs->GR_L(r1),regs->GR_L(r2),evd_hdr->type); if( HDC3(debug_sclp_unknown_event, evd_hdr, sccb, regs) ) break; /* Set response code X'73F0' in SCCB header */ sccb->reas = SCCB_REAS_SYNTAX_ERROR; sccb->resp = SCCB_RESP_SYNTAX_ERROR; break; } break; case SCLP_READ_EVENT_DATA: /* Set the main storage change bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set response code X'0100' if SCCB crosses a page boundary */ if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) != ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK)) { sccb->reas = SCCB_REAS_NOT_PGBNDRY; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Point to SCCB data area following SCCB header */ evd_hdr = (SCCB_EVD_HDR*)(sccb+1); if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_PRIOR) && sclp_attn_pending(SCCB_EVD_TYPE_PRIOR)) { sclp_opcmd_event(sccb, SCCB_EVD_TYPE_PRIOR); break; } if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_OPCMD) && sclp_attn_pending(SCCB_EVD_TYPE_OPCMD)) { sclp_opcmd_event(sccb, SCCB_EVD_TYPE_OPCMD); break; } #if defined(FEATURE_SCEDIO) if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SCEDIO) && sclp_attn_pending(SCCB_EVD_TYPE_SCEDIO)) { ARCH_DEP(sclp_scedio_event)(sccb); break; } #endif /*defined(FEATURE_SCEDIO)*/ #if defined(FEATURE_INTEGRATED_3270_CONSOLE) if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SYSG) && sclp_attn_pending(SCCB_EVD_TYPE_SYSG)) { sclp_sysg_poll(sccb); break; } #endif /*defined(FEATURE_INTEGRATED_3270_CONSOLE)*/ #if defined(FEATURE_INTEGRATED_ASCII_CONSOLE) if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_VT220) && sclp_attn_pending(SCCB_EVD_TYPE_VT220)) { sclp_sysa_poll(sccb); break; } #endif /*defined(FEATURE_INTEGRATED_ASCII_CONSOLE)*/ if(SCLP_RECV_ENABLED(SCCB_EVD_TYPE_SIGQ) && sclp_attn_pending(SCCB_EVD_TYPE_SIGQ)) { sclp_sigq_event(sccb); break; } PTT(PTT_CL_ERR,"*SERVC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); if( HDC3(debug_sclp_event_data, evd_hdr, sccb, regs) ) break; /* Set response code X'62F0' if events are pending but suppressed */ if(sclp_attn_pending(0)) { sccb->reas = SCCB_REAS_EVENTS_SUP; sccb->resp = SCCB_RESP_EVENTS_SUP; break; } else { /* Set response code X'60F0' if no outstanding events */ sccb->reas = SCCB_REAS_NO_EVENTS; sccb->resp = SCCB_RESP_NO_EVENTS; } break; case SCLP_WRITE_EVENT_MASK: /* Set the main storage change bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set response code X'0100' if SCCB crosses a page boundary */ if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) != ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK)) { sccb->reas = SCCB_REAS_NOT_PGBNDRY; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Point to SCCB data area following SCCB header */ evd_mask = (SCCB_EVENT_MASK*)(sccb+1); /* Get length of single mask field */ FETCH_HW(masklen, evd_mask->length); /* Save old mask settings in order to suppress superflous messages */ old_cp_recv_mask = servc_cp_recv_mask & ARCH_DEP(sclp_send_mask) & SCCB_EVENT_CONS_RECV_MASK; old_cp_send_mask = servc_cp_send_mask & ARCH_DEP(sclp_recv_mask) & SCCB_EVENT_CONS_SEND_MASK; for (i = 0; i < 4; i++) { servc_cp_recv_mask <<= 8; servc_cp_send_mask <<= 8; if ((U32)i < masklen) { servc_cp_recv_mask |= evd_mask->masks[i+(0*masklen)]; servc_cp_send_mask |= evd_mask->masks[i+(1*masklen)]; } } if((servc_cp_recv_mask & ~ARCH_DEP(sclp_recv_mask)) || (servc_cp_send_mask & ~ARCH_DEP(sclp_send_mask))) HDC3(debug_sclp_unknown_event_mask, evd_mask, sccb, regs); /* Write the events that we support back */ memset (&evd_mask->masks[2 * masklen], 0, 2 * masklen); for (i = 0; (i < 4) && ((U32)i < masklen); i++) { evd_mask->masks[i+(2*masklen)] |= (ARCH_DEP(sclp_recv_mask) >> ((3-i)*8)) & 0xFF; evd_mask->masks[i+(3*masklen)] |= (ARCH_DEP(sclp_send_mask) >> ((3-i)*8)) & 0xFF; } /* Issue message only when supported mask has changed */ if ((servc_cp_recv_mask & ARCH_DEP(sclp_send_mask) & SCCB_EVENT_CONS_RECV_MASK) != old_cp_recv_mask || (servc_cp_send_mask & ARCH_DEP(sclp_recv_mask) & SCCB_EVENT_CONS_SEND_MASK) != old_cp_send_mask) { if ((servc_cp_recv_mask & SCCB_EVENT_CONS_RECV_MASK) != 0 || (servc_cp_send_mask & SCCB_EVENT_CONS_SEND_MASK) != 0) logmsg (_("HHCCP041I SYSCONS interface active\n")); else logmsg (_("HHCCP042I SYSCONS interface inactive\n")); } /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; break; #endif /*FEATURE_SYSTEM_CONSOLE*/ #ifdef FEATURE_EXPANDED_STORAGE case SCLP_READ_XST_MAP: /* Set the main storage change bit */ STORAGE_KEY(sccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set response code X'0100' if SCCB crosses a page boundary */ if ((sccb_absolute_addr & STORAGE_KEY_PAGEMASK) != ((sccb_absolute_addr + sccblen - 1) & STORAGE_KEY_PAGEMASK)) { sccb->reas = SCCB_REAS_NOT_PGBNDRY; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Calculate number of blocks per increment */ xstblkinc = XSTORE_INCREMENT_SIZE / XSTORE_PAGESIZE; /* Set response code X'0300' if SCCB length is insufficient to contain xstore info */ if ( sccblen < sizeof(SCCB_HEADER) + sizeof(SCCB_XST_MAP) + xstblkinc/8) { sccb->reas = SCCB_REAS_TOO_SHORT; sccb->resp = SCCB_RESP_BLOCK_ERROR; break; } /* Point to SCCB data area following SCCB header */ sccbxmap = (SCCB_XST_MAP*)(sccb+1); /* Verify expanded storage increment number */ xstincnum = sysblk.xpndsize / (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT); FETCH_FW(i, sccbxmap->incnum); if ( i < 1 || (U32)i > xstincnum ) { sccb->reas = SCCB_REAS_INVALID_RSC; sccb->resp = SCCB_RESP_REJECT; break; } /* Point to bitmap */ xstmap = (BYTE*)(sccbxmap+1); /* Set all blocks available */ memset (xstmap, 0x00, xstblkinc/8); /* Set response code X'0010' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_INFO; break; #endif /*FEATURE_EXPANDED_STORAGE*/ #ifdef FEATURE_CPU_RECONFIG case SCLP_CONFIGURE_CPU: i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT; /* Return invalid resource in parm if target does not exist */ if(i >= MAX_CPU) { sccb->reas = SCCB_REAS_INVALID_RSCP; sccb->resp = SCCB_RESP_REJECT; break; } /* Add cpu to the configuration */ configure_cpu(i); /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; break; case SCLP_DECONFIGURE_CPU: i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT; /* Return invalid resource in parm if target does not exist */ if(i >= MAX_CPU) { sccb->reas = SCCB_REAS_INVALID_RSCP; sccb->resp = SCCB_RESP_REJECT; break; } /* Take cpu out of the configuration */ deconfigure_cpu(i); /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; break; #ifdef FEATURE_VECTOR_FACILITY case SCLP_DISCONNECT_VF: i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT; /* Return invalid resource in parm if target does not exist */ if(i >= MAX_CPU || !IS_CPU_ONLINE(i)) { sccb->reas = SCCB_REAS_INVALID_RSCP; sccb->resp = SCCB_RESP_REJECT; break; } if(sysblk.regs[i]->vf->online) logmsg(_("CPU%4.4X: Vector Facility configured offline\n"),i); /* Take the VF out of the configuration */ sysblk.regs[i]->vf->online = 0; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; break; case SCLP_CONNECT_VF: i = (sclp_command & SCLP_RESOURCE_MASK) >> SCLP_RESOURCE_SHIFT; /* Return invalid resource in parm if target does not exist */ if(i >= MAX_CPU) { sccb->reas = SCCB_REAS_INVALID_RSCP; sccb->resp = SCCB_RESP_REJECT; break; } /* Return improper state if associated cpu is offline */ if(!IS_CPU_ONLINE(i)) { sccb->reas = SCCB_REAS_IMPROPER_RSC; sccb->resp = SCCB_RESP_REJECT; break; } if(!sysblk.regs[i]->vf->online) logmsg(_("CPU%4.4X: Vector Facility configured online\n"),i); /* Mark the VF online to the CPU */ sysblk.regs[i]->vf->online = 1; /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; break; #endif /*FEATURE_VECTOR_FACILITY*/ #endif /*FEATURE_CPU_RECONFIG*/ default: invalidcmd: PTT(PTT_CL_INF|PTT_CL_ERR,"*SERVC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); if( HDC3(debug_sclp_unknown_command, sclp_command, sccb, regs) ) break; /* Set response code X'01F0' for invalid SCLP command */ sccb->reas = SCCB_REAS_INVALID_CMD; sccb->resp = SCCB_RESP_REJECT; break; } /* end switch(sclp_command) */ /* If immediate response is requested, return condition code 1 */ if ((sccb->flag & SCCB_FLAG_SYNC) && (sclp_command & SCLP_COMMAND_CLASS) != 0x01) { regs->psw.cc = 1; return; } /* Set service signal external interrupt pending */ sysblk.servparm &= ~SERVSIG_ADDR; sysblk.servparm |= sccb_absolute_addr; ON_IC_SERVSIG; /* Release the interrupt lock */ RELEASE_INTLOCK(regs); /* Set condition code 0 */ regs->psw.cc = 0; } /* end function service_call */ #endif /*defined(FEATURE_SERVICE_PROCESSOR)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "service.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "service.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/scedasd.c0000664000175000017500000006132212564723224011761 00000000000000/* SCEDASD.C (c) Copyright Jan Jaeger, 2001-2009 */ /* Service Control Element DASD I/O functions */ #include "hstdinc.h" #define _HENGINE_DLL_ #include "hercules.h" #include "opcode.h" #if !defined(_SCEDASD_C) #define _SCEDASD_C static TID scedio_tid; /* Thread id of the i/o driver */ static char *sce_basedir = NULL; char *get_sce_dir() { return sce_basedir; } void set_sce_dir(char *path) { char realdir[MAX_PATH]; char tempdir[MAX_PATH]; if(sce_basedir) { free(sce_basedir); sce_basedir = NULL; } if(!path) sce_basedir = NULL; else if(!realpath(path,tempdir)) { logmsg(_("HHCSC011E set_sce_dir: %s: %s\n"),path,strerror(errno)); sce_basedir = NULL; } else { hostpath(realdir, tempdir, sizeof(realdir)); strlcat(realdir,"/",sizeof(realdir)); sce_basedir = strdup(realdir); } } static char *set_sce_basedir(char *path) { char *basedir; char realdir[MAX_PATH]; char tempdir[MAX_PATH]; if(sce_basedir) { free(sce_basedir); sce_basedir = NULL; } if(!realpath(path,tempdir)) { logmsg(_("HHCSC012E set_sce_basedir: %s: %s\n"),path,strerror(errno)); sce_basedir = NULL; return NULL; } hostpath(realdir, tempdir, sizeof(realdir)); if((basedir = strrchr(realdir,'/'))) { *(++basedir) = '\0'; sce_basedir = strdup(realdir); return (basedir = strrchr(path,'/')) ? ++basedir : path; } else { sce_basedir = NULL; return path; } } static char *check_sce_filepath(const char *path, char *fullpath) { char temppath[MAX_PATH]; char tempreal[MAX_PATH]; /* Return file access error if no basedir has been set */ if(!sce_basedir) { strlcpy(fullpath,path,sizeof(temppath)); errno = EACCES; return NULL; } /* Establish the full path of the file we are trying to access */ strlcpy(temppath,sce_basedir,sizeof(temppath)); strlcat(temppath,path,sizeof(temppath)); if(!realpath(temppath,tempreal)) { hostpath(fullpath, tempreal, sizeof(temppath)); if(strncmp( sce_basedir, fullpath, strlen(sce_basedir))) errno = EACCES; return NULL; } hostpath(fullpath, tempreal, sizeof(temppath)); if(strncmp( sce_basedir, fullpath, strlen(sce_basedir))) { errno = EACCES; return NULL; } return fullpath; } #endif /* !defined(_SCEDASD_C) */ /*-------------------------------------------------------------------*/ /* function load_hmc simulates the load from the service processor */ /* the filename pointed to is a descriptor file which has the */ /* following format: */ /* */ /* '*' in col 1 is comment */ /* core image file followed by address where it should be loaded */ /* */ /* For example: */ /* */ /* * Linux/390 cdrom boot image */ /* boot_images/tapeipl.ikr 0x00000000 */ /* boot_images/initrd 0x00800000 */ /* boot_images/parmfile 0x00010480 */ /* */ /* The location of the image files is relative to the location of */ /* the descriptor file. Jan Jaeger 10-11-01 */ /* */ /*-------------------------------------------------------------------*/ int ARCH_DEP(load_hmc) (char *fname, int cpu, int clear) { REGS *regs; /* -> Regs */ FILE *fp; char inputbuff[MAX_PATH]; char *inputline; char filename[MAX_PATH]; /* filename of image file */ char pathname[MAX_PATH]; /* pathname of image file */ U32 fileaddr; int rc = 0; /* Return codes (work) */ /* Get started */ if (ARCH_DEP(common_load_begin) (cpu, clear) != 0) return -1; /* The actual IPL proper starts here... */ regs = sysblk.regs[cpu]; /* Point to IPL CPU's registers */ if(fname == NULL) /* Default ipl from DASD */ fname = "HERCULES.ins"; /* from HERCULES.ins */ hostpath(pathname, fname, sizeof(pathname)); if(!(fname = set_sce_basedir(pathname))) return -1; /* Construct and check full pathname */ if(!check_sce_filepath(fname,filename)) { logmsg(_("HHCSC001E Load from %s failed: %s\n"),fname,strerror(errno)); return -1; } fp = fopen(filename, "r"); if(fp == NULL) { logmsg(_("HHCSC002E Load from %s failed: %s\n"),fname,strerror(errno)); return -1; } do { inputline = fgets(inputbuff,sizeof(inputbuff),fp); #if !defined(_MSVC_) if(inputline && *inputline == 0x1a) inputline = NULL; #endif /*!defined(_MSVC_)*/ if(inputline) { rc = sscanf(inputline,"%" MSTRING(MAX_PATH) "s %i",filename,&fileaddr); } /* If no load address was found load to location zero */ if(inputline && rc < 2) fileaddr = 0; if(inputline && rc > 0 && *filename != '*' && *filename != '#') { hostpath(pathname, filename, sizeof(pathname)); /* Construct and check full pathname */ if(!check_sce_filepath(pathname,filename)) { logmsg(_("HHCSC003E Load from %s failed: %s\n"),pathname,strerror(errno)); return -1; } if( ARCH_DEP(load_main) (filename, fileaddr) < 0 ) { fclose(fp); HDC1(debug_cpu_state, regs); return -1; } sysblk.main_clear = sysblk.xpnd_clear = 0; } } while(inputline); fclose(fp); /* Finish up... */ return ARCH_DEP(common_load_finish) (regs); } /* end function load_hmc */ /*-------------------------------------------------------------------*/ /* Function to Load (read) specified file into absolute main storage */ /*-------------------------------------------------------------------*/ int ARCH_DEP(load_main) (char *fname, RADR startloc) { int fd; int len; int rc = 0; RADR pageaddr; U32 pagesize; fd = hopen(fname, O_RDONLY|O_BINARY); if (fd < 0) { if(errno != ENOENT) logmsg(_("HHCSC031E load_main: %s: %s\n"), fname, strerror(errno)); return fd; } pagesize = PAGEFRAME_PAGESIZE - (startloc & PAGEFRAME_BYTEMASK); pageaddr = startloc; for( ; ; ) { if (pageaddr >= sysblk.mainsize) { logmsg(_("HHCSC032W load_main: terminated at end of mainstor\n")); close(fd); return rc; } len = read(fd, sysblk.mainstor + pageaddr, pagesize); if (len > 0) { STORAGE_KEY(pageaddr, &sysblk) |= STORKEY_REF|STORKEY_CHANGE; rc += len; } if (len < (int)pagesize) { close(fd); return rc; } pageaddr += PAGEFRAME_PAGESIZE; pageaddr &= PAGEFRAME_PAGEMASK; pagesize = PAGEFRAME_PAGESIZE; } } /* end function load_main */ #if defined(FEATURE_SCEDIO) /*-------------------------------------------------------------------*/ /* Function to write to a file on the service processor disk */ /*-------------------------------------------------------------------*/ static S64 ARCH_DEP(write_file)(char *fname, int mode, CREG sto, S64 size) { int fd, nwrite; U64 totwrite = 0; fd = hopen(fname, mode |O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (fd < 0) { logmsg (_("HHCSC041E %s open error: %s\n"), fname, strerror(errno)); return -1; } #if defined(FEATURE_ESAME) sto &= ASCE_TO; #else /*!defined(FEATURE_ESAME)*/ sto &= STD_STO; #endif /*!defined(FEATURE_ESAME)*/ for( ; size > 0 ; sto += sizeof(sto)) { #if defined(FEATURE_ESAME) DBLWRD *ste; #else /*!defined(FEATURE_ESAME)*/ FWORD *ste; #endif /*!defined(FEATURE_ESAME)*/ CREG pto, pti; /* Fetch segment table entry and calc Page Table Origin */ if( sto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) ste = (DBLWRD*)(sysblk.mainstor + sto); #else /*!defined(FEATURE_ESAME)*/ ste = (FWORD*)(sysblk.mainstor + sto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pto, ste); STORAGE_KEY(sto, &sysblk) |= (STORKEY_REF); if( pto & SEGTAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pto &= ZSEGTAB_PTO; #else /*!defined(FEATURE_ESAME)*/ pto &= SEGTAB_PTO; #endif /*!defined(FEATURE_ESAME)*/ for(pti = 0; pti < 256 && size > 0; pti++, pto += sizeof(pto)) { #if defined(FEATURE_ESAME) DBLWRD *pte; #else /*!defined(FEATURE_ESAME)*/ FWORD *pte; #endif /*!defined(FEATURE_ESAME)*/ CREG pgo; BYTE *page; /* Fetch Page Table Entry to get page origin */ if( pto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) pte = (DBLWRD*)(sysblk.mainstor + pto); #else /*!defined(FEATURE_ESAME)*/ pte = (FWORD*)(sysblk.mainstor + pto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pgo, pte); STORAGE_KEY(pto, &sysblk) |= (STORKEY_REF); if( !(pgo & PAGETAB_INVALID) ) { #if defined(FEATURE_ESAME) pgo &= ZPGETAB_PFRA; #else /*!defined(FEATURE_ESAME)*/ pgo &= PAGETAB_PFRA; #endif /*!defined(FEATURE_ESAME)*/ /* Write page to SCE disk */ if( pgo >= sysblk.mainsize) goto eof; page = sysblk.mainstor + pgo; nwrite = write(fd, page, STORAGE_KEY_PAGESIZE); totwrite += nwrite; if( nwrite != STORAGE_KEY_PAGESIZE ) goto eof; STORAGE_KEY(pgo, &sysblk) |= (STORKEY_REF); } size -= STORAGE_KEY_PAGESIZE; } } eof: close(fd); return totwrite; } /*-------------------------------------------------------------------*/ /* Function to read from a file on the service processor disk */ /*-------------------------------------------------------------------*/ static S64 ARCH_DEP(read_file)(char *fname, CREG sto, S64 seek, S64 size) { int fd, nread; U64 totread = 0; fd = hopen(fname, O_RDONLY|O_BINARY); if (fd < 0) { if(errno != ENOENT) logmsg (_("HHCSC051E %s open error: %s\n"), fname, strerror(errno)); return -1; } if(lseek(fd, (off_t)seek, SEEK_SET) == (off_t)seek) { #if defined(FEATURE_ESAME) sto &= ASCE_TO; #else /*!defined(FEATURE_ESAME)*/ sto &= STD_STO; #endif /*!defined(FEATURE_ESAME)*/ for( ; size > 0 ; sto += sizeof(sto)) { #if defined(FEATURE_ESAME) DBLWRD *ste; #else /*!defined(FEATURE_ESAME)*/ FWORD *ste; #endif /*!defined(FEATURE_ESAME)*/ CREG pto, pti; /* Fetch segment table entry and calc Page Table Origin */ if( sto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) ste = (DBLWRD*)(sysblk.mainstor + sto); #else /*!defined(FEATURE_ESAME)*/ ste = (FWORD*)(sysblk.mainstor + sto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pto, ste); STORAGE_KEY(sto, &sysblk) |= (STORKEY_REF); if( pto & SEGTAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pto &= ZSEGTAB_PTO; #else /*!defined(FEATURE_ESAME)*/ pto &= SEGTAB_PTO; #endif /*!defined(FEATURE_ESAME)*/ for(pti = 0; pti < 256 && size > 0; pti++, pto += sizeof(pto)) { #if defined(FEATURE_ESAME) DBLWRD *pte; #else /*!defined(FEATURE_ESAME)*/ FWORD *pte; #endif /*!defined(FEATURE_ESAME)*/ CREG pgo; BYTE *page; /* Fetch Page Table Entry to get page origin */ if( pto >= sysblk.mainsize) goto eof; #if defined(FEATURE_ESAME) pte = (DBLWRD*)(sysblk.mainstor + pto); #else /*!defined(FEATURE_ESAME)*/ pte = (FWORD*)(sysblk.mainstor + pto); #endif /*!defined(FEATURE_ESAME)*/ FETCH_W(pgo, pte); STORAGE_KEY(pto, &sysblk) |= (STORKEY_REF); if( pgo & PAGETAB_INVALID ) goto eof; #if defined(FEATURE_ESAME) pgo &= ZPGETAB_PFRA; #else /*!defined(FEATURE_ESAME)*/ pgo &= PAGETAB_PFRA; #endif /*!defined(FEATURE_ESAME)*/ /* Read page into main storage */ if( pgo >= sysblk.mainsize) goto eof; page = sysblk.mainstor + pgo; nread = read(fd, page, STORAGE_KEY_PAGESIZE); totread += nread; size -= nread; if( nread != STORAGE_KEY_PAGESIZE ) goto eof; STORAGE_KEY(pgo, &sysblk) |= (STORKEY_REF|STORKEY_CHANGE); } } } eof: close(fd); return totread; } static int ARCH_DEP(scedio_ior)(SCCB_SCEDIOR_BK *scedior_bk) { U32 origin; char image[9]; S32 size; unsigned int i; char filename[MAX_PATH]; FETCH_FW(origin,scedior_bk->origin); /* Convert image filename to null terminated ascii string */ for(i = 0; i < sizeof(image)-1 && scedior_bk->image[i] != 0x40; i++) image[i] = guest_to_host((int)scedior_bk->image[i]); image[i] = '\0'; /* Ensure file access is allowed and within specified directory */ if(!check_sce_filepath(image,filename)) { if(errno != ENOENT) logmsg (_("HHCSC101E access error: %s: %s\n"), image, strerror(errno)); return FALSE; } size = ARCH_DEP(load_main)(filename,origin); return (size >= 0) ? TRUE : FALSE; } static int ARCH_DEP(scedio_iov)(SCCB_SCEDIOV_BK *scediov_bk) { S64 seek; S64 length; S64 totread, totwrite; U64 sto; char fname[MAX_PATH]; switch(scediov_bk->type) { case SCCB_SCEDIOV_TYPE_INIT: return TRUE; break; case SCCB_SCEDIOV_TYPE_READ: /* Ensure file access is allowed and within specified directory */ if(!check_sce_filepath((char*)scediov_bk->filename,fname)) { if(errno != ENOENT) logmsg (_("HHCSC201E access error: %s: %s\n"), fname, strerror(errno)); return FALSE; } FETCH_DW(sto,scediov_bk->sto); FETCH_DW(seek,scediov_bk->seek); FETCH_DW(length,scediov_bk->length); totread = ARCH_DEP(read_file)(fname, sto, seek, length); if(totread > 0) { STORE_DW(scediov_bk->length,totread); if(totread == length) STORE_DW(scediov_bk->ncomp,0); else STORE_DW(scediov_bk->ncomp,seek+totread); return TRUE; } else return FALSE; break; case SCCB_SCEDIOV_TYPE_CREATE: case SCCB_SCEDIOV_TYPE_APPEND: /* Ensure file access is allowed and within specified directory */ if(!check_sce_filepath((char*)scediov_bk->filename,fname)) { if(errno != ENOENT) logmsg (_("HHCSC202I access error: %s: %s\n"), fname, strerror(errno)); /* A file not found error may be expected for a create request */ if(!(errno == ENOENT && scediov_bk->type == SCCB_SCEDIOV_TYPE_CREATE)) return FALSE; } FETCH_DW(sto,scediov_bk->sto); FETCH_DW(seek,scediov_bk->seek); FETCH_DW(length,scediov_bk->length); totwrite = ARCH_DEP(write_file)(fname, ((scediov_bk->type == SCCB_SCEDIOV_TYPE_CREATE) ? (O_CREAT|O_TRUNC) : O_APPEND), sto, length); if(totwrite >= 0) { STORE_DW(scediov_bk->ncomp,totwrite); return TRUE; } else return FALSE; break; default: PTT(PTT_CL_ERR,"*SERVC",(U32)scediov_bk->type,(U32)scediov_bk->flag1,scediov_bk->flag2); return FALSE; } } /*-------------------------------------------------------------------*/ /* Thread to perform service processor I/O functions */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(scedio_thread)(SCCB_SCEDIO_BK *scedio_bk) { SCCB_SCEDIOV_BK *scediov_bk; SCCB_SCEDIOR_BK *scedior_bk; switch(scedio_bk->flag1) { case SCCB_SCEDIO_FLG1_IOV: scediov_bk = (SCCB_SCEDIOV_BK*)(scedio_bk + 1); if( ARCH_DEP(scedio_iov)(scediov_bk) ) scedio_bk->flag3 |= SCCB_SCEDIO_FLG3_COMPLETE; else scedio_bk->flag3 &= ~SCCB_SCEDIO_FLG3_COMPLETE; break; case SCCB_SCEDIO_FLG1_IOR: scedior_bk = (SCCB_SCEDIOR_BK*)(scedio_bk + 1); if( ARCH_DEP(scedio_ior)(scedior_bk) ) scedio_bk->flag3 |= SCCB_SCEDIO_FLG3_COMPLETE; else scedio_bk->flag3 &= ~SCCB_SCEDIO_FLG3_COMPLETE; break; default: PTT(PTT_CL_ERR,"*SERVC",(U32)scedio_bk->flag0,(U32)scedio_bk->flag1,scedio_bk->flag3); } OBTAIN_INTLOCK(NULL); while(IS_IC_SERVSIG) { RELEASE_INTLOCK(NULL); sched_yield(); OBTAIN_INTLOCK(NULL); } sclp_attention(SCCB_EVD_TYPE_SCEDIO); scedio_tid = 0; RELEASE_INTLOCK(NULL); } /*-------------------------------------------------------------------*/ /* Function to interface with the service processor I/O thread */ /*-------------------------------------------------------------------*/ static int ARCH_DEP(scedio_request)(U32 sclp_command, SCCB_EVD_HDR *evd_hdr) { SCCB_SCEDIO_BK *scedio_bk = (SCCB_SCEDIO_BK*)(evd_hdr + 1); SCCB_SCEDIOV_BK *scediov_bk; SCCB_SCEDIOR_BK *scedior_bk; static struct { SCCB_SCEDIO_BK scedio_bk; union { SCCB_SCEDIOV_BK v; SCCB_SCEDIOR_BK r; } io; } static_scedio_bk ; static int scedio_pending; if(sclp_command == SCLP_READ_EVENT_DATA) { int pending_req = scedio_pending; U16 evd_len; /* Return no data if the scedio thread is still active */ if(scedio_tid) return 0; /* Update the scedio_bk copy in the SCCB */ if(scedio_pending) { /* Zero all fields */ memset (evd_hdr, 0, sizeof(SCCB_EVD_HDR)); /* Set type in event header */ evd_hdr->type = SCCB_EVD_TYPE_SCEDIO; /* Store scedio header */ *scedio_bk = static_scedio_bk.scedio_bk; /* Calculate event response length */ evd_len = sizeof(SCCB_EVD_HDR) + sizeof(SCCB_SCEDIO_BK); switch(scedio_bk->flag1) { case SCCB_SCEDIO_FLG1_IOR: scedior_bk = (SCCB_SCEDIOR_BK*)(scedio_bk + 1); *scedior_bk = static_scedio_bk.io.r; evd_len += sizeof(SCCB_SCEDIOR_BK); break; case SCCB_SCEDIO_FLG1_IOV: scediov_bk = (SCCB_SCEDIOV_BK*)(scedio_bk + 1); *scediov_bk = static_scedio_bk.io.v ; evd_len += sizeof(SCCB_SCEDIOV_BK); break; default: PTT(PTT_CL_ERR,"*SERVC",(U32)evd_hdr->type,(U32)scedio_bk->flag1,scedio_bk->flag3); } /* Set length in event header */ STORE_HW(evd_hdr->totlen, evd_len); } /* Reset the pending flag */ scedio_pending = 0; /* Return true if a request was pending */ return pending_req; } else { #if !defined(NO_SIGABEND_HANDLER) switch(scedio_bk->flag1) { case SCCB_SCEDIO_FLG1_IOV: scediov_bk = (SCCB_SCEDIOV_BK*)(scedio_bk + 1); switch(scediov_bk->type) { case SCCB_SCEDIOV_TYPE_INIT: /* Kill the scedio thread if it is active */ if( scedio_tid ) { OBTAIN_INTLOCK(NULL); signal_thread(scedio_tid, SIGKILL); scedio_tid = 0; scedio_pending = 0; RELEASE_INTLOCK(NULL); } break; } break; } #endif /* Take a copy of the scedio_bk in the SCCB */ static_scedio_bk.scedio_bk = *scedio_bk; switch(scedio_bk->flag1) { case SCCB_SCEDIO_FLG1_IOR: scedior_bk = (SCCB_SCEDIOR_BK*)(scedio_bk + 1); static_scedio_bk.io.r = *scedior_bk; break; case SCCB_SCEDIO_FLG1_IOV: scediov_bk = (SCCB_SCEDIOV_BK*)(scedio_bk + 1); static_scedio_bk.io.v = *scediov_bk; break; default: PTT(PTT_CL_ERR,"*SERVC",(U32)evd_hdr->type,(U32)scedio_bk->flag1,scedio_bk->flag3); } /* Create the scedio thread */ if( create_thread(&scedio_tid, &sysblk.detattr, ARCH_DEP(scedio_thread), &static_scedio_bk, "scedio_thread") ) return -1; scedio_pending = 1; } return 0; } /*-------------------------------------------------------------------*/ /* Function to request service processor I/O */ /*-------------------------------------------------------------------*/ void ARCH_DEP(sclp_scedio_request) (SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb + 1); if( ARCH_DEP(scedio_request)(SCLP_WRITE_EVENT_DATA, evd_hdr) ) { /* Set response code X'0040' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_BACKOUT; } else { /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } /* Indicate Event Processed */ evd_hdr->flag |= SCCB_EVD_FLAG_PROC; } /*-------------------------------------------------------------------*/ /* Function to read service processor I/O event data */ /*-------------------------------------------------------------------*/ void ARCH_DEP(sclp_scedio_event) (SCCB_HEADER *sccb) { SCCB_EVD_HDR *evd_hdr = (SCCB_EVD_HDR*)(sccb + 1); U16 sccb_len; U16 evd_len; if( ARCH_DEP(scedio_request)(SCLP_READ_EVENT_DATA, evd_hdr) ) { /* Update SCCB length field if variable request */ if (sccb->type & SCCB_TYPE_VARIABLE) { FETCH_HW(evd_len, evd_hdr->totlen); sccb_len = evd_len + sizeof(SCCB_HEADER); STORE_HW(sccb->length, sccb_len); sccb->type &= ~SCCB_TYPE_VARIABLE; } /* Set response code X'0020' in SCCB header */ sccb->reas = SCCB_REAS_NONE; sccb->resp = SCCB_RESP_COMPLETE; } } #endif /*defined(FEATURE_SCEDIO)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "scedasd.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "scedasd.c" #endif /*-------------------------------------------------------------------*/ /* Service Processor Load (load/ipl from the specified file) */ /*-------------------------------------------------------------------*/ int load_hmc (char *fname, int cpu, int clear) { switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: return s370_load_hmc (fname, cpu, clear); #endif #if defined(_390) case ARCH_390: return s390_load_hmc (fname, cpu, clear); #endif #if defined(_900) case ARCH_900: /* z/Arch always starts out in ESA390 mode */ return s390_load_hmc (fname, cpu, clear); #endif } return -1; } /*-------------------------------------------------------------------*/ /* Load/Read specified file into absolute main storage */ /*-------------------------------------------------------------------*/ int load_main (char *fname, RADR startloc) { switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: return s370_load_main (fname, startloc); #endif #if defined(_390) case ARCH_390: return s390_load_main (fname, startloc); #endif #if defined(_900) case ARCH_900: return z900_load_main (fname, startloc); #endif } return -1; } #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/losc.c0000664000175000017500000000422612564723224011313 00000000000000/* LOSC.C (c) Copyright Jan Jaeger, 2009 */ /* Hercules Licensed Operating System Check */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_LOSC_C_) #define _LOSC_C_ #endif #include "hercules.h" #ifdef OPTION_MSGCLR #define KEEPMSG "" #else #define KEEPMSG "" #endif static char *licensed_os[] = { "MVS", /* Generic name for MVS, OS/390, z/OS */ "VM", /* Generic name for VM, VM/XA, VM/ESA, z/VM */ "VSE", "TPF", NULL }; static int os_licensed = 0; static int check_done = 0; void losc_set (int license_status) { os_licensed = license_status; check_done = 0; } void losc_check(char *ostype) { char **lictype; int i; CPU_BITMAP mask; if(check_done) return; else check_done = 1; for(lictype = licensed_os; *lictype; lictype++) { if(!strncasecmp(ostype, *lictype, strlen(*lictype))) { if(os_licensed == PGM_PRD_OS_LICENSED) { logmsg(_( KEEPMSG "HHCCF039W PGMPRDOS LICENSED specified.\n" KEEPMSG " A licensed program product operating system is running.\n" KEEPMSG " You are responsible for meeting all conditions of your\n" KEEPMSG " software licenses.\n")); } else { logmsg(_( KEEPMSG "HHCCF079A A licensed program product operating system has been\n" KEEPMSG " detected. All processors have been stopped.\n")); mask = sysblk.started_mask; for (i = 0; mask; i++) { if (mask & 1) { REGS *regs = sysblk.regs[i]; regs->opinterv = 1; regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); signal_condition(®s->intcond); } mask >>= 1; } } } } } hercules-3.12/chsc.c0000664000175000017500000001635112564723224011275 00000000000000/* CHSC.C (c) Copyright Jan Jaeger, 2002-2009 */ /* Channel Subsystem Call */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements channel subsystem interface functions */ /* for the Hercules ESA/390 emulator. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_CHSC_C_) #define _CHSC_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "chsc.h" #if defined(FEATURE_CHSC) int ARCH_DEP(chsc_get_sch_desc) (CHSC_REQ *chsc_req, CHSC_RSP *chsc_rsp) { U16 req_len, sch, f_sch, l_sch, rsp_len; CHSC_REQ4 *chsc_req4 = (CHSC_REQ4 *)(chsc_req); CHSC_RSP4 *chsc_rsp4 = (CHSC_RSP4 *)(chsc_rsp); #if 0 { U16 resv1, resv2, resv3; FETCH_HW(resv1,chsc_req4->resv1); FETCH_HW(resv2,chsc_req4->resv2); FETCH_HW(resv3,chsc_req4->resv3); logmsg(D_("chsc_get_sch_desc: resv1=%4.4X resv2=%4.4X resv3=%4.4X\n"),resv1,resv2,resv3); } #endif FETCH_HW(f_sch,chsc_req4->f_sch); FETCH_HW(l_sch,chsc_req4->l_sch); /* Fetch length of request field */ FETCH_HW(req_len, chsc_req4->length); rsp_len = sizeof(CHSC_RSP) + ((1 + l_sch - f_sch) * sizeof(CHSC_RSP4)); if(l_sch < f_sch || rsp_len > (0x1000 - req_len)) { /* Set response field length */ STORE_HW(chsc_rsp->length,sizeof(CHSC_RSP)); /* Store request error */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_ERRREQ); /* No reaon code */ STORE_FW(chsc_rsp->info,0); return 0; } for(sch = f_sch; sch <= l_sch; sch++, chsc_rsp4++) { DEVBLK *dev; memset(chsc_rsp4, 0x00, sizeof(CHSC_RSP4) ); // ZZ FIXME: Dunno how to put the proper lcss id in here... if((dev = find_device_by_subchan(0x00010000|sch))) { chsc_rsp4->sch_val = 1; if(dev->pmcw.flag5 & PMCW5_V) chsc_rsp4->dev_val = 1; chsc_rsp4->st = (dev->pmcw.flag25 & PMCW25_TYPE) >> 5; chsc_rsp4->unit_addr = dev->devnum & 0xff; STORE_HW(chsc_rsp4->devno,dev->devnum); chsc_rsp4->path_mask = dev->pmcw.pim; STORE_HW(chsc_rsp4->sch, sch); memcpy(chsc_rsp4->chpid, dev->pmcw.chpid, 8); } } /* Store response length */ STORE_HW(chsc_rsp->length,rsp_len); /* Store request OK */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_OK); /* No reaon code */ STORE_FW(chsc_rsp->info,0); return 0; } int ARCH_DEP(chsc_get_css_info) (CHSC_REQ *chsc_req, CHSC_RSP *chsc_rsp) { CHSC_RSP10 *chsc_rsp10; U16 req_len, rsp_len; UNREFERENCED(chsc_req); chsc_rsp10 = (CHSC_RSP10 *)(chsc_rsp + 1); /* Fetch length of request field */ FETCH_HW(req_len, chsc_req->length); rsp_len = sizeof(CHSC_RSP) + sizeof(CHSC_RSP10); if(rsp_len > (0x1000 - req_len)) { /* Set response field length */ STORE_HW(chsc_rsp->length,sizeof(CHSC_RSP)); /* Store request error */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_ERRREQ); /* No reaon code */ STORE_FW(chsc_rsp->info,0); return 0; } STORE_HW(chsc_rsp->length,rsp_len); memset(chsc_rsp10->general_char, 0x00, sizeof(chsc_rsp10->general_char)); memset(chsc_rsp10->chsc_char, 0x00, sizeof(chsc_rsp10->chsc_char)); chsc_rsp10->general_char[0][0] = 0 #if defined(FEATURE_REGION_RELOCATE) | 0x24 #endif #if defined(FEATURE_CANCEL_IO_FACILITY) | 0x02 #endif ; #if defined(FEATURE_QUEUED_DIRECT_IO) chsc_rsp10->general_char[1][1] = 0 | 0x40 /* Adapter Interruption Facility */ ; chsc_rsp10->chsc_char[3][1] = 0 | 0x10 /* Set Channel Subsystem Char */ | 0x08 /* Fast CHSCs */ ; chsc_rsp10->general_char[2][0] = 0 // | 0x10 /* OSA/FCP Thin interrupts */ ; chsc_rsp10->general_char[1][3] = 0 // | 0x80 /* AIF Time Delay Disablement Fac */ ; #endif /*defined(FEATURE_QUEUED_DIRECT_IO)*/ /* Store request OK */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_OK); /* No reaon code */ STORE_FW(chsc_rsp->info,0); return 0; } /*-------------------------------------------------------------------*/ /* B25F CHSC - Channel Subsystem Call [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(channel_subsystem_call) { int r1, r2; /* register values */ VADR n; /* Unsigned work */ BYTE *mn; /* Unsigned work */ U16 req_len; /* Length of request */ U16 req; /* Request code */ CHSC_REQ *chsc_req; /* Request structure */ CHSC_RSP *chsc_rsp; /* Response structure*/ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_INF,"CHSC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); n = regs->GR(r1) & ADDRESS_MAXWRAP(regs); if(n & 0xFFF) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); mn = MADDR(n, r1, regs, ACCTYPE_READ, regs->psw.pkey); chsc_req = (CHSC_REQ*)(mn); /* Fetch length of request field */ FETCH_HW(req_len, chsc_req->length); chsc_rsp = (CHSC_RSP*)((BYTE*)chsc_req + req_len); if((req_len < sizeof(CHSC_REQ)) || (req_len > (0x1000 - sizeof(CHSC_RSP)))) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); FETCH_HW(req,chsc_req->req); ARCH_DEP(validate_operand) (n, r1, 0, ACCTYPE_WRITE, regs); switch(req) { case CHSC_REQ_SCHDESC: regs->psw.cc = ARCH_DEP(chsc_get_sch_desc) (chsc_req, chsc_rsp); break; #if 0 case CHSC_REQ_CSSINFO: regs->psw.cc = ARCH_DEP(chsc_get_css_info) (chsc_req, chsc_rsp); break; #endif default: PTT(PTT_CL_ERR,"*CHSC",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); if( HDC3(debug_chsc_unknown_request, chsc_rsp, chsc_req, regs) ) break; /* Set response field length */ STORE_HW(chsc_rsp->length,sizeof(CHSC_RSP)); /* Store unsupported command code */ STORE_HW(chsc_rsp->rsp,CHSC_REQ_INVALID); /* No reaon code */ STORE_FW(chsc_rsp->info,0); regs->psw.cc = 0; } } #endif /*defined(FEATURE_CHSC)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "chsc.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "chsc.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/opcode.c0000664000175000017500000076143412564723224011637 00000000000000/* OPCODE.C (c) Copyright Jan Jaeger, 2000-2010 */ /* (c) Copyright TurboHercules, SAS 2010 */ /* Instruction decoding functions */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_OPCODE_C_) #define _OPCODE_C_ #endif #include "feature.h" #if !defined(_GEN_ARCH) #if defined(_ARCHMODE3) #define _GEN_ARCH _ARCHMODE3 #include "opcode.c" #undef _GEN_ARCH #endif #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "opcode.c" #undef _GEN_ARCH #endif #endif /*!defined(_GEN_ARCH)*/ #include "hercules.h" #include "opcode.h" #define UNDEF_INST(_x) \ DEF_INST(_x) { ARCH_DEP(operation_exception) \ (inst,regs); } #if !defined(FEATURE_CHANNEL_SUBSYSTEM) UNDEF_INST(clear_subchannel) UNDEF_INST(halt_subchannel) UNDEF_INST(modify_subchannel) UNDEF_INST(reset_channel_path) UNDEF_INST(resume_subchannel) UNDEF_INST(set_address_limit) UNDEF_INST(set_channel_monitor) UNDEF_INST(start_subchannel) UNDEF_INST(store_channel_path_status) UNDEF_INST(store_channel_report_word) UNDEF_INST(store_subchannel) UNDEF_INST(test_pending_interruption) UNDEF_INST(test_subchannel) #endif /*!defined(FEATURE_CHANNEL_SUBSYSTEM)*/ #if !defined(FEATURE_S370_CHANNEL) UNDEF_INST(start_io) UNDEF_INST(test_io) UNDEF_INST(halt_io) UNDEF_INST(test_channel) UNDEF_INST(store_channel_id) #endif /*!defined(FEATURE_S370_CHANNEL)*/ #if !defined(FEATURE_IMMEDIATE_AND_RELATIVE) UNDEF_INST(test_under_mask_high) UNDEF_INST(test_under_mask_low) UNDEF_INST(branch_relative_on_condition) UNDEF_INST(branch_relative_and_save) UNDEF_INST(branch_relative_on_count) UNDEF_INST(load_halfword_immediate) UNDEF_INST(add_halfword_immediate) UNDEF_INST(multiply_halfword_immediate) UNDEF_INST(compare_halfword_immediate) UNDEF_INST(multiply_single_register) UNDEF_INST(multiply_single) UNDEF_INST(branch_relative_on_index_high) UNDEF_INST(branch_relative_on_index_low_or_equal) #endif /*!defined(FEATURE_IMMEDIATE_AND_RELATIVE)*/ #if !defined(FEATURE_STRING_INSTRUCTION) UNDEF_INST(compare_logical_string) UNDEF_INST(compare_until_substring_equal) UNDEF_INST(move_string) UNDEF_INST(search_string) #endif /*!defined(FEATURE_STRING_INSTRUCTION)*/ #if !defined(FEATURE_COMPARE_AND_MOVE_EXTENDED) UNDEF_INST(compare_logical_long_extended) UNDEF_INST(move_long_extended) #endif /*!defined(FEATURE_COMPARE_AND_MOVE_EXTENDED)*/ #if !defined(FEATURE_CHECKSUM_INSTRUCTION) UNDEF_INST(checksum) #endif /*!defined(FEATURE_CHECKSUM_INSTRUCTION)*/ #if !defined(FEATURE_PERFORM_LOCKED_OPERATION) UNDEF_INST(perform_locked_operation) #endif /*!defined(FEATURE_PERFORM_LOCKED_OPERATION)*/ #if !defined(FEATURE_SUBSPACE_GROUP) UNDEF_INST(branch_in_subspace_group) #endif /*!defined(FEATURE_SUBSPACE_GROUP)*/ #if !defined(FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST) UNDEF_INST(set_address_space_control_fast) #else /*!defined(FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST)*/ #define s390_set_address_space_control_fast s390_set_address_space_control #define z900_set_address_space_control_fast z900_set_address_space_control #endif /*!defined(FEATURE_SET_ADDRESS_SPACE_CONTROL_FAST)*/ #if !defined(FEATURE_BRANCH_AND_SET_AUTHORITY) UNDEF_INST(branch_and_set_authority) #endif /*!defined(FEATURE_BRANCH_AND_SET_AUTHORITY)*/ #if !defined(FEATURE_EXPANDED_STORAGE) UNDEF_INST(page_in) UNDEF_INST(page_out) #endif /*!defined(FEATURE_EXPANDED_STORAGE)*/ #if !defined(FEATURE_BROADCASTED_PURGING) UNDEF_INST(compare_and_swap_and_purge) #endif /*!defined(FEATURE_BROADCASTED_PURGING)*/ #if !defined(FEATURE_BIMODAL_ADDRESSING) UNDEF_INST(branch_and_set_mode) UNDEF_INST(branch_and_save_and_set_mode) #endif /*!defined(FEATURE_BIMODAL_ADDRESSING)*/ #if !defined(FEATURE_MOVE_PAGE_FACILITY_2) UNDEF_INST(move_page) UNDEF_INST(invalidate_expanded_storage_block_entry) #endif /*!defined(FEATURE_MOVE_PAGE_FACILITY_2)*/ #if !defined(FEATURE_BASIC_STORAGE_KEYS) UNDEF_INST(insert_storage_key) UNDEF_INST(set_storage_key) UNDEF_INST(reset_reference_bit) #endif /*!defined(FEATURE_BASIC_STORAGE_KEYS)*/ #if !defined(FEATURE_LINKAGE_STACK) UNDEF_INST(branch_and_stack) UNDEF_INST(modify_stacked_state) UNDEF_INST(extract_stacked_registers) UNDEF_INST(extract_stacked_state) UNDEF_INST(program_return) UNDEF_INST(trap2) UNDEF_INST(trap4) #endif /*!defined(FEATURE_LINKAGE_STACK)*/ #if !defined(FEATURE_DUAL_ADDRESS_SPACE) UNDEF_INST(extract_primary_asn) UNDEF_INST(extract_secondary_asn) UNDEF_INST(insert_address_space_control) UNDEF_INST(insert_virtual_storage_key) UNDEF_INST(load_address_space_parameters) UNDEF_INST(move_to_primary) UNDEF_INST(move_to_secondary) UNDEF_INST(move_with_key) UNDEF_INST(program_call) UNDEF_INST(program_transfer) UNDEF_INST(set_address_space_control) UNDEF_INST(set_secondary_asn) #endif /*!defined(FEATURE_DUAL_ADDRESS_SPACE)*/ #if !defined(FEATURE_ASN_AND_LX_REUSE) UNDEF_INST(extract_primary_asn_and_instance) UNDEF_INST(extract_secondary_asn_and_instance) UNDEF_INST(program_transfer_with_instance) UNDEF_INST(set_secondary_asn_with_instance) #endif /*!defined(FEATURE_ASN_AND_LX_REUSE)*/ #if !defined(FEATURE_ACCESS_REGISTERS) UNDEF_INST(load_access_multiple) UNDEF_INST(store_access_multiple) UNDEF_INST(purge_accesslist_lookaside_buffer) UNDEF_INST(test_access) UNDEF_INST(copy_access) UNDEF_INST(set_access_register) UNDEF_INST(extract_access_register) #endif /*!defined(FEATURE_ACCESS_REGISTERS)*/ #if !defined(FEATURE_EXTENDED_STORAGE_KEYS) UNDEF_INST(insert_storage_key_extended) UNDEF_INST(reset_reference_bit_extended) UNDEF_INST(set_storage_key_extended) #endif /*!defined(FEATURE_EXTENDED_STORAGE_KEYS)*/ #if !defined(FEATURE_TOD_CLOCK_STEERING) UNDEF_INST(perform_timing_facility_function) #endif #if !defined(FEATURE_EXTENDED_TOD_CLOCK) UNDEF_INST(set_clock_programmable_field) UNDEF_INST(store_clock_extended) #endif /*!defined(FEATURE_EXTENDED_TOD_CLOCK)*/ #if !defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS) UNDEF_INST(move_with_optional_specifications) #endif /*!defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS)*/ #if !defined(FEATURE_EXTRACT_CPU_TIME) UNDEF_INST(extract_cpu_time) #endif /*!defined(FEATURE_EXTRACT_CPU_TIME)*/ #if !defined(FEATURE_COMPARE_AND_SWAP_AND_STORE) UNDEF_INST(compare_and_swap_and_store) #endif /*!defined(FEATURE_COMPARE_AND_SWAP_AND_STORE)*/ #if !defined(FEATURE_STORE_SYSTEM_INFORMATION) UNDEF_INST(store_system_information) #endif /*!defined(FEATURE_STORE_SYSTEM_INFORMATION)*/ #if !defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) /*208*/ UNDEF_INST(perform_topology_function) /*208*/ #endif /*!defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ /*208*/ #if !defined(FEATURE_ENHANCED_DAT_FACILITY) /*208*/ UNDEF_INST(perform_frame_management_function) /*208*/ #endif /*!defined(FEATURE_ENHANCED_DAT_FACILITY)*/ /*208*/ #if !defined(FEATURE_ENHANCED_DAT_FACILITY_2) /*912*/ UNDEF_INST(compare_and_replace_dat_table_entry) /*912*/ #endif /*!defined(FEATURE_ENHANCED_DAT_FACILITY_2)*/ /*912*/ #if !defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) /*208*/ UNDEF_INST(execute_relative_long) /*208*/ #endif /*!defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/ /*208*/ #if !defined(FEATURE_EXECUTION_HINT_FACILITY) /*912*/ UNDEF_INST(branch_prediction_preload) /*912*/ UNDEF_INST(branch_prediction_relative_preload) /*912*/ UNDEF_INST(next_instruction_access_intent) /*912*/ #endif /*!defined(FEATURE_EXECUTION_HINT_FACILITY)*/ /*912*/ #if !defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY) /*208*/ UNDEF_INST(add_immediate_long_storage) UNDEF_INST(add_immediate_storage) UNDEF_INST(add_logical_with_signed_immediate) UNDEF_INST(add_logical_with_signed_immediate_long) UNDEF_INST(compare_and_branch_register) UNDEF_INST(compare_and_branch_long_register) UNDEF_INST(compare_and_branch_relative_register) UNDEF_INST(compare_and_branch_relative_long_register) UNDEF_INST(compare_and_trap_long_register) UNDEF_INST(compare_and_trap_register) UNDEF_INST(compare_halfword_immediate_halfword_storage) UNDEF_INST(compare_halfword_immediate_long_storage) UNDEF_INST(compare_halfword_immediate_storage) UNDEF_INST(compare_halfword_long) UNDEF_INST(compare_halfword_relative_long) UNDEF_INST(compare_halfword_relative_long_long) UNDEF_INST(compare_immediate_and_branch) UNDEF_INST(compare_immediate_and_branch_long) UNDEF_INST(compare_immediate_and_branch_relative) UNDEF_INST(compare_immediate_and_branch_relative_long) UNDEF_INST(compare_immediate_and_trap) UNDEF_INST(compare_immediate_and_trap_long) UNDEF_INST(compare_logical_and_branch_long_register) UNDEF_INST(compare_logical_and_branch_register) UNDEF_INST(compare_logical_and_branch_relative_long_register) UNDEF_INST(compare_logical_and_branch_relative_register) UNDEF_INST(compare_logical_and_trap_long_register) UNDEF_INST(compare_logical_and_trap_register) UNDEF_INST(compare_logical_immediate_and_branch) UNDEF_INST(compare_logical_immediate_and_branch_long) UNDEF_INST(compare_logical_immediate_and_branch_relative) UNDEF_INST(compare_logical_immediate_and_branch_relative_long) UNDEF_INST(compare_logical_immediate_and_trap_fullword) UNDEF_INST(compare_logical_immediate_and_trap_long) UNDEF_INST(compare_logical_immediate_fullword_storage) UNDEF_INST(compare_logical_immediate_halfword_storage) UNDEF_INST(compare_logical_immediate_long_storage) UNDEF_INST(compare_logical_relative_long) UNDEF_INST(compare_logical_relative_long_halfword) UNDEF_INST(compare_logical_relative_long_long) UNDEF_INST(compare_logical_relative_long_long_fullword) UNDEF_INST(compare_logical_relative_long_long_halfword) UNDEF_INST(compare_relative_long) UNDEF_INST(compare_relative_long_long) UNDEF_INST(compare_relative_long_long_fullword) UNDEF_INST(extract_cache_attribute) UNDEF_INST(load_address_extended_y) UNDEF_INST(load_and_test_long_fullword) UNDEF_INST(load_halfword_relative_long) UNDEF_INST(load_halfword_relative_long_long) UNDEF_INST(load_logical_halfword_relative_long) UNDEF_INST(load_logical_halfword_relative_long_long) UNDEF_INST(load_logical_relative_long_long_fullword) UNDEF_INST(load_relative_long) UNDEF_INST(load_relative_long_long) UNDEF_INST(load_relative_long_long_fullword) UNDEF_INST(move_fullword_from_halfword_immediate) UNDEF_INST(move_halfword_from_halfword_immediate) UNDEF_INST(move_long_from_halfword_immediate) UNDEF_INST(multiply_halfword_y) UNDEF_INST(multiply_single_immediate_fullword) UNDEF_INST(multiply_single_immediate_long_fullword) UNDEF_INST(multiply_y) UNDEF_INST(prefetch_data) UNDEF_INST(prefetch_data_relative_long) UNDEF_INST(rotate_then_and_selected_bits_long_reg) UNDEF_INST(rotate_then_exclusive_or_selected_bits_long_reg) UNDEF_INST(rotate_then_insert_selected_bits_long_reg) UNDEF_INST(rotate_then_or_selected_bits_long_reg) UNDEF_INST(store_halfword_relative_long) UNDEF_INST(store_relative_long) UNDEF_INST(store_relative_long_long) #endif /*!defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY)*/ /*208*/ #if !defined(FEATURE_PARSING_ENHANCEMENT_FACILITY) /*208*/ UNDEF_INST(translate_and_test_extended) /*208*/ UNDEF_INST(translate_and_test_reverse_extended) /*208*/ #endif /*!defined(FEATURE_PARSING_ENHANCEMENT_FACILITY)*/ /*208*/ #if !defined(FEATURE_HIGH_WORD_FACILITY) /*810*/ UNDEF_INST(add_high_high_high_register) /*810*/ UNDEF_INST(add_high_high_low_register) /*810*/ UNDEF_INST(add_high_immediate) /*810*/ UNDEF_INST(add_logical_high_high_high_register) /*810*/ UNDEF_INST(add_logical_high_high_low_register) /*810*/ UNDEF_INST(add_logical_with_signed_immediate_high) /*810*/ UNDEF_INST(add_logical_with_signed_immediate_high_n) /*810*/ UNDEF_INST(branch_relative_on_count_high) /*810*/ UNDEF_INST(compare_high_high_register) /*810*/ UNDEF_INST(compare_high_low_register) /*810*/ UNDEF_INST(compare_high_fullword) /*810*/ UNDEF_INST(compare_high_immediate) /*810*/ UNDEF_INST(compare_logical_high_high_register) /*810*/ UNDEF_INST(compare_logical_high_low_register) /*810*/ UNDEF_INST(compare_logical_high_fullword) /*810*/ UNDEF_INST(compare_logical_high_immediate) /*810*/ UNDEF_INST(load_byte_high) /*810*/ UNDEF_INST(load_fullword_high) /*810*/ UNDEF_INST(load_halfword_high) /*810*/ UNDEF_INST(load_logical_character_high) /*810*/ UNDEF_INST(load_logical_halfword_high) /*810*/ UNDEF_INST(rotate_then_insert_selected_bits_high_long_reg) /*810*/ UNDEF_INST(rotate_then_insert_selected_bits_low_long_reg) /*810*/ UNDEF_INST(store_character_high) /*810*/ UNDEF_INST(store_fullword_high) /*810*/ UNDEF_INST(store_halfword_high) /*810*/ UNDEF_INST(subtract_high_high_high_register) /*810*/ UNDEF_INST(subtract_high_high_low_register) /*810*/ UNDEF_INST(subtract_logical_high_high_high_register) /*810*/ UNDEF_INST(subtract_logical_high_high_low_register) /*810*/ #endif /*!defined(FEATURE_HIGH_WORD_FACILITY)*/ /*810*/ #if !defined(FEATURE_INTERLOCKED_ACCESS_FACILITY) /*810*/ UNDEF_INST(load_and_add) /*810*/ UNDEF_INST(load_and_add_long) /*810*/ UNDEF_INST(load_and_add_logical) /*810*/ UNDEF_INST(load_and_add_logical_long) /*810*/ UNDEF_INST(load_and_and) /*810*/ UNDEF_INST(load_and_and_long) /*810*/ UNDEF_INST(load_and_exclusive_or) /*810*/ UNDEF_INST(load_and_exclusive_or_long) /*810*/ UNDEF_INST(load_and_or) /*810*/ UNDEF_INST(load_and_or_long) /*810*/ UNDEF_INST(load_pair_disjoint) /*810*/ UNDEF_INST(load_pair_disjoint_long) /*810*/ #endif /*!defined(FEATURE_INTERLOCKED_ACCESS_FACILITY)*/ /*810*/ #if !defined(FEATURE_LOAD_STORE_ON_CONDITION_FACILITY) /*810*/ UNDEF_INST(load_on_condition_register) /*810*/ UNDEF_INST(load_on_condition_long_register) /*810*/ UNDEF_INST(load_on_condition) /*810*/ UNDEF_INST(load_on_condition_long) /*810*/ UNDEF_INST(store_on_condition) /*810*/ UNDEF_INST(store_on_condition_long) /*810*/ #endif /*!defined(FEATURE_LOAD_STORE_ON_CONDITION_FACILITY)*/ /*810*/ #if !defined(FEATURE_DISTINCT_OPERANDS_FACILITY) /*810*/ UNDEF_INST(add_distinct_register) /*810*/ UNDEF_INST(add_distinct_long_register) /*810*/ UNDEF_INST(add_distinct_halfword_immediate) /*810*/ UNDEF_INST(add_distinct_long_halfword_immediate) /*810*/ UNDEF_INST(add_logical_distinct_register) /*810*/ UNDEF_INST(add_logical_distinct_long_register) /*810*/ UNDEF_INST(add_logical_distinct_signed_halfword_immediate) /*810*/ UNDEF_INST(add_logical_distinct_long_signed_halfword_immediate)/*810*/ UNDEF_INST(and_distinct_register) /*810*/ UNDEF_INST(and_distinct_long_register) /*810*/ UNDEF_INST(exclusive_or_distinct_register) /*810*/ UNDEF_INST(exclusive_or_distinct_long_register) /*810*/ UNDEF_INST(or_distinct_register) /*810*/ UNDEF_INST(or_distinct_long_register) /*810*/ UNDEF_INST(shift_left_single_distinct) /*810*/ UNDEF_INST(shift_left_single_logical_distinct) /*810*/ UNDEF_INST(shift_right_single_distinct) /*810*/ UNDEF_INST(shift_right_single_logical_distinct) /*810*/ UNDEF_INST(subtract_distinct_register) /*810*/ UNDEF_INST(subtract_distinct_long_register) /*810*/ UNDEF_INST(subtract_logical_distinct_register) /*810*/ UNDEF_INST(subtract_logical_distinct_long_register) /*810*/ #endif /*!defined(FEATURE_DISTINCT_OPERANDS_FACILITY)*/ /*810*/ #if !defined(FEATURE_POPULATION_COUNT_FACILITY) /*810*/ UNDEF_INST(population_count) /*810*/ #endif /*!defined(FEATURE_POPULATION_COUNT_FACILITY)*/ /*810*/ #if !defined(FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY) /*810*/ UNDEF_INST(reset_reference_bits_multiple) /*810*/ #endif /*!defined(FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY)*/ #if !defined(FEATURE_LOAD_AND_TRAP_FACILITY) /*912*/ UNDEF_INST(load_and_trap) /*912*/ UNDEF_INST(load_long_and_trap) /*912*/ UNDEF_INST(load_fullword_high_and_trap) /*912*/ UNDEF_INST(load_logical_long_fullword_and_trap) /*912*/ UNDEF_INST(load_logical_long_thirtyone_and_trap) /*912*/ #endif /*!defined(FEATURE_LOAD_AND_TRAP_FACILITY)*/ /*912*/ #if !defined(FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY) /*912*/ UNDEF_INST(compare_logical_and_trap) /*912*/ UNDEF_INST(compare_logical_and_trap_long) /*912*/ UNDEF_INST(rotate_then_insert_selected_bits_long_reg_n) /*912*/ #endif /*!defined(FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY)*/ #if !defined(FEATURE_VECTOR_FACILITY) UNDEF_INST(execute_a4xx) #if !defined(FEATURE_ESAME) && !defined(FEATURE_ESAME_N3_ESA390) UNDEF_INST(execute_a5xx) #endif /*!defined(FEATURE_ESAME) && !defined(FEATURE_ESAME_N3_ESA390)*/ UNDEF_INST(execute_a6xx) UNDEF_INST(execute_e4xx) UNDEF_INST(v_test_vmr) UNDEF_INST(v_complement_vmr) UNDEF_INST(v_count_left_zeros_in_vmr) UNDEF_INST(v_count_ones_in_vmr) UNDEF_INST(v_extract_vct) UNDEF_INST(v_extract_vector_modes) UNDEF_INST(v_restore_vr) UNDEF_INST(v_save_changed_vr) UNDEF_INST(v_save_vr) UNDEF_INST(v_load_vmr) UNDEF_INST(v_load_vmr_complement) UNDEF_INST(v_store_vmr) UNDEF_INST(v_and_to_vmr) UNDEF_INST(v_or_to_vmr) UNDEF_INST(v_exclusive_or_to_vmr) UNDEF_INST(v_save_vsr) UNDEF_INST(v_save_vmr) UNDEF_INST(v_restore_vsr) UNDEF_INST(v_restore_vmr) UNDEF_INST(v_load_vct_from_address) UNDEF_INST(v_clear_vr) UNDEF_INST(v_set_vector_mask_mode) UNDEF_INST(v_load_vix_from_address) UNDEF_INST(v_store_vector_parameters) UNDEF_INST(v_save_vac) UNDEF_INST(v_restore_vac) #endif /*!defined(FEATURE_VECTOR_FACILITY)*/ #if !defined(FEATURE_ESAME) && !defined(FEATURE_ESAME_N3_ESA390) UNDEF_INST(execute_e3xx) UNDEF_INST(execute_ecxx) UNDEF_INST(execute_c0xx) UNDEF_INST(execute_c2xx) /*@Z9*/ #endif /*!defined(FEATURE_ESAME) && !defined(FEATURE_ESAME_N3_ESA390)*/ #if !defined(FEATURE_ESAME) UNDEF_INST(execute_c8xx) #endif /*!defined(FEATURE_ESAME)*/ #if !defined(FEATURE_BASIC_FP_EXTENSIONS) UNDEF_INST(execute_b3xx) UNDEF_INST(execute_edxx) #endif /*!defined(FEATURE_BASIC_FP_EXTENSIONS)*/ #if !defined(FEATURE_HEXADECIMAL_FLOATING_POINT) UNDEF_INST(load_positive_float_long_reg) UNDEF_INST(load_negative_float_long_reg) UNDEF_INST(load_and_test_float_long_reg) UNDEF_INST(load_complement_float_long_reg) UNDEF_INST(halve_float_long_reg) UNDEF_INST(load_rounded_float_long_reg) UNDEF_INST(multiply_float_ext_reg) UNDEF_INST(multiply_float_long_to_ext_reg) UNDEF_INST(load_float_long_reg) UNDEF_INST(compare_float_long_reg) UNDEF_INST(add_float_long_reg) UNDEF_INST(subtract_float_long_reg) UNDEF_INST(multiply_float_long_reg) UNDEF_INST(divide_float_long_reg) UNDEF_INST(add_unnormal_float_long_reg) UNDEF_INST(subtract_unnormal_float_long_reg) UNDEF_INST(load_positive_float_short_reg) UNDEF_INST(load_negative_float_short_reg) UNDEF_INST(load_and_test_float_short_reg) UNDEF_INST(load_complement_float_short_reg) UNDEF_INST(halve_float_short_reg) UNDEF_INST(load_rounded_float_short_reg) UNDEF_INST(add_float_ext_reg) UNDEF_INST(subtract_float_ext_reg) UNDEF_INST(load_float_short_reg) UNDEF_INST(compare_float_short_reg) UNDEF_INST(add_float_short_reg) UNDEF_INST(subtract_float_short_reg) UNDEF_INST(multiply_float_short_to_long_reg) UNDEF_INST(divide_float_short_reg) UNDEF_INST(add_unnormal_float_short_reg) UNDEF_INST(subtract_unnormal_float_short_reg) UNDEF_INST(store_float_long) UNDEF_INST(multiply_float_long_to_ext) UNDEF_INST(load_float_long) UNDEF_INST(compare_float_long) UNDEF_INST(add_float_long) UNDEF_INST(subtract_float_long) UNDEF_INST(multiply_float_long) UNDEF_INST(divide_float_long) UNDEF_INST(add_unnormal_float_long) UNDEF_INST(subtract_unnormal_float_long) UNDEF_INST(store_float_short) UNDEF_INST(load_float_short) UNDEF_INST(compare_float_short) UNDEF_INST(add_float_short) UNDEF_INST(subtract_float_short) UNDEF_INST(multiply_float_short_to_long) UNDEF_INST(divide_float_short) UNDEF_INST(add_unnormal_float_short) UNDEF_INST(subtract_unnormal_float_short) UNDEF_INST(divide_float_ext_reg) #endif /*!defined(FEATURE_HEXADECIMAL_FLOATING_POINT)*/ #if !defined(FEATURE_HFP_EXTENSIONS) UNDEF_INST(load_lengthened_float_short_to_long_reg) UNDEF_INST(load_lengthened_float_long_to_ext_reg) UNDEF_INST(load_lengthened_float_short_to_ext_reg) UNDEF_INST(squareroot_float_ext_reg) UNDEF_INST(multiply_float_short_reg) UNDEF_INST(load_positive_float_ext_reg) UNDEF_INST(load_negative_float_ext_reg) UNDEF_INST(load_and_test_float_ext_reg) UNDEF_INST(load_complement_float_ext_reg) UNDEF_INST(load_rounded_float_ext_to_short_reg) UNDEF_INST(load_fp_int_float_ext_reg) UNDEF_INST(compare_float_ext_reg) UNDEF_INST(load_fp_int_float_short_reg) UNDEF_INST(load_fp_int_float_long_reg) UNDEF_INST(convert_fixed_to_float_short_reg) UNDEF_INST(convert_fixed_to_float_long_reg) UNDEF_INST(convert_fixed_to_float_ext_reg) UNDEF_INST(convert_float_short_to_fixed_reg) UNDEF_INST(convert_float_long_to_fixed_reg) UNDEF_INST(convert_float_ext_to_fixed_reg) UNDEF_INST(load_lengthened_float_short_to_long) UNDEF_INST(load_lengthened_float_long_to_ext) UNDEF_INST(load_lengthened_float_short_to_ext) UNDEF_INST(squareroot_float_short) UNDEF_INST(squareroot_float_long) UNDEF_INST(multiply_float_short) #endif /*!defined(FEATURE_HFP_EXTENSIONS)*/ #if !defined(FEATURE_FPS_EXTENSIONS) UNDEF_INST(convert_bfp_long_to_float_long_reg) UNDEF_INST(convert_bfp_short_to_float_long_reg) UNDEF_INST(convert_float_long_to_bfp_long_reg) UNDEF_INST(convert_float_long_to_bfp_short_reg) UNDEF_INST(load_float_ext_reg) UNDEF_INST(load_zero_float_ext_reg) UNDEF_INST(load_zero_float_long_reg) UNDEF_INST(load_zero_float_short_reg) #endif /*!defined(FEATURE_FPS_EXTENSIONS)*/ #if !defined(FEATURE_FPS_ENHANCEMENT) UNDEF_INST(copy_sign_fpr_long_reg) UNDEF_INST(load_complement_fpr_long_reg) UNDEF_INST(load_fpr_from_gr_long_reg) UNDEF_INST(load_gr_from_fpr_long_reg) UNDEF_INST(load_negative_fpr_long_reg) UNDEF_INST(load_positive_fpr_long_reg) UNDEF_INST(set_dfp_rounding_mode) #endif /*!defined(FEATURE_FPS_ENHANCEMENT)*/ #if !defined(FEATURE_IEEE_EXCEPTION_SIMULATION) UNDEF_INST(load_fpc_and_signal) UNDEF_INST(set_fpc_and_signal) #endif /*!defined(FEATURE_IEEE_EXCEPTION_SIMULATION)*/ #if !defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT) UNDEF_INST(multiply_add_float_short_reg) UNDEF_INST(multiply_add_float_long_reg) UNDEF_INST(multiply_add_float_short) UNDEF_INST(multiply_add_float_long) UNDEF_INST(multiply_subtract_float_short_reg) UNDEF_INST(multiply_subtract_float_long_reg) UNDEF_INST(multiply_subtract_float_short) UNDEF_INST(multiply_subtract_float_long) #endif /*!defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT)*/ #if !defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) /*@Z9*/ UNDEF_INST(multiply_unnormal_float_long_to_ext_reg) /*@Z9*/ UNDEF_INST(multiply_unnormal_float_long_to_ext_low_reg) /*@Z9*/ UNDEF_INST(multiply_unnormal_float_long_to_ext_high_reg) /*@Z9*/ UNDEF_INST(multiply_add_unnormal_float_long_to_ext_reg) /*@Z9*/ UNDEF_INST(multiply_add_unnormal_float_long_to_ext_low_reg) /*@Z9*/ UNDEF_INST(multiply_add_unnormal_float_long_to_ext_high_reg) /*@Z9*/ UNDEF_INST(multiply_unnormal_float_long_to_ext) /*@Z9*/ UNDEF_INST(multiply_unnormal_float_long_to_ext_low) /*@Z9*/ UNDEF_INST(multiply_unnormal_float_long_to_ext_high) /*@Z9*/ UNDEF_INST(multiply_add_unnormal_float_long_to_ext) /*@Z9*/ UNDEF_INST(multiply_add_unnormal_float_long_to_ext_low) /*@Z9*/ UNDEF_INST(multiply_add_unnormal_float_long_to_ext_high) /*@Z9*/ #endif /*!defined(FEATURE_HFP_UNNORMALIZED_EXTENSION)*/ /*@Z9*/ #if !defined(FEATURE_BINARY_FLOATING_POINT) UNDEF_INST(store_fpc) UNDEF_INST(load_fpc) UNDEF_INST(set_fpc) UNDEF_INST(extract_fpc) UNDEF_INST(set_bfp_rounding_mode_2bit) #endif /*!defined(FEATURE_BINARY_FLOATING_POINT)*/ #if !defined(FEATURE_BINARY_FLOATING_POINT) UNDEF_INST(add_bfp_ext_reg) UNDEF_INST(add_bfp_long) UNDEF_INST(add_bfp_long_reg) UNDEF_INST(add_bfp_short) UNDEF_INST(add_bfp_short_reg) UNDEF_INST(compare_and_signal_bfp_ext_reg) UNDEF_INST(compare_and_signal_bfp_long) UNDEF_INST(compare_and_signal_bfp_long_reg) UNDEF_INST(compare_and_signal_bfp_short) UNDEF_INST(compare_and_signal_bfp_short_reg) UNDEF_INST(compare_bfp_ext_reg) UNDEF_INST(compare_bfp_long) UNDEF_INST(compare_bfp_long_reg) UNDEF_INST(compare_bfp_short) UNDEF_INST(compare_bfp_short_reg) UNDEF_INST(convert_bfp_ext_to_fix32_reg) UNDEF_INST(convert_bfp_long_to_fix32_reg) UNDEF_INST(convert_bfp_short_to_fix32_reg) UNDEF_INST(convert_fix32_to_bfp_ext_reg) UNDEF_INST(convert_fix32_to_bfp_long_reg) UNDEF_INST(convert_fix32_to_bfp_short_reg) UNDEF_INST(convert_fix64_to_bfp_ext_reg) UNDEF_INST(convert_fix64_to_bfp_long_reg) UNDEF_INST(convert_fix64_to_bfp_short_reg) UNDEF_INST(convert_bfp_ext_to_fix64_reg) UNDEF_INST(convert_bfp_long_to_fix64_reg) UNDEF_INST(convert_bfp_short_to_fix64_reg) UNDEF_INST(divide_bfp_ext_reg) UNDEF_INST(divide_bfp_long) UNDEF_INST(divide_bfp_long_reg) UNDEF_INST(divide_bfp_short) UNDEF_INST(divide_bfp_short_reg) UNDEF_INST(divide_integer_bfp_long_reg) UNDEF_INST(divide_integer_bfp_short_reg) UNDEF_INST(load_and_test_bfp_ext_reg) UNDEF_INST(load_and_test_bfp_long_reg) UNDEF_INST(load_and_test_bfp_short_reg) UNDEF_INST(load_fp_int_bfp_ext_reg) UNDEF_INST(load_fp_int_bfp_long_reg) UNDEF_INST(load_fp_int_bfp_short_reg) UNDEF_INST(load_complement_bfp_ext_reg) UNDEF_INST(load_complement_bfp_long_reg) UNDEF_INST(load_complement_bfp_short_reg) UNDEF_INST(load_negative_bfp_ext_reg) UNDEF_INST(load_negative_bfp_long_reg) UNDEF_INST(load_negative_bfp_short_reg) UNDEF_INST(load_positive_bfp_ext_reg) UNDEF_INST(load_positive_bfp_long_reg) UNDEF_INST(load_positive_bfp_short_reg) UNDEF_INST(load_lengthened_bfp_short_to_long) UNDEF_INST(load_lengthened_bfp_short_to_long_reg) UNDEF_INST(load_lengthened_bfp_long_to_ext) UNDEF_INST(load_lengthened_bfp_long_to_ext_reg) UNDEF_INST(load_lengthened_bfp_short_to_ext) UNDEF_INST(load_lengthened_bfp_short_to_ext_reg) UNDEF_INST(load_rounded_bfp_long_to_short_reg) UNDEF_INST(load_rounded_bfp_ext_to_long_reg) UNDEF_INST(load_rounded_bfp_ext_to_short_reg) UNDEF_INST(multiply_bfp_ext_reg) UNDEF_INST(multiply_bfp_long_to_ext_reg) UNDEF_INST(multiply_bfp_long_to_ext) UNDEF_INST(multiply_bfp_long) UNDEF_INST(multiply_bfp_long_reg) UNDEF_INST(multiply_bfp_short_to_long_reg) UNDEF_INST(multiply_bfp_short_to_long) UNDEF_INST(multiply_bfp_short) UNDEF_INST(multiply_bfp_short_reg) UNDEF_INST(multiply_add_bfp_long_reg) UNDEF_INST(multiply_add_bfp_long) UNDEF_INST(multiply_add_bfp_short_reg) UNDEF_INST(multiply_add_bfp_short) UNDEF_INST(multiply_subtract_bfp_long_reg) UNDEF_INST(multiply_subtract_bfp_long) UNDEF_INST(multiply_subtract_bfp_short_reg) UNDEF_INST(multiply_subtract_bfp_short) UNDEF_INST(squareroot_bfp_ext_reg) UNDEF_INST(squareroot_bfp_long) UNDEF_INST(squareroot_bfp_long_reg) UNDEF_INST(squareroot_bfp_short) UNDEF_INST(squareroot_bfp_short_reg) UNDEF_INST(subtract_bfp_ext_reg) UNDEF_INST(subtract_bfp_long) UNDEF_INST(subtract_bfp_long_reg) UNDEF_INST(subtract_bfp_short) UNDEF_INST(subtract_bfp_short_reg) UNDEF_INST(test_data_class_bfp_short) UNDEF_INST(test_data_class_bfp_long) UNDEF_INST(test_data_class_bfp_ext) #endif /*!defined(FEATURE_BINARY_FLOATING_POINT)*/ #if !defined(FEATURE_DECIMAL_FLOATING_POINT) UNDEF_INST(add_dfp_ext_reg) UNDEF_INST(add_dfp_long_reg) UNDEF_INST(compare_dfp_ext_reg) UNDEF_INST(compare_dfp_long_reg) UNDEF_INST(compare_and_signal_dfp_ext_reg) UNDEF_INST(compare_and_signal_dfp_long_reg) UNDEF_INST(compare_exponent_dfp_ext_reg) UNDEF_INST(compare_exponent_dfp_long_reg) UNDEF_INST(convert_fix64_to_dfp_ext_reg) UNDEF_INST(convert_fix64_to_dfp_long_reg) UNDEF_INST(convert_sbcd128_to_dfp_ext_reg) UNDEF_INST(convert_sbcd64_to_dfp_long_reg) UNDEF_INST(convert_ubcd128_to_dfp_ext_reg) UNDEF_INST(convert_ubcd64_to_dfp_long_reg) UNDEF_INST(convert_dfp_ext_to_fix64_reg) UNDEF_INST(convert_dfp_long_to_fix64_reg) UNDEF_INST(convert_dfp_ext_to_sbcd128_reg) UNDEF_INST(convert_dfp_long_to_sbcd64_reg) UNDEF_INST(convert_dfp_ext_to_ubcd128_reg) UNDEF_INST(convert_dfp_long_to_ubcd64_reg) UNDEF_INST(divide_dfp_ext_reg) UNDEF_INST(divide_dfp_long_reg) UNDEF_INST(extract_biased_exponent_dfp_ext_to_fix64_reg) UNDEF_INST(extract_biased_exponent_dfp_long_to_fix64_reg) UNDEF_INST(extract_significance_dfp_ext_reg) UNDEF_INST(extract_significance_dfp_long_reg) UNDEF_INST(insert_biased_exponent_fix64_to_dfp_ext_reg) UNDEF_INST(insert_biased_exponent_fix64_to_dfp_long_reg) UNDEF_INST(load_and_test_dfp_ext_reg) UNDEF_INST(load_and_test_dfp_long_reg) UNDEF_INST(load_fp_int_dfp_ext_reg) UNDEF_INST(load_fp_int_dfp_long_reg) UNDEF_INST(load_lengthened_dfp_long_to_ext_reg) UNDEF_INST(load_lengthened_dfp_short_to_long_reg) UNDEF_INST(load_rounded_dfp_ext_to_long_reg) UNDEF_INST(load_rounded_dfp_long_to_short_reg) UNDEF_INST(multiply_dfp_ext_reg) UNDEF_INST(multiply_dfp_long_reg) UNDEF_INST(quantize_dfp_ext_reg) UNDEF_INST(quantize_dfp_long_reg) UNDEF_INST(reround_dfp_ext_reg) UNDEF_INST(reround_dfp_long_reg) UNDEF_INST(shift_coefficient_left_dfp_ext) UNDEF_INST(shift_coefficient_left_dfp_long) UNDEF_INST(shift_coefficient_right_dfp_ext) UNDEF_INST(shift_coefficient_right_dfp_long) UNDEF_INST(subtract_dfp_ext_reg) UNDEF_INST(subtract_dfp_long_reg) UNDEF_INST(test_data_class_dfp_ext) UNDEF_INST(test_data_class_dfp_long) UNDEF_INST(test_data_class_dfp_short) UNDEF_INST(test_data_group_dfp_ext) UNDEF_INST(test_data_group_dfp_long) UNDEF_INST(test_data_group_dfp_short) #endif /*!defined(FEATURE_DECIMAL_FLOATING_POINT)*/ #if !defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY) /*912*/ UNDEF_INST(convert_zoned_to_dfp_long) /*912*/ UNDEF_INST(convert_zoned_to_dfp_ext) /*912*/ UNDEF_INST(convert_dfp_long_to_zoned) /*912*/ UNDEF_INST(convert_dfp_ext_to_zoned) /*912*/ #endif /*!defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY)*/ /*912*/ #if !defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ UNDEF_INST(convert_bfp_short_to_u32_reg) /*810*/ UNDEF_INST(convert_bfp_long_to_u32_reg) /*810*/ UNDEF_INST(convert_bfp_ext_to_u32_reg) /*810*/ UNDEF_INST(convert_bfp_short_to_u64_reg) /*810*/ UNDEF_INST(convert_bfp_long_to_u64_reg) /*810*/ UNDEF_INST(convert_bfp_ext_to_u64_reg) /*810*/ UNDEF_INST(convert_u32_to_bfp_short_reg) /*810*/ UNDEF_INST(convert_u32_to_bfp_long_reg) /*810*/ UNDEF_INST(convert_u32_to_bfp_ext_reg) /*810*/ UNDEF_INST(convert_u64_to_bfp_short_reg) /*810*/ UNDEF_INST(convert_u64_to_bfp_long_reg) /*810*/ UNDEF_INST(convert_u64_to_bfp_ext_reg) /*810*/ UNDEF_INST(convert_dfp_long_to_fix32_reg) /*810*/ UNDEF_INST(convert_dfp_long_to_u32_reg) /*810*/ UNDEF_INST(convert_dfp_long_to_u64_reg) /*810*/ UNDEF_INST(convert_dfp_ext_to_fix32_reg) /*810*/ UNDEF_INST(convert_dfp_ext_to_u32_reg) /*810*/ UNDEF_INST(convert_dfp_ext_to_u64_reg) /*810*/ UNDEF_INST(convert_fix32_to_dfp_long_reg) /*810*/ UNDEF_INST(convert_fix32_to_dfp_ext_reg) /*810*/ UNDEF_INST(convert_u32_to_dfp_long_reg) /*810*/ UNDEF_INST(convert_u32_to_dfp_ext_reg) /*810*/ UNDEF_INST(convert_u64_to_dfp_long_reg) /*810*/ UNDEF_INST(convert_u64_to_dfp_ext_reg) /*810*/ UNDEF_INST(set_bfp_rounding_mode_3bit) /*810*/ #endif /*!defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ #if !defined(FEATURE_PFPO) UNDEF_INST(perform_floating_point_operation) #endif /*!defined(FEATURE_PFPO)*/ #if !defined(FEATURE_EMULATE_VM) UNDEF_INST(inter_user_communication_vehicle) #endif /*!defined(FEATURE_EMULATE_VM)*/ #if !defined(FEATURE_RESUME_PROGRAM) UNDEF_INST(resume_program) #endif /*!defined(FEATURE_RESUME_PROGRAM)*/ #if !defined(FEATURE_COMPRESSION) UNDEF_INST(compression_call) #endif /*!defined(FEATURE_COMPRESSION)*/ #if !defined(FEATURE_LOCK_PAGE) UNDEF_INST(lock_page) #endif /*!defined(FEATURE_LOCK_PAGE)*/ #if !defined(FEATURE_SQUARE_ROOT) UNDEF_INST(squareroot_float_long_reg) UNDEF_INST(squareroot_float_short_reg) #endif /*!defined(FEATURE_SQUARE_ROOT)*/ #if !defined(FEATURE_INTERPRETIVE_EXECUTION) UNDEF_INST(start_interpretive_execution) #endif /*!defined(FEATURE_INTERPRETIVE_EXECUTION)*/ #if !defined(FEATURE_REGION_RELOCATE) UNDEF_INST(store_zone_parameter) UNDEF_INST(set_zone_parameter) #endif /*!defined(FEATURE_REGION_RELOCATE)*/ #if !defined(FEATURE_IO_ASSIST) UNDEF_INST(test_pending_zone_interrupt) #endif /*!defined(FEATURE_IO_ASSIST)*/ #if !defined(FEATURE_QUEUED_DIRECT_IO) UNDEF_INST(signal_adapter) #endif /*!defined(FEATURE_QUEUED_DIRECT_IO)*/ #if !defined(FEATURE_CHANNEL_SWITCHING) UNDEF_INST(connect_channel_set) UNDEF_INST(disconnect_channel_set) #endif /*!defined(FEATURE_CHANNEL_SWITCHING)*/ #if !defined(FEATURE_PROCESSOR_ASSIST_FACILITY) /*912*/ UNDEF_INST(perform_processor_assist) /*912*/ #endif /*!defined(FEATURE_PROCESSOR_ASSIST_FACILITY)*/ /*912*/ #if !defined(FEATURE_TRANSACTIONAL_EXECUTION_FACILITY) /*912*/ UNDEF_INST(extract_transaction_nesting_depth) /*912*/ UNDEF_INST(nontransactional_store_long) /*912*/ UNDEF_INST(transaction_abort) /*912*/ UNDEF_INST(transaction_begin) /*912*/ UNDEF_INST(transaction_begin_constrained) /*912*/ UNDEF_INST(transaction_end) /*912*/ #endif /*!defined(FEATURE_TRANSACTIONAL_EXECUTION_FACILITY)*/ /*912*/ #if !defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY) UNDEF_INST(load_program_parameter) #endif /*!defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY)*/ #if !defined(FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY) UNDEF_INST(extract_coprocessor_group_address) UNDEF_INST(extract_cpu_counter) UNDEF_INST(extract_peripheral_counter) UNDEF_INST(load_cpu_counter_set_controls) UNDEF_INST(load_peripheral_counter_set_controls) UNDEF_INST(query_counter_information) UNDEF_INST(set_cpu_counter) UNDEF_INST(set_peripheral_counter) #endif /*!defined(FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY)*/ #if !defined(FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY) UNDEF_INST(load_sampling_controls) UNDEF_INST(query_sampling_information) #endif /*!defined(FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY)*/ #if !defined(FEATURE_EXTENDED_TRANSLATION) UNDEF_INST(translate_extended) UNDEF_INST(convert_utf16_to_utf8) UNDEF_INST(convert_utf8_to_utf16) #endif /*!defined(FEATURE_EXTENDED_TRANSLATION)*/ #if !defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) UNDEF_INST(compare_logical_long_unicode) UNDEF_INST(move_long_unicode) UNDEF_INST(pack_ascii) UNDEF_INST(pack_unicode) UNDEF_INST(test_decimal) UNDEF_INST(translate_one_to_one) UNDEF_INST(translate_one_to_two) UNDEF_INST(translate_two_to_one) UNDEF_INST(translate_two_to_two) UNDEF_INST(unpack_ascii) UNDEF_INST(unpack_unicode) #endif /*!defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if !defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_3) UNDEF_INST(convert_utf16_to_utf32) UNDEF_INST(convert_utf32_to_utf16) UNDEF_INST(convert_utf32_to_utf8) UNDEF_INST(convert_utf8_to_utf32) UNDEF_INST(search_string_unicode) UNDEF_INST(translate_and_test_reverse) #endif /*!defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_3)*/ #if !defined(FEATURE_LOAD_REVERSED) && !defined(FEATURE_ESAME_N3_ESA390) UNDEF_INST(load_reversed_register) UNDEF_INST(load_reversed) UNDEF_INST(load_reversed_half) UNDEF_INST(store_reversed) UNDEF_INST(store_reversed_half) #if !defined(FEATURE_ESAME) UNDEF_INST(load_reversed_long_register) UNDEF_INST(store_reversed_long) #endif /*!defined(FEATURE_ESAME)*/ #endif /*!defined(FEATURE_LOAD_REVERSED) && !defined(FEATURE_ESAME_N3_ESA390)*/ #if !defined(FEATURE_SERVICE_PROCESSOR) UNDEF_INST(service_call) #endif /*!defined(FEATURE_SERVICE_PROCESSOR)*/ #if !defined(FEATURE_CHSC) UNDEF_INST(channel_subsystem_call) #endif /*!defined(FEATURE_CHSC)*/ #if !defined(FEATURE_ESAME_N3_ESA390) && !defined(FEATURE_ESAME) UNDEF_INST(add_logical_carry) UNDEF_INST(add_logical_carry_register) UNDEF_INST(branch_relative_and_save_long) UNDEF_INST(branch_relative_on_condition_long) UNDEF_INST(divide_logical) UNDEF_INST(divide_logical_register) UNDEF_INST(extract_psw) UNDEF_INST(load_address_relative_long) UNDEF_INST(multiply_logical) UNDEF_INST(multiply_logical_register) UNDEF_INST(rotate_left_single_logical) UNDEF_INST(set_addressing_mode_24) UNDEF_INST(set_addressing_mode_31) UNDEF_INST(subtract_logical_borrow) UNDEF_INST(subtract_logical_borrow_register) UNDEF_INST(test_addressing_mode) #endif /*!defined(FEATURE_ESAME_N3_ESA390) && !defined(FEATURE_ESAME)*/ #if !defined(FEATURE_STORE_FACILITY_LIST) UNDEF_INST(store_facility_list) #endif /*!defined(FEATURE_STORE_FACILITY_LIST) */ #if !defined(FEATURE_CANCEL_IO_FACILITY) UNDEF_INST(cancel_subchannel) #endif /*!defined(FEATURE_CANCEL_IO_FACILITY)*/ #if !defined(FEATURE_ECPSVM) UNDEF_INST(ecpsvm_basic_freex) UNDEF_INST(ecpsvm_basic_fretx) UNDEF_INST(ecpsvm_lock_page) UNDEF_INST(ecpsvm_unlock_page) UNDEF_INST(ecpsvm_decode_next_ccw) UNDEF_INST(ecpsvm_free_ccwstor) UNDEF_INST(ecpsvm_locate_vblock) UNDEF_INST(ecpsvm_disp1) UNDEF_INST(ecpsvm_tpage) UNDEF_INST(ecpsvm_tpage_lock) UNDEF_INST(ecpsvm_inval_segtab) UNDEF_INST(ecpsvm_inval_ptable) UNDEF_INST(ecpsvm_decode_first_ccw) UNDEF_INST(ecpsvm_dispatch_main) UNDEF_INST(ecpsvm_locate_rblock) UNDEF_INST(ecpsvm_comm_ccwproc) UNDEF_INST(ecpsvm_unxlate_ccw) UNDEF_INST(ecpsvm_disp2) UNDEF_INST(ecpsvm_store_level) UNDEF_INST(ecpsvm_loc_chgshrpg) UNDEF_INST(ecpsvm_extended_freex) UNDEF_INST(ecpsvm_extended_fretx) UNDEF_INST(ecpsvm_prefmach_assist) #endif /*!defined(FEATURE_ECPSVM)*/ #if !defined(FEATURE_LONG_DISPLACEMENT) UNDEF_INST(add_y) UNDEF_INST(add_halfword_y) UNDEF_INST(add_logical_y) UNDEF_INST(and_immediate_y) UNDEF_INST(and_y) UNDEF_INST(compare_y) UNDEF_INST(compare_and_swap_y) UNDEF_INST(compare_double_and_swap_y) UNDEF_INST(compare_halfword_y) UNDEF_INST(compare_logical_y) UNDEF_INST(compare_logical_immediate_y) UNDEF_INST(compare_logical_characters_under_mask_y) UNDEF_INST(convert_to_binary_y) UNDEF_INST(convert_to_decimal_y) UNDEF_INST(exclusive_or_immediate_y) UNDEF_INST(exclusive_or_y) UNDEF_INST(insert_character_y) UNDEF_INST(insert_characters_under_mask_y) UNDEF_INST(load_y) UNDEF_INST(load_address_y) UNDEF_INST(load_byte) UNDEF_INST(load_byte_long) UNDEF_INST(load_halfword_y) UNDEF_INST(load_multiple_y) UNDEF_INST(load_real_address_y) UNDEF_INST(move_immediate_y) UNDEF_INST(multiply_single_y) UNDEF_INST(or_immediate_y) UNDEF_INST(or_y) UNDEF_INST(store_y) UNDEF_INST(store_character_y) UNDEF_INST(store_characters_under_mask_y) UNDEF_INST(store_halfword_y) UNDEF_INST(store_multiple_y) UNDEF_INST(subtract_y) UNDEF_INST(subtract_halfword_y) UNDEF_INST(subtract_logical_y) UNDEF_INST(test_under_mask_y) #endif /*!defined(FEATURE_LONG_DISPLACEMENT)*/ #if !defined(FEATURE_LONG_DISPLACEMENT) \ || !defined(FEATURE_ACCESS_REGISTERS) UNDEF_INST(load_access_multiple_y) UNDEF_INST(store_access_multiple_y) #endif /*!defined(FEATURE_LONG_DISPLACEMENT) || !defined(FEATURE_ACCESS_REGISTERS)*/ #if !defined(FEATURE_LONG_DISPLACEMENT) \ || !defined(FEATURE_HEXADECIMAL_FLOATING_POINT) UNDEF_INST(load_float_long_y) UNDEF_INST(load_float_short_y) UNDEF_INST(store_float_long_y) UNDEF_INST(store_float_short_y) #endif /*!defined(FEATURE_LONG_DISPLACEMENT) || !defined(FEATURE_HEXADECIMAL_FLOATING_POINT)*/ #if !defined(FEATURE_MESSAGE_SECURITY_ASSIST) UNDEF_INST(cipher_message_r) UNDEF_INST(cipher_message_with_chaining_r) UNDEF_INST(compute_intermediate_message_digest_r) UNDEF_INST(compute_last_message_digest_r) UNDEF_INST(compute_message_authentication_code_r) #endif /*!defined(FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if !defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) /*810*/ UNDEF_INST(perform_cryptographic_key_management_operation_r) /*810*/ #endif /*!defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3)*/ #if !defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) /*810*/ UNDEF_INST(perform_cryptographic_computation_r) /*810*/ UNDEF_INST(cipher_message_with_cipher_feedback_r) /*810*/ UNDEF_INST(cipher_message_with_output_feedback_r) /*810*/ UNDEF_INST(cipher_message_with_counter_r) /*810*/ #endif /*!defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4)*/ #if !defined(FEATURE_DAT_ENHANCEMENT) UNDEF_INST(compare_and_swap_and_purge_long) UNDEF_INST(invalidate_dat_table_entry) #endif /*!defined(FEATURE_DAT_ENHANCEMENT)*/ #if !defined(FEATURE_EXTENDED_IMMEDIATE) /*@Z9*/ UNDEF_INST(add_fullword_immediate) /*@Z9*/ UNDEF_INST(add_long_fullword_immediate) /*@Z9*/ UNDEF_INST(add_logical_fullword_immediate) /*@Z9*/ UNDEF_INST(add_logical_long_fullword_immediate) /*@Z9*/ UNDEF_INST(and_immediate_high_fullword) /*@Z9*/ UNDEF_INST(and_immediate_low_fullword) /*@Z9*/ UNDEF_INST(compare_fullword_immediate) /*@Z9*/ UNDEF_INST(compare_long_fullword_immediate) /*@Z9*/ UNDEF_INST(compare_logical_fullword_immediate) /*@Z9*/ UNDEF_INST(compare_logical_long_fullword_immediate) /*@Z9*/ UNDEF_INST(exclusive_or_immediate_high_fullword) /*@Z9*/ UNDEF_INST(exclusive_or_immediate_low_fullword) /*@Z9*/ UNDEF_INST(insert_immediate_high_fullword) /*@Z9*/ UNDEF_INST(insert_immediate_low_fullword) /*@Z9*/ UNDEF_INST(load_long_fullword_immediate) /*@Z9*/ UNDEF_INST(load_logical_immediate_high_fullword) /*@Z9*/ UNDEF_INST(load_logical_immediate_low_fullword) /*@Z9*/ UNDEF_INST(or_immediate_high_fullword) /*@Z9*/ UNDEF_INST(or_immediate_low_fullword) /*@Z9*/ UNDEF_INST(subtract_logical_fullword_immediate) /*@Z9*/ UNDEF_INST(subtract_logical_long_fullword_immediate) /*@Z9*/ #endif /*!defined(FEATURE_EXTENDED_IMMEDIATE)*/ /*@Z9*/ #if !defined(FEATURE_EXTENDED_IMMEDIATE) /*@Z9*/ UNDEF_INST(load_and_test) /*@Z9*/ UNDEF_INST(load_and_test_long) /*@Z9*/ UNDEF_INST(load_byte_register) /*@Z9*/ UNDEF_INST(load_long_byte_register) /*@Z9*/ UNDEF_INST(load_halfword_register) /*@Z9*/ UNDEF_INST(load_long_halfword_register) /*@Z9*/ UNDEF_INST(load_logical_character) /*@Z9*/ UNDEF_INST(load_logical_character_register) /*@Z9*/ UNDEF_INST(load_logical_long_character_register) /*@Z9*/ UNDEF_INST(load_logical_halfword) /*@Z9*/ UNDEF_INST(load_logical_halfword_register) /*@Z9*/ UNDEF_INST(load_logical_long_halfword_register) /*@Z9*/ UNDEF_INST(find_leftmost_one_long_register) /*@Z9*/ #endif /*!defined(FEATURE_EXTENDED_IMMEDIATE)*/ /*@Z9*/ #if !defined(FEATURE_DAT_ENHANCEMENT_FACILITY_2) /*@Z9*/ UNDEF_INST(load_page_table_entry_address) /*@Z9*/ #endif /*!defined(FEATURE_DAT_ENHANCEMENT_FACILITY_2)*/ /*@Z9*/ #if !defined(FEATURE_STORE_CLOCK_FAST) UNDEF_INST(store_clock_fast) #else /*!defined(FEATURE_STORE_CLOCK_FAST)*/ #define z900_store_clock_fast z900_store_clock #endif /*!defined(FEATURE_STORE_CLOCK_FAST)*/ #if !defined(FEATURE_STORE_FACILITY_LIST_EXTENDED) /*@Z9*/ UNDEF_INST(store_facility_list_extended) /*@Z9*/ #endif /*!defined(FEATURE_STORE_FACILITY_LIST_EXTENDED)*/ /*@Z9*/ /* The following execute_xxxx routines can be optimized by the compiler to an indexed jump, leaving the stack frame untouched as the called routine has the same arguments, and the routine exits immediately after the call. *JJ */ #if ARCH_MODE != ARCH_370 DEF_INST(execute_01xx) { regs->ARCH_DEP(opcode_01xx)[inst[1]](inst, regs); } #endif DEF_INST(execute_a7xx) { regs->ARCH_DEP(opcode_a7xx)[inst[1]](inst, regs); } DEF_INST(execute_b2xx) { regs->ARCH_DEP(opcode_b2xx)[inst[1]](inst, regs); } DEF_INST(execute_b9xx) { regs->ARCH_DEP(opcode_b9xx)[inst[1]](inst, regs); } DEF_INST(execute_ebxx) { regs->ARCH_DEP(opcode_ebxx)[inst[5]](inst, regs); } #if defined(FEATURE_BASIC_FP_EXTENSIONS) DEF_INST(execute_b3xx) { regs->ARCH_DEP(opcode_b3xx)[inst[1]](inst, regs); } DEF_INST(execute_edxx) { regs->ARCH_DEP(opcode_edxx)[inst[5]](inst, regs); } #endif /*defined(FEATURE_BASIC_FP_EXTENSIONS)*/ DEF_INST(execute_e5xx) { regs->ARCH_DEP(opcode_e5xx)[inst[1]](inst, regs); } #if ARCH_MODE == ARCH_370 DEF_INST(execute_e6xx) { regs->ARCH_DEP(opcode_e6xx)[inst[1]](inst, regs); } #endif #if defined(FEATURE_ESAME) || defined(FEATURE_ESAME_N3_ESA390) DEF_INST(execute_a5xx) { regs->ARCH_DEP(opcode_a5xx)[inst[1]](inst, regs); } DEF_INST(execute_e3xx) { regs->ARCH_DEP(opcode_e3xx)[inst[5]](inst, regs); } DEF_INST(execute_ecxx) { regs->ARCH_DEP(opcode_ecxx[inst[5]])(inst, regs); } DEF_INST(execute_c0xx) { regs->ARCH_DEP(opcode_c0xx)[inst[1]](inst, regs); } DEF_INST(execute_c2xx) /*@Z9*/ { /*@Z9*/ regs->ARCH_DEP(opcode_c2xx)[inst[1]](inst, regs); /*@Z9*/ } /*@Z9*/ #endif /*defined(FEATURE_ESAME) || defined(FEATURE_ESAME_N3_ESA390)*/ DEF_INST(execute_c4xx) /*208*/ { /*208*/ regs->ARCH_DEP(opcode_c4xx)[inst[1]](inst, regs); /*208*/ } /*208*/ DEF_INST(execute_c6xx) /*208*/ { /*208*/ regs->ARCH_DEP(opcode_c6xx)[inst[1]](inst, regs); /*208*/ } /*208*/ #if defined(FEATURE_ESAME) DEF_INST(execute_c8xx) { regs->ARCH_DEP(opcode_c8xx)[inst[1]](inst, regs); } #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*810*/ DEF_INST(execute_ccxx) /*810*/ { /*810*/ regs->ARCH_DEP(opcode_ccxx)[inst[1]](inst, regs); /*810*/ } /*810*/ #endif /*defined(FEATURE_ESAME)*/ /*810*/ #if defined(FEATURE_VECTOR_FACILITY) DEF_INST(execute_a4xx) { regs->ARCH_DEP(opcode_a4xx)[inst[1]](inst, regs); } DEF_INST(execute_a5xx) { regs->ARCH_DEP(opcode_a5xx)[inst[1]](inst, regs); } DEF_INST(execute_a6xx) { regs->ARCH_DEP(opcode_a6xx)[inst[1]](inst, regs); } DEF_INST(execute_e4xx) { regs->ARCH_DEP(opcode_e4xx)[inst[1]](inst, regs); } #endif /*defined(FEATURE_VECTOR_FACILITY)*/ DEF_INST(operation_exception) { INST_UPDATE_PSW (regs, ILC(inst[0]), ILC(inst[0])); #if defined(MODEL_DEPENDENT) #if defined(_FEATURE_SIE) /* The B2XX extended opcodes which are not defined are always intercepted by SIE when issued in supervisor state */ if(!PROBSTATE(®s->psw) && inst[0] == 0xB2) SIE_INTERCEPT(regs); #endif /*defined(_FEATURE_SIE)*/ #endif /*defined(MODEL_DEPENDENT)*/ ARCH_DEP(program_interrupt)(regs, PGM_OPERATION_EXCEPTION); } DEF_INST(dummy_instruction) { // logmsg(_("Dummy instruction: ")); ARCH_DEP(display_inst) (regs, inst); INST_UPDATE_PSW (regs, ILC(inst[0]), ILC(inst[0])); } #if !defined(_GEN_ARCH) #define DISASM_ROUTE(_table,_route) \ int disasm_ ## _table (BYTE inst[], char unused[], char *p) \ { \ func disasm_fn; \ char* mnemonic; \ UNREFERENCED(unused); \ mnemonic = (void*)opcode_ ## _table [inst _route ][GEN_MAXARCH-1]; \ disasm_fn = (void*)opcode_ ## _table [inst _route ][GEN_MAXARCH-2]; \ return disasm_fn(inst, mnemonic, p); \ } DISASM_ROUTE(table,[0]) DISASM_ROUTE(01xx,[1]) DISASM_ROUTE(a5xx,[1] & 0x0F) DISASM_ROUTE(a7xx,[1] & 0x0F) DISASM_ROUTE(b2xx,[1]) DISASM_ROUTE(b3xx,[1]) DISASM_ROUTE(b9xx,[1]) DISASM_ROUTE(c0xx,[1] & 0x0F) DISASM_ROUTE(c2xx,[1] & 0x0F) /*@Z9*/ DISASM_ROUTE(c4xx,[1] & 0x0F) /*208*/ DISASM_ROUTE(c6xx,[1] & 0x0F) /*208*/ DISASM_ROUTE(c8xx,[1] & 0x0F) DISASM_ROUTE(ccxx,[1] & 0x0F) /*810*/ DISASM_ROUTE(e3xx,[5]) DISASM_ROUTE(e5xx,[1]) DISASM_ROUTE(e6xx,[1]) DISASM_ROUTE(ebxx,[5]) DISASM_ROUTE(ecxx,[5]) DISASM_ROUTE(edxx,[5]) #if defined(FEATURE_VECTOR_FACILITY) #define opcode_a4xx v_opcode_a4xx DISASM_ROUTE(a4xx,[1]) #undef opcode_a4xx #define opcode_a6xx v_opcode_a6xx DISASM_ROUTE(a6xx,[1]) #undef opcode_a6xx #define opcode_e4xx v_opcode_e4xx DISASM_ROUTE(e4xx,[1]) #undef opcode_e4xx #else /*defined(FEATURE_VECTOR_FACILITY)*/ #define disasm_a4xx disasm_none #define disasm_a6xx disasm_none #define disasm_e4xx disasm_none #endif /*defined(FEATURE_VECTOR_FACILITY)*/ #define DISASM_COMMON_VARS \ char* name; \ char operands[64] #define DISASM_SET_NAME \ name = mnemonic+1; while(*name++) #define DISASM_PRINT_OPERANDS \ snprintf(operands,sizeof(operands)-1, #define DISASM_LOGMSG \ operands[sizeof(operands)-1]=0; \ return sprintf(p, "%-5s %-19s %s",mnemonic,operands,name) // instructions using alternate mnemonic suffixed by 'A' /*810*/ #define DISASM_LOGMSG_ALTCODE \ operands[sizeof(operands)-1]=0; \ return sprintf(p, "%sA %-*s %s",mnemonic, \ (int)(23-strlen(mnemonic)),operands,name) int disasm_none (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; UNREFERENCED(inst); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%c",','); DISASM_LOGMSG; } int disasm_E (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; UNREFERENCED(inst); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%c",','); DISASM_LOGMSG; } int disasm_IE (BYTE inst[], char mnemonic[], char *p) /*912*/ { DISASM_COMMON_VARS; int i1, i2; i1 = inst[3] >> 4; i2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d",i1,i2); DISASM_LOGMSG; } int disasm_MII_A (BYTE inst[], char mnemonic[], char *p) /*912*/ { DISASM_COMMON_VARS; int m1,i2,i3; const S64 Two_S64=2; m1 = inst[1] >> 4; i2 = (S32)(((U32)inst[1] << 8) | (U32)inst[2]); i3 = (S32)(((U32)inst[3] << 16) | ((U32)inst[4] << 8) | (U32)inst[5]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,*%+"I64_FMT"d,*%+"I64_FMT"d",m1,i2*Two_S64,i3*Two_S64); DISASM_LOGMSG; } int disasm_RR (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1, r2; r1 = inst[1] >> 4; r2 = inst[1] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d",r1,r2); DISASM_LOGMSG; } // "Mnemonic R1" int disasm_RR_R1 (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1; r1 = inst[1] >> 4; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d",r1); DISASM_LOGMSG; } int disasm_RR_SVC (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d",inst[1]); DISASM_LOGMSG; } int disasm_RRE (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1, r2; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d",r1,r2); DISASM_LOGMSG; } // "Mnemonic R1" int disasm_RRE_R1 (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1; r1 = inst[3] >> 4; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d",r1); DISASM_LOGMSG; } // RRE instructions with an alternate RRF_MM format /*810*/ int disasm_RRE_MMA (BYTE inst[], char mnemonic[], char *p) /*810*/ { DISASM_COMMON_VARS; int m3,m4,r1,r2; m3 = inst[2] >> 4; m4 = inst[2] & 0x0F; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; if (m3 == 0 && m4 == 0) { DISASM_PRINT_OPERANDS "%d,%d",r1,r2); DISASM_LOGMSG; } else { DISASM_PRINT_OPERANDS "%d,%d,%d,%d",r1,m3,r2,m4); DISASM_LOGMSG_ALTCODE; } } int disasm_RRF_R (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,r2; r1 = inst[2] >> 4; r3 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",r1,r3,r2); DISASM_LOGMSG; } int disasm_RRF_M (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int m3,r1,r2; m3 = inst[2] >> 4; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",r1,m3,r2); DISASM_LOGMSG; } int disasm_RRF_M3 (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int m3,r1,r2; m3 = inst[2] >> 4; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",r1,r2,m3); DISASM_LOGMSG; } int disasm_RRF_M4 (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int m4,r1,r2; m4 = inst[2] & 0x0F; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",r1,r2,m4); DISASM_LOGMSG; } int disasm_RRF_MM (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int m3,m4,r1,r2; m3 = inst[2] >> 4; m4 = inst[2] & 0x0F; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,%d",r1,m3,r2,m4); DISASM_LOGMSG; } int disasm_RRF_RM (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r3,m4,r1,r2; r3 = inst[2] >> 4; m4 = inst[2] & 0x0F; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,%d",r1,r3,r2,m4); DISASM_LOGMSG; } // RRF_M instructions with an alternate RRF_MM format /*810*/ int disasm_RRF_MMA (BYTE inst[], char mnemonic[], char *p) /*810*/ { DISASM_COMMON_VARS; int m3,m4,r1,r2; m3 = inst[2] >> 4; m4 = inst[2] & 0x0F; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; if (m4 == 0) { DISASM_PRINT_OPERANDS "%d,%d,%d",r1,m3,r2); DISASM_LOGMSG; } else { DISASM_PRINT_OPERANDS "%d,%d,%d,%d",r1,m3,r2,m4); DISASM_LOGMSG_ALTCODE; } } int disasm_RRR (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r2,r3; r3 = inst[2] >> 4; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",r1,r2,r3); DISASM_LOGMSG; } int disasm_RRR_M (BYTE inst[], char mnemonic[], char *p) /*810*/ { DISASM_COMMON_VARS; int r1,r2,r3,m4; r3 = inst[2] >> 4; m4 = inst[2] & 0x0F; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,%d",r1,r2,r3,m4); DISASM_LOGMSG; } // RRR instructions with an alternate RRR_M format /*810*/ int disasm_RRR_MA (BYTE inst[], char mnemonic[], char *p) /*810*/ { DISASM_COMMON_VARS; int r1,r2,r3,m4; r3 = inst[2] >> 4; m4 = inst[2] & 0x0F; r1 = inst[3] >> 4; r2 = inst[3] & 0x0F; DISASM_SET_NAME; if (m4 == 0) { DISASM_PRINT_OPERANDS "%d,%d,%d",r1,r2,r3); DISASM_LOGMSG; } else { DISASM_PRINT_OPERANDS "%d,%d,%d,%d",r1,r2,r3,m4); DISASM_LOGMSG_ALTCODE; } } int disasm_RX (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,x2,b2,d2; r1 = inst[1] >> 4; x2 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d,%d)",r1,d2,x2,b2); DISASM_LOGMSG; } int disasm_RXE (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,x2,b2,d2; r1 = inst[1] >> 4; x2 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d,%d)",r1,d2,x2,b2); DISASM_LOGMSG; } int disasm_RXY (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,x2,b2,d2; r1 = inst[1] >> 4; x2 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (((S8)inst[4]) << 12) | (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d,%d)",r1,d2,x2,b2); DISASM_LOGMSG; } int disasm_RXF (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,x2,b2,d2; r1 = inst[4] >> 4; r3 = inst[1] >> 4; x2 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d(%d,%d)",r1,r3,d2,x2,b2); DISASM_LOGMSG; } int disasm_RS (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,b2,d2; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d(%d)",r1,r3,d2,b2); DISASM_LOGMSG; } // "Mnemonic R1,D2(B2)" int disasm_RS_R1D2B2 (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,b2,d2; r1 = inst[1] >> 4; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d)",r1,d2,b2); DISASM_LOGMSG; } int disasm_RSE (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,b2,d2; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d(%d)",r1,r3,d2,b2); DISASM_LOGMSG; } int disasm_RSY (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,b2,d2; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (((S8)inst[4]) << 12) | (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d(%d)",r1,r3,d2,b2); DISASM_LOGMSG; } int disasm_RSY_M3 (BYTE inst[], char mnemonic[], char *p) /*810*/ { DISASM_COMMON_VARS; int r1,b2,d2,m3; r1 = inst[1] >> 4; m3 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (((S8)inst[4]) << 12) | (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d),%d",r1,d2,b2,m3); DISASM_LOGMSG; } int disasm_RSL (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int l1,b1,d1; l1 = inst[1] >> 4; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d,%d)",d1,l1+1,b1); DISASM_LOGMSG; } int disasm_RSL_RM (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,l2,b2,d2,m3; l2 = inst[1]; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; r1 = inst[4] >> 4; m3 = inst[4] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d,%d),%d",r1,d2,l2+1,b2,m3); DISASM_LOGMSG; } int disasm_RSI_B (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,i2; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; i2 = (S16)(((U16)inst[2] << 8) | inst[3]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,*%+d",r1,r3,i2*2); DISASM_LOGMSG; } int disasm_RI (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,i2; r1 = inst[1] >> 4; i2 = (S16)(((U16)inst[2] << 8) | inst[3]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d",r1,i2); DISASM_LOGMSG; } int disasm_RI_B (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,i2; r1 = inst[1] >> 4; i2 = (S16)(((U16)inst[2] << 8) | inst[3]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,*%+d",r1,i2*2); DISASM_LOGMSG; } int disasm_RIE (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,i2; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; i2 = (S16)(((U16)inst[2] << 8) | inst[3]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,*%+d",r1,r3,i2*2); DISASM_LOGMSG; } int disasm_RIE_RRI (BYTE inst[], char mnemonic[], char *p) /*810*/ { DISASM_COMMON_VARS; int r1,r3,i2; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; i2 = (S16)(((U16)inst[2] << 8) | inst[3]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",r1,r3,i2); DISASM_LOGMSG; } int disasm_RIE_RIM (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int r1,i2,m3; r1 = inst[1] >> 4; i2 = (S16)(((U16)inst[2] << 8) | inst[3]); m3 = inst[4] >> 4; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",r1,i2,m3); DISASM_LOGMSG; } int disasm_RIE_RRIM (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int r1,r2,i4,m3; r1 = inst[1] >> 4; r2 = inst[1] & 0x0F; i4 = (S16)(((U16)inst[2] << 8) | inst[3]); m3 = inst[4] >> 4; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,*%+d",r1,r2,m3,i4*2); DISASM_LOGMSG; } int disasm_RIE_RMII (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int r1,m3,i4,i2; r1 = inst[1] >> 4; m3 = inst[1] & 0x0F; i4 = (S16)(((U16)inst[2] << 8) | inst[3]); i2 = inst[4]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,*%+d",r1,i2,m3,i4*2); DISASM_LOGMSG; } int disasm_RIE_RRIII (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int r1,r2,i3,i4,i5; r1 = inst[1] >> 4; r2 = inst[1] & 0x0F; i3 = inst[2]; i4 = inst[3]; i5 = inst[4]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,%d,%d",r1,r2,i3,i4,i5); DISASM_LOGMSG; } int disasm_RIL (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,i2; r1 = inst[1] >> 4; i2 = (S32)((((U32)inst[2] << 24) | ((U32)inst[3] << 16) | ((U32)inst[4] << 8)) | inst[5]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%"I32_FMT"d",r1,i2); DISASM_LOGMSG; } int disasm_RIL_A (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int r1,i2; const S64 Two_S64=2; r1 = inst[1] >> 4; i2 = (S32)((((U32)inst[2] << 24) | ((U32)inst[3] << 16) | ((U32)inst[4] << 8)) | inst[5]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,*%+"I64_FMT"d",r1,i2*Two_S64); DISASM_LOGMSG; } int disasm_RIS (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int r1,i2,m3,b4,d4; r1 = inst[1] >> 4; m3 = inst[1] & 0x0F; b4 = inst[2] >> 4; d4 = (inst[2] & 0x0F) << 8 | inst[3]; i2 = inst[4]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,%d(%d)",r1,i2,m3,d4,b4); DISASM_LOGMSG; } int disasm_RRS (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int r1,r2,m3,b4,d4; r1 = inst[1] >> 4; r2 = inst[1] & 0x0F; b4 = inst[2] >> 4; d4 = (inst[2] & 0x0F) << 8 | inst[3]; m3 = inst[4] >> 4; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d,%d(%d)",r1,r2,m3,d4,b4); DISASM_LOGMSG; } int disasm_SI (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int i2,b1,d1; i2 = inst[1]; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d),%d",d1,b1,i2); DISASM_LOGMSG; } int disasm_SIY (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int i2,b1,d1; i2 = inst[1]; b1 = inst[2] >> 4; d1 = (((S8)inst[4]) << 12) | (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d),%d",d1,b1,i2); DISASM_LOGMSG; } int disasm_SIL (BYTE inst[], char mnemonic[], char *p) /*208*/ { DISASM_COMMON_VARS; int b1,d1,i2; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; i2 = (S16)(((U16)inst[4] << 8) | inst[5]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d),%d",d1,b1,i2); DISASM_LOGMSG; } int disasm_SMI_A (BYTE inst[], char mnemonic[], char *p) /*912*/ { DISASM_COMMON_VARS; int m1,i2,b3,d3; const S64 Two_S64=2; m1 = inst[1] >> 4; b3 = inst[2] >> 4; d3 = (inst[2] & 0x0F) << 8 | inst[3]; i2 = (S32)(((U32)inst[4] << 8) | (U32)inst[5]); DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,*%+"I64_FMT"d,%d(%d)",m1,i2*Two_S64,d3,b3); DISASM_LOGMSG; } int disasm_S (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int d2,b2; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d)",d2,b2); DISASM_LOGMSG; } int disasm_SS (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int l1,l2,b1,d1,b2,d2; l1 = inst[1] >> 4; l2 = inst[1] & 0x0F; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d,%d),%d(%d,%d)",d1,l1+1,b1,d2,l2+1,b2); DISASM_LOGMSG; } int disasm_SS_L (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int l1,b1,d1,b2,d2; l1 = inst[1]; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d,%d),%d(%d)",d1,l1+1,b1,d2,b2); DISASM_LOGMSG; } // "Mnemonic D1(B1),D2(L2,B2)" int disasm_SS_L2 (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int l2,b1,d1,b2,d2; l2 = inst[1]; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d),%d(%d,%d)",d1,b1,d2,l2+1,b2); DISASM_LOGMSG; } int disasm_SS_R (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,b2,d2,b4,d4; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; b4 = inst[4] >> 4; d4 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d(%d),%d(%d)",r1,r3,d2,b2,d4,b4); DISASM_LOGMSG; } // "Mnemonic D1(R1,B1),D2(B2),R3" int disasm_SS_R3 (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,b1,d1,b2,d2; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d,%d),%d(%d),%d",d1,r1,b1,d2,b2,r3); DISASM_LOGMSG; } // "Mnemonic R1,D2(B2),R3,D4(B4)" int disasm_SS_RSRS (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r1,r3,b2,d2,b4,d4; r1 = inst[1] >> 4; r3 = inst[1] & 0x0F; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; b4 = inst[4] >> 4; d4 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d),%d,%d(%d)",r1,d2,b2,r3,d4,b4); DISASM_LOGMSG; } // "Mnemonic D1(L1,B1),D2(B2),I3" int disasm_SS_I (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int l1,i3,b1,d1,b2,d2; l1 = inst[1] >> 4; i3 = inst[1] & 0x0F; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d,%d),%d(%d),%d",d1,l1,b1,d2,b2,i3); DISASM_LOGMSG; } int disasm_SSE (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int b1,d1,b2,d2; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d),%d(%d)",d1,b1,d2,b2); DISASM_LOGMSG; } int disasm_SSF (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int r3,b1,d1,b2,d2; r3 = inst[1] >> 4; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d),%d(%d),%d",d1,b1,d2,b2,r3); DISASM_LOGMSG; } int disasm_SSF_RSS (BYTE inst[], char mnemonic[], char *p) /*810*/ { DISASM_COMMON_VARS; int r3,b1,d1,b2,d2; r3 = inst[1] >> 4; b1 = inst[2] >> 4; d1 = (inst[2] & 0x0F) << 8 | inst[3]; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d(%d),%d(%d)",r3,d1,b1,d2,b2); DISASM_LOGMSG; } int disasm_VST (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int vr3,rt2,vr1,rs2; vr3 = inst[2] >> 4; rt2 = inst[2] & 0x0F; vr1 = inst[3] >> 4; rs2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d(%d)",vr1,vr3,rs2,rt2); DISASM_LOGMSG; } int disasm_VR (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int vr1,fr3,gr2; fr3 = inst[2] >> 4; vr1 = inst[3] >> 4; gr2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d",vr1,fr3,gr2); DISASM_LOGMSG; } int disasm_VS (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int rs2; rs2 = inst[3] & 0x0F; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d",rs2); DISASM_LOGMSG; } int disasm_VRSE (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int vr1,vr3,d2,b2; vr3 = inst[2] >> 4; vr1 = inst[3] >> 4; b2 = inst[4] >> 4; d2 = (inst[4] & 0x0F) << 8 | inst[5]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d,%d,%d(%d)",vr1,vr3,d2,b2); DISASM_LOGMSG; } int disasm_S_NW (BYTE inst[], char mnemonic[], char *p) { DISASM_COMMON_VARS; int d2,b2; b2 = inst[2] >> 4; d2 = (inst[2] & 0x0F) << 8 | inst[3]; DISASM_SET_NAME; DISASM_PRINT_OPERANDS "%d(%d)",d2,b2); DISASM_LOGMSG; } /* Gabor Hoffer (performance option) */ DLL_EXPORT zz_func s370_opcode_table[256]; static zz_func s370_opcode_a4xx[256]; static zz_func s370_opcode_a5xx[256]; static zz_func s370_opcode_a6xx[256]; static zz_func s370_opcode_a7xx[256]; static zz_func s370_opcode_b2xx[256]; static zz_func s370_opcode_b3xx[256]; /*FPE*/ static zz_func s370_opcode_b9xx[256]; static zz_func s370_opcode_c0xx[256]; /*@N3*/ static zz_func s370_opcode_c2xx[256]; /*208*/ static zz_func s370_opcode_c4xx[256]; /*208*/ static zz_func s370_opcode_c6xx[256]; /*208*/ static zz_func s370_opcode_e3xx[256]; /*@N3*/ static zz_func s370_opcode_e4xx[256]; static zz_func s370_opcode_e5xx[256]; static zz_func s370_opcode_e6xx[256]; static zz_func s370_opcode_ebxx[256]; static zz_func s370_opcode_ecxx[256]; /*@N3*/ zz_func s390_opcode_table[256]; static zz_func s390_opcode_01xx[256]; static zz_func s390_opcode_a4xx[256]; static zz_func s390_opcode_a5xx[256]; static zz_func s390_opcode_a6xx[256]; static zz_func s390_opcode_a7xx[256]; static zz_func s390_opcode_b2xx[256]; static zz_func s390_opcode_b3xx[256]; static zz_func s390_opcode_b9xx[256]; static zz_func s390_opcode_c0xx[256]; static zz_func s390_opcode_c2xx[256]; /*@Z9*/ static zz_func s390_opcode_c4xx[256]; /*208*/ static zz_func s390_opcode_c6xx[256]; /*208*/ static zz_func s390_opcode_e3xx[256]; static zz_func s390_opcode_e4xx[256]; static zz_func s390_opcode_e5xx[256]; static zz_func s390_opcode_ebxx[256]; static zz_func s390_opcode_ecxx[256]; static zz_func s390_opcode_edxx[256]; zz_func z900_opcode_table[256]; static zz_func z900_opcode_01xx[256]; static zz_func z900_opcode_a5xx[256]; static zz_func z900_opcode_a7xx[256]; static zz_func z900_opcode_b2xx[256]; static zz_func z900_opcode_b3xx[256]; static zz_func z900_opcode_b9xx[256]; static zz_func z900_opcode_c0xx[256]; static zz_func z900_opcode_c2xx[256]; /*@Z9*/ static zz_func z900_opcode_c4xx[256]; /*208*/ static zz_func z900_opcode_c6xx[256]; /*208*/ static zz_func z900_opcode_c8xx[256]; static zz_func z900_opcode_ccxx[256]; /*810*/ static zz_func z900_opcode_e3xx[256]; static zz_func z900_opcode_e5xx[256]; static zz_func z900_opcode_ebxx[256]; static zz_func z900_opcode_ecxx[256]; static zz_func z900_opcode_edxx[256]; DLL_EXPORT void copy_opcode_tables() { int i; for (i = 0; i < 256; i++) { #if defined(_370) s370_opcode_table[i] = opcode_table[i][ARCH_370]; s370_opcode_a4xx [i] = v_opcode_a4xx [i][ARCH_370]; s370_opcode_a5xx [i] = v_opcode_a5xx [i][ARCH_370]; s370_opcode_a6xx [i] = v_opcode_a6xx [i][ARCH_370]; s370_opcode_a7xx [i] = opcode_a7xx [i&0x0F][ARCH_370]; s370_opcode_b2xx [i] = opcode_b2xx [i][ARCH_370]; s370_opcode_b3xx [i] = opcode_b3xx [i][ARCH_370]; /*FPE*/ s370_opcode_b9xx [i] = opcode_b9xx [i][ARCH_370]; s370_opcode_c0xx [i] = opcode_c0xx [i&0x0F][ARCH_370]; /*@N3*/ s370_opcode_c2xx [i] = opcode_c2xx [i&0x0F][ARCH_370]; /*208*/ s370_opcode_c4xx [i] = opcode_c4xx [i&0x0F][ARCH_370]; /*208*/ s370_opcode_c6xx [i] = opcode_c6xx [i&0x0F][ARCH_370]; /*208*/ s370_opcode_e3xx [i] = opcode_e3xx [i][ARCH_370]; /*@N3*/ s370_opcode_e4xx [i] = v_opcode_e4xx [i][ARCH_370]; s370_opcode_e5xx [i] = opcode_e5xx [i][ARCH_370]; s370_opcode_e6xx [i] = opcode_e6xx [i][ARCH_370]; s370_opcode_ebxx [i] = opcode_ebxx [i][ARCH_370]; s370_opcode_ecxx [i] = opcode_ecxx [i][ARCH_370]; /*@N3*/ #endif #if defined(_390) s390_opcode_table[i] = opcode_table[i][ARCH_390]; s390_opcode_01xx [i] = opcode_01xx [i][ARCH_390]; s390_opcode_a4xx [i] = v_opcode_a4xx [i][ARCH_390]; s390_opcode_a5xx [i] = v_opcode_a5xx [i][ARCH_390]; s390_opcode_a6xx [i] = v_opcode_a6xx [i][ARCH_390]; s390_opcode_a7xx [i] = opcode_a7xx [i&0x0F][ARCH_390]; s390_opcode_b2xx [i] = opcode_b2xx [i][ARCH_390]; s390_opcode_b3xx [i] = opcode_b3xx [i][ARCH_390]; s390_opcode_b9xx [i] = opcode_b9xx [i][ARCH_390]; s390_opcode_c0xx [i] = opcode_c0xx [i&0x0F][ARCH_390]; s390_opcode_c2xx [i] = opcode_c2xx [i&0x0F][ARCH_390]; /*@Z9*/ s390_opcode_c4xx [i] = opcode_c4xx [i&0x0F][ARCH_390]; /*208*/ s390_opcode_c6xx [i] = opcode_c6xx [i&0x0F][ARCH_390]; /*208*/ s390_opcode_e3xx [i] = opcode_e3xx [i][ARCH_390]; s390_opcode_e4xx [i] = v_opcode_e4xx [i][ARCH_390]; s390_opcode_e5xx [i] = opcode_e5xx [i][ARCH_390]; s390_opcode_ebxx [i] = opcode_ebxx [i][ARCH_390]; s390_opcode_ecxx [i] = opcode_ecxx [i][ARCH_390]; s390_opcode_edxx [i] = opcode_edxx [i][ARCH_390]; #endif #if defined(_900) z900_opcode_table[i] = opcode_table[i][ARCH_900]; z900_opcode_01xx [i] = opcode_01xx [i][ARCH_900]; z900_opcode_a5xx [i] = opcode_a5xx [i&0x0F][ARCH_900]; z900_opcode_a7xx [i] = opcode_a7xx [i&0x0F][ARCH_900]; z900_opcode_b2xx [i] = opcode_b2xx [i][ARCH_900]; z900_opcode_b3xx [i] = opcode_b3xx [i][ARCH_900]; z900_opcode_b9xx [i] = opcode_b9xx [i][ARCH_900]; z900_opcode_c0xx [i] = opcode_c0xx [i&0x0F][ARCH_900]; z900_opcode_c2xx [i] = opcode_c2xx [i&0x0F][ARCH_900]; /*@Z9*/ z900_opcode_c4xx [i] = opcode_c4xx [i&0x0F][ARCH_900]; /*208*/ z900_opcode_c6xx [i] = opcode_c6xx [i&0x0F][ARCH_900]; /*208*/ z900_opcode_c8xx [i] = opcode_c8xx [i&0x0F][ARCH_900]; z900_opcode_ccxx [i] = opcode_ccxx [i&0x0F][ARCH_900]; /*810*/ z900_opcode_e3xx [i] = opcode_e3xx [i][ARCH_900]; z900_opcode_e5xx [i] = opcode_e5xx [i][ARCH_900]; z900_opcode_ebxx [i] = opcode_ebxx [i][ARCH_900]; z900_opcode_ecxx [i] = opcode_ecxx [i][ARCH_900]; z900_opcode_edxx [i] = opcode_edxx [i][ARCH_900]; #endif } } void set_opcode_pointers(REGS *regs) { #if defined(_370) memcpy(regs->s370_opcode_table, s370_opcode_table, sizeof(s370_opcode_table)); regs->s370_opcode_a4xx = s370_opcode_a4xx; regs->s370_opcode_a5xx = s370_opcode_a5xx; regs->s370_opcode_a6xx = s370_opcode_a6xx; #if defined(MULTI_BYTE_ASSIST) memcpy(regs->s370_opcode_a7xx, s370_opcode_a7xx, sizeof(s370_opcode_a7xx)); memcpy(regs->s370_opcode_b2xx, s370_opcode_b2xx, sizeof(s370_opcode_b2xx)); memcpy(regs->s370_opcode_b9xx, s370_opcode_b9xx, sizeof(s370_opcode_b9xx)); memcpy(regs->s370_opcode_c0xx, s370_opcode_c0xx, /*@N3*/ sizeof(s370_opcode_c0xx)); /*@N3*/ memcpy(regs->s370_opcode_e3xx, s370_opcode_e3xx, /*@N3*/ sizeof(s370_opcode_e3xx)); /*@N3*/ memcpy(regs->s370_opcode_ebxx, s370_opcode_ebxx, sizeof(s370_opcode_ebxx)); #else regs->s370_opcode_a7xx = s370_opcode_a7xx; regs->s370_opcode_b2xx = s370_opcode_b2xx; regs->s370_opcode_b9xx = s370_opcode_b9xx; regs->s370_opcode_c0xx = s370_opcode_c0xx; /*@N3*/ regs->s370_opcode_e3xx = s370_opcode_e3xx; /*@N3*/ regs->s370_opcode_ebxx = s370_opcode_ebxx; #endif regs->s370_opcode_b3xx = s370_opcode_b3xx; /*FPE*/ regs->s370_opcode_c2xx = s370_opcode_c2xx; /*208*/ regs->s370_opcode_c4xx = s370_opcode_c4xx; /*208*/ regs->s370_opcode_c6xx = s370_opcode_c6xx; /*208*/ regs->s370_opcode_e4xx = s370_opcode_e4xx; regs->s370_opcode_e5xx = s370_opcode_e5xx; regs->s370_opcode_e6xx = s370_opcode_e6xx; regs->s370_opcode_ecxx = s370_opcode_ecxx; /*@N3*/ #endif #if defined(_390) memcpy(regs->s390_opcode_table, s390_opcode_table, sizeof(s390_opcode_table)); regs->s390_opcode_01xx = s390_opcode_01xx; regs->s390_opcode_a4xx = s390_opcode_a4xx; regs->s390_opcode_a5xx = s390_opcode_a5xx; regs->s390_opcode_a6xx = s390_opcode_a6xx; #if defined(MULTI_BYTE_ASSIST) memcpy(regs->s390_opcode_a7xx, s390_opcode_a7xx, sizeof(s390_opcode_a7xx)); memcpy(regs->s390_opcode_b2xx, s390_opcode_b2xx, sizeof(s390_opcode_b2xx)); memcpy(regs->s390_opcode_b9xx, s390_opcode_b9xx, sizeof(s390_opcode_b9xx)); memcpy(regs->s390_opcode_c0xx, s390_opcode_c0xx, sizeof(s390_opcode_c0xx)); memcpy(regs->s390_opcode_e3xx, s390_opcode_e3xx, sizeof(s390_opcode_e3xx)); memcpy(regs->s390_opcode_ebxx, s390_opcode_ebxx, sizeof(s390_opcode_ebxx)); #else regs->s390_opcode_a7xx = s390_opcode_a7xx; regs->s390_opcode_b2xx = s390_opcode_b2xx; regs->s390_opcode_b9xx = s390_opcode_b9xx; regs->s390_opcode_c0xx = s390_opcode_c0xx; regs->s390_opcode_e3xx = s390_opcode_e3xx; regs->s390_opcode_ebxx = s390_opcode_ebxx; #endif regs->s390_opcode_b3xx = s390_opcode_b3xx; regs->s390_opcode_c2xx = s390_opcode_c2xx; /*@Z9*/ regs->s390_opcode_c4xx = s390_opcode_c4xx; /*208*/ regs->s390_opcode_c6xx = s390_opcode_c6xx; /*208*/ regs->s390_opcode_e4xx = s390_opcode_e4xx; regs->s390_opcode_e5xx = s390_opcode_e5xx; regs->s390_opcode_ecxx = s390_opcode_ecxx; regs->s390_opcode_edxx = s390_opcode_edxx; #endif #if defined(_900) memcpy(regs->z900_opcode_table, z900_opcode_table, sizeof(z900_opcode_table)); regs->z900_opcode_01xx = z900_opcode_01xx; regs->z900_opcode_a5xx = z900_opcode_a5xx; #if defined(MULTI_BYTE_ASSIST) memcpy(regs->z900_opcode_a7xx, z900_opcode_a7xx, sizeof(z900_opcode_a7xx)); memcpy(regs->z900_opcode_b2xx, z900_opcode_b2xx, sizeof(z900_opcode_b2xx)); memcpy(regs->z900_opcode_b9xx, z900_opcode_b9xx, sizeof(z900_opcode_b9xx)); memcpy(regs->z900_opcode_c0xx, z900_opcode_c0xx, sizeof(z900_opcode_c0xx)); memcpy(regs->z900_opcode_e3xx, z900_opcode_e3xx, sizeof(z900_opcode_e3xx)); memcpy(regs->z900_opcode_ebxx, z900_opcode_ebxx, sizeof(z900_opcode_ebxx)); #else regs->z900_opcode_a7xx = z900_opcode_a7xx; regs->z900_opcode_b2xx = z900_opcode_b2xx; regs->z900_opcode_b9xx = z900_opcode_b9xx; regs->z900_opcode_c0xx = z900_opcode_c0xx; regs->z900_opcode_e3xx = z900_opcode_e3xx; regs->z900_opcode_ebxx = z900_opcode_ebxx; #endif regs->z900_opcode_b3xx = z900_opcode_b3xx; regs->z900_opcode_c2xx = z900_opcode_c2xx; /*@Z9*/ regs->z900_opcode_c4xx = z900_opcode_c4xx; /*208*/ regs->z900_opcode_c6xx = z900_opcode_c6xx; /*208*/ regs->z900_opcode_c8xx = z900_opcode_c8xx; regs->z900_opcode_ccxx = z900_opcode_ccxx; /*810*/ regs->z900_opcode_e5xx = z900_opcode_e5xx; regs->z900_opcode_ecxx = z900_opcode_ecxx; regs->z900_opcode_edxx = z900_opcode_edxx; #endif } DLL_EXPORT zz_func opcode_table[256][GEN_MAXARCH] = { /*00*/ GENx___x___x___ , /*01*/ GENx___x390x900 (execute_01xx,01xx,""), /*02*/ GENx___x___x___ , /*03*/ GENx___x___x___ , /*04*/ GENx370x390x900 (set_program_mask,RR_R1,"SPM"), /*05*/ GENx370x390x900 (branch_and_link_register,RR,"BALR"), /*06*/ GENx370x390x900 (branch_on_count_register,RR,"BCTR"), /*07*/ GENx370x390x900 (branch_on_condition_register,RR,"BCR"), /*08*/ GENx370x___x___ (set_storage_key,RR,"SSK"), /*09*/ GENx370x___x___ (insert_storage_key,RR,"ISK"), /*0A*/ GENx370x390x900 (supervisor_call,RR_SVC,"SVC"), /*0B*/ GENx___x390x900 (branch_and_set_mode,RR,"BSM"), /*0C*/ GENx___x390x900 (branch_and_save_and_set_mode,RR,"BASSM"), /*0D*/ GENx370x390x900 (branch_and_save_register,RR,"BASR"), /*0E*/ GENx370x390x900 (move_long,RR,"MVCL"), /*0F*/ GENx370x390x900 (compare_logical_character_long,RR,"CLCL"), /*10*/ GENx370x390x900 (load_positive_register,RR,"LPR"), /*11*/ GENx370x390x900 (load_negative_register,RR,"LNR"), /*12*/ GENx370x390x900 (load_and_test_register,RR,"LTR"), /*13*/ GENx370x390x900 (load_complement_register,RR,"LCR"), /*14*/ GENx370x390x900 (and_register,RR,"NR"), /*15*/ GENx370x390x900 (compare_logical_register,RR,"CLR"), /*16*/ GENx370x390x900 (or_register,RR,"OR"), /*17*/ GENx370x390x900 (exclusive_or_register,RR,"XR"), /*18*/ GENx370x390x900 (load_register,RR,"LR"), /*19*/ GENx370x390x900 (compare_register,RR,"CR"), /*1A*/ GENx370x390x900 (add_register,RR,"AR"), /*1B*/ GENx370x390x900 (subtract_register,RR,"SR"), /*1C*/ GENx370x390x900 (multiply_register,RR,"MR"), /*1D*/ GENx370x390x900 (divide_register,RR,"DR"), /*1E*/ GENx370x390x900 (add_logical_register,RR,"ALR"), /*1F*/ GENx370x390x900 (subtract_logical_register,RR,"SLR"), /*20*/ GENx370x390x900 (load_positive_float_long_reg,RR,"LPDR"), /*21*/ GENx370x390x900 (load_negative_float_long_reg,RR,"LNDR"), /*22*/ GENx370x390x900 (load_and_test_float_long_reg,RR,"LTDR"), /*23*/ GENx370x390x900 (load_complement_float_long_reg,RR,"LCDR"), /*24*/ GENx370x390x900 (halve_float_long_reg,RR,"HDR"), /*25*/ GENx370x390x900 (load_rounded_float_long_reg,RR,"LDXR"), /*26*/ GENx370x390x900 (multiply_float_ext_reg,RR,"MXR"), /*27*/ GENx370x390x900 (multiply_float_long_to_ext_reg,RR,"MXDR"), /*28*/ GENx370x390x900 (load_float_long_reg,RR,"LDR"), /*29*/ GENx370x390x900 (compare_float_long_reg,RR,"CDR"), /*2A*/ GENx370x390x900 (add_float_long_reg,RR,"ADR"), /*2B*/ GENx370x390x900 (subtract_float_long_reg,RR,"SDR"), /*2C*/ GENx370x390x900 (multiply_float_long_reg,RR,"MDR"), /*2D*/ GENx370x390x900 (divide_float_long_reg,RR,"DDR"), /*2E*/ GENx370x390x900 (add_unnormal_float_long_reg,RR,"AWR"), /*2F*/ GENx370x390x900 (subtract_unnormal_float_long_reg,RR,"SWR"), /*30*/ GENx370x390x900 (load_positive_float_short_reg,RR,"LPER"), /*31*/ GENx370x390x900 (load_negative_float_short_reg,RR,"LNER"), /*32*/ GENx370x390x900 (load_and_test_float_short_reg,RR,"LTER"), /*33*/ GENx370x390x900 (load_complement_float_short_reg,RR,"LCER"), /*34*/ GENx370x390x900 (halve_float_short_reg,RR,"HER"), /*35*/ GENx370x390x900 (load_rounded_float_short_reg,RR,"LEDR"), /*36*/ GENx370x390x900 (add_float_ext_reg,RR,"AXR"), /*37*/ GENx370x390x900 (subtract_float_ext_reg,RR,"SXR"), /*38*/ GENx370x390x900 (load_float_short_reg,RR,"LER"), /*39*/ GENx370x390x900 (compare_float_short_reg,RR,"CER"), /*3A*/ GENx370x390x900 (add_float_short_reg,RR,"AER"), /*3B*/ GENx370x390x900 (subtract_float_short_reg,RR,"SER"), /*3C*/ GENx370x390x900 (multiply_float_short_to_long_reg,RR,"MDER"), /*3D*/ GENx370x390x900 (divide_float_short_reg,RR,"DER"), /*3E*/ GENx370x390x900 (add_unnormal_float_short_reg,RR,"AUR"), /*3F*/ GENx370x390x900 (subtract_unnormal_float_short_reg,RR,"SUR"), /*40*/ GENx370x390x900 (store_halfword,RX,"STH"), /*41*/ GENx370x390x900 (load_address,RX,"LA"), /*42*/ GENx370x390x900 (store_character,RX,"STC"), /*43*/ GENx370x390x900 (insert_character,RX,"IC"), /*44*/ GENx370x390x900 (execute,RX,"EX"), /*45*/ GENx370x390x900 (branch_and_link,RX,"BAL"), /*46*/ GENx370x390x900 (branch_on_count,RX,"BCT"), /*47*/ GENx370x390x900 (branch_on_condition,RX,"BC"), /*48*/ GENx370x390x900 (load_halfword,RX,"LH"), /*49*/ GENx370x390x900 (compare_halfword,RX,"CH"), /*4A*/ GENx370x390x900 (add_halfword,RX,"AH"), /*4B*/ GENx370x390x900 (subtract_halfword,RX,"SH"), /*4C*/ GENx370x390x900 (multiply_halfword,RX,"MH"), /*4D*/ GENx370x390x900 (branch_and_save,RX,"BAS"), /*4E*/ GENx370x390x900 (convert_to_decimal,RX,"CVD"), /*4F*/ GENx370x390x900 (convert_to_binary,RX,"CVB"), /*50*/ GENx370x390x900 (store,RX,"ST"), /*51*/ GENx___x390x900 (load_address_extended,RX,"LAE"), /*52*/ GENx___x___x___ , /*53*/ GENx___x___x___ , /*54*/ GENx370x390x900 (and,RX,"N"), /*55*/ GENx370x390x900 (compare_logical,RX,"CL"), /*56*/ GENx370x390x900 (or,RX,"O"), /*57*/ GENx370x390x900 (exclusive_or,RX,"X"), /*58*/ GENx370x390x900 (load,RX,"L"), /*59*/ GENx370x390x900 (compare,RX,"C"), /*5A*/ GENx370x390x900 (add,RX,"A"), /*5B*/ GENx370x390x900 (subtract,RX,"S"), /*5C*/ GENx370x390x900 (multiply,RX,"M"), /*5D*/ GENx370x390x900 (divide,RX,"D"), /*5E*/ GENx370x390x900 (add_logical,RX,"AL"), /*5F*/ GENx370x390x900 (subtract_logical,RX,"SL"), /*60*/ GENx370x390x900 (store_float_long,RX,"STD"), /*61*/ GENx___x___x___ , /*62*/ GENx___x___x___ , /*63*/ GENx___x___x___ , /*64*/ GENx___x___x___ , /*65*/ GENx___x___x___ , /*66*/ GENx___x___x___ , /*67*/ GENx370x390x900 (multiply_float_long_to_ext,RX,"MXD"), /*68*/ GENx370x390x900 (load_float_long,RX,"LD"), /*69*/ GENx370x390x900 (compare_float_long,RX,"CD"), /*6A*/ GENx370x390x900 (add_float_long,RX,"AD"), /*6B*/ GENx370x390x900 (subtract_float_long,RX,"SD"), /*6C*/ GENx370x390x900 (multiply_float_long,RX,"MD"), /*6D*/ GENx370x390x900 (divide_float_long,RX,"DD"), /*6E*/ GENx370x390x900 (add_unnormal_float_long,RX,"AW"), /*6F*/ GENx370x390x900 (subtract_unnormal_float_long,RX,"SW"), /*70*/ GENx370x390x900 (store_float_short,RX,"STE"), /*71*/ GENx37Xx390x900 (multiply_single,RX,"MS"), /*72*/ GENx___x___x___ , /*73*/ GENx___x___x___ , /*74*/ GENx___x___x___ , /*75*/ GENx___x___x___ , /*76*/ GENx___x___x___ , /*77*/ GENx___x___x___ , /*78*/ GENx370x390x900 (load_float_short,RX,"LE"), /*79*/ GENx370x390x900 (compare_float_short,RX,"CE"), /*7A*/ GENx370x390x900 (add_float_short,RX,"AE"), /*7B*/ GENx370x390x900 (subtract_float_short,RX,"SE"), /*7C*/ GENx370x390x900 (multiply_float_short_to_long,RX,"MDE"), /*7D*/ GENx370x390x900 (divide_float_short,RX,"DE"), /*7E*/ GENx370x390x900 (add_unnormal_float_short,RX,"AU"), /*7F*/ GENx370x390x900 (subtract_unnormal_float_short,RX,"SU"), /*80*/ GENx370x390x900 (set_system_mask,S,"SSM"), /*81*/ GENx___x___x___ , /*82*/ GENx370x390x900 (load_program_status_word,S,"LPSW"), /*83*/ GENx370x390x900 (diagnose,RS,"DIAG"), /*84*/ GENx37Xx390x900 (branch_relative_on_index_high,RSI_B,"BRXH"), /*85*/ GENx37Xx390x900 (branch_relative_on_index_low_or_equal,RSI_B,"BRXLE"), /*86*/ GENx370x390x900 (branch_on_index_high,RS,"BXH"), /*87*/ GENx370x390x900 (branch_on_index_low_or_equal,RS,"BXLE"), /*88*/ GENx370x390x900 (shift_right_single_logical,RS_R1D2B2,"SRL"), /*89*/ GENx370x390x900 (shift_left_single_logical,RS_R1D2B2,"SLL"), /*8A*/ GENx370x390x900 (shift_right_single,RS_R1D2B2,"SRA"), /*8B*/ GENx370x390x900 (shift_left_single,RS_R1D2B2,"SLA"), /*8C*/ GENx370x390x900 (shift_right_double_logical,RS_R1D2B2,"SRDL"), /*8D*/ GENx370x390x900 (shift_left_double_logical,RS_R1D2B2,"SLDL"), /*8E*/ GENx370x390x900 (shift_right_double,RS_R1D2B2,"SRDA"), /*8F*/ GENx370x390x900 (shift_left_double,RS_R1D2B2,"SLDA"), /*90*/ GENx370x390x900 (store_multiple,RS,"STM"), /*91*/ GENx370x390x900 (test_under_mask,SI,"TM"), /*92*/ GENx370x390x900 (move_immediate,SI,"MVI"), /*93*/ GENx370x390x900 (test_and_set,S,"TS"), /*94*/ GENx370x390x900 (and_immediate,SI,"NI"), /*95*/ GENx370x390x900 (compare_logical_immediate,SI,"CLI"), /*96*/ GENx370x390x900 (or_immediate,SI,"OI"), /*97*/ GENx370x390x900 (exclusive_or_immediate,SI,"XI"), /*98*/ GENx370x390x900 (load_multiple,RS,"LM"), /*99*/ GENx___x390x900 (trace,RS,"TRACE"), /*9A*/ GENx___x390x900 (load_access_multiple,RS,"LAM"), /*9B*/ GENx___x390x900 (store_access_multiple,RS,"STAM"), /*9C*/ GENx370x___x___ (start_io,S,"SIO"), /*9D*/ GENx370x___x___ (test_io,S,"TIO"), /*9E*/ GENx370x___x___ (halt_io,S,"HIO"), /*9F*/ GENx370x___x___ (test_channel,S,"TCH"), /*A0*/ GENx___x___x___ , /*A1*/ GENx___x___x___ , /*A2*/ GENx___x___x___ , /*A3*/ GENx___x___x___ , /*A4*/ GENx370x390x___ (execute_a4xx,a4xx,""), /*A5*/ GENx370x390x900 (execute_a5xx,a5xx,""), /*A6*/ GENx370x390x___ (execute_a6xx,a6xx,""), /*A7*/ GENx37Xx390x900 (execute_a7xx,a7xx,""), /*A8*/ GENx370x390x900 (move_long_extended,RS,"MVCLE"), /*A9*/ GENx370x390x900 (compare_logical_long_extended,RS,"CLCLE"), /*AA*/ GENx___x___x___ , /*AB*/ GENx___x___x___ , /*AC*/ GENx370x390x900 (store_then_and_system_mask,SI,"STNSM"), /*AD*/ GENx370x390x900 (store_then_or_system_mask,SI,"STOSM"), /*AE*/ GENx370x390x900 (signal_processor,RS,"SIGP"), /*AF*/ GENx370x390x900 (monitor_call,SI,"MC"), /*B0*/ GENx___x___x___ , /*B1*/ GENx370x390x900 (load_real_address,RX,"LRA"), /*B2*/ GENx370x390x900 (execute_b2xx,b2xx,""), /*B3*/ GENx37Xx390x900 (execute_b3xx,b3xx,""), /*B4*/ GENx___x___x___ , /*B5*/ GENx___x___x___ , /*B6*/ GENx370x390x900 (store_control,RS,"STCTL"), /*B7*/ GENx370x390x900 (load_control,RS,"LCTL"), /*B8*/ GENx___x___x___ , /*B9*/ GENx37Xx390x900 (execute_b9xx,b9xx,""), /*BA*/ GENx370x390x900 (compare_and_swap,RS,"CS"), /*BB*/ GENx370x390x900 (compare_double_and_swap,RS,"CDS"), /*BC*/ GENx___x___x___ , /*BD*/ GENx370x390x900 (compare_logical_characters_under_mask,RS,"CLM"), /*BE*/ GENx370x390x900 (store_characters_under_mask,RS,"STCM"), /*BF*/ GENx370x390x900 (insert_characters_under_mask,RS,"ICM"), /*C0*/ GENx37Xx390x900 (execute_c0xx,c0xx,""), /*C1*/ GENx___x___x___ , /*C2*/ GENx37Xx390x900 (execute_c2xx,c2xx,""), /*@Z9*/ /*C3*/ GENx___x___x___ , /*C4*/ GENx37Xx390x900 (execute_c4xx,c4xx,""), /*208*/ /*C5*/ GENx___x___x900 (branch_prediction_relative_preload,MII_A,"BPRP"), /*912*/ /*C6*/ GENx37Xx390x900 (execute_c6xx,c6xx,""), /*208*/ /*C7*/ GENx___x___x900 (branch_prediction_preload,SMI_A,"BPP"), /*912*/ /*C8*/ GENx___x___x900 (execute_c8xx,c8xx,""), /*C9*/ GENx___x___x___ , /*CA*/ GENx___x___x___ , /*CB*/ GENx___x___x___ , /*CC*/ GENx___x___x900 (execute_ccxx,ccxx,""), /*810*/ /*CD*/ GENx___x___x___ , /*CE*/ GENx___x___x___ , /*CF*/ GENx___x___x___ , /*D0*/ GENx37Xx390x900 (translate_and_test_reverse,SS_L,"TRTR"), /*D1*/ GENx370x390x900 (move_numerics,SS_L,"MVN"), /*D2*/ GENx370x390x900 (move_character,SS_L,"MVC"), /*D3*/ GENx370x390x900 (move_zones,SS_L,"MVZ"), /*D4*/ GENx370x390x900 (and_character,SS_L,"NC"), /*D5*/ GENx370x390x900 (compare_logical_character,SS_L,"CLC"), /*D6*/ GENx370x390x900 (or_character,SS_L,"OC"), /*D7*/ GENx370x390x900 (exclusive_or_character,SS_L,"XC"), /*D8*/ GENx___x___x___ , /*D9*/ GENx370x390x900 (move_with_key,SS_R3,"MVCK"), /*DA*/ GENx370x390x900 (move_to_primary,SS_R3,"MVCP"), /*DB*/ GENx370x390x900 (move_to_secondary,SS_R3,"MVCS"), /*DC*/ GENx370x390x900 (translate,SS_L,"TR"), /*DD*/ GENx370x390x900 (translate_and_test,SS_L,"TRT"), /*DE*/ GENx370x390x900 (edit_x_edit_and_mark,SS_L,"ED"), /*DF*/ GENx370x390x900 (edit_x_edit_and_mark,SS_L,"EDMK"), /*E0*/ GENx___x___x___ , /*E1*/ GENx37Xx390x900 (pack_unicode,SS_L2,"PKU"), /*E2*/ GENx37Xx390x900 (unpack_unicode,SS_L,"UNPKU"), /*E3*/ GENx37Xx390x900 (execute_e3xx,e3xx,""), /*E4*/ GENx370x390x___ (execute_e4xx,e4xx,""), /*E5*/ GENx370x390x900 (execute_e5xx,e5xx,""), /*E6*/ GENx370x___x___ (execute_e6xx,e6xx,""), /*E7*/ GENx___x___x___ , /*E8*/ GENx370x390x900 (move_inverse,SS_L,"MVCIN"), /*E9*/ GENx37Xx390x900 (pack_ascii,SS_L2,"PKA"), /*EA*/ GENx37Xx390x900 (unpack_ascii,SS_L,"UNPKA"), /*EB*/ GENx37Xx390x900 (execute_ebxx,ebxx,""), /*EC*/ GENx37Xx390x900 (execute_ecxx,ecxx,""), /*ED*/ GENx37Xx390x900 (execute_edxx,edxx,""), /*EE*/ GENx___x390x900 (perform_locked_operation,SS_RSRS,"PLO"), /*EF*/ GENx___x___x900 (load_multiple_disjoint,SS_R,"LMD"), /*F0*/ GENx370x390x900 (shift_and_round_decimal,SS_I,"SRP"), /*F1*/ GENx370x390x900 (move_with_offset,SS,"MVO"), /*F2*/ GENx370x390x900 (pack,SS,"PACK"), /*F3*/ GENx370x390x900 (unpack,SS,"UNPK"), /*F4*/ GENx___x___x___ , /*F5*/ GENx___x___x___ , /*F6*/ GENx___x___x___ , /*F7*/ GENx___x___x___ , /*F8*/ GENx370x390x900 (zero_and_add,SS,"ZAP"), /*F9*/ GENx370x390x900 (compare_decimal,SS,"CP"), /*FA*/ GENx370x390x900 (add_decimal,SS,"AP"), /*FB*/ GENx370x390x900 (subtract_decimal,SS,"SP"), /*FC*/ GENx370x390x900 (multiply_decimal,SS,"MP"), /*FD*/ GENx370x390x900 (divide_decimal,SS,"DP"), /*FE*/ GENx___x___x___ , /*FF*/ GENx___x___x___ }; DLL_EXPORT zz_func opcode_01xx[256][GEN_MAXARCH] = { /*0100*/ GENx___x___x___ , /*0101*/ GENx___x390x900 (program_return,E,"PR"), /*0102*/ GENx___x390x900 (update_tree,E,"UPT"), /*0103*/ GENx___x___x___ , /*0104*/ GENx___x___x900 (perform_timing_facility_function,E,"PTFF"), /*0105*/ GENx___x___x___ , /*(clear_message,?,"CMSG"),*/ /*0106*/ GENx___x___x___ , /*(test_message,?,"TMSG"),*/ /*0107*/ GENx___x390x900 (set_clock_programmable_field,E,"SCKPF"), /*0108*/ GENx___x___x___ , /*(test_message_path_state,?,"TMPS"),*/ /*0109*/ GENx___x___x___ , /*(clear_message_path_state,?,"CMPS"),*/ /*010A*/ GENx___x390x900 (perform_floating_point_operation,E,"PFPO"), /*010B*/ GENx___x390x900 (test_addressing_mode,E,"TAM"), /*010C*/ GENx___x390x900 (set_addressing_mode_24,E,"SAM24"), /*010D*/ GENx___x390x900 (set_addressing_mode_31,E,"SAM31"), /*010E*/ GENx___x___x900 (set_addressing_mode_64,E,"SAM64"), /*010F*/ GENx___x___x___ , /*0110*/ GENx___x___x___ , /*0111*/ GENx___x___x___ , /*0112*/ GENx___x___x___ , /*0113*/ GENx___x___x___ , /*0114*/ GENx___x___x___ , /*0115*/ GENx___x___x___ , /*0116*/ GENx___x___x___ , /*0117*/ GENx___x___x___ , /*0118*/ GENx___x___x___ , /*0119*/ GENx___x___x___ , /*011A*/ GENx___x___x___ , /*011B*/ GENx___x___x___ , /*011C*/ GENx___x___x___ , /*011D*/ GENx___x___x___ , /*011E*/ GENx___x___x___ , /*011F*/ GENx___x___x___ , /*0120*/ GENx___x___x___ , /*0121*/ GENx___x___x___ , /*0122*/ GENx___x___x___ , /*0123*/ GENx___x___x___ , /*0124*/ GENx___x___x___ , /*0125*/ GENx___x___x___ , /*0126*/ GENx___x___x___ , /*0127*/ GENx___x___x___ , /*0128*/ GENx___x___x___ , /*0129*/ GENx___x___x___ , /*012A*/ GENx___x___x___ , /*012B*/ GENx___x___x___ , /*012C*/ GENx___x___x___ , /*012D*/ GENx___x___x___ , /*012E*/ GENx___x___x___ , /*012F*/ GENx___x___x___ , /*0130*/ GENx___x___x___ , /*0131*/ GENx___x___x___ , /*0132*/ GENx___x___x___ , /*0133*/ GENx___x___x___ , /*0134*/ GENx___x___x___ , /*0135*/ GENx___x___x___ , /*0136*/ GENx___x___x___ , /*0137*/ GENx___x___x___ , /*0138*/ GENx___x___x___ , /*0139*/ GENx___x___x___ , /*013A*/ GENx___x___x___ , /*013B*/ GENx___x___x___ , /*013C*/ GENx___x___x___ , /*013D*/ GENx___x___x___ , /*013E*/ GENx___x___x___ , /*013F*/ GENx___x___x___ , /*0140*/ GENx___x___x___ , /*0141*/ GENx___x___x___ , /*0142*/ GENx___x___x___ , /*0143*/ GENx___x___x___ , /*0144*/ GENx___x___x___ , /*0145*/ GENx___x___x___ , /*0146*/ GENx___x___x___ , /*0147*/ GENx___x___x___ , /*0148*/ GENx___x___x___ , /*0149*/ GENx___x___x___ , /*014A*/ GENx___x___x___ , /*014B*/ GENx___x___x___ , /*014C*/ GENx___x___x___ , /*014D*/ GENx___x___x___ , /*014E*/ GENx___x___x___ , /*014F*/ GENx___x___x___ , /*0150*/ GENx___x___x___ , /*0151*/ GENx___x___x___ , /*0152*/ GENx___x___x___ , /*0153*/ GENx___x___x___ , /*0154*/ GENx___x___x___ , /*0155*/ GENx___x___x___ , /*0156*/ GENx___x___x___ , /*0157*/ GENx___x___x___ , /*0158*/ GENx___x___x___ , /*0159*/ GENx___x___x___ , /*015A*/ GENx___x___x___ , /*015B*/ GENx___x___x___ , /*015C*/ GENx___x___x___ , /*015D*/ GENx___x___x___ , /*015E*/ GENx___x___x___ , /*015F*/ GENx___x___x___ , /*0160*/ GENx___x___x___ , /*0161*/ GENx___x___x___ , /*0162*/ GENx___x___x___ , /*0163*/ GENx___x___x___ , /*0164*/ GENx___x___x___ , /*0165*/ GENx___x___x___ , /*0166*/ GENx___x___x___ , /*0167*/ GENx___x___x___ , /*0168*/ GENx___x___x___ , /*0169*/ GENx___x___x___ , /*016A*/ GENx___x___x___ , /*016B*/ GENx___x___x___ , /*016C*/ GENx___x___x___ , /*016D*/ GENx___x___x___ , /*016E*/ GENx___x___x___ , /*016F*/ GENx___x___x___ , /*0170*/ GENx___x___x___ , /*0171*/ GENx___x___x___ , /*0172*/ GENx___x___x___ , /*0173*/ GENx___x___x___ , /*0174*/ GENx___x___x___ , /*0175*/ GENx___x___x___ , /*0176*/ GENx___x___x___ , /*0177*/ GENx___x___x___ , /*0178*/ GENx___x___x___ , /*0179*/ GENx___x___x___ , /*017A*/ GENx___x___x___ , /*017B*/ GENx___x___x___ , /*017C*/ GENx___x___x___ , /*017D*/ GENx___x___x___ , /*017E*/ GENx___x___x___ , /*017F*/ GENx___x___x___ , /*0180*/ GENx___x___x___ , /*0181*/ GENx___x___x___ , /*0182*/ GENx___x___x___ , /*0183*/ GENx___x___x___ , /*0184*/ GENx___x___x___ , /*0185*/ GENx___x___x___ , /*0186*/ GENx___x___x___ , /*0187*/ GENx___x___x___ , /*0188*/ GENx___x___x___ , /*0189*/ GENx___x___x___ , /*018A*/ GENx___x___x___ , /*018B*/ GENx___x___x___ , /*018C*/ GENx___x___x___ , /*018D*/ GENx___x___x___ , /*018E*/ GENx___x___x___ , /*018F*/ GENx___x___x___ , /*0190*/ GENx___x___x___ , /*0191*/ GENx___x___x___ , /*0192*/ GENx___x___x___ , /*0193*/ GENx___x___x___ , /*0194*/ GENx___x___x___ , /*0195*/ GENx___x___x___ , /*0196*/ GENx___x___x___ , /*0197*/ GENx___x___x___ , /*0198*/ GENx___x___x___ , /*0199*/ GENx___x___x___ , /*019A*/ GENx___x___x___ , /*019B*/ GENx___x___x___ , /*019C*/ GENx___x___x___ , /*019D*/ GENx___x___x___ , /*019E*/ GENx___x___x___ , /*019F*/ GENx___x___x___ , /*01A0*/ GENx___x___x___ , /*01A1*/ GENx___x___x___ , /*01A2*/ GENx___x___x___ , /*01A3*/ GENx___x___x___ , /*01A4*/ GENx___x___x___ , /*01A5*/ GENx___x___x___ , /*01A6*/ GENx___x___x___ , /*01A7*/ GENx___x___x___ , /*01A8*/ GENx___x___x___ , /*01A9*/ GENx___x___x___ , /*01AA*/ GENx___x___x___ , /*01AB*/ GENx___x___x___ , /*01AC*/ GENx___x___x___ , /*01AD*/ GENx___x___x___ , /*01AE*/ GENx___x___x___ , /*01AF*/ GENx___x___x___ , /*01B0*/ GENx___x___x___ , /*01B1*/ GENx___x___x___ , /*01B2*/ GENx___x___x___ , /*01B3*/ GENx___x___x___ , /*01B4*/ GENx___x___x___ , /*01B5*/ GENx___x___x___ , /*01B6*/ GENx___x___x___ , /*01B7*/ GENx___x___x___ , /*01B8*/ GENx___x___x___ , /*01B9*/ GENx___x___x___ , /*01BA*/ GENx___x___x___ , /*01BB*/ GENx___x___x___ , /*01BC*/ GENx___x___x___ , /*01BD*/ GENx___x___x___ , /*01BE*/ GENx___x___x___ , /*01BF*/ GENx___x___x___ , /*01C0*/ GENx___x___x___ , /*01C1*/ GENx___x___x___ , /*01C2*/ GENx___x___x___ , /*01C3*/ GENx___x___x___ , /*01C4*/ GENx___x___x___ , /*01C5*/ GENx___x___x___ , /*01C6*/ GENx___x___x___ , /*01C7*/ GENx___x___x___ , /*01C8*/ GENx___x___x___ , /*01C9*/ GENx___x___x___ , /*01CA*/ GENx___x___x___ , /*01CB*/ GENx___x___x___ , /*01CC*/ GENx___x___x___ , /*01CD*/ GENx___x___x___ , /*01CE*/ GENx___x___x___ , /*01CF*/ GENx___x___x___ , /*01D0*/ GENx___x___x___ , /*01D1*/ GENx___x___x___ , /*01D2*/ GENx___x___x___ , /*01D3*/ GENx___x___x___ , /*01D4*/ GENx___x___x___ , /*01D5*/ GENx___x___x___ , /*01D6*/ GENx___x___x___ , /*01D7*/ GENx___x___x___ , /*01D8*/ GENx___x___x___ , /*01D9*/ GENx___x___x___ , /*01DA*/ GENx___x___x___ , /*01DB*/ GENx___x___x___ , /*01DC*/ GENx___x___x___ , /*01DD*/ GENx___x___x___ , /*01DE*/ GENx___x___x___ , /*01DF*/ GENx___x___x___ , /*01E0*/ GENx___x___x___ , /*01E1*/ GENx___x___x___ , /*01E2*/ GENx___x___x___ , /*01E3*/ GENx___x___x___ , /*01E4*/ GENx___x___x___ , /*01E5*/ GENx___x___x___ , /*01E6*/ GENx___x___x___ , /*01E7*/ GENx___x___x___ , /*01E8*/ GENx___x___x___ , /*01E9*/ GENx___x___x___ , /*01EA*/ GENx___x___x___ , /*01EB*/ GENx___x___x___ , /*01EC*/ GENx___x___x___ , /*01ED*/ GENx___x___x___ , /*01EE*/ GENx___x___x___ , /*01EF*/ GENx___x___x___ , /*01F0*/ GENx___x___x___ , /*01F1*/ GENx___x___x___ , /*01F2*/ GENx___x___x___ , /*01F3*/ GENx___x___x___ , /*01F4*/ GENx___x___x___ , /*01F5*/ GENx___x___x___ , /*01F6*/ GENx___x___x___ , /*01F7*/ GENx___x___x___ , /*01F8*/ GENx___x___x___ , /*01F9*/ GENx___x___x___ , /*01FA*/ GENx___x___x___ , /*01FB*/ GENx___x___x___ , /*01FC*/ GENx___x___x___ , /*01FD*/ GENx___x___x___ , /*01FE*/ GENx___x___x___ , /*01FF*/ GENx___x390x900 (trap2,E,"TRAP2") }; // #if defined(FEATURE_ESAME) DLL_EXPORT zz_func opcode_a4xx[256][GEN_MAXARCH] = { /*A400*/ GENx___x___x___ , /*A401*/ GENx___x___x___ , /*A402*/ GENx___x___x___ , /*A403*/ GENx___x___x___ , /*A404*/ GENx___x___x___ , /*A405*/ GENx___x___x___ , /*A406*/ GENx___x___x___ , /*A407*/ GENx___x___x___ , /*A408*/ GENx___x___x___ , /*A409*/ GENx___x___x___ , /*A40A*/ GENx___x___x___ , /*A40B*/ GENx___x___x___ , /*A40C*/ GENx___x___x___ , /*A40D*/ GENx___x___x___ , /*A40E*/ GENx___x___x___ , /*A40F*/ GENx___x___x___ , /*A410*/ GENx___x___x___ , /*A411*/ GENx___x___x___ , /*A412*/ GENx___x___x___ , /*A413*/ GENx___x___x___ , /*A414*/ GENx___x___x___ , /*A415*/ GENx___x___x___ , /*A416*/ GENx___x___x___ , /*A417*/ GENx___x___x___ , /*A418*/ GENx___x___x___ , /*A419*/ GENx___x___x___ , /*A41A*/ GENx___x___x___ , /*A41B*/ GENx___x___x___ , /*A41C*/ GENx___x___x___ , /*A41D*/ GENx___x___x___ , /*A41E*/ GENx___x___x___ , /*A41F*/ GENx___x___x___ , /*A420*/ GENx___x___x___ , /*A421*/ GENx___x___x___ , /*A422*/ GENx___x___x___ , /*A423*/ GENx___x___x___ , /*A424*/ GENx___x___x___ , /*A425*/ GENx___x___x___ , /*A426*/ GENx___x___x___ , /*A427*/ GENx___x___x___ , /*A428*/ GENx___x___x___ , /*A429*/ GENx___x___x___ , /*A42A*/ GENx___x___x___ , /*A42B*/ GENx___x___x___ , /*A42C*/ GENx___x___x___ , /*A42D*/ GENx___x___x___ , /*A42E*/ GENx___x___x___ , /*A42F*/ GENx___x___x___ , /*A430*/ GENx___x___x___ , /*A431*/ GENx___x___x___ , /*A432*/ GENx___x___x___ , /*A433*/ GENx___x___x___ , /*A434*/ GENx___x___x___ , /*A435*/ GENx___x___x___ , /*A436*/ GENx___x___x___ , /*A437*/ GENx___x___x___ , /*A438*/ GENx___x___x___ , /*A439*/ GENx___x___x___ , /*A43A*/ GENx___x___x___ , /*A43B*/ GENx___x___x___ , /*A43C*/ GENx___x___x___ , /*A43D*/ GENx___x___x___ , /*A43E*/ GENx___x___x___ , /*A43F*/ GENx___x___x___ , /*A440*/ GENx___x___x___ , /*A441*/ GENx___x___x___ , /*A442*/ GENx___x___x___ , /*A443*/ GENx___x___x___ , /*A444*/ GENx___x___x___ , /*A445*/ GENx___x___x___ , /*A446*/ GENx___x___x___ , /*A447*/ GENx___x___x___ , /*A448*/ GENx___x___x___ , /*A449*/ GENx___x___x___ , /*A44A*/ GENx___x___x___ , /*A44B*/ GENx___x___x___ , /*A44C*/ GENx___x___x___ , /*A44D*/ GENx___x___x___ , /*A44E*/ GENx___x___x___ , /*A44F*/ GENx___x___x___ , /*A450*/ GENx___x___x___ , /*A451*/ GENx___x___x___ , /*A452*/ GENx___x___x___ , /*A453*/ GENx___x___x___ , /*A454*/ GENx___x___x___ , /*A455*/ GENx___x___x___ , /*A456*/ GENx___x___x___ , /*A457*/ GENx___x___x___ , /*A458*/ GENx___x___x___ , /*A459*/ GENx___x___x___ , /*A45A*/ GENx___x___x___ , /*A45B*/ GENx___x___x___ , /*A45C*/ GENx___x___x___ , /*A45D*/ GENx___x___x___ , /*A45E*/ GENx___x___x___ , /*A45F*/ GENx___x___x___ , /*A460*/ GENx___x___x___ , /*A461*/ GENx___x___x___ , /*A462*/ GENx___x___x___ , /*A463*/ GENx___x___x___ , /*A464*/ GENx___x___x___ , /*A465*/ GENx___x___x___ , /*A466*/ GENx___x___x___ , /*A467*/ GENx___x___x___ , /*A468*/ GENx___x___x___ , /*A469*/ GENx___x___x___ , /*A46A*/ GENx___x___x___ , /*A46B*/ GENx___x___x___ , /*A46C*/ GENx___x___x___ , /*A46D*/ GENx___x___x___ , /*A46E*/ GENx___x___x___ , /*A46F*/ GENx___x___x___ , /*A470*/ GENx___x___x___ , /*A471*/ GENx___x___x___ , /*A472*/ GENx___x___x___ , /*A473*/ GENx___x___x___ , /*A474*/ GENx___x___x___ , /*A475*/ GENx___x___x___ , /*A476*/ GENx___x___x___ , /*A477*/ GENx___x___x___ , /*A478*/ GENx___x___x___ , /*A479*/ GENx___x___x___ , /*A47A*/ GENx___x___x___ , /*A47B*/ GENx___x___x___ , /*A47C*/ GENx___x___x___ , /*A47D*/ GENx___x___x___ , /*A47E*/ GENx___x___x___ , /*A47F*/ GENx___x___x___ , /*A480*/ GENx___x___x___ , /*A481*/ GENx___x___x___ , /*A482*/ GENx___x___x___ , /*A483*/ GENx___x___x___ , /*A484*/ GENx___x___x___ , /*A485*/ GENx___x___x___ , /*A486*/ GENx___x___x___ , /*A487*/ GENx___x___x___ , /*A488*/ GENx___x___x___ , /*A489*/ GENx___x___x___ , /*A48A*/ GENx___x___x___ , /*A48B*/ GENx___x___x___ , /*A48C*/ GENx___x___x___ , /*A48D*/ GENx___x___x___ , /*A48E*/ GENx___x___x___ , /*A48F*/ GENx___x___x___ , /*A490*/ GENx___x___x___ , /*A491*/ GENx___x___x___ , /*A492*/ GENx___x___x___ , /*A493*/ GENx___x___x___ , /*A494*/ GENx___x___x___ , /*A495*/ GENx___x___x___ , /*A496*/ GENx___x___x___ , /*A497*/ GENx___x___x___ , /*A498*/ GENx___x___x___ , /*A499*/ GENx___x___x___ , /*A49A*/ GENx___x___x___ , /*A49B*/ GENx___x___x___ , /*A49C*/ GENx___x___x___ , /*A49D*/ GENx___x___x___ , /*A49E*/ GENx___x___x___ , /*A49F*/ GENx___x___x___ , /*A4A0*/ GENx___x___x___ , /*A4A1*/ GENx___x___x___ , /*A4A2*/ GENx___x___x___ , /*A4A3*/ GENx___x___x___ , /*A4A4*/ GENx___x___x___ , /*A4A5*/ GENx___x___x___ , /*A4A6*/ GENx___x___x___ , /*A4A7*/ GENx___x___x___ , /*A4A8*/ GENx___x___x___ , /*A4A9*/ GENx___x___x___ , /*A4AA*/ GENx___x___x___ , /*A4AB*/ GENx___x___x___ , /*A4AC*/ GENx___x___x___ , /*A4AD*/ GENx___x___x___ , /*A4AE*/ GENx___x___x___ , /*A4AF*/ GENx___x___x___ , /*A4B0*/ GENx___x___x___ , /*A4B1*/ GENx___x___x___ , /*A4B2*/ GENx___x___x___ , /*A4B3*/ GENx___x___x___ , /*A4B4*/ GENx___x___x___ , /*A4B5*/ GENx___x___x___ , /*A4B6*/ GENx___x___x___ , /*A4B7*/ GENx___x___x___ , /*A4B8*/ GENx___x___x___ , /*A4B9*/ GENx___x___x___ , /*A4BA*/ GENx___x___x___ , /*A4BB*/ GENx___x___x___ , /*A4BC*/ GENx___x___x___ , /*A4BD*/ GENx___x___x___ , /*A4BE*/ GENx___x___x___ , /*A4BF*/ GENx___x___x___ , /*A4C0*/ GENx___x___x___ , /*A4C1*/ GENx___x___x___ , /*A4C2*/ GENx___x___x___ , /*A4C3*/ GENx___x___x___ , /*A4C4*/ GENx___x___x___ , /*A4C5*/ GENx___x___x___ , /*A4C6*/ GENx___x___x___ , /*A4C7*/ GENx___x___x___ , /*A4C8*/ GENx___x___x___ , /*A4C9*/ GENx___x___x___ , /*A4CA*/ GENx___x___x___ , /*A4CB*/ GENx___x___x___ , /*A4CC*/ GENx___x___x___ , /*A4CD*/ GENx___x___x___ , /*A4CE*/ GENx___x___x___ , /*A4CF*/ GENx___x___x___ , /*A4D0*/ GENx___x___x___ , /*A4D1*/ GENx___x___x___ , /*A4D2*/ GENx___x___x___ , /*A4D3*/ GENx___x___x___ , /*A4D4*/ GENx___x___x___ , /*A4D5*/ GENx___x___x___ , /*A4D6*/ GENx___x___x___ , /*A4D7*/ GENx___x___x___ , /*A4D8*/ GENx___x___x___ , /*A4D9*/ GENx___x___x___ , /*A4DA*/ GENx___x___x___ , /*A4DB*/ GENx___x___x___ , /*A4DC*/ GENx___x___x___ , /*A4DD*/ GENx___x___x___ , /*A4DE*/ GENx___x___x___ , /*A4DF*/ GENx___x___x___ , /*A4E0*/ GENx___x___x___ , /*A4E1*/ GENx___x___x___ , /*A4E2*/ GENx___x___x___ , /*A4E3*/ GENx___x___x___ , /*A4E4*/ GENx___x___x___ , /*A4E5*/ GENx___x___x___ , /*A4E6*/ GENx___x___x___ , /*A4E7*/ GENx___x___x___ , /*A4E8*/ GENx___x___x___ , /*A4E9*/ GENx___x___x___ , /*A4EA*/ GENx___x___x___ , /*A4EB*/ GENx___x___x___ , /*A4EC*/ GENx___x___x___ , /*A4ED*/ GENx___x___x___ , /*A4EE*/ GENx___x___x___ , /*A4EF*/ GENx___x___x___ , /*A4F0*/ GENx___x___x___ , /*A4F1*/ GENx___x___x___ , /*A4F2*/ GENx___x___x___ , /*A4F3*/ GENx___x___x___ , /*A4F4*/ GENx___x___x___ , /*A4F5*/ GENx___x___x___ , /*A4F6*/ GENx___x___x___ , /*A4F7*/ GENx___x___x___ , /*A4F8*/ GENx___x___x___ , /*A4F9*/ GENx___x___x___ , /*A4FA*/ GENx___x___x___ , /*A4FB*/ GENx___x___x___ , /*A4FC*/ GENx___x___x___ , /*A4FD*/ GENx___x___x___ , /*A4FE*/ GENx___x___x___ , /*A4FF*/ GENx___x___x___ }; // #endif /*defined(FEATURE_ESAME)*/ // #if defined(FEATURE_ESAME) DLL_EXPORT zz_func opcode_a5xx[16][GEN_MAXARCH] = { /*A5x0*/ GENx___x___x900 (insert_immediate_high_high,RI,"IIHH"), /*A5x1*/ GENx___x___x900 (insert_immediate_high_low,RI,"IIHL"), /*A5x2*/ GENx___x___x900 (insert_immediate_low_high,RI,"IILH"), /*A5x3*/ GENx___x___x900 (insert_immediate_low_low,RI,"IILL"), /*A5x4*/ GENx___x___x900 (and_immediate_high_high,RI,"NIHH"), /*A5x5*/ GENx___x___x900 (and_immediate_high_low,RI,"NIHL"), /*A5x6*/ GENx___x___x900 (and_immediate_low_high,RI,"NILH"), /*A5x7*/ GENx___x___x900 (and_immediate_low_low,RI,"NILL"), /*A5x8*/ GENx___x___x900 (or_immediate_high_high,RI,"OIHH"), /*A5x9*/ GENx___x___x900 (or_immediate_high_low,RI,"OIHL"), /*A5xA*/ GENx___x___x900 (or_immediate_low_high,RI,"OILH"), /*A5xB*/ GENx___x___x900 (or_immediate_low_low,RI,"OILL"), /*A5xC*/ GENx___x___x900 (load_logical_immediate_high_high,RI,"LLIHH"), /*A5xD*/ GENx___x___x900 (load_logical_immediate_high_low,RI,"LLIHL"), /*A5xE*/ GENx___x___x900 (load_logical_immediate_low_high,RI,"LLILH"), /*A5xF*/ GENx___x___x900 (load_logical_immediate_low_low,RI,"LLILL") } ; // #endif /*defined(FEATURE_ESAME)*/ DLL_EXPORT zz_func opcode_a7xx[16][GEN_MAXARCH] = { /*A7x0*/ GENx37Xx390x900 (test_under_mask_high,RI,"TMLH"), /*A7x1*/ GENx37Xx390x900 (test_under_mask_low,RI,"TMLL"), /*A7x2*/ GENx___x___x900 (test_under_mask_high_high,RI,"TMHH"), /*A7x3*/ GENx___x___x900 (test_under_mask_high_low,RI,"TMHL"), /*A7x4*/ GENx37Xx390x900 (branch_relative_on_condition,RI_B,"BRC"), /*A7x5*/ GENx37Xx390x900 (branch_relative_and_save,RI_B,"BRAS"), /*A7x6*/ GENx37Xx390x900 (branch_relative_on_count,RI_B,"BRCT"), /*A7x7*/ GENx___x___x900 (branch_relative_on_count_long,RI_B,"BRCTG"), /*A7x8*/ GENx37Xx390x900 (load_halfword_immediate,RI,"LHI"), /*A7x9*/ GENx___x___x900 (load_long_halfword_immediate,RI,"LGHI"), /*A7xA*/ GENx37Xx390x900 (add_halfword_immediate,RI,"AHI"), /*A7xB*/ GENx___x___x900 (add_long_halfword_immediate,RI,"AGHI"), /*A7xC*/ GENx37Xx390x900 (multiply_halfword_immediate,RI,"MHI"), /*A7xD*/ GENx___x___x900 (multiply_long_halfword_immediate,RI,"MGHI"), /*A7xE*/ GENx37Xx390x900 (compare_halfword_immediate,RI,"CHI"), /*A7xF*/ GENx___x___x900 (compare_long_halfword_immediate,RI,"CGHI") }; DLL_EXPORT zz_func opcode_b2xx[256][GEN_MAXARCH] = { /*B200*/ GENx370x___x___ (connect_channel_set,S,"CONCS"), /*B201*/ GENx370x___x___ (disconnect_channel_set,S,"DISCS"), /*B202*/ GENx370x390x900 (store_cpu_id,S,"STIDP"), /*B203*/ GENx370x___x___ (store_channel_id,S,"STIDC"), /*B204*/ GENx370x390x900 (set_clock,S,"SCK"), /*B205*/ GENx370x390x900 (store_clock,S,"STCK"), /*B206*/ GENx370x390x900 (set_clock_comparator,S,"SCKC"), /*B207*/ GENx370x390x900 (store_clock_comparator,S,"STCKC"), /*B208*/ GENx370x390x900 (set_cpu_timer,S,"SPT"), /*B209*/ GENx370x390x900 (store_cpu_timer,S,"STPT"), /*B20A*/ GENx370x390x900 (set_psw_key_from_address,S,"SPKA"), /*B20B*/ GENx370x390x900 (insert_psw_key,none,"IPK"), /*B20C*/ GENx___x___x___ , /*B20D*/ GENx370x390x900 (purge_translation_lookaside_buffer,none,"PTLB"), /*B20E*/ GENx___x___x___ , /*B20F*/ GENx___x___x___ , /*B210*/ GENx370x390x900 (set_prefix,S,"SPX"), /*B211*/ GENx370x390x900 (store_prefix,S,"STPX"), /*B212*/ GENx370x390x900 (store_cpu_address,S,"STAP"), /*B213*/ GENx370x___x___ (reset_reference_bit,S,"RRB"), /*B214*/ GENx___x390x900 (start_interpretive_execution,S,"SIE"), /*B215*/ GENx___x___x___ , /*B216*/ GENx___x___x___ , /*%SETR/SSYN */ /*B217*/ GENx___x___x___ , /*%STETR/STSYN */ /*B218*/ GENx370x390x900 (program_call,S,"PC"), /*B219*/ GENx370x390x900 (set_address_space_control,S,"SAC"), /*B21A*/ GENx___x390x900 (compare_and_form_codeword,S,"CFC"), /*B21B*/ GENx___x___x___ , /*B21C*/ GENx___x___x___ , /*B21D*/ GENx___x___x___ , /*B21E*/ GENx___x___x___ , /*B21F*/ GENx___x___x___ , /*B220*/ GENx___x390x900 (service_call,RRE,"SERVC"), /*B221*/ GENx370x390x900 (invalidate_page_table_entry,RRR,"IPTE"), /*B222*/ GENx370x390x900 (insert_program_mask,RRE_R1,"IPM"), /*B223*/ GENx370x390x900 (insert_virtual_storage_key,RRE,"IVSK"), /*B224*/ GENx370x390x900 (insert_address_space_control,RRE_R1,"IAC"), /*B225*/ GENx370x390x900 (set_secondary_asn,RRE_R1,"SSAR"), /*B226*/ GENx370x390x900 (extract_primary_asn,RRE_R1,"EPAR"), /*B227*/ GENx370x390x900 (extract_secondary_asn,RRE_R1,"ESAR"), /*B228*/ GENx370x390x900 (program_transfer,RRE,"PT"), /*B229*/ GENx370x390x900 (insert_storage_key_extended,RRE,"ISKE"), /*B22A*/ GENx370x390x900 (reset_reference_bit_extended,RRE,"RRBE"), /*B22B*/ GENx370x390x900 (set_storage_key_extended,RRF_M,"SSKE"), /*B22C*/ GENx370x390x900 (test_block,RRE,"TB"), /*B22D*/ GENx370x390x900 (divide_float_ext_reg,RRE,"DXR"), /*B22E*/ GENx___x390x900 (page_in,RRE,"PGIN"), /*B22F*/ GENx___x390x900 (page_out,RRE,"PGOUT"), /*B230*/ GENx___x390x900 (clear_subchannel,none,"CSCH"), /*B231*/ GENx___x390x900 (halt_subchannel,none,"HSCH"), /*B232*/ GENx___x390x900 (modify_subchannel,S,"MSCH"), /*B233*/ GENx___x390x900 (start_subchannel,S,"SSCH"), /*B234*/ GENx___x390x900 (store_subchannel,S,"STSCH"), /*B235*/ GENx___x390x900 (test_subchannel,S,"TSCH"), /*B236*/ GENx___x390x900 (test_pending_interruption,S,"TPI"), /*B237*/ GENx___x390x900 (set_address_limit,none,"SAL"), /*B238*/ GENx___x390x900 (resume_subchannel,none,"RSCH"), /*B239*/ GENx___x390x900 (store_channel_report_word,S,"STCRW"), /*B23A*/ GENx___x390x900 (store_channel_path_status,S,"STCPS"), /*B23B*/ GENx___x390x900 (reset_channel_path,none,"RCHP"), /*B23C*/ GENx___x390x900 (set_channel_monitor,none,"SCHM"), /*B23D*/ GENx___x390x900 (store_zone_parameter,S,"STZP"), /*B23E*/ GENx___x390x900 (set_zone_parameter,S,"SZP"), /*B23F*/ GENx___x390x900 (test_pending_zone_interrupt,S,"TPZI"), /*B240*/ GENx___x390x900 (branch_and_stack,RRE,"BAKR"), /*B241*/ GENx37Xx390x900 (checksum,RRE,"CKSM"), /*B242*/ GENx___x___x___ , /**Add FRR */ /*B243*/ GENx___x___x___ , /*#MA */ /*B244*/ GENx37Xx390x900 (squareroot_float_long_reg,RRE,"SQDR"), /*B245*/ GENx37Xx390x900 (squareroot_float_short_reg,RRE,"SQER"), /*B246*/ GENx___x390x900 (store_using_real_address,RRE,"STURA"), /*B247*/ GENx___x390x900 (modify_stacked_state,RRE_R1,"MSTA"), /*B248*/ GENx___x390x900 (purge_accesslist_lookaside_buffer,none,"PALB"), /*B249*/ GENx___x390x900 (extract_stacked_registers,RRE,"EREG"), /*B24A*/ GENx___x390x900 (extract_stacked_state,RRE,"ESTA"), /*B24B*/ GENx___x390x900 (load_using_real_address,RRE,"LURA"), /*B24C*/ GENx___x390x900 (test_access,RRE,"TAR"), /*B24D*/ GENx___x390x900 (copy_access,RRE,"CPYA"), /*B24E*/ GENx___x390x900 (set_access_register,RRE,"SAR"), /*B24F*/ GENx___x390x900 (extract_access_register,RRE,"EAR"), /*B250*/ GENx___x390x900 (compare_and_swap_and_purge,RRE,"CSP"), /*B251*/ GENx___x___x___ , /*B252*/ GENx37Xx390x900 (multiply_single_register,RRE,"MSR"), /*B253*/ GENx___x___x___ , /*B254*/ GENx___x390x900 (move_page,RRE,"MVPG"), /*B255*/ GENx37Xx390x900 (move_string,RRE,"MVST"), /*B256*/ GENx___x___x___ , /*B257*/ GENx37Xx390x900 (compare_until_substring_equal,RRE,"CUSE"), /*B258*/ GENx___x390x900 (branch_in_subspace_group,RRE,"BSG"), /*B259*/ GENx___x390x900 (invalidate_expanded_storage_block_entry,RRE,"IESBE"), /*B25A*/ GENx___x390x900 (branch_and_set_authority,RRE,"BSA"), /*B25B*/ GENx___x___x___ , /*%PGXIN */ /*B25C*/ GENx___x___x___ , /*%PGXOUT */ /*B25D*/ GENx37Xx390x900 (compare_logical_string,RRE,"CLST"), /*B25E*/ GENx37Xx390x900 (search_string,RRE,"SRST"), /*B25F*/ GENx___x390x900 (channel_subsystem_call,RRE,"CHSC"), /*B260*/ GENx___x___x___ , /* Sysplex */ /*B261*/ GENx___x___x___ , /* Sysplex */ /*B262*/ GENx___x390x900 (lock_page,RRE,"LKPG"), /*B263*/ GENx37Xx390x900 (compression_call,RRE,"CMPSC"), /*B264*/ GENx___x___x___ , /* Sysplex */ /*B265*/ GENx___x___x___ , /*(set_vector_summary,?,"SVS"),*/ /* Sysplex */ /*B266*/ GENx___x___x___ , /* Sysplex */ /*B267*/ GENx___x___x___ , /* Sysplex */ /*B268*/ GENx___x___x___ , /*(define_vector,?,"DV"),*/ /* Sysplex */ /*B269*/ GENx___x___x___ , /* Crypto */ /*B26A*/ GENx___x___x___ , /* Crypto */ /*B26B*/ GENx___x___x___ , /* Crypto */ /*B26C*/ GENx___x___x___ , /* Crypto */ /*B26D*/ GENx___x___x___ , /* Crypto */ /*B26E*/ GENx___x___x___ , /* Crypto */ /*B26F*/ GENx___x___x___ , /* Crypto */ /*B270*/ GENx___x___x___ , /*%SPCS */ /*B271*/ GENx___x___x___ , /*%STPCS */ /*B272*/ GENx___x___x___ , /* Sysplex */ /*B273*/ GENx___x___x___ , /*B274*/ GENx___x390x900 (signal_adapter,S,"SIGA"), /*B275*/ GENx___x___x___ , /*B276*/ GENx___x390x900 (cancel_subchannel,none,"XSCH"), /*B277*/ GENx___x390x900 (resume_program,S,"RP"), /*B278*/ GENx___x390x900 (store_clock_extended,S,"STCKE"), /*B279*/ GENx___x390x900 (set_address_space_control_fast,S,"SACF"), /*B27A*/ GENx___x___x___ , /* Sysplex */ /*B27B*/ GENx___x___x___ , /* TFF/Sysplx*/ /*B27C*/ GENx___x___x900 (store_clock_fast,S,"STCKF"), /*B27D*/ GENx370x390x900 (store_system_information,S,"STSI"), /*B27E*/ GENx___x___x___ , /* Sysplex */ /*B27F*/ GENx___x___x___ , /* Sysplex */ /*B280*/ GENx___x___x900 (load_program_parameter,S,"LPP"), /* LPPF */ /*B281*/ GENx___x___x___ , /*#LN S */ /*B282*/ GENx___x___x___ , /*#EXP L */ /*B283*/ GENx___x___x___ , /*#EXP S */ /*B284*/ GENx___x___x900 (load_cpu_counter_set_controls,S,"LCCTL"), /* CMCF */ /*B285*/ GENx___x___x900 (load_peripheral_counter_set_controls,S,"LPCTL"), /* CMCF */ /*B286*/ GENx___x___x900 (query_sampling_information,S,"QSI"), /* CMCF */ /*B287*/ GENx___x___x900 (load_sampling_controls,S,"LSCTL"), /* CMCF */ /*B288*/ GENx___x___x___ , /*#SIN L */ /*B289*/ GENx___x___x___ , /*#SIN S */ /*B28A*/ GENx___x___x___ , /*#COS L */ /*B28B*/ GENx___x___x___ , /*#COS S */ /*B28C*/ GENx___x___x___ , /*B28D*/ GENx___x___x___ , /*B28E*/ GENx___x___x900 (query_counter_information,S,"QCTRI"), /* CMCF */ /*B28F*/ GENx___x___x___ , /*B290*/ GENx___x___x___ , /*B291*/ GENx___x___x___ , /*B292*/ GENx___x___x___ , /*B293*/ GENx___x___x___ , /*B294*/ GENx___x___x___ , /*#ARCTAN L */ /*B295*/ GENx___x___x___ , /*#ARCTAN S */ /*B296*/ GENx___x___x___ , /*B297*/ GENx___x___x___ , /*B298*/ GENx___x___x___ , /*B299*/ GENx37Xx390x900 (set_bfp_rounding_mode_2bit,S,"SRNM"), /*B29A*/ GENx___x___x___ , /*B29B*/ GENx___x___x___ , /*B29C*/ GENx37Xx390x900 (store_fpc,S,"STFPC"), /*B29D*/ GENx37Xx390x900 (load_fpc,S,"LFPC"), /*B29E*/ GENx___x___x___ , /*B29F*/ GENx___x___x___ , /*B2A0*/ GENx___x___x___ , /*B2A1*/ GENx___x___x___ , /*B2A2*/ GENx___x___x___ , /*B2A3*/ GENx___x___x___ , /*B2A4*/ GENx___x___x___ , /*(move_channel_buffer_data_multiple,?,"MCBDM"),*//*Sysplex*/ /*B2A5*/ GENx37Xx390x900 (translate_extended,RRE,"TRE"), /*B2A6*/ GENx37Xx390x900 (convert_utf16_to_utf8,RRF_M3,"CU21 (CUUTF)"), /*B2A7*/ GENx37Xx390x900 (convert_utf8_to_utf16,RRF_M3,"CU12 (CUTFU)"), /*B2A8*/ GENx___x___x___ , /* Sysplex */ /*B2A9*/ GENx___x___x___ , /*B2AA*/ GENx___x___x___ , /*B2AB*/ GENx___x___x___ , /*B2AC*/ GENx___x___x___ , /*B2AD*/ GENx___x___x___ , /*B2AE*/ GENx___x___x___ , /*B2AF*/ GENx___x___x___ , /*B2B0*/ GENx___x390x900 (store_facility_list_extended,S,"STFLE"), /*!SARCH */ /*@Z9*/ /*B2B1*/ GENx___x390x900 (store_facility_list,S,"STFL"), /*B2B2*/ GENx___x___x900 (load_program_status_word_extended,S,"LPSWE"), /*B2B3*/ GENx___x___x___ , /*(store_etr_attachment_information,?,"STEAI"),*/ /*B2B4*/ GENx___x___x___ , /*B2B5*/ GENx___x___x___ , /*B2B6*/ GENx___x___x___ , /*B2B7*/ GENx___x___x___ , /*B2B8*/ GENx37Xx390x900 (set_bfp_rounding_mode_3bit,S,"SRNMB"), /*810*/ /*B2B9*/ GENx___x390x900 (set_dfp_rounding_mode,S,"SRNMT"), /*B2BA*/ GENx___x___x___ , /*B2BB*/ GENx___x___x___ , /*B2BC*/ GENx___x___x___ , /*B2BD*/ GENx37Xx390x900 (load_fpc_and_signal,S,"LFAS"), /*B2BE*/ GENx___x___x___ , /*B2BF*/ GENx___x___x___ , /*B2C0*/ GENx___x___x___ , /*$ADRN */ /*B2C1*/ GENx___x___x___ , /*$AERN */ /*B2C2*/ GENx___x___x___ , /*$SDRN */ /*B2C3*/ GENx___x___x___ , /*$SERN */ /*B2C4*/ GENx___x___x___ , /*$MDRN */ /*B2C5*/ GENx___x___x___ , /*$MERN */ /*B2C6*/ GENx___x___x___ , /*$DDRN */ /*B2C7*/ GENx___x___x___ , /*$DERN */ /*B2C8*/ GENx___x___x___ , /*$LERN */ /*B2C9*/ GENx___x___x___ , /*B2CA*/ GENx___x___x___ , /*B2CB*/ GENx___x___x___ , /*B2CC*/ GENx___x___x___ , /*B2CD*/ GENx___x___x___ , /*B2CE*/ GENx___x___x___ , /*B2CF*/ GENx___x___x___ , /*B2D0*/ GENx___x___x___ , /*$AACDR */ /*B2D1*/ GENx___x___x___ , /*$AACER */ /*B2D2*/ GENx___x___x___ , /*$SACDR */ /*B2D3*/ GENx___x___x___ , /*$SACER */ /*B2D4*/ GENx___x___x___ , /*$MACD */ /*B2D5*/ GENx___x___x___ , /*B2D6*/ GENx___x___x___ , /*$RACD */ /*B2D7*/ GENx___x___x___ , /*$RACE */ /*B2D8*/ GENx___x___x___ , /*$AACAC */ /*B2D9*/ GENx___x___x___ , /*$SACAC */ /*B2DA*/ GENx___x___x___ , /*$CLAC */ /*B2DB*/ GENx___x___x___ , /*B2DC*/ GENx___x___x___ , /*B2DD*/ GENx___x___x___ , /*B2DE*/ GENx___x___x___ , /*B2DF*/ GENx___x___x___ , /*B2E0*/ GENx___x___x900 (set_cpu_counter,RRE,"SCCTR"), /* CMCF */ /*B2E1*/ GENx___x___x900 (set_peripheral_counter,RRE,"SPCTR"), /* CMCF */ /*B2E2*/ GENx___x___x___ , /*B2E3*/ GENx___x___x___ , /*B2E4*/ GENx___x___x900 (extract_cpu_counter,RRE,"ECCTR"), /* CMCF */ /*B2E5*/ GENx___x___x900 (extract_peripheral_counter,RRE,"EPCTR"), /* CMCF */ /*B2E6*/ GENx___x___x___ , /*B2E7*/ GENx___x___x___ , /*B2E8*/ GENx___x___x900 (perform_processor_assist,RRF_M3,"PPA"), /*912*/ /*B2E9*/ GENx___x___x___ , /*B2EA*/ GENx___x___x___ , /*B2EB*/ GENx___x___x___ , /*B2EC*/ GENx___x___x900 (extract_transaction_nesting_depth,RRE_R1,"ETND"), /*912*/ /*B2ED*/ GENx___x___x900 (extract_coprocessor_group_address,RRE,"ECPGA"), /* CMCF */ /*B2EE*/ GENx___x___x___ , /*B2EF*/ GENx___x___x___ , /*B2F0*/ GENx370x390x900 (inter_user_communication_vehicle,S,"IUCV"), /*B2F1*/ GENx___x___x___ , /* Sysplex */ /*B2F2*/ GENx___x___x___ , /*B2F3*/ GENx___x___x___ , /*B2F4*/ GENx___x___x___ , /*B2F5*/ GENx___x___x___ , /*B2F6*/ GENx___x___x___ , /* Sysplex */ /*B2F7*/ GENx___x___x___ , /*B2F8*/ GENx___x___x900 (transaction_end,none,"TEND"), /*912*/ /*B2F9*/ GENx___x___x___ , /*B2FA*/ GENx___x___x900 (next_instruction_access_intent,IE,"NIAI"), /*912*/ /*B2FB*/ GENx___x___x___ , /*B2FC*/ GENx___x___x900 (transaction_abort,S,"TABORT"), /*912*/ /*B2FD*/ GENx___x___x___ , /*B2FE*/ GENx___x___x___ , /*B2FF*/ GENx___x390x900 (trap4,S,"TRAP4") }; // #if defined(FEATURE_BASIC_FP_EXTENSIONS) DLL_EXPORT zz_func opcode_b3xx[256][GEN_MAXARCH] = { /*B300*/ GENx37Xx390x900 (load_positive_bfp_short_reg,RRE,"LPEBR"), /*B301*/ GENx37Xx390x900 (load_negative_bfp_short_reg,RRE,"LNEBR"), /*B302*/ GENx37Xx390x900 (load_and_test_bfp_short_reg,RRE,"LTEBR"), /*B303*/ GENx37Xx390x900 (load_complement_bfp_short_reg,RRE,"LCEBR"), /*B304*/ GENx37Xx390x900 (load_lengthened_bfp_short_to_long_reg,RRE,"LDEBR"), /*B305*/ GENx37Xx390x900 (load_lengthened_bfp_long_to_ext_reg,RRE,"LXDBR"), /*B306*/ GENx37Xx390x900 (load_lengthened_bfp_short_to_ext_reg,RRE,"LXEBR"), /*B307*/ GENx37Xx390x900 (multiply_bfp_long_to_ext_reg,RRE,"MXDBR"), /*B308*/ GENx37Xx390x900 (compare_and_signal_bfp_short_reg,RRE,"KEBR"), /*B309*/ GENx37Xx390x900 (compare_bfp_short_reg,RRE,"CEBR"), /*B30A*/ GENx37Xx390x900 (add_bfp_short_reg,RRE,"AEBR"), /*B30B*/ GENx37Xx390x900 (subtract_bfp_short_reg,RRE,"SEBR"), /*B30C*/ GENx37Xx390x900 (multiply_bfp_short_to_long_reg,RRE,"MDEBR"), /*B30D*/ GENx37Xx390x900 (divide_bfp_short_reg,RRE,"DEBR"), /*B30E*/ GENx37Xx390x900 (multiply_add_bfp_short_reg,RRF_R,"MAEBR"), /*B30F*/ GENx37Xx390x900 (multiply_subtract_bfp_short_reg,RRF_R,"MSEBR"), /*B310*/ GENx37Xx390x900 (load_positive_bfp_long_reg,RRE,"LPDBR"), /*B311*/ GENx37Xx390x900 (load_negative_bfp_long_reg,RRE,"LNDBR"), /*B312*/ GENx37Xx390x900 (load_and_test_bfp_long_reg,RRE,"LTDBR"), /*B313*/ GENx37Xx390x900 (load_complement_bfp_long_reg,RRE,"LCDBR"), /*B314*/ GENx37Xx390x900 (squareroot_bfp_short_reg,RRE,"SQEBR"), /*B315*/ GENx37Xx390x900 (squareroot_bfp_long_reg,RRE,"SQDBR"), /*B316*/ GENx37Xx390x900 (squareroot_bfp_ext_reg,RRE,"SQXBR"), /*B317*/ GENx37Xx390x900 (multiply_bfp_short_reg,RRE,"MEEBR"), /*B318*/ GENx37Xx390x900 (compare_and_signal_bfp_long_reg,RRE,"KDBR"), /*B319*/ GENx37Xx390x900 (compare_bfp_long_reg,RRE,"CDBR"), /*B31A*/ GENx37Xx390x900 (add_bfp_long_reg,RRE,"ADBR"), /*B31B*/ GENx37Xx390x900 (subtract_bfp_long_reg,RRE,"SDBR"), /*B31C*/ GENx37Xx390x900 (multiply_bfp_long_reg,RRE,"MDBR"), /*B31D*/ GENx37Xx390x900 (divide_bfp_long_reg,RRE,"DDBR"), /*B31E*/ GENx37Xx390x900 (multiply_add_bfp_long_reg,RRF_R,"MADBR"), /*B31F*/ GENx37Xx390x900 (multiply_subtract_bfp_long_reg,RRF_R,"MSDBR"), /*B320*/ GENx___x___x___ , /*B321*/ GENx___x___x___ , /*B322*/ GENx___x___x___ , /*B323*/ GENx___x___x___ , /*B324*/ GENx37Xx390x900 (load_lengthened_float_short_to_long_reg,RRE,"LDER"), /*B325*/ GENx37Xx390x900 (load_lengthened_float_long_to_ext_reg,RRE,"LXDR"), /*B326*/ GENx37Xx390x900 (load_lengthened_float_short_to_ext_reg,RRE,"LXER"), /*B327*/ GENx___x___x___ , /*B328*/ GENx___x___x___ , /*B329*/ GENx___x___x___ , /*B32A*/ GENx___x___x___ , /*B32B*/ GENx___x___x___ , /*B32C*/ GENx___x___x___ , /*B32D*/ GENx___x___x___ , /*B32E*/ GENx37Xx390x900 (multiply_add_float_short_reg,RRF_R,"MAER"), /*B32F*/ GENx37Xx390x900 (multiply_subtract_float_short_reg,RRF_R,"MSER"), /*B330*/ GENx___x___x___ , /*B331*/ GENx___x___x___ , /*B332*/ GENx___x___x___ , /*B333*/ GENx___x___x___ , /*B334*/ GENx___x___x___ , /*B335*/ GENx___x___x___ , /*B336*/ GENx37Xx390x900 (squareroot_float_ext_reg,RRE,"SQXR"), /*B337*/ GENx37Xx390x900 (multiply_float_short_reg,RRE,"MEER"), /*B338*/ GENx37Xx___x900 (multiply_add_unnormal_float_long_to_ext_low_reg,RRF_R,"MAYLR"), /*@Z9*/ /*B339*/ GENx37Xx___x900 (multiply_unnormal_float_long_to_ext_low_reg,RRF_R,"MYLR"), /*@Z9*/ /*B33A*/ GENx37Xx___x900 (multiply_add_unnormal_float_long_to_ext_reg,RRF_R,"MAYR"), /*@Z9*/ /*B33B*/ GENx37Xx___x900 (multiply_unnormal_float_long_to_ext_reg,RRF_R,"MYR"), /*@Z9*/ /*B33C*/ GENx37Xx___x900 (multiply_add_unnormal_float_long_to_ext_high_reg,RRF_R,"MAYHR"), /*@Z9*/ /*B33D*/ GENx37Xx___x900 (multiply_unnormal_float_long_to_ext_high_reg,RRF_R,"MYHR"), /*@Z9*/ /*B33E*/ GENx37Xx390x900 (multiply_add_float_long_reg,RRF_R,"MADR"), /*B33F*/ GENx37Xx390x900 (multiply_subtract_float_long_reg,RRF_R,"MSDR"), /*B340*/ GENx37Xx390x900 (load_positive_bfp_ext_reg,RRE,"LPXBR"), /*B341*/ GENx37Xx390x900 (load_negative_bfp_ext_reg,RRE,"LNXBR"), /*B342*/ GENx37Xx390x900 (load_and_test_bfp_ext_reg,RRE,"LTXBR"), /*B343*/ GENx37Xx390x900 (load_complement_bfp_ext_reg,RRE,"LCXBR"), /*B344*/ GENx37Xx390x900 (load_rounded_bfp_long_to_short_reg,RRE_MMA,"LEDBR"), /*B345*/ GENx37Xx390x900 (load_rounded_bfp_ext_to_long_reg,RRE_MMA,"LDXBR"), /*B346*/ GENx37Xx390x900 (load_rounded_bfp_ext_to_short_reg,RRE_MMA,"LEXBR"), /*B347*/ GENx37Xx390x900 (load_fp_int_bfp_ext_reg,RRF_MMA,"FIXBR"), /*B348*/ GENx37Xx390x900 (compare_and_signal_bfp_ext_reg,RRE,"KXBR"), /*B349*/ GENx37Xx390x900 (compare_bfp_ext_reg,RRE,"CXBR"), /*B34A*/ GENx37Xx390x900 (add_bfp_ext_reg,RRE,"AXBR"), /*B34B*/ GENx37Xx390x900 (subtract_bfp_ext_reg,RRE,"SXBR"), /*B34C*/ GENx37Xx390x900 (multiply_bfp_ext_reg,RRE,"MXBR"), /*B34D*/ GENx37Xx390x900 (divide_bfp_ext_reg,RRE,"DXBR"), /*B34E*/ GENx___x___x___ , /*B34F*/ GENx___x___x___ , /*B350*/ GENx37Xx390x900 (convert_float_long_to_bfp_short_reg,RRF_M,"TBEDR"), /*B351*/ GENx37Xx390x900 (convert_float_long_to_bfp_long_reg,RRF_M,"TBDR"), /*B352*/ GENx___x___x___ , /*B353*/ GENx37Xx390x900 (divide_integer_bfp_short_reg,RRF_RM,"DIEBR"), /*B354*/ GENx___x___x___ , /*B355*/ GENx___x___x___ , /*B356*/ GENx___x___x___ , /*B357*/ GENx37Xx390x900 (load_fp_int_bfp_short_reg,RRF_MMA,"FIEBR"), /*B358*/ GENx37Xx390x900 (convert_bfp_short_to_float_long_reg,RRE,"THDER"), /*B359*/ GENx37Xx390x900 (convert_bfp_long_to_float_long_reg,RRE,"THDR"), /*B35A*/ GENx___x___x___ , /*B35B*/ GENx37Xx390x900 (divide_integer_bfp_long_reg,RRF_RM,"DIDBR"), /*B35C*/ GENx___x___x___ , /*B35D*/ GENx___x___x___ , /*B35E*/ GENx___x___x___ , /*B35F*/ GENx37Xx390x900 (load_fp_int_bfp_long_reg,RRF_MMA,"FIDBR"), /*B360*/ GENx37Xx390x900 (load_positive_float_ext_reg,RRE,"LPXR"), /*B361*/ GENx37Xx390x900 (load_negative_float_ext_reg,RRE,"LNXR"), /*B362*/ GENx37Xx390x900 (load_and_test_float_ext_reg,RRE,"LTXR"), /*B363*/ GENx37Xx390x900 (load_complement_float_ext_reg,RRE,"LCXR"), /*B364*/ GENx___x___x___ , /*B365*/ GENx37Xx390x900 (load_float_ext_reg,RRE,"LXR"), /*B366*/ GENx37Xx390x900 (load_rounded_float_ext_to_short_reg,RRE,"LEXR"), /*B367*/ GENx37Xx390x900 (load_fp_int_float_ext_reg,RRE,"FIXR"), /*B368*/ GENx___x___x___ , /*B369*/ GENx37Xx390x900 (compare_float_ext_reg,RRE,"CXR"), /*B36A*/ GENx___x___x___ , /*B36B*/ GENx___x___x___ , /*B36C*/ GENx___x___x___ , /*B36D*/ GENx___x___x___ , /*B36E*/ GENx___x___x___ , /*B36F*/ GENx___x___x___ , /*B370*/ GENx37Xx390x900 (load_positive_fpr_long_reg,RRE,"LPDFR"), /*B371*/ GENx37Xx390x900 (load_negative_fpr_long_reg,RRE,"LNDFR"), /*B372*/ GENx37Xx390x900 (copy_sign_fpr_long_reg,RRF_M,"CPSDR"), /*B373*/ GENx37Xx390x900 (load_complement_fpr_long_reg,RRE,"LCDFR"), /*B374*/ GENx37Xx390x900 (load_zero_float_short_reg,RRE_R1,"LZER"), /*B375*/ GENx37Xx390x900 (load_zero_float_long_reg,RRE_R1,"LZDR"), /*B376*/ GENx37Xx390x900 (load_zero_float_ext_reg,RRE_R1,"LZXR"), /*B377*/ GENx37Xx390x900 (load_fp_int_float_short_reg,RRE,"FIER"), /*B378*/ GENx___x___x___ , /*B379*/ GENx___x___x___ , /*B37A*/ GENx___x___x___ , /*B37B*/ GENx___x___x___ , /*B37C*/ GENx___x___x___ , /*B37D*/ GENx___x___x___ , /*B37E*/ GENx___x___x___ , /*B37F*/ GENx37Xx390x900 (load_fp_int_float_long_reg,RRE,"FIDR"), /*B380*/ GENx___x___x___ , /*B381*/ GENx___x___x___ , /*B382*/ GENx___x___x___ , /*B383*/ GENx___x___x___ , /*B384*/ GENx37Xx390x900 (set_fpc,RRE_R1,"SFPC"), /*B385*/ GENx37Xx390x900 (set_fpc_and_signal,RRE_R1,"SFASR"), /*B386*/ GENx___x___x___ , /*B387*/ GENx___x___x___ , /*B388*/ GENx___x___x___ , /*B389*/ GENx___x___x___ , /*B38A*/ GENx___x___x___ , /*B38B*/ GENx___x___x___ , /*B38C*/ GENx37Xx390x900 (extract_fpc,RRE_R1,"EFPC"), /*B38D*/ GENx___x___x___ , /*B38E*/ GENx___x___x___ , /*B38F*/ GENx___x___x___ , /*B390*/ GENx37Xx390x900 (convert_u32_to_bfp_short_reg,RRF_MM,"CELFBR"), /*810*/ /*B391*/ GENx37Xx390x900 (convert_u32_to_bfp_long_reg,RRF_MM,"CDLFBR"), /*810*/ /*B392*/ GENx37Xx390x900 (convert_u32_to_bfp_ext_reg,RRF_MM,"CXLFBR"), /*810*/ /*B393*/ GENx___x___x___ , /*B394*/ GENx37Xx390x900 (convert_fix32_to_bfp_short_reg,RRE_MMA,"CEFBR"), /*B395*/ GENx37Xx390x900 (convert_fix32_to_bfp_long_reg,RRE_MMA,"CDFBR"), /*B396*/ GENx37Xx390x900 (convert_fix32_to_bfp_ext_reg,RRE_MMA,"CXFBR"), /*B397*/ GENx___x___x___ , /*B398*/ GENx37Xx390x900 (convert_bfp_short_to_fix32_reg,RRF_MMA,"CFEBR"), /*B399*/ GENx37Xx390x900 (convert_bfp_long_to_fix32_reg,RRF_MMA,"CFDBR"), /*B39A*/ GENx37Xx390x900 (convert_bfp_ext_to_fix32_reg,RRF_MMA,"CFXBR"), /*B39B*/ GENx___x___x___ , /*B39C*/ GENx37Xx390x900 (convert_bfp_short_to_u32_reg,RRF_MM,"CLFEBR"), /*810*/ /*B39D*/ GENx37Xx390x900 (convert_bfp_long_to_u32_reg,RRF_MM,"CLFDBR"), /*810*/ /*B39E*/ GENx37Xx390x900 (convert_bfp_ext_to_u32_reg,RRF_MM,"CLFXBR"), /*810*/ /*B39F*/ GENx___x___x___ , /*B3A0*/ GENx___x___x900 (convert_u64_to_bfp_short_reg,RRF_MM,"CELGBR"), /*810*/ /*B3A1*/ GENx___x___x900 (convert_u64_to_bfp_long_reg,RRF_MM,"CDLGBR"), /*810*/ /*B3A2*/ GENx___x___x900 (convert_u64_to_bfp_ext_reg,RRF_MM,"CXLGBR"), /*810*/ /*B3A3*/ GENx___x___x___ , /*B3A4*/ GENx___x___x900 (convert_fix64_to_bfp_short_reg,RRE_MMA,"CEGBR"), /*B3A5*/ GENx___x___x900 (convert_fix64_to_bfp_long_reg,RRE_MMA,"CDGBR"), /*B3A6*/ GENx___x___x900 (convert_fix64_to_bfp_ext_reg,RRE_MMA,"CXGBR"), /*B3A7*/ GENx___x___x___ , /*B3A8*/ GENx___x___x900 (convert_bfp_short_to_fix64_reg,RRF_MMA,"CGEBR"), /*B3A9*/ GENx___x___x900 (convert_bfp_long_to_fix64_reg,RRF_MMA,"CGDBR"), /*B3AA*/ GENx___x___x900 (convert_bfp_ext_to_fix64_reg,RRF_MMA,"CGXBR"), /*B3AB*/ GENx___x___x___ , /*B3AC*/ GENx___x___x900 (convert_bfp_short_to_u64_reg,RRF_MM,"CLGEBR"), /*810*/ /*B3AD*/ GENx___x___x900 (convert_bfp_long_to_u64_reg,RRF_MM,"CLGDBR"), /*810*/ /*B3AE*/ GENx___x___x900 (convert_bfp_ext_to_u64_reg,RRF_MM,"CLGXBR"), /*810*/ /*B3AF*/ GENx___x___x___ , /*B3B0*/ GENx___x___x___ , /*B3B1*/ GENx___x___x___ , /*B3B2*/ GENx___x___x___ , /*B3B3*/ GENx___x___x___ , /*B3B4*/ GENx37Xx390x900 (convert_fixed_to_float_short_reg,RRE,"CEFR"), /*B3B5*/ GENx37Xx390x900 (convert_fixed_to_float_long_reg,RRE,"CDFR"), /*B3B6*/ GENx37Xx390x900 (convert_fixed_to_float_ext_reg,RRE,"CXFR"), /*B3B7*/ GENx___x___x___ , /*B3B8*/ GENx37Xx390x900 (convert_float_short_to_fixed_reg,RRF_M,"CFER"), /*B3B9*/ GENx37Xx390x900 (convert_float_long_to_fixed_reg,RRF_M,"CFDR"), /*B3BA*/ GENx37Xx390x900 (convert_float_ext_to_fixed_reg,RRF_M,"CFXR"), /*B3BB*/ GENx___x___x___ , /*B3BC*/ GENx___x___x___ , /*B3BD*/ GENx___x___x___ , /*B3BE*/ GENx___x___x___ , /*B3BF*/ GENx___x___x___ , /*B3C0*/ GENx___x___x___ , /*B3C1*/ GENx___x___x900 (load_fpr_from_gr_long_reg,RRE,"LDGR"), /*B3C2*/ GENx___x___x___ , /*B3C3*/ GENx___x___x___ , /*B3C4*/ GENx___x___x900 (convert_fix64_to_float_short_reg,RRE,"CEGR"), /*B3C5*/ GENx___x___x900 (convert_fix64_to_float_long_reg,RRE,"CDGR"), /*B3C6*/ GENx___x___x900 (convert_fix64_to_float_ext_reg,RRE,"CXGR"), /*B3C7*/ GENx___x___x___ , /*B3C8*/ GENx___x___x900 (convert_float_short_to_fix64_reg,RRF_M,"CGER"), /*B3C9*/ GENx___x___x900 (convert_float_long_to_fix64_reg,RRF_M,"CGDR"), /*B3CA*/ GENx___x___x900 (convert_float_ext_to_fix64_reg,RRF_M,"CGXR"), /*B3CB*/ GENx___x___x___ , /*B3CC*/ GENx___x___x___ , /*B3CD*/ GENx___x___x900 (load_gr_from_fpr_long_reg,RRE,"LGDR"), /*B3CE*/ GENx___x___x___ , /*B3CF*/ GENx___x___x___ , /*B3D0*/ GENx___x390x900 (multiply_dfp_long_reg,RRR_MA,"MDTR"), /*B3D1*/ GENx___x390x900 (divide_dfp_long_reg,RRR_MA,"DDTR"), /*B3D2*/ GENx___x390x900 (add_dfp_long_reg,RRR_MA,"ADTR"), /*B3D3*/ GENx___x390x900 (subtract_dfp_long_reg,RRR_MA,"SDTR"), /*B3D4*/ GENx___x390x900 (load_lengthened_dfp_short_to_long_reg,RRF_M4,"LDETR"), /*B3D5*/ GENx___x390x900 (load_rounded_dfp_long_to_short_reg,RRF_MM,"LEDTR"), /*B3D6*/ GENx___x390x900 (load_and_test_dfp_long_reg,RRE,"LTDTR"), /*B3D7*/ GENx___x390x900 (load_fp_int_dfp_long_reg,RRF_MM,"FIDTR"), /*B3D8*/ GENx___x390x900 (multiply_dfp_ext_reg,RRR_MA,"MXTR"), /*B3D9*/ GENx___x390x900 (divide_dfp_ext_reg,RRR_MA,"DXTR"), /*B3DA*/ GENx___x390x900 (add_dfp_ext_reg,RRR_MA,"AXTR"), /*B3DB*/ GENx___x390x900 (subtract_dfp_ext_reg,RRR_MA,"SXTR"), /*B3DC*/ GENx___x390x900 (load_lengthened_dfp_long_to_ext_reg,RRF_M4,"LXDTR"), /*B3DD*/ GENx___x390x900 (load_rounded_dfp_ext_to_long_reg,RRF_MM,"LDXTR"), /*B3DE*/ GENx___x390x900 (load_and_test_dfp_ext_reg,RRE,"LTXTR"), /*B3DF*/ GENx___x390x900 (load_fp_int_dfp_ext_reg,RRF_MM,"FIXTR"), /*B3E0*/ GENx___x390x900 (compare_and_signal_dfp_long_reg,RRE,"KDTR"), /*B3E1*/ GENx___x390x900 (convert_dfp_long_to_fix64_reg,RRF_MMA,"CGDTR"), /*B3E2*/ GENx___x390x900 (convert_dfp_long_to_ubcd64_reg,RRE,"CUDTR"), /*B3E3*/ GENx___x390x900 (convert_dfp_long_to_sbcd64_reg,RRF_M4,"CSDTR"), /*B3E4*/ GENx___x390x900 (compare_dfp_long_reg,RRE,"CDTR"), /*B3E5*/ GENx___x390x900 (extract_biased_exponent_dfp_long_to_fix64_reg,RRE,"EEDTR"), /*B3E6*/ GENx___x___x___ , /*B3E7*/ GENx___x390x900 (extract_significance_dfp_long_reg,RRE,"ESDTR"), /*B3E8*/ GENx___x390x900 (compare_and_signal_dfp_ext_reg,RRE,"KXTR"), /*B3E9*/ GENx___x390x900 (convert_dfp_ext_to_fix64_reg,RRF_MMA,"CGXTR"), /*B3EA*/ GENx___x390x900 (convert_dfp_ext_to_ubcd128_reg,RRE,"CUXTR"), /*B3EB*/ GENx___x390x900 (convert_dfp_ext_to_sbcd128_reg,RRF_M4,"CSXTR"), /*B3EC*/ GENx___x390x900 (compare_dfp_ext_reg,RRE,"CXTR"), /*B3ED*/ GENx___x390x900 (extract_biased_exponent_dfp_ext_to_fix64_reg,RRE,"EEXTR"), /*B3EE*/ GENx___x___x___ , /*B3EF*/ GENx___x390x900 (extract_significance_dfp_ext_reg,RRE,"ESXTR"), /*B3F0*/ GENx___x___x___ , /*B3F1*/ GENx___x390x900 (convert_fix64_to_dfp_long_reg,RRE_MMA,"CDGTR"), /*B3F2*/ GENx___x390x900 (convert_ubcd64_to_dfp_long_reg,RRE,"CDUTR"), /*B3F3*/ GENx___x390x900 (convert_sbcd64_to_dfp_long_reg,RRE,"CDSTR"), /*B3F4*/ GENx___x390x900 (compare_exponent_dfp_long_reg,RRE,"CEDTR"), /*B3F5*/ GENx___x390x900 (quantize_dfp_long_reg,RRF_RM,"QADTR"), /*B3F6*/ GENx___x390x900 (insert_biased_exponent_fix64_to_dfp_long_reg,RRF_M,"IEDTR"), /*B3F7*/ GENx___x390x900 (reround_dfp_long_reg,RRF_RM,"RRDTR"), /*B3F8*/ GENx___x___x___ , /*B3F9*/ GENx___x390x900 (convert_fix64_to_dfp_ext_reg,RRE_MMA,"CXGTR"), /*B3FA*/ GENx___x390x900 (convert_ubcd128_to_dfp_ext_reg,RRE,"CXUTR"), /*B3FB*/ GENx___x390x900 (convert_sbcd128_to_dfp_ext_reg,RRE,"CXSTR"), /*B3FC*/ GENx___x390x900 (compare_exponent_dfp_ext_reg,RRE,"CEXTR"), /*B3FD*/ GENx___x390x900 (quantize_dfp_ext_reg,RRF_RM,"QAXTR"), /*B3FE*/ GENx___x390x900 (insert_biased_exponent_fix64_to_dfp_ext_reg,RRF_M,"IEXTR"), /*B3FF*/ GENx___x390x900 (reround_dfp_ext_reg,RRF_RM,"RRXTR") }; // #endif /*defined(FEATURE_BASIC_FP_EXTENSIONS)*/ // #if defined(FEATURE_ESAME) DLL_EXPORT zz_func opcode_b9xx[256][GEN_MAXARCH] = { /*B900*/ GENx___x___x900 (load_positive_long_register,RRE,"LPGR"), /*B901*/ GENx___x___x900 (load_negative_long_register,RRE,"LNGR"), /*B902*/ GENx___x___x900 (load_and_test_long_register,RRE,"LTGR"), /*B903*/ GENx___x___x900 (load_complement_long_register,RRE,"LCGR"), /*B904*/ GENx___x___x900 (load_long_register,RRE,"LGR"), /*B905*/ GENx___x___x900 (load_using_real_address_long,RRE,"LURAG"), /*B906*/ GENx___x___x900 (load_long_byte_register,RRE,"LGBR"), /*@Z9*/ /*B907*/ GENx___x___x900 (load_long_halfword_register,RRE,"LGHR"), /*@Z9*/ /*B908*/ GENx___x___x900 (add_long_register,RRE,"AGR"), /*B909*/ GENx___x___x900 (subtract_long_register,RRE,"SGR"), /*B90A*/ GENx___x___x900 (add_logical_long_register,RRE,"ALGR"), /*B90B*/ GENx___x___x900 (subtract_logical_long_register,RRE,"SLGR"), /*B90C*/ GENx___x___x900 (multiply_single_long_register,RRE,"MSGR"), /*B90D*/ GENx___x___x900 (divide_single_long_register,RRE,"DSGR"), /*B90E*/ GENx___x___x900 (extract_stacked_registers_long,RRE,"EREGG"), /*B90F*/ GENx___x___x900 (load_reversed_long_register,RRE,"LRVGR"), /*B910*/ GENx___x___x900 (load_positive_long_fullword_register,RRE,"LPGFR"), /*B911*/ GENx___x___x900 (load_negative_long_fullword_register,RRE,"LNGFR"), /*B912*/ GENx___x___x900 (load_and_test_long_fullword_register,RRE,"LTGFR"), /*B913*/ GENx___x___x900 (load_complement_long_fullword_register,RRE,"LCGFR"), /*B914*/ GENx___x___x900 (load_long_fullword_register,RRE,"LGFR"), /*B915*/ GENx___x___x___ , /*B916*/ GENx___x___x900 (load_logical_long_fullword_register,RRE,"LLGFR"), /*B917*/ GENx___x___x900 (load_logical_long_thirtyone_register,RRE,"LLGTR"), /*B918*/ GENx___x___x900 (add_long_fullword_register,RRE,"AGFR"), /*B919*/ GENx___x___x900 (subtract_long_fullword_register,RRE,"SGFR"), /*B91A*/ GENx___x___x900 (add_logical_long_fullword_register,RRE,"ALGFR"), /*B91B*/ GENx___x___x900 (subtract_logical_long_fullword_register,RRE,"SLGFR"), /*B91C*/ GENx___x___x900 (multiply_single_long_fullword_register,RRE,"MSGFR"), /*B91D*/ GENx___x___x900 (divide_single_long_fullword_register,RRE,"DSGFR"), /*B91E*/ GENx37Xx390x900 (compute_message_authentication_code_r,RRE,"KMAC"), /*B91F*/ GENx___x390x900 (load_reversed_register,RRE,"LRVR"), /*B920*/ GENx___x___x900 (compare_long_register,RRE,"CGR"), /*B921*/ GENx___x___x900 (compare_logical_long_register,RRE,"CLGR"), /*B922*/ GENx___x___x___ , /*B923*/ GENx___x___x___ , /*B924*/ GENx___x___x___ , /*B925*/ GENx___x___x900 (store_using_real_address_long,RRE,"STURG"), /*B926*/ GENx37Xx390x900 (load_byte_register,RRE,"LBR"), /*@Z9*/ /*B927*/ GENx37Xx390x900 (load_halfword_register,RRE,"LHR"), /*@Z9*/ /*B928*/ GENx37Xx390x900 (perform_cryptographic_key_management_operation_r,none,"PCKMO"), /*810*/ /*B929*/ GENx___x___x___ , /*B92A*/ GENx37Xx390x900 (cipher_message_with_cipher_feedback_r,RRE,"KMF"), /*810*/ /*B92B*/ GENx37Xx390x900 (cipher_message_with_output_feedback_r,RRE,"KMO"), /*810*/ /*B92C*/ GENx37Xx390x900 (perform_cryptographic_computation_r,none,"PCC"), /*810*/ /*B92D*/ GENx37Xx390x900 (cipher_message_with_counter_r,RRF_M,"KMCTR"), /*810*/ /*B92E*/ GENx37Xx390x900 (cipher_message_r,RRE,"KM"), /*B92F*/ GENx37Xx390x900 (cipher_message_with_chaining_r,RRE,"KMC"), /*B930*/ GENx___x___x900 (compare_long_fullword_register,RRE,"CGFR"), /*B931*/ GENx___x___x900 (compare_logical_long_fullword_register,RRE,"CLGFR"), /*B932*/ GENx___x___x___ , /*B933*/ GENx___x___x___ , /*B934*/ GENx___x___x___ , /*B935*/ GENx___x___x___ , /*B936*/ GENx___x___x___ , /*B937*/ GENx___x___x___ , /*B938*/ GENx___x___x___ , /*B939*/ GENx___x___x___ , /*B93A*/ GENx___x___x___ , /*B93B*/ GENx___x___x___ , /*B93C*/ GENx___x___x___ , /*B93D*/ GENx___x___x___ , /*B93E*/ GENx37Xx390x900 (compute_intermediate_message_digest_r,RRE,"KIMD"), /*B93F*/ GENx37Xx390x900 (compute_last_message_digest_r,RRE,"KLMD"), /*B940*/ GENx___x___x___ , /*B941*/ GENx___x390x900 (convert_dfp_long_to_fix32_reg,RRF_MM,"CFDTR"), /*810*/ /*B942*/ GENx___x___x900 (convert_dfp_long_to_u64_reg,RRF_MM,"CLGDTR"), /*810*/ /*B943*/ GENx___x390x900 (convert_dfp_long_to_u32_reg,RRF_MM,"CLFDTR"), /*810*/ /*B944*/ GENx___x___x___ , /*B945*/ GENx___x___x___ , /*B946*/ GENx___x___x900 (branch_on_count_long_register,RRE,"BCTGR"), /*B947*/ GENx___x___x___ , /*B948*/ GENx___x___x___ , /*B949*/ GENx___x390x900 (convert_dfp_ext_to_fix32_reg,RRF_MM,"CFXTR"), /*810*/ /*B94A*/ GENx___x___x900 (convert_dfp_ext_to_u64_reg,RRF_MM,"CLGXTR"), /*810*/ /*B94B*/ GENx___x390x900 (convert_dfp_ext_to_u32_reg,RRF_MM,"CLFXTR"), /*810*/ /*B94C*/ GENx___x___x___ , /*B94D*/ GENx___x___x___ , /*B94E*/ GENx___x___x___ , /*B94F*/ GENx___x___x___ , /*B950*/ GENx___x___x___ , /*B951*/ GENx___x390x900 (convert_fix32_to_dfp_long_reg,RRF_MM,"CDFTR"), /*810*/ /*B952*/ GENx___x___x900 (convert_u64_to_dfp_long_reg,RRF_MM,"CDLGTR"), /*810*/ /*B953*/ GENx___x390x900 (convert_u32_to_dfp_long_reg,RRF_MM,"CDLFTR"), /*810*/ /*B954*/ GENx___x___x___ , /*B955*/ GENx___x___x___ , /*B956*/ GENx___x___x___ , /*B957*/ GENx___x___x___ , /*B958*/ GENx___x___x___ , /*B959*/ GENx___x390x900 (convert_fix32_to_dfp_ext_reg,RRF_MM,"CXFTR"), /*810*/ /*B95A*/ GENx___x___x900 (convert_u64_to_dfp_ext_reg,RRF_MM,"CXLGTR"), /*810*/ /*B95B*/ GENx___x390x900 (convert_u32_to_dfp_ext_reg,RRF_MM,"CXLFTR"), /*810*/ /*B95C*/ GENx___x___x___ , /*B95D*/ GENx___x___x___ , /*B95E*/ GENx___x___x___ , /*B95F*/ GENx___x___x___ , /*B960*/ GENx___x___x900 (compare_and_trap_long_register,RRF_M3,"CGRT"), /*208*/ /*B961*/ GENx___x___x900 (compare_logical_and_trap_long_register,RRF_M3,"CLGRT"), /*208*/ /*B962*/ GENx___x___x___ , /*B963*/ GENx___x___x___ , /*B964*/ GENx___x___x___ , /*B965*/ GENx___x___x___ , /*B966*/ GENx___x___x___ , /*B967*/ GENx___x___x___ , /*B968*/ GENx___x___x___ , /*B969*/ GENx___x___x___ , /*B96A*/ GENx___x___x___ , /*B96B*/ GENx___x___x___ , /*B96C*/ GENx___x___x___ , /*B96D*/ GENx___x___x___ , /*B96E*/ GENx___x___x___ , /*B96F*/ GENx___x___x___ , /*B970*/ GENx___x___x___ , /*B971*/ GENx___x___x___ , /*B972*/ GENx37Xx390x900 (compare_and_trap_register,RRF_M3,"CRT"), /*208*/ /*B973*/ GENx37Xx390x900 (compare_logical_and_trap_register,RRF_M3,"CLRT"), /*208*/ /*B974*/ GENx___x___x___ , /*B975*/ GENx___x___x___ , /*B976*/ GENx___x___x___ , /*B977*/ GENx___x___x___ , /*B978*/ GENx___x___x___ , /*B979*/ GENx___x___x___ , /*B97A*/ GENx___x___x___ , /*B97B*/ GENx___x___x___ , /*B97C*/ GENx___x___x___ , /*B97D*/ GENx___x___x___ , /*B97E*/ GENx___x___x___ , /*B97F*/ GENx___x___x___ , /*B980*/ GENx___x___x900 (and_long_register,RRE,"NGR"), /*B981*/ GENx___x___x900 (or_long_register,RRE,"OGR"), /*B982*/ GENx___x___x900 (exclusive_or_long_register,RRE,"XGR"), /*B983*/ GENx___x___x900 (find_leftmost_one_long_register,RRE,"FLOGR"), /*@Z9*/ /*B984*/ GENx___x___x900 (load_logical_long_character_register,RRE,"LLGCR"), /*@Z9*/ /*B985*/ GENx___x___x900 (load_logical_long_halfword_register,RRE,"LLGHR"), /*@Z9*/ /*B986*/ GENx___x___x900 (multiply_logical_long_register,RRE,"MLGR"), /*B987*/ GENx___x___x900 (divide_logical_long_register,RRE,"DLGR"), /*B988*/ GENx___x___x900 (add_logical_carry_long_register,RRE,"ALCGR"), /*B989*/ GENx___x___x900 (subtract_logical_borrow_long_register,RRE,"SLBGR"), /*B98A*/ GENx___x___x900 (compare_and_swap_and_purge_long,RRE,"CSPG"), /*B98B*/ GENx___x___x___ , /*B98C*/ GENx___x___x___ , /*B98D*/ GENx37Xx390x900 (extract_psw,RRE,"EPSW"), /*B98E*/ GENx___x___x900 (invalidate_dat_table_entry,RRF_RM,"IDTE"), /*912*/ /*B98F*/ GENx___x___x900 (compare_and_replace_dat_table_entry,RRF_RM,"CRDTE"), /*912*/ /*B990*/ GENx37Xx390x900 (translate_two_to_two,RRF_M3,"TRTT"), /*B991*/ GENx37Xx390x900 (translate_two_to_one,RRF_M3,"TRTO"), /*B992*/ GENx37Xx390x900 (translate_one_to_two,RRF_M3,"TROT"), /*B993*/ GENx37Xx390x900 (translate_one_to_one,RRF_M3,"TROO"), /*B994*/ GENx37Xx390x900 (load_logical_character_register,RRE,"LLCR"), /*@Z9*/ /*B995*/ GENx37Xx390x900 (load_logical_halfword_register,RRE,"LLHR"), /*@Z9*/ /*B996*/ GENx37Xx390x900 (multiply_logical_register,RRE,"MLR"), /*B997*/ GENx37Xx390x900 (divide_logical_register,RRE,"DLR"), /*B998*/ GENx37Xx390x900 (add_logical_carry_register,RRE,"ALCR"), /*B999*/ GENx37Xx390x900 (subtract_logical_borrow_register,RRE,"SLBR"), /*B99A*/ GENx___x___x900 (extract_primary_asn_and_instance,RRE_R1,"EPAIR"), /*B99B*/ GENx___x___x900 (extract_secondary_asn_and_instance,RRE_R1,"ESAIR"), /*B99C*/ GENx___x___x___ , /*(extract_qdio_buffer_state,?,"EQBS"),*/ /*B99D*/ GENx___x___x900 (extract_and_set_extended_authority,RRE_R1,"ESEA"), /*B99E*/ GENx___x___x900 (program_transfer_with_instance,RRE,"PTI"), /*B99F*/ GENx___x___x900 (set_secondary_asn_with_instance,RRE_R1,"SSAIR"), /*B9A0*/ GENx___x___x___ , /*B9A1*/ GENx___x___x___ , /*B9A2*/ GENx___x___x900 (perform_topology_function,RRE,"PTF"), /*B9A3*/ GENx___x___x___ , /*B9B9*/ GENx___x___x___ , /*B9A5*/ GENx___x___x___ , /*B9A6*/ GENx___x___x___ , /*B9A7*/ GENx___x___x___ , /*B9A8*/ GENx___x___x___ , /*B9A9*/ GENx___x___x___ , /*B9AA*/ GENx___x___x900 (load_page_table_entry_address,RRF_RM,"LPTEA"), /*@Z9*/ /*B9AB*/ GENx___x___x___ , /*(extract_and_set_storage_attributes,?,"ESSA"),*/ /*B9AC*/ GENx___x___x___ , /*B9AD*/ GENx___x___x___ , /*B9AE*/ GENx___x___x900 (reset_reference_bits_multiple,RRE,"RRBM"), /*810*/ /*B9AF*/ GENx___x___x900 (perform_frame_management_function,RRE,"PFMF"), /*B9B0*/ GENx37Xx390x900 (convert_utf8_to_utf32,RRF_M3,"CU14"), /*B9B1*/ GENx37Xx390x900 (convert_utf16_to_utf32,RRF_M3,"CU24"), /*B9B2*/ GENx37Xx390x900 (convert_utf32_to_utf8,RRE,"CU41"), /*B9B3*/ GENx37Xx390x900 (convert_utf32_to_utf16,RRE,"CU42"), /*B9B4*/ GENx___x___x___ , /*B9B5*/ GENx___x___x___ , /*B9B6*/ GENx___x___x___ , /*B9B7*/ GENx___x___x___ , /*B9B8*/ GENx___x___x___ , /*B9B9*/ GENx___x___x___ , /*B9BA*/ GENx___x___x___ , /*B9BB*/ GENx___x___x___ , /*B9BC*/ GENx___x___x___ , /*B9BD*/ GENx37Xx390x900 (translate_and_test_reverse_extended,RRF_M3,"TRTRE"), /*B9BE*/ GENx37Xx390x900 (search_string_unicode,RRE,"SRSTU"), /*B9BF*/ GENx37Xx390x900 (translate_and_test_extended,RRF_M3,"TRTE"), /*B9C0*/ GENx___x___x___ , /*B9C1*/ GENx___x___x___ , /*B9C2*/ GENx___x___x___ , /*B9C3*/ GENx___x___x___ , /*B9C4*/ GENx___x___x___ , /*B9C5*/ GENx___x___x___ , /*B9C6*/ GENx___x___x___ , /*B9C7*/ GENx___x___x___ , /*B9C8*/ GENx___x___x900 (add_high_high_high_register,RRF_M3,"AHHHR"), /*810*/ /*B9C9*/ GENx___x___x900 (subtract_high_high_high_register,RRF_M3,"SHHHR"), /*810*/ /*B9CA*/ GENx___x___x900 (add_logical_high_high_high_register,RRF_M3,"ALHHHR"), /*810*/ /*B9CB*/ GENx___x___x900 (subtract_logical_high_high_high_register,RRF_M3,"SLHHHR"), /*810*/ /*B9CC*/ GENx___x___x___ , /*B9CD*/ GENx___x___x900 (compare_high_high_register,RRE,"CHHR"), /*810*/ /*B9CE*/ GENx___x___x___ , /*B9CF*/ GENx___x___x900 (compare_logical_high_high_register,RRE,"CLHHR"), /*810*/ /*B9D0*/ GENx___x___x___ , /*B9D1*/ GENx___x___x___ , /*B9D2*/ GENx___x___x___ , /*B9D3*/ GENx___x___x___ , /*B9D4*/ GENx___x___x___ , /*B9D5*/ GENx___x___x___ , /*B9D6*/ GENx___x___x___ , /*B9D7*/ GENx___x___x___ , /*B9D8*/ GENx___x___x900 (add_high_high_low_register,RRF_M3,"AHHLR"), /*810*/ /*B9D9*/ GENx___x___x900 (subtract_high_high_low_register,RRF_M3,"SHHLR"), /*810*/ /*B9DA*/ GENx___x___x900 (add_logical_high_high_low_register,RRF_M3,"ALHHLR"), /*810*/ /*B9DB*/ GENx___x___x900 (subtract_logical_high_high_low_register,RRF_M3,"SLHHLR"), /*810*/ /*B9DC*/ GENx___x___x___ , /*B9DD*/ GENx___x___x900 (compare_high_low_register,RRE,"CHLR"), /*810*/ /*B9DE*/ GENx___x___x___ , /*B9DF*/ GENx___x___x900 (compare_logical_high_low_register,RRE,"CLHLR"), /*810*/ /*B9E0*/ GENx___x___x___ , /*B9E1*/ GENx___x___x900 (population_count,RRE,"POPCNT"), /*810*/ /*B9E2*/ GENx___x___x900 (load_on_condition_long_register,RRF_M3,"LOCGR"), /*810*/ /*B9E3*/ GENx___x___x___ , /*B9E4*/ GENx___x___x900 (and_distinct_long_register,RRR,"NGRK"), /*810*/ /*B9E5*/ GENx___x___x___ , /*B9E6*/ GENx___x___x900 (or_distinct_long_register,RRR,"OGRK"), /*810*/ /*B9E7*/ GENx___x___x900 (exclusive_or_distinct_long_register,RRR,"XGRK"), /*810*/ /*B9E8*/ GENx___x___x900 (add_distinct_long_register,RRR,"AGRK"), /*810*/ /*B9E9*/ GENx___x___x900 (subtract_distinct_long_register,RRR,"SGRK"), /*810*/ /*B9EA*/ GENx___x___x900 (add_logical_distinct_long_register,RRR,"ALGRK"), /*810*/ /*B9EB*/ GENx___x___x900 (subtract_logical_distinct_long_register,RRR,"SLGRK"), /*810*/ /*B9EC*/ GENx___x___x___ , /*B9ED*/ GENx___x___x___ , /*B9EE*/ GENx___x___x___ , /*B9EF*/ GENx___x___x___ , /*B9F0*/ GENx___x___x___ , /*B9F1*/ GENx___x___x___ , /*B9F2*/ GENx37Xx390x900 (load_on_condition_register,RRF_M3,"LOCR"), /*810*/ /*B9F3*/ GENx___x___x___ , /*B9F4*/ GENx37Xx390x900 (and_distinct_register,RRR,"NRK"), /*810*/ /*B9F5*/ GENx___x___x___ , /*B9F6*/ GENx37Xx390x900 (or_distinct_register,RRR,"ORK"), /*810*/ /*B9F7*/ GENx37Xx390x900 (exclusive_or_distinct_register,RRR,"XRK"), /*810*/ /*B9F8*/ GENx37Xx390x900 (add_distinct_register,RRR,"ARK"), /*810*/ /*B9F9*/ GENx37Xx390x900 (subtract_distinct_register,RRR,"SRK"), /*810*/ /*B9FA*/ GENx37Xx390x900 (add_logical_distinct_register,RRR,"ALRK"), /*810*/ /*B9FB*/ GENx37Xx390x900 (subtract_logical_distinct_register,RRR,"SLRK"), /*810*/ /*B9FC*/ GENx___x___x___ , /*B9FD*/ GENx___x___x___ , /*B9FE*/ GENx___x___x___ , /*B9FF*/ GENx___x___x___ }; // #endif /*defined(FEATURE_ESAME)*/ // #if defined(FEATURE_ESAME) DLL_EXPORT zz_func opcode_c0xx[16][GEN_MAXARCH] = { /*C0x0*/ GENx37Xx390x900 (load_address_relative_long,RIL_A,"LARL"), /*C0x1*/ GENx___x___x900 (load_long_fullword_immediate,RIL,"LGFI"), /*@Z9*/ /*C0x2*/ GENx___x___x___ , /*C0x3*/ GENx___x___x___ , /*C0x4*/ GENx37Xx390x900 (branch_relative_on_condition_long,RIL_A,"BRCL"), /*C0x5*/ GENx37Xx390x900 (branch_relative_and_save_long,RIL_A,"BRASL"), /*C0x6*/ GENx___x___x900 (exclusive_or_immediate_high_fullword,RIL,"XIHF"), /*@Z9*/ /*C0x7*/ GENx___x___x900 (exclusive_or_immediate_low_fullword,RIL,"XILF"), /*@Z9*/ /*C0x8*/ GENx___x___x900 (insert_immediate_high_fullword,RIL,"IIHF"), /*@Z9*/ /*C0x9*/ GENx___x___x900 (insert_immediate_low_fullword,RIL,"IILF"), /*@Z9*/ /*C0xA*/ GENx___x___x900 (and_immediate_high_fullword,RIL,"NIHF"), /*@Z9*/ /*C0xB*/ GENx___x___x900 (and_immediate_low_fullword,RIL,"NILF"), /*@Z9*/ /*C0xC*/ GENx___x___x900 (or_immediate_high_fullword,RIL,"OIHF"), /*@Z9*/ /*C0xD*/ GENx___x___x900 (or_immediate_low_fullword,RIL,"OILF"), /*@Z9*/ /*C0xE*/ GENx___x___x900 (load_logical_immediate_high_fullword,RIL,"LLIHF"), /*@Z9*/ /*C0xF*/ GENx___x___x900 (load_logical_immediate_low_fullword,RIL,"LLILF") }; /*@Z9*/ DLL_EXPORT zz_func opcode_c2xx[16][GEN_MAXARCH] = { /*@Z9*/ /*C2x0*/ GENx___x___x900 (multiply_single_immediate_long_fullword,RIL,"MSGFI"), /*208*/ /*C2x1*/ GENx37Xx390x900 (multiply_single_immediate_fullword,RIL,"MSFI"), /*208*/ /*C2x2*/ GENx___x___x___ , /*@Z9*/ /*C2x3*/ GENx___x___x___ , /*@Z9*/ /*C2x4*/ GENx___x___x900 (subtract_logical_long_fullword_immediate,RIL,"SLGFI"), /*@Z9*/ /*C2x5*/ GENx37Xx390x900 (subtract_logical_fullword_immediate,RIL,"SLFI"), /*@Z9*/ /*C2x6*/ GENx___x___x___ , /*@Z9*/ /*C2x7*/ GENx___x___x___ , /*@Z9*/ /*C2x8*/ GENx___x___x900 (add_long_fullword_immediate,RIL,"AGFI"), /*@Z9*/ /*C2x9*/ GENx37Xx390x900 (add_fullword_immediate,RIL,"AFI"), /*@Z9*/ /*C2xA*/ GENx___x___x900 (add_logical_long_fullword_immediate,RIL,"ALGFI"), /*@Z9*/ /*C2xB*/ GENx37Xx390x900 (add_logical_fullword_immediate,RIL,"ALFI"), /*@Z9*/ /*C2xC*/ GENx___x___x900 (compare_long_fullword_immediate,RIL,"CGFI"), /*@Z9*/ /*C2xD*/ GENx37Xx390x900 (compare_fullword_immediate,RIL,"CFI"), /*@Z9*/ /*C2xE*/ GENx___x___x900 (compare_logical_long_fullword_immediate,RIL,"CLGFI"), /*@Z9*/ /*C2xF*/ GENx37Xx390x900 (compare_logical_fullword_immediate,RIL,"CLFI") }; /*@Z9*/ DLL_EXPORT zz_func opcode_c4xx[16][GEN_MAXARCH] = { /*208*/ /*C4x0*/ GENx___x___x___ , /*208*/ /*C4x1*/ GENx___x___x___ , /*208*/ /*C4x2*/ GENx37Xx390x900 (load_logical_halfword_relative_long,RIL_A,"LLHRL"), /*208*/ /*C4x3*/ GENx___x___x___ , /*208*/ /*C4x4*/ GENx___x___x900 (load_halfword_relative_long_long,RIL_A,"LGHRL"), /*208*/ /*C4x5*/ GENx37Xx390x900 (load_halfword_relative_long,RIL_A,"LHRL"), /*208*/ /*C4x6*/ GENx___x___x900 (load_logical_halfword_relative_long_long,RIL_A,"LLGHRL"), /*208*/ /*C4x7*/ GENx37Xx390x900 (store_halfword_relative_long,RIL_A,"STHRL"), /*208*/ /*C4x8*/ GENx___x___x900 (load_relative_long_long,RIL_A,"LGRL"), /*208*/ /*C4x9*/ GENx___x___x___ , /*208*/ /*C4xA*/ GENx___x___x___ , /*208*/ /*C4xB*/ GENx___x___x900 (store_relative_long_long,RIL_A,"STGRL"), /*208*/ /*C4xC*/ GENx___x___x900 (load_relative_long_long_fullword,RIL_A,"LGFRL"), /*208*/ /*C4xD*/ GENx37Xx390x900 (load_relative_long,RIL_A,"LRL"), /*208*/ /*C4xE*/ GENx___x___x900 (load_logical_relative_long_long_fullword,RIL_A,"LLGFRL"), /*208*/ /*C4xF*/ GENx37Xx390x900 (store_relative_long,RIL_A,"STRL") }; /*208*/ DLL_EXPORT zz_func opcode_c6xx[16][GEN_MAXARCH] = { /*208*/ /*C6x0*/ GENx37Xx390x900 (execute_relative_long,RIL_A,"EXRL"), /*208*/ /*C6x1*/ GENx___x___x___ , /*208*/ /*C6x2*/ GENx37Xx390x900 (prefetch_data_relative_long,RIL_A,"PFDRL"), /*208*/ /*C6x3*/ GENx___x___x___ , /*208*/ /*C6x4*/ GENx___x___x900 (compare_halfword_relative_long_long,RIL_A,"CGHRL"), /*208*/ /*C6x5*/ GENx37Xx390x900 (compare_halfword_relative_long,RIL_A,"CHRL"), /*208*/ /*C6x6*/ GENx___x___x900 (compare_logical_relative_long_long_halfword,RIL_A,"CLGHRL"), /*208*/ /*C6x7*/ GENx37Xx390x900 (compare_logical_relative_long_halfword,RIL_A,"CLHRL"), /*208*/ /*C6x8*/ GENx___x___x900 (compare_relative_long_long,RIL_A,"CGRL"), /*208*/ /*C6x9*/ GENx___x___x___ , /*208*/ /*C6xA*/ GENx___x___x900 (compare_logical_relative_long_long,RIL_A,"CLGRL"), /*208*/ /*C6xB*/ GENx___x___x___ , /*208*/ /*C6xC*/ GENx___x___x900 (compare_relative_long_long_fullword,RIL_A,"CGFRL"), /*208*/ /*C6xD*/ GENx37Xx390x900 (compare_relative_long,RIL_A,"CRL"), /*208*/ /*C6xE*/ GENx___x___x900 (compare_logical_relative_long_long_fullword,RIL_A,"CLGFRL"), /*208*/ /*C6xF*/ GENx37Xx390x900 (compare_logical_relative_long,RIL_A,"CLRL") }; /*208*/ DLL_EXPORT zz_func opcode_c8xx[16][GEN_MAXARCH] = { /*C8x0*/ GENx___x___x900 (move_with_optional_specifications,SSF,"MVCOS"), /*C8x1*/ GENx___x___x900 (extract_cpu_time,SSF,"ECTG"), /*C8x2*/ GENx___x___x900 (compare_and_swap_and_store,SSF,"CSST"), /*C8x3*/ GENx___x___x___ , /*C8x4*/ GENx37Xx390x900 (load_pair_disjoint,SSF_RSS,"LPD"), /*810*/ /*C8x5*/ GENx___x___x900 (load_pair_disjoint_long,SSF_RSS,"LPDG"), /*810*/ /*C8x6*/ GENx___x___x___ , /*C8x7*/ GENx___x___x___ , /*C8x8*/ GENx___x___x___ , /*C8x9*/ GENx___x___x___ , /*C8xA*/ GENx___x___x___ , /*C8xB*/ GENx___x___x___ , /*C8xC*/ GENx___x___x___ , /*C8xD*/ GENx___x___x___ , /*C8xE*/ GENx___x___x___ , /*C8xF*/ GENx___x___x___ }; DLL_EXPORT zz_func opcode_ccxx[16][GEN_MAXARCH] = { /*810*/ /*CCx0*/ GENx___x___x___ , /*CCx1*/ GENx___x___x___ , /*CCx2*/ GENx___x___x___ , /*CCx3*/ GENx___x___x___ , /*CCx4*/ GENx___x___x___ , /*CCx5*/ GENx___x___x___ , /*CCx6*/ GENx___x___x900 (branch_relative_on_count_high,RIL,"BRCTH"), /*810*/ /*CCx7*/ GENx___x___x___ , /*CCx8*/ GENx___x___x900 (add_high_immediate,RIL,"AIH"), /*810*/ /*CCx9*/ GENx___x___x___ , /*CCxA*/ GENx___x___x900 (add_logical_with_signed_immediate_high,RIL,"ALSIH"), /*810*/ /*CCxB*/ GENx___x___x900 (add_logical_with_signed_immediate_high_n,RIL,"ALSIHN"), /*810*/ /*CCxC*/ GENx___x___x___ , /*CCxD*/ GENx___x___x900 (compare_high_immediate,RIL,"CIH"), /*810*/ /*CCxE*/ GENx___x___x___ , /*CCxF*/ GENx___x___x900 (compare_logical_high_immediate,RIL,"CLIH") }; /*810*/ // #endif /*defined(FEATURE_ESAME)*/ // #if defined(FEATURE_ESAME) DLL_EXPORT zz_func opcode_e3xx[256][GEN_MAXARCH] = { /*E300*/ GENx___x___x___ , /*E301*/ GENx___x___x___ , /*E302*/ GENx___x___x900 (load_and_test_long,RXY,"LTG"), /*@Z9*/ /*E303*/ GENx___x___x900 (load_real_address_long,RXY,"LRAG"), /*E304*/ GENx___x___x900 (load_long,RXY,"LG"), /*E305*/ GENx___x___x___ , /*E306*/ GENx___x___x900 (convert_to_binary_y,RXY,"CVBY"), /*E307*/ GENx___x___x___ , /*E308*/ GENx___x___x900 (add_long,RXY,"AG"), /*E309*/ GENx___x___x900 (subtract_long,RXY,"SG"), /*E30A*/ GENx___x___x900 (add_logical_long,RXY,"ALG"), /*E30B*/ GENx___x___x900 (subtract_logical_long,RXY,"SLG"), /*E30C*/ GENx___x___x900 (multiply_single_long,RXY,"MSG"), /*E30D*/ GENx___x___x900 (divide_single_long,RXY,"DSG"), /*E30E*/ GENx___x___x900 (convert_to_binary_long,RXY,"CVBG"), /*E30F*/ GENx___x___x900 (load_reversed_long,RXY,"LRVG"), /*E310*/ GENx___x___x___ , /*E311*/ GENx___x___x___ , /*E312*/ GENx37Xx390x900 (load_and_test,RXY,"LT"), /*@Z9*/ /*E313*/ GENx___x___x900 (load_real_address_y,RXY,"LRAY"), /*E314*/ GENx___x___x900 (load_long_fullword,RXY,"LGF"), /*E315*/ GENx___x___x900 (load_long_halfword,RXY,"LGH"), /*E316*/ GENx___x___x900 (load_logical_long_fullword,RXY,"LLGF"), /*E317*/ GENx___x___x900 (load_logical_long_thirtyone,RXY,"LLGT"), /*E318*/ GENx___x___x900 (add_long_fullword,RXY,"AGF"), /*E319*/ GENx___x___x900 (subtract_long_fullword,RXY,"SGF"), /*E31A*/ GENx___x___x900 (add_logical_long_fullword,RXY,"ALGF"), /*E31B*/ GENx___x___x900 (subtract_logical_long_fullword,RXY,"SLGF"), /*E31C*/ GENx___x___x900 (multiply_single_long_fullword,RXY,"MSGF"), /*E31D*/ GENx___x___x900 (divide_single_long_fullword,RXY,"DSGF"), /*E31E*/ GENx___x390x900 (load_reversed,RXY,"LRV"), /*E31F*/ GENx___x390x900 (load_reversed_half,RXY,"LRVH"), /*E320*/ GENx___x___x900 (compare_long,RXY,"CG"), /*E321*/ GENx___x___x900 (compare_logical_long,RXY,"CLG"), /*E322*/ GENx___x___x___ , /*E323*/ GENx___x___x___ , /*E324*/ GENx___x___x900 (store_long,RXY,"STG"), /*E325*/ GENx___x___x900 (nontransactional_store_long,RXY,"NTSTG"), /*912*/ /*E326*/ GENx___x___x900 (convert_to_decimal_y,RXY,"CVDY"), /*E327*/ GENx___x___x___ , /*E328*/ GENx___x___x___ , /*E329*/ GENx___x___x___ , /*E32A*/ GENx___x___x___ , /*E32B*/ GENx___x___x___ , /*E32C*/ GENx___x___x___ , /*E32D*/ GENx___x___x___ , /*E32E*/ GENx___x___x900 (convert_to_decimal_long,RXY,"CVDG"), /*E32F*/ GENx___x___x900 (store_reversed_long,RXY,"STRVG"), /*E330*/ GENx___x___x900 (compare_long_fullword,RXY,"CGF"), /*E331*/ GENx___x___x900 (compare_logical_long_fullword,RXY,"CLGF"), /*E332*/ GENx___x___x900 (load_and_test_long_fullword,RXY,"LTGF"), /*208*/ /*E333*/ GENx___x___x___ , /*E334*/ GENx___x___x900 (compare_halfword_long,RXY,"CGH"), /*208*/ /*E335*/ GENx___x___x___ , /*E336*/ GENx37Xx390x900 (prefetch_data,RXY,"PFD"), /*208*/ /*E337*/ GENx___x___x___ , /*E338*/ GENx___x___x___ , /*E339*/ GENx___x___x___ , /*E33A*/ GENx___x___x___ , /*E33B*/ GENx___x___x___ , /*E33C*/ GENx___x___x___ , /*E33D*/ GENx___x___x___ , /*E33E*/ GENx___x390x900 (store_reversed,RXY,"STRV"), /*E33F*/ GENx___x390x900 (store_reversed_half,RXY,"STRVH"), /*E340*/ GENx___x___x___ , /*E341*/ GENx___x___x___ , /*E342*/ GENx___x___x___ , /*E343*/ GENx___x___x___ , /*E344*/ GENx___x___x___ , /*E345*/ GENx___x___x___ , /*E346*/ GENx___x___x900 (branch_on_count_long,RXY,"BCTG"), /*E347*/ GENx___x___x___ , /*E348*/ GENx___x___x___ , /*E349*/ GENx___x___x___ , /*E34A*/ GENx___x___x___ , /*E34B*/ GENx___x___x___ , /*E34C*/ GENx___x___x___ , /*E34D*/ GENx___x___x___ , /*E34E*/ GENx___x___x___ , /*E34F*/ GENx___x___x___ , /*E350*/ GENx___x___x900 (store_y,RXY,"STY"), /*E351*/ GENx___x___x900 (multiply_single_y,RXY,"MSY"), /*E352*/ GENx___x___x___ , /*E353*/ GENx___x___x___ , /*E354*/ GENx___x___x900 (and_y,RXY,"NY"), /*E355*/ GENx___x___x900 (compare_logical_y,RXY,"CLY"), /*E356*/ GENx___x___x900 (or_y,RXY,"OY"), /*E357*/ GENx___x___x900 (exclusive_or_y,RXY,"XY"), /*E358*/ GENx___x___x900 (load_y,RXY,"LY"), /*E359*/ GENx___x___x900 (compare_y,RXY,"CY"), /*E35A*/ GENx___x___x900 (add_y,RXY,"AY"), /*E35B*/ GENx___x___x900 (subtract_y,RXY,"SY"), /*E35C*/ GENx___x___x900 (multiply_y,RXY,"MFY"), /*208*/ /*E35D*/ GENx___x___x___ , /*E35E*/ GENx___x___x900 (add_logical_y,RXY,"ALY"), /*E35F*/ GENx___x___x900 (subtract_logical_y,RXY,"SLY"), /*E360*/ GENx___x___x___ , /*E361*/ GENx___x___x___ , /*E362*/ GENx___x___x___ , /*E363*/ GENx___x___x___ , /*E364*/ GENx___x___x___ , /*E365*/ GENx___x___x___ , /*E366*/ GENx___x___x___ , /*E367*/ GENx___x___x___ , /*E368*/ GENx___x___x___ , /*E369*/ GENx___x___x___ , /*E36A*/ GENx___x___x___ , /*E36B*/ GENx___x___x___ , /*E36C*/ GENx___x___x___ , /*E36D*/ GENx___x___x___ , /*E36E*/ GENx___x___x___ , /*E36F*/ GENx___x___x___ , /*E370*/ GENx___x___x900 (store_halfword_y,RXY,"STHY"), /*E371*/ GENx___x___x900 (load_address_y,RXY,"LAY"), /*E372*/ GENx___x___x900 (store_character_y,RXY,"STCY"), /*E373*/ GENx___x___x900 (insert_character_y,RXY,"ICY"), /*E374*/ GENx___x___x___ , /*E375*/ GENx___x___x900 (load_address_extended_y,RXY,"LAEY"), /*208*/ /*E376*/ GENx___x___x900 (load_byte,RXY,"LB"), /*E377*/ GENx___x___x900 (load_byte_long,RXY,"LGB"), /*E378*/ GENx___x___x900 (load_halfword_y,RXY,"LHY"), /*E379*/ GENx___x___x900 (compare_halfword_y,RXY,"CHY"), /*E37A*/ GENx___x___x900 (add_halfword_y,RXY,"AHY"), /*E37B*/ GENx___x___x900 (subtract_halfword_y,RXY,"SHY"), /*E37C*/ GENx___x___x900 (multiply_halfword_y,RXY,"MHY"), /*208*/ /*E37D*/ GENx___x___x___ , /*E37E*/ GENx___x___x___ , /*E37F*/ GENx___x___x___ , /*E380*/ GENx___x___x900 (and_long,RXY,"NG"), /*E381*/ GENx___x___x900 (or_long,RXY,"OG"), /*E382*/ GENx___x___x900 (exclusive_or_long,RXY,"XG"), /*E383*/ GENx___x___x___ , /*E384*/ GENx___x___x___ , /*E385*/ GENx___x___x900 (load_long_and_trap,RXY,"LGAT"), /*912*/ /*E386*/ GENx___x___x900 (multiply_logical_long,RXY,"MLG"), /*E387*/ GENx___x___x900 (divide_logical_long,RXY,"DLG"), /*E388*/ GENx___x___x900 (add_logical_carry_long,RXY,"ALCG"), /*E389*/ GENx___x___x900 (subtract_logical_borrow_long,RXY,"SLBG"), /*E38A*/ GENx___x___x___ , /*E38B*/ GENx___x___x___ , /*E38C*/ GENx___x___x___ , /*E38D*/ GENx___x___x___ , /*E38E*/ GENx___x___x900 (store_pair_to_quadword,RXY,"STPQ"), /*E38F*/ GENx___x___x900 (load_pair_from_quadword,RXY,"LPQ"), /*E390*/ GENx___x___x900 (load_logical_long_character,RXY,"LLGC"), /*E391*/ GENx___x___x900 (load_logical_long_halfword,RXY,"LLGH"), /*E392*/ GENx___x___x___ , /*E393*/ GENx___x___x___ , /*E394*/ GENx37Xx390x900 (load_logical_character,RXY,"LLC"), /*@Z9*/ /*E395*/ GENx37Xx390x900 (load_logical_halfword,RXY,"LLH"), /*@Z9*/ /*E396*/ GENx37Xx390x900 (multiply_logical,RXY,"ML"), /*E397*/ GENx37Xx390x900 (divide_logical,RXY,"DL"), /*E398*/ GENx37Xx390x900 (add_logical_carry,RXY,"ALC"), /*E399*/ GENx37Xx390x900 (subtract_logical_borrow,RXY,"SLB"), /*E39A*/ GENx___x___x___ , /*E39B*/ GENx___x___x___ , /*E39C*/ GENx___x___x900 (load_logical_long_thirtyone_and_trap,RXY,"LLGTAT"), /*912*/ /*E39D*/ GENx___x___x900 (load_logical_long_fullword_and_trap,RXY,"LLGFAT"), /*912*/ /*E39E*/ GENx___x___x___ , /*E39F*/ GENx___x___x900 (load_and_trap,RXY,"LAT"), /*912*/ /*E3A0*/ GENx___x___x___ , /*E3A1*/ GENx___x___x___ , /*E3A2*/ GENx___x___x___ , /*E3A3*/ GENx___x___x___ , /*E3E3*/ GENx___x___x___ , /*E3A5*/ GENx___x___x___ , /*E3A6*/ GENx___x___x___ , /*E3A7*/ GENx___x___x___ , /*E3A8*/ GENx___x___x___ , /*E3A9*/ GENx___x___x___ , /*E3AA*/ GENx___x___x___ , /*E3AB*/ GENx___x___x___ , /*E3AC*/ GENx___x___x___ , /*E3AD*/ GENx___x___x___ , /*E3AE*/ GENx___x___x___ , /*E3AF*/ GENx___x___x___ , /*E3B0*/ GENx___x___x___ , /*E3B1*/ GENx___x___x___ , /*E3B2*/ GENx___x___x___ , /*E3B3*/ GENx___x___x___ , /*E3B4*/ GENx___x___x___ , /*E3B5*/ GENx___x___x___ , /*E3B6*/ GENx___x___x___ , /*E3B7*/ GENx___x___x___ , /*E3B8*/ GENx___x___x___ , /*E3E3*/ GENx___x___x___ , /*E3BA*/ GENx___x___x___ , /*E3BB*/ GENx___x___x___ , /*E3BC*/ GENx___x___x___ , /*E3BD*/ GENx___x___x___ , /*E3BE*/ GENx___x___x___ , /*E3BF*/ GENx___x___x___ , /*E3C0*/ GENx___x___x900 (load_byte_high,RXY,"LBH"), /*810*/ /*E3C1*/ GENx___x___x___ , /*E3C2*/ GENx___x___x900 (load_logical_character_high,RXY,"LLCH"), /*810*/ /*E3C3*/ GENx___x___x900 (store_character_high,RXY,"STCH"), /*810*/ /*E3C4*/ GENx___x___x900 (load_halfword_high,RXY,"LHH"), /*810*/ /*E3C5*/ GENx___x___x___ , /*E3C6*/ GENx___x___x900 (load_logical_halfword_high,RXY,"LLHH"), /*810*/ /*E3C7*/ GENx___x___x900 (store_halfword_high,RXY,"STHH"), /*810*/ /*E3C8*/ GENx___x___x900 (load_fullword_high_and_trap,RXY,"LFHAT"), /*912*/ /*E3C9*/ GENx___x___x___ , /*E3CA*/ GENx___x___x900 (load_fullword_high,RXY,"LFH"), /*810*/ /*E3CB*/ GENx___x___x900 (store_fullword_high,RXY,"STFH"), /*810*/ /*E3CC*/ GENx___x___x___ , /*E3CD*/ GENx___x___x900 (compare_high_fullword,RXY,"CHF"), /*810*/ /*E3CE*/ GENx___x___x___ , /*E3CF*/ GENx___x___x900 (compare_logical_high_fullword,RXY,"CLHF"), /*810*/ /*E3D0*/ GENx___x___x___ , /*E3D1*/ GENx___x___x___ , /*E3D2*/ GENx___x___x___ , /*E3D3*/ GENx___x___x___ , /*E3D4*/ GENx___x___x___ , /*E3D5*/ GENx___x___x___ , /*E3D6*/ GENx___x___x___ , /*E3D7*/ GENx___x___x___ , /*E3D8*/ GENx___x___x___ , /*E3D9*/ GENx___x___x___ , /*E3DA*/ GENx___x___x___ , /*E3DB*/ GENx___x___x___ , /*E3DC*/ GENx___x___x___ , /*E3DD*/ GENx___x___x___ , /*E3DE*/ GENx___x___x___ , /*E3DF*/ GENx___x___x___ , /*E3E0*/ GENx___x___x___ , /*E3E1*/ GENx___x___x___ , /*E3E2*/ GENx___x___x___ , /*E3E3*/ GENx___x___x___ , /*E3E4*/ GENx___x___x___ , /*E3E5*/ GENx___x___x___ , /*E3E6*/ GENx___x___x___ , /*E3E7*/ GENx___x___x___ , /*E3E8*/ GENx___x___x___ , /*E3E9*/ GENx___x___x___ , /*E3EA*/ GENx___x___x___ , /*E3EB*/ GENx___x___x___ , /*E3EC*/ GENx___x___x___ , /*E3ED*/ GENx___x___x___ , /*E3EE*/ GENx___x___x___ , /*E3EF*/ GENx___x___x___ , /*E3F0*/ GENx___x___x___ , /*E3F1*/ GENx___x___x___ , /*E3F2*/ GENx___x___x___ , /*E3F3*/ GENx___x___x___ , /*E3F4*/ GENx___x___x___ , /*E3F5*/ GENx___x___x___ , /*E3F6*/ GENx___x___x___ , /*E3F7*/ GENx___x___x___ , /*E3F8*/ GENx___x___x___ , /*E3F9*/ GENx___x___x___ , /*E3FA*/ GENx___x___x___ , /*E3FB*/ GENx___x___x___ , /*E3FC*/ GENx___x___x___ , /*E3FD*/ GENx___x___x___ , /*E3FE*/ GENx___x___x___ , /*E3FF*/ GENx___x___x___ }; // #endif /*defined(FEATURE_ESAME)*/ DLL_EXPORT zz_func opcode_e5xx[256][GEN_MAXARCH] = { /*E500*/ GENx370x390x900 (load_address_space_parameters,SSE,"LASP"), /*E501*/ GENx370x390x900 (test_protection,SSE,"TPROT"), /* The following opcode has been re-used in z/Arch */ #define s370_store_real_address s370_fix_page /*E502*/ GENx370x___x900 (store_real_address,SSE,"STRAG"), /*E503*/ GENx370x390x900 (svc_assist,SSE,"Assist"), /*E504*/ GENx370x390x900 (obtain_local_lock,SSE,"Assist"), /*E505*/ GENx370x390x900 (release_local_lock,SSE,"Assist"), /*E506*/ GENx370x390x900 (obtain_cms_lock,SSE,"Assist"), /*E507*/ GENx370x390x900 (release_cms_lock,SSE,"Assist"), /*E508*/ GENx370x___x___ (trace_svc_interruption,SSE,"Assist"), /*E509*/ GENx370x___x___ (trace_program_interruption,SSE,"Assist"), /*E50A*/ GENx370x___x___ (trace_initial_srb_dispatch,SSE,"Assist"), /*E50B*/ GENx370x___x___ (trace_io_interruption,SSE,"Assist"), /*E50C*/ GENx370x___x___ (trace_task_dispatch,SSE,"Assist"), /*E50D*/ GENx370x___x___ (trace_svc_return,SSE,"Assist"), /*E50E*/ GENx___x390x900 (move_with_source_key,SSE,"MVCSK"), /*E50F*/ GENx___x390x900 (move_with_destination_key,SSE,"MVCDK"), /*E510*/ GENx___x___x___ , /*E511*/ GENx___x___x___ , /*E512*/ GENx___x___x___ , /*E513*/ GENx___x___x___ , /*E514*/ GENx___x___x___ , /*E515*/ GENx___x___x___ , /*E516*/ GENx___x___x___ , /*E517*/ GENx___x___x___ , /*E518*/ GENx___x___x___ , /*E519*/ GENx___x___x___ , /*E51A*/ GENx___x___x___ , /*E51B*/ GENx___x___x___ , /*E51C*/ GENx___x___x___ , /*E51D*/ GENx___x___x___ , /*E51E*/ GENx___x___x___ , /*E51F*/ GENx___x___x___ , /*E520*/ GENx___x___x___ , /*E521*/ GENx___x___x___ , /*E522*/ GENx___x___x___ , /*E523*/ GENx___x___x___ , /*E524*/ GENx___x___x___ , /*E525*/ GENx___x___x___ , /*E526*/ GENx___x___x___ , /*E527*/ GENx___x___x___ , /*E528*/ GENx___x___x___ , /*E529*/ GENx___x___x___ , /*E52A*/ GENx___x___x___ , /*E52B*/ GENx___x___x___ , /*E52C*/ GENx___x___x___ , /*E52D*/ GENx___x___x___ , /*E52E*/ GENx___x___x___ , /*E52F*/ GENx___x___x___ , /*E530*/ GENx___x___x___ , /*E531*/ GENx___x___x___ , /*E532*/ GENx___x___x___ , /*E533*/ GENx___x___x___ , /*E534*/ GENx___x___x___ , /*E535*/ GENx___x___x___ , /*E536*/ GENx___x___x___ , /*E537*/ GENx___x___x___ , /*E538*/ GENx___x___x___ , /*E539*/ GENx___x___x___ , /*E53A*/ GENx___x___x___ , /*E53B*/ GENx___x___x___ , /*E53C*/ GENx___x___x___ , /*E53D*/ GENx___x___x___ , /*E53E*/ GENx___x___x___ , /*E53F*/ GENx___x___x___ , /*E540*/ GENx___x___x___ , /*E541*/ GENx___x___x___ , /*E542*/ GENx___x___x___ , /*E543*/ GENx___x___x___ , /*E544*/ GENx37Xx390x900 (move_halfword_from_halfword_immediate,SIL,"MVHHI"), /*208*/ /*E545*/ GENx___x___x___ , /*E546*/ GENx___x___x___ , /*E547*/ GENx___x___x___ , /*E548*/ GENx37Xx390x900 (move_long_from_halfword_immediate,SIL,"MVGHI"), /*208*/ /*E549*/ GENx___x___x___ , /*E54A*/ GENx___x___x___ , /*E54B*/ GENx___x___x___ , /*E54C*/ GENx37Xx390x900 (move_fullword_from_halfword_immediate,SIL,"MVHI"), /*208*/ /*E54D*/ GENx___x___x___ , /*E54E*/ GENx___x___x___ , /*E54F*/ GENx___x___x___ , /*E550*/ GENx___x___x___ , /*E551*/ GENx___x___x___ , /*E552*/ GENx___x___x___ , /*E553*/ GENx___x___x___ , /*E554*/ GENx37Xx390x900 (compare_halfword_immediate_halfword_storage,SIL,"CHHSI"), /*208*/ /*E555*/ GENx37Xx390x900 (compare_logical_immediate_halfword_storage,SIL,"CLHHSI"), /*208*/ /*E556*/ GENx___x___x___ , /*E557*/ GENx___x___x___ , /*E558*/ GENx37Xx390x900 (compare_halfword_immediate_long_storage,SIL,"CGHSI"), /*208*/ /*E559*/ GENx37Xx390x900 (compare_logical_immediate_long_storage,SIL,"CLGHSI"), /*208*/ /*E55A*/ GENx___x___x___ , /*E55B*/ GENx___x___x___ , /*E55C*/ GENx37Xx390x900 (compare_halfword_immediate_storage,SIL,"CHSI"), /*208*/ /*E55D*/ GENx37Xx390x900 (compare_logical_immediate_fullword_storage,SIL,"CLFHSI"), /*208*/ /*E55E*/ GENx___x___x___ , /*E55F*/ GENx___x___x___ , /*E560*/ GENx___x___x900 (transaction_begin,SIL,"TBEGIN"), /*912*/ /*E561*/ GENx___x___x900 (transaction_begin_constrained,SIL,"TBEGINC"), /*912*/ /*E562*/ GENx___x___x___ , /*E563*/ GENx___x___x___ , /*E564*/ GENx___x___x___ , /*E565*/ GENx___x___x___ , /*E566*/ GENx___x___x___ , /*E567*/ GENx___x___x___ , /*E568*/ GENx___x___x___ , /*E569*/ GENx___x___x___ , /*E56A*/ GENx___x___x___ , /*E56B*/ GENx___x___x___ , /*E56C*/ GENx___x___x___ , /*E56D*/ GENx___x___x___ , /*E56E*/ GENx___x___x___ , /*E56F*/ GENx___x___x___ , /*E570*/ GENx___x___x___ , /*E571*/ GENx___x___x___ , /*E572*/ GENx___x___x___ , /*E573*/ GENx___x___x___ , /*E574*/ GENx___x___x___ , /*E575*/ GENx___x___x___ , /*E576*/ GENx___x___x___ , /*E577*/ GENx___x___x___ , /*E578*/ GENx___x___x___ , /*E579*/ GENx___x___x___ , /*E57A*/ GENx___x___x___ , /*E57B*/ GENx___x___x___ , /*E57C*/ GENx___x___x___ , /*E57D*/ GENx___x___x___ , /*E57E*/ GENx___x___x___ , /*E57F*/ GENx___x___x___ , /*E580*/ GENx___x___x___ , /*E581*/ GENx___x___x___ , /*E582*/ GENx___x___x___ , /*E583*/ GENx___x___x___ , /*E584*/ GENx___x___x___ , /*E585*/ GENx___x___x___ , /*E586*/ GENx___x___x___ , /*E587*/ GENx___x___x___ , /*E588*/ GENx___x___x___ , /*E589*/ GENx___x___x___ , /*E58A*/ GENx___x___x___ , /*E58B*/ GENx___x___x___ , /*E58C*/ GENx___x___x___ , /*E58D*/ GENx___x___x___ , /*E58E*/ GENx___x___x___ , /*E58F*/ GENx___x___x___ , /*E590*/ GENx___x___x___ , /*E591*/ GENx___x___x___ , /*E592*/ GENx___x___x___ , /*E593*/ GENx___x___x___ , /*E594*/ GENx___x___x___ , /*E595*/ GENx___x___x___ , /*E596*/ GENx___x___x___ , /*E597*/ GENx___x___x___ , /*E598*/ GENx___x___x___ , /*E599*/ GENx___x___x___ , /*E59A*/ GENx___x___x___ , /*E59B*/ GENx___x___x___ , /*E59C*/ GENx___x___x___ , /*E59D*/ GENx___x___x___ , /*E59E*/ GENx___x___x___ , /*E59F*/ GENx___x___x___ , /*E5A0*/ GENx___x___x___ , /*E5A1*/ GENx___x___x___ , /*E5A2*/ GENx___x___x___ , /*E5A3*/ GENx___x___x___ , /*E5A4*/ GENx___x___x___ , /*E5A5*/ GENx___x___x___ , /*E5A6*/ GENx___x___x___ , /*E5A7*/ GENx___x___x___ , /*E5A8*/ GENx___x___x___ , /*E5A9*/ GENx___x___x___ , /*E5AA*/ GENx___x___x___ , /*E5AB*/ GENx___x___x___ , /*E5AC*/ GENx___x___x___ , /*E5AD*/ GENx___x___x___ , /*E5AE*/ GENx___x___x___ , /*E5AF*/ GENx___x___x___ , /*E5B0*/ GENx___x___x___ , /*E5B1*/ GENx___x___x___ , /*E5B2*/ GENx___x___x___ , /*E5B3*/ GENx___x___x___ , /*E5B4*/ GENx___x___x___ , /*E5B5*/ GENx___x___x___ , /*E5B6*/ GENx___x___x___ , /*E5B7*/ GENx___x___x___ , /*E5B8*/ GENx___x___x___ , /*E5B9*/ GENx___x___x___ , /*E5BA*/ GENx___x___x___ , /*E5BB*/ GENx___x___x___ , /*E5BC*/ GENx___x___x___ , /*E5BD*/ GENx___x___x___ , /*E5BE*/ GENx___x___x___ , /*E5BF*/ GENx___x___x___ , /*E5C0*/ GENx___x___x___ , /*E5C1*/ GENx___x___x___ , /*E5C2*/ GENx___x___x___ , /*E5C3*/ GENx___x___x___ , /*E5C4*/ GENx___x___x___ , /*E5C5*/ GENx___x___x___ , /*E5C6*/ GENx___x___x___ , /*E5C7*/ GENx___x___x___ , /*E5C8*/ GENx___x___x___ , /*E5C9*/ GENx___x___x___ , /*E5CA*/ GENx___x___x___ , /*E5CB*/ GENx___x___x___ , /*E5CC*/ GENx___x___x___ , /*E5CD*/ GENx___x___x___ , /*E5CE*/ GENx___x___x___ , /*E5CF*/ GENx___x___x___ , /*E5D0*/ GENx___x___x___ , /*E5D1*/ GENx___x___x___ , /*E5D2*/ GENx___x___x___ , /*E5D3*/ GENx___x___x___ , /*E5D4*/ GENx___x___x___ , /*E5D5*/ GENx___x___x___ , /*E5D6*/ GENx___x___x___ , /*E5D7*/ GENx___x___x___ , /*E5D8*/ GENx___x___x___ , /*E5D9*/ GENx___x___x___ , /*E5DA*/ GENx___x___x___ , /*E5DB*/ GENx___x___x___ , /*E5DC*/ GENx___x___x___ , /*E5DD*/ GENx___x___x___ , /*E5DE*/ GENx___x___x___ , /*E5DF*/ GENx___x___x___ , /*E5E0*/ GENx___x___x___ , /*E5E1*/ GENx___x___x___ , /*E5E2*/ GENx___x___x___ , /*E5E3*/ GENx___x___x___ , /*E5E4*/ GENx___x___x___ , /*E5E5*/ GENx___x___x___ , /*E5E6*/ GENx___x___x___ , /*E5E7*/ GENx___x___x___ , /*E5E8*/ GENx___x___x___ , /*E5E9*/ GENx___x___x___ , /*E5EA*/ GENx___x___x___ , /*E5EB*/ GENx___x___x___ , /*E5EC*/ GENx___x___x___ , /*E5ED*/ GENx___x___x___ , /*E5EE*/ GENx___x___x___ , /*E5EF*/ GENx___x___x___ , /*E5F0*/ GENx___x___x___ , /*E5F1*/ GENx___x___x___ , /*E5F2*/ GENx___x___x___ , /*E5F3*/ GENx___x___x___ , /*E5F4*/ GENx___x___x___ , /*E5F5*/ GENx___x___x___ , /*E5F6*/ GENx___x___x___ , /*E5F7*/ GENx___x___x___ , /*E5F8*/ GENx___x___x___ , /*E5F9*/ GENx___x___x___ , /*E5FA*/ GENx___x___x___ , /*E5FB*/ GENx___x___x___ , /*E5FC*/ GENx___x___x___ , /*E5FD*/ GENx___x___x___ , /*E5FE*/ GENx___x___x___ , /*E5FF*/ GENx___x___x___ }; DLL_EXPORT zz_func opcode_e6xx[256][GEN_MAXARCH] = { /*E600*/ GENx370x___x___ (ecpsvm_basic_freex,SSE,"FREE"), /*E601*/ GENx370x___x___ (ecpsvm_basic_fretx,SSE,"FRET"), /*E602*/ GENx370x___x___ (ecpsvm_lock_page,SSE,"VLKPG"), /*E603*/ GENx370x___x___ (ecpsvm_unlock_page,SSE,"VULKP"), /*E604*/ GENx370x___x___ (ecpsvm_decode_next_ccw,SSE,"DNCCW"), /*E605*/ GENx370x___x___ (ecpsvm_free_ccwstor,SSE,"FCCWS"), /*E606*/ GENx370x___x___ (ecpsvm_locate_vblock,SSE,"SCNVU"), /*E607*/ GENx370x___x___ (ecpsvm_disp1,SSE,"ECPS:DISP1"), /*E608*/ GENx370x___x___ (ecpsvm_tpage,SSE,"ECPS:TRBRG"), /*E609*/ GENx370x___x___ (ecpsvm_tpage_lock,SSE,"TRLCK"), /*E60A*/ GENx370x___x___ (ecpsvm_inval_segtab,SSE,"VIST"), /*E60B*/ GENx370x___x___ (ecpsvm_inval_ptable,SSE,"VIPT"), /*E60C*/ GENx370x___x___ (ecpsvm_decode_first_ccw,SSE,"DFCCW"), /*E60D*/ GENx370x___x___ (ecpsvm_dispatch_main,SSE,"DISP0"), /*E60E*/ GENx370x___x___ (ecpsvm_locate_rblock,SSE,"SCNRU"), /*E60F*/ GENx370x___x___ (ecpsvm_comm_ccwproc,SSE,"CCWGN"), /*E610*/ GENx370x___x___ (ecpsvm_unxlate_ccw,SSE,"UXCCW"), /*E611*/ GENx370x___x___ (ecpsvm_disp2,SSE,"DISP2"), /*E612*/ GENx370x___x___ (ecpsvm_store_level,SSE,"STEVL"), /*E613*/ GENx370x___x___ (ecpsvm_loc_chgshrpg,SSE,"LCSPG"), /*E614*/ GENx370x___x___ (ecpsvm_extended_freex,SSE,"FREEX"), /*E615*/ GENx370x___x___ (ecpsvm_extended_fretx,SSE,"FRETX"), /*E616*/ GENx370x___x___ (ecpsvm_prefmach_assist,SSE,"PRFMA"), /*E617*/ GENx___x___x___ , /*E618*/ GENx___x___x___ , /*E619*/ GENx___x___x___ , /*E61A*/ GENx___x___x___ , /*E61B*/ GENx___x___x___ , /*E61C*/ GENx___x___x___ , /*E61D*/ GENx___x___x___ , /*E61E*/ GENx___x___x___ , /*E61F*/ GENx___x___x___ , /*E620*/ GENx___x___x___ , /*E621*/ GENx___x___x___ , /*E622*/ GENx___x___x___ , /*E623*/ GENx___x___x___ , /*E624*/ GENx___x___x___ , /*E625*/ GENx___x___x___ , /*E626*/ GENx___x___x___ , /*E627*/ GENx___x___x___ , /*E628*/ GENx___x___x___ , /*E629*/ GENx___x___x___ , /*E62A*/ GENx___x___x___ , /*E62B*/ GENx___x___x___ , /*E62C*/ GENx___x___x___ , /*E62D*/ GENx___x___x___ , /*E62E*/ GENx___x___x___ , /*E62F*/ GENx___x___x___ , /*E630*/ GENx___x___x___ , /*E631*/ GENx___x___x___ , /*E632*/ GENx___x___x___ , /*E633*/ GENx___x___x___ , /*E634*/ GENx___x___x___ , /*E635*/ GENx___x___x___ , /*E636*/ GENx___x___x___ , /*E637*/ GENx___x___x___ , /*E638*/ GENx___x___x___ , /*E639*/ GENx___x___x___ , /*E63A*/ GENx___x___x___ , /*E63B*/ GENx___x___x___ , /*E63C*/ GENx___x___x___ , /*E63D*/ GENx___x___x___ , /*E63E*/ GENx___x___x___ , /*E63F*/ GENx___x___x___ , /*E640*/ GENx___x___x___ , /*E641*/ GENx___x___x___ , /*E642*/ GENx___x___x___ , /*E643*/ GENx___x___x___ , /*E644*/ GENx___x___x___ , /*E645*/ GENx___x___x___ , /*E646*/ GENx___x___x___ , /*E647*/ GENx___x___x___ , /*E648*/ GENx___x___x___ , /*E649*/ GENx___x___x___ , /*E64A*/ GENx___x___x___ , /*E64B*/ GENx___x___x___ , /*E64C*/ GENx___x___x___ , /*E64D*/ GENx___x___x___ , /*E64E*/ GENx___x___x___ , /*E64F*/ GENx___x___x___ , /*E650*/ GENx___x___x___ , /*E651*/ GENx___x___x___ , /*E652*/ GENx___x___x___ , /*E653*/ GENx___x___x___ , /*E654*/ GENx___x___x___ , /*E655*/ GENx___x___x___ , /*E656*/ GENx___x___x___ , /*E657*/ GENx___x___x___ , /*E658*/ GENx___x___x___ , /*E659*/ GENx___x___x___ , /*E65A*/ GENx___x___x___ , /*E65B*/ GENx___x___x___ , /*E65C*/ GENx___x___x___ , /*E65D*/ GENx___x___x___ , /*E65E*/ GENx___x___x___ , /*E65F*/ GENx___x___x___ , /*E660*/ GENx___x___x___ , /*E661*/ GENx___x___x___ , /*E662*/ GENx___x___x___ , /*E663*/ GENx___x___x___ , /*E664*/ GENx___x___x___ , /*E665*/ GENx___x___x___ , /*E666*/ GENx___x___x___ , /*E667*/ GENx___x___x___ , /*E668*/ GENx___x___x___ , /*E669*/ GENx___x___x___ , /*E66A*/ GENx___x___x___ , /*E66B*/ GENx___x___x___ , /*E66C*/ GENx___x___x___ , /*E66D*/ GENx___x___x___ , /*E66E*/ GENx___x___x___ , /*E66F*/ GENx___x___x___ , /*E670*/ GENx___x___x___ , /*E671*/ GENx___x___x___ , /*E672*/ GENx___x___x___ , /*E673*/ GENx___x___x___ , /*E674*/ GENx___x___x___ , /*E675*/ GENx___x___x___ , /*E676*/ GENx___x___x___ , /*E677*/ GENx___x___x___ , /*E678*/ GENx___x___x___ , /*E679*/ GENx___x___x___ , /*E67A*/ GENx___x___x___ , /*E67B*/ GENx___x___x___ , /*E67C*/ GENx___x___x___ , /*E67D*/ GENx___x___x___ , /*E67E*/ GENx___x___x___ , /*E67F*/ GENx___x___x___ , /*E680*/ GENx___x___x___ , /*E681*/ GENx___x___x___ , /*E682*/ GENx___x___x___ , /*E683*/ GENx___x___x___ , /*E684*/ GENx___x___x___ , /*E685*/ GENx___x___x___ , /*E686*/ GENx___x___x___ , /*E687*/ GENx___x___x___ , /*E688*/ GENx___x___x___ , /*E689*/ GENx___x___x___ , /*E68A*/ GENx___x___x___ , /*E68B*/ GENx___x___x___ , /*E68C*/ GENx___x___x___ , /*E68D*/ GENx___x___x___ , /*E68E*/ GENx___x___x___ , /*E68F*/ GENx___x___x___ , /*E690*/ GENx___x___x___ , /*E691*/ GENx___x___x___ , /*E692*/ GENx___x___x___ , /*E693*/ GENx___x___x___ , /*E694*/ GENx___x___x___ , /*E695*/ GENx___x___x___ , /*E696*/ GENx___x___x___ , /*E697*/ GENx___x___x___ , /*E698*/ GENx___x___x___ , /*E699*/ GENx___x___x___ , /*E69A*/ GENx___x___x___ , /*E69B*/ GENx___x___x___ , /*E69C*/ GENx___x___x___ , /*E69D*/ GENx___x___x___ , /*E69E*/ GENx___x___x___ , /*E69F*/ GENx___x___x___ , /*E6A0*/ GENx___x___x___ , /*E6A1*/ GENx___x___x___ , /*E6A2*/ GENx___x___x___ , /*E6A3*/ GENx___x___x___ , /*E6A4*/ GENx___x___x___ , /*E6A5*/ GENx___x___x___ , /*E6A6*/ GENx___x___x___ , /*E6A7*/ GENx___x___x___ , /*E6A8*/ GENx___x___x___ , /*E6A9*/ GENx___x___x___ , /*E6AA*/ GENx___x___x___ , /*E6AB*/ GENx___x___x___ , /*E6AC*/ GENx___x___x___ , /*E6AD*/ GENx___x___x___ , /*E6AE*/ GENx___x___x___ , /*E6AF*/ GENx___x___x___ , /*E6B0*/ GENx___x___x___ , /*E6B1*/ GENx___x___x___ , /*E6B2*/ GENx___x___x___ , /*E6B3*/ GENx___x___x___ , /*E6B4*/ GENx___x___x___ , /*E6B5*/ GENx___x___x___ , /*E6B6*/ GENx___x___x___ , /*E6B7*/ GENx___x___x___ , /*E6B8*/ GENx___x___x___ , /*E6B9*/ GENx___x___x___ , /*E6BA*/ GENx___x___x___ , /*E6BB*/ GENx___x___x___ , /*E6BC*/ GENx___x___x___ , /*E6BD*/ GENx___x___x___ , /*E6BE*/ GENx___x___x___ , /*E6BF*/ GENx___x___x___ , /*E6C0*/ GENx___x___x___ , /*E6C1*/ GENx___x___x___ , /*E6C2*/ GENx___x___x___ , /*E6C3*/ GENx___x___x___ , /*E6C4*/ GENx___x___x___ , /*E6C5*/ GENx___x___x___ , /*E6C6*/ GENx___x___x___ , /*E6C7*/ GENx___x___x___ , /*E6C8*/ GENx___x___x___ , /*E6C9*/ GENx___x___x___ , /*E6CA*/ GENx___x___x___ , /*E6CB*/ GENx___x___x___ , /*E6CC*/ GENx___x___x___ , /*E6CD*/ GENx___x___x___ , /*E6CE*/ GENx___x___x___ , /*E6CF*/ GENx___x___x___ , /*E6D0*/ GENx___x___x___ , /*E6D1*/ GENx___x___x___ , /*E6D2*/ GENx___x___x___ , /*E6D3*/ GENx___x___x___ , /*E6D4*/ GENx___x___x___ , /*E6D5*/ GENx___x___x___ , /*E6D6*/ GENx___x___x___ , /*E6D7*/ GENx___x___x___ , /*E6D8*/ GENx___x___x___ , /*E6D9*/ GENx___x___x___ , /*E6DA*/ GENx___x___x___ , /*E6DB*/ GENx___x___x___ , /*E6DC*/ GENx___x___x___ , /*E6DD*/ GENx___x___x___ , /*E6DE*/ GENx___x___x___ , /*E6DF*/ GENx___x___x___ , /*E6E0*/ GENx___x___x___ , /*E6E1*/ GENx___x___x___ , /*E6E2*/ GENx___x___x___ , /*E6E3*/ GENx___x___x___ , /*E6E4*/ GENx___x___x___ , /*E6E5*/ GENx___x___x___ , /*E6E6*/ GENx___x___x___ , /*E6E7*/ GENx___x___x___ , /*E6E8*/ GENx___x___x___ , /*E6E9*/ GENx___x___x___ , /*E6EA*/ GENx___x___x___ , /*E6EB*/ GENx___x___x___ , /*E6EC*/ GENx___x___x___ , /*E6ED*/ GENx___x___x___ , /*E6EE*/ GENx___x___x___ , /*E6EF*/ GENx___x___x___ , /*E6F0*/ GENx___x___x___ , /*E6F1*/ GENx___x___x___ , /*E6F2*/ GENx___x___x___ , /*E6F3*/ GENx___x___x___ , /*E6F4*/ GENx___x___x___ , /*E6F5*/ GENx___x___x___ , /*E6F6*/ GENx___x___x___ , /*E6F7*/ GENx___x___x___ , /*E6F8*/ GENx___x___x___ , /*E6F9*/ GENx___x___x___ , /*E6FA*/ GENx___x___x___ , /*E6FB*/ GENx___x___x___ , /*E6FC*/ GENx___x___x___ , /*E6FD*/ GENx___x___x___ , /*E6FE*/ GENx___x___x___ , /*E6FF*/ GENx___x___x___ }; // #if defined(FEATURE_ESAME) /* opcodes EBxxxxxx00 */ DLL_EXPORT zz_func opcode_ebxx[256][GEN_MAXARCH] = { /*EB00*/ GENx___x___x___ , /*EB01*/ GENx___x___x___ , /*EB02*/ GENx___x___x___ , /*EB03*/ GENx___x___x___ , /*EB04*/ GENx___x___x900 (load_multiple_long,RSY,"LMG"), /*EB05*/ GENx___x___x___ , /*EB06*/ GENx___x___x___ , /*EB07*/ GENx___x___x___ , /*EB08*/ GENx___x___x___ , /*EB09*/ GENx___x___x___ , /*EB0A*/ GENx___x___x900 (shift_right_single_long,RSY,"SRAG"), /*EB0B*/ GENx___x___x900 (shift_left_single_long,RSY,"SLAG"), /*EB0C*/ GENx___x___x900 (shift_right_single_logical_long,RSY,"SRLG"), /*EB0D*/ GENx___x___x900 (shift_left_single_logical_long,RSY,"SLLG"), /*EB0E*/ GENx___x___x___ , /*EB0F*/ GENx___x___x900 (trace_long,RSY,"TRACG"), /*EB10*/ GENx___x___x___ , /*EB11*/ GENx___x___x___ , /*EB12*/ GENx___x___x___ , /*EB13*/ GENx___x___x___ , /*EB14*/ GENx___x___x900 (compare_and_swap_y,RSY,"CSY"), /*EB15*/ GENx___x___x___ , /*EB16*/ GENx___x___x___ , /*EB17*/ GENx___x___x___ , /*EB18*/ GENx___x___x___ , /*EB19*/ GENx___x___x___ , /*EB1A*/ GENx___x___x___ , /*EB1B*/ GENx___x___x___ , /*EB1C*/ GENx___x___x900 (rotate_left_single_logical_long,RSY,"RLLG"), /*EB1D*/ GENx37Xx390x900 (rotate_left_single_logical,RSY,"RLL"), /*EB1E*/ GENx___x___x___ , /*EB1F*/ GENx___x___x___ , /*EB20*/ GENx___x___x900 (compare_logical_characters_under_mask_high,RSY,"CLMH"), /*EB21*/ GENx___x___x900 (compare_logical_characters_under_mask_y,RSY,"CLMY"), /*EB22*/ GENx___x___x___ , /*EB23*/ GENx___x___x900 (compare_logical_and_trap,RSY,"CLT"), /*912*/ /*EB24*/ GENx___x___x900 (store_multiple_long,RSY,"STMG"), /*EB25*/ GENx___x___x900 (store_control_long,RSY,"STCTG"), /*EB26*/ GENx___x___x900 (store_multiple_high,RSY,"STMH"), /*EB27*/ GENx___x___x___ , /*EB28*/ GENx___x___x___ , /*EB29*/ GENx___x___x___ , /*EB2A*/ GENx___x___x___ , /*EB2B*/ GENx___x___x900 (compare_logical_and_trap_long,RSY,"CLGT"), /*912*/ /*EB2C*/ GENx___x___x900 (store_characters_under_mask_high,RSY,"STCMH"), /*EB2D*/ GENx___x___x900 (store_characters_under_mask_y,RSY,"STCMY"), /*EB2E*/ GENx___x___x___ , /*EB2F*/ GENx___x___x900 (load_control_long,RSY,"LCTLG"), /*EB30*/ GENx___x___x900 (compare_and_swap_long,RSY,"CSG"), /*EB31*/ GENx___x___x900 (compare_double_and_swap_y,RSY,"CDSY"), /*EB32*/ GENx___x___x___ , /*EB33*/ GENx___x___x___ , /*EB34*/ GENx___x___x___ , /*EB35*/ GENx___x___x___ , /*EB36*/ GENx___x___x___ , /*EB37*/ GENx___x___x___ , /*EB38*/ GENx___x___x___ , /*EB39*/ GENx___x___x___ , /*EB3A*/ GENx___x___x___ , /*EB3B*/ GENx___x___x___ , /*EB3C*/ GENx___x___x___ , /*EB3D*/ GENx___x___x___ , /*EB3E*/ GENx___x___x900 (compare_double_and_swap_long,RSY,"CDSG"), /*EB3F*/ GENx___x___x___ , /*EB40*/ GENx___x___x___ , /*EB41*/ GENx___x___x___ , /*EB42*/ GENx___x___x___ , /*EB43*/ GENx___x___x___ , /*EB44*/ GENx___x___x900 (branch_on_index_high_long,RSY,"BXHG"), /*EB45*/ GENx___x___x900 (branch_on_index_low_or_equal_long,RSY,"BXLEG"), /*EB46*/ GENx___x___x___ , /*EB47*/ GENx___x___x___ , /*EB48*/ GENx___x___x___ , /*EB49*/ GENx___x___x___ , /*EB4A*/ GENx___x___x___ , /*EB4B*/ GENx___x___x___ , /*EB4C*/ GENx___x___x900 (extract_cache_attribute,RSY,"ECAG"), /*208*/ /*EB4D*/ GENx___x___x___ , /*EB4E*/ GENx___x___x___ , /*EB4F*/ GENx___x___x___ , /*EB50*/ GENx___x___x___ , /*EB51*/ GENx___x___x900 (test_under_mask_y,SIY,"TMY"), /*EB52*/ GENx___x___x900 (move_immediate_y,SIY,"MVIY"), /*EB53*/ GENx___x___x___ , /*EB54*/ GENx___x___x900 (and_immediate_y,SIY,"NIY"), /*EB55*/ GENx___x___x900 (compare_logical_immediate_y,SIY,"CLIY"), /*EB56*/ GENx___x___x900 (or_immediate_y,SIY,"OIY"), /*EB57*/ GENx___x___x900 (exclusive_or_immediate_y,SIY,"XIY"), /*EB58*/ GENx___x___x___ , /*EB59*/ GENx___x___x___ , /*EB5A*/ GENx___x___x___ , /*EB5B*/ GENx___x___x___ , /*EB5C*/ GENx___x___x___ , /*EB5D*/ GENx___x___x___ , /*EB5E*/ GENx___x___x___ , /*EB5F*/ GENx___x___x___ , /*EB60*/ GENx___x___x___ , /*EB61*/ GENx___x___x___ , /*EB62*/ GENx___x___x___ , /*EB63*/ GENx___x___x___ , /*EB64*/ GENx___x___x___ , /*EB65*/ GENx___x___x___ , /*EB66*/ GENx___x___x___ , /*EB67*/ GENx___x___x___ , /*EB68*/ GENx___x___x___ , /*EB69*/ GENx___x___x___ , /*EB6A*/ GENx37Xx390x900 (add_immediate_storage,SIY,"ASI"), /*208*/ /*EB6B*/ GENx___x___x___ , /*EB6C*/ GENx___x___x___ , /*EB6D*/ GENx___x___x___ , /*EB6E*/ GENx37Xx390x900 (add_logical_with_signed_immediate,SIY,"ALSI"), /*208*/ /*EB6F*/ GENx___x___x___ , /*EB70*/ GENx___x___x___ , /*EB71*/ GENx___x___x___ , /*EB72*/ GENx___x___x___ , /*EB73*/ GENx___x___x___ , /*EB74*/ GENx___x___x___ , /*EB75*/ GENx___x___x___ , /*EB76*/ GENx___x___x___ , /*EB77*/ GENx___x___x___ , /*EB78*/ GENx___x___x___ , /*EB79*/ GENx___x___x___ , /*EB7A*/ GENx37Xx390x900 (add_immediate_long_storage,SIY,"AGSI"), /*208*/ /*EB7B*/ GENx___x___x___ , /*EB7C*/ GENx___x___x___ , /*EB7D*/ GENx___x___x___ , /*EB7E*/ GENx37Xx390x900 (add_logical_with_signed_immediate_long,SIY,"ALGSI"), /*208*/ /*EB7F*/ GENx___x___x___ , /*EB80*/ GENx___x___x900 (insert_characters_under_mask_high,RSY,"ICMH"), /*EB81*/ GENx___x___x900 (insert_characters_under_mask_y,RSY,"ICMY"), /*EB82*/ GENx___x___x___ , /*EB83*/ GENx___x___x___ , /*EB84*/ GENx___x___x___ , /*EB85*/ GENx___x___x___ , /*EB86*/ GENx___x___x___ , /*EB87*/ GENx___x___x___ , /*EB88*/ GENx___x___x___ , /*EB89*/ GENx___x___x___ , /*EB8A*/ GENx___x___x___ , /*(set_qdio_buffer_state,?,"SQBS"),*/ /*EB8B*/ GENx___x___x___ , /*EB8C*/ GENx___x___x___ , /*EB8D*/ GENx___x___x___ , /*EB8E*/ GENx37Xx390x900 (move_long_unicode,RSY,"MVCLU"), /*EB8F*/ GENx37Xx390x900 (compare_logical_long_unicode,RSY,"CLCLU"), /*EB90*/ GENx___x___x900 (store_multiple_y,RSY,"STMY"), /*EB91*/ GENx___x___x___ , /*EB92*/ GENx___x___x___ , /*EB93*/ GENx___x___x___ , /*EB94*/ GENx___x___x___ , /*EB95*/ GENx___x___x___ , /*EB96*/ GENx___x___x900 (load_multiple_high,RSY,"LMH"), /*EB97*/ GENx___x___x___ , /*EB98*/ GENx___x___x900 (load_multiple_y,RSY,"LMY"), /*EB99*/ GENx___x___x___ , /*EB9A*/ GENx___x___x900 (load_access_multiple_y,RSY,"LAMY"), /*EB9B*/ GENx___x___x900 (store_access_multiple_y,RSY,"STAMY"), /*EB9C*/ GENx___x___x___ , /*EB9D*/ GENx___x___x___ , /*EB9E*/ GENx___x___x___ , /*EB9F*/ GENx___x___x___ , /*EBA0*/ GENx___x___x___ , /*EBA1*/ GENx___x___x___ , /*EBA2*/ GENx___x___x___ , /*EBA3*/ GENx___x___x___ , /*EBEB*/ GENx___x___x___ , /*EBA5*/ GENx___x___x___ , /*EBA6*/ GENx___x___x___ , /*EBA7*/ GENx___x___x___ , /*EBA8*/ GENx___x___x___ , /*EBA9*/ GENx___x___x___ , /*EBAA*/ GENx___x___x___ , /*EBAB*/ GENx___x___x___ , /*EBAC*/ GENx___x___x___ , /*EBAD*/ GENx___x___x___ , /*EBAE*/ GENx___x___x___ , /*EBAF*/ GENx___x___x___ , /*EBB0*/ GENx___x___x___ , /*EBB1*/ GENx___x___x___ , /*EBB2*/ GENx___x___x___ , /*EBB3*/ GENx___x___x___ , /*EBB4*/ GENx___x___x___ , /*EBB5*/ GENx___x___x___ , /*EBB6*/ GENx___x___x___ , /*EBB7*/ GENx___x___x___ , /*EBB8*/ GENx___x___x___ , /*EBEB*/ GENx___x___x___ , /*EBBA*/ GENx___x___x___ , /*EBBB*/ GENx___x___x___ , /*EBBC*/ GENx___x___x___ , /*EBBD*/ GENx___x___x___ , /*EBBE*/ GENx___x___x___ , /*EBBF*/ GENx___x___x___ , /*EBC0*/ GENx37Xx390x900 (test_decimal,RSL,"TP"), /*EBC1*/ GENx___x___x___ , /*EBC2*/ GENx___x___x___ , /*EBC3*/ GENx___x___x___ , /*EBC4*/ GENx___x___x___ , /*EBC5*/ GENx___x___x___ , /*EBC6*/ GENx___x___x___ , /*EBC7*/ GENx___x___x___ , /*EBC8*/ GENx___x___x___ , /*EBC9*/ GENx___x___x___ , /*EBCA*/ GENx___x___x___ , /*EBCB*/ GENx___x___x___ , /*EBCC*/ GENx___x___x___ , /*EBCD*/ GENx___x___x___ , /*EBCE*/ GENx___x___x___ , /*EBCF*/ GENx___x___x___ , /*EBD0*/ GENx___x___x___ , /*EBD1*/ GENx___x___x___ , /*EBD2*/ GENx___x___x___ , /*EBD3*/ GENx___x___x___ , /*EBD4*/ GENx___x___x___ , /*EBD5*/ GENx___x___x___ , /*EBD6*/ GENx___x___x___ , /*EBD7*/ GENx___x___x___ , /*EBD8*/ GENx___x___x___ , /*EBD9*/ GENx___x___x___ , /*EBDA*/ GENx___x___x___ , /*EBDB*/ GENx___x___x___ , /*EBDC*/ GENx37Xx390x900 (shift_right_single_distinct,RSY,"SRAK"), /*810*/ /*EBDD*/ GENx37Xx390x900 (shift_left_single_distinct,RSY,"SLAK"), /*810*/ /*EBDE*/ GENx37Xx390x900 (shift_right_single_logical_distinct,RSY,"SRLK"), /*810*/ /*EBDF*/ GENx37Xx390x900 (shift_left_single_logical_distinct,RSY,"SLLK"), /*810*/ /*EBE0*/ GENx___x___x___ , /*EBE1*/ GENx___x___x___ , /*EBE2*/ GENx___x___x900 (load_on_condition_long,RSY_M3,"LOCG"), /*810*/ /*EBE3*/ GENx___x___x900 (store_on_condition_long,RSY_M3,"STOCG"), /*810*/ /*EBE4*/ GENx___x___x900 (load_and_and_long,RSY,"LANG"), /*810*/ /*EBE5*/ GENx___x___x___ , /*EBE6*/ GENx___x___x900 (load_and_or_long,RSY,"LAOG"), /*810*/ /*EBE7*/ GENx___x___x900 (load_and_exclusive_or_long,RSY,"LAXG"), /*810*/ /*EBE8*/ GENx___x___x900 (load_and_add_long,RSY,"LAAG"), /*810*/ /*EBE9*/ GENx___x___x___ , /*EBEA*/ GENx___x___x900 (load_and_add_logical_long,RSY,"LAALG"), /*810*/ /*EBEB*/ GENx___x___x___ , /*EBEC*/ GENx___x___x___ , /*EBED*/ GENx___x___x___ , /*EBEE*/ GENx___x___x___ , /*EBEF*/ GENx___x___x___ , /*EBF0*/ GENx___x___x___ , /*EBF1*/ GENx___x___x___ , /*EBF2*/ GENx37Xx390x900 (load_on_condition,RSY_M3,"LOC"), /*810*/ /*EBF3*/ GENx37Xx390x900 (store_on_condition,RSY_M3,"STOC"), /*810*/ /*EBF4*/ GENx37Xx390x900 (load_and_and,RSY,"LAN"), /*810*/ /*EBF5*/ GENx___x___x___ , /*EBF6*/ GENx37Xx390x900 (load_and_or,RSY,"LAO"), /*810*/ /*EBF7*/ GENx37Xx390x900 (load_and_exclusive_or,RSY,"LAX"), /*810*/ /*EBF8*/ GENx37Xx390x900 (load_and_add,RSY,"LAA"), /*810*/ /*EBF9*/ GENx___x___x___ , /*EBFA*/ GENx37Xx390x900 (load_and_add_logical,RSY,"LAAL"), /*810*/ /*EBFB*/ GENx___x___x___ , /*EBFC*/ GENx___x___x___ , /*EBFD*/ GENx___x___x___ , /*EBFE*/ GENx___x___x___ , /*EBFF*/ GENx___x___x___ }; // #endif /*defined(FEATURE_ESAME)*/ // #if defined(FEATURE_ESAME) DLL_EXPORT zz_func opcode_ecxx[256][GEN_MAXARCH] = { /*EC00*/ GENx___x___x___ , /*EC01*/ GENx___x___x___ , /*EC02*/ GENx___x___x___ , /*EC03*/ GENx___x___x___ , /*EC04*/ GENx___x___x___ , /*EC05*/ GENx___x___x___ , /*EC06*/ GENx___x___x___ , /*EC07*/ GENx___x___x___ , /*EC08*/ GENx___x___x___ , /*EC09*/ GENx___x___x___ , /*EC0A*/ GENx___x___x___ , /*EC0B*/ GENx___x___x___ , /*EC0C*/ GENx___x___x___ , /*EC0D*/ GENx___x___x___ , /*EC0E*/ GENx___x___x___ , /*EC0F*/ GENx___x___x___ , /*EC10*/ GENx___x___x___ , /*EC11*/ GENx___x___x___ , /*EC12*/ GENx___x___x___ , /*EC13*/ GENx___x___x___ , /*EC14*/ GENx___x___x___ , /*EC15*/ GENx___x___x___ , /*EC16*/ GENx___x___x___ , /*EC17*/ GENx___x___x___ , /*EC18*/ GENx___x___x___ , /*EC19*/ GENx___x___x___ , /*EC1A*/ GENx___x___x___ , /*EC1B*/ GENx___x___x___ , /*EC1C*/ GENx___x___x___ , /*EC1D*/ GENx___x___x___ , /*EC1E*/ GENx___x___x___ , /*EC1F*/ GENx___x___x___ , /*EC20*/ GENx___x___x___ , /*EC21*/ GENx___x___x___ , /*EC22*/ GENx___x___x___ , /*EC23*/ GENx___x___x___ , /*EC24*/ GENx___x___x___ , /*EC25*/ GENx___x___x___ , /*EC26*/ GENx___x___x___ , /*EC27*/ GENx___x___x___ , /*EC28*/ GENx___x___x___ , /*EC29*/ GENx___x___x___ , /*EC2A*/ GENx___x___x___ , /*EC2B*/ GENx___x___x___ , /*EC2C*/ GENx___x___x___ , /*EC2D*/ GENx___x___x___ , /*EC2E*/ GENx___x___x___ , /*EC2F*/ GENx___x___x___ , /*EC30*/ GENx___x___x___ , /*EC31*/ GENx___x___x___ , /*EC32*/ GENx___x___x___ , /*EC33*/ GENx___x___x___ , /*EC34*/ GENx___x___x___ , /*EC35*/ GENx___x___x___ , /*EC36*/ GENx___x___x___ , /*EC37*/ GENx___x___x___ , /*EC38*/ GENx___x___x___ , /*EC39*/ GENx___x___x___ , /*EC3A*/ GENx___x___x___ , /*EC3B*/ GENx___x___x___ , /*EC3C*/ GENx___x___x___ , /*EC3D*/ GENx___x___x___ , /*EC3E*/ GENx___x___x___ , /*EC3F*/ GENx___x___x___ , /*EC40*/ GENx___x___x___ , /*EC41*/ GENx___x___x___ , /*EC42*/ GENx___x___x___ , /*EC43*/ GENx___x___x___ , /*EC44*/ GENx___x___x900 (branch_relative_on_index_high_long,RIE,"BRXHG"), /*EC45*/ GENx___x___x900 (branch_relative_on_index_low_or_equal_long,RIE,"BRXLG"), /*EC46*/ GENx___x___x___ , /*EC47*/ GENx___x___x___ , /*EC48*/ GENx___x___x___ , /*EC49*/ GENx___x___x___ , /*EC4A*/ GENx___x___x___ , /*EC4B*/ GENx___x___x___ , /*EC4C*/ GENx___x___x___ , /*EC4D*/ GENx___x___x___ , /*EC4E*/ GENx___x___x___ , /*EC4F*/ GENx___x___x___ , /*EC50*/ GENx___x___x___ , /*EC51*/ GENx___x___x900 (rotate_then_insert_selected_bits_low_long_reg,RIE_RRIII,"RISBLG"), /*810*/ /*EC52*/ GENx___x___x___ , /*EC53*/ GENx___x___x___ , /*EC54*/ GENx___x___x900 (rotate_then_and_selected_bits_long_reg,RIE_RRIII,"RNSBG"), /*208*/ /*EC55*/ GENx___x___x900 (rotate_then_insert_selected_bits_long_reg,RIE_RRIII,"RISBG"), /*208*/ /*EC56*/ GENx___x___x900 (rotate_then_or_selected_bits_long_reg,RIE_RRIII,"ROSBG"), /*208*/ /*EC57*/ GENx___x___x900 (rotate_then_exclusive_or_selected_bits_long_reg,RIE_RRIII,"RXSBG"), /*208*/ /*EC58*/ GENx___x___x___ , /*EC59*/ GENx___x___x900 (rotate_then_insert_selected_bits_long_reg_n,RIE_RRIII,"RISBGN"), /*912*/ /*EC5A*/ GENx___x___x___ , /*EC5B*/ GENx___x___x___ , /*EC5C*/ GENx___x___x___ , /*EC5D*/ GENx___x___x900 (rotate_then_insert_selected_bits_high_long_reg,RIE_RRIII,"RISBHG"), /*810*/ /*EC5E*/ GENx___x___x___ , /*EC5F*/ GENx___x___x___ , /*EC60*/ GENx___x___x___ , /*EC61*/ GENx___x___x___ , /*EC62*/ GENx___x___x___ , /*EC63*/ GENx___x___x___ , /*EC64*/ GENx___x___x900 (compare_and_branch_relative_long_register,RIE_RRIM,"CGRJ"), /*208*/ /*EC65*/ GENx___x___x900 (compare_logical_and_branch_relative_long_register,RIE_RRIM,"CLGRJ"), /*208*/ /*EC66*/ GENx___x___x___ , /*EC67*/ GENx___x___x___ , /*EC68*/ GENx___x___x___ , /*EC69*/ GENx___x___x___ , /*EC6A*/ GENx___x___x___ , /*EC6B*/ GENx___x___x___ , /*EC6C*/ GENx___x___x___ , /*EC6D*/ GENx___x___x___ , /*EC6E*/ GENx___x___x___ , /*EC6F*/ GENx___x___x___ , /*EC70*/ GENx___x___x900 (compare_immediate_and_trap_long,RIE_RIM,"CGIT"), /*208*/ /*EC71*/ GENx___x___x900 (compare_logical_immediate_and_trap_long,RIE_RIM,"CLGIT"), /*208*/ /*EC72*/ GENx37Xx390x900 (compare_immediate_and_trap,RIE_RIM,"CIT"), /*208*/ /*EC73*/ GENx37Xx390x900 (compare_logical_immediate_and_trap_fullword,RIE_RIM,"CLFIT"), /*208*/ /*EC74*/ GENx___x___x___ , /*EC75*/ GENx___x___x___ , /*EC76*/ GENx37Xx390x900 (compare_and_branch_relative_register,RIE_RRIM,"CRJ"), /*208*/ /*EC77*/ GENx37Xx390x900 (compare_logical_and_branch_relative_register,RIE_RRIM,"CLRJ"), /*208*/ /*EC78*/ GENx___x___x___ , /*EC79*/ GENx___x___x___ , /*EC7A*/ GENx___x___x___ , /*EC7B*/ GENx___x___x___ , /*EC7C*/ GENx___x___x900 (compare_immediate_and_branch_relative_long,RIE_RMII,"CGIJ"), /*208*/ /*EC7D*/ GENx___x___x900 (compare_logical_immediate_and_branch_relative_long,RIE_RMII,"CLGIJ"), /*208*/ /*EC7E*/ GENx37Xx390x900 (compare_immediate_and_branch_relative,RIE_RMII,"CIJ"), /*208*/ /*EC7F*/ GENx37Xx390x900 (compare_logical_immediate_and_branch_relative,RIE_RMII,"CLIJ"), /*208*/ /*EC80*/ GENx___x___x___ , /*EC81*/ GENx___x___x___ , /*EC82*/ GENx___x___x___ , /*EC83*/ GENx___x___x___ , /*EC84*/ GENx___x___x___ , /*EC85*/ GENx___x___x___ , /*EC86*/ GENx___x___x___ , /*EC87*/ GENx___x___x___ , /*EC88*/ GENx___x___x___ , /*EC89*/ GENx___x___x___ , /*EC8A*/ GENx___x___x___ , /*EC8B*/ GENx___x___x___ , /*EC8C*/ GENx___x___x___ , /*EC8D*/ GENx___x___x___ , /*EC8E*/ GENx___x___x___ , /*EC8F*/ GENx___x___x___ , /*EC90*/ GENx___x___x___ , /*EC91*/ GENx___x___x___ , /*EC92*/ GENx___x___x___ , /*EC93*/ GENx___x___x___ , /*EC94*/ GENx___x___x___ , /*EC95*/ GENx___x___x___ , /*EC96*/ GENx___x___x___ , /*EC97*/ GENx___x___x___ , /*EC98*/ GENx___x___x___ , /*EC99*/ GENx___x___x___ , /*EC9A*/ GENx___x___x___ , /*EC9B*/ GENx___x___x___ , /*EC9C*/ GENx___x___x___ , /*EC9D*/ GENx___x___x___ , /*EC9E*/ GENx___x___x___ , /*EC9F*/ GENx___x___x___ , /*ECA0*/ GENx___x___x___ , /*ECA1*/ GENx___x___x___ , /*ECA2*/ GENx___x___x___ , /*ECA3*/ GENx___x___x___ , /*ECA4*/ GENx___x___x___ , /*ECA5*/ GENx___x___x___ , /*ECA6*/ GENx___x___x___ , /*ECA7*/ GENx___x___x___ , /*ECA8*/ GENx___x___x___ , /*ECA9*/ GENx___x___x___ , /*ECAA*/ GENx___x___x___ , /*ECAB*/ GENx___x___x___ , /*ECAC*/ GENx___x___x___ , /*ECAD*/ GENx___x___x___ , /*ECAE*/ GENx___x___x___ , /*ECAF*/ GENx___x___x___ , /*ECB0*/ GENx___x___x___ , /*ECB1*/ GENx___x___x___ , /*ECB2*/ GENx___x___x___ , /*ECB3*/ GENx___x___x___ , /*ECB4*/ GENx___x___x___ , /*ECB5*/ GENx___x___x___ , /*ECB6*/ GENx___x___x___ , /*ECB7*/ GENx___x___x___ , /*ECB8*/ GENx___x___x___ , /*ECB9*/ GENx___x___x___ , /*ECBA*/ GENx___x___x___ , /*ECBB*/ GENx___x___x___ , /*ECBC*/ GENx___x___x___ , /*ECBD*/ GENx___x___x___ , /*ECBE*/ GENx___x___x___ , /*ECBF*/ GENx___x___x___ , /*ECC0*/ GENx___x___x___ , /*ECC1*/ GENx___x___x___ , /*ECC2*/ GENx___x___x___ , /*ECC3*/ GENx___x___x___ , /*ECC4*/ GENx___x___x___ , /*ECC5*/ GENx___x___x___ , /*ECC6*/ GENx___x___x___ , /*ECC7*/ GENx___x___x___ , /*ECC8*/ GENx___x___x___ , /*ECC9*/ GENx___x___x___ , /*ECCA*/ GENx___x___x___ , /*ECCB*/ GENx___x___x___ , /*ECCC*/ GENx___x___x___ , /*ECCD*/ GENx___x___x___ , /*ECCE*/ GENx___x___x___ , /*ECCF*/ GENx___x___x___ , /*ECD0*/ GENx___x___x___ , /*ECD1*/ GENx___x___x___ , /*ECD2*/ GENx___x___x___ , /*ECD3*/ GENx___x___x___ , /*ECD4*/ GENx___x___x___ , /*ECD5*/ GENx___x___x___ , /*ECD6*/ GENx___x___x___ , /*ECD7*/ GENx___x___x___ , /*ECD8*/ GENx37Xx390x900 (add_distinct_halfword_immediate,RIE_RRI,"AHIK"), /*810*/ /*ECD9*/ GENx___x___x900 (add_distinct_long_halfword_immediate,RIE_RRI,"AGHIK"), /*810*/ /*ECDA*/ GENx37Xx390x900 (add_logical_distinct_signed_halfword_immediate,RIE_RRI,"ALHSIK"), /*810*/ /*ECDB*/ GENx___x___x900 (add_logical_distinct_long_signed_halfword_immediate,RIE_RRI,"AGLHSIK"), /*810*/ /*ECDC*/ GENx___x___x___ , /*ECDD*/ GENx___x___x___ , /*ECDE*/ GENx___x___x___ , /*ECDF*/ GENx___x___x___ , /*ECE0*/ GENx___x___x___ , /*ECE1*/ GENx___x___x___ , /*ECE2*/ GENx___x___x___ , /*ECE3*/ GENx___x___x___ , /*ECE4*/ GENx___x___x900 (compare_and_branch_long_register,RRS,"CGRB"), /*208*/ /*ECE5*/ GENx___x___x900 (compare_logical_and_branch_long_register,RRS,"CLGRB"), /*208*/ /*ECE6*/ GENx___x___x___ , /*ECE7*/ GENx___x___x___ , /*ECE8*/ GENx___x___x___ , /*ECE9*/ GENx___x___x___ , /*ECEA*/ GENx___x___x___ , /*ECEB*/ GENx___x___x___ , /*ECEC*/ GENx___x___x___ , /*ECED*/ GENx___x___x___ , /*ECEE*/ GENx___x___x___ , /*ECEF*/ GENx___x___x___ , /*ECF0*/ GENx___x___x___ , /*ECF1*/ GENx___x___x___ , /*ECF2*/ GENx___x___x___ , /*ECF3*/ GENx___x___x___ , /*ECF4*/ GENx___x___x___ , /*ECF5*/ GENx___x___x___ , /*ECF6*/ GENx37Xx390x900 (compare_and_branch_register,RRS,"CRB"), /*208*/ /*ECF7*/ GENx37Xx390x900 (compare_logical_and_branch_register,RRS,"CLRB"), /*208*/ /*ECF8*/ GENx___x___x___ , /*ECF9*/ GENx___x___x___ , /*ECFA*/ GENx___x___x___ , /*ECFB*/ GENx___x___x___ , /*ECFC*/ GENx___x___x900 (compare_immediate_and_branch_long,RIS,"CGIB"), /*208*/ /*ECFD*/ GENx___x___x900 (compare_logical_immediate_and_branch_long,RIS,"CLGIB"), /*208*/ /*ECFE*/ GENx37Xx390x900 (compare_immediate_and_branch,RIS,"CIB"), /*208*/ /*ECFF*/ GENx37Xx390x900 (compare_logical_immediate_and_branch,RIS,"CLIB") }; /*208*/ // #endif /*defined(FEATURE_ESAME)*/ // #if defined(FEATURE_BASIC_FP_EXTENSIONS) DLL_EXPORT zz_func opcode_edxx[256][GEN_MAXARCH] = { /*ED00*/ GENx___x___x___ , /*ED01*/ GENx___x___x___ , /*ED02*/ GENx___x___x___ , /*ED03*/ GENx___x___x___ , /*ED04*/ GENx37Xx390x900 (load_lengthened_bfp_short_to_long,RXE,"LDEB"), /*ED05*/ GENx37Xx390x900 (load_lengthened_bfp_long_to_ext,RXE,"LXDB"), /*ED06*/ GENx37Xx390x900 (load_lengthened_bfp_short_to_ext,RXE,"LXEB"), /*ED07*/ GENx37Xx390x900 (multiply_bfp_long_to_ext,RXE,"MXDB"), /*ED08*/ GENx37Xx390x900 (compare_and_signal_bfp_short,RXE,"KEB"), /*ED09*/ GENx37Xx390x900 (compare_bfp_short,RXE,"CEB"), /*ED0A*/ GENx37Xx390x900 (add_bfp_short,RXE,"AEB"), /*ED0B*/ GENx37Xx390x900 (subtract_bfp_short,RXE,"SEB"), /*ED0C*/ GENx37Xx390x900 (multiply_bfp_short_to_long,RXE,"MDEB"), /*ED0D*/ GENx37Xx390x900 (divide_bfp_short,RXE,"DEB"), /*ED0E*/ GENx37Xx390x900 (multiply_add_bfp_short,RXF,"MAEB"), /*ED0F*/ GENx37Xx390x900 (multiply_subtract_bfp_short,RXF,"MSEB"), /*ED10*/ GENx37Xx390x900 (test_data_class_bfp_short,RXE,"TCEB"), /*ED11*/ GENx37Xx390x900 (test_data_class_bfp_long,RXE,"TCDB"), /*ED12*/ GENx37Xx390x900 (test_data_class_bfp_ext,RXE,"TCXB"), /*ED13*/ GENx___x___x___ , /*ED14*/ GENx37Xx390x900 (squareroot_bfp_short,RXE,"SQEB"), /*ED15*/ GENx37Xx390x900 (squareroot_bfp_long,RXE,"SQDB"), /*ED16*/ GENx___x___x___ , /*ED17*/ GENx37Xx390x900 (multiply_bfp_short,RXE,"MEEB"), /*ED18*/ GENx37Xx390x900 (compare_and_signal_bfp_long,RXE,"KDB"), /*ED19*/ GENx37Xx390x900 (compare_bfp_long,RXE,"CDB"), /*ED1A*/ GENx37Xx390x900 (add_bfp_long,RXE,"ADB"), /*ED1B*/ GENx37Xx390x900 (subtract_bfp_long,RXE,"SDB"), /*ED1C*/ GENx37Xx390x900 (multiply_bfp_long,RXE,"MDB"), /*ED1D*/ GENx37Xx390x900 (divide_bfp_long,RXE,"DDB"), /*ED1E*/ GENx37Xx390x900 (multiply_add_bfp_long,RXF,"MADB"), /*ED1F*/ GENx37Xx390x900 (multiply_subtract_bfp_long,RXF,"MSDB"), /*ED20*/ GENx___x___x___ , /*ED21*/ GENx___x___x___ , /*ED22*/ GENx___x___x___ , /*ED23*/ GENx___x___x___ , /*ED24*/ GENx37Xx390x900 (load_lengthened_float_short_to_long,RXE,"LDE"), /*ED25*/ GENx37Xx390x900 (load_lengthened_float_long_to_ext,RXE,"LXD"), /*ED26*/ GENx37Xx390x900 (load_lengthened_float_short_to_ext,RXE,"LXE"), /*ED27*/ GENx___x___x___ , /*ED28*/ GENx___x___x___ , /*ED29*/ GENx___x___x___ , /*ED2A*/ GENx___x___x___ , /*ED2B*/ GENx___x___x___ , /*ED2C*/ GENx___x___x___ , /*ED2D*/ GENx___x___x___ , /*ED2E*/ GENx37Xx390x900 (multiply_add_float_short,RXF,"MAE"), /*ED2F*/ GENx37Xx390x900 (multiply_subtract_float_short,RXF,"MSE"), /*ED30*/ GENx___x___x___ , /*ED31*/ GENx___x___x___ , /*ED32*/ GENx___x___x___ , /*ED33*/ GENx___x___x___ , /*ED34*/ GENx37Xx390x900 (squareroot_float_short,RXE,"SQE"), /*ED35*/ GENx37Xx390x900 (squareroot_float_long,RXE,"SQD"), /*ED36*/ GENx___x___x___ , /*ED37*/ GENx37Xx390x900 (multiply_float_short,RXE,"MEE"), /*ED38*/ GENx37Xx___x900 (multiply_add_unnormal_float_long_to_ext_low,RXF,"MAYL"), /*@Z9*/ /*ED39*/ GENx37Xx___x900 (multiply_unnormal_float_long_to_ext_low,RXF,"MYL"), /*@Z9*/ /*ED3A*/ GENx37Xx___x900 (multiply_add_unnormal_float_long_to_ext,RXF,"MAY"), /*@Z9*/ /*ED3B*/ GENx37Xx___x900 (multiply_unnormal_float_long_to_ext,RXF,"MY"), /*@Z9*/ /*ED3C*/ GENx37Xx___x900 (multiply_add_unnormal_float_long_to_ext_high,RXF,"MAYH"), /*@Z9*/ /*ED3D*/ GENx37Xx___x900 (multiply_unnormal_float_long_to_ext_high,RXF,"MYH"), /*@Z9*/ /*ED3E*/ GENx37Xx390x900 (multiply_add_float_long,RXF,"MAD"), /*ED3F*/ GENx37Xx390x900 (multiply_subtract_float_long,RXF,"MSD"), /*ED40*/ GENx___x390x900 (shift_coefficient_left_dfp_long,RXF,"SLDT"), /*ED41*/ GENx___x390x900 (shift_coefficient_right_dfp_long,RXF,"SRDT"), /*ED42*/ GENx___x___x___ , /*ED43*/ GENx___x___x___ , /*ED44*/ GENx___x___x___ , /*ED45*/ GENx___x___x___ , /*ED46*/ GENx___x___x___ , /*ED47*/ GENx___x___x___ , /*ED48*/ GENx___x390x900 (shift_coefficient_left_dfp_ext,RXF,"SLXT"), /*ED49*/ GENx___x390x900 (shift_coefficient_right_dfp_ext,RXF,"SRXT"), /*ED4A*/ GENx___x___x___ , /*ED4B*/ GENx___x___x___ , /*ED4C*/ GENx___x___x___ , /*ED4D*/ GENx___x___x___ , /*ED4E*/ GENx___x___x___ , /*ED4F*/ GENx___x___x___ , /*ED50*/ GENx___x390x900 (test_data_class_dfp_short,RXE,"TDCET"), /*ED51*/ GENx___x390x900 (test_data_group_dfp_short,RXE,"TDGET"), /*ED52*/ GENx___x___x___ , /*ED53*/ GENx___x___x___ , /*ED54*/ GENx___x390x900 (test_data_class_dfp_long,RXE,"TDCDT"), /*ED55*/ GENx___x390x900 (test_data_group_dfp_long,RXE,"TDGDT"), /*ED56*/ GENx___x___x___ , /*ED57*/ GENx___x___x___ , /*ED58*/ GENx___x390x900 (test_data_class_dfp_ext,RXE,"TDCXT"), /*ED59*/ GENx___x390x900 (test_data_group_dfp_ext,RXE,"TDGXT"), /*ED5A*/ GENx___x___x___ , /*ED5B*/ GENx___x___x___ , /*ED5C*/ GENx___x___x___ , /*ED5D*/ GENx___x___x___ , /*ED5E*/ GENx___x___x___ , /*ED5F*/ GENx___x___x___ , /*ED60*/ GENx___x___x___ , /*ED61*/ GENx___x___x___ , /*ED62*/ GENx___x___x___ , /*ED63*/ GENx___x___x___ , /*ED64*/ GENx___x___x900 (load_float_short_y,RXY,"LEY"), /*ED65*/ GENx___x___x900 (load_float_long_y,RXY,"LDY"), /*ED66*/ GENx___x___x900 (store_float_short_y,RXY,"STEY"), /*ED67*/ GENx___x___x900 (store_float_long_y,RXY,"STDY"), /*ED68*/ GENx___x___x___ , /*ED69*/ GENx___x___x___ , /*ED6A*/ GENx___x___x___ , /*ED6B*/ GENx___x___x___ , /*ED6C*/ GENx___x___x___ , /*ED6D*/ GENx___x___x___ , /*ED6E*/ GENx___x___x___ , /*ED6F*/ GENx___x___x___ , /*ED70*/ GENx___x___x___ , /*ED71*/ GENx___x___x___ , /*ED72*/ GENx___x___x___ , /*ED73*/ GENx___x___x___ , /*ED74*/ GENx___x___x___ , /*ED75*/ GENx___x___x___ , /*ED76*/ GENx___x___x___ , /*ED77*/ GENx___x___x___ , /*ED78*/ GENx___x___x___ , /*ED79*/ GENx___x___x___ , /*ED7A*/ GENx___x___x___ , /*ED7B*/ GENx___x___x___ , /*ED7C*/ GENx___x___x___ , /*ED7D*/ GENx___x___x___ , /*ED7E*/ GENx___x___x___ , /*ED7F*/ GENx___x___x___ , /*ED80*/ GENx___x___x___ , /*ED81*/ GENx___x___x___ , /*ED82*/ GENx___x___x___ , /*ED83*/ GENx___x___x___ , /*ED84*/ GENx___x___x___ , /*ED85*/ GENx___x___x___ , /*ED86*/ GENx___x___x___ , /*ED87*/ GENx___x___x___ , /*ED88*/ GENx___x___x___ , /*ED89*/ GENx___x___x___ , /*ED8A*/ GENx___x___x___ , /*ED8B*/ GENx___x___x___ , /*ED8C*/ GENx___x___x___ , /*ED8D*/ GENx___x___x___ , /*ED8E*/ GENx___x___x___ , /*ED8F*/ GENx___x___x___ , /*ED90*/ GENx___x___x___ , /*ED91*/ GENx___x___x___ , /*ED92*/ GENx___x___x___ , /*ED93*/ GENx___x___x___ , /*ED94*/ GENx___x___x___ , /*ED95*/ GENx___x___x___ , /*ED96*/ GENx___x___x___ , /*ED97*/ GENx___x___x___ , /*ED98*/ GENx___x___x___ , /*ED99*/ GENx___x___x___ , /*ED9A*/ GENx___x___x___ , /*ED9B*/ GENx___x___x___ , /*ED9C*/ GENx___x___x___ , /*ED9D*/ GENx___x___x___ , /*ED9E*/ GENx___x___x___ , /*ED9F*/ GENx___x___x___ , /*EDA0*/ GENx___x___x___ , /*EDA1*/ GENx___x___x___ , /*EDA2*/ GENx___x___x___ , /*EDA3*/ GENx___x___x___ , /*EDA4*/ GENx___x___x___ , /*EDA5*/ GENx___x___x___ , /*EDA6*/ GENx___x___x___ , /*EDA7*/ GENx___x___x___ , /*EDA8*/ GENx___x___x900 (convert_dfp_long_to_zoned,RSL_RM,"CZDT"), /*912*/ /*EDA9*/ GENx___x___x900 (convert_dfp_ext_to_zoned,RSL_RM,"CZXT"), /*912*/ /*EDAA*/ GENx___x___x900 (convert_zoned_to_dfp_long,RSL_RM,"CDZT"), /*912*/ /*EDAB*/ GENx___x___x900 (convert_zoned_to_dfp_ext,RSL_RM,"CXZT"), /*912*/ /*EDAC*/ GENx___x___x___ , /*EDAD*/ GENx___x___x___ , /*EDAE*/ GENx___x___x___ , /*EDAF*/ GENx___x___x___ , /*EDB0*/ GENx___x___x___ , /*EDB1*/ GENx___x___x___ , /*EDB2*/ GENx___x___x___ , /*EDB3*/ GENx___x___x___ , /*EDB4*/ GENx___x___x___ , /*EDB5*/ GENx___x___x___ , /*EDB6*/ GENx___x___x___ , /*EDB7*/ GENx___x___x___ , /*EDB8*/ GENx___x___x___ , /*EDB3*/ GENx___x___x___ , /*EDBA*/ GENx___x___x___ , /*EDBB*/ GENx___x___x___ , /*EDBC*/ GENx___x___x___ , /*EDBD*/ GENx___x___x___ , /*EDBE*/ GENx___x___x___ , /*EDBF*/ GENx___x___x___ , /*EDC0*/ GENx___x___x___ , /*EDC1*/ GENx___x___x___ , /*EDC2*/ GENx___x___x___ , /*EDC3*/ GENx___x___x___ , /*EDC4*/ GENx___x___x___ , /*EDC5*/ GENx___x___x___ , /*EDC6*/ GENx___x___x___ , /*EDC7*/ GENx___x___x___ , /*EDC8*/ GENx___x___x___ , /*EDC9*/ GENx___x___x___ , /*EDCA*/ GENx___x___x___ , /*EDCB*/ GENx___x___x___ , /*EDCC*/ GENx___x___x___ , /*EDCD*/ GENx___x___x___ , /*EDCE*/ GENx___x___x___ , /*EDCF*/ GENx___x___x___ , /*EDD0*/ GENx___x___x___ , /*EDD1*/ GENx___x___x___ , /*EDD2*/ GENx___x___x___ , /*EDD3*/ GENx___x___x___ , /*EDD4*/ GENx___x___x___ , /*EDD5*/ GENx___x___x___ , /*EDD6*/ GENx___x___x___ , /*EDD7*/ GENx___x___x___ , /*EDD8*/ GENx___x___x___ , /*EDD9*/ GENx___x___x___ , /*EDDA*/ GENx___x___x___ , /*EDDB*/ GENx___x___x___ , /*EDDC*/ GENx___x___x___ , /*EDDD*/ GENx___x___x___ , /*EDDE*/ GENx___x___x___ , /*EDDF*/ GENx___x___x___ , /*EDE0*/ GENx___x___x___ , /*EDE1*/ GENx___x___x___ , /*EDE2*/ GENx___x___x___ , /*EDE3*/ GENx___x___x___ , /*EDE4*/ GENx___x___x___ , /*EDE5*/ GENx___x___x___ , /*EDE6*/ GENx___x___x___ , /*EDE7*/ GENx___x___x___ , /*EDE8*/ GENx___x___x___ , /*EDE9*/ GENx___x___x___ , /*EDEA*/ GENx___x___x___ , /*EDEB*/ GENx___x___x___ , /*EDEC*/ GENx___x___x___ , /*EDED*/ GENx___x___x___ , /*EDEE*/ GENx___x___x___ , /*EDEF*/ GENx___x___x___ , /*EDF0*/ GENx___x___x___ , /*EDF1*/ GENx___x___x___ , /*EDF2*/ GENx___x___x___ , /*EDF3*/ GENx___x___x___ , /*EDF4*/ GENx___x___x___ , /*EDF5*/ GENx___x___x___ , /*EDF6*/ GENx___x___x___ , /*EDF7*/ GENx___x___x___ , /*EDF8*/ GENx___x___x___ , /*EDF9*/ GENx___x___x___ , /*EDFA*/ GENx___x___x___ , /*EDFB*/ GENx___x___x___ , /*EDFC*/ GENx___x___x___ , /*EDFD*/ GENx___x___x___ , /*EDFE*/ GENx___x___x___ , /*EDFF*/ GENx___x___x___ }; // #endif /*defined(FEATURE_BASIC_FP_EXTENSIONS)*/ // #if defined (FEATURE_VECTOR_FACILITY) zz_func v_opcode_a4xx[256][GEN_MAXARCH] = { /*A400*/ GENx___x___x___ , /*A401*/ GENx___x___x___ , /*A402*/ GENx___x___x___ , /*A403*/ GENx___x___x___ , /*A404*/ GENx___x___x___ , /*A405*/ GENx___x___x___ , /*A406*/ GENx___x___x___ , /*A407*/ GENx___x___x___ , /*A408*/ GENx___x___x___ , /*A409*/ GENx___x___x___ , /*A40A*/ GENx___x___x___ , /*A40B*/ GENx___x___x___ , /*A40C*/ GENx___x___x___ , /*A40D*/ GENx___x___x___ , /*A40E*/ GENx___x___x___ , /*A40F*/ GENx___x___x___ , /*A410*/ GENx___x___x___ , /*A411*/ GENx___x___x___ , /*A412*/ GENx___x___x___ , /*A413*/ GENx___x___x___ , /*A414*/ GENx___x___x___ , /*A415*/ GENx___x___x___ , /*A416*/ GENx___x___x___ , /*A417*/ GENx___x___x___ , /*A418*/ GENx___x___x___ , /*A419*/ GENx___x___x___ , /*A41A*/ GENx___x___x___ , /*A41B*/ GENx___x___x___ , /*A41C*/ GENx___x___x___ , /*A41D*/ GENx___x___x___ , /*A41E*/ GENx___x___x___ , /*A41F*/ GENx___x___x___ , /*A420*/ GENx___x___x___ , /*A421*/ GENx___x___x___ , /*A422*/ GENx___x___x___ , /*A423*/ GENx___x___x___ , /*A424*/ GENx___x___x___ , /*A425*/ GENx___x___x___ , /*A426*/ GENx___x___x___ , /*A427*/ GENx___x___x___ , /*A428*/ GENx___x___x___ , /*A429*/ GENx___x___x___ , /*A42A*/ GENx___x___x___ , /*A42B*/ GENx___x___x___ , /*A42C*/ GENx___x___x___ , /*A42D*/ GENx___x___x___ , /*A42E*/ GENx___x___x___ , /*A42F*/ GENx___x___x___ , /*A430*/ GENx___x___x___ , /*A431*/ GENx___x___x___ , /*A432*/ GENx___x___x___ , /*A433*/ GENx___x___x___ , /*A434*/ GENx___x___x___ , /*A435*/ GENx___x___x___ , /*A436*/ GENx___x___x___ , /*A437*/ GENx___x___x___ , /*A438*/ GENx___x___x___ , /*A439*/ GENx___x___x___ , /*A43A*/ GENx___x___x___ , /*A43B*/ GENx___x___x___ , /*A43C*/ GENx___x___x___ , /*A43D*/ GENx___x___x___ , /*A43E*/ GENx___x___x___ , /*A43F*/ GENx___x___x___ , /*A440*/ GENx___x___x___ , /*A441*/ GENx___x___x___ , /*A442*/ GENx___x___x___ , /*A443*/ GENx___x___x___ , /*A444*/ GENx___x___x___ , /*A445*/ GENx___x___x___ , /*A446*/ GENx___x___x___ , /*A447*/ GENx___x___x___ , /*A448*/ GENx___x___x___ , /*A449*/ GENx___x___x___ , /*A44A*/ GENx___x___x___ , /*A44B*/ GENx___x___x___ , /*A44C*/ GENx___x___x___ , /*A44D*/ GENx___x___x___ , /*A44E*/ GENx___x___x___ , /*A44F*/ GENx___x___x___ , /*A450*/ GENx___x___x___ , /*A451*/ GENx___x___x___ , /*A452*/ GENx___x___x___ , /*A453*/ GENx___x___x___ , /*A454*/ GENx___x___x___ , /*A455*/ GENx___x___x___ , /*A456*/ GENx___x___x___ , /*A457*/ GENx___x___x___ , /*A458*/ GENx___x___x___ , /*A459*/ GENx___x___x___ , /*A45A*/ GENx___x___x___ , /*A45B*/ GENx___x___x___ , /*A45C*/ GENx___x___x___ , /*A45D*/ GENx___x___x___ , /*A45E*/ GENx___x___x___ , /*A45F*/ GENx___x___x___ , /*A460*/ GENx___x___x___ , /*A461*/ GENx___x___x___ , /*A462*/ GENx___x___x___ , /*A463*/ GENx___x___x___ , /*A464*/ GENx___x___x___ , /*A465*/ GENx___x___x___ , /*A466*/ GENx___x___x___ , /*A467*/ GENx___x___x___ , /*A468*/ GENx___x___x___ , /*A469*/ GENx___x___x___ , /*A46A*/ GENx___x___x___ , /*A46B*/ GENx___x___x___ , /*A46C*/ GENx___x___x___ , /*A46D*/ GENx___x___x___ , /*A46E*/ GENx___x___x___ , /*A46F*/ GENx___x___x___ , /*A470*/ GENx___x___x___ , /*A471*/ GENx___x___x___ , /*A472*/ GENx___x___x___ , /*A473*/ GENx___x___x___ , /*A474*/ GENx___x___x___ , /*A475*/ GENx___x___x___ , /*A476*/ GENx___x___x___ , /*A477*/ GENx___x___x___ , /*A478*/ GENx___x___x___ , /*A479*/ GENx___x___x___ , /*A47A*/ GENx___x___x___ , /*A47B*/ GENx___x___x___ , /*A47C*/ GENx___x___x___ , /*A47D*/ GENx___x___x___ , /*A47E*/ GENx___x___x___ , /*A47F*/ GENx___x___x___ , /*A480*/ GENx___x___x___ , /*A481*/ GENx___x___x___ , /*A482*/ GENx___x___x___ , /*A483*/ GENx___x___x___ , /*A484*/ GENx___x___x___ , /*A485*/ GENx___x___x___ , /*A486*/ GENx___x___x___ , /*A487*/ GENx___x___x___ , /*A488*/ GENx___x___x___ , /*A489*/ GENx___x___x___ , /*A48A*/ GENx___x___x___ , /*A48B*/ GENx___x___x___ , /*A48C*/ GENx___x___x___ , /*A48D*/ GENx___x___x___ , /*A48E*/ GENx___x___x___ , /*A48F*/ GENx___x___x___ , /*A490*/ GENx___x___x___ , /*A491*/ GENx___x___x___ , /*A492*/ GENx___x___x___ , /*A493*/ GENx___x___x___ , /*A494*/ GENx___x___x___ , /*A495*/ GENx___x___x___ , /*A496*/ GENx___x___x___ , /*A497*/ GENx___x___x___ , /*A498*/ GENx___x___x___ , /*A499*/ GENx___x___x___ , /*A49A*/ GENx___x___x___ , /*A49B*/ GENx___x___x___ , /*A49C*/ GENx___x___x___ , /*A49D*/ GENx___x___x___ , /*A49E*/ GENx___x___x___ , /*A49F*/ GENx___x___x___ , /*A4A0*/ GENx___x___x___ , /*A4A1*/ GENx___x___x___ , /*A4A2*/ GENx___x___x___ , /*A4A3*/ GENx___x___x___ , /*A4A4*/ GENx___x___x___ , /*A4A5*/ GENx___x___x___ , /*A4A6*/ GENx___x___x___ , /*A4A7*/ GENx___x___x___ , /*A4A8*/ GENx___x___x___ , /*A4A9*/ GENx___x___x___ , /*A4AA*/ GENx___x___x___ , /*A4AB*/ GENx___x___x___ , /*A4AC*/ GENx___x___x___ , /*A4AD*/ GENx___x___x___ , /*A4AE*/ GENx___x___x___ , /*A4AF*/ GENx___x___x___ , /*A4B0*/ GENx___x___x___ , /*A4B1*/ GENx___x___x___ , /*A4B2*/ GENx___x___x___ , /*A4B3*/ GENx___x___x___ , /*A4B4*/ GENx___x___x___ , /*A4B5*/ GENx___x___x___ , /*A4B6*/ GENx___x___x___ , /*A4B7*/ GENx___x___x___ , /*A4B8*/ GENx___x___x___ , /*A4B9*/ GENx___x___x___ , /*A4BA*/ GENx___x___x___ , /*A4BB*/ GENx___x___x___ , /*A4BC*/ GENx___x___x___ , /*A4BD*/ GENx___x___x___ , /*A4BE*/ GENx___x___x___ , /*A4BF*/ GENx___x___x___ , /*A4C0*/ GENx___x___x___ , /*A4C1*/ GENx___x___x___ , /*A4C2*/ GENx___x___x___ , /*A4C3*/ GENx___x___x___ , /*A4C4*/ GENx___x___x___ , /*A4C5*/ GENx___x___x___ , /*A4C6*/ GENx___x___x___ , /*A4C7*/ GENx___x___x___ , /*A4C8*/ GENx___x___x___ , /*A4C9*/ GENx___x___x___ , /*A4CA*/ GENx___x___x___ , /*A4CB*/ GENx___x___x___ , /*A4CC*/ GENx___x___x___ , /*A4CD*/ GENx___x___x___ , /*A4CE*/ GENx___x___x___ , /*A4CF*/ GENx___x___x___ , /*A4D0*/ GENx___x___x___ , /*A4D1*/ GENx___x___x___ , /*A4D2*/ GENx___x___x___ , /*A4D3*/ GENx___x___x___ , /*A4D4*/ GENx___x___x___ , /*A4D5*/ GENx___x___x___ , /*A4D6*/ GENx___x___x___ , /*A4D7*/ GENx___x___x___ , /*A4D8*/ GENx___x___x___ , /*A4D9*/ GENx___x___x___ , /*A4DA*/ GENx___x___x___ , /*A4DB*/ GENx___x___x___ , /*A4DC*/ GENx___x___x___ , /*A4DD*/ GENx___x___x___ , /*A4DE*/ GENx___x___x___ , /*A4DF*/ GENx___x___x___ , /*A4E0*/ GENx___x___x___ , /*A4E1*/ GENx___x___x___ , /*A4E2*/ GENx___x___x___ , /*A4E3*/ GENx___x___x___ , /*A4E4*/ GENx___x___x___ , /*A4E5*/ GENx___x___x___ , /*A4E6*/ GENx___x___x___ , /*A4E7*/ GENx___x___x___ , /*A4E8*/ GENx___x___x___ , /*A4E9*/ GENx___x___x___ , /*A4EA*/ GENx___x___x___ , /*A4EB*/ GENx___x___x___ , /*A4EC*/ GENx___x___x___ , /*A4ED*/ GENx___x___x___ , /*A4EE*/ GENx___x___x___ , /*A4EF*/ GENx___x___x___ , /*A4F0*/ GENx___x___x___ , /*A4F1*/ GENx___x___x___ , /*A4F2*/ GENx___x___x___ , /*A4F3*/ GENx___x___x___ , /*A4F4*/ GENx___x___x___ , /*A4F5*/ GENx___x___x___ , /*A4F6*/ GENx___x___x___ , /*A4F7*/ GENx___x___x___ , /*A4F8*/ GENx___x___x___ , /*A4F9*/ GENx___x___x___ , /*A4FA*/ GENx___x___x___ , /*A4FB*/ GENx___x___x___ , /*A4FC*/ GENx___x___x___ , /*A4FD*/ GENx___x___x___ , /*A4FE*/ GENx___x___x___ , /*A4FF*/ GENx___x___x___ }; // #endif /*defined (FEATURE_VECTOR_FACILITY)*/ // #if defined (FEATURE_VECTOR_FACILITY) zz_func v_opcode_a5xx[256][GEN_MAXARCH] = { /*A500*/ GENx___x___x___ , /*A501*/ GENx___x___x___ , /*A502*/ GENx___x___x___ , /*A503*/ GENx___x___x___ , /*A504*/ GENx___x___x___ , /*A505*/ GENx___x___x___ , /*A506*/ GENx___x___x___ , /*A507*/ GENx___x___x___ , /*A508*/ GENx___x___x___ , /*A509*/ GENx___x___x___ , /*A50A*/ GENx___x___x___ , /*A50B*/ GENx___x___x___ , /*A50C*/ GENx___x___x___ , /*A50D*/ GENx___x___x___ , /*A50E*/ GENx___x___x___ , /*A50F*/ GENx___x___x___ , /*A510*/ GENx___x___x___ , /*A511*/ GENx___x___x___ , /*A512*/ GENx___x___x___ , /*A513*/ GENx___x___x___ , /*A514*/ GENx___x___x___ , /*A515*/ GENx___x___x___ , /*A516*/ GENx___x___x___ , /*A517*/ GENx___x___x___ , /*A518*/ GENx___x___x___ , /*A519*/ GENx___x___x___ , /*A51A*/ GENx___x___x___ , /*A51B*/ GENx___x___x___ , /*A51C*/ GENx___x___x___ , /*A51D*/ GENx___x___x___ , /*A51E*/ GENx___x___x___ , /*A51F*/ GENx___x___x___ , /*A520*/ GENx___x___x___ , /*A521*/ GENx___x___x___ , /*A522*/ GENx___x___x___ , /*A523*/ GENx___x___x___ , /*A524*/ GENx___x___x___ , /*A525*/ GENx___x___x___ , /*A526*/ GENx___x___x___ , /*A527*/ GENx___x___x___ , /*A528*/ GENx___x___x___ , /*A529*/ GENx___x___x___ , /*A52A*/ GENx___x___x___ , /*A52B*/ GENx___x___x___ , /*A52C*/ GENx___x___x___ , /*A52D*/ GENx___x___x___ , /*A52E*/ GENx___x___x___ , /*A52F*/ GENx___x___x___ , /*A530*/ GENx___x___x___ , /*A531*/ GENx___x___x___ , /*A532*/ GENx___x___x___ , /*A533*/ GENx___x___x___ , /*A534*/ GENx___x___x___ , /*A535*/ GENx___x___x___ , /*A536*/ GENx___x___x___ , /*A537*/ GENx___x___x___ , /*A538*/ GENx___x___x___ , /*A539*/ GENx___x___x___ , /*A53A*/ GENx___x___x___ , /*A53B*/ GENx___x___x___ , /*A53C*/ GENx___x___x___ , /*A53D*/ GENx___x___x___ , /*A53E*/ GENx___x___x___ , /*A53F*/ GENx___x___x___ , /*A540*/ GENx___x___x___ , /*A541*/ GENx___x___x___ , /*A542*/ GENx___x___x___ , /*A543*/ GENx___x___x___ , /*A544*/ GENx___x___x___ , /*A545*/ GENx___x___x___ , /*A546*/ GENx___x___x___ , /*A547*/ GENx___x___x___ , /*A548*/ GENx___x___x___ , /*A549*/ GENx___x___x___ , /*A54A*/ GENx___x___x___ , /*A54B*/ GENx___x___x___ , /*A54C*/ GENx___x___x___ , /*A54D*/ GENx___x___x___ , /*A54E*/ GENx___x___x___ , /*A54F*/ GENx___x___x___ , /*A550*/ GENx___x___x___ , /*A551*/ GENx___x___x___ , /*A552*/ GENx___x___x___ , /*A553*/ GENx___x___x___ , /*A554*/ GENx___x___x___ , /*A555*/ GENx___x___x___ , /*A556*/ GENx___x___x___ , /*A557*/ GENx___x___x___ , /*A558*/ GENx___x___x___ , /*A559*/ GENx___x___x___ , /*A55A*/ GENx___x___x___ , /*A55B*/ GENx___x___x___ , /*A55C*/ GENx___x___x___ , /*A55D*/ GENx___x___x___ , /*A55E*/ GENx___x___x___ , /*A55F*/ GENx___x___x___ , /*A560*/ GENx___x___x___ , /*A561*/ GENx___x___x___ , /*A562*/ GENx___x___x___ , /*A563*/ GENx___x___x___ , /*A564*/ GENx___x___x___ , /*A565*/ GENx___x___x___ , /*A566*/ GENx___x___x___ , /*A567*/ GENx___x___x___ , /*A568*/ GENx___x___x___ , /*A569*/ GENx___x___x___ , /*A56A*/ GENx___x___x___ , /*A56B*/ GENx___x___x___ , /*A56C*/ GENx___x___x___ , /*A56D*/ GENx___x___x___ , /*A56E*/ GENx___x___x___ , /*A56F*/ GENx___x___x___ , /*A570*/ GENx___x___x___ , /*A571*/ GENx___x___x___ , /*A572*/ GENx___x___x___ , /*A573*/ GENx___x___x___ , /*A574*/ GENx___x___x___ , /*A575*/ GENx___x___x___ , /*A576*/ GENx___x___x___ , /*A577*/ GENx___x___x___ , /*A578*/ GENx___x___x___ , /*A579*/ GENx___x___x___ , /*A57A*/ GENx___x___x___ , /*A57B*/ GENx___x___x___ , /*A57C*/ GENx___x___x___ , /*A57D*/ GENx___x___x___ , /*A57E*/ GENx___x___x___ , /*A57F*/ GENx___x___x___ , /*A580*/ GENx___x___x___ , /*A581*/ GENx___x___x___ , /*A582*/ GENx___x___x___ , /*A583*/ GENx___x___x___ , /*A584*/ GENx___x___x___ , /*A585*/ GENx___x___x___ , /*A586*/ GENx___x___x___ , /*A587*/ GENx___x___x___ , /*A588*/ GENx___x___x___ , /*A589*/ GENx___x___x___ , /*A58A*/ GENx___x___x___ , /*A58B*/ GENx___x___x___ , /*A58C*/ GENx___x___x___ , /*A58D*/ GENx___x___x___ , /*A58E*/ GENx___x___x___ , /*A58F*/ GENx___x___x___ , /*A590*/ GENx___x___x___ , /*A591*/ GENx___x___x___ , /*A592*/ GENx___x___x___ , /*A593*/ GENx___x___x___ , /*A594*/ GENx___x___x___ , /*A595*/ GENx___x___x___ , /*A596*/ GENx___x___x___ , /*A597*/ GENx___x___x___ , /*A598*/ GENx___x___x___ , /*A599*/ GENx___x___x___ , /*A59A*/ GENx___x___x___ , /*A59B*/ GENx___x___x___ , /*A59C*/ GENx___x___x___ , /*A59D*/ GENx___x___x___ , /*A59E*/ GENx___x___x___ , /*A59F*/ GENx___x___x___ , /*A5A0*/ GENx___x___x___ , /*A5A1*/ GENx___x___x___ , /*A5A2*/ GENx___x___x___ , /*A5A3*/ GENx___x___x___ , /*A5A4*/ GENx___x___x___ , /*A5A5*/ GENx___x___x___ , /*A5A6*/ GENx___x___x___ , /*A5A7*/ GENx___x___x___ , /*A5A8*/ GENx___x___x___ , /*A5A9*/ GENx___x___x___ , /*A5AA*/ GENx___x___x___ , /*A5AB*/ GENx___x___x___ , /*A5AC*/ GENx___x___x___ , /*A5AD*/ GENx___x___x___ , /*A5AE*/ GENx___x___x___ , /*A5AF*/ GENx___x___x___ , /*A5B0*/ GENx___x___x___ , /*A5B1*/ GENx___x___x___ , /*A5B2*/ GENx___x___x___ , /*A5B3*/ GENx___x___x___ , /*A5B4*/ GENx___x___x___ , /*A5B5*/ GENx___x___x___ , /*A5B6*/ GENx___x___x___ , /*A5B7*/ GENx___x___x___ , /*A5B8*/ GENx___x___x___ , /*A5B9*/ GENx___x___x___ , /*A5BA*/ GENx___x___x___ , /*A5BB*/ GENx___x___x___ , /*A5BC*/ GENx___x___x___ , /*A5BD*/ GENx___x___x___ , /*A5BE*/ GENx___x___x___ , /*A5BF*/ GENx___x___x___ , /*A5C0*/ GENx___x___x___ , /*A5C1*/ GENx___x___x___ , /*A5C2*/ GENx___x___x___ , /*A5C3*/ GENx___x___x___ , /*A5C4*/ GENx___x___x___ , /*A5C5*/ GENx___x___x___ , /*A5C6*/ GENx___x___x___ , /*A5C7*/ GENx___x___x___ , /*A5C8*/ GENx___x___x___ , /*A5C9*/ GENx___x___x___ , /*A5CA*/ GENx___x___x___ , /*A5CB*/ GENx___x___x___ , /*A5CC*/ GENx___x___x___ , /*A5CD*/ GENx___x___x___ , /*A5CE*/ GENx___x___x___ , /*A5CF*/ GENx___x___x___ , /*A5D0*/ GENx___x___x___ , /*A5D1*/ GENx___x___x___ , /*A5D2*/ GENx___x___x___ , /*A5D3*/ GENx___x___x___ , /*A5D4*/ GENx___x___x___ , /*A5D5*/ GENx___x___x___ , /*A5D6*/ GENx___x___x___ , /*A5D7*/ GENx___x___x___ , /*A5D8*/ GENx___x___x___ , /*A5D9*/ GENx___x___x___ , /*A5DA*/ GENx___x___x___ , /*A5DB*/ GENx___x___x___ , /*A5DC*/ GENx___x___x___ , /*A5DD*/ GENx___x___x___ , /*A5DE*/ GENx___x___x___ , /*A5DF*/ GENx___x___x___ , /*A5E0*/ GENx___x___x___ , /*A5E1*/ GENx___x___x___ , /*A5E2*/ GENx___x___x___ , /*A5E3*/ GENx___x___x___ , /*A5E4*/ GENx___x___x___ , /*A5E5*/ GENx___x___x___ , /*A5E6*/ GENx___x___x___ , /*A5E7*/ GENx___x___x___ , /*A5E8*/ GENx___x___x___ , /*A5E9*/ GENx___x___x___ , /*A5EA*/ GENx___x___x___ , /*A5EB*/ GENx___x___x___ , /*A5EC*/ GENx___x___x___ , /*A5ED*/ GENx___x___x___ , /*A5EE*/ GENx___x___x___ , /*A5EF*/ GENx___x___x___ , /*A5F0*/ GENx___x___x___ , /*A5F1*/ GENx___x___x___ , /*A5F2*/ GENx___x___x___ , /*A5F3*/ GENx___x___x___ , /*A5F4*/ GENx___x___x___ , /*A5F5*/ GENx___x___x___ , /*A5F6*/ GENx___x___x___ , /*A5F7*/ GENx___x___x___ , /*A5F8*/ GENx___x___x___ , /*A5F9*/ GENx___x___x___ , /*A5FA*/ GENx___x___x___ , /*A5FB*/ GENx___x___x___ , /*A5FC*/ GENx___x___x___ , /*A5FD*/ GENx___x___x___ , /*A5FE*/ GENx___x___x___ , /*A5FF*/ GENx___x___x___ }; // #endif /*defined (FEATURE_VECTOR_FACILITY)*/ // #if defined (FEATURE_VECTOR_FACILITY) zz_func v_opcode_a6xx[256][GEN_MAXARCH] = { /*A600*/ GENx___x___x___ , /*A601*/ GENx___x___x___ , /*A602*/ GENx___x___x___ , /*A603*/ GENx___x___x___ , /*A604*/ GENx___x___x___ , /*A605*/ GENx___x___x___ , /*A606*/ GENx___x___x___ , /*A607*/ GENx___x___x___ , /*A608*/ GENx___x___x___ , /*A609*/ GENx___x___x___ , /*A60A*/ GENx___x___x___ , /*A60B*/ GENx___x___x___ , /*A60C*/ GENx___x___x___ , /*A60D*/ GENx___x___x___ , /*A60E*/ GENx___x___x___ , /*A60F*/ GENx___x___x___ , /*A610*/ GENx___x___x___ , /*A611*/ GENx___x___x___ , /*A612*/ GENx___x___x___ , /*A613*/ GENx___x___x___ , /*A614*/ GENx___x___x___ , /*A615*/ GENx___x___x___ , /*A616*/ GENx___x___x___ , /*A617*/ GENx___x___x___ , /*A618*/ GENx___x___x___ , /*A619*/ GENx___x___x___ , /*A61A*/ GENx___x___x___ , /*A61B*/ GENx___x___x___ , /*A61C*/ GENx___x___x___ , /*A61D*/ GENx___x___x___ , /*A61E*/ GENx___x___x___ , /*A61F*/ GENx___x___x___ , /*A620*/ GENx___x___x___ , /*A621*/ GENx___x___x___ , /*A622*/ GENx___x___x___ , /*A623*/ GENx___x___x___ , /*A624*/ GENx___x___x___ , /*A625*/ GENx___x___x___ , /*A626*/ GENx___x___x___ , /*A627*/ GENx___x___x___ , /*A628*/ GENx___x___x___ , /*A629*/ GENx___x___x___ , /*A62A*/ GENx___x___x___ , /*A62B*/ GENx___x___x___ , /*A62C*/ GENx___x___x___ , /*A62D*/ GENx___x___x___ , /*A62E*/ GENx___x___x___ , /*A62F*/ GENx___x___x___ , /*A630*/ GENx___x___x___ , /*A631*/ GENx___x___x___ , /*A632*/ GENx___x___x___ , /*A633*/ GENx___x___x___ , /*A634*/ GENx___x___x___ , /*A635*/ GENx___x___x___ , /*A636*/ GENx___x___x___ , /*A637*/ GENx___x___x___ , /*A638*/ GENx___x___x___ , /*A639*/ GENx___x___x___ , /*A63A*/ GENx___x___x___ , /*A63B*/ GENx___x___x___ , /*A63C*/ GENx___x___x___ , /*A63D*/ GENx___x___x___ , /*A63E*/ GENx___x___x___ , /*A63F*/ GENx___x___x___ , /*A640*/ GENx370x390x___ (v_test_vmr,RRE,"VTVM"), /*A641*/ GENx370x390x___ (v_complement_vmr,RRE,"VCVM"), /*A642*/ GENx370x390x___ (v_count_left_zeros_in_vmr,RRE,"VCZVM"), /*A643*/ GENx370x390x___ (v_count_ones_in_vmr,RRE,"VCOVM"), /*A644*/ GENx370x390x___ (v_extract_vct,RRE,"VXVC"), /*A645*/ GENx___x___x___ , /*A646*/ GENx370x390x___ (v_extract_vector_modes,RRE,"VXVMM"), /*A647*/ GENx___x___x___ , /*A648*/ GENx370x390x___ (v_restore_vr,RRE,"VRRS"), /*A649*/ GENx370x390x___ (v_save_changed_vr,RRE,"VRSVC"), /*A64A*/ GENx370x390x___ (v_save_vr,RRE,"VRSV"), /*A64B*/ GENx___x___x___ , /*A64C*/ GENx___x___x___ , /*A64D*/ GENx___x___x___ , /*A64E*/ GENx___x___x___ , /*A64F*/ GENx___x___x___ , /*A650*/ GENx___x___x___ , /*A651*/ GENx___x___x___ , /*A652*/ GENx___x___x___ , /*A653*/ GENx___x___x___ , /*A654*/ GENx___x___x___ , /*A655*/ GENx___x___x___ , /*A656*/ GENx___x___x___ , /*A657*/ GENx___x___x___ , /*A658*/ GENx___x___x___ , /*A659*/ GENx___x___x___ , /*A65A*/ GENx___x___x___ , /*A65B*/ GENx___x___x___ , /*A65C*/ GENx___x___x___ , /*A65D*/ GENx___x___x___ , /*A65E*/ GENx___x___x___ , /*A65F*/ GENx___x___x___ , /*A660*/ GENx___x___x___ , /*A661*/ GENx___x___x___ , /*A662*/ GENx___x___x___ , /*A663*/ GENx___x___x___ , /*A664*/ GENx___x___x___ , /*A665*/ GENx___x___x___ , /*A666*/ GENx___x___x___ , /*A667*/ GENx___x___x___ , /*A668*/ GENx___x___x___ , /*A669*/ GENx___x___x___ , /*A66A*/ GENx___x___x___ , /*A66B*/ GENx___x___x___ , /*A66C*/ GENx___x___x___ , /*A66D*/ GENx___x___x___ , /*A66E*/ GENx___x___x___ , /*A66F*/ GENx___x___x___ , /*A670*/ GENx___x___x___ , /*A671*/ GENx___x___x___ , /*A672*/ GENx___x___x___ , /*A673*/ GENx___x___x___ , /*A674*/ GENx___x___x___ , /*A675*/ GENx___x___x___ , /*A676*/ GENx___x___x___ , /*A677*/ GENx___x___x___ , /*A678*/ GENx___x___x___ , /*A679*/ GENx___x___x___ , /*A67A*/ GENx___x___x___ , /*A67B*/ GENx___x___x___ , /*A67C*/ GENx___x___x___ , /*A67D*/ GENx___x___x___ , /*A67E*/ GENx___x___x___ , /*A67F*/ GENx___x___x___ , /*A680*/ GENx370x390x___ (v_load_vmr,VS,"VLVM"), /*A681*/ GENx370x390x___ (v_load_vmr_complement,VS,"VLCVM"), /*A682*/ GENx370x390x___ (v_store_vmr,VS,"VSTVM"), /*A683*/ GENx___x___x___ , /*A684*/ GENx370x390x___ (v_and_to_vmr,VS,"VNVM"), /*A685*/ GENx370x390x___ (v_or_to_vmr,VS,"VOVM"), /*A686*/ GENx370x390x___ (v_exclusive_or_to_vmr,VS,"VXVM"), /*A687*/ GENx___x___x___ , /*A688*/ GENx___x___x___ , /*A689*/ GENx___x___x___ , /*A68A*/ GENx___x___x___ , /*A68B*/ GENx___x___x___ , /*A68C*/ GENx___x___x___ , /*A68D*/ GENx___x___x___ , /*A68E*/ GENx___x___x___ , /*A68F*/ GENx___x___x___ , /*A690*/ GENx___x___x___ , /*A691*/ GENx___x___x___ , /*A692*/ GENx___x___x___ , /*A693*/ GENx___x___x___ , /*A694*/ GENx___x___x___ , /*A695*/ GENx___x___x___ , /*A696*/ GENx___x___x___ , /*A697*/ GENx___x___x___ , /*A698*/ GENx___x___x___ , /*A699*/ GENx___x___x___ , /*A69A*/ GENx___x___x___ , /*A69B*/ GENx___x___x___ , /*A69C*/ GENx___x___x___ , /*A69D*/ GENx___x___x___ , /*A69E*/ GENx___x___x___ , /*A69F*/ GENx___x___x___ , /*A6A0*/ GENx___x___x___ , /*A6A1*/ GENx___x___x___ , /*A6A2*/ GENx___x___x___ , /*A6A3*/ GENx___x___x___ , /*A6A4*/ GENx___x___x___ , /*A6A5*/ GENx___x___x___ , /*A6A6*/ GENx___x___x___ , /*A6A7*/ GENx___x___x___ , /*A6A8*/ GENx___x___x___ , /*A6A9*/ GENx___x___x___ , /*A6AA*/ GENx___x___x___ , /*A6AB*/ GENx___x___x___ , /*A6AC*/ GENx___x___x___ , /*A6AD*/ GENx___x___x___ , /*A6AE*/ GENx___x___x___ , /*A6AF*/ GENx___x___x___ , /*A6B0*/ GENx___x___x___ , /*A6B1*/ GENx___x___x___ , /*A6B2*/ GENx___x___x___ , /*A6B3*/ GENx___x___x___ , /*A6B4*/ GENx___x___x___ , /*A6B5*/ GENx___x___x___ , /*A6B6*/ GENx___x___x___ , /*A6B7*/ GENx___x___x___ , /*A6B8*/ GENx___x___x___ , /*A6B9*/ GENx___x___x___ , /*A6BA*/ GENx___x___x___ , /*A6BB*/ GENx___x___x___ , /*A6BC*/ GENx___x___x___ , /*A6BD*/ GENx___x___x___ , /*A6BE*/ GENx___x___x___ , /*A6BF*/ GENx___x___x___ , /*A6C0*/ GENx370x390x___ (v_save_vsr,S,"VSRSV"), /*A6C1*/ GENx370x390x___ (v_save_vmr,S,"VMRSV"), /*A6C2*/ GENx370x390x___ (v_restore_vsr,S,"VSRRS"), /*A6C3*/ GENx370x390x___ (v_restore_vmr,S,"VMRRS"), /*A6C4*/ GENx370x390x___ (v_load_vct_from_address,S,"VLVCA"), /*A6C5*/ GENx370x390x___ (v_clear_vr,S,"VRCL"), /*A6C6*/ GENx370x390x___ (v_set_vector_mask_mode,S,"VSVMM"), /*A6C7*/ GENx370x390x___ (v_load_vix_from_address,S,"VLVXA"), /*A6C8*/ GENx370x390x___ (v_store_vector_parameters,S,"VSTVP"), /*A6C9*/ GENx___x___x___ , /*A6CA*/ GENx370x390x___ (v_save_vac,S,"VACSV"), /*A6CB*/ GENx370x390x___ (v_restore_vac,S,"VACRS"), /*A6CC*/ GENx___x___x___ , /*A6CD*/ GENx___x___x___ , /*A6CE*/ GENx___x___x___ , /*A6CF*/ GENx___x___x___ , /*A6D0*/ GENx___x___x___ , /*A6D1*/ GENx___x___x___ , /*A6D2*/ GENx___x___x___ , /*A6D3*/ GENx___x___x___ , /*A6D4*/ GENx___x___x___ , /*A6D5*/ GENx___x___x___ , /*A6D6*/ GENx___x___x___ , /*A6D7*/ GENx___x___x___ , /*A6D8*/ GENx___x___x___ , /*A6D9*/ GENx___x___x___ , /*A6DA*/ GENx___x___x___ , /*A6DB*/ GENx___x___x___ , /*A6DC*/ GENx___x___x___ , /*A6DD*/ GENx___x___x___ , /*A6DE*/ GENx___x___x___ , /*A6DF*/ GENx___x___x___ , /*A6E0*/ GENx___x___x___ , /*A6E1*/ GENx___x___x___ , /*A6E2*/ GENx___x___x___ , /*A6E3*/ GENx___x___x___ , /*A6E4*/ GENx___x___x___ , /*A6E5*/ GENx___x___x___ , /*A6E6*/ GENx___x___x___ , /*A6E7*/ GENx___x___x___ , /*A6E8*/ GENx___x___x___ , /*A6E9*/ GENx___x___x___ , /*A6EA*/ GENx___x___x___ , /*A6EB*/ GENx___x___x___ , /*A6EC*/ GENx___x___x___ , /*A6ED*/ GENx___x___x___ , /*A6EE*/ GENx___x___x___ , /*A6EF*/ GENx___x___x___ , /*A6F0*/ GENx___x___x___ , /*A6F1*/ GENx___x___x___ , /*A6F2*/ GENx___x___x___ , /*A6F3*/ GENx___x___x___ , /*A6F4*/ GENx___x___x___ , /*A6F5*/ GENx___x___x___ , /*A6F6*/ GENx___x___x___ , /*A6F7*/ GENx___x___x___ , /*A6F8*/ GENx___x___x___ , /*A6F9*/ GENx___x___x___ , /*A6FA*/ GENx___x___x___ , /*A6FB*/ GENx___x___x___ , /*A6FC*/ GENx___x___x___ , /*A6FD*/ GENx___x___x___ , /*A6FE*/ GENx___x___x___ , /*A6FF*/ GENx___x___x___ }; // #endif /*defined (FEATURE_VECTOR_FACILITY)*/ // #if defined (FEATURE_VECTOR_FACILITY) zz_func v_opcode_e4xx[256][GEN_MAXARCH] = { /*E400*/ GENx___x___x___ , /*E401*/ GENx___x___x___ , /*E402*/ GENx___x___x___ , /*E403*/ GENx___x___x___ , /*E404*/ GENx___x___x___ , /*E405*/ GENx___x___x___ , /*E406*/ GENx___x___x___ , /*E407*/ GENx___x___x___ , /*E408*/ GENx___x___x___ , /*E409*/ GENx___x___x___ , /*E40A*/ GENx___x___x___ , /*E40B*/ GENx___x___x___ , /*E40C*/ GENx___x___x___ , /*E40D*/ GENx___x___x___ , /*E40E*/ GENx___x___x___ , /*E40F*/ GENx___x___x___ , /*E410*/ GENx___x___x___ , /*E411*/ GENx___x___x___ , /*E412*/ GENx___x___x___ , /*E413*/ GENx___x___x___ , /*E414*/ GENx___x___x___ , /*E415*/ GENx___x___x___ , /*E416*/ GENx___x___x___ , /*E417*/ GENx___x___x___ , /*E418*/ GENx___x___x___ , /*E419*/ GENx___x___x___ , /*E41A*/ GENx___x___x___ , /*E41B*/ GENx___x___x___ , /*E41C*/ GENx___x___x___ , /*E41D*/ GENx___x___x___ , /*E41E*/ GENx___x___x___ , /*E41F*/ GENx___x___x___ , /*E420*/ GENx___x___x___ , /*E421*/ GENx___x___x___ , /*E422*/ GENx___x___x___ , /*E423*/ GENx___x___x___ , /*E424*/ GENx___x___x___ , /*E425*/ GENx___x___x___ , /*E426*/ GENx___x___x___ , /*E427*/ GENx___x___x___ , /*E428*/ GENx___x___x___ , /*E429*/ GENx___x___x___ , /*E42A*/ GENx___x___x___ , /*E42B*/ GENx___x___x___ , /*E42C*/ GENx___x___x___ , /*E42D*/ GENx___x___x___ , /*E42E*/ GENx___x___x___ , /*E42F*/ GENx___x___x___ , /*E430*/ GENx___x___x___ , /*E431*/ GENx___x___x___ , /*E432*/ GENx___x___x___ , /*E433*/ GENx___x___x___ , /*E434*/ GENx___x___x___ , /*E435*/ GENx___x___x___ , /*E436*/ GENx___x___x___ , /*E437*/ GENx___x___x___ , /*E438*/ GENx___x___x___ , /*E439*/ GENx___x___x___ , /*E43A*/ GENx___x___x___ , /*E43B*/ GENx___x___x___ , /*E43C*/ GENx___x___x___ , /*E43D*/ GENx___x___x___ , /*E43E*/ GENx___x___x___ , /*E43F*/ GENx___x___x___ , /*E440*/ GENx___x___x___ , /*E441*/ GENx___x___x___ , /*E442*/ GENx___x___x___ , /*E443*/ GENx___x___x___ , /*E444*/ GENx___x___x___ , /*E445*/ GENx___x___x___ , /*E446*/ GENx___x___x___ , /*E447*/ GENx___x___x___ , /*E448*/ GENx___x___x___ , /*E449*/ GENx___x___x___ , /*E44A*/ GENx___x___x___ , /*E44B*/ GENx___x___x___ , /*E44C*/ GENx___x___x___ , /*E44D*/ GENx___x___x___ , /*E44E*/ GENx___x___x___ , /*E44F*/ GENx___x___x___ , /*E450*/ GENx___x___x___ , /*E451*/ GENx___x___x___ , /*E452*/ GENx___x___x___ , /*E453*/ GENx___x___x___ , /*E454*/ GENx___x___x___ , /*E455*/ GENx___x___x___ , /*E456*/ GENx___x___x___ , /*E457*/ GENx___x___x___ , /*E458*/ GENx___x___x___ , /*E459*/ GENx___x___x___ , /*E45A*/ GENx___x___x___ , /*E45B*/ GENx___x___x___ , /*E45C*/ GENx___x___x___ , /*E45D*/ GENx___x___x___ , /*E45E*/ GENx___x___x___ , /*E45F*/ GENx___x___x___ , /*E460*/ GENx___x___x___ , /*E461*/ GENx___x___x___ , /*E462*/ GENx___x___x___ , /*E463*/ GENx___x___x___ , /*E464*/ GENx___x___x___ , /*E465*/ GENx___x___x___ , /*E466*/ GENx___x___x___ , /*E467*/ GENx___x___x___ , /*E468*/ GENx___x___x___ , /*E469*/ GENx___x___x___ , /*E46A*/ GENx___x___x___ , /*E46B*/ GENx___x___x___ , /*E46C*/ GENx___x___x___ , /*E46D*/ GENx___x___x___ , /*E46E*/ GENx___x___x___ , /*E46F*/ GENx___x___x___ , /*E470*/ GENx___x___x___ , /*E471*/ GENx___x___x___ , /*E472*/ GENx___x___x___ , /*E473*/ GENx___x___x___ , /*E474*/ GENx___x___x___ , /*E475*/ GENx___x___x___ , /*E476*/ GENx___x___x___ , /*E477*/ GENx___x___x___ , /*E478*/ GENx___x___x___ , /*E479*/ GENx___x___x___ , /*E47A*/ GENx___x___x___ , /*E47B*/ GENx___x___x___ , /*E47C*/ GENx___x___x___ , /*E47D*/ GENx___x___x___ , /*E47E*/ GENx___x___x___ , /*E47F*/ GENx___x___x___ , /*E480*/ GENx___x___x___ , /*E481*/ GENx___x___x___ , /*E482*/ GENx___x___x___ , /*E483*/ GENx___x___x___ , /*E484*/ GENx___x___x___ , /*E485*/ GENx___x___x___ , /*E486*/ GENx___x___x___ , /*E487*/ GENx___x___x___ , /*E488*/ GENx___x___x___ , /*E489*/ GENx___x___x___ , /*E48A*/ GENx___x___x___ , /*E48B*/ GENx___x___x___ , /*E48C*/ GENx___x___x___ , /*E48D*/ GENx___x___x___ , /*E48E*/ GENx___x___x___ , /*E48F*/ GENx___x___x___ , /*E490*/ GENx___x___x___ , /*E491*/ GENx___x___x___ , /*E492*/ GENx___x___x___ , /*E493*/ GENx___x___x___ , /*E494*/ GENx___x___x___ , /*E495*/ GENx___x___x___ , /*E496*/ GENx___x___x___ , /*E497*/ GENx___x___x___ , /*E498*/ GENx___x___x___ , /*E499*/ GENx___x___x___ , /*E49A*/ GENx___x___x___ , /*E49B*/ GENx___x___x___ , /*E49C*/ GENx___x___x___ , /*E49D*/ GENx___x___x___ , /*E49E*/ GENx___x___x___ , /*E49F*/ GENx___x___x___ , /*E4A0*/ GENx___x___x___ , /*E4A1*/ GENx___x___x___ , /*E4A2*/ GENx___x___x___ , /*E4A3*/ GENx___x___x___ , /*E4A4*/ GENx___x___x___ , /*E4A5*/ GENx___x___x___ , /*E4A6*/ GENx___x___x___ , /*E4A7*/ GENx___x___x___ , /*E4A8*/ GENx___x___x___ , /*E4A9*/ GENx___x___x___ , /*E4AA*/ GENx___x___x___ , /*E4AB*/ GENx___x___x___ , /*E4AC*/ GENx___x___x___ , /*E4AD*/ GENx___x___x___ , /*E4AE*/ GENx___x___x___ , /*E4AF*/ GENx___x___x___ , /*E4B0*/ GENx___x___x___ , /*E4B1*/ GENx___x___x___ , /*E4B2*/ GENx___x___x___ , /*E4B3*/ GENx___x___x___ , /*E4B4*/ GENx___x___x___ , /*E4B5*/ GENx___x___x___ , /*E4B6*/ GENx___x___x___ , /*E4B7*/ GENx___x___x___ , /*E4B8*/ GENx___x___x___ , /*E4B9*/ GENx___x___x___ , /*E4BA*/ GENx___x___x___ , /*E4BB*/ GENx___x___x___ , /*E4BC*/ GENx___x___x___ , /*E4BD*/ GENx___x___x___ , /*E4BE*/ GENx___x___x___ , /*E4BF*/ GENx___x___x___ , /*E4C0*/ GENx___x___x___ , /*E4C1*/ GENx___x___x___ , /*E4C2*/ GENx___x___x___ , /*E4C3*/ GENx___x___x___ , /*E4C4*/ GENx___x___x___ , /*E4C5*/ GENx___x___x___ , /*E4C6*/ GENx___x___x___ , /*E4C7*/ GENx___x___x___ , /*E4C8*/ GENx___x___x___ , /*E4C9*/ GENx___x___x___ , /*E4CA*/ GENx___x___x___ , /*E4CB*/ GENx___x___x___ , /*E4CC*/ GENx___x___x___ , /*E4CD*/ GENx___x___x___ , /*E4CE*/ GENx___x___x___ , /*E4CF*/ GENx___x___x___ , /*E4D0*/ GENx___x___x___ , /*E4D1*/ GENx___x___x___ , /*E4D2*/ GENx___x___x___ , /*E4D3*/ GENx___x___x___ , /*E4D4*/ GENx___x___x___ , /*E4D5*/ GENx___x___x___ , /*E4D6*/ GENx___x___x___ , /*E4D7*/ GENx___x___x___ , /*E4D8*/ GENx___x___x___ , /*E4D9*/ GENx___x___x___ , /*E4DA*/ GENx___x___x___ , /*E4DB*/ GENx___x___x___ , /*E4DC*/ GENx___x___x___ , /*E4DD*/ GENx___x___x___ , /*E4DE*/ GENx___x___x___ , /*E4DF*/ GENx___x___x___ , /*E4E0*/ GENx___x___x___ , /*E4E1*/ GENx___x___x___ , /*E4E2*/ GENx___x___x___ , /*E4E3*/ GENx___x___x___ , /*E4E4*/ GENx___x___x___ , /*E4E5*/ GENx___x___x___ , /*E4E6*/ GENx___x___x___ , /*E4E7*/ GENx___x___x___ , /*E4E8*/ GENx___x___x___ , /*E4E9*/ GENx___x___x___ , /*E4EA*/ GENx___x___x___ , /*E4EB*/ GENx___x___x___ , /*E4EC*/ GENx___x___x___ , /*E4ED*/ GENx___x___x___ , /*E4EE*/ GENx___x___x___ , /*E4EF*/ GENx___x___x___ , /*E4F0*/ GENx___x___x___ , /*E4F1*/ GENx___x___x___ , /*E4F2*/ GENx___x___x___ , /*E4F3*/ GENx___x___x___ , /*E4F4*/ GENx___x___x___ , /*E4F5*/ GENx___x___x___ , /*E4F6*/ GENx___x___x___ , /*E4F7*/ GENx___x___x___ , /*E4F8*/ GENx___x___x___ , /*E4F9*/ GENx___x___x___ , /*E4FA*/ GENx___x___x___ , /*E4FB*/ GENx___x___x___ , /*E4FC*/ GENx___x___x___ , /*E4FD*/ GENx___x___x___ , /*E4FE*/ GENx___x___x___ , /*E4FF*/ GENx___x___x___ }; // #endif /*defined (FEATURE_VECTOR_FACILITY)*/ #endif /*!defined (_GEN_ARCH)*/ /* end of OPCODE.C */ hercules-3.12/diagnose.c0000664000175000017500000006044112564723224012145 00000000000000/* DIAGNOSE.C (c) Copyright Roger Bowler, 2000-2009 */ /* ESA/390 Diagnose Functions */ /*-------------------------------------------------------------------*/ /* This module implements miscellaneous diagnose functions */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Hercules-specific diagnose calls by Jay Maynard. */ /* Set/reset bad frame indicator call by Jan Jaeger. */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_DIAGNOSE_C_) #define _DIAGNOSE_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if !defined(_DIAGNOSE_H) #define _DIAGNOSE_H /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ /* Diagnose 308 function subcodes */ #define DIAG308_IPL_CLEAR 3 /* IPL clear */ #define DIAG308_IPL_NORMAL 4 /* IPL normal/dump */ #define DIAG308_SET_PARAM 5 /* Set IPL parameters */ #define DIAG308_STORE_PARAM 6 /* Store IPL parameters */ /* Diagnose 308 return codes */ #define DIAG308_RC_OK 1 #endif /*!defined(_DIAGNOSE_H)*/ #if defined(OPTION_DYNAMIC_LOAD) && defined(FEATURE_HERCULES_DIAGCALLS) void ARCH_DEP(diagf14_call)(int r1, int r3, REGS *regs) { char name[32+1]; char entry[64]; unsigned int i; void (*dllcall)(int, int, REGS *); static char *prefix[] = { #if defined(_370) "s370_diagf14_", #endif #if defined(_390) "s390_diagf14_", #endif #if defined(_900) "z900_diagf14_" #endif }; ARCH_DEP(vfetchc) (name,sizeof(name)-2, regs->GR(r1), USE_REAL_ADDR, regs); for(i = 0; i < sizeof(name)-1; i++) { name[i] = guest_to_host(name[i]); if(!isprint(name[i]) || isspace(name[i])) { name[i] = '\0'; break; } } /* Ensure string terminator */ name[i] = '\0'; strcpy(entry,prefix[regs->arch_mode]); strcat(entry,name); if( (dllcall = HDL_FINDSYM(entry)) ) dllcall(r1, r3, regs); else ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } #endif /*defined(OPTION_DYNAMIC_LOAD)*/ #if defined(FEATURE_PROGRAM_DIRECTED_REIPL) && !defined(STOP_CPUS_AND_IPL) #define STOP_CPUS_AND_IPL /*---------------------------------------------------------------------------*/ /* Within diagnose 0x308 (re-ipl) a thread is started with the next code. */ /*---------------------------------------------------------------------------*/ void *stop_cpus_and_ipl(int *ipltype) { int i; char iplcmd[256]; int cpustates; CPU_BITMAP mask; panel_command("stopall"); logmsg("HHCDN001I Diagnose 0x308 called: System is re-ipled\n"); sprintf(iplcmd, "%s %03X", ipltype, sysblk.ipldev); do { OBTAIN_INTLOCK(NULL); cpustates = CPUSTATE_STOPPED; mask = sysblk.started_mask; for(i = 0; mask; i++) { if(mask & 1) { logmsg("HHCDN002I Checking cpu %d\n", i); if(IS_CPU_ONLINE(i) && sysblk.regs[i]->cpustate != CPUSTATE_STOPPED) cpustates = sysblk.regs[i]->cpustate; } mask >>= 1; } RELEASE_INTLOCK(NULL); if(cpustates != CPUSTATE_STOPPED) { logmsg("HHCDN003I Waiting 1 second for cpu's to stop...\n"); SLEEP(1); } } while(cpustates != CPUSTATE_STOPPED); panel_command(iplcmd); return NULL; } #endif /*defined(FEATURE_PROGRAM_DIRECTED_REIPL) && !defined(STOP_CPUS_AND_IPL)*/ /*-------------------------------------------------------------------*/ /* Diagnose instruction */ /*-------------------------------------------------------------------*/ void ARCH_DEP(diagnose_call) (VADR effective_addr2, int b2, int r1, int r2, REGS *regs) { #ifdef FEATURE_HERCULES_DIAGCALLS U32 n; /* 32-bit operand value */ #endif /*FEATURE_HERCULES_DIAGCALLS*/ U32 code; code = effective_addr2; switch(code) { #if defined(FEATURE_IO_ASSIST) case 0x002: /*---------------------------------------------------------------*/ /* Diagnose 002: Update Interrupt Interlock Control Bit in PMCW */ /*---------------------------------------------------------------*/ ARCH_DEP(diagnose_002) (regs, r1, r2); break; #endif case 0x01F: /*---------------------------------------------------------------*/ /* Diagnose 01F: Power Off */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* The poweroff diagnose is only valid on the 9221 */ if(((sysblk.cpuid >> 16 & 0xFFFF) != 0x9221 ) /* and r1/r2 must contain C'POWEROFF' in EBCDIC */ || regs->GR_L(r1) != 0xD7D6E6C5 || regs->GR_L(r2) != 0xD9D6C6C6) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); /* Release the configuration */ do_shutdown(); /* Power Off: exit hercules */ exit(0); break; #if defined(FEATURE_HYPERVISOR) || defined(FEATURE_EMULATE_VM) case 0x044: /*---------------------------------------------------------------*/ /* Diagnose 044: Voluntary Time Slice End */ /*---------------------------------------------------------------*/ ARCH_DEP(scpend_call) (); break; #endif #ifdef FEATURE_MSSF_CALL case 0x080: /*---------------------------------------------------------------*/ /* Diagnose 080: MSSF Call */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(mssf_call) (r1, r2, regs); break; #endif /*FEATURE_MSSF_CALL*/ #if defined(FEATURE_HYPERVISOR) || defined(FEATURE_EMULATE_VM) case 0x09C: /*---------------------------------------------------------------*/ /* Diagnose 09C: Voluntary Time Slice End With Target CPU */ /*---------------------------------------------------------------*/ ARCH_DEP(scpend_call) (); // (treat same as DIAG X'44') break; #endif #if defined(FEATURE_HYPERVISOR) case 0x204: /*---------------------------------------------------------------*/ /* Diagnose 204: LPAR RMF Interface */ /*---------------------------------------------------------------*/ ARCH_DEP(diag204_call) (r1, r2, regs); regs->psw.cc = 0; break; case 0x224: /*---------------------------------------------------------------*/ /* Diagnose 224: CPU Names */ /*---------------------------------------------------------------*/ ARCH_DEP(diag224_call) (r1, r2, regs); regs->psw.cc = 0; break; #endif /*defined(FEATURE_HYPERVISOR)*/ #if 0 case 0x21C: /*---------------------------------------------------------------*/ /* Diagnose 21C: ???? */ /*---------------------------------------------------------------*/ /*INCOMPLETE*/ regs->psw.cc = 0; break; #endif #ifdef FEATURE_EMULATE_VM case 0x000: /*---------------------------------------------------------------*/ /* Diagnose 000: Store Extended Identification Code */ /*---------------------------------------------------------------*/ ARCH_DEP(extid_call) (r1, r2, regs); break; case 0x008: /*---------------------------------------------------------------*/ /* Diagnose 008: Virtual Console Function */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Process CP command and set condition code */ regs->psw.cc = ARCH_DEP(cpcmd_call) (r1, r2, regs); break; case 0x00C: /*---------------------------------------------------------------*/ /* Diagnose 00C: Pseudo Timer */ /*---------------------------------------------------------------*/ ARCH_DEP(pseudo_timer) (code, r1, r2, regs); break; case 0x024: /*---------------------------------------------------------------*/ /* Diagnose 024: Device Type and Features */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(diag_devtype) (r1, r2, regs); break; case 0x05C: /*---------------------------------------------------------------*/ /* Diagnose 05C: Error Message Editing */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ regs->psw.cc = 0; break; case 0x060: /*---------------------------------------------------------------*/ /* Diagnose 060: Virtual Machine Storage Size */ /*---------------------------------------------------------------*/ /* Load main storage size in bytes into R1 register */ regs->GR_L(r1) = sysblk.mainsize; break; case 0x064: /*---------------------------------------------------------------*/ /* Diagnose 064: Named Saved Segment Manipulation */ /*---------------------------------------------------------------*/ /* Return code 44 cond code 2 means segment does not exist */ regs->GR_L(r2) = 44; regs->psw.cc = 2; break; case 0x0A4: /*---------------------------------------------------------------*/ /* Diagnose 0A4: Synchronous I/O (Standard CMS Blocksize) */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(syncblk_io) (r1, r2, regs); // logmsg ("Diagnose X\'0A4\': CC=%d, R15=%8.8X\n", /*debug*/ // regs->psw.cc, regs->GR_L(15)); /*debug*/ break; case 0x0A8: /*---------------------------------------------------------------*/ /* Diagnose 0A8: Synchronous General I/O */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(syncgen_io) (r1, r2, regs); // logmsg ("Diagnose X\'0A8\': CC=%d, R15=%8.8X\n", /*debug*/ // regs->psw.cc, regs->GR_L(15)); /*debug*/ break; case 0x0B0: /*---------------------------------------------------------------*/ /* Diagnose 0B0: Access Re-IPL Data */ /*---------------------------------------------------------------*/ ARCH_DEP(access_reipl_data) (r1, r2, regs); break; case 0x0DC: /*---------------------------------------------------------------*/ /* Diagnose 0DC: Control Application Monitor Record Collection */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ regs->GR_L(r2) = 0; regs->psw.cc = 0; break; case 0x210: /*---------------------------------------------------------------*/ /* Diagnose 210: Retrieve Device Information */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(device_info) (r1, r2, regs); break; case 0x214: /*---------------------------------------------------------------*/ /* Diagnose 214: Pending Page Release */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(diag_ppagerel) (r1, r2, regs); break; case 0x220: /*---------------------------------------------------------------*/ /* Diagnose 220: TOD Epoch */ /*---------------------------------------------------------------*/ ODD_CHECK(r2, regs); switch(regs->GR_L(r1)) { case 0: /* Obtain TOD features */ regs->GR_L(r2) =0xc0000000; regs->GR_L(r2+1)=0x00000000; break; case 1: /* Obtain TOD offset to real TOD in R2, R2+1 */ regs->GR_L(r2) = (regs->tod_epoch >> 24) & 0xFFFFFFFF; regs->GR_L(r2+1)= (regs->tod_epoch << 8) & 0xFFFFFFFF; break; default: ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); } break; case 0x23C: /*---------------------------------------------------------------*/ /* Diagnose 23C: Address Space Services */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ regs->GR_L(r2) = 0; break; #if defined(FEATURE_VM_BLOCKIO) case 0x250: /*---------------------------------------------------------------*/ /* Diagnose 250: Standardized Block I/O */ /*---------------------------------------------------------------*/ regs->psw.cc = ARCH_DEP(vm_blockio) (r1, r2, regs); break; #endif /*defined(FEATURE_VM_BLOCKIO)*/ case 0x260: /*---------------------------------------------------------------*/ /* Diagnose 260: Access Certain Virtual Machine Information */ /*---------------------------------------------------------------*/ ARCH_DEP(vm_info) (r1, r2, regs); break; case 0x264: /*---------------------------------------------------------------*/ /* Diagnose 264: CP Communication */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ PTT(PTT_CL_ERR,"*DIAG264",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 0; break; case 0x270: /*---------------------------------------------------------------*/ /* Diagnose 270: Pseudo Timer Extended */ /*---------------------------------------------------------------*/ ARCH_DEP(pseudo_timer) (code, r1, r2, regs); break; case 0x274: /*---------------------------------------------------------------*/ /* Diagnose 274: Set Timezone Interrupt Flag */ /*---------------------------------------------------------------*/ /* This function is implemented as a no-operation */ PTT(PTT_CL_ERR,"*DIAG274",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 0; break; #endif /*FEATURE_EMULATE_VM*/ #ifdef FEATURE_HERCULES_DIAGCALLS case 0xF00: /*---------------------------------------------------------------*/ /* Diagnose F00: Hercules normal mode */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); sysblk.inststep = 0; SET_IC_TRACE; break; case 0xF04: /*---------------------------------------------------------------*/ /* Diagnose F04: Hercules single step mode */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); sysblk.inststep = 1; SET_IC_TRACE; break; case 0xF08: /*---------------------------------------------------------------*/ /* Diagnose F08: Hercules get instruction counter */ /*---------------------------------------------------------------*/ regs->GR_L(r1) = (U32)INSTCOUNT(regs); break; case 0xF0C: /*---------------------------------------------------------------*/ /* Diagnose F0C: Set/reset bad frame indicator */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Load 4K block address from R2 register */ n = regs->GR_L(r2) & ADDRESS_MAXWRAP(regs); /* Convert real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); /* Addressing exception if block is outside main storage */ if ( n > regs->mainlim ) { ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); break; } /* Update the storage key from R1 register bit 31 */ STORAGE_KEY(n, regs) &= ~(STORKEY_BADFRM); STORAGE_KEY(n, regs) |= regs->GR_L(r1) & STORKEY_BADFRM; break; case 0xF10: /*---------------------------------------------------------------*/ /* Diagnose F10: Hercules CPU stop */ /*---------------------------------------------------------------*/ /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); break; #if defined(OPTION_DYNAMIC_LOAD) case 0xF14: /*---------------------------------------------------------------*/ /* Diagnose F14: Hercules DLL interface */ /*---------------------------------------------------------------*/ ARCH_DEP(diagf14_call) (r1, r2, regs); break; #endif /*defined(OPTION_DYNAMIC_LOAD)*/ #if !defined(NO_SIGABEND_HANDLER) /* The following diagnose calls cause a exigent (non-repressible) machine check, and are used for test purposes only *JJ */ case 0xFE8: /*---------------------------------------------------------------*/ /* Diagnose FE8: Simulate Illegal Instruction */ /*---------------------------------------------------------------*/ raise(SIGILL); break; case 0xFEC: /*---------------------------------------------------------------*/ /* Diagnose FEC: Simulate Floating Point Exception */ /*---------------------------------------------------------------*/ raise(SIGFPE); break; case 0xFF0: /*---------------------------------------------------------------*/ /* Diagnose FF0: Simulate Segment Violation */ /*---------------------------------------------------------------*/ raise(SIGSEGV); break; case 0xFF4: /*---------------------------------------------------------------*/ /* Diagnose FF4: Simulate BUS Error */ /*---------------------------------------------------------------*/ raise(SIGBUS); break; case 0xFF8: /*---------------------------------------------------------------*/ /* Diagnose FF8: Simulate Loop */ /*---------------------------------------------------------------*/ while(1); break; case 0xFFC: /*---------------------------------------------------------------*/ /* Diagnose FFC: Simulate Wait */ /*---------------------------------------------------------------*/ SLEEP(300); break; #endif /*!defined(NO_SIGABEND_HANDLER)*/ #endif /*FEATURE_HERCULES_DIAGCALLS*/ case 0x308: /*---------------------------------------------------------------*/ /* Diagnose 308: IPL functions */ /*---------------------------------------------------------------*/ switch(r2) { #ifdef FEATURE_PROGRAM_DIRECTED_REIPL TID tid; /* Thread identifier */ char *ipltype; /* "ipl" or "iplc" */ case DIAG308_IPL_CLEAR: ipltype = "iplc"; goto diag308_cthread; case DIAG308_IPL_NORMAL: ipltype = "ipl"; diag308_cthread: if(create_thread(&tid, DETACHED, stop_cpus_and_ipl, ipltype, "Stop cpus and ipl")) logmsg("HHCDN004E Error starting thread in diagnose 0x308: %s\n", strerror(errno)); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); break; case DIAG308_SET_PARAM: /* INCOMPLETE */ regs->GR(1) = DIAG308_RC_OK; break; case DIAG308_STORE_PARAM: /* INCOMPLETE */ regs->GR(1) = DIAG308_RC_OK; break; #endif /*FEATURE_PROGRAM_DIRECTED_REIPL*/ default: ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); } /* end switch(r2) */ break; default: /*---------------------------------------------------------------*/ /* Diagnose xxx: Invalid function code */ /*---------------------------------------------------------------*/ if( HDC4(debug_diagnose, code, r1, r2, regs) ) return; /* Power Off diagnose on 4361, 9371, 9373, 9375, 9377, 9221: */ /* */ /* DS 0H */ /* DC X'8302',S(SHUTDATA) MUST BE R0 AND R2 */ /* ... */ /* DS 0H */ /* SHUTDATA DC X'0000FFFF' MUST BE X'0000FFFF' */ if (0 == r1 && 2 == r2 && (sysblk.cpuid >> 56 & 0xFF) != 0xFF && ((sysblk.cpuid >> 16 & 0xFFFF) == 0x4361 || (sysblk.cpuid >> 16 & 0xFFF9) == 0x9371 /* (937X) */ || (sysblk.cpuid >> 16 & 0xFFFF) == 0x9221) ) { if (0x0000FFFF == ARCH_DEP(vfetch4)(effective_addr2, b2, regs)) { /* If diag8cmd is not enabled then we are not allowed * to manipulate the real machine i.e. hercules itself */ if(!(sysblk.diag8cmd & DIAG8CMD_ENABLE)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); /* Release the configuration */ do_shutdown(); /* Power Off: exit hercules */ exit(0); } } #if defined(FEATURE_S370_CHANNEL) && defined(OPTION_NOP_MODEL158_DIAGNOSE) if((sysblk.cpuid >> 16 & 0xFFFF) != 0x0158) #endif ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); return; } /* end switch(code) */ return; } /* end function diagnose_call */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "diagnose.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "diagnose.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/diagmssf.c0000664000175000017500000007620112564723224012152 00000000000000/* DIAGMSSF.C (c) Copyright Jan Jaeger, 1999-2009 */ /* ESA/390 Diagnose Functions */ /*-------------------------------------------------------------------*/ /* This module implements various diagnose functions */ /* MSSF call as described in SA22-7098-0 */ /* SCPEND as described in GC19-6215-0 which is also used with PR/SM */ /* LPAR RMF interface call */ /* */ /* 04/12/1999 Jan Jaeger */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_DIAGMSSF_C_) #define _DIAGMSSF_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "service.h" #if !defined(_DIAGMSSF_C) #define _DIAGMSSF_C /*-------------------------------------------------------------------*/ /* MSSF Call service processor commands */ /*-------------------------------------------------------------------*/ #define MSSF_READ_CONFIG_INFO 0x00020001 #define MSSF_READ_CHP_STATUS 0x00030001 /*-------------------------------------------------------------------*/ /* Service Processor Command Control Block */ /*-------------------------------------------------------------------*/ typedef struct _SPCCB_HEADER { HWORD length; /* Total length of SPCCB */ BYTE resv1[4]; /* Reserved */ HWORD resp; /* Response code */ } SPCCB_HEADER; #define SPCCB_REAS_COMPLETE 0x00 #define SPCCB_RESP_COMPLETE 0x10 #define SPCCB_REAS_CHECK 0x00 #define SPCCB_RESP_CHECK 0x40 #define SPCCB_REAS_BADLENGTH 0x01 #define SPCCB_RESP_BADLENGTH 0xF0 #define SPCCB_REAS_NOT2KALIGN 0x01 #define SPCCB_RESP_NOT2KALIGN 0x00 #define SPCCB_REAS_UNASSIGNED 0x06 #define SPCCB_RESP_UNASSIGNED 0xF0 /*-------------------------------------------------------------------*/ /* Service Processor Command Control Block */ /*-------------------------------------------------------------------*/ typedef struct _SPCCB_CONFIG_INFO { BYTE totstori; /* Total number of installed storage increments. */ BYTE storisiz; /* Storage increment size in units of one megabyte. */ BYTE hex04; /* This field contains the value of 04 hex. */ BYTE hex01; /* This field contains the value of either 01 hex or 02 hex. */ FWORD reserved; /* Reserved. */ HWORD toticpu; /* Total number of installed CPUs. This number also specifies the total number of entries in the CPU- description list. */ HWORD officpu; /* Offset in the SPCCB to the first entry in the CPU- description list. */ HWORD tothsa; /* Total number of machine- storage areas reserved for the requesting configuration. This number also specifies the total number of entries in the machine-storage-area- description list. */ HWORD offhsa; /* Offset in the SPCCB to the first entry in the machine-storage-area- description list. */ BYTE loadparm[8]; /* Load parameter. This field conains eight bytes of EBCDIC information specified by the operator for the manually initiated load function. If the operator specifies fewer then eight characters, they are left- justified and padded on the right with 40 hex (preferred), or F0 hex, or 00 hex to form an eight byte load parameter. If the operator does not specify a load parameter, a default load parameter is formed, consisting of F1 hex (preferred), or 40 hex, or 00 hex, padded on the right with 40 hex (preferred), or F0 hex, of 00 hex. The load parameter is set to this default value by the activation of the system-reset-clear key or by performing certain operator functions. */ } SPCCB_CONFIG_INFO; typedef struct _SPCCB_CPU_INFO { BYTE cpuaddr; /* Rightmost eight bits of the CPU address */ BYTE todid; /* Identity of the TOD clock accessed by this CPU */ } SPCCB_CPU_INFO; typedef struct _SPCCB_HSA_INFO { BYTE hsasize; /* Bits 1-15 of this field specify the size of the area in units of 4K bytes or 32K bytes. When bit 0 of byte 0 is zero, the size is in units of 32K bytes; otherwise, the size is in units of 4K bytes. */ BYTE hsaaddr; /* Absolute address of the start of the machine- storage area. */ } SPCCB_HSA_INFO; typedef struct _SPCCB_CHP_STATUS { BYTE installed[32]; /* Installed-channel-path bit map. */ BYTE assigned[32]; /* Assigned-channel-path bit map. */ BYTE configured[32]; /* Configured-channel-path bit map. */ BYTE reserved[152]; /* Reserved. */ } SPCCB_CHP_STATUS; typedef struct _DIAG204_HDR { BYTE numpart; /* Number of partitions */ BYTE flags; /* Flag Byte */ #define DIAG204_PHYSICAL_PRESENT 0x80 HWORD resv; /* Unknown , 0 on 2003, 0x0005 under VM */ HWORD physcpu; /* Number of phys CP's */ HWORD offown; /* Offset to own partition */ DBLWRD diagstck; /* TOD of last diag204 */ } DIAG204_HDR; typedef struct _DIAG204_PART { BYTE partnum; /* Logical partition number starts with 1 */ BYTE virtcpu; /* Number of virt CP's */ HWORD resv1[3]; BYTE partname[8]; /* Partition name */ } DIAG204_PART; typedef struct _DIAG204_PART_CPU { HWORD cpaddr; /* CP address */ BYTE resv1[2]; BYTE index; /* Index into diag224 area */ BYTE cflag; /* ??? */ HWORD weight; /* Weight */ DBLWRD totdispatch; /* Total dispatch time */ DBLWRD effdispatch; /* Effective dispatch time */ } DIAG204_PART_CPU; typedef struct _DIAG204_X_HDR { BYTE numpart; /* Number of partitions */ BYTE flags; /* Flag Byte */ #define DIAG204_X_PHYSICAL_PRESENT 0x80 HWORD resv1; /* Unknown , 0 on 2003, 0x0005 under VM */ HWORD physcpu; /* Number of phys CP's */ HWORD offown; /* Offset to own partition */ DBLWRD diagstck1; /* TOD of last diag204 */ DBLWRD diagstck2; /* in STCKE format */ BYTE resv2[40]; } DIAG204_X_HDR; typedef struct _DIAG204_X_PART { BYTE partnum; /* Logical partition number starts with 1 */ BYTE virtcpu; /* Number of virt CP's */ BYTE realcpu; /* Number of real CP's */ BYTE pflag; FWORD mlu; BYTE partname[8]; /* Partition name */ BYTE cpcname[8]; /* CPC name */ BYTE osname[8]; /* Operating system type */ DBLWRD cssize; /* Central storage size */ DBLWRD essize; /* Expanded Storage size */ BYTE upid; BYTE resv1[3]; FWORD gr_mlu; BYTE gr_name[8]; /* Sysplex name? */ BYTE resv2[32]; } DIAG204_X_PART; typedef struct _DIAG204_X_PART_CPU { HWORD cpaddr; /* CP address */ BYTE resv1[2]; BYTE index; /* Index into diag224 area */ BYTE cflag; /* ??? */ HWORD weight; /* Weight */ DBLWRD totdispatch; /* Total dispatch time */ DBLWRD effdispatch; /* Effective dispatch time */ HWORD minweight; HWORD curweight; HWORD maxweight; BYTE resv2[2]; DBLWRD onlinetime; DBLWRD waittime; FWORD pmaweight; FWORD polarweight; BYTE resv3[40]; } DIAG204_X_PART_CPU; static const char diag224_cputable[]= { "CP " "ICF " "ZAAP " "IFL " "*UNKNOWN* " "ZIIP " }; #endif /*!defined(_DIAGMSSF_C)*/ /*-------------------------------------------------------------------*/ /* Process SCPEND call (Function code 0x044) */ /*-------------------------------------------------------------------*/ void ARCH_DEP(scpend_call) (void) { sched_yield(); /* Just go to the dispatcher for a minimum delay */ } /* end function scpend_call */ #ifdef FEATURE_MSSF_CALL /*-------------------------------------------------------------------*/ /* Process MSSF call (Function code 0x080) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(mssf_call) (int r1, int r2, REGS *regs) { U32 spccb_absolute_addr; /* Absolute addr of SPCCB */ U32 mssf_command; /* MSSF command word */ U32 spccblen; /* Length of SPCCB */ SPCCB_HEADER *spccb; /* -> SPCCB header */ SPCCB_CONFIG_INFO *spccbconfig; /* -> SPCCB CONFIG info */ SPCCB_CPU_INFO *spccbcpu; /* -> SPCCB CPU information */ SPCCB_CHP_STATUS *spccbchp; /* -> SPCCB channel path info */ U16 offset; /* Offset from start of SPCCB */ int i; /* loop counter */ DEVBLK *dev; /* Device block pointer */ /* R1 contains the real address of the SPCCB */ spccb_absolute_addr = APPLY_PREFIXING (regs->GR_L(r1), regs->PX); /* R2 contains the service-processor-command word */ mssf_command = regs->GR_L(r2); /* Program check if SPCCB is not on a doubleword boundary */ if ( spccb_absolute_addr & 0x00000007 ) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if SPCCB is outside main storage */ if ( spccb_absolute_addr > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); // /*debug*/logmsg("MSSF call %8.8X SPCCB=%8.8X\n", // /*debug*/ mssf_command, spccb_absolute_addr); /* Point to Service Processor Command Control Block */ spccb = (SPCCB_HEADER*)(regs->mainstor + spccb_absolute_addr); /* Load SPCCB length from header */ FETCH_HW(spccblen,spccb->length); /* Mark page referenced */ STORAGE_KEY(spccb_absolute_addr, regs) |= STORKEY_REF; /* Program check if end of SPCCB falls outside main storage */ if ( sysblk.mainsize - spccblen < spccb_absolute_addr ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); /* If a service signal is pending then we cannot process the request */ if( IS_IC_SERVSIG && (sysblk.servparm & SERVSIG_ADDR)) { RELEASE_INTLOCK(regs); return 2; /* Service Processor Busy */ } if( spccb_absolute_addr & 0x7ffff800 ) { spccb->resp[0] = SPCCB_REAS_NOT2KALIGN; spccb->resp[1] = SPCCB_RESP_NOT2KALIGN; } else /* Test MSSF command word */ switch (mssf_command) { case MSSF_READ_CONFIG_INFO: /* Set response code X'01F0' if SPCCB length is insufficient to contain CONFIG info */ if ( spccblen < 64 ) { spccb->resp[0] = SPCCB_REAS_BADLENGTH; spccb->resp[1] = SPCCB_RESP_BADLENGTH; break; } /* Point to SPCCB data area following SPCCB header */ spccbconfig = (SPCCB_CONFIG_INFO*)(spccb+1); memset (spccbconfig, 0, sizeof(SPCCB_CONFIG_INFO)); /* Set main storage size in SPCCB */ spccbconfig->totstori = sysblk.mainsize >> 20; spccbconfig->storisiz = 1; spccbconfig->hex04 = 0x04; spccbconfig->hex01 = 0x01; /* Set CPU array count and offset in SPCCB */ STORE_HW(spccbconfig->toticpu,MAX_CPU); offset = sizeof(SPCCB_HEADER) + sizeof(SPCCB_CONFIG_INFO); STORE_HW(spccbconfig->officpu,offset); /* Set HSA array count and offset in SPCCB */ STORE_HW(spccbconfig->tothsa,0); offset += sizeof(SPCCB_CPU_INFO) * MAX_CPU; STORE_HW(spccbconfig->offhsa,offset); /* Move IPL load parameter to SPCCB */ get_loadparm (spccbconfig->loadparm); /* Build the CPU information array after the SCP info */ spccbcpu = (SPCCB_CPU_INFO*)(spccbconfig+1); for (i = 0; i < MAX_CPU; i++, spccbcpu++) { memset (spccbcpu, 0, sizeof(SPCCB_CPU_INFO)); spccbcpu->cpuaddr = i; spccbcpu->todid = 0; } /* Set response code X'0010' in SPCCB header */ spccb->resp[0] = SPCCB_REAS_COMPLETE; spccb->resp[1] = SPCCB_RESP_COMPLETE; break; case MSSF_READ_CHP_STATUS: /* Set response code X'0300' if SPCCB length is insufficient to contain channel path info */ if ( spccblen < sizeof(SPCCB_HEADER) + sizeof(SPCCB_CHP_STATUS)) { spccb->resp[0] = SPCCB_REAS_BADLENGTH; spccb->resp[1] = SPCCB_RESP_BADLENGTH; break; } /* Point to SPCCB data area following SPCCB header */ spccbchp = (SPCCB_CHP_STATUS*)(spccb+1); memset (spccbchp, 0, sizeof(SPCCB_CHP_STATUS)); /* Identify CHPIDs used */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { spccbchp->installed[dev->devnum >> 11] |= 0x80 >> ((dev->devnum >> 8) & 7); spccbchp->assigned[dev->devnum >> 11] |= 0x80 >> ((dev->devnum >> 8) & 7); spccbchp->configured[dev->devnum >> 11] |= 0x80 >> ((dev->devnum >> 8) & 7); } /* Set response code X'0010' in SPCCB header */ spccb->resp[0] = SPCCB_REAS_COMPLETE; spccb->resp[1] = SPCCB_RESP_COMPLETE; break; default: PTT(PTT_CL_ERR,"*DIAG080",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); /* Set response code X'06F0' for invalid MSSF command */ spccb->resp[0] = SPCCB_REAS_UNASSIGNED; spccb->resp[1] = SPCCB_RESP_UNASSIGNED; break; } /* end switch(mssf_command) */ /* Mark page changed */ STORAGE_KEY(spccb_absolute_addr, regs) |= STORKEY_CHANGE; /* Set service signal external interrupt pending */ sysblk.servparm &= ~SERVSIG_ADDR; sysblk.servparm |= spccb_absolute_addr; ON_IC_SERVSIG; /* Release the interrupt lock */ RELEASE_INTLOCK(regs); /* Return condition code 0: Command initiated */ return 0; } /* end function mssf_call */ #endif /* FEATURE_MSSF_CALL */ /*-------------------------------------------------------------------*/ /* Process LPAR DIAG 204 call */ /*-------------------------------------------------------------------*/ void ARCH_DEP(diag204_call) (int r1, int r2, REGS *regs) { DIAG204_HDR *hdrinfo; /* Header */ DIAG204_PART *partinfo; /* Partition info */ DIAG204_PART_CPU *cpuinfo; /* CPU info */ #if defined(FEATURE_EXTENDED_DIAG204) DIAG204_X_HDR *hdrxinfo; /* Header */ DIAG204_X_PART *partxinfo; /* Partition info */ DIAG204_X_PART_CPU *cpuxinfo; /* CPU info */ U64 tdis; #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ RADR abs; /* abs addr of data area */ U64 dreg; /* work doubleword */ int i; /* loop counter */ struct rusage usage; /* RMF type data */ static U64 diag204tod; /* last diag204 tod */ #if defined(FEATURE_PHYSICAL_DIAG204) static BYTE physical[8] = {0xD7,0xC8,0xE8,0xE2,0xC9,0xC3,0xC1,0xD3}; /* PHYSICAL */ #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ /* Test DIAG204 command word */ switch (regs->GR_L(r2)) { case 0x04: abs = APPLY_PREFIXING (GR_A(r1,regs), regs->PX); /* Program check if RMF data is not on a page boundary */ if ( (abs & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if RMF data area is outside main storage */ if ( abs > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Point to DIAG 204 data area */ hdrinfo = (DIAG204_HDR*)(regs->mainstor + abs); /* Mark page referenced */ STORAGE_KEY(abs, regs) |= STORKEY_REF | STORKEY_CHANGE; /* save last diag204 tod */ dreg = diag204tod; /* Retrieve the TOD clock value and shift out the epoch */ diag204tod = tod_clock(regs) << 8; memset(hdrinfo, 0, sizeof(DIAG204_HDR)); hdrinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrinfo->flags = DIAG204_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrinfo->physcpu,sysblk.cpus); STORE_HW(hdrinfo->offown,sizeof(DIAG204_HDR)); STORE_DW(hdrinfo->diagstck,dreg); /* hercules partition */ partinfo = (DIAG204_PART*)(hdrinfo + 1); memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = 1; /* Hercules partition */ partinfo->virtcpu = sysblk.cpus; get_lparname(partinfo->partname); /* hercules cpu's */ getrusage(RUSAGE_SELF,&usage); cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index=sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); dreg = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->totdispatch,dreg); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->effdispatch,dreg); cpuinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* lpar management */ getrusage(RUSAGE_CHILDREN,&usage); partinfo = (DIAG204_PART*)cpuinfo; memset(partinfo, 0, sizeof(DIAG204_PART)); partinfo->partnum = 0; /* Physical machine */ partinfo->virtcpu = sysblk.cpus; memcpy(partinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ getrusage(RUSAGE_SELF,&usage); cpuinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i)) { memset(cpuinfo, 0, sizeof(DIAG204_PART_CPU)); STORE_HW(cpuinfo->cpaddr,sysblk.regs[i]->cpuad); cpuinfo->index = sysblk.ptyp[i]; STORE_HW(cpuinfo->weight,100); dreg = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->totdispatch,dreg); dreg = (U64)(usage.ru_utime.tv_sec) * 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuinfo->effdispatch,dreg); cpuinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #if defined(FEATURE_EXTENDED_DIAG204) /* Extended subcode 5 returns the size of the data areas provided by extended subcodes 6 and 7 */ case 0x00010005: i = sizeof(DIAG204_X_HDR) + ((sizeof(DIAG204_X_PART) + (MAX_CPU * sizeof(DIAG204_X_PART_CPU))) * 2); regs->GR_L(r2+1) = (i + PAGEFRAME_BYTEMASK) / PAGEFRAME_PAGESIZE; regs->GR_L(r2) = 0; break; /* Provide extended information */ case 0x00010006: /* We fall through as we do not have any secondary cpus (that we know of) */ /* Provide extended information, including information about secondary CPUs */ case 0x00010007: /* Program check if RMF data is not on a page boundary */ if ( (regs->GR_L(r1) & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Obtain absolute address of main storage block, check protection, and set reference and change bits */ hdrxinfo = (DIAG204_X_HDR*)MADDR (GR_A(r1,regs), r1, regs, ACCTYPE_WRITE, regs->psw.pkey); /* save last diag204 tod */ dreg = diag204tod; /* Retrieve the TOD clock value and shift out the epoch */ diag204tod = tod_clock(regs) << 8; memset(hdrxinfo, 0, sizeof(DIAG204_X_HDR)); hdrxinfo->numpart = 1; #if defined(FEATURE_PHYSICAL_DIAG204) hdrxinfo->flags = DIAG204_X_PHYSICAL_PRESENT; #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ STORE_HW(hdrxinfo->physcpu,sysblk.cpus); STORE_HW(hdrxinfo->offown,sizeof(DIAG204_X_HDR)); STORE_DW(hdrxinfo->diagstck1,(dreg >> 8)); STORE_DW(hdrxinfo->diagstck2,( 0x0000000001000000ULL | (regs->cpuad << 16) | regs->todpr)); /* hercules partition */ partxinfo = (DIAG204_X_PART*)(hdrxinfo + 1); memset(partxinfo, 0, sizeof(DIAG204_PART)); partxinfo->partnum = 1; /* Hercules partition */ partxinfo->virtcpu = sysblk.cpus; partxinfo->realcpu = hostinfo.num_procs; get_lparname(partxinfo->partname); get_sysname(partxinfo->cpcname); get_systype(partxinfo->osname); STORE_DW(partxinfo->cssize,sysblk.mainsize); STORE_DW(partxinfo->essize,sysblk.xpndsize); get_sysplex(partxinfo->gr_name); /* hercules cpu's */ getrusage(RUSAGE_SELF,&usage); cpuxinfo = (DIAG204_X_PART_CPU*)(partxinfo + 1); for(i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); tdis = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; tdis = (tdis + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; tdis <<= 12; STORE_DW(cpuxinfo->totdispatch,tdis); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuxinfo->effdispatch,dreg); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, diag204tod - sysblk.todstart); STORE_DW(cpuxinfo->waittime, (diag204tod - sysblk.todstart) - tdis); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #if defined(FEATURE_PHYSICAL_DIAG204) /* lpar management */ partxinfo = (DIAG204_X_PART*)cpuxinfo; memset(partxinfo, 0, sizeof(DIAG204_X_PART)); partxinfo->partnum = 0; /* Physical machine */ partxinfo->virtcpu = sysblk.cpus; partxinfo->realcpu = hostinfo.num_procs; memcpy(partxinfo->partname,physical,sizeof(physical)); /* report all emulated physical cpu's */ getrusage(RUSAGE_CHILDREN,&usage); cpuxinfo = (DIAG204_PART_CPU*)(partinfo + 1); for(i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i)) { memset(cpuxinfo, 0, sizeof(DIAG204_X_PART_CPU)); STORE_HW(cpuxinfo->cpaddr,sysblk.regs[i]->cpuad); cpuxinfo->index = sysblk.ptyp[i]; STORE_HW(cpuxinfo->weight,100); tdis = (U64)(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000; tdis = (tdis + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec)) / sysblk.cpus; tdis <<= 12; STORE_DW(cpuxinfo->totdispatch,tdis); dreg = (U64)(usage.ru_utime.tv_sec)* 1000000; dreg = (dreg + (usage.ru_utime.tv_usec)) / sysblk.cpus; dreg <<= 12; STORE_DW(cpuxinfo->effdispatch,dreg); STORE_HW(cpuxinfo->minweight,1000); STORE_HW(cpuxinfo->curweight,1000); STORE_HW(cpuxinfo->maxweight,1000); STORE_DW(cpuxinfo->onlinetime, diag204tod - sysblk.todstart); STORE_DW(cpuxinfo->waittime, (diag204tod - sysblk.todstart) - tdis); STORE_HW(cpuxinfo->pmaweight,1000); STORE_HW(cpuxinfo->polarweight,1000); cpuxinfo += 1; } #endif /*defined(FEATURE_PHYSICAL_DIAG204)*/ regs->GR_L(r2) = 0; break; #endif /*defined(FEATURE_EXTENDED_DIAG204)*/ default: PTT(PTT_CL_ERR,"*DIAG204",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->GR_L(r2) = 4; } /*switch(regs->GR_L(r2))*/ } /* end function diag204_call */ /*-------------------------------------------------------------------*/ /* Process LPAR DIAG 224 call */ /*-------------------------------------------------------------------*/ void ARCH_DEP(diag224_call) (int r1, int r2, REGS *regs) { RADR abs; /* abs addr of data area */ BYTE *p; /* pointer to the data area */ unsigned int i; /* loop index */ //FIXME : this is probably incomplete. // see linux/arch/s390/hypfs/hypfs_diag.c UNREFERENCED(r1); abs = APPLY_PREFIXING (regs->GR_L(r2), regs->PX); /* Program check if data area is not on a page boundary */ if ( (abs & PAGEFRAME_BYTEMASK) != 0x000) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if data area is outside main storage */ if ( abs > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Point to DIAG 224 data area */ p = regs->mainstor + abs; /* Mark page referenced */ STORAGE_KEY(abs, regs) |= STORKEY_REF | STORKEY_CHANGE; /* First byte contains the number of entries - 1 */ *p = 5; /* Clear the next 15 bytes */ memset (p + 1, 0, 15); /* Set the 6 possible entries */ p += 16; memcpy(p,diag224_cputable,sizeof(diag224_cputable)-1); /* Convert to EBCDIC */ for (i = 0; i < sizeof(diag224_cputable); i++) p[i] = host_to_guest(p[i]); } /* end function diag224_call */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "diagmssf.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "diagmssf.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/vm.c0000664000175000017500000017212712564723224011003 00000000000000/* VM.C (c) Copyright Roger Bowler, 2000-2009 */ /* ESA/390 VM Diagnose calls and IUCV instruction */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements miscellaneous diagnose functions */ /* described in SC24-5670 VM/ESA CP Programming Services */ /* and SC24-5855 VM/ESA CP Diagnosis Reference */ /* and SC24-6084 z/VM 5.4 CP Programming Services. */ /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif /*_HENGINE_DLL_*/ #if !defined(_VM_C_) #define _VM_C_ #endif /* _VM_C_ */ #include "hercules.h" #include "opcode.h" #include "inline.h" #include "commadpt.h" #if defined(FEATURE_EMULATE_VM) #if !defined(_VM_C) #define _VM_C /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ #define DEV024(_type,_cls,_typ) \ { _type,_cls,_typ,0xC0 } #define DEV210(_type,_cls,_typ) \ { _type,_cls,_typ,0x40 } /*-------------------------------------------------------------------*/ /* Synchronous Block I/O Parameter List */ /*-------------------------------------------------------------------*/ typedef struct _HCPSBIOP { HWORD devnum; /* Device number */ BYTE akey; /* Bits 0-3=key, 4-7=zeroes */ BYTE type; /* I/O request type */ FWORD blksize; /* Fixed block size */ FWORD sbiaddr; /* Address of SBILIST */ FWORD sbicount; /* Number of SBILIST entries */ FWORD blkcount; /* Number of blocks processed*/ BYTE unitstat; /* Device status */ BYTE chanstat; /* Subchannel status */ HWORD residual; /* Residual byte count */ BYTE lpm; /* Logical path mask */ BYTE resv1[5]; /* Reserved bytes, must be 0 */ HWORD sensecount; /* Number of sense bytes */ BYTE resv2[24]; /* Reserved bytes, must be 0 */ BYTE sense[32]; /* Sense bytes */ } HCPSBIOP; /* Definitions for I/O request type */ #define HCPSBIOP_WRITE 0x01 #define HCPSBIOP_READ 0x02 /*-------------------------------------------------------------------*/ /* Synchronous General I/O Parameter List */ /*-------------------------------------------------------------------*/ typedef struct _HCPSGIOP { HWORD devnum; /* Device number */ BYTE akey; /* Bits 0-3=key, 4-7=zeroes */ BYTE flag; /* Flags */ FWORD resv1; /* Reserved word, must be 0 */ FWORD ccwaddr; /* Address of channel program*/ FWORD resv2; /* Reserved word, must be 0 */ FWORD lastccw; /* CCW address at interrupt */ BYTE unitstat; /* Device status */ BYTE chanstat; /* Subchannel status */ HWORD residual; /* Residual byte count */ BYTE lpm; /* Logical path mask */ BYTE resv3[5]; /* Reserved bytes, must be 0 */ HWORD sensecount; /* Number of sense bytes */ BYTE resv4[24]; /* Reserved bytes, must be 0 */ BYTE sense[32]; /* Sense bytes */ } HCPSGIOP; /* Bit definitions for flags */ #define HCPSGIOP_FORMAT1_CCW 0x80 /* 1=Format-1 CCW */ #define HCPSGIOP_FLAG_RESV 0x7F /* Reserved bits, must be 0 */ /*-------------------------------------------------------------------*/ /* DIAGNOSE X'24' and DIAGNOSE X'210' Structures and Table */ /*-------------------------------------------------------------------*/ /* VM Device Class Definitions */ #define DC_TERM 0x80 #define DC_GRAF 0x40 #define DC_URI 0x20 #define DC_URO 0x10 #define DC_TAPE 0x08 #define DC_DASD 0x04 #define DC_SPEC 0x02 #define DC_FBA 0x01 /* VM Device Type Definitions */ #define DT_CTCA 0x80 #define DT_FBA 0x00 #define DT_OSA 0x20 /* Not yet supported */ #define DT_UNKN 0x01 #define DT_0671 0x20 #define DT_1052 0x00 #define DT_1403 0x41 #define DT_1442 0x88 #define DT_2305 0x02 #define DT_2311 0x80 #define DT_2314 0x40 #define DT_2501 0x81 #define DT_2703 0x40 #define DT_3211 0x42 #define DT_3215 0x00 #define DT_3277 0x04 #define DT_3287 0x02 #define DT_3310 0x01 #define DT_3330 0x10 #define DT_3340 0x01 #define DT_3350 0x08 #define DT_3370 0x02 #define DT_3375 0x04 #define DT_3380 0x20 #define DT_3390 0x82 #define DT_3410 0x08 #define DT_3420 0x10 #define DT_3422 0x82 #define DT_3430 0x02 #define DT_3480 0x01 #define DT_3490 0x81 #define DT_3505 0x84 #define DT_3525 0x84 #define DT_3590 0x83 #define DT_370x 0x40 #define DT_8809 0x04 #define DT_9332 0x08 #define DT_9335 0x04 #define DT_9336 0x40 #define DT_9345 0x81 #define DT_9347 0x84 /* VM Virtual Device Status Definitions */ #define DS_DED 0x01 /* Dedicated device */ #define DS_BUSY 0x20 /* Device is busy */ /* VM Virtual Device Flag Definitions */ #define DF_ENA 0x80 /* 270x line enabled */ #define DF_CONN 0x40 /* 270x line connected */ #define DF_RSRL 0x02 /* Reserve/Release supported */ #define DF_MIDAW 0x01 /* MIDAW's supported */ /* VM Real Device Features */ #define DRF_RPS 0x80 /* Device has RPS */ #define DRF_EXTSNS 0x40 /* Extended Sense */ #define DRF_CTCA 0x40 /* CTCA device */ #define DRF_35M 0x08 /* 3340 has 35M data module */ #define DRF_70M 0x04 /* 3340 has 70M data module */ #define DRF_RSRL 0x02 /* Reserve/Release valid */ /*-------------------------------------------------------------------*/ /* Hercules-to-VM Device Table */ /*-------------------------------------------------------------------*/ typedef struct _VMDEVTBL { U16 vmhtype; /* Hercules device type */ BYTE vmdevcls; /* VM Device Class */ BYTE vmdevtyp; /* VM Device Type */ BYTE vmdiags; /* DIAGS recognizing device */ #define VMDIAG024 0x80 /* Device recognized by DIAGNOSE X'24' */ #define VMDIAG210 0x40 /* Device recognized by DIAGNOSE X'210' */ } VMDEVTBL; #define VMDEV_SIZE sizeof(VMDEVTBL) static VMDEVTBL vmdev[] = { DEV024(0x0671,DC_FBA, DT_0671), DEV024(0x1052,DC_TERM,DT_1052), DEV024(0x1403,DC_URO, DT_1403), DEV024(0x1442,DC_URI, DT_1442), DEV024(0x2305,DC_DASD,DT_2305), DEV024(0x2311,DC_DASD,DT_2311), DEV024(0x2314,DC_DASD,DT_2314), DEV024(0x2501,DC_URI, DT_2501), DEV024(0x2703,DC_TERM,DT_2703), DEV024(0x3088,DC_SPEC,DT_CTCA), DEV024(0x3211,DC_URI, DT_3211), DEV024(0x3215,DC_TERM,DT_3215), DEV024(0x3270,DC_GRAF,DT_3277), DEV024(0x3287,DC_GRAF,DT_3287), DEV024(0x3310,DC_FBA, DT_3310), DEV024(0x3330,DC_DASD,DT_3330), DEV024(0x3340,DC_DASD,DT_3340), DEV024(0x3350,DC_DASD,DT_3350), DEV024(0x3370,DC_FBA, DT_3370), DEV024(0x3375,DC_DASD,DT_3375), DEV024(0x3380,DC_DASD,DT_3380), DEV210(0x3390,DC_DASD,DT_3390), DEV024(0x3410,DC_TAPE,DT_3410), DEV024(0x3420,DC_TAPE,DT_3420), DEV024(0x3422,DC_TAPE,DT_3422), DEV024(0x3430,DC_TAPE,DT_3430), DEV024(0x3480,DC_TAPE,DT_3480), DEV210(0x3490,DC_TAPE,DT_3490), DEV024(0x3505,DC_URI, DT_3505), DEV024(0x3525,DC_URO, DT_3525), DEV024(0x3590,DC_TAPE,DT_3590), DEV024(0x3705,DC_SPEC,DT_370x), DEV024(0x8809,DC_TAPE,DT_8809), DEV024(0x9332,DC_FBA, DT_9332), DEV024(0x9335,DC_FBA, DT_9335), DEV024(0x9336,DC_FBA, DT_9336), DEV210(0x9345,DC_DASD,DT_9345), DEV024(0x9347,DC_TAPE,DT_9347) }; #define VMDEV_NUM (sizeof(vmdev)/VMDEV_SIZE) /*-------------------------------------------------------------------*/ /* Virtual Device Data */ /*-------------------------------------------------------------------*/ typedef struct _VRDCVDAT { BYTE vdevcls; /* Virtual device class */ BYTE vdevtyp; /* Virtual device type */ BYTE vdevstat; /* Virtual device status */ BYTE vdevflag; /* Virtual device flag */ } VRDCVDAT; /*-------------------------------------------------------------------*/ /* Real Device Data */ /*-------------------------------------------------------------------*/ typedef struct _VRDCRCDT { BYTE rdevcls; /* Real device class */ BYTE rdevtyp; /* Real device type */ BYTE rdevmodl; /* Real device model */ BYTE rdevfeat; /* Real device features */ } VRDCRCDT; /*-------------------------------------------------------------------*/ /* Virtual/Real Device Characteristics Block */ /*-------------------------------------------------------------------*/ typedef struct _VRDCBLOK { /*00*/ HWORD vrdcdvno; /* Device number */ /*02*/ HWORD vrdclen; /* VRDCBLOK length */ /*04*/ VRDCVDAT vrdcvdat; /* Virtual device data */ /*08*/ VRDCRCDT vrdcrcdt; /* Real device data */ /*0C*/ BYTE vrdcundv; /* Real underlying device */ /*0D*/ BYTE vrdcrdaf; /* Real device additional features */ #define VRDCEMRD 0x02 /* No emulated real device */ /*0E*/ HWORD vrdcrsvd; /* Reserved - must be zeros */ /*10*/ BYTE vrdcrdc[64]; /* READ DEVICE CHARACTERISTICS data */ /*50*/ BYTE vrdcpgid[11]; /* Path Group Identifier */ /*5B*/ BYTE resv5[5]; /* reserved */ /*60*/ BYTE vrdcvers; /* version */ /*61*/ BYTE vrdcrsio[31]; /* reserved for Input/Output */ /*80*/ HWORD vrdcrdev; /* Real device number */ /*82*/ BYTE vrdcrsve[126]; /* reserverd */ /*100*/ } VRDCBLOK; #define VRDCBLOK_SIZE sizeof(VRDCBLOK) #endif /*!defined(_VM_C)*/ /*-------------------------------------------------------------------*/ /* Internal Function Prototypes */ /*-------------------------------------------------------------------*/ DEVBLK* ARCH_DEP(vmdevice_data)(int, U16, VRDCVDAT *, VRDCRCDT *); /*-------------------------------------------------------------------*/ /* Provide VM Virtual and Real Device Data based upon device number */ /*-------------------------------------------------------------------*/ DEVBLK* ARCH_DEP(vmdevice_data)(int code, U16 devnum, VRDCVDAT *vdat, VRDCRCDT *rdat) { U32 i; /* loop index */ VMDEVTBL *vmentry; /* -> VMDEVTBL entry found */ DEVBLK *dev; /* -> DEVBLK */ /* Clear vdat and rdat */ memset (vdat, 0x00, sizeof(*vdat)); memset (rdat, 0x00, sizeof(*rdat)); /* Locate the device block */ dev = find_device_by_devnum (0,devnum); /* Return 0 if device is not found */ if (!dev) return 0; /* Indicate the device is dedicated - all Hercules devices are */ vdat->vdevstat = DS_DED; /* Find the device in the VM table */ vmentry=NULL; for (i = 0; i < (int)VMDEV_NUM; i++) { #if 0 logmsg ("vmdevice_data: i=%i %4.4X %2.2X %2.2X %2.2X\n",i, vmdev[i].vmhtype,vmdev[i].vmdevcls,vmdev[i].vmdevtyp,vmdev[i].vmdiags); #endif if (dev->devtype == vmdev[i].vmhtype) { vmentry = &vmdev[i]; break; } } #if 0 logmsg ("FOUND: %4.4X %2.2X %2.2X %2.2X\n", vmentry->vmhtype,vmentry->vmdevcls,vmentry->vmdevtyp,vmentry->vmdiags); #endif /* If device is not in the table or it isn't recognized by DIAG X'24' */ if ( !vmentry || ( code==0x24 && !(vmentry->vmdiags & VMDIAG024 ) ) ) { /* Set the real and virtual data to an unsupported device */ vdat->vdevcls = DC_SPEC; vdat->vdevtyp = DT_UNKN; rdat->rdevcls = DC_SPEC; rdat->rdevtyp = DT_UNKN; return dev; } /* Set the virtual and real data to the device's VM class and type */ vdat->vdevcls = vmentry->vmdevcls; vdat->vdevtyp = vmentry->vmdevtyp; rdat->rdevcls = vmentry->vmdevcls; rdat->rdevtyp = vmentry->vmdevtyp; /* Indicate if the device is busy */ if ( (dev->busy && dev->ioactive == DEV_SYS_LOCAL) || dev->startpending ) vdat->vdevstat |= DS_BUSY; /* Set virtual device flags, and real device model and features */ vdat->vdevflag = 0x00; rdat->rdevmodl = 0x00; rdat->rdevfeat = 0x00; if (dev->hnd->reserve) /* Indicate if RESERVE/RELEASE supported */ vdat->vdevflag |= DF_RSRL; #if defined(FEATURE_MIDAW) /* If DIAGNOSE X'210', indicate if MIDAW's are supported */ if (code==0x210) vdat->vdevflag |= DF_MIDAW; #endif /* FEATURE_MIDAW */ switch (rdat->rdevcls) { case DC_DASD: if (dev->hnd->reserve) rdat->rdevfeat |= DRF_RSRL; if (dev->numsense==24) rdat->rdevfeat |= DRF_EXTSNS; if (dev->ckdtab->sectors) rdat->rdevfeat |= DRF_RPS; if (dev->devtype == 0x3340) { if (dev->ckdtab->model==0x01) rdat->rdevfeat |= DRF_35M; else rdat->rdevfeat |= DRF_70M; } if ( dev->devtype == 0x3380 && code == 0x24) rdat->rdevmodl = (dev->ckdtab->model & 0x0F) | (dev->ckdcu->model & 0xF0); else rdat->rdevmodl = dev->ckdtab->model; break; case DC_FBA: rdat->rdevmodl = dev->fbatab->model; break; case DC_TERM: if (dev->devtype==0x3215) { rdat->rdevfeat = 0x50; /* Note: 0x50 is carried forward from the previous version of */ /* DIAGNOSE X'24'. The actual meaning was not previously documented */ } else { if (dev->devtype==0x2703 && dev->commadpt) { if (dev->commadpt->enabled) vdat->vdevflag |= DF_ENA; if (dev->commadpt->connect) vdat->vdevflag |= DF_CONN; } } break; case DC_SPEC: if (rdat->rdevtyp==DT_CTCA) rdat->rdevfeat = DRF_CTCA; } /* Return the located DEVBLK to the caller */ return dev; } /* end function vmdevice_data */ /*-------------------------------------------------------------------*/ /* Device Type and Features (Function code 0x024) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(diag_devtype) (int r1, int r2, REGS *regs) { DEVBLK *dev; /* -> Device block */ U16 devnum; /* Device number */ VRDCVDAT vdat; /* Virtual device data */ VRDCRCDT rdat; /* Real device data */ #if defined(FEATURE_ESAME) /* Program check if 64-bit addressing is being used. */ if (regs->psw.amode64) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } #endif /* FEATURE_ESAME */ /* Return console information if R1 register is all ones */ if (regs->GR_L(r1) == 0xFFFFFFFF) { for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if ( dev->allocated && ( dev->devtype == 0x3215 || dev->devtype == 0x1503 ) ) { regs->GR_L(r1) = dev->devnum; break; } } /* Extract the device number from the R1 register */ devnum = regs->GR_L(r1); /* Locate the device block and set the virtual and real device information */ dev = ARCH_DEP(vmdevice_data) (0x24,devnum,&vdat,&rdat); /* Return condition code 3 if device does not exist */ if (!dev) return 3; /* Return virtual device information in the R2 register */ FETCH_FW(regs->GR_L(r2),&vdat); /* Return real device information in the R2+1 register */ if (r2 != 15) FETCH_FW(regs->GR_L(r2+1),&rdat); #if 0 logmsg ("Diagnose X\'024\':" "devnum=%4.4X VRDCVDAT=%8.8X VRDCRCDT=%8.8X\n", devnum, vdat, rdat); #endif /* Return condition code 0 */ return 0; } /* end function diag_devtype */ /*-------------------------------------------------------------------*/ /* Process Synchronous Fixed Block I/O call (Function code 0x0A4) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(syncblk_io) (int r1, int r2, REGS *regs) { U32 i; /* Array subscript */ U32 numsense; /* Number of sense bytes */ U32 iopaddr; /* Address of HCPSBIOP */ HCPSBIOP ioparm; /* I/O parameter list */ DEVBLK *dev; /* -> Device block */ U16 devnum; /* Device number */ U16 residual; /* Residual byte count */ U32 blksize; /* Fixed block size */ U32 sbiaddr; /* Addr of SBILIST */ U32 sbicount; /* Number of SBILIST entries */ U32 blkcount; /* Number of blocks processed*/ U32 blknum; /* Block number */ U32 absadr; /* Absolute storage address */ BYTE accum; /* Work area */ BYTE unitstat = 0; /* Device status */ BYTE chanstat = 0; /* Subchannel status */ BYTE skey1, skey2; /* Storage keys of first and last byte of I/O buffer */ //FIXME: code not right for shared devices UNREFERENCED(r2); /* Register R1 contains the real address of the parameter list */ iopaddr = regs->GR_L(r1); /* Program check if parameter list not on fullword boundary */ if (iopaddr & 0x00000003) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return 0; } /* Ensure that parameter list operand is addressable */ ARCH_DEP(validate_operand) (iopaddr, USE_REAL_ADDR, sizeof(ioparm)-1, ACCTYPE_WRITE, regs); /* Fetch the parameter list from real storage */ ARCH_DEP(vfetchc) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs); /* Load numeric fields from the parameter list */ devnum = (ioparm.devnum[0] << 8) | ioparm.devnum[1]; blksize = (ioparm.blksize[0] << 24) | (ioparm.blksize[1] << 16) | (ioparm.blksize[2] << 8) | ioparm.blksize[3]; sbiaddr = (ioparm.sbiaddr[0] << 24) | (ioparm.sbiaddr[1] << 16) | (ioparm.sbiaddr[2] << 8) | ioparm.sbiaddr[3]; sbicount = (ioparm.sbicount[0] << 24) | (ioparm.sbicount[1] << 16) | (ioparm.sbicount[2] << 8) | ioparm.sbicount[3]; /* Locate the device block */ dev = find_device_by_devnum (0,devnum); /* Set return code 2 and cond code 1 if device does not exist or does not support the synchronous I/O call */ if (dev == NULL || dev->devtype != 0x3370) { regs->GR_L(15) = 2; return 1; } /* Program check if protect key bits 4-7 are not zero or if I/O request type is not read or write */ if ((ioparm.akey & 0x0F) || !(ioparm.type == HCPSBIOP_WRITE || ioparm.type == HCPSBIOP_READ)) { ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); return 0; } /* Set return code 8 and cond code 2 if blocksize is invalid */ if (!(blksize == 512 || blksize == 1024 || blksize == 2048 || blksize == 4096)) { regs->GR_L(15) = 8; return 2; } /* Program check if SBILIST is not on a doubleword boundary */ if (sbiaddr & 0x00000007) { ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); return 0; } /* Program check if reserved fields are not zero */ for (accum = 0, i = 0; i < sizeof(ioparm.resv1); i++) accum |= ioparm.resv1[i]; for (i = 0; i < sizeof(ioparm.resv2); i++) accum |= ioparm.resv2[i]; if (accum != 0) { ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); return 0; } /* Set return code 11 and cond code 2 if SBI count is invalid */ if (sbicount < 1 || sbicount > 500) { regs->GR_L(15) = 11; return 2; } /* Obtain the device lock */ obtain_lock (&dev->lock); #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Return code 5 and condition code 1 if status pending */ if ((dev->scsw.flag3 & SCSW3_SC_PEND) || (dev->pciscsw.flag3 & SCSW3_SC_PEND)) { release_lock (&dev->lock); regs->GR_L(15) = 5; return 1; } #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Return code 5 and condition code 1 if device is busy */ if (dev->busy || IOPENDING(dev)) { release_lock (&dev->lock); regs->GR_L(15) = 5; return 1; } /* Set the device busy indicator */ dev->busy = 1; /* Release the device lock */ release_lock (&dev->lock); /* Process each entry in the SBILIST */ for (blkcount = 0; blkcount < sbicount; blkcount++) { /* Return code 10 and cond code 2 if SBILIST entry is outside main storage or is fetch protected. Note that the SBI address is an absolute address and is not subject to fetch-protection override or storage-protection override mechanisms, and an SBILIST entry cannot cross a page boundary */ if (sbiaddr > regs->mainlim || ((STORAGE_KEY(sbiaddr, regs) & STORKEY_FETCH) && (STORAGE_KEY(sbiaddr, regs) & STORKEY_KEY) != ioparm.akey && ioparm.akey != 0)) { regs->GR_L(15) = 10; return 2; } /* Load block number and data address from SBILIST */ blknum = ARCH_DEP(fetch_fullword_absolute)(sbiaddr, regs); absadr = ARCH_DEP(fetch_fullword_absolute)(sbiaddr+4, regs); if (dev->ccwtrace || dev->ccwstep) { logmsg ("%4.4X:Diagnose X\'0A4\':%s " "blk=%8.8X adr=%8.8X len=%8.8X\n", dev->devnum, (ioparm.type == HCPSBIOP_WRITE ? "WRITE" : "READ"), blknum, absadr, blksize); } /* Return code 12 and cond code 2 if buffer exceeds storage */ if (absadr > regs->mainlim - blksize) { regs->GR_L(15) = 12; return 2; } /* Channel protection check if access key does not match storage keys of buffer. Note that the buffer address is an absolute address, the buffer cannot span more than two pages, and the access is not subject to fetch-protection override, storage-protection override, or low-address protection */ skey1 = STORAGE_KEY(absadr, regs); skey2 = STORAGE_KEY(absadr + blksize - 1, regs); if (ioparm.akey != 0 && ( ((skey1 & STORKEY_KEY) != ioparm.akey && ((skey1 & STORKEY_FETCH) || ioparm.type == HCPSBIOP_READ)) || ((skey2 & STORKEY_KEY) != ioparm.akey && ((skey2 & STORKEY_FETCH) || ioparm.type == HCPSBIOP_READ)) )) { chanstat |= CSW_PROTC; break; } /* Call device handler to read or write one block */ fbadasd_syncblk_io (dev, ioparm.type, blknum, blksize, regs->mainstor + absadr, &unitstat, &residual); /* Set incorrect length if residual count is non-zero */ if (residual != 0) chanstat |= CSW_IL; /* Exit if any unusual status */ if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) break; /* Point to next SBILIST entry */ sbiaddr += 8; } /* end for(blkcount) */ /* Reset the device busy indicator */ dev->busy = 0; /* Store the block count in the parameter list */ ioparm.blkcount[0] = (blkcount >> 24) & 0xFF; ioparm.blkcount[1] = (blkcount >> 16) & 0xFF; ioparm.blkcount[2] = (blkcount >> 8) & 0xFF; ioparm.blkcount[3] = blkcount & 0xFF; /* Store the device and subchannel status in the parameter list */ ioparm.unitstat = unitstat; ioparm.chanstat = chanstat; /* Store the residual byte count in the parameter list */ ioparm.residual[0] = (residual >> 8) & 0xFF; ioparm.residual[1] = residual & 0xFF; /* Return sense data if unit check occurred */ if (unitstat & CSW_UC) { numsense = dev->numsense; if (numsense > sizeof(ioparm.sense)) numsense = sizeof(ioparm.sense); ioparm.sensecount[0] = (numsense >> 8) & 0xFF; ioparm.sensecount[1] = numsense & 0xFF; memcpy (ioparm.sense, dev->sense, numsense); } /* Store the updated parameter list in real storage */ ARCH_DEP(vstorec) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs); /* If I/O error occurred, set return code 13 and cond code 3 */ if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) { regs->GR_L(15) = 13; return 3; } /* Set return code 0 and cond code 0 */ regs->GR_L(15) = 0; return 0; } /* end function syncblk_io */ /*-------------------------------------------------------------------*/ /* Process Synchronous General I/O call (Function code 0x0A8) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(syncgen_io) (int r1, int r2, REGS *regs) { U32 i; /* Array subscript */ U32 numsense; /* Number of sense bytes */ U32 iopaddr; /* Address of HCPSGIOP */ HCPSGIOP ioparm; /* I/O parameter list */ DEVBLK *dev; /* -> Device block */ U16 devnum; /* Device number */ U16 residual; /* Residual byte count */ U32 ccwaddr; /* Address of channel program*/ U32 lastccw; /* CCW address at interrupt */ BYTE accum; /* Work area */ BYTE unitstat = 0; /* Device status */ BYTE chanstat = 0; /* Subchannel status */ //FIXME: code not right for shared devices UNREFERENCED(r2); /* Register R1 contains the real address of the parameter list */ iopaddr = regs->GR_L(r1); /* Program check if parameter list not on fullword boundary */ if (iopaddr & 0x00000003) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return 0; } /* Ensure that parameter list operand is addressable */ ARCH_DEP(validate_operand) (iopaddr, USE_REAL_ADDR, sizeof(ioparm)-1, ACCTYPE_WRITE, regs); /* Fetch the parameter list from real storage */ ARCH_DEP(vfetchc) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs); /* Load numeric fields from the parameter list */ devnum = (ioparm.devnum[0] << 8) | ioparm.devnum[1]; ccwaddr = (ioparm.ccwaddr[0] << 24) | (ioparm.ccwaddr[1] << 16) | (ioparm.ccwaddr[2] << 8) | ioparm.ccwaddr[3]; /* Locate the device block */ dev = find_device_by_devnum (0,devnum); /* Set return code 1 and cond code 1 if device does not exist */ if (dev == NULL) { regs->GR_L(15) = 1; return 1; } /* Program check if protect key bits 4-7 are not zero or if the reserved bits in the flag byte are not zero */ if ((ioparm.akey & 0x0F) || (ioparm.flag & HCPSGIOP_FLAG_RESV)) { ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); return 0; } #ifdef FEATURE_S370_CHANNEL /* Program check if flag byte specifies format-1 CCW */ if (ioparm.flag & HCPSGIOP_FORMAT1_CCW) { ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); return 0; } #endif /*FEATURE_S370_CHANNEL*/ /* Program check if CCW is not on a doubleword boundary, or if CCW address exceeds maximum according to CCW format */ if ((ccwaddr & 0x00000007) || ccwaddr > ((ioparm.flag & HCPSGIOP_FORMAT1_CCW) ? (U32)0x7FFFFFFF : (U32)0x00FFFFFF)) { ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); return 0; } /* Program check if reserved fields are not zero */ for (accum = 0, i = 0; i < sizeof(ioparm.resv1); i++) accum |= ioparm.resv1[i]; for (i = 0; i < sizeof(ioparm.resv2); i++) accum |= ioparm.resv2[i]; for (i = 0; i < sizeof(ioparm.resv3); i++) accum |= ioparm.resv3[i]; for (i = 0; i < sizeof(ioparm.resv4); i++) accum |= ioparm.resv4[i]; if (accum != 0) { ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); return 0; } /* Obtain the interrupt lock */ obtain_lock (&dev->lock); #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Return code 5 and condition code 1 if status pending */ if ((dev->scsw.flag3 & SCSW3_SC_PEND) || (dev->pciscsw.flag3 & SCSW3_SC_PEND)) { release_lock (&dev->lock); regs->GR_L(15) = 5; return 1; } #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Return code 5 and condition code 1 if device is busy */ if (dev->busy || IOPENDING(dev)) { release_lock (&dev->lock); regs->GR_L(15) = 5; return 1; } /* Set the device busy indicator */ dev->busy = 1; /* Release the device lock */ release_lock (&dev->lock); /* Build the operation request block */ /*@IWZ*/ memset (&dev->orb, 0, sizeof(ORB)); /*@IWZ*/ STORE_FW(dev->orb.ccwaddr, ccwaddr); /*@IWZ*/ dev->orb.flag4 = ioparm.akey & ORB4_KEY; /*@IWZ*/ if (ioparm.flag & HCPSGIOP_FORMAT1_CCW) /*@IWZ*/ dev->orb.flag5 |= ORB5_F; /*@IWZ*/ /* Execute the channel program synchronously */ ARCH_DEP(execute_ccw_chain) (dev); /* Obtain status, CCW address, and residual byte count */ #ifdef FEATURE_S370_CHANNEL lastccw = (dev->csw[1] << 16) || (dev->csw[2] << 8) || dev->csw[3]; unitstat = dev->csw[4]; chanstat = dev->csw[5]; residual = (dev->csw[6] << 8) || dev->csw[7]; #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM lastccw = (dev->scsw.ccwaddr[0] << 24) || (dev->scsw.ccwaddr[1] << 16) || (dev->scsw.ccwaddr[2] << 8) || dev->scsw.ccwaddr[3]; unitstat = dev->scsw.unitstat; chanstat = dev->scsw.chanstat; residual = (dev->scsw.count[0] << 8) || dev->scsw.count[1]; #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Clear the interrupt pending and device busy conditions */ obtain_lock (&dev->lock); dev->busy = dev->pending = 0; dev->scsw.flag2 = 0; dev->scsw.flag3 = 0; release_lock (&dev->lock); /* Store the last CCW address in the parameter list */ ioparm.lastccw[0] = (lastccw >> 24) & 0xFF; ioparm.lastccw[1] = (lastccw >> 16) & 0xFF; ioparm.lastccw[2] = (lastccw >> 8) & 0xFF; ioparm.lastccw[3] = lastccw & 0xFF; /* Store the device and subchannel status in the parameter list */ ioparm.unitstat = unitstat; ioparm.chanstat = chanstat; /* Store the residual byte count in the parameter list */ ioparm.residual[0] = (residual >> 8) & 0xFF; ioparm.residual[1] = residual & 0xFF; /* Return sense data if unit check occurred */ if (unitstat & CSW_UC) { numsense = dev->numsense; if (numsense > sizeof(ioparm.sense)) numsense = sizeof(ioparm.sense); ioparm.sensecount[0] = (numsense >> 8) & 0xFF; ioparm.sensecount[1] = numsense & 0xFF; memcpy (ioparm.sense, dev->sense, numsense); } /* Store the updated parameter list in real storage */ ARCH_DEP(vstorec) (&ioparm, sizeof(ioparm)-1, iopaddr, USE_REAL_ADDR, regs); /* If I/O error occurred, set return code 13 and cond code 3 */ if (unitstat != (CSW_CE | CSW_DE) || chanstat != 0) { regs->GR_L(15) = 13; return 3; } /* Return with condition code 0 and register 15 unchanged */ return 0; } /* end function syncgen_io */ /*-------------------------------------------------------------------*/ /* Store Extended Identification Code (Function code 0x000) */ /*-------------------------------------------------------------------*/ void ARCH_DEP(extid_call) (int r1, int r2, REGS *regs) { int i; /* Array subscript */ int ver, rel; /* Version and release number*/ U32 idaddr; /* Address of storage operand*/ U32 idlen; /* Length of storage operand */ BYTE buf[40]; /* Extended identification */ #if defined( HAVE_GETLOGIN_R ) #if !defined(LOGIN_NAME_MAX) #define LOGIN_NAME_MAX 100 #endif char unam[LOGIN_NAME_MAX+1]; /* User name */ #endif char *puser; /* Pointer to user name */ BYTE c; /* Character work area */ /* Load storage operand address from R1 register */ idaddr = regs->GR_L(r1); /* Program check if operand is not on a doubleword boundary */ if (idaddr & 0x00000007) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return; } /* Load storage operand length from R2 register */ idlen = regs->GR_L(r2); /* Program check if operand length is invalid */ if (idlen < 1) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return; } /* Bytes 0-7 contain the system name ("HERCULES" in EBCDIC) */ get_lparname(buf); /* Bytes 8-9 contain the execution environment bits */ buf[8] = 0x00; buf[9] = 0x00; /* Byte 10 contains the system product version number */ sscanf (MSTRING(VERSION), "%d.%d", &ver, &rel); buf[10] = ver; /* Byte 11 contains version number from STIDP */ buf[11] = sysblk.cpuid >> 56; /* Bytes 12-13 contain MCEL length from STIDP */ buf[12] = (sysblk.cpuid >> 8) & 0xFF; buf[13] = sysblk.cpuid & 0xFF; /* Bytes 14-15 contain the CP address */ buf[14] = (regs->cpuad >> 8) & 0xFF; buf[15] = regs->cpuad & 0xFF; /* Bytes 16-23 contain the userid in EBCDIC */ #if defined( HAVE_GETLOGIN_R ) memset( unam, 0, sizeof(unam) ); VERIFY( getlogin_r ( unam, sizeof(unam) ) == 0 ); puser = unam; #else puser = ""; #endif for (i = 0; i < 8; i++) { c = (*puser == '\0' ? SPACE : *(puser++)); buf[16+i] = host_to_guest(toupper(c)); } /* Bytes 24-31 contain the program product bitmap */ memcpy (buf+24, "\x7F\xFE\x00\x00\x00\x00\x00\x00", 8); /* Bytes 32-35 contain the time zone differential */ memset (buf+32, '\0', 4); /* Bytes 36-39 contain version, level, and service level */ buf[36] = ver; buf[37] = rel; buf[38] = 0x00; buf[39] = 0x00; #if 0 logmsg ("Diagnose X\'000\':" "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t" "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t" "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31], buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39]); #endif /* Enforce maximum length to store */ if (idlen > sizeof(buf)) idlen = sizeof(buf); /* Store the extended identification code at operand address */ ARCH_DEP(vstorec) (buf, idlen-1, idaddr, USE_REAL_ADDR, regs); /* Deduct number of bytes from the R2 register */ regs->GR_L(r2) -= idlen; } /* end function extid_call */ /*-------------------------------------------------------------------*/ /* Process CP command (Function code 0x008) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(cpcmd_call) (int r1, int r2, REGS *regs) { U32 i; /* Array subscript */ U32 cc = 0; /* Condition code */ U32 cmdaddr; /* Address of command string */ U32 cmdlen; /* Length of command string */ U32 respadr; /* Address of response buffer*/ U32 maxrlen; /* Length of response buffer */ U32 resplen; /* Length of actual response */ BYTE cmdflags; /* Command flags */ #define CMDFLAGS_REJPASSW 0x80 /* Reject password in command*/ #define CMDFLAGS_RESPONSE 0x40 /* Return response in buffer */ #define CMDFLAGS_REQPASSW 0x20 /* Prompt for password */ #define CMDFLAGS_RESERVED 0x1F /* Reserved bits, must be 0 */ char bufi[256]; /* Command buffer (ASCIIZ) */ char bufo[257]; /* Command buffer (ASCIIZ) */ char resp[256]; /* Response buffer (ASCIIZ) */ char *dresp; /* Default response (ASCIIZ) */ int freeresp; /* Flag to free resp bfr */ U32 j,k; /* Obtain command address from R1 register */ cmdaddr = regs->GR_L(r1); /* Obtain command length and flags from R2 register */ cmdflags = regs->GR_L(r2) >> 24; cmdlen = regs->GR_L(r2) & 0x00FFFFFF; /* Program check if invalid flags, or if command string is too long, or if response buffer is specified and registers are consecutive or either register specifies register 15 */ if ((cmdflags & CMDFLAGS_RESERVED) || cmdlen > sizeof(bufi)-1 || ((cmdflags & CMDFLAGS_RESPONSE) && (r1 == 15 || r2 == 15 || r1 == r2 + 1 || r2 == r1 + 1))) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return 0; } /* Put machine into stopped state if command length is zero */ if (cmdlen == 0) { regs->opinterv = 0; regs->cpustate = CPUSTATE_STOPPED; ON_IC_INTERRUPT(regs); return 0; } /* Obtain the command string from storage */ ARCH_DEP(vfetchc) (bufi, cmdlen-1, cmdaddr, USE_REAL_ADDR, regs); /* Prepend '-' if noecho is requested */ i=0; if(!(sysblk.diag8cmd & DIAG8CMD_ECHO)) { bufo[0]='-'; i=1; } /* Translate EBCDIC command to ASCII */ for (j=0; j < cmdlen; i++,j++) { bufo[i] = guest_to_host(bufi[j]); } bufo[i] = '\0'; dresp=""; freeresp=0; if(*bufo) { #ifdef FEATURE_HERCULES_DIAGCALLS int shcmd = 0; { char* p = bufo; while (*p && isspace(*p)) p++; if ((*(p+0) == 's' || *(p+0) == 'S') && (*(p+1) == 'h' || *(p+1) == 'H') && isspace(*(p+2))) shcmd = 1; } if ((sysblk.diag8cmd & DIAG8CMD_ENABLE) && (!shcmd || !(sysblk.shcmdopt & (SHCMDOPT_DISABLE | SHCMDOPT_NODIAG8))) ) { if(sysblk.diag8cmd & DIAG8CMD_ECHO) logmsgp (_("HHCVM001I *%s* panel command issued by guest\n"), bufo); if (cmdflags & CMDFLAGS_RESPONSE) { dresp=log_capture(panel_command,bufo); if(dresp!=NULL) { freeresp=1; } else { dresp=""; } } else { panel_command(bufo); if(sysblk.diag8cmd & DIAG8CMD_ECHO) logmsgp (_("HHCVM002I *%s* command complete\n"), bufo); } } else { if(sysblk.diag8cmd & DIAG8CMD_ECHO) { logmsgp (_("HHCVM005W *%s* panel command issued by guest (but disabled)\n"), bufo); } dresp=_("HHCVM003I Host command processing disabled by configuration statement"); } #else dresp=_("HHCVM004E Host command processing not included in engine build"); #endif } /* Store the response and set length if response requested */ if (cmdflags & CMDFLAGS_RESPONSE) { if(!freeresp) { strlcpy (resp, dresp, sizeof(resp)); dresp=resp; } resplen = strlen(dresp); for (i = 0; i < resplen; i++) dresp[i] = host_to_guest(dresp[i]); respadr = regs->GR_L(r1+1); maxrlen = regs->GR_L(r2+1); i=(resplen<=maxrlen) ? resplen : maxrlen; j=0; while(i>0) { k=(i<255 ? i : 255); ARCH_DEP(vstorec) (&dresp[j], k-1 , respadr+j, USE_REAL_ADDR, regs); i-=k; j+=k; } regs->GR_L(r2+1) = (resplen<=maxrlen) ? resplen : resplen-maxrlen; cc = (resplen<=maxrlen) ? 0 : 1; } if(freeresp) { free(dresp); } /* Set R2 register to CP completion code */ regs->GR_L(r2) = 0; /* Return condition code */ return cc; } /* end function cpcmd_call */ /*-------------------------------------------------------------------*/ /* Access Re-IPL data (Function code 0x0B0) */ /*-------------------------------------------------------------------*/ void ARCH_DEP(access_reipl_data) (int r1, int r2, REGS *regs) { U32 bufadr; /* Real addr of data buffer */ U32 buflen; /* Length of data buffer */ /* Obtain buffer address and length from R1 and R2 registers */ bufadr = regs->GR_L(r1); buflen = regs->GR_L(r2); /* Program check if buffer length is negative */ if ((S32)buflen < 0) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return; } /* Store IPL information if buffer length is non-zero */ if (buflen > 0) { /* Store one byte of zero to indicate no IPL information */ ARCH_DEP(vstoreb) (0, bufadr, USE_REAL_ADDR, regs); } PTT(PTT_CL_ERR,"*DIAG0B0",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); /* Return code 4 means no re-IPL information available */ regs->GR_L(r2) = 4; } /* end function access_reipl_data */ /*-------------------------------------------------------------------*/ /* Access Device Information (Function code 0x210) */ /*-------------------------------------------------------------------*/ /* Note: This implementation emulates z/VM 5.4 */ int ARCH_DEP(device_info) (int r1, int r2, REGS *regs) { DEVBLK *dev; /* -> Device block */ VRDCBLOK vrdc; /* VRDCBLOK */ RADR blokaddr; /* Location of the VRDCBLOK */ U16 bloklen; /* Length from the VRDCBLOK */ #if 0 /* Only required if implementation is for the z/VM 5.3 level */ U16 reserved; /* Bytes 14 and 15 */ #endif U16 devnum; /* Device number from the VRDCBLOK */ UNREFERENCED(r2); if (regs->GR_L(r1) & 0x3 #if defined(FEATURE_ESAME) || (regs->psw.amode64) #endif /* FEATURE_ESAME */ ) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } blokaddr = regs->GR_L(r1); /* Fetch the first 4 bytes of the VRDCBLOK */ ARCH_DEP(vfetchc) (&vrdc, 3, blokaddr, USE_REAL_ADDR, regs); /* Get the VRDCBLOK length from the working VRDC */ FETCH_HW(bloklen,&vrdc.vrdclen); /* VRDCBLOK length must be at least 8 bytes */ if (bloklen<8) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Fetch remainder of supplied VRDCBLOK, but no more */ if (bloklen>VRDCBLOK_SIZE) bloklen=VRDCBLOK_SIZE; ARCH_DEP(vfetchc) (&vrdc.vrdcvdat,bloklen-5,blokaddr+4, USE_REAL_ADDR, regs); #if 0 /* If length is 16 or greater, bytes 14 and 15 must be zero on z/VM 5.3.0 or earlier */ if ( bloklen>=16) { FETCH_HW(reserved,&vrdc.vrdcrsvd); if (reserved != 0) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } } #endif /* Get the device number from the working VRDC */ FETCH_HW(devnum,&vrdc.vrdcdvno); /* Locate the device block and set the virtual and real device information */ dev = ARCH_DEP(vmdevice_data) (0x210,devnum,&vrdc.vrdcvdat,&vrdc.vrdcrcdt); /* Return condition code 3 if device does not exist */ if (!dev) { PTT(PTT_CL_ERR,"*DIAG210",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); return 3; } /* Set the underlying device and real device features */ vrdc.vrdcundv=0x00; vrdc.vrdcrdaf=0x00; /* Create device dependent mappings */ if (vrdc.vrdcvdat.vdevcls == DC_DASD) { memcpy(&vrdc.vrdcrdc,dev->devchar,42); switch (dev->devtype) { case 0x2311: case 0x2314: case 0x2305: case 0x3330: case 0x3340: case 0x3350: /* Set non-keyed overhead */ STORE_HW(&vrdc.vrdcrdc[0x18],dev->ckdtab->f2); /* Set keyed overhead */ STORE_HW(&vrdc.vrdcrdc[0x1A],dev->ckdtab->f1); /* Note: for all other DASD devices these fields contain bytes 24-27 of the RDC */ } /* Set Control Unit ID */ vrdc.vrdcrdc[0x2A]=dev->devchar[56]; } else if (vrdc.vrdcvdat.vdevcls == DC_FBA) memcpy(&vrdc.vrdcrdc,dev->devchar,32); /* Set Path Group ID */ memcpy(&vrdc.vrdcpgid,dev->pgid,11); /* Set version */ if (bloklen>0x60) vrdc.vrdcvers=0x01; /* Set underlying real device */ if (!(vrdc.vrdcrdaf & VRDCEMRD)) memcpy(&vrdc.vrdcrdev,&vrdc.vrdcdvno,2); /* Update the VRDC in main storage */ ARCH_DEP(vstorec) (&vrdc, bloklen-1, blokaddr, USE_REAL_ADDR, regs); /* Return condition code 0 for success */ return 0; } /* end function device_info */ /*-------------------------------------------------------------------*/ /* Access Certain Virtual Machine Information (Function code 0x260) */ /*-------------------------------------------------------------------*/ /* Note: This implementation emulates z/VM 5.4 */ void ARCH_DEP(vm_info) (int r1, int r2, REGS *regs) { DEVBLK *dev; /* -> Device block */ U16 devnum; /* Device number */ #if defined(FEATURE_ESAME) RADR stgarea; /* Storage extent area */ S64 stglen; /* Storage extent area length */ #endif /* FEATURE_ESAME */ /* Ry contains the subcode */ switch(regs->GR_L(r2)) { case 0x00000000: /* Highest addressable byte */ #if defined(FEATURE_ESAME) /* Program check if running in z/Architecture mode and */ /* 64-bit addressing is being used. */ if (regs->psw.amode64) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } #endif /* FEATURE_ESAME */ regs->GR_L(r1) = regs->mainlim; /* provide highest addressable byte */ return; case 0x00000004: /* Provide BYUSER ID value */ /* Program check if Rx and Ry are the same registers or */ /* or Ry is not an even register or the address provided */ /* in Rx is not on a doubleword boundary or if running */ /* in z/Architecture mode and 64-bit addressing is being used. */ if ( r1 == r2 || r2 & 0x1 || regs->GR_L(r1) & 0x7 #if defined(FEATURE_ESAME) || (regs->psw.amode64) #endif /* FEATURE_ESAME */ ) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } regs->GR_L(r2+1)=0x4; /* Indicate no BYUSER ID for Hercules */ return; case 0x00000008: /* Return number of lines per page */ #if defined(FEATURE_ESAME) /* Program check if running in z/Architecture mode and */ /* 64-bit addressing is being used. */ if (regs->psw.amode64) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } #endif /* FEATURE_ESAME */ /* Get the device number from the Rx register */ devnum=regs->GR_LHL(r1); /* Locate the device block */ dev = find_device_by_devnum(0,devnum); /* Set 0 lines per page for a valid printer or console (meaning SPOOL is OFF) */ if (dev != NULL && (dev->devtype == 0x1403 || dev->devtype == 0x3211 || dev->devtype == 0x1052 || dev->devtype == 0x3215 ) ) { regs->GR_L(r1) = 0; /* Set zero lines per page */ regs->GR_L(r2) = 0; /* Set return code to indicate a valid device */ } else { regs->GR_L(r2) = 4; /* Set return code to indicate an invalid device */ } return; #if defined(FEATURE_ESAME) case 0x0000000C: /* Return highest addressable byte for z/Architecture machine */ regs->GR_G(r1) = regs->mainlim; regs->GR_G(r2) = regs->mainlim; return; case 0x00000010: /* Set storage extent */ /* Obtain the storage extent area real address from Rx */ /* and its length from Rx+1 */ stgarea=regs->GR_G(r1); stglen=regs->GR_G(r1+1); /* Length is treated as a signed value */ /* Program check if Rx is not an even register or the address */ /* provided in Rx is not on a quadword boundary or the length */ /* provided in Rx+1 is not positive or not a multiple of 16 */ if ( r1 & 1 || stgarea & 0xF || stglen <= 0 || stglen & 0xF ) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Convert real addres to absolute address */ stgarea=APPLY_PREFIXING(stgarea,regs->PX ); /* Check to ensure extent information can be stored */ if (stgarea > regs->mainlim - 16) { regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); } /* Set start of storage extent to zero */ ARCH_DEP(store_doubleword_absolute)(0,stgarea,regs); /* Set end of storage extent to last addressable byte of main storage */ ARCH_DEP(store_doubleword_absolute)(regs->mainlim,stgarea+8,regs); /* Set number of extents to 1 in Ry */ regs->GR_G(r2) = 1; /* Indicate all extents returned */ regs->psw.cc = 0; return; #endif /* FEATURE_ESAME */ default: /* Invalid subcode */ ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } } /*-------------------------------------------------------------------*/ /* Pseudo Timer Extended (Function code 0x270) */ /* Pseudo Timer (Function code 0x00C) */ /*-------------------------------------------------------------------*/ void ARCH_DEP(pseudo_timer) (U32 code, int r1, int r2, REGS *regs) { int i; /* Array subscript */ time_t timeval; /* Current time */ struct tm *tmptr; /* -> Current time structure */ U32 bufadr; /* Real addr of data buffer */ U32 buflen; /* Length of data buffer */ char buf[64]; /* Response buffer */ BYTE dattim[64]; /* Date and time (EBCDIC) */ #define DIAG_DATEFMT_SHORT 0x80 /* Date format mm/dd/yy */ #define DIAG_DATEFMT_FULL 0x40 /* Date format mm/dd/yyyy */ #define DIAG_DATEFMT_ISO 0x20 /* Date format yyyy-mm-dd */ #define DIAG_DATEFMT_SYSDFLT 0x10 /* System-wide default format*/ static char timefmt[]="%m/%d/%y%H:%M:%S%m/%d/%Y%Y-%m-%d"; /* Get the current date and time in EBCDIC */ timeval = time(NULL); tmptr = localtime(&timeval); strftime((char *)dattim, sizeof(dattim), timefmt, tmptr); for (i = 0; dattim[i] != '\0'; i++) dattim[i] = host_to_guest(dattim[i]); /* Obtain buffer address and length from R1 and R2 registers */ bufadr = regs->GR_L(r1); buflen = regs->GR_L(r2); /* Use length 32 if R2 is zero or function code is 00C */ if (r2 == 0 || code == 0x00C) buflen = 32; /* Program check if R1 and R2 specify the same non-zero register number, or if buffer length is less than or equal to zero, or if buffer address is zero, or if buffer is not on a doubleword boundary */ if ((r2 != 0 && r2 == r1) || (S32)buflen <= 0 || bufadr == 0 || (bufadr & 0x00000007)) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return; } /* Build the response buffer */ memset (buf, 0x00, sizeof(buf)); /* Bytes 0-7 contain the date as EBCDIC MM/DD/YY */ memcpy (buf, dattim, 8); /* Bytes 8-15 contain the time as EBCDIC HH:MM:SS */ memcpy (buf+8, dattim+8, 8); /* Bytes 16-23 contain the virtual CPU time used in microseconds */ /* Bytes 24-31 contain the total CPU time used in microseconds */ /* Bytes 32-41 contain the date as EBCDIC MM/DD/YYYY */ memcpy (buf+32, dattim+16, 10); /* Bytes 42-47 contain binary zeroes */ /* Bytes 48-57 contain the date as EBCDIC YYYY-MM-DD */ memcpy (buf+48, dattim+26, 10); /* Byte 58 contains the diagnose 270 version code */ buf[58] = 0x01; /* Byte 59 contains the user's default date format */ buf[59] = DIAG_DATEFMT_ISO; /* Byte 60 contains the system default date format */ buf[60] = DIAG_DATEFMT_ISO; /* Bytes 61-63 contain binary zeroes */ #if 0 logmsg ("Diagnose X\'%3.3X\':" "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t" "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t" "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n\t\t" "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n", code, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31], buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39], buf[40], buf[41], buf[42], buf[43], buf[44], buf[45], buf[46], buf[47], buf[48], buf[49], buf[50], buf[51], buf[52], buf[53], buf[54], buf[55], buf[56], buf[57], buf[58], buf[59], buf[60], buf[61], buf[63], buf[63]); #endif /* Enforce maximum length to store */ if (buflen > sizeof(buf)) buflen = sizeof(buf); /* Store the response buffer at the operand location */ ARCH_DEP(vstorec) (buf, buflen-1, bufadr, USE_REAL_ADDR, regs); } /* end function pseudo_timer */ /*-------------------------------------------------------------------*/ /* Pending Page Release (Function code 0x214) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(diag_ppagerel) (int r1, int r2, REGS *regs) { U32 abs, start, end; /* Absolute frame addresses */ BYTE skey; /* Specified storage key */ BYTE func; /* Function code... */ #define DIAG214_EPR 0x00 /* Establish pending release */ #define DIAG214_CPR 0x01 /* Cancel pending release */ #define DIAG214_CAPR 0x02 /* Cancel all pending release*/ #define DIAG214_CPRV 0x03 /* Cancel and validate */ /* Program check if R1 is not an even-numbered register */ if (r1 & 1) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return 0; } /* Extract the function code from R1+1 register bits 24-31 */ func = regs->GR_L(r1+1) & 0xFF; /* Extract the start/end addresses from R1 and R1+1 registers */ start = regs->GR_L(r1) & STORAGE_KEY_PAGEMASK; end = regs->GR_L(r1+1) & STORAGE_KEY_PAGEMASK; /* Validate start/end addresses if function is not CAPR */ if (func != DIAG214_CAPR && (start > end || end > regs->mainlim)) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return 0; } /* Process depending on function code */ switch (func) { case DIAG214_EPR: /* Establish Pending Release */ break; case DIAG214_CPR: /* Cancel Pending Release */ case DIAG214_CPRV: /* Cancel Pending Release and Validate */ /* Do not set storage keys if R2 is register 0 */ if (r2 == 0) break; /* Obtain key from R2 register bits 24-28 */ skey = regs->GR_L(r2) & (STORKEY_KEY | STORKEY_FETCH); /* Set storage key for each frame within specified range */ for (abs = start; abs <= end; abs += STORAGE_KEY_PAGESIZE) { STORAGE_KEY(abs, regs) &= ~(STORKEY_KEY | STORKEY_FETCH); STORAGE_KEY(abs, regs) |= skey; } /* end for(abs) */ break; case DIAG214_CAPR: /* Cancel All Pending Releases */ break; default: /* Invalid function code */ ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); return 0; } /* end switch(func) */ /* Return condition code zero */ return 0; } /* end function diag_ppagerel */ /*-------------------------------------------------------------------*/ /* B2F0 IUCV - Inter User Communications Vehicle [S] */ /*-------------------------------------------------------------------*/ DEF_INST(inter_user_communication_vehicle) { int b2; /* Effective addr base */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); #if defined(FEATURE_ECPSVM) if(ecpsvm_doiucv(regs,b2,effective_addr2)==0) { return; } #endif /* Program check if in problem state, the IUCV instruction generates an operation exception rather then a priviliged operation exception when executed in problem state *JJ */ if ( PROBSTATE(®s->psw) ) ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); SIE_INTERCEPT(regs); if( HDC3(debug_iucv, b2, effective_addr2, regs) ) return; PTT(PTT_CL_ERR,"*IUCV",b2,effective_addr2,regs->psw.IA_L); /* Set condition code to indicate IUCV not available */ regs->psw.cc = 3; } #endif /*FEATURE_EMULATE_VM*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "vm.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "vm.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/vmd250.c0000664000175000017500000024656512564723224011406 00000000000000/* VMD250.C (c) Copyright Harold Grovesteen, 2009 */ /* z/VM 5.4 DIAGNOSE code X'250' */ /*-------------------------------------------------------------------*/ /* This module implements DIAGNOSE code X'250' */ /* described in SC24-6084 z/VM 5.4 CP Programming Services. */ /*-------------------------------------------------------------------*/ /* Hercules extends the use to System/370 with 4K pages and 2K pages */ /* with recommended constraints */ /* Unconditional log messages generated */ /* HHCVM006E - Could not allocate storage for Block I/O environment */ /* HHCVM009E - Invalid list processor status code returned */ /* HHCVM010E - Error creating asynchronous thread */ /* HHCVM011E - Could not allocate storage for asynchronous I/O request*/ /* Conditional log messages when device tracing is enabled */ /* HHCVM007I - BLKTAB information used when device tracing is enabled */ /* HHCVM008I - Established environment when device tracing is enabled */ /* HHCVM012I - Block I/O owns device */ /* HHCVM013I - Block I/O returned device */ /* HHCVM014I - BIOE status returned */ /* HHCVM015I - List processor parameters */ /* HHCVM016I - BIOE operation being performed */ /* HHCVM017I - List processor status code */ /* HHCVM018I - Read/Write I/O operation */ /* HHCVM019I - Syncronous or asynchronous request information */ /* HHCVM020I - Address checking results */ /* HHCVM021I - Device driver results */ /* HHCVM022I - Block I/O environment removed */ /* HHCVM023I - Triggered Block I/O interrupt */ /* The following structure exists between the different functions */ /* */ /* From diagnose.c */ /* */ /* AD:vm_blockio */ /* | */ /* INIT: */ /* +---> d250_init32---+ */ /* | +---> d250_init */ /* +---> d250_init64---+ */ /* | */ /* IOREQ: */ /* +-> AD:d250_iorq32--+---SYNC----> d250_list32--+ */ /* | V ^ | */ /* | ASYNC Thread | | d250_read */ /* | +-> AD:d250_async32-+ +--> d250_write */ /* | d250_bio_interrupt | (calls */ /* | | drivers) */ /* +-> AD:d250_iorq64--+----SYNC---> d250_list64--+ */ /* | V ^ */ /* | ASYNC Thread | */ /* | +-> AD:d250_async64-+ */ /* | d250_bio_interrupt */ /* REMOVE: */ /* +---> d250_remove */ /* */ /* Function ARCH_DEP On CPU On Async Owns */ /* thread thread device */ /* */ /* vm_blockio Yes Yes No No */ /* d250_init32/64 No Yes No No */ /* d250_init No Yes No No */ /* d250_iorq32/64 Yes Yes No No */ /* d250_async32/64 Yes No Yes No */ /* d250_list32/64 Yes Yes Yes Yes */ /* d250_bio_interrup No No Yes N/A */ /* d250_read No Yes Yes Yes */ /* d250_write No Yes Yes Yes */ /* d250_remove No Yes No No */ /* d250_addrck Yes Yes Yes No */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif /*_HENGINE_DLL_*/ #if !defined(_VMD250_C_) #define _VMD250_C_ #endif /* !defined(_VMD250_C_) */ #include "hercules.h" #include "opcode.h" #include "inline.h" #include "vmd250.h" #if defined(FEATURE_VM_BLOCKIO) #if !defined(_VMD250_C) #define _VMD250_C #if !defined(_VMD250_H) #define _VMD250_H /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Block I/O Function, Condition and Return Codes */ /*-------------------------------------------------------------------*/ /* Function Codes (Ry) */ #define INIT 0x00 /* Initialize Block I/O environment */ #define IOREQ 0x01 /* Perform I/O request */ #define REMOVE 0x02 /* Remove the Block I/O environment */ /* Condition Codes (cc) */ #define CC_SUCCESS 0 /* Function completed successfully */ #define CC_PARTIAL 1 /* Function partially completed */ #define CC_FAILED 2 /* Function failed */ /* Note: cc 3 is not returned by Block I/O */ /* General Return Codes (Rx+1)- All functions */ #define RC_SUCCESS 0 /* Function competed successfully */ #define RC_NODEV 16 /* Device not defined */ #define RC_STATERR 28 /* Env. state error */ #define RC_ERROR 255 /* Irrecoverable error */ /* Note: RC_ERROR is used to indicate an internal Hercules error */ /* and it should be accompanied by a log message */ /* INIT Return Codes (Rx+1) */ #define RC_READONLY 4 /* Successful for R/O device */ #define RC_NOSUPP 20 /* Not a supported DASD device */ #define RC_BADBLKSZ 24 /* Unsupported block size */ /* IOREQ Return Codes (Rx+1) */ #define RC_ASYNC 8 /* Asynchronous request initiated */ #define RC_SYN_PART 12 /* Synchronous request partially successful */ #define RC_CNT_ERR 36 /* Block count not between 1 and 256 */ #define RC_ALL_BAD 40 /* All blocks unsuccessful */ #define RC_REM_PART 44 /* Remove aborted request - should not occur */ #define RC_EXI_PART 48 /* Exigent aborted req. - should not occur */ /* Note: Because the DEVBLK lock is held RC_REM_PART and RC_EXI_PART */ /* should not occur in Hercules */ /*-------------------------------------------------------------------*/ /* Block I/O Parameter List Formats (BIOPL) */ /*-------------------------------------------------------------------*/ #define INIT32R1_LEN 21 #define INIT32R2_LEN 24 typedef struct _BIOPL_INIT32 { HWORD devnum; /* Device number */ BYTE flaga; /* Addressing mode flag */ BYTE resv1[INIT32R1_LEN]; /* reserved - must be zeros */ FWORD blksize; /* Block size */ FWORD offset; /* Physical block 1 offset */ FWORD startblk; /* First physical block number */ FWORD endblk; /* Last physical block number */ BYTE resv2[INIT32R2_LEN]; /* reserved - must be zeros */ } BIOPL_INIT32; #define INIT64R1_LEN 21 #define INIT64R2_LEN 4 #define INIT64R3_LEN 8 typedef struct _BIOPL_INIT64 { HWORD devnum; /* Device number */ BYTE flaga; /* Addressing mode flag */ BYTE resv1[INIT64R1_LEN]; /* reserved - must be zeros */ FWORD blksize; /* Block size */ BYTE resv2[INIT64R2_LEN]; /* Physical block 1 offset */ DBLWRD offset; /* Physical block 1 offset */ DBLWRD startblk; /* First physical block number */ DBLWRD endblk; /* Last physical block number */ BYTE resv3[INIT64R3_LEN]; /* reserved - must be zeros */ } BIOPL_INIT64; #define IORQ32R1_LEN 21 #define IORQ32R2_LEN 2 #define IORQ32R3_LEN 20 typedef struct _BIOPL_IORQ32 { HWORD devnum; /* Device number */ BYTE flaga; /* Addressing mode flag */ BYTE resv1[IORQ32R1_LEN]; /* reserved - must be zeros */ BYTE key; /* Storage key */ BYTE flags; /* I/O request flags */ BYTE resv2[IORQ32R2_LEN]; /* reserved - must be zeros */ FWORD blkcount; /* Block count of request */ FWORD bioealet; /* BIOE list ALET */ FWORD bioeladr; /* BIOE list address */ FWORD intparm; /* Interrupt parameter */ BYTE resv3[IORQ32R3_LEN]; /* reserved - must be zeros */ } BIOPL_IORQ32; #define IORQ64R1_LEN 21 #define IORQ64R2_LEN 2 #define IORQ64R3_LEN 4 #define IORQ64R4_LEN 8 typedef struct _BIOPL_IORQ64 { HWORD devnum; /* Device number */ BYTE flaga; /* Addressing mode flag */ BYTE resv1[IORQ64R1_LEN]; /* reserved - must be zeros */ BYTE key; /* Storage key */ BYTE flags; /* I/O request flags */ BYTE resv2[IORQ64R2_LEN]; /* reserved - must be zeros */ FWORD blkcount; /* Block count of request */ FWORD bioealet; /* BIOE list ALET */ BYTE resv3[IORQ64R3_LEN]; /* reserved - must be zeros */ DBLWRD intparm; /* Interrupt parameter */ DBLWRD bioeladr; /* BIOE list address */ BYTE resv4[IORQ64R4_LEN]; /* reserved - must be zeros */ } BIOPL_IORQ64; #define REMOVER1_LEN 62 typedef struct _BIOPL_REMOVE { HWORD devnum; /* Device number */ BYTE resv1[REMOVER1_LEN]; /* reserved - must be zeros */ } BIOPL_REMOVE; typedef struct _BIOPL { HWORD devnum; /* Device number */ BYTE flaga; /* Addressing mode flag */ BYTE resv1[61]; /* Additional Parameters */ } BIOPL; /* BIOPL flaga field related values */ #define BIOPL_FLAGARSV 0x7F /* Reserved bits must be zero */ #define BIOPL_FLAGAMSK 0x80 /* Addressing flag */ #define BIOPL_32BIT 0x00 /* 32-bit BIOPL/BIOE Formats */ #define BIOPL_64BIT 0x80 /* 64-bit BIOPL/BIOE Formats */ /* BIOPL flags field related values */ #define BIOPL_FLAGSRSV 0xFC /* Reserved bits must be zero */ #define BIOPL_ASYNC 0x02 /* Asynchronous request */ #define BIOPL_CACHE 0x01 /* Not used - z/VM specific */ /* BIOPL key field values */ #define BIOPL_KEYRSV 0x0F /* Reserved bits must be zero */ /*-------------------------------------------------------------------*/ /* Block I/O Entry Formats (BIOE) */ /*-------------------------------------------------------------------*/ typedef struct _BIOE32 { BYTE type; /* Type of I/O request */ BYTE status; /* Status of I/O request */ BYTE resv1[2]; /* reserved - must be zeros */ FWORD blknum; /* Requested block number */ FWORD bufalet; /* Data buffer ALET */ FWORD bufaddr; /* Data buffer absolute address */ } BIOE32; typedef struct _BIOE64 { BYTE type; /* Type of I/O request */ BYTE status; /* Status of I/O request */ BYTE resv1[2]; /* reserved - must be zeros */ FWORD bufalet; /* Data buffer ALET */ DBLWRD blknum; /* Requested block number */ DBLWRD bufaddr; /* Data buffer absolute address */ } BIOE64; /* BIOE type field values */ #define BIOE_WRITE 0x01 /* Write block request type */ #define BIOE_READ 0x02 /* Read block request type */ /* BIOE status field values */ #define BIOE_SUCCESS 0x00 /* Request successful */ #define BIOE_BADBLOCK 0x01 /* Invalid block specified */ #define BIOE_ADDREXC 0x02 /* Data buffer address exception */ #define BIOE_DASDRO 0x03 /* Write request to read-only device */ #define BIOE_CKDRECL 0x04 /* CKD record size not block size */ #define BIOE_IOERROR 0x05 /* I/O error on device */ #define BIOE_BADREQ 0x06 /* Request type invalid */ #define BIOE_PROTEXC 0x07 /* A protection exception occurred */ #define BIOE_ADRCAP 0x08 /* Not used - z/VM specific */ #define BIOE_ALENEXC 0x09 /* Not used - z/VM specific */ #define BIOE_ALETEXC 0x0A /* Not used - z/VM specific */ #define BIOE_NOTZERO 0x0B /* Reserved fields not zero */ #define BIOE_ABORTED 0x0C /* Request aborted */ /*-------------------------------------------------------------------*/ /* I/O Request Control Structures and Flags */ /*-------------------------------------------------------------------*/ #if 0 #define ADDR32 0 /* 32-bit addressing fields being used */ #define ADDR64 1 /* 64-bit addressing fields being used */ #endif #define SYNC 0 /* Synchronous request being processed */ #define ASYNC 1 /* Asynchronous request being processed */ /* Synchronous or asynchronous processing status codes */ #define PSC_SUCCESS 0x00 /* Successful processing */ #define PSC_PARTIAL 0x01 /* Partial success */ #define PSC_STGERR 0x02 /* Error on storage of BIOE */ #define PSC_REMOVED 0x03 /* Block I/O environment removed */ /* Structure passed to the asynchronous thread */ typedef struct _IOCTL32 { /* Hercules structures involved in the request */ REGS *regs; /* CPU register structure */ DEVBLK *dev; /* Device block */ /* External interrupt related values */ BYTE subintcod; /* Sub-interruption code */ BYTE statuscod; /* Interruption status code */ U32 intrparm; /* 32-bit interrupt parm */ /* List control structure */ S32 blkcount; /* Block count */ U32 listaddr; /* BIOE list address */ BYTE key; /* Storage Key */ int goodblks; /* Number of successful I/O's */ int badblks; /* Number of unsuccessful I/O's */ } IOCTL32; /* Structure passed to the asynchronous thread */ typedef struct _IOCTL64 { /* Hercules structures involved in the request */ REGS *regs; /* CPU register structure */ DEVBLK *dev; /* Device block */ /* External interrupt related values related values */ BYTE subintcod; /* Sub-interruption code */ BYTE statuscod; /* Interruption status code */ U64 intrparm; /* 64-bit interrupt parm */ /* List control structure */ S64 blkcount; /* Block count */ U64 listaddr; /* BIOE list address */ BYTE key; /* Storage Key */ int goodblks; /* Number of successful I/O's */ int badblks; /* Number of unsuccessful I/O's */ } IOCTL64; #endif /* !defined(_VMD250_H) */ /*-------------------------------------------------------------------*/ /* Internal Architecture Independent Function Prototypes */ /*-------------------------------------------------------------------*/ /* Initialization Functions */ int d250_init32(DEVBLK *, int *, BIOPL_INIT32 *, REGS *); int d250_init64(DEVBLK *, int *, BIOPL_INIT64 *, REGS *); struct VMBIOENV* d250_init(DEVBLK *, U32, S64, int *, int *); /* Input/Output Request Functions */ void d250_preserve(DEVBLK *); void d250_restore(DEVBLK *); int d250_read(DEVBLK *, S64, S32, void *); int d250_write(DEVBLK *, S64, S32, void *); /* Note: some I/O request functions are architecture dependent */ /* Removal Function */ int d250_remove(DEVBLK *, int *, BIOPL_REMOVE *, REGS *); /* Asynchronous Interrupt Generation */ void d250_bio_interrupt(DEVBLK *, U64 intparm, BYTE status, BYTE code); /*-------------------------------------------------------------------*/ /* Trigger Block I/O External Interrupt */ /*-------------------------------------------------------------------*/ void d250_bio_interrupt(DEVBLK *dev, U64 intparm, BYTE status, BYTE subcode) { OBTAIN_INTLOCK(NULL); /* This is inspired by sclp_attn_thread function in service.c */ /* Make sure a service signal interrupt is not pending */ while(IS_IC_SERVSIG) { RELEASE_INTLOCK(NULL); sched_yield(); OBTAIN_INTLOCK(NULL); } /* Can now safely store my interrupt information */ sysblk.bioparm = intparm; /* Trigger with the interrupt parameter */ sysblk.biostat = status; /* Trigger with the status */ sysblk.biosubcd = subcode; /* Trigger with the subcode */ sysblk.biodev = dev; /* Trigger for this device */ sysblk.servcode = EXT_BLOCKIO_INTERRUPT; /* The Block I/O external interrupt is enabled by the same CR0 bit */ /* as are service signal interrupts. This means the guest will */ /* be interrupted when it has enabled service signals. For this */ /* reason the Block I/O is being treated like a service signal and */ /* handled by the service signal handling logic in external.c */ /* Make the "service signal" interrupt pending */ ON_IC_SERVSIG; /* Wake up any waiters */ WAKEUP_CPUS_MASK (sysblk.waiting_mask); if (dev->ccwtrace) { logmsg (_("%4.4X:HHCVM023I Triggered Block I/O interrupt: " "code=%4.4X parm=%16.16X status=%2.2X subcode=%2.2X\n"), sysblk.biodev->devnum, sysblk.servcode, sysblk.bioparm, sysblk.biostat, sysblk.biosubcd ); } /* Free the interrupt lock */ RELEASE_INTLOCK(NULL); } /*-------------------------------------------------------------------*/ /* Initialize Environment - 32-bit Addressing */ /*-------------------------------------------------------------------*/ int d250_init32(DEVBLK *dev, int *diag_rc, BIOPL_INIT32 *biopl, REGS *regs) { BIOPL_INIT32 bioplx00; /* Use to check reserved fields */ /* Passed to the generic INIT function */ U32 blksize; /* Blocksize */ S32 offset; /* Offset */ /* Returned by generic INIT function */ struct VMBIOENV *bioenv; /* -->allocated environement */ int rc; /* return code */ int cc; /* Condition code to return */ /* Clear the reserved BIOPL */ memset(&bioplx00,0x00,sizeof(BIOPL_INIT32)); /* Make sure reserved fields are binary zeros */ if ((memcmp(&biopl->resv1,&bioplx00,INIT32R1_LEN)!=0) || (memcmp(&biopl->resv2,&bioplx00,INIT32R2_LEN)!=0)) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Fetch the block size from the BIOPL */ FETCH_FW(blksize,&biopl->blksize); /* Fetch the offset from the BIOPL provided by the guest */ FETCH_FW(offset,&biopl->offset); /* Call the addressing independent initialization function */ bioenv=d250_init(dev, blksize, (S64)offset, &cc, &rc); if (bioenv) { /* Save the values in the BIOPL for return to guest */ STORE_FW(&biopl->startblk,(U32)bioenv->begblk); STORE_FW(&biopl->endblk,(U32)bioenv->endblk); if (dev->ccwtrace) { logmsg ("%4.4X:HHCVM008I d250_init32 s=%i,o=%i,b=%i,e=%i\n", dev->devnum, blksize, offset, bioenv->begblk, bioenv->endblk ); } } *diag_rc = rc; return cc; } /* end function d250_init32 */ /*-------------------------------------------------------------------*/ /* Initialize Environment - 64-bit Addressing */ /*-------------------------------------------------------------------*/ int d250_init64(DEVBLK *dev, int *diag_rc, BIOPL_INIT64 *biopl, REGS *regs) { BIOPL_INIT64 bioplx00; /* Use to check reserved fields */ /* Passed to the generic INIT function */ U32 blksize; /* Blocksize */ S64 offset; /* Offset */ /* Returned by generic INIT function */ struct VMBIOENV *bioenv; /* -->allocated environement */ int rc; /* return code */ int cc; /* condition code */ /* Clear the reserved BIOPL */ memset(&bioplx00,0x00,sizeof(BIOPL_INIT64)); /* Make sure reserved fields are binary zeros */ if ((memcmp(&biopl->resv1,&bioplx00,INIT64R1_LEN)!=0) || (memcmp(&biopl->resv2,&bioplx00,INIT64R2_LEN)!=0) || (memcmp(&biopl->resv3,&bioplx00,INIT64R3_LEN)!=0)) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Fetch the block size from the BIOPL */ FETCH_FW(blksize,&biopl->blksize); /* Fetch the offset from the BIOPL provided by the guest */ FETCH_DW(offset,&biopl->offset); bioenv=d250_init(dev, blksize, offset, &cc, &rc); if (bioenv) { /* Save the values in the BIOPL for return to guest */ STORE_DW(&biopl->startblk,bioenv->begblk); STORE_DW(&biopl->endblk,bioenv->endblk); if (dev->ccwtrace) { logmsg ("%4.4X:HHCVM008I d250_init64 s=%i,o=%lli,b=%lli,e=%lli\n", dev->devnum, blksize, offset, bioenv->begblk, bioenv->endblk ); } } *diag_rc = rc; return cc; } /* end function d250_init64 */ /*-------------------------------------------------------------------*/ /* Initialize Environment - Addressing Independent */ /*-------------------------------------------------------------------*/ struct VMBIOENV* d250_init(DEVBLK *dev, U32 blksize, S64 offset, int *cc, int *rc ) { int isCKD; /* Flag for CKD device */ int isRO; /* Flag for readonly device */ int seccyl;/* Number of sectors/block or records/track for dev. */ int numblks; /* Number of blocks on the device */ S32 begblk; /* Starting block number */ S32 endblk; /* Ending block number */ BLKTAB *blktab; /* Pointer to device std block-to-physical info */ /* Established environement */ struct VMBIOENV *bioenv; /* -->allocated environement */ /* Return with an error if the device does not exist */ if (!dev) { *rc = RC_NODEV; /* Set the return code for no device */ *cc = CC_FAILED; /* Indicate the function failed */ return 0; } /* Look up the block-to-phyical mapping information */ blktab=dasd_lookup(DASD_STDBLK,NULL,(U32)dev->devtype,0); if (!blktab) { *rc = RC_NOSUPP; /* Set the return code for unsuppored device */ *cc = CC_FAILED; /* Indicate the function failed */ return NULL; } if (dev->ccwtrace) { logmsg (_("%4.4X:HHCVM007I d250_init BLKTAB: " "type=%4.4X arch=%i,512=%i,1024=%i,2048=%i,4096=%i\n"), dev->devnum, blktab->devt, blktab->darch, blktab->phys512, blktab->phys1024, blktab->phys2048, blktab->phys4096 ); } /* Save the device architecture */ isCKD = blktab->darch; /* Determine if the blocksize is valid and its physical/block value */ switch(blksize) { case 4096: seccyl=blktab->phys4096; break; case 512: seccyl=blktab->phys512; break; case 1024: seccyl=blktab->phys1024; break; case 2048: seccyl=blktab->phys2048; break; default: *rc = RC_BADBLKSZ; *cc = CC_FAILED; return NULL; } isRO = 0; /* Assume device is read-write */ if (isCKD) { /* Number of standard blocks is based upon number of primary */ /* cylinders */ numblks=(dev->ckdtab->cyls * dev->ckdtab->heads * seccyl); if (dev->ckdrdonly) { isRO = 1; } } else { numblks=(dev->fbanumblk*dev->fbablksiz)/blksize; /* FBA devices are never read only */ } /* Establish the environment's beginning and ending block numbers */ /* Block numbers in the environment are relative to 1, not zero */ begblk=1-offset; endblk=numblks-offset; if (!(bioenv=(struct VMBIOENV *)malloc(sizeof(struct VMBIOENV)))) { logmsg (_("HHCVM006E VM BLOCK I/O environment malloc failed\n")); *rc = RC_ERROR; /* Indicate an irrecoverable error occurred */ *cc = CC_FAILED; return NULL; } /* Set the fields in the environment structure */ bioenv->dev = dev ; /* Set device block pointer */ bioenv->blksiz = blksize ; /* Pass the block size */ bioenv->offset = offset ; /* Pass the offset */ bioenv->begblk = begblk ; /* Save the starting block */ bioenv->endblk = endblk ; /* Save the ending block */ bioenv->isCKD = isCKD ; /* Save the device type */ bioenv->isRO = isRO ; /* Save the read/write status */ bioenv->blkphys = seccyl ; /* Save the block-to-phys mapping */ /* Attach the environment to the DEVBLK */ /* Lock the DEVBLK in case another thread wants it */ obtain_lock (&dev->lock); if (dev->vmd250env == NULL) { /* If an environment does not exist, establish it */ dev->vmd250env = bioenv ; /* No need to hold the device lock now, environment is set */ release_lock (&dev->lock); /* Set the appropriate successful return and condition codes */ if (isRO) { *rc = RC_READONLY ; /* Set READ ONLY success return code */ } else { *rc = RC_SUCCESS ; /* Set the READ/WRITE success return code */ } *cc = CC_SUCCESS ; /* Set that the function has succeeded */ } else { /* If an environment already exists, this is an error: */ /* 1. Release the device block */ /* 2. free the environment just built */ /* 3. Reset the retuned environment to NULL and */ /* 4. Reset return and condition codes to reflect */ /* the error condition */ release_lock (&dev->lock); free(bioenv); bioenv = NULL ; *rc = RC_STATERR; *cc = CC_FAILED; } /* Return the bioenv so that the start and end blocks can */ /* be returned to the guest in the addressing mode specific */ /* BIOPL format */ return bioenv ; } /* end function d250_init */ /*-------------------------------------------------------------------*/ /* Preserve Device Status */ /*-------------------------------------------------------------------*/ /* WARNING: This function must NOT be called with the device lock held */ /* From the perspective of Hercules, Block I/O is occurring at the */ /* level of the device, NOT the channel or channel subsystem. For */ /* the channel subsytem or other CPU's, the device is made to */ /* appear busy and reserved if shared. */ /* */ /* It is possible for block I/O to take control between the */ /* completion of a CCW chain and the presentation by the device of */ /* related sense information. The device related sense information*/ /* is therefore stored in the Block I/O environment and restored */ /* upon completion. This also allows the device drivers to set */ /* sense information during Block I/O operations, which they do. */ /* A pointer is used by the device drivers for unit status, so */ /* this can be redirected to a Block I/O location. */ /* */ /* A cleaner but more intrusive change would be to have the */ /* the drivers use a pointer for where sense is stored rather than */ /* assume the device block. This is deferred for a possible future*/ /* enhancement. */ void d250_preserve(DEVBLK *dev) { /* Note: this logic comes from the beginning of */ /* channel.c ARCH_DEP(execute_ccw_chain) */ obtain_lock(&dev->lock); if ( dev->shared ) { while (dev->ioactive != DEV_SYS_NONE && dev->ioactive != DEV_SYS_LOCAL) { dev->iowaiters++; wait_condition(&dev->iocond, &dev->lock); dev->iowaiters--; } dev->ioactive = DEV_SYS_LOCAL; } else { dev->ioactive = DEV_SYS_LOCAL; } dev->busy = 1; dev->startpending = 0; if (dev->sns_pending) { /* Save the pending sense */ memcpy(&dev->vmd250env->sense,&dev->sense,sizeof(dev->sense)); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM012I d250_preserve pending sense preserved\n"), dev->devnum); } } /* Both fbadasd.c and ckddasd.c set the local reserved flag before */ /* calling the shared device client */ dev->reserved = 1; if (dev->hnd->reserve) { release_lock(&dev->lock); (dev->hnd->reserve)(dev); } else { release_lock(&dev->lock); } } /*-------------------------------------------------------------------*/ /* Restore Device Status */ /*-------------------------------------------------------------------*/ /* WARNING: This function MUST not be called with the device lock held */ void d250_restore(DEVBLK *dev) { obtain_lock(&dev->lock); if (dev->hnd->release) { release_lock(&dev->lock); (dev->hnd->release)(dev); obtain_lock(&dev->lock); } /* Both fbadasd.c and ckddasd.c reset the local reserved flag */ /* after calling the shared device client */ dev->reserved = 0; if (dev->sns_pending) { /* Restore the pending sense */ memcpy(&dev->sense,&dev->vmd250env->sense,sizeof(dev->sense)); if (dev->ccwtrace) { logmsg (_("%4.4X:HHCVM013I d250_restore pending sense restored\n"), dev->devnum); } } dev->ioactive = DEV_SYS_NONE; dev->busy = 0; release_lock(&dev->lock); } /*-------------------------------------------------------------------*/ /* Environment Remove - Any Addressing */ /*-------------------------------------------------------------------*/ int d250_remove(DEVBLK *dev, int *rc, BIOPL_REMOVE * biopl, REGS *regs) { BIOPL_REMOVE bioplx00; /* Use to check reserved fields */ struct VMBIOENV *bioenv; /* -->allocated environement */ int cc; /* Condition code to return */ /* Clear the reserved BIOPL */ memset(&bioplx00,0x00,sizeof(BIOPL_REMOVE)); /* Make sure reserved fields are binary zeros */ if (memcmp(&biopl->resv1,&bioplx00,REMOVER1_LEN)!=0) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Return with an error if the device does not exist */ if (!dev) { *rc = RC_NODEV; /* Set the return code for no device */ return CC_FAILED; /* Indicate the function failed */ } /* Attach the environment to the DEVBLK */ /* Lock the DEVBLK in case another CPU is trying something */ obtain_lock (&dev->lock); bioenv=dev->vmd250env; if (dev->vmd250env == NULL) { /* If an environment does not exist, it should be */ /* Return the environment state error return code */ /* and failed condition code */ release_lock (&dev->lock); *rc = RC_STATERR; cc = CC_FAILED; } else { /* 1. Restore pending sense, if any */ /* 2. Free the environment previously established */ /* 3. Set the device environment pointer to NULL, */ /* telling others that the environment doesn't exist */ /* 4. Release the device block */ /* 5. Free the environment previously established */ /* 6. Return successful return and condition codes */ if (dev->sns_pending) { memcpy(&dev->sense,dev->vmd250env->sense,sizeof(dev->sense)); } dev->vmd250env = NULL ; /* No need to hold the device lock while freeing the environment */ release_lock (&dev->lock); free(bioenv); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM022I d250_remove Block I/O environment removed\n"), dev->devnum); } *rc = RC_SUCCESS; cc = CC_SUCCESS ; /* Set that the function has succeeded */ } return cc ; } /* end function d250_remove */ /*-------------------------------------------------------------------*/ /* Device Independent Read Block */ /*-------------------------------------------------------------------*/ int d250_read(DEVBLK *dev, S64 pblknum, S32 blksize, void *buffer) { BYTE unitstat; /* Device unit status */ U16 residual; /* Residual byte count */ /* Note: Not called with device lock held */ obtain_lock(&dev->lock); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM018I d250_read %d-byte block (rel. to 0): %d\n"), dev->devnum, blksize, pblknum); } if (dev->vmd250env->isCKD) { release_lock(&dev->lock); /* Do CKD I/O */ /* CKD to be supplied */ return BIOE_IOERROR; } else { /* Do FBA I/O */ /* Call the I/O start exit */ if (dev->hnd->start) (dev->hnd->start) (dev); unitstat = 0; /* Call the FBA driver's read standard block routine */ fbadasd_read_block(dev, (int)pblknum, (int)blksize, dev->vmd250env->blkphys, buffer, &unitstat, &residual ); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM021I d250_read " "FBA unit status=%2.2X residual=%d\n"), dev->devnum, unitstat, residual ); } /* Call the I/O end exit */ if (dev->hnd->end) (dev->hnd->end) (dev); release_lock(&dev->lock); } /* If an I/O error occurred, return status of I/O Error */ if ( unitstat != ( CSW_CE | CSW_DE ) ) { return BIOE_IOERROR; } /* If there was a residual count, block size error, return status of 2 */ /* Note: This can only happen for CKD devices */ if ( residual != 0 ) { return BIOE_CKDRECL; } /* Success! return 0 status */ return BIOE_SUCCESS; } /*-------------------------------------------------------------------*/ /* Device Independent Write Block */ /*-------------------------------------------------------------------*/ int d250_write(DEVBLK *dev, S64 pblknum, S32 blksize, void *buffer) { BYTE unitstat; /* Device unit status */ U16 residual; /* Residual byte count */ obtain_lock(&dev->lock); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM018I d250_write %d-byte block (rel. to 0): %d\n"), dev->devnum, blksize, pblknum); } if (!dev->vmd250env) { release_lock(&dev->lock); return BIOE_ABORTED; } if (dev->vmd250env->isCKD) { release_lock(&dev->lock); /* Do CKD I/O */ /* CKD to be supplied */ return BIOE_IOERROR; } else { /* Do FBA I/O */ /* Call the I/O start exit */ if (dev->hnd->start) (dev->hnd->start) (dev); unitstat = 0; /* Call the FBA driver's write standard block routine */ fbadasd_write_block(dev, (int)pblknum, (int)blksize, dev->vmd250env->blkphys, buffer, &unitstat, &residual ); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM021I d250_write " "FBA unit status=%2.2X residual=%d\n"), dev->devnum, unitstat, residual ); } /* Call the I/O end exit */ if (dev->hnd->end) (dev->hnd->end) (dev); release_lock(&dev->lock); } /* If an I/O error occurred, return status of 1 */ if ( unitstat != ( CSW_CE | CSW_DE ) ) { return BIOE_IOERROR; } /* If there was a residual count, block size error, return status of 2 */ /* Note: This can only happen for CKD devices */ if ( residual != 0 ) { return BIOE_CKDRECL; } /* Success! */ return BIOE_SUCCESS; } #endif /*!defined(_VMD250_C)*/ /*-------------------------------------------------------------------*/ /* Internal Architecture Dependent Function Prototypes */ /*-------------------------------------------------------------------*/ /* Input/Output Request Functions */ int ARCH_DEP(d250_iorq32)(DEVBLK *, int *, BIOPL_IORQ32 *, REGS *); int ARCH_DEP(d250_list32)(IOCTL32 *, int); U16 ARCH_DEP(d250_addrck)(RADR, RADR, int, BYTE, REGS *); #if defined(FEATURE_ESAME) int ARCH_DEP(d250_iorq64)(DEVBLK *, int *, BIOPL_IORQ64 *, REGS *); /* void *ARCH_DEP(d250_async64)(void *); */ int ARCH_DEP(d250_list64)(IOCTL64 *, int); #endif /* defined(FEATURE_ESAME) */ /*-------------------------------------------------------------------*/ /* Process Standard Block I/O (Function code 0x250) */ /*-------------------------------------------------------------------*/ int ARCH_DEP(vm_blockio) (int r1, int r2, REGS *regs) { /* Guest related paramters and values */ RADR biopaddr; /* BIOPL address */ union parmlist{ /* BIOPL formats that */ BIOPL biopl; /* May be supplied by the */ BIOPL_INIT32 init32; /* guest */ BIOPL_IORQ32 iorq32; BIOPL_REMOVE remove; #if defined(FEATURE_ESAME) BIOPL_INIT64 init64; BIOPL_IORQ64 iorq64; #endif /* defined(FEATURE_ESAME) */ }; union parmlist bioplin; /* BIOPL from/to guest */ U16 devnum; /* Device number */ DEVBLK *dev; /* --> Device block */ int rc; /* return code in Rx+1 */ int cc; /* condition code */ rc = RC_ERROR; /* Initialize the return code to error */ cc = CC_FAILED; /* Failure assumed unless otherwise successful */ #if 0 if (sizeof(BIOPL) != 64) { logmsg("BIOPL size not 64: %d\n",sizeof(BIOPL)); } if (sizeof(BIOPL_INIT32) != 64) { logmsg("BIOPL_INIT32 size not 64: %d\n",sizeof(BIOPL_INIT32)); } if (sizeof(BIOPL_INIT64) != 64) { logmsg("BIOPL_INIT64 size not 64: %d\n",sizeof(BIOPL_INIT64)); } if (sizeof(BIOPL_IORQ32) != 64) { logmsg("BIOPL_IORQ32 size not 64: %d\n",sizeof(BIOPL_IORQ32)); } if (sizeof(BIOPL_REMOVE) != 64) { logmsg("BIOPL_REMOVE size not 64: %d\n",sizeof(BIOPL_REMOVE)); } if (sizeof(BIOPL_IORQ64) != 64) { logmsg("BIOPL_IORQ64 size not 64: %d\n",sizeof(BIOPL_IORQ64)); } if (sizeof(BIOE32) != 16) { logmsg("BIOE32 size not 16: %d\n",sizeof(BIOE32)); } if (sizeof(BIOE64) != 24) { logmsg("BIOE64 size not 24: %d\n",sizeof(BIOE64)); } #endif /* Retrieve the BIOPL address from R1 */ biopaddr = regs->GR(r1); /* Specification exception if the BIOPL is not on a doubleword boundary */ if (biopaddr & 0x00000007) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Fetch the BIOPL from guest storage */ ARCH_DEP(wfetchc) (&bioplin, sizeof(bioplin)-1, biopaddr, USE_REAL_ADDR, regs); /* Access the targeted device number from the BIOPL*/ FETCH_HW(devnum,&bioplin.biopl.devnum); /* Locate the device by the number */ dev = find_device_by_devnum (0,devnum); /* Device not found will be checked by the called function */ switch(regs->GR_L(r2)) { /*--------------------------------------------------------*/ /* Initialize the Block I/O Device Environment */ /*--------------------------------------------------------*/ case INIT: #if !defined(FEATURE_ESAME) /* 64-bit formats not supported for S/370 or ESA/390 */ /* and bits 1-7 must be zero */ if (bioplin.biopl.flaga != 0x00) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Call the 32-bit addressing function */ cc = d250_init32(dev,&rc,&bioplin.init32,regs); #else /* Bits 1-7 must be zero for z/Architecture */ if (bioplin.biopl.flaga & BIOPL_FLAGARSV) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Call the addressing sensitive function */ if (bioplin.biopl.flaga & BIOPL_FLAGAMSK) { cc = d250_init64(dev,&rc,&bioplin.init64,regs); } else { cc = d250_init32(dev,&rc,&bioplin.init32,regs); } #endif /* !FEATURE_ESAME */ break; /*--------------------------------------------------------*/ /* Perform block I/O read/write requests to the device */ /*--------------------------------------------------------*/ case IOREQ: #if !defined(FEATURE_ESAME) /* 64-bit formats not supported for S/370 or ESA/390 */ /* and bits 1-7 must be zero */ if (bioplin.biopl.flaga != 0x00) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } cc = ARCH_DEP(d250_iorq32)(dev,&rc,&bioplin.iorq32,regs); #else /* Bits 1-7 must be zero for z/Architecture */ if (bioplin.biopl.flaga & BIOPL_FLAGARSV) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } if (bioplin.biopl.flaga & BIOPL_FLAGAMSK) { cc = ARCH_DEP(d250_iorq64)(dev,&rc,&bioplin.iorq64,regs); } else { cc = ARCH_DEP(d250_iorq32)(dev,&rc,&bioplin.iorq32,regs); } #endif /* !FEATURE_ESAME */ break; /*--------------------------------------------------------*/ /* Remove the Block I/O Device Environment */ /*--------------------------------------------------------*/ case REMOVE: cc = d250_remove(dev,&rc,&bioplin.remove,regs); break; default: ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); } /* end switch(regs->GR_L(r2)) */ /* Update the BIOPL in main storage */ ARCH_DEP(wstorec) (&bioplin, sizeof(bioplin)-1, biopaddr, USE_REAL_ADDR, regs); /* Set the return code in Rx+1 */ regs->GR_L((r1+1)&0xF) = rc; /* Return the condition code */ return cc; } /* end function vm_blockio */ /*-------------------------------------------------------------------*/ /* Asynchronous Input/Outut 32-bit Driver Thread */ /*-------------------------------------------------------------------*/ static void *ARCH_DEP(d250_async32)(void *ctl) { IOCTL32 *ioctl; /* 32-bit IO request controls */ BYTE psc; /* List processing status code */ /* Fetch the IO request control structure */ ioctl=(IOCTL32 *)ctl; /* Call the 32-bit BIOE request processor on this async thread*/ psc=ARCH_DEP(d250_list32)(ioctl, ASYNC); /* Trigger the external interrupt here */ d250_bio_interrupt(ioctl->dev, ioctl->intrparm, psc, 0x03); free(ioctl); return NULL; } /* end function ARCH_DEP(d250_async32) */ /*-------------------------------------------------------------------*/ /* Input/Output Request - 32-bit Addressing */ /*-------------------------------------------------------------------*/ int ARCH_DEP(d250_iorq32)(DEVBLK *dev, int *rc, BIOPL_IORQ32 *biopl, REGS *regs) { BIOPL_IORQ32 bioplx00; /* Used to check reserved fields */ IOCTL32 ioctl; /* Request information */ BYTE psc; /* List processing status code */ /* Asynchronous request related fields */ TID tid; /* Asynchronous thread ID */ char tname[32]; /* Thread name */ IOCTL32 *asyncp; /* Pointer to async thread's storage */ /* Clear the reserved BIOPL */ memset(&bioplx00,0x00,sizeof(BIOPL_IORQ32)); /* Make sure reserved fields and bits are binary zeros */ if ((memcmp(&biopl->resv1,&bioplx00,IORQ32R1_LEN)!=0) || (memcmp(&biopl->resv2,&bioplx00,IORQ32R2_LEN)!=0) || (memcmp(&biopl->resv3,&bioplx00,IORQ32R3_LEN)!=0) || (biopl->flags & BIOPL_FLAGSRSV) || (biopl->key & BIOPL_KEYRSV) ) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Return with an error return code if the device does not exist */ if (!dev) { *rc = RC_NODEV; /* Set the return code for no device */ return CC_FAILED; /* Indicate the function failed */ } /* If no environment, return with an error */ if (!(dev->vmd250env)) { *rc = RC_STATERR; return CC_FAILED; } /* Fetch the block count from the BIOPL */ FETCH_FW(ioctl.blkcount,&biopl->blkcount); /* Block count must be between 1 and 256, inclusive */ if ((ioctl.blkcount<1) || (ioctl.blkcount>256)) { *rc = RC_CNT_ERR; return CC_FAILED; } /* Fetch the address of the BIO entry list from the BIOPL */ FETCH_FW(ioctl.listaddr,&biopl->bioeladr); /* Extract the storage key from the BIOPL */ ioctl.key=biopl->key; /* Set the structures that are involved in this request */ ioctl.dev = dev; ioctl.regs = regs; /* Set I/O success/failure counts to zero */ ioctl.goodblks = 0; ioctl.badblks = 0; if (biopl->flags & BIOPL_ASYNC) { /* Build the request structure */ /* Extract the 32-bit interrupt parameter from the BIOPL */ FETCH_FW(ioctl.intrparm,biopl->intparm); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM019I ASYNC BIOEL=%8.8X, " "Entries=%d, Key=%2.2X, Intp=%8.8X\n"), dev->devnum, ioctl.listaddr, ioctl.blkcount, ioctl.key, ioctl.intrparm); } /* Set the default status code to an aborted list */ /* Note: This should be set correctly from the returned PSC */ ioctl.statuscod = PSC_STGERR; /* Get the storage for the thread's parameters */ if (!(asyncp=(IOCTL32 *)malloc(sizeof(IOCTL32)))) { logmsg (_("HHCVM011E VM BLOCK I/O request malloc failed\n")); *rc = RC_ERROR; return CC_FAILED; } /* Copy the thread's parameters to its own storage */ memcpy(asyncp,&ioctl,sizeof(IOCTL32)); /* Launch the asynchronous request on a separate thread */ snprintf(tname,sizeof(tname),"d250_async %4.4X",dev->devnum); tname[sizeof(tname)-1]=0; if ( create_thread (&tid, DETACHED, ARCH_DEP(d250_async32), asyncp, tname) ) { logmsg (_("%4.4X:HHCVM010E Block I/O create_thread error: %s"), dev->devnum, strerror(errno)); release_lock (&dev->lock); *rc = RC_ERROR; return CC_FAILED; } /* Launched the async request successfully */ *rc = RC_ASYNC; return CC_SUCCESS; } else { /* Perform the I/O request synchronously on this thread */ /* Call the 32-bit BIOE request processor */ if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM019I d250_iorq32 SYNC BIOEL=%8.8X, " "Entries=%d, Key=%2.2X\n"), dev->devnum, ioctl.listaddr, ioctl.blkcount, ioctl.key); } psc=ARCH_DEP(d250_list32)(&ioctl, SYNC); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM017I d250_iorq32 " "PSC=%d, succeeded=%d, failed=%d\n"), dev->devnum,psc,ioctl.goodblks,ioctl.badblks); } } /* Processor status used to determine return and condition codes */ switch(psc) { case PSC_SUCCESS: *rc = RC_SUCCESS; return CC_SUCCESS; case PSC_PARTIAL: if (ioctl.goodblks == 0) { *rc = RC_ALL_BAD; return CC_FAILED; } else { *rc = RC_SYN_PART; return CC_PARTIAL; } case PSC_REMOVED: *rc = RC_REM_PART; return CC_PARTIAL; default: logmsg (_("HHCVM009E d250_list32 error: PSC=%i\n"), psc); *rc = RC_ERROR; return CC_FAILED; } } /* end function ARCH_DEP(d250_iorq32) */ /* BIOE Address and Status Handling (32-bit and 64-bit formats) */ /* */ /* The entire BIOE is fetched from storage, but only the status */ /* field will be updated. BIOE addresses and block addresses are */ /* handled the same. Only key protection and addressing */ /* exceptions are recognized for these absolute addresses. */ /* Architecture will determine the maximum address allowed not the */ /* addressing mode specified in the PSW. An addressing exception */ /* will be recognized if a BIOE extends beyond the architecture */ /* maximum address. */ /* */ /* Setting of reference bit in a storage key is based upon */ /* inline.h ARCH_DEP(fetch_xxx_absolute) functions */ /* Setting of changed bit in a storage key is based upon */ /* inline.h ARCH_DEP(store_xxx_absolute) functions */ /*-------------------------------------------------------------------*/ /* Input/Outut 32-bit List Processor - Sychronicity Independent */ /*-------------------------------------------------------------------*/ int ARCH_DEP(d250_list32)(IOCTL32* ioctl, int async) /* WARNING: Device Block lock must be released before returning */ { BIOE32 bioe; /* 32-bit BIOE fetched from absolute storage */ RADR bioebeg; /* Starting address of the BIOE */ RADR bioeend; /* Address of last byte of BIOE */ U16 xcode; /* Detected exception condition */ int blocks; /* Number of blocks being processed */ int block; /* counter used in block I/O loop */ S32 blknum; /* Block number of the request */ BYTE status; /* Returned BIOE status */ /* Passed to generic block I/O function */ int physblk; /* Physical block number */ RADR bufbeg; /* Address where the read/write will occur */ RADR bufend; /* Last byte read or written */ xcode = 0; /* Initialize the address check exception code */ status = 0xFF; /* Set undefined status */ /* Preserve pending sense if any and establish my ownership */ /* of the device by reserving it if shared and locking it */ if (ioctl->dev->ccwtrace) { logmsg ("%4.4X:HHCVM015I d250_list32 BIOE's=%i A:" F_RADR " I/O key=%2.2X\n", ioctl->dev->devnum, ioctl->blkcount, ioctl->listaddr, ioctl->key ); } /* Take ownership of the device */ d250_preserve(ioctl->dev); /* Note: the DEVBLK is now locked */ if (!ioctl->dev->vmd250env) { d250_restore(ioctl->dev); /* Note: the device lock is now released */ return PSC_REMOVED; } blocks=(int)ioctl->blkcount; bioebeg=ioctl->listaddr & AMASK31 ; /* Process each of the BIOE's supplied by the BIOPL count field */ for ( block = 0 ; block < blocks ; block++ ) { status = 0xFF; /* Set undefined status */ bioeend=( bioebeg + sizeof(BIOE32) - 1 ) & AMASK31; xcode=ARCH_DEP(d250_addrck) (bioebeg,bioeend,ACCTYPE_READ,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list32 xcode=%4.4X " "BIOE32=%8.8X-%8.8X FETCH key=%2.2X\n"), ioctl->dev->devnum,xcode,bioebeg,bioeend,ioctl->key); } if ( xcode ) { break; } /* Fetch the BIOE from storage */ memcpy(&bioe,ioctl->regs->mainstor+bioebeg,sizeof(BIOE32)); STORAGE_KEY(bioebeg, ioctl->regs) |= (STORKEY_REF); STORAGE_KEY(bioeend, ioctl->regs) |= (STORKEY_REF); /* Process a single BIOE */ do { /* Make sure reserved field is zeros */ if ( bioe.resv1[0]!=0x00 || bioe.resv1[1]!=0x00 ) { status=BIOE_NOTZERO; continue; } /* Fetch and validate block number */ FETCH_FW(blknum,&bioe.blknum); if ( (blknum < ioctl->dev->vmd250env->begblk) || (blknum > ioctl->dev->vmd250env->endblk) ) { status=BIOE_BADBLOCK; continue; } /* Fetch the storage address used for I/O */ FETCH_FW(bufbeg,&bioe.bufaddr); bufbeg &= AMASK31; /* Ensure the environment still exists */ if (!ioctl->dev->vmd250env) { d250_restore(ioctl->dev); /* Note: the device lock is now released */ status=BIOE_ABORTED; return PSC_REMOVED; } /* The I/O handler routines are normally called without the */ /* device lock being held. The device is reserved by the */ /* busy status. */ /* Determine the last byte of the I/O buffer */ bufend=( bufbeg + ioctl->dev->vmd250env->blksiz -1 ) & AMASK31 ; if (ioctl->dev->ccwtrace) { logmsg (_("%4.4X:HHCVM016I d250_list32 BIOE %8.8X" ", oper=%2.2X, block=%i" ", buffer=%8.8X\n"), ioctl->dev->devnum, bioebeg, bioe.type, blknum, bufbeg ); } /* Determine the physical block on the device relative to zero */ physblk=(S64)blknum+ioctl->dev->vmd250env->offset-1; /* The read/write routines will convert this to a physical disk */ /* location for reading or writing */ if (bioe.type == BIOE_READ) { xcode=ARCH_DEP(d250_addrck) (bufbeg,bufend,ACCTYPE_READ,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list32 xcode=%4.4X " "Rd Buf=%8.8X-%8.8X FETCH key=%2.2X\n"), ioctl->dev->devnum,xcode,bufbeg,bufend,ioctl->key); } switch ( xcode ) { case PGM_ADDRESSING_EXCEPTION: status=BIOE_ADDREXC; continue; case PGM_PROTECTION_EXCEPTION: status=BIOE_PROTEXC; continue; } /* At this point, the block number has been validated */ /* and the buffer is addressable and accessible */ status=d250_read(ioctl->dev, physblk, ioctl->dev->vmd250env->blksiz, ioctl->regs->mainstor+bufbeg); /* Set I/O storage key references if successful */ if (!status) { STORAGE_KEY(bufbeg, ioctl->regs) |= (STORKEY_REF); STORAGE_KEY(bufend, ioctl->regs) |= (STORKEY_REF); #if defined(FEATURE_2K_STORAGE_KEYS) if ( ioctl->dev->vmd250env->blksiz == 4096 ) { STORAGE_KEY(bufbeg+2048, ioctl->regs) |= (STORKEY_REF); } #endif } continue; } /* end of BIOE_READ */ else { if (bioe.type == BIOE_WRITE) { xcode=ARCH_DEP(d250_addrck) (bufbeg,bufend,ACCTYPE_WRITE,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list32 xcode=%4.4X " "Wr Buf=%8.8X-%8.8X STORE key=%2.2X\n"), ioctl->dev->devnum, xcode,bufbeg, bufend, ioctl->key); } switch ( xcode ) { case PGM_ADDRESSING_EXCEPTION: status=BIOE_ADDREXC; continue; case PGM_PROTECTION_EXCEPTION: status=BIOE_PROTEXC; continue; } if (ioctl->dev->vmd250env->isRO) { status=BIOE_DASDRO; continue; } status=d250_write(ioctl->dev, physblk, ioctl->dev->vmd250env->blksiz, ioctl->regs->mainstor+bufbeg); /* Set I/O storage key references if good I/O */ if (!status) { STORAGE_KEY(bufbeg, ioctl->regs) |= (STORKEY_REF | STORKEY_CHANGE); STORAGE_KEY(bufend, ioctl->regs) |= (STORKEY_REF | STORKEY_CHANGE); #if defined(FEATURE_2K_STORAGE_KEYS) if ( ioctl->dev->vmd250env->blksiz == 4096 ) { STORAGE_KEY(bufbeg+2048, ioctl->regs) |= (STORKEY_REF | STORKEY_CHANGE); } #endif } continue; } /* end of if BIOE_WRITE */ else { status=BIOE_BADREQ; continue; } /* end of else BIOE_WRITE */ } /* end of else BIOE_READ */ }while(0); /* end of do */ /* Determine if we can store the status in the BIOE */ xcode=ARCH_DEP(d250_addrck) (bioebeg+1,bioebeg+1,ACCTYPE_WRITE,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list32 xcode=%4.4X " "Status=%8.8X-%8.8X STORE key=%2.2X\n"), ioctl->dev->devnum,xcode,bioebeg+1,bioebeg+1,ioctl->key); } /* If the status byte is store protected, give up on processing any */ /* more BIOE's. Leave the BIOE list process for loop */ if ( xcode ) { break; } /* Store the status in the BIOE */ memcpy(ioctl->regs->mainstor+bioebeg+1,&status,1); /* Set the storage key change bit */ STORAGE_KEY(bioebeg+1, ioctl->regs) |= (STORKEY_REF | STORKEY_CHANGE); if (ioctl->dev->ccwtrace) { logmsg (_("%4.4X:HHCVM014I d250_list32 BIOE=%8.8X status=%2.2X\n"), ioctl->dev->devnum,bioebeg,status); } /* Count if this BIOE was a success or failure */ if ( status ) { ioctl->badblks+=1; if ( status == BIOE_ABORTED ) { break; } } else { ioctl->goodblks+=1; } /* Determine the address of the next BIOE */ bioebeg += sizeof(BIOE32); bioebeg &= AMASK31; } /* end of for loop */ #if 0 logmsg(_("(d250_list32) BIOE's processed: %d\n"),block); #endif /* Restore device to guest ownership */ d250_restore(ioctl->dev); /* Note: device lock not held */ /* If an access exception occurred: */ /* If this is a synchronous request, generate a program exception */ /* or if this is asynchrnous, just return with a storage error */ if ( xcode ) { if (async) return PSC_STGERR; else ARCH_DEP(program_interrupt)(ioctl->regs, xcode); } if ( status == BIOE_ABORTED ) { return PSC_REMOVED; } /* Determine if we were completely successful or only partially */ /* successful. 'Partial' includes none successful. */ /* Synchronous and asynchronous requests handle all failed */ /* differently. The good and bad blocks field are used by the */ /* caller */ if (ioctl->goodblks < blocks) { return PSC_PARTIAL; } return PSC_SUCCESS; } /* end function d250_list32 */ /*-------------------------------------------------------------------*/ /* Absolue Address Checking without Reference and Change Recording */ /*-------------------------------------------------------------------*/ U16 ARCH_DEP(d250_addrck) (RADR beg, RADR end, int acctype, BYTE key, REGS *regs) /* Note: inline.h and vstore.c functions are not used because they */ /* will generate program exceptions automatically. DIAGNOSE X'250' in */ /* the asynchronous case, must not do that, but rather reflect the */ /* error in the interrupt status code or BIOE status field. So this */ /* function only detects and reports the error. */ /* The caller must decide whether to generate a program interrupt or */ /* just report the encountered error without a program interruption */ /* and must set the reference and change bit as appropriate */ { BYTE sk1; /* Storage key of first byte of area */ BYTE sk2; /* Storage key of last byte of area */ #if defined(FEATURE_2K_STORAGE_KEYS) BYTE skmid; /* Storage key of middle byte of area */ #endif /* defined(FEATURE_2K_STORAGE_KEYS) */ if ( (end > regs->mainlim) || (end > MAXADDRESS) || end < beg ) { return PGM_ADDRESSING_EXCEPTION; } /* Note this logic is inspired by */ /* inline.h ARCH_DEP(is_fetch_protected) */ /* inline.h ARCH_DEP(is_store_protected) */ if (key == 0) { return 0; } sk1=STORAGE_KEY(beg,regs); sk2=STORAGE_KEY(end,regs); #if defined(FEATURE_2K_STORAGE_KEYS) if ( ( end - beg ) > 2048 ) { skmid=STORAGE_KEY(beg + 2048,regs); } else { skmid = sk2; } #endif /* defined(FEATURE_2K_STORAGE_KEYS) */ if (acctype == ACCTYPE_READ) { /* Check for fetch protection */ if ( ((sk1 & STORKEY_FETCH) && (key != (sk1 & STORKEY_KEY))) ||((sk2 & STORKEY_FETCH) && (key != (sk2 & STORKEY_KEY))) #if defined(FEATURE_2K_STORAGE_KEYS) ||((skmid & STORKEY_FETCH) && (key != (skmid & STORKEY_KEY))) #endif /* defined(FEATURE_2K_STORAGE_KEYS) */ ) { return PGM_PROTECTION_EXCEPTION; } } else /* assume ACCTYPE_WRITE */ { /* Check for store protection */ if ( (key != (sk1 & STORKEY_KEY)) ||(key != (sk2 & STORKEY_KEY)) #if defined(FEATURE_2K_STORAGE_KEYS) ||(key != (skmid & STORKEY_KEY)) #endif /* defined(FEATURE_2K_STORAGE_KEYS) */ ) { return PGM_PROTECTION_EXCEPTION; } } return 0; } /* end of function ARCH_DEP(d250_addrck) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* Asynchronous Input/Output 64-bit Driver Thread */ /*-------------------------------------------------------------------*/ void ARCH_DEP(d250_async64)(void *ctl) { IOCTL64 *ioctl; /* 64-bit IO request controls */ BYTE psc; /* List processing status code */ /* Fetch the IO request control structure */ ioctl=(IOCTL64 *)ctl; /* Call the 32-bit BIOE request processor on this async thread*/ psc=ARCH_DEP(d250_list64)(ioctl, ASYNC); d250_bio_interrupt(ioctl->dev, ioctl->intrparm, psc, 0x07); free(ioctl); } /* end function ARCH_DEP(d250_async64) */ /*-------------------------------------------------------------------*/ /* Input/Output Request - 64-bit Addressing */ /*-------------------------------------------------------------------*/ int ARCH_DEP(d250_iorq64)(DEVBLK *dev, int *rc, BIOPL_IORQ64 *biopl, REGS *regs) { BIOPL_IORQ64 bioplx00; /* Used to check reserved fields */ IOCTL64 ioctl; /* Request information */ BYTE psc; /* List processing status code */ /* Asynchronous request related fields */ TID tid; /* Asynchronous thread ID */ char tname[32]; /* Thread name */ IOCTL64 *asyncp; /* Pointer to async thread's free standing storage */ #if 0 logmsg("(d250_iorq64) Entered\n"); #endif /* Clear the reserved BIOPL */ memset(&bioplx00,0x00,sizeof(BIOPL_IORQ64)); /* Make sure reserved fields are binary zeros */ if ((memcmp(&biopl->resv1,&bioplx00,IORQ64R1_LEN)!=0) || (memcmp(&biopl->resv2,&bioplx00,IORQ64R2_LEN)!=0) || (memcmp(&biopl->resv3,&bioplx00,IORQ64R3_LEN)!=0) || (memcmp(&biopl->resv4,&bioplx00,IORQ64R4_LEN)!=0) || (biopl->flags & BIOPL_FLAGSRSV) || (biopl->key & BIOPL_KEYRSV) ) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Return with an error return code if the device does not exist */ if (!dev) { *rc = RC_NODEV; /* Set the return code for no device */ return CC_FAILED; /* Indicate the function failed */ } /* If no environment, return with an error */ if (!dev->vmd250env) { *rc = RC_STATERR; return CC_FAILED; } /* Fetch the block count from the BIOPL */ FETCH_FW(ioctl.blkcount,&biopl->blkcount); #if 0 logmsg("(d250_iorq64) ioctl.blkcount=%d,\n", ioctl.blkcount); #endif /* Block count must be between 1 and 256, inclusive */ if ((ioctl.blkcount<1) || (ioctl.blkcount>256)) { *rc = RC_CNT_ERR; return CC_FAILED; } /* Fetch the address of the BIO entry list from the BIOPL */ FETCH_DW(ioctl.listaddr,&biopl->bioeladr); #if 0 logmsg (_("(d250_iorq64) ioctl.listaddr=%16.16X,\n"), ioctl.listaddr); #endif /* Extract the storage key from the BIOPL */ ioctl.key=biopl->key; /* Set the structures that are involved in this request */ ioctl.dev = dev; ioctl.regs = regs; /* Set I/O success/failure counts to zero */ ioctl.goodblks = 0; ioctl.badblks = 0; /* Determine if request is an asynchronous or synchronous */ if (biopl->flags & BIOPL_ASYNC) { /* Build the request structure */ /* Extract the 64-bit interrupt parameter from the BIOPL */ FETCH_DW(ioctl.intrparm,&biopl->intparm); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM019I ASYNC BIOEL=%16.16X, " "Entries=%d, Key=%2.2X, Intp=%16.16X\n"), dev->devnum, ioctl.listaddr, ioctl.blkcount, ioctl.key, ioctl.intrparm); } /* Set the default status code to an aborted list */ /* Note: This should be set correctly from the returned PSC */ ioctl.statuscod = PSC_STGERR; /* Get the storage for the thread's parameters */ if (!(asyncp=(IOCTL64 *)malloc(sizeof(IOCTL64)))) { logmsg (_("HHCVM011E VM BLOCK I/O request malloc failed\n")); *rc = RC_ERROR; return CC_FAILED; } /* Copy the thread's parameters to its own storage */ memcpy(asyncp,&ioctl,sizeof(IOCTL64)); /* Launch the asynchronous request on a separate thread */ snprintf(tname,sizeof(tname),"d250_async %4.4X",dev->devnum); tname[sizeof(tname)-1]=0; if ( create_thread (&tid, DETACHED, ARCH_DEP(d250_async64), asyncp, tname) ) { logmsg (_("%4.4X:HHCVM010E create_thread error: %s"), dev->devnum, strerror(errno)); release_lock (&dev->lock); *rc = RC_ERROR; return CC_FAILED; } /* Launched the async request successfully */ *rc = RC_ASYNC; return CC_SUCCESS; } else { if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM019I d250_iorq64 SYNC BIOEL=%16.16X, " "Entries=%d, Key=%2.2X\n"), dev->devnum, ioctl.listaddr, ioctl.blkcount, ioctl.key); } psc=ARCH_DEP(d250_list64)(&ioctl, SYNC); if (dev->ccwtrace) { logmsg(_("%4.4X:HHCVM017I d250_iorq64 " "PSC=%d, succeeded=%d, failed=%d\n"), dev->devnum,psc,ioctl.goodblks,ioctl.badblks); } } /* Processor status used to determine return and condition codes */ switch(psc) { case PSC_SUCCESS: *rc = RC_SUCCESS; return CC_SUCCESS; case PSC_PARTIAL: if (ioctl.goodblks == 0) { *rc = RC_ALL_BAD; return CC_FAILED; } else { *rc = RC_SYN_PART; return CC_PARTIAL; } case PSC_REMOVED: *rc = RC_REM_PART; return CC_PARTIAL; default: logmsg (_("HHCVM009E d250_list64 error: PSC=%i\n"), psc); *rc = RC_ERROR; return CC_FAILED; } /* end switch(psc) */ } /* end function d250_iorq64 */ /*-------------------------------------------------------------------*/ /* Input/Outut 64-bit List Processor - Sychronicity Independent */ /*-------------------------------------------------------------------*/ int ARCH_DEP(d250_list64)(IOCTL64* ioctl, int async) /* WARNING: Device Block lock must be released before returning */ { BIOE64 bioe; /* 32-bit BIOE fetched from absolute storage */ RADR bioebeg; /* Starting address of the BIOE */ RADR bioeend; /* Address of last byte of BIOE */ U16 xcode; /* Detected exception condition */ int blocks; /* Number of blocks being processed */ int block; /* counter used in block I/O loop */ S64 blknum; /* Block number of the request */ BYTE status; /* Returned BIOE status */ /* Passed to generic block I/O function */ int physblk; /* Physical block number */ RADR bufbeg; /* Address where the read/write will occur */ RADR bufend; /* Last byte read or written */ xcode = 0; /* Initialize the address check exception code */ status = 0xFF; /* Set undefined status */ /* Preserve pending sense if any and establish my ownership */ /* of the device by reserving it if shared and locking it */ if (ioctl->dev->ccwtrace) { logmsg (_("%4.4X:HHCVM015I d250_list64 BIOE's=%i A:" F_RADR " I/O key=%2.2X\n"), ioctl->dev->devnum, ioctl->blkcount, ioctl->listaddr, ioctl->key ); } /* Take ownership of the device */ d250_preserve(ioctl->dev); /* Note: the DEVBLK is now locked */ if (!ioctl->dev->vmd250env) { d250_restore(ioctl->dev); /* Note: the device lock is now released */ return PSC_REMOVED; } blocks=(int)ioctl->blkcount; bioebeg=ioctl->listaddr & AMASK64 ; /* Process each of the BIOE's supplied by the BIOPL count field */ for ( block = 0 ; block < blocks ; block++ ) { status = 0xFF; /* Set undefined status */ bioeend=( bioebeg + sizeof(BIOE32) - 1 ) & AMASK31; xcode=ARCH_DEP(d250_addrck) (bioebeg,bioeend,ACCTYPE_READ,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list64 xcode=%4.4X " "BIOE64=%8.8X-%8.8X FETCH key=%2.2X\n"), ioctl->dev->devnum,xcode,bioebeg,bioeend,ioctl->key); } if ( xcode ) { break; } /* Fetch the BIOE from storage */ memcpy(&bioe,ioctl->regs->mainstor+bioebeg,sizeof(BIOE64)); STORAGE_KEY(bioebeg, ioctl->regs) |= (STORKEY_REF); STORAGE_KEY(bioeend, ioctl->regs) |= (STORKEY_REF); /* Process a single BIOE */ do { /* Make sure reserved field is zeros */ if ( bioe.resv1[0]!=0x00 || bioe.resv1[1]!=0x00 ) { status=BIOE_NOTZERO; continue; } /* Fetch and validate block number */ FETCH_DW(blknum,&bioe.blknum); if ( (blknum < ioctl->dev->vmd250env->begblk) || (blknum > ioctl->dev->vmd250env->endblk) ) { status=BIOE_BADBLOCK; continue; } /* Fetch the storage address used for I/O */ FETCH_DW(bufbeg,&bioe.bufaddr); bufbeg &= AMASK64; /* Ensure the environment still exists */ if (!ioctl->dev->vmd250env) { d250_restore(ioctl->dev); /* Note: the device lock is now released */ status=BIOE_ABORTED; return PSC_REMOVED; } /* The I/O handler routines are normally called without the */ /* device lock being held. The device is reserved by the */ /* busy status. */ /* Determine the last byte of the I/O buffer */ bufend=( bufbeg + ioctl->dev->vmd250env->blksiz -1 ) & AMASK64 ; if (ioctl->dev->ccwtrace) { logmsg (_("%4.4X:HHCVM016I d250_list64 BIOE %16.16X" ", oper=%2.2X, block=%i" ", buffer=%16.16X\n"), ioctl->dev->devnum, bioebeg, bioe.type, blknum, bufbeg ); } /* Determine the physical block on the device relative to zero */ physblk=(S64)blknum+ioctl->dev->vmd250env->offset-1; /* The read/write routines will convert this to a physical disk */ /* location for reading or writing */ if (bioe.type == BIOE_READ) { xcode=ARCH_DEP(d250_addrck) (bufbeg,bufend,ACCTYPE_READ,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list64 xcode=%4.4X " "Rd Buf=%16.16X-%16.16X FETCH key=%2.2X\n"), ioctl->dev->devnum,xcode,bufbeg,bufend,ioctl->key); } switch ( xcode ) { case PGM_ADDRESSING_EXCEPTION: status=BIOE_ADDREXC; continue; case PGM_PROTECTION_EXCEPTION: status=BIOE_PROTEXC; continue; } /* At this point, the block number has been validated */ /* and the buffer is addressable and accessible */ status=d250_read(ioctl->dev, physblk, ioctl->dev->vmd250env->blksiz, ioctl->regs->mainstor+bufbeg); /* Set I/O storage key references if successful */ if (!status) { STORAGE_KEY(bufbeg, ioctl->regs) |= (STORKEY_REF); STORAGE_KEY(bufend, ioctl->regs) |= (STORKEY_REF); } continue; } /* end of BIOE_READ */ else { if (bioe.type == BIOE_WRITE) { xcode=ARCH_DEP(d250_addrck) (bufbeg,bufend,ACCTYPE_WRITE,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list64 xcode=%4.4X " "Wr Buf=%16.16X-%16.16X STORE key=%2.2X\n"), ioctl->dev->devnum, xcode,bufbeg, bufend, ioctl->key); } switch ( xcode ) { case PGM_ADDRESSING_EXCEPTION: status=BIOE_ADDREXC; continue; case PGM_PROTECTION_EXCEPTION: status=BIOE_PROTEXC; continue; } if (ioctl->dev->vmd250env->isRO) { status=BIOE_DASDRO; continue; } status=d250_write(ioctl->dev, physblk, ioctl->dev->vmd250env->blksiz, ioctl->regs->mainstor+bufbeg); /* Set I/O storage key references if good I/O */ if (!status) { STORAGE_KEY(bufbeg, ioctl->regs) |= (STORKEY_REF | STORKEY_CHANGE); STORAGE_KEY(bufend, ioctl->regs) |= (STORKEY_REF | STORKEY_CHANGE); } continue; } /* end of if BIOE_WRITE */ else { status=BIOE_BADREQ; continue; } /* end of else BIOE_WRITE */ } /* end of else BIOE_READ */ }while(0); /* end of do */ /* Determine if we can store the status in the BIOE */ xcode=ARCH_DEP(d250_addrck) (bioebeg+1,bioebeg+1,ACCTYPE_WRITE,ioctl->key,ioctl->regs); if (ioctl->dev->ccwtrace) { logmsg(_("%4.4X:HHCVM020I d250_list64 xcode=%4.4X " "Status=%16.16X-%16.16X STORE key=%2.2X\n"), ioctl->dev->devnum,xcode,bioebeg+1,bioebeg+1,ioctl->key); } /* If the status byte is store protected, give up on processing any */ /* more BIOE's. Leave the BIOE list process for loop */ if ( xcode ) { break; } /* Store the status in the BIOE */ memcpy(ioctl->regs->mainstor+bioebeg+1,&status,1); /* Set the storage key change bit */ STORAGE_KEY(bioebeg+1, ioctl->regs) |= (STORKEY_REF | STORKEY_CHANGE); if (ioctl->dev->ccwtrace) { logmsg (_("%4.4X:HHCVM014I d250_list64 BIOE=%16.16X status=%2.2X\n"), ioctl->dev->devnum,bioebeg,status); } /* Count if this BIOE was a success or failure */ if ( status ) { ioctl->badblks+=1; if ( status == BIOE_ABORTED ) { break; } } else { ioctl->goodblks+=1; } /* Determine the address of the next BIOE */ bioebeg += sizeof(BIOE64); bioebeg &= AMASK64; } /* end of for loop */ #if 0 /* remove after testing */ logmsg(_("(d250_list64) BIOE's processed: %d\n"),block); #endif /* Restore device to guest ownership */ d250_restore(ioctl->dev); /* Note: device lock not held */ /* If an access exception occurred: */ /* If this is a synchronous request, generate a program exception */ /* or if this is asynchrnous, just return with a storage error */ if ( xcode ) { if (async) return PSC_STGERR; else ARCH_DEP(program_interrupt)(ioctl->regs, xcode); } if ( status == BIOE_ABORTED ) { return PSC_REMOVED; } /* Determine if we were completely successful or only partially */ /* successful. 'Partial' includes none successful. */ /* Synchronous and asynchronous requests handle all failed */ /* differently. The good and bad blocks field are used by the */ /* caller */ if (ioctl->goodblks < blocks) { return PSC_PARTIAL; } return PSC_SUCCESS; } /* end function ARCH_DEP(d250_list64) */ #endif /* defined(FEATURE_ESAME) */ #endif /*FEATURE_VM_BLOCKIO*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "vmd250.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "vmd250.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/channel.c0000664000175000017500000041161212564723224011764 00000000000000/* CHANNEL.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 Channel Emulator */ /*-------------------------------------------------------------------*/ /* This module contains the channel subsystem functions for the */ /* Hercules S/370 and ESA/390 emulator. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Measurement block support by Jan Jaeger */ /* Fix program check on NOP due to addressing - Jan Jaeger */ /* Fix program check on TIC as first ccw on RSCH - Jan Jaeger */ /* Fix PCI intermediate status flags - Jan Jaeger */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /* 64-bit IDAW support - Roger Bowler v209 @IWZ*/ /* Incorrect-length-indication-suppression - Jan Jaeger */ /* Read backward support contributed by Hackules 13jun2002 */ /* Read backward fixes contributed by Jay Jaeger 16sep2003 */ /* MIDAW support - Roger Bowler 03aug2005 @MW*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "opcode.h" #if defined(OPTION_FISHIO) #include "w32chan.h" #endif // defined(OPTION_FISHIO) void call_execute_ccw_chain(int arch_mode, void* pDevBlk); #ifdef OPTION_IODELAY_KLUDGE #define IODELAY(_dev) \ do { \ if (sysblk.iodelay > 0 && (_dev)->devchar[10] == 0x20) \ usleep(sysblk.iodelay); \ } while (0) #else #define IODELAY(_dev) #endif #undef CHADDRCHK #if defined(FEATURE_ADDRESS_LIMIT_CHECKING) #define CHADDRCHK(_addr,_dev) \ ( ((_addr) > (_dev)->mainlim) \ || ((dev->orb.flag5 & ORB5_A) \ && ((((_dev)->pmcw.flag5 & PMCW5_LM_LOW) \ && ((_addr) < sysblk.addrlimval)) \ || (((_dev)->pmcw.flag5 & PMCW5_LM_HIGH) \ && ((_addr) >= sysblk.addrlimval)) ) )) #else /*!defined(FEATURE_ADDRESS_LIMIT_CHECKING)*/ #define CHADDRCHK(_addr,_dev) \ ((_addr) > (_dev)->mainlim) #endif /*!defined(FEATURE_ADDRESS_LIMIT_CHECKING)*/ #if !defined(_CHANNEL_C) #define _CHANNEL_C /*-------------------------------------------------------------------*/ /* FORMAT I/O BUFFER DATA */ /*-------------------------------------------------------------------*/ static void format_iobuf_data (RADR addr, BYTE *area, DEVBLK *dev) /*@IWZ*/ { BYTE *a; /* -> Byte in main storage */ int i, j; /* Array subscripts */ BYTE c; /* Character work area */ area[0] = '\0'; if (addr <= dev->mainlim - 16) { a = dev->mainstor + addr; j = sprintf ((char *)area, "=>%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X" " %2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X ", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); for (i = 0; i < 16; i++) { c = guest_to_host(*a++); if (!isprint(c)) c = '.'; area[j++] = c; } area[j] = '\0'; } } /* end function format_iobuf_data */ /*-------------------------------------------------------------------*/ /* DISPLAY CHANNEL COMMAND WORD AND DATA */ /*-------------------------------------------------------------------*/ static void display_ccw (DEVBLK *dev, BYTE ccw[], U32 addr) { BYTE area[64]; /* Data display area */ format_iobuf_data (addr, area, dev); logmsg (_("HHCCP048I %4.4X:CCW=%2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X%s\n"), dev->devnum, ccw[0], ccw[1], ccw[2], ccw[3], ccw[4], ccw[5], ccw[6], ccw[7], area); } /* end function display_ccw */ /*-------------------------------------------------------------------*/ /* DISPLAY CHANNEL STATUS WORD */ /*-------------------------------------------------------------------*/ static void display_csw (DEVBLK *dev, BYTE csw[]) { logmsg (_("HHCCP049I %4.4X:Stat=%2.2X%2.2X Count=%2.2X%2.2X " "CCW=%2.2X%2.2X%2.2X\n"), dev->devnum, csw[4], csw[5], csw[6], csw[7], csw[1], csw[2], csw[3]); } /* end function display_csw */ /*-------------------------------------------------------------------*/ /* DISPLAY SUBCHANNEL STATUS WORD */ /*-------------------------------------------------------------------*/ static void display_scsw (DEVBLK *dev, SCSW scsw) { logmsg (_("HHCCP050I %4.4X:SCSW=%2.2X%2.2X%2.2X%2.2X " "Stat=%2.2X%2.2X Count=%2.2X%2.2X " "CCW=%2.2X%2.2X%2.2X%2.2X\n"), dev->devnum, scsw.flag0, scsw.flag1, scsw.flag2, scsw.flag3, scsw.unitstat, scsw.chanstat, scsw.count[0], scsw.count[1], scsw.ccwaddr[0], scsw.ccwaddr[1], scsw.ccwaddr[2], scsw.ccwaddr[3]); } /* end function display_scsw */ /*-------------------------------------------------------------------*/ /* STORE CHANNEL ID */ /*-------------------------------------------------------------------*/ int stchan_id (REGS *regs, U16 chan) { U32 chanid; /* Channel identifier word */ int devcount = 0; /* #of devices on channel */ DEVBLK *dev; /* -> Device control block */ PSA_3XX *psa; /* -> Prefixed storage area */ /* Find a device on specified channel */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { /* Skip the device if not on specified channel */ if ((dev->devnum & 0xFF00) != chan || (dev->pmcw.flag5 & PMCW5_V) == 0 #if defined(FEATURE_CHANNEL_SWITCHING) || regs->chanset != dev->chanset #endif /*defined(FEATURE_CHANNEL_SWITCHING)*/ ) continue; /* Found device on the channel */ devcount++; break; } /* end for(dev) */ /* Exit with condition code 3 if no devices on channel */ if (devcount == 0) return 3; /* Construct the channel id word */ /* According to GA22-7000-4, Page 192, 2nd paragraph, * channel 0 is a Byte Multiplexor.. Return STIDC data * accordingly * ISW 20080313 */ if(!chan) { chanid = CHANNEL_MPX; } else { chanid = CHANNEL_BMX; } /* Store the channel id word at PSA+X'A8' */ psa = (PSA_3XX*)(regs->mainstor + regs->PX); STORE_FW(psa->chanid, chanid); /* Exit with condition code 0 indicating channel id stored */ return 0; } /* end function stchan_id */ /*-------------------------------------------------------------------*/ /* TEST CHANNEL */ /*-------------------------------------------------------------------*/ int testch (REGS *regs, U16 chan) { DEVBLK *dev; /* -> Device control block */ int devcount = 0; /* Number of devices found */ int cc = 0; /* Returned condition code */ /* Scan devices on the channel */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { /* Skip the device if not on specified channel */ if ((dev->devnum & 0xFF00) != chan || (dev->pmcw.flag5 & PMCW5_V) == 0 #if defined(FEATURE_CHANNEL_SWITCHING) || regs->chanset != dev->chanset #endif /*defined(FEATURE_CHANNEL_SWITCHING)*/ ) continue; /* Increment device count on this channel */ devcount++; /* Test for pending interrupt */ if (IOPENDING(dev)) { cc = 1; break; } } /* Set condition code 3 if no devices found on the channel */ if (devcount == 0) cc = 3; return cc; } /* end function testch */ /*-------------------------------------------------------------------*/ /* TEST I/O */ /*-------------------------------------------------------------------*/ int testio (REGS *regs, DEVBLK *dev, BYTE ibyte) { int cc; /* Condition code */ PSA_3XX *psa; /* -> Prefixed storage area */ IOINT *ioint=NULL; UNREFERENCED(ibyte); if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP051I %4.4X: Test I/O\n"), dev->devnum); obtain_lock (&dev->lock); /* Test device status and set condition code */ if ((dev->busy && dev->ioactive == DEV_SYS_LOCAL) || dev->startpending) { /* Set condition code 2 if device is busy */ cc = 2; } else { if (IOPENDING(dev)) { /* Set condition code 1 if interrupt pending */ cc = 1; /* Store the channel status word at PSA+X'40' */ psa = (PSA_3XX*)(regs->mainstor + regs->PX); if (dev->pcipending) { memcpy (psa->csw, dev->pcicsw, 8); ioint=&dev->pciioint; } else { if(dev->pending) { memcpy (psa->csw, dev->csw, 8); ioint=&dev->ioint; } else { memcpy (psa->csw, dev->attncsw, 8); ioint=&dev->attnioint; } } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } if (dev->ccwtrace || dev->ccwstep) display_csw (dev, psa->csw); } else { /* Set condition code 1 if device is LCS CTC */ if ( dev->ctctype == CTC_LCS ) { cc = 1; dev->csw[4] = 0; dev->csw[5] = 0; psa = (PSA_3XX*)(regs->mainstor + regs->PX); memcpy (psa->csw, dev->csw, 8); if (dev->ccwtrace) { logmsg(_("HHCCP052I TIO modification executed CC=1\n")); display_csw (dev, dev->csw); } } else /* Set condition code 0 if device is available */ cc = 0; } } /* Dequeue the interrupt */ if(ioint) DEQUEUE_IO_INTERRUPT(ioint); release_lock (&dev->lock); /* Update interrupt status */ if(ioint) { OBTAIN_INTLOCK(regs); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(regs); } /* Return the condition code */ return cc; } /* end function testio */ /*-------------------------------------------------------------------*/ /* HALT I/O */ /*-------------------------------------------------------------------*/ int haltio (REGS *regs, DEVBLK *dev, BYTE ibyte) { int cc; /* Condition code */ PSA_3XX *psa; /* -> Prefixed storage area */ int pending = 0; /* New interrupt pending */ UNREFERENCED(ibyte); if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP053I %4.4X: Halt I/O\n"), dev->devnum); obtain_lock (&dev->lock); /* Test device status and set condition code */ if (dev->busy) { /* Invoke the provided halt_device routine @ISW */ /* if it has been provided by the handler @ISW */ /* code at init @ISW */ if(dev->halt_device!=NULL) /* @ISW */ { /* @ISW */ dev->halt_device(dev); /* @ISW */ psa = (PSA_3XX*)( regs->mainstor + regs->PX ); psa->csw[4] = 0; /* Store partial CSW */ psa->csw[5] = 0; cc = 1; /* Set CC for CSW stored */ } /* @ISW */ else { /* Set condition code 2 if device is busy */ cc = 2; /* Tell channel and device to halt */ dev->scsw.flag2 |= SCSW2_FC_HALT; /* Clear pending interrupts */ dev->pending = dev->pcipending = dev->attnpending = 0; } } else if (!IOPENDING(dev) && dev->ctctype != CTC_LCS) { /* Set condition code 1 */ cc = 1; /* Store the channel status word at PSA+X'40' */ psa = (PSA_3XX*)(regs->mainstor + regs->PX); memcpy (psa->csw, dev->csw, 8); /* Set pending interrupt */ dev->pending = pending = 1; if (dev->ccwtrace || dev->ccwstep) display_csw (dev, dev->csw); } else { /* Set cc 1 if interrupt is not pending and LCS CTC */ if ( dev->ctctype == CTC_LCS ) { cc = 1; dev->csw[4] = 0; dev->csw[5] = 0; psa = (PSA_3XX*)(regs->mainstor + regs->PX); memcpy (psa->csw, dev->csw, 8); if (dev->ccwtrace) { logmsg(_("HHCCP054I HIO modification executed CC=1\n")); display_csw (dev, dev->csw); } } else /* Set condition code 0 if interrupt is pending */ cc = 0; } /* For 3270 device, clear any pending input */ if (dev->devtype == 0x3270) { dev->readpending = 0; dev->rlen3270 = 0; } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Queue the interrupt */ if (pending) QUEUE_IO_INTERRUPT (&dev->ioint); release_lock (&dev->lock); /* Update interrupt status */ if (pending) { OBTAIN_INTLOCK(regs); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(regs); } /* Return the condition code */ return cc; } /* end function haltio */ /*-------------------------------------------------------------------*/ /* CANCEL SUBCHANNEL */ /*-------------------------------------------------------------------*/ /* Input */ /* regs -> CPU register context */ /* dev -> Device control block */ /* Return value */ /* The return value is the condition code for the XSCH */ /* 0=start function cancelled (not yet implemented) */ /* 1=status pending (no action taken) */ /* 2=function not applicable */ /*-------------------------------------------------------------------*/ int cancel_subchan (REGS *regs, DEVBLK *dev) { int cc; /* Condition code */ UNREFERENCED(regs); obtain_lock (&dev->lock); #if defined(_FEATURE_IO_ASSIST) if(SIE_MODE(regs) && (regs->siebk->zone != dev->pmcw.zone || !(dev->pmcw.flag27 & PMCW27_I))) { release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_INST); } #endif /* Check pending status */ if ((dev->pciscsw.flag3 & SCSW3_SC_PEND) || (dev->scsw.flag3 & SCSW3_SC_PEND) || (dev->attnscsw.flag3 & SCSW3_SC_PEND)) cc = 1; else { cc = 2; #if !defined(OPTION_FISHIO) obtain_lock(&sysblk.ioqlock); if(sysblk.ioq != NULL) { DEVBLK *tmp; /* special case for head of queue */ if(sysblk.ioq == dev) { /* Remove device from the i/o queue */ sysblk.ioq = dev->nextioq; cc = 0; } else { /* Search for device on i/o queue */ for(tmp = sysblk.ioq; tmp->nextioq != NULL && tmp->nextioq != dev; tmp = tmp->nextioq); /* Remove from queue if found */ if(tmp->nextioq == dev) { tmp->nextioq = tmp->nextioq->nextioq; cc = 0; } } /* Reset the device */ if(!cc) { /* Terminate suspended channel program */ if (dev->scsw.flag3 & SCSW3_AC_SUSP) { dev->suspended = 0; signal_condition (&dev->resumecond); } /* Reset the scsw */ dev->scsw.flag2 &= ~(SCSW2_AC_RESUM | SCSW2_FC_START | SCSW2_AC_START); dev->scsw.flag3 &= ~(SCSW3_AC_SUSP); /* Reset the device busy indicator */ dev->busy = dev->startpending = 0; } } release_lock(&sysblk.ioqlock); #endif /*!defined(OPTION_FISHIO)*/ } release_lock (&dev->lock); /* Return the condition code */ return cc; } /* end function cancel_subchan */ /*-------------------------------------------------------------------*/ /* TEST SUBCHANNEL */ /*-------------------------------------------------------------------*/ /* Input */ /* regs -> CPU register context */ /* dev -> Device control block */ /* Output */ /* irb -> Interruption response block */ /* Return value */ /* The return value is the condition code for the TSCH */ /* instruction: 0=status was pending and is now cleared, */ /* 1=no status was pending. The IRB is updated in both cases. */ /*-------------------------------------------------------------------*/ int test_subchan (REGS *regs, DEVBLK *dev, IRB *irb) { int cc; /* Condition code */ #if defined(_FEATURE_IO_ASSIST) UNREFERENCED(regs); #endif obtain_lock (&dev->lock); #if defined(_FEATURE_IO_ASSIST) if(SIE_MODE(regs) && (regs->siebk->zone != dev->pmcw.zone || !(dev->pmcw.flag27 & PMCW27_I))) { release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_INST); } #endif /* Return PCI SCSW if PCI status is pending */ if (dev->pciscsw.flag3 & SCSW3_SC_PEND) { #if defined(_FEATURE_IO_ASSIST) /* For I/O assisted devices we must intercept if type B status is present on the subchannel */ if(SIE_MODE(regs) && ( (regs->siebk->tschds & dev->pciscsw.unitstat) || (regs->siebk->tschsc & dev->pciscsw.chanstat) ) ) { dev->pmcw.flag27 &= ~PMCW27_I; release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_IOINST); } #endif /* Display the subchannel status word */ if (dev->ccwtrace || dev->ccwstep) display_scsw (dev, dev->pciscsw); /* Copy the PCI SCSW to the IRB */ irb->scsw = dev->pciscsw; /* Clear the ESW and ECW in the IRB */ memset (&irb->esw, 0, sizeof(ESW)); irb->esw.lpum = 0x80; memset (irb->ecw, 0, sizeof(irb->ecw)); /* Clear the pending PCI status */ dev->pciscsw.flag2 &= ~(SCSW2_FC | SCSW2_AC); dev->pciscsw.flag3 &= ~(SCSW3_SC); dev->pcipending = 0; /* Dequeue the interrupt */ DEQUEUE_IO_INTERRUPT(&dev->pciioint); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(regs); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(regs); /* Return condition code 0 to indicate status was pending */ return 0; } /* end if(pcipending) */ /* Copy the subchannel status word to the IRB */ irb->scsw = dev->scsw; /* Copy the extended status word to the IRB */ irb->esw = dev->esw; /* Copy the extended control word to the IRB */ memcpy (irb->ecw, dev->ecw, sizeof(irb->ecw)); /* Test device status and set condition code */ if (dev->scsw.flag3 & SCSW3_SC_PEND) { #if defined(_FEATURE_IO_ASSIST) /* For I/O assisted devices we must intercept if type B status is present on the subchannel */ if(SIE_MODE(regs) && ( (regs->siebk->tschds & dev->scsw.unitstat) || (regs->siebk->tschsc & dev->scsw.chanstat) ) ) { dev->pmcw.flag27 &= ~PMCW27_I; release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_IOINST); } #endif /* Set condition code 0 for status pending */ cc = 0; /* Display the subchannel status word */ if (dev->ccwtrace || dev->ccwstep) display_scsw (dev, dev->scsw); /* [14.3.13] If status is anything other than intermediate with pending then clear the function control, activity control, status control, and path not-operational bits in the SCSW */ if ((dev->scsw.flag3 & SCSW3_SC) != (SCSW3_SC_INTER | SCSW3_SC_PEND)) { dev->scsw.flag2 &= ~(SCSW2_FC | SCSW2_AC); dev->scsw.flag3 &= ~(SCSW3_AC_SUSP); dev->scsw.flag1 &= ~(SCSW1_N); } else { /* [14.3.13] Clear the function control bits if function code is halt and the channel program is suspended */ if ((dev->scsw.flag2 & SCSW2_FC_HALT) && (dev->scsw.flag3 & SCSW3_AC_SUSP)) dev->scsw.flag2 &= ~(SCSW2_FC); /* [14.3.13] Clear the activity control bits if function code is start+halt and channel program is suspended */ if ((dev->scsw.flag2 & (SCSW2_FC_START | SCSW2_FC_HALT)) == (SCSW2_FC_START | SCSW2_FC_HALT) && (dev->scsw.flag3 & SCSW3_AC_SUSP)) { dev->scsw.flag2 &= ~(SCSW2_AC); dev->scsw.flag3 &= ~(SCSW3_AC_SUSP); dev->scsw.flag1 &= ~(SCSW1_N); } /* [14.3.13] Clear the resume pending bit if function code is start without halt and channel program suspended */ if ((dev->scsw.flag2 & (SCSW2_FC_START | SCSW2_FC_HALT)) == SCSW2_FC_START && (dev->scsw.flag3 & SCSW3_AC_SUSP)) { dev->scsw.flag2 &= ~(SCSW2_AC_RESUM); dev->scsw.flag1 &= ~(SCSW1_N); } } /* end if(INTER+PEND) */ /* Clear the status bits in the SCSW */ dev->scsw.flag3 &= ~(SCSW3_SC); } else { /* Test device status and set condition code */ if (dev->attnscsw.flag3 & SCSW3_SC_PEND) { #if defined(_FEATURE_IO_ASSIST) /* For I/O assisted devices we must intercept if type B status is present on the subchannel */ if(SIE_MODE(regs) && ( (regs->siebk->tschds & dev->attnscsw.unitstat) || (regs->siebk->tschsc & dev->attnscsw.chanstat) ) ) { dev->pmcw.flag27 &= ~PMCW27_I; release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_IOINST); } #endif /* Set condition code 0 for status pending */ cc = 0; /* Display the subchannel status word */ if (dev->ccwtrace || dev->ccwstep) display_scsw (dev, dev->attnscsw); /* Copy the ATTN SCSW to the IRB */ irb->scsw = dev->attnscsw; /* Clear the ESW and ECW in the IRB */ memset (&irb->esw, 0, sizeof(ESW)); irb->esw.lpum = 0x80; memset (irb->ecw, 0, sizeof(irb->ecw)); /* Clear the pending ATTN status */ dev->attnscsw.flag2 &= ~(SCSW2_FC | SCSW2_AC); dev->attnscsw.flag3 &= ~(SCSW3_SC); dev->attnpending = 0; /* Dequeue the interrupt */ DEQUEUE_IO_INTERRUPT(&dev->attnioint); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(regs); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(regs); /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Return condition code 0 to indicate status was pending */ return 0; } else { /* Set condition code 1 if status not pending */ cc = 1; } } /* Dequeue the interrupt */ DEQUEUE_IO_INTERRUPT(&dev->ioint); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(regs); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(regs); /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Return the condition code */ return cc; } /* end function test_subchan */ /*-------------------------------------------------------------------*/ /* CLEAR SUBCHANNEL */ /*-------------------------------------------------------------------*/ /* Input */ /* regs -> CPU register context */ /* dev -> Device control block */ /*-------------------------------------------------------------------*/ void clear_subchan (REGS *regs, DEVBLK *dev) { int pending = 0; UNREFERENCED(regs); if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP055I %4.4X: Clear subchannel\n"), dev->devnum); obtain_lock (&dev->lock); #if defined(_FEATURE_IO_ASSIST) if(SIE_MODE(regs) && (regs->siebk->zone != dev->pmcw.zone || !(dev->pmcw.flag27 & PMCW27_I))) { release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_INST); } #endif /* If the device is busy then signal the device to clear */ if ((dev->busy && dev->ioactive == DEV_SYS_LOCAL) || dev->startpending) { /* Set clear pending condition */ dev->scsw.flag2 |= SCSW2_FC_CLEAR | SCSW2_AC_CLEAR; /* Signal the subchannel to resume if it is suspended */ if (dev->scsw.flag3 & SCSW3_AC_SUSP) { dev->scsw.flag2 |= SCSW2_AC_RESUM; signal_condition (&dev->resumecond); } #if !defined(NO_SIGABEND_HANDLER) else { if( dev->ctctype ) signal_thread(dev->tid, SIGUSR2); } #endif /*!defined(NO_SIGABEND_HANDLER)*/ } else { /* [15.3.2] Perform clear function subchannel modification */ dev->pmcw.pom = 0xFF; dev->pmcw.lpum = 0x00; dev->pmcw.pnom = 0x00; /* [15.3.3] Perform clear function signaling and completion */ dev->scsw.flag0 = 0; dev->scsw.flag1 = 0; dev->scsw.flag2 &= ~(SCSW2_FC | SCSW2_AC); dev->scsw.flag2 |= SCSW2_FC_CLEAR; dev->scsw.flag3 &= (~(SCSW3_AC | SCSW3_SC))&0xff; dev->scsw.flag3 |= SCSW3_SC_PEND; store_fw (dev->scsw.ccwaddr, 0); dev->scsw.chanstat = 0; dev->scsw.unitstat = 0; store_hw (dev->scsw.count, 0); dev->pcipending = 0; dev->pending = 1; pending = 1; /* For 3270 device, clear any pending input */ if (dev->devtype == 0x3270) { dev->readpending = 0; dev->rlen3270 = 0; } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } } /* Queue any pending i/o interrupt */ if (pending) QUEUE_IO_INTERRUPT (&dev->ioint); release_lock (&dev->lock); /* Update interrupt status */ if (pending) { OBTAIN_INTLOCK(regs); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(regs); } } /* end function clear_subchan */ /*-------------------------------------------------------------------*/ /* HALT SUBCHANNEL */ /*-------------------------------------------------------------------*/ /* Input */ /* regs -> CPU register context */ /* dev -> Device control block */ /* Return value */ /* The return value is the condition code for the HSCH */ /* instruction: 0=Halt initiated, 1=Non-intermediate status */ /* pending, 2=Busy */ /*-------------------------------------------------------------------*/ int halt_subchan (REGS *regs, DEVBLK *dev) { int pending = 0; UNREFERENCED(regs); if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP056I %4.4X: Halt subchannel\n"), dev->devnum); obtain_lock (&dev->lock); #if defined(_FEATURE_IO_ASSIST) if(SIE_MODE(regs) && (regs->siebk->zone != dev->pmcw.zone || !(dev->pmcw.flag27 & PMCW27_I))) { release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_INST); } #endif /* Set condition code 1 if subchannel is status pending alone or is status pending with alert, primary, or secondary status */ if ((dev->scsw.flag3 & SCSW3_SC) == SCSW3_SC_PEND || ((dev->scsw.flag3 & SCSW3_SC_PEND) && (dev->scsw.flag3 & (SCSW3_SC_ALERT | SCSW3_SC_PRI | SCSW3_SC_SEC)))) { if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP057I %4.4X: Halt subchannel: cc=1\n"), dev->devnum); release_lock (&dev->lock); return 1; } /* Set condition code 2 if the halt function or the clear function is already in progress at the subchannel */ if (dev->scsw.flag2 & (SCSW2_AC_HALT | SCSW2_AC_CLEAR)) { if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP058I %4.4X: Halt subchannel: cc=2\n"), dev->devnum); release_lock (&dev->lock); return 2; } /* If the device is busy then signal subchannel to halt */ if ((dev->busy && dev->ioactive == DEV_SYS_LOCAL) || dev->startpending || dev->suspended) { /* Set halt pending condition and reset pending condition */ dev->scsw.flag2 |= (SCSW2_FC_HALT | SCSW2_AC_HALT); dev->scsw.flag3 &= ~SCSW3_SC_PEND; /* Clear any pending interrupt */ dev->pending = dev->pcipending = dev->attnpending = 0; /* Signal the subchannel to resume if it is suspended */ if (dev->scsw.flag3 & SCSW3_AC_SUSP) { dev->scsw.flag2 |= SCSW2_AC_RESUM; signal_condition (&dev->resumecond); } #if !defined(OPTION_FISHIO) /* Remove the device from the ioq if startpending */ obtain_lock(&sysblk.ioqlock); if(dev->startpending) { if(sysblk.ioq == dev) sysblk.ioq = dev->nextioq; else if ( sysblk.ioq != NULL ) /* add check for empty IOQ */ { DEVBLK *tmp; for(tmp = sysblk.ioq; tmp->nextioq != NULL && tmp->nextioq != dev; tmp = tmp->nextioq); if(tmp->nextioq == dev) tmp->nextioq = tmp->nextioq->nextioq; } } dev->startpending = 0; release_lock(&sysblk.ioqlock); #endif /*!defined(OPTION_FISHIO)*/ /* Invoke the provided halt_device routine @ISW */ /* if it has been provided by the handler @ISW */ /* code at init @ISW */ if(dev->halt_device!=NULL) /* @ISW */ { /* @ISW */ dev->halt_device(dev); /* @ISW */ } /* @ISW */ #if !defined(NO_SIGABEND_HANDLER) else { if( dev->ctctype && dev->tid) signal_thread(dev->tid, SIGUSR2); } #endif /*!defined(NO_SIGABEND_HANDLER)*/ } else { /* [15.4.2] Perform halt function signaling and completion */ dev->scsw.flag2 |= SCSW2_FC_HALT; dev->scsw.flag3 |= SCSW3_SC_PEND; dev->pcipending = 0; dev->pending = 1; pending = 1; /* For 3270 device, clear any pending input */ if (dev->devtype == 0x3270) { dev->readpending = 0; dev->rlen3270 = 0; } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } } /* Queue any pending i/o interrupt */ if (pending) QUEUE_IO_INTERRUPT (&dev->ioint); release_lock (&dev->lock); /* Update interrupt status */ if (pending) { OBTAIN_INTLOCK(regs); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(regs); } if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP059I %4.4X: Halt subchannel: cc=0\n"), dev->devnum); /* Return condition code zero */ return 0; } /* end function halt_subchan */ /*-------------------------------------------------------------------*/ /* RESUME SUBCHANNEL */ /*-------------------------------------------------------------------*/ /* Input */ /* regs -> CPU register context */ /* dev -> Device control block */ /* Return value */ /* The return value is the condition code for the RSCH */ /* instruction: 0=subchannel has been made resume pending, */ /* 1=status was pending, 2=resume not allowed */ /*-------------------------------------------------------------------*/ int resume_subchan (REGS *regs, DEVBLK *dev) { UNREFERENCED(regs); obtain_lock (&dev->lock); #if defined(_FEATURE_IO_ASSIST) if(SIE_MODE(regs) && (regs->siebk->zone != dev->pmcw.zone || !(dev->pmcw.flag27 & PMCW27_I))) { release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_INST); } #endif /* Set condition code 1 if subchannel has status pending */ if (dev->scsw.flag3 & SCSW3_SC_PEND) { if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP060I %4.4X: Resume subchannel: cc=1\n"), dev->devnum); release_lock (&dev->lock); return 1; } /* Set condition code 2 if subchannel has any function other than the start function alone, is already resume pending, or the ORB for the SSCH did not specify suspend control */ if ((dev->scsw.flag2 & SCSW2_FC) != SCSW2_FC_START || (dev->scsw.flag2 & SCSW2_AC_RESUM) || (dev->scsw.flag0 & SCSW0_S) == 0) { if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP061I %4.4X: Resume subchannel: cc=2\n"), dev->devnum); release_lock (&dev->lock); return 2; } /* Clear the path not-operational mask if in suspend state */ if (dev->scsw.flag3 & SCSW3_AC_SUSP) dev->pmcw.pnom = 0x00; /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Set the resume pending flag and signal the subchannel */ dev->scsw.flag2 |= SCSW2_AC_RESUM; signal_condition (&dev->resumecond); release_lock (&dev->lock); if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP062I %4.4X: Resume subchannel: cc=0\n"), dev->devnum); /* Return condition code zero */ return 0; } /* end function resume_subchan */ /*-------------------------------------------------------------------*/ /* Reset a device to initialized status */ /* */ /* Called by: */ /* channelset_reset */ /* chp_reset */ /* io_reset */ /* */ /* Caller holds `intlock' */ /*-------------------------------------------------------------------*/ void device_reset (DEVBLK *dev) { obtain_lock (&dev->lock); obtain_lock(&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->attnioint); release_lock(&sysblk.iointqlk); dev->busy = dev->reserved = dev->pending = dev->pcipending = dev->attnpending = dev->startpending = 0; dev->ioactive = DEV_SYS_NONE; if (dev->suspended) { dev->suspended = 0; signal_condition (&dev->resumecond); } if (dev->iowaiters) signal_condition (&dev->iocond); store_fw (dev->pmcw.intparm, 0); dev->pmcw.flag4 &= ~PMCW4_ISC; dev->pmcw.flag5 &= ~(PMCW5_E | PMCW5_LM | PMCW5_MM | PMCW5_D); dev->pmcw.pnom = 0; dev->pmcw.lpum = 0; store_hw (dev->pmcw.mbi, 0); dev->pmcw.flag27 &= ~PMCW27_S; #if defined(_FEATURE_IO_ASSIST) dev->pmcw.zone = 0; dev->pmcw.flag25 &= ~PMCW25_VISC; dev->pmcw.flag27 &= ~PMCW27_I; #endif memset (&dev->scsw, 0, sizeof(SCSW)); memset (&dev->pciscsw, 0, sizeof(SCSW)); memset (&dev->attnscsw, 0, sizeof(SCSW)); dev->readpending = 0; dev->crwpending = 0; dev->ckdxtdef = 0; dev->ckdsetfm = 0; dev->ckdlcount = 0; dev->ckdssi = 0; memset (dev->sense, 0, sizeof(dev->sense)); dev->sns_pending = 0; memset (dev->pgid, 0, sizeof(dev->pgid)); /* By Adrian - Reset drive password */ memset (dev->drvpwd, 0, sizeof(dev->drvpwd)); #if defined(_FEATURE_IO_ASSIST) dev->mainstor = sysblk.mainstor; dev->storkeys = sysblk.storkeys; dev->mainlim = sysblk.mainsize - 1; #endif dev->ioint.dev = dev; dev->ioint.pending = 1; dev->pciioint.dev = dev; dev->pciioint.pcipending = 1; dev->attnioint.dev = dev; dev->attnioint.attnpending = 1; #if defined(FEATURE_VM_BLOCKIO) if (dev->vmd250env) { free(dev->vmd250env); dev->vmd250env = 0 ; } #endif /* defined(FEATURE_VM_BLOCKIO) */ release_lock (&dev->lock); } /* end device_reset() */ /*-------------------------------------------------------------------*/ /* Reset all devices on a particular channelset */ /* */ /* Called by: */ /* SIGP_IMPL (control.c) */ /* SIGP_IPR (control.c) */ /*-------------------------------------------------------------------*/ void channelset_reset(REGS *regs) { DEVBLK *dev; /* -> Device control block */ int console = 0; /* 1 = console device reset */ /* Reset each device in the configuration */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { if( regs->chanset == dev->chanset) { if (dev->console) console = 1; device_reset(dev); } } /* Signal console thread to redrive select */ if (console) SIGNAL_CONSOLE_THREAD(); } /* end function channelset_reset */ /*-------------------------------------------------------------------*/ /* Reset all devices on a particular chpid */ /* */ /* Called by: */ /* RHCP (Reset Channel Path) (io.c) */ /*-------------------------------------------------------------------*/ int chp_reset(REGS *regs, BYTE chpid) { DEVBLK *dev; /* -> Device control block */ int i; int operational = 3; int console = 0; OBTAIN_INTLOCK(regs); /* Reset each device in the configuration */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { for(i = 0; i < 8; i++) { if((chpid == dev->pmcw.chpid[i]) && (dev->pmcw.pim & dev->pmcw.pam & dev->pmcw.pom & (0x80 >> i)) ) { operational = 0; if (dev->console) console = 1; device_reset(dev); } } } /* Signal console thread to redrive select */ if (console) SIGNAL_CONSOLE_THREAD(); RELEASE_INTLOCK(regs); return operational; } /* end function chp_reset */ /*-------------------------------------------------------------------*/ /* I/O RESET */ /* Resets status of all devices ready for IPL. Note that device */ /* positioning is not affected by I/O reset; thus the system can */ /* be IPLed from current position in a tape or card reader file. */ /* */ /* Caller holds `intlock' */ /*-------------------------------------------------------------------*/ void io_reset (void) { DEVBLK *dev; /* -> Device control block */ int console = 0; /* 1 = console device reset */ int i; /* reset sclp interface */ sclp_reset(); /* Connect each channel set to its home cpu */ for (i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i)) sysblk.regs[i]->chanset = i < FEATURE_LCSS_MAX ? i : 0xFFFF; /* Reset each device in the configuration */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { if (dev->console) console = 1; device_reset(dev); } /* No crws pending anymore */ OFF_IC_CHANRPT; /* Signal console thread to redrive select */ if (console) SIGNAL_CONSOLE_THREAD(); } /* end function io_reset */ #if !defined(OPTION_FISHIO) /*-------------------------------------------------------------------*/ /* Set a thread's priority to its proper value */ /*-------------------------------------------------------------------*/ void adjust_thread_priority(int *newprio) { /* Set root mode in order to set priority */ SETMODE(ROOT); /* Set device thread priority; ignore any errors */ setpriority(PRIO_PROCESS, 0, *newprio); /* Back to user mode */ SETMODE(USER); } /*-------------------------------------------------------------------*/ /* Execute a queued I/O */ /*-------------------------------------------------------------------*/ void *device_thread (void *arg) { char thread_name[32]; DEVBLK *dev; int current_priority; /* Current thread priority */ UNREFERENCED(arg); adjust_thread_priority(&sysblk.devprio); current_priority = getpriority(PRIO_PROCESS, 0); obtain_lock(&sysblk.ioqlock); sysblk.devtnbr++; if (sysblk.devtnbr > sysblk.devthwm) sysblk.devthwm = sysblk.devtnbr; while (1) { while ((dev=sysblk.ioq) != NULL) { snprintf ( thread_name, sizeof(thread_name), "device %4.4X thread", dev->devnum ); thread_name[sizeof(thread_name)-1]=0; SET_THREAD_NAME(thread_name); sysblk.ioq = dev->nextioq; dev->tid = thread_id(); /* Set priority to requested device priority */ if (dev->devprio != current_priority) adjust_thread_priority(&dev->devprio); current_priority = dev->devprio; release_lock (&sysblk.ioqlock); call_execute_ccw_chain(sysblk.arch_mode, dev); obtain_lock(&sysblk.ioqlock); dev->tid = 0; } SET_THREAD_NAME("idle device thread"); if (sysblk.devtmax < 0 || (sysblk.devtmax == 0 && sysblk.devtwait > 3) || (sysblk.devtmax > 0 && sysblk.devtnbr > sysblk.devtmax) || (sysblk.shutdown)) break; /* Wait for work to arrive */ sysblk.devtwait++; wait_condition (&sysblk.ioqcond, &sysblk.ioqlock); } sysblk.devtnbr--; release_lock (&sysblk.ioqlock); return NULL; } /* end function device_thread */ #endif // !defined(OPTION_FISHIO) #endif /*!defined(_CHANNEL_C)*/ /*-------------------------------------------------------------------*/ /* RAISE A PCI INTERRUPT */ /* This function is called during execution of a channel program */ /* whenever a CCW is fetched which has the CCW_FLAGS_PCI flag set */ /*-------------------------------------------------------------------*/ /* Input */ /* dev -> Device control block */ /* ccwkey = Key in which channel program is executing */ /* ccwfmt = CCW format (0 or 1) */ /* ccwaddr = Address of next CCW */ /* Output */ /* The PCI CSW or SCSW is saved in the device block, and the */ /* pcipending flag is set, and an I/O interrupt is scheduled. */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(raise_pci) ( DEVBLK *dev, /* -> Device block */ BYTE ccwkey, /* Bits 0-3=key, 4-7=zeroes */ BYTE ccwfmt, /* CCW format (0 or 1) */ U32 ccwaddr) /* Main storage addr of CCW */ { #if !defined(FEATURE_CHANNEL_SUBSYSTEM) UNREFERENCED(ccwfmt); #endif IODELAY(dev); obtain_lock (&dev->lock); #ifdef FEATURE_S370_CHANNEL /* Save the PCI CSW replacing any previous pending PCI */ dev->pcicsw[0] = ccwkey; dev->pcicsw[1] = (ccwaddr & 0xFF0000) >> 16; dev->pcicsw[2] = (ccwaddr & 0xFF00) >> 8; dev->pcicsw[3] = ccwaddr & 0xFF; dev->pcicsw[4] = 0; dev->pcicsw[5] = CSW_PCI; dev->pcicsw[6] = 0; dev->pcicsw[7] = 0; #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM dev->pciscsw.flag0 = ccwkey & SCSW0_KEY; dev->pciscsw.flag1 = (ccwfmt == 1 ? SCSW1_F : 0); dev->pciscsw.flag2 = SCSW2_FC_START; dev->pciscsw.flag3 = SCSW3_AC_SCHAC | SCSW3_AC_DEVAC | SCSW3_SC_INTER | SCSW3_SC_PEND; STORE_FW(dev->pciscsw.ccwaddr,ccwaddr); dev->pciscsw.unitstat = 0; dev->pciscsw.chanstat = CSW_PCI; store_hw (dev->pciscsw.count, 0); #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Queue the PCI pending interrupt */ QUEUE_IO_INTERRUPT(&dev->pciioint); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(devregs(dev)); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); } /* end function raise_pci */ /*-------------------------------------------------------------------*/ /* FETCH A CHANNEL COMMAND WORD FROM MAIN STORAGE */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(fetch_ccw) ( DEVBLK *dev, /* -> Device block */ BYTE ccwkey, /* Bits 0-3=key, 4-7=zeroes */ BYTE ccwfmt, /* CCW format (0 or 1) @IWZ*/ U32 ccwaddr, /* Main storage addr of CCW */ BYTE *code, /* Returned operation code */ U32 *addr, /* Returned data address */ BYTE *flags, /* Returned flags */ U16 *count, /* Returned data count */ BYTE *chanstat) /* Returned channel status */ { BYTE storkey; /* Storage key */ BYTE *ccw; /* CCW pointer */ UNREFERENCED_370(dev); *code=0; *count=0; *flags=0; *addr=0; /* Channel program check if CCW is not on a doubleword boundary or is outside limit of main storage */ if ( (ccwaddr & 0x00000007) || CHADDRCHK(ccwaddr, dev) ) { *chanstat = CSW_PROGC; return; } /* Channel protection check if CCW is fetch protected */ storkey = STORAGE_KEY(ccwaddr, dev); if (ccwkey != 0 && (storkey & STORKEY_FETCH) && (storkey & STORKEY_KEY) != ccwkey) { *chanstat = CSW_PROTC; return; } /* Set the main storage reference bit for the CCW location */ STORAGE_KEY(ccwaddr, dev) |= STORKEY_REF; /* Point to the CCW in main storage */ ccw = dev->mainstor + ccwaddr; /* Extract CCW opcode, flags, byte count, and data address */ if (ccwfmt == 0) { *code = ccw[0]; *addr = ((U32)(ccw[1]) << 16) | ((U32)(ccw[2]) << 8) | ccw[3]; *flags = ccw[4]; *count = ((U16)(ccw[6]) << 8) | ccw[7]; } else { *code = ccw[0]; *flags = ccw[1]; *count = ((U16)(ccw[2]) << 8) | ccw[3]; *addr = ((U32)(ccw[4]) << 24) | ((U32)(ccw[5]) << 16) | ((U32)(ccw[6]) << 8) | ccw[7]; } } /* end function fetch_ccw */ /*-------------------------------------------------------------------*/ /* FETCH AN INDIRECT DATA ADDRESS WORD FROM MAIN STORAGE */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(fetch_idaw) ( DEVBLK *dev, /* -> Device block */ BYTE code, /* CCW operation code */ BYTE ccwkey, /* Bits 0-3=key, 4-7=zeroes */ BYTE idawfmt, /* IDAW format (1 or 2) @IWZ*/ U16 idapmask, /* IDA page size - 1 @IWZ*/ int idaseq, /* 0=1st IDAW */ U32 idawaddr, /* Main storage addr of IDAW */ RADR *addr, /* Returned IDAW content @IWZ*/ U16 *len, /* Returned IDA data length */ BYTE *chanstat) /* Returned channel status */ { RADR idaw; /* Contents of IDAW @IWZ*/ U32 idaw1; /* Format-1 IDAW @IWZ*/ U64 idaw2; /* Format-2 IDAW @IWZ*/ RADR idapage; /* Addr of next IDA page @IWZ*/ U16 idalen; /* #of bytes until next page */ BYTE storkey; /* Storage key */ UNREFERENCED_370(dev); *addr = 0; *len = 0; /* Channel program check if IDAW is not on correct @IWZ boundary or is outside limit of main storage */ if ((idawaddr & ((idawfmt == 2) ? 0x07 : 0x03)) /*@IWZ*/ || CHADDRCHK(idawaddr, dev) ) { *chanstat = CSW_PROGC; return; } /* Channel protection check if IDAW is fetch protected */ storkey = STORAGE_KEY(idawaddr, dev); if (ccwkey != 0 && (storkey & STORKEY_FETCH) && (storkey & STORKEY_KEY) != ccwkey) { *chanstat = CSW_PROTC; return; } /* Set the main storage reference bit for the IDAW location */ STORAGE_KEY(idawaddr, dev) |= STORKEY_REF; /* Fetch IDAW from main storage */ if (idawfmt == 2) /*@IWZ*/ { /*@IWZ*/ /* Fetch format-2 IDAW */ /*@IWZ*/ FETCH_DW(idaw2, dev->mainstor + idawaddr); /*@IWZ*/ #ifndef FEATURE_ESAME /*@IWZ*/ /* Channel program check in ESA/390 mode if the format-2 IDAW exceeds 2GB-1 */ /*@IWZ*/ if (idaw2 > 0x7FFFFFFF) /*@IWZ*/ { /*@IWZ*/ *chanstat = CSW_PROGC; /*@IWZ*/ return; /*@IWZ*/ } /*@IWZ*/ #endif /*!FEATURE_ESAME*/ /*@IWZ*/ /* Save contents of format-2 IDAW */ /*@IWZ*/ idaw = idaw2; /*@IWZ*/ } /*@IWZ*/ else /*@IWZ*/ { /*@IWZ*/ /* Fetch format-1 IDAW */ /*@IWZ*/ FETCH_FW(idaw1, dev->mainstor + idawaddr); /*@IWZ*/ /* Channel program check if bit 0 of the format-1 IDAW is not zero */ /*@IWZ*/ if (idaw1 & 0x80000000) /*@IWZ*/ { /*@IWZ*/ *chanstat = CSW_PROGC; /*@IWZ*/ return; /*@IWZ*/ } /*@IWZ*/ /* Save contents of format-1 IDAW */ /*@IWZ*/ idaw = idaw1; /*@IWZ*/ } /*@IWZ*/ /* Channel program check if IDAW data location is outside main storage */ if ( CHADDRCHK(idaw, dev) ) { *chanstat = CSW_PROGC; return; } /* Channel program check if IDAW data location is not on a page boundary, except for the first IDAW */ /*@IWZ*/ if (IS_CCW_RDBACK (code)) { if (idaseq > 0 && ((idaw+1) & idapmask) != 0) { *chanstat = CSW_PROGC; return; } /* Calculate address of next page boundary */ idapage = (idaw & ~idapmask); idalen = (idaw - idapage) + 1; /* Return the address and length for this IDAW */ *addr = idaw; *len = idalen; } else { if (idaseq > 0 && (idaw & idapmask) != 0) /*@IWZ*/ { *chanstat = CSW_PROGC; return; } /* Calculate address of next page boundary */ /*@IWZ*/ idapage = (idaw + idapmask + 1) & ~idapmask; /*@IWZ*/ idalen = idapage - idaw; /* Return the address and length for this IDAW */ *addr = idaw; *len = idalen; } } /* end function fetch_idaw */ #if defined(FEATURE_MIDAW) /*@MW*/ /*-------------------------------------------------------------------*/ /* FETCH A MODIFIED INDIRECT DATA ADDRESS WORD FROM MAIN STORAGE @MW*/ /*-------------------------------------------------------------------*/ static void ARCH_DEP(fetch_midaw) ( /*@MW*/ DEVBLK *dev, /* -> Device block */ BYTE code, /* CCW operation code */ BYTE ccwkey, /* Bits 0-3=key, 4-7=zeroes */ int midawseq, /* 0=1st MIDAW */ U32 midawadr, /* Main storage addr of MIDAW*/ RADR *addr, /* Returned MIDAW content */ U16 *len, /* Returned MIDAW data length*/ BYTE *flags, /* Returned MIDAW flags */ BYTE *chanstat) /* Returned channel status */ { U64 mword1, mword2; /* MIDAW high and low words */ RADR mdaddr; /* Data address from MIDAW */ U16 mcount; /* Count field from MIDAW */ BYTE mflags; /* Flags byte from MIDAW */ BYTE storkey; /* Storage key */ U16 maxlen; /* Maximum allowable length */ UNREFERENCED_370(dev); /* Channel program check if MIDAW is not on quadword boundary or is outside limit of main storage */ if ((midawadr & 0x0F) || CHADDRCHK(midawadr, dev) ) { *chanstat = CSW_PROGC; return; } /* Channel program check if MIDAW list crosses a page boundary */ if (midawseq > 0 && (midawadr & PAGEFRAME_BYTEMASK) == 0) { *chanstat = CSW_PROGC; return; } /* Channel protection check if MIDAW is fetch protected */ storkey = STORAGE_KEY(midawadr, dev); if (ccwkey != 0 && (storkey & STORKEY_FETCH) && (storkey & STORKEY_KEY) != ccwkey) { *chanstat = CSW_PROTC; return; } /* Set the main storage reference bit for the MIDAW location */ STORAGE_KEY(midawadr, dev) |= STORKEY_REF; /* Fetch MIDAW from main storage (MIDAW is quadword aligned and so cannot cross a page boundary) */ FETCH_DW(mword1, dev->mainstor + midawadr); FETCH_DW(mword2, dev->mainstor + midawadr + 8); /* Channel program check in reserved bits are non-zero */ if (mword1 & 0xFFFFFFFFFF000000ULL) { *chanstat = CSW_PROGC; return; } /* Extract fields from MIDAW */ mflags = mword1 >> 16; mcount = mword1 & 0xFFFF; mdaddr = (RADR)mword2; /* Channel program check if data transfer interrupt flag is set */ if (mflags & MIDAW_DTI) { *chanstat = CSW_PROGC; return; } /* Channel program check if MIDAW count is zero */ if (mcount == 0) { *chanstat = CSW_PROGC; return; } /* Channel program check if MIDAW data location is outside main storage */ if ( CHADDRCHK(mdaddr, dev) ) { *chanstat = CSW_PROGC; return; } /* Channel program check if skipping not in effect and the MIDAW data area crosses a page boundary */ maxlen = (IS_CCW_RDBACK(code)) ? mdaddr - (mdaddr & PAGEFRAME_PAGEMASK) + 1 : (mdaddr | PAGEFRAME_BYTEMASK) - mdaddr + 1 ; if ((mflags & MIDAW_SKIP) == 0 && mcount > maxlen) { *chanstat = CSW_PROGC; return; } /* Return the data address, length, flags for this MIDAW */ *addr = mdaddr; *len = mcount; *flags = mflags; } /* end function fetch_midaw */ /*@MW*/ #endif /*defined(FEATURE_MIDAW)*/ /*@MW*/ /*-------------------------------------------------------------------*/ /* COPY DATA BETWEEN CHANNEL I/O BUFFER AND MAIN STORAGE */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(copy_iobuf) ( DEVBLK *dev, /* -> Device block */ BYTE code, /* CCW operation code */ BYTE flags, /* CCW flags */ U32 addr, /* Data address */ U16 count, /* Data count */ BYTE ccwkey, /* Protection key */ BYTE idawfmt, /* IDAW format (1 or 2) @IWZ*/ U16 idapmask, /* IDA page size - 1 @IWZ*/ BYTE *iobuf, /* -> Channel I/O buffer */ BYTE *chanstat) /* Returned channel status */ { U32 idawaddr; /* Main storage addr of IDAW */ U16 idacount; /* IDA bytes remaining */ int idaseq; /* IDA sequence number */ RADR idadata; /* IDA data address @IWZ*/ U16 idalen; /* IDA data length */ BYTE storkey; /* Storage key */ RADR page,startpage,endpage; /* Storage key pages */ BYTE readcmd; /* 1=READ, SENSE, or RDBACK */ BYTE area[64]; /* Data display area */ #if defined(FEATURE_MIDAW) /*@MW*/ int midawseq; /* MIDAW counter (0=1st) @MW*/ U32 midawptr; /* Real addr of MIDAW @MW*/ U16 midawrem; /* CCW bytes remaining @MW*/ U16 midawlen=0; /* MIDAW data length @MW*/ RADR midawdat=0; /* MIDAW data area addr @MW*/ BYTE midawflg; /* MIDAW flags @MW*/ #endif /*defined(FEATURE_MIDAW)*/ /*@MW*/ /* Exit if no bytes are to be copied */ if (count == 0) return; /* Set flag to indicate direction of data movement */ readcmd = IS_CCW_READ(code) || IS_CCW_SENSE(code) || IS_CCW_RDBACK(code); #if defined(FEATURE_MIDAW) /*@MW*/ /* Move data when modified indirect data addressing is used */ if (flags & CCW_FLAGS_MIDAW) { midawptr = addr; midawrem = count; midawflg = 0; for (midawseq = 0; midawrem > 0 && (midawflg & MIDAW_LAST) == 0; midawseq++) { /* Fetch MIDAW and set data address, length, flags */ ARCH_DEP(fetch_midaw) (dev, code, ccwkey, midawseq, midawptr, &midawdat, &midawlen, &midawflg, chanstat); /* Exit if fetch_midaw detected channel program check */ if (*chanstat != 0) return; /* Channel program check if MIDAW length exceeds the remaining CCW count */ if (midawlen > midawrem) { *chanstat = CSW_PROGC; return; } /* Perform data movement unless SKIP flag is set in MIDAW */ if ((midawflg & MIDAW_SKIP) ==0) { /* Note: MIDAW data area cannot cross a page boundary The fetch_midaw function enforces this restriction */ /* Channel protection check if MIDAW data location is fetch protected, or if location is store protected and command is READ, READ BACKWARD, or SENSE */ storkey = STORAGE_KEY(midawdat, dev); if (ccwkey != 0 && (storkey & STORKEY_KEY) != ccwkey && ((storkey & STORKEY_FETCH) || readcmd)) { *chanstat = CSW_PROTC; return; } /* Set the main storage reference and change bits */ STORAGE_KEY(midawdat, dev) |= (readcmd ? (STORKEY_REF|STORKEY_CHANGE) : STORKEY_REF); /* Copy data between main storage and channel buffer */ if (IS_CCW_RDBACK(code)) { midawdat = (midawdat - midawlen) + 1; memcpy (dev->mainstor + midawdat, iobuf + dev->curblkrem + midawrem - midawlen, midawlen); /* Decrement buffer pointer */ iobuf -= midawlen; } else { if (readcmd) memcpy (dev->mainstor + midawdat, iobuf, midawlen); else memcpy (iobuf, dev->mainstor + midawdat, midawlen); /* Increment buffer pointer */ iobuf += midawlen; } } /* end if(!MIDAW_FLAG_SKIP) */ /* Display the MIDAW if CCW tracing is on */ if (dev->ccwtrace || dev->ccwstep) { format_iobuf_data (midawdat, area, dev); logmsg ( _("HHCCP078I " "%4.4X:MIDAW=%2.2X %4.4"I16_FMT"X %16.16"I64_FMT"X\n" "%4.4X:------------- %s\n"), dev->devnum, midawflg, midawlen, (U64)midawdat, dev->devnum, area); } /* Decrement remaining count */ midawrem -= midawlen; /* Increment to next MIDAW address */ midawptr += 16; } /* end for(midawseq) */ /* Channel program check if sum of MIDAW lengths did not exhaust the CCW count */ if (midawrem > 0) { *chanstat = CSW_PROGC; return; } } /* end if(CCW_FLAGS_MIDAW) */ /*@MW*/ else /*@MW*/ #endif /*defined(FEATURE_MIDAW)*/ /*@MW*/ /* Move data when indirect data addressing is used */ if (flags & CCW_FLAGS_IDA) { idawaddr = addr; idacount = count; for (idaseq = 0; idacount > 0; idaseq++) { /* Fetch the IDAW and set IDA pointer and length */ ARCH_DEP(fetch_idaw) (dev, code, ccwkey, idawfmt, /*@IWZ*/ idapmask, idaseq, idawaddr, /*@IWZ*/ &idadata, &idalen, chanstat); /* Exit if fetch_idaw detected channel program check */ if (*chanstat != 0) return; /* Channel protection check if IDAW data location is fetch protected, or if location is store protected and command is READ, READ BACKWARD, or SENSE */ storkey = STORAGE_KEY(idadata, dev); if (ccwkey != 0 && (storkey & STORKEY_KEY) != ccwkey && ((storkey & STORKEY_FETCH) || readcmd)) { *chanstat = CSW_PROTC; return; } /* Reduce length if less than one page remaining */ if (idalen > idacount) idalen = idacount; /* Set the main storage reference and change bits */ STORAGE_KEY(idadata, dev) |= (readcmd ? (STORKEY_REF|STORKEY_CHANGE) : STORKEY_REF); /* Copy data between main storage and channel buffer */ if (IS_CCW_RDBACK(code)) { idadata = (idadata - idalen) + 1; memcpy (dev->mainstor + idadata, iobuf + dev->curblkrem + idacount - idalen, idalen); } else { if (readcmd) memcpy (dev->mainstor + idadata, iobuf, idalen); else memcpy (iobuf, dev->mainstor + idadata, idalen); /* JRJ: I believe that the following line of code code is suspect, because data chaining adds the used length later, as needed. Also, I note that this kind of thing is not done in non-IDA mode. Finally, since iobuf is not used for anything after this (in IDA mode), it probably doesn't hurt anything. */ /* rbowler: I disagree with the above comment. Here we are in a loop processing a list of IDAWs and it is necessary to update the iobuf pointer so that it is correctly positioned ready for the data to be read or written by the subsequent IDAW */ /* Increment buffer pointer */ iobuf += idalen; } /* Display the IDAW if CCW tracing is on */ if (dev->ccwtrace || dev->ccwstep) { format_iobuf_data (idadata, area, dev); if (idawfmt == 1) /*@IWZ*/ { /*@IWZ*/ logmsg ( _("HHCCP063I " /*@IWZ*/ "%4.4X:IDAW=%8.8"I32_FMT"X Len=%3.3"I16_FMT"X%s\n"), dev->devnum, (U32)idadata, idalen, /*@IWZ*/ area); /*@IWZ*/ } else { /*@IWZ*/ logmsg ( _("HHCCP064I " /*@IWZ*/ "%4.4X:IDAW=%16.16"I64_FMT"X Len=%4.4"I16_FMT"X\n" "%4.4X:---------------------%s\n"), /*@IWZ*/ dev->devnum, (U64)idadata, idalen, dev->devnum, area); /*@IWZ*/ } } /* Decrement remaining count, increment buffer pointer */ idacount -= idalen; /* Increment to next IDAW address */ idawaddr += (idawfmt == 1) ? 4 : 8; } /* end for(idaseq) */ } else { /* Non-IDA data addressing */ /* Point to start of data for read backward command */ if (IS_CCW_RDBACK (code)) { addr = addr - count + 1; } /* Channel program check if data is outside main storage */ if ( CHADDRCHK(addr, dev) || CHADDRCHK(addr + (count - 1), dev) ) { *chanstat = CSW_PROGC; return; } /* Channel protection check if any data is fetch protected, or if location is store protected and command is READ, READ BACKWARD, or SENSE */ startpage = addr; endpage = addr + (count - 1); for (page = startpage & STORAGE_KEY_PAGEMASK; page <= (endpage | STORAGE_KEY_BYTEMASK); page += STORAGE_KEY_PAGESIZE) { storkey = STORAGE_KEY(page, dev); if (ccwkey != 0 && (storkey & STORKEY_KEY) != ccwkey && ((storkey & STORKEY_FETCH) || readcmd)) { *chanstat = CSW_PROTC; return; } } /* end for(page) */ /* Set the main storage reference and change bits */ for (page = startpage & STORAGE_KEY_PAGEMASK; page <= (endpage | STORAGE_KEY_BYTEMASK); page += STORAGE_KEY_PAGESIZE) { STORAGE_KEY(page, dev) |= (readcmd ? (STORKEY_REF|STORKEY_CHANGE) : STORKEY_REF); } /* end for(page) */ /* Copy data between main storage and channel buffer */ if (readcmd) { if (IS_CCW_RDBACK(code)) { /* read backward - use END of buffer */ memcpy(dev->mainstor + addr,iobuf + dev->curblkrem, count); } else /* read forward */ { memcpy (dev->mainstor + addr, iobuf, count); } } else { memcpy (iobuf, dev->mainstor + addr, count); } } /* end if(!IDA) */ } /* end function copy_iobuf */ /*-------------------------------------------------------------------*/ /* DEVICE ATTENTION */ /* Raises an unsolicited interrupt condition for a specified device. */ /* Return value is 0 if successful, 1 if device is busy or pending */ /* or 3 if subchannel is not valid or not enabled */ /*-------------------------------------------------------------------*/ DLL_EXPORT int ARCH_DEP(device_attention) (DEVBLK *dev, BYTE unitstat) { obtain_lock (&dev->lock); if (dev->hnd->attention) (dev->hnd->attention) (dev); #ifdef FEATURE_CHANNEL_SUBSYSTEM /* If subchannel not valid and enabled, do not present interrupt */ if ((dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0) { release_lock (&dev->lock); return 3; } #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* If device is already busy or interrupt pending */ if (dev->busy || IOPENDING(dev) || (dev->scsw.flag3 & SCSW3_SC_PEND)) { /* Resume the suspended device with attention set */ if(dev->scsw.flag3 & SCSW3_AC_SUSP) { dev->scsw.flag3 |= SCSW3_SC_ALERT | SCSW3_SC_PEND; dev->scsw.unitstat |= unitstat; dev->scsw.flag2 |= SCSW2_AC_RESUM; signal_condition(&dev->resumecond); release_lock (&dev->lock); if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP065I DEV%4.4X: attention signalled\n"), dev->devnum); return 0; } release_lock (&dev->lock); return 1; } if (dev->ccwtrace || dev->ccwstep) logmsg (_("HHCCP066I DEV%4.4X: attention\n"), dev->devnum); #ifdef FEATURE_S370_CHANNEL /* Set CSW for attention interrupt */ dev->attncsw[0] = 0; dev->attncsw[1] = 0; dev->attncsw[2] = 0; dev->attncsw[3] = 0; dev->attncsw[4] = unitstat; dev->attncsw[5] = 0; dev->attncsw[6] = 0; dev->attncsw[7] = 0; #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Set SCSW for attention interrupt */ dev->attnscsw.flag0 = 0; dev->attnscsw.flag1 = 0; dev->attnscsw.flag2 = 0; dev->attnscsw.flag3 = SCSW3_SC_ALERT | SCSW3_SC_PEND; store_fw (dev->attnscsw.ccwaddr, 0); dev->attnscsw.unitstat = unitstat; dev->attnscsw.chanstat = 0; store_hw (dev->attnscsw.count, 0); #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Queue the attention interrupt */ QUEUE_IO_INTERRUPT (&dev->attnioint); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(devregs(dev)); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); return 0; } /* end function device_attention */ /*-------------------------------------------------------------------*/ /* START A CHANNEL PROGRAM */ /* This function is called by the SIO and SSCH instructions */ /*-------------------------------------------------------------------*/ /* Input */ /* dev -> Device control block */ /* orb -> Operation request block @IWZ*/ /* Output */ /* The I/O parameters are stored in the device block, and a */ /* thread is created to execute the CCW chain asynchronously. */ /* The return value is the condition code for the SIO or */ /* SSCH instruction. */ /* Note */ /* For S/370 SIO, only the protect key and CCW address are */ /* valid, all other ORB parameters are set to zero. */ /*-------------------------------------------------------------------*/ int ARCH_DEP(startio) (REGS *regs, DEVBLK *dev, ORB *orb) /*@IWZ*/ { int syncio; /* 1=Do synchronous I/O */ #if !defined(OPTION_FISHIO) int rc; /* Return code */ DEVBLK *previoq, *ioq; /* Device I/O queue pointers */ #endif // !defined(OPTION_FISHIO) obtain_lock (&dev->lock); dev->regs = NULL; dev->syncio_active = dev->syncio_retry = 0; #if defined(_FEATURE_IO_ASSIST) if(SIE_MODE(regs) && (regs->siebk->zone != dev->pmcw.zone || !(dev->pmcw.flag27 & PMCW27_I))) { release_lock (&dev->lock); longjmp(regs->progjmp,SIE_INTERCEPT_INST); } #endif #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Return condition code 1 if status pending */ if ((dev->scsw.flag3 & SCSW3_SC_PEND) || (dev->pciscsw.flag3 & SCSW3_SC_PEND) || (dev->attnscsw.flag3 & SCSW3_SC_PEND)) { release_lock (&dev->lock); return 1; } #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Return condition code 2 if device is busy */ if ((dev->busy && dev->ioactive == DEV_SYS_LOCAL) || dev->startpending) { release_lock (&dev->lock); return 2; } /* Set the device busy indicator */ dev->busy = dev->startpending = 1; /* Initialize the subchannel status word */ memset (&dev->scsw, 0, sizeof(SCSW)); memset (&dev->pciscsw, 0, sizeof(SCSW)); memset (&dev->attnscsw, 0, sizeof(SCSW)); dev->scsw.flag0 = (orb->flag4 & SCSW0_KEY); /*@IWZ*/ if (orb->flag4 & ORB4_S) dev->scsw.flag0 |= SCSW0_S; /*@IWZ*/ if (orb->flag5 & ORB5_F) dev->scsw.flag1 |= SCSW1_F; /*@IWZ*/ if (orb->flag5 & ORB5_P) dev->scsw.flag1 |= SCSW1_P; /*@IWZ*/ if (orb->flag5 & ORB5_I) dev->scsw.flag1 |= SCSW1_I; /*@IWZ*/ if (orb->flag5 & ORB5_A) dev->scsw.flag1 |= SCSW1_A; /*@IWZ*/ if (orb->flag5 & ORB5_U) dev->scsw.flag1 |= SCSW1_U; /*@IWZ*/ /* Make the subchannel start-pending */ dev->scsw.flag2 = SCSW2_FC_START | SCSW2_AC_START; /* Copy the I/O parameter to the path management control word */ memcpy (dev->pmcw.intparm, orb->intparm, /*@IWZ*/ sizeof(dev->pmcw.intparm)); /*@IWZ*/ /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Store the start I/O parameters in the device block */ memcpy (&dev->orb, orb, sizeof(ORB)); /*@IWZ*/ /* Schedule the I/O. The various methods are a direct * correlation to the interest in the subject: * [1] Synchronous I/O. Attempts to complete the channel program * in the cpu thread to avoid any threads overhead. * [2] FishIO. Use native win32 APIs to coordinate I/O * thread scheduling. * [3] Device threads. Queue the I/O and signal a device thread. * Eliminates the overhead of thead creation/termination. * [4] Original. Create a thread to execute this I/O */ /* Determine if we can do synchronous I/O */ if (dev->syncio == 1) syncio = 1; else if (dev->syncio == 2 && fetch_fw(dev->orb.ccwaddr) < dev->mainlim) { dev->code = dev->mainstor[fetch_fw(dev->orb.ccwaddr)]; syncio = IS_CCW_TIC(dev->code) || IS_CCW_SENSE(dev->code) || IS_CCW_IMMEDIATE(dev); } else syncio = 0; if (syncio && dev->ioactive == DEV_SYS_NONE #ifdef OPTION_IODELAY_KLUDGE && sysblk.iodelay < 1 #endif /*OPTION_IODELAY_KLUDGE*/ ) { /* Initiate synchronous I/O */ dev->syncio_active = 1; dev->ioactive = DEV_SYS_LOCAL; dev->regs = regs; release_lock (&dev->lock); /* * `syncio' is set with intlock held. This allows * SYNCHRONIZE_CPUS to consider this CPU waiting while * performing synchronous i/o. */ if (regs->cpubit != sysblk.started_mask) { OBTAIN_INTLOCK(regs); regs->hostregs->syncio = 1; RELEASE_INTLOCK(regs); } call_execute_ccw_chain(sysblk.arch_mode, dev); /* Return if retry not required */ if (regs->hostregs->syncio) { OBTAIN_INTLOCK(regs); regs->hostregs->syncio = 0; RELEASE_INTLOCK(regs); } dev->regs = NULL; dev->syncio_active = 0; if (!dev->syncio_retry) return 0; /* * syncio_retry gets turned off after the execute ccw * device handler routine is called for the first time */ } else release_lock (&dev->lock); #if defined(OPTION_FISHIO) return ScheduleIORequest( dev, dev->devnum, &dev->devprio ); #else // !defined(OPTION_FISHIO) if (sysblk.devtmax >= 0) { /* Queue the I/O request */ obtain_lock (&sysblk.ioqlock); /* Insert the device into the I/O queue */ for (previoq = NULL, ioq = sysblk.ioq; ioq; ioq = ioq->nextioq) { if (dev->priority < ioq->priority) break; previoq = ioq; } dev->nextioq = ioq; if (previoq) previoq->nextioq = dev; else sysblk.ioq = dev; /* Signal a device thread if one is waiting, otherwise create a device thread if the maximum number hasn't been created */ if (sysblk.devtwait) { sysblk.devtwait--; signal_condition(&sysblk.ioqcond); } else if (sysblk.devtmax == 0 || sysblk.devtnbr < sysblk.devtmax) { rc = create_thread (&dev->tid, DETACHED, device_thread, NULL, "idle device thread"); if (rc != 0 && sysblk.devtnbr == 0) { logmsg (_("HHCCP067E %4.4X create_thread error: %s"), dev->devnum, strerror(errno)); release_lock (&sysblk.ioqlock); release_lock (&dev->lock); return 2; } } else sysblk.devtunavail++; release_lock (&sysblk.ioqlock); } else { char thread_name[32]; snprintf(thread_name,sizeof(thread_name), "execute %4.4X ccw chain",dev->devnum); thread_name[sizeof(thread_name)-1]=0; /* Execute the CCW chain on a separate thread */ if ( create_thread (&dev->tid, DETACHED, ARCH_DEP(execute_ccw_chain), dev, thread_name) ) { logmsg (_("HHCCP068E %4.4X create_thread error: %s"), dev->devnum, strerror(errno)); release_lock (&dev->lock); return 2; } } /* Return with condition code zero */ return 0; #endif // defined(OPTION_FISHIO) } /* end function startio */ /*-------------------------------------------------------------------*/ /* EXECUTE A CHANNEL PROGRAM */ /*-------------------------------------------------------------------*/ void *ARCH_DEP(execute_ccw_chain) (DEVBLK *dev) { int sysid = DEV_SYS_LOCAL; /* System Identifier */ U32 ccwaddr; /* Address of CCW @IWZ*/ U32 ticaddr = 0; /* Previous CCW was a TIC */ U16 idapmask; /* IDA page size - 1 @IWZ*/ BYTE idawfmt; /* IDAW format (1 or 2) @IWZ*/ BYTE ccwfmt; /* CCW format (0 or 1) @IWZ*/ BYTE ccwkey; /* Bits 0-3=key, 4-7=zero@IWZ*/ BYTE opcode; /* CCW operation code */ BYTE flags; /* CCW flags */ U32 addr; /* CCW data address */ #ifdef FEATURE_CHANNEL_SUBSYSTEM U32 mbaddr; /* Measure block address */ MBK *mbk; /* Measure block */ U16 mbcount; /* Measure block count */ #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ U16 count; /* CCW byte count */ BYTE *ccw; /* CCW pointer */ BYTE unitstat; /* Unit status */ BYTE chanstat; /* Channel status */ U16 residual; /* Residual byte count */ BYTE more; /* 1=Count exhausted */ BYTE chain = 1; /* 1=Chain to next CCW */ BYTE tracethis = 0; /* 1=Trace this CCW only */ BYTE area[64]; /* Message area */ int bufpos = 0; /* Position in I/O buffer */ BYTE iobuf[65536]; /* Channel I/O buffer */ int cmdretry = 255; /* Limit command retry */ /* Wait for the device to become available */ obtain_lock (&dev->lock); if (!dev->syncio_active && dev->shared) { while (dev->ioactive != DEV_SYS_NONE && dev->ioactive != sysid) { dev->iowaiters++; wait_condition(&dev->iocond, &dev->lock); dev->iowaiters--; } dev->ioactive = sysid; dev->busy = 1; if (sysid == DEV_SYS_LOCAL) dev->startpending = 0; } else { dev->ioactive = DEV_SYS_LOCAL; dev->startpending = 0; } #ifdef FEATURE_CHANNEL_SUBSYSTEM /* For hercules `resume' resume suspended state */ if (dev->resumesuspended) { dev->resumesuspended=0; goto resume_suspend; } #endif release_lock (&dev->lock); /* Call the i/o start exit */ if (!dev->syncio_retry) if (dev->hnd->start) (dev->hnd->start) (dev); /* Extract the I/O parameters from the ORB */ /*@IWZ*/ FETCH_FW(ccwaddr, dev->orb.ccwaddr); /*@IWZ*/ ccwfmt = (dev->orb.flag5 & ORB5_F) ? 1 : 0; /*@IWZ*/ ccwkey = dev->orb.flag4 & ORB4_KEY; /*@IWZ*/ idawfmt = (dev->orb.flag5 & ORB5_H) ? 2 : 1; /*@IWZ*/ /* Determine IDA page size */ /*@IWZ*/ if (idawfmt == 2) /*@IWZ*/ { /*@IWZ*/ /* Page size is 2K or 4K depending on flag bit */ /*@IWZ*/ idapmask = /*@IWZ*/ (dev->orb.flag5 & ORB5_T) ? 0x7FF : 0xFFF; /*@IWZ*/ } else { /*@IWZ*/ /* Page size is always 2K for format-1 IDAW */ /*@IWZ*/ idapmask = 0x7FF; /*@IWZ*/ } /*@IWZ*/ /* Turn off the start pending bit in the SCSW */ dev->scsw.flag2 &= ~SCSW2_AC_START; /* Set the subchannel active and device active bits in the SCSW */ dev->scsw.flag3 |= (SCSW3_AC_SCHAC | SCSW3_AC_DEVAC); /* Check for retried synchronous I/O */ if (dev->syncio_retry) { dev->syncios--; dev->asyncios++; ccwaddr = dev->syncio_addr; dev->code = dev->prevcode; dev->prevcode = 0; dev->chained &= ~CCW_FLAGS_CD; dev->prev_chained = 0; logdevtr (dev, "asynchronous I/O ccw addr %8.8x\n", ccwaddr); } else { dev->chained = dev->prev_chained = dev->code = dev->prevcode = dev->ccwseq = 0; } /* Check for synchronous I/O */ if (dev->syncio_active) { dev->syncios++; logdevtr (dev, "synchronous I/O ccw addr %8.8x\n", ccwaddr); } #if defined(_FEATURE_IO_ASSIST) #define _IOA_MBO sysblk.zpb[dev->pmcw.zone].mbo #define _IOA_MBM sysblk.zpb[dev->pmcw.zone].mbm #define _IOA_MBK sysblk.zpb[dev->pmcw.zone].mbk #else /*defined(_FEATURE_IO_ASSIST)*/ #define _IOA_MBO sysblk.mbo #define _IOA_MBM sysblk.mbm #define _IOA_MBK sysblk.mbk #endif /*defined(_FEATURE_IO_ASSIST)*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Update the measurement block if applicable */ if (_IOA_MBM && (dev->pmcw.flag5 & PMCW5_MM_MBU)) { mbaddr = _IOA_MBO; mbaddr += (dev->pmcw.mbi[0] << 8 | dev->pmcw.mbi[1]) << 5; if ( !CHADDRCHK(mbaddr, dev) && (((STORAGE_KEY(mbaddr, dev) & STORKEY_KEY) == _IOA_MBK) || (_IOA_MBK == 0))) { STORAGE_KEY(mbaddr, dev) |= (STORKEY_REF | STORKEY_CHANGE); mbk = (MBK*)&dev->mainstor[mbaddr]; FETCH_HW(mbcount,mbk->srcount); mbcount++; STORE_HW(mbk->srcount,mbcount); } else { /* Generate subchannel logout indicating program check or protection check, and set the subchannel measurement-block-update-enable to zero */ dev->pmcw.flag5 &= ~PMCW5_MM_MBU; dev->esw.scl0 |= !CHADDRCHK(mbaddr, dev) ? SCL0_ESF_MBPTK : SCL0_ESF_MBPGK; /*INCOMPLETE*/ } } /* Generate an initial status I/O interruption if requested */ if ((dev->scsw.flag1 & SCSW1_I) && !dev->syncio_retry) { IODELAY(dev); /* do the delay NOW, before obtaining the INTLOCK */ obtain_lock (&dev->lock); /* Update the CCW address in the SCSW */ STORE_FW(dev->scsw.ccwaddr,ccwaddr); /* Set the zero condition-code flag in the SCSW */ dev->scsw.flag1 |= SCSW1_Z; /* Set intermediate status in the SCSW */ dev->scsw.flag3 = SCSW3_SC_INTER | SCSW3_SC_PEND; /* Queue the interrupt */ QUEUE_IO_INTERRUPT (&dev->ioint); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(devregs(dev)); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); if (dev->ccwtrace || dev->ccwstep || tracethis) logmsg (_("HHCCP069I Device %4.4X initial status interrupt\n"), dev->devnum); } #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Execute the CCW chain */ /* On entry : No locks held */ while ( chain ) { /* Test for attention status from device */ if (dev->scsw.flag3 & SCSW3_SC_ALERT) { IODELAY(dev); /* Call the i/o end exit */ if (dev->hnd->end) (dev->hnd->end) (dev); obtain_lock (&dev->lock); /* Turn off busy bit, turn on pending bit */ dev->busy = 0; dev->pending = 1; /* Wake up any waiters if the device isn't reserved */ if (!dev->reserved) { dev->ioactive = DEV_SYS_NONE; if (dev->iowaiters) signal_condition (&dev->iocond); } /* Queue the pending interrupt */ QUEUE_IO_INTERRUPT (&dev->ioint); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(devregs(dev)); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); if (dev->ccwtrace || dev->ccwstep || tracethis) logmsg (_("HHCCP070I Device %4.4X attention completed\n"), dev->devnum); return NULL; } /* end attention processing */ /* Test for clear subchannel request */ if (dev->scsw.flag2 & SCSW2_AC_CLEAR) { IODELAY(dev); /* Call the i/o end exit */ if (dev->hnd->end) (dev->hnd->end) (dev); obtain_lock (&dev->lock); /* [15.3.2] Perform clear function subchannel modification */ dev->pmcw.pom = 0xFF; dev->pmcw.lpum = 0x00; dev->pmcw.pnom = 0x00; /* [15.3.3] Perform clear function signaling and completion */ dev->scsw.flag0 = 0; dev->scsw.flag1 = 0; dev->scsw.flag2 &= ~((SCSW2_FC - SCSW2_FC_CLEAR) | SCSW2_AC); dev->scsw.flag3 &= (~(SCSW3_AC | SCSW3_SC))&0xff; dev->scsw.flag3 |= SCSW3_SC_PEND; store_fw (dev->scsw.ccwaddr, 0); dev->scsw.chanstat = 0; dev->scsw.unitstat = 0; store_hw (dev->scsw.count, 0); /* Turn off busy & pcipending bits, turn on pending bit */ dev->busy = dev->pcipending = 0; dev->pending = 1; /* Wake up any waiters if the device isn't reserved */ if (!dev->reserved) { dev->ioactive = DEV_SYS_NONE; if (dev->iowaiters) signal_condition (&dev->iocond); } /* For 3270 device, clear any pending input */ if (dev->devtype == 0x3270) { dev->readpending = 0; dev->rlen3270 = 0; } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Queue the pending interrupt */ obtain_lock(&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); QUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); release_lock(&sysblk.iointqlk); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(devregs(dev)); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); if (dev->ccwtrace || dev->ccwstep || tracethis) logmsg (_("HHCCP071I Device %4.4X clear completed\n"), dev->devnum); return NULL; } /* end perform clear subchannel */ /* Test for halt subchannel request */ if (dev->scsw.flag2 & SCSW2_AC_HALT) { IODELAY(dev); /* Call the i/o end exit */ if (dev->hnd->end) (dev->hnd->end) (dev); obtain_lock (&dev->lock); /* [15.4.2] Perform halt function signaling and completion */ dev->scsw.flag2 &= ~SCSW2_AC_HALT; dev->scsw.flag3 |= SCSW3_SC_PEND; dev->scsw.unitstat |= CSW_CE | CSW_DE; /* Turn off busy & pcipending bits, turn on pending bit */ dev->busy = dev->pcipending = 0; dev->pending = 1; /* Wake up any waiters if the device isn't reserved */ if (!dev->reserved) { dev->ioactive = DEV_SYS_NONE; if (dev->iowaiters) signal_condition (&dev->iocond); } /* For 3270 device, clear any pending input */ if (dev->devtype == 0x3270) { dev->readpending = 0; dev->rlen3270 = 0; } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Queue the pending interrupt */ obtain_lock(&sysblk.iointqlk); DEQUEUE_IO_INTERRUPT_QLOCKED(&dev->pciioint); QUEUE_IO_INTERRUPT_QLOCKED(&dev->ioint); release_lock(&sysblk.iointqlk); release_lock (&dev->lock); /* Update interrupt status */ OBTAIN_INTLOCK(devregs(dev)); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); if (dev->ccwtrace || dev->ccwstep || tracethis) logmsg (_("HHCCP072I Device %4.4X halt completed\n"), dev->devnum); return NULL; } /* end perform halt subchannel */ /* Clear the channel status and unit status */ chanstat = 0; unitstat = 0; /* Fetch the next CCW */ ARCH_DEP(fetch_ccw) (dev, ccwkey, ccwfmt, ccwaddr, &opcode, &addr, &flags, &count, &chanstat); /* For an invalid CCW address in a TIC we must backup to TIC+8 */ if(ticaddr && (chanstat & CSW_PROGC)) ccwaddr = ticaddr-8; /* Point to the CCW in main storage */ ccw = dev->mainstor + ccwaddr; /* Increment to next CCW address */ if ((dev->chained & CCW_FLAGS_CD) == 0) dev->syncio_addr = ccwaddr; ccwaddr += 8; /* Update the CCW address in the SCSW */ STORE_FW(dev->scsw.ccwaddr,ccwaddr); /* Exit if fetch_ccw detected channel program check */ if (chanstat != 0) break; /* Display the CCW */ if (dev->ccwtrace || dev->ccwstep) display_ccw (dev, ccw, addr); /*----------------------------------------------*/ /* TRANSFER IN CHANNEL (TIC) command */ /*----------------------------------------------*/ if (IS_CCW_TIC(opcode)) { /* Channel program check if TIC-to-TIC */ if (ticaddr) { chanstat = CSW_PROGC; break; } /* Channel program check if format-1 TIC reserved bits set*/ if (ccwfmt == 1 && (opcode != 0x08 || flags != 0 || count != 0)) { chanstat = CSW_PROGC; break; } /* Set new CCW address (leaving the values of chained and code untouched to allow data-chaining through TIC) */ ticaddr = ccwaddr; ccwaddr = addr; chain = 1; continue; } /* end if TIC */ /*----------------------------------------------*/ /* Commands other than TRANSFER IN CHANNEL */ /*----------------------------------------------*/ /* Reset the TIC-to-TIC flag */ ticaddr = 0; /* Update current CCW opcode, unless data chaining */ if ((dev->chained & CCW_FLAGS_CD) == 0) { dev->prevcode = dev->code; dev->code = opcode; } #if !defined(FEATURE_MIDAW) /*@MW*/ /* Channel program check if MIDAW not installed */ /*@MW*/ if (flags & CCW_FLAGS_MIDAW) /*@MW*/ { chanstat = CSW_PROGC; break; } #endif /*!defined(FEATURE_MIDAW)*/ /*@MW*/ #if defined(FEATURE_MIDAW) /*@MW*/ /* Channel program check if MIDAW not enabled in ORB */ /*@MW*/ if ((flags & CCW_FLAGS_MIDAW) && /*@MW*/ (dev->orb.flag7 & ORB7_D) == 0) /*@MW*/ { /*@MW*/ chanstat = CSW_PROGC; /*@MW*/ break; /*@MW*/ } /*@MW*/ /* Channel program check if MIDAW with SKIP or IDA */ /*@MW*/ if ((flags & CCW_FLAGS_MIDAW) && /*@MW*/ (flags & (CCW_FLAGS_SKIP | CCW_FLAGS_IDA))) /*@MW*/ { /*@MW*/ chanstat = CSW_PROGC; /*@MW*/ break; /*@MW*/ } /*@MW*/ #endif /*defined(FEATURE_MIDAW)*/ /*@MW*/ #ifdef FEATURE_S370_CHANNEL /* For S/370, channel program check if suspend flag is set */ if (flags & CCW_FLAGS_SUSP) { chanstat = CSW_PROGC; break; } #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Suspend channel program if suspend flag is set */ if (flags & CCW_FLAGS_SUSP) { /* Channel program check if the ORB suspend control bit was zero, or if this is a data chained CCW */ if ((dev->scsw.flag0 & SCSW0_S) == 0 || (dev->chained & CCW_FLAGS_CD)) { chanstat = CSW_PROGC; break; } /* Retry if synchronous I/O */ if (dev->syncio_active) { dev->syncio_retry = 1; return NULL; } IODELAY(dev); /* Call the i/o suspend exit */ if (dev->hnd->suspend) (dev->hnd->suspend) (dev); obtain_lock (&dev->lock); /* Suspend the device if not already resume pending */ if ((dev->scsw.flag2 & SCSW2_AC_RESUM) == 0) { /* Set the subchannel status word to suspended */ dev->scsw.flag3 = SCSW3_AC_SUSP | SCSW3_SC_INTER | SCSW3_SC_PEND; dev->scsw.unitstat = 0; dev->scsw.chanstat = 0; STORE_HW(dev->scsw.count,count); /* Generate I/O interrupt unless the ORB specified that suspend interrupts are to be suppressed */ if ((dev->scsw.flag1 & SCSW1_U) == 0) { /* Queue the interrupt */ QUEUE_IO_INTERRUPT(&dev->ioint); /* Update interrupt status */ release_lock (&dev->lock); OBTAIN_INTLOCK(devregs(dev)); UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); obtain_lock (&dev->lock); } /* Wake up any waiters if the device isn't reserved */ if (!dev->reserved) { dev->ioactive = DEV_SYS_NONE; if (dev->iowaiters) signal_condition (&dev->iocond); } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } /* Turn on the `suspended' bit. This enables remote systems to use the device while we're waiting */ dev->suspended = 1; if (dev->ccwtrace || dev->ccwstep || tracethis) logmsg (_("HHCCP073I Device %4.4X suspended\n"), dev->devnum); // FIXME: Not a very elegant way to fix the suspend/resume problem dev->ccwaddr = ccwaddr; dev->idapmask = idapmask; dev->idawfmt = idawfmt; dev->ccwfmt = ccwfmt; dev->ccwkey = ccwkey; resume_suspend: ccwaddr = dev->ccwaddr; idapmask = dev->idapmask; idawfmt = dev->idawfmt; ccwfmt = dev->ccwfmt; ccwkey = dev->ccwkey; /* Suspend the device until resume instruction */ while (dev->suspended && (dev->scsw.flag2 & SCSW2_AC_RESUM) == 0) { wait_condition (&dev->resumecond, &dev->lock); } /* If the device has been reset then simply return */ if (!dev->suspended) { if (dev->ioactive == sysid) { dev->busy = 0; /* Wake up any waiters if the device isn't reserved */ if (!dev->reserved) { dev->ioactive = DEV_SYS_NONE; if (dev->iowaiters) signal_condition (&dev->iocond); } } release_lock (&dev->lock); return NULL; } /* Turn the `suspended' bit off */ dev->suspended = 0; /* Wait for the device to become available */ while (dev->ioactive != DEV_SYS_NONE && dev->ioactive != sysid) { dev->iowaiters++; wait_condition(&dev->iocond, &dev->lock); dev->iowaiters--; } dev->ioactive = sysid; dev->busy = 1; if (dev->ccwtrace || dev->ccwstep || tracethis) logmsg (_("HHCCP074I Device %4.4X resumed\n"), dev->devnum); /* Reset the suspended status in the SCSW */ dev->scsw.flag3 &= ~SCSW3_AC_SUSP; dev->scsw.flag3 |= (SCSW3_AC_SCHAC | SCSW3_AC_DEVAC); } /* Reset the resume pending flag */ dev->scsw.flag2 &= ~SCSW2_AC_RESUM; release_lock (&dev->lock); /* Call the i/o resume exit */ if (dev->hnd->resume) (dev->hnd->resume) (dev); /* Reset fields as if starting a new channel program */ dev->code = 0; ticaddr = 0; chain = 1; dev->chained = 0; dev->prev_chained = 0; dev->prevcode = 0; dev->ccwseq = 0; bufpos = 0; dev->syncio_retry = 0; /* Go back and refetch the suspended CCW */ ccwaddr -= 8; continue; } /* end if(CCW_FLAGS_SUSP) */ #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Signal I/O interrupt if PCI flag is set */ if ((flags & CCW_FLAGS_PCI) && !dev->syncio_retry) { ARCH_DEP(raise_pci) (dev, ccwkey, ccwfmt, ccwaddr); /*@MW*/ } /* Allow the device handler to determine whether this is an immediate CCW (i.e. CONTROL with no data transfer) */ dev->is_immed = IS_CCW_IMMEDIATE(dev); /* Channel program check if invalid count */ if (count == 0 && (ccwfmt == 0 || (flags & CCW_FLAGS_CD) || (dev->chained & CCW_FLAGS_CD))) { chanstat = CSW_PROGC; break; } /* If immediate, chain data is ignored */ if (dev->is_immed && (flags & CCW_FLAGS_CD)) { flags &= ~CCW_FLAGS_CD; dev->chained &= ~CCW_FLAGS_CD; } /* If synchronous I/O and a syncio 2 device and not an immediate CCW then retry asynchronously */ if (dev->syncio_active && dev->syncio == 2 && !dev->is_immed && !IS_CCW_SENSE(dev->code)) { dev->syncio_retry = 1; return NULL; } /* For WRITE and non-immediate CONTROL operations, copy data from main storage into channel buffer */ if ( IS_CCW_WRITE(dev->code) || ( IS_CCW_CONTROL(dev->code) && (!dev->is_immed))) { /* Channel program check if data exceeds buffer size */ if (bufpos + count > 65536) { chanstat = CSW_PROGC; break; } /* Copy data into channel buffer */ ARCH_DEP(copy_iobuf) (dev, dev->code, flags, addr, count, ccwkey, idawfmt, idapmask, /*@IWZ*/ iobuf + bufpos, &chanstat); if (chanstat != 0) break; /* Update number of bytes in channel buffer */ bufpos += count; /* If device handler has requested merging of data chained write CCWs, then collect data from all CCWs in chain before passing buffer to device handler */ if (dev->cdwmerge) { if (flags & CCW_FLAGS_CD) { /* If this is the first CCW in the data chain, then save the chaining flags from the previous CCW */ if ((dev->chained & CCW_FLAGS_CD) == 0) dev->prev_chained = dev->chained; /* Process next CCW in data chain */ dev->chained = CCW_FLAGS_CD; chain = 1; continue; } /* If this is the last CCW in the data chain, then restore the chaining flags from the previous CCW */ if (dev->chained & CCW_FLAGS_CD) dev->chained = dev->prev_chained; } /* end if(dev->cdwmerge) */ /* Reset the total count at end of data chain */ count = bufpos; bufpos = 0; } /* Set chaining flag */ chain = ( flags & (CCW_FLAGS_CD | CCW_FLAGS_CC) ) ? 1 : 0; /* Initialize residual byte count */ residual = count; more = 0; /* Channel program check if invalid CCW opcode */ if (!(IS_CCW_WRITE(dev->code) || IS_CCW_READ(dev->code) || IS_CCW_CONTROL(dev->code) || IS_CCW_SENSE(dev->code) || IS_CCW_RDBACK(dev->code))) { chanstat = CSW_PROGC; break; } /* Pass the CCW to the device handler for execution */ (dev->hnd->exec) (dev, dev->code, flags, dev->chained, count, dev->prevcode, dev->ccwseq, iobuf, &more, &unitstat, &residual); /* Check if synchronous I/O needs to be retried */ if (dev->syncio_active && dev->syncio_retry) return NULL; /* * NOTE: syncio_retry is left on for an asynchronous I/O until * after the first call to the execute ccw device handler. * This allows the device handler to realize that the I/O is * being retried asynchronously. */ dev->syncio_retry = 0; /* Check for Command Retry (suggested by Jim Pierson) */ if ( --cmdretry && unitstat == ( CSW_CE | CSW_DE | CSW_UC | CSW_SM ) ) { chain = 1; ccwaddr -= 8; /* (retry same ccw again) */ continue; } /* For READ, SENSE, and READ BACKWARD operations, copy data from channel buffer to main storage, unless SKIP is set */ if ((flags & CCW_FLAGS_SKIP) == 0 && (IS_CCW_READ(dev->code) || IS_CCW_SENSE(dev->code) || IS_CCW_RDBACK(dev->code))) { ARCH_DEP(copy_iobuf) (dev, dev->code, flags, addr, count - residual, ccwkey, idawfmt, idapmask, /*@IWZ*/ iobuf, &chanstat); } /* Check for incorrect length */ if (residual != 0 || (more && ((flags & CCW_FLAGS_CD) == 0))) { /* Set incorrect length status if data chaining or or if suppress length indication flag is off for non-NOP CCWs */ if (((flags & CCW_FLAGS_CD) || (flags & CCW_FLAGS_SLI) == 0) && (!dev->is_immed) #if defined(FEATURE_INCORRECT_LENGTH_INDICATION_SUPPRESSION) /* Suppress incorrect length indication if CCW format is one and SLI mode is indicated in the ORB */ && !((dev->orb.flag5 & ORB5_F) && (dev->orb.flag5 & ORB5_U)) #endif /*defined(FEATURE_INCORRECT_LENGTH_INDICATION_SUPPRESSION)*/ ) chanstat |= CSW_IL; } /* Force tracing for this CCW if any unusual status occurred */ if ((chanstat & (CSW_PROGC | CSW_PROTC | CSW_CDC | CSW_CCC | CSW_ICC | CSW_CHC)) || ((unitstat & CSW_UC) && dev->sense[0] != 0)) { /* Trace the CCW if not already done */ if (!(dev->ccwtrace || dev->ccwstep || tracethis) && (CPU_STEPPING_OR_TRACING_ALL || sysblk.pgminttr || dev->ccwtrace || dev->ccwstep) ) display_ccw (dev, ccw, addr); /* Activate tracing for this CCW chain only if any trace is already active */ if(CPU_STEPPING_OR_TRACING_ALL || sysblk.pgminttr || dev->ccwtrace || dev->ccwstep) tracethis = 1; } /* Trace the results of CCW execution */ if (dev->ccwtrace || dev->ccwstep || tracethis) { /* Format data for READ or SENSE commands only */ if (IS_CCW_READ(dev->code) || IS_CCW_SENSE(dev->code) || IS_CCW_RDBACK(dev->code)) format_iobuf_data (addr, area, dev); else area[0] = '\0'; /* Display status and residual byte count */ logmsg (_("HHCCP075I %4.4X:Stat=%2.2X%2.2X Count=%4.4X %s\n"), dev->devnum, unitstat, chanstat, residual, area); /* Display sense bytes if unit check is indicated */ if (unitstat & CSW_UC) { logmsg (_("HHCCP076I %4.4X:Sense=%2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X\n"), dev->devnum, dev->sense[0], dev->sense[1], dev->sense[2], dev->sense[3], dev->sense[4], dev->sense[5], dev->sense[6], dev->sense[7], dev->sense[8], dev->sense[9], dev->sense[10], dev->sense[11], dev->sense[12], dev->sense[13], dev->sense[14], dev->sense[15], dev->sense[16], dev->sense[17], dev->sense[18], dev->sense[19], dev->sense[20], dev->sense[21], dev->sense[22], dev->sense[23]); if (dev->sense[0] != 0 || dev->sense[1] != 0) { logmsg (_("HHCCP077I %4.4X:Sense=%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s\n"), dev->devnum, (dev->sense[0] & SENSE_CR) ? "CMDREJ " : "", (dev->sense[0] & SENSE_IR) ? "INTREQ " : "", (dev->sense[0] & SENSE_BOC) ? "BOC " : "", (dev->sense[0] & SENSE_EC) ? "EQC " : "", (dev->sense[0] & SENSE_DC) ? "DCK " : "", (dev->sense[0] & SENSE_OR) ? "OVR " : "", (dev->sense[0] & SENSE_CC) ? "CCK " : "", (dev->sense[0] & SENSE_OC) ? "OCK " : "", (dev->sense[1] & SENSE1_PER) ? "PER " : "", (dev->sense[1] & SENSE1_ITF) ? "ITF " : "", (dev->sense[1] & SENSE1_EOC) ? "EOC " : "", (dev->sense[1] & SENSE1_MTO) ? "MSG " : "", (dev->sense[1] & SENSE1_NRF) ? "NRF " : "", (dev->sense[1] & SENSE1_FP) ? "FP " : "", (dev->sense[1] & SENSE1_WRI) ? "WRI " : "", (dev->sense[1] & SENSE1_IE) ? "IE " : ""); } } } /* Increment CCW address if device returned status modifier */ if (unitstat & CSW_SM) ccwaddr += 8; /* Terminate the channel program if any unusual status */ if (chanstat != 0 || (unitstat & ~CSW_SM) != (CSW_CE | CSW_DE)) chain = 0; /* Update the chaining flags */ dev->chained = flags & (CCW_FLAGS_CD | CCW_FLAGS_CC); /* Update the CCW sequence number unless data chained */ if ((flags & CCW_FLAGS_CD) == 0) dev->ccwseq++; } /* end while(chain) */ IODELAY(dev); /* Call the i/o end exit */ if (dev->hnd->end) (dev->hnd->end) (dev); obtain_lock (&dev->lock); #ifdef FEATURE_S370_CHANNEL /* Build the channel status word */ dev->csw[0] = ccwkey & 0xF0; dev->csw[1] = (ccwaddr & 0xFF0000) >> 16; dev->csw[2] = (ccwaddr & 0xFF00) >> 8; dev->csw[3] = ccwaddr & 0xFF; dev->csw[4] = unitstat; dev->csw[5] = chanstat; dev->csw[6] = (residual & 0xFF00) >> 8; dev->csw[7] = residual & 0xFF; #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Complete the subchannel status word */ dev->scsw.flag3 &= ~(SCSW3_AC_SCHAC | SCSW3_AC_DEVAC); dev->scsw.flag3 |= (SCSW3_SC_PRI | SCSW3_SC_SEC | SCSW3_SC_PEND); STORE_FW(dev->scsw.ccwaddr,ccwaddr); dev->scsw.unitstat = unitstat; dev->scsw.chanstat = chanstat; STORE_HW(dev->scsw.count,residual); /* Set alert status if terminated by any unusual condition */ if (chanstat != 0 || unitstat != (CSW_CE | CSW_DE)) dev->scsw.flag3 |= SCSW3_SC_ALERT; /* Build the format-1 extended status word */ memset (&dev->esw, 0, sizeof(ESW)); dev->esw.lpum = 0x80; /* Clear the extended control word */ memset (dev->ecw, 0, sizeof(dev->ecw)); /* Return sense information if PMCW allows concurrent sense */ if ((unitstat & CSW_UC) && (dev->pmcw.flag27 & PMCW27_S)) { dev->scsw.flag1 |= SCSW1_E; dev->esw.erw0 |= ERW0_S; dev->esw.erw1 = (dev->numsense < (int)sizeof(dev->ecw)) ? dev->numsense : sizeof(dev->ecw); memcpy (dev->ecw, dev->sense, dev->esw.erw1 & ERW1_SCNT); memset (dev->sense, 0, sizeof(dev->sense)); dev->sns_pending = 0; } #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Wake up any waiters if the device isn't reserved */ if (!dev->reserved) { dev->ioactive = DEV_SYS_NONE; if (dev->iowaiters) signal_condition (&dev->iocond); } /* Signal console thread to redrive select */ if (dev->console) { SIGNAL_CONSOLE_THREAD(); } dev->busy = 0; /* Queue the interrupt */ QUEUE_IO_INTERRUPT (&dev->ioint); release_lock (&dev->lock); /* Present the interrupt */ OBTAIN_INTLOCK(devregs(dev)); if (dev->regs) dev->regs->hostregs->syncio = 0; UPDATE_IC_IOPENDING(); RELEASE_INTLOCK(devregs(dev)); return NULL; } /* end function execute_ccw_chain */ /*-------------------------------------------------------------------*/ /* TEST WHETHER INTERRUPTS ARE ENABLED FOR THE SPECIFIED DEVICE */ /* When configured for S/370 channels, the PSW system mask and/or */ /* the channel masks in control register 2 determine whether the */ /* device is enabled. When configured for the XA or ESA channel */ /* subsystem, the interrupt subclass masks in control register 6 */ /* determine eligability; the PSW system mask is not tested, because */ /* the TPI instruction can operate with I/O interrupts masked off. */ /* Returns non-zero if interrupts enabled, 0 if interrupts disabled. */ /*-------------------------------------------------------------------*/ /* I/O Assist: */ /* This routine must return: */ /* */ /* 0 - In the case of no pending interrupt */ /* SIE_NO_INTERCEPT - For a non-intercepted I/O interrupt */ /* SIE_INTERCEPT_IOINT - For an intercepted I/O interrupt */ /* SIE_INTERCEPT_IOINTP- For a pending I/O interception */ /* */ /* SIE_INTERCEPT_IOINT may only be returned to a guest */ /*-------------------------------------------------------------------*/ static inline int ARCH_DEP(interrupt_enabled) (REGS *regs, DEVBLK *dev) { int i; /* Interruption subclass */ /* Ignore this device if subchannel not valid */ if (!(dev->pmcw.flag5 & PMCW5_V)) return 0; #if defined(_FEATURE_IO_ASSIST) /* For I/O Assist the zone must match the guest zone */ if(SIE_MODE(regs) && regs->siebk->zone != dev->pmcw.zone) return 0; #endif #if defined(_FEATURE_IO_ASSIST) /* The interrupt interlock control bit must be on if not we must intercept */ if(SIE_MODE(regs) && !(dev->pmcw.flag27 & PMCW27_I)) return SIE_INTERCEPT_IOINT; #endif #ifdef FEATURE_S370_CHANNEL #if defined(FEATURE_CHANNEL_SWITCHING) /* Is this device on a channel connected to this CPU? */ if( #if defined(_FEATURE_IO_ASSIST) !SIE_MODE(regs) && #endif regs->chanset != dev->chanset) return 0; #endif /*defined(FEATURE_CHANNEL_SWITCHING)*/ /* Isolate the channel number */ i = dev->devnum >> 8; if (!ECMODE(®s->psw) && i < 6) { #if defined(_FEATURE_IO_ASSIST) /* We must always intercept in BC mode */ if(SIE_MODE(regs)) return SIE_INTERCEPT_IOINT; #endif /* For BC mode channels 0-5, test system mask bits 0-5 */ if ((regs->psw.sysmask & (0x80 >> i)) == 0) return 0; } else { /* For EC mode and channels 6-31, test system mask bit 6 */ if ((regs->psw.sysmask & PSW_IOMASK) == 0) return 0; /* If I/O mask is enabled, test channel masks in CR2 */ if (i > 31) i = 31; if ((regs->CR(2) & (0x80000000 >> i)) == 0) return #if defined(_FEATURE_IO_ASSIST) SIE_MODE(regs) ? SIE_INTERCEPT_IOINTP : #endif 0; } #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Ignore this device if subchannel not enabled */ if (!(dev->pmcw.flag5 & PMCW5_E)) return 0; /* Isolate the interruption subclass */ i = #if defined(_FEATURE_IO_ASSIST) /* For I/O Assisted devices use the guest (V)ISC */ SIE_MODE(regs) ? (dev->pmcw.flag25 & PMCW25_VISC) : #endif ((dev->pmcw.flag4 & PMCW4_ISC) >> 3); /* Test interruption subclass mask bit in CR6 */ if ((regs->CR_L(6) & (0x80000000 >> i)) == 0) return #if defined(_FEATURE_IO_ASSIST) SIE_MODE(regs) ? SIE_INTERCEPT_IOINTP : #endif 0; #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ /* Interrupts are enabled for this device */ return SIE_NO_INTERCEPT; } /* end function interrupt_enabled */ /*-------------------------------------------------------------------*/ /* PRESENT PENDING I/O INTERRUPT */ /* Finds a device with a pending condition for which an interrupt */ /* is allowed by the CPU whose regs structure is passed as a */ /* parameter. Clears the interrupt condition and returns the */ /* I/O address and I/O interruption parameter (for channel subsystem)*/ /* or the I/O address and CSW (for S/370 channels). */ /* This routine does not perform a PSW switch. */ /* The CSW pointer is NULL in the case of TPI. */ /* The return value is the condition code for the TPI instruction: */ /* 0 if no allowable pending interrupt exists, otherwise 1. */ /* Note: The caller MUST hold the interrupt lock (sysblk.intlock). */ /*-------------------------------------------------------------------*/ /* I/O Assist: */ /* This routine must return: */ /* */ /* 0 - In the case of no pending interrupt */ /* SIE_NO_INTERCEPT - For a non-intercepted I/O interrupt */ /* SIE_INTERCEPT_IOINT - For an I/O interrupt which must intercept */ /* SIE_INTERCEPT_IOINTP- For a pending I/O interception */ /* */ /* SIE_INTERCEPT_IOINT may only be returned to a guest */ /*-------------------------------------------------------------------*/ int ARCH_DEP(present_io_interrupt) (REGS *regs, U32 *ioid, U32 *ioparm, U32 *iointid, BYTE *csw) { IOINT *io, *io2; /* -> I/O interrupt entry */ DEVBLK *dev; /* -> Device control block */ int icode = 0; /* Intercept code */ #if defined(FEATURE_S370_CHANNEL) BYTE *pendcsw; /* Pending CSW */ #endif UNREFERENCED_370(ioparm); UNREFERENCED_370(iointid); #if defined(_FEATURE_IO_ASSIST) UNREFERENCED_390(iointid); #endif UNREFERENCED_390(csw); UNREFERENCED_900(csw); /* Find a device with pending interrupt */ /* (N.B. devlock cannot be acquired while iointqlk held; iointqlk must be acquired after devlock) */ retry: dev = NULL; obtain_lock(&sysblk.iointqlk); for (io = sysblk.iointq; io != NULL; io = io->next) { /* Exit loop if enabled for interrupts from this device */ if ((icode = ARCH_DEP(interrupt_enabled)(regs, io->dev)) #if defined(_FEATURE_IO_ASSIST) && icode != SIE_INTERCEPT_IOINTP #endif ) { dev = io->dev; break; } /* See if another CPU can take this interrupt */ WAKEUP_CPU_MASK (sysblk.waiting_mask); } /* end for(io) */ #if defined(_FEATURE_IO_ASSIST) /* In the case of I/O assist, do a rescan, to see if there are any devices with pending subclasses for which we are not enabled, if so cause a interception */ if (io == NULL && SIE_MODE(regs)) { /* Find a device with a pending interrupt, regardless of the interrupt subclass mask */ ASSERT(dev == NULL); for (io = sysblk.iointq; io != NULL; io = io->next) { /* Exit loop if pending interrupts from this device */ if ((icode = ARCH_DEP(interrupt_enabled)(regs, io->dev))) { dev = io->dev; break; } } /* end for(io) */ } #endif release_lock(&sysblk.iointqlk); /* If no interrupt pending, exit with condition code 0 */ if (io == NULL) { ASSERT(dev == NULL); UPDATE_IC_IOPENDING(); return 0; } /* Obtain device lock for device with interrupt */ ASSERT(dev != NULL); obtain_lock (&dev->lock); /* Verify interrupt for this device still exists */ obtain_lock(&sysblk.iointqlk); for (io2 = sysblk.iointq; io2 != NULL && io2 != io; io2 = io2->next); if (io2 == NULL) { /* Our interrupt was dequeued; retry */ release_lock(&sysblk.iointqlk); release_lock (&dev->lock); goto retry; } #ifdef FEATURE_S370_CHANNEL /* Extract the I/O address and CSW */ *ioid = dev->devnum; if(io->pcipending) { pendcsw=dev->pcicsw; memcpy (csw, pendcsw , 8); } if(io->pending) { pendcsw=dev->csw; memcpy (csw, pendcsw , 8); } if(io->attnpending) { pendcsw=dev->attncsw; memcpy (csw, pendcsw , 8); } /* Display the channel status word */ if (dev->ccwtrace || dev->ccwstep) display_csw (dev, csw); #endif /*FEATURE_S370_CHANNEL*/ #ifdef FEATURE_CHANNEL_SUBSYSTEM /* Extract the I/O address and interrupt parameter */ *ioid = (dev->ssid << 16) | dev->subchan; FETCH_FW(*ioparm,dev->pmcw.intparm); #if defined(FEATURE_ESAME) || defined(_FEATURE_IO_ASSIST) *iointid = #if defined(_FEATURE_IO_ASSIST) /* For I/O Assisted devices use (V)ISC */ (SIE_MODE(regs)) ? (icode == SIE_NO_INTERCEPT) ? ((dev->pmcw.flag25 & PMCW25_VISC) << 27) : ((dev->pmcw.flag25 & PMCW25_VISC) << 27) | (dev->pmcw.zone << 16) | ((dev->pmcw.flag27 & PMCW27_I) << 8) : #endif ((dev->pmcw.flag4 & PMCW4_ISC) << 24) #if defined(_FEATURE_IO_ASSIST) | (dev->pmcw.zone << 16) | ((dev->pmcw.flag27 & PMCW27_I) << 8) #endif ; #endif /*defined(FEATURE_ESAME) || defined(_FEATURE_IO_ASSIST)*/ #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ #if defined(_FEATURE_IO_ASSIST) /* Do not drain pending interrupts on intercept due to zero ISC mask */ if(!SIE_MODE(regs) || icode != SIE_INTERCEPT_IOINTP) #endif { if(!SIE_MODE(regs) || icode != SIE_NO_INTERCEPT) dev->pmcw.flag27 &= ~PMCW27_I; /* Dequeue the interrupt */ DEQUEUE_IO_INTERRUPT_QLOCKED(io); UPDATE_IC_IOPENDING_QLOCKED(); /* Signal console thread to redrive select */ if (dev->console) SIGNAL_CONSOLE_THREAD(); } release_lock(&sysblk.iointqlk); release_lock (&dev->lock); /* Exit with condition code indicating interrupt cleared */ return icode; } /* end function present_io_interrupt */ #if defined(_FEATURE_IO_ASSIST) int ARCH_DEP(present_zone_io_interrupt) (U32 *ioid, U32 *ioparm, U32 *iointid, BYTE zone) { IOINT *io; /* -> I/O interrupt entry */ DEVBLK *dev; /* -> Device control block */ typedef struct _DEVLIST { /* list of device block ptrs */ struct _DEVLIST *next; /* next list entry or NULL */ DEVBLK *dev; /* DEVBLK in requested zone */ U16 ssid; /* Subsystem ID incl. lcssid */ U16 subchan; /* Subchannel number */ FWORD intparm; /* Interruption parameter */ int visc; /* Guest Interrupt Subclass */ } DEVLIST; DEVLIST *pDEVLIST, *pPrevDEVLIST = NULL;/* (work) */ DEVLIST *pZoneDevs = NULL; /* devices in requested zone */ /* Gather devices within our zone with pending interrupt flagged */ for (dev = sysblk.firstdev; dev; dev = dev->nextdev) { obtain_lock (&dev->lock); if (1 /* Pending interrupt flagged */ && (dev->pending || dev->pcipending) /* Subchannel valid and enabled */ && ((dev->pmcw.flag5 & (PMCW5_E | PMCW5_V)) == (PMCW5_E | PMCW5_V)) /* Within requested zone */ && (dev->pmcw.zone == zone) ) { /* (save this device for further scrutiny) */ pDEVLIST = malloc( sizeof(DEVLIST) ); pDEVLIST->next = NULL; pDEVLIST->dev = dev; pDEVLIST->ssid = dev->ssid; pDEVLIST->subchan = dev->subchan; // pDEVLIST->intparm = dev->pmcw.intparm; memcpy( pDEVLIST->intparm, dev->pmcw.intparm, sizeof(pDEVLIST->intparm) ); pDEVLIST->visc = (dev->pmcw.flag25 & PMCW25_VISC); if (!pZoneDevs) pZoneDevs = pDEVLIST; if (pPrevDEVLIST) pPrevDEVLIST->next = pDEVLIST; pPrevDEVLIST = pDEVLIST; } release_lock (&dev->lock); } /* Exit with condition code 0 if no devices within our zone with a pending interrupt */ if (!pZoneDevs) return 0; /* Remove from our list those devices without a pending interrupt queued */ obtain_lock(&sysblk.iointqlk); for (pDEVLIST = pZoneDevs, pPrevDEVLIST = NULL; pDEVLIST;) { /* Search interrupt queue for this device */ for (io = sysblk.iointq; io != NULL && io->dev != pDEVLIST->dev; io = io->next); /* Is interrupt queued for this device? */ if (io == NULL) { /* No, remove it from our list */ if (!pPrevDEVLIST) { ASSERT(pDEVLIST == pZoneDevs); pZoneDevs = pDEVLIST->next; free(pDEVLIST); pDEVLIST = pZoneDevs; } else { pPrevDEVLIST->next = pDEVLIST->next; free(pDEVLIST); pDEVLIST = pPrevDEVLIST->next; } } else { /* Yes, go on to next list entry */ pPrevDEVLIST = pDEVLIST; pDEVLIST = pDEVLIST->next; } } release_lock(&sysblk.iointqlk); /* If no devices remain, exit with condition code 0 */ if (!pZoneDevs) return 0; /* Extract the I/O address and interrupt parameter for the first pending subchannel */ dev = pZoneDevs->dev; *ioid = (pZoneDevs->ssid << 16) | pZoneDevs->subchan; FETCH_FW(*ioparm,pZoneDevs->intparm); *iointid = (0x80000000 >> pZoneDevs->visc) | (zone << 16); pDEVLIST = pZoneDevs->next; free (pZoneDevs); /* Find all other pending subclasses */ while (pDEVLIST) { *iointid |= (0x80000000 >> pDEVLIST->visc); pPrevDEVLIST = pDEVLIST; pDEVLIST = pDEVLIST->next; free (pPrevDEVLIST); } /* Exit with condition code indicating interrupt pending */ return 1; } /* end function present_zone_io_interrupt */ #endif #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "channel.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "channel.c" #endif int device_attention (DEVBLK *dev, BYTE unitstat) { switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: /* Do NOT raise if initial power-on state */ /* * FIXME : The dev->crwpending test in S/370 * mode prevents any devices added * at run time after IPL from being * operational. The test has been * temporarily disabled until it is * either confirmed as being superfluous * or another solution is found. * ISW 20070109 */ /* if (dev->crwpending) return 3; */ return s370_device_attention(dev, unitstat); #endif #if defined(_390) case ARCH_390: return s390_device_attention(dev, unitstat); #endif #if defined(_900) case ARCH_900: return z900_device_attention(dev, unitstat); #endif } return 3; } void call_execute_ccw_chain(int arch_mode, void* pDevBlk) { switch (arch_mode) { #if defined(_370) case ARCH_370: s370_execute_ccw_chain((DEVBLK*)pDevBlk); break; #endif #if defined(_390) case ARCH_390: s390_execute_ccw_chain((DEVBLK*)pDevBlk); break; #endif #if defined(_900) case ARCH_900: z900_execute_ccw_chain((DEVBLK*)pDevBlk); break; #endif } } #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/external.c0000664000175000017500000005050112564723224012172 00000000000000/* EXTERNAL.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 External Interrupt and Timer */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module implements external interrupt, timer, and signalling */ /* functions for the Hercules ESA/390 emulator. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* TOD clock offset contributed by Jay Maynard */ /* Correction to timer interrupt by Valery Pogonchenko */ /* TOD clock drag factor contributed by Jan Jaeger */ /* CPU timer and clock comparator interrupt improvements by */ /* Jan Jaeger, after a suggestion by Willem Koynenberg */ /* Prevent TOD clock and CPU timer from going back - Jan Jaeger */ /* Use longjmp on all interrupt types - Jan Jaeger */ /* Fix todclock - Jay Maynard */ /* Modifications for Interpretive Execution (SIE) by Jan Jaeger */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_EXTERNAL_C_) #define _EXTERNAL_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" /*-------------------------------------------------------------------*/ /* Load external interrupt new PSW */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(external_interrupt) (int code, REGS *regs) { RADR pfx; PSA *psa; int rc; PTT(PTT_CL_SIG,"*EXTINT",code,regs->cpuad,regs->psw.IA_L); #if defined(_FEATURE_SIE) /* Set the main storage reference and change bits */ if(SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) && !SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) && !SIE_FEATB(regs, EC0, EXTA) #endif ) { /* Point to SIE copy of PSA in state descriptor */ psa = (void*)(regs->hostregs->mainstor + SIE_STATE(regs) + SIE_IP_PSA_OFFSET); STORAGE_KEY(SIE_STATE(regs), regs->hostregs) |= (STORKEY_REF | STORKEY_CHANGE); } else #endif /*defined(_FEATURE_SIE)*/ { /* Point to PSA in main storage */ pfx = regs->PX; #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) SIE_TRANSLATE(&pfx, ACCTYPE_SIE, regs); #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ psa = (void*)(regs->mainstor + pfx); STORAGE_KEY(pfx, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* Store the interrupt code in the PSW */ regs->psw.intcode = code; /* Zero extcpuad field unless extcall or ems signal or blockio */ if(code != EXT_EXTERNAL_CALL_INTERRUPT #if defined(FEATURE_VM_BLOCKIO) && code != EXT_BLOCKIO_INTERRUPT #endif /* defined(FEATURE_VM_BLOCKIO) */ && code != EXT_EMERGENCY_SIGNAL_INTERRUPT) STORE_HW(psa->extcpad,0); #if defined(FEATURE_BCMODE) /* For ECMODE, store external interrupt code at PSA+X'86' */ if ( ECMODE(®s->psw) ) #endif /*defined(FEATURE_BCMODE)*/ STORE_HW(psa->extint,code); if ( !SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) || SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) || SIE_FEATB(regs, EC0, EXTA) #endif ) { /* Store current PSW at PSA+X'18' */ ARCH_DEP(store_psw) (regs, psa->extold); /* Load new PSW from PSA+X'58' */ rc = ARCH_DEP(load_psw) (regs, psa->extnew); if ( rc ) { RELEASE_INTLOCK(regs); ARCH_DEP(program_interrupt)(regs, rc); } } #if defined(FEATURE_INTERVAL_TIMER) /* Ensure the interval timer is uptodate */ ARCH_DEP(store_int_timer_nolock) (regs); #endif RELEASE_INTLOCK(regs); if ( SIE_MODE(regs) #if defined(_FEATURE_EXPEDITED_SIE_SUBSET) && !SIE_FEATB(regs, S, EXP_TIMER) #endif /*defined(_FEATURE_EXPEDITED_SIE_SUBSET)*/ #if defined(_FEATURE_EXTERNAL_INTERRUPT_ASSIST) && !SIE_FEATB(regs, EC0, EXTA) #endif ) longjmp (regs->progjmp, SIE_INTERCEPT_EXT); else longjmp (regs->progjmp, SIE_NO_INTERCEPT); } /* end function external_interrupt */ /*-------------------------------------------------------------------*/ /* Perform external interrupt if pending */ /* */ /* This function is called by the CPU to check whether any */ /* external interrupt conditions are pending, and to perform */ /* an external interrupt if so. If multiple external interrupts */ /* are pending, then only the highest priority interrupt is taken, */ /* and any other interrupts remain pending. Remaining interrupts */ /* will be processed one-by-one during subsequent calls. */ /* */ /* Important notes: */ /* (i) This function must NOT be called if the CPU is disabled */ /* for external interrupts (PSW bit 7 is zero). */ /* (ii) The caller MUST hold the interrupt lock (sysblk.intlock) */ /* to ensure correct serialization of interrupt pending bits. */ /*-------------------------------------------------------------------*/ void ARCH_DEP(perform_external_interrupt) (REGS *regs) { PSA *psa; /* -> Prefixed storage area */ U16 cpuad; /* Originating CPU address */ #if defined(FEATURE_VM_BLOCKIO) #if defined(FEATURE_ESAME) RADR servpadr; /* Address of 64-bit block I/O interrupt */ #endif U16 servcode; /* Service Signal or Block I/O Interrupt code */ #endif /* defined(FEATURE_VM_BLOCKIO) */ /* External interrupt if console interrupt key was depressed */ if ( OPEN_IC_INTKEY(regs) && !SIE_MODE(regs) ) { logmsg (_("HHCCP023I External interrupt: Interrupt key\n")); /* Reset interrupt key pending */ OFF_IC_INTKEY; /* Generate interrupt key interrupt */ ARCH_DEP(external_interrupt) (EXT_INTERRUPT_KEY_INTERRUPT, regs); } /* External interrupt if malfunction alert is pending */ if (OPEN_IC_MALFALT(regs)) { /* Find first CPU which generated a malfunction alert */ for (cpuad = 0; regs->malfcpu[cpuad] == 0; cpuad++) { if (cpuad >= MAX_CPU) { OFF_IC_MALFALT(regs); return; } } /* end for(cpuad) */ // /*debug*/ logmsg (_("External interrupt: Malfuction Alert from CPU %d\n"), // /*debug*/ cpuad); /* Reset the indicator for the CPU which was found */ regs->malfcpu[cpuad] = 0; /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,cpuad); /* Reset emergency signal pending flag if there are no other CPUs which generated emergency signal */ OFF_IC_MALFALT(regs); while (++cpuad < MAX_CPU) { if (regs->malfcpu[cpuad]) { ON_IC_MALFALT(regs); break; } } /* end while */ /* Generate emergency signal interrupt */ ARCH_DEP(external_interrupt) (EXT_MALFUNCTION_ALERT_INTERRUPT, regs); } /* External interrupt if emergency signal is pending */ if (OPEN_IC_EMERSIG(regs)) { /* Find first CPU which generated an emergency signal */ for (cpuad = 0; regs->emercpu[cpuad] == 0; cpuad++) { if (cpuad >= MAX_CPU) { OFF_IC_EMERSIG(regs); return; } } /* end for(cpuad) */ // /*debug*/ logmsg (_("External interrupt: Emergency Signal from CPU %d\n"), // /*debug*/ cpuad); /* Reset the indicator for the CPU which was found */ regs->emercpu[cpuad] = 0; /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,cpuad); /* Reset emergency signal pending flag if there are no other CPUs which generated emergency signal */ OFF_IC_EMERSIG(regs); while (++cpuad < MAX_CPU) { if (regs->emercpu[cpuad]) { ON_IC_EMERSIG(regs); break; } } /* end while */ /* Generate emergency signal interrupt */ ARCH_DEP(external_interrupt) (EXT_EMERGENCY_SIGNAL_INTERRUPT, regs); } /* External interrupt if external call is pending */ if (OPEN_IC_EXTCALL(regs)) { // /*debug*/logmsg (_("External interrupt: External Call from CPU %d\n"), // /*debug*/ regs->extccpu); /* Reset external call pending */ OFF_IC_EXTCALL(regs); /* Store originating CPU address at PSA+X'84' */ psa = (void*)(regs->mainstor + regs->PX); STORE_HW(psa->extcpad,regs->extccpu); /* Generate external call interrupt */ ARCH_DEP(external_interrupt) (EXT_EXTERNAL_CALL_INTERRUPT, regs); } /* External interrupt if TOD clock exceeds clock comparator */ if ( tod_clock(regs) > regs->clkc && OPEN_IC_CLKC(regs) ) { if (CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP024I External interrupt: Clock comparator\n")); } ARCH_DEP(external_interrupt) (EXT_CLOCK_COMPARATOR_INTERRUPT, regs); } /* External interrupt if CPU timer is negative */ if ( CPU_TIMER(regs) < 0 && OPEN_IC_PTIMER(regs) ) { if (CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP025I External interrupt: CPU timer=%16.16" I64_FMT "X\n"), (long long)CPU_TIMER(regs) << 8); } ARCH_DEP(external_interrupt) (EXT_CPU_TIMER_INTERRUPT, regs); } /* External interrupt if interval timer interrupt is pending */ #if defined(FEATURE_INTERVAL_TIMER) if (OPEN_IC_ITIMER(regs) #if defined(_FEATURE_SIE) && !(SIE_STATB(regs, M, ITMOF)) #endif /*defined(_FEATURE_SIE)*/ ) { if (CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP026I External interrupt: Interval timer\n")); } OFF_IC_ITIMER(regs); ARCH_DEP(external_interrupt) (EXT_INTERVAL_TIMER_INTERRUPT, regs); } #if defined(FEATURE_ECPSVM) if ( OPEN_IC_ECPSVTIMER(regs) ) { OFF_IC_ECPSVTIMER(regs); ARCH_DEP(external_interrupt) (EXT_VINTERVAL_TIMER_INTERRUPT,regs); } #endif /*FEATURE_ECPSVM*/ #endif /*FEATURE_INTERVAL_TIMER*/ /* External interrupt if service signal is pending */ if ( OPEN_IC_SERVSIG(regs) && !SIE_MODE(regs) ) { #if defined(FEATURE_VM_BLOCKIO) /* Note: Both Block I/O and Service Signal are enabled by the */ /* the same CR0 bit. Hence they are handled in the same code */ switch(sysblk.servcode) { case EXT_BLOCKIO_INTERRUPT: /* VM Block I/O Interrupt */ if (sysblk.biodev->ccwtrace) { logmsg (_("%4.4X:HHCCP031I Processing Block I/O interrupt: " "code=%4.4X parm=%16.16X status=%2.2X subcode=%2.2X\n"), sysblk.biodev->devnum, sysblk.servcode, sysblk.bioparm, sysblk.biostat, sysblk.biosubcd ); } servcode = EXT_BLOCKIO_INTERRUPT; #if defined(FEATURE_ESAME) /* Real address used to store the 64-bit interrupt parameter */ #define VM_BLOCKIO_INT_PARM 0x11B8 if (sysblk.biosubcd == 0x07) { /* 8-byte interrupt parm */ if (CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP028I External interrupt: Block I/O %16.16X\n"), sysblk.bioparm); } /* Set the main storage reference and change bits */ /* for 64-bit interruption parameter. */ /* Note: This is handled for the first 4K page in */ /* ARCH_DEP(external_interrupt), but not for the */ /* the second 4K page used for the 64-bit interrupt */ /* parameter. */ /* Point to 2nd page of PSA in main storage */ servpadr=APPLY_PREFIXING(VM_BLOCKIO_INT_PARM,regs->PX); STORAGE_KEY(servpadr, regs) |= (STORKEY_REF | STORKEY_CHANGE); #if 0 /* Store the 64-bit interrupt parameter */ logmsg (_("Saving 64-bit Block I/O interrupt parm at " "%16.16X: %16.16X\n"), servpadr, sysblk.bioparm ); #endif STORE_DW(regs->mainstor + servpadr,sysblk.bioparm); psa = (void*)(regs->mainstor + regs->PX); } else { #endif /* defined(FEATURE_ESAME) */ /* 4-byte interrupt parm */ if (CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP028I External interrupt: Block I/O %8.8X\n"), (U32)sysblk.bioparm); } /* Store Block I/O parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,(U32)sysblk.bioparm); #if defined(FEATURE_ESAME) } #endif /* Store sub-interruption code and status at PSA+X'84' */ STORE_HW(psa->extcpad,(sysblk.biosubcd<<8)|sysblk.biostat); /* Reset interruption data */ sysblk.bioparm = 0; sysblk.biosubcd = 0; sysblk.biostat = 0; break; case EXT_SERVICE_SIGNAL_INTERRUPT: /* Service Signal */ default: servcode = EXT_SERVICE_SIGNAL_INTERRUPT; /* Apply prefixing if the parameter is a storage address */ if ( (sysblk.servparm & SERVSIG_ADDR) ) sysblk.servparm = APPLY_PREFIXING (sysblk.servparm, regs->PX); if (CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP027I External interrupt: Service signal %8.8X\n"), sysblk.servparm); } /* Store service signal parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,sysblk.servparm); } /* end switch(sysblk.servcode) */ /* Reset service parameter */ sysblk.servparm = 0; /* Reset service code */ sysblk.servcode = 0; /* Reset service signal pending */ OFF_IC_SERVSIG; /* Generate service signal interrupt */ ARCH_DEP(external_interrupt) (servcode, regs); #else /* defined(FEATURE_VM_BLOCKIO) */ /* Apply prefixing if the parameter is a storage address */ if ( (sysblk.servparm & SERVSIG_ADDR) ) sysblk.servparm = APPLY_PREFIXING (sysblk.servparm, regs->PX); if (CPU_STEPPING_OR_TRACING_ALL) { logmsg (_("HHCCP027I External interrupt: Service signal %8.8X\n"), sysblk.servparm); } /* Store service signal parameter at PSA+X'80' */ psa = (void*)(regs->mainstor + regs->PX); STORE_FW(psa->extparm,sysblk.servparm); /* Reset service parameter */ sysblk.servparm = 0; /* Reset service signal pending */ OFF_IC_SERVSIG; /* Generate service signal interrupt */ ARCH_DEP(external_interrupt) (EXT_SERVICE_SIGNAL_INTERRUPT, regs); #endif /* defined(FEATURE_VM_BLOCKIO) */ } /* end OPEN_IC_SERVSIG(regs) */ } /* end function perform_external_interrupt */ /*-------------------------------------------------------------------*/ /* Store Status */ /* Input: */ /* sregs Register context of CPU whose status is to be stored */ /* aaddr A valid absolute address of a 512-byte block into */ /* which status is to be stored */ /* For an implicit store status, or an operator */ /* initiated store status the absolute address will be */ /* zero, for a store status at address order the */ /* supplied address will be nonzero */ /*-------------------------------------------------------------------*/ void ARCH_DEP(store_status) (REGS *ssreg, RADR aaddr) { int i; /* Array subscript */ PSA *sspsa; /* -> Store status area */ /* Set reference and change bits */ STORAGE_KEY(aaddr, ssreg) |= (STORKEY_REF | STORKEY_CHANGE); #if defined(FEATURE_ESAME) /* The ESAME PSA is two pages in size */ if(!aaddr) STORAGE_KEY(aaddr + 4096, ssreg) |= (STORKEY_REF | STORKEY_CHANGE); #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /* For store status at address, we must adjust the PSA offset */ /* ZZ THIS TEST IS NOT CONCLUSIVE */ if(aaddr != 0 && aaddr != ssreg->PX) aaddr -= 512 + 4096 ; #endif aaddr &= 0x7FFFFE00; /* Point to the PSA into which status is to be stored */ sspsa = (void*)(ssreg->mainstor + aaddr); /* Store CPU timer in bytes 216-223 */ STORE_DW(sspsa->storeptmr, cpu_timer(ssreg)); /* Store clock comparator in bytes 224-231 */ #if defined(FEATURE_ESAME) STORE_DW(sspsa->storeclkc, ssreg->clkc); #else /*defined(FEATURE_ESAME)*/ STORE_DW(sspsa->storeclkc, ssreg->clkc << 8); #endif /*defined(FEATURE_ESAME)*/ /* Store PSW in bytes 256-263 */ ARCH_DEP(store_psw) (ssreg, sspsa->storepsw); /* Store prefix register in bytes 264-267 */ STORE_FW(sspsa->storepfx,ssreg->PX); #if defined(FEATURE_ESAME) /* Store Floating Point Control Register */ STORE_FW(sspsa->storefpc,ssreg->fpc); /* Store TOD Programable register */ STORE_FW(sspsa->storetpr,ssreg->todpr); #endif /*defined(FEATURE_ESAME)*/ #if defined(_900) /* Only store the arch mode indicator for a PSA type store status */ if(!aaddr) #if defined(FEATURE_ESAME) sspsa->arch = 1; #else /*defined(FEATURE_ESAME)*/ sspsa->arch = 0; #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(_900)*/ /* Store access registers in bytes 288-351 */ for (i = 0; i < 16; i++) STORE_FW(sspsa->storear[i],ssreg->AR(i)); /* Store floating-point registers in bytes 352-383 */ #if defined(FEATURE_ESAME) for (i = 0; i < 32; i++) #else /*!defined(FEATURE_ESAME)*/ for (i = 0; i < 8; i++) #endif /*!defined(FEATURE_ESAME)*/ STORE_FW(sspsa->storefpr[i],ssreg->fpr[i]); /* Store general-purpose registers in bytes 384-447 */ for (i = 0; i < 16; i++) STORE_W(sspsa->storegpr[i],ssreg->GR(i)); /* Store control registers in bytes 448-511 */ for (i = 0; i < 16; i++) STORE_W(sspsa->storecr[i],ssreg->CR(i)); } /* end function store_status */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "external.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "external.c" #endif void store_status (REGS *ssreg, U64 aaddr) { switch(ssreg->arch_mode) { #if defined(_370) case ARCH_370: aaddr &= 0x7FFFFFFF; s370_store_status (ssreg, aaddr); break; #endif #if defined(_390) case ARCH_390: aaddr &= 0x7FFFFFFF; s390_store_status (ssreg, aaddr); break; #endif #if defined(_900) case ARCH_900: z900_store_status (ssreg, aaddr); break; #endif } } #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/float.c0000664000175000017500000103070712622153562011461 00000000000000/* FLOAT.C (c) Copyright Peter Kuschnerus, 2000-2009 */ /* ESA/390 Hex Floatingpoint Instructions */ /*-------------------------------------------------------------------*/ /* This module implements the ESA/390 Hex Floatingpoint Instructions */ /* described in the manual ESA/390 Principles of Operation. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Incorporated all floating point instructions from cpu.c in order */ /* to implement revised instruction decoding. */ /* Jan Jaeger 01/07/00 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Added the square-root-facility (instructions SQDR, SQER). */ /* Peter Kuschnerus 01/09/00 */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Added the HFP-extension-facility (26 additional instructions). */ /* Added the AFP-Registers-facility (additional float registers). */ /* Peter Kuschnerus 13/12/00 */ /* Long Displacement Facility: LDY,LEY,STDY,STEY R.Bowler 29/06/03 */ /* FPS Extensions Facility: LXR,LZER,LZDR,LZXR R.Bowler 06juil03 */ /* HFP Multiply and Add/Subtract Facility R.Bowler 10juil03 */ /* Convert 64fixed to float family CEGR,CDGR,CXGR BvdHelm 28/01/06 */ /* Completed the family CGER, CGDR and CGXR BvdHelm 04/11/06 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_FLOAT_C_) #define _FLOAT_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_HEXADECIMAL_FLOATING_POINT) /* Rename all inline functions for multi architectural support *JJ */ #undef get_sf #undef store_sf #undef get_lf #undef store_lf #undef get_ef #undef store_ef #undef vfetch_sf #undef vfetch_lf #undef normal_sf #undef normal_lf #undef normal_ef #undef overflow_sf #undef overflow_lf #undef overflow_ef #undef underflow_sf #undef underflow_lf #undef underflow_ef #undef over_under_flow_sf #undef over_under_flow_lf #undef over_under_flow_ef #undef significance_sf #undef significance_lf #undef significance_ef #undef add_ef #undef add_lf #undef add_sf #undef cmp_ef #undef cmp_lf #undef cmp_sf #undef div_U128 #undef div_U256 #undef div_ef #undef div_lf #undef div_sf #undef mul_ef #undef mul_sf #undef mul_lf #undef mul_lf_to_ef #undef mul_sf_to_lf #undef square_root_fraction #undef sq_sf #undef sq_lf #if __GEN_ARCH == 370 #define get_ef s370_get_ef #define get_lf s370_get_lf #define get_sf s370_get_sf #define normal_ef s370_normal_ef #define normal_lf s370_normal_lf #define normal_sf s370_normal_sf #define over_under_flow_ef s370_over_under_flow_ef #define over_under_flow_lf s370_over_under_flow_lf #define over_under_flow_sf s370_over_under_flow_sf #define overflow_ef s370_overflow_ef #define overflow_lf s370_overflow_lf #define overflow_sf s370_overflow_sf #define significance_ef s370_significance_ef #define significance_lf s370_significance_lf #define significance_sf s370_significance_sf #define store_ef s370_store_ef #define store_lf s370_store_lf #define store_sf s370_store_sf #define underflow_ef s370_underflow_ef #define underflow_lf s370_underflow_lf #define underflow_sf s370_underflow_sf #define vfetch_lf s370_vfetch_lf #define vfetch_sf s370_vfetch_sf #define add_ef s370_add_ef #define add_lf s370_add_lf #define add_sf s370_add_sf #define cmp_ef s370_cmp_ef #define cmp_lf s370_cmp_lf #define cmp_sf s370_cmp_sf #define div_U128 s370_div_U128 #define div_U256 s370_div_U256 #define div_ef s370_div_ef #define div_lf s370_div_lf #define div_sf s370_div_sf #define mul_ef s370_mul_ef #define mul_sf s370_mul_sf #define mul_lf s370_mul_lf #define mul_lf_to_ef s370_mul_lf_to_ef #define mul_sf_to_lf s370_mul_sf_to_lf #define square_root_fraction s370_square_root_fraction #define sq_sf s370_sq_sf #define sq_lf s370_sq_lf #elif __GEN_ARCH == 390 #define get_ef s390_get_ef #define get_lf s390_get_lf #define get_sf s390_get_sf #define normal_ef s390_normal_ef #define normal_lf s390_normal_lf #define normal_sf s390_normal_sf #define over_under_flow_ef s390_over_under_flow_ef #define over_under_flow_lf s390_over_under_flow_lf #define over_under_flow_sf s390_over_under_flow_sf #define overflow_ef s390_overflow_ef #define overflow_lf s390_overflow_lf #define overflow_sf s390_overflow_sf #define significance_ef s390_significance_ef #define significance_lf s390_significance_lf #define significance_sf s390_significance_sf #define store_ef s390_store_ef #define store_lf s390_store_lf #define store_sf s390_store_sf #define underflow_ef s390_underflow_ef #define underflow_lf s390_underflow_lf #define underflow_sf s390_underflow_sf #define vfetch_lf s390_vfetch_lf #define vfetch_sf s390_vfetch_sf #define add_ef s390_add_ef #define add_lf s390_add_lf #define add_sf s390_add_sf #define cmp_ef s390_cmp_ef #define cmp_lf s390_cmp_lf #define cmp_sf s390_cmp_sf #define div_U128 s390_div_U128 #define div_U256 s390_div_U256 #define div_ef s390_div_ef #define div_lf s390_div_lf #define div_sf s390_div_sf #define mul_ef s390_mul_ef #define mul_sf s390_mul_sf #define mul_lf s390_mul_lf #define mul_lf_to_ef s390_mul_lf_to_ef #define mul_sf_to_lf s390_mul_sf_to_lf #define square_root_fraction s390_square_root_fraction #define sq_sf s390_sq_sf #define sq_lf s390_sq_lf #elif __GEN_ARCH == 900 #define get_ef z900_get_ef #define get_lf z900_get_lf #define get_sf z900_get_sf #define normal_ef z900_normal_ef #define normal_lf z900_normal_lf #define normal_sf z900_normal_sf #define over_under_flow_ef z900_over_under_flow_ef #define over_under_flow_lf z900_over_under_flow_lf #define over_under_flow_sf z900_over_under_flow_sf #define overflow_ef z900_overflow_ef #define overflow_lf z900_overflow_lf #define overflow_sf z900_overflow_sf #define significance_ef z900_significance_ef #define significance_lf z900_significance_lf #define significance_sf z900_significance_sf #define store_ef z900_store_ef #define store_lf z900_store_lf #define store_sf z900_store_sf #define underflow_ef z900_underflow_ef #define underflow_lf z900_underflow_lf #define underflow_sf z900_underflow_sf #define vfetch_lf z900_vfetch_lf #define vfetch_sf z900_vfetch_sf #define add_ef z900_add_ef #define add_lf z900_add_lf #define add_sf z900_add_sf #define cmp_ef z900_cmp_ef #define cmp_lf z900_cmp_lf #define cmp_sf z900_cmp_sf #define div_U128 z900_div_U128 #define div_U256 z900_div_U256 #define div_ef z900_div_ef #define div_lf z900_div_lf #define div_sf z900_div_sf #define mul_ef z900_mul_ef #define mul_sf z900_mul_sf #define mul_lf z900_mul_lf #define mul_lf_to_ef z900_mul_lf_to_ef #define mul_sf_to_lf z900_mul_sf_to_lf #define square_root_fraction z900_square_root_fraction #define sq_sf z900_sq_sf #define sq_lf z900_sq_lf #else #error Unable to determine GEN_ARCH #endif #if !defined(_FLOAT_C) #define _FLOAT_C /*-------------------------------------------------------------------*/ /* Definitions */ /*-------------------------------------------------------------------*/ #define POS 0 /* Positive value of sign */ #define NEG 1 /* Negative value of sign */ #define UNNORMAL 0 /* Without normalisation */ #define NORMAL 1 /* With normalisation */ #define OVUNF 1 /* Check for over/underflow */ #define NOOVUNF 0 /* Leave exponent as is (for multiply-add/subtrace) */ #define SIGEX 1 /* Significance exception if result fraction is zero */ #define NOSIGEX 0 /* Do not raise significance exception, use true zero */ #define FLOAT_DEBUG 0 /* Change to 1 to enable debug messages */ /*-------------------------------------------------------------------*/ /* Add 128 bit unsigned integer */ /* The result is placed in operand a */ /* */ /* msa most significant 64 bit of operand a */ /* lsa least significant 64 bit of operand a */ /* msb most significant 64 bit of operand b */ /* lsb least significant 64 bit of operand b */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define add_U128(msa, lsa, msb, lsb) \ (lsa) += (lsb); \ (msa) += (msb); \ if ((lsa) < (lsb)) \ (msa)++ /*-------------------------------------------------------------------*/ /* Subtract 128 bit unsigned integer */ /* The operand b is subtracted from operand a */ /* The result is placed in operand a */ /* */ /* msa most significant 64 bit of operand a */ /* lsa least significant 64 bit of operand a */ /* msb most significant 64 bit of operand b */ /* lsb least significant 64 bit of operand b */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define sub_U128(msa, lsa, msb, lsb) \ (msa) -= (msb); \ if ((lsa) < (lsb)) \ (msa)--; \ (lsa) -= (lsb) /*-------------------------------------------------------------------*/ /* Subtract 128 bit unsigned integer reverse */ /* The operand a is subtracted from operand b */ /* The result is placed in operand a */ /* */ /* msa most significant 64 bit of operand a */ /* lsa least significant 64 bit of operand a */ /* msb most significant 64 bit of operand b */ /* lsb least significant 64 bit of operand b */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define sub_reverse_U128(msa, lsa, msb, lsb) \ (msa) = (msb) - (msa); \ if ((lsb) < (lsa)) \ (msa)--; \ (lsa) = (lsb) - (lsa) /*-------------------------------------------------------------------*/ /* Shift 128 bit one bit right */ /* */ /* ms most significant 64 bit of operand */ /* ls least significant 64 bit of operand */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define shift_right_U128(ms, ls) \ (ls) = ((ls) >> 1) | ((ms) << 63); \ (ms) >>= 1 /*-------------------------------------------------------------------*/ /* Shift 128 bit one bit left */ /* */ /* ms most significant 64 bit of operand */ /* ls least significant 64 bit of operand */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define shift_left_U128(ms, ls) \ (ms) = ((ms) << 1) | ((ls) >> 63); \ (ls) <<= 1 /*-------------------------------------------------------------------*/ /* Shift 128 bit 4 bits right with shifted digit */ /* */ /* ms most significant 64 bit of operand */ /* ls least significant 64 bit of operand */ /* dig least significant 4 bits removed by right shift */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define shift_right4_U128(ms, ls, dig) \ (dig) = (ls) & 0xF; \ (ls) = ((ls) >> 4) | ((ms) << 60); \ (ms) >>= 4 /*-------------------------------------------------------------------*/ /* Shift 128 bit 4 bits left with shifted digit */ /* */ /* ms most significant 64 bit of operand */ /* ls least significant 64 bit of operand */ /* dig most significant 4 bits removed by left shift */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define shift_left4_U128(ms, ls, dig) \ (dig) = (ms) >> 60; \ (ms) = ((ms) << 4) | ((ls) >> 60); \ (ls) <<= 4 /*-------------------------------------------------------------------*/ /* Shift 256 bit one bit left */ /* */ /* mms most significant 64 bit of operand */ /* ms more significant 64 bit of operand */ /* ls less significant 64 bit of operand */ /* lls least significant 64 bit of operand */ /* */ /* all operands are expected to be defined as U64 */ /*-------------------------------------------------------------------*/ #define shift_left_U256(mms, ms, ls, lls) \ (mms) = ((mms) << 1) | ((ms) >> 63); \ (ms) = ((ms) << 1) | ((ls) >> 63); \ (ls) = ((ls) << 1) | ((lls) >> 63); \ (lls) <<= 1 /*-------------------------------------------------------------------*/ /* Structure definition for internal short floatingpoint format */ /*-------------------------------------------------------------------*/ typedef struct _SHORT_FLOAT { U32 short_fract; /* Fraction */ short expo; /* Exponent + 64 */ BYTE sign; /* Sign */ } SHORT_FLOAT; /*-------------------------------------------------------------------*/ /* Structure definition for internal long floatingpoint format */ /*-------------------------------------------------------------------*/ typedef struct _LONG_FLOAT { U64 long_fract; /* Fraction */ short expo; /* Exponent + 64 */ BYTE sign; /* Sign */ } LONG_FLOAT; /*-------------------------------------------------------------------*/ /* Structure definition for internal extended floatingpoint format */ /*-------------------------------------------------------------------*/ typedef struct _EXTENDED_FLOAT { U64 ms_fract, ls_fract; /* Fraction */ short expo; /* Exponent + 64 */ BYTE sign; /* Sign */ } EXTENDED_FLOAT; #endif /*!defined(_FLOAT_C)*/ /*-------------------------------------------------------------------*/ /* Static inline functions */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Get short float from register */ /* */ /* Input: */ /* fl Internal float format to be converted to */ /* fpr Pointer to register to be converted from */ /*-------------------------------------------------------------------*/ static inline void get_sf( SHORT_FLOAT *fl, U32 *fpr ) { fl->sign = *fpr >> 31; fl->expo = (*fpr >> 24) & 0x007F; fl->short_fract = *fpr & 0x00FFFFFF; } /* end function get_sf */ /*-------------------------------------------------------------------*/ /* Store short float to register */ /* */ /* Input: */ /* fl Internal float format to be converted from */ /* fpr Pointer to register to be converted to */ /*-------------------------------------------------------------------*/ static inline void store_sf( SHORT_FLOAT *fl, U32 *fpr ) { *fpr = ((U32)fl->sign << 31) | ((U32)fl->expo << 24) | (fl->short_fract); } /* end function store_sf */ /*-------------------------------------------------------------------*/ /* Get long float from register */ /* */ /* Input: */ /* fl Internal float format to be converted to */ /* fpr Pointer to register to be converted from */ /*-------------------------------------------------------------------*/ static inline void get_lf( LONG_FLOAT *fl, U32 *fpr ) { fl->sign = *fpr >> 31; fl->expo = (*fpr >> 24) & 0x007F; fl->long_fract = ((U64)(fpr[0] & 0x00FFFFFF) << 32) | fpr[1]; } /* end function get_lf */ /*-------------------------------------------------------------------*/ /* Store long float to register */ /* */ /* Input: */ /* fl Internal float format to be converted from */ /* fpr Pointer to register to be converted to */ /*-------------------------------------------------------------------*/ static inline void store_lf( LONG_FLOAT *fl, U32 *fpr ) { fpr[0] = ((U32)fl->sign << 31) | ((U32)fl->expo << 24) | (fl->long_fract >> 32); fpr[1] = fl->long_fract; } /* end function store_lf */ /*-------------------------------------------------------------------*/ /* Get extended float from register */ /* */ /* Input: */ /* fl Internal float format to be converted to */ /* fpr Pointer to register to be converted from */ /*-------------------------------------------------------------------*/ static inline void get_ef( EXTENDED_FLOAT *fl, U32 *fpr ) { fl->sign = *fpr >> 31; fl->expo = (*fpr >> 24) & 0x007F; fl->ms_fract = ((U64)(fpr[0] & 0x00FFFFFF) << 24) | (fpr[1] >> 8); fl->ls_fract = (((U64)fpr[1]) << 56) | (((U64)(fpr[FPREX] & 0x00FFFFFF)) << 32) | fpr[FPREX+1]; } /* end function get_ef */ /*-------------------------------------------------------------------*/ /* Store extended float to register */ /* */ /* Input: */ /* fl Internal float format to be converted from */ /* fpr Pointer to register to be converted from */ /*-------------------------------------------------------------------*/ static inline void store_ef( EXTENDED_FLOAT *fl, U32 *fpr ) { fpr[0] = ((U32)fl->sign << 31) | ((U32)fl->expo << 24) | (fl->ms_fract >> 24); fpr[1] = (fl->ms_fract << 8) | (fl->ls_fract >> 56); fpr[FPREX] = ((U32)fl->sign << 31) | ((fl->ls_fract >> 32) & 0x00FFFFFF); fpr[FPREX+1] = fl->ls_fract; if ( fpr[0] || fpr[1] || fpr[FPREX] || fpr[FPREX+1] ) { fpr[FPREX] |= ((((U32)fl->expo - 14) << 24) & 0x7f000000); } } /* end function store_ef */ #if defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) /*-------------------------------------------------------------------*/ /* Store extended float high-order part to register unnormalized */ /* */ /* Input: */ /* fl Internal float format to be converted from */ /* fpr Pointer to register to be converted to */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(store_ef_unnorm_hi)( EXTENDED_FLOAT *fl, U32 *fpr ) { fpr[0] = ((U32)fl->sign << 31) | (((U32)fl->expo & 0x7f) << 24) | ((fl->ms_fract >> 24) & 0x00FFFFFF); fpr[1] = (fl->ms_fract << 8) | (fl->ls_fract >> 56); } /* end ARCH_DEP(store_ef_unnorm_hi) */ /*-------------------------------------------------------------------*/ /* Store extended float low-order part to register unnormalized */ /* */ /* Input: */ /* fl Internal float format to be converted from */ /* fpr Pointer to register to be converted to */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(store_ef_unnorm_lo)( EXTENDED_FLOAT *fl, U32 *fpr ) { fpr[0] = ((U32)fl->sign << 31) | ((((U32)fl->expo - 14 ) & 0x7f) << 24) | ((fl->ls_fract >> 32) & 0x00FFFFFF); fpr[1] = fl->ls_fract; } /* end ARCH_DEP(store_ef_unnorm_lo) */ /*-------------------------------------------------------------------*/ /* Store extended float to register pair unnormalized */ /* */ /* Input: */ /* fl Internal float format to be converted from */ /* fpr Pointer to register to be converted to */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(store_ef_unnorm)( EXTENDED_FLOAT *fl, U32 *fpr ) { ARCH_DEP(store_ef_unnorm_hi)(fl,fpr); ARCH_DEP(store_ef_unnorm_lo)(fl,fpr+FPREX); } /* end ARCH_DEP(store_ef_unnorm) */ /*-------------------------------------------------------------------*/ /* Convert long to extended format unnormalized */ /* */ /* Input: */ /* fl Internal float format to be converted from */ /* fpr Pointer to register to be converted to */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(lf_to_ef_unnorm) ( EXTENDED_FLOAT *fx, LONG_FLOAT *fl ) { fx->sign = fl->sign; fx->expo = fl->expo; fx->ms_fract = fl->long_fract >> 8; fx->ls_fract = (fl->long_fract & 0xff) << 56; } /* end ARCH_DEP(lf_to_ef_unnorm) */ #endif /* defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) */ /*-------------------------------------------------------------------*/ /* Fetch a short floatingpoint operand from virtual storage */ /* */ /* Input: */ /* fl Internal float format */ /* addr Logical address of leftmost byte of operand */ /* arn Access register number */ /* regs CPU register context */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ static inline void vfetch_sf( SHORT_FLOAT *fl, VADR addr, int arn, REGS *regs ) { U32 value; /* Operand value */ /* Fetch 4 bytes from operand address */ value = ARCH_DEP(vfetch4) (addr, arn, regs); /* Extract sign and exponent from high-order byte */ fl->sign = value >> 31; fl->expo = (value >> 24) & 0x007F; /* Extract fraction from low-order 3 bytes */ fl->short_fract = value & 0x00FFFFFF; } /* end function vfetch_sf */ /*-------------------------------------------------------------------*/ /* Fetch a long floatingpoint operand from virtual storage */ /* */ /* Input: */ /* fl Internal float format */ /* addr Logical address of leftmost byte of operand */ /* arn Access register number */ /* regs CPU register context */ /* */ /* A program check may be generated if the logical address */ /* causes an addressing, translation, or fetch protection */ /* exception, and in this case the function does not return. */ /*-------------------------------------------------------------------*/ static inline void vfetch_lf( LONG_FLOAT *fl, VADR addr, int arn, REGS *regs ) { U64 value; /* Operand value */ /* Fetch 8 bytes from operand address */ value = ARCH_DEP(vfetch8) (addr, arn, regs); /* Extract sign and exponent from high-order byte */ fl->sign = value >> 63; fl->expo = (value >> 56) & 0x007F; /* Extract fraction from low-order 7 bytes */ fl->long_fract = value & 0x00FFFFFFFFFFFFFFULL; } /* end function vfetch_lf */ /*-------------------------------------------------------------------*/ /* Normalize short float */ /* */ /* Input: */ /* fl Internal float */ /*-------------------------------------------------------------------*/ static inline void normal_sf( SHORT_FLOAT *fl ) { if (fl->short_fract) { if ((fl->short_fract & 0x00FFFF00) == 0) { fl->short_fract <<= 16; fl->expo -= 4; } if ((fl->short_fract & 0x00FF0000) == 0) { fl->short_fract <<= 8; fl->expo -= 2; } if ((fl->short_fract & 0x00F00000) == 0) { fl->short_fract <<= 4; (fl->expo)--; } } else { fl->sign = POS; fl->expo = 0; } } /* end function normal_sf */ /*-------------------------------------------------------------------*/ /* Normalize long float */ /* */ /* Input: */ /* fl Internal float */ /*-------------------------------------------------------------------*/ static inline void normal_lf( LONG_FLOAT *fl ) { if (fl->long_fract) { if ((fl->long_fract & 0x00FFFFFFFF000000ULL) == 0) { fl->long_fract <<= 32; fl->expo -= 8; } if ((fl->long_fract & 0x00FFFF0000000000ULL) == 0) { fl->long_fract <<= 16; fl->expo -= 4; } if ((fl->long_fract & 0x00FF000000000000ULL) == 0) { fl->long_fract <<= 8; fl->expo -= 2; } if ((fl->long_fract & 0x00F0000000000000ULL) == 0) { fl->long_fract <<= 4; (fl->expo)--; } } else { fl->sign = POS; fl->expo = 0; } } /* end function normal_lf */ /*-------------------------------------------------------------------*/ /* Normalize extended float */ /* */ /* Input: */ /* fl Internal float */ /*-------------------------------------------------------------------*/ static inline void normal_ef( EXTENDED_FLOAT *fl ) { if (fl->ms_fract || fl->ls_fract) { if (fl->ms_fract == 0) { fl->ms_fract = fl->ls_fract >> 16; fl->ls_fract <<= 48; fl->expo -= 12; } if ((fl->ms_fract & 0x0000FFFFFFFF0000ULL) == 0) { if (fl->ls_fract) { fl->ms_fract = (fl->ms_fract << 32) | (fl->ls_fract >> 32); fl->ls_fract <<= 32; } else { fl->ms_fract <<= 32; } fl->expo -= 8; } if ((fl->ms_fract & 0x0000FFFF00000000ULL) == 0) { if (fl->ls_fract) { fl->ms_fract = (fl->ms_fract << 16) | (fl->ls_fract >> 48); fl->ls_fract <<= 16; } else { fl->ms_fract <<= 16; } fl->expo -= 4; } if ((fl->ms_fract & 0x0000FF0000000000ULL) == 0) { if (fl->ls_fract) { fl->ms_fract = (fl->ms_fract << 8) | (fl->ls_fract >> 56); fl->ls_fract <<= 8; } else { fl->ms_fract <<= 8; } fl->expo -= 2; } if ((fl->ms_fract & 0x0000F00000000000ULL) == 0) { if (fl->ls_fract) { fl->ms_fract = (fl->ms_fract << 4) | (fl->ls_fract >> 60); fl->ls_fract <<= 4; } else { fl->ms_fract <<= 4; } (fl->expo)--; } } else { fl->sign = POS; fl->expo = 0; } } /* end function normal_ef */ /*-------------------------------------------------------------------*/ /* Overflow of short float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int overflow_sf( SHORT_FLOAT *fl, REGS *regs ) { UNREFERENCED(regs); if (fl->expo > 127) { fl->expo &= 0x007F; return(PGM_EXPONENT_OVERFLOW_EXCEPTION); } return(0); } /* end function overflow_sf */ /*-------------------------------------------------------------------*/ /* Overflow of long float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int overflow_lf( LONG_FLOAT *fl, REGS *regs ) { UNREFERENCED(regs); if (fl->expo > 127) { fl->expo &= 0x007F; return(PGM_EXPONENT_OVERFLOW_EXCEPTION); } return(0); } /* end function overflow_lf */ /*-------------------------------------------------------------------*/ /* Overflow of extended float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int overflow_ef( EXTENDED_FLOAT *fl, REGS *regs ) { UNREFERENCED(regs); if (fl->expo > 127) { fl->expo &= 0x007F; return(PGM_EXPONENT_OVERFLOW_EXCEPTION); } return(0); } /* end function overflow_ef */ /*-------------------------------------------------------------------*/ /* Underflow of short float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int underflow_sf( SHORT_FLOAT *fl, REGS *regs ) { if (fl->expo < 0) { if (EUMASK(®s->psw)) { fl->expo &= 0x007F; return(PGM_EXPONENT_UNDERFLOW_EXCEPTION); } else { /* set true 0 */ fl->short_fract = 0; fl->expo = 0; fl->sign = POS; } } return(0); } /* end function underflow_sf */ /*-------------------------------------------------------------------*/ /* Underflow of long float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int underflow_lf( LONG_FLOAT *fl, REGS *regs ) { if (fl->expo < 0) { if (EUMASK(®s->psw)) { fl->expo &= 0x007F; return(PGM_EXPONENT_UNDERFLOW_EXCEPTION); } else { /* set true 0 */ fl->long_fract = 0; fl->expo = 0; fl->sign = POS; } } return(0); } /* end function underflow_lf */ /*-------------------------------------------------------------------*/ /* Underflow of extended float */ /* */ /* Input: */ /* fl Internal float */ /* fpr Pointer to register to be stored to */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int underflow_ef( EXTENDED_FLOAT *fl, U32 *fpr, REGS *regs ) { if (fl->expo < 0) { if (EUMASK(®s->psw)) { fl->expo &= 0x007F; store_ef( fl, fpr ); return(PGM_EXPONENT_UNDERFLOW_EXCEPTION); } else { /* set true 0 */ fpr[0] = 0; fpr[1] = 0; fpr[FPREX] = 0; fpr[FPREX+1] = 0; fl->ms_fract = 0; fl->ls_fract = 0; return(0); } } store_ef( fl, fpr ); return(0); } /* end function underflow_ef */ /*-------------------------------------------------------------------*/ /* Overflow and underflow of short float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int over_under_flow_sf( SHORT_FLOAT *fl, REGS *regs ) { if (fl->expo > 127) { fl->expo &= 0x007F; return(PGM_EXPONENT_OVERFLOW_EXCEPTION); } else { if (fl->expo < 0) { if (EUMASK(®s->psw)) { fl->expo &= 0x007F; return(PGM_EXPONENT_UNDERFLOW_EXCEPTION); } else { /* set true 0 */ fl->short_fract = 0; fl->expo = 0; fl->sign = POS; } } } return(0); } /* end function over_under_flow_sf */ /*-------------------------------------------------------------------*/ /* Overflow and underflow of long float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int over_under_flow_lf( LONG_FLOAT *fl, REGS *regs ) { if (fl->expo > 127) { fl->expo &= 0x007F; return(PGM_EXPONENT_OVERFLOW_EXCEPTION); } else { if (fl->expo < 0) { if (EUMASK(®s->psw)) { fl->expo &= 0x007F; return(PGM_EXPONENT_UNDERFLOW_EXCEPTION); } else { /* set true 0 */ fl->long_fract = 0; fl->expo = 0; fl->sign = POS; } } } return(0); } /* end function over_under_flow_lf */ /*-------------------------------------------------------------------*/ /* Overflow and underflow of extended float */ /* */ /* Input: */ /* fl Internal float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int over_under_flow_ef( EXTENDED_FLOAT *fl, REGS *regs ) { if (fl->expo > 127) { fl->expo &= 0x007F; return(PGM_EXPONENT_OVERFLOW_EXCEPTION); } else { if (fl->expo < 0) { if (EUMASK(®s->psw)) { fl->expo &= 0x007F; return(PGM_EXPONENT_UNDERFLOW_EXCEPTION); } else { /* set true 0 */ fl->ms_fract = 0; fl->ls_fract = 0; fl->expo = 0; fl->sign = POS; } } } return(0); } /* end function over_under_flow_ef */ /*-------------------------------------------------------------------*/ /* Significance of short float */ /* The fraction is expected to be zero */ /* */ /* Input: */ /* fl Internal float */ /* sigex Allow significance exception if true */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int significance_sf( SHORT_FLOAT *fl, BYTE sigex, REGS *regs ) { fl->sign = POS; if (sigex && SGMASK(®s->psw)) { return(PGM_SIGNIFICANCE_EXCEPTION); } /* set true 0 */ fl->expo = 0; return(0); } /* end function significance_sf */ /*-------------------------------------------------------------------*/ /* Significance of long float */ /* The fraction is expected to be zero */ /* */ /* Input: */ /* fl Internal float */ /* sigex Allow significance exception if true */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int significance_lf( LONG_FLOAT *fl, BYTE sigex, REGS *regs ) { fl->sign = POS; if (sigex && SGMASK(®s->psw)) { return(PGM_SIGNIFICANCE_EXCEPTION); } /* set true 0 */ fl->expo = 0; return(0); } /* end function significance_lf */ /*-------------------------------------------------------------------*/ /* Significance of extended float */ /* The fraction is expected to be zero */ /* */ /* Input: */ /* fl Internal float */ /* fpr Pointer to register to be stored to */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static inline int significance_ef( EXTENDED_FLOAT *fl, U32 *fpr, REGS *regs ) { fpr[1] = 0; fpr[FPREX+1] = 0; if (SGMASK(®s->psw)) { fpr[0] = (U32)fl->expo << 24; fpr[FPREX] = (((U32)fl->expo - 14) << 24) & 0x7f000000; return(PGM_SIGNIFICANCE_EXCEPTION); } /* set true 0 */ fpr[0] = 0; fpr[FPREX] = 0; return(0); } /* end function significance_ef */ /*-------------------------------------------------------------------*/ /* Static functions */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Add short float */ /* */ /* Input: */ /* fl Float */ /* add_fl Float to be added */ /* normal Normalize if true */ /* sigex Allow significance exception if true */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int add_sf( SHORT_FLOAT *fl, SHORT_FLOAT *add_fl, BYTE normal, BYTE sigex, REGS *regs ) { int pgm_check; BYTE shift; pgm_check = 0; if (add_fl->short_fract || add_fl->expo) { /* add_fl not 0 */ if (fl->short_fract || fl->expo) { /* fl not 0 */ /* both not 0 */ if (fl->expo == add_fl->expo) { /* expo equal */ /* both guard digits */ fl->short_fract <<= 4; add_fl->short_fract <<= 4; } else { /* expo not equal, denormalize */ if (fl->expo < add_fl->expo) { /* shift minus guard digit */ shift = add_fl->expo - fl->expo - 1; fl->expo = add_fl->expo; if (shift) { if (shift >= 6 || ((fl->short_fract >>= (shift * 4)) == 0)) { /* 0, copy summand */ fl->sign = add_fl->sign; fl->short_fract = add_fl->short_fract; if (fl->short_fract == 0) { pgm_check = significance_sf(fl, sigex, regs); } else { if (normal == NORMAL) { normal_sf(fl); pgm_check = underflow_sf(fl, regs); } } return(pgm_check); } } /* guard digit */ add_fl->short_fract <<= 4; } else { /* shift minus guard digit */ shift = fl->expo - add_fl->expo - 1; if (shift) { if (shift >= 6 || ((add_fl->short_fract >>= (shift * 4)) == 0)) { /* 0, nothing to add */ if (fl->short_fract == 0) { pgm_check = significance_sf(fl, sigex, regs); } else { if (normal == NORMAL) { normal_sf(fl); pgm_check = underflow_sf(fl, regs); } } return(pgm_check); } } /* guard digit */ fl->short_fract <<= 4; } } /* compute with guard digit */ if (fl->sign == add_fl->sign) { fl->short_fract += add_fl->short_fract; } else { if (fl->short_fract == add_fl->short_fract) { /* true 0 */ fl->short_fract = 0; return( significance_sf(fl, sigex, regs) ); } else if (fl->short_fract > add_fl->short_fract) { fl->short_fract -= add_fl->short_fract; } else { fl->short_fract = add_fl->short_fract - fl->short_fract; fl->sign = add_fl->sign; } } /* handle overflow with guard digit */ if (fl->short_fract & 0xF0000000) { fl->short_fract >>= 8; (fl->expo)++; pgm_check = overflow_sf(fl, regs); } else { if (normal == NORMAL) { /* normalize with guard digit */ if (fl->short_fract) { /* not 0 */ if (fl->short_fract & 0x0F000000) { /* not normalize, just guard digit */ fl->short_fract >>= 4; } else { (fl->expo)--; normal_sf(fl); pgm_check = underflow_sf(fl, regs); } } else { /* true 0 */ pgm_check = significance_sf(fl, sigex, regs); } } else { /* not normalize, just guard digit */ fl->short_fract >>= 4; if (fl->short_fract == 0) { pgm_check = significance_sf(fl, sigex, regs); } } } return(pgm_check); } else { /* fl 0, add_fl not 0 */ /* copy summand */ fl->expo = add_fl->expo; fl->sign = add_fl->sign; fl->short_fract = add_fl->short_fract; if (fl->short_fract == 0) { return( significance_sf(fl, sigex, regs) ); } } } else { /* add_fl 0 */ if (fl->short_fract == 0) { /* fl 0 */ /* both 0 */ return( significance_sf(fl, sigex, regs) ); } } if (normal == NORMAL) { normal_sf(fl); pgm_check = underflow_sf(fl, regs); } return(pgm_check); } /* end function add_sf */ /*-------------------------------------------------------------------*/ /* Add long float */ /* */ /* Input: */ /* fl Float */ /* add_fl Float to be added */ /* normal Normalize if true */ /* sigex Allow significance exception if true */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int add_lf( LONG_FLOAT *fl, LONG_FLOAT *add_fl, BYTE normal, BYTE sigex, REGS *regs ) { int pgm_check; BYTE shift; pgm_check = 0; if (add_fl->long_fract || add_fl->expo) { /* add_fl not 0 */ if (fl->long_fract || fl->expo) { /* fl not 0 */ /* both not 0 */ if (fl->expo == add_fl->expo) { /* expo equal */ /* both guard digits */ fl->long_fract <<= 4; add_fl->long_fract <<= 4; } else { /* expo not equal, denormalize */ if (fl->expo < add_fl->expo) { /* shift minus guard digit */ shift = add_fl->expo - fl->expo - 1; fl->expo = add_fl->expo; if (shift) { if (shift >= 14 || ((fl->long_fract >>= (shift * 4)) == 0)) { /* 0, copy summand */ fl->sign = add_fl->sign; fl->long_fract = add_fl->long_fract; if (fl->long_fract == 0) { pgm_check = significance_lf(fl, sigex, regs); } else { if (normal == NORMAL) { normal_lf(fl); pgm_check = underflow_lf(fl, regs); } } return(pgm_check); } } /* guard digit */ add_fl->long_fract <<= 4; } else { /* shift minus guard digit */ shift = fl->expo - add_fl->expo - 1; if (shift) { if (shift >= 14 || ((add_fl->long_fract >>= (shift * 4)) == 0)) { /* 0, nothing to add */ if (fl->long_fract == 0) { pgm_check = significance_lf(fl, sigex, regs); } else { if (normal == NORMAL) { normal_lf(fl); pgm_check = underflow_lf(fl, regs); } } return(pgm_check); } } /* guard digit */ fl->long_fract <<= 4; } } /* compute with guard digit */ if (fl->sign == add_fl->sign) { fl->long_fract += add_fl->long_fract; } else { if (fl->long_fract == add_fl->long_fract) { /* true 0 */ fl->long_fract = 0; return( significance_lf(fl, sigex, regs) ); } else if (fl->long_fract > add_fl->long_fract) { fl->long_fract -= add_fl->long_fract; } else { fl->long_fract = add_fl->long_fract - fl->long_fract; fl->sign = add_fl->sign; } } /* handle overflow with guard digit */ if (fl->long_fract & 0xF000000000000000ULL) { fl->long_fract >>= 8; (fl->expo)++; pgm_check = overflow_lf(fl, regs); } else { if (normal == NORMAL) { /* normalize with guard digit */ if (fl->long_fract) { /* not 0 */ if (fl->long_fract & 0x0F00000000000000ULL) { /* not normalize, just guard digit */ fl->long_fract >>= 4; } else { (fl->expo)--; normal_lf(fl); pgm_check = underflow_lf(fl, regs); } } else { /* true 0 */ pgm_check = significance_lf(fl, sigex, regs); } } else { /* not normalize, just guard digit */ fl->long_fract >>= 4; if (fl->long_fract == 0) { pgm_check = significance_lf(fl, sigex, regs); } } } return(pgm_check); } else { /* fl 0, add_fl not 0 */ /* copy summand */ fl->expo = add_fl->expo; fl->sign = add_fl->sign; fl->long_fract = add_fl->long_fract; if (fl->long_fract == 0) { return( significance_lf(fl, sigex, regs) ); } } } else { /* add_fl 0 */ if (fl->long_fract == 0) { /* fl 0 */ /* both 0 */ return( significance_lf(fl, sigex, regs) ); } } if (normal == NORMAL) { normal_lf(fl); pgm_check = underflow_lf(fl, regs); } return(pgm_check); } /* end function add_lf */ /*-------------------------------------------------------------------*/ /* Add extended float normalized */ /* */ /* Input: */ /* fl Float */ /* add_fl Float to be added */ /* fpr Pointer to register */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int add_ef( EXTENDED_FLOAT *fl, EXTENDED_FLOAT *add_fl, U32 *fpr, REGS *regs ) { int pgm_check; BYTE shift; pgm_check = 0; if (add_fl->ms_fract || add_fl->ls_fract || add_fl->expo) { /* add_fl not 0 */ if (fl->ms_fract || fl->ls_fract || fl->expo) { /* fl not 0 */ /* both not 0 */ if (fl->expo == add_fl->expo) { /* expo equal */ /* both guard digits */ fl->ms_fract = (fl->ms_fract << 4) | (fl->ls_fract >> 60); fl->ls_fract <<= 4; add_fl->ms_fract = (add_fl->ms_fract << 4) | (add_fl->ls_fract >> 60); add_fl->ls_fract <<= 4; } else { /* expo not equal, denormalize */ if (fl->expo < add_fl->expo) { /* shift minus guard digit */ shift = add_fl->expo - fl->expo - 1; fl->expo = add_fl->expo; if (shift) { if (shift >= 28) { /* 0, copy summand */ fl->sign = add_fl->sign; fl->ms_fract = add_fl->ms_fract; fl->ls_fract = add_fl->ls_fract; if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { pgm_check = significance_ef(fl, fpr, regs); } else { normal_ef(fl); pgm_check = underflow_ef(fl, fpr, regs); } return(pgm_check); } else if (shift >= 16) { fl->ls_fract = fl->ms_fract; if (shift > 16) { fl->ls_fract >>= (shift - 16) * 4; } fl->ms_fract = 0; } else { shift *= 4; fl->ls_fract = fl->ms_fract << (64 - shift) | fl->ls_fract >> shift; fl->ms_fract >>= shift; } if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { /* 0, copy summand */ fl->sign = add_fl->sign; fl->ms_fract = add_fl->ms_fract; fl->ls_fract = add_fl->ls_fract; if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { pgm_check = significance_ef(fl, fpr, regs); } else { normal_ef(fl); pgm_check = underflow_ef(fl, fpr, regs); } return(pgm_check); } } /* guard digit */ add_fl->ms_fract = (add_fl->ms_fract << 4) | (add_fl->ls_fract >> 60); add_fl->ls_fract <<= 4; } else { /* shift minus guard digit */ shift = fl->expo - add_fl->expo - 1; if (shift) { if (shift >= 28) { /* 0, nothing to add */ if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { pgm_check = significance_ef(fl, fpr, regs); } else { normal_ef(fl); pgm_check = underflow_ef(fl, fpr, regs); } return(pgm_check); } else if (shift >= 16) { add_fl->ls_fract = add_fl->ms_fract; if (shift > 16) { add_fl->ls_fract >>= (shift - 16) * 4; } add_fl->ms_fract = 0; } else { shift *= 4; add_fl->ls_fract = add_fl->ms_fract << (64 - shift) | add_fl->ls_fract >> shift; add_fl->ms_fract >>= shift; } if ((add_fl->ms_fract == 0) && (add_fl->ls_fract == 0)) { /* 0, nothing to add */ if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { pgm_check = significance_ef(fl, fpr, regs); } else { normal_ef(fl); pgm_check = underflow_ef(fl, fpr, regs); } return(pgm_check); } } /* guard digit */ fl->ms_fract = (fl->ms_fract << 4) | (fl->ls_fract >> 60); fl->ls_fract <<= 4; } } /* compute with guard digit */ if (fl->sign == add_fl->sign) { add_U128(fl->ms_fract, fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract); } else { if ((fl->ms_fract == add_fl->ms_fract) && (fl->ls_fract == add_fl->ls_fract)) { /* true 0 */ fl->ms_fract = 0; fl->ls_fract = 0; return( significance_ef(fl, fpr, regs) ); } else if ( (fl->ms_fract > add_fl->ms_fract) || ( (fl->ms_fract == add_fl->ms_fract) && (fl->ls_fract > add_fl->ls_fract))) { sub_U128(fl->ms_fract, fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract); } else { sub_reverse_U128(fl->ms_fract, fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract); fl->sign = add_fl->sign; } } /* handle overflow with guard digit */ if (fl->ms_fract & 0x00F0000000000000ULL) { fl->ls_fract = (fl->ms_fract << 56) | (fl->ls_fract >> 8); fl->ms_fract >>= 8; (fl->expo)++; pgm_check = overflow_ef(fl, regs); store_ef( fl, fpr ); } else { /* normalize with guard digit */ if (fl->ms_fract || fl->ls_fract) { /* not 0 */ if (fl->ms_fract & 0x000F000000000000ULL) { /* not normalize, just guard digit */ fl->ls_fract = (fl->ms_fract << 60) | (fl->ls_fract >> 4); fl->ms_fract >>= 4; store_ef( fl, fpr ); } else { (fl->expo)--; normal_ef(fl); pgm_check = underflow_ef(fl, fpr, regs); } } else { /* true 0 */ pgm_check = significance_ef(fl, fpr, regs); } } return(pgm_check); } else { /* fl 0, add_fl not 0 */ /* copy summand */ fl->expo = add_fl->expo; fl->sign = add_fl->sign; fl->ms_fract = add_fl->ms_fract; fl->ls_fract = add_fl->ls_fract; if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { return( significance_ef(fl, fpr, regs) ); } } } else { /* add_fl 0*/ if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { /* fl 0 */ /* both 0 */ return( significance_ef(fl, fpr, regs) ); } } normal_ef(fl); return( underflow_ef(fl, fpr, regs) ); } /* end function add_ef */ /*-------------------------------------------------------------------*/ /* Compare short float */ /* */ /* Input: */ /* fl Float */ /* cmp_fl Float to be compared */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static void cmp_sf( SHORT_FLOAT *fl, SHORT_FLOAT *cmp_fl, REGS *regs ) { BYTE shift; if (cmp_fl->short_fract || cmp_fl->expo) { /* cmp_fl not 0 */ if (fl->short_fract || fl->expo) { /* fl not 0 */ /* both not 0 */ if (fl->expo == cmp_fl->expo) { /* expo equal */ /* both guard digits */ fl->short_fract <<= 4; cmp_fl->short_fract <<= 4; } else { /* expo not equal, denormalize */ if (fl->expo < cmp_fl->expo) { /* shift minus guard digit */ shift = cmp_fl->expo - fl->expo - 1; if (shift) { if (shift >= 6 || ((fl->short_fract >>= (shift * 4)) == 0)) { /* Set condition code */ if (cmp_fl->short_fract) { regs->psw.cc = cmp_fl->sign ? 2 : 1; } else { regs->psw.cc = 0; } return; } } /* guard digit */ cmp_fl->short_fract <<= 4; } else { /* shift minus guard digit */ shift = fl->expo - cmp_fl->expo - 1; if (shift) { if (shift >= 6 || ((cmp_fl->short_fract >>= (shift * 4)) == 0)) { /* Set condition code */ if (fl->short_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } } /* guard digit */ fl->short_fract <<= 4; } } /* compute with guard digit */ if (fl->sign != cmp_fl->sign) { fl->short_fract += cmp_fl->short_fract; } else if (fl->short_fract >= cmp_fl->short_fract) { fl->short_fract -= cmp_fl->short_fract; } else { fl->short_fract = cmp_fl->short_fract - fl->short_fract; fl->sign = ! (cmp_fl->sign); } /* handle overflow with guard digit */ if (fl->short_fract & 0xF0000000) { fl->short_fract >>= 4; } /* Set condition code */ if (fl->short_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } else { /* fl 0, cmp_fl not 0 */ /* Set condition code */ if (cmp_fl->short_fract) { regs->psw.cc = cmp_fl->sign ? 2 : 1; } else { regs->psw.cc = 0; } return; } } else { /* cmp_fl 0 */ /* Set condition code */ if (fl->short_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } } /* end function cmp_sf */ /*-------------------------------------------------------------------*/ /* Compare long float */ /* */ /* Input: */ /* fl Float */ /* cmp_fl Float to be compared */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static void cmp_lf( LONG_FLOAT *fl, LONG_FLOAT *cmp_fl, REGS *regs ) { BYTE shift; if (cmp_fl->long_fract || cmp_fl->expo) { /* cmp_fl not 0 */ if (fl->long_fract || fl->expo) { /* fl not 0 */ /* both not 0 */ if (fl->expo == cmp_fl->expo) { /* expo equal */ /* both guard digits */ fl->long_fract <<= 4; cmp_fl->long_fract <<= 4; } else { /* expo not equal, denormalize */ if (fl->expo < cmp_fl->expo) { /* shift minus guard digit */ shift = cmp_fl->expo - fl->expo - 1; if (shift) { if (shift >= 14 || ((fl->long_fract >>= (shift * 4)) == 0)) { /* Set condition code */ if (cmp_fl->long_fract) { regs->psw.cc = cmp_fl->sign ? 2 : 1; } else { regs->psw.cc = 0; } return; } } /* guard digit */ cmp_fl->long_fract <<= 4; } else { /* shift minus guard digit */ shift = fl->expo - cmp_fl->expo - 1; if (shift) { if (shift >= 14 || ((cmp_fl->long_fract >>= (shift * 4)) == 0)) { /* Set condition code */ if (fl->long_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } } /* guard digit */ fl->long_fract <<= 4; } } /* compute with guard digit */ if (fl->sign != cmp_fl->sign) { fl->long_fract += cmp_fl->long_fract; } else if (fl->long_fract >= cmp_fl->long_fract) { fl->long_fract -= cmp_fl->long_fract; } else { fl->long_fract = cmp_fl->long_fract - fl->long_fract; fl->sign = ! (cmp_fl->sign); } /* handle overflow with guard digit */ if (fl->long_fract & 0xF0000000) { fl->long_fract >>= 4; } /* Set condition code */ if (fl->long_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } else { /* fl 0, cmp_fl not 0 */ /* Set condition code */ if (cmp_fl->long_fract) { regs->psw.cc = cmp_fl->sign ? 2 : 1; } else { regs->psw.cc = 0; } return; } } else { /* cmp_fl 0 */ /* Set condition code */ if (fl->long_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } } /* end function cmp_lf */ #if defined (FEATURE_HFP_EXTENSIONS) /*-------------------------------------------------------------------*/ /* Compare extended float */ /* */ /* Input: */ /* fl Float */ /* cmp_fl Float to be compared */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static void cmp_ef( EXTENDED_FLOAT *fl, EXTENDED_FLOAT *cmp_fl, REGS *regs ) { BYTE shift; if (cmp_fl->ms_fract || cmp_fl->ls_fract || cmp_fl->expo) { /* cmp_fl not 0 */ if (fl->ms_fract || fl->ls_fract || fl->expo) { /* fl not 0 */ /* both not 0 */ if (fl->expo == cmp_fl->expo) { /* expo equal */ /* both guard digits */ fl->ms_fract = (fl->ms_fract << 4) | (fl->ls_fract >> 60); fl->ls_fract <<= 4; cmp_fl->ms_fract = (cmp_fl->ms_fract << 4) | (cmp_fl->ls_fract >> 60); cmp_fl->ls_fract <<= 4; } else { /* expo not equal, denormalize */ if (fl->expo < cmp_fl->expo) { /* shift minus guard digit */ shift = cmp_fl->expo - fl->expo - 1; if (shift) { if (shift >= 28) { /* Set condition code */ if (cmp_fl->ms_fract || cmp_fl->ls_fract) { regs->psw.cc = cmp_fl->sign ? 2 : 1; } else { regs->psw.cc = 0; } return; } else if (shift >= 16) { fl->ls_fract = fl->ms_fract; if (shift > 16) { fl->ls_fract >>= (shift - 16) * 4; } fl->ms_fract = 0; } else { shift *= 4; fl->ls_fract = fl->ms_fract << (64 - shift) | fl->ls_fract >> shift; fl->ms_fract >>= shift; } if ((fl->ms_fract == 0) && (fl->ls_fract == 0)) { /* Set condition code */ if (cmp_fl->ms_fract || cmp_fl->ls_fract) { regs->psw.cc = cmp_fl->sign ? 2 : 1; } else { regs->psw.cc = 0; } return; } } /* guard digit */ cmp_fl->ms_fract = (cmp_fl->ms_fract << 4) | (cmp_fl->ls_fract >> 60); cmp_fl->ls_fract <<= 4; } else { /* shift minus guard digit */ shift = fl->expo - cmp_fl->expo - 1; if (shift) { if (shift >= 28) { /* Set condition code */ if (fl->ms_fract || fl->ls_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } else if (shift >= 16) { cmp_fl->ls_fract = cmp_fl->ms_fract; if (shift > 16) { cmp_fl->ls_fract >>= (shift - 16) * 4; } cmp_fl->ms_fract = 0; } else { shift *= 4; cmp_fl->ls_fract = cmp_fl->ms_fract << (64 - shift) | cmp_fl->ls_fract >> shift; cmp_fl->ms_fract >>= shift; } if ((cmp_fl->ms_fract == 0) && (cmp_fl->ls_fract == 0)) { /* Set condition code */ if (fl->ms_fract || fl->ls_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } } /* guard digit */ fl->ms_fract = (fl->ms_fract << 4) | (fl->ls_fract >> 60); fl->ls_fract <<= 4; } } /* compute with guard digit */ if (fl->sign != cmp_fl->sign) { add_U128(fl->ms_fract, fl->ls_fract, cmp_fl->ms_fract, cmp_fl->ls_fract); } else if ((fl->ms_fract > cmp_fl->ms_fract) || ((fl->ms_fract == cmp_fl->ms_fract) && (fl->ls_fract >= cmp_fl->ls_fract))) { sub_U128(fl->ms_fract, fl->ls_fract, cmp_fl->ms_fract, cmp_fl->ls_fract); } else { sub_reverse_U128(fl->ms_fract, fl->ls_fract, cmp_fl->ms_fract, cmp_fl->ls_fract); fl->sign = ! (cmp_fl->sign); } /* handle overflow with guard digit */ if (fl->ms_fract & 0x00F0000000000000ULL) { fl->ls_fract = (fl->ms_fract << 60) | (fl->ls_fract >> 4); fl->ms_fract >>= 4; } /* Set condition code */ if (fl->ms_fract || fl->ls_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } else { /* fl 0, cmp_fl not 0 */ /* Set condition code */ if (cmp_fl->ms_fract || cmp_fl->ls_fract) { regs->psw.cc = cmp_fl->sign ? 2 : 1; } else { regs->psw.cc = 0; } return; } } else { /* cmp_fl 0 */ /* Set condition code */ if (fl->ms_fract || fl->ls_fract) { regs->psw.cc = fl->sign ? 1 : 2; } else { regs->psw.cc = 0; } return; } } /* end function cmp_ef */ #endif /*defined (FEATURE_HFP_EXTENSIONS)*/ /*-------------------------------------------------------------------*/ /* Multiply short float to long float */ /* */ /* Input: */ /* fl Multiplicand short float */ /* mul_fl Multiplicator short float */ /* result_fl Result long float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int mul_sf_to_lf( SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl, LONG_FLOAT *result_fl, REGS *regs ) { if (fl->short_fract && mul_fl->short_fract) { /* normalize operands */ normal_sf( fl ); normal_sf( mul_fl ); /* multiply fracts */ result_fl->long_fract = (U64) fl->short_fract * mul_fl->short_fract; /* normalize result and compute expo */ if (result_fl->long_fract & 0x0000F00000000000ULL) { result_fl->long_fract <<= 8; result_fl->expo = fl->expo + mul_fl->expo - 64; } else { result_fl->long_fract <<= 12; result_fl->expo = fl->expo + mul_fl->expo - 65; } /* determine sign */ result_fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG; /* handle overflow and underflow */ return( over_under_flow_lf(result_fl, regs) ); } else { /* set true 0 */ result_fl->long_fract = 0; result_fl->expo = 0; result_fl->sign = POS; return(0); } } /* end function mul_sf_to_lf */ /*-------------------------------------------------------------------*/ /* Multiply long float to extended float */ /* */ /* Input: */ /* fl Multiplicand long float */ /* mul_fl Multiplicator long float */ /* result_fl Result extended float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int mul_lf_to_ef( LONG_FLOAT *fl, LONG_FLOAT *mul_fl, EXTENDED_FLOAT *result_fl, REGS *regs ) { U64 wk; if (fl->long_fract && mul_fl->long_fract) { /* normalize operands */ normal_lf( fl ); normal_lf( mul_fl ); /* multiply fracts by sum of partial multiplications */ wk = (fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL); result_fl->ls_fract = wk & 0x00000000FFFFFFFFULL; wk >>= 32; wk += ((fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract >> 32)); wk += ((fl->long_fract >> 32) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL)); result_fl->ls_fract |= wk << 32; result_fl->ms_fract = (wk >> 32) + ((fl->long_fract >> 32) * (mul_fl->long_fract >> 32)); /* normalize result and compute expo */ if (result_fl->ms_fract & 0x0000F00000000000ULL) { result_fl->expo = fl->expo + mul_fl->expo - 64; } else { result_fl->ms_fract = (result_fl->ms_fract << 4) | (result_fl->ls_fract >> 60); result_fl->ls_fract <<= 4; result_fl->expo = fl->expo + mul_fl->expo - 65; } /* determine sign */ result_fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG; /* handle overflow and underflow */ return( over_under_flow_ef(result_fl, regs) ); } else { /* set true 0 */ result_fl->ms_fract = 0; result_fl->ls_fract = 0; result_fl->expo = 0; result_fl->sign = POS; return(0); } } /* end function mul_lf_to_ef */ #if defined(FEATURE_HFP_EXTENSIONS) \ || defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT) /*-------------------------------------------------------------------*/ /* Multiply short float */ /* */ /* Input: */ /* fl Multiplicand short float */ /* mul_fl Multiplicator short float */ /* ovunf Handle overflow/underflow if true */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int mul_sf( SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl, BYTE ovunf, REGS *regs ) { U64 wk; if (fl->short_fract && mul_fl->short_fract) { /* normalize operands */ normal_sf( fl ); normal_sf( mul_fl ); /* multiply fracts */ wk = (U64) fl->short_fract * mul_fl->short_fract; /* normalize result and compute expo */ if (wk & 0x0000F00000000000ULL) { fl->short_fract = wk >> 24; fl->expo = fl->expo + mul_fl->expo - 64; } else { fl->short_fract = wk >> 20; fl->expo = fl->expo + mul_fl->expo - 65; } /* determine sign */ fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG; /* handle overflow and underflow if required */ if (ovunf == OVUNF) return( over_under_flow_sf(fl, regs) ); /* otherwise leave exponent as is */ return(0); } else { /* set true 0 */ fl->short_fract = 0; fl->expo = 0; fl->sign = POS; return(0); } } /* end function mul_sf */ #endif /*FEATURE_HFP_EXTENSIONS || FEATURE_HFP_MULTIPLY_ADD_SUBTRACT*/ /*-------------------------------------------------------------------*/ /* Multiply long float */ /* */ /* Input: */ /* fl Multiplicand long float */ /* mul_fl Multiplicator long float */ /* ovunf Handle overflow/underflow if true */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int mul_lf( LONG_FLOAT *fl, LONG_FLOAT *mul_fl, BYTE ovunf, REGS *regs ) { U64 wk; U32 v; if (fl->long_fract && mul_fl->long_fract) { /* normalize operands */ normal_lf( fl ); normal_lf( mul_fl ); /* multiply fracts by sum of partial multiplications */ wk = ((fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL)) >> 32; wk += ((fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract >> 32)); wk += ((fl->long_fract >> 32) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL)); v = wk; fl->long_fract = (wk >> 32) + ((fl->long_fract >> 32) * (mul_fl->long_fract >> 32)); /* normalize result and compute expo */ if (fl->long_fract & 0x0000F00000000000ULL) { fl->long_fract = (fl->long_fract << 8) | (v >> 24); fl->expo = fl->expo + mul_fl->expo - 64; } else { fl->long_fract = (fl->long_fract << 12) | (v >> 20); fl->expo = fl->expo + mul_fl->expo - 65; } /* determine sign */ fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG; /* handle overflow and underflow if required */ if (ovunf == OVUNF) return( over_under_flow_lf(fl, regs) ); /* otherwise leave exponent as is */ return(0); } else { /* set true 0 */ fl->long_fract = 0; fl->expo = 0; fl->sign = POS; return(0); } } /* end function mul_lf */ /*-------------------------------------------------------------------*/ /* Multiply extended float */ /* */ /* Input: */ /* fl Multiplicand extended float */ /* mul_fl Multiplicator extended float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int mul_ef( EXTENDED_FLOAT *fl, EXTENDED_FLOAT *mul_fl, REGS *regs ) { U64 wk1; U64 wk2; U64 wk3; U64 wk4; U64 wk; U32 wk0; U32 v; if ((fl->ms_fract || fl->ls_fract) && (mul_fl->ms_fract || mul_fl->ls_fract)) { /* normalize operands */ normal_ef ( fl ); normal_ef ( mul_fl ); /* multiply fracts by sum of partial multiplications */ wk0 = ((fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL)) >> 32; wk1 = (fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract >> 32); wk2 = (fl->ls_fract >> 32) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL); wk = wk0 + (wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL); wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32); wk1 = (fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL); wk2 = (fl->ls_fract >> 32) * (mul_fl->ls_fract >> 32); wk3 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL); wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL) + (wk3 & 0x00000000FFFFFFFFULL)); wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32) + (wk3 >> 32); wk1 = (fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract >> 32); wk2 = (fl->ls_fract >> 32) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL); wk3 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract >> 32); wk4 = (fl->ms_fract >> 32) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL); wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL) + (wk3 & 0x00000000FFFFFFFFULL) + (wk4 & 0x00000000FFFFFFFFULL)); v = wk; wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32) + (wk3 >> 32) + (wk4 >> 32); wk1 = (fl->ls_fract >> 32) * (mul_fl->ms_fract >> 32); wk2 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL); wk3 = (fl->ms_fract >> 32) * (mul_fl->ls_fract >> 32); wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL) + (wk3 & 0x00000000FFFFFFFFULL)); fl->ls_fract = wk & 0x00000000FFFFFFFFULL; wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32) + (wk3 >> 32); wk1 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract >> 32); wk2 = (fl->ms_fract >> 32) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL); wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL)); fl->ls_fract |= wk << 32; wk0 = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32); wk0 += ((fl->ms_fract >> 32) * (mul_fl->ms_fract >> 32)); fl->ms_fract = wk0; /* normalize result and compute expo */ if (wk0 & 0xF0000000UL) { fl->ms_fract = (fl->ms_fract << 16) | (fl->ls_fract >> 48); fl->ls_fract = (fl->ls_fract << 16) | (v >> 16); fl->expo = fl->expo + mul_fl->expo - 64; } else { fl->ms_fract = (fl->ms_fract << 20) | (fl->ls_fract >> 44); fl->ls_fract = (fl->ls_fract << 20) | (v >> 12); fl->expo = fl->expo + mul_fl->expo - 65; } /* determine sign */ fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG; /* handle overflow and underflow */ return ( over_under_flow_ef (fl, regs) ); } else { /* set true 0 */ fl->ms_fract = 0; fl->ls_fract = 0; fl->expo = 0; fl->sign = POS; return (0); } } /* end function mul_ef */ /*-------------------------------------------------------------------*/ /* Divide short float */ /* */ /* Input: */ /* fl Dividend short float */ /* div_fl Divisor short float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int div_sf( SHORT_FLOAT *fl, SHORT_FLOAT *div_fl, REGS *regs ) { U64 wk; if (div_fl->short_fract) { if (fl->short_fract) { /* normalize operands */ normal_sf( fl ); normal_sf( div_fl ); /* position fracts and compute expo */ if (fl->short_fract < div_fl->short_fract) { wk = (U64) fl->short_fract << 24; fl->expo = fl->expo - div_fl->expo + 64; } else { wk = (U64) fl->short_fract << 20; fl->expo = fl->expo - div_fl->expo + 65; } /* divide fractions */ fl->short_fract = wk / div_fl->short_fract; /* determine sign */ fl->sign = (fl->sign == div_fl->sign) ? POS : NEG; /* handle overflow and underflow */ return( over_under_flow_sf(fl, regs) ); } else { /* fraction of dividend 0, set true 0 */ fl->short_fract = 0; fl->expo = 0; fl->sign = POS; } } else { /* divisor 0 */ ARCH_DEP(program_interrupt) (regs, PGM_FLOATING_POINT_DIVIDE_EXCEPTION); } return(0); } /* end function div_sf */ /*-------------------------------------------------------------------*/ /* Divide long float */ /* */ /* Input: */ /* fl Dividend long float */ /* div_fl Divisor long float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int div_lf( LONG_FLOAT *fl, LONG_FLOAT *div_fl, REGS *regs ) { U64 wk; U64 wk2; int i; if (div_fl->long_fract) { if (fl->long_fract) { /* normalize operands */ normal_lf( fl ); normal_lf( div_fl ); /* position fracts and compute expo */ if (fl->long_fract < div_fl->long_fract) { fl->expo = fl->expo - div_fl->expo + 64; } else { fl->expo = fl->expo - div_fl->expo + 65; div_fl->long_fract <<= 4; } /* partial divide first hex digit */ wk2 = fl->long_fract / div_fl->long_fract; wk = (fl->long_fract % div_fl->long_fract) << 4; /* partial divide middle hex digits */ i = 13; while (i--) { wk2 = (wk2 << 4) | (wk / div_fl->long_fract); wk = (wk % div_fl->long_fract) << 4; } /* partial divide last hex digit */ fl->long_fract = (wk2 << 4) | (wk / div_fl->long_fract); /* determine sign */ fl->sign = (fl->sign == div_fl->sign) ? POS : NEG; /* handle overflow and underflow */ return( over_under_flow_lf(fl, regs) ); } else { /* fraction of dividend 0, set true 0 */ fl->long_fract = 0; fl->expo = 0; fl->sign = POS; } } else { /* divisor 0 */ ARCH_DEP(program_interrupt) (regs, PGM_FLOATING_POINT_DIVIDE_EXCEPTION); } return(0); } /* end function div_lf */ /*-------------------------------------------------------------------*/ /* Divide extended float */ /* */ /* Input: */ /* fl Dividend extended float */ /* div_fl Divisor extended float */ /* regs CPU register context */ /* Value: */ /* exeption */ /*-------------------------------------------------------------------*/ static int div_ef( EXTENDED_FLOAT *fl, EXTENDED_FLOAT *div_fl, REGS *regs ) { U64 wkm; U64 wkl; int i; if (div_fl->ms_fract || div_fl->ls_fract) { if (fl->ms_fract || fl->ls_fract) { /* normalize operands */ normal_ef( fl ); normal_ef( div_fl ); /* position fracts and compute expo */ if ((fl->ms_fract < div_fl->ms_fract) || ((fl->ms_fract == div_fl->ms_fract) && (fl->ls_fract < div_fl->ls_fract))) { fl->expo = fl->expo - div_fl->expo + 64; } else { fl->expo = fl->expo - div_fl->expo + 65; div_fl->ms_fract = (div_fl->ms_fract << 4) | (div_fl->ls_fract >> 60); div_fl->ls_fract <<= 4; } /* divide fractions */ /* the first binary digit */ wkm = fl->ms_fract; wkl = fl->ls_fract; sub_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract); wkm = (wkm << 1) | (wkl >> 63); wkl <<= 1; fl->ms_fract = 0; if (((S64)wkm) >= 0) { fl->ls_fract = 1; sub_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract); } else { fl->ls_fract = 0; add_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract); } /* the middle binary digits */ i = 111; while (i--) { wkm = (wkm << 1) | (wkl >> 63); wkl <<= 1; fl->ms_fract = (fl->ms_fract << 1) | (fl->ls_fract >> 63); fl->ls_fract <<= 1; if (((S64)wkm) >= 0) { fl->ls_fract |= 1; sub_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract); } else { add_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract); } } /* the last binary digit */ fl->ms_fract = (fl->ms_fract << 1) | (fl->ls_fract >> 63); fl->ls_fract <<= 1; if (((S64)wkm) >= 0) { fl->ls_fract |= 1; } /* determine sign */ fl->sign = (fl->sign == div_fl->sign) ? POS : NEG; /* handle overflow and underflow */ return( over_under_flow_ef(fl, regs) ); } else { /* fraction of dividend 0, set true 0 */ fl->ms_fract = 0; fl->ls_fract = 0; fl->expo = 0; fl->sign = POS; } } else { /* divisor 0 */ ARCH_DEP(program_interrupt) (regs, PGM_FLOATING_POINT_DIVIDE_EXCEPTION); } return(0); } /* end function div_ef */ #if defined (FEATURE_SQUARE_ROOT) /*-------------------------------------------------------------------*/ /* Square root of fraction */ /* This routine uses the Newton-Iteration-Method */ /* The iteration is startet with a table look up */ /* */ /* Input: */ /* a short fraction expanded to U64 */ /* Value: */ /* square root as U32 */ /*-------------------------------------------------------------------*/ static U32 square_root_fraction( U64 a ) { U32 xi; U32 xj; static const unsigned short sqtab[] = { /* 0 */ 0, /* 1 */ 304, /* 2 */ 401, /* 3 */ 476, /* 4 */ 541, /* 5 */ 599, /* 6 */ 652, /* 7 */ 700, /* 8 */ 746, /* 9 */ 788, /* 10 */ 829, /* 11 */ 868, /* 12 */ 905, /* 13 */ 940, /* 14 */ 975, /* 15 */ 1008, /* 16 */ 1040, /* 17 */ 1071, /* 18 */ 1101, /* 19 */ 1130, /* 20 */ 1159, /* 21 */ 1187, /* 22 */ 1214, /* 23 */ 1241, /* 24 */ 1267, /* 25 */ 1293, /* 26 */ 1318, /* 27 */ 1342, /* 28 */ 1367, /* 29 */ 1390, /* 30 */ 1414, /* 31 */ 1437, /* 32 */ 1459, /* 33 */ 1482, /* 34 */ 1504, /* 35 */ 1525, /* 36 */ 1547, /* 37 */ 1568, /* 38 */ 1588, /* 39 */ 1609, /* 40 */ 1629, /* 41 */ 1649, /* 42 */ 1669, /* 43 */ 1688, /* 44 */ 1708, /* 45 */ 1727, /* 46 */ 1746, /* 47 */ 1764, /* 48 */ 1783, /* 49 */ 1801, /* 50 */ 1819, /* 51 */ 1837, /* 52 */ 1855, /* 53 */ 1872, /* 54 */ 1890, /* 55 */ 1907, /* 56 */ 1924, /* 57 */ 1941, /* 58 */ 1958, /* 59 */ 1975, /* 60 */ 1991, /* 61 */ 2008, /* 62 */ 2024, /* 63 */ 2040, /* 64 */ 2056, /* 65 */ 2072, /* 66 */ 2088, /* 67 */ 2103, /* 68 */ 2119, /* 69 */ 2134, /* 70 */ 2149, /* 71 */ 2165, /* 72 */ 2180, /* 73 */ 2195, /* 74 */ 2210, /* 75 */ 2224, /* 76 */ 2239, /* 77 */ 2254, /* 78 */ 2268, /* 79 */ 2283, /* 80 */ 2297, /* 81 */ 2311, /* 82 */ 2325, /* 83 */ 2339, /* 84 */ 2353, /* 85 */ 2367, /* 86 */ 2381, /* 87 */ 2395, /* 88 */ 2408, /* 89 */ 2422, /* 90 */ 2435, /* 91 */ 2449, /* 92 */ 2462, /* 93 */ 2475, /* 94 */ 2489, /* 95 */ 2502, /* 96 */ 2515, /* 97 */ 2528, /* 98 */ 2541, /* 99 */ 2554, /* 100 */ 2566, /* 101 */ 2579, /* 102 */ 2592, /* 103 */ 2604, /* 104 */ 2617, /* 105 */ 2629, /* 106 */ 2642, /* 107 */ 2654, /* 108 */ 2667, /* 109 */ 2679, /* 110 */ 2691, /* 111 */ 2703, /* 112 */ 2715, /* 113 */ 2727, /* 114 */ 2739, /* 115 */ 2751, /* 116 */ 2763, /* 117 */ 2775, /* 118 */ 2787, /* 119 */ 2798, /* 120 */ 2810, /* 121 */ 2822, /* 122 */ 2833, /* 123 */ 2845, /* 124 */ 2856, /* 125 */ 2868, /* 126 */ 2879, /* 127 */ 2891, /* 128 */ 2902, /* 129 */ 2913, /* 130 */ 2924, /* 131 */ 2936, /* 132 */ 2947, /* 133 */ 2958, /* 134 */ 2969, /* 135 */ 2980, /* 136 */ 2991, /* 137 */ 3002, /* 138 */ 3013, /* 139 */ 3024, /* 140 */ 3034, /* 141 */ 3045, /* 142 */ 3056, /* 143 */ 3067, /* 144 */ 3077, /* 145 */ 3088, /* 146 */ 3099, /* 147 */ 3109, /* 148 */ 3120, /* 149 */ 3130, /* 150 */ 3141, /* 151 */ 3151, /* 152 */ 3161, /* 153 */ 3172, /* 154 */ 3182, /* 155 */ 3192, /* 156 */ 3203, /* 157 */ 3213, /* 158 */ 3223, /* 159 */ 3233, /* 160 */ 3243, /* 161 */ 3253, /* 162 */ 3263, /* 163 */ 3273, /* 164 */ 3283, /* 165 */ 3293, /* 166 */ 3303, /* 167 */ 3313, /* 168 */ 3323, /* 169 */ 3333, /* 170 */ 3343, /* 171 */ 3353, /* 172 */ 3362, /* 173 */ 3372, /* 174 */ 3382, /* 175 */ 3391, /* 176 */ 3401, /* 177 */ 3411, /* 178 */ 3420, /* 179 */ 3430, /* 180 */ 3439, /* 181 */ 3449, /* 182 */ 3458, /* 183 */ 3468, /* 184 */ 3477, /* 185 */ 3487, /* 186 */ 3496, /* 187 */ 3505, /* 188 */ 3515, /* 189 */ 3524, /* 190 */ 3533, /* 191 */ 3543, /* 192 */ 3552, /* 193 */ 3561, /* 194 */ 3570, /* 195 */ 3579, /* 196 */ 3589, /* 197 */ 3598, /* 198 */ 3607, /* 199 */ 3616, /* 200 */ 3625, /* 201 */ 3634, /* 202 */ 3643, /* 203 */ 3652, /* 204 */ 3661, /* 205 */ 3670, /* 206 */ 3679, /* 207 */ 3688, /* 208 */ 3697, /* 209 */ 3705, /* 210 */ 3714, /* 211 */ 3723, /* 212 */ 3732, /* 213 */ 3741, /* 214 */ 3749, /* 215 */ 3758, /* 216 */ 3767, /* 217 */ 3775, /* 218 */ 3784, /* 219 */ 3793, /* 220 */ 3801, /* 221 */ 3810, /* 222 */ 3819, /* 223 */ 3827, /* 224 */ 3836, /* 225 */ 3844, /* 226 */ 3853, /* 227 */ 3861, /* 228 */ 3870, /* 229 */ 3878, /* 230 */ 3887, /* 231 */ 3895, /* 232 */ 3903, /* 233 */ 3912, /* 234 */ 3920, /* 235 */ 3929, /* 236 */ 3937, /* 237 */ 3945, /* 238 */ 3954, /* 239 */ 3962, /* 240 */ 3970, /* 241 */ 3978, /* 242 */ 3987, /* 243 */ 3995, /* 244 */ 4003, /* 245 */ 4011, /* 246 */ 4019, /* 247 */ 4027, /* 248 */ 4036, /* 249 */ 4044, /* 250 */ 4052, /* 251 */ 4060, /* 252 */ 4068, /* 253 */ 4076, /* 254 */ 4084, /* 255 */ 4092 }; /* initial table look up */ xi = ((U32) sqtab[a >> 48]) << 16; if (xi == 0) return(xi); /* iterate */ /* exit iteration when xi, xj equal or differ by 1 */ for (;;) { xj = (((U32)(a / xi)) + xi) >> 1; if ((xj == xi) || (abs(xj - xi) == 1)) { break; } xi = xj; } return(xj); } /* end function square_root_fraction */ /*-------------------------------------------------------------------*/ /* Divide 128 bit integer by 64 bit integer */ /* The result is returned as 64 bit integer */ /* */ /* Input: */ /* msa most significant 64 bit of dividend */ /* lsa least significant 64 bit of dividend */ /* div divisor */ /* Value: */ /* quotient */ /*-------------------------------------------------------------------*/ static U64 div_U128( U64 msa, U64 lsa, U64 div ) { U64 q; int i; /* the first binary digit */ msa -= div; shift_left_U128(msa, lsa); if (((S64)msa) >= 0) { q = 1; msa -= div; } else { q = 0; msa += div; } /* the middle binary digits */ i = 63; while (i--) { shift_left_U128(msa, lsa); q <<= 1; if (((S64)msa) >= 0) { q |= 1; msa -= div; } else { msa += div; } } /* the last binary digit */ q <<= 1; if (((S64)msa) >= 0) { q |= 1; } return(q); } /* end function div_U128 */ /*-------------------------------------------------------------------*/ /* Square root short float */ /* */ /* Input: */ /* sq_fl Result short float */ /* fl Input short float */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static void sq_sf( SHORT_FLOAT *sq_fl, SHORT_FLOAT *fl, REGS *regs ) { U64 a; U32 x; if (fl->short_fract) { if (fl->sign) { /* less than zero */ sq_fl->short_fract = 0; sq_fl->expo = 0; ARCH_DEP(program_interrupt) (regs, PGM_SQUARE_ROOT_EXCEPTION); } else { /* normalize operand */ normal_sf(fl); if (fl->expo & 1) { /* odd */ /* compute characteristic */ sq_fl->expo = (fl->expo + 65) >> 1; /* with guard digit */ a = (U64) fl->short_fract << 28; } else { /* even */ /* compute characteristic */ sq_fl->expo = (fl->expo + 64) >> 1; /* without guard digit */ a = (U64) fl->short_fract << 32; } /* square root of fraction */ /* common subroutine of all square root */ x = square_root_fraction(a); /* round with guard digit */ sq_fl->short_fract = (x + 8) >> 4; } } else { /* true zero */ sq_fl->short_fract = 0; sq_fl->expo = 0; } /* all results positive */ sq_fl->sign = POS; } /* end function sq_sf */ /*-------------------------------------------------------------------*/ /* Square root long float */ /* */ /* Input: */ /* sq_fl Result long float */ /* fl Input long float */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static void sq_lf( LONG_FLOAT *sq_fl, LONG_FLOAT *fl, REGS *regs ) { U64 msa, lsa; U64 xi; U64 xj; if (fl->long_fract) { if (fl->sign) { /* less than zero */ ARCH_DEP(program_interrupt) (regs, PGM_SQUARE_ROOT_EXCEPTION); } else { /* normalize operand */ normal_lf(fl); if (fl->expo & 1) { /* odd */ /* compute characteristic */ sq_fl->expo = (fl->expo + 65) >> 1; /* with guard digit */ msa = fl->long_fract >> 4; lsa = fl->long_fract << 60; } else { /* even */ /* compute characteristic */ sq_fl->expo = (fl->expo + 64) >> 1; /* without guard digit */ msa = fl->long_fract; lsa = 0; } /* square root of fraction low precision */ /* common subroutine of all square root */ xi = ((U64) (square_root_fraction(msa & 0xFFFFFFFFFFFFFFFEULL)) << 32) | 0x80000000UL; /* continue iteration for high precision */ for (;;) { xj = (div_U128(msa, lsa, xi) + xi) >> 1; if (xj == xi) { break; } xi = xj; } /* round with guard digit */ sq_fl->long_fract = (xi + 8) >> 4; } } else { /* true zero */ sq_fl->long_fract = 0; sq_fl->expo = 0; } /* all results positive */ sq_fl->sign = POS; } /* end function sq_lf */ #endif /* FEATURE_SQUARE_ROOT */ #if defined (FEATURE_HFP_EXTENSIONS) /*-------------------------------------------------------------------*/ /* Divide 256 bit integer by 128 bit integer */ /* The result is returned as 128 bit integer */ /* */ /* Input: */ /* mmsa most significant 64 bit of dividend */ /* msa more significant 64 bit of dividend */ /* lsa less significant 64 bit of dividend */ /* llsa least significant 64 bit of dividend */ /* msd most significant 64 bit of divisor */ /* lsd least significant 64 bit of divisor */ /* msq most significant 64 bit of quotient */ /* lsq least significant 64 bit of quotient */ /*-------------------------------------------------------------------*/ static void div_U256( U64 mmsa, U64 msa, U64 lsa, U64 llsa, U64 msd, U64 lsd, U64 *msq, U64 *lsq ) { int i; /* the first binary digit */ sub_U128(mmsa, msa, msd, lsd); shift_left_U256(mmsa, msa, lsa, llsa); *msq = 0; if (((S64)mmsa) >= 0) { *lsq = 1; sub_U128(mmsa, msa, msd, lsd); } else { *lsq = 0; add_U128(mmsa, msa, msd, lsd); } /* the middle binary digits */ i = 127; while (i--) { shift_left_U256(mmsa, msa, lsa, llsa); shift_left_U128(*msq, *lsq); if (((S64)mmsa) >= 0) { *lsq |= 1; sub_U128(mmsa, msa, msd, lsd); } else { add_U128(mmsa, msa, msd, lsd); } } /* the last binary digit */ shift_left_U128(*msq, *lsq); if (((S64)mmsa) >= 0) { *lsq |= 1; } } /* end function div_U256 */ #endif /* FEATURE_HFP_EXTENSIONS */ #if defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) /*-------------------------------------------------------------------*/ /* Multiply long float to extended float unnormalized */ /* */ /* Input: */ /* fl Multiplicand long float */ /* mul_fl Multiplicator long float */ /* result_fl Intermediate extended float result */ /* regs CPU register context */ /* Value: */ /* none */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(mul_lf_to_ef_unnorm)( LONG_FLOAT *fl, LONG_FLOAT *mul_fl, EXTENDED_FLOAT *result_fl ) { U64 wk; /* multiply fracts by sum of partial multiplications */ wk = (fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL); result_fl->ls_fract = wk & 0x00000000FFFFFFFFULL; wk >>= 32; wk += ((fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract >> 32)); wk += ((fl->long_fract >> 32) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL)); result_fl->ls_fract |= wk << 32; result_fl->ms_fract = (wk >> 32) + ((fl->long_fract >> 32) * (mul_fl->long_fract >> 32)); /* compute expo */ result_fl->expo = fl->expo + mul_fl->expo - 64; /* determine sign */ result_fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG; } /* end function mul_lf_to_ef_unnorm */ /*-------------------------------------------------------------------*/ /* Add extended float unnormalized */ /* Note: This addition is specific to MULTIPLY AND ADD UNNORMALIZED */ /* set of instructions */ /* */ /* Input: */ /* prod_fl Extended Intermediate product */ /* add_fl Extended Addend */ /* result_fl Extended Intermediate result */ /* Value: */ /* none */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(add_ef_unnorm)( EXTENDED_FLOAT *prod_fl, EXTENDED_FLOAT *add_fl, EXTENDED_FLOAT *result_fl ) { int ldigits = 0; /* or'd left digits shifted */ int rdigits = 0; /* or'd right digits shifted */ int xdigit; /* digit lost by addend shifting */ /* Note: In EXTENDED_FLOAT, ms_fract and ls_fract taken together*/ /* constitute a U128 value. */ /* Convert separate high/low fractions to contiguous U128 */ #if FLOAT_DEBUG logmsg (_("Prod Frac: %16.16llX %16.16llX\n"), prod_fl->ms_fract, prod_fl->ls_fract); logmsg (_("Adnd Frac: %16.16llX %16.16llX\n"), add_fl->ms_fract, add_fl->ls_fract); #endif result_fl->ms_fract = 0; result_fl->ls_fract = 0; /* Default result to product sign in case addend expo == prod expo */ result_fl->sign = prod_fl->sign; /* Step one - shift addend to match product's characteristic */ if (add_fl->expo < prod_fl->expo) { while(add_fl->expo != prod_fl->expo) { if ((!add_fl->ms_fract) && (!add_fl->ls_fract)) { /* If both the high and low parts of the fraction are zero */ /* we don't need to shift any more digits. */ /* Just force the exponents equal and quit */ add_fl->expo = prod_fl->expo; break; } /* shift addend fraction right until characteristics are equal */ shift_right4_U128(add_fl->ms_fract, add_fl->ls_fract, xdigit); rdigits |= xdigit; add_fl->expo += 1; } } else if(add_fl->expo > prod_fl->expo) { while(add_fl->expo != prod_fl->expo) { if ((!add_fl->ms_fract) && (!add_fl->ls_fract)) { /* If both the high and low parts of the fraction are zero */ /* we don't need to shift any more digits. */ /* Just force the exponents equal and quit */ add_fl->expo = prod_fl->expo; break; } /* shift addend fraction right until characteristics are equal */ shift_left4_U128(add_fl->ms_fract, add_fl->ls_fract, xdigit); ldigits |= xdigit; add_fl->expo -= 1; } } #if FLOAT_DEBUG logmsg (_("Shft Frac: %16.16llX %16.16llX\n"), add_fl->ms_fract, add_fl->ls_fract); #endif /* Step 2 - Do algebraic addition of aligned fractions */ if (add_fl->sign == prod_fl->sign) { /* signs equal, so just add fractions */ result_fl->sign = prod_fl->sign; result_fl->ms_fract = prod_fl->ms_fract; result_fl->ls_fract = prod_fl->ls_fract; add_U128(result_fl->ms_fract, result_fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract); /* Recognize any overflow of left hand digits */ ldigits |= result_fl->ms_fract >> 48; /* Remove them from the result */ result_fl->ms_fract &= 0x0000FFFFFFFFFFFFULL; /* result sign already set to product sign */ } else { /* signs unequal, subtract the larger fraction from the smaller */ /* result has sign of the larger fraction */ if ( (prod_fl->ms_fract > add_fl->ms_fract) || ((prod_fl->ms_fract == add_fl->ms_fract) && (prod_fl->ls_fract >= add_fl->ls_fract)) ) /* product fraction larger than or equal to addend fraction */ { /* subtract addend fraction from product fraction */ /* result has sign of product */ result_fl->ms_fract = prod_fl->ms_fract; result_fl->ls_fract = prod_fl->ls_fract; if (rdigits) { /* If any right shifted addend digits, then we need to */ /* borrow from the product fraction to reflect the shifted*/ /* digits participation in the result */ sub_U128(result_fl->ms_fract, result_fl->ls_fract, (U64)0, (U64)1); #if FLOAT_DEBUG logmsg (_("Barw Frac: %16.16llX %16.16llX\n"), result_fl->ms_fract, result_fl->ls_fract); #endif /* Due to participation of right shifted digits */ /* result fraction NOT zero, so true zero will not result */ /* hence, force sign will not to change */ ldigits = 1; } sub_U128(result_fl->ms_fract, result_fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract); #if FLOAT_DEBUG logmsg (_("P-A Frac: %16.16llX %16.16llX\n"), result_fl->ms_fract, result_fl->ls_fract); #endif /* result sign already set to product sign above as default */ } else /* addend fraction larger than product fraction */ { /* subtract product fraction from addend fraction */ /* result has sign of addend */ result_fl->ms_fract = add_fl->ms_fract; result_fl->ls_fract = add_fl->ls_fract; sub_U128(result_fl->ms_fract, result_fl->ls_fract, prod_fl->ms_fract, prod_fl->ls_fract); #if FLOAT_DEBUG logmsg (_("A-P Frac: %16.16llX %16.16llX\n"), result_fl->ms_fract, result_fl->ls_fract); #endif result_fl->sign = add_fl->sign; } } #if FLOAT_DEBUG logmsg (_("Resl Frac: %16.16llX %16.16llX\n"), result_fl->ms_fract, result_fl->ls_fract); #endif /* result exponent always the same as the product */ result_fl->expo = prod_fl->expo; /* Step 3 - If fraction is TRULY zero, sign is set to positive */ if ( (!result_fl->ms_fract) && (!result_fl->ls_fract) && (!ldigits) && (!rdigits) ) { result_fl->sign = POS; } } /* end ARCH_DEP(add_ef_unnorm) */ #endif /* defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) */ /*-------------------------------------------------------------------*/ /* Extern functions */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* 20 LPDR - Load Positive Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, clear the sign bit */ regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Set condition code */ regs->psw.cc = ((regs->fpr[i1] & 0x00FFFFFF) || regs->fpr[i1+1]) ? 2 : 0; } /* end DEF_INST(load_positive_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 21 LNDR - Load Negative Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, set the sign bit */ regs->fpr[i1] = regs->fpr[i2] | 0x80000000; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Set condition code */ regs->psw.cc = ((regs->fpr[i1] & 0x00FFFFFF) || regs->fpr[i1+1]) ? 1 : 0; } /* end DEF_INST(load_negative_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 22 LTDR - Load and Test Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents */ regs->fpr[i1] = regs->fpr[i2]; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Set condition code */ if ((regs->fpr[i1] & 0x00FFFFFF) || regs->fpr[i1+1]) { regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2; } else { regs->psw.cc = 0; } } /* end DEF_INST(load_and_test_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 23 LCDR - Load Complement Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, invert sign bit */ regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Set condition code */ if ((regs->fpr[i1] & 0x00FFFFFF) || regs->fpr[i1+1]) { regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2; } else { regs->psw.cc = 0; } } /* end DEF_INST(load_complement_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 24 HDR - Halve Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(halve_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_lf(&fl, regs->fpr + i2); /* Halve the value */ if (fl.long_fract & 0x00E0000000000000ULL) { fl.long_fract >>= 1; pgm_check = 0; } else { fl.long_fract <<= 3; (fl.expo)--; normal_lf(&fl); pgm_check = underflow_lf(&fl, regs); } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(halve_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 25 LDXR - Load Rounded Floating Point Long Register [RR] */ /* Older mnemonic of this instruction is LRDR */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); HFPODD_CHECK(r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_lf(&fl, regs->fpr + i2); /* Rounding */ fl.long_fract += ((regs->fpr[FPR2I(r2 + 2)] >> 23) & 1); /* Handle overflow */ if (fl.long_fract & 0x0F00000000000000ULL) { fl.long_fract >>= 4; (fl.expo)++; pgm_check = overflow_lf(&fl, regs); } else { pgm_check = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(load_rounded_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 26 MXR - Multiply Floating Point Extended Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT fl; EXTENDED_FLOAT mul_fl; int pgm_check; RR(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_ef(&fl, regs->fpr + i1); get_ef(&mul_fl, regs->fpr + i2); /* multiply extended */ pgm_check = mul_ef(&fl, &mul_fl, regs); /* Back to register */ store_ef(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* 27 MXDR - Multiply Floating Point Long to Extended Reg. [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_long_to_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT mul_fl; EXTENDED_FLOAT result_fl; int pgm_check; RR(inst, regs, r1, r2); HFPODD_CHECK(r1, regs); HFPREG_CHECK(r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&mul_fl, regs->fpr + i2); /* multiply long to extended */ pgm_check = mul_lf_to_ef(&fl, &mul_fl, &result_fl, regs); /* Back to register */ store_ef(&result_fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_long_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* 28 LDR - Load Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents */ regs->fpr[i1] = regs->fpr[i2]; regs->fpr[i1+1] = regs->fpr[i2+1]; } /* end DEF_INST(load_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 29 CDR - Compare Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT cmp_fl; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&cmp_fl, regs->fpr + i2); /* Compare long */ cmp_lf(&fl, &cmp_fl, regs); } /* end DEF_INST(compare_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 2A ADR - Add Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT add_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&add_fl, regs->fpr + i2); /* Add long with normalization */ pgm_check = add_lf(&fl, &add_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 2B SDR - Subtract Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT sub_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&sub_fl, regs->fpr + i2); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add long with normalization */ pgm_check = add_lf(&fl, &sub_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 2C MDR - Multiply Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT mul_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&mul_fl, regs->fpr + i2); /* multiply long */ pgm_check = mul_lf(&fl, &mul_fl, OVUNF, regs); /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 2D DDR - Divide Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT div_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&div_fl, regs->fpr + i2); /* divide long */ pgm_check = div_lf(&fl, &div_fl, regs); /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(divide_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 2E AWR - Add Unnormalized Floating Point Long Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_unnormal_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT add_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&add_fl, regs->fpr + i2); /* Add long without normalization */ pgm_check = add_lf(&fl, &add_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_unnormal_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 2F SWR - Subtract Unnormalized Floating Point Long Reg. [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_unnormal_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; LONG_FLOAT sub_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_lf(&fl, regs->fpr + i1); get_lf(&sub_fl, regs->fpr + i2); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add long without normalization */ pgm_check = add_lf(&fl, &sub_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_unnormal_float_long_reg) */ /*-------------------------------------------------------------------*/ /* 30 LPER - Load Positive Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, clear sign bit */ regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF; /* Set condition code */ regs->psw.cc = (regs->fpr[i1] & 0x00FFFFFF) ? 2 : 0; } /* end DEF_INST(load_positive_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 31 LNER - Load Negative Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, set sign bit */ regs->fpr[i1] = regs->fpr[i2] | 0x80000000; /* Set condition code */ regs->psw.cc = (regs->fpr[i1] & 0x00FFFFFF) ? 1 : 0; } /* end DEF_INST(load_negative_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 32 LTER - Load and Test Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents */ regs->fpr[i1] = regs->fpr[i2]; /* Set condition code */ if (regs->fpr[i1] & 0x00FFFFFF) { regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2; } else { regs->psw.cc = 0; } } /* end DEF_INST(load_and_test_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 33 LCER - Load Complement Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, invert sign bit */ regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000; /* Set condition code */ if (regs->fpr[i1] & 0x00FFFFFF) { regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2; } else { regs->psw.cc = 0; } } /* end DEF_INST(load_complement_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 34 HER - Halve Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(halve_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_sf(&fl, regs->fpr + i2); /* Halve the value */ if (fl.short_fract & 0x00E00000) { fl.short_fract >>= 1; pgm_check = 0; } else { fl.short_fract <<= 3; (fl.expo)--; normal_sf(&fl); pgm_check = underflow_sf(&fl, regs); } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(halve_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 35 LEDR - Load Rounded Floating Point Short Register [RR] */ /* Older mnemonic of this instruction is LRER */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT from_fl; SHORT_FLOAT to_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_lf(&from_fl, regs->fpr + i2); /* Rounding */ to_fl.short_fract = (from_fl.long_fract + 0x0000000080000000ULL) >> 32; to_fl.sign = from_fl.sign; to_fl.expo = from_fl.expo; /* Handle overflow */ if (to_fl.short_fract & 0x0F000000) { to_fl.short_fract >>= 4; (to_fl.expo)++; pgm_check = overflow_sf(&to_fl, regs); } else { pgm_check = 0; } /* To register */ store_sf(&to_fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(load_rounded_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 36 AXR - Add Floating Point Extended Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT fl; EXTENDED_FLOAT add_fl; int pgm_check; RR(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_ef(&fl, regs->fpr + i1); get_ef(&add_fl, regs->fpr + i2); /* Add extended */ pgm_check = add_ef(&fl, &add_fl, regs->fpr + i1, regs); /* Set condition code */ if (fl.ms_fract || fl.ls_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* 37 SXR - Subtract Floating Point Extended Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT fl; EXTENDED_FLOAT sub_fl; int pgm_check; RR(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_ef(&fl, regs->fpr + i1); get_ef(&sub_fl, regs->fpr + i2); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add extended */ pgm_check = add_ef(&fl, &sub_fl, regs->fpr + i1, regs); /* Set condition code */ if (fl.ms_fract || fl.ls_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* 38 LER - Load Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(load_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register content */ regs->fpr[i1] = regs->fpr[i2]; } /* end DEF_INST(load_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 39 CER - Compare Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT cmp_fl; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&cmp_fl, regs->fpr + i2); /* Compare short */ cmp_sf(&fl, &cmp_fl, regs); } /* end DEF_INST(compare_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 3A AER - Add Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT add_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&add_fl, regs->fpr + i2); /* Add short with normalization */ pgm_check = add_sf(&fl, &add_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 3B SER - Subtract Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT sub_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&sub_fl, regs->fpr + i2); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Subtract short with normalization */ pgm_check = add_sf(&fl, &sub_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 3C MDER - Multiply Short to Long Floating Point Register [RR] */ /* Older mnemonic of this instruction is MER */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_short_to_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT mul_fl; LONG_FLOAT result_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&mul_fl, regs->fpr + i2); /* multiply short to long */ pgm_check = mul_sf_to_lf(&fl, &mul_fl, &result_fl, regs); /* Back to register */ store_lf(&result_fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_short_to_long_reg) */ /*-------------------------------------------------------------------*/ /* 3D DER - Divide Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT div_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&div_fl, regs->fpr + i2); /* divide short */ pgm_check = div_sf(&fl, &div_fl, regs); /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(divide_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 3E AUR - Add Unnormalized Floating Point Short Register [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_unnormal_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT add_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&add_fl, regs->fpr + i2); /* Add short without normalization */ pgm_check = add_sf(&fl, &add_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_unnormal_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 3F SUR - Subtract Unnormalized Floating Point Short Reg. [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_unnormal_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT sub_fl; int pgm_check; RR(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&sub_fl, regs->fpr + i2); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add short without normalization */ pgm_check = add_sf(&fl, &sub_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_unnormal_float_short_reg) */ /*-------------------------------------------------------------------*/ /* 60 STD - Store Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(store_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word workarea */ RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Store register contents at operand address */ dreg = ((U64)regs->fpr[i1] << 32) | regs->fpr[i1+1]; ARCH_DEP(vstore8) (dreg, effective_addr2, b2, regs); } /* end DEF_INST(store_float_long) */ /*-------------------------------------------------------------------*/ /* 67 MXD - Multiply Floating Point Long to Extended [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_long_to_ext) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT mul_fl; EXTENDED_FLOAT result_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPODD_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&mul_fl, effective_addr2, b2, regs ); /* multiply long to extended */ pgm_check = mul_lf_to_ef(&fl, &mul_fl, &result_fl, regs); /* Back to register */ store_ef(&result_fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_long_to_ext) */ /*-------------------------------------------------------------------*/ /* 68 LD - Load Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word workarea */ RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Fetch value from operand address */ dreg = ARCH_DEP(vfetch8) (effective_addr2, b2, regs); /* Update register contents */ regs->fpr[i1] = dreg >> 32; regs->fpr[i1+1] = dreg; } /* end DEF_INST(load_float_long) */ /*-------------------------------------------------------------------*/ /* 69 CD - Compare Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT cmp_fl; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&cmp_fl, effective_addr2, b2, regs ); /* Compare long */ cmp_lf(&fl, &cmp_fl, regs); } /* end DEF_INST(compare_float_long) */ /*-------------------------------------------------------------------*/ /* 6A AD - Add Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(add_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT add_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&add_fl, effective_addr2, b2, regs ); /* Add long with normalization */ pgm_check = add_lf(&fl, &add_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_float_long) */ /*-------------------------------------------------------------------*/ /* 6B SD - Subtract Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT sub_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&sub_fl, effective_addr2, b2, regs ); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add long with normalization */ pgm_check = add_lf(&fl, &sub_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_float_long) */ /*-------------------------------------------------------------------*/ /* 6C MD - Multiply Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT mul_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&mul_fl, effective_addr2, b2, regs ); /* multiply long */ pgm_check = mul_lf(&fl, &mul_fl, OVUNF, regs); /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_long) */ /*-------------------------------------------------------------------*/ /* 6D DD - Divide Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT div_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&div_fl, effective_addr2, b2, regs ); /* divide long */ pgm_check = div_lf(&fl, &div_fl, regs); /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(divide_float_long) */ /*-------------------------------------------------------------------*/ /* 6E AW - Add Unnormalized Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(add_unnormal_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT add_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&add_fl, effective_addr2, b2, regs ); /* Add long without normalization */ pgm_check = add_lf(&fl, &add_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_unnormal_float_long) */ /*-------------------------------------------------------------------*/ /* 6F SW - Subtract Unnormalized Floating Point Long [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_unnormal_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl; LONG_FLOAT sub_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_lf(&fl, regs->fpr + i1); vfetch_lf(&sub_fl, effective_addr2, b2, regs ); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add long without normalization */ pgm_check = add_lf(&fl, &sub_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.long_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_lf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_unnormal_float_long) */ /*-------------------------------------------------------------------*/ /* 70 STE - Store Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(store_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Store register contents at operand address */ ARCH_DEP(vstore4) (regs->fpr[i1], effective_addr2, b2, regs); } /* end DEF_INST(store_float_short) */ /*-------------------------------------------------------------------*/ /* 78 LE - Load Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(load_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Update first 32 bits of register from operand address */ regs->fpr[i1] = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); } /* end DEF_INST(load_float_short) */ /*-------------------------------------------------------------------*/ /* 79 CE - Compare Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT cmp_fl; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&cmp_fl, effective_addr2, b2, regs ); /* Compare long */ cmp_sf(&fl, &cmp_fl, regs); } /* end DEF_INST(compare_float_short) */ /*-------------------------------------------------------------------*/ /* 7A AE - Add Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(add_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT add_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&add_fl, effective_addr2, b2, regs ); /* Add short with normalization */ pgm_check = add_sf(&fl, &add_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_float_short) */ /*-------------------------------------------------------------------*/ /* 7B SE - Subtract Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT sub_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&sub_fl, effective_addr2, b2, regs ); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add short with normalization */ pgm_check = add_sf(&fl, &sub_fl, NORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_float_short) */ /*-------------------------------------------------------------------*/ /* 7C MDE - Multiply Floating Point Short to Long [RX] */ /* Older mnemonic of this instruction is ME */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_short_to_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT mul_fl; LONG_FLOAT result_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&mul_fl, effective_addr2, b2, regs ); /* multiply short to long */ pgm_check = mul_sf_to_lf(&fl, &mul_fl, &result_fl, regs); /* Back to register */ store_lf(&result_fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_short_to_long) */ /*-------------------------------------------------------------------*/ /* 7D DE - Divide Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT div_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&div_fl, effective_addr2, b2, regs ); /* divide short */ pgm_check = div_sf(&fl, &div_fl, regs); /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(divide_float_short) */ /*-------------------------------------------------------------------*/ /* 7E AU - Add Unnormalized Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(add_unnormal_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT add_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&add_fl, effective_addr2, b2, regs ); /* Add short without normalization */ pgm_check = add_sf(&fl, &add_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(add_unnormal_float_short) */ /*-------------------------------------------------------------------*/ /* 7F SU - Subtract Unnormalized Floating Point Short [RX] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_unnormal_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT sub_fl; int pgm_check; RX(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&sub_fl, effective_addr2, b2, regs ); /* Invert the sign of 2nd operand */ sub_fl.sign = ! (sub_fl.sign); /* Add short without normalization */ pgm_check = add_sf(&fl, &sub_fl, UNNORMAL, SIGEX, regs); /* Set condition code */ if (fl.short_fract) { regs->psw.cc = fl.sign ? 1 : 2; } else { regs->psw.cc = 0; } /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(subtract_unnormal_float_short) */ /*-------------------------------------------------------------------*/ /* B22D DXR - Divide Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT fl; EXTENDED_FLOAT div_fl; int pgm_check; RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_ef(&fl, regs->fpr + i1); get_ef(&div_fl, regs->fpr + i2); /* divide extended */ pgm_check = div_ef(&fl, &div_fl, regs); /* Back to register */ store_ef(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(divide_float_ext_reg) */ #if defined (FEATURE_SQUARE_ROOT) /*-------------------------------------------------------------------*/ /* B244 SQDR - Square Root Floating Point Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT sq_fl; LONG_FLOAT fl; RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the 2nd operand */ get_lf(&fl, regs->fpr + i2); /* square root long */ sq_lf(&sq_fl, &fl, regs); /* Back to register */ store_lf(&sq_fl, regs->fpr + i1); } /* end DEF_INST(squareroot_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B245 SQER - Square Root Floating Point Short Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT sq_fl; SHORT_FLOAT fl; RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the 2nd operand */ get_sf(&fl, regs->fpr + i2); /* square root short */ sq_sf(&sq_fl, &fl, regs); /* Back to register */ store_sf(&sq_fl, regs->fpr + i1); } /* end DEF_INST(squareroot_float_short_reg) */ #endif /* FEATURE_SQUARE_ROOT */ #if defined (FEATURE_HFP_EXTENSIONS) /*-------------------------------------------------------------------*/ /* B324 LDER - Load Length. Float. Short to Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_float_short_to_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register content */ regs->fpr[i1] = regs->fpr[i2]; /* Clear register */ regs->fpr[i1+1] = 0; } /* end DEF_INST(load_lengthened_float_short_to_long_reg) */ /*-------------------------------------------------------------------*/ /* B325 LXDR - Load Length. Float. Long to Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_float_long_to_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPODD_CHECK(r1, regs); HFPREG_CHECK(r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); if ((regs->fpr[i2] & 0x00FFFFFF) || regs->fpr[i2+1]) { /* Copy register contents */ regs->fpr[i1] = regs->fpr[i2]; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Low order register */ regs->fpr[i1+FPREX] = (regs->fpr[i2] & 0x80000000) | ((regs->fpr[i2] - (14 << 24)) & 0x7F000000); } else { /* true zero with sign */ regs->fpr[i1] = regs->fpr[i2] & 0x80000000; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX] = regs->fpr[i1]; } /* Clear register */ regs->fpr[i1+FPREX+1] = 0; } /* end DEF_INST(load_lengthened_float_long_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* B326 LXER - Load Length. Float. Short to Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_float_short_to_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPODD_CHECK(r1, regs); HFPREG_CHECK(r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); if (regs->fpr[i2] & 0x00FFFFFF) { /* Copy register content */ regs->fpr[i1] = regs->fpr[i2]; /* Low order register */ regs->fpr[i1+FPREX] = (regs->fpr[i2] & 0x80000000) | ((regs->fpr[i2] - (14 << 24)) & 0x7F000000); } else { /* true zero with sign */ regs->fpr[i1] = regs->fpr[i2] & 0x80000000; regs->fpr[i1+FPREX] = regs->fpr[i1]; } /* Clear register */ regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX+1] = 0; } /* end DEF_INST(load_lengthened_float_short_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* B336 SQXR - Square Root Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT sq_fl; EXTENDED_FLOAT fl; U64 mmsa, msa, lsa, llsa; U64 xi; U64 xj; U64 msi, lsi; U64 msj, lsj; RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the 2nd operand */ get_ef(&fl, regs->fpr + i2); if ((fl.ms_fract) || (fl.ls_fract)) { if (fl.sign) { /* less than zero */ ARCH_DEP(program_interrupt) (regs, PGM_SQUARE_ROOT_EXCEPTION); return; /* Never reached */ } else { /* normalize operand */ normal_ef(&fl); if (fl.expo & 1) { /* odd */ /* compute characteristic */ sq_fl.expo = (fl.expo + 65) >> 1; /* with guard digit */ mmsa = fl.ms_fract >> 4; msa = (fl.ms_fract << 60) | (fl.ls_fract >> 4); lsa = fl.ls_fract << 60; llsa = 0; } else { /* even */ /* compute characteristic */ sq_fl.expo = (fl.expo + 64) >> 1; /* without guard digit */ mmsa = fl.ms_fract; msa = fl.ls_fract; lsa = 0; llsa = 0; } /* square root of fraction low precision */ /* common subroutine of all square root */ xi = ((U64) (square_root_fraction(mmsa & 0xFFFFFFFFFFFFFFFEULL)) << 32) | 0x80000000UL; /* continue iteration for high precision */ /* done iteration when xi, xj equal or differ by 1 */ for (;;) { xj = (div_U128(mmsa, msa, xi) + xi) >> 1; if ((xj == xi) || (abs(xj - xi) == 1)) { break; } xi = xj; } msi = xi; lsi = 0x8000000000000000ULL; /* continue iteration for extended precision */ for (;;) { div_U256(mmsa, msa, lsa, llsa, msi, lsi, &msj, &lsj); add_U128(msj, lsj, msi, lsi); shift_right_U128(msj, lsj); if ((msj == msi) && (lsj == lsi)) { break; } msi = msj; lsi = lsj; } /* round with guard digit */ add_U128(msi, lsi, 0, 0x80); sq_fl.ls_fract = (lsi >> 8) | (msi << 56); sq_fl.ms_fract = msi >> 8; } } else { /* true zero */ sq_fl.ms_fract = 0; sq_fl.ls_fract = 0; sq_fl.expo = 0; } /* all results positive */ sq_fl.sign = POS; /* Back to register */ store_ef(&sq_fl, regs->fpr + i1); } /* end DEF_INST(squareroot_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B337 MEER - Multiply Floating Point Short Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; SHORT_FLOAT mul_fl; int pgm_check; RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_sf(&fl, regs->fpr + i1); get_sf(&mul_fl, regs->fpr + i2); /* multiply short to long */ pgm_check = mul_sf(&fl, &mul_fl, OVUNF, regs); /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_short_reg) */ /*-------------------------------------------------------------------*/ /* B360 LPXR - Load Positive Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); if ((regs->fpr[i2] & 0x00FFFFFF) || regs->fpr[i2+1] || (regs->fpr[i2+FPREX] & 0x00FFFFFF) || regs->fpr[i2+FPREX+1]) { /* Copy register contents, clear the sign bit */ regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Low order register */ regs->fpr[i1+FPREX] = (((regs->fpr[i2] - (14 << 24)) & 0x7F000000)) | (regs->fpr[i2+FPREX] & 0x00FFFFFF); regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1]; /* Set condition code */ regs->psw.cc = 2; } else { /* true zero */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX] = 0; regs->fpr[i1+FPREX+1] = 0; /* Set condition code */ regs->psw.cc = 0; } } /* end DEF_INST(load_positive_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B361 LNXR - Load Negative Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); if ((regs->fpr[i2] & 0x00FFFFFF) || regs->fpr[i2+1] || (regs->fpr[i2+FPREX] & 0x00FFFFFF) || regs->fpr[i2+FPREX+1]) { /* Copy register contents, set the sign bit */ regs->fpr[i1] = 0x80000000 | regs->fpr[i2]; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Low order register */ regs->fpr[i1+FPREX] = 0x80000000 | (((regs->fpr[i2] - (14 << 24)) & 0x7F000000)) | (regs->fpr[i2+FPREX] & 0x00FFFFFF); regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1]; /* Set condition code */ regs->psw.cc = 1; } else { /* true zero with sign */ regs->fpr[i1] = 0x80000000; regs->fpr[i1+FPREX] = 0x80000000; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX+1] = 0; /* Set condition code */ regs->psw.cc = 0; } } /* end DEF_INST(load_negative_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B362 LTXR - Load and Test Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); if ((regs->fpr[i2] & 0x00FFFFFF) || regs->fpr[i2+1] || (regs->fpr[i2+FPREX] & 0x00FFFFFF) || regs->fpr[i2+FPREX+1]) { /* Copy register contents */ regs->fpr[i1] = regs->fpr[i2]; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Low order register */ regs->fpr[i1+FPREX] = (regs->fpr[i2] & 0x80000000) | ((regs->fpr[i2] - (14 << 24)) & 0x7F000000) | (regs->fpr[i2+FPREX] & 0x00FFFFFF); regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1]; /* Set condition code */ regs->psw.cc = (regs->fpr[i2] & 0x80000000) ? 1 : 2; } else { /* true zero with sign */ regs->fpr[i1] = regs->fpr[i2] & 0x80000000; regs->fpr[i1+FPREX] = regs->fpr[i1]; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX+1] = 0; /* Set condition code */ regs->psw.cc = 0; } } /* end DEF_INST(load_and_test_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B363 LCXR - Load Complement Float. Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); if ((regs->fpr[i2] & 0x00FFFFFF) || regs->fpr[i2+1] || (regs->fpr[i2+FPREX] & 0x00FFFFFF) || regs->fpr[i2+FPREX+1]) { /* Copy register contents, invert sign bit */ regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Low order register */ regs->fpr[i1+FPREX] = (regs->fpr[i1] & 0x80000000) |(((regs->fpr[i1] & 0x7F000000) - 0x0E000000) & 0x7F000000) | (regs->fpr[i2+FPREX] & 0x00FFFFFF); regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1]; /* Set condition code */ regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2; } else { /* true zero with sign */ regs->fpr[i1] = (regs->fpr[i2] ^ 0x80000000) & 0x80000000; regs->fpr[i1+FPREX] = regs->fpr[i1]; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX+1] = 0; /* Set condition code */ regs->psw.cc = 0; } } /* end DEF_INST(load_complement_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B366 LEXR - Load Rounded Float. Extended to Short Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_float_ext_to_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT from_fl; SHORT_FLOAT to_fl; int pgm_check; RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); HFPODD_CHECK(r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_ef(&from_fl, regs->fpr + i2); /* Rounding */ to_fl.short_fract = (from_fl.ms_fract + 0x0000000000800000ULL) >> 24; to_fl.sign = from_fl.sign; to_fl.expo = from_fl.expo; /* Handle overflow */ if (to_fl.short_fract & 0x0F000000) { to_fl.short_fract >>= 4; (to_fl.expo)++; pgm_check = overflow_sf(&to_fl, regs); } else { pgm_check = 0; } /* To register */ store_sf(&to_fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(load_rounded_float_ext_to_short_reg) */ /*-------------------------------------------------------------------*/ /* B367 FIXR - Load FP Integer Float. Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT fl; BYTE shift; RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_ef(&fl, regs->fpr + i2); if (fl.expo > 64) { if (fl.expo < 92) { /* Denormalize */ shift = (92 - fl.expo) * 4; if (shift > 64) { fl.ls_fract = fl.ms_fract >> (shift - 64); fl.ms_fract = 0; } else if (shift == 64) { fl.ls_fract = fl.ms_fract; fl.ms_fract = 0; } else { fl.ls_fract = (fl.ls_fract >> shift) | (fl.ms_fract << (64 - shift)); fl.ms_fract >>= shift; } fl.expo = 92; } /* Normalize result */ normal_ef(&fl); /* To register */ store_ef(&fl, regs->fpr + i1); } else { /* True zero */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX] = 0; regs->fpr[i1+FPREX+1] = 0; } } /* end DEF_INST(load_fp_int_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B369 CXR - Compare Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ EXTENDED_FLOAT fl; EXTENDED_FLOAT cmp_fl; RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get the operands */ get_ef(&fl, regs->fpr + i1); get_ef(&cmp_fl, regs->fpr + i2);; /* Compare extended */ cmp_ef(&fl, &cmp_fl, regs); } /* end DEF_INST(compare_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B377 FIER - Load FP Integer Floating Point Short Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ SHORT_FLOAT fl; RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_sf(&fl, regs->fpr + i2); if (fl.expo > 64) { if (fl.expo < 70) { /* Denormalize */ fl.short_fract >>= ((70 - fl.expo) * 4); fl.expo = 70; } /* Normalize result */ normal_sf(&fl); /* To register */ store_sf(&fl, regs->fpr + i1); } else { /* True zero */ regs->fpr[i1] = 0; } } /* end DEF_INST(load_fp_int_float_short_reg) */ /*-------------------------------------------------------------------*/ /* B37F FIDR - Load FP Integer Floating Point Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_float_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Get register content */ get_lf(&fl, regs->fpr + i2); if (fl.expo > 64) { if (fl.expo < 78) { /* Denormalize */ fl.long_fract >>= ((78 - fl.expo) * 4); fl.expo = 78; } /* Normalize result */ normal_lf(&fl); /* To register */ store_lf(&fl, regs->fpr + i1); } else { /* True zero */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; } } /* end DEF_INST(load_fp_int_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B3B4 CEFR - Convert from Fixed to Float. Short Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fixed_to_float_short_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ LONG_FLOAT fl; S64 fix; RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* get fixed value */ fix = regs->GR_L(r2); if (fix & 0x0000000080000000) fix |= 0xFFFFFFFF00000000ULL; if (fix) { if (fix < 0) { fl.sign = NEG; fl.long_fract = (-fix); } else { fl.sign = POS; fl.long_fract = fix; } fl.expo = 78; /* Normalize result */ normal_lf(&fl); /* To register (converting to short float) */ regs->fpr[i1] = ((U32)fl.sign << 31) | ((U32)fl.expo << 24) | (fl.long_fract >> 32); } else { /* true zero */ regs->fpr[i1] = 0; } } /* end DEF_INST(convert_fixed_to_float_short_reg) */ /*-------------------------------------------------------------------*/ /* B3B5 CDFR - Convert from Fixed to Float. Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fixed_to_float_long_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ LONG_FLOAT fl; S64 fix; RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* get fixed value */ fix = regs->GR_L(r2); if (fix & 0x0000000080000000) fix |= 0xFFFFFFFF00000000ULL; if (fix) { if (fix < 0) { fl.sign = NEG; fl.long_fract = (-fix); } else { fl.sign = POS; fl.long_fract = fix; } fl.expo = 78; /* Normalize result */ normal_lf(&fl); /* To register */ store_lf(&fl, regs->fpr + i1); } else { /* true zero */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; } } /* end DEF_INST(convert_fixed_to_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B3B6 CXFR - Convert from Fixed to Float. Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fixed_to_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ EXTENDED_FLOAT fl; S64 fix; RRE(inst, regs, r1, r2); HFPODD_CHECK(r1, regs); i1 = FPR2I(r1); /* get fixed value */ fix = regs->GR_L(r2); if (fix & 0x0000000080000000) fix |= 0xFFFFFFFF00000000ULL; if (fix) { if (fix < 0) { fl.sign = NEG; fl.ms_fract = (-fix); } else { fl.sign = POS; fl.ms_fract = fix; } fl.ls_fract = 0; fl.expo = 76; /* 64 + 12 digits) */ /* Normalize result */ normal_ef(&fl); /* To register */ store_ef(&fl, regs->fpr + i1); } else { /* true zero */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX] = 0; regs->fpr[i1+FPREX+1] = 0; } } /* end DEF_INST(convert_fixed_to_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3C4 CEGR - Convert from Fix64 to Float. Short Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_float_short_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ SHORT_FLOAT fl; U64 fix; RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); fix = regs->GR_G(r2); /* Test for negative value */ if (fix & 0x8000000000000000ULL) { fix = ~fix + 1; /* fix = abs(fix); */ fl.sign = NEG; } else fl.sign = POS; if (fix) { fl.expo = 70; /* Truncate fraction to 6 hexadecimal digits */ while (fix & 0xFFFFFFFFFF000000ULL) { fix >>= 4; fl.expo += 1; } fl.short_fract = (U32)fix; /* Normalize result */ normal_sf(&fl); /* To register */ store_sf(&fl, regs->fpr + i1); } else { /* true zero */ regs->fpr[i1] = 0; } } /* end DEF_INST(convert_fix64_to_float_short_reg) */ /*-------------------------------------------------------------------*/ /* B3C5 CDGR - Convert from Fix64 to Float. Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_float_long_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ LONG_FLOAT fl; U64 fix; RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); fix = regs->GR_G(r2); /* Test for negative value */ if (fix & 0x8000000000000000ULL) { fix = ~fix + 1; /* fix = abs(fix); */ fl.sign = NEG; } else fl.sign = POS; if (fix) { fl.long_fract = fix; fl.expo = 78; /* Truncate fraction to 14 hexadecimal digits */ while (fl.long_fract & 0xFF00000000000000ULL) { fl.long_fract >>= 4; fl.expo += 1; } /* Normalize result */ normal_lf(&fl); /* To register */ store_lf(&fl, regs->fpr + i1); } else { /* true zero */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; } } /* end DEF_INST(convert_fix64_to_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B3C6 CXGR - Convert from Fix64 to Float. Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ EXTENDED_FLOAT fl; U64 fix; RRE(inst, regs, r1, r2); HFPODD_CHECK(r1, regs); i1 = FPR2I(r1); fix = regs->GR_G(r2); /* Test for negative value */ if (fix & 0x8000000000000000ULL) { fix = ~fix + 1; /* fix = abs(fix); */ fl.sign = NEG; } else fl.sign = POS; if (fix) { fl.ms_fract = fix >> 16; /* Fraction high (12 digits) */ fl.ls_fract = fix << 48; /* Fraction low (16 digits) */ fl.expo = 80; /* Normalize result */ normal_ef(&fl); /* To register */ store_ef(&fl, regs->fpr + i1); } else { /* true zero */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX] = 0; regs->fpr[i1+FPREX+1] = 0; } } /* end DEF_INST(convert_fix64_to_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3B8 CFER - Convert from Float. Short to Fixed Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_short_to_fixed_reg) { int r1, r2; /* Values of R fields */ int i2; /* Index of R2 in fpr array */ int m3; /* Value of mask field */ SHORT_FLOAT fl; BYTE shift; U32 lsfract; RRF_M(inst, regs, r1, r2, m3); HFPM_CHECK(m3, regs); HFPREG_CHECK(r2, regs); i2 = FPR2I(r2); /* Get register content */ get_sf(&fl, regs->fpr + i2); if (fl.short_fract) { /* not zero */ normal_sf(&fl); if (fl.expo > 72) { /* exeeds range by exponent */ regs->GR_L(r1) = fl.sign ? 0x80000000UL : 0x7FFFFFFFUL; regs->psw.cc = 3; return; } if (fl.expo > 70) { /* to be left shifted */ fl.short_fract <<= ((fl.expo - 70) * 4); if (fl.sign) { /* negative */ if (fl.short_fract > 0x80000000UL) { /* exeeds range by value */ regs->GR_L(r1) = 0x80000000UL; regs->psw.cc = 3; return; } } else { /* positive */ if (fl.short_fract > 0x7FFFFFFFUL) { /* exeeds range by value */ regs->GR_L(r1) = 0x7FFFFFFFUL; regs->psw.cc = 3; return; } } } else if ((fl.expo > 64) && (fl.expo < 70)) { /* to be right shifted and to be rounded */ shift = ((70 - fl.expo) * 4); lsfract = fl.short_fract << (32 - shift); fl.short_fract >>= shift; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x80000000UL) { fl.short_fract++; } } else if (m3 == 4) { /* round to nearest */ if ((lsfract > 0x80000000UL) || ((fl.short_fract & 0x00000001UL) && (lsfract == 0x80000000UL))) { fl.short_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { fl.short_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { fl.short_fract++; } } } else if (fl.expo == 64) { /* to be rounded */ lsfract = fl.short_fract << 8; fl.short_fract = 0; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x80000000UL) { fl.short_fract++; } } else if (m3 == 4) { /* round to nearest */ if (lsfract > 0x80000000UL) { fl.short_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { fl.short_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { fl.short_fract++; } } } else if (fl.expo < 64) { fl.short_fract = 0; if (((m3 == 6) && (fl.sign == POS)) || ((m3 == 7) && (fl.sign == NEG))) { fl.short_fract++; } } if (fl.sign) { /* negative */ regs->GR_L(r1) = -((S32) fl.short_fract); regs->psw.cc = 1; } else { /* positive */ regs->GR_L(r1) = fl.short_fract; regs->psw.cc = 2; } } else { /* zero */ regs->GR_L(r1) = 0; regs->psw.cc = 0; } } /* end DEF_INST(convert_float_short_to_fixed_reg) */ /*-------------------------------------------------------------------*/ /* B3B9 CFDR - Convert from Float. Long to Fixed Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_long_to_fixed_reg) { int r1, r2; /* Values of R fields */ int i2; /* Index of R2 in fpr array */ int m3; /* Value of mask field */ LONG_FLOAT fl; BYTE shift; U64 lsfract; RRF_M(inst, regs, r1, r2, m3); HFPM_CHECK(m3, regs); HFPREG_CHECK(r2, regs); i2 = FPR2I(r2); /* Get register content */ get_lf(&fl, regs->fpr + i2); if (fl.long_fract) { /* not zero */ normal_lf(&fl); if (fl.expo > 72) { /* exeeds range by exponent */ regs->GR_L(r1) = fl.sign ? 0x80000000UL : 0x7FFFFFFFUL; regs->psw.cc = 3; return; } if (fl.expo > 64) { /* to be right shifted and to be rounded */ shift = ((78 - fl.expo) * 4); lsfract = fl.long_fract << (64 - shift); fl.long_fract >>= shift; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { fl.long_fract++; } } else if (m3 == 4) { /* round to nearest */ if ((lsfract > 0x8000000000000000ULL) || ((fl.long_fract & 0x0000000000000001ULL) && (lsfract == 0x8000000000000000ULL))) { fl.long_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { fl.long_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { fl.long_fract++; } } if (fl.expo == 72) { if (fl.sign) { /* negative */ if (fl.long_fract > 0x80000000UL) { /* exeeds range by value */ regs->GR_L(r1) = 0x80000000UL; regs->psw.cc = 3; return; } } else { /* positive */ if (fl.long_fract > 0x7FFFFFFFUL) { /* exeeds range by value */ regs->GR_L(r1) = 0x7FFFFFFFUL; regs->psw.cc = 3; return; } } } } else if (fl.expo == 64) { /* to be rounded */ lsfract = fl.long_fract << 8; fl.long_fract = 0; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { fl.long_fract++; } } else if (m3 == 4) { /* round to nearest */ if (lsfract > 0x8000000000000000ULL) { fl.long_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { fl.long_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { fl.long_fract++; } } } else { /* fl.expo < 64 */ fl.long_fract = 0; if (((m3 == 6) && (fl.sign == POS)) || ((m3 == 7) && (fl.sign == NEG))) { fl.long_fract++; } } if (fl.sign) { /* negative */ regs->GR_L(r1) = -((S32) fl.long_fract); regs->psw.cc = 1; } else { /* positive */ regs->GR_L(r1) = fl.long_fract; regs->psw.cc = 2; } } else { /* zero */ regs->GR_L(r1) = 0; regs->psw.cc = 0; } } /* end DEF_INST(convert_float_long_to_fixed_reg) */ /*-------------------------------------------------------------------*/ /* B3BA CFXR - Convert from Float. Extended to Fixed Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_ext_to_fixed_reg) { int r1, r2; /* Values of R fields */ int i2; /* Index of R2 in fpr array */ int m3; /* Value of mask field */ EXTENDED_FLOAT fl; BYTE shift; U64 lsfract; RRF_M(inst, regs, r1, r2, m3); HFPM_CHECK(m3, regs); HFPODD_CHECK(r2, regs); i2 = FPR2I(r2); /* Get register content */ get_ef(&fl, regs->fpr + i2); if (fl.ms_fract || fl.ls_fract) { /* not zero */ normal_ef(&fl); if (fl.expo > 72) { /* exeeds range by exponent */ regs->GR_L(r1) = fl.sign ? 0x80000000UL : 0x7FFFFFFFUL; regs->psw.cc = 3; return; } if (fl.expo > 64) { /* to be right shifted and to be rounded */ shift = ((92 - fl.expo - 16) * 4); lsfract = fl.ms_fract << (64 - shift); fl.ms_fract >>= shift; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { fl.ms_fract++; } } else if (m3 == 4) { /* round to nearest */ if (((lsfract & 0x8000000000000000ULL) && ((lsfract & 0x7FFFFFFFFFFFFFFFULL) || fl.ls_fract)) || ( (fl.ms_fract & 0x0000000000000001ULL) && (lsfract == 0x8000000000000000ULL) && (fl.ls_fract == 0))) { fl.ms_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && (lsfract || fl.ls_fract)) { fl.ms_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && (lsfract || fl.ls_fract)) { fl.ms_fract++; } } } else if (fl.expo == 64) { /* to be rounded */ lsfract = fl.ms_fract << 16; fl.ms_fract = 0; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { fl.ms_fract++; } } else if (m3 == 4) { /* round to nearest */ if ((lsfract & 0x8000000000000000ULL) && ((lsfract & 0x7FFFFFFFFFFFFFFFULL) || fl.ls_fract)) { fl.ms_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && (lsfract || fl.ls_fract)) { fl.ms_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && (lsfract || fl.ls_fract)) { fl.ms_fract++; } } } else { /* fl.expo < 64 */ fl.ms_fract = 0; if (((m3 == 6) && (fl.sign == POS)) || ((m3 == 7) && (fl.sign == NEG))) { fl.ms_fract++; } } if (fl.sign) { /* negative */ if (fl.ms_fract > 0x80000000UL) { /* exeeds range by value */ regs->GR_L(r1) = 0x80000000UL; regs->psw.cc = 3; return; } regs->GR_L(r1) = -((S32) fl.ms_fract); regs->psw.cc = 1; } else { /* positive */ if (fl.ms_fract > 0x7FFFFFFFUL) { /* exeeds range by value */ regs->GR_L(r1) = 0x7FFFFFFFUL; regs->psw.cc = 3; return; } regs->GR_L(r1) = fl.ms_fract; regs->psw.cc = 2; } } else { /* zero */ regs->GR_L(r1) = 0; regs->psw.cc = 0; } } /* end DEF_INST(convert_float_ext_to_fixed_reg) */ /*-------------------------------------------------------------------*/ /* B3C8 CGER - Convert from Float. Short to Fix64 Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_short_to_fix64_reg) { int r1, r2; /* Values of R fields */ int i2; /* Index of R2 in fpr array */ int m3; /* Value of mask field */ SHORT_FLOAT fl; BYTE shift; U64 intpart; U32 lsfract; RRF_M(inst, regs, r1, r2, m3); HFPM_CHECK(m3, regs); HFPREG_CHECK(r2, regs); i2 = FPR2I(r2); /* Get register content */ get_sf(&fl, regs->fpr + i2); if (fl.short_fract) { /* not zero */ normal_sf(&fl); if (fl.expo > 80) { /* exeeds range by exponent */ regs->GR_G(r1) = fl.sign ? 0x8000000000000000ULL : 0x7FFFFFFFFFFFFFFFULL; regs->psw.cc = 3; return; } if (fl.expo > 70) { /* to be left shifted */ intpart = (U64)fl.short_fract << ((fl.expo - 70) * 4); if (fl.sign) { /* negative */ if (intpart > 0x8000000000000000ULL) { /* exeeds range by value */ regs->GR_G(r1) = 0x8000000000000000ULL; regs->psw.cc = 3; return; } } else { /* positive */ if (intpart > 0x7FFFFFFFFFFFFFFFULL) { /* exeeds range by value */ regs->GR_G(r1) = 0x7FFFFFFFFFFFFFFFULL; regs->psw.cc = 3; return; } } } else if ((fl.expo > 64) && (fl.expo < 70)) { /* to be right shifted and to be rounded */ shift = ((70 - fl.expo) * 4); lsfract = fl.short_fract << (32 - shift); intpart = fl.short_fract >> shift; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x80000000UL) { intpart++; } } else if (m3 == 4) { /* round to nearest */ if ((lsfract > 0x80000000UL) || ((intpart & 0x0000000000000001ULL) && (lsfract == 0x80000000UL))) { intpart++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { intpart++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { intpart++; } } } else if (fl.expo == 64) { /* to be rounded */ lsfract = fl.short_fract << 8; intpart = 0; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x80000000UL) { intpart++; } } else if (m3 == 4) { /* round to nearest */ if (lsfract > 0x80000000UL) { intpart++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { intpart++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { intpart++; } } } else if (fl.expo < 64) { intpart = 0; if (((m3 == 6) && (fl.sign == POS)) || ((m3 == 7) && (fl.sign == NEG))) { intpart++; } } else /* fl.expo == 70 */ { /* no shift or round required */ intpart = (U64)fl.short_fract; } if (fl.sign) { /* negative */ if (intpart == 0x8000000000000000ULL) regs->GR_G(r1) = 0x8000000000000000ULL; else regs->GR_G(r1) = -((S64)intpart); regs->psw.cc = 1; } else { /* positive */ regs->GR_G(r1) = intpart; regs->psw.cc = 2; } } else { /* zero */ regs->GR_G(r1) = 0; regs->psw.cc = 0; } } /* end DEF_INST(convert_float_short_to_fix64_reg) */ /*-------------------------------------------------------------------*/ /* B3C9 CGDR - Convert from Float. Long to Fix64 Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_long_to_fix64_reg) { int r1, r2; /* Values of R fields */ int i2; /* Index of R2 in fpr array */ int m3; /* Value of mask field */ LONG_FLOAT fl; BYTE shift; U64 lsfract; RRF_M(inst, regs, r1, r2, m3); HFPM_CHECK(m3, regs); HFPREG_CHECK(r2, regs); i2 = FPR2I(r2); /* Get register content */ get_lf(&fl, regs->fpr + i2); if (fl.long_fract) { /* not zero */ normal_lf(&fl); if (fl.expo > 80) { /* exeeds range by exponent */ regs->GR_G(r1) = fl.sign ? 0x8000000000000000ULL : 0x7FFFFFFFFFFFFFFFULL; regs->psw.cc = 3; return; } if (fl.expo > 78) { /* to be left shifted */ fl.long_fract <<= ((fl.expo - 78) * 4); if (fl.sign) { /* negative */ if (fl.long_fract > 0x8000000000000000ULL) { /* exeeds range by value */ regs->GR_G(r1) = 0x8000000000000000ULL; regs->psw.cc = 3; return; } } else { /* positive */ if (fl.long_fract > 0x7FFFFFFFFFFFFFFFULL) { /* exeeds range by value */ regs->GR_G(r1) = 0x7FFFFFFFFFFFFFFFULL; regs->psw.cc = 3; return; } } } else if ((fl.expo > 64) && (fl.expo < 78)) { /* to be right shifted and to be rounded */ shift = ((78 - fl.expo) * 4); lsfract = fl.long_fract << (64 - shift); fl.long_fract >>= shift; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { fl.long_fract++; } } else if (m3 == 4) { /* round to nearest */ if ((lsfract > 0x8000000000000000ULL) || ((fl.long_fract & 0x0000000000000001ULL) && (lsfract == 0x8000000000000000ULL))) { fl.long_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { fl.long_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { fl.long_fract++; } } } else if (fl.expo == 64) { /* to be rounded */ lsfract = fl.long_fract << 8; fl.long_fract = 0; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { fl.long_fract++; } } else if (m3 == 4) { /* round to nearest */ if (lsfract > 0x8000000000000000ULL) { fl.long_fract++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { fl.long_fract++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { fl.long_fract++; } } } else if (fl.expo < 64) { fl.long_fract = 0; if (((m3 == 6) && (fl.sign == POS)) || ((m3 == 7) && (fl.sign == NEG))) { fl.long_fract++; } } if (fl.sign) { /* negative */ if (fl.long_fract == 0x8000000000000000ULL) regs->GR_G(r1) = 0x8000000000000000ULL; else regs->GR_G(r1) = -((S64)fl.long_fract); regs->psw.cc = 1; } else { /* positive */ regs->GR_G(r1) = fl.long_fract; regs->psw.cc = 2; } } else { /* zero */ regs->GR_G(r1) = 0; regs->psw.cc = 0; } } /* end DEF_INST(convert_float_long_to_fix64_reg) */ /*-------------------------------------------------------------------*/ /* B3CA CGXR - Convert from Float. Extended to Fix64 Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_ext_to_fix64_reg) { int r1, r2; /* Values of R fields */ int i2; /* Index of R2 in fpr array */ int m3; /* Value of mask field */ EXTENDED_FLOAT fl; BYTE shift; U64 intpart; U64 lsfract; RRF_M(inst, regs, r1, r2, m3); HFPM_CHECK(m3, regs); HFPODD_CHECK(r2, regs); i2 = FPR2I(r2); /* Get register content */ get_ef(&fl, regs->fpr + i2); if (fl.ms_fract || fl.ls_fract) { /* not zero */ normal_ef(&fl); if (fl.expo > 80) { /* exeeds range by exponent */ regs->GR_G(r1) = fl.sign ? 0x8000000000000000ULL : 0x7FFFFFFFFFFFFFFFULL; regs->psw.cc = 3; return; } if (fl.expo > 64) { /* to be right shifted and to be rounded */ shift = ((92 - fl.expo) * 4); if (shift > 64) { intpart = fl.ms_fract >> (shift - 64); lsfract = (fl.ls_fract >> (128 - shift)) | (fl.ms_fract << (128 - shift)); } else if (shift < 64) { intpart = (fl.ls_fract >> shift) | (fl.ms_fract << (64 - shift)); lsfract = fl.ls_fract << (64 - shift); } else /* shift == 64 */ { intpart = fl.ms_fract; lsfract = fl.ls_fract; } if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { intpart++; } } else if (m3 == 4) { /* round to nearest */ if ((lsfract > 0x8000000000000000ULL) || ((intpart & 0x0000000000000001ULL) && (lsfract == 0x8000000000000000ULL))) { intpart++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { intpart++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { intpart++; } } } else if (fl.expo == 64) { /* to be rounded */ lsfract = (fl.ms_fract << 16) | (fl.ls_fract >> 48); intpart = 0; if (m3 == 1) { /* biased round to nearest */ if (lsfract & 0x8000000000000000ULL) { intpart++; } } else if (m3 == 4) { /* round to nearest */ if (lsfract > 0x8000000000000000ULL) { intpart++; } } else if (m3 == 6) { /* round toward + */ if ((fl.sign == POS) && lsfract) { intpart++; } } else if (m3 == 7) { /* round toward - */ if ((fl.sign == NEG) && lsfract) { intpart++; } } } else { /* fl.expo < 64 */ intpart = 0; if (((m3 == 6) && (fl.sign == POS)) || ((m3 == 7) && (fl.sign == NEG))) { intpart++; } } if (fl.sign) { /* negative */ if (intpart > 0x8000000000000000ULL) { /* exeeds range by value */ regs->GR_G(r1) = 0x8000000000000000ULL; regs->psw.cc = 3; return; } if (intpart == 0x8000000000000000ULL) regs->GR_G(r1) = 0x8000000000000000ULL; else regs->GR_G(r1) = -((S64)intpart); regs->psw.cc = 1; } else { /* positive */ if (intpart > 0x7FFFFFFFFFFFFFFFULL) { /* exeeds range by value */ regs->GR_G(r1) = 0x7FFFFFFFFFFFFFFFULL; regs->psw.cc = 3; return; } regs->GR_G(r1) = intpart; regs->psw.cc = 2; } } else { /* zero */ regs->GR_G(r1) = 0; regs->psw.cc = 0; } } /* end DEF_INST(convert_float_ext_to_fix64_reg) */ /*-------------------------------------------------------------------*/ /* ED24 LDE - Load Lengthened Floating Point Short to Long [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_float_short_to_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXE(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Update first 32 bits of register from operand address */ regs->fpr[i1] = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); /* Zero register content */ regs->fpr[i1+1] = 0; } /* end DEF_INST(load_lengthened_float_short_to_long) */ /*-------------------------------------------------------------------*/ /* ED25 LXD - Load Lengthened Floating Point Long to Extended [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_float_long_to_ext) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 wk; U64 wkd; RXE(inst, regs, r1, b2, effective_addr2); HFPODD_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the 2nd operand */ wkd = ARCH_DEP(vfetch8) (effective_addr2, b2, regs); wk = wkd >> 32; if (wkd & 0x00FFFFFFFFFFFFFFULL) { /* Back to register */ regs->fpr[i1] = wk; regs->fpr[i1+1] = wkd; /* Low order register */ regs->fpr[i1+FPREX] = (wk & 0x80000000) | ((wk - (14 << 24)) & 0x7F000000); } else { /* true zero with sign */ regs->fpr[i1] = (wk & 0x80000000); regs->fpr[i1+FPREX] = regs->fpr[i1]; regs->fpr[i1+1] = 0; } regs->fpr[i1+FPREX+1] = 0; } /* end DEF_INST(load_lengthened_float_long_to_ext) */ /*-------------------------------------------------------------------*/ /* ED26 LXE - Load Lengthened Float. Short to Extended [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_float_short_to_ext) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 wk; RXE(inst, regs, r1, b2, effective_addr2); HFPODD_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the 2nd operand */ wk = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); if (wk & 0x00FFFFFF) { /* Back to register */ regs->fpr[i1] = wk; /* Zero register content */ regs->fpr[i1+1] = 0; /* Low order register */ regs->fpr[i1+FPREX] = (wk & 0x80000000) | ((wk - (14 << 24)) & 0x7F000000); regs->fpr[i1+FPREX+1] = 0; } else { /* true zero with sign */ regs->fpr[i1] = (wk & 0x80000000); regs->fpr[i1+FPREX] = regs->fpr[i1]; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX+1] = 0; } } /* end DEF_INST(load_lengthened_float_short_to_ext) */ /*-------------------------------------------------------------------*/ /* ED34 SQE - Square Root Floating Point Short [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT sq_fl; SHORT_FLOAT fl; RXE(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the 2nd operand */ vfetch_sf(&fl, effective_addr2, b2, regs ); /* short square root subroutine */ sq_sf(&sq_fl, &fl, regs); /* Back to register */ store_sf(&sq_fl, regs->fpr + i1); } /* end DEF_INST(squareroot_float_short) */ /*-------------------------------------------------------------------*/ /* ED35 SQD - Square Root Floating Point Long [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_float_long) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT sq_fl; LONG_FLOAT fl; RXE(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the 2nd operand */ vfetch_lf(&fl, effective_addr2, b2, regs ); /* long square root subroutine */ sq_lf(&sq_fl, &fl, regs); /* Back to register */ store_lf(&sq_fl, regs->fpr + i1); } /* end DEF_INST(squareroot_float_long) */ /*-------------------------------------------------------------------*/ /* ED37 MEE - Multiply Floating Point Short [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_float_short) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl; SHORT_FLOAT mul_fl; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Get the operands */ get_sf(&fl, regs->fpr + i1); vfetch_sf(&mul_fl, effective_addr2, b2, regs ); /* multiply short to long */ pgm_check = mul_sf(&fl, &mul_fl, OVUNF, regs); /* Back to register */ store_sf(&fl, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_float_short) */ #endif /* FEATURE_HFP_EXTENSIONS */ #if defined(FEATURE_FPS_EXTENSIONS) /*-------------------------------------------------------------------*/ /* B365 LXR - Load Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* Indexes into fpr array */ RRE(inst, regs, r1, r2); HFPODD2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register R2 contents to register R1 */ regs->fpr[i1] = regs->fpr[i2]; regs->fpr[i1+1] = regs->fpr[i2+1]; regs->fpr[i1+FPREX] = regs->fpr[i2+FPREX]; regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1]; } /* end DEF_INST(load_float_ext_reg) */ /*-------------------------------------------------------------------*/ /* B374 LZER - Load Zero Floating Point Short Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_zero_float_short_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Set all bits of register R1 to zeros */ regs->fpr[i1] = 0; } /* end DEF_INST(load_zero_float_short_reg) */ /*-------------------------------------------------------------------*/ /* B375 LZDR - Load Zero Floating Point Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_zero_float_long_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Set all bits of register R1 to zeros */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; } /* end DEF_INST(load_zero_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B376 LZXR - Load Zero Floating Point Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_zero_float_ext_reg) { int r1, r2; /* Values of R fields */ int i1; /* Index of R1 in fpr array */ RRE(inst, regs, r1, r2); HFPODD_CHECK(r1, regs); i1 = FPR2I(r1); /* Set all bits of register R1 to zeros */ regs->fpr[i1] = 0; regs->fpr[i1+1] = 0; regs->fpr[i1+FPREX] = 0; regs->fpr[i1+FPREX+1] = 0; } /* end DEF_INST(load_zero_float_ext_reg) */ #endif /*defined(FEATURE_FPS_EXTENSIONS)*/ #if defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT) /*-------------------------------------------------------------------*/ /* B32E MAER - Multiply and Add Floating Point Short Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_float_short_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ SHORT_FLOAT fl1, fl2, fl3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); HFPREG2_CHECK(r1, r2, regs); HFPREG_CHECK(r3, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_sf(&fl1, regs->fpr + i1); get_sf(&fl2, regs->fpr + i2); get_sf(&fl3, regs->fpr + i3); /* Multiply third and second operands */ mul_sf(&fl2, &fl3, NOOVUNF, regs); /* Add the first operand with normalization */ pgm_check = add_sf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Store result back to first operand register */ store_sf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_add_float_short_reg) */ /*-------------------------------------------------------------------*/ /* B32F MSER - Multiply and Subtract Floating Point Short Reg [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_float_short_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ SHORT_FLOAT fl1, fl2, fl3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); HFPREG2_CHECK(r1, r2, regs); HFPREG_CHECK(r3, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_sf(&fl1, regs->fpr + i1); get_sf(&fl2, regs->fpr + i2); get_sf(&fl3, regs->fpr + i3); /* Multiply third and second operands */ mul_sf(&fl2, &fl3, NOOVUNF, regs); /* Invert the sign of the first operand */ fl1.sign = ! (fl1.sign); /* Subtract the first operand with normalization */ pgm_check = add_sf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Store result back to first operand register */ store_sf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_subtract_float_short_reg) */ /*-------------------------------------------------------------------*/ /* B33E MADR - Multiply and Add Floating Point Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_float_long_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl1, fl2, fl3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); HFPREG2_CHECK(r1, r2, regs); HFPREG_CHECK(r3, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Multiply long third and second operands */ mul_lf(&fl2, &fl3, NOOVUNF, regs); /* Add the first operand with normalization */ pgm_check = add_lf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Store result back to first operand register */ store_lf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_add_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B33F MSDR - Multiply and Subtract Floating Point Long Reg [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_float_long_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl1, fl2, fl3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); HFPREG2_CHECK(r1, r2, regs); HFPREG_CHECK(r3, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Multiply long third and second operands */ mul_lf(&fl2, &fl3, NOOVUNF, regs); /* Invert the sign of the first operand */ fl1.sign = ! (fl1.sign); /* Subtract the first operand with normalization */ pgm_check = add_lf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Store result back to first operand register */ store_lf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_subtract_float_long_reg) */ /*-------------------------------------------------------------------*/ /* ED2E MAE - Multiply and Add Floating Point Short [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_float_short) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl1, fl2, fl3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ get_sf(&fl1, regs->fpr + i1); vfetch_sf(&fl2, effective_addr2, b2, regs ); get_sf(&fl3, regs->fpr + i3); /* Multiply third and second operands */ mul_sf(&fl2, &fl3, NOOVUNF, regs); /* Add the first operand with normalization */ pgm_check = add_sf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Back to register */ store_sf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_add_float_short) */ /*-------------------------------------------------------------------*/ /* ED2F MSE - Multiply and Subtract Floating Point Short [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_float_short) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ SHORT_FLOAT fl1, fl2, fl3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ get_sf(&fl1, regs->fpr + i1); vfetch_sf(&fl2, effective_addr2, b2, regs ); get_sf(&fl3, regs->fpr + i3); /* Multiply third and second operands */ mul_sf(&fl2, &fl3, NOOVUNF, regs); /* Invert the sign of the first operand */ fl1.sign = ! (fl1.sign); /* Subtract the first operand with normalization */ pgm_check = add_sf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Back to register */ store_sf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_subtract_float_short) */ /*-------------------------------------------------------------------*/ /* ED3E MAD - Multiply and Add Floating Point Long [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_float_long) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl1, fl2, fl3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Multiply long third and second operands */ mul_lf(&fl2, &fl3, NOOVUNF, regs); /* Add long first operand with normalization */ pgm_check = add_lf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Back to register */ store_lf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_add_float_long) */ /*-------------------------------------------------------------------*/ /* ED3F MSD - Multiply and Subtract Floating Point Long [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_float_long) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl1, fl2, fl3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Multiply long third and second operands */ mul_lf(&fl2, &fl3, NOOVUNF, regs); /* Invert the sign of the first operand */ fl1.sign = ! (fl1.sign); /* Subtract long with normalization */ pgm_check = add_lf(&fl1, &fl2, NORMAL, NOSIGEX, regs); /* Back to register */ store_lf(&fl1, regs->fpr + i1); /* Program check ? */ if (pgm_check) { ARCH_DEP(program_interrupt) (regs, pgm_check); } } /* end DEF_INST(multiply_subtract_float_long) */ #endif /*defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT)*/ #if defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) /*-------------------------------------------------------------------*/ /* B338 MAYLR - Multiply and Add Unnorm. Long to Ext. Low Reg. [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_low_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ LONG_FLOAT fl1; /* Addend */ EXTENDED_FLOAT fxp1; /* Intermediate product */ EXTENDED_FLOAT fxadd; /* Addend in extended format */ EXTENDED_FLOAT fxres; /* Extended result */ RRF_R(inst, regs, r1, r2, r3) HFPREG2_CHECK(r2, r3, regs); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate product */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fxp1); /* Convert Addend to extended format */ ARCH_DEP(lf_to_ef_unnorm)(&fxadd, &fl1); /* Add the addend to the intermediate product */ ARCH_DEP(add_ef_unnorm)(&fxp1, &fxadd, &fxres); /* Place low-order part of result in register */ ARCH_DEP(store_ef_unnorm_lo)(&fxres, regs->fpr + i1); } /* end DEF_INST(multiply_add_unnormal_float_long_to_ext_low_reg) */ /*-------------------------------------------------------------------*/ /* B339 MYLR - Multiply Unnormalized Long to Ext. Low FP Reg. [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_unnormal_float_long_to_ext_low_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ EXTENDED_FLOAT fx1; /* Intermediate result */ RRF_R(inst, regs, r1, r2, r3); HFPREG2_CHECK(r2, r3, regs); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate result */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fx1); /* Place low-order part of result in register */ ARCH_DEP(store_ef_unnorm_lo)(&fx1, regs->fpr + i1); } /* end DEF_INST(multiply_unnormal_float_long_to_ext_low_reg) */ /*-------------------------------------------------------------------*/ /* B33A MAYR - Multiply and Add Unnorm. Long to Ext. Reg. [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ LONG_FLOAT fl1; /* Addend */ EXTENDED_FLOAT fxp1; /* Intermediate product */ EXTENDED_FLOAT fxadd; /* Addend in extended format */ EXTENDED_FLOAT fxres; /* Extended result */ RRF_R(inst, regs, r1, r2, r3); HFPREG2_CHECK(r2, r3, regs); HFPREG_CHECK(r1, regs); /* Either the low- or high-numbered register of a pair is valid */ i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate product */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fxp1); /* Convert Addend to extended format */ ARCH_DEP(lf_to_ef_unnorm)(&fxadd, &fl1); /* Add the addend to the intermediate product */ ARCH_DEP(add_ef_unnorm)(&fxp1, &fxadd, &fxres); /* Place result in register */ r1 &= 13; /* Convert to the low numbered register */ i1 = FPR2I(r1); ARCH_DEP(store_ef_unnorm)(&fxres, regs->fpr + i1); } /* end DEF_INST(multiply_add_unnormal_float_long_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* B33B MYR - Multiply Unnormalized Long to Extended Reg [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_unnormal_float_long_to_ext_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ EXTENDED_FLOAT fx1; /* Intermediate result */ RRF_R(inst, regs, r1, r2, r3); HFPODD_CHECK(r1, regs); HFPREG2_CHECK(r2, r3, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate result */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fx1); /* Place result in register */ ARCH_DEP(store_ef_unnorm)(&fx1, regs->fpr + i1); } /* DEF_INST(multiply_unnormal_float_long_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* B33C MAYHR - Multiply and Add Unnorm. Long to Ext. High Reg [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_high_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ LONG_FLOAT fl1; /* Addend */ EXTENDED_FLOAT fxp1; /* Intermediate product */ EXTENDED_FLOAT fxadd; /* Addend in extended format */ EXTENDED_FLOAT fxres; /* Extended result */ RRF_R(inst, regs, r1, r2, r3); HFPREG2_CHECK(r2, r3, regs); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate product */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fxp1); /* Convert Addend to extended format */ ARCH_DEP(lf_to_ef_unnorm)(&fxadd, &fl1); /* Add the addend to the intermediate product */ ARCH_DEP(add_ef_unnorm)(&fxp1, &fxadd, &fxres); /* Place high-order part of result in register */ ARCH_DEP(store_ef_unnorm_hi)(&fxres, regs->fpr + i1); } /* end DEF_INST(multiply_add_unnormal_float_long_to_ext_high_reg) */ /*-------------------------------------------------------------------*/ /* B33D MYHR - Multiply Unnormalized Long to Ext. High FP Reg[RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_unnormal_float_long_to_ext_high_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* Indexes into fpr array */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ EXTENDED_FLOAT fx1; /* Intermediate result */ RRF_R(inst, regs, r1, r2, r3); HFPODD_CHECK(r1, regs); HFPREG2_CHECK(r2, r3, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl2, regs->fpr + i2); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate result */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fx1); /* Place high-order part of result in register */ ARCH_DEP(store_ef_unnorm_hi)(&fx1, regs->fpr + i1); } /* end DEF_INST(multiply_unnormal_float_long_to_ext_high_reg) */ /*-------------------------------------------------------------------*/ /* ED38 MAYL - Multiply and Add Unnorm. Long to Ext. Low FP [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_low) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl2,fl3; /* Multiplier/Multiplicand */ LONG_FLOAT fl1; /* Addend */ EXTENDED_FLOAT fxp1; /* Intermediate product */ EXTENDED_FLOAT fxadd; /* Addend in extended format */ EXTENDED_FLOAT fxres; /* Extended result */ RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate product */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fxp1); /* Convert Addend to extended format */ ARCH_DEP(lf_to_ef_unnorm)(&fxadd, &fl1); /* Add the addend to the intermediate product */ ARCH_DEP(add_ef_unnorm)(&fxp1, &fxadd, &fxres); /* Place low-order part of result in register */ ARCH_DEP(store_ef_unnorm_lo)(&fxres, regs->fpr + i1); } /* end DEF_INST(multiply_add_unnormal_float_long_to_ext_low) */ /*-------------------------------------------------------------------*/ /* ED39 MYL - Multiply Unnormalized Long to Extended Low FP [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_unnormal_float_long_to_ext_low) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ EXTENDED_FLOAT fx1; /* Intermediate result */ RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate result */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fx1); /* Place low-order part of result in register */ ARCH_DEP(store_ef_unnorm_lo)(&fx1, regs->fpr + i1); } /* end DEF_INST(multiply_unnormal_float_long_to_ext_low) */ /*-------------------------------------------------------------------*/ /* ED3A MAY - Multiply and Add Unnorm. Long to Extended FP [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_unnormal_float_long_to_ext) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ LONG_FLOAT fl1; /* Addend */ EXTENDED_FLOAT fxp1; /* Intermediate product */ EXTENDED_FLOAT fxadd; /* Addend in extended format */ EXTENDED_FLOAT fxres; /* Extended result */ RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); /* Either the low- or high-numbered register of a pair is valid */ i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate product */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fxp1); /* Convert Addend to extended format */ ARCH_DEP(lf_to_ef_unnorm)(&fxadd, &fl1); /* Add the addend to the intermediate product */ ARCH_DEP(add_ef_unnorm)(&fxp1, &fxadd, &fxres); /* Place result in register */ r1 &= 13; /* Convert to the low numbered register */ i1 = FPR2I(r1); ARCH_DEP(store_ef_unnorm)(&fxres, regs->fpr + i1); } /* end DEF_INST(multiply_add_unnormal_float_long_to_ext) */ /*-------------------------------------------------------------------*/ /* ED3B MY - Multiply Unnormalized Long to Extended FP [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_unnormal_float_long_to_ext) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ EXTENDED_FLOAT fx1; /* Intermediate result */ RXF(inst, regs, r1, r3, b2, effective_addr2); HFPODD_CHECK(r1, regs); HFPREG_CHECK(r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate result */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fx1); /* Place result in register */ ARCH_DEP(store_ef_unnorm)(&fx1, regs->fpr + i1); } /* end DEF_INST(multiply_unnormal_float_long_to_ext) */ /*-------------------------------------------------------------------*/ /* ED3C MAYH - Multiply and Add Unnorm. Long to Extended High [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_unnormal_float_long_to_ext_high) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ LONG_FLOAT fl1; /* Addend */ EXTENDED_FLOAT fxp1; /* Intermediate product */ EXTENDED_FLOAT fxadd; /* Addend in extended format */ EXTENDED_FLOAT fxres; /* Extended result */ RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ get_lf(&fl1, regs->fpr + i1); vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate product */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fxp1); /* Convert Addend to extended format */ ARCH_DEP(lf_to_ef_unnorm)(&fxadd, &fl1); /* Add the addend to the intermediate product */ ARCH_DEP(add_ef_unnorm)(&fxp1, &fxadd, &fxres); /* Place high-order part of result in register */ ARCH_DEP(store_ef_unnorm_hi)(&fxres, regs->fpr + i1); } /* end DEF_INST(multiply_add_unnormal_float_long_to_ext_high) */ /*-------------------------------------------------------------------*/ /* ED3D MYH - Multiply Unnormalized Long to Extended High FP [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_unnormal_float_long_to_ext_high) { int r1, r3; /* Values of R fields */ int i1, i3; /* Indexes into fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ LONG_FLOAT fl2, fl3; /* Multiplier/Multiplicand */ EXTENDED_FLOAT fx1; /* Intermediate result */ RXF(inst, regs, r1, r3, b2, effective_addr2); HFPREG2_CHECK(r1, r3, regs); i1 = FPR2I(r1); i3 = FPR2I(r3); /* Get the operands */ vfetch_lf(&fl2, effective_addr2, b2, regs ); get_lf(&fl3, regs->fpr + i3); /* Calculate intermediate result */ ARCH_DEP(mul_lf_to_ef_unnorm)(&fl2, &fl3, &fx1); /* Place high-order part of result in register */ ARCH_DEP(store_ef_unnorm_hi)(&fx1, regs->fpr + i1); } /* end DEF_INST(multiply_unnormal_float_long_to_ext_high) */ #endif /*defined(FEATURE_HFP_UNNORMALIZED_EXTENSION)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* ED64 LEY - Load Floating Point Short (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_float_short_y) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Update first 32 bits of register from operand address */ regs->fpr[i1] = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); } /* end DEF_INST(load_float_short_y) */ /*-------------------------------------------------------------------*/ /* ED65 LDY - Load Floating Point Long (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_float_long_y) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word workarea */ RXY(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Fetch value from operand address */ dreg = ARCH_DEP(vfetch8) (effective_addr2, b2, regs); /* Update register contents */ regs->fpr[i1] = dreg >> 32; regs->fpr[i1+1] = dreg; } /* end DEF_INST(load_float_long_y) */ /*-------------------------------------------------------------------*/ /* ED66 STEY - Store Floating Point Short (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_float_short_y) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Store register contents at operand address */ ARCH_DEP(vstore4) (regs->fpr[i1], effective_addr2, b2, regs); } /* end DEF_INST(store_float_short_y) */ /*-------------------------------------------------------------------*/ /* ED67 STDY - Store Floating Point Long (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_float_long_y) { int r1; /* Value of R field */ int i1; /* Index of R1 in fpr array */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 dreg; /* Double word workarea */ RXY(inst, regs, r1, b2, effective_addr2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Store register contents at operand address */ dreg = ((U64)regs->fpr[i1] << 32) | regs->fpr[i1+1]; ARCH_DEP(vstore8) (dreg, effective_addr2, b2, regs); } /* end DEF_INST(store_float_long_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #endif /* FEATURE_HEXADECIMAL_FLOATING_POINT */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "float.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "float.c" #endif #endif /*!defined(_GEN_ARCH)*/ /* end of float.c */ hercules-3.12/trace.c0000664000175000017500000011603412564723224011452 00000000000000/* TRACE.C (c) Copyright Jan Jaeger, 2000-2009 */ /* Implicit tracing functions */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* This module contains procedures for creating entries in the */ /* system trace table as described in the manuals: */ /* SA22-7201 ESA/390 Principles of Operation */ /* SA22-7832 z/Architecture Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* ASN-and-LX-reuse facility - Roger Bowler July 2004*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_TRACE_C_) #define _TRACE_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_TRACING) #if !defined(_TRACE_H) #define _TRACE_H /*-------------------------------------------------------------------*/ /* Format definitions for trace table entries */ /*-------------------------------------------------------------------*/ typedef struct _TRACE_F1_BR { FWORD newia24; /* Bits 0-7 are zeros */ } TRACE_F1_BR; typedef struct _TRACE_F2_BR { FWORD newia31; /* Bit 0 is one */ } TRACE_F2_BR; typedef struct _TRACE_F3_BR { BYTE format; /* B'01010010' */ #define TRACE_F3_BR_FMT 0x52 BYTE fmt2; /* B'1100' B'0000' */ #define TRACE_F3_BR_FM2 0xC0 HWORD resv; DBLWRD newia64; } TRACE_F3_BR; typedef struct _TRACE_F1_BSG { BYTE format; /* B'01000001' */ #define TRACE_F1_BSG_FMT 0x41 BYTE alet[3]; FWORD newia; } TRACE_F1_BSG; typedef struct _TRACE_F2_BSG { BYTE format; /* B'01000010' */ #define TRACE_F2_BSG_FMT 0x42 BYTE alet[3]; DBLWRD newia; } TRACE_F2_BSG; typedef struct _TRACE_F1_MS { BYTE format; #define TRACE_F1_MS_FMT 0x51 BYTE fmt2; #define TRACE_F1_MS_FM2 0x30 HWORD resv; FWORD newia; } TRACE_F1_MS; typedef struct _TRACE_F2_MS { BYTE format; #define TRACE_F2_MS_FMT 0x51 BYTE fmt2; #define TRACE_F2_MS_FM2 0x20 HWORD resv; FWORD newia; } TRACE_F2_MS; typedef struct _TRACE_F3_MS { BYTE format; #define TRACE_F3_MS_FMT 0x52 BYTE fmt2; #define TRACE_F3_MS_FM2 0x60 HWORD resv; DBLWRD newia; } TRACE_F3_MS; typedef struct _TRACE_F1_MSB { BYTE format; #define TRACE_F1_MSB_FMT 0x51 BYTE fmt2; #define TRACE_F1_MSB_FM2 0xA0 HWORD resv; FWORD newia; } TRACE_F1_MSB; typedef struct _TRACE_F2_MSB { BYTE format; #define TRACE_F2_MSB_FMT 0x51 BYTE fmt2; #define TRACE_F2_MSB_FM2 0xB0 HWORD resv; FWORD newia; } TRACE_F2_MSB; typedef struct _TRACE_F3_MSB { BYTE format; #define TRACE_F3_MSB_FMT 0x52 BYTE fmt2; #define TRACE_F3_MSB_FM2 0xF0 HWORD resv; DBLWRD newia; } TRACE_F3_MSB; typedef struct _TRACE_F1_PT { BYTE format; #define TRACE_F1_PT_FMT 0x31 BYTE pswkey; #define TRACE_F1_PT_FM2 0x00 HWORD newpasn; FWORD r2; } TRACE_F1_PT; typedef struct _TRACE_F2_PT { BYTE format; #define TRACE_F2_PT_FMT 0x31 BYTE pswkey; #define TRACE_F2_PT_FM2 0x08 HWORD newpasn; FWORD r2; } TRACE_F2_PT; typedef struct _TRACE_F3_PT { BYTE format; #define TRACE_F3_PT_FMT 0x32 BYTE pswkey; #define TRACE_F3_PT_FM2 0x0C HWORD newpasn; DBLWRD r2; } TRACE_F3_PT; typedef struct _TRACE_F1_SSAR { BYTE format; #define TRACE_F1_SSAR_FMT 0x10 BYTE extfmt; HWORD newsasn; } TRACE_F1_SSAR; typedef struct _TRACE_F1_TRACE { BYTE format; BYTE zero; HWORD tod1631; FWORD tod3263; FWORD operand; FWORD regs[16]; } TRACE_F1_TRACE; typedef struct _TRACE_F2_TRACE { BYTE format; BYTE extfmt; HWORD tod1631; DBLWRD tod3279; FWORD operand; DBLWRD regs[16]; } TRACE_F2_TRACE; typedef struct _TRACE_F1_PR { BYTE format; #define TRACE_F1_PR_FMT 0x32 BYTE pswkey; #define TRACE_F1_PR_FM2 0x00 HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F1_PR; typedef struct _TRACE_F2_PR { BYTE format; #define TRACE_F2_PR_FMT 0x32 BYTE pswkey; #define TRACE_F2_PR_FM2 0x02 HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F2_PR; typedef struct _TRACE_F3_PR { BYTE format; #define TRACE_F3_PR_FMT 0x33 BYTE pswkey; #define TRACE_F3_PR_FM2 0x03 HWORD newpasn; FWORD retna; DBLWRD newia; } TRACE_F3_PR; typedef struct _TRACE_F4_PR { BYTE format; #define TRACE_F4_PR_FMT 0x32 BYTE pswkey; #define TRACE_F4_PR_FM2 0x08 HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F4_PR; typedef struct _TRACE_F5_PR { BYTE format; #define TRACE_F5_PR_FMT 0x32 BYTE pswkey; #define TRACE_F5_PR_FM2 0x0A HWORD newpasn; FWORD retna; FWORD newia; } TRACE_F5_PR; typedef struct _TRACE_F6_PR { BYTE format; #define TRACE_F6_PR_FMT 0x33 BYTE pswkey; #define TRACE_F6_PR_FM2 0x0B HWORD newpasn; FWORD retna; DBLWRD newia; } TRACE_F6_PR; typedef struct _TRACE_F7_PR { BYTE format; #define TRACE_F7_PR_FMT 0x33 BYTE pswkey; #define TRACE_F7_PR_FM2 0x0C HWORD newpasn; DBLWRD retna; FWORD newia; } TRACE_F7_PR; typedef struct _TRACE_F8_PR { BYTE format; #define TRACE_F8_PR_FMT 0x33 BYTE pswkey; #define TRACE_F8_PR_FM2 0x0E HWORD newpasn; DBLWRD retna; FWORD newia; } TRACE_F8_PR; typedef struct _TRACE_F9_PR { BYTE format; #define TRACE_F9_PR_FMT 0x34 BYTE pswkey; #define TRACE_F9_PR_FM2 0x0F HWORD newpasn; DBLWRD retna; DBLWRD newia; } TRACE_F9_PR; typedef struct _TRACE_F1_PC { BYTE format; #define TRACE_F1_PC_FMT 0x21 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; FWORD retna; } TRACE_F1_PC; typedef struct _TRACE_F2_PC { BYTE format; #define TRACE_F2_PC_FMT 0x22 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; DBLWRD retna; } TRACE_F2_PC; typedef struct _TRACE_F3_PC { BYTE format; #define TRACE_F3_PC_FMT 0x21 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; FWORD retna; } TRACE_F3_PC; typedef struct _TRACE_F4_PC { BYTE format; #define TRACE_F4_PC_FMT 0x22 BYTE pswkey_pcnum_hi; HWORD pcnum_lo; DBLWRD retna; } TRACE_F4_PC; typedef struct _TRACE_F5_PC { BYTE format; #define TRACE_F5_PC_FMT 0x22 BYTE pswkey; #define TRACE_F5_PC_FM2 0x08 HWORD resv; FWORD retna; FWORD pcnum; } TRACE_F5_PC; typedef struct _TRACE_F6_PC { BYTE format; #define TRACE_F6_PC_FMT 0x22 BYTE pswkey; #define TRACE_F6_PC_FM2 0x0A HWORD resv; FWORD retna; FWORD pcnum; } TRACE_F6_PC; typedef struct _TRACE_F7_PC { BYTE format; #define TRACE_F7_PC_FMT 0x23 BYTE pswkey; #define TRACE_F7_PC_FM2 0x0E HWORD resv; DBLWRD retna; FWORD pcnum; } TRACE_F7_PC; typedef struct _TRACE_F1_TR { BYTE format; #define TRACE_F1_TR_FMT 0x70 BYTE fmt2; #define TRACE_F1_TR_FM2 0x00 HWORD clk16; FWORD clk32; FWORD operand; FWORD reg[16]; } TRACE_F1_TR; typedef struct _TRACE_F2_TR { BYTE format; #define TRACE_F2_TR_FMT 0x70 BYTE fmt2; #define TRACE_F2_TR_FM2 0x80 HWORD clk0; FWORD clk16; FWORD clk48; FWORD operand; DBLWRD reg[16]; } TRACE_F2_TR; #endif /*!defined(_TRACE_H)*/ /*-------------------------------------------------------------------*/ /* Reserve space for a new trace entry */ /* */ /* Input: */ /* size Number of bytes required for trace entry */ /* regs Pointer to the CPU register context */ /* Output: */ /* abs_guest Guest absolute address of trace entry (if SIE) */ /* Return value: */ /* Absolute address of new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ static inline RADR ARCH_DEP(get_trace_entry) (RADR *abs_guest, int size, REGS *regs) { RADR n; /* Addr of trace table entry */ /* Obtain the trace entry address from control register 12 */ n = regs->CR(12) & CR12_TRACEEA; /* Apply low-address protection to trace entry address */ if (ARCH_DEP(is_low_address_protected) (n, regs)) { #ifdef FEATURE_SUPPRESSION_ON_PROTECTION regs->TEA = (n & STORAGE_KEY_PAGEMASK); regs->excarid = 0; #endif /*FEATURE_SUPPRESSION_ON_PROTECTION*/ ARCH_DEP(program_interrupt) (regs, PGM_PROTECTION_EXCEPTION); } /* Program check if trace entry is outside main storage */ if ( n > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Program check if storing would overflow a 4K page boundary */ if ( ((n + size) & PAGEFRAME_PAGEMASK) != (n & PAGEFRAME_PAGEMASK) ) ARCH_DEP(program_interrupt) (regs, PGM_TRACE_TABLE_EXCEPTION); /* Convert trace entry real address to absolute address */ n = APPLY_PREFIXING (n, regs->PX); #if defined(_FEATURE_SIE) *abs_guest = n; SIE_TRANSLATE(&n, ACCTYPE_WRITE, regs); #endif /*defined(_FEATURE_SIE)*/ return n; } /* end function ARCH_DEP(get_trace_entry) */ /*-------------------------------------------------------------------*/ /* Commit a new trace entry */ /* */ /* Input: */ /* abs_guest Guest absolute address of trace entry (if SIE) */ /* raddr Absolute address of trace entry */ /* size Number of bytes reserved for trace entry */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after committing the trace entry */ /*-------------------------------------------------------------------*/ static inline CREG ARCH_DEP(set_trace_entry) (RADR abs_guest, RADR raddr, int size, REGS *regs) { #if defined(_FEATURE_SIE) RADR abs_host; abs_host = raddr; #endif /*defined(_FEATURE_SIE)*/ raddr += size; #if defined(_FEATURE_SIE) /* Recalculate the Guest absolute address */ raddr = abs_guest + (raddr - abs_host); #endif /*defined(_FEATURE_SIE)*/ /* Convert trace entry absolute address back to real address */ raddr = APPLY_PREFIXING (raddr, regs->PX); /* Return updated value of control register 12 */ return (regs->CR(12) & ~CR12_TRACEEA) | raddr; } /* end function ARCH_DEP(set_trace_entry) */ /*-------------------------------------------------------------------*/ /* Form implicit branch trace entry */ /* */ /* Input: */ /* amode Non-zero if branch destination is a 31-bit address */ /* or a 64 bit address */ /* ia Branch destination address */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_br) (int amode, VADR ia, REGS *regs) { RADR raddr; RADR ag; int size; #if defined(FEATURE_ESAME) if(amode && ia > 0xFFFFFFFFULL) { TRACE_F3_BR *tte; size = sizeof(TRACE_F3_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_BR_FMT; tte->fmt2 = TRACE_F3_BR_FM2; STORE_HW(tte->resv,0); STORE_DW(tte->newia64,ia); } else #endif /*defined(FEATURE_ESAME)*/ if(amode) { TRACE_F2_BR *tte; size = sizeof(TRACE_F2_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); STORE_FW(tte->newia31,ia | 0x80000000); } else { TRACE_F1_BR *tte; size = sizeof(TRACE_F1_BR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); STORE_FW(tte->newia24,ia & 0x00FFFFFF); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_br) */ #if defined(FEATURE_SUBSPACE_GROUP) /*-------------------------------------------------------------------*/ /* Form implicit BSG trace entry */ /* */ /* Input: */ /* alet Destination address space ALET */ /* ia Branch destination address */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_bsg) (U32 alet, VADR ia, REGS *regs) { RADR raddr; RADR ag; int size; #if defined(FEATURE_ESAME) if(regs->psw.amode64) { TRACE_F2_BSG *tte; size = sizeof(TRACE_F2_BSG); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_BSG_FMT; tte->alet[0] = (alet >> 16) & 0xFF; tte->alet[1] = (alet >> 8) & 0xFF; tte->alet[2] = alet & 0xFF; STORE_DW(tte->newia,ia); } else #endif /*defined(FEATURE_ESAME)*/ { TRACE_F1_BSG *tte; size = sizeof(TRACE_F1_BSG); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_BSG_FMT; tte->alet[0] = ((alet >> 17) & 0x80) | ((alet >> 16) & 0x7F); tte->alet[1] = (alet >> 8) & 0xFF; tte->alet[2] = alet & 0xFF; if ((ia & 0x80000000) == 0) ia &=0x00FFFFFF; STORE_FW(tte->newia,ia); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_bsg) */ #endif /*defined(FEATURE_SUBSPACE_GROUP)*/ /*-------------------------------------------------------------------*/ /* Form implicit SSAR/SSAIR trace entry */ /* */ /* Input: */ /* ssair 1=SSAIR instruction, 0=SSAR instruction */ /* sasn Secondary address space number */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_ssar) (int ssair, U16 sasn, REGS *regs) { RADR raddr; RADR ag; int size; BYTE nbit = (ssair ? 1 : 0); { TRACE_F1_SSAR *tte; size = sizeof(TRACE_F1_SSAR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_SSAR_FMT; tte->extfmt = 0 | nbit; STORE_HW(tte->newsasn,sasn); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_ssar) */ /*-------------------------------------------------------------------*/ /* Form implicit PC trace entry */ /* */ /* Input: */ /* pcea PC instruction effective address (20 or 32 bits) */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_pc) (U32 pcea, REGS *regs) { RADR raddr; RADR ag; int size; int eamode; SET_PSW_IA(regs); eamode = regs->psw.amode64; #if defined(FEATURE_ESAME) if (ASN_AND_LX_REUSE_ENABLED(regs)) { if ((pcea & PC_BIT44) && regs->psw.amode64 && regs->psw.IA_H) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled, 32-bit PC number is used, and bits 0-31 of return address are not all zeros */ TRACE_F7_PC *tte; size = sizeof(TRACE_F7_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F7_PC_FMT; tte->pswkey = regs->psw.pkey | TRACE_F7_PC_FM2 | eamode; STORE_HW(tte->resv, 0x0000); STORE_DW(tte->retna, regs->psw.IA_G | PROBSTATE(®s->psw)); STORE_FW(tte->pcnum, pcea); } else if ((pcea & PC_BIT44) && regs->psw.amode64) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled, 32-bit PC number is used, and bits 0-31 of return address are all zeros */ TRACE_F6_PC *tte; size = sizeof(TRACE_F6_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F6_PC_FMT; tte->pswkey = regs->psw.pkey | TRACE_F6_PC_FM2 | eamode; STORE_HW(tte->resv, 0x0000); STORE_FW(tte->retna, regs->psw.IA_L | PROBSTATE(®s->psw)); STORE_FW(tte->pcnum, pcea); } else if ((pcea & PC_BIT44)) { /* In 24-bit or 31-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled and 32-bit PC number is used */ TRACE_F5_PC *tte; size = sizeof(TRACE_F5_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F5_PC_FMT; tte->pswkey = regs->psw.pkey | TRACE_F5_PC_FM2 | eamode; STORE_HW(tte->resv, 0x0000); STORE_FW(tte->retna, (regs->psw.amode << 31) | regs->psw.IA_L | PROBSTATE(®s->psw)); STORE_FW(tte->pcnum, pcea); } else if(regs->psw.amode64) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled and 20-bit PC number is used */ TRACE_F4_PC *tte; size = sizeof(TRACE_F4_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F4_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_DW(tte->retna, regs->psw.IA_G | PROBSTATE(®s->psw)); } else { /* In 24-bit or 31-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is enabled and 20-bit PC number is used */ TRACE_F3_PC *tte; size = sizeof(TRACE_F3_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_FW(tte->retna, (regs->psw.amode << 31) | regs->psw.IA_L | PROBSTATE(®s->psw)); } } /* end ASN_AND_LX_REUSE_ENABLED */ else if(regs->psw.amode64) { /* In 64-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is not enabled */ TRACE_F2_PC *tte; size = sizeof(TRACE_F2_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_DW(tte->retna, regs->psw.IA_G | PROBSTATE(®s->psw)); } else #endif /*defined(FEATURE_ESAME)*/ { /* In 24-bit or 31-bit mode, regardless of resulting mode, when ASN-and-LX-reuse is not enabled */ TRACE_F1_PC *tte; size = sizeof(TRACE_F1_PC); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_PC_FMT; tte->pswkey_pcnum_hi = regs->psw.pkey | ((pcea & 0xF0000) >> 16); STORE_HW(tte->pcnum_lo, pcea & 0x0FFFF); STORE_FW(tte->retna, (regs->psw.amode << 31) | regs->psw.IA_L | PROBSTATE(®s->psw)); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_pc) */ #if defined(_MSVC_) /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */ #pragma optimize("",off) #endif /*defined(_MSVC_)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* Form implicit PR trace entry */ /* */ /* Input: */ /* newregs Pointer to registers after PR instruction */ /* regs Pointer to registers before PR instruction */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_pr) (REGS *newregs, REGS *regs) { RADR raddr; RADR ag; int size; SET_PSW_IA(regs); SET_PSW_IA(newregs); #if defined(FEATURE_ESAME) if(!regs->psw.amode64 && !newregs->psw.amode64) #endif /*defined(FEATURE_ESAME)*/ { TRACE_F1_PR *tte; size = sizeof(TRACE_F1_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F1_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, (newregs->psw.amode << 31) | newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, (regs->psw.amode << 31) | regs->psw.IA_L); } #if defined(FEATURE_ESAME) else if(regs->psw.amode64 && regs->psw.IA_H == 0 && !newregs->psw.amode64) { TRACE_F2_PR *tte; size = sizeof(TRACE_F2_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F2_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, (newregs->psw.amode << 31) | newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H != 0 && !newregs->psw.amode64) { TRACE_F3_PR *tte; size = sizeof(TRACE_F3_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F3_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, (newregs->psw.amode << 31) | newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_DW(tte->newia, regs->psw.IA_G); } else if(!regs->psw.amode64 && newregs->psw.amode64 && newregs->psw.IA_H == 0) { TRACE_F4_PR *tte; size = sizeof(TRACE_F4_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F4_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F4_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, (regs->psw.amode << 31) | regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H == 0 && newregs->psw.amode64 && newregs->psw.IA_H == 0) { TRACE_F5_PR *tte; size = sizeof(TRACE_F5_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F5_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F5_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H != 0 && newregs->psw.amode64 && newregs->psw.IA_H == 0) { TRACE_F6_PR *tte; size = sizeof(TRACE_F6_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F6_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F6_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_FW(tte->retna, newregs->psw.IA_L | PROBSTATE(&newregs->psw)); STORE_DW(tte->newia, regs->psw.IA_G); } else if(!regs->psw.amode64 && newregs->psw.amode64 && newregs->psw.IA_H != 0) { TRACE_F7_PR *tte; size = sizeof(TRACE_F7_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F7_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F7_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_DW(tte->retna, newregs->psw.IA_G | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, (regs->psw.amode << 31) | regs->psw.IA_L); } else if(regs->psw.amode64 && regs->psw.IA_H == 0 && newregs->psw.amode64 && newregs->psw.IA_H != 0) { TRACE_F8_PR *tte; size = sizeof(TRACE_F8_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F8_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F8_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_DW(tte->retna, newregs->psw.IA_G | PROBSTATE(&newregs->psw)); STORE_FW(tte->newia, regs->psw.IA_L); } else /* if(regs->psw.amode64 && regs->psw.IA_H != 0 && newregs->psw.amode64 && newregs->psw.IA_H != 0) */ { TRACE_F9_PR *tte; size = sizeof(TRACE_F9_PR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F9_PR_FMT; tte->pswkey = regs->psw.pkey | TRACE_F9_PR_FM2; STORE_HW(tte->newpasn, newregs->CR_LHL(4)); STORE_DW(tte->retna, newregs->psw.IA_G | PROBSTATE(&newregs->psw)); STORE_DW(tte->newia, regs->psw.IA_G); } #endif /*defined(FEATURE_ESAME)*/ return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_pr) */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(_MSVC_) /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */ #pragma optimize("",on) #endif /*defined(_MSVC_)*/ /*-------------------------------------------------------------------*/ /* Form implicit PT/PTI trace entry */ /* */ /* Input: */ /* pti 1=PTI instruction, 0=PT instruction */ /* pasn Primary address space number */ /* gpr2 Contents of PT second operand register */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_pt) (int pti, U16 pasn, GREG gpr2, REGS *regs) { RADR raddr; RADR ag; int size; BYTE nbit = (pti ? 1 : 0); #if defined(FEATURE_ESAME) if(regs->psw.amode64 && gpr2 > 0xFFFFFFFFULL) { TRACE_F3_PT *tte; size = sizeof(TRACE_F3_PT); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_PT_FMT; tte->pswkey = regs->psw.pkey | TRACE_F3_PT_FM2 | nbit; STORE_HW(tte->newpasn, pasn); STORE_DW(tte->r2, gpr2); } else if(regs->psw.amode64) { TRACE_F2_PT *tte; size = sizeof(TRACE_F2_PT); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_PT_FMT; tte->pswkey = regs->psw.pkey | TRACE_F2_PT_FM2 | nbit; STORE_HW(tte->newpasn, pasn); STORE_FW(tte->r2, gpr2 & 0xFFFFFFFF); } else #endif /*defined(FEATURE_ESAME)*/ { TRACE_F1_PT *tte; size = sizeof(TRACE_F1_PT); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_PT_FMT; tte->pswkey = regs->psw.pkey | TRACE_F1_PT_FM2 | nbit; STORE_HW(tte->newpasn, pasn); STORE_FW(tte->r2, gpr2 & 0xFFFFFFFF); } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_pt) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* Form implicit MS trace entry */ /* */ /* Input: */ /* br Mode switch branch indicator */ /* baddr Branch address for mode switch branch */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_ms) (int br, VADR baddr, REGS *regs) { RADR raddr; RADR ag; int size; SET_PSW_IA(regs); if(!br) { if(!regs->psw.amode64) { TRACE_F1_MS *tte; size = sizeof(TRACE_F1_MS); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_MS_FMT; tte->fmt2 = TRACE_F1_MS_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, regs->psw.IA | (regs->psw.amode << 31)); } else if(regs->psw.amode64 && regs->psw.IA <= 0x7FFFFFFF) { TRACE_F2_MS *tte; size = sizeof(TRACE_F2_MS); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_MS_FMT; tte->fmt2 = TRACE_F2_MS_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, regs->psw.IA); } else { TRACE_F3_MS *tte; size = sizeof(TRACE_F3_MS); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_MS_FMT; tte->fmt2 = TRACE_F3_MS_FM2; STORE_HW(tte->resv, 0); STORE_DW(tte->newia, regs->psw.IA); } } else { /* if currently in 64-bit, we are switching out */ if(regs->psw.amode64) { TRACE_F1_MSB *tte; size = sizeof(TRACE_F1_MSB); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F1_MSB_FMT; tte->fmt2 = TRACE_F1_MSB_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, baddr); } else if(!regs->psw.amode64 && baddr <= 0x7FFFFFFF) { TRACE_F2_MSB *tte; size = sizeof(TRACE_F2_MSB); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F2_MSB_FMT; tte->fmt2 = TRACE_F2_MSB_FM2; STORE_HW(tte->resv, 0); STORE_FW(tte->newia, baddr); } else { TRACE_F3_MSB *tte; size = sizeof(TRACE_F3_MSB); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); tte->format = TRACE_F3_MSB_FMT; tte->fmt2 = TRACE_F3_MSB_FM2; STORE_HW(tte->resv, 0); STORE_DW(tte->newia, baddr); } } return ARCH_DEP(set_trace_entry) (ag, raddr, size, regs); } /* end function ARCH_DEP(trace_ms) */ #endif /*defined(FEATURE_ESAME)*/ /*-------------------------------------------------------------------*/ /* Form explicit TRACE trace entry */ /* */ /* Input: */ /* r1, r3 registers identifying register space to be written */ /* op Trace operand */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_tr) (int r1, int r3, U32 op, REGS *regs) { RADR raddr; RADR ag; int size; int i, j, n; U64 dreg; { TRACE_F1_TR *tte; size = sizeof(TRACE_F1_TR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); /* Calculate the number of registers to be traced, minus 1 */ n = ( r3 < r1 ) ? r3 + 16 - r1 : r3 - r1; /* Retrieve the TOD clock value and shift out the epoch */ dreg = (tod_clock(regs) << 8) | regs->cpuad; tte->format = TRACE_F1_TR_FMT | n; tte->fmt2 = TRACE_F1_TR_FM2; STORE_HW(tte->clk16, (dreg >> 32) & 0xFFFF); STORE_FW(tte->clk32, dreg & 0xFFFFFFFF); STORE_FW(tte->operand, op); for(i = r1, j = 0; ; ) { STORE_FW(tte->reg[j++], regs->GR_L(i)); /* Regdump is complete when r3 is done */ if(r3 == i) break; /* Update register number and wrap */ i++; i &= 15; } } return ARCH_DEP(set_trace_entry) (ag, raddr, size - (4 * (15 - n)), regs); } /* end function ARCH_DEP(trace_tr) */ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* Form explicit TRACG trace entry */ /* */ /* Input: */ /* r1, r3 registers identifying register space to be written */ /* op Trace operand */ /* regs Pointer to the CPU register context */ /* Return value: */ /* Updated value for CR12 after adding new trace entry */ /* */ /* This function does not return if a program check occurs. */ /*-------------------------------------------------------------------*/ CREG ARCH_DEP(trace_tg) (int r1, int r3, U32 op, REGS *regs) { RADR raddr; RADR ag; int size; int i, j, n; U64 dreg; { TRACE_F2_TR *tte; size = sizeof(TRACE_F2_TR); raddr = ARCH_DEP(get_trace_entry) (&ag, size, regs); tte = (void*)(regs->mainstor + raddr); /* Calculate the number of registers to be traced, minus 1 */ n = ( r3 < r1 ) ? r3 + 16 - r1 : r3 - r1; /* Retrieve the TOD clock value including the epoch */ dreg = tod_clock(regs); tte->format = TRACE_F2_TR_FMT | n; tte->fmt2 = TRACE_F2_TR_FM2; STORE_HW(tte->clk0, (dreg >> 48) & 0xFFFF); /* shift out the epoch */ dreg = (dreg << 8) | regs->cpuad; STORE_FW(tte->clk16, (dreg >> 32) & 0xFFFFFFFF); STORE_FW(tte->clk48, dreg & 0xFFFFFFFF); STORE_FW(tte->operand, op); for(i = r1, j = 0; ; ) { STORE_DW(tte->reg[j++], regs->GR_G(i)); /* Regdump is complete when r3 is done */ if(r3 == i) break; /* Update register number and wrap */ i++; i &= 15; } } return ARCH_DEP(set_trace_entry) (ag, raddr, size - (8 * (15 - n)), regs); } /* end function ARCH_DEP(trace_tg) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_TRACING)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "trace.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "trace.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/machchk.c0000664000175000017500000003146012564723224011751 00000000000000/* MACHCHK.C (c) Copyright Jan Jaeger, 2000-2009 */ /* ESA/390 Machine Check Functions */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ /* The machine check function supports dynamic I/O configuration. */ /* When a subchannel is added/changed/deleted an ancillary */ /* channel report is made pending. This ancillary channel */ /* report can be read by the store channel report word I/O */ /* instruction. Changes to the availability will result in */ /* Messages IOS150I and IOS151I (device xxxx now/not available) */ /* Added Instruction processing damage machine check function such */ /* that abends/waits/loops in instructions will be reflected to the */ /* system running under hercules as a machine malfunction. This */ /* includes the machine check, checkstop, and malfunction alert */ /* external interrupt as defined in the architecture. - 6/8/01 *JJ */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_MACHCHK_C_) #define _MACHCHK_C_ #endif #include "hercules.h" #include "opcode.h" #if !defined(_MACHCHK_C) #define _MACHCHK_C /*-------------------------------------------------------------------*/ /* Return pending channel report */ /* */ /* Returns zero if no device has CRW pending. Otherwise returns */ /* the channel report word for the first channel path or device */ /* which has a CRW pending, and resets the CRW for that device. */ /*-------------------------------------------------------------------*/ U32 channel_report(REGS *regs) { DEVBLK *dev; U32 i,j; /* Scan for channel path reset CRW's */ for(i = 0; i < 8; i++) { if(sysblk.chp_reset[i]) { OBTAIN_INTLOCK(regs); for(j = 0; j < 32; j++) { if(sysblk.chp_reset[i] & (0x80000000 >> j)) { sysblk.chp_reset[i] &= ~(0x80000000 >> j); RELEASE_INTLOCK(regs); return CRW_SOL | CRW_CHPID | CRW_AR | CRW_INIT | ((i*32)+j); } } RELEASE_INTLOCK(regs); } } /* Scan for subchannel alert CRW's */ for(dev = sysblk.firstdev; dev!= NULL; dev = dev->nextdev) { if(dev->crwpending) { obtain_lock(&dev->lock); if(dev->crwpending) { dev->crwpending = 0; release_lock(&dev->lock); return CRW_SUBCH | CRW_AR | CRW_ALERT | dev->subchan; } release_lock(&dev->lock); } } return 0; } /* end function channel_report */ /*-------------------------------------------------------------------*/ /* Indicate crw pending */ /*-------------------------------------------------------------------*/ void machine_check_crwpend() { /* Signal waiting CPUs that an interrupt may be pending */ OBTAIN_INTLOCK(NULL); ON_IC_CHANRPT; WAKEUP_CPUS_MASK (sysblk.waiting_mask); RELEASE_INTLOCK(NULL); } /* end function machine_check_crwpend */ #endif /*!defined(_MACHCHK_C)*/ /*-------------------------------------------------------------------*/ /* Present Machine Check Interrupt */ /* Input: */ /* regs Pointer to the CPU register context */ /* Output: */ /* mcic Machine check interrupt code */ /* xdmg External damage code */ /* fsta Failing storage address */ /* Return code: */ /* 0=No machine check, 1=Machine check presented */ /* */ /* Generic machine check function. At the momement the only */ /* supported machine check is the channel report. */ /* */ /* This routine must be called with the sysblk.intlock held */ /*-------------------------------------------------------------------*/ int ARCH_DEP(present_mck_interrupt)(REGS *regs, U64 *mcic, U32 *xdmg, RADR *fsta) { int rc = 0; UNREFERENCED_370(regs); UNREFERENCED_370(mcic); UNREFERENCED_370(xdmg); UNREFERENCED_370(fsta); #ifdef FEATURE_CHANNEL_SUBSYSTEM /* If there is a crw pending and we are enabled for the channel report interrupt subclass then process the interrupt */ if( OPEN_IC_CHANRPT(regs) ) { *mcic = MCIC_CP | MCIC_WP | MCIC_MS | MCIC_PM | MCIC_IA | #ifdef FEATURE_HEXADECIMAL_FLOATING_POINT MCIC_FP | #endif /*FEATURE_HEXADECIMAL_FLOATING_POINT*/ MCIC_GR | MCIC_CR | MCIC_ST | #ifdef FEATURE_ACCESS_REGISTERS MCIC_AR | #endif /*FEATURE_ACCESS_REGISTERS*/ #if defined(FEATURE_ESAME) && defined(FEATURE_EXTENDED_TOD_CLOCK) MCIC_PR | #endif /*defined(FEATURE_ESAME) && defined(FEATURE_EXTENDED_TOD_CLOCK)*/ #if defined(FEATURE_BINARY_FLOATING_POINT) MCIC_XF | #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ MCIC_AP | MCIC_CT | MCIC_CC ; *xdmg = 0; *fsta = 0; OFF_IC_CHANRPT; rc = 1; } if(!IS_IC_CHANRPT) #endif /*FEATURE_CHANNEL_SUBSYSTEM*/ OFF_IC_CHANRPT; return rc; } /* end function present_mck_interrupt */ void ARCH_DEP(sync_mck_interrupt) (REGS *regs) { int rc; /* Return code */ PSA *psa; /* -> Prefixed storage area */ U64 mcic = MCIC_P | /* Instruction processing damage */ MCIC_WP | MCIC_MS | MCIC_PM | MCIC_IA | #ifdef FEATURE_HEXADECIMAL_FLOATING_POINT MCIC_FP | #endif /*FEATURE_HEXADECIMAL_FLOATING_POINT*/ MCIC_GR | MCIC_CR | MCIC_ST | #ifdef FEATURE_ACCESS_REGISTERS MCIC_AR | #endif /*FEATURE_ACCESS_REGISTERS*/ #if defined(FEATURE_ESAME) && defined(FEATURE_EXTENDED_TOD_CLOCK) MCIC_PR | #endif /*defined(FEATURE_ESAME) && defined(FEATURE_EXTENDED_TOD_CLOCK)*/ #if defined(FEATURE_BINARY_FLOATING_POINT) MCIC_XF | #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ MCIC_CT | MCIC_CC ; U32 xdmg = 0; RADR fsta = 0; /* Release intlock if held */ if (regs->cpuad == sysblk.intowner) RELEASE_INTLOCK(regs); /* Release mainlock if held */ if (regs->cpuad == sysblk.mainowner) RELEASE_MAINLOCK(regs); /* Exit SIE when active */ #if defined(FEATURE_INTERPRETIVE_EXECUTION) if(regs->sie_active) ARCH_DEP(sie_exit) (regs, SIE_HOST_INTERRUPT); #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ /* Set the main storage reference and change bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Point to the PSA in main storage */ psa = (void*)(regs->mainstor + regs->PX); /* Store registers in machine check save area */ ARCH_DEP(store_status) (regs, regs->PX); #if !defined(FEATURE_ESAME) // ZZ /* Set the extended logout area to zeros */ memset(psa->storepsw, 0, 16); #endif /* Store the machine check interrupt code at PSA+232 */ STORE_DW(psa->mckint, mcic); /* Trace the machine check interrupt */ if (CPU_STEPPING_OR_TRACING(regs, 0)) logmsg (_("HHCCP019I Machine Check code=%16.16" I64_FMT "u\n"), (long long)mcic); /* Store the external damage code at PSA+244 */ STORE_FW(psa->xdmgcode, xdmg); #if defined(FEATURE_ESAME) /* Store the failing storage address at PSA+248 */ STORE_DW(psa->mcstorad, fsta); #else /*!defined(FEATURE_ESAME)*/ /* Store the failing storage address at PSA+248 */ STORE_FW(psa->mcstorad, fsta); #endif /*!defined(FEATURE_ESAME)*/ /* Store current PSW at PSA+X'30' */ ARCH_DEP(store_psw) ( regs, psa->mckold ); /* Load new PSW from PSA+X'70' */ rc = ARCH_DEP(load_psw) ( regs, psa->mcknew ); if ( rc ) ARCH_DEP(program_interrupt) (regs, rc); } /* end function sync_mck_interrupt */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "machchk.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "machchk.c" #endif #if !defined(NO_SIGABEND_HANDLER) void sigabend_handler (int signo) { REGS *regs = NULL; TID tid; int i; tid = thread_id(); if( signo == SIGUSR2 ) { DEVBLK *dev; if ( equal_threads( tid, sysblk.cnsltid ) || equal_threads( tid, sysblk.socktid ) || equal_threads( tid, sysblk.httptid ) ) return; for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if ( equal_threads( dev->tid, tid ) || equal_threads( dev->shrdtid, tid ) ) break; if( dev == NULL) { if (!sysblk.shutdown) logmsg(_("HHCCP020E signal USR2 received for " "undetermined device\n")); } else if(dev->ccwtrace) logmsg(_("HHCCP021E signal USR2 received for device " "%4.4X\n"),dev->devnum); return; } for (i = 0; i < MAX_CPU; i++) { if ( equal_threads( sysblk.cputid[i], tid ) ) { regs = sysblk.regs[i]; break; } } if (regs == NULL) { signal(signo, SIG_DFL); raise(signo); return; } if(MACHMASK(®s->psw)) { #if defined(_FEATURE_SIE) logmsg(_("HHCCP017I CPU%4.4X: Machine check due to host error: %s\n"), regs->sie_active ? regs->guestregs->cpuad : regs->cpuad, strsignal(signo)); #else /*!defined(_FEATURE_SIE)*/ logmsg(_("HHCCP017I CPU%4.4X: Machine check due to host error: %s\n"), regs->cpuad, strsignal(signo)); #endif /*!defined(_FEATURE_SIE)*/ display_inst( #if defined(_FEATURE_SIE) regs->sie_active ? regs->guestregs : #endif /*defined(_FEATURE_SIE)*/ regs, #if defined(_FEATURE_SIE) regs->sie_active ? regs->guestregs->ip : #endif /*defined(_FEATURE_SIE)*/ regs->ip); switch(regs->arch_mode) { #if defined(_370) case ARCH_370: s370_sync_mck_interrupt(regs); break; #endif #if defined(_390) case ARCH_390: s390_sync_mck_interrupt(regs); break; #endif #if defined(_900) case ARCH_900: z900_sync_mck_interrupt(regs); break; #endif } } else { #if defined(_FEATURE_SIE) logmsg(_("HHCCP018I CPU%4.4X: Check-Stop due to host error: %s\n"), regs->sie_active ? regs->guestregs->cpuad : regs->cpuad, strsignal(signo)); #else /*!defined(_FEATURE_SIE)*/ logmsg(_("HHCCP018I CPU%4.4X: Check-Stop due to host error: %s\n"), regs->cpuad, strsignal(signo)); #endif /*!defined(_FEATURE_SIE)*/ display_inst( #if defined(_FEATURE_SIE) regs->sie_active ? regs->guestregs : #endif /*defined(_FEATURE_SIE)*/ regs, #if defined(_FEATURE_SIE) regs->sie_active ? regs->guestregs->ip : #endif /*defined(_FEATURE_SIE)*/ regs->ip); regs->cpustate = CPUSTATE_STOPPING; regs->checkstop = 1; ON_IC_INTERRUPT(regs); /* Notify other CPU's by means of a malfuction alert if possible */ if (!try_obtain_lock(&sysblk.sigplock)) { if(!try_obtain_lock(&sysblk.intlock)) { for (i = 0; i < MAX_CPU; i++) if (i != regs->cpuad && IS_CPU_ONLINE(i)) { ON_IC_MALFALT(sysblk.regs[i]); sysblk.regs[i]->malfcpu[regs->cpuad] = 1; } release_lock(&sysblk.intlock); } release_lock(&sysblk.sigplock); } } longjmp (regs->progjmp, SIE_INTERCEPT_MCK); } #endif /*!defined(NO_SIGABEND_HANDLER)*/ #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/vector.c0000664000175000017500000006347612564723224011671 00000000000000/* VECTOR.C (c) Copyright Jan Jaeger, 1999-2009 */ /* S/370 and ESA/390 Vector Operations */ /*-------------------------------------------------------------------*/ /* This module implements the Vector Facility instruction execution */ /* function of the S/370 and ESA/390 architectures, as described in */ /* SA22-7125-03 Vector Operations (S/370 & ESA/370) */ /* SA22-7207-00 Vector Operations (ESA/390) */ /* 28/05/2000 Jan Jaeger */ /* */ /* Instruction decoding rework 09/07/2000 Jan Jaeger */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_VECTOR_FACILITY) /* The vector save area must be aligned on a boundary 8 times the section size, however VM stores at 4 times the section size. I do not know if the book or VM is wrong. *JJ */ #define VSA_ALIGN 4 /*-------------------------------------------------------------------*/ /* A640 VTVM - Test VMR [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_test_vmr) { int unused1, unused2; U32 n, n1; RRE(inst, regs, unused1, unused2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* cc0 when the vector count is zero */ if( n == 0) { regs->psw.cc = 0; return; } /* Preset condition code according to first bit */ regs->psw.cc = VMR_SET(0, regs) ? 3 : 0; /* Check VMR bit to be equal to the first, exit with cc1 if an unequal bit found */ for(n1 = 1; n1 < n; n1++) if((regs->psw.cc == 0) != (VMR_SET(n1, regs) == 0)) { regs->psw.cc = 1; return; } } /*-------------------------------------------------------------------*/ /* A641 VCVM - Complement VMR [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_complement_vmr) { int unused1, unused2; U32 n, n1, n2; RRE(inst, regs, unused1, unused2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* Bytes - 1 */ n1 = n >> 3; /* Complement VMR */ for(n2 = 0; n2 <= n1; n2++) regs->vf->vmr[n2] ^= 0xFF; /* zeroize remainder */ regs->vf->vmr[n1] &= 0x7F00 >> (n & 7); for(n1++; n1 < sizeof(regs->vf->vmr); n1++) regs->vf->vmr[n1] = 0; } /*-------------------------------------------------------------------*/ /* A642 VCZVM - Count Left Zeros in VMR [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_count_left_zeros_in_vmr) { int gr1, unused2; U32 n, n1; RRE(inst, regs, gr1, unused2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* cc0 when the vector count is zero */ if( n == 0) { regs->psw.cc = 0; return; } /* Preset condition code according to first bit */ regs->psw.cc = VMR_SET(0, regs) ? 3 : 0; /* If the VCT is 1 and the first bit is one then exit wirh gr1 set to zero */ regs->GR_L(gr1) = 0; if(n == 1 && VMR_SET(0, regs)) return; /* Count left zeros, set cc1 and exit if a one is found */ regs->GR_L(gr1) = 1; for(n1 = 1; n1 < n; n1++) { if(!VMR_SET(n1, regs)) regs->GR_L(gr1)++; else { regs->psw.cc = 1; return; } } } /*-------------------------------------------------------------------*/ /* A643 VCOVM - Count Ones In VMR [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_count_ones_in_vmr) { int gr1, unused2; U32 n, n1; RRE(inst, regs, gr1, unused2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* cc0 when the vector count is zero */ if( n == 0) { regs->psw.cc = 0; return; } /* Preset condition code according to first bit */ regs->psw.cc = VMR_SET(0, regs) ? 3 : 0; /* Check VMR bit to be equal to the first, Count all ones, set cc1 if a bit is unequal */ regs->GR_L(gr1) = 0; for(n1 = 0; n1 < n; n1++) { if(VMR_SET(n1, regs)) { regs->GR_L(gr1)++; if(!VMR_SET(0, regs)) regs->psw.cc = 1; } else if(VMR_SET(0, regs)) regs->psw.cc = 1; } } /*-------------------------------------------------------------------*/ /* A644 VXVC - Exctract VCT [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_extract_vct) { int gr1, unused2; RRE(inst, regs, gr1, unused2); VOP_CHECK(regs); regs->GR_L(gr1) = VECTOR_COUNT(regs); } /*-------------------------------------------------------------------*/ /* A646 VXVMM - Extract Vector Modes [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_extract_vector_modes) { int gr1, unused2; RRE(inst, regs, gr1, unused2); VOP_CHECK(regs); regs->GR_L(gr1) = (regs->vf->vsr >> 48); } /*-------------------------------------------------------------------*/ /* A648 VRRS - Restore VR [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_restore_vr) { int gr1, unused2; U32 n, n1, n2; U64 d; RRE(inst, regs, gr1, unused2); VOP_CHECK(regs); ODD_CHECK(gr1, regs); /* n contrains the current save area address */ n = regs->GR_L(gr1) & ADDRESS_MAXWRAP(regs); /* n1 contains the starting element number */ if((n1 = regs->GR_L(gr1 + 1) >> 16) >= VECTOR_SECTION_SIZE) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Starting address must be eight times the section size aligned */ if((n - (8 * n1)) & ((VECTOR_SECTION_SIZE * VSA_ALIGN) - 1) ) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* n2 contains VR pair, which must be an even reg */ if((n2 = regs->GR_L(gr1 + 1) & 0x0000FFFF) & 0x0000FFF1) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); if( VR_INUSE(n2, regs) ) { /* Set the vector changed bit if in problem state */ if( PROBSTATE(®s->psw) ) SET_VR_CHANGED(n2, regs); for(; n1 < VECTOR_SECTION_SIZE; n1++) { /* Fetch vr pair from central storage */ d = ARCH_DEP(vfetch8)(n, gr1, regs); regs->vf->vr[n2][n1] = d >> 32; regs->vf->vr[n2+1][n1] = d; /* Increment element number */ n1++; regs->GR_L(gr1 + 1) &= 0x0000FFFF; regs->GR_L(gr1 + 1) |= n1 << 16; /* Update savearea address */ regs->GR_L(gr1) += 8; #if 0 /* This is where the instruction may be interrupted */ UPD_PSW_IA(regs, PSW_IA(regs, -4)); return; #endif } /* Indicate vr pair restored */ regs->psw.cc = 2; } else { regs->GR_L(gr1) += 8 * (VECTOR_SECTION_SIZE - n1); /* indicate v2 pair not restored */ regs->psw.cc = 0; } /* Set 2 if vr 14 is restored, 0 if not restored, 3 and 1 for other VR's respectively */ if(n2 != 14) regs->psw.cc++; /* Update the vector pair number, and zero element number */ n2 += 2; regs->GR_L(gr1 + 1) = n2; } /*-------------------------------------------------------------------*/ /* A649 VRSVC - Save Changed VR [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_save_changed_vr) { int gr1, unused2; U32 n, n1, n2; U64 d; RRE(inst, regs, gr1, unused2); VOP_CHECK(regs); PRIV_CHECK(regs); ODD_CHECK(gr1, regs); /* n contrains the current save area address */ n = regs->GR_L(gr1) & ADDRESS_MAXWRAP(regs); /* n1 contains the starting element number */ if((n1 = regs->GR_L(gr1 + 1) >> 16) >= VECTOR_SECTION_SIZE) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Starting address must be eight times the section size aligned */ if((n - (8 * n1)) & ((VECTOR_SECTION_SIZE * VSA_ALIGN) - 1) ) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* n2 contains VR pair, which must be an even reg */ if((n2 = regs->GR_L(gr1 + 1) & 0x0000FFFF) & 0x0000FFF1) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); if( VR_CHANGED(n2, regs) ) { for(; n1 < VECTOR_SECTION_SIZE; n1++) { /* Store vr pair in savearea */ d = ((U64)regs->vf->vr[n2][n1] << 32) | regs->vf->vr[n2+1][n1]; ARCH_DEP(vstore8)(d, n, gr1, regs); /* Update element number */ n1++; regs->GR_L(gr1 + 1) &= 0x0000FFFF; regs->GR_L(gr1 + 1) |= n1 << 16; regs->GR_L(gr1) += 8; #if 0 /* This is where the instruction may be interrupted */ UPD_PSW_IA(regs, PSW_IA(regs, -4)); return; #endif } /* Indicate vr pair saved */ regs->psw.cc = 2; /* Reset the VR changed bit */ RESET_VR_CHANGED(n2, regs); } else { regs->GR_L(gr1) += 8 * (VECTOR_SECTION_SIZE - n1); /* vr pair not saved */ regs->psw.cc = 0; } /* Set 2 if vr 14 is restored, 0 if not restored, 3 and 1 for other VR's respectively */ if(n2 != 14) regs->psw.cc++; /* Update the vector pair number, and zero element number */ n2 += 2; regs->GR_L(gr1 + 1) = n2; } /*-------------------------------------------------------------------*/ /* A64A VRSV - Save VR [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(v_save_vr) { int gr1, unused2; U32 n, n1, n2; U64 d; RRE(inst, regs, gr1, unused2); VOP_CHECK(regs); ODD_CHECK(gr1, regs); /* n contrains the current save area address */ n = regs->GR_L(gr1) & ADDRESS_MAXWRAP(regs); /* n1 contains the starting element number */ if((n1 = regs->GR_L(gr1 + 1) >> 16) >= VECTOR_SECTION_SIZE) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Starting address must be eight times the section size aligned */ if((n - (8 * n1)) & ((VECTOR_SECTION_SIZE * VSA_ALIGN) - 1) ) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* n2 contains VR pair, which must be an even reg */ if((n2 = regs->GR_L(gr1 + 1) & 0x0000FFFF) & 0x0000FFF1) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); if( VR_INUSE(n2, regs) ) { for(; n1 < VECTOR_SECTION_SIZE; n1++) { /* Store vr pair in savearea */ d = ((U64)regs->vf->vr[n2][n1] << 32) | regs->vf->vr[n2+1][n1]; ARCH_DEP(vstore8)(d, n, gr1, regs); /* Update element number */ n1++; regs->GR_L(gr1 + 1) &= 0x0000FFFF; regs->GR_L(gr1 + 1) |= n1 << 16; regs->GR_L(gr1) += 8; #if 0 /* This is where the instruction may be interrupted */ UPD_PSW_IA(regs, PSW_IA(regs, -4)); return; #endif } /* Indicate vr pair restored */ regs->psw.cc = 2; } else { regs->GR_L(gr1) += 8 * (VECTOR_SECTION_SIZE - n1); /* Indicate vr pair not restored */ regs->psw.cc = 0; } /* Set 2 if vr 14 is restored, 0 if not restored, 3 and 1 for other VR's respectively */ if(n2 != 14) regs->psw.cc++; /* Update the vector pair number, and zero element number */ n2 += 2; regs->GR_L(gr1 + 1) = n2; } /*-------------------------------------------------------------------*/ /* A680 VLVM - Load VMR [VS] */ /*-------------------------------------------------------------------*/ DEF_INST(v_load_vmr) { int rs2; U32 n, n1; VS(inst, regs, rs2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); n1 = n >> 3; ARCH_DEP(vfetchc)(regs->vf->vmr, n1, regs->GR_L(rs2) & ADDRESS_MAXWRAP(regs), rs2, regs); /* Set the inactive bits to zero */ regs->vf->vmr[n1] &= 0x7F00 >> (n & 7); for(n1++; n1 < sizeof(regs->vf->vmr); n1++) regs->vf->vmr[n1] = 0; } /*-------------------------------------------------------------------*/ /* A681 VLCVM - Load VMR Complement [VS] */ /*-------------------------------------------------------------------*/ DEF_INST(v_load_vmr_complement) { int rs2; U32 n, n1, n2; VS(inst, regs, rs2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* Number of bytes - 1 */ n1 = n >> 3; ARCH_DEP(vfetchc)(regs->vf->vmr, n1, regs->GR_L(rs2) & ADDRESS_MAXWRAP(regs), rs2, regs); /* Complement all bits loaded */ for(n2 = 0; n2 <= n1; n2++) regs->vf->vmr[n2] ^= 0xFF; /* Set the inactive bits to zero */ regs->vf->vmr[n1] &= 0x7F00 >> (n & 7); for(n1++; n1 < sizeof(regs->vf->vmr); n1++) regs->vf->vmr[n1] = 0; } /*-------------------------------------------------------------------*/ /* A682 VSTVM - Store VMR [VS] */ /*-------------------------------------------------------------------*/ DEF_INST(v_store_vmr) { int rs2; U32 n; VS(inst, regs, rs2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); ARCH_DEP(vstorec)(regs->vf->vmr, n >> 3, regs->GR_L(rs2) & ADDRESS_MAXWRAP(regs), rs2, regs); } /*-------------------------------------------------------------------*/ /* A684 VNVM - AND To VMR [VS] */ /*-------------------------------------------------------------------*/ DEF_INST(v_and_to_vmr) { int rs2; U32 n, n1, n2; BYTE workvmr[VECTOR_SECTION_SIZE/8]; VS(inst, regs, rs2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* Number of bytes - 1 */ n1 = n >> 3; ARCH_DEP(vfetchc)(workvmr, n1, regs->GR_L(rs2) & ADDRESS_MAXWRAP(regs), rs2, regs); /* And VMR with workvmr */ for(n2 = 0; n2 <= n1; n2++) regs->vf->vmr[n2] &= workvmr[n2]; /* zeroize remainder */ regs->vf->vmr[n1] &= 0x7F00 >> (n & 7); for(n1++; n1 < sizeof(regs->vf->vmr); n1++) regs->vf->vmr[n1] = 0; } /*-------------------------------------------------------------------*/ /* A685 VOVM - OR To VMR [VS] */ /*-------------------------------------------------------------------*/ DEF_INST(v_or_to_vmr) { int rs2; U32 n, n1, n2; BYTE workvmr[VECTOR_SECTION_SIZE/8]; VS(inst, regs, rs2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* Number of bytes - 1 */ n1 = n >> 3; ARCH_DEP(vfetchc)(workvmr, n1, regs->GR_L(rs2) & ADDRESS_MAXWRAP(regs), rs2, regs); /* OR VMR with workvmr */ for(n2 = 0; n2 <= n1; n2++) regs->vf->vmr[n2] |= workvmr[n2]; /* zeroize remainder */ regs->vf->vmr[n1] &= 0x7F00 >> (n & 7); for(n1++; n1 < sizeof(regs->vf->vmr); n1++) regs->vf->vmr[n1] = 0; } /*-------------------------------------------------------------------*/ /* A686 VXVM - Exclusive OR To VMR [VS] */ /*-------------------------------------------------------------------*/ DEF_INST(v_exclusive_or_to_vmr) { int rs2; U32 n, n1, n2; BYTE workvmr[VECTOR_SECTION_SIZE/8]; VS(inst, regs, rs2); VOP_CHECK(regs); /* Extract vector count (number of active bits in vmr) */ n = VECTOR_COUNT(regs); /* Number of bytes - 1 */ n1 = n >> 3; ARCH_DEP(vfetchc)(workvmr, n1, regs->GR_L(rs2) & ADDRESS_MAXWRAP(regs), rs2, regs); /* OR VMR with workvmr */ for(n2 = 0; n2 <= n1; n2++) regs->vf->vmr[n2] ^= workvmr[n2]; /* zeroize remainder */ regs->vf->vmr[n1] &= 0x7F00 >> (n & 7); for(n1++; n1 < sizeof(regs->vf->vmr); n1++) regs->vf->vmr[n1] = 0; } /*-------------------------------------------------------------------*/ /* A6C0 VSRSV - Save VSR [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_save_vsr) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); DW_CHECK(effective_addr2, regs); ARCH_DEP(vstore8)(regs->vf->vsr, effective_addr2, b2, regs); } /*-------------------------------------------------------------------*/ /* A6C1 VMRSV - Save VMR [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_save_vmr) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); ARCH_DEP(vstorec)(regs->vf->vmr, sizeof(regs->vf->vmr) - 1, effective_addr2, b2, regs); } /*-------------------------------------------------------------------*/ /* A6C2 VSRRS - Restore VSR [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_restore_vsr) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n1, n2; U64 d; S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); DW_CHECK(effective_addr2, regs); /* Fetch operand */ d = ARCH_DEP(vfetch8)(effective_addr2, b2, regs); /* Check for reserved bits nonzero, vector count not greater then section size and vector interruption index not greater then section size */ if((d & VSR_RESV) || ((d & VSR_VCT) >> 32) > VECTOR_SECTION_SIZE || ((d & VSR_VIX) >> 16) >= VECTOR_SECTION_SIZE) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* In problem state the change bit are set corresponding the inuse bits */ if(PROBSTATE(®s->psw)) { d &= ~VSR_VCH; d |= (d & VSR_VIU) >> 8; } /* Clear any VRs whose inuse bits are being set to zero */ for(n1 = 0; n1 < 16; n1 += 2) { if( VR_INUSE(n1, regs) && !((d & VSR_VIU) & (VSR_VCH0 >> (n1 >> 1))) ) for(n2 = 0; n2 < VECTOR_SECTION_SIZE; n2++) { regs->vf->vr[n1][n2] = 0; regs->vf->vr[n1+1][n2] = 0; } } /* Update the vector status register */ regs->vf->vsr = d; } /*-------------------------------------------------------------------*/ /* A6C3 VMRRS - Restore VMR [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_restore_vmr) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); ARCH_DEP(vfetchc)(regs->vf->vmr, sizeof(regs->vf->vmr) - 1, effective_addr2, b2, regs); } /*-------------------------------------------------------------------*/ /* A6C4 VLVCA - Load VCT from Address [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_load_vct_from_address) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; S_NW(inst, regs, b2, effective_addr2); VOP_CHECK(regs); regs->psw.cc = ((S32)effective_addr2 == 0) ? 0 : ((S32)effective_addr2 < 0) ? 1 : ((S32)effective_addr2 > VECTOR_SECTION_SIZE) ? 2 : 3; n = (S32)effective_addr2 < 0 ? 0 : (S32)effective_addr2 > VECTOR_SECTION_SIZE ? VECTOR_SECTION_SIZE : (S32)effective_addr2; regs->vf->vsr &= ~VSR_VCT; regs->vf->vsr |= (U64)n << 32; } /*-------------------------------------------------------------------*/ /* A6C5 VRCL - Clear VR [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_clear_vr) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n, n1, n2; S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); /* Set vector interruption index to zero */ regs->vf->vsr &= ~VSR_VIX; /* Clear vr's identified in the bit mask n1 contains the vr number n2 contains the bitmask identifying the vr number n contains the element number */ for(n1 = 0, n2 = 0x80; n1 <= 14; n1 += 2, n2 >>= 1) if(effective_addr2 & n2) { for(n = 0; n < VECTOR_SECTION_SIZE; n++) { regs->vf->vr[n1][n] = 0; regs->vf->vr[n1+1][n] = 0; } RESET_VR_INUSE(n1, regs); } } /*-------------------------------------------------------------------*/ /* A6C6 VSVMM - Set Vector Mask Mode [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_set_vector_mask_mode) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); if(effective_addr2 & 1) regs->vf->vsr |= VSR_M; else regs->vf->vsr &= ~VSR_M; } /*-------------------------------------------------------------------*/ /* A6C7 VLVXA - Load VIX from Address [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_load_vix_from_address) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; S_NW(inst, regs, b2, effective_addr2); VOP_CHECK(regs); regs->psw.cc = ((S32)effective_addr2 == 0) ? 0 : ((S32)effective_addr2 < 0) ? 1 : ((S32)effective_addr2 < VECTOR_COUNT(regs)) ? 2 : 3; n = (S32)effective_addr2 < 0 ? 0 : (S32)effective_addr2 > VECTOR_SECTION_SIZE ? VECTOR_SECTION_SIZE : (S32)effective_addr2; regs->vf->vsr &= ~VSR_VIX; regs->vf->vsr |= (U64)n << 16; } /*-------------------------------------------------------------------*/ /* A6C8 VSTVP - Store Vector Parameters [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_store_vector_parameters) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); FW_CHECK(effective_addr2, regs); /* Store the section size and partial sum number */ ARCH_DEP(vstore4)(VECTOR_SECTION_SIZE << 16 | VECTOR_PARTIAL_SUM_NUMBER, effective_addr2, b2, regs); } /*-------------------------------------------------------------------*/ /* A6CA VACSV - Save VAC [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_save_vac) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, VACSV)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ ARCH_DEP(vstore8)(regs->vf->vac, effective_addr2, b2, regs); } /*-------------------------------------------------------------------*/ /* A6CB VACRS - Restore VAC [S] */ /*-------------------------------------------------------------------*/ DEF_INST(v_restore_vac) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); VOP_CHECK(regs); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, VACRS)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ regs->vf->vac = ARCH_DEP(vfetch8)(effective_addr2, b2, regs) & VAC_MASK; } #endif /*defined(FEATURE_VECTOR_FACILITY)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "vector.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "vector.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/xstore.c0000664000175000017500000005300312564723224011674 00000000000000/* XSTORE.C (c) Copyright Jan Jaeger, 1999-2009 */ /* Expanded storage related instructions */ /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ /* MVPG moved from cpu.c to xstore.c 05/07/00 Jan Jaeger */ /*-------------------------------------------------------------------*/ /* This module implements the expanded storage instructions */ /* for the Hercules ESA/390 emulator. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_XSTORE_C_) #define _XSTORE_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_EXPANDED_STORAGE) /*-------------------------------------------------------------------*/ /* B22E PGIN - Page in from expanded storage [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(page_in) { int r1, r2; /* Values of R fields */ VADR vaddr; /* Virtual storage address */ BYTE *maddr; /* Main storage address */ U32 xaddr; /* Expanded storage block# */ size_t xoffs; /* Byte offset into xpndstor */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); if(SIE_STATB(regs, IC3, PGX)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Cannot perform xstore page movement in XC mode */ if(SIE_STATB(regs, MX, XC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* expanded storage block number */ xaddr = regs->GR_L(r2); if(SIE_MODE(regs)) { xaddr += regs->sie_xso; if(xaddr >= regs->sie_xsl) { PTT(PTT_CL_ERR,"*PGIN",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 3; return; } } /* If the expanded storage block is not configured then terminate with cc3 */ if (xaddr >= sysblk.xpndsize) { PTT(PTT_CL_ERR,"*PGIN",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 3; return; } /* Byte offset in expanded storage */ xoffs = (size_t)xaddr << XSTORE_PAGESHIFT; /* Obtain abs address, verify access and set ref/change bits */ vaddr = (regs->GR(r1) & ADDRESS_MAXWRAP(regs)) & XSTORE_PAGEMASK; maddr = MADDRL (vaddr, 4096, USE_REAL_ADDR, regs, ACCTYPE_WRITE, 0); /* Copy data from expanded to main */ memcpy (maddr, sysblk.xpndstor + xoffs, XSTORE_PAGESIZE); /* cc0 means pgin ok */ regs->psw.cc = 0; } /* end DEF_INST(page_in) */ #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ #if defined(FEATURE_EXPANDED_STORAGE) /*-------------------------------------------------------------------*/ /* B22F PGOUT - Page out to expanded storage [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(page_out) { int r1, r2; /* Values of R fields */ VADR vaddr; /* Virtual storage address */ BYTE *maddr; /* Main storage address */ U32 xaddr; /* Expanded storage block# */ size_t xoffs; /* Byte offset into xpndstor */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); if(SIE_STATB(regs, IC3, PGX)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) /* Cannot perform xstore page movement in XC mode */ if(SIE_STATB(regs, MX, XC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* expanded storage block number */ xaddr = regs->GR_L(r2); if(SIE_MODE(regs)) { xaddr += regs->sie_xso; if(xaddr >= regs->sie_xsl) { PTT(PTT_CL_ERR,"*PGOUT",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 3; return; } } /* If the expanded storage block is not configured then terminate with cc3 */ if (xaddr >= sysblk.xpndsize) { PTT(PTT_CL_ERR,"*PGOUT",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); regs->psw.cc = 3; return; } /* Byte offset in expanded storage */ xoffs = (size_t)xaddr << XSTORE_PAGESHIFT; /* Obtain abs address, verify access and set ref/change bits */ vaddr = (regs->GR(r1) & ADDRESS_MAXWRAP(regs)) & XSTORE_PAGEMASK; maddr = MADDR (vaddr, USE_REAL_ADDR, regs, ACCTYPE_READ, 0); /* Copy data from main to expanded */ memcpy (sysblk.xpndstor + xoffs, maddr, XSTORE_PAGESIZE); /* cc0 means pgout ok */ regs->psw.cc = 0; } /* end DEF_INST(page_out) */ #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ #if defined(FEATURE_MOVE_PAGE_FACILITY_2) && defined(FEATURE_EXPANDED_STORAGE) /*-------------------------------------------------------------------*/ /* B259 IESBE - Invalidate Expanded Storage Block Entry [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(invalidate_expanded_storage_block_entry) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(SIE_STATNB(regs, EC0, MVPG)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before operation */ PERFORM_SERIALIZATION (regs); OBTAIN_INTLOCK(regs); SYNCHRONIZE_CPUS(regs); /* Invalidate page table entry */ ARCH_DEP(invalidate_pte) (inst[1], regs->GR_G(r1), regs->GR_L(r2), regs); RELEASE_INTLOCK(regs); /* Perform serialization after operation */ PERFORM_SERIALIZATION (regs); } /* end DEF_INST(invalidate_expanded_storage_block_entry) */ #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ #if defined(_MSVC_) /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */ #pragma optimize("",off) #endif /*defined(_MSVC_)*/ #if defined(FEATURE_MOVE_PAGE_FACILITY_2) /*-------------------------------------------------------------------*/ /* B254 MVPG - Move Page [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(move_page) { int r1, r2; /* Register values */ int rc = 0; /* Return code */ int cc = 0; /* Condition code */ VADR vaddr1, vaddr2; /* Virtual addresses */ RADR raddr1=0, raddr2=0, xpkeya; /* Real addresses */ BYTE *main1 = NULL, *main2 = NULL; /* Mainstor addresses */ BYTE *sk1; /* Storage key address */ BYTE akey; /* Access key in register 0 */ BYTE akey1, akey2; /* Access keys for operands */ #if defined(FEATURE_EXPANDED_STORAGE) int xpvalid1 = 0, xpvalid2 = 0; /* 1=Operand in expanded stg */ CREG pte1 = 0, pte2 = 0; /* Page table entry */ U32 xpblk1 = 0, xpblk2 = 0; /* Expanded storage block# */ BYTE xpkey1 = 0, xpkey2 = 0; /* Expanded storage keys */ #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ RRE(inst, regs, r1, r2); #if defined(_FEATURE_SIE) if(SIE_STATNB(regs, EC0, MVPG)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ /* Use PSW key as access key for both operands */ akey1 = akey2 = regs->psw.pkey; /* If register 0 bit 20 or 21 is one, get access key from R0 */ if (regs->GR_L(0) & 0x00000C00) { /* Extract the access key from register 0 bits 24-27 */ akey = regs->GR_L(0) & 0x000000F0; /* Priviliged operation exception if in problem state, and the specified key is not permitted by the PSW key mask */ if ( PROBSTATE(®s->psw) && ((regs->CR(3) << (akey >> 4)) & 0x80000000) == 0 ) regs->program_interrupt (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); /* If register 0 bit 20 is one, use R0 key for operand 1 */ if (regs->GR_L(0) & 0x00000800) akey1 = akey; /* If register 0 bit 21 is one, use R0 key for operand 2 */ if (regs->GR_L(0) & 0x00000400) akey2 = akey; } /* Specification exception if register 0 bits 16-19 are not all zero, or if bits 20 and 21 are both ones */ if ((regs->GR_L(0) & 0x0000F000) != 0 || (regs->GR_L(0) & 0x00000C00) == 0x00000C00) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Determine the logical addresses of each operand */ vaddr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); vaddr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Isolate the page addresses of each operand */ vaddr1 &= XSTORE_PAGEMASK; vaddr2 &= XSTORE_PAGEMASK; /* Obtain the real or expanded address of each operand */ if ( !REAL_MODE(®s->psw) || SIE_MODE(regs) ) { /* Translate the second operand address to a real address */ if(!REAL_MODE(®s->psw)) { rc = ARCH_DEP(translate_addr) (vaddr2, r2, regs, ACCTYPE_READ); raddr2 = regs->dat.raddr; } else raddr2 = vaddr2; if(rc != 0 && rc != 2) goto mvpg_progck; raddr2 = APPLY_PREFIXING (raddr2, regs->PX); if (raddr2 > regs->mainlim) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && !regs->sie_pref) { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr2, (SIE_STATB(regs, MX, XC) && AR_BIT(®s->psw) && r2 > 0) ? r2 : USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) #else /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr2, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) #endif /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ (regs->hostregs->program_interrupt) (regs->hostregs, regs->hostregs->dat.xcode); /* Convert host real address to host absolute address */ raddr2 = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); } #endif /*defined(_FEATURE_SIE)*/ #if defined(FEATURE_EXPANDED_STORAGE) if(rc == 2) { FETCH_W(pte2,regs->mainstor + raddr2); /* If page is invalid in real storage but valid in expanded storage then xpblk2 now contains expanded storage block# */ if(pte2 & PAGETAB_ESVALID) { xpblk2 = (pte2 & ZPGETAB_PFRA) >> 12; #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { /* Add expanded storage origin for this guest */ xpblk2 += regs->sie_xso; /* If the block lies beyond this guests limit then we must terminate the instruction */ if(xpblk2 >= regs->sie_xsl) { cc = 2; goto mvpg_progck; } } #endif /*defined(_FEATURE_SIE)*/ rc = 0; xpvalid2 = 1; xpkeya = raddr2 + #if defined(FEATURE_ESAME) 2048; #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390 mode, the XPTE lies directly beyond the PTE, and each entry is 12 bytes long, we must therefor add 1024 + 8 times the page index */ 1024 + ((vaddr2 & 0x000FF000) >> 9); #endif /*!defined(FEATURE_ESAME)*/ if (xpkeya > regs->mainlim) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); xpkey2 = regs->mainstor[xpkeya]; /*DEBUG logmsg("MVPG pte2 = " F_CREG ", xkey2 = %2.2X, xpblk2 = %5.5X, akey2 = %2.2X\n", pte2,xpkey2,xpblk2,akey2); */ } else { cc = 2; goto mvpg_progck; } } #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ /* Program check if second operand is not valid in either main storage or expanded storage */ if (rc) { cc = 2; goto mvpg_progck; } /* Reset protection indication before calling translate_addr() */ regs->dat.protect = 0; /* Translate the first operand address to a real address */ if(!REAL_MODE(®s->psw)) { rc = ARCH_DEP(translate_addr) (vaddr1, r1, regs, ACCTYPE_WRITE); raddr1 = regs->dat.raddr; } else raddr1 = vaddr1; if(rc != 0 && rc != 2) goto mvpg_progck; raddr1 = APPLY_PREFIXING (raddr1, regs->PX); if (raddr1 > regs->mainlim) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && !regs->sie_pref) { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr1, (SIE_STATB(regs, MX, XC) && AR_BIT(®s->psw) && r1 > 0) ? r1 : USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) #else /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ if (SIE_TRANSLATE_ADDR (regs->sie_mso + raddr1, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) #endif /*!defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ (regs->hostregs->program_interrupt) (regs->hostregs, regs->hostregs->dat.xcode); /* Convert host real address to host absolute address */ raddr1 = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); } #endif /*defined(_FEATURE_SIE)*/ #if defined(FEATURE_EXPANDED_STORAGE) if(rc == 2) { FETCH_W(pte1,regs->mainstor + raddr1); /* If page is invalid in real storage but valid in expanded storage then xpblk1 now contains expanded storage block# */ if(pte1 & PAGETAB_ESVALID) { xpblk1 = (pte1 & ZPGETAB_PFRA) >> 12; #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { /* Add expanded storage origin for this guest */ xpblk1 += regs->sie_xso; /* If the block lies beyond this guests limit then we must terminate the instruction */ if(xpblk1 >= regs->sie_xsl) { cc = 1; goto mvpg_progck; } } #endif /*defined(_FEATURE_SIE)*/ rc = 0; xpvalid1 = 1; xpkeya = raddr1 + #if defined(FEATURE_ESAME) 2048; #else /*!defined(FEATURE_ESAME)*/ /* For ESA/390 mode, the XPTE lies directly beyond the PTE, and each entry is 12 bytes long, we must therefor add 1024 + 8 times the page index */ 1024 + ((vaddr1 & 0x000FF000) >> 9); #endif /*!defined(FEATURE_ESAME)*/ if (xpkeya > regs->mainlim) regs->program_interrupt (regs, PGM_ADDRESSING_EXCEPTION); xpkey1 = regs->mainstor[xpkeya]; /*DEBUG logmsg("MVPG pte1 = " F_CREG ", xkey1 = %2.2X, xpblk1 = %5.5X, akey1 = %2.2X\n", pte1,xpkey1,xpblk1,akey1); */ } else { cc = 1; goto mvpg_progck; } } #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ /* Program check if operand not valid in main or expanded */ if (rc) { cc = 1; goto mvpg_progck; } /* Program check if page protection or access-list controlled protection applies to the first operand */ if (regs->dat.protect || (xpvalid1 && (pte1 & PAGETAB_PROT))) { regs->TEA = vaddr1 | TEA_PROT_AP | regs->dat.stid; regs->excarid = (ACCESS_REGISTER_MODE(®s->psw)) ? r1 : 0; regs->program_interrupt (regs, PGM_PROTECTION_EXCEPTION); } } /* end if(!REAL_MODE) */ #if defined(FEATURE_EXPANDED_STORAGE) /* Program check if both operands are in expanded storage, or if first operand is in expanded storage and the destination reference intention (register 0 bit 22) is set to one, or if first operand is in expanded storage and pte lock bit on, or if first operand is in expanded storage and frame invalid */ if ((xpvalid1 && xpvalid2) || (xpvalid1 && (regs->GR_L(0) & 0x00000200)) || (xpvalid1 && (pte1 & PAGETAB_PGLOCK)) || (xpvalid1 && (xpblk1 >= sysblk.xpndsize))) { regs->dat.xcode = PGM_PAGE_TRANSLATION_EXCEPTION; rc = 2; cc = 1; goto mvpg_progck; } /* More Program check checking, but at lower priority: if second operand is in expanded storage and pte lock bit on, or if second operand is in expanded storage and frame invalid */ if ((xpvalid2 && (pte2 & PAGETAB_PGLOCK)) || (xpvalid2 && (xpblk2 >= sysblk.xpndsize))) { /* re-do translation to set up TEA */ rc = ARCH_DEP(translate_addr) (vaddr2, r2, regs, ACCTYPE_READ); regs->dat.xcode = PGM_PAGE_TRANSLATION_EXCEPTION; cc = 1; goto mvpg_progck; } /* Perform protection checks */ if (xpvalid1) { /* Key check on expanded storage block if NoKey bit off in PTE */ if (akey1 != 0 && akey1 != (xpkey1 & STORKEY_KEY) && (pte1 & PAGETAB_ESNK) == 0 && !((regs->CR(0) & CR0_STORE_OVRD) && ((xpkey1 & STORKEY_KEY) == 0x90))) { regs->program_interrupt (regs, PGM_PROTECTION_EXCEPTION); } sk1=NULL; } else #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ { /* Obtain absolute address of main storage block, check protection, and set reference and change bits */ main1 = MADDRL (vaddr1, 4096, r1, regs, ACCTYPE_WRITE_SKP, akey1); sk1 = regs->dat.storkey; } #if defined(FEATURE_EXPANDED_STORAGE) if (xpvalid2) { /* Key check on expanded storage block if NoKey bit off in PTE */ if (akey2 != 0 && (xpkey2 & STORKEY_FETCH) && akey2 != (xpkey2 & STORKEY_KEY) && (pte2 & PAGETAB_ESNK) == 0) { regs->program_interrupt (regs, PGM_PROTECTION_EXCEPTION); } } else #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ { /* Obtain absolute address of main storage block, check protection, and set reference bit. Use last byte of page to avoid FPO area. */ main2 = MADDR (vaddr2 | 0xFFF, r2, regs, ACCTYPE_READ, akey2); main2 -= 0xFFF; } #if defined(FEATURE_EXPANDED_STORAGE) /* Perform page movement */ if (xpvalid2) { /* Set the main storage reference and change bits */ *sk1 |= (STORKEY_REF | STORKEY_CHANGE); /* Set Expanded Storage reference bit in the PTE */ STORE_W(regs->mainstor + raddr2, pte2 | PAGETAB_ESREF); /* Move 4K bytes from expanded storage to main storage */ memcpy (main1, sysblk.xpndstor + ((size_t)xpblk2 << XSTORE_PAGESHIFT), XSTORE_PAGESIZE); } else if (xpvalid1) { /* Set Expanded Storage reference and change bits in the PTE */ STORE_W(regs->mainstor + raddr1, pte1 | PAGETAB_ESREF | PAGETAB_ESCHA); /* Move 4K bytes from main storage to expanded storage */ memcpy (sysblk.xpndstor + ((size_t)xpblk1 << XSTORE_PAGESHIFT), main2, XSTORE_PAGESIZE); } else #endif /*defined(FEATURE_EXPANDED_STORAGE)*/ { /* Set the main storage reference and change bits */ *sk1 |= (STORKEY_REF | STORKEY_CHANGE); /* Move 4K bytes from main storage to main storage */ memcpy (main1, main2, XSTORE_PAGESIZE); } /* Return condition code zero */ regs->psw.cc = 0; return; mvpg_progck: PTT(PTT_CL_ERR,"*MVPG",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); /* If page translation exception (PTE invalid) and condition code option in register 0 bit 23 is set, return condition code */ if ((regs->GR_L(0) & 0x00000100) && regs->dat.xcode == PGM_PAGE_TRANSLATION_EXCEPTION && rc == 2) { regs->psw.cc = cc; return; } /* Otherwise generate program check */ /* (Bit 29 of TEA is on for PIC 11 & operand ID also stored) */ if (regs->dat.xcode == PGM_PAGE_TRANSLATION_EXCEPTION) { regs->TEA |= TEA_MVPG; regs->opndrid = (r1 << 4) | r2; } regs->program_interrupt (regs, regs->dat.xcode); } /* end DEF_INST(move_page) */ #endif /*defined(FEATURE_MOVE_PAGE_FACILITY_2)*/ #if defined(_MSVC_) /* Workaround for "fatal error C1001: INTERNAL COMPILER ERROR" in MSVC */ #pragma optimize("",on) #endif /*defined(_MSVC_)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "xstore.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "xstore.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/cmpsc.c0000664000175000017500000023650312622153562011462 00000000000000/* CMPSC.C (c) Bernard van der Helm, 2000-2015 */ /* S/390 compression call instruction */ /*----------------------------------------------------------------------------*/ /* Implementation of the S/390 compression call instruction described in */ /* SA22-7208-01: Data Compression within the Hercules S/390 emulator. */ /* This implementation couldn't be done without the test programs from */ /* Mario Bezzi. Thanks Mario! Also special thanks to Greg Smith who */ /* introduced iregs, needed when a page fault occurs. */ /* */ /* Please pay attention to the Q Public License Version 1. This is open */ /* source, but you are not allowed to "reuse" parts for your own purpose */ /* without the author's written permission! */ /* */ /* Implemented "unique" features: */ /* 8 index symbol block fetching and storing, preventing cbn calculations. */ /* Expand symbol translation caching. */ /* Compression dead end determination and elimination. */ /* Proactive dead end determination and elimination. */ /* */ /* (c) Copyright Bernard van der Helm, 2000-2015 */ /* Noordwijkerhout, The Netherlands. */ /* */ /*----------------------------------------------------------------------------*/ #include "hstdinc.h" #ifndef _HENGINE_DLL_ #define _HENGINE_DLL_ #endif /* #ifndef _HENGINE_DLL_ */ #ifndef _CMPSC_C_ #define _CMPSC_C_ #endif /* #ifndef _CMPSC_C_ */ #include "hercules.h" #include "opcode.h" #include "inline.h" #ifdef FEATURE_COMPRESSION /*============================================================================*/ /* Common */ /*============================================================================*/ /*----------------------------------------------------------------------------*/ /* Debugging options: */ /*----------------------------------------------------------------------------*/ #if 0 #define OPTION_CMPSC_DEBUG #define TRUEFALSE(boolean) ((boolean) ? "True" : "False") #endif /* #if 0|1 */ /*----------------------------------------------------------------------------*/ /* After a successful compression of characters to an index symbol or a */ /* successful translation of an index symbol to characters, the registers */ /* must be updated. */ /*----------------------------------------------------------------------------*/ #define ADJUSTREGS(r, regs, iregs, len) \ { \ SET_GR_A((r), (iregs), (GR_A((r), (iregs)) + (len)) & ADDRESS_MAXWRAP((regs))); \ SET_GR_A((r) + 1, (iregs), GR_A((r) + 1, (iregs)) - (len)); \ } /*----------------------------------------------------------------------------*/ /* Commit intermediate registers */ /*----------------------------------------------------------------------------*/ #ifdef OPTION_CMPSC_DEBUG #define COMMITREGS(regs, iregs, r1, r2) \ __COMMITREGS((regs), (iregs), (r1), (r2)) \ logmsg("*** Regs committed\n"); #else #define COMMITREGS(regs, iregs, r1, r2) \ __COMMITREGS((regs), (iregs), (r1), (r2)) #endif /* ifdef OPTION_CMPSC_DEBUG */ #define __COMMITREGS(regs, iregs, r1, r2) \ { \ SET_GR_A(1, (regs), GR_A(1, (iregs))); \ SET_GR_A((r1), (regs), GR_A((r1), (iregs))); \ SET_GR_A((r1) + 1, (regs), GR_A((r1) + 1, (iregs))); \ SET_GR_A((r2), (regs), GR_A((r2), (iregs))); \ SET_GR_A((r2) + 1, (regs), GR_A((r2) + 1, (iregs))); \ } /*----------------------------------------------------------------------------*/ /* Commit intermediate registers, except for GR1 */ /*----------------------------------------------------------------------------*/ #ifdef OPTION_CMPSC_DEBUG #define COMMITREGS2(regs, iregs, r1, r2) \ __COMMITREGS2((regs), (iregs), (r1), (r2)) \ logmsg("*** Regs committed\n"); #else #define COMMITREGS2(regs, iregs, r1, r2) \ __COMMITREGS2((regs), (iregs), (r1), (r2)) #endif /* #ifdef OPTION_CMPSC_DEBUG */ #define __COMMITREGS2(regs, iregs, r1, r2) \ { \ SET_GR_A((r1), (regs), GR_A((r1), (iregs))); \ SET_GR_A((r1) + 1, (regs), GR_A((r1) + 1, (iregs))); \ SET_GR_A((r2), (regs), GR_A((r2), (iregs))); \ SET_GR_A((r2) + 1, (regs), GR_A((r2) + 1, (iregs))); \ } /*----------------------------------------------------------------------------*/ /* Initialize intermediate registers */ /*----------------------------------------------------------------------------*/ #define INITREGS(iregs, regs, r1, r2) \ { \ (iregs)->gr[1] = (regs)->gr[1]; \ (iregs)->gr[(r1)] = (regs)->gr[(r1)]; \ (iregs)->gr[(r1) + 1] = (regs)->gr[(r1) + 1]; \ (iregs)->gr[(r2)] = (regs)->gr[(r2)]; \ (iregs)->gr[(r2) + 1] = (regs)->gr[(r2) + 1]; \ } #if __GEN_ARCH == 900 #undef INITREGS #define INITREGS(iregs, regs, r1, r2) \ { \ (iregs)->gr[1] = (regs)->gr[1]; \ (iregs)->gr[(r1)] = (regs)->gr[(r1)]; \ (iregs)->gr[(r1) + 1] = (regs)->gr[(r1) + 1]; \ (iregs)->gr[(r2)] = (regs)->gr[(r2)]; \ (iregs)->gr[(r2) + 1] = (regs)->gr[(r2) + 1]; \ (iregs)->psw.amode64 = (regs)->psw.amode64; \ } #endif /* #if __GEN_ARCH == 900 */ /*----------------------------------------------------------------------------*/ /* General Purpose Register 0 macro's (GR0) */ /*----------------------------------------------------------------------------*/ /* cdss : compressed-data symbol size */ /* e : expansion operation */ /* f1 : format-1 sibling descriptors */ /* st : symbol-translation option */ /* zp : zero padding */ /* */ /* We recognize the zp flag and do conform POP nothing! We do something */ /* better: Eight index symbol processing. It saves a lot of time in cbn */ /* processing, index symbol fetching and storing. Please contact me if a */ /* 100% equal functionality is needed. I doubt it! */ /*----------------------------------------------------------------------------*/ #define GR0_cdss(regs) (((regs)->GR_L(0) & 0x0000F000) >> 12) #define GR0_e(regs) ((regs)->GR_L(0) & 0x00000100) #define GR0_f1(regs) ((regs)->GR_L(0) & 0x00000200) #define GR0_st(regs) ((regs)->GR_L(0) & 0x00010000) #define GR0_zp(regs) ((regs)->GR_L(0) & 0x00020000) /*----------------------------------------------------------------------------*/ /* General Purpose Register 0 macro's (GR0) derived */ /*----------------------------------------------------------------------------*/ /* dcten : # dictionary entries */ /* dctsz : dictionary size */ /* smbsz : symbol size */ /*----------------------------------------------------------------------------*/ #define GR0_dcten(regs) (0x100 << GR0_cdss((regs))) #define GR0_dctsz(regs) (0x800 << GR0_cdss((regs))) #define GR0_smbsz(regs) (GR0_cdss((regs)) + 8) /*----------------------------------------------------------------------------*/ /* General Purpose Register 1 macro's (GR1) */ /*----------------------------------------------------------------------------*/ /* cbn : compressed-data bit number */ /* dictor: compression dictionary or expansion dictionary */ /* sttoff: symbol-translation-table offset */ /*----------------------------------------------------------------------------*/ #define GR1_cbn(regs) (((regs)->GR_L(1) & 0x00000007)) #define GR1_dictor(regs) (GR_A(1, (regs)) & ((GREG) 0xFFFFFFFFFFFFF000ULL)) #define GR1_sttoff(regs) (((regs)->GR_L(1) & 0x00000FF8) << 4) /*----------------------------------------------------------------------------*/ /* Set the compressed bit number in GR1 */ /*----------------------------------------------------------------------------*/ #define GR1_setcbn(regs, cbn) ((regs)->GR_L(1) = ((regs)->GR_L(1) & 0xFFFFFFF8) | ((cbn) & 0x00000007)) /*----------------------------------------------------------------------------*/ /* Constants */ /*----------------------------------------------------------------------------*/ #define MINPROC_SIZE 32768 /* Minumum processing size */ /*----------------------------------------------------------------------------*/ /* Typedefs and prototypes */ /*----------------------------------------------------------------------------*/ #ifndef NO_2ND_COMPILE struct cc /* Compress context */ { BYTE *cce; /* Character entry under investigation */ int cr; /* Characters read to check #261 */ unsigned dctsz; /* Dictionary size */ BYTE deadadm[8192][0x100 / 8]; /* Dead end administration */ BYTE deadend; /* Dead end indicator */ BYTE *dest; /* Destination MADDR address */ BYTE *dict[32]; /* Dictionary MADDR addresses */ GREG dictor; /* Dictionary origin */ BYTE *edict[32]; /* Expansion dictionary MADDR addrs */ int f1; /* Indication format-1 sibling descr */ REGS *iregs; /* Intermediate registers */ U16 is[8]; /* Cache for 8 index symbols */ unsigned ofst; /* Latest fetched offset */ int r1; /* Guess what */ int r2; /* Yep */ REGS *regs; /* Registers */ BYTE searchadm[1][0x100 / 8]; /* Search administration */ unsigned smbsz; /* Symbol size */ BYTE *src; /* Source MADDR page address */ unsigned srclen; /* Source length left in page */ BYTE st; /* Symbol translation */ }; struct ec /* Expand context */ { BYTE *dest; /* Destination MADDR page address */ BYTE *dict[32]; /* Dictionary MADDR addresses */ GREG dictor; /* Dictionary origin */ BYTE ec[8192 * 7]; /* Expanded index symbol cache */ int eci[8192]; /* Index within cache for is */ int ecl[8192]; /* Size of expanded is */ int ecwm; /* Water mark */ REGS *iregs; /* Intermediate registers */ BYTE oc[8 * 260]; /* Output cache */ unsigned ocl; /* Output cache length */ int r1; /* Guess what */ int r2; /* Yep */ REGS *regs; /* Registers */ unsigned smbsz; /* Symbol size */ BYTE *src; /* Source MADDR page address */ #ifdef OPTION_CMPSC_DEBUG unsigned dbgac; /* Alphabet characters */ unsigned dbgbi; /* bytes in */ unsigned dbgbo; /* bytes out */ unsigned dbgch; /* Cache hits */ unsigned dbgiss; /* Expanded iss */ #endif /* #ifdef OPTION_CMPSC_DEBUG */ }; #endif /* #ifndef NO_2ND_COMPILE */ static void ARCH_DEP(cmpsc_compress)(int r1, int r2, REGS *regs, REGS *iregs); static int ARCH_DEP(cmpsc_compress_single_is)(struct cc *cc); static void ARCH_DEP(cmpsc_expand)(int r1, int r2, REGS *regs, REGS *iregs); static void ARCH_DEP(cmpsc_expand_is)(struct ec *ec, U16 is); static int ARCH_DEP(cmpsc_expand_single_is)(struct ec *ec); static BYTE *ARCH_DEP(cmpsc_fetch_cce)(struct cc *cc, unsigned index); static int ARCH_DEP(cmpsc_fetch_ch)(struct cc *cc); static int ARCH_DEP(cmpsc_fetch_is)(struct ec *ec, U16 *is); static void ARCH_DEP(cmpsc_fetch_iss)(struct ec *ec, U16 is[8]); #ifdef OPTION_CMPSC_DEBUG static void cmpsc_print_cce(BYTE *cce); static void cmpsc_print_ece(BYTE *ece); static void cmpsc_print_sd(int f1, BYTE *sd1, BYTE *sd2); #endif /* #ifdef OPTION_CMPSC_DEBUG */ static int ARCH_DEP(cmpsc_search_cce)(struct cc *cc, U16 *is); static int ARCH_DEP(cmpsc_search_sd)(struct cc *cc, U16 *is); static int ARCH_DEP(cmpsc_store_is)(struct cc *cc, U16 is); static void ARCH_DEP(cmpsc_store_iss)(struct cc *cc); static int ARCH_DEP(cmpsc_test_ec)(struct cc *cc, BYTE *cce); static int ARCH_DEP(cmpsc_vstore)(struct ec *ec, BYTE *buf, unsigned len); /*----------------------------------------------------------------------------*/ /* B263 CMPSC - Compression Call [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(compression_call) { REGS iregs; /* Intermediate registers */ int r1; /* Guess what */ int r2; /* Yep */ RRE(inst, regs, r1, r2); #ifdef OPTION_CMPSC_DEBUG logmsg("CMPSC: compression call\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" length : " F_GREG "\n", regs->GR(r1 + 1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" zp : %s\n", TRUEFALSE(GR0_zp(regs))); logmsg(" st : %s\n", TRUEFALSE(GR0_st(regs))); logmsg(" cdss : %d\n", GR0_cdss(regs)); logmsg(" f1 : %s\n", TRUEFALSE(GR0_f1(regs))); logmsg(" e : %s\n", TRUEFALSE(GR0_e(regs))); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); logmsg(" dictor: " F_GREG "\n", GR1_dictor(regs)); logmsg(" sttoff: %08X\n", GR1_sttoff(regs)); logmsg(" cbn : %d\n", GR1_cbn(regs)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Check the registers on even-odd pairs and valid compression-data symbol size */ if(unlikely(r1 & 0x01 || r2 & 0x01 || !GR0_cdss(regs) || GR0_cdss(regs) > 5)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Check for empty input */ if(unlikely(!GR_A(r2 + 1, regs))) { #ifdef OPTION_CMPSC_DEBUG logmsg(" Zero input, returning cc0\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ regs->psw.cc = 0; return; } /* Check for empty output */ if(unlikely(!GR_A(r1 + 1, regs))) { #ifdef OPTION_CMPSC_DEBUG logmsg(" Zero output, returning cc1\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ regs->psw.cc = 1; return; } /* Initialize intermediate registers */ INITREGS(&iregs, regs, r1, r2); /* Now go to the requested function */ if(likely(GR0_e(regs))) ARCH_DEP(cmpsc_expand)(r1, r2, regs, &iregs); else ARCH_DEP(cmpsc_compress)(r1, r2, regs, &iregs); } /*============================================================================*/ /* Compress */ /*============================================================================*/ /*----------------------------------------------------------------------------*/ /* Compression Character Entry macro's (CCE) */ /*----------------------------------------------------------------------------*/ /* act : additional-extension-character count */ /* cct : child count */ /* cptr : child pointer; index of first child */ /* d : double-character entry */ /* x(i) : examine child bit for children 1 to 5 */ /* y(i) : examine child bit for 6th/13th and 7th/14th sibling */ /*----------------------------------------------------------------------------*/ #define CCE_act(cce) ((cce)[1] >> 5) #define CCE_cct(cce) ((cce)[0] >> 5) #define CCE_cptr(cce) ((((cce)[1] & 0x1f) << 8) | (cce)[2]) #define CCE_d(cce) ((cce)[1] & 0x20) #define CCE_x(cce, i) ((cce)[0] & (0x10 >> (i))) #define CCE_y(cce, i) ((cce)[1] & (0x80 >> (i))) /*----------------------------------------------------------------------------*/ /* Compression Character Entry macro's (CCE) derived */ /*----------------------------------------------------------------------------*/ /* cc(i) : child character */ /* ccc(i) : indication consecutive child character */ /* ccs : number of child characters */ /* ec(i) : additional extension character */ /* ecs : number of additional extension characters */ /* mcc : indication if siblings follow child characters */ /*----------------------------------------------------------------------------*/ #define CCE_cc(cce, i) ((cce)[3 + CCE_ecs((cce)) + (i)]) #define CCE_ccc(cce, i) (CCE_cc((cce), (i)) == CCE_cc((cce), 0)) #define CCE_ccs(cce) (CCE_cct((cce)) - (CCE_mcc((cce)) ? 1 : 0)) #define CCE_ec(cce, i) ((cce)[3 + (i)]) #define CCE_ecs(cce) ((CCE_cct((cce)) <= 1) ? CCE_act((cce)) : (CCE_d((cce)) ? 1 : 0)) #define CCE_mcc(cce) ((CCE_cct((cce)) + (CCE_d((cce)) ? 1 : 0) == 6)) /*----------------------------------------------------------------------------*/ /* Format-0 Sibling Descriptors macro's (SD0) */ /*----------------------------------------------------------------------------*/ /* sct : sibling count */ /* y(i) : examine child bit for siblings 1 to 5 */ /*----------------------------------------------------------------------------*/ #define SD0_sct(sd0) ((sd0)[0] >> 5) #define SD0_y(sd0, i) ((sd0)[0] & (0x10 >> (i))) /*----------------------------------------------------------------------------*/ /* Format-0 Sibling Descriptors macro's (SD0) derived */ /*----------------------------------------------------------------------------*/ /* ccc(i) : indication consecutive child character */ /* ecb(i) : examine child bit, if y then 6th/7th fetched from parent */ /* msc : indication if siblings follows last sibling */ /* sc(i) : sibling character */ /* scs : number of sibling characters */ /*----------------------------------------------------------------------------*/ #define SD0_ccc(sd0, i) (SD0_sc((sd0), (i)) == SD0_sc((sd0), 0)) #define SD0_ecb(sd0, i, cce, y) (((i) < 5) ? SD0_y((sd0), (i)) : (y) ? CCE_y((cce), ((i) - 5)) : 1) #define SD0_msc(sd0) (!SD0_sct((sd0))) #define SD0_sc(sd0, i) ((sd0)[1 + (i)]) #define SD0_scs(sd0) (SD0_msc((sd0)) ? 7 : SD0_sct((sd0))) /*----------------------------------------------------------------------------*/ /* Format-1 Sibling Descriptors macro's (SD1) */ /*----------------------------------------------------------------------------*/ /* sct : sibling count */ /* y(i) : examine child bit for sibling 1 to 12 */ /*----------------------------------------------------------------------------*/ #define SD1_sct(sd1) ((sd1)[0] >> 4) #define SD1_y(sd1, i) ((i) < 4 ? ((sd1)[0] & (0x08 >> (i))) : ((sd1)[1] & (0x800 >> (i)))) /*----------------------------------------------------------------------------*/ /* Format-1 Sibling Descriptors macro's (SD1) derived */ /*----------------------------------------------------------------------------*/ /* ccc(i) : indication consecutive child character */ /* ecb(i) : examine child bit, if y then 13th/14th fetched from parent */ /* msc : indication if siblings follows last sibling */ /* sc(i) : sibling character */ /* scs : number of sibling characters */ /*----------------------------------------------------------------------------*/ #define SD1_ccc(sd1, sd2, i) (SD1_sc((sd1), (sd2), (i)) == SD1_sc((sd1), (sd2), 0)) #define SD1_ecb(sd1, i, cce, y) (((i) < 12) ? SD1_y((sd1), (i)) : (y) ? CCE_y((cce), ((i) - 12)) : 1) #define SD1_msc(sd1) ((SD1_sct((sd1)) == 15)) #define SD1_sc(sd1, sd2, i) ((i) < 6 ? (sd1)[2 + (i)] : (sd2)[(i) - 6]) #define SD1_scs(sd1) (SD1_msc((sd1)) ? 14 : SD1_sct((sd1))) /*----------------------------------------------------------------------------*/ /* Format independent sibling descriptor macro's */ /*----------------------------------------------------------------------------*/ #define SD_ccc(f1, sd1, sd2, i) ((f1) ? SD1_ccc((sd1), (sd2), (i)) : SD0_ccc((sd1), (i))) #define SD_ecb(f1, sd1, i, cce, y) ((f1) ? SD1_ecb((sd1), (i), (cce), (y)) : SD0_ecb((sd1), (i), (cce), (y))) #define SD_msc(f1, sd1) ((f1) ? SD1_msc((sd1)) : SD0_msc((sd1))) #define SD_sc(f1, sd1, sd2, i) ((f1) ? SD1_sc((sd1), (sd2), (i)) : SD0_sc((sd1), (i))) #define SD_scs(f1, sd1) ((f1) ? SD1_scs((sd1)) : SD0_scs((sd1))) /*----------------------------------------------------------------------------*/ /* ADJUSTREGS in compression context */ /*----------------------------------------------------------------------------*/ #define ADJUSTREGSC(cc, r, regs, iregs, len) \ { \ ADJUSTREGS((r), (regs), (iregs), (len)) \ if(likely((cc)->srclen > (len))) \ { \ (cc)->src += (len); \ (cc)->srclen -= (len); \ } \ else \ { \ (cc)->src = NULL; \ (cc)->srclen = 0; \ } \ } #define BIT_get(array, is, ch) ((array)[(is)][(ch) / 8] & (0x80 >> ((ch) % 8))) #define BIT_set(array, is, ch) ((array)[(is)][(ch) / 8] |= (0x80 >> ((ch) % 8))) /*============================================================================*/ /*----------------------------------------------------------------------------*/ /* cmpsc_compress */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(cmpsc_compress)(int r1, int r2, REGS *regs, REGS *iregs) { struct cc cc; /* Compression context */ int i; /* Index */ U16 is; /* Last matched index symbol */ int j; /* Index */ GREG srclen; /* Source length */ /* Initialize compression context */ cc.dctsz = GR0_dctsz(regs); memset(cc.deadadm, 0, sizeof(cc.deadadm)); cc.dest = NULL; memset(cc.dict, 0, sizeof(cc.dict)); memset(cc.edict, 0, sizeof(cc.edict)); cc.dictor = GR1_dictor(iregs); cc.f1 = GR0_f1(regs); cc.iregs = iregs; cc.r1 = r1; cc.r2 = r2; cc.regs = regs; cc.smbsz = GR0_smbsz(regs); cc.src = NULL; cc.srclen = 0; cc.st = GR0_st(regs) ? 1 : 0; /* Initialize values */ srclen = GR_A(cc.r2 + 1, cc.iregs); /*--------------------------------------------------------------------------*/ /* Process individual index symbols until cbn becomes zero */ while(unlikely(GR1_cbn(cc.iregs))) { if(unlikely(ARCH_DEP(cmpsc_compress_single_is)(&cc))) return; } /*--------------------------------------------------------------------------*/ /* Block processing, cbn stays zero */ while(likely(GR_A(cc.r1 + 1, cc.iregs) >= cc.smbsz)) { for(i = 0; i < 8; i++) { /* Get the next character, return on end of source */ if(unlikely(!cc.src && ARCH_DEP(cmpsc_fetch_ch)(&cc))) { /* Write individual found index symbols */ for(j = 0; j < i; j++) ARCH_DEP(cmpsc_store_is)(&cc, cc.is[j]); COMMITREGS(cc.regs, cc.iregs, cc.r1, cc.r2); return; } #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_ch : %02X at " F_VADR "\n", *cc.src, GR_A(cc.r2, cc.iregs)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Set the alphabet entry, adjust registers and initiate charcters read */ is = *cc.src; ADJUSTREGSC(&cc, cc.r2, cc.regs, cc.iregs, 1); cc.cr = 1; /* Check for alphabet entry ch dead end combination */ if(unlikely(!(cc.src && BIT_get(cc.deadadm, is, *cc.src)))) { /* Get the alphabet entry and try to find a child */ cc.cce = ARCH_DEP(cmpsc_fetch_cce)(&cc, is); while(ARCH_DEP(cmpsc_search_cce)(&cc, &is)) { /* Check for other dead end combination */ if(unlikely(cc.src && BIT_get(cc.deadadm, is, *cc.src))) { #ifdef OPTION_CMPSC_DEBUG logmsg("dead end : %04X %02X encountered\n", is, *cc.src); #endif /* #ifdef OPTION_CMPSC_DEBUG */ break; } } /* Registrate possible found dead ends */ if(unlikely(cc.deadend && cc.src)) { #ifdef OPTION_CMPSC_DEBUG logmsg("dead end : %04X in combination with", is); for(j = 0; j < 0x100; j++) { if(!(j % 16)) logmsg("\n :"); if(BIT_get(cc.searchadm, 0, j)) logmsg(" "); else logmsg(" %02X", j); } logmsg("\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Registrate all discovered dead ends */ for(j = 0; j < 0x100 / 8; j++) cc.deadadm[is][j] = ~cc.searchadm[0][j]; } } #ifdef OPTION_CMPSC_DEBUG else logmsg("dead end : %04X %02X encountered\n", is, *cc.src); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Write the last match */ cc.is[i] = is; #ifdef OPTION_CMPSC_DEBUG logmsg("compress : is %04X (%d)\n", is, i); #endif /* #ifdef OPTION_CMPSC_DEBUG */ } /* Write index symbols and commit */ ARCH_DEP(cmpsc_store_iss)(&cc); COMMITREGS2(cc.regs, cc.iregs, cc.r1, cc.r2); /* Return with cc3 on interrupt pending after a minumum size of processing */ if(unlikely(srclen - GR_A(cc.r2 + 1, cc.iregs) >= MINPROC_SIZE && INTERRUPT_PENDING(cc.regs))) { #ifdef OPTION_CMPSC_DEBUG logmsg("Interrupt pending, commit and return with cc3\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ cc.regs->psw.cc = 3; return; } } /*--------------------------------------------------------------------------*/ /* Process individual index symbols until end of destination (or source) */ while(!likely(ARCH_DEP(cmpsc_compress_single_is)(&cc))); } /*----------------------------------------------------------------------------*/ /* cmpsc_compress_single_is */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_compress_single_is)(struct cc *cc) { int i; /* Index */ U16 is; /* index symbol */ /* Get the next character, return -1 on end of source */ if(unlikely(!cc->src && ARCH_DEP(cmpsc_fetch_ch)(cc))) return(-1); #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_ch : %02X at " F_VADR "\n", *cc->src, GR_A(cc->r2, cc->iregs)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Set the alphabet entry, adjust registers and initiate characters read */ is = *cc->src; ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, 1); cc->cr = 1; /* Search for child when no src and no dead end combination */ if(unlikely(!(cc->src && BIT_get(cc->deadadm, is, *cc->src)))) { /* Get the alphabet entry and try to find a child */ cc->cce = ARCH_DEP(cmpsc_fetch_cce)(cc, is); while(ARCH_DEP(cmpsc_search_cce)(cc, &is)) { /* Check for (found cce entry + ch) dead end combination */ if(unlikely(cc->src && BIT_get(cc->deadadm, is, *cc->src))) { #ifdef OPTION_CMPSC_DEBUG logmsg("dead end : %04X %02X encountered\n", is, *cc->src); #endif /* #ifdef OPTION_CMPSC_DEBUG */ break; } } /* Registrate possible found dead ends */ if(unlikely(cc->deadend && cc->src)) { #ifdef OPTION_CMPSC_DEBUG logmsg("dead end : %04X in combination with", is); for(i = 0; i < 0x100; i++) { if(!(i % 16)) logmsg("\n :"); if(BIT_get(cc->searchadm, 0, i)) logmsg(" "); else logmsg(" %02X", i); } logmsg("\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Registrate all discovered dead ends */ for(i = 0; i < 0x100 / 8; i++) cc->deadadm[is][i] = ~cc->searchadm[0][i]; } } #ifdef OPTION_CMPSC_DEBUG else logmsg("dead end : %04X %02X encountered\n", is, *cc->src); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Write the last match, return on end of destination */ if(unlikely(ARCH_DEP(cmpsc_store_is)(cc, is))) return(-1); /* Commit registers */ COMMITREGS(cc->regs, cc->iregs, cc->r1, cc->r2); return(0); } /*----------------------------------------------------------------------------*/ /* cmpsc_fetch_cce (compression character entry) */ /*----------------------------------------------------------------------------*/ static BYTE *ARCH_DEP(cmpsc_fetch_cce)(struct cc *cc, unsigned index) { BYTE *cce; /* Compression child entry */ unsigned cct; /* Child count */ index *= 8; if(unlikely(!cc->dict[index / 0x800])) cc->dict[index / 0x800] = MADDR((cc->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey); cce = &cc->dict[index / 0x800][index % 0x800]; ITIMER_SYNC((cc->dictor + index) & ADDRESS_MAXWRAP(cc->regs), 8 - 1, cc->regs); #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_cce: index %04X\n", index / 8); cmpsc_print_cce(cce); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Check for data exception */ cct = CCE_cct(cce); if(cct < 2) { if(unlikely(CCE_act(cce) > 4)) { cc->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION); } } else { if(!CCE_d(cce)) { if(unlikely(cct == 7)) { cc->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION); } } else { if(unlikely(cct > 5)) { cc->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION); } } } return(cce); } /*----------------------------------------------------------------------------*/ /* cmpsc_fetch_ch (character) */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_fetch_ch)(struct cc *cc) { /* Check for end of source condition */ if(unlikely(!GR_A(cc->r2 + 1, cc->iregs))) { #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_ch : reached end of source\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ cc->regs->psw.cc = 0; return(-1); } /* Calculate source length in page */ cc->srclen = 0x800 - (GR_A(cc->r2, cc->iregs) & 0x7ff); if(unlikely(GR_A(cc->r2 + 1, cc->iregs) < cc->srclen)) cc->srclen = GR_A(cc->r2 + 1, cc->iregs); /* Get address */ cc->src = MADDR(GR_A(cc->r2, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey); return(0); } #ifndef NO_2ND_COMPILE #ifdef OPTION_CMPSC_DEBUG /*----------------------------------------------------------------------------*/ /* cmpsc_print_cce (compression character entry) */ /*----------------------------------------------------------------------------*/ static void cmpsc_print_cce(BYTE *cce) { int j; /* Index */ int prt_detail; /* Switch for detailed printing */ logmsg(" cce : "); prt_detail = 0; for(j = 0; j < 8; j++) { if(!prt_detail && cce[j]) prt_detail = 1; logmsg("%02X", cce[j]); } logmsg("\n"); if(prt_detail) { logmsg(" cct : %d\n", CCE_cct(cce)); switch(CCE_cct(cce)) { case 0: { logmsg(" act : %d\n", (int) CCE_act(cce)); if(CCE_act(cce)) { logmsg(" ec(s) :"); for(j = 0; j < CCE_ecs(cce); j++) logmsg(" %02X", CCE_ec(cce, j)); logmsg("\n"); } break; } case 1: { logmsg(" x1 : %c\n", (int) (CCE_x(cce, 0) ? '1' : '0')); logmsg(" act : %d\n", (int) CCE_act(cce)); logmsg(" cptr : %04X\n", CCE_cptr(cce)); if(CCE_act(cce)) { logmsg(" ec(s) :"); for(j = 0; j < CCE_ecs(cce); j++) logmsg(" %02X", CCE_ec(cce, j)); logmsg("\n"); } logmsg(" cc : %02X\n", CCE_cc(cce, 0)); break; } default: { logmsg(" x1..x5 : "); for(j = 0; j < 5; j++) logmsg("%c", (int) (CCE_x(cce, j) ? '1' : '0')); logmsg("\n y1..y2 : "); for(j = 0; j < 2; j++) logmsg("%c", (int) (CCE_y(cce, j) ? '1' : '0')); logmsg("\n d : %s\n", TRUEFALSE(CCE_d(cce))); logmsg(" cptr : %04X\n", CCE_cptr(cce)); if(CCE_d(cce)) logmsg(" ec : %02X\n", CCE_ec(cce, 0)); logmsg(" ccs :"); for(j = 0; j < CCE_ccs(cce); j++) logmsg(" %02X", CCE_cc(cce, j)); logmsg("\n"); break; } } } } /*----------------------------------------------------------------------------*/ /* cmpsc_print_sd (sibling descriptor) */ /*----------------------------------------------------------------------------*/ static void cmpsc_print_sd(int f1, BYTE *sd1, BYTE *sd2) { int j; /* Index */ int prt_detail; /* Switch for detailed printing */ if(f1) { logmsg(" sd1 : "); prt_detail = 0; for(j = 0; j < 8; j++) { if(!prt_detail && sd1[j]) prt_detail = 1; logmsg("%02X", sd1[j]); } for(j = 0; j < 8; j++) { if(!prt_detail && sd2[j]) prt_detail = 1; logmsg("%02X", sd2[j]); } logmsg("\n"); if(prt_detail) { logmsg(" sct : %d\n", SD1_sct(sd1)); logmsg(" y1..y12: "); for(j = 0; j < 12; j++) logmsg("%c", (SD1_y(sd1, j) ? '1' : '0')); logmsg("\n sc(s) :"); for(j = 0; j < SD1_scs(sd1); j++) logmsg(" %02X", SD1_sc(sd1, sd2, j)); logmsg("\n"); } } else { logmsg(" sd0 : "); prt_detail = 0; for(j = 0; j < 8; j++) { if(!prt_detail && sd1[j]) prt_detail = 1; logmsg("%02X", sd1[j]); } logmsg("\n"); if(prt_detail) { logmsg(" sct : %d\n", SD0_sct(sd1)); logmsg(" y1..y5 : "); for(j = 0; j < 5; j++) logmsg("%c", (SD0_y(sd1, j) ? '1' : '0')); logmsg("\n sc(s) :"); for(j = 0; j < SD0_scs(sd1); j++) logmsg(" %02X", SD0_sc(sd1, j)); logmsg("\n"); } } } #endif /* #ifdef OPTION_CMPSC_DEBUG */ #endif /* #ifndef NO_2ND_COMPILE */ /*----------------------------------------------------------------------------*/ /* cmpsc_search_cce (compression character entry) */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_search_cce)(struct cc *cc, U16 *is) { BYTE *ccce; /* Child compression character entry */ int ccs; /* Number of child characters */ int i; /* Child character index */ int ind_search_siblings; /* Indicator for searching siblings */ /* Initialize values */ ccs = CCE_ccs(cc->cce); /* Get the next character when there are children */ if(likely(ccs)) { if(unlikely(!cc->src && ARCH_DEP(cmpsc_fetch_ch(cc)))) return(0); #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_ch : %02X at " F_VADR "\n", *cc->src, GR_A(cc->r2, cc->iregs)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Check for reading character 261 */ cc->cr++; if(unlikely(cc->cr > 260)) { #ifdef OPTION_CMPSC_DEBUG logmsg("Trying to read character #%d\n", cc->cr); #endif /* #ifdef OPTION_CMPSC_DEBUG */ cc->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION); } memset(cc->searchadm, 0, sizeof(cc->searchadm)); cc->deadend = 1; ind_search_siblings = 1; /* Now check all children in parent */ for(i = 0; i < ccs; i++) { /* Stop searching when child tested and no consecutive child character */ if(unlikely(!ind_search_siblings && !CCE_ccc(cc->cce, i))) return(0); /* Compare character with child */ if(unlikely(*cc->src == CCE_cc(cc->cce, i))) { /* Child is tested, so stop searching for siblings and no dead end */ ind_search_siblings = 0; cc->deadend = 0; /* Check if child should not be examined */ if(unlikely(!CCE_x(cc->cce, i))) { /* No need to examine child, found the last match */ ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, 1); *is = CCE_cptr(cc->cce) + i; return(0); } /* Found a child get the character entry and check if additional extension characters match */ ccce = ARCH_DEP(cmpsc_fetch_cce)(cc, CCE_cptr(cc->cce) + i); if(likely(!CCE_ecs(ccce) || !ARCH_DEP(cmpsc_test_ec)(cc, ccce))) { /* Set last match */ ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, (U32) CCE_ecs(ccce) + 1); *is = CCE_cptr(cc->cce) + i; #ifdef OPTION_CMPSC_DEBUG logmsg("search_cce index %04X parent\n", *is); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Found a matching child, make it parent and keep searching */ cc->cce = ccce; return(1); } } BIT_set(cc->searchadm, 0, CCE_cc(cc->cce, i)); } /* Are there siblings? */ if(likely(CCE_mcc(cc->cce))) return(ARCH_DEP(cmpsc_search_sd)(cc, is)); } else { /* No children, no extension character, always a dead end */ if(!CCE_act(cc->cce)) { #ifdef OPTION_CMPSC_DEBUG logmsg("dead end : %04X permanent dead end discovered\n", *is); #endif /* #ifdef OPTION_CMPSC_DEBUG */ memset(&cc->deadadm[*is], 0xff, 0x100 / 8); } cc->deadend = 0; } /* No siblings, write found index symbol */ return(0); } /*----------------------------------------------------------------------------*/ /* cmpsc_search_sd (sibling descriptor) */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_search_sd)(struct cc *cc, U16 *is) { BYTE *ccce; /* Child compression character entry */ int i; /* Sibling character index */ int ind_search_siblings; /* Indicator for keep searching */ U16 index; /* Index within dictionary */ int scs; /* Number of sibling characters */ BYTE *sd1; /* Sibling descriptor fmt-0|1 part 1 */ BYTE *sd2 = NULL; /* Sibling descriptor fmt-1 part 2 */ int sd_ptr; /* Pointer to sibling descriptor */ int y_in_parent; /* Indicator if y bits are in parent */ /* Initialize values */ ind_search_siblings = 1; sd_ptr = CCE_ccs(cc->cce); y_in_parent = 1; do { /* Get the sibling descriptor */ index = (CCE_cptr(cc->cce) + sd_ptr) * 8; if(unlikely(!cc->dict[index / 0x800])) cc->dict[index / 0x800] = MADDR((cc->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey); sd1 = &cc->dict[index / 0x800][index % 0x800]; ITIMER_SYNC((cc->dictor + index) & ADDRESS_MAXWRAP(cc->regs), 8 - 1, cc->regs); /* If format-1, get second half from the expansion dictionary */ if(cc->f1) { if(unlikely(!cc->edict[index / 0x800])) cc->edict[index / 0x800] = MADDR((cc->dictor + cc->dctsz + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey); sd2 = &cc->edict[index / 0x800][index % 0x800]; ITIMER_SYNC((cc->dictor + cc->dctsz + index) & ADDRESS_MAXWRAP(cc->regs), 8 - 1, cc->regs); #ifdef OPTION_CMPSC_DEBUG /* Print before possible exception */ logmsg("fetch_sd1: index %04X\n", CCE_cptr(cc->cce) + sd_ptr); cmpsc_print_sd(1, sd1, sd2); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Check for data exception */ if(unlikely(!SD1_sct(sd1))) { cc->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)((cc->regs), PGM_DATA_EXCEPTION); } } #ifdef OPTION_CMPSC_DEBUG else { logmsg("fetch_sd0: index %04X\n", CCE_cptr(cc->cce) + sd_ptr); cmpsc_print_sd(0, sd1, sd2); } #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Check all children in sibling descriptor */ scs = SD_scs(cc->f1, sd1); for(i = 0; i < scs; i++) { /* Stop searching when child tested and no consecutive child character */ if(unlikely(!ind_search_siblings && !SD_ccc(cc->f1, sd1, sd2, i))) return(0); if(unlikely(*cc->src == SD_sc(cc->f1, sd1, sd2, i))) { /* Child is tested, so stop searching for siblings and no dead end */ ind_search_siblings = 0; cc->deadend = 0; /* Check if child should not be examined */ if(unlikely(!SD_ecb(cc->f1, sd1, i, cc->cce, y_in_parent))) { /* No need to examine child, found the last match */ ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, 1); *is = CCE_cptr(cc->cce) + sd_ptr + i + 1; return(0); } /* Found a child get the character entry and check if additional extension characters match */ ccce = ARCH_DEP(cmpsc_fetch_cce)(cc, CCE_cptr(cc->cce) + sd_ptr + i + 1); if(likely(!CCE_ecs(ccce) || !ARCH_DEP(cmpsc_test_ec)(cc, ccce))) { /* Set last match */ ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, (U32) CCE_ecs(ccce) + 1); *is = CCE_cptr(cc->cce) + sd_ptr + i + 1; #ifdef OPTION_CMPSC_DEBUG logmsg("search_sd: index %04X parent\n", *is); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Found a matching child, make it parent and keep searching */ cc->cce = ccce; return(1); } } BIT_set(cc->searchadm, 0, SD_sc(cc->f1, sd1, sd2, i)); } /* Next sibling follows last possible child */ sd_ptr += scs + 1; /* We get the next sibling descriptor, no y bits in parent for him */ y_in_parent = 0; } while(ind_search_siblings && SD_msc(cc->f1, sd1)); return(0); } /*----------------------------------------------------------------------------*/ /* cmpsc_store_is (index symbol) */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_store_is)(struct cc *cc, U16 is) { unsigned cbn; /* Compressed-data bit number */ U32 set_mask; /* Mask to set the bits */ BYTE work[3]; /* Work bytes */ /* Initialize values */ cbn = GR1_cbn(cc->iregs); /* Can we write an index or interchange symbol */ if(unlikely(GR_A(cc->r1 + 1, cc->iregs) < 3 && ((cbn + cc->smbsz - 1) / 8) >= GR_A(cc->r1 + 1, cc->iregs))) { cc->regs->psw.cc = 1; #ifdef OPTION_CMPSC_DEBUG logmsg("store_is : end of output buffer\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ return(-1); } /* Check if symbol translation is requested */ if(unlikely(cc->st)) { /* Get the interchange symbol */ ARCH_DEP(vfetchc)(work, 1, (cc->dictor + GR1_sttoff(cc->iregs) + is * 2) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs); #ifdef OPTION_CMPSC_DEBUG logmsg("store_is : %04X -> %02X%02X\n", is, work[0], work[1]); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* set index_symbol to interchange symbol */ is = (work[0] << 8) + work[1]; } /* Allign set mask */ set_mask = ((U32) is) << (24 - cc->smbsz - cbn); /* Calculate first byte */ if(likely(cbn)) { work[0] = ARCH_DEP(vfetchb)(GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs); work[0] |= (set_mask >> 16) & 0xff; } else work[0] = (set_mask >> 16) & 0xff; /* Calculate second byte */ work[1] = (set_mask >> 8) & 0xff; /* Calculate possible third byte and store */ if(unlikely((cc->smbsz + cbn) > 16)) { work[2] = set_mask & 0xff; ARCH_DEP(vstorec)(work, 2, GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs); } else ARCH_DEP(vstorec)(work, 1, GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs); /* Adjust destination registers */ ADJUSTREGS(cc->r1, cc->regs, cc->iregs, (cbn + cc->smbsz) / 8); /* Calculate and set the new Compressed-data Bit Number */ GR1_setcbn(cc->iregs, (cbn + cc->smbsz) % 8); #ifdef OPTION_CMPSC_DEBUG logmsg("store_is : %04X, cbn=%d, GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", is, GR1_cbn(cc->iregs), cc->r1, cc->iregs->GR(cc->r1), cc->r1 + 1, cc->iregs->GR(cc->r1 + 1)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ return(0); } /*----------------------------------------------------------------------------*/ /* cmpsc_store_iss (index symbols) */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(cmpsc_store_iss)(struct cc *cc) { GREG dictor; /* Dictionary origin */ int i; U16 *is; /* Index symbol array */ unsigned len1; /* Length in first page */ BYTE *main1; /* Address first page */ BYTE mem[13]; /* Build buffer */ unsigned ofst; /* Offset within page */ BYTE *sk; /* Storage key */ /* Check if symbol translation is requested */ if(unlikely(cc->st)) { dictor = cc->dictor + GR1_sttoff(cc->iregs); for(i = 0; i < 8; i++) { /* Get the interchange symbol */ ARCH_DEP(vfetchc)(mem, 1, (dictor + cc->is[i] * 2) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs); #ifdef OPTION_CMPSC_DEBUG logmsg("store_iss: %04X -> %02X%02X\n", cc->is[i], mem[0], mem[1]); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* set index_symbol to interchange symbol */ cc->is[i] = (mem[0] << 8) + mem[1]; } } /* Calculate buffer for 8 index symbols */ is = cc->is; switch(cc->smbsz) { case 9: /* 9-bits */ { /* 0 1 2 3 4 5 6 7 8 */ /* 012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 012345678012345678012345678012345678012345678012345678012345678012345678 */ /* 0 1 2 3 4 5 6 7 */ mem[0] = ( (is[0] >> 1)); mem[1] = ((is[0] << 7) | (is[1] >> 2)); mem[2] = ((is[1] << 6) | (is[2] >> 3)); mem[3] = ((is[2] << 5) | (is[3] >> 4)); mem[4] = ((is[3] << 4) | (is[4] >> 5)); mem[5] = ((is[4] << 3) | (is[5] >> 6)); mem[6] = ((is[5] << 2) | (is[6] >> 7)); mem[7] = ((is[6] << 1) | (is[7] >> 8)); mem[8] = ((is[7]) ); break; } case 10: /* 10-bits */ { /* 0 1 2 3 4 5 6 7 8 9 */ /* 01234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */ /* 0 1 2 3 4 5 6 7 */ mem[0] = ( (is[0] >> 2)); mem[1] = ((is[0] << 6) | (is[1] >> 4)); mem[2] = ((is[1] << 4) | (is[2] >> 6)); mem[3] = ((is[2] << 2) | (is[3] >> 8)); mem[4] = ((is[3]) ); mem[5] = ( (is[4] >> 2)); mem[6] = ((is[4] << 6) | (is[5] >> 4)); mem[7] = ((is[5] << 4) | (is[6] >> 6)); mem[8] = ((is[6] << 2) | (is[7] >> 8)); mem[9] = ((is[7]) ); break; } case 11: /* 11-bits */ { /* 0 1 2 3 4 5 6 7 8 9 a */ /* 0123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a */ /* 0 1 2 3 4 5 6 7 */ mem[ 0] = ( (is[0] >> 3)); mem[ 1] = ((is[0] << 5) | (is[1] >> 6)); mem[ 2] = ((is[1] << 2) | (is[2] >> 9)); mem[ 3] = ( (is[2] >> 1)); mem[ 4] = ((is[2] << 7) | (is[3] >> 4)); mem[ 5] = ((is[3] << 4) | (is[4] >> 7)); mem[ 6] = ((is[4] << 1) | (is[5] >> 10)); mem[ 7] = ( (is[5] >> 2)); mem[ 8] = ((is[5] << 6) | (is[6] >> 5)); mem[ 9] = ((is[6] << 3) | (is[7] >> 8)); mem[10] = ((is[7]) ); break; } case 12: /* 12-bits */ { /* 0 1 2 3 4 5 6 7 8 9 a b */ /* 012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab */ /* 0 1 2 3 4 5 6 7 */ mem[ 0] = ( (is[0] >> 4)); mem[ 1] = ((is[0] << 4) | (is[1] >> 8)); mem[ 2] = ((is[1]) ); mem[ 3] = ( (is[2] >> 4)); mem[ 4] = ((is[2] << 4) | (is[3] >> 8)); mem[ 5] = ((is[3]) ); mem[ 6] = ( (is[4] >> 4)); mem[ 7] = ((is[4] << 4) | (is[5] >> 8)); mem[ 8] = ((is[5]) ); mem[ 9] = ( (is[6] >> 4)); mem[10] = ((is[6] << 4) | (is[7] >> 8)); mem[11] = ((is[7]) ); break; } case 13: /* 13-bits */ { /* 0 1 2 3 4 5 6 7 8 9 a b c */ /* 01234567012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc */ /* 0 1 2 3 4 5 6 7 */ mem[ 0] = ( (is[0] >> 5)); mem[ 1] = ((is[0] << 3) | (is[1] >> 10)); mem[ 2] = ( (is[1] >> 2)); mem[ 3] = ((is[1] << 6) | (is[2] >> 7)); mem[ 4] = ((is[2] << 1) | (is[3] >> 12)); mem[ 5] = ( (is[3] >> 4)); mem[ 6] = ((is[3] << 4) | (is[4] >> 9)); mem[ 7] = ( (is[4] >> 1)); mem[ 8] = ((is[4] << 7) | (is[5] >> 6)); mem[ 9] = ((is[5] << 2) | (is[6] >> 11)); mem[10] = ( (is[6] >> 3)); mem[11] = ((is[6] << 5) | (is[7] >> 8)); mem[12] = ((is[7]) ); break; } } /* Fingers crossed that we stay within one page */ ofst = GR_A(cc->r1, cc->iregs) & 0x7ff; if(likely(ofst + cc->smbsz <= 0x800)) { if(unlikely(!cc->dest)) cc->dest = MADDR((GR_A(cc->r1, cc->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs, ACCTYPE_WRITE, cc->regs->psw.pkey); memcpy(&cc->dest[ofst], mem, cc->smbsz); ITIMER_UPDATE(GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->smbsz - 1, cc->regs); /* Perfect fit? */ if(unlikely(ofst + cc->smbsz == 0x800)) cc->dest = NULL; } else { /* We need 2 pages */ if(unlikely(!cc->dest)) main1 = MADDR((GR_A(cc->r1, cc->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs, ACCTYPE_WRITE_SKP, cc->regs->psw.pkey); else main1 = cc->dest; sk = cc->regs->dat.storkey; len1 = 0x800 - ofst; cc->dest = MADDR((GR_A(cc->r1, cc->iregs) + len1) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs, ACCTYPE_WRITE, cc->regs->psw.pkey); memcpy(&main1[ofst], mem, len1); memcpy(cc->dest, &mem[len1], cc->smbsz - len1); *sk |= (STORKEY_REF | STORKEY_CHANGE); } ADJUSTREGS(cc->r1, cc->regs, cc->iregs, cc->smbsz); #ifdef OPTION_CMPSC_DEBUG logmsg("store_iss:"); for(i = 0; i < 8; i++) logmsg(" %04X", cc->is[i]); logmsg(", GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", cc->r1, cc->iregs->GR(cc->r1), cc->r1 + 1, cc->iregs->GR(cc->r1 + 1)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ } /*----------------------------------------------------------------------------*/ /* cmpsc_test_ec (extension characters) */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_test_ec)(struct cc *cc, BYTE *cce) { BYTE buf[4]; /* Cross page buffer */ BYTE *src; /* Source pointer */ /* No dead end */ cc->deadend = 0; /* Get address of source */ if(likely(cc->srclen > (unsigned) CCE_ecs(cce))) { src = &cc->src[1]; ITIMER_SYNC((GR_A(cc->r2, cc->iregs) + 1) & ADDRESS_MAXWRAP(cc->regs), CCE_ecs(cce) - 1, cc->regs); } else { /* Return nomatch on end of source condition */ if(unlikely(GR_A(cc->r2 + 1, cc->iregs) <= (unsigned) CCE_ecs(cce))) return(1); /* Get the cross page data */ ARCH_DEP(vfetchc)(buf, CCE_ecs(cce) - 1, (GR_A(cc->r2, cc->iregs) + 1) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs); src = buf; } /* Compare additional extension characters */ if(!memcmp(src, &CCE_ec(cce, 0), CCE_ecs(cce))) { /* Check for reading character 261 */ cc->cr += CCE_ecs(cce); if(unlikely(cc->cr > 260)) { #ifdef OPTION_CMPSC_DEBUG logmsg("Trying to read character #%d\n", cc->cr); #endif /* #ifdef OPTION_CMSPC_DEBUG */ cc->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION); } return(0); } else return(1); } /*============================================================================*/ /* Expand */ /*============================================================================*/ /*----------------------------------------------------------------------------*/ /* Expansion Character Entry macro's (ECE) */ /*----------------------------------------------------------------------------*/ /* bit34 : indication of bits 3 and 4 (what else ;-) */ /* csl : complete symbol length */ /* ofst : offset from current position in output area */ /* pptr : predecessor pointer */ /* psl : partial symbol length */ /*----------------------------------------------------------------------------*/ #define ECE_bit34(ece) ((ece)[0] & 0x18) #define ECE_csl(ece) ((ece)[0] & 0x07) #define ECE_ofst(ece) ((ece)[7]) #define ECE_pptr(ece) ((((ece)[0] & 0x1f) << 8) | (ece)[1]) #define ECE_psl(ece) ((ece)[0] >> 5) /*----------------------------------------------------------------------------*/ /* cmpsc_expand */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(cmpsc_expand)(int r1, int r2, REGS *regs, REGS *iregs) { GREG destlen; /* Destination length */ struct ec ec; /* Expand cache */ int i; /* Index */ U16 iss[8] = {0}; /* Index symbols */ /* Initialize values */ destlen = GR_A(r1 + 1, iregs); /* Initialize expansion context */ ec.dest = NULL; ec.dictor = GR1_dictor(iregs); memset(ec.dict, 0, sizeof(ec.dict)); /* Initialize expanded index symbol cache and prefill with alphabet entries */ memset(ec.ecl, 0, sizeof(ec.ecl)); for(i = 0; i < 256; i++) /* Alphabet entries */ { ec.ec[i] = i; ec.eci[i] = i; ec.ecl[i] = 1; } ec.ecwm = 256; /* Set watermark after alphabet part */ ec.iregs = iregs; ec.r1 = r1; ec.r2 = r2; ec.regs = regs; ec.smbsz = GR0_smbsz(regs); ec.src = NULL; #ifdef OPTION_CMPSC_DEBUG ec.dbgac = 0; ec.dbgbi = 0; ec.dbgbo = 0; ec.dbgch = 0; ec.dbgiss = 0; #endif /* #ifdef OPTION_CMPSC_DEBUG */ /*--------------------------------------------------------------------------*/ /* Process individual index symbols until cbn becomes zero */ while(unlikely(GR1_cbn(ec.iregs))) { if(unlikely(ARCH_DEP(cmpsc_expand_single_is)(&ec))) return; } /*--------------------------------------------------------------------------*/ /* Block processing, cbn stays zero */ while(likely(GR_A(ec.r2 + 1, ec.iregs) >= ec.smbsz)) { ARCH_DEP(cmpsc_fetch_iss)(&ec, iss); ec.ocl = 0; /* Initialize output cache */ for(i = 0; i < 8; i++) { #ifdef OPTION_CMPSC_DEBUG logmsg("expand : is %04X (%d)\n", iss[i], i); ec.dbgiss++; #endif /* #ifdef OPTION_CMPSC_DEBUG */ if(unlikely(!ec.ecl[iss[i]])) ARCH_DEP(cmpsc_expand_is)(&ec, iss[i]); else { memcpy(&ec.oc[ec.ocl], &ec.ec[ec.eci[iss[i]]], ec.ecl[iss[i]]); ec.ocl += ec.ecl[iss[i]]; #ifdef OPTION_CMPSC_DEBUG if(iss[i] < 0x100) ec.dbgac++; else ec.dbgch++; #endif /* #ifdef OPTION_CMPSC_DEBUG */ } } #ifdef OPTION_CMPSC_DEBUG ec.dbgbi += ec.smbsz; ec.dbgbo += ec.ocl; logmsg("Stats: iss %6u; ach %6u: %3d%; hts %6u: %3d%; bin %6u, out %6u: %6d%\n", ec.dbgiss, ec.dbgac, ec.dbgac * 100 / ec.dbgiss, ec.dbgch, ec.dbgch * 100 / ec.dbgiss, ec.dbgbi, ec.dbgbo, ec.dbgbo * 100 / ec.dbgbi); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Write and commit, cbn unchanged, so no commit for GR1 needed */ if(unlikely(ARCH_DEP(cmpsc_vstore)(&ec, ec.oc, ec.ocl))) return; /* Commit registers */ COMMITREGS2(ec.regs, ec.iregs, ec.r1, ec.r2); /* Return with cc3 on interrupt pending */ if(unlikely(destlen - GR_A(ec.r1 + 1, ec.iregs) >= MINPROC_SIZE && INTERRUPT_PENDING(ec.regs))) { #ifdef OPTION_CMPSC_DEBUG logmsg("Interrupt pending, commit and return with cc3\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ ec.regs->psw.cc = 3; return; } } /*--------------------------------------------------------------------------*/ /* Process individual index symbols until end of source (or destination) */ while(likely(!ARCH_DEP(cmpsc_expand_single_is)(&ec))); } /*----------------------------------------------------------------------------*/ /* cmpsc_expand_is (index symbol) */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(cmpsc_expand_is)(struct ec *ec, U16 is) { int csl; /* Complete symbol length */ unsigned cw; /* Characters written */ BYTE *ece; /* Expansion Character Entry */ U16 index; /* Index within dictionary */ int psl; /* Partial symbol length */ /* Initialize values */ cw = 0; /* Get expansion character entry */ index = is * 8; if(unlikely(!ec->dict[index / 0x800])) ec->dict[index / 0x800] = MADDR((ec->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey); ece = &ec->dict[index / 0x800][index % 0x800]; ITIMER_SYNC((ec->dictor + index) & ADDRESS_MAXWRAP(ec->regs), 8 - 1, ec->regs); #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_ece: index %04X\n", is); cmpsc_print_ece(ece); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Process preceded entries */ psl = ECE_psl(ece); while(likely(psl)) { /* Count and check for writing child 261 and check valid psl */ cw += psl; if(unlikely(cw > 260 || psl > 5)) { #ifdef OPTION_CMPSC_DEBUG if(cw > 260) logmsg("Trying to write character #%d\n", cw); #endif /* #ifdef OPTION_CMPSC_DEBUG */ ec->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)((ec->regs), PGM_DATA_EXCEPTION); } /* Process extension characters in preceded entry */ memcpy(&ec->oc[ec->ocl + ECE_ofst(ece)], &ece[2], psl); /* Get preceding entry */ index = ECE_pptr(ece) * 8; if(unlikely(!ec->dict[index / 0x800])) ec->dict[index / 0x800] = MADDR((ec->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey); ece = &ec->dict[index / 0x800][index % 0x800]; ITIMER_SYNC((ec->dictor + index) & ADDRESS_MAXWRAP(ec->regs), 8 - 1, ec->regs); #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_ece: index %04X\n", index / 8); cmpsc_print_ece(ece); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Calculate partial symbol length */ psl = ECE_psl(ece); } /* Count and check for writing child 261, valid csl and invalid bits */ csl = ECE_csl(ece); cw += csl; if(unlikely(cw > 260 || !csl || ECE_bit34(ece))) { #ifdef OPTION_CMPSC_DEBUG if(cw > 260) logmsg("Trying to write character #%d\n", cw); #endif /* #ifdef OPTION_CMPSC_DEBUG */ ec->regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt)((ec->regs), PGM_DATA_EXCEPTION); } /* Process extension characters in unpreceded entry */ memcpy(&ec->oc[ec->ocl], &ece[1], csl); /* Place within cache */ memcpy(&ec->ec[ec->ecwm], &ec->oc[ec->ocl], cw); ec->eci[is] = ec->ecwm; ec->ecl[is] = cw; ec->ecwm += cw; /* Commit in output buffer */ ec->ocl += cw; } /*----------------------------------------------------------------------------*/ /* cmpsc_expand_single_is (index symbol) */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_expand_single_is)(struct ec *ec) { U16 is; /* Index symbol */ if(unlikely(ARCH_DEP(cmpsc_fetch_is)(ec, &is))) return(-1); if(!ec->ecl[is]) { ec->ocl = 0; /* Initialize output cache */ ARCH_DEP(cmpsc_expand_is)(ec, is); if(unlikely(ARCH_DEP(cmpsc_vstore)(ec, ec->oc, ec->ocl))) return(-1); } else { if(unlikely(ARCH_DEP(cmpsc_vstore)(ec, &ec->ec[ec->eci[is]], ec->ecl[is]))) return(-1); } /* Commit, including GR1 */ COMMITREGS(ec->regs, ec->iregs, ec->r1, ec->r2); return(0); } /*----------------------------------------------------------------------------*/ /* cmpsc_fetch_is (index symbol) */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_fetch_is)(struct ec *ec, U16 *is) { unsigned cbn; /* Compressed-data bit number */ U32 mask; /* Working mask */ BYTE work[3]; /* Working field */ /* Initialize values */ cbn = GR1_cbn(ec->iregs); /* Check if we can read an index symbol */ if(unlikely(GR_A(ec->r2 + 1, ec->iregs) < 3 && ((cbn + ec->smbsz - 1) / 8) >= GR_A(ec->r2 + 1, ec->iregs))) { #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_is : reached end of source\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ ec->regs->psw.cc = 0; return(-1); } /* Clear possible fetched 3rd byte */ work[2] = 0; ARCH_DEP(vfetchc)(&work, (ec->smbsz + cbn - 1) / 8, GR_A(ec->r2, ec->iregs) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs); /* Get the bits */ mask = work[0] << 16 | work[1] << 8 | work[2]; mask >>= (24 - ec->smbsz - cbn); mask &= 0xFFFF >> (16 - ec->smbsz); *is = mask; /* Adjust source registers */ ADJUSTREGS(ec->r2, ec->regs, ec->iregs, (cbn + ec->smbsz) / 8); /* Calculate and set the new compressed-data bit number */ GR1_setcbn(ec->iregs, (cbn + ec->smbsz) % 8); #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_is : %04X, cbn=%d, GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", *is, GR1_cbn(ec->iregs), ec->r2, ec->iregs->GR(ec->r2), ec->r2 + 1, ec->iregs->GR(ec->r2 + 1)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ return(0); } /*----------------------------------------------------------------------------*/ /* cmpsc_fetch_iss */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(cmpsc_fetch_iss)(struct ec *ec, U16 is[8]) { BYTE buf[13]; /* Buffer for Index Symbols */ #ifdef OPTION_CMPSC_DEBUG int i; #endif /* #ifdef OPTION_CMPSC_DEBUG */ unsigned len1; /* Lenght in first page */ BYTE *mem; /* Pointer to maddr or buf */ unsigned ofst; /* Offset in first page */ /* Fingers crossed that we stay within one page */ ofst = GR_A(ec->r2, ec->iregs) & 0x7ff; if(unlikely(!ec->src)) ec->src = MADDR((GR_A(ec->r2, ec->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey); if(likely(ofst + ec->smbsz <= 0x800)) { ITIMER_SYNC(GR_A(ec->r2, ec->iregs) & ADDRESS_MAXWRAP(ec->regs), ec->smbsz - 1, ec->regs); mem = &ec->src[ofst]; /* Perfect fit? */ if(unlikely(ofst + ec->smbsz == 0x800)) ec->src = NULL; } else { /* We need data spread over 2 pages */ len1 = 0x800 - ofst; memcpy(buf, &ec->src[ofst], len1); ec->src = MADDR((GR_A(ec->r2, ec->iregs) + len1) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey); memcpy(&buf[len1], ec->src, ec->smbsz - len1); mem = buf; } /* Calculate the 8 index symbols */ switch(ec->smbsz) { case 9: /* 9-bits */ { /* 0 1 2 3 4 5 6 7 8 */ /* 012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 012345678012345678012345678012345678012345678012345678012345678012345678 */ /* 0 1 2 3 4 5 6 7 */ is[0] = ((mem[0] << 1) | (mem[1] >> 7)); is[1] = ((mem[1] << 2) | (mem[2] >> 6)) & 0x01ff; is[2] = ((mem[2] << 3) | (mem[3] >> 5)) & 0x01ff; is[3] = ((mem[3] << 4) | (mem[4] >> 4)) & 0x01ff; is[4] = ((mem[4] << 5) | (mem[5] >> 3)) & 0x01ff; is[5] = ((mem[5] << 6) | (mem[6] >> 2)) & 0x01ff; is[6] = ((mem[6] << 7) | (mem[7] >> 1)) & 0x01ff; is[7] = ((mem[7] << 8) | (mem[8] )) & 0x01ff; break; } case 10: /* 10-bits */ { /* 0 1 2 3 4 5 6 7 8 9 */ /* 01234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */ /* 0 1 2 3 4 5 6 7 */ is[0] = ((mem[0] << 2) | (mem[1] >> 6)); is[1] = ((mem[1] << 4) | (mem[2] >> 4)) & 0x03ff; is[2] = ((mem[2] << 6) | (mem[3] >> 2)) & 0x03ff; is[3] = ((mem[3] << 8) | (mem[4] )) & 0x03ff; is[4] = ((mem[5] << 2) | (mem[6] >> 6)); is[5] = ((mem[6] << 4) | (mem[7] >> 4)) & 0x03ff; is[6] = ((mem[7] << 6) | (mem[8] >> 2)) & 0x03ff; is[7] = ((mem[8] << 8) | (mem[9] )) & 0x03ff; break; } case 11: /* 11-bits */ { /* 0 1 2 3 4 5 6 7 8 9 a */ /* 0123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a */ /* 0 1 2 3 4 5 6 7 */ is[0] = ((mem[0] << 3) | (mem[ 1] >> 5) ); is[1] = ((mem[1] << 6) | (mem[ 2] >> 2) ) & 0x07ff; is[2] = ((mem[2] << 9) | (mem[ 3] << 1) | (mem[4] >> 7)) & 0x07ff; is[3] = ((mem[4] << 4) | (mem[ 5] >> 4) ) & 0x07ff; is[4] = ((mem[5] << 7) | (mem[ 6] >> 1) ) & 0x07ff; is[5] = ((mem[6] << 10) | (mem[ 7] << 2) | (mem[8] >> 6)) & 0x07ff; is[6] = ((mem[8] << 5) | (mem[ 9] >> 3) ) & 0x07ff; is[7] = ((mem[9] << 8) | (mem[10] ) ) & 0x07ff; break; } case 12: /* 12-bits */ { /* 0 1 2 3 4 5 6 7 8 9 a b */ /* 012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab */ /* 0 1 2 3 4 5 6 7 */ is[0] = ((mem[ 0] << 4) | (mem[ 1] >> 4)); is[1] = ((mem[ 1] << 8) | (mem[ 2] )) & 0x0fff; is[2] = ((mem[ 3] << 4) | (mem[ 4] >> 4)); is[3] = ((mem[ 4] << 8) | (mem[ 5] )) & 0x0fff; is[4] = ((mem[ 6] << 4) | (mem[ 7] >> 4)); is[5] = ((mem[ 7] << 8) | (mem[ 8] )) & 0x0fff; is[6] = ((mem[ 9] << 4) | (mem[10] >> 4)); is[7] = ((mem[10] << 8) | (mem[11] )) & 0x0fff; break; } case 13: /* 13-bits */ { /* 0 1 2 3 4 5 6 7 8 9 a b c */ /* 01234567012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */ /* 0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc */ /* 0 1 2 3 4 5 6 7 */ is[0] = ((mem[ 0] << 5) | (mem[ 1] >> 3) ); is[1] = ((mem[ 1] << 10) | (mem[ 2] << 2) | (mem[ 3] >> 6)) & 0x1fff; is[2] = ((mem[ 3] << 7) | (mem[ 4] >> 1) ) & 0x1fff; is[3] = ((mem[ 4] << 12) | (mem[ 5] << 4) | (mem[ 6] >> 4)) & 0x1fff; is[4] = ((mem[ 6] << 9) | (mem[ 7] << 1) | (mem[ 8] >> 7)) & 0x1fff; is[5] = ((mem[ 8] << 6) | (mem[ 9] >> 2) ) & 0x1fff; is[6] = ((mem[ 9] << 11) | (mem[10] << 3) | (mem[11] >> 5)) & 0x1fff; is[7] = ((mem[11] << 8) | (mem[12] ) ) & 0x1fff; break; } } /* Adjust source registers */ ADJUSTREGS(ec->r2, ec->regs, ec->iregs, ec->smbsz); #ifdef OPTION_CMPSC_DEBUG logmsg("fetch_iss:"); for(i = 0; i < 8; i++) logmsg(" %04X", is[i]); logmsg(", GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", ec->r2, ec->iregs->GR(ec->r2), ec->r2 + 1, ec->iregs->GR(ec->r2 + 1)); #endif /* #ifdef OPTION_CMPSC_DEBUG */ } #ifndef NO_2ND_COMPILE #ifdef OPTION_CMPSC_DEBUG /*----------------------------------------------------------------------------*/ /* cmpsc_print_ece (expansion character entry) */ /*----------------------------------------------------------------------------*/ static void cmpsc_print_ece(BYTE *ece) { int i; /* Index */ int prt_detail; /* Switch detailed printing */ logmsg(" ece : "); prt_detail = 0; for(i = 0; i < 8; i++) { if(!prt_detail && ece[i]) prt_detail = 1; logmsg("%02X", ece[i]); } logmsg("\n"); if(prt_detail) { if(ECE_psl(ece)) { logmsg(" psl : %d\n", ECE_psl(ece)); logmsg(" pptr : %04X\n", ECE_pptr(ece)); logmsg(" ecs :"); for(i = 0; i < ECE_psl(ece); i++) logmsg(" %02X", ece[i + 2]); logmsg("\n"); logmsg(" ofst : %02X\n", ECE_ofst(ece)); } else { logmsg(" psl : %d\n", ECE_psl(ece)); logmsg(" bit34 : %s\n", TRUEFALSE(ECE_bit34(ece))); logmsg(" csl : %d\n", ECE_csl(ece)); logmsg(" ecs :"); for(i = 0; i < ECE_csl(ece); i++) logmsg(" %02X", ece[i + 1]); logmsg("\n"); } } } #endif /* #ifdef OPTION_CMPSC_DEBUG */ #endif /* #ifndef NO_2ND_COMPILE */ /*----------------------------------------------------------------------------*/ /* cmpsc_vstore */ /*----------------------------------------------------------------------------*/ static int ARCH_DEP(cmpsc_vstore)(struct ec *ec, BYTE *buf, unsigned len) { unsigned len1; /* Length in first page */ unsigned len2; /* Length in second page */ BYTE *main1; /* Address first page */ unsigned ofst; /* Offset within page */ BYTE *sk; /* Storage key */ #ifdef OPTION_CMPSC_DEBUG unsigned i; /* Index */ unsigned j; /* Index */ static BYTE pbuf[2060]; /* Print buffer */ static unsigned plen = 2061; /* Impossible value */ #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Check destination size */ if(unlikely(GR_A(ec->r1 + 1, ec->iregs) < len)) { #ifdef OPTION_CMPSC_DEBUG logmsg("vstore : Reached end of destination\n"); #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Indicate end of destination */ ec->regs->psw.cc = 1; return(-1); } #ifdef OPTION_CMPSC_DEBUG if(plen == len && !memcmp(pbuf, buf, plen)) logmsg(F_GREG " - " F_GREG " Same buffer as previously shown\n", ec->iregs->GR(ec->r1), ec->iregs->GR(ec->r1) + len - 1); else { for(i = 0; i < len; i += 32) { logmsg(F_GREG, ec->iregs->GR(ec->r1) + i); if(i && i + 32 < len && !memcmp(&buf[i], &buf[i - 32], 32)) { for(j = i + 32; j + 32 < len && !memcmp(&buf[j], &buf[j - 32], 32); j += 32); if(j > 32) { logmsg(": Same line as above\n" F_GREG, ec->iregs->GR(ec->r1) + j); i = j; } } logmsg(": "); for(j = 0; j < 32; j++) { if(!(j % 8)) logmsg(" "); if(i + j >= len) logmsg(" "); else logmsg("%02X", buf[i + j]); } logmsg(" | "); for(j = 0; j < 32; j++) { if(i + j >= len) logmsg(" "); else { if(isprint(guest_to_host(buf[i + j]))) logmsg("%c", guest_to_host(buf[i + j])); else logmsg("."); } } logmsg(" |\n"); } memcpy(pbuf, buf, len); plen = len; } #endif /* #ifdef OPTION_CMPSC_DEBUG */ /* Fingers crossed that we stay within one page */ ofst = GR_A(ec->r1, ec->iregs) & 0x7ff; if(likely(ofst + len <= 0x800)) { if(unlikely(!ec->dest)) ec->dest = MADDR((GR_A(ec->r1, ec->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE, ec->regs->psw.pkey); memcpy(&ec->dest[ofst], buf, len); ITIMER_UPDATE(GR_A(ec->r1, ec->iregs) & ADDRESS_MAXWRAP(ec->regs), len - 1, ec->regs); /* Perfect fit? */ if(unlikely(ofst + len == 0x800)) ec->dest = NULL; } else { /* We need multiple pages */ if(unlikely(!ec->dest)) main1 = MADDR((GR_A(ec->r1, ec->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE_SKP, ec->regs->psw.pkey); else main1 = ec->dest; sk = ec->regs->dat.storkey; len1 = 0x800 - ofst; ec->dest = MADDR((GR_A(ec->r1, ec->iregs) + len1) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE, ec->regs->psw.pkey); memcpy(&main1[ofst], buf, len1); len2 = len - len1; /* We always start with a len2 */ do { memcpy(ec->dest, &buf[len1], (len2 > 0x800 ? 0x800 : len2)); *sk |= (STORKEY_REF | STORKEY_CHANGE); if(unlikely(len2 >= 0x800)) { len1 += 0x800; len2 -= 0x800; /* Perfect fit? */ if(unlikely(!len2)) ec->dest = NULL; else ec->dest = MADDR((GR_A(ec->r1, ec->iregs) + len1) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE, ec->regs->psw.pkey); sk = ec->regs->dat.storkey; } else len2 = 0; } while(len2); } ADJUSTREGS(ec->r1, ec->regs, ec->iregs, len); return(0); } #define NO_2ND_COMPILE #endif /* FEATURE_COMPRESSION */ #ifndef _GEN_ARCH #ifdef _ARCHMODE2 #define _GEN_ARCH _ARCHMODE2 #include "cmpsc.c" #endif /* #ifdef _ARCHMODE2 */ #ifdef _ARCHMODE3 #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "cmpsc.c" #endif /* #ifdef _ARCHMODE3 */ #endif /* #ifndef _GEN_ARCH */ hercules-3.12/sie.c0000664000175000017500000013462612564723224011143 00000000000000/* SIE.C (c) Copyright Jan Jaeger, 1999-2009 */ /* Interpretive Execution */ /* This module contains the SIE instruction as */ /* described in IBM S/370 Extended Architecture */ /* Interpretive Execution, SA22-7095-01 */ /* and */ /* Enterprise Systems Architecture / Extended Configuration */ /* Principles of Operation, SC24-5594-02 and SC24-5965-00 */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2007 */ #include "hstdinc.h" // #define SIE_DEBUG // #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_SIE_C_) #define _SIE_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(_FEATURE_SIE) #if !defined(_SIE_C) #define _SIE_C int s370_run_sie (REGS *regs); int s390_run_sie (REGS *regs); #if defined(_900) int z900_run_sie (REGS *regs); #endif /*defined(_900)*/ static int (* run_sie[GEN_MAXARCH]) (REGS *regs) = { #if defined(_370) s370_run_sie, #endif #if defined(_390) s390_run_sie, #endif #if defined(_900) z900_run_sie #endif }; #define GUESTREGS (regs->guestregs) #define STATEBK ((SIEBK *)GUESTREGS->siebk) #define SIE_I_STOP(_guestregs) \ ((_guestregs)->siebk->v & SIE_V_STOP) #define SIE_I_EXT(_guestregs) \ (((_guestregs)->siebk->v & SIE_V_EXT) \ && ((_guestregs)->psw.sysmask & PSW_EXTMASK)) #define SIE_I_HOST(_hostregs) IC_INTERRUPT_CPU(_hostregs) #if defined(SIE_DEBUG_PERFMON) #define SIE_PERF_MAXNEG 0x1F static int sie_perfmon[0x41 + SIE_PERF_MAXNEG]; #define SIE_PERFMON(_code) \ do { \ sie_perfmon[(_code) + SIE_PERF_MAXNEG] ++; \ } while(0) #define SIE_PERF_PGMINT \ (code <= 0 ? code : (((code-1) & 0x3F)+1)) void *sie_perfmon_disp() { static char *dbg_name[] = { /* -31 */ "SIE re-dispatch state descriptor", /* -30 */ "SIE exit", /* -29 */ "SIE run", /* -28 */ "SIE runloop 1", /* -27 */ "SIE runloop 2", /* -26 */ "SIE interrupt check", /* -25 */ "SIE execute instruction", /* -24 */ "SIE unrolled execute", /* -23 */ NULL, /* -22 */ NULL, /* -21 */ NULL, /* -20 */ NULL, /* -19 */ NULL, /* -18 */ NULL, /* -17 */ "SIE intercept I/O instruction", /* -16 */ "SIE intercept I/O interrupt pending", /* -15 */ "SIE intercept I/O interrupt", /* -14 */ "SIE intercept PER interrupt", /* -13 */ "SIE validity check", /* -12 */ "SIE intercept external interrupt pending", /* -11 */ "SIE intercept machine check interrupt", /* -10 */ "SIE intercept restart interrupt", /* -9 */ "SIE intercept stop request", /* -8 */ "SIE intercept virtual machine wait", /* -7 */ "SIE intercept I/O interrupt request", /* -6 */ "SIE intercept external interrupt request", /* -5 */ "SIE intercept instruction completion", /* -4 */ "SIE intercept instruction", /* -3 */ "SIE host program interrupt", /* -2 */ "SIE host interrupt", /* -1 */ "SIE no intercept", /* 0 */ "SIE entry", /* 01 */ "SIE intercept Operation exception", /* 02 */ "SIE intercept Privileged-operation exception", /* 03 */ "SIE intercept Execute exception", /* 04 */ "SIE intercept Protection exception", /* 05 */ "SIE intercept Addressing exception", /* 06 */ "SIE intercept Specification exception", /* 07 */ "SIE intercept Data exception", /* 08 */ "SIE intercept Fixed-point-overflow exception", /* 09 */ "SIE intercept Fixed-point-divide exception", /* 0A */ "SIE intercept Decimal-overflow exception", /* 0B */ "SIE intercept Decimal-divide exception", /* 0C */ "SIE intercept HFP-exponent-overflow exception", /* 0D */ "SIE intercept HFP-exponent-underflow exception", /* 0E */ "SIE intercept HFP-significance exception", /* 0F */ "SIE intercept HFP-floating-point-divide exception", /* 10 */ "SIE intercept Segment-translation exception", /* 11 */ "SIE intercept Page-translation exception", /* 12 */ "SIE intercept Translation-specification exception", /* 13 */ "SIE intercept Special-operation exception", /* 14 */ "SIE intercept Pseudo-page-fault exception", /* 15 */ "SIE intercept Operand exception", /* 16 */ "SIE intercept Trace-table exception", /* 17 */ "SIE intercept ASN-translation exception", /* 18 */ "SIE intercept Page access exception", /* 19 */ "SIE intercept Vector/Crypto operation exception", /* 1A */ "SIE intercept Page state exception", /* 1B */ "SIE intercept Page transition exception", /* 1C */ "SIE intercept Space-switch event", /* 1D */ "SIE intercept Square-root exception", /* 1E */ "SIE intercept Unnormalized-operand exception", /* 1F */ "SIE intercept PC-translation specification exception", /* 20 */ "SIE intercept AFX-translation exception", /* 21 */ "SIE intercept ASX-translation exception", /* 22 */ "SIE intercept LX-translation exception", /* 23 */ "SIE intercept EX-translation exception", /* 24 */ "SIE intercept Primary-authority exception", /* 25 */ "SIE intercept LFX-translation exception", /* 26 */ "SIE intercept LSX-translation exception", /* 27 */ "SIE intercept Control-switch exception", /* 28 */ "SIE intercept ALET-specification exception", /* 29 */ "SIE intercept ALEN-translation exception", /* 2A */ "SIE intercept ALE-sequence exception", /* 2B */ "SIE intercept ASTE-validity exception", /* 2C */ "SIE intercept ASTE-sequence exception", /* 2D */ "SIE intercept Extended-authority exception", /* 2E */ "SIE intercept LSTE-sequence exception", /* 2F */ "SIE intercept ASTE-instance exception", /* 30 */ "SIE intercept Stack-full exception", /* 31 */ "SIE intercept Stack-empty exception", /* 32 */ "SIE intercept Stack-specification exception", /* 33 */ "SIE intercept Stack-type exception", /* 34 */ "SIE intercept Stack-operation exception", /* 35 */ NULL, /* 36 */ NULL, /* 37 */ NULL, /* 38 */ "SIE intercept ASCE-type exception", /* 39 */ "SIE intercept Region-first-translation exception", /* 3A */ "SIE intercept Region-second-translation exception", /* 3B */ "SIE intercept Region-third-translation exception", /* 3C */ NULL, /* 3D */ NULL, /* 3E */ NULL, /* 3F */ NULL, /* 40 */ "SIE intercept Monitor event" }; if(sie_perfmon[SIE_PERF_ENTER+SIE_PERF_MAXNEG]) { int i; for(i = 0; i < 0x61; i++) if(sie_perfmon[i]) logmsg("%9u: %s\n",sie_perfmon[i],dbg_name[i]); logmsg("%9u: Average instructions/SIE invocation\n", (sie_perfmon[SIE_PERF_EXEC+SIE_PERF_MAXNEG] + sie_perfmon[SIE_PERF_EXEC_U+SIE_PERF_MAXNEG]*7) / sie_perfmon[SIE_PERF_ENTER+SIE_PERF_MAXNEG]); } else logmsg("No SIE performance data\n"); } #else #define SIE_PERFMON(_code) #endif #endif /*!defined(_SIE_C)*/ #undef SIE_I_WAIT #if defined(_FEATURE_WAITSTATE_ASSIST) #define SIE_I_WAIT(_guestregs) \ (WAITSTATE(&(_guestregs)->psw) && !((_guestregs)->siebk->ec[0] & SIE_EC0_WAIA)) #else #define SIE_I_WAIT(_guestregs) \ (WAITSTATE(&(_guestregs)->psw)) #endif #undef SIE_I_IO #if defined(FEATURE_BCMODE) #define SIE_I_IO(_guestregs) \ (((_guestregs)->siebk->v & SIE_V_IO) \ && ((_guestregs)->psw.sysmask \ & (ECMODE(&(_guestregs)->psw) ? PSW_IOMASK : 0xFE) )) #else /*!defined(FEATURE_BCMODE)*/ #define SIE_I_IO(_guestregs) \ (((_guestregs)->siebk->v & SIE_V_IO) \ && ((_guestregs)->psw.sysmask & PSW_IOMASK )) #endif /*!defined(FEATURE_BCMODE)*/ #endif /*defined(_FEATURE_SIE)*/ #if defined(FEATURE_INTERPRETIVE_EXECUTION) /*-------------------------------------------------------------------*/ /* B214 SIE - Start Interpretive Execution [S] */ /*-------------------------------------------------------------------*/ DEF_INST(start_interpretive_execution) { int b2; /* Values of R fields */ RADR effective_addr2; /* address of state desc. */ int n; /* Loop counter */ U16 lhcpu; /* Last Host CPU address */ volatile int icode = 0; /* Interception code */ U64 dreg; S(inst, regs, b2, effective_addr2); SIE_INTERCEPT(regs); PRIV_CHECK(regs); PTT(PTT_CL_SIE,"SIE", regs->GR_L(14), regs->GR_L(15), (U32)(effective_addr2 & 0xffffffff)); SIE_PERFMON(SIE_PERF_ENTER); #if !defined(FEATURE_ESAME) && !defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(!regs->psw.amode || !PRIMARY_SPACE_MODE(&(regs->psw))) ARCH_DEP(program_interrupt) (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif if((effective_addr2 & (sizeof(SIEBK)-1)) != 0 #if defined(FEATURE_ESAME) || (effective_addr2 & 0xFFFFFFFFFFFFF000ULL) == 0 || (effective_addr2 & 0xFFFFFFFFFFFFF000ULL) == regs->PX) #else /*!defined(FEATURE_ESAME)*/ || (effective_addr2 & 0x7FFFF000) == 0 || (effective_addr2 & 0x7FFFF000) == regs->PX) #endif /*!defined(FEATURE_ESAME)*/ ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); #if defined(SIE_DEBUG) logmsg(_("SIE: state descriptor " F_RADR "\n"),effective_addr2); ARCH_DEP(display_inst) (regs, regs->instinvalid ? NULL : regs->ip); #endif /*defined(SIE_DEBUG)*/ if(effective_addr2 > regs->mainlim - (sizeof(SIEBK)-1)) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* * As long as regs->sie_active is off, no serialization is * required for GUESTREGS. sie_active should always be off here. * Any other thread looking at sie_active holds the intlock. */ if (regs->sie_active) { OBTAIN_INTLOCK(regs); regs->sie_active = 0; RELEASE_INTLOCK(regs); } /* Initialize guestregs if first time */ if (GUESTREGS == NULL) { GUESTREGS = calloc (sizeof(REGS), 1); if (GUESTREGS == NULL) { logmsg (_("HHCCP079E CPU%4.4X: calloc failed for sie regs: %s\n"), regs->cpuad, strerror(errno)); #if !defined(NO_SIGABEND_HANDLER) signal_thread(sysblk.cputid[regs->cpuad], SIGUSR1); #endif return; } cpu_init (regs->cpuad, GUESTREGS, regs); } /* Direct pointer to state descriptor block */ GUESTREGS->siebk = (void*)(regs->mainstor + effective_addr2); #if defined(FEATURE_ESAME) if (STATEBK->mx & SIE_MX_ESAME) { GUESTREGS->arch_mode = ARCH_900; GUESTREGS->program_interrupt = &z900_program_interrupt; GUESTREGS->trace_br = (func)&z900_trace_br; icode = z900_load_psw(GUESTREGS, STATEBK->psw); } #else /*!defined(FEATURE_ESAME)*/ if (STATEBK->m & SIE_M_370) { #if defined(_370) GUESTREGS->arch_mode = ARCH_370; GUESTREGS->program_interrupt = &s370_program_interrupt; icode = s370_load_psw(GUESTREGS, STATEBK->psw); #else /* Validity intercept when 370 mode not installed */ SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_370NI, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; #endif } #endif /*!defined(FEATURE_ESAME)*/ else #if !defined(FEATURE_ESAME) if (STATEBK->m & SIE_M_XA) #endif /*!defined(FEATURE_ESAME)*/ { GUESTREGS->arch_mode = ARCH_390; GUESTREGS->program_interrupt = &s390_program_interrupt; GUESTREGS->trace_br = (func)&s390_trace_br; icode = s390_load_psw(GUESTREGS, STATEBK->psw); } #if !defined(FEATURE_ESAME) else { /* Validity intercept for invalid mode */ SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_MODE, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } #endif /*!defined(FEATURE_ESAME)*/ /* Prefered guest indication */ GUESTREGS->sie_pref = (STATEBK->m & SIE_M_VR) ? 1 : 0; /* Load prefix from state descriptor */ FETCH_FW(GUESTREGS->PX, STATEBK->prefix); GUESTREGS->PX &= #if !defined(FEATURE_ESAME) PX_MASK; #else /*defined(FEATURE_ESAME)*/ (GUESTREGS->arch_mode == ARCH_900) ? PX_MASK : 0x7FFFF000; #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_REGION_RELOCATE) if(STATEBK->mx & SIE_MX_RRF) { RADR mso, msl, eso = 0, esl = 0; if(STATEBK->zone >= FEATURE_SIE_MAXZONES) { /* Validity intercept for invalid zone */ SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_AZNNI, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } mso = sysblk.zpb[STATEBK->zone].mso << 20; msl = (sysblk.zpb[STATEBK->zone].msl << 20) | 0xFFFFF; eso = sysblk.zpb[STATEBK->zone].eso << 20; esl = (sysblk.zpb[STATEBK->zone].esl << 20) | 0xFFFFF; if(mso > msl) { /* Validity intercept for invalid zone */ SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_MSDEF, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } /* Ensure addressing exceptions on incorrect zone defs */ if(mso > regs->mainlim || msl > regs->mainlim) mso = msl = 0; #if defined(SIE_DEBUG) logmsg(_("SIE: zone %d: mso=" F_RADR " msl=" F_RADR "\n"), STATEBK->zone, mso, msl); #endif /*defined(SIE_DEBUG)*/ GUESTREGS->sie_pref = 1; GUESTREGS->sie_mso = 0; GUESTREGS->mainstor = &(sysblk.mainstor[mso]); GUESTREGS->mainlim = msl - mso; GUESTREGS->storkeys = &(STORAGE_KEY(mso, &sysblk)); GUESTREGS->sie_xso = eso; GUESTREGS->sie_xsl = esl; GUESTREGS->sie_xso *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT); GUESTREGS->sie_xsl *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT); } else #endif /*defined(FEATURE_REGION_RELOCATE)*/ { GUESTREGS->mainstor = sysblk.mainstor; GUESTREGS->storkeys = sysblk.storkeys; if(STATEBK->zone) { /* Validity intercept for invalid zone */ SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_AZNNZ, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } #if defined(FEATURE_ESAME) /* Load main storage origin */ FETCH_DW(GUESTREGS->sie_mso,STATEBK->mso); GUESTREGS->sie_mso &= SIE2_MS_MASK; /* Load main storage extend */ FETCH_DW(GUESTREGS->mainlim,STATEBK->mse); GUESTREGS->mainlim |= ~SIE2_MS_MASK; if(GUESTREGS->sie_mso > GUESTREGS->mainlim) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_MSDEF, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } /* Calculate main storage size */ GUESTREGS->mainlim -= GUESTREGS->sie_mso; #else /*!defined(FEATURE_ESAME)*/ /* Load main storage origin */ FETCH_HW(GUESTREGS->sie_mso,STATEBK->mso); GUESTREGS->sie_mso <<= 16; /* Load main storage extend */ FETCH_HW(GUESTREGS->mainlim,STATEBK->mse); GUESTREGS->mainlim = ((GUESTREGS->mainlim + 1) << 16) - 1; #endif /*!defined(FEATURE_ESAME)*/ /* Load expanded storage origin */ GUESTREGS->sie_xso = STATEBK->xso[0] << 16 | STATEBK->xso[1] << 8 | STATEBK->xso[2]; GUESTREGS->sie_xso *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT); /* Load expanded storage limit */ GUESTREGS->sie_xsl = STATEBK->xsl[0] << 16 | STATEBK->xsl[1] << 8 | STATEBK->xsl[2]; GUESTREGS->sie_xsl *= (XSTORE_INCREMENT_SIZE >> XSTORE_PAGESHIFT); } /* Validate Guest prefix */ if(GUESTREGS->PX > GUESTREGS->mainlim) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_PFOUT, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } /* System Control Area Origin */ FETCH_FW(GUESTREGS->sie_scao, STATEBK->scao); if(GUESTREGS->sie_scao > regs->mainlim) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_SCADR, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } /* Validate MSO */ if (GUESTREGS->sie_mso) { /* Preferred guest must have zero MSO */ if (GUESTREGS->sie_pref) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_MSONZ, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } /* MCDS guest must have zero MSO */ if (STATEBK->mx & SIE_MX_XC) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_MSODS, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } } #if !defined(FEATURE_ESAME) /* Reference and Change Preservation Origin */ FETCH_FW(GUESTREGS->sie_rcpo, STATEBK->rcpo); if (!GUESTREGS->sie_rcpo && !GUESTREGS->sie_pref) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_RCZER, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; return; } #endif /*!defined(FEATURE_ESAME)*/ /* Load the CPU timer */ FETCH_DW(dreg, STATEBK->cputimer); set_cpu_timer(GUESTREGS, dreg); /* Load the TOD clock offset for this guest */ FETCH_DW(GUESTREGS->sie_epoch, STATEBK->epoch); GUESTREGS->tod_epoch = regs->tod_epoch + (GUESTREGS->sie_epoch >> 8); /* Load the clock comparator */ FETCH_DW(GUESTREGS->clkc, STATEBK->clockcomp); GUESTREGS->clkc >>= 8; /* Internal Hercules format */ /* Load TOD Programmable Field */ FETCH_HW(GUESTREGS->todpr, STATEBK->todpf); /* Load the guest registers */ memcpy(GUESTREGS->gr, regs->gr, 14 * sizeof(regs->gr[0])); memcpy(GUESTREGS->ar, regs->ar, 16 * sizeof(regs->ar[0])); memcpy(GUESTREGS->fpr, regs->fpr, 32 * sizeof(regs->fpr[0])); #if defined(FEATURE_BINARY_FLOATING_POINT) GUESTREGS->fpc = regs->fpc; #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ /* Load GR14 */ FETCH_W(GUESTREGS->GR(14), STATEBK->gr14); /* Load GR15 */ FETCH_W(GUESTREGS->GR(15), STATEBK->gr15); /* Load control registers */ for(n = 0;n < 16; n++) FETCH_W(GUESTREGS->CR(n), STATEBK->cr[n]); FETCH_HW(lhcpu, STATEBK->lhcpu); /* * If this is not the last host cpu that dispatched this state * descriptor then clear the guest TLB entries */ if (regs->cpuad != lhcpu || SIE_STATE(GUESTREGS) != effective_addr2) { SIE_PERFMON(SIE_PERF_ENTER_F); /* Absolute address of state descriptor block */ SIE_STATE(GUESTREGS) = effective_addr2; /* Update Last Host CPU address */ STORE_HW(STATEBK->lhcpu, regs->cpuad); /* Purge guest TLB entries */ ARCH_DEP(purge_tlb) (GUESTREGS); ARCH_DEP(purge_alb) (GUESTREGS); } /* Initialize interrupt mask and state */ SET_IC_MASK(GUESTREGS); SET_IC_INITIAL_STATE(GUESTREGS); SET_IC_PER(GUESTREGS); /* Initialize accelerated address lookup values */ SET_AEA_MODE(GUESTREGS); SET_AEA_COMMON(GUESTREGS); INVALIDATE_AIA(GUESTREGS); GUESTREGS->tracing = regs->tracing; /* * Do setjmp(progjmp) because translate_addr() may result in * longjmp(progjmp) for addressing exceptions. */ if(!setjmp(GUESTREGS->progjmp)) { /* * Set sie_active to 1. This means other threads may now * access guestregs when holding intlock. * This is the *only* place sie_active is set to one. */ OBTAIN_INTLOCK(regs); regs->sie_active = 1; RELEASE_INTLOCK(regs); /* Get PSA pointer and ensure PSA is paged in */ if(GUESTREGS->sie_pref) { GUESTREGS->psa = (PSA_3XX*)(GUESTREGS->mainstor + GUESTREGS->PX); GUESTREGS->sie_px = GUESTREGS->PX; } else { if (ARCH_DEP(translate_addr) (GUESTREGS->sie_mso + GUESTREGS->PX, USE_PRIMARY_SPACE, regs, ACCTYPE_SIE)) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_PFACC, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; OBTAIN_INTLOCK(regs); regs->sie_active = 0; RELEASE_INTLOCK(regs); return; } /* Convert host real address to host absolute address */ GUESTREGS->sie_px = APPLY_PREFIXING (regs->dat.raddr, regs->PX); if (regs->dat.protect || GUESTREGS->sie_px > regs->mainlim) { SIE_SET_VI(SIE_VI_WHO_CPU, SIE_VI_WHEN_SIENT, SIE_VI_WHY_PFACC, GUESTREGS); STATEBK->c = SIE_C_VALIDITY; OBTAIN_INTLOCK(regs); regs->sie_active = 0; RELEASE_INTLOCK(regs); return; } GUESTREGS->psa = (PSA_3XX*)(GUESTREGS->mainstor + GUESTREGS->sie_px); } /* Intialize guest timers */ OBTAIN_INTLOCK(regs); /* CPU timer */ if(CPU_TIMER(GUESTREGS) < 0) ON_IC_PTIMER(GUESTREGS); /* Clock comparator */ if( TOD_CLOCK(GUESTREGS) > GUESTREGS->clkc ) ON_IC_CLKC(GUESTREGS); #if !defined(FEATURE_ESAME) /* Interval timer if S/370 and timer is enabled */ if((STATEBK->m & SIE_M_370) && !(STATEBK->m & SIE_M_ITMOF)) { S32 itimer, olditimer; U32 residue; /* Set the interval timer pending according to the T bit in the state control */ if(STATEBK->s & SIE_S_T) ON_IC_ITIMER(GUESTREGS); /* Fetch the residu from the state descriptor */ FETCH_FW(residue,STATEBK->residue); /* Fetch the timer value from location 80 */ FETCH_FW(olditimer,GUESTREGS->psa->inttimer); /* Bit position 23 of the interval timer is decremented once for each multiple of 3,333 usecs containded in bit position 0-19 of the residue counter */ itimer = olditimer - ((residue / 3333) >> 4); /* Store the timer back */ STORE_FW(GUESTREGS->psa->inttimer, itimer); /* Set interrupt flag and interval timer interrupt pending if the interval timer went from positive to negative */ if (itimer < 0 && olditimer >= 0) ON_IC_ITIMER(GUESTREGS); } #endif /*!defined(FEATURE_ESAME)*/ RELEASE_INTLOCK(regs); /* Early exceptions associated with the guest load_psw() */ if(icode) GUESTREGS->program_interrupt (GUESTREGS, icode); /* Run SIE in guests architecture mode */ icode = run_sie[GUESTREGS->arch_mode] (regs); } /* if (setjmp(GUESTREGS->progjmp)) */ ARCH_DEP(sie_exit) (regs, icode); /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); longjmp(regs->progjmp, SIE_NO_INTERCEPT); } /* Exit SIE state, restore registers and update the state descriptor */ void ARCH_DEP(sie_exit) (REGS *regs, int code) { int n; #if defined(OPTION_PTTRACE) if(pttclass & PTT_CL_SIE) { U32 nt1 = 0, nt2 = 0; BYTE *ip; if(!GUESTREGS->instinvalid) { if(GUESTREGS->ip[0] == 0x44 #if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) || (GUESTREGS->ip[0] == 0xc6 && !(GUESTREGS->ip[1] & 0x0f)) #endif /*defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/ ) { ip = GUESTREGS->exinst; nt2 = (GUESTREGS->ip[0] == 0x44) ? 0x44 : ((0xc6 << 8) | (GUESTREGS->ip[1] & 0x0f)); } else ip = GUESTREGS->ip; nt1 = (ip[0] << 24) | (ip[1] << 16); if(ILC(ip[0]) > 2) nt1 |= (ip[2] << 8) | ip[3]; if(ILC(ip[0]) > 4) nt2 |= (ip[4] << 24) | (ip[5] << 16); } PTT(PTT_CL_SIE,"*SIE", nt1, nt2, code); } #endif /*defined(OPTION_PTTRACE)*/ #if defined(SIE_DEBUG) logmsg(_("SIE: interception code %d\n"),code); ARCH_DEP(display_inst) (GUESTREGS, GUESTREGS->instinvalid ? NULL : GUESTREGS->ip); #endif /*defined(SIE_DEBUG)*/ SIE_PERFMON(SIE_PERF_EXIT); SIE_PERFMON(SIE_PERF_PGMINT); /* Indicate we have left SIE mode */ OBTAIN_INTLOCK(regs); regs->sie_active = 0; RELEASE_INTLOCK(regs); /* zeroize interception status */ STATEBK->f = 0; switch(code > 0 ? code & ~PGM_PER_EVENT : code) { case SIE_HOST_INTERRUPT: /* If a host interrupt is pending then backup the psw and exit */ SET_PSW_IA(regs); UPD_PSW_IA (regs, regs->psw.IA -REAL_ILC(regs)); break; case SIE_HOST_PGMINT: break; case SIE_INTERCEPT_INST: STATEBK->c = SIE_C_INST; break; case SIE_INTERCEPT_PER: STATEBK->f |= SIE_F_IF; /*fallthru*/ case SIE_INTERCEPT_INSTCOMP: STATEBK->c = SIE_C_PGMINST; break; case SIE_INTERCEPT_WAIT: STATEBK->c = SIE_C_WAIT; break; case SIE_INTERCEPT_STOPREQ: STATEBK->c = SIE_C_STOPREQ; break; case SIE_INTERCEPT_IOREQ: STATEBK->c = SIE_C_IOREQ; break; case SIE_INTERCEPT_EXTREQ: STATEBK->c = SIE_C_EXTREQ; break; case SIE_INTERCEPT_EXT: STATEBK->c = SIE_C_EXTINT; break; case SIE_INTERCEPT_VALIDITY: STATEBK->c = SIE_C_VALIDITY; break; case SIE_INTERCEPT_IOINT: case SIE_INTERCEPT_IOINTP: STATEBK->c = SIE_C_IOINT; break; case SIE_INTERCEPT_IOINST: STATEBK->c = SIE_C_IOINST; break; case PGM_OPERATION_EXCEPTION: STATEBK->c = SIE_C_OPEREXC; break; default: STATEBK->c = SIE_C_PGMINT; break; } /* Save CPU timer */ STORE_DW(STATEBK->cputimer, cpu_timer(GUESTREGS)); /* Save clock comparator */ STORE_DW(STATEBK->clockcomp, GUESTREGS->clkc << 8); #if defined(_FEATURE_INTERVAL_TIMER) && !defined(FEATURE_ESAME) /* If this is a S/370 guest, and the interval timer is enabled then save the timer state control bit */ if( (STATEBK->m & SIE_M_370) && !(STATEBK->m & SIE_M_ITMOF)) { /* Save the shadow interval timer */ s370_store_int_timer(regs); if(IS_IC_ITIMER(GUESTREGS)) STATEBK->s |= SIE_S_T; else STATEBK->s &= ~SIE_S_T; } #endif /*defined(_FEATURE_INTERVAL_TIMER) && !defined(FEATURE_ESAME)*/ /* Save TOD Programmable Field */ STORE_HW(STATEBK->todpf, GUESTREGS->todpr); /* Save GR14 */ STORE_W(STATEBK->gr14, GUESTREGS->GR(14)); /* Save GR15 */ STORE_W(STATEBK->gr15, GUESTREGS->GR(15)); /* Store the PSW */ if(GUESTREGS->arch_mode == ARCH_390) s390_store_psw (GUESTREGS, STATEBK->psw); #if defined(_370) || defined(_900) else #endif #if defined(FEATURE_ESAME) z900_store_psw (GUESTREGS, STATEBK->psw); #else /*!defined(FEATURE_ESAME)*/ #if defined(_370) s370_store_psw (GUESTREGS, STATEBK->psw); #endif #endif /*!defined(FEATURE_ESAME)*/ /* save control registers */ for(n = 0;n < 16; n++) STORE_W(STATEBK->cr[n], GUESTREGS->CR(n)); /* Update the approprate host registers */ memcpy(regs->gr, GUESTREGS->gr, 14 * sizeof(regs->gr[0])); memcpy(regs->ar, GUESTREGS->ar, 16 * sizeof(regs->ar[0])); memcpy(regs->fpr, GUESTREGS->fpr, 32 * sizeof(regs->fpr[0])); #if defined(FEATURE_BINARY_FLOATING_POINT) regs->fpc = GUESTREGS->fpc; #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ INVALIDATE_AIA(regs); SET_AEA_MODE(regs); /* Zeroize the interruption parameters */ memset(STATEBK->ipa, 0, 10); if( STATEBK->c == SIE_C_INST || STATEBK->c == SIE_C_PGMINST || STATEBK->c == SIE_C_OPEREXC || STATEBK->c == SIE_C_IOINST ) { /* Indicate interception format 2 */ STATEBK->f |= SIE_F_IN; #if defined(_FEATURE_PER) /* Handle PER or concurrent PER event */ if( OPEN_IC_PER(GUESTREGS) && ECMODE(&GUESTREGS->psw) && (GUESTREGS->psw.sysmask & PSW_PERMODE) ) { PSA *psa; #if defined(_FEATURE_PER2) GUESTREGS->perc |= OPEN_IC_PER(GUESTREGS) >> ((32 - IC_CR9_SHIFT) - 16); /* Positions 14 and 15 contain zeros if a storage alteration event was not indicated */ if( !(OPEN_IC_PER_SA(GUESTREGS)) || (OPEN_IC_PER_STURA(GUESTREGS)) ) GUESTREGS->perc &= 0xFFFC; #endif /*defined(_FEATURE_PER2)*/ /* Point to PSA fields in state descriptor */ psa = (void*)(regs->mainstor + SIE_STATE(GUESTREGS) + SIE_IP_PSA_OFFSET); STORE_HW(psa->perint, GUESTREGS->perc); STORE_W(psa->peradr, GUESTREGS->peradr); } if (IS_IC_PER_IF(GUESTREGS)) STATEBK->f |= SIE_F_IF; /* Reset any pending PER indication */ OFF_IC_PER(GUESTREGS); #endif /*defined(_FEATURE_PER)*/ /* Backup to the previous instruction */ GUESTREGS->ip -= REAL_ILC(GUESTREGS); if (GUESTREGS->ip < GUESTREGS->aip) GUESTREGS->ip = GUESTREGS->inst; /* Update interception parameters in the state descriptor */ if(GUESTREGS->ip[0] == 0x44 #if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) || (GUESTREGS->ip[0] == 0xc6 && !(GUESTREGS->ip[1] & 0x0f)) #endif /*defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/ ) { int exilc; STATEBK->f |= SIE_F_EX; exilc = ILC(GUESTREGS->exinst[0]); memcpy(STATEBK->ipa, GUESTREGS->exinst, exilc); } else { if(!GUESTREGS->instinvalid) memcpy(STATEBK->ipa, GUESTREGS->ip, ILC(GUESTREGS->ip[0])); } } } #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ #if defined(_FEATURE_SIE) /* Execute guest instructions */ int ARCH_DEP(run_sie) (REGS *regs) { int icode; /* SIE longjmp intercept code */ BYTE oldv; /* siebk->v change check reference */ BYTE *ip; /* instruction pointer */ SIE_PERFMON(SIE_PERF_RUNSIE); #if defined(_FEATURE_PER) /* Reset any PER pending indication */ OFF_IC_PER(GUESTREGS); #endif /*defined(_FEATURE_PER)*/ #ifdef FEATURE_INTERVAL_TIMER /* Load the shadow interval timer */ { S32 itimer; FETCH_FW(itimer,GUESTREGS->psa->inttimer); set_int_timer(GUESTREGS, itimer); } #endif do { SIE_PERFMON(SIE_PERF_RUNLOOP_1); if(!(icode = setjmp(GUESTREGS->progjmp))) do { SIE_PERFMON(SIE_PERF_RUNLOOP_2); /* Keep a copy if SIEBK 'v' field for later checks */ oldv=GUESTREGS->siebk->v; /* Set `execflag' to 0 in case EXecuted instruction did progjmp */ GUESTREGS->execflag = 0; if( SIE_I_STOP(GUESTREGS) || SIE_I_EXT(GUESTREGS) || SIE_I_IO(GUESTREGS) ) break; if( SIE_IC_INTERRUPT_CPU(GUESTREGS) ) { SIE_PERFMON(SIE_PERF_INTCHECK); /* Process PER program interrupts */ if( OPEN_IC_PER(GUESTREGS) ) ARCH_DEP(program_interrupt) (GUESTREGS, PGM_PER_EVENT); OBTAIN_INTLOCK(regs); OFF_IC_INTERRUPT(GUESTREGS); /* Set psw.IA and invalidate the aia */ INVALIDATE_AIA(GUESTREGS); if( OPEN_IC_EXTPENDING(GUESTREGS) ) ARCH_DEP(perform_external_interrupt) (GUESTREGS); if( (STATEBK->ec[0] & SIE_EC0_IOA) && OPEN_IC_IOPENDING(GUESTREGS) ) { PERFORM_SERIALIZATION (GUESTREGS); PERFORM_CHKPT_SYNC (GUESTREGS); ARCH_DEP (perform_io_interrupt) (GUESTREGS); } #if defined(_FEATURE_WAITSTATE_ASSIST) /* Wait state assist */ if (WAITSTATE(&GUESTREGS->psw) && (STATEBK->ec[0] & SIE_EC0_WAIA)) { /* Test for disabled wait PSW and issue message */ if( IS_IC_DISABLED_WAIT_PSW(GUESTREGS) ) { RELEASE_INTLOCK(regs); longjmp(GUESTREGS->progjmp, SIE_INTERCEPT_WAIT); } if( SIE_I_STOP(GUESTREGS) || SIE_I_EXT(GUESTREGS) || SIE_I_IO(GUESTREGS) || SIE_I_HOST(regs) ) { RELEASE_INTLOCK(regs); break; } SET_AEA_MODE(GUESTREGS); { struct timespec waittime; U64 now = host_tod(); waittime.tv_sec = now / 1000000; waittime.tv_nsec = ((now % 1000000) + 3333) * 1000; #ifdef OPTION_MIPS_COUNTING regs->waittod = now; #endif sysblk.waiting_mask |= regs->cpubit; sysblk.intowner = LOCK_OWNER_NONE; timed_wait_condition (®s->intcond, &sysblk.intlock, &waittime); while (sysblk.syncing) wait_condition (&sysblk.sync_bc_cond, &sysblk.intlock); sysblk.intowner = regs->cpuad; sysblk.waiting_mask ^= regs->cpubit; #ifdef OPTION_MIPS_COUNTING regs->waittime += host_tod() - regs->waittod; regs->waittod = 0; #endif } RELEASE_INTLOCK(regs); break; } /* end if(wait) */ #endif RELEASE_INTLOCK(regs); } if( SIE_I_WAIT(GUESTREGS) ) break; ip = INSTRUCTION_FETCH(GUESTREGS, 0); #if defined(SIE_DEBUG) /* Display the instruction */ ARCH_DEP(display_inst) (GUESTREGS, GUESTREGS->instinvalid ? NULL : ip); #endif /*defined(SIE_DEBUG)*/ SIE_PERFMON(SIE_PERF_EXEC); GUESTREGS->instcount = 1; EXECUTE_INSTRUCTION(ip, GUESTREGS); do { SIE_PERFMON(SIE_PERF_EXEC_U); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); GUESTREGS->instcount += 12; UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); UNROLLED_EXECUTE(GUESTREGS); } while( likely(!SIE_I_HOST(regs) && GUESTREGS->siebk->v==oldv && !SIE_INTERRUPT_PENDING(GUESTREGS))); /******************************************/ /* ABOVE : Keep executing instructions */ /* in a tight loop until... */ /* - A Host Interrupt is made pending */ /* - An external source changes siebk->v */ /* - A guest interrupt is made pending */ /******************************************/ regs->instcount += GUESTREGS->instcount; } while( unlikely(!SIE_I_HOST(regs) && !SIE_I_WAIT(GUESTREGS) && !SIE_I_EXT(GUESTREGS) && !SIE_I_IO(GUESTREGS) && !SIE_INTERRUPT_PENDING(GUESTREGS))); /******************************************/ /* ABOVE : Remain in SIE until... */ /* - A Host Interrupt is made pending */ /* - A Sie defined irpt becomes enabled */ /* - A guest interrupt is made pending */ /******************************************/ if(icode == 0 || icode == SIE_NO_INTERCEPT) { /* Check PER first, higher priority */ if( OPEN_IC_PER(GUESTREGS) ) ARCH_DEP(program_interrupt) (GUESTREGS, PGM_PER_EVENT); if( SIE_I_EXT(GUESTREGS) ) icode = SIE_INTERCEPT_EXTREQ; else if( SIE_I_IO(GUESTREGS) ) icode = SIE_INTERCEPT_IOREQ; else if( SIE_I_STOP(GUESTREGS) ) icode = SIE_INTERCEPT_STOPREQ; else if( SIE_I_WAIT(GUESTREGS) ) icode = SIE_INTERCEPT_WAIT; else if( SIE_I_HOST(regs) ) icode = SIE_HOST_INTERRUPT; } } while(icode == 0 || icode == SIE_NO_INTERCEPT); return icode; } #if defined(FEATURE_INTERPRETIVE_EXECUTION) #if defined(FEATURE_REGION_RELOCATE) /*-------------------------------------------------------------------*/ /* B23D STZP - Store Zone Parameter [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_zone_parameter) { int b2; /* Values of R fields */ RADR effective_addr2; /* address of state desc. */ ZPB zpb; /* Zone Parameter Block */ int zone; /* Zone number */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_IO,"STZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L); FW_CHECK(regs->GR(2), regs); zone = regs->GR_LHLCL(1); if(zone >= FEATURE_SIE_MAXZONES) { PTT(PTT_CL_ERR,"*STZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L); regs->psw.cc = 3; return; } STORE_W(zpb.mso,sysblk.zpb[zone].mso); STORE_W(zpb.msl,sysblk.zpb[zone].msl); STORE_W(zpb.eso,sysblk.zpb[zone].eso); STORE_W(zpb.esl,sysblk.zpb[zone].esl); ARCH_DEP(vstorec(&zpb, sizeof(ZPB)-1,regs->GR(2), 2, regs)); regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* B23E SZP - Set Zone Parameter [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_zone_parameter) { int b2; /* Values of R fields */ RADR effective_addr2; /* address of state desc. */ ZPB zpb; /* Zone Parameter Block */ int zone; /* Zone number */ RADR mso, /* Main Storage Origin */ msl, /* Main Storage Length */ eso, /* Expanded Storage Origin */ esl; /* Expanded Storage Length */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_IO,"SZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L); FW_CHECK(regs->GR(2), regs); zone = regs->GR_LHLCL(1); if(zone == 0 || zone >= FEATURE_SIE_MAXZONES) { PTT(PTT_CL_ERR,"*SZP", regs->GR_L(1), regs->GR_L(2),regs->psw.IA_L); regs->psw.cc = 3; return; } ARCH_DEP(vfetchc(&zpb, sizeof(ZPB)-1,regs->GR(2), 2, regs)); FETCH_W(mso,zpb.mso); FETCH_W(msl,zpb.msl); FETCH_W(eso,zpb.eso); FETCH_W(esl,zpb.esl); #if defined(FEATURE_ESAME) if( (mso & ~ZPB2_MS_VALID) || (msl & ~ZPB2_MS_VALID) || (eso & ~ZPB2_ES_VALID) || (esl & ~ZPB2_ES_VALID) ) ARCH_DEP(program_interrupt) (regs, PGM_OPERAND_EXCEPTION); #endif /*defined(FEATURE_ESAME)*/ sysblk.zpb[zone].mso = mso; sysblk.zpb[zone].msl = msl; sysblk.zpb[zone].eso = eso; sysblk.zpb[zone].esl = esl; regs->psw.cc = 0; } #endif /*defined(FEATURE_REGION_RELOCATE)*/ #if defined(FEATURE_IO_ASSIST) /*-------------------------------------------------------------------*/ /* B23F TPZI - Test Pending Zone Interrupt [S] */ /*-------------------------------------------------------------------*/ DEF_INST(test_pending_zone_interrupt) { int b2; /* Values of R fields */ RADR effective_addr2; /* address of state desc. */ U32 ioid; /* I/O interruption address */ U32 ioparm; /* I/O interruption parameter*/ U32 iointid; /* I/O interruption ident */ FWORD tpziid[3]; int zone; /* Zone number */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTT(PTT_CL_IO,"TPZI", regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L); FW_CHECK(regs->GR(2), regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); zone = regs->GR_LHLCL(1); if(zone >= FEATURE_SIE_MAXZONES) { PTT(PTT_CL_ERR,"*TPZI", regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L); regs->psw.cc = 0; return; } if( IS_IC_IOPENDING ) { /* Obtain the interrupt lock */ OBTAIN_INTLOCK(regs); /* Test (but don't clear!) pending interrupt, and set condition code */ if( ARCH_DEP(present_zone_io_interrupt) (&ioid, &ioparm, &iointid, zone) ) /* Store the SSID word and I/O parameter if an interrupt was pending */ { /* Store interruption parms */ STORE_FW(tpziid[0],ioid); STORE_FW(tpziid[1],ioparm); STORE_FW(tpziid[2],iointid); /* Release the interrupt lock */ RELEASE_INTLOCK(regs); ARCH_DEP(vstorec(&tpziid, sizeof(tpziid)-1,regs->GR(2), 2, regs)); regs->psw.cc = 1; } else { /* Release the interrupt lock */ RELEASE_INTLOCK(regs); regs->psw.cc = 0; } } else regs->psw.cc = 0; } /*-------------------------------------------------------------------*/ /* DIAG 002 - Update Interrupt Interlock Control Bit in PMCW */ /*-------------------------------------------------------------------*/ void ARCH_DEP(diagnose_002) (REGS *regs, int r1, int r3) { DEVBLK *dev; U32 newgr1; /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, or is not enabled */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0) { PTT(PTT_CL_ERR,"*DIAG002", regs->GR_L(r1),regs->GR_L(r3),regs->GR_L(1)); regs->psw.cc = 3; return; } /* Obtain the device lock */ obtain_lock (&dev->lock); /* Set newgr1 to the current value of pending and interlock control */ newgr1 = ((dev->scsw.flag3 & SCSW3_SC_PEND) || (dev->pciscsw.flag3 & SCSW3_SC_PEND)) ? 0x02 : 0; if(dev->pmcw.flag27 & PMCW27_I) newgr1 |= 0x01; /* Do a compare-and-swap operation on the interrupt interlock control bit where both interlock and pending bits are compared, but only the interlock bit is swapped */ if((regs->GR_L(r1) & 0x03) == newgr1) { dev->pmcw.flag27 &= ~PMCW27_I; dev->pmcw.flag27 |= (regs->GR_L(r3) & 0x01) ? PMCW27_I : 0; regs->psw.cc = 0; } else { regs->GR_L(r1) &= ~0x03; regs->GR_L(r1) |= newgr1; regs->psw.cc = 1; } /* Release the device lock */ release_lock (&dev->lock); } #endif /*defined(FEATURE_IO_ASSIST)*/ #endif /*defined(FEATURE_INTERPRETIVE_EXECUTION)*/ #endif #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "sie.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "sie.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/qdio.c0000664000175000017500000000606312564723224011310 00000000000000/* QDIO.C (c) Copyright Jan Jaeger, 2003-2009 */ /* Queued Direct Input Output */ /* This module contains the Signal Adapter instruction */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_QDIO_C_) #define _QDIO_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #undef PTIO #define PTIO(_class, _name) \ PTT(PTT_CL_ ## _class,_name,regs->GR_L(1),(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L) #if defined(FEATURE_QUEUED_DIRECT_IO) /*-------------------------------------------------------------------*/ /* B274 SIGA - Signal Adapter [S] */ /*-------------------------------------------------------------------*/ DEF_INST(signal_adapter) { int b2; RADR effective_addr2; DEVBLK *dev; /* -> device block */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); SIE_INTERCEPT(regs); PTIO(IO,"SIGA"); /* Specification exception if invalid function code */ if(regs->GR_L(0) > SIGA_FC_MAX) ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if the ssid including lcss is invalid */ SSID_CHECK(regs); /* Locate the device block for this subchannel */ dev = find_device_by_subchan (regs->GR_L(1)); /* Condition code 3 if subchannel does not exist, is not valid, or is not enabled or is not a QDIO subchannel */ if (dev == NULL || (dev->pmcw.flag5 & PMCW5_V) == 0 || (dev->pmcw.flag5 & PMCW5_E) == 0 || (dev->pmcw.flag4 & PMCW4_Q) == 0) { PTIO(ERR,"*SIGA"); #if defined(_FEATURE_QUEUED_DIRECT_IO_ASSIST) SIE_INTERCEPT(regs); #endif regs->psw.cc = 3; return; } /* Obtain the device lock */ obtain_lock (&dev->lock); /* Check that device is QDIO active */ if ((dev->scsw.flag2 & SCSW2_Q) == 0) { PTIO(ERR,"*SIGA"); release_lock (&dev->lock); regs->psw.cc = 1; return; } switch(regs->GR_L(0)) { case SIGA_FC_R: if(dev->hnd->siga_r) regs->psw.cc = (dev->hnd->siga_r) (dev, regs->GR_L(2) ); else { PTIO(ERR,"*SIGA"); regs->psw.cc = 3; } break; case SIGA_FC_W: if(dev->hnd->siga_w) regs->psw.cc = (dev->hnd->siga_w) (dev, regs->GR_L(2) ); else { PTIO(ERR,"*SIGA"); regs->psw.cc = 3; } break; case SIGA_FC_S: /* No signalling required for sync requests as we emulate a real machine */ regs->psw.cc = 0; break; default: PTIO(ERR,"*SIGA"); } release_lock (&dev->lock); } #endif /*defined(FEATURE_QUEUED_DIRECT_IO)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "qdio.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "qdio.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/clock.c0000664000175000017500000004363212564723224011452 00000000000000/* CLOCK.C (c) Copyright Jan Jaeger, 2000-2009 */ /* TOD Clock functions */ /*-------------------------------------------------------------------*/ /* The emulated hardware clock is based on the host clock, adjusted */ /* by means of an offset and a steering rate. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "sr.h" #if !defined(_CLOCK_C_) #define _CLOCK_C_ #include "clock.h" // static int clock_state = CC_CLOCK_SET; static CSR old; static CSR new; static CSR *current = &new; void csr_reset() { new.start_time = 0; new.base_offset = 0; new.fine_s_rate = 0; new.gross_s_rate = 0; current = &new; old = new; } static U64 universal_tod; static U64 universal_clock(void) /* really: any clock used as a base */ { struct timeval tv; gettimeofday (&tv, NULL); /* Load number of seconds since 00:00:00 01 Jan 1970 */ universal_tod = (U64)tv.tv_sec; universal_tod += SECONDS_IN_SEVENTY_YEARS; /* Convert to microseconds */ universal_tod = (universal_tod * 1000000) + tv.tv_usec; /* Shift left 4 bits so that bits 0-7=TOD Clock Epoch, bits 8-59=TOD Clock bits 0-51, bits 60-63=zero */ universal_tod <<= 4; return universal_tod; } /* The hercules hardware clock, based on the universal clock, but */ /* running at its own speed as optionally set by set_tod_steering() */ /* The hardware clock returns a unique value */ static double hw_steering = 0.0; /* Current TOD clock steering rate */ static U64 hw_episode; /* TOD of start of steering episode */ static S64 hw_offset = 0; /* Current offset between TOD and HW */ // static U64 hw_tod = 0; /* Globally defined in clock.h */ static inline U64 hw_adjust(U64 base_tod) { /* Apply hardware offset, this is the offset achieved by all previous steering episodes */ base_tod += hw_offset; /* Apply the steering offset from the current steering episode */ base_tod += (S64)(base_tod - hw_episode) * hw_steering; /* Ensure that the clock returns a unique value */ if(hw_tod < base_tod) return base_tod; else return hw_tod += 0x10; } U64 hw_clock(void) { U64 temp_tod; obtain_lock(&sysblk.todlock); /* Get the time of day (GMT) */ temp_tod = universal_clock(); /* Ajust speed and ensure uniqueness */ hw_tod = hw_adjust(temp_tod); release_lock(&sysblk.todlock); return hw_tod; } static U64 hw_clock_l(void) { hw_tod = hw_adjust(universal_clock()); return hw_tod; } /* set_tod_steering(double) sets a new steering rate. */ /* When a new steering episode begins, the offset is adjusted, */ /* and the new steering rate takes effect */ void set_tod_steering(double steering) { obtain_lock(&sysblk.todlock); hw_offset = hw_clock_l() - universal_tod; hw_episode = hw_tod; hw_steering = steering; release_lock(&sysblk.todlock); } /* Start a new episode */ static inline void start_new_episode() { hw_offset = hw_tod - universal_tod; hw_episode = hw_tod; new.start_time = hw_episode; hw_steering = ldexp(2,-44) * (S32)(new.fine_s_rate + new.gross_s_rate); current = &new; } /* Prepare for a new episode */ static inline void prepare_new_episode() { if(current == &new) { old = new; current = &old; } } /* Ajust the epoch for all active cpu's in the configuration */ static U64 adjust_epoch_cpu_all(U64 epoch) { int cpu; /* Update the TOD clock of all CPU's in the configuration as we simulate 1 shared TOD clock, and do not support the TOD clock sync check */ for (cpu = 0; cpu < MAX_CPU; cpu++) { obtain_lock(&sysblk.cpulock[cpu]); if (IS_CPU_ONLINE(cpu)) sysblk.regs[cpu]->tod_epoch = epoch; release_lock(&sysblk.cpulock[cpu]); } return epoch; } double get_tod_steering(void) { return hw_steering; } void set_tod_epoch(S64 epoch) { obtain_lock(&sysblk.todlock); csr_reset(); tod_epoch = epoch; release_lock(&sysblk.todlock); adjust_epoch_cpu_all(epoch); } void adjust_tod_epoch(S64 epoch) { obtain_lock(&sysblk.todlock); csr_reset(); tod_epoch += epoch; release_lock(&sysblk.todlock); adjust_epoch_cpu_all(tod_epoch); } void set_tod_clock(U64 tod) { set_tod_epoch(tod - hw_clock()); } S64 get_tod_epoch() { return tod_epoch; } static void set_gross_steering_rate(S32 gsr) { obtain_lock(&sysblk.todlock); prepare_new_episode(); new.gross_s_rate = gsr; release_lock(&sysblk.todlock); } static void set_fine_steering_rate(S32 fsr) { obtain_lock(&sysblk.todlock); prepare_new_episode(); new.fine_s_rate = fsr; release_lock(&sysblk.todlock); } static void set_tod_offset(S64 offset) { obtain_lock(&sysblk.todlock); prepare_new_episode(); new.base_offset = offset; release_lock(&sysblk.todlock); } static void adjust_tod_offset(S64 offset) { obtain_lock(&sysblk.todlock); prepare_new_episode(); new.base_offset = old.base_offset + offset; release_lock(&sysblk.todlock); } /* The cpu timer is internally kept as an offset to the hw_clock() * the cpu timer counts down as the clock approaches the timer epoch */ void set_cpu_timer(REGS *regs, S64 timer) { regs->cpu_timer = (timer >> 8) + hw_clock(); } S64 cpu_timer(REGS *regs) { S64 timer; timer = (regs->cpu_timer - hw_clock()) << 8; return timer; } U64 tod_clock(REGS *regs) { U64 current_tod; obtain_lock(&sysblk.todlock); current_tod = hw_clock_l(); /* If we are in the old episode, and the new episode has arrived then we must take action to start the new episode */ if(current == &old) start_new_episode(); /* Set the clock to the new updated value with offset applied */ current_tod += current->base_offset; tod_value = current_tod; release_lock(&sysblk.todlock); return current_tod + regs->tod_epoch; } #if defined(_FEATURE_INTERVAL_TIMER) #if defined(_FEATURE_ECPSVM) static inline S32 ecps_vtimer(REGS *regs) { return (S32)TOD_TO_ITIMER((S64)(regs->ecps_vtimer - hw_clock())); } static inline void set_ecps_vtimer(REGS *regs, S32 vtimer) { regs->ecps_vtimer = (U64)(hw_clock() + ITIMER_TO_TOD(vtimer)); regs->ecps_oldtmr = vtimer; } #endif /*defined(_FEATURE_ECPSVM)*/ S32 int_timer(REGS *regs) { return (S32)TOD_TO_ITIMER((S64)(regs->int_timer - hw_clock())); } void set_int_timer(REGS *regs, S32 itimer) { regs->int_timer = (U64)(hw_clock() + ITIMER_TO_TOD(itimer)); regs->old_timer = itimer; } int chk_int_timer(REGS *regs) { S32 itimer; int pending = 0; itimer = int_timer(regs); if(itimer < 0 && regs->old_timer >= 0) { ON_IC_ITIMER(regs); pending = 1; regs->old_timer=itimer; } #if defined(_FEATURE_ECPSVM) if(regs->ecps_vtmrpt) { itimer = ecps_vtimer(regs); if(itimer < 0 && regs->ecps_oldtmr >= 0) { ON_IC_ECPSVTIMER(regs); pending += 2; } } #endif /*defined(_FEATURE_ECPSVM)*/ return pending; } #endif /*defined(_FEATURE_INTERVAL_TIMER)*/ /*-------------------------------------------------------------------*/ /* Update TOD clock */ /* */ /* This function updates the TOD clock. */ /* */ /* This function is called by timer_update_thread and by cpu_thread */ /* instructions that manipulate any of the timer related entities */ /* (clock comparator, cpu timer and interval timer). */ /* */ /* Internal function `check_timer_event' is called which will signal */ /* any timer related interrupts to the appropriate cpu_thread. */ /* */ /* Callers *must* own the todlock and *must not* own the intlock. */ /* */ /* update_tod_clock() returns the tod delta, by which the cpu timer */ /* has been adjusted. */ /* */ /*-------------------------------------------------------------------*/ // static U64 tod_value; U64 update_tod_clock(void) { U64 new_clock; obtain_lock(&sysblk.todlock); new_clock = hw_clock_l(); /* If we are in the old episode, and the new episode has arrived then we must take action to start the new episode */ if(current == &old) start_new_episode(); /* Set the clock to the new updated value with offset applied */ new_clock += current->base_offset; tod_value = new_clock; release_lock(&sysblk.todlock); /* Update the timers and check if either a clock related event has become pending */ update_cpu_timer(); return new_clock; } #define SR_SYS_CLOCK_CURRENT_CSR ( SR_SYS_CLOCK | 0x001 ) #define SR_SYS_CLOCK_UNIVERSAL_TOD ( SR_SYS_CLOCK | 0x002 ) #define SR_SYS_CLOCK_HW_STEERING ( SR_SYS_CLOCK | 0x004 ) #define SR_SYS_CLOCK_HW_EPISODE ( SR_SYS_CLOCK | 0x005 ) #define SR_SYS_CLOCK_HW_OFFSET ( SR_SYS_CLOCK | 0x006 ) #define SR_SYS_CLOCK_OLD_CSR ( SR_SYS_CLOCK | 0x100 ) #define SR_SYS_CLOCK_OLD_CSR_START_TIME ( SR_SYS_CLOCK | 0x101 ) #define SR_SYS_CLOCK_OLD_CSR_BASE_OFFSET ( SR_SYS_CLOCK | 0x102 ) #define SR_SYS_CLOCK_OLD_CSR_FINE_S_RATE ( SR_SYS_CLOCK | 0x103 ) #define SR_SYS_CLOCK_OLD_CSR_GROSS_S_RATE ( SR_SYS_CLOCK | 0x104 ) #define SR_SYS_CLOCK_NEW_CSR ( SR_SYS_CLOCK | 0x200 ) #define SR_SYS_CLOCK_NEW_CSR_START_TIME ( SR_SYS_CLOCK | 0x201 ) #define SR_SYS_CLOCK_NEW_CSR_BASE_OFFSET ( SR_SYS_CLOCK | 0x202 ) #define SR_SYS_CLOCK_NEW_CSR_FINE_S_RATE ( SR_SYS_CLOCK | 0x203 ) #define SR_SYS_CLOCK_NEW_CSR_GROSS_S_RATE ( SR_SYS_CLOCK | 0x204 ) int clock_hsuspend(void *file) { int i; char buf[SR_MAX_STRING_LENGTH]; i = (current == &new); SR_WRITE_VALUE(file, SR_SYS_CLOCK_CURRENT_CSR, i, sizeof(i)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_UNIVERSAL_TOD, universal_tod, sizeof(universal_tod)); snprintf(buf, sizeof(buf), "%f", hw_steering); SR_WRITE_STRING(file, SR_SYS_CLOCK_HW_STEERING, buf); SR_WRITE_VALUE(file, SR_SYS_CLOCK_HW_EPISODE, hw_episode, sizeof(hw_episode)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_HW_OFFSET, hw_offset, sizeof(hw_offset)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_START_TIME, old.start_time, sizeof(old.start_time)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_BASE_OFFSET, old.base_offset, sizeof(old.base_offset)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_FINE_S_RATE, old.fine_s_rate, sizeof(old.fine_s_rate)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_OLD_CSR_GROSS_S_RATE, old.gross_s_rate, sizeof(old.gross_s_rate)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_START_TIME, new.start_time, sizeof(new.start_time)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_BASE_OFFSET, new.base_offset, sizeof(new.base_offset)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_FINE_S_RATE, new.fine_s_rate, sizeof(new.fine_s_rate)); SR_WRITE_VALUE(file, SR_SYS_CLOCK_NEW_CSR_GROSS_S_RATE, new.gross_s_rate, sizeof(new.gross_s_rate)); return 0; } int clock_hresume(void *file) { size_t key, len; int i; float f; char buf[SR_MAX_STRING_LENGTH]; memset(&old, 0, sizeof(CSR)); memset(&new, 0, sizeof(CSR)); current = &new; universal_tod = 0; hw_steering = 0.0; hw_episode = 0; hw_offset = 0; do { SR_READ_HDR(file, key, len); switch (key) { case SR_SYS_CLOCK_CURRENT_CSR: SR_READ_VALUE(file, len, &i, sizeof(i)); current = i ? &new : &old; break; case SR_SYS_CLOCK_UNIVERSAL_TOD: SR_READ_VALUE(file, len, &universal_tod, sizeof(universal_tod)); break; case SR_SYS_CLOCK_HW_STEERING: SR_READ_STRING(file, buf, len); sscanf(buf, "%f",&f); hw_steering = f; break; case SR_SYS_CLOCK_HW_EPISODE: SR_READ_VALUE(file, len, &hw_episode, sizeof(hw_episode)); break; case SR_SYS_CLOCK_HW_OFFSET: SR_READ_VALUE(file, len, &hw_offset, sizeof(hw_offset)); break; case SR_SYS_CLOCK_OLD_CSR_START_TIME: SR_READ_VALUE(file, len, &old.start_time, sizeof(old.start_time)); break; case SR_SYS_CLOCK_OLD_CSR_BASE_OFFSET: SR_READ_VALUE(file, len, &old.base_offset, sizeof(old.base_offset)); break; case SR_SYS_CLOCK_OLD_CSR_FINE_S_RATE: SR_READ_VALUE(file, len, &old.fine_s_rate, sizeof(old.fine_s_rate)); break; case SR_SYS_CLOCK_OLD_CSR_GROSS_S_RATE: SR_READ_VALUE(file, len, &old.gross_s_rate, sizeof(old.gross_s_rate)); break; case SR_SYS_CLOCK_NEW_CSR_START_TIME: SR_READ_VALUE(file, len, &new.start_time, sizeof(new.start_time)); break; case SR_SYS_CLOCK_NEW_CSR_BASE_OFFSET: SR_READ_VALUE(file, len, &new.base_offset, sizeof(new.base_offset)); break; case SR_SYS_CLOCK_NEW_CSR_FINE_S_RATE: SR_READ_VALUE(file, len, &new.fine_s_rate, sizeof(new.fine_s_rate)); break; case SR_SYS_CLOCK_NEW_CSR_GROSS_S_RATE: SR_READ_VALUE(file, len, &new.gross_s_rate, sizeof(new.gross_s_rate)); break; default: SR_READ_SKIP(file, len); break; } } while ((key & SR_SYS_MASK) == SR_SYS_CLOCK); return 0; } #endif #if defined(FEATURE_INTERVAL_TIMER) static void ARCH_DEP(_store_int_timer_2) (REGS *regs,int getlock) { S32 itimer; S32 vtimer=0; if(getlock) { OBTAIN_INTLOCK(regs->hostregs?regs:NULL); } itimer=int_timer(regs); STORE_FW(regs->psa->inttimer, itimer); #if defined(FEATURE_ECPSVM) if(regs->ecps_vtmrpt) { vtimer=ecps_vtimer(regs); STORE_FW(regs->ecps_vtmrpt, itimer); } #endif /*defined(FEATURE_ECPSVM)*/ chk_int_timer(regs); #if defined(FEATURE_ECPSVM) if(regs->ecps_vtmrpt) { regs->ecps_oldtmr = vtimer; } #endif /*defined(FEATURE_ECPSVM)*/ if(getlock) { RELEASE_INTLOCK(regs->hostregs?regs:NULL); } } DLL_EXPORT void ARCH_DEP(store_int_timer) (REGS *regs) { ARCH_DEP(_store_int_timer_2) (regs,1); } void ARCH_DEP(store_int_timer_nolock) (REGS *regs) { ARCH_DEP(_store_int_timer_2) (regs,0); } DLL_EXPORT void ARCH_DEP(fetch_int_timer) (REGS *regs) { S32 itimer; FETCH_FW(itimer, regs->psa->inttimer); OBTAIN_INTLOCK(regs->hostregs?regs:NULL); set_int_timer(regs, itimer); #if defined(FEATURE_ECPSVM) if(regs->ecps_vtmrpt) { FETCH_FW(itimer, regs->ecps_vtmrpt); set_ecps_vtimer(regs, itimer); } #endif /*defined(FEATURE_ECPSVM)*/ RELEASE_INTLOCK(regs->hostregs?regs:NULL); } #endif #if defined(FEATURE_TOD_CLOCK_STEERING) void ARCH_DEP(set_gross_s_rate) (REGS *regs) { S32 gsr; gsr = ARCH_DEP(vfetch4) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); set_gross_steering_rate(gsr); } void ARCH_DEP(set_fine_s_rate) (REGS *regs) { S32 fsr; fsr = ARCH_DEP(vfetch4) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); set_fine_steering_rate(fsr); } void ARCH_DEP(set_tod_offset) (REGS *regs) { S64 offset; offset = ARCH_DEP(vfetch8) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); set_tod_offset(offset >> 8); } void ARCH_DEP(adjust_tod_offset) (REGS *regs) { S64 offset; offset = ARCH_DEP(vfetch8) (regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); adjust_tod_offset(offset >> 8); } void ARCH_DEP(query_physical_clock) (REGS *regs) { ARCH_DEP(vstore8) (universal_clock() << 8, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); } void ARCH_DEP(query_steering_information) (REGS *regs) { PTFFQSI qsi; obtain_lock(&sysblk.todlock); STORE_DW(qsi.physclk, universal_clock() << 8); STORE_DW(qsi.oldestart, old.start_time << 8); STORE_DW(qsi.oldebase, old.base_offset << 8); STORE_FW(qsi.oldfsr, old.fine_s_rate ); STORE_FW(qsi.oldgsr, old.gross_s_rate ); STORE_DW(qsi.newestart, new.start_time << 8); STORE_DW(qsi.newebase, new.base_offset << 8); STORE_FW(qsi.newfsr, new.fine_s_rate ); STORE_FW(qsi.newgsr, new.gross_s_rate ); release_lock(&sysblk.todlock); ARCH_DEP(vstorec) (&qsi, sizeof(qsi)-1, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); } void ARCH_DEP(query_tod_offset) (REGS *regs) { PTFFQTO qto; obtain_lock(&sysblk.todlock); STORE_DW(qto.todoff, (hw_clock_l() - universal_tod) << 8); STORE_DW(qto.physclk, universal_tod << 8); STORE_DW(qto.ltodoff, current->base_offset << 8); STORE_DW(qto.todepoch, regs->tod_epoch << 8); release_lock(&sysblk.todlock); ARCH_DEP(vstorec) (&qto, sizeof(qto)-1, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); } void ARCH_DEP(query_available_functions) (REGS *regs) { PTFFQAF qaf; STORE_FW(qaf.sb[0] , 0xF0000000); /* Functions 0x00..0x1F */ STORE_FW(qaf.sb[1] , 0x00000000); /* Functions 0x20..0x3F */ STORE_FW(qaf.sb[2] , 0xF0000000); /* Functions 0x40..0x5F */ STORE_FW(qaf.sb[3] , 0x00000000); /* Functions 0x60..0x7F */ ARCH_DEP(vstorec) (&qaf, sizeof(qaf)-1, regs->GR(1) & ADDRESS_MAXWRAP(regs), 1, regs); } #endif /*defined(FEATURE_TOD_CLOCK_STEERING)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "clock.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "clock.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/timer.c0000664000175000017500000002277412564723224011503 00000000000000/* TIMER.C (c) Copyright Roger Bowler, 1999-2009 */ /* Timer support functions */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009 */ #include "hstdinc.h" #include "hercules.h" #include "opcode.h" #include "feat390.h" #include "feat370.h" // ZZ int ecpsvm_testvtimer(REGS *,int); /*-------------------------------------------------------------------*/ /* Check for timer event */ /* */ /* Checks for the following interrupts: */ /* [1] Clock comparator */ /* [2] CPU timer */ /* [3] Interval timer */ /* CPUs with an outstanding interrupt are signalled */ /* */ /* tod_delta is in hercules internal clock format (>> 8) */ /*-------------------------------------------------------------------*/ void update_cpu_timer(void) { int cpu; /* CPU counter */ REGS *regs; /* -> CPU register context */ CPU_BITMAP intmask = 0; /* Interrupt CPU mask */ /* Access the diffent register contexts with the intlock held */ OBTAIN_INTLOCK(NULL); /* Check for [1] clock comparator, [2] cpu timer, and * [3] interval timer interrupts for each CPU. */ for (cpu = 0; cpu < HI_CPU; cpu++) { /* Ignore this CPU if it is not started */ if (!IS_CPU_ONLINE(cpu) || CPUSTATE_STOPPED == sysblk.regs[cpu]->cpustate) continue; /* Point to the CPU register context */ regs = sysblk.regs[cpu]; /*-------------------------------------------* * [1] Check for clock comparator interrupt * *-------------------------------------------*/ if (TOD_CLOCK(regs) > regs->clkc) { if (!IS_IC_CLKC(regs)) { ON_IC_CLKC(regs); intmask |= regs->cpubit; } } else if (IS_IC_CLKC(regs)) OFF_IC_CLKC(regs); #if defined(_FEATURE_SIE) /* If running under SIE also check the SIE copy */ if(regs->sie_active) { /* Signal clock comparator interrupt if needed */ if(TOD_CLOCK(regs->guestregs) > regs->guestregs->clkc) { ON_IC_CLKC(regs->guestregs); intmask |= regs->cpubit; } else OFF_IC_CLKC(regs->guestregs); } #endif /*defined(_FEATURE_SIE)*/ /*-------------------------------------------* * [2] Decrement the CPU timer for each CPU * *-------------------------------------------*/ /* Set interrupt flag if the CPU timer is negative */ if (CPU_TIMER(regs) < 0) { if (!IS_IC_PTIMER(regs)) { ON_IC_PTIMER(regs); intmask |= regs->cpubit; } } else if(IS_IC_PTIMER(regs)) OFF_IC_PTIMER(regs); #if defined(_FEATURE_SIE) /* When running under SIE also update the SIE copy */ if(regs->sie_active) { /* Set interrupt flag if the CPU timer is negative */ if (CPU_TIMER(regs->guestregs) < 0) { ON_IC_PTIMER(regs->guestregs); intmask |= regs->cpubit; } else OFF_IC_PTIMER(regs->guestregs); } #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_INTERVAL_TIMER) /*-------------------------------------------* * [3] Check for interval timer interrupt * *-------------------------------------------*/ if(regs->arch_mode == ARCH_370) { if( chk_int_timer(regs) ) intmask |= regs->cpubit; } #if defined(_FEATURE_SIE) /* When running under SIE also update the SIE copy */ if(regs->sie_active) { if(SIE_STATB(regs->guestregs, M, 370) && SIE_STATNB(regs->guestregs, M, ITMOF)) { if( chk_int_timer(regs->guestregs) ) intmask |= regs->cpubit; } } #endif /*defined(_FEATURE_SIE)*/ #endif /*defined(_FEATURE_INTERVAL_TIMER)*/ } /* end for(cpu) */ /* If a timer interrupt condition was detected for any CPU then wake up those CPUs if they are waiting */ WAKEUP_CPUS_MASK (intmask); RELEASE_INTLOCK(NULL); } /* end function check_timer_event */ /*-------------------------------------------------------------------*/ /* TOD clock and timer thread */ /* */ /* This function runs as a separate thread. It wakes up every */ /* 1 microsecond, updates the TOD clock, and decrements the */ /* CPU timer for each CPU. If any CPU timer goes negative, or */ /* if the TOD clock exceeds the clock comparator for any CPU, */ /* it signals any waiting CPUs to wake up and process interrupts. */ /*-------------------------------------------------------------------*/ void *timer_update_thread (void *argp) { #ifdef OPTION_MIPS_COUNTING int i; /* Loop index */ REGS *regs; /* -> REGS */ U64 now; /* Current time of day (us) */ U64 then; /* Previous time of day (us) */ U64 diff; /* Interval (us) */ U64 mipsrate; /* Calculated MIPS rate */ U64 siosrate; /* Calculated SIO rate */ U64 cpupct; /* Calculated cpu percentage */ U64 total_mips; /* Total MIPS rate */ U64 total_sios; /* Total SIO rate */ #endif /*OPTION_MIPS_COUNTING*/ UNREFERENCED(argp); /* Set root mode in order to set priority */ SETMODE(ROOT); /* Set timer thread priority */ if (setpriority(PRIO_PROCESS, 0, sysblk.todprio)) logmsg (_("HHCTT001W Timer thread set priority %d failed: %s\n"), sysblk.todprio, strerror(errno)); /* Back to user mode */ SETMODE(USER); /* Display thread started message on control panel */ logmsg (_("HHCTT002I Timer thread started: tid="TIDPAT", pid=%d, " "priority=%d\n"), thread_id(), getpid(), getpriority(PRIO_PROCESS,0)); #ifdef OPTION_MIPS_COUNTING then = host_tod(); #endif while (sysblk.cpus) { /* Update TOD clock */ update_tod_clock(); #ifdef OPTION_MIPS_COUNTING now = host_tod(); diff = now - then; if (diff >= 1000000) { then = now; total_mips = total_sios = 0; #if defined(OPTION_SHARED_DEVICES) total_sios = sysblk.shrdcount; sysblk.shrdcount = 0; #endif for (i = 0; i < HI_CPU; i++) { obtain_lock (&sysblk.cpulock[i]); if (!IS_CPU_ONLINE(i)) { release_lock(&sysblk.cpulock[i]); continue; } regs = sysblk.regs[i]; /* 0% if CPU is STOPPED */ if (regs->cpustate == CPUSTATE_STOPPED) { regs->mipsrate = regs->siosrate = regs->cpupct = 0; release_lock(&sysblk.cpulock[i]); continue; } /* Calculate instructions per second */ mipsrate = regs->instcount; regs->instcount = 0; regs->prevcount += mipsrate; mipsrate = (mipsrate*1000000 + diff/2) / diff; if (mipsrate > MAX_REPORTED_MIPSRATE) mipsrate = 0; regs->mipsrate = mipsrate; total_mips += mipsrate; /* Calculate SIOs per second */ siosrate = regs->siocount; regs->siocount = 0; regs->siototal += siosrate; siosrate = (siosrate*1000000 + diff/2) / diff; if (siosrate > MAX_REPORTED_SIOSRATE) siosrate = 0; regs->siosrate = siosrate; total_sios += siosrate; /* Calculate CPU busy percentage */ cpupct = regs->waittime; regs->waittime = 0; if (regs->waittod) { cpupct += now - regs->waittod; regs->waittod = now; } cpupct = ((diff - cpupct)*100) / diff; if (cpupct > 100) cpupct = 100; regs->cpupct = cpupct; release_lock(&sysblk.cpulock[i]); } /* end for(cpu) */ /* Total for ALL CPUs together */ sysblk.mipsrate = total_mips; sysblk.siosrate = total_sios; } /* end if(diff >= 1000000) */ #endif /*OPTION_MIPS_COUNTING*/ /* Sleep for another timer update interval... */ usleep ( sysblk.timerint ); } /* end while */ logmsg (_("HHCTT003I Timer thread ended\n")); sysblk.todtid = 0; return NULL; } /* end function timer_update_thread */ hercules-3.12/esame.c0000664000175000017500000117527712564723224011465 00000000000000/* ESAME.C (c) Copyright Jan Jaeger, 2000-2013 */ /* ESAME (z/Architecture) instructions */ /*-------------------------------------------------------------------*/ /* This module implements the instructions which exist in ESAME */ /* mode but not in ESA/390 mode, as described in the manual */ /* SA22-7832-00 z/Architecture Principles of Operation */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* EPSW/EREGG/LMD instructions - Roger Bowler */ /* PKA/PKU/UNPKA/UNPKU instructions - Roger Bowler */ /* Multiply/Divide Logical instructions - Vic Cross Feb2001*/ /* Long displacement facility - Roger Bowler June2003*/ /* DAT enhancement facility - Roger Bowler July2004*/ /* Extended immediate facility - Roger Bowler Aug2005*/ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_ESAME_C_) #define _ESAME_C_ BYTE * get_stfl_data(int, int *); #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #define CRYPTO_EXTERN extern #include "crypto.h" #include "clock.h" #if defined(FEATURE_BINARY_FLOATING_POINT) /*-------------------------------------------------------------------*/ /* B29C STFPC - Store FPC [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_fpc) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); BFPINST_CHECK(regs); /* Store register contents at operand address */ ARCH_DEP(vstore4) ( regs->fpc, effective_addr2, b2, regs ); } /* end DEF_INST(store_fpc) */ #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ #if defined(FEATURE_BINARY_FLOATING_POINT) /*-------------------------------------------------------------------*/ /* B29D LFPC - Load FPC [S] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fpc) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 tmp_fpc; S(inst, regs, b2, effective_addr2); BFPINST_CHECK(regs); /* Load FPC register from operand address */ tmp_fpc = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); /* Program check if reserved bits are non-zero */ FPC_CHECK(tmp_fpc, regs); /* Update FPC register */ regs->fpc = tmp_fpc; } /* end DEF_INST(load_fpc) */ #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ #if defined(FEATURE_BINARY_FLOATING_POINT) /*-------------------------------------------------------------------*/ /* B384 SFPC - Set FPC [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(set_fpc) { int r1, unused; /* Values of R fields */ RRE(inst, regs, r1, unused); BFPINST_CHECK(regs); /* Program check if reserved bits are non-zero */ FPC_CHECK(regs->GR_L(r1), regs); /* Load FPC register from R1 register bits 32-63 */ regs->fpc = regs->GR_L(r1); } /* end DEF_INST(set_fpc) */ #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ #if defined(FEATURE_BINARY_FLOATING_POINT) /*-------------------------------------------------------------------*/ /* B38C EFPC - Extract FPC [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_fpc) { int r1, unused; /* Values of R fields */ RRE(inst, regs, r1, unused); BFPINST_CHECK(regs); /* Load R1 register bits 32-63 from FPC register */ regs->GR_L(r1) = regs->fpc; } /* end DEF_INST(extract_fpc) */ #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ #if defined(FEATURE_BINARY_FLOATING_POINT) /*-------------------------------------------------------------------*/ /* B299 SRNM - Set BFP Rounding Mode (2-bit) [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_bfp_rounding_mode_2bit) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); BFPINST_CHECK(regs); /* Set FPC register BFP rounding mode bits from operand address */ regs->fpc &= ~(FPC_BRM_2BIT); regs->fpc |= (effective_addr2 & FPC_BRM_2BIT); #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ /* Zeroize FPC bit 29 if FP Extension Facility is installed */ regs->fpc &= ~(FPC_BIT29); #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ } /* end DEF_INST(set_bfp_rounding_mode_2bit) */ #endif /*defined(FEATURE_BINARY_FLOATING_POINT)*/ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B2B8 SRNMB - Set BFP Rounding Mode (3-bit) [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_bfp_rounding_mode_3bit) /*810*/ { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); BFPINST_CHECK(regs); /* Program check if operand address bits 56-60 are non-zero */ if ((effective_addr2 & 0xFF) & ~(FPC_BRM_3BIT)) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Program check if operand address bits 61-63 not a valid BRM */ if ((effective_addr2 & FPC_BRM_3BIT) == BRM_RESV4 || (effective_addr2 & FPC_BRM_3BIT) == BRM_RESV5 || (effective_addr2 & FPC_BRM_3BIT) == BRM_RESV6) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Set FPC 3-bit BFP rounding mode bits from operand address */ regs->fpc &= ~(FPC_BRM_3BIT); regs->fpc |= (effective_addr2 & FPC_BRM_3BIT); } /* end DEF_INST(set_bfp_rounding_mode_3bit) */ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* 01FF TRAP2 - Trap [E] */ /*-------------------------------------------------------------------*/ DEF_INST(trap2) { E(inst, regs); ARCH_DEP(trap_x) (0, regs, 0); } /* end DEF_INST(trap2) */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_LINKAGE_STACK) /*-------------------------------------------------------------------*/ /* B2FF TRAP4 - Trap [S] */ /*-------------------------------------------------------------------*/ DEF_INST(trap4) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); ARCH_DEP(trap_x) (1, regs, effective_addr2); } /* end DEF_INST(trap4) */ #endif /*defined(FEATURE_LINKAGE_STACK)*/ #if defined(FEATURE_RESUME_PROGRAM) /*-------------------------------------------------------------------*/ /* B277 RP - Resume Program [S] */ /*-------------------------------------------------------------------*/ DEF_INST(resume_program) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ VADR pl_addr; /* Address of parmlist */ U16 flags; /* Flags in parmfield */ U16 psw_offset; /* Offset to new PSW */ U16 ar_offset; /* Offset to new AR */ U16 gr_offset; /* Offset to new GR */ U32 ar; /* Copy of new AR */ U32 gr = 0; /* Copy of new GR */ #if defined(FEATURE_ESAME) U16 grd_offset = 0; /* Offset of disjoint GR_H */ BYTE psw[16]; /* Copy of new PSW */ U64 gr8 = 0; /* Copy of new GR - 8 bytes */ U32 grd = 0; /* Copy of new GR - disjoint */ U64 ia; /* ia for trace */ BYTE amode64; /* save for amod64 */ #else /*!defined(FEATURE_ESAME)*/ BYTE psw[8]; /* Copy of new PSW */ U32 ia; /* ia for trace */ #endif /*!defined(FEATURE_ESAME)*/ BYTE amode; /* amode for trace */ PSW save_psw; /* Saved copy of current PSW */ BYTE *mn; /* Mainstor address of parm */ #ifdef FEATURE_TRACING CREG newcr12 = 0; /* CR12 upon completion */ #endif /*FEATURE_TRACING*/ S(inst, regs, b2, effective_addr2); /* Determine the address of the parameter list */ pl_addr = !regs->execflag ? PSW_IA(regs, 0) : regs->exrl ? (regs->ET + 6) : (regs->ET + 4); /* Fetch flags from the instruction address space */ mn = MADDR (pl_addr, USE_INST_SPACE, regs, ACCTYPE_INSTFETCH, regs->psw.pkey); FETCH_HW(flags, mn); #if defined(FEATURE_ESAME) /* Bits 0-12 must be zero */ if(flags & 0xFFF8) #else /*!defined(FEATURE_ESAME)*/ /* All flag bits must be zero in ESA/390 mode */ if(flags) #endif /*!defined(FEATURE_ESAME)*/ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Fetch the offset to the new psw */ mn = MADDR (pl_addr + 2, USE_INST_SPACE, regs, ACCTYPE_INSTFETCH, regs->psw.pkey); FETCH_HW(psw_offset, mn); /* Fetch the offset to the new ar */ mn = MADDR (pl_addr + 4, USE_INST_SPACE, regs, ACCTYPE_INSTFETCH, regs->psw.pkey); FETCH_HW(ar_offset, mn); /* Fetch the offset to the new gr */ mn = MADDR (pl_addr + 6, USE_INST_SPACE, regs, ACCTYPE_INSTFETCH, regs->psw.pkey); FETCH_HW(gr_offset, mn); #if defined(FEATURE_ESAME) /* Fetch the offset to the new disjoint gr_h */ if((flags & 0x0003) == 0x0003) { mn = MADDR (pl_addr + 8, USE_INST_SPACE, regs, ACCTYPE_INSTFETCH, regs->psw.pkey); FETCH_HW(grd_offset, mn); } #endif /*defined(FEATURE_ESAME)*/ /* Fetch the PSW from the operand address + psw offset */ #if defined(FEATURE_ESAME) if(flags & 0x0004) ARCH_DEP(vfetchc) (psw, 15, (effective_addr2 + psw_offset) & ADDRESS_MAXWRAP(regs), b2, regs); else #endif /*defined(FEATURE_ESAME)*/ ARCH_DEP(vfetchc) (psw, 7, (effective_addr2 + psw_offset) & ADDRESS_MAXWRAP(regs), b2, regs); /* Fetch new AR (B2) from operand address + AR offset */ ar = ARCH_DEP(vfetch4) ((effective_addr2 + ar_offset) & ADDRESS_MAXWRAP(regs), b2, regs); /* Fetch the new gr from operand address + GPR offset */ #if defined(FEATURE_ESAME) /* General Register Field 1 is eight bytes */ if((flags & 0x0003) == 0x0002) { gr8 = ARCH_DEP(vfetch8) ((effective_addr2 + gr_offset) & ADDRESS_MAXWRAP(regs), b2, regs); } /* General Register Field 1 and 2 are four bytes - disjoint */ else if((flags & 0x0003) == 0x0003) { gr = ARCH_DEP(vfetch4) ((effective_addr2 + gr_offset) & ADDRESS_MAXWRAP(regs), b2, regs); grd = ARCH_DEP(vfetch4) ((effective_addr2 + grd_offset) & ADDRESS_MAXWRAP(regs), b2, regs); } else #endif /*defined(FEATURE_ESAME)*/ gr = ARCH_DEP(vfetch4) ((effective_addr2 + gr_offset) & ADDRESS_MAXWRAP(regs), b2, regs); #if defined(FEATURE_TRACING) #if defined(FEATURE_ESAME) /* fetch 8 or 4 byte IA depending on psw operand size */ if (flags & 0x0004) FETCH_DW(ia, psw + 8); else FETCH_FW(ia, psw + 4); amode64 = psw[3] & 0x01; #else /*!defined(FEATURE_ESAME)*/ FETCH_FW(ia, psw + 4); ia &= 0x7FFFFFFF; #endif /*!defined(FEATURE_ESAME)*/ amode = psw[4] & 0x80; #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && (regs->psw.amode64 != amode64)) newcr12 = ARCH_DEP(trace_ms) (regs->CR(12) & CR12_BRTRACE ? 1 : 0, ia, regs); else #endif /*defined(FEATURE_ESAME)*/ if (regs->CR(12) & CR12_BRTRACE) newcr12 = ARCH_DEP(trace_br) (amode, ia, regs); #endif /*defined(FEATURE_TRACING)*/ INVALIDATE_AIA(regs); /* Save current PSW */ save_psw = regs->psw; /* Use bytes 0 and 1 of old psw and byte 2 from operand */ psw[0] = save_psw.sysmask; psw[1] = save_psw.pkey | save_psw.states; /* ignore bits 24-30 */ psw[3] = 0x01 & psw[3]; #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(SIE_STATB(regs, MX, XC) && (psw[2] & 0x80)) regs->program_interrupt (regs, PGM_SPECIAL_OPERATION_EXCEPTION); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Special operation exception when setting AR space mode and ASF is off */ if(!REAL_MODE(®s->psw) && ((psw[2] & 0xC0) == 0x40) && !ASF_ENABLED(regs) ) regs->program_interrupt (regs, PGM_SPECIAL_OPERATION_EXCEPTION); /* Privileged Operation exception when setting home space mode in problem state */ if(!REAL_MODE(®s->psw) && PROBSTATE(®s->psw) && ((psw[2] & 0xC0) == 0xC0) ) regs->program_interrupt (regs, PGM_PRIVILEGED_OPERATION_EXCEPTION); #if defined(FEATURE_ESAME) /* Handle 16 byte psw operand */ if(flags & 0x0004) { psw[1] &= ~0x08; /* force bit 12 off */ if( ARCH_DEP(load_psw) (regs, psw) )/* only check invalid IA not odd */ { /* restore the psw */ regs->psw = save_psw; /* And generate a program interrupt */ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } } /* Handle 8 byte psw operand */ else { /* Save amode64, do not check amode64 bit (force to zero) */ /* This is so s390_load_psw will work. */ /* Checks for amode64 will be done a few lines later */ amode64 = psw[3] & 01; psw[3] &= ~0x01; #endif /*defined(FEATURE_ESAME)*/ psw[1] |= 0x08; /* force bit 12 on */ if( s390_load_psw(regs, psw) ) { /* restore the psw */ regs->psw = save_psw; /* And generate a program interrupt */ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } #if defined(FEATURE_ESAME) regs->psw.states &= ~BIT(PSW_NOTESAME_BIT); /* clear high word of IA since operand was 8-byte psw */ regs->psw.IA_H = 0; /* Check original amode64 and restore and do checks */ if (amode64) { /* if amode64 (31) on, then amode (32) must be on too */ if (!regs->psw.amode) { /* restore the psw */ regs->psw = save_psw; /* And generate a program interrupt */ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } regs->psw.amode64 = 1; regs->psw.AMASK = AMASK64; } else { regs->psw.amode64 = 0; regs->psw.AMASK_H = 0; } } #endif /*defined(FEATURE_ESAME)*/ /* Check for odd IA in psw */ if(regs->psw.IA & 0x01) { /* restore the psw */ regs->psw = save_psw; /* And generate a program interrupt */ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } /* Update access register b2 */ regs->AR(b2) = ar; /* Update general register b2 */ #if defined(FEATURE_ESAME) if((flags & 0x0003) == 0x0002) regs->GR_G(b2) = gr8; else if((flags & 0x0003) == 0x0003) { regs->GR_L(b2) = gr; regs->GR_H(b2) = grd; } else #endif /*defined(FEATURE_ESAME)*/ regs->GR_L(b2) = gr; #ifdef FEATURE_TRACING /* Update trace table address if branch tracing is on */ if (newcr12) regs->CR(12) = newcr12; #endif /*FEATURE_TRACING*/ SET_BEAR_REG(regs, regs->ip - 4); SET_IC_ECMODE_MASK(regs); SET_AEA_MODE(regs); PER_SB(regs, regs->psw.IA); /* Space switch event when switching into or out of home space mode AND space-switch-event on in CR1 or CR13 */ if((HOME_SPACE_MODE(&(regs->psw)) ^ HOME_SPACE_MODE(&save_psw)) && (!REAL_MODE(®s->psw)) && ((regs->CR(1) & SSEVENT_BIT) || (regs->CR(13) & SSEVENT_BIT) || OPEN_IC_PER(regs) )) { if (HOME_SPACE_MODE(&(regs->psw))) { /* When switching into home-space mode, set the translation exception address equal to the primary ASN, with the high-order bit set equal to the value of the primary space-switch-event control bit */ regs->TEA = regs->CR_LHL(4); if (regs->CR(1) & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; } else { /* When switching out of home-space mode, set the translation exception address equal to zero, with the high-order bit set equal to the value of the home space-switch-event control bit */ regs->TEA = 0; if (regs->CR(13) & SSEVENT_BIT) regs->TEA |= TEA_SSEVENT; } regs->program_interrupt (regs, PGM_SPACE_SWITCH_EVENT); } RETURN_INTCHECK(regs); } /* end DEF_INST(resume_program) */ #endif /*defined(FEATURE_RESUME_PROGRAM)*/ #if defined(FEATURE_ESAME) && defined(FEATURE_TRACING) /*-------------------------------------------------------------------*/ /* EB0F TRACG - Trace Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(trace_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ #if defined(FEATURE_TRACING) U32 op; /* Operand */ #endif /*defined(FEATURE_TRACING)*/ RSY(inst, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); FW_CHECK(effective_addr2, regs); /* Exit if explicit tracing (control reg 12 bit 31) is off */ if ( (regs->CR(12) & CR12_EXTRACE) == 0 ) return; /* Fetch the trace operand */ op = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Exit if bit zero of the trace operand is one */ if ( (op & 0x80000000) ) return; /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); regs->CR(12) = ARCH_DEP(trace_tg) (r1, r3, op, regs); /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* end DEF_INST(trace_long) */ #endif /*defined(FEATURE_ESAME) && defined(FEATURE_TRACING)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E30E CVBG - Convert to Binary Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_to_binary_long) { U64 dreg; /* 64-bit result accumulator */ int r1; /* Value of R1 field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int ovf; /* 1=overflow */ int dxf; /* 1=data exception */ BYTE dec[16]; /* Packed decimal operand */ RXY(inst, regs, r1, b2, effective_addr2); /* Fetch 16-byte packed decimal operand */ ARCH_DEP(vfetchc) ( dec, 16-1, effective_addr2, b2, regs ); /* Convert 16-byte packed decimal to 64-bit signed binary */ packed_to_binary (dec, 16-1, &dreg, &ovf, &dxf); /* Data exception if invalid digits or sign */ if (dxf) { regs->dxc = DXC_DECIMAL; regs->program_interrupt (regs, PGM_DATA_EXCEPTION); } /* Exception if overflow (operation suppressed, R1 unchanged) */ if (ovf) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); /* Store 64-bit result into R1 register */ regs->GR_G(r1) = dreg; } /* end DEF_INST(convert_to_binary_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E32E CVDG - Convert to Decimal Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_to_decimal_long) { S64 bin; /* Signed value to convert */ int r1; /* Value of R1 field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE dec[16]; /* Packed decimal result */ RXY(inst, regs, r1, b2, effective_addr2); /* Load signed value of register */ bin = (S64)(regs->GR_G(r1)); /* Convert to 16-byte packed decimal number */ binary_to_packed (bin, dec); /* Store 16-byte packed decimal result at operand address */ ARCH_DEP(vstorec) ( dec, 16-1, effective_addr2, b2, regs ); } /* end DEF_INST(convert_to_decimal_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E396 ML - Multiply Logical [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_logical) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective Address */ U32 m; U64 p; RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ m = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); /* Multiply unsigned values */ p = (U64)regs->GR_L(r1 + 1) * m; /* Store the result */ regs->GR_L(r1) = (p >> 32); regs->GR_L(r1 + 1) = (p & 0xFFFFFFFF); } /* end DEF_INST(multiply_logical) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E386 MLG - Multiply Logical Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_logical_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective Address */ U64 m, ph, pl; RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ m = ARCH_DEP(vfetch8) (effective_addr2, b2, regs); /* Multiply unsigned values */ mult_logical_long(&ph, &pl, regs->GR_G(r1 + 1), m); /* Store the result */ regs->GR_G(r1) = ph; regs->GR_G(r1 + 1) = pl; } /* end DEF_INST(multiply_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B996 MLR - Multiply Logical Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_logical_register) { int r1, r2; /* Values of R fields */ U64 p; RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); /* Multiply unsigned values */ p = (U64)regs->GR_L(r1 + 1) * (U64)regs->GR_L(r2); /* Store the result */ regs->GR_L(r1) = (p >> 32); regs->GR_L(r1 + 1) = (p & 0xFFFFFFFF); } /* end DEF_INST(multiply_logical_register) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B986 MLGR - Multiply Logical Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_logical_long_register) { int r1, r2; /* Values of R fields */ U64 ph, pl; RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); /* Multiply unsigned values */ mult_logical_long(&ph, &pl, regs->GR_G(r1 + 1), regs->GR_G(r2)); /* Store the result */ regs->GR_G(r1) = ph; regs->GR_G(r1 + 1) = pl; } /* end DEF_INST(multiply_logical_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E397 DL - Divide Logical [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_logical) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective Address */ U32 d; U64 n; RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); n = ((U64)regs->GR_L(r1) << 32) | (U32)regs->GR_L(r1 + 1); /* Load second operand from operand address */ d = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); if (d == 0 || (n / d) > 0xFFFFFFFF) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); /* Divide unsigned registers */ regs->GR_L(r1) = n % d; regs->GR_L(r1 + 1) = n / d; } /* end DEF_INST(divide_logical) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E387 DLG - Divide Logical Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_logical_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective Address */ U64 d, r, q; RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ d = ARCH_DEP(vfetch8) (effective_addr2, b2, regs); if (regs->GR_G(r1) == 0) /* check for the simple case */ { if (d == 0) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); /* Divide signed registers */ regs->GR_G(r1) = regs->GR_G(r1 + 1) % d; regs->GR_G(r1 + 1) = regs->GR_G(r1 + 1) / d; } else { if (div_logical_long(&r, &q, regs->GR_G(r1), regs->GR_G(r1 + 1), d) ) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); else { regs->GR_G(r1) = r; regs->GR_G(r1 + 1) = q; } } } /* end DEF_INST(divide_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B997 DLR - Divide Logical Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_logical_register) { int r1, r2; /* Values of R fields */ U64 n; U32 d; RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); n = ((U64)regs->GR_L(r1) << 32) | regs->GR_L(r1 + 1); d = regs->GR_L(r2); if(d == 0 || (n / d) > 0xFFFFFFFF) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); /* Divide signed registers */ regs->GR_L(r1) = n % d; regs->GR_L(r1 + 1) = n / d; } /* end DEF_INST(divide_logical_register) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B987 DLGR - Divide Logical Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_logical_long_register) { int r1, r2; /* Values of R fields */ U64 r, q, d; RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); d = regs->GR_G(r2); if (regs->GR_G(r1) == 0) /* check for the simple case */ { if(d == 0) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); /* Divide signed registers */ regs->GR_G(r1) = regs->GR_G(r1 + 1) % d; regs->GR_G(r1 + 1) = regs->GR_G(r1 + 1) / d; } else { if (div_logical_long(&r, &q, regs->GR_G(r1), regs->GR_G(r1 + 1), d) ) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); else { regs->GR_G(r1) = r; regs->GR_G(r1 + 1) = q; } } } /* end DEF_INST(divide_logical_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B988 ALCGR - Add Logical with Carry Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_carry_long_register) { int r1, r2; /* Values of R fields */ int carry = 0; U64 n; RRE0(inst, regs, r1, r2); n = regs->GR_G(r2); /* Add the carry to operand */ if(regs->psw.cc & 2) carry = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), 1) & 2; /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n) | carry; } /* end DEF_INST(add_logical_carry_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B989 SLBGR - Subtract Logical with Borrow Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_borrow_long_register) { int r1, r2; /* Values of R fields */ int borrow = 2; U64 n; RRE0(inst, regs, r1, r2); n = regs->GR_G(r2); /* Subtract the borrow from operand */ if(!(regs->psw.cc & 2)) borrow = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), 1); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n) & (borrow|1); } /* end DEF_INST(subtract_logical_borrow_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_DAT_ENHANCEMENT) /*-------------------------------------------------------------------*/ /* B98A CSPG - Compare and Swap and Purge Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_swap_and_purge_long) { int r1, r2; /* Values of R fields */ U64 n2; /* Virtual address of op2 */ BYTE *main2; /* Mainstor address of op2 */ U64 old; /* Old value */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); ODD_CHECK(r1, regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs,IC0, IPTECSP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && regs->sie_scao) { STORAGE_KEY(regs->sie_scao, regs) |= STORKEY_REF; if(regs->mainstor[regs->sie_scao] & 0x80) longjmp(regs->progjmp, SIE_INTERCEPT_INST); } #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Obtain 2nd operand address from r2 */ n2 = regs->GR(r2) & 0xFFFFFFFFFFFFFFF8ULL & ADDRESS_MAXWRAP(regs); main2 = MADDR (n2, r2, regs, ACCTYPE_WRITE, regs->psw.pkey); old = CSWAP64 (regs->GR_G(r1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg8 (&old, CSWAP64(regs->GR_G(r1+1)), main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); if (regs->psw.cc == 0) { /* Perform requested funtion specified as per request code in r2 */ if (regs->GR_L(r2) & 3) { OBTAIN_INTLOCK(regs); SYNCHRONIZE_CPUS(regs); if (regs->GR_L(r2) & 1) ARCH_DEP(purge_tlb_all)(); if (regs->GR_L(r2) & 2) ARCH_DEP(purge_alb_all)(); RELEASE_INTLOCK(regs); } } else { PTT(PTT_CL_CSF,"*CSPG",regs->GR_L(r1),regs->GR_L(r2),regs->psw.IA_L); /* Otherwise yield */ regs->GR_G(r1) = CSWAP64(old); if (sysblk.cpus > 1) sched_yield(); } /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); } /* end DEF_INST(compare_and_swap_and_purge_long) */ #endif /*defined(FEATURE_DAT_ENHANCEMENT)*/ #if defined(FEATURE_DAT_ENHANCEMENT) /*-------------------------------------------------------------------*/ /* B98E IDTE - Invalidate DAT Table Entry [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(invalidate_dat_table_entry) { int r1, r2, r3; /* Values of R fields */ int m4; /* Unused mask field */ U64 asceto; /* ASCE table origin */ int ascedt; /* ASCE designation type */ int count; /* Invalidation counter */ int eiindx; /* Eff. invalidation index */ U64 asce; /* Contents of ASCE */ BYTE *mn; /* Mainstor address of ASCE */ RRF_RM(inst, regs, r1, r2, r3, m4); SIE_XC_INTERCEPT(regs); PRIV_CHECK(regs); /* Program check if bits 44-51 of r2 register are non-zero */ if (regs->GR_L(r2) & 0x000FF000) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_STATB(regs,IC0, IPTECSP)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && regs->sie_scao) { STORAGE_KEY(regs->sie_scao, regs) |= STORKEY_REF; if(regs->mainstor[regs->sie_scao] & 0x80) longjmp(regs->progjmp, SIE_INTERCEPT_INST); } #endif /*defined(_FEATURE_SIE)*/ /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Bit 52 of the r2 register determines the operation performed */ if ((regs->GR_L(r2) & 0x00000800) == 0) { /* Perform invalidation-and-clearing operation */ /* Extract the invalidation table origin and type from r1 */ asceto = regs->GR_G(r1) & ASCE_TO; ascedt = regs->GR_L(r1) & ASCE_DT; /* Extract the effective invalidation index from r2 */ switch(ascedt) { case TT_R1TABL: /* Region first table */ eiindx = (regs->GR_H(r2) & 0xFF700000) >> 18; break; case TT_R2TABL: /* Region second table */ eiindx = (regs->GR_H(r2) & 0x001FFC00) >> 7; break; case TT_R3TABL: /* Region third table */ eiindx = (regs->GR_G(r2) & 0x000003FF80000000ULL) >> 28; break; case TT_SEGTAB: /* Segment table */ default: eiindx = (regs->GR_L(r2) & 0x7FF00000) >> 17; break; } /* end switch(ascedt) */ /* Calculate the address of table for invalidation, noting that it is always a 64-bit address regardless of the current addressing mode, and that overflow is ignored */ asceto += eiindx; /* Extract the additional entry count from r2 */ count = (regs->GR_L(r2) & 0x7FF) + 1; /* Perform invalidation of one or more table entries */ while (count-- > 0) { /* Fetch the table entry, set the invalid bit, then store only the byte containing the invalid bit */ mn = MADDR (asceto, USE_REAL_ADDR, regs, ACCTYPE_WRITE, regs->psw.pkey); FETCH_DW(asce, mn); asce |= ZSEGTAB_I; mn[7] = asce & 0xFF; /* Calculate the address of the next table entry, noting that it is always a 64-bit address regardless of the current addressing mode, and that overflow is ignored */ asceto += 8; } /* end while */ /* Clear the TLB and signal all other CPUs to clear their TLB */ /* Note: Currently we clear all entries regardless of whether a clearing ASCE is passed in the r3 register. This conforms to the POP which only specifies the minimum set of entries which must be cleared from the TLB. */ OBTAIN_INTLOCK(regs); SYNCHRONIZE_CPUS(regs); ARCH_DEP(purge_tlb_all)(); RELEASE_INTLOCK(regs); } /* end if(invalidation-and-clearing) */ else { /* Perform clearing-by-ASCE operation */ /* Clear the TLB and signal all other CPUs to clear their TLB */ /* Note: Currently we clear all entries regardless of the clearing ASCE passed in the r3 register. This conforms to the POP which only specifies the minimum set of entries which must be cleared from the TLB. */ OBTAIN_INTLOCK(regs); SYNCHRONIZE_CPUS(regs); ARCH_DEP(purge_tlb_all)(); RELEASE_INTLOCK(regs); } /* end else(clearing-by-ASCE) */ /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); } /* end DEF_INST(invalidate_dat_table_entry) */ #endif /*defined(FEATURE_DAT_ENHANCEMENT)*/ #if defined(FEATURE_ENHANCED_DAT_FACILITY_2) /*912*/ /*-------------------------------------------------------------------*/ /* B98F CRDTE - Compare and Replace DAT Table Entry [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_replace_dat_table_entry) /*912*/ { int r1, r2, r3; /* Values of R fields */ int m4; /* Value of mask field */ U64 to; /* Table origin */ U64 ei; /* Effective index */ RADR ea; /* Second operand address */ U64 dte; /* Second operand value */ U64 asce = 0; /* Address space control elem*/ int dtt; /* Designated table type */ BYTE *mn; /* Mainstor addr of 2nd opnd */ RRF_RM(inst, regs, r1, r2, r3, m4); SIE_XC_INTERCEPT(regs); PRIV_CHECK(regs); ODD2_CHECK(r1, r2, regs); /* The designated table type is in R2 bits 59-61 */ dtt = (regs->GR_L(r2) & 0x1C0) >> 2; /* Calculate the second operand address depending on table type */ switch (dtt) { case 0: /* Page table */ to = regs->GR_G(r2) & ZSEGTAB_PTO; ei = (regs->GR_L(r2+1) & 0x000FF000) >> 12; break; case 4: /* Segment table */ to = regs->GR_G(r2) & REGTAB_TO; ei = (regs->GR_L(r2+1) & 0x7FF00000) >> 20; break; case 5: /* Region third table */ to = regs->GR_G(r2) & REGTAB_TO; ei = (regs->GR_G(r2+1) & 0x000003FF80000000ULL) >> 31; break; case 6: /* Region second table */ to = regs->GR_G(r2) & REGTAB_TO; ei = (regs->GR_G(r2+1) & 0x001FFC0000000000ULL) >> 42; break; case 7: /* Region first table */ to = regs->GR_G(r2) & ASCE_TO; ei = (regs->GR_G(r2+1) & 0xFFE0000000000000ULL) >> 53; break; default: /* Invalid table type */ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } /* Program check if bits 52-63 of R2+1 are non-zero */ if ((regs->GR_L(r2+1) & 0xFFF) != 0) { regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } /* Load the address space control element from R3 bits 0-51, 60-61 */ if (r3 != 0) { asce = regs->GR_G(r3) & (ASCE_TO | ASCE_DT); } /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Load the second operand from storage */ ea = to + 8*ei; mn = MADDR(ea, USE_REAL_ADDR, regs, ACCTYPE_WRITE, regs->psw.pkey); FETCH_DW(dte, mn); /* Compare first and second operands */ if (regs->GR_G(r1) == dte) { /* Store R1+1 register at second operand location */ STORE_DW(mn, regs->GR_G(r1+1)); /* Clear the TLB and signal all other CPUs to clear their TLB */ /* Note: Currently we clear all entries regardless of whether they are related to the original DTE and regardless of whether a clearing ASCE is passed in the r3 register. This conforms to the POP which permits the implementation to clear more entries from the TLB than are strictly necessary. */ OBTAIN_INTLOCK(regs); SYNCHRONIZE_CPUS(regs); ARCH_DEP(purge_tlb_all)(); RELEASE_INTLOCK(regs); /* Set condition code zero to indicate equal operands */ regs->psw.cc = 0; } else { /* Load second operand into the R1 register */ regs->GR_G(r1) = dte; /* Set condition code 1 to indicate unequal operands */ regs->psw.cc = 1; } /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); } /* end DEF_INST(compare_and_replace_dat_table_entry) */ #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY_2)*/ #if defined(FEATURE_DAT_ENHANCEMENT_FACILITY_2) /*-------------------------------------------------------------------*/ /* B9AA LPTEA - Load Page-Table-Entry Address [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_page_table_entry_address) { VADR vaddr; /* Virtual address */ int r1, r2, r3; /* Register numbers */ int m4; /* Mask field */ int n; /* Address space indication */ int cc; /* Condition code */ int acctype = ACCTYPE_LPTEA; /* Storage access type */ RRF_RM(inst, regs, r1, r2, r3, m4); SIE_XC_INTERCEPT(regs); PRIV_CHECK(regs); /* The m4 field determines which address space to use */ switch (m4) { case 0: /* Use ASCE in control register 1 */ n = USE_PRIMARY_SPACE; break; case 1: /* Use ALET in access register r2 */ n = USE_ARMODE | r2; break; case 2: /* Use ASCE in control register 7 */ n = USE_SECONDARY_SPACE; break; case 3: /* Use ASCE in control register 13 */ n = USE_HOME_SPACE; break; case 4: /* Use current addressing mode (PSW bits 16-17) */ n = r2; /* r2 is the access register number if ARMODE */ break; default: /* Specification exception if invalid value for m4 */ n = -1; /* makes compiler happy */ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } /* end switch(m4) */ /* Load the virtual address from the r2 register */ vaddr = regs->GR(r2) & ADDRESS_MAXWRAP(regs); /* Find the page table address and condition code */ cc = ARCH_DEP(translate_addr) (vaddr, n, regs, acctype); /* Set R1 to real address or exception code depending on cc */ regs->GR_G(r1) = (cc < 3) ? regs->dat.raddr : regs->dat.xcode; /* Set condition code */ regs->psw.cc = cc; } /* end DEF_INST(load_page_table_entry_address) */ #endif /*defined(FEATURE_DAT_ENHANCEMENT_FACILITY_2)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E388 ALCG - Add Logical with Carry Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_carry_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ int carry = 0; RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Add the carry to operand */ if(regs->psw.cc & 2) carry = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), 1) & 2; /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n) | carry; } /* end DEF_INST(add_logical_carry_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E389 SLBG - Subtract Logical with Borrow Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_borrow_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ int borrow = 2; RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Subtract the borrow from operand */ if(!(regs->psw.cc & 2)) borrow = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), 1); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n) & (borrow|1); } /* end DEF_INST(subtract_logical_borrow_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B998 ALCR - Add Logical with Carry Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_carry_register) { int r1, r2; /* Values of R fields */ int carry = 0; U32 n; RRE0(inst, regs, r1, r2); n = regs->GR_L(r2); /* Add the carry to operand */ if(regs->psw.cc & 2) carry = add_logical(&(regs->GR_L(r1)), regs->GR_L(r1), 1) & 2; /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical(&(regs->GR_L(r1)), regs->GR_L(r1), n) | carry; } /* end DEF_INST(add_logical_carry_register) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B999 SLBR - Subtract Logical with Borrow Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_borrow_register) { int r1, r2; /* Values of R fields */ int borrow = 2; U32 n; RRE0(inst, regs, r1, r2); n = regs->GR_L(r2); /* Subtract the borrow from operand */ if(!(regs->psw.cc & 2)) borrow = sub_logical(&(regs->GR_L(r1)), regs->GR_L(r1), 1); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical(&(regs->GR_L(r1)), regs->GR_L(r1), n) & (borrow|1); } /* end DEF_INST(subtract_logical_borrow_register) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E398 ALC - Add Logical with Carry [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_carry) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ int carry = 0; RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Add the carry to operand */ if(regs->psw.cc & 2) carry = add_logical(&(regs->GR_L(r1)), regs->GR_L(r1), 1) & 2; /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical(&(regs->GR_L(r1)), regs->GR_L(r1), n) | carry; } /* end DEF_INST(add_logical_carry) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E399 SLB - Subtract Logical with Borrow [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_borrow) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ int borrow = 2; RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Subtract the borrow from operand */ if(!(regs->psw.cc & 2)) borrow = sub_logical(&(regs->GR_L(r1)), regs->GR_L(r1), 1); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical(&(regs->GR_L(r1)), regs->GR_L(r1), n) & (borrow|1); } /* end DEF_INST(subtract_logical_borrow) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E30D DSG - Divide Single Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_single_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); if(n == 0 || ((S64)n == -1LL && regs->GR_G(r1 + 1) == 0x8000000000000000ULL)) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); regs->GR_G(r1) = (S64)regs->GR_G(r1 + 1) % (S64)n; regs->GR_G(r1 + 1) = (S64)regs->GR_G(r1 + 1) / (S64)n; } /* end DEF_INST(divide_single_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E31D DSGF - Divide Single Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_single_long_fullword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); if(n == 0 || ((S32)n == -1 && regs->GR_G(r1 + 1) == 0x8000000000000000ULL)) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); regs->GR_G(r1) = (S64)regs->GR_G(r1 + 1) % (S32)n; regs->GR_G(r1 + 1) = (S64)regs->GR_G(r1 + 1) / (S32)n; } /* end DEF_INST(divide_single_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B90D DSGR - Divide Single Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_single_long_register) { int r1, r2; /* Values of R fields */ U64 n; RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); if(regs->GR_G(r2) == 0 || ((S64)regs->GR_G(r2) == -1LL && regs->GR_G(r1 + 1) == 0x8000000000000000ULL)) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); n = regs->GR_G(r2); /* Divide signed registers */ regs->GR_G(r1) = (S64)regs->GR_G(r1 + 1) % (S64)n; regs->GR_G(r1 + 1) = (S64)regs->GR_G(r1 + 1) / (S64)n; } /* end DEF_INST(divide_single_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B91D DSGFR - Divide Single Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_single_long_fullword_register) { int r1, r2; /* Values of R fields */ U32 n; RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); if(regs->GR_L(r2) == 0 || ((S32)regs->GR_L(r2) == -1 && regs->GR_G(r1 + 1) == 0x8000000000000000ULL)) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); n = regs->GR_L(r2); /* Divide signed registers */ regs->GR_G(r1) = (S64)regs->GR_G(r1 + 1) % (S32)n; regs->GR_G(r1 + 1) = (S64)regs->GR_G(r1 + 1) / (S32)n; } /* end DEF_INST(divide_single_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E390 LLGC - Load Logical Long Character [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_character) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); regs->GR_G(r1) = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_logical_long_character) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E391 LLGH - Load Logical Long Halfword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); regs->GR_G(r1) = ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_logical_long_halfword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E38E STPQ - Store Pair to Quadword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_pair_to_quadword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ QWORD qwork; /* Quadword work area */ RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); QW_CHECK(effective_addr2, regs); /* Store regs in workarea */ STORE_DW(qwork, regs->GR_G(r1)); STORE_DW(qwork+8, regs->GR_G(r1+1)); /* Store R1 and R1+1 registers to second operand Provide storage consistancy by means of obtaining the main storage access lock */ OBTAIN_MAINLOCK(regs); ARCH_DEP(vstorec) ( qwork, 16-1, effective_addr2, b2, regs ); RELEASE_MAINLOCK(regs); } /* end DEF_INST(store_pair_to_quadword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E38F LPQ - Load Pair from Quadword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_pair_from_quadword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ QWORD qwork; /* Quadword work area */ RXY(inst, regs, r1, b2, effective_addr2); ODD_CHECK(r1, regs); QW_CHECK(effective_addr2, regs); /* Load R1 and R1+1 registers contents from second operand Provide storage consistancy by means of obtaining the main storage access lock */ OBTAIN_MAINLOCK(regs); ARCH_DEP(vfetchc) ( qwork, 16-1, effective_addr2, b2, regs ); RELEASE_MAINLOCK(regs); /* Load regs from workarea */ FETCH_DW(regs->GR_G(r1), qwork); FETCH_DW(regs->GR_G(r1+1), qwork+8); } /* end DEF_INST(load_pair_from_quadword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B90E EREGG - Extract Stacked Registers Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_stacked_registers_long) { int r1, r2; /* Values of R fields */ LSED lsed; /* Linkage stack entry desc. */ VADR lsea; /* Linkage stack entry addr */ RRE(inst, regs, r1, r2); SIE_XC_INTERCEPT(regs); /* Find the virtual address of the entry descriptor of the current state entry in the linkage stack */ lsea = ARCH_DEP(locate_stack_entry) (0, &lsed, regs); /* Load registers from the stack entry */ ARCH_DEP(unstack_registers) (1, lsea, r1, r2, regs); } /* end DEF_INST(extract_stacked_registers_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B98D EPSW - Extract PSW [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_psw) { int r1, r2; /* Values of R fields */ QWORD currpsw; /* Work area for PSW */ RRE(inst, regs, r1, r2); #if defined(_FEATURE_ZSIE) if(SIE_STATB(regs, IC1, LPSW)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_ZSIE)*/ /* Store the current PSW in work area */ ARCH_DEP(store_psw) (regs, currpsw); /* Load PSW bits 0-31 into bits 32-63 of the R1 register */ FETCH_FW(regs->GR_L(r1), currpsw); /* If R2 specifies a register other than register zero, load PSW bits 32-63 into bits 32-63 of the R2 register */ if(r2 != 0) { FETCH_FW(regs->GR_L(r2), currpsw+4); #if !defined(FEATURE_ESAME) /* The Ninth Edition of ESA/390 POP (SA22-7201-08) requires the low 31 bits to be set to zeroes in ESA/390 mode */ regs->GR_L(r2) &= 0x80000000; #endif /*!defined(FEATURE_ESAME)*/ } } /* end DEF_INST(extract_psw) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B99D ESEA - Extract and Set Extended Authority [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_and_set_extended_authority) { int r1, unused; /* Value of R field */ RRE(inst, regs, r1, unused); PRIV_CHECK(regs); #if 0 #if defined(_FEATURE_ZSIE) if(SIE_STATB(regs, LCTL1, CR8)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_ZSIE)*/ #endif regs->GR_LHH(r1) = regs->CR_LHH(8); regs->CR_LHH(8) = regs->GR_LHL(r1); } /* end DEF_INST(extract_and_set_extended_authority) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C0x0 LARL - Load Address Relative Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_address_relative_long) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand values */ RIL0(inst, regs, r1, opcd, i2); SET_GR_A(r1, regs, likely(!regs->execflag) ? PSW_IA(regs, -6 + 2LL*(S32)i2) : (regs->ET + 2LL*(S32)i2) & ADDRESS_MAXWRAP(regs)); } /* end DEF_INST(load_address_relative_long) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x0 IIHH - Insert Immediate High High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_immediate_high_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_HHH(r1) = i2; } /* end DEF_INST(insert_immediate_high_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x1 IIHL - Insert Immediate High Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_immediate_high_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_HHL(r1) = i2; } /* end DEF_INST(insert_immediate_high_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x2 IILH - Insert Immediate Low High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_immediate_low_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_LHH(r1) = i2; } /* end DEF_INST(insert_immediate_low_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x3 IILL - Insert Immediate Low Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_immediate_low_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_LHL(r1) = i2; } /* end DEF_INST(insert_immediate_low_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x4 NIHH - And Immediate High High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate_high_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_HHH(r1) &= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_HHH(r1) ? 1 : 0; } /* end DEF_INST(and_immediate_high_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x5 NIHL - And Immediate High Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate_high_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_HHL(r1) &= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_HHL(r1) ? 1 : 0; } /* end DEF_INST(and_immediate_high_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x6 NILH - And Immediate Low High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate_low_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_LHH(r1) &= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_LHH(r1) ? 1 : 0; } /* end DEF_INST(and_immediate_low_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x7 NILL - And Immediate Low Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate_low_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_LHL(r1) &= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_LHL(r1) ? 1 : 0; } /* end DEF_INST(and_immediate_low_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x8 OIHH - Or Immediate High High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate_high_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_HHH(r1) |= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_HHH(r1) ? 1 : 0; } /* end DEF_INST(or_immediate_high_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5x9 OIHL - Or Immediate High Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate_high_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_HHL(r1) |= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_HHL(r1) ? 1 : 0; } /* end DEF_INST(or_immediate_high_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5xA OILH - Or Immediate Low High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate_low_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_LHH(r1) |= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_LHH(r1) ? 1 : 0; } /* end DEF_INST(or_immediate_low_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5xB OILL - Or Immediate Low Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate_low_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_LHL(r1) |= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_LHL(r1) ? 1 : 0; } /* end DEF_INST(or_immediate_low_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5xC LLIHH - Load Logical Immediate High High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_immediate_high_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_G(r1) = (U64)i2 << 48; } /* end DEF_INST(load_logical_immediate_high_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5xD LLIHL - Load Logical Immediate High Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_immediate_high_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_G(r1) = (U64)i2 << 32; } /* end DEF_INST(load_logical_immediate_high_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5xE LLILH - Load Logical Immediate Low High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_immediate_low_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_G(r1) = (U64)i2 << 16; } /* end DEF_INST(load_logical_immediate_low_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A5xF LLILL - Load Logical Immediate Low Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_immediate_low_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); regs->GR_G(r1) = (U64)i2; } /* end DEF_INST(load_logical_immediate_low_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C0x4 BRCL - Branch Relative on Condition Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_condition_long) { //int r1; /* Register number */ //int opcd; /* Opcode */ //U32 i2; /* 32-bit operand values */ // RIL(inst, regs, r1, opcd, i2); /* Branch if R1 mask bit is set */ if (inst[1] & (0x80 >> regs->psw.cc)) SUCCESSFUL_RELATIVE_BRANCH_LONG(regs, 2LL*(S32)fetch_fw(inst+2)); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(branch_relative_on_condition_long) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* C0x5 BRASL - Branch Relative And Save Long [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_and_save_long) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand values */ RIL_B(inst, regs, r1, opcd, i2); #if defined(FEATURE_ESAME) if(regs->psw.amode64) regs->GR_G(r1) = PSW_IA64(regs, 6); else #endif /*defined(FEATURE_ESAME)*/ if ( regs->psw.amode ) regs->GR_L(r1) = 0x80000000 | PSW_IA31(regs, 6); else regs->GR_L(r1) = PSW_IA24(regs, 6); SUCCESSFUL_RELATIVE_BRANCH_LONG(regs, 2LL*(S32)fetch_fw(inst+2)); } /* end DEF_INST(branch_relative_and_save_long) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB20 CLMH - Compare Logical Characters under Mask High [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_characters_under_mask_high) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, j; /* Integer work areas */ int cc = 0; /* Condition code */ BYTE rbyte[4], /* Register bytes */ vbyte; /* Virtual storage byte */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Set register bytes by mask */ i = 0; if (r3 & 0x8) rbyte[i++] = (regs->GR_H(r1) >> 24) & 0xFF; if (r3 & 0x4) rbyte[i++] = (regs->GR_H(r1) >> 16) & 0xFF; if (r3 & 0x2) rbyte[i++] = (regs->GR_H(r1) >> 8) & 0xFF; if (r3 & 0x1) rbyte[i++] = (regs->GR_H(r1) ) & 0xFF; /* Perform access check if mask is 0 */ if (!r3) ARCH_DEP(vfetchb) (effective_addr2, b2, regs); /* Compare byte by byte */ for (j = 0; j < i && !cc; j++) { effective_addr2 &= ADDRESS_MAXWRAP(regs); vbyte = ARCH_DEP(vfetchb) (effective_addr2++, b2, regs); if (rbyte[j] != vbyte) cc = rbyte[j] < vbyte ? 1 : 2; } regs->psw.cc = cc; } /* end DEF_INST(compare_logical_characters_under_mask_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB2C STCMH - Store Characters under Mask High [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_characters_under_mask_high) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Integer work area */ BYTE rbyte[4]; /* Register bytes from mask */ RSY(inst, regs, r1, r3, b2, effective_addr2); switch (r3) { case 15: /* Optimized case */ ARCH_DEP(vstore4) (regs->GR_H(r1), effective_addr2, b2, regs); break; default: /* Extract value from register by mask */ i = 0; if (r3 & 0x8) rbyte[i++] = (regs->GR_H(r1) >> 24) & 0xFF; if (r3 & 0x4) rbyte[i++] = (regs->GR_H(r1) >> 16) & 0xFF; if (r3 & 0x2) rbyte[i++] = (regs->GR_H(r1) >> 8) & 0xFF; if (r3 & 0x1) rbyte[i++] = (regs->GR_H(r1) ) & 0xFF; if (i) ARCH_DEP(vstorec) (rbyte, i-1, effective_addr2, b2, regs); #if defined(MODEL_DEPENDENT_STCM) /* If the mask is all zero, we nevertheless access one byte from the storage operand, because POP states that an access exception may be recognized on the first byte */ else ARCH_DEP(validate_operand) (effective_addr2, b2, 0, ACCTYPE_WRITE, regs); #endif break; } /* switch (r3) */ } /* end DEF_INST(store_characters_under_mask_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_EXTRACT_CPU_TIME) /*-------------------------------------------------------------------*/ /* C8x1 ECTG - Extract CPU Time [SSF] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_cpu_time) { int b1, b2; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ VADR effective_addr2; /* Effective address */ int r3; /* R3 register number */ S64 dreg; /* Double word workarea */ U64 gr0, gr1; /* Result register workareas */ SSF(inst, regs, b1, effective_addr1, b2, effective_addr2, r3); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC3, SPT)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ OBTAIN_INTLOCK(regs); /* Save the CPU timer value */ dreg = cpu_timer(regs); /* Reset the cpu timer pending flag according to its value */ if( CPU_TIMER(regs) < 0 ) { ON_IC_PTIMER(regs); /* Roll back the instruction and take the timer interrupt if we have a pending CPU timer and we are enabled for such interrupts *JJ */ if( OPEN_IC_PTIMER(regs) ) { RELEASE_INTLOCK(regs); UPD_PSW_IA(regs, PSW_IA(regs, !regs->execflag ? -6 : regs->exrl ? -6 : -4)); RETURN_INTCHECK(regs); } } else OFF_IC_PTIMER(regs); RELEASE_INTLOCK(regs); /* The value of the current CPU timer is subtracted from the first operand and the result is placed in general register 0 */ gr0 = ARCH_DEP(vfetch8) (effective_addr1, b1, regs) - dreg; /* The second operand is placed in general register 1 */ gr1 = ARCH_DEP(vfetch8) (effective_addr2, b2, regs); /* The eight bytes at the third operand location replace the contents of general register R3. The operands are treated as unsigned 64-bit integers. The contents of R3 is treated according to current addressing mode. In AR mode, access register R3 is used. */ regs->GR_G(r3) = ARCH_DEP(wfetch8) (regs->GR_G(r3), r3, regs); regs->GR_G(0) = gr0; regs->GR_G(1) = gr1; RETURN_INTCHECK(regs); } /* end DEF_INST(extract_cpu_time) */ #endif /*defined(FEATURE_EXTRACT_CPU_TIME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB80 ICMH - Insert Characters under Mask High [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_characters_under_mask_high) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Integer work area */ BYTE vbyte[4]; /* Fetched storage bytes */ U32 n; /* Fetched value */ static const int /* Length-1 to fetch by mask */ icmhlen[16] = {0, 0, 0, 1, 0, 1, 1, 2, 0, 1, 1, 2, 1, 2, 2, 3}; static const unsigned int /* Turn reg bytes off by mask*/ icmhmask[16] = {0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFFFF0000, 0xFF00FFFF, 0xFF00FF00, 0xFF0000FF, 0xFF000000, 0x00FFFFFF, 0x00FFFF00, 0x00FF00FF, 0x00FF0000, 0x0000FFFF, 0x0000FF00, 0x000000FF, 0x00000000}; RSY(inst, regs, r1, r3, b2, effective_addr2); switch (r3) { case 15: /* Optimized case */ regs->GR_H(r1) = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); regs->psw.cc = regs->GR_H(r1) ? regs->GR_H(r1) & 0x80000000 ? 1 : 2 : 0; break; default: memset (vbyte, 0, 4); ARCH_DEP(vfetchc)(vbyte, icmhlen[r3], effective_addr2, b2, regs); /* If mask was 0 then we still had to fetch, according to POP. If so, set the fetched byte to 0 to force zero cc */ if (!r3) vbyte[0] = 0; n = fetch_fw (vbyte); regs->psw.cc = n ? n & 0x80000000 ? 1 : 2 : 0; /* Turn off the reg bytes we are going to set */ regs->GR_H(r1) &= icmhmask[r3]; /* Set bytes one at a time according to the mask */ i = 0; if (r3 & 0x8) regs->GR_H(r1) |= vbyte[i++] << 24; if (r3 & 0x4) regs->GR_H(r1) |= vbyte[i++] << 16; if (r3 & 0x2) regs->GR_H(r1) |= vbyte[i++] << 8; if (r3 & 0x1) regs->GR_H(r1) |= vbyte[i]; break; } /* switch (r3) */ } /* end DEF_INST(insert_characters_under_mask_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC44 BRXHG - Branch Relative on Index High Long [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_index_high_long) { int r1, r3; /* Register numbers */ S16 i2; /* 16-bit immediate offset */ S64 i,j; /* Integer workareas */ RIE_B(inst, regs, r1, r3, i2); /* Load the increment value from the R3 register */ i = (S64)regs->GR_G(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S64)regs->GR_G(r3) : (S64)regs->GR_G(r3+1); /* Add the increment value to the R1 register */ regs->GR_G(r1) = (S64)regs->GR_G(r1) + i; /* Branch if result compares high */ if ( (S64)regs->GR_G(r1) > j ) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i2, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(branch_relative_on_index_high_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EC45 BRXLG - Branch Relative on Index Low or Equal Long [RIE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_index_low_or_equal_long) { int r1, r3; /* Register numbers */ S16 i2; /* 16-bit immediate offset */ S64 i,j; /* Integer workareas */ RIE_B(inst, regs, r1, r3, i2); /* Load the increment value from the R3 register */ i = (S64)regs->GR_G(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S64)regs->GR_G(r3) : (S64)regs->GR_G(r3+1); /* Add the increment value to the R1 register */ regs->GR_G(r1) = (S64)regs->GR_G(r1) + i; /* Branch if result compares low or equal */ if ( (S64)regs->GR_G(r1) <= j ) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*i2, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(branch_relative_on_index_low_or_equal_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB44 BXHG - Branch on Index High Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_index_high_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ S64 i, j; /* Integer work areas */ RSY_B(inst, regs, r1, r3, b2, effective_addr2); /* Load the increment value from the R3 register */ i = (S64)regs->GR_G(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S64)regs->GR_G(r3) : (S64)regs->GR_G(r3+1); /* Add the increment value to the R1 register */ regs->GR_G(r1) = (S64)regs->GR_G(r1) + i; /* Branch if result compares high */ if ( (S64)regs->GR_G(r1) > j ) SUCCESSFUL_BRANCH(regs, effective_addr2, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(branch_on_index_high_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB45 BXLEG - Branch on Index Low or Equal Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_index_low_or_equal_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ S64 i, j; /* Integer work areas */ RSY_B(inst, regs, r1, r3, b2, effective_addr2); /* Load the increment value from the R3 register */ i = regs->GR_G(r3); /* Load compare value from R3 (if R3 odd), or R3+1 (if even) */ j = (r3 & 1) ? (S64)regs->GR_G(r3) : (S64)regs->GR_G(r3+1); /* Add the increment value to the R1 register */ regs->GR_G(r1) = (S64)regs->GR_G(r1) + i; /* Branch if result compares low or equal */ if ( (S64)regs->GR_G(r1) <= j ) SUCCESSFUL_BRANCH(regs, effective_addr2, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(branch_on_index_low_or_equal_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB30 CSG - Compare and Swap Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_swap_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ BYTE *main2; /* mainstor address */ U64 old; /* old value */ RSY(inst, regs, r1, r3, b2, effective_addr2); DW_CHECK(effective_addr2, regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Get operand absolute address */ main2 = MADDR (effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get old value */ old = CSWAP64(regs->GR_G(r1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg8 (&old, CSWAP64(regs->GR_G(r3)), main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); if (regs->psw.cc == 1) { regs->GR_G(r1) = CSWAP64(old); #if defined(_FEATURE_ZSIE) if(SIE_STATB(regs, IC0, CS1)) { if( !OPEN_IC_PER(regs) ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else longjmp(regs->progjmp, SIE_INTERCEPT_INSTCOMP); } else #endif /*defined(_FEATURE_ZSIE)*/ if (sysblk.cpus > 1) sched_yield(); } } /* end DEF_INST(compare_and_swap_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB3E CDSG - Compare Double and Swap Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_double_and_swap_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ BYTE *main2; /* mainstor address */ U64 old1, old2; /* old value */ RSY(inst, regs, r1, r3, b2, effective_addr2); ODD2_CHECK(r1, r3, regs); QW_CHECK(effective_addr2, regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Get operand mainstor address */ main2 = MADDR (effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get old values */ old1 = CSWAP64(regs->GR_G(r1)); old2 = CSWAP64(regs->GR_G(r1+1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg16 (&old1, &old2, CSWAP64(regs->GR_G(r3)), CSWAP64(regs->GR_G(r3+1)), main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); if (regs->psw.cc == 1) { regs->GR_G(r1) = CSWAP64(old1); regs->GR_G(r1+1) = CSWAP64(old2); #if defined(_FEATURE_ZSIE) if(SIE_STATB(regs, IC0, CS1)) { if( !OPEN_IC_PER(regs) ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else longjmp(regs->progjmp, SIE_INTERCEPT_INSTCOMP); } else #endif /*defined(_FEATURE_ZSIE)*/ if (sysblk.cpus > 1) sched_yield(); } } /* end DEF_INST(compare_double_and_swap_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E346 BCTG - Branch on Count Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_count_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY_B(inst, regs, r1, b2, effective_addr2); /* Subtract 1 from the R1 operand and branch if non-zero */ if ( --(regs->GR_G(r1)) ) SUCCESSFUL_BRANCH(regs, effective_addr2, 6); else INST_UPDATE_PSW(regs, 6, 0); } /* end DEF_INST(branch_on_count_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B946 BCTGR - Branch on Count Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_on_count_long_register) { int r1, r2; /* Values of R fields */ VADR newia; /* New instruction address */ RRE_B(inst, regs, r1, r2); /* Compute the branch address from the R2 operand */ newia = regs->GR_G(r2); /* Subtract 1 from the R1 operand and branch if result is non-zero and R2 operand is not register zero */ if ( --(regs->GR_G(r1)) && r2 != 0 ) SUCCESSFUL_BRANCH(regs, newia, 2); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_on_count_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B920 CGR - Compare Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S64)regs->GR_G(r2) ? 1 : (S64)regs->GR_G(r1) > (S64)regs->GR_G(r2) ? 2 : 0; } /* end DEF_INST(compare_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B930 CGFR - Compare Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S32)regs->GR_L(r2) ? 1 : (S64)regs->GR_G(r1) > (S32)regs->GR_L(r2) ? 2 : 0; } /* end DEF_INST(compare_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E320 CG - Compare Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S64)n ? 1 : (S64)regs->GR_G(r1) > (S64)n ? 2 : 0; } /* end DEF_INST(compare_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E330 CGF - Compare Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_long_fullword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S32)n ? 1 : (S64)regs->GR_G(r1) > (S32)n ? 2 : 0; } /* end DEF_INST(compare_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E30A ALG - Add Logical Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n); } /* end DEF_INST(add_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E31A ALGF - Add Logical Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_long_fullword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n); } /* end DEF_INST(add_logical_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E318 AGF - Add Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_long_fullword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long (&(regs->GR_G(r1)), regs->GR_G(r1), (S32)n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E308 AG - Add Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long (&(regs->GR_G(r1)), regs->GR_G(r1), n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E30B SLG - Subtract Logical Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n); } /* end DEF_INST(subtract_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E31B SLGF - Subtract Logical Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_long_fullword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), n); } /* end DEF_INST(subtract_logical_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E319 SGF - Subtract Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_long_fullword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed_long(&(regs->GR_G(r1)), regs->GR_G(r1), (S32)n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E309 SG - Subtract Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed_long(&(regs->GR_G(r1)), regs->GR_G(r1), n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B909 SGR - Subtract Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_long_register) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed_long(&(regs->GR_G(r1)), regs->GR_G(r1), regs->GR_G(r2)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B919 SGFR - Subtract Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed_long(&(regs->GR_G(r1)), regs->GR_G(r1), (S32)regs->GR_L(r2)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B908 AGR - Add Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_long_register) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long(&(regs->GR_G(r1)), regs->GR_G(r1), regs->GR_G(r2)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B918 AGFR - Add Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long(&(regs->GR_G(r1)), regs->GR_G(r1), (S32)regs->GR_L(r2)); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B900 LPGR - Load Positive Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_long_register) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); /* Condition code 3 and program check if overflow */ if ( regs->GR_G(r2) == 0x8000000000000000ULL ) { regs->GR_G(r1) = regs->GR_G(r2); regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Load positive value of second operand and set cc */ regs->GR_G(r1) = (S64)regs->GR_G(r2) < 0 ? -((S64)regs->GR_G(r2)) : (S64)regs->GR_G(r2); regs->psw.cc = (S64)regs->GR_G(r1) == 0 ? 0 : 2; } /* end DEF_INST(load_positive_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B910 LPGFR - Load Positive Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_long_fullword_register) { int r1, r2; /* Values of R fields */ S64 gpr2l; RRE0(inst, regs, r1, r2); gpr2l = (S32)regs->GR_L(r2); /* Load positive value of second operand and set cc */ regs->GR_G(r1) = gpr2l < 0 ? -gpr2l : gpr2l; regs->psw.cc = (S64)regs->GR_G(r1) == 0 ? 0 : 2; } /* end DEF_INST(load_positive_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B901 LNGR - Load Negative Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load negative value of second operand and set cc */ regs->GR_G(r1) = (S64)regs->GR_G(r2) > 0 ? -((S64)regs->GR_G(r2)) : (S64)regs->GR_G(r2); regs->psw.cc = (S64)regs->GR_G(r1) == 0 ? 0 : 1; } /* end DEF_INST(load_negative_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B911 LNGFR - Load Negative Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_long_fullword_register) { int r1, r2; /* Values of R fields */ S64 gpr2l; RRE0(inst, regs, r1, r2); gpr2l = (S32)regs->GR_L(r2); /* Load negative value of second operand and set cc */ regs->GR_G(r1) = gpr2l > 0 ? -gpr2l : gpr2l; regs->psw.cc = (S64)regs->GR_G(r1) == 0 ? 0 : 1; } /* end DEF_INST(load_negative_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B902 LTGR - Load and Test Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy second operand and set condition code */ regs->GR_G(r1) = regs->GR_G(r2); regs->psw.cc = (S64)regs->GR_G(r1) < 0 ? 1 : (S64)regs->GR_G(r1) > 0 ? 2 : 0; } /* end DEF_INST(load_and_test_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B912 LTGFR - Load and Test Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy second operand and set condition code */ regs->GR_G(r1) = (S32)regs->GR_L(r2); regs->psw.cc = (S64)regs->GR_G(r1) < 0 ? 1 : (S64)regs->GR_G(r1) > 0 ? 2 : 0; } /* end DEF_INST(load_and_test_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B903 LCGR - Load Complement Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_long_register) { int r1, r2; /* Values of R fields */ RRE(inst, regs, r1, r2); /* Condition code 3 and program check if overflow */ if ( regs->GR_G(r2) == 0x8000000000000000ULL ) { regs->GR_G(r1) = regs->GR_G(r2); regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Load complement of second operand and set condition code */ regs->GR_G(r1) = -((S64)regs->GR_G(r2)); regs->psw.cc = (S64)regs->GR_G(r1) < 0 ? 1 : (S64)regs->GR_G(r1) > 0 ? 2 : 0; } /* end DEF_INST(load_complement_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B913 LCGFR - Load Complement Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_long_fullword_register) { int r1, r2; /* Values of R fields */ S64 gpr2l; RRE0(inst, regs, r1, r2); gpr2l = (S32)regs->GR_L(r2); /* Load complement of second operand and set condition code */ regs->GR_G(r1) = -gpr2l; regs->psw.cc = (S64)regs->GR_G(r1) < 0 ? 1 : (S64)regs->GR_G(r1) > 0 ? 2 : 0; } /* end DEF_INST(load_complement_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A7x2 TMHH - Test under Mask High High [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(test_under_mask_high_high) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ U16 h1; /* 16-bit operand values */ U16 h2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); /* AND register bits 0-15 with immediate operand */ h1 = i2 & regs->GR_HHH(r1); /* Isolate leftmost bit of immediate operand */ for ( h2 = 0x8000; h2 != 0 && (h2 & i2) == 0; h2 >>= 1 ); /* Set condition code according to result */ regs->psw.cc = ( h1 == 0 ) ? 0 : /* result all zeroes */ ( h1 == i2) ? 3 : /* result all ones */ ((h1 & h2) == 0) ? 1 : /* leftmost bit zero */ 2; /* leftmost bit one */ } /* end DEF_INST(test_under_mask_high_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A7x3 TMHL - Test under Mask High Low [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(test_under_mask_high_low) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ U16 h1; /* 16-bit operand values */ U16 h2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); /* AND register bits 16-31 with immediate operand */ h1 = i2 & regs->GR_HHL(r1); /* Isolate leftmost bit of immediate operand */ for ( h2 = 0x8000; h2 != 0 && (h2 & i2) == 0; h2 >>= 1 ); /* Set condition code according to result */ regs->psw.cc = ( h1 == 0 ) ? 0 : /* result all zeroes */ ( h1 == i2) ? 3 : /* result all ones */ ((h1 & h2) == 0) ? 1 : /* leftmost bit zero */ 2; /* leftmost bit one */ } /* end DEF_INST(test_under_mask_high_low) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A7x7 BRCTG - Branch Relative on Count Long [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(branch_relative_on_count_long) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI_B(inst, regs, r1, i2); /* Subtract 1 from the R1 operand and branch if non-zero */ if ( --(regs->GR_G(r1)) ) SUCCESSFUL_RELATIVE_BRANCH(regs, 2*(S16)i2, 4); else INST_UPDATE_PSW(regs, 4, 0); } /* end DEF_INST(branch_relative_on_count_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E321 CLG - Compare Logical long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < n ? 1 : regs->GR_G(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E331 CLGF - Compare Logical long fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_long_fullword) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < n ? 1 : regs->GR_G(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B931 CLGFR - Compare Logical Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < regs->GR_L(r2) ? 1 : regs->GR_G(r1) > regs->GR_L(r2) ? 2 : 0; } /* end DEF_INST(compare_logical_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B917 LLGTR - Load Logical Long Thirtyone Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_thirtyone_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); regs->GR_G(r1) = regs->GR_L(r2) & 0x7FFFFFFF; } /* end DEF_INST(load_logical_long_thirtyone_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B921 CLGR - Compare Logical Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < regs->GR_G(r2) ? 1 : regs->GR_G(r1) > regs->GR_G(r2) ? 2 : 0; } /* end DEF_INST(compare_logical_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB1C RLLG - Rotate Left Single Logical Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_left_single_logical_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U64 n; /* Integer work areas */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Rotate and copy contents of r3 to r1 */ regs->GR_G(r1) = (regs->GR_G(r3) << n) | ((n == 0) ? 0 : (regs->GR_G(r3) >> (64 - n))); } /* end DEF_INST(rotate_left_single_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB1D RLL - Rotate Left Single Logical [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(rotate_left_single_logical) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U64 n; /* Integer work areas */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost five bits of operand address as shift count */ n = effective_addr2 & 0x1F; /* Rotate and copy contents of r3 to r1 */ regs->GR_L(r1) = (regs->GR_L(r3) << n) | ((n == 0) ? 0 : (regs->GR_L(r3) >> (32 - n))); } /* end DEF_INST(rotate_left_single_logical) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB0D SLLG - Shift Left Single Logical Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_single_logical_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U64 n; /* Integer work areas */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Copy contents of r3 to r1 and perform shift */ regs->GR_G(r1) = regs->GR_G(r3) << n; } /* end DEF_INST(shift_left_single_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB0C SRLG - Shift Right Single Logical Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_single_logical_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U64 n; /* Integer work areas */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Copy contents of r3 to r1 and perform shift */ regs->GR_G(r1) = regs->GR_G(r3) >> n; } /* end DEF_INST(shift_right_single_logical_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB0B SLAG - Shift Left Single Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_left_single_long) { U32 r1, r3; /* Register numbers */ U32 b2; /* effective address base */ VADR effective_addr2; /* effective address */ U64 n, n1, n2; /* 64-bit operand values */ U32 i, j; /* Integer work areas */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Load the numeric and sign portions from the R3 register */ n1 = regs->GR_G(r3) & 0x7FFFFFFFFFFFFFFFULL; n2 = regs->GR_G(r3) & 0x8000000000000000ULL; /* Shift the numeric portion left n positions */ for (i = 0, j = 0; i < n; i++) { /* Shift bits 1-63 left one bit position */ n1 <<= 1; /* Overflow if bit shifted out is unlike the sign bit */ if ((n1 & 0x8000000000000000ULL) != n2) j = 1; } /* Load the updated value into the R1 register */ regs->GR_G(r1) = (n1 & 0x7FFFFFFFFFFFFFFFULL) | n2; /* Condition code 3 and program check if overflow occurred */ if (j) { regs->psw.cc = 3; if ( FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); return; } /* Set the condition code */ regs->psw.cc = (S64)regs->GR_G(r1) > 0 ? 2 : (S64)regs->GR_G(r1) < 0 ? 1 : 0; } /* end DEF_INST(shift_left_single_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB0A SRAG - Shift Right Single Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_right_single_long) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ U64 n; /* Integer work areas */ RSY0(inst, regs, r1, r3, b2, effective_addr2); /* Use rightmost six bits of operand address as shift count */ n = effective_addr2 & 0x3F; /* Copy and shift the signed value of the R3 register */ regs->GR_G(r1) = (n > 62) ? ((S64)regs->GR_G(r3) < 0 ? -1LL : 0) : (S64)regs->GR_G(r3) >> n; /* Set the condition code */ regs->psw.cc = (S64)regs->GR_G(r1) > 0 ? 2 : (S64)regs->GR_G(r1) < 0 ? 1 : 0; } /* end DEF_INST(shift_right_single_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E31C MSGF - Multiply Single Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_long_fullword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Multiply signed operands ignoring overflow */ regs->GR_G(r1) = (S64)regs->GR_G(r1) * (S32)n; } /* end DEF_INST(multiply_single_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E30C MSG - Multiply Single Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Multiply signed operands ignoring overflow */ regs->GR_G(r1) = (S64)regs->GR_G(r1) * (S64)n; } /* end DEF_INST(multiply_single_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B91C MSGFR - Multiply Single Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Multiply signed registers ignoring overflow */ regs->GR_G(r1) = (S64)regs->GR_G(r1) * (S32)regs->GR_L(r2); } /* end DEF_INST(multiply_single_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B90C MSGR - Multiply Single Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Multiply signed registers ignoring overflow */ regs->GR_G(r1) = (S64)regs->GR_G(r1) * (S64)regs->GR_G(r2); } /* end DEF_INST(multiply_single_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A7x9 LGHI - Load Long Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit operand values */ RI0(inst, regs, r1, i2); /* Load operand into register */ regs->GR_G(r1) = (S16)i2; } /* end DEF_INST(load_long_halfword_immediate) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A7xB AGHI - Add Long Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(add_long_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit immediate op */ RI(inst, regs, r1, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long(&(regs->GR_G(r1)), regs->GR_G(r1), (S16)i2); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_long_halfword_immediate) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A7xD MGHI - Multiply Long Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_long_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit operand */ RI0(inst, regs, r1, i2); /* Multiply register by operand ignoring overflow */ regs->GR_G(r1) = (S64)regs->GR_G(r1) * (S16)i2; } /* end DEF_INST(multiply_long_halfword_immediate) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* A7xF CGHI - Compare Long Halfword Immediate [RI] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_long_halfword_immediate) { int r1; /* Register number */ U16 i2; /* 16-bit operand */ RI0(inst, regs, r1, i2); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S16)i2 ? 1 : (S64)regs->GR_G(r1) > (S16)i2 ? 2 : 0; } /* end DEF_INST(compare_long_halfword_immediate) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B980 NGR - And Register Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(and_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* AND second operand with first and set condition code */ regs->psw.cc = ( regs->GR_G(r1) &= regs->GR_G(r2) ) ? 1 : 0; } /* end DEF_INST(and_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B981 OGR - Or Register Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(or_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* OR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_G(r1) |= regs->GR_G(r2) ) ? 1 : 0; } /* end DEF_INST(or_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B982 XGR - Exclusive Or Register Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* XOR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_G(r1) ^= regs->GR_G(r2) ) ? 1 : 0; } /* end DEF_INST(exclusive_or_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E380 NG - And Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(and_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* AND second operand with first and set condition code */ regs->psw.cc = ( regs->GR_G(r1) &= n ) ? 1 : 0; } /* end DEF_INST(and_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E381 OG - Or Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(or_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* OR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_G(r1) |= n ) ? 1 : 0; } /* end DEF_INST(or_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E382 XG - Exclusive Or Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U64 n; /* 64-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* XOR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_G(r1) ^= n ) ? 1 : 0; } /* end DEF_INST(exclusive_or_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B904 LGR - Load Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy second operand to first operand */ regs->GR_G(r1) = regs->GR_G(r2); } /* end DEF_INST(load_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B916 LLGFR - Load Logical Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy second operand to first operand */ regs->GR_G(r1) = regs->GR_L(r2); } /* end DEF_INST(load_logical_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B914 LGFR - Load Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy second operand to first operand */ regs->GR_G(r1) = (S32)regs->GR_L(r2); } /* end DEF_INST(load_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B90A ALGR - Add Logical Register Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), regs->GR_G(r2)); } /* end DEF_INST(add_logical_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B91A ALGFR - Add Logical Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), regs->GR_L(r2)); } /* end DEF_INST(add_logical_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B91B SLGFR - Subtract Logical Long Fullword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_long_fullword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), regs->GR_L(r2)); } /* end DEF_INST(subtract_logical_long_fullword_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B90B SLGR - Subtract Logical Register Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), regs->GR_G(r2)); } /* end DEF_INST(subtract_logical_long_register) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EF LMD - Load Multiple Disjoint [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(load_multiple_disjoint) { int r1, r3; /* Register numbers */ int b2, b4; /* Base register numbers */ VADR effective_addr2; /* Operand2 address */ VADR effective_addr4; /* Operand4 address */ int i, n; /* Integer work areas */ U32 rwork1[16], rwork2[16]; /* Intermediate work areas */ SS(inst, regs, r1, r3, b2, effective_addr2, b4, effective_addr4); n = ((r3 - r1) & 0xF) + 1; ARCH_DEP(vfetchc) (rwork1, (n * 4) - 1, effective_addr2, b2, regs); ARCH_DEP(vfetchc) (rwork2, (n * 4) - 1, effective_addr4, b4, regs); /* Load a register at a time */ for (i = 0; i < n; i++) { regs->GR_H((r1 + i) & 0xF) = fetch_fw(&rwork1[i]); regs->GR_L((r1 + i) & 0xF) = fetch_fw(&rwork2[i]); } } /* end DEF_INST(load_multiple_disjoint) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB96 LMH - Load Multiple High [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_multiple_high) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2; /* Mainstor pointers */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to load */ n = (((r3 - r1) & 0xF) + 1) << 2; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Address of operand beginning */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if (likely(n <= m)) { /* Boundary not crossed */ n >>= 2; for (i = 0; i < n; i++, p1++) regs->GR_H((r1 + i) & 0xF) = fetch_fw (p1); } else { /* Boundary crossed, get 2nd page address */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if (likely((m & 0x3) == 0)) { /* Addresses are word aligned */ m >>= 2; for (i = 0; i < m; i++, p1++) regs->GR_H((r1 + i) & 0xF) = fetch_fw (p1); n >>= 2; for ( ; i < n; i++, p2++) regs->GR_H((r1 + i) & 0xF) = fetch_fw (p2); } else { /* Worst case */ U32 rwork[16]; BYTE *b1, *b2; b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b1++ = *b2++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b1++ = *b2++; n >>= 2; for (i = 0; i < n; i++) regs->GR_H((r1 + i) & 0xF) = CSWAP32(rwork[i]); } } } /* end DEF_INST(load_multiple_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB04 LMG - Load Multiple Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_multiple_long) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, m, n; /* Integer work areas */ U64 *p1, *p2; /* Mainstor pointers */ BYTE *bp1; /* Unaligned Mainstor ptr */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to load */ n = (((r3 - r1) & 0xF) + 1) << 3; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Address of operand beginning */ bp1 = (BYTE*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); p1=(U64*)bp1; if (likely(n <= m)) { /* Boundary not crossed */ n >>= 3; #if defined(OPTION_STRICT_ALIGNMENT) if(likely(!(((uintptr_t)effective_addr2)&0x07))) { #endif #if defined(OPTION_SINGLE_CPU_DW) && defined(ASSIST_STORE_DW) if (regs->cpubit == regs->sysblk->started_mask) for (i = 0; i < n; i++, p1++) regs->GR_G((r1 + i) & 0xF) = CSWAP64(*p1); else #endif for (i = 0; i < n; i++, p1++) regs->GR_G((r1 + i) & 0xF) = fetch_dw (p1); #if defined(OPTION_STRICT_ALIGNMENT) } else { for (i = 0; i < n; i++, bp1+=8) regs->GR_G((r1 + i) & 0xF) = fetch_dw (bp1); } #endif } else { /* Boundary crossed, get 2nd page address */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U64*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if (likely((m & 0x7) == 0)) { /* FIXME: This code blows up on at least Mac OS X Snow Leopard (10.6) when compiled for a 32-bit Intel host using gcc 4.2.1 unless the PTT call below is present. The problem appears to be in the gcc 4.2.1 optimizer, as the code works when compiled with -O0. DO NOT REMOVE this until it's been found and fixed. -- JRM, 11 Feb 2010 */ // PTT(PTT_CL_INF,"LMG2KIN",p2,0,0); /* Addresses are double-word aligned */ m >>= 3; for (i = 0; i < m; i++, p1++) regs->GR_G((r1 + i) & 0xF) = fetch_dw (p1); n >>= 3; for ( ; i < n; i++, p2++) regs->GR_G((r1 + i) & 0xF) = fetch_dw (p2); } else { /* Worst case */ U64 rwork[16]; BYTE *b1, *b2; b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b1++ = *b2++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b1++ = *b2++; n >>= 3; for (i = 0; i < n; i++) regs->GR_G((r1 + i) & 0xF) = CSWAP64(rwork[i]); } } } /* end DEF_INST(load_multiple_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB25 STCTG - Store Control Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_control_long) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, m, n; /* Integer work areas */ U64 *p1, *p2 = NULL; /* Mainstor pointers */ RSY(inst, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_ZSIE) if(SIE_STATB(regs, IC1, STCTL)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_ZSIE)*/ /* Calculate number of regs to store */ n = ((r3 - r1) & 0xF) + 1; /* Calculate number of double words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 3; /* Address of operand beginning */ p1 = (U64*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely (m < n)) p2 = (U64*)MADDR(effective_addr2 + (m*8), b2, regs, ACCTYPE_WRITE, regs->psw.pkey); else m = n; /* Store to first page */ for (i = 0; i < m; i++) store_dw(p1++, regs->CR_G((r1 + i) & 0xF)); /* Store to next page */ for ( ; i < n; i++) store_dw(p2++, regs->CR_G((r1 + i) & 0xF)); } /* end DEF_INST(store_control_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB2F LCTLG - Load Control Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_control_long) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, m, n; /* Integer work areas */ U64 *p1, *p2 = NULL; /* Mainstor pointers */ U16 updated = 0; /* Updated control regs */ RSY(inst, regs, r1, r3, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); /* Calculate number of regs to load */ n = ((r3 - r1) & 0xF) + 1; #if defined(_FEATURE_ZSIE) if ( SIE_MODE(regs) ) { U16 cr_mask = fetch_hw (regs->siebk->lctl_ctl); for (i = 0; i < n; i++) if (cr_mask & BIT(15 - ((r1 + i) & 0xF))) longjmp(regs->progjmp, SIE_INTERCEPT_INST); } #endif /* Calculate number of double words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 3; /* Address of operand beginning */ p1 = (U64*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely (m < n)) p2 = (U64*)MADDR(effective_addr2 + (m*8), b2, regs, ACCTYPE_READ, regs->psw.pkey); else m = n; /* Load from first page */ for (i = 0; i < m; i++, p1++) { regs->CR_G((r1 + i) & 0xF) = fetch_dw(p1); updated |= BIT((r1 + i) & 0xF); } /* Load from next page */ for ( ; i < n; i++, p2++) { regs->CR_G((r1 + i) & 0xF) = fetch_dw(p2); updated |= BIT((r1 + i) & 0xF); } /* Actions based on updated control regs */ SET_IC_MASK(regs); if (updated & (BIT(1) | BIT(7) | BIT(13))) SET_AEA_COMMON(regs); if (updated & BIT(regs->aea_ar[USE_INST_SPACE])) INVALIDATE_AIA(regs); if (updated & BIT(9)) { OBTAIN_INTLOCK(regs); SET_IC_PER(regs); RELEASE_INTLOCK(regs); if (EN_IC_PER_SA(regs)) ARCH_DEP(invalidate_tlb)(regs,~(ACC_WRITE|ACC_CHECK)); } RETURN_INTCHECK(regs); } /* end DEF_INST(load_control_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB24 STMG - Store Multiple Long [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_multiple_long) { int r1, r3; /* Register numbers */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int i, m, n; /* Integer work areas */ U64 *p1, *p2; /* Mainstor pointers */ BYTE *bp1; /* Unaligned Mainstor ptr */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to store */ n = (((r3 - r1) & 0xF) + 1) << 3; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Get address of first page */ bp1 = (BYTE*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); p1=(U64*)bp1; if (likely(n <= m)) { /* Boundary not crossed */ n >>= 3; #if defined(OPTION_STRICT_ALIGNMENT) if(likely(!(((uintptr_t)effective_addr2)&0x07))) { #endif #if defined(OPTION_SINGLE_CPU_DW) && defined(ASSIST_STORE_DW) if (regs->cpubit == regs->sysblk->started_mask) for (i = 0; i < n; i++) *p1++ = CSWAP64(regs->GR_G((r1 + i) & 0xF)); else #endif for (i = 0; i < n; i++) store_dw (p1++, regs->GR_G((r1 + i) & 0xF)); #if defined(OPTION_STRICT_ALIGNMENT) } else { for (i = 0; i < n; i++,bp1+=8) store_dw (bp1, regs->GR_G((r1 + i) & 0xF)); } #endif } if (likely(n <= m)) { /* boundary not crossed */ n >>= 3; } else { /* boundary crossed, get address of the 2nd page */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U64*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); if (likely((m & 0x7) == 0)) { /* double word aligned */ m >>= 3; for (i = 0; i < m; i++) store_dw (p1++, regs->GR_G((r1 + i) & 0xF)); n >>= 3; for ( ; i < n; i++) store_dw (p2++, regs->GR_G((r1 + i) & 0xF)); } else { /* worst case */ U64 rwork[16]; BYTE *b1, *b2; for (i = 0; i < (n >> 3); i++) rwork[i] = CSWAP64(regs->GR_G((r1 + i) & 0xF)); b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b2++ = *b1++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b2++ = *b1++; } } } /* end DEF_INST(store_multiple_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* EB26 STMH - Store Multiple High [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_multiple_high) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2; /* Mainstor pointers */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to store */ n = (((r3 - r1) & 0xF) + 1) << 2; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Get address of first page */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); if (likely(n <= m)) { /* boundary not crossed */ n >>= 2; for (i = 0; i < n; i++) store_fw (p1++, regs->GR_H((r1 + i) & 0xF)); } else { /* boundary crossed, get address of the 2nd page */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); if (likely((m & 0x3) == 0)) { /* word aligned */ m >>= 2; for (i = 0; i < m; i++) store_fw (p1++, regs->GR_H((r1 + i) & 0xF)); n >>= 2; for ( ; i < n; i++) store_fw (p2++, regs->GR_H((r1 + i) & 0xF)); } else { /* worst case */ U32 rwork[16]; BYTE *b1, *b2; for (i = 0; i < (n >> 2); i++) rwork[i] = CSWAP32(regs->GR_H((r1 + i) & 0xF)); b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b2++ = *b1++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b2++ = *b1++; } } } /* end DEF_INST(store_multiple_high) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B905 LURAG - Load Using Real Address Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_using_real_address_long) { int r1, r2; /* Values of R fields */ RADR n; /* Unsigned work */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* R2 register contains operand real storage address */ n = regs->GR_G(r2) & ADDRESS_MAXWRAP(regs); /* Program check if operand not on doubleword boundary */ DW_CHECK(n, regs); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch8) ( n, USE_REAL_ADDR, regs ); } /* end DEF_INST(load_using_real_address_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B925 STURG - Store Using Real Address Long [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(store_using_real_address_long) { int r1, r2; /* Values of R fields */ RADR n; /* Unsigned work */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* R2 register contains operand real storage address */ n = regs->GR_G(r2) & ADDRESS_MAXWRAP(regs); /* Program check if operand not on doubleword boundary */ DW_CHECK(n, regs); /* Store R1 register at second operand location */ ARCH_DEP(vstore8) (regs->GR_G(r1), n, USE_REAL_ADDR, regs ); #if defined(FEATURE_PER2) /* Storage alteration must be enabled for STURA to be recognised */ if( EN_IC_PER_SA(regs) && EN_IC_PER_STURA(regs) ) { ON_IC_PER_SA(regs) ; ON_IC_PER_STURA(regs) ; } #endif /*defined(FEATURE_PER2)*/ } /* end DEF_INST(store_using_real_address_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* 010B TAM - Test Addressing Mode [E] */ /*-------------------------------------------------------------------*/ DEF_INST(test_addressing_mode) { E(inst, regs); regs->psw.cc = #if defined(FEATURE_ESAME) (regs->psw.amode64 << 1) | #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode; } /* end DEF_INST(test_addressing_mode) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* 010C SAM24 - Set Addressing Mode 24 [E] */ /*-------------------------------------------------------------------*/ DEF_INST(set_addressing_mode_24) { VADR ia = PSW_IA(regs, 0); /* Unupdated instruction addr*/ E(inst, regs); /* Set the bear register */ SET_BEAR_REG(regs, regs->bear_ip); /* Program check if instruction is located above 16MB */ if (ia > 0xFFFFFFULL) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && regs->psw.amode64) regs->CR(12) = ARCH_DEP(trace_ms) (0, 0, regs); #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) regs->psw.amode64 = #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode = 0; regs->psw.AMASK = AMASK24; } /* end DEF_INST(set_addressing_mode_24) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* 010D SAM31 - Set Addressing Mode 31 [E] */ /*-------------------------------------------------------------------*/ DEF_INST(set_addressing_mode_31) { VADR ia = PSW_IA(regs, 0); /* Unupdated instruction addr*/ E(inst, regs); /* Set the bear register */ SET_BEAR_REG(regs, regs->bear_ip); /* Program check if instruction is located above 2GB */ if (ia > 0x7FFFFFFFULL) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && regs->psw.amode64) regs->CR(12) = ARCH_DEP(trace_ms) (0, 0, regs); #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) regs->psw.amode64 = 0; #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode = 1; regs->psw.AMASK = AMASK31; } /* end DEF_INST(set_addressing_mode_31) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* 010E SAM64 - Set Addressing Mode 64 [E] */ /*-------------------------------------------------------------------*/ DEF_INST(set_addressing_mode_64) { E(inst, regs); /* Set the bear register */ SET_BEAR_REG(regs, regs->bear_ip); #if defined(FEATURE_ESAME) /* Add a mode trace entry when switching in/out of 64 bit mode */ if((regs->CR(12) & CR12_MTRACE) && !regs->psw.amode64) regs->CR(12) = ARCH_DEP(trace_ms) (0, 0, regs); #endif /*defined(FEATURE_ESAME)*/ regs->psw.amode = regs->psw.amode64 = 1; regs->psw.AMASK = AMASK64; } /* end DEF_INST(set_addressing_mode_64) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E324 STG - Store Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store register contents at operand address */ ARCH_DEP(vstore8) ( regs->GR_G(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E502 STRAG - Store Real Address [SSE] */ /*-------------------------------------------------------------------*/ DEF_INST(store_real_address) { int b1, b2; /* Values of base registers */ VADR effective_addr1, effective_addr2; /* Effective addresses */ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr1, regs); /* Translate virtual address to real address */ if (ARCH_DEP(translate_addr) (effective_addr2, b2, regs, ACCTYPE_STRAG)) regs->program_interrupt (regs, regs->dat.xcode); /* Store register contents at operand address */ ARCH_DEP(vstore8) (regs->dat.raddr, effective_addr1, b1, regs ); } /* end DEF_INST(store_real_address) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E304 LG - Load Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E314 LGF - Load Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_fullword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = (S32)ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E315 LGH - Load Long Halfword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_long_halfword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E316 LLGF - Load Logical Long Fullword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_fullword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_logical_long_fullword) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E317 LLGT - Load Logical Long Thirtyone [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_thirtyone) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ) & 0x7FFFFFFF; } /* end DEF_INST(load_logical_long_thirtyone) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B2B2 LPSWE - Load PSW Extended [S] */ /*-------------------------------------------------------------------*/ DEF_INST(load_program_status_word_extended) { int b2; /* Base of effective addr */ U64 effective_addr2; /* Effective address */ QWORD qword; int rc; S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); DW_CHECK(effective_addr2, regs); #if defined(_FEATURE_ZSIE) if(SIE_STATB(regs, IC1, LPSW)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_ZSIE)*/ /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); /* Fetch new PSW from operand address */ ARCH_DEP(vfetchc) ( qword, 16-1, effective_addr2, b2, regs ); /* Set the breaking event address register */ SET_BEAR_REG(regs, regs->ip - 4); /* Load updated PSW */ if ( ( rc = ARCH_DEP(load_psw) ( regs, qword ) ) ) regs->program_interrupt (regs, rc); /* Perform serialization and checkpoint synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); RETURN_INTCHECK(regs); } /* end DEF_INST(load_program_status_word_extended) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E303 LRAG - Load Real Address Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_real_address_long) { int r1; /* Register number */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int cc; /* Condition code */ RXY(inst, regs, r1, b2, effective_addr2); SIE_XC_INTERCEPT(regs); PRIV_CHECK(regs); /* Translate the effective address to a real address */ cc = ARCH_DEP(translate_addr) (effective_addr2, b2, regs, ACCTYPE_LRA); /* If ALET exception or ASCE-type or region translation exception, or if the segment table entry is outside the table and the entry address exceeds 2GB, set exception code in R1 bits 48-63, set bit 32 of R1, and set cc 3 */ if (cc > 3 || (cc == 3 && regs->dat.raddr > 0x7FFFFFFF)) { regs->GR_L(r1) = 0x80000000 | regs->dat.xcode; cc = 3; } else if (cc == 3) /* && regs->dat.raddr <= 0x7FFFFFFF */ { /* If segment table entry is outside table and entry address does not exceed 2GB, return bits 32-63 of the entry address and leave bits 0-31 unchanged */ regs->GR_L(r1) = regs->dat.raddr; } else { /* Set R1 and condition code as returned by translate_addr */ regs->GR_G(r1) = regs->dat.raddr; } /* Set condition code */ regs->psw.cc = cc; } /* end DEF_INST(load_real_address_long) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_TOD_CLOCK_STEERING) /*-------------------------------------------------------------------*/ /* 0104 PTFF - Perform Timing Facility Function [E] */ /*-------------------------------------------------------------------*/ DEF_INST(perform_timing_facility_function) { E(inst, regs); SIE_INTERCEPT(regs); if(regs->GR_L(0) & PTFF_GPR0_RESV) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); switch(regs->GR_L(0) & PTFF_GPR0_FC_MASK) { case PTFF_GPR0_FC_QAF: ARCH_DEP(query_available_functions) (regs); regs->psw.cc = 0; break; case PTFF_GPR0_FC_QTO: ARCH_DEP(query_tod_offset) (regs); regs->psw.cc = 0; break; case PTFF_GPR0_FC_QSI: ARCH_DEP(query_steering_information) (regs); regs->psw.cc = 0; break; case PTFF_GPR0_FC_QPT: ARCH_DEP(query_physical_clock) (regs); regs->psw.cc = 0; break; case PTFF_GPR0_FC_ATO: PRIV_CHECK(regs); ARCH_DEP(adjust_tod_offset) (regs); regs->psw.cc = 0; break; case PTFF_GPR0_FC_STO: PRIV_CHECK(regs); ARCH_DEP(set_tod_offset) (regs); regs->psw.cc = 0; break; case PTFF_GPR0_FC_SFS: PRIV_CHECK(regs); ARCH_DEP(set_fine_s_rate) (regs); regs->psw.cc = 0; break; case PTFF_GPR0_FC_SGS: PRIV_CHECK(regs); ARCH_DEP(set_gross_s_rate) (regs); regs->psw.cc = 0; break; default: PTT(PTT_CL_ERR,"*PTFF",regs->GR_L(0),regs->GR_L(1),regs->psw.IA_L); regs->psw.cc = 3; } } /* end DEF_INST(perform_timing_facility_function) */ #endif /*defined(FEATURE_TOD_CLOCK_STEERING)*/ #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) /*-------------------------------------------------------------------*/ /* B9A2 PTF - Perform Topology Function [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(perform_topology_function) { int r1, unused; /* Values of R fields */ int fc, rc = 0; /* Function / Reason Code */ RRE(inst, regs, r1, unused); PTT(PTT_CL_INF,"PTF",regs->GR_G(r1),0,regs->psw.IA_L); PRIV_CHECK(regs); SIE_INTERCEPT(regs); /* Specification Exception if bits 0-55 of general register R1 are not zeros */ if (regs->GR_G(r1) & 0xFFFFFFFFFFFFFF00ULL) { PTT(PTT_CL_ERR,"*PTF",regs->GR_G(r1),rc,regs->psw.IA_L); regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } /* Extract function code */ fc = (int)(regs->GR_G(r1) & 0x00000000000000FFULL); /* Perform requested function */ switch (fc) { case 0: /* Request horizontal polarization */ if (sysblk.topology == TOPOLOGY_HORIZ) { regs->psw.cc = 2; /* Request rejected */ rc = 1; /* Already polarized as specified */ } else { sysblk.topology = TOPOLOGY_HORIZ; sysblk.topchnge = 1; regs->psw.cc = 0; rc = 0; } break; case 1: /* Request vertical polarization */ if (sysblk.topology == TOPOLOGY_VERT) { regs->psw.cc = 2; /* Request rejected */ rc = 1; /* Already polarized as specified */ } else { sysblk.topology = TOPOLOGY_VERT; sysblk.topchnge = 1; regs->psw.cc = 0; rc = 0; } break; case 2: /* Check topology-change status */ OBTAIN_INTLOCK(regs); regs->psw.cc = sysblk.topchnge ? 1 /* (report was pending) */ : 0; /* (report not pending) */ sysblk.topchnge = 0; /* (clear pending flag) */ RELEASE_INTLOCK(regs); break; default: /* Undefined function code */ PTT(PTT_CL_ERR,"*PTF",regs->GR_G(r1),rc,regs->psw.IA_L); regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } /* Set reason code in bits 48-55 when condition code is 2 */ if (regs->psw.cc == 2) regs->GR_G(r1) |= rc << 8; if (regs->psw.cc != 0) PTT(PTT_CL_ERR,"*PTF",regs->GR_G(r1),rc,regs->psw.IA_L); } #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ #if defined(FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY) /*-------------------------------------------------------------------*/ /* B9AE RRBM - Reset Reference Bits Multiple [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(reset_reference_bits_multiple) { int r1, r2; /* Register values */ RADR a; /* Abs frame addr stor key */ BYTE storkey; /* Storage key */ int i; U64 bitmap; /* Bitmap to be ret in r1 */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* Load 4K block address from R2 register */ a = regs->GR(r2) & ADDRESS_MAXWRAP_E(regs); /* Addressing exception if block is outside main storage */ if ( a > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); /* Ignore bits 46-63 of the 2nd operand */ a &= ~0x3ffffULL; #if defined(_FEATURE_SIE) if(SIE_MODE(regs) && (SIE_STATB(regs, IC2, RRBE))) longjmp(regs->progjmp, SIE_INTERCEPT_INST); for(i =0 , bitmap = 0; i < 64; i++, a+= PAGEFRAME_PAGESIZE, bitmap <<= 1) { RADR n = a; if(SIE_MODE(regs)) { SIE_TRANSLATE(&n, ACCTYPE_SIE, regs); if(regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if((SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && SIE_STATB(regs, RCPO2, RCPBY)) { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | (STORAGE_KEY2(n, regs) & (STORKEY_REF)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { BYTE rcpkey, realkey; RADR ra; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(SIE_STATB(regs, MX, XC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += n >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; STORAGE_KEY(rcpa, regs) |= STORKEY_REF; if (!SIE_TRANSLATE_ADDR (regs->sie_mso + n, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE)) { ra = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); #if !defined(_FEATURE_2K_STORAGE_KEYS) realkey = STORAGE_KEY(ra, regs) & (STORKEY_REF); #else realkey = (STORAGE_KEY1(ra, regs) | STORAGE_KEY2(ra, regs)) & (STORKEY_REF); #endif /* Reset the reference and change bits in the real machine storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(ra, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(ra, regs) &= ~(STORKEY_REF); STORAGE_KEY2(ra, regs) &= ~(STORKEY_REF); #endif } else realkey = 0; /* The storage key is obtained by logical or or the real and guest RC bits */ storkey = realkey | (rcpkey & (STORKEY_REF)); /* or with host set */ rcpkey |= realkey << 4; /* Put storage key in guest set */ rcpkey |= storkey; /* reset the reference bit */ rcpkey &= ~(STORKEY_REF); regs->mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa, regs) |= (STORKEY_REF); } } else { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | (STORAGE_KEY2(n, regs) & (STORKEY_REF)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) storkey = STORAGE_KEY(n, regs); #else storkey = STORAGE_KEY1(n, regs) | (STORAGE_KEY2(n, regs) & (STORKEY_REF)) #endif ; /* Reset the reference bit in the storage key */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) &= ~(STORKEY_REF); #else STORAGE_KEY1(n, regs) &= ~(STORKEY_REF); STORAGE_KEY2(n, regs) &= ~(STORKEY_REF); #endif } /* Insert the original state of the reference bit in the bitmap */ bitmap |= (storkey & STORKEY_REF) ? 0x01ULL : 0; /* If the storage key had the REF bit on then perform * accelerated lookup invalidations on all CPUs * so that the REF bit will be set when referenced next. */ if (storkey & STORKEY_REF) STORKEY_INVALIDATE(regs, n); } regs->GR_G(r1) = bitmap; } /* end DEF_INST(reset_reference_bits_multiple) */ #endif /*defined(FEATURE_RESET_REFERENCE_BITS_MULTIPLE_FACILITY)*/ #if defined(FEATURE_ENHANCED_DAT_FACILITY) /*-------------------------------------------------------------------*/ /* SUBROUTINE TO PERFORM CONDITIONAL KEY PROCESSING */ /* Input: */ /* mask PFMF mask bits from R1 register */ /* skey Contents of storage key before modification */ /* r1key Storage key to be set */ /* Output (when conditional SSKE is not indicated): */ /* The function return value is 0. */ /* Output (when conditional SSKE is indicated): */ /* The function return value is 1. */ /*-------------------------------------------------------------------*/ static inline int ARCH_DEP(conditional_key_procedure) (U32 mask, BYTE skey, BYTE r1key) { /* Perform normal SSKE if MR and MC bits are both zero */ if ((mask & (PFMF_MR | PFMF_MC)) == 0) return 0; /* Ignore Bad Frame indicator */ skey &= ~(STORKEY_BADFRM); /* If storage key and fetch bit do not equal new values in R1 register bits 56-60 then set condition code 1 and return to PFMF to update storage key */ if ((skey & (STORKEY_KEY | STORKEY_FETCH)) != (r1key & (STORKEY_KEY | STORKEY_FETCH))) return 0; /* If both MR and MC mask bits are one then set condition code 0 and leave storage key unchanged */ if ((mask & (PFMF_MR | PFMF_MC)) == (PFMF_MR | PFMF_MC)) return 1; /* If MR bit is zero and reference bit is equal to bit 61 of R1 register then set condition code 0 and leave storage key unchanged */ if ((mask & PFMF_MR) == 0 && ((skey & STORKEY_REF) == (r1key & STORKEY_REF))) return 1; /* If MC bit is zero and the change bit is equal to bit 62 of R1 register then set condition code 0 and leave storage key unchanged */ if ((mask & PFMF_MC) == 0 && ((skey & STORKEY_CHANGE) == (r1key & STORKEY_CHANGE))) return 1; /* Set condition code 1 and let PFMF update storage key */ return 0; } /* end function conditional_key_procedure */ /*-------------------------------------------------------------------*/ /* B9AF PFMF - Perform Frame Management Function [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(perform_frame_management_function) { int r1, r2; /* Register values */ U32 mask; /* Mask bits from R1 */ int fc = 1; /* Frame count */ RADR addr, aaddr; /* Address of storage frame */ int page_offset; /* Low order bits of R2 */ RRE(inst, regs, r1, r2); PRIV_CHECK(regs); /* Load mask bits from R1 register */ mask = regs->GR_L(r1); /* Program check if reserved bits are non-zero */ if ((regs->GR_L(r1) & (PFMF_RESERVED|PFMF_FMFI_RESV)) || (regs->GR_L(r1) & PFMF_NQ)) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Wrap address according to addressing mode */ aaddr = addr = ADDRESS_MAXWRAP(regs) & regs->GR_G(r2) & PAGEFRAME_PAGEMASK; page_offset = regs->GR_G(r2) & PAGEFRAME_BYTEMASK; /* Convert real address to absolute address */ switch (PFMF_FSC & regs->GR_L(r1)) { case PFMF_FSC_1M: /* Prefixing is not applied in multipage mode */ fc = 0x100 - ((regs->GR_L(r2) & 0xFF000) >> 12); break; #if defined(FEATURE_ENHANCED_DAT_FACILITY_2) case PFMF_FSC_2G: /* Program check if 2GB frame size with 24-bit addressing mode */ if (regs->psw.amode64 == 0 && regs->psw.amode == 0) { regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); } /* Prefixing is not applied in multipage mode */ fc = 0x80000 - ((regs->GR_L(r2) & 0x7FFFF000) >> 12); break; #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY_2)*/ default: /* Program check if frame size code is invalid */ regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); break; case PFMF_FSC_4K: /* Prefixing is applied in single frame operation */ aaddr = addr = APPLY_PREFIXING (addr, regs->PX); fc = 1; break; } /* Note that real hardware does not update R2 for each page, only on interrupt or at completion. Nor does it reference R1 more than once. This has implications for the case of R1 == R2. The low order 12 bits of R2 must remain unchanged. */ for( ; fc--; ) { /* Addressing exception if block is outside main storage */ if ( addr > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); if(regs->GR_L(r1) & PFMF_FMFI_CF) SIE_TRANSLATE(&aaddr, ACCTYPE_SIE, regs); /* Set Key Control */ if(regs->GR_L(r1) & PFMF_FMFI_SK) { BYTE sk = regs->GR_L(r1) & PFMF_KEY; RADR n = addr; BYTE rck = 0; /* Ref Bit must be updated */ if (!(regs->GR_L(r1) & PFMF_MR)) rck |= STORKEY_REF; /* Change Bit must be updated */ if ((regs->GR_L(r1) & PFMF_MC)) rck |= STORKEY_CHANGE; /* Mask out R/C bits to be bypassed */ sk &= ~rck; /* Addressing exception if block is outside main storage */ if ( aaddr > regs->mainlim ) ARCH_DEP(program_interrupt) (regs, PGM_ADDRESSING_EXCEPTION); #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) { if(SIE_STATB(regs, IC2, SSKE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); if(!regs->sie_pref) { #if defined(_FEATURE_STORAGE_KEY_ASSIST) if ((SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) && SIE_STATB(regs, RCPO2, RCPBY)) { SIE_TRANSLATE(&aaddr, ACCTYPE_SIE, regs); } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { int sr; BYTE realkey, rcpkey, protkey; RADR rcpa; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) { /* guest absolute to host PTE addr */ if (SIE_TRANSLATE_ADDR (regs->sie_mso + aaddr, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_PTE)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* Convert real address to absolute address */ rcpa = APPLY_PREFIXING (regs->hostregs->dat.raddr, regs->hostregs->PX); /* For ESA/390 the RCP byte entry is at offset 1 in a four byte entry directly beyond the page table, for ESAME mode, this entry is eight bytes long */ rcpa += regs->hostregs->arch_mode == ARCH_900 ? 2049 : 1025; } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE) if(SIE_STATB(regs, MX, XC)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(FEATURE_MULTIPLE_CONTROLLED_DATA_SPACE)*/ /* Obtain address of the RCP area from the state desc */ rcpa = regs->sie_rcpo &= 0x7FFFF000; /* frame index as byte offset to 4K keys in RCP area */ rcpa += aaddr >> 12; /* host primary to host absolute */ rcpa = SIE_LOGICAL_TO_ABS (rcpa, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE, 0); } /* guest absolute to host real */ sr = SIE_TRANSLATE_ADDR (regs->sie_mso + aaddr, USE_PRIMARY_SPACE, regs->hostregs, ACCTYPE_SIE); if (sr #if defined(_FEATURE_STORAGE_KEY_ASSIST) && !(SIE_FEATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); /* fetch the RCP key */ rcpkey = regs->mainstor[rcpa]; /* set the reference bit in the RCP key */ STORAGE_KEY(rcpa, regs) |= STORKEY_REF; #if defined(_FEATURE_STORAGE_KEY_ASSIST) if(sr) { realkey = 0; protkey = rcpkey & (STORKEY_REF | STORKEY_CHANGE); /* rcpa-1 is correct here - would have been SIE Intercepted otherwise */ protkey |= regs->mainstor[rcpa-1] & (STORKEY_KEY | STORKEY_FETCH); } else #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { /* host real to host absolute */ n = APPLY_PREFIXING(regs->hostregs->dat.raddr, regs->hostregs->PX); protkey = #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(n, regs) #else (STORAGE_KEY1(n, regs) | STORAGE_KEY2(n, regs)) #endif ; realkey = protkey & (STORKEY_REF | STORKEY_CHANGE); } /* Perform conditional SSKE procedure */ if (ARCH_DEP(conditional_key_procedure)(mask, protkey, sk)) return; /* or with host set */ rcpkey |= realkey << 4; /* insert new settings of the guest set */ rcpkey &= ~(STORKEY_REF | STORKEY_CHANGE); rcpkey |= sk & (STORKEY_REF | STORKEY_CHANGE); regs->mainstor[rcpa] = rcpkey; STORAGE_KEY(rcpa, regs) |= (STORKEY_REF|STORKEY_CHANGE); #if defined(_FEATURE_STORAGE_KEY_ASSIST) /* Insert key in new storage key */ if(SIE_STATB(regs, RCPO0, SKA) #if defined(_FEATURE_ZSIE) || (regs->hostregs->arch_mode == ARCH_900) #endif /*defined(_FEATURE_ZSIE)*/ ) regs->mainstor[rcpa-1] = sk & (STORKEY_KEY | STORKEY_FETCH); if(!sr) #endif /*defined(_FEATURE_STORAGE_KEY_ASSIST)*/ { #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY(aaddr, regs) |= sk & (STORKEY_KEY | STORKEY_FETCH); #else STORAGE_KEY1(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY1(aaddr, regs) |= sk & (STORKEY_KEY | STORKEY_FETCH); STORAGE_KEY2(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY2(aaddr, regs) |= sk & (STORKEY_KEY | STORKEY_FETCH); #endif } } } else { /* Perform conditional SSKE procedure */ if (ARCH_DEP(conditional_key_procedure)(mask, #if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(aaddr, regs), #else (STORAGE_KEY1(aaddr, regs) | STORAGE_KEY2(aaddr, regs)), #endif sk)) return; /* Update the storage key from R1 register bits 24-30 */ #if !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY(aaddr, regs) |= sk & ~(STORKEY_BADFRM); #else STORAGE_KEY1(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY1(aaddr, regs) |= sk & ~(STORKEY_BADFRM); STORAGE_KEY2(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY2(aaddr, regs) |= sk & ~(STORKEY_BADFRM); #endif } } else #endif /*defined(_FEATURE_SIE)*/ { /* Perform conditional SSKE procedure */ if (ARCH_DEP(conditional_key_procedure)(mask, #if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(aaddr, regs), #else (STORAGE_KEY1(aaddr, regs) | STORAGE_KEY2(n, regs)), #endif sk)) return; /* Update the storage key from R1 register bits 24-30 */ #if defined(FEATURE_4K_STORAGE_KEYS) && !defined(_FEATURE_2K_STORAGE_KEYS) STORAGE_KEY(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY(aaddr, regs) |= sk & ~(STORKEY_BADFRM); #else STORAGE_KEY1(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY1(aaddr, regs) |= sk & ~(STORKEY_BADFRM); STORAGE_KEY2(aaddr, regs) &= STORKEY_BADFRM; STORAGE_KEY2(aaddr, regs) |= sk & ~(STORKEY_BADFRM); #endif } /* Quiesce */ if (!(regs->GR_L(r1) & PFMF_NQ)) { /* Perform serialization and checkpoint-synchronization */ PERFORM_SERIALIZATION (regs); PERFORM_CHKPT_SYNC (regs); } /* Invalidate AIA/AEA so that the REF and CHANGE bits will be set when referenced next */ STORKEY_INVALIDATE(regs, n); } /* Clear Frame Control */ if(regs->GR_L(r1) & PFMF_FMFI_CF) memset(regs->mainstor + aaddr, 0, PAGEFRAME_PAGESIZE); /* Update r2 - point to the next frame */ switch (PFMF_FSC & regs->GR_L(r1)) { case PFMF_FSC_1M: case PFMF_FSC_2G: aaddr = addr += 0x1000; SET_GR_A(r2, regs, (addr & ADDRESS_MAXWRAP(regs)) + page_offset); break; default: break; case PFMF_FSC_4K: /* Leave R2 unchanged */ break; } #if 0 /* Usage Indication */ if (regs->GR_L(r1) & PFMF_UI) { } #endif } } /* end DEF_INST(perform_frame_management_function) */ #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ #if defined(FEATURE_STORE_FACILITY_LIST) #define HAVE_STFL_DATA 1 BYTE ARCH_DEP(stfl_data)[] = { 0 #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME) | STFL_0_N3 #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) | STFL_0_ESAME_ACTIVE #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) | STFL_0_ESAME_INSTALLED #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_DAT_ENHANCEMENT) | STFL_0_IDTE_INSTALLED #endif /*defined(FEATURE_DAT_ENHANCEMENT)*/ #if defined(FEATURE_ASN_AND_LX_REUSE) | STFL_0_ASN_LX_REUSE #endif /*defined(FEATURE_ASN_AND_LX_REUSE)*/ #if defined(FEATURE_STORE_FACILITY_LIST_EXTENDED) | STFL_0_STFL_EXTENDED #endif /*defined(FEATURE_STORE_FACILITY_LIST_EXTENDED)*/ , 0 #if defined(FEATURE_ENHANCED_DAT_FACILITY) /*208*/ | STFL_1_ENHANCED_DAT /*208*/ #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY)*/ /*208*/ #if defined(FEATURE_SENSE_RUNNING_STATUS) | STFL_1_SENSE_RUN_STATUS #endif /*defined(FEATURE_SENSE_RUNNING_STATUS)*/ #if defined(FEATURE_CONDITIONAL_SSKE) | STFL_1_CONDITIONAL_SSKE #endif /*defined(FEATURE_CONDITIONAL_SSKE)*/ #if defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY) /*208*/ | STFL_1_CONFIG_TOPOLOGY /*208*/ #endif /*defined(FEATURE_CONFIGURATION_TOPOLOGY_FACILITY)*/ /*208*/ , 0 #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) | STFL_2_TRAN_FAC2 #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_MESSAGE_SECURITY_ASSIST) | STFL_2_MSG_SECURITY #endif /*defined(FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(FEATURE_LONG_DISPLACEMENT) | STFL_2_LONG_DISPL_INST | STFL_2_LONG_DISPL_HPERF #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT) | STFL_2_HFP_MULT_ADD_SUB #endif /*defined(FEATURE_HFP_MULTIPLY_ADD_SUBTRACT)*/ #if defined(FEATURE_EXTENDED_IMMEDIATE) | STFL_2_EXTENDED_IMMED #endif /*defined(FEATURE_EXTENDED_IMMEDIATE)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_3) | STFL_2_TRAN_FAC3 #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_3)*/ #if defined(FEATURE_HFP_UNNORMALIZED_EXTENSION) | STFL_2_HFP_UNNORM_EXT #endif /*defined(FEATURE_HFP_UNNORMALIZED_EXTENSION)*/ , 0 #if defined(FEATURE_ETF2_ENHANCEMENT) | STFL_3_ETF2_ENHANCEMENT #endif /*defined(FEATURE_ETF2_ENHANCEMENT)*/ #if defined(FEATURE_STORE_CLOCK_FAST) | STFL_3_STORE_CLOCK_FAST #endif /*defined(FEATURE_STORE_CLOCK_FAST)*/ #if defined(FEATURE_PARSING_ENHANCEMENT_FACILITY) /*208*/ | STFL_3_PARSING_ENHANCE /*208*/ #endif /*defined(FEATURE_PARSING_ENHANCEMENT_FACILITY)*/ /*208*/ #if defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS) /*208*/ | STFL_3_MVCOS /*208*/ #endif /*defined(FEATURE_MOVE_WITH_OPTIONAL_SPECIFICATIONS)*/ /*208*/ #if defined(FEATURE_TOD_CLOCK_STEERING) | STFL_3_TOD_CLOCK_STEER #endif /*defined(FEATURE_TOD_CLOCK_STEERING)*/ #if defined(FEATURE_ETF3_ENHANCEMENT) | STFL_3_ETF3_ENHANCEMENT #endif /*defined(FEATURE_ETF3_ENHANCEMENT)*/ #if defined(FEATURE_EXTRACT_CPU_TIME) | STFL_3_EXTRACT_CPU_TIME #endif /*defined(FEATURE_EXTRACT_CPU_TIME)*/ , 0 #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE) | STFL_4_CSSF #endif /*defined(FEATURE_COMPARE_AND_SWAP_AND_STORE)*/ #if defined(FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2) /*208*/ | STFL_4_CSSF2 /*208*/ #endif /*FEATURE_COMPARE_AND_SWAP_AND_STORE_FACILITY_2*/ /*208*/ #if defined(FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY) /*208*/ | STFL_4_GEN_INST_EXTN /*208*/ #endif /*FEATURE_GENERAL_INSTRUCTIONS_EXTENSION_FACILITY*/ /*208*/ #if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) /*208*/ | STFL_4_EXECUTE_EXTN /*208*/ #endif /*defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/ /*208*/ #if defined(FEATURE_ENHANCED_MONITOR_FACILITY) /*810*/ | STFL_4_ENH_MONITOR /*810*/ #endif /*defined(FEATURE_ENHANCED_MONITOR_FACILITY)*/ /*810*/ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ | STFL_4_FP_EXTENSION /*810*/ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ , 0 #if defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY) | STFL_5_LOAD_PROG_PARAM #endif /*defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY)*/ #if defined(FEATURE_FPS_ENHANCEMENT) | STFL_5_FPS_ENHANCEMENT #endif /*defined(FEATURE_FPS_ENHANCEMENT)*/ #if defined(FEATURE_DECIMAL_FLOATING_POINT) | STFL_5_DECIMAL_FLOAT | STFL_5_DFP_HPERF #endif /*defined(FEATURE_DECIMAL_FLOATING_POINT)*/ #if defined(FEATURE_PFPO) | STFL_5_PFPO #endif /*defined(FEATURE_PFPO)*/ #if defined(FEATURE_FAST_BCR_SERIALIZATION_FACILITY) /*810*/ | STFL_5_FAST_BCR_SERIAL /*810*/ #endif /*defined(FEATURE_FAST_BCR_SERIALIZATION_FACILITY)*/ /*810*/ , 0 #if defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY) /*912*/ | STFL_6_DFP_ZONED_CONV /*912*/ #endif /*defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY)*/ /*912*/ #if defined(FEATURE_EXECUTION_HINT_FACILITY) /*912*/ \ && defined(FEATURE_LOAD_AND_TRAP_FACILITY) /*912*/ \ && defined(FEATURE_MISC_INSTRUCTION_EXTENSIONS_FACILITY) /*912*/ \ && defined(FEATURE_PROCESSOR_ASSIST_FACILITY) /*912*/ | STFL_6_MISC_INST_EXT /*912*/ #endif /*912*/ #if defined(FEATURE_TRANSACTIONAL_EXECUTION_FACILITY) /*912*/ | STFL_6_CONSTRAINED_TEF /*912*/ #endif /*defined(FEATURE_TRANSACTIONAL_EXECUTION_FACILITY)*/ /*912*/ #if defined(FEATURE_LOCAL_TLB_CLEARING_FACILITY) /*912*/ | STFL_6_LOCAL_TLB_CLEAR /*912*/ #endif /*defined(FEATURE_LOCAL_TLB_CLEARING_FACILITY)*/ /*912*/ #if defined(FEATURE_INTERLOCKED_ACCESS_FACILITY_2) /*912*/ | STFL_6_INTERLOCK_ACC_2 /*912*/ #endif /*defined(FEATURE_INTERLOCKED_ACCESS_FACILITY_2)*/ /*912*/ , 0 , 0 #if defined(FEATURE_FAST_BCR_SERIALIZATION_FACILITY) /*810*/ | STFL_5_FAST_BCR_SERIAL /*810*/ #endif /*defined(FEATURE_FAST_BCR_SERIALIZATION_FACILITY)*/ /*810*/ #if defined(FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY) | STFL_8_CPU_MEAS_COUNTER #endif /*defined(FEATURE_CPU_MEASUREMENT_COUNTER_FACILITY)*/ #if defined(FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY) | STFL_8_CPU_MEAS_SAMPLNG #endif /*defined(FEATURE_CPU_MEASUREMENT_SAMPLING_FACILITY)*/ , 0 #if defined(FEATURE_TRANSACTIONAL_EXECUTION_FACILITY) /*912*/ | STFL_9_TRANSACT_EXEC /*912*/ #endif /*defined(FEATURE_TRANSACTIONAL_EXECUTION_FACILITY)*/ /*912*/ #if defined(FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION) /*810*/ | STFL_9_ACC_EX_FS_INDIC /*810*/ #endif /*defined(FEATURE_ACCESS_EXCEPTION_FETCH_STORE_INDICATION)*/ #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) /*810*/ | STFL_9_MSA_EXTENSION_3 /*810*/ #endif /*defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3)*/ /*810*/ #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) /*810*/ | STFL_9_MSA_EXTENSION_4 /*810*/ #endif /*defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4)*/ /*810*/ #if defined(FEATURE_ENHANCED_DAT_FACILITY_2) /*912*/ | STFL_9_ENHANCED_DAT_2 /*912*/ #endif /*defined(FEATURE_ENHANCED_DAT_FACILITY_2)*/ /*912*/ , 0 , 0 , 0 , 0 , 0 , 0 }; /*-------------------------------------------------------------------*/ /* Adjust the facility list to account for runtime options */ /*-------------------------------------------------------------------*/ BYTE * ARCH_DEP(adjust_stfl_data) (int *data_len, REGS *regs) { int stfl_len; /* Length of STFL data */ BYTE *stfl_data; /* -> STFL data being modified. Depends upon */ /* installed architecture, but not the current */ /* architecture mode being executed. */ /* ARCH_DEP is unreliable choice for STFL data */ /* post IPL of a z/Architecture machine but */ /* before the CPU has been placed in */ /* in z/Architecture mode. In this case, */ /* ARCH_DEP selects ESA/390 STFL data which is */ /* incomplete when z/Architecture is installed. */ /* This creates problems for OS's that expect to */ /* detect z/Architecture features before */ /* entering z/Architecture mode and only find */ /* ESA/390 features. */ if (sysblk.arch_z900) { /* 'ARCHMODE z/Arch' in configuration (or console configured) */ /* Locate the STFL data for a z/Architecture system */ stfl_data=get_stfl_data(ARCH_900, &stfl_len); /* A little overkill, but deals with the possible corner case */ if (!stfl_data) { stfl_len=sizeof(ARCH_DEP(stfl_data)); stfl_data=&ARCH_DEP(stfl_data)[0]; } stfl_data[0] |= STFL_0_ESAME_INSTALLED; /* Set whether z/Arch is active based upon CPU mode */ if (regs->arch_mode == ARCH_900) stfl_data[0] |= STFL_0_ESAME_ACTIVE; else stfl_data[0] &= ~STFL_0_ESAME_ACTIVE; } else { /* 'ARCHMODE ESA/390' in configuration (or console configured) */ /* Locate the STFL data for an ESA/390 system */ stfl_data=get_stfl_data(ARCH_390, &stfl_len); /* Same overkill, but just in case */ if (!stfl_data) { stfl_len=sizeof(ARCH_DEP(stfl_data)); stfl_data=&ARCH_DEP(stfl_data)[0]; } stfl_data[0] &= ~STFL_0_ESAME_INSTALLED; stfl_data[0] &= ~STFL_0_ESAME_ACTIVE; } #if defined(FEATURE_MESSAGE_SECURITY_ASSIST) /* MSA is enabled only if the dyncrypt DLL module is loaded */ if (ARCH_DEP(cipher_message)) { stfl_data[2] |= STFL_2_MSG_SECURITY; #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 stfl_data[9] |= STFL_9_MSA_EXTENSION_3; #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 stfl_data[9] |= STFL_9_MSA_EXTENSION_4; #endif } else { stfl_data[2] &= ~(STFL_2_MSG_SECURITY); #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 stfl_data[9] &= ~(STFL_9_MSA_EXTENSION_3); #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 stfl_data[9] &= ~(STFL_9_MSA_EXTENSION_4); #endif } #endif /*defined(FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(_FEATURE_ASN_AND_LX_REUSE) /* ALRF enablement is an option in the configuration file */ if(sysblk.asnandlxreuse) stfl_data[0] |= STFL_0_ASN_LX_REUSE; else stfl_data[0] &= ~STFL_0_ASN_LX_REUSE; #endif /*defined(FEATURE_ASN_AND_LX_REUSE)*/ *data_len=stfl_len; return stfl_data; } /* end ARCH_DEP(adjust_stfl_data) */ /*-------------------------------------------------------------------*/ /* B2B1 STFL - Store Facility List [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_facility_list) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int data_len; /* Size of STFL data */ /* Note: data_len not used here, but STFLE needs it */ PSA *psa; /* -> Prefixed storage area */ BYTE *stfl_data; /* -> STFL data */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); #if defined(_FEATURE_SIE) if(SIE_STATB(regs,IC0, STFL)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ SIE_INTERCEPT(regs); PTT(PTT_CL_INF,"STFL",b2,(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L); /* Adjust the facility list to account for runtime options */ stfl_data = ARCH_DEP(adjust_stfl_data)(&data_len, regs); #if 0 logmsg ("store_facility_list STFL data length %i\n",data_len); logmsg ("STFL=%2.2X %2.2X %2.2X %2.2X\n", *stfl_data,*(stfl_data+1),*(stfl_data+2),*(stfl_data+3)); #endif /* Set the main storage reference and change bits */ STORAGE_KEY(regs->PX, regs) |= (STORKEY_REF | STORKEY_CHANGE); /* Point to PSA in main storage */ psa = (void*)(regs->mainstor + regs->PX); memcpy(psa->stfl, stfl_data, sizeof(psa->stfl)); } /* end DEF_INST(store_facility_list) */ #if defined(FEATURE_STORE_FACILITY_LIST_EXTENDED) /*-------------------------------------------------------------------*/ /* B2B0 STFLE - Store Facility List Extended [S] */ /*-------------------------------------------------------------------*/ DEF_INST(store_facility_list_extended) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int data_len; /* Size of STFL data */ int nmax; /* #of doublewords defined */ int ndbl; /* #of doublewords to store */ int cc; /* Condition code */ BYTE *stfl_data; /* -> STFL data */ S(inst, regs, b2, effective_addr2); #if defined(_FEATURE_SIE) if(SIE_STATB(regs,IC0, STFL)) longjmp(regs->progjmp, SIE_INTERCEPT_INST); #endif /*defined(_FEATURE_SIE)*/ PTT(PTT_CL_INF,"STFLE",regs->GR_L(0),(U32)(effective_addr2 & 0xffffffff),regs->psw.IA_L); /* Note: STFLE is NOT a privileged instruction (unlike STFL) */ DW_CHECK(effective_addr2, regs); /* Adjust the facility list to account for runtime options */ stfl_data = ARCH_DEP(adjust_stfl_data)(&data_len, regs); /* Calculate number of doublewords of facilities defined */ nmax = (data_len+7) / 8; /* Obtain operand length from register 0 bits 56-63 */ ndbl = regs->GR_LHLCL(0) + 1; /* Check if operand length is sufficient */ if (ndbl >= nmax) { ndbl = nmax; cc = 0; } else { PTT(PTT_CL_ERR,"*STFLE", ndbl, nmax, regs->psw.IA_L); cc = 3; } /* Store facility list at operand location */ ARCH_DEP(vstorec) ( stfl_data, ndbl*8-1, effective_addr2, b2, regs ); /* Save number of doublewords minus 1 into register 0 bits 56-63 */ regs->GR_LHLCL(0) = (BYTE)(nmax - 1); /* Set condition code */ regs->psw.cc = cc; } /* end DEF_INST(store_facility_list_extended) */ #endif /*defined(FEATURE_STORE_FACILITY_LIST_EXTENDED)*/ #endif /*defined(FEATURE_STORE_FACILITY_LIST) */ #if defined(FEATURE_LOAD_REVERSED) && defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B90F LRVGR - Load Reversed Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_reversed_long_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy second operand to first operand */ regs->GR_G(r1) = bswap_64(regs->GR_G(r2)); } /* end DEF_INST(load_reversed_long_register) */ #endif /*defined(FEATURE_LOAD_REVERSED) && defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED) /*-------------------------------------------------------------------*/ /* B91F LRVR - Load Reversed Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_reversed_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Copy second operand to first operand */ regs->GR_L(r1) = bswap_32(regs->GR_L(r2)); } /* end DEF_INST(load_reversed_register) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED)*/ #if defined(FEATURE_LOAD_REVERSED) && defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E30F LRVG - Load Reversed Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_reversed_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = bswap_64(ARCH_DEP(vfetch8) ( effective_addr2, b2, regs )); } /* end DEF_INST(load_reversed_long) */ #endif /*defined(FEATURE_LOAD_REVERSED) && defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED) /*-------------------------------------------------------------------*/ /* E31E LRV - Load Reversed [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_reversed) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_L(r1) = bswap_32(ARCH_DEP(vfetch4) ( effective_addr2, b2, regs )); } /* end DEF_INST(load_reversed) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED) /*-------------------------------------------------------------------*/ /* E31F LRVH - Load Reversed Half [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_reversed_half) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_LHL(r1) = bswap_16(ARCH_DEP(vfetch2) ( effective_addr2, b2, regs )); } /* end DEF_INST(load_reversed_half) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED)*/ #if defined(FEATURE_LOAD_REVERSED) && defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* E32F STRVG - Store Reversed Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_reversed_long) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store register contents at operand address */ ARCH_DEP(vstore8) ( bswap_64(regs->GR_G(r1)), effective_addr2, b2, regs ); } /* end DEF_INST(store_reversed_long) */ #endif /*defined(FEATURE_LOAD_REVERSED) && defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED) /*-------------------------------------------------------------------*/ /* E33E STRV - Store Reversed [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_reversed) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store register contents at operand address */ ARCH_DEP(vstore4) ( bswap_32(regs->GR_L(r1)), effective_addr2, b2, regs ); } /* end DEF_INST(store_reversed) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED)*/ #if defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED) /*-------------------------------------------------------------------*/ /* E33F STRVH - Store Reversed Half [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_reversed_half) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store register contents at operand address */ ARCH_DEP(vstore2) ( bswap_16(regs->GR_LHL(r1)), effective_addr2, b2, regs ); } /* end DEF_INST(store_reversed_half) */ #endif /*defined(FEATURE_ESAME_N3_ESA390) || defined(FEATURE_LOAD_REVERSED)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* E9 PKA - Pack ASCII [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(pack_ascii) { int len; /* Second operand length */ int b1, b2; /* Base registers */ VADR addr1, addr2; /* Effective addresses */ BYTE source[33]; /* 32 digits + implied sign */ BYTE result[16]; /* 31-digit packed result */ int i, j; /* Array subscripts */ SS_L(inst, regs, len, b1, addr1, b2, addr2); /* Program check if operand length (len+1) exceeds 32 bytes */ if (len > 31) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Fetch the second operand and right justify */ memset (source, 0, sizeof(source)); ARCH_DEP(vfetchc) ( source+31-len, len, addr2, b2, regs ); /* Append an implied plus sign */ source[32] = 0x0C; /* Pack the rightmost 31 digits and sign into the result */ for (i = 1, j = 0; j < 16; i += 2, j++) { result[j] = (source[i] << 4) | (source[i+1] & 0x0F); } /* Store 16-byte packed decimal result at operand address */ ARCH_DEP(vstorec) ( result, 16-1, addr1, b1, regs ); } /* end DEF_INST(pack_ascii) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* E1 PKU - Pack Unicode [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(pack_unicode) { int len; /* Second operand length */ int b1, b2; /* Base registers */ VADR addr1, addr2; /* Effective addresses */ BYTE source[66]; /* 32 digits + implied sign */ BYTE result[16]; /* 31-digit packed result */ int i, j; /* Array subscripts */ SS_L(inst, regs, len, b1, addr1, b2, addr2); /* Program check if byte count (len+1) exceeds 64 or is odd */ if (len > 63 || (len & 1) == 0) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Fetch the second operand and right justify */ memset (source, 0, sizeof(source)); ARCH_DEP(vfetchc) ( source+63-len, len, addr2, b2, regs ); /* Append an implied plus sign */ source[64] = 0x00; source[65] = 0x0C; /* Pack the rightmost 31 digits and sign into the result */ for (i = 2, j = 0; j < 16; i += 4, j++) { result[j] = (source[i+1] << 4) | (source[i+3] & 0x0F); } /* Store 16-byte packed decimal result at operand address */ ARCH_DEP(vstorec) ( result, 16-1, addr1, b1, regs ); } /* end DEF_INST(pack_unicode) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* EA UNPKA - Unpack ASCII [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(unpack_ascii) { int len; /* First operand length */ int b1, b2; /* Base registers */ VADR addr1, addr2; /* Effective addresses */ BYTE result[32]; /* 32-digit result */ BYTE source[16]; /* 31-digit packed operand */ int i, j; /* Array subscripts */ int cc; /* Condition code */ SS_L(inst, regs, len, b1, addr1, b2, addr2); /* Program check if operand length (len+1) exceeds 32 bytes */ if (len > 31) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Fetch the 16-byte second operand */ ARCH_DEP(vfetchc) ( source, 15, addr2, b2, regs ); /* Set high-order result byte to ASCII zero */ result[0] = 0x30; /* Unpack remaining 31 digits into the result */ for (j = 1, i = 0; ; i++) { result[j++] = (source[i] >> 4) | 0x30; if (i == 15) break; result[j++] = (source[i] & 0x0F) | 0x30; } /* Store rightmost digits of result at first operand address */ ARCH_DEP(vstorec) ( result+31-len, len, addr1, b1, regs ); /* Set the condition code according to the sign */ switch (source[15] & 0x0F) { case 0x0A: case 0x0C: case 0x0E: case 0x0F: cc = 0; break; case 0x0B: case 0x0D: cc = 1; break; default: cc = 3; } /* end switch */ regs->psw.cc = cc; } /* end DEF_INST(unpack_ascii) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* E2 UNPKU - Unpack Unicode [SS] */ /*-------------------------------------------------------------------*/ DEF_INST(unpack_unicode) { int len; /* First operand length */ int b1, b2; /* Base registers */ VADR addr1, addr2; /* Effective addresses */ BYTE result[64]; /* 32-digit result */ BYTE source[16]; /* 31-digit packed operand */ int i, j; /* Array subscripts */ int cc; /* Condition code */ SS_L(inst, regs, len, b1, addr1, b2, addr2); /* Program check if byte count (len+1) exceeds 64 or is odd */ if (len > 63 || (len & 1) == 0) regs->program_interrupt (regs, PGM_SPECIFICATION_EXCEPTION); /* Fetch the 16-byte second operand */ ARCH_DEP(vfetchc) ( source, 15, addr2, b2, regs ); /* Set high-order result pair to Unicode zero */ result[0] = 0x00; result[1] = 0x30; /* Unpack remaining 31 digits into the result */ for (j = 2, i = 0; ; i++) { result[j++] = 0x00; result[j++] = (source[i] >> 4) | 0x30; if (i == 15) break; result[j++] = 0x00; result[j++] = (source[i] & 0x0F) | 0x30; } /* Store rightmost digits of result at first operand address */ ARCH_DEP(vstorec) ( result+63-len, len, addr1, b1, regs ); /* Set the condition code according to the sign */ switch (source[15] & 0x0F) { case 0x0A: case 0x0C: case 0x0E: case 0x0F: cc = 0; break; case 0x0B: case 0x0D: cc = 1; break; default: cc = 3; } /* end switch */ regs->psw.cc = cc; } /* end DEF_INST(unpack_unicode) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* B993 TROO - Translate One to One [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_one_to_one) { int r1, r2; /* Values of R fields */ VADR addr1, addr2, trtab; /* Effective addresses */ GREG len; BYTE svalue, dvalue, tvalue; #ifdef FEATURE_ETF2_ENHANCEMENT int tccc; /* Test-Character-Comparison Control */ #endif // NOTE: it's faster to decode with RRE format // and then to handle the 'tccc' flag separately... // RRF_M(inst, regs, r1, r2, tccc); RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Set Test-Character-Comparison Control */ if(inst[2] & 0x10) tccc = 1; else tccc = 0; #endif /* Determine length */ len = GR_A(r1 + 1,regs); /* Determine destination, source and translate table address */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); trtab = regs->GR(1) & ADDRESS_MAXWRAP(regs) & ~7; /* Determine test value */ tvalue = regs->GR_LHLCL(0); /* Preset condition code to zero in case of zero length */ if(!len) regs->psw.cc = 0; while(len) { svalue = ARCH_DEP(vfetchb) (addr2, r2, regs); /* Fetch value from translation table */ dvalue = ARCH_DEP(vfetchb) (((trtab + svalue) & ADDRESS_MAXWRAP(regs) ), 1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Test-Character-Comparison Control */ if(!tccc) { #endif /* If the testvalue was found then exit with cc1 */ if(dvalue == tvalue) { regs->psw.cc = 1; break; } #ifdef FEATURE_ETF2_ENHANCEMENT } #endif /* Store destination value */ ARCH_DEP(vstoreb) (dvalue, addr1, r1, regs); /* Adjust source addr, destination addr and length */ addr1++; addr1 &= ADDRESS_MAXWRAP(regs); addr2++; addr2 &= ADDRESS_MAXWRAP(regs); len--; /* Update the registers */ SET_GR_A(r1, regs, addr1); SET_GR_A(r1 + 1, regs, len); SET_GR_A(r2, regs, addr2); /* Set cc0 when all values have been processed */ regs->psw.cc = len ? 3 : 0; /* exit on the cpu determined number of bytes */ if((len != 0) && (!(addr1 & 0xfff) || !(addr2 & 0xfff))) break; } /* end while */ } /* end DEF_INST(translate_one_to_one) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* B992 TROT - Translate One to Two [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_one_to_two) { int r1, r2; /* Values of R fields */ VADR addr1, addr2, trtab; /* Effective addresses */ GREG len; BYTE svalue; U16 dvalue, tvalue; #ifdef FEATURE_ETF2_ENHANCEMENT int tccc; /* Test-Character-Comparison Control */ #endif // NOTE: it's faster to decode with RRE format // and then to handle the 'tccc' flag separately... // RRF_M(inst, regs, r1, r2, tccc); RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Set Test-Character-Comparison Control */ if(inst[2] & 0x10) tccc = 1; else tccc = 0; #endif /* Determine length */ len = GR_A(r1 + 1,regs); /* Determine destination, source and translate table address */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); trtab = regs->GR(1) & ADDRESS_MAXWRAP(regs) & ~7; /* Determine test value */ tvalue = regs->GR_LHL(0); /* Preset condition code to zero in case of zero length */ if(!len) regs->psw.cc = 0; while(len) { svalue = ARCH_DEP(vfetchb) (addr2, r2, regs); /* Fetch value from translation table */ dvalue = ARCH_DEP(vfetch2) (((trtab + (svalue << 1)) & ADDRESS_MAXWRAP(regs) ), 1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Test-Character-Comparison Control */ if(!tccc) { #endif /* If the testvalue was found then exit with cc1 */ if(dvalue == tvalue) { regs->psw.cc = 1; break; } #ifdef FEATURE_ETF2_ENHANCEMENT } #endif /* Store destination value */ ARCH_DEP(vstore2) (dvalue, addr1, r1, regs); /* Adjust source addr, destination addr and length */ addr1 += 2; addr1 &= ADDRESS_MAXWRAP(regs); addr2++; addr2 &= ADDRESS_MAXWRAP(regs); len--; /* Update the registers */ SET_GR_A(r1, regs, addr1); SET_GR_A(r1 + 1, regs, len); SET_GR_A(r2, regs, addr2); /* Set cc0 when all values have been processed */ regs->psw.cc = len ? 3 : 0; /* exit on the cpu determined number of bytes */ if((len != 0) && (!(addr1 & 0xfff) || !(addr2 & 0xfff))) break; } /* end while */ } /* end DEF_INST(translate_one_to_two) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* B991 TRTO - Translate Two to One [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_two_to_one) { int r1, r2; /* Values of R fields */ VADR addr1, addr2, trtab; /* Effective addresses */ GREG len; U16 svalue; BYTE dvalue, tvalue; #ifdef FEATURE_ETF2_ENHANCEMENT int tccc; /* Test-Character-Comparison Control */ #endif // NOTE: it's faster to decode with RRE format // and then to handle the 'tccc' flag separately... // RRF_M(inst, regs, r1, r2, tccc); RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Set Test-Character-Comparison Control */ if(inst[2] & 0x10) tccc = 1; else tccc = 0; #endif /* Determine length */ len = GR_A(r1 + 1,regs); ODD_CHECK(len, regs); /* Determine destination, source and translate table address */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); #ifdef FEATURE_ETF2_ENHANCEMENT trtab = regs->GR(1) & ADDRESS_MAXWRAP(regs) & ~7; #else trtab = regs->GR(1) & ADDRESS_MAXWRAP(regs) & ~0xfff; #endif /* Determine test value */ tvalue = regs->GR_LHLCL(0); /* Preset condition code to zero in case of zero length */ if(!len) regs->psw.cc = 0; while(len) { svalue = ARCH_DEP(vfetch2) (addr2, r2, regs); /* Fetch value from translation table */ dvalue = ARCH_DEP(vfetchb) (((trtab + svalue) & ADDRESS_MAXWRAP(regs) ), 1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Test-Character-Comparison Control */ if(!tccc) { #endif /* If the testvalue was found then exit with cc1 */ if(dvalue == tvalue) { regs->psw.cc = 1; break; } #ifdef FEATURE_ETF2_ENHANCEMENT } #endif /* Store destination value */ ARCH_DEP(vstoreb) (dvalue, addr1, r1, regs); /* Adjust source addr, destination addr and length */ addr1++; addr1 &= ADDRESS_MAXWRAP(regs); addr2 += 2; addr2 &= ADDRESS_MAXWRAP(regs); len -= 2; /* Update the registers */ SET_GR_A(r1, regs, addr1); SET_GR_A(r1 + 1, regs, len); SET_GR_A(r2, regs, addr2); /* Set cc0 when all values have been processed */ regs->psw.cc = len ? 3 : 0; /* exit on the cpu determined number of bytes */ if((len != 0) && (!(addr1 & 0xfff) || !(addr2 & 0xfff))) break; } /* end while */ } /* end DEF_INST(translate_two_to_one) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* B990 TRTT - Translate Two to Two [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(translate_two_to_two) { int r1, r2; /* Values of R fields */ VADR addr1, addr2, trtab; /* Effective addresses */ GREG len; U16 svalue, dvalue, tvalue; #ifdef FEATURE_ETF2_ENHANCEMENT int tccc; /* Test-Character-Comparison Control */ #endif // NOTE: it's faster to decode with RRE format // and then to handle the 'tccc' flag separately... // RRF_M(inst, regs, r1, r2, tccc); RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Set Test-Character-Comparison Control */ if(inst[2] & 0x10) tccc = 1; else tccc = 0; #endif /* Determine length */ len = GR_A(r1 + 1,regs); ODD_CHECK(len, regs); /* Determine destination, source and translate table address */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr2 = regs->GR(r2) & ADDRESS_MAXWRAP(regs); #ifdef FEATURE_ETF2_ENHANCEMENT trtab = regs->GR(1) & ADDRESS_MAXWRAP(regs) & ~7; #else trtab = regs->GR(1) & ADDRESS_MAXWRAP(regs) & ~0xfff; #endif /* Determine test value */ tvalue = regs->GR_LHL(0); /* Preset condition code to zero in case of zero length */ if(!len) regs->psw.cc = 0; while(len) { svalue = ARCH_DEP(vfetch2) (addr2, r2, regs); /* Fetch value from translation table */ dvalue = ARCH_DEP(vfetch2) (((trtab + (svalue << 1)) & ADDRESS_MAXWRAP(regs) ), 1, regs); #ifdef FEATURE_ETF2_ENHANCEMENT /* Test-Character-Comparison Control */ if(!tccc) { #endif /* If the testvalue was found then exit with cc1 */ if(dvalue == tvalue) { regs->psw.cc = 1; break; } #ifdef FEATURE_ETF2_ENHANCEMENT } #endif /* Store destination value */ ARCH_DEP(vstore2) (dvalue, addr1, r1, regs); /* Adjust source addr, destination addr and length */ addr1 += 2; addr1 &= ADDRESS_MAXWRAP(regs); addr2 += 2; addr2 &= ADDRESS_MAXWRAP(regs); len -= 2; /* Update the registers */ SET_GR_A(r1, regs, addr1); SET_GR_A(r1 + 1, regs, len); SET_GR_A(r2, regs, addr2); /* Set cc0 when all values have been processed */ regs->psw.cc = len ? 3 : 0; /* exit on the cpu determined number of bytes */ if((len != 0) && (!(addr1 & 0xfff) || !(addr2 & 0xfff))) break; } /* end while */ } /* end DEF_INST(translate_two_to_two) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* EB8E MVCLU - Move Long Unicode [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(move_long_unicode) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Loop counter */ int cc; /* Condition code */ VADR addr1, addr3; /* Operand addresses */ GREG len1, len3; /* Operand lengths */ U16 odbyte; /* Operand double byte */ U16 pad; /* Padding double byte */ int cpu_length; /* cpu determined length */ RSY(inst, regs, r1, r3, b2, effective_addr2); ODD2_CHECK(r1, r3, regs); /* Load operand lengths from bits 0-31 of R1+1 and R3+1 */ len1 = GR_A(r1 + 1, regs); len3 = GR_A(r3 + 1, regs); ODD2_CHECK(len1, len3, regs); /* Load padding doublebyte from bits 48-63 of effective address */ pad = effective_addr2 & 0xFFFF; /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr3 = regs->GR(r3) & ADDRESS_MAXWRAP(regs); /* set cpu_length as shortest distance to new page */ if ((addr1 & 0xFFF) > (addr3 & 0xFFF)) cpu_length = 0x1000 - (addr1 & 0xFFF); else cpu_length = 0x1000 - (addr3 & 0xFFF); /* Set the condition code according to the lengths */ cc = (len1 < len3) ? 1 : (len1 > len3) ? 2 : 0; /* Process operands from left to right */ for (i = 0; len1 > 0; i += 2) { /* If cpu determined length has been moved, exit with cc=3 */ if (i >= cpu_length) { cc = 3; break; } /* Fetch byte from source operand, or use padding double byte */ if (len3 > 0) { odbyte = ARCH_DEP(vfetch2) ( addr3, r3, regs ); addr3 += 2; addr3 &= ADDRESS_MAXWRAP(regs); len3 -= 2; } else odbyte = pad; /* Store the double byte in the destination operand */ ARCH_DEP(vstore2) ( odbyte, addr1, r1, regs ); addr1 +=2; addr1 &= ADDRESS_MAXWRAP(regs); len1 -= 2; /* Update the registers */ SET_GR_A(r1, regs, addr1); SET_GR_A(r1 + 1, regs, len1); SET_GR_A(r3, regs, addr3); SET_GR_A(r3 + 1, regs, len3); } /* end for(i) */ regs->psw.cc = cc; } /* end DEF_INST(move_long_unicode) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2) /*-------------------------------------------------------------------*/ /* EB8F CLCLU - Compare Logical Long Unicode [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_long_unicode) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Loop counter */ int cc = 0; /* Condition code */ VADR addr1, addr3; /* Operand addresses */ GREG len1, len3; /* Operand lengths */ U16 dbyte1, dbyte3; /* Operand double bytes */ U16 pad; /* Padding double byte */ int cpu_length; /* cpu determined length */ RSY(inst, regs, r1, r3, b2, effective_addr2); ODD2_CHECK(r1, r3, regs); /* Load operand lengths from bits 0-31 of R1+1 and R3+1 */ len1 = GR_A(r1 + 1, regs); len3 = GR_A(r3 + 1, regs); ODD2_CHECK(len1, len3, regs); /* Load padding doublebyte from bits 48-64 of effective address */ pad = effective_addr2 & 0xFFFF; /* Determine the destination and source addresses */ addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs); addr3 = regs->GR(r3) & ADDRESS_MAXWRAP(regs); /* set cpu_length as shortest distance to new page */ if ((addr1 & 0xFFF) > (addr3 & 0xFFF)) cpu_length = 0x1000 - (addr1 & 0xFFF); else cpu_length = 0x1000 - (addr3 & 0xFFF); /* Process operands from left to right */ for (i = 0; len1 > 0 || len3 > 0 ; i += 2) { /* If max 4096 bytes have been compared, exit with cc=3 */ if (i >= cpu_length) { cc = 3; break; } /* Fetch a byte from each operand, or use padding double byte */ dbyte1 = (len1 > 0) ? ARCH_DEP(vfetch2) (addr1, r1, regs) : pad; dbyte3 = (len3 > 0) ? ARCH_DEP(vfetch2) (addr3, r3, regs) : pad; /* Compare operand bytes, set condition code if unequal */ if (dbyte1 != dbyte3) { cc = (dbyte1 < dbyte3) ? 1 : 2; break; } /* end if */ /* Update the first operand address and length */ if (len1 > 0) { addr1 += 2; addr1 &= ADDRESS_MAXWRAP(regs); len1 -= 2; } /* Update the second operand address and length */ if (len3 > 0) { addr3 += 2; addr3 &= ADDRESS_MAXWRAP(regs); len3 -= 2; } } /* end for(i) */ /* Update the registers */ SET_GR_A(r1, regs, addr1); SET_GR_A(r1 + 1, regs, len1); SET_GR_A(r3, regs, addr3); SET_GR_A(r3 + 1, regs, len3); regs->psw.cc = cc; } /* end DEF_INST(compare_logical_long_unicode) */ #endif /*defined(FEATURE_EXTENDED_TRANSLATION_FACILITY_2)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E376 LB - Load Byte [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_byte) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load sign-extended byte from operand address */ regs->GR_L(r1) = (S8)ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_byte) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E377 LGB - Load Byte Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_byte_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load sign-extended byte from operand address */ regs->GR_G(r1) = (S8)ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_byte_long) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E35A AY - Add (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_y) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r1), n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E37A AHY - Add Halfword (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_halfword_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load 2 bytes from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r1), (U32)n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_halfword_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E35E ALY - Add Logical (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Add signed operands and set condition code */ regs->psw.cc = add_logical (&(regs->GR_L(r1)), regs->GR_L(r1), n); } /* end DEF_INST(add_logical_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB54 NIY - And Immediate (Long Displacement) [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate_y) { BYTE i2; /* Immediate byte of opcode */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE rbyte; /* Result byte */ SIY(inst, regs, i2, b1, effective_addr1); /* Fetch byte from operand address */ rbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* AND with immediate operand */ rbyte &= i2; /* Store result at operand address */ ARCH_DEP(vstoreb) ( rbyte, effective_addr1, b1, regs ); /* Set condition code */ regs->psw.cc = rbyte ? 1 : 0; } /* end DEF_INST(and_immediate_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E354 NY - And (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(and_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* AND second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) &= n ) ? 1 : 0; } /* end DEF_INST(and_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E359 CY - Compare (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_y) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < (S32)n ? 1 : (S32)regs->GR_L(r1) > (S32)n ? 2 : 0; } /* end DEF_INST(compare_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E379 CHY - Compare Halfword (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_halfword_y) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load rightmost 2 bytes of comparand from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < n ? 1 : (S32)regs->GR_L(r1) > n ? 2 : 0; } /* end DEF_INST(compare_halfword_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E355 CLY - Compare Logical (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_y) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_L(r1) < n ? 1 : regs->GR_L(r1) > n ? 2 : 0; } /* end DEF_INST(compare_logical_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB55 CLIY - Compare Logical Immediate (Long Displacement) [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_immediate_y) { BYTE i2; /* Immediate byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE cbyte; /* Compare byte */ SIY(inst, regs, i2, b1, effective_addr1); /* Fetch byte from operand address */ cbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* Compare with immediate operand and set condition code */ regs->psw.cc = (cbyte < i2) ? 1 : (cbyte > i2) ? 2 : 0; } /* end DEF_INST(compare_logical_immediate_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB21 CLMY - Compare Logical Characters under Mask Long Disp[RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_characters_under_mask_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, j; /* Integer work areas */ int cc = 0; /* Condition code */ BYTE rbyte[4], /* Register bytes */ vbyte; /* Virtual storage byte */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Set register bytes by mask */ i = 0; if (r3 & 0x8) rbyte[i++] = (regs->GR_L(r1) >> 24) & 0xFF; if (r3 & 0x4) rbyte[i++] = (regs->GR_L(r1) >> 16) & 0xFF; if (r3 & 0x2) rbyte[i++] = (regs->GR_L(r1) >> 8) & 0xFF; if (r3 & 0x1) rbyte[i++] = (regs->GR_L(r1) ) & 0xFF; /* Perform access check if mask is 0 */ if (!r3) ARCH_DEP(vfetchb) (effective_addr2, b2, regs); /* Compare byte by byte */ for (j = 0; j < i && !cc; j++) { effective_addr2 &= ADDRESS_MAXWRAP(regs); vbyte = ARCH_DEP(vfetchb) (effective_addr2++, b2, regs); if (rbyte[j] != vbyte) cc = rbyte[j] < vbyte ? 1 : 2; } regs->psw.cc = cc; } /* end DEF_INST(compare_logical_characters_under_mask_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB14 CSY - Compare and Swap (Long Displacement) [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_swap_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ BYTE *main2; /* mainstor address */ U32 old; /* old value */ RSY(inst, regs, r1, r3, b2, effective_addr2); FW_CHECK(effective_addr2, regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Get operand mainstor address */ main2 = MADDR (effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get old value */ old = CSWAP32(regs->GR_L(r1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg4 (&old, CSWAP32(regs->GR_L(r3)), main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); if (regs->psw.cc == 1) { regs->GR_L(r1) = CSWAP32(old); #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC0, CS1)) { if( !OPEN_IC_PER(regs) ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else longjmp(regs->progjmp, SIE_INTERCEPT_INSTCOMP); } else #endif /*defined(_FEATURE_SIE)*/ if (sysblk.cpus > 1) sched_yield(); } } /* end DEF_INST(compare_and_swap_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB31 CDSY - Compare Double and Swap (Long Displacement) [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_double_and_swap_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ BYTE *main2; /* mainstor address */ U64 old, new; /* old, new values */ RSY(inst, regs, r1, r3, b2, effective_addr2); ODD2_CHECK(r1, r3, regs); DW_CHECK(effective_addr2, regs); /* Perform serialization before starting operation */ PERFORM_SERIALIZATION (regs); /* Get operand mainstor address */ main2 = MADDR (effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get old, new values */ old = CSWAP64(((U64)(regs->GR_L(r1)) << 32) | regs->GR_L(r1+1)); new = CSWAP64(((U64)(regs->GR_L(r3)) << 32) | regs->GR_L(r3+1)); /* Obtain main-storage access lock */ OBTAIN_MAINLOCK(regs); /* Attempt to exchange the values */ regs->psw.cc = cmpxchg8 (&old, new, main2); /* Release main-storage access lock */ RELEASE_MAINLOCK(regs); /* Perform serialization after completing operation */ PERFORM_SERIALIZATION (regs); if (regs->psw.cc == 1) { regs->GR_L(r1) = CSWAP64(old) >> 32; regs->GR_L(r1+1) = CSWAP64(old) & 0xffffffff; #if defined(_FEATURE_SIE) if(SIE_STATB(regs, IC0, CS1)) { if( !OPEN_IC_PER(regs) ) longjmp(regs->progjmp, SIE_INTERCEPT_INST); else longjmp(regs->progjmp, SIE_INTERCEPT_INSTCOMP); } else #endif /*defined(_FEATURE_SIE)*/ if (sysblk.cpus > 1) sched_yield(); } } /* end DEF_INST(compare_double_and_swap_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E306 CVBY - Convert to Binary (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_to_binary_y) { U64 dreg; /* 64-bit result accumulator */ int r1; /* Value of R1 field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ int ovf; /* 1=overflow */ int dxf; /* 1=data exception */ BYTE dec[8]; /* Packed decimal operand */ RXY(inst, regs, r1, b2, effective_addr2); /* Fetch 8-byte packed decimal operand */ ARCH_DEP(vfetchc) (dec, 8-1, effective_addr2, b2, regs); /* Convert 8-byte packed decimal to 64-bit signed binary */ packed_to_binary (dec, 8-1, &dreg, &ovf, &dxf); /* Data exception if invalid digits or sign */ if (dxf) { regs->dxc = DXC_DECIMAL; regs->program_interrupt (regs, PGM_DATA_EXCEPTION); } /* Overflow if result exceeds 31 bits plus sign */ if ((S64)dreg < -2147483648LL || (S64)dreg > 2147483647LL) ovf = 1; /* Store low-order 32 bits of result into R1 register */ regs->GR_L(r1) = dreg & 0xFFFFFFFF; /* Program check if overflow (R1 contains rightmost 32 bits) */ if (ovf) regs->program_interrupt (regs, PGM_FIXED_POINT_DIVIDE_EXCEPTION); } #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E326 CVDY - Convert to Decimal (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_to_decimal_y) { S64 bin; /* 64-bit signed binary value*/ int r1; /* Value of R1 field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ BYTE dec[16]; /* Packed decimal result */ RXY(inst, regs, r1, b2, effective_addr2); /* Load value of register and sign-extend to 64 bits */ bin = (S64)((S32)(regs->GR_L(r1))); /* Convert to 16-byte packed decimal number */ binary_to_packed (bin, dec); /* Store low 8 bytes of result at operand address */ ARCH_DEP(vstorec) ( dec+8, 8-1, effective_addr2, b2, regs ); } /* end DEF_INST(convert_to_decimal_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB57 XIY - Exclusive Or Immediate (Long Displacement) [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_immediate_y) { BYTE i2; /* Immediate operand */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE rbyte; /* Result byte */ SIY(inst, regs, i2, b1, effective_addr1); /* Fetch byte from operand address */ rbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* XOR with immediate operand */ rbyte ^= i2; /* Store result at operand address */ ARCH_DEP(vstoreb) ( rbyte, effective_addr1, b1, regs ); /* Set condition code */ regs->psw.cc = rbyte ? 1 : 0; } /* end DEF_INST(exclusive_or_immediate_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E357 XY - Exclusive Or (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_y) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* XOR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) ^= n ) ? 1 : 0; } /* end DEF_INST(exclusive_or_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E373 ICY - Insert Character (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_character_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Insert character in r1 register */ regs->GR_LHLCL(r1) = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /* end DEF_INST(insert_character_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB81 ICMY - Insert Characters under Mask Long Displacement [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_characters_under_mask_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Integer work area */ BYTE vbyte[4]; /* Fetched storage bytes */ U32 n; /* Fetched value */ static const int /* Length-1 to fetch by mask */ icmylen[16] = {0, 0, 0, 1, 0, 1, 1, 2, 0, 1, 1, 2, 1, 2, 2, 3}; static const unsigned int /* Turn reg bytes off by mask*/ icmymask[16] = {0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFFFF0000, 0xFF00FFFF, 0xFF00FF00, 0xFF0000FF, 0xFF000000, 0x00FFFFFF, 0x00FFFF00, 0x00FF00FF, 0x00FF0000, 0x0000FFFF, 0x0000FF00, 0x000000FF, 0x00000000}; RSY(inst, regs, r1, r3, b2, effective_addr2); switch (r3) { case 15: /* Optimized case */ regs->GR_L(r1) = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); regs->psw.cc = regs->GR_L(r1) ? regs->GR_L(r1) & 0x80000000 ? 1 : 2 : 0; break; default: memset (vbyte, 0, 4); ARCH_DEP(vfetchc)(vbyte, icmylen[r3], effective_addr2, b2, regs); /* If mask was 0 then we still had to fetch, according to POP. If so, set the fetched byte to 0 to force zero cc */ if (!r3) vbyte[0] = 0; n = fetch_fw (vbyte); regs->psw.cc = n ? n & 0x80000000 ? 1 : 2 : 0; /* Turn off the reg bytes we are going to set */ regs->GR_L(r1) &= icmymask[r3]; /* Set bytes one at a time according to the mask */ i = 0; if (r3 & 0x8) regs->GR_L(r1) |= vbyte[i++] << 24; if (r3 & 0x4) regs->GR_L(r1) |= vbyte[i++] << 16; if (r3 & 0x2) regs->GR_L(r1) |= vbyte[i++] << 8; if (r3 & 0x1) regs->GR_L(r1) |= vbyte[i]; break; } /* switch (r3) */ } /* end DEF_INST(insert_characters_under_mask_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E358 LY - Load (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_L(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* EB9A LAMY - Load Access Multiple (Long Displacement) [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_access_multiple_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2 = NULL; /* Mainstor pointers */ RSY(inst, regs, r1, r3, b2, effective_addr2); FW_CHECK(effective_addr2, regs); /* Calculate number of regs to load */ n = ((r3 - r1) & 0xF) + 1; /* Calculate number of words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 2; /* Address of operand beginning */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely (m < n)) p2 = (U32*)MADDR(effective_addr2 + (m*4), b2, regs, ACCTYPE_READ, regs->psw.pkey); else m = n; /* Load from first page */ for (i = 0; i < m; i++, p1++) { regs->AR((r1 + i) & 0xF) = fetch_fw (p1); SET_AEA_AR(regs, (r1 + i) & 0xF); } /* Load from next page */ for ( ; i < n; i++, p2++) { regs->AR((r1 + i) & 0xF) = fetch_fw (p2); SET_AEA_AR(regs, (r1 + i) & 0xF); } } /* end DEF_INST(load_access_multiple_y) */ #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E371 LAY - Load Address (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_address_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY0(inst, regs, r1, b2, effective_addr2); /* Load operand address into register */ SET_GR_A(r1, regs, effective_addr2); } /* end DEF_INST(load_address_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E378 LHY - Load Halfword (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_halfword_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load rightmost 2 bytes of register from operand address */ regs->GR_L(r1) = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_halfword_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB98 LMY - Load Multiple (Long Displacement) [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_multiple_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2; /* Mainstor pointers */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to load */ n = (((r3 - r1) & 0xF) + 1) << 2; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Address of operand beginning */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if (likely(n <= m)) { /* Boundary not crossed */ n >>= 2; for (i = 0; i < n; i++, p1++) regs->GR_L((r1 + i) & 0xF) = fetch_fw (p1); } else { /* Boundary crossed, get 2nd page address */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_READ, regs->psw.pkey); if (likely((m & 0x3) == 0)) { /* Addresses are word aligned */ m >>= 2; for (i = 0; i < m; i++, p1++) regs->GR_L((r1 + i) & 0xF) = fetch_fw (p1); n >>= 2; for ( ; i < n; i++, p2++) regs->GR_L((r1 + i) & 0xF) = fetch_fw (p2); } else { /* Worst case */ U32 rwork[16]; BYTE *b1, *b2; b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b1++ = *b2++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b1++ = *b2++; n >>= 2; for (i = 0; i < n; i++) regs->GR_L((r1 + i) & 0xF) = CSWAP32(rwork[i]); } } } /* end DEF_INST(load_multiple_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E313 LRAY - Load Real Address (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_real_address_y) { int r1; /* Register number */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); ARCH_DEP(load_real_address_proc) (regs, r1, b2, effective_addr2); } /* end DEF_INST(load_real_address_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB52 MVIY - Move Immediate (Long Displacement) [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(move_immediate_y) { BYTE i2; /* Immediate operand */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ SIY(inst, regs, i2, b1, effective_addr1); /* Store immediate operand at operand address */ ARCH_DEP(vstoreb) ( i2, effective_addr1, b1, regs ); } /* end DEF_INST(move_immediate_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E351 MSY - Multiply Single (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_single_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = (S32)ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Multiply signed operands ignoring overflow */ regs->GR_L(r1) = (S32)regs->GR_L(r1) * n; } /* end DEF_INST(multiply_single) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB56 OIY - Or Immediate (Long Displacement) [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate_y) { BYTE i2; /* Immediate operand byte */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE rbyte; /* Result byte */ SIY(inst, regs, i2, b1, effective_addr1); /* Fetch byte from operand address */ rbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* OR with immediate operand */ rbyte |= i2; /* Store result at operand address */ ARCH_DEP(vstoreb) ( rbyte, effective_addr1, b1, regs ); /* Set condition code */ regs->psw.cc = rbyte ? 1 : 0; } /* end DEF_INST(or_immediate_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E356 OY - Or (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(or_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* OR second operand with first and set condition code */ regs->psw.cc = ( regs->GR_L(r1) |= n ) ? 1 : 0; } /* end DEF_INST(or_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E350 STY - Store (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_y) { int r1; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store register contents at operand address */ ARCH_DEP(vstore4) ( regs->GR_L(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) #if defined(FEATURE_ACCESS_REGISTERS) /*-------------------------------------------------------------------*/ /* EB9B STAMY - Store Access Multiple (Long Displacement) [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_access_multiple_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work area */ U32 *p1, *p2 = NULL; /* Mainstor pointers */ RSY(inst, regs, r1, r3, b2, effective_addr2); FW_CHECK(effective_addr2, regs); /* Calculate number of regs to store */ n = ((r3 - r1) & 0xF) + 1; /* Store 4 bytes at a time */ ARCH_DEP(validate_operand)(effective_addr2, b2, (n*4) - 1, ACCTYPE_WRITE, regs); for (i = 0; i < n; i++) ARCH_DEP(vstore4)(regs->AR((r1 + i) & 0xF), effective_addr2 + (i*4), b2, regs); /* Calculate number of words to next boundary */ m = (0x800 - (effective_addr2 & 0x7ff)) >> 2; /* Address of operand beginning */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); /* Get address of next page if boundary crossed */ if (unlikely(m < n)) p2 = (U32*)MADDR(effective_addr2 + (m*4), b2, regs, ACCTYPE_WRITE, regs->psw.pkey); else m = n; /* Store at operand beginning */ for (i = 0; i < m; i++) store_fw (p1++, regs->AR((r1 + i) & 0xF)); /* Store on next page */ for ( ; i < n; i++) store_fw (p2++, regs->AR((r1 + i) & 0xF)); } /* end DEF_INST(store_access_multiple_y) */ #endif /*defined(FEATURE_ACCESS_REGISTERS)*/ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E372 STCY - Store Character (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_character_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store rightmost byte of R1 register at operand address */ ARCH_DEP(vstoreb) ( regs->GR_LHLCL(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store_character_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB2D STCMY - Store Characters under Mask (Long Displacement)[RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_characters_under_mask_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i; /* Integer work area */ BYTE rbyte[4]; /* Byte work area */ RSY(inst, regs, r1, r3, b2, effective_addr2); switch (r3) { case 15: /* Optimized case */ ARCH_DEP(vstore4) (regs->GR_L(r1), effective_addr2, b2, regs); break; default: /* Extract value from register by mask */ i = 0; if (r3 & 0x8) rbyte[i++] = (regs->GR_L(r1) >> 24) & 0xFF; if (r3 & 0x4) rbyte[i++] = (regs->GR_L(r1) >> 16) & 0xFF; if (r3 & 0x2) rbyte[i++] = (regs->GR_L(r1) >> 8) & 0xFF; if (r3 & 0x1) rbyte[i++] = (regs->GR_L(r1) ) & 0xFF; if (i) ARCH_DEP(vstorec) (rbyte, i-1, effective_addr2, b2, regs); #if defined(MODEL_DEPENDENT_STCM) /* If the mask is all zero, we nevertheless access one byte from the storage operand, because POP states that an access exception may be recognized on the first byte */ else ARCH_DEP(validate_operand) (effective_addr2, b2, 0, ACCTYPE_WRITE, regs); #endif break; } /* switch (r3) */ } /* end DEF_INST(store_characters_under_mask_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E370 STHY - Store Halfword (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_halfword_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Store rightmost 2 bytes of R1 register at operand address */ ARCH_DEP(vstore2) ( regs->GR_LHL(r1), effective_addr2, b2, regs ); } /* end DEF_INST(store_halfword_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB90 STMY - Store Multiple (Long Displacement) [RSY] */ /*-------------------------------------------------------------------*/ DEF_INST(store_multiple_y) { int r1, r3; /* Register numbers */ int b2; /* effective address base */ VADR effective_addr2; /* effective address */ int i, m, n; /* Integer work areas */ U32 *p1, *p2; /* Mainstor pointers */ RSY(inst, regs, r1, r3, b2, effective_addr2); /* Calculate number of bytes to store */ n = (((r3 - r1) & 0xF) + 1) << 2; /* Calculate number of bytes to next boundary */ m = 0x800 - ((VADR_L)effective_addr2 & 0x7ff); /* Get address of first page */ p1 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); if (likely(n <= m)) { /* boundary not crossed */ n >>= 2; for (i = 0; i < n; i++) store_fw (p1++, regs->GR_L((r1 + i) & 0xF)); } else { /* boundary crossed, get address of the 2nd page */ effective_addr2 += m; effective_addr2 &= ADDRESS_MAXWRAP(regs); p2 = (U32*)MADDR(effective_addr2, b2, regs, ACCTYPE_WRITE, regs->psw.pkey); if (likely((m & 0x3) == 0)) { /* word aligned */ m >>= 2; for (i = 0; i < m; i++) store_fw (p1++, regs->GR_L((r1 + i) & 0xF)); n >>= 2; for ( ; i < n; i++) store_fw (p2++, regs->GR_L((r1 + i) & 0xF)); } else { /* worst case */ U32 rwork[16]; BYTE *b1, *b2; for (i = 0; i < (n >> 2); i++) rwork[i] = CSWAP32(regs->GR_L((r1 + i) & 0xF)); b1 = (BYTE *)&rwork[0]; b2 = (BYTE *)p1; for (i = 0; i < m; i++) *b2++ = *b1++; b2 = (BYTE *)p2; for ( ; i < n; i++) *b2++ = *b1++; } } } /* end DEF_INST(store_multiple_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E35B SY - Subtract (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_L(r1)), regs->GR_L(r1), n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E37B SHY - Subtract Halfword (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_halfword_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load 2 bytes from operand address */ n = (S16)ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); /* Subtract signed operands and set condition code */ regs->psw.cc = sub_signed (&(regs->GR_L(r1)), regs->GR_L(r1), (U32)n); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(subtract_halfword_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* E35F SLY - Subtract Logical (Long Displacement) [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_y) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 n; /* 32-bit operand values */ RXY(inst, regs, r1, b2, effective_addr2); /* Load second operand from operand address */ n = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical (&(regs->GR_L(r1)), regs->GR_L(r1), n); } /* end DEF_INST(subtract_logical_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_LONG_DISPLACEMENT) /*-------------------------------------------------------------------*/ /* EB51 TMY - Test under Mask (Long Displacement) [SIY] */ /*-------------------------------------------------------------------*/ DEF_INST(test_under_mask_y) { BYTE i2; /* Immediate operand */ int b1; /* Base of effective addr */ VADR effective_addr1; /* Effective address */ BYTE tbyte; /* Work byte */ SIY(inst, regs, i2, b1, effective_addr1); /* Fetch byte from operand address */ tbyte = ARCH_DEP(vfetchb) ( effective_addr1, b1, regs ); /* AND with immediate operand mask */ tbyte &= i2; /* Set condition code according to result */ regs->psw.cc = ( tbyte == 0 ) ? 0 : /* result all zeroes */ ( tbyte == i2) ? 3 : /* result all ones */ 1 ; /* result mixed */ } /* end DEF_INST(test_under_mask_y) */ #endif /*defined(FEATURE_LONG_DISPLACEMENT)*/ #if defined(FEATURE_EXTENDED_IMMEDIATE) /*@Z9*/ /*-------------------------------------------------------------------*/ /* C2x9 AFI - Add Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(add_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL(inst, regs, r1, opcd, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed (&(regs->GR_L(r1)), regs->GR_L(r1), (S32)i2); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C2x8 AGFI - Add Long Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(add_long_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL(inst, regs, r1, opcd, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_signed_long (&(regs->GR_G(r1)), regs->GR_G(r1), (S32)i2); /* Program check if fixed-point overflow */ if ( regs->psw.cc == 3 && FOMASK(®s->psw) ) regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION); } /* end DEF_INST(add_long_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C2xB ALFI - Add Logical Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Add signed operands and set condition code */ regs->psw.cc = add_logical (&(regs->GR_L(r1)), regs->GR_L(r1), i2); } /* end DEF_INST(add_logical_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C2xA ALGFI - Add Logical Long Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(add_logical_long_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Add unsigned operands and set condition code */ regs->psw.cc = add_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), i2); } /* end DEF_INST(add_logical_long_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C0xA NIHF - And Immediate High Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate_high_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* And fullword operand with high 32 bits of register */ regs->GR_H(r1) &= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_H(r1) ? 1 : 0; } /* end DEF_INST(and_immediate_high_fullword) */ /*-------------------------------------------------------------------*/ /* C0xB NILF - And Immediate Low Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(and_immediate_low_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* And fullword operand with low 32 bits of register */ regs->GR_L(r1) &= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_L(r1) ? 1 : 0; } /* end DEF_INST(and_immediate_low_fullword) */ /*-------------------------------------------------------------------*/ /* C2xD CFI - Compare Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Compare signed operands and set condition code */ regs->psw.cc = (S32)regs->GR_L(r1) < (S32)i2 ? 1 : (S32)regs->GR_L(r1) > (S32)i2 ? 2 : 0; } /* end DEF_INST(compare_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C2xC CGFI - Compare Long Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_long_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Compare signed operands and set condition code */ regs->psw.cc = (S64)regs->GR_G(r1) < (S32)i2 ? 1 : (S64)regs->GR_G(r1) > (S32)i2 ? 2 : 0; } /* end DEF_INST(compare_long_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C2xF CLFI - Compare Logical Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_L(r1) < i2 ? 1 : regs->GR_L(r1) > i2 ? 2 : 0; } /* end DEF_INST(compare_logical_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C2xE CLGFI - Compare Logical Long Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_logical_long_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Compare unsigned operands and set condition code */ regs->psw.cc = regs->GR_G(r1) < i2 ? 1 : regs->GR_G(r1) > i2 ? 2 : 0; } /* end DEF_INST(compare_logical_long_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C0x6 XIHF - Exclusive Or Immediate High Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_immediate_high_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* XOR fullword operand with high 32 bits of register */ regs->GR_H(r1) ^= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_H(r1) ? 1 : 0; } /* end DEF_INST(exclusive_or_immediate_high_fullword) */ /*-------------------------------------------------------------------*/ /* C0x7 XILF - Exclusive Or Immediate Low Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(exclusive_or_immediate_low_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* XOR fullword operand with low 32 bits of register */ regs->GR_L(r1) ^= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_L(r1) ? 1 : 0; } /* end DEF_INST(exclusive_or_immediate_low_fullword) */ /*-------------------------------------------------------------------*/ /* C0x8 IIHF - Insert Immediate High Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_immediate_high_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Insert fullword operand into high 32 bits of register */ regs->GR_H(r1) = i2; } /* end DEF_INST(insert_immediate_high_fullword) */ /*-------------------------------------------------------------------*/ /* C0x9 IILF - Insert Immediate Low Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_immediate_low_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Insert fullword operand into low 32 bits of register */ regs->GR_L(r1) = i2; } /* end DEF_INST(insert_immediate_low_fullword) */ /*-------------------------------------------------------------------*/ /* C0xE LLIHF - Load Logical Immediate High Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_immediate_high_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Load fullword operand into high 32 bits of register and set remaining bits to zero */ regs->GR_H(r1) = i2; regs->GR_L(r1) = 0; } /* end DEF_INST(load_logical_immediate_high_fullword) */ /*-------------------------------------------------------------------*/ /* C0xF LLILF - Load Logical Immediate Low Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_immediate_low_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Load fullword operand into low 32 bits of register and set remaining bits to zero */ regs->GR_G(r1) = i2; } /* end DEF_INST(load_logical_immediate_low_fullword) */ /*-------------------------------------------------------------------*/ /* C0x1 LGFI - Load Long Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Load operand into register */ regs->GR_G(r1) = (S32)i2; } /* end DEF_INST(load_long_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C0xC OIHF - Or Immediate High Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate_high_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Or fullword operand with high 32 bits of register */ regs->GR_H(r1) |= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_H(r1) ? 1 : 0; } /* end DEF_INST(or_immediate_high_fullword) */ /*-------------------------------------------------------------------*/ /* C0xD OILF - Or Immediate Low Fullword [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(or_immediate_low_fullword) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Or fullword operand with low 32 bits of register */ regs->GR_L(r1) |= i2; /* Set condition code according to result */ regs->psw.cc = regs->GR_L(r1) ? 1 : 0; } /* end DEF_INST(or_immediate_low_fullword) */ /*-------------------------------------------------------------------*/ /* C2x5 SLFI - Subtract Logical Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical (&(regs->GR_L(r1)), regs->GR_L(r1), i2); } /* end DEF_INST(subtract_logical_fullword_immediate) */ /*-------------------------------------------------------------------*/ /* C2x4 SLGFI - Subtract Logical Long Fullword Immediate [RIL] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_logical_long_fullword_immediate) { int r1; /* Register number */ int opcd; /* Opcode */ U32 i2; /* 32-bit operand value */ RIL0(inst, regs, r1, opcd, i2); /* Subtract unsigned operands and set condition code */ regs->psw.cc = sub_logical_long(&(regs->GR_G(r1)), regs->GR_G(r1), i2); } /* end DEF_INST(subtract_logical_long_fullword_immediate) */ #endif /*defined(FEATURE_EXTENDED_IMMEDIATE)*/ /*@Z9*/ #if defined(FEATURE_EXTENDED_IMMEDIATE) /*@Z9*/ /*-------------------------------------------------------------------*/ /* E312 LT - Load and Test [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_L(r1) = ARCH_DEP(vfetch4) ( effective_addr2, b2, regs ); /* Set condition code according to value loaded */ regs->psw.cc = (S32)regs->GR_L(r1) < 0 ? 1 : (S32)regs->GR_L(r1) > 0 ? 2 : 0; } /* end DEF_INST(load_and_test) */ /*-------------------------------------------------------------------*/ /* E302 LTG - Load and Test Long [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); /* Load R1 register from second operand */ regs->GR_G(r1) = ARCH_DEP(vfetch8) ( effective_addr2, b2, regs ); /* Set condition code according to value loaded */ regs->psw.cc = (S64)regs->GR_G(r1) < 0 ? 1 : (S64)regs->GR_G(r1) > 0 ? 2 : 0; } /* end DEF_INST(load_and_test_long) */ /*-------------------------------------------------------------------*/ /* B926 LBR - Load Byte Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_byte_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load sign-extended byte from second register */ regs->GR_L(r1) = (S32)(S8)(regs->GR_LHLCL(r2)); } /* end DEF_INST(load_byte_register) */ /*-------------------------------------------------------------------*/ /* B906 LGBR - Load Long Byte Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_byte_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load sign-extended byte from second register */ regs->GR_G(r1) = (S64)(S8)(regs->GR_LHLCL(r2)); } /* end DEF_INST(load_long_byte_register) */ /*-------------------------------------------------------------------*/ /* B927 LHR - Load Halfword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_halfword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load sign-extended halfword from second register */ regs->GR_L(r1) = (S32)(S16)(regs->GR_LHL(r2)); } /* end DEF_INST(load_halfword_register) */ /*-------------------------------------------------------------------*/ /* B907 LGHR - Load Long Halfword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_long_halfword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load sign-extended halfword from second register */ regs->GR_G(r1) = (S64)(S16)(regs->GR_LHL(r2)); } /* end DEF_INST(load_long_halfword_register) */ /*-------------------------------------------------------------------*/ /* E394 LLC - Load Logical Character [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_character) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); regs->GR_L(r1) = ARCH_DEP(vfetchb) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_logical_character) */ /*-------------------------------------------------------------------*/ /* B994 LLCR - Load Logical Character Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_character_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load bits 56-63 from second register and clear bits 32-55 */ regs->GR_L(r1) = regs->GR_LHLCL(r2); } /* end DEF_INST(load_logical_character_register) */ /*-------------------------------------------------------------------*/ /* B984 LLGCR - Load Logical Long Character Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_character_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load bits 56-63 from second register and clear bits 0-55 */ regs->GR_G(r1) = regs->GR_LHLCL(r2); } /* end DEF_INST(load_logical_long_character_register) */ /*-------------------------------------------------------------------*/ /* E395 LLH - Load Logical Halfword [RXY] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_halfword) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ RXY(inst, regs, r1, b2, effective_addr2); regs->GR_L(r1) = ARCH_DEP(vfetch2) ( effective_addr2, b2, regs ); } /* end DEF_INST(load_logical_halfword) */ /*-------------------------------------------------------------------*/ /* B995 LLHR - Load Logical Halfword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_halfword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load bits 48-63 from second register and clear bits 32-47 */ regs->GR_L(r1) = regs->GR_LHL(r2); } /* end DEF_INST(load_logical_halfword_register) */ /*-------------------------------------------------------------------*/ /* B985 LLGHR - Load Logical Long Halfword Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_logical_long_halfword_register) { int r1, r2; /* Values of R fields */ RRE0(inst, regs, r1, r2); /* Load bits 48-63 from second register and clear bits 0-47 */ regs->GR_G(r1) = regs->GR_LHL(r2); } /* end DEF_INST(load_logical_long_halfword_register) */ /*-------------------------------------------------------------------*/ /* B983 FLOGR - Find Leftmost One Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(find_leftmost_one_long_register) { int r1, r2; /* Values of R fields */ U64 op; /* R2 contents */ U64 mask; /* Bit mask for leftmost one */ int n; /* Position of leftmost one */ RRE(inst, regs, r1, r2); ODD_CHECK(r1, regs); /* Load contents of second register */ op = regs->GR_G(r2); /* If R2 contents is all zero, set R1 register to 64, set R1+1 register to zero, and return cond code 0 */ if (op == 0) { regs->GR_G(r1) = 64; regs->GR_G(r1+1) = 0; regs->psw.cc = 0; } else { /* Find leftmost one */ for (mask = 0x8000000000000000ULL, n=0; n < 64 && (op & mask) == 0; n++, mask >>= 1); /* Load leftmost one position into R1 register */ regs->GR_G(r1) = n; /* Copy original R2 to R1+1 and clear leftmost one */ regs->GR_G(r1+1) = op & (~mask); /* Return with condition code 2 */ regs->psw.cc = 2; } } /* end DEF_INST(find_leftmost_one_long_register) */ #endif /*defined(FEATURE_EXTENDED_IMMEDIATE)*/ /*@Z9*/ #if defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B280 LPP - Load Program Parameter [S] */ /*-------------------------------------------------------------------*/ DEF_INST(load_program_parameter) { int b2; /* Base of effective addr */ U64 effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); PRIV_CHECK(regs); /* Fetch data from operand address */ sysblk.program_parameter = ARCH_DEP(vfetch8) (effective_addr2, b2, regs); } /* end DEF_INST(load_program_parameter) */ #endif /*defined(FEATURE_LOAD_PROGRAM_PARAMETER_FACILITY)*/ /*810*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "esame.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "esame.c" #endif #if defined(HAVE_STFL_DATA) /*-------------------------------------------------------------------*/ /* Locate STFL data independent of current architecture mode setting */ /*-------------------------------------------------------------------*/ /* Note: this function must be here so that all ARCH_DEP(stlf_data) */ /* with correct architecture settings have been defined with */ /* architecture sensitive features */ BYTE* get_stfl_data(int mode, int *data_len) { switch(mode) { #if defined(_390) case ARCH_390: *data_len=sizeof(s390_stfl_data); return &s390_stfl_data[0]; #endif #if defined(_900) case ARCH_900: *data_len=sizeof(z900_stfl_data); return &z900_stfl_data[0]; #endif } *data_len=0; return NULL; } #endif /* defined(HAVE_STFL_DATA) */ #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/ieee.c0000664000175000017500000037507112564723224011273 00000000000000/* IEEE.C (c) Copyright Willem Konynenberg, 2001-2003 */ /* (c) Copyright Roger Bowler and others, 2003-2014 */ /* Hercules Binary (IEEE) Floating Point Instructions */ /*-------------------------------------------------------------------*/ /* This module implements ESA/390 Binary Floating-Point (IEEE 754) */ /* instructions as described in SA22-7201-05 ESA/390 Principles of */ /* Operation and SA22-7832-08 z/Architecture Principles of Operation.*/ /*-------------------------------------------------------------------*/ /* * Hercules System/370, ESA/390, z/Architecture emulator * ieee.c * Binary (IEEE) Floating Point Instructions * Copyright (c) 2001-2009 Willem Konynenberg * TCEB, TCDB and TCXB contributed by Per Jessen, 20 September 2001. * THDER,THDR by Roger Bowler, 19 July 2003. * Additional instructions by Roger Bowler, November 2004: * LXDBR,LXDB,LXEBR,LXEB,LDXBR,LEXBR,CXFBR,CXGBR,CFXBR,CGXBR, * MXDBR,MXDB,MDEBR,MDEB,MADBR,MADB,MAEBR,MAEB,MSDBR,MSDB, * MSEBR,MSEB,DIEBR,DIDBR,TBEDR,TBDR. * Licensed under the Q Public License * For details, see html/herclic.html * Based very loosely on float.c by Peter Kuschnerus, (c) 2000-2006. * Converted to use J.R.Hauser's softfloat package - RB, Oct 2013. * Floating-point extension facility - RB, April 2014: * CELFBR,CDLFBR,CXLFBR,CLFEBR,CLFDBR,CLFXBR, * CELGBR,CDLGBR,CXLGBR,CLGEBR,CLGDBR,CLGXBR. * Floating-point extension facility - RB, August 2014: * FIEBRA,FIDBRA,FIXBRA,LDXBRA,LEXBRA,LEDBRA, * CEFBRA,CDFBRA,CXFBRA,CFEBRA,CFDBRA,CFXBRA, * CEGBRA,CDGBRA,CXGBRA,CGEBRA,CGDBRA,CGXBRA. */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_IEEE_C_) #define _IEEE_C_ #endif #include "hercules.h" #if defined(FEATURE_BINARY_FLOATING_POINT) #include "opcode.h" #include "inline.h" /* Definitions of BFP rounding methods */ #define RM_DEFAULT_ROUNDING 0 #define RM_BIASED_ROUND_TO_NEAREST 1 #define RM_PREPARE_SHORTER_PRECISION 3 #define RM_ROUND_TO_NEAREST 4 #define RM_ROUND_TOWARD_ZERO 5 #define RM_ROUND_TOWARD_POS_INF 6 #define RM_ROUND_TOWARD_NEG_INF 7 /* Macro to generate program check if invalid BFP rounding method */ #undef BFPRM_CHECK #if !defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) #define BFPRM_CHECK(x,regs) \ {if (!((x)==0 || (x)==1 || ((x)>=4 && (x)<=7))) \ {regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION);}} #else /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ #define BFPRM_CHECK(x,regs) \ {if (!((x)==0 || (x)==1 || ((x)>=3 && (x)<=7))) \ {regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION);}} #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ #if !defined(_IEEE_C) /* Architecture independent code goes within this ifdef */ #include "milieu.h" #include "softfloat.h" /* Floating point exponent bias values */ #define FLOAT32_BIAS 127 #define FLOAT64_BIAS 1023 #define FLOAT128_BIAS 16383 #endif /* !defined(_IEEE_C) */ /* externally defined architecture-dependent functions */ #define vfetch4 ARCH_DEP(vfetch4) #define vfetch8 ARCH_DEP(vfetch8) /* locally defined architecture-dependent functions */ #define float_exception_masked ARCH_DEP(float_exception_masked) #define float_exception ARCH_DEP(float_exception) #define vfetch_float32 ARCH_DEP(vfetch_float32) #define vfetch_float64 ARCH_DEP(vfetch_float64) #define add_ebfp ARCH_DEP(add_ebfp) #define add_lbfp ARCH_DEP(add_lbfp) #define add_sbfp ARCH_DEP(add_sbfp) #define compare_ebfp ARCH_DEP(compare_ebfp) #define compare_lbfp ARCH_DEP(compare_lbfp) #define compare_sbfp ARCH_DEP(compare_sbfp) #define divide_ebfp ARCH_DEP(divide_ebfp) #define divide_lbfp ARCH_DEP(divide_lbfp) #define divide_sbfp ARCH_DEP(divide_sbfp) #define load_test_ebfp ARCH_DEP(load_test_ebfp) #define load_test_lbfp ARCH_DEP(load_test_lbfp) #define load_test_sbfp ARCH_DEP(load_test_sbfp) #define load_neg_ebfp ARCH_DEP(load_neg_ebfp) #define load_neg_lbfp ARCH_DEP(load_neg_lbfp) #define load_neg_sbfp ARCH_DEP(load_neg_sbfp) #define load_pos_ebfp ARCH_DEP(load_pos_ebfp) #define load_pos_lbfp ARCH_DEP(load_pos_lbfp) #define load_pos_sbfp ARCH_DEP(load_pos_sbfp) #define multiply_ebfp ARCH_DEP(multiply_ebfp) #define multiply_lbfp ARCH_DEP(multiply_lbfp) #define multiply_sbfp ARCH_DEP(multiply_sbfp) #define multiply_add_ebfp ARCH_DEP(multiply_add_ebfp) #define multiply_add_lbfp ARCH_DEP(multiply_add_lbfp) #define multiply_add_sbfp ARCH_DEP(multiply_add_sbfp) #define multiply_subtract_ebfp ARCH_DEP(multiply_subtract_ebfp) #define multiply_subtract_lbfp ARCH_DEP(multiply_subtract_lbfp) #define multiply_subtract_sbfp ARCH_DEP(multiply_subtract_sbfp) #define squareroot_ebfp ARCH_DEP(squareroot_ebfp) #define squareroot_lbfp ARCH_DEP(squareroot_lbfp) #define squareroot_sbfp ARCH_DEP(squareroot_sbfp) #define subtract_ebfp ARCH_DEP(subtract_ebfp) #define subtract_lbfp ARCH_DEP(subtract_lbfp) #define subtract_sbfp ARCH_DEP(subtract_sbfp) #define test_data_class_ebfp ARCH_DEP(test_data_class_ebfp) #define test_data_class_lbfp ARCH_DEP(test_data_class_lbfp) #define test_data_class_sbfp ARCH_DEP(test_data_class_sbfp) #define divint_lbfp ARCH_DEP(divint_lbfp) #define divint_sbfp ARCH_DEP(divint_sbfp) /* * Convert from Softfloat IEEE exception to Pop IEEE exception * with suppression of exceptions according to mask bits: * - mask bit 0x04 (XxC) suppresses the inexact exception */ static int float_exception_masked(REGS * regs, int mask) { int fpc = 0; int dxc = 0; int exc = 0; int8 flags = float_get_exception_flags(); if (flags & float_flag_inexact) { fpc = FPC_FLAG_SFX; } if (flags & float_flag_underflow) { fpc |= FPC_FLAG_SFU; } else if (flags & float_flag_overflow) { fpc |= FPC_FLAG_SFO; } else if (flags & float_flag_divbyzero) { fpc |= FPC_FLAG_SFZ; } else if (flags & float_flag_invalid) { fpc |= FPC_FLAG_SFI; } exc = (fpc & FPC_FLAG) & ((regs->fpc & FPC_MASK) >> 8); #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /* Suppress inexact exception if the XxC mask bit is set */ if (mask & 0x04) { exc &= ~FPC_FLAG_SFX; } #else UNREFERENCED(mask); #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ if (exc & FPC_FLAG_SFI) { dxc = DXC_IEEE_INVALID_OP; } else if (exc & FPC_FLAG_SFZ) { dxc = DXC_IEEE_DIV_ZERO; } else if (exc & FPC_FLAG_SFO) { dxc = (fpc & FPC_FLAG_SFX) ? DXC_IEEE_OF_INEX_TRUNC : DXC_IEEE_OF_EXACT; } else if (exc & FPC_FLAG_SFU) { dxc = (fpc & FPC_FLAG_SFX) ? DXC_IEEE_UF_INEX_TRUNC : DXC_IEEE_UF_EXACT; } else if (exc & FPC_FLAG_SFX) { dxc = DXC_IEEE_INEXACT_TRUNC; } if (exc) { regs->dxc = dxc; if (dxc == DXC_IEEE_DIV_ZERO || dxc == DXC_IEEE_INVALID_OP) { /* suppress operation */ regs->program_interrupt(regs, PGM_DATA_EXCEPTION); } fpc &= ~exc; regs->fpc |= fpc; /* * Other operations need to take appropriate action * to complete the operation. */ return PGM_DATA_EXCEPTION; } else { /* Set flags in FPC */ regs->fpc |= fpc; /* have caller take default action */ return 0; } } /* end function float_exception_masked */ /* * Convert from Softfloat IEEE exception to Pop IEEE exception * without suppression of exceptions by mask bits */ static inline int float_exception(REGS * regs) { return float_exception_masked(regs, 0); } /* end function float_exception */ #if !defined(_IEEE_C) /* * Set softfloat rounding mode according to BFP rounding mode mask */ void set_rounding_mode(U32 fpcreg, int mask) { int brm; int8 flrm; /* If mask is zero, obtain rounding mode from FPC register */ if (mask == RM_DEFAULT_ROUNDING) brm = ((fpcreg & FPC_BRM) >> FPC_BRM_SHIFT) + 4; else brm = mask; /* Convert BFP rounding mode to nearest equivalent FE rounding mode */ switch (brm) { case RM_ROUND_TO_NEAREST: /* Round to nearest ties to even */ flrm = float_round_nearest_even; break; case RM_ROUND_TOWARD_ZERO: /* Round toward zero */ flrm = float_round_to_zero; break; case RM_ROUND_TOWARD_POS_INF: /* Round toward +infinity */ flrm = float_round_up; break; case RM_ROUND_TOWARD_NEG_INF: /* Round toward -infinity */ flrm = float_round_down; break; default: flrm = float_round_nearest_even; break; } /* end switch(brm) */ /* Set rounding mode for softfloat */ float_set_rounding_mode(flrm); } /* end function set_rounding_mode */ #endif /* !defined(_IEEE_C) */ #if !defined(_IEEE_C) /* * Get softfloat operands from registers */ static inline void get_float32(float32 *op, U32 *fpr) { *op = *fpr; } static inline void get_float64(float64 *op, U32 *fpr) { *op = ((U64)fpr[0] << 32) | fpr[1]; } static inline void get_float128(float128 *op, U32 *fpr) { op->high = ((U64)fpr[0] << 32) | fpr[1]; op->low = ((U64)fpr[FPREX] << 32) | fpr[FPREX+1]; } #endif /* !defined(_IEEE_C) */ /* * Fetch softfloat operands from memory */ static inline void vfetch_float32(float32 *op, VADR addr, int arn, REGS *regs) { *op = vfetch4(addr, arn, regs); } static inline void vfetch_float64(float64 *op, VADR addr, int arn, REGS *regs) { *op = vfetch8(addr, arn, regs); } #if !defined(_IEEE_C) /* * Put softfloat operands into registers */ static inline void put_float32(float32 *op, U32 *fpr) { *fpr = *op; } static inline void put_float64(float64 *op, U32 *fpr) { fpr[0] = (U32)(*op >> 32); fpr[1] = (U32)(*op & 0xFFFFFFFF); } static inline void put_float128(float128 *op, U32 *fpr) { fpr[0] = (U32)(op->high >> 32); fpr[1] = (U32)(op->high & 0xFFFFFFFF); fpr[FPREX] = (U32)(op->low >> 32); fpr[FPREX+1] = (U32)(op->low & 0xFFFFFFFF); } #define _IEEE_C #endif /* !defined(_IEEE_C) */ /* * Chapter 9. Floating-Point Overview and Support Instructions */ #if defined(FEATURE_FPS_EXTENSIONS) #if !defined(_CBH_FUNC) /* * Convert binary floating point to hexadecimal long floating point * save result into long register and return condition code * Roger Bowler, 19 July 2003 */ static int cnvt_bfp_to_hfp (float64 *op, U32 *fpr) { int exp; U64 fract; U32 r0, r1; int cc; int sign; sign = float64_is_neg(*op) ? 1 : 0; if (float64_is_nan(*op)) { r0 = 0x7FFFFFFF; r1 = 0xFFFFFFFF; cc = 3; } else if (float64_is_inf(*op)) { r0 = sign ? 0xFFFFFFFF : 0x7FFFFFFF; r1 = 0xFFFFFFFF; cc = 3; } else if (float64_is_zero(*op)) { r0 = sign ? 0x80000000 : 0; r1 = 0; cc = 0; } else if (float64_is_subnormal(*op)) { r0 = sign ? 0x80000000 : 0; r1 = 0; cc = sign ? 1 : 2; } else { //logmsg("ieee: exp=%d (X\'%3.3x\')\tfract=%16.16"I64_FMT"x\n", // float64_exp(*op), float64_exp(*op), float64_fract(*op)); /* Insert an implied 1. in front of the 52 bit binary fraction and lengthen the result to 56 bits */ fract = (U64)(float64_fract(*op) | 0x10000000000000ULL) << 3; /* The binary exponent is equal to the biased exponent - 1023 adjusted by 1 to move the point before the 56 bit fraction */ exp = float64_exp(*op) - 1023 + 1; //logmsg("ieee: adjusted exp=%d\tfract=%16.16"I64_FMT"x\n", exp, fract); /* Shift the fraction right one bit at a time until the binary exponent becomes a multiple of 4 */ while (exp & 3) { exp++; fract >>= 1; } //logmsg("ieee: shifted exp=%d\tfract=%16.16"I64_FMT"x\n", exp, fract); /* Convert the binary exponent into a hexadecimal exponent by dropping the last two bits (which are now zero) */ exp >>= 2; /* If the hexadecimal exponent is less than -64 then return a signed zero result with a non-zero condition code */ if (exp < -64) { r0 = sign ? 0x80000000 : 0; r1 = 0; cc = sign ? 1 : 2; } /* If the hexadecimal exponent exceeds +63 then return a signed maximum result with condition code 3 */ else if (exp > 63) { r0 = sign ? 0xFFFFFFFF : 0x7FFFFFFF; r1 = 0xFFFFFFFF; cc = 3; } else { /* Convert the hexadecimal exponent to a characteristic by adding 64 */ exp += 64; /* Pack the exponent and the fraction into the result */ r0 = (sign ? 1<<31 : 0) | (exp << 24) | (fract >> 32); r1 = fract & 0xFFFFFFFF; cc = sign ? 1 : 2; } } /* Store high and low halves of result into fp register array and return condition code */ fpr[0] = r0; fpr[1] = r1; return cc; } /* end function cnvt_bfp_to_hfp */ /* * Convert hexadecimal long floating point register to * binary floating point and return condition code * Roger Bowler, 28 Nov 2004 */ static int cnvt_hfp_to_bfp (U32 *fpr, int rounding, int bfp_fractbits, int bfp_emax, int bfp_ebias, int *result_sign, int *result_exp, U64 *result_fract) { BYTE sign; short expo; U64 fract; int roundup = 0; int cc; U64 b; /* Break the source operand into sign, characteristic, fraction */ sign = fpr[0] >> 31; expo = (fpr[0] >> 24) & 0x007F; fract = ((U64)(fpr[0] & 0x00FFFFFF) << 32) | fpr[1]; /* Determine whether to round up or down */ switch (rounding) { case RM_BIASED_ROUND_TO_NEAREST: case RM_ROUND_TO_NEAREST: roundup = 0; break; case RM_DEFAULT_ROUNDING: case RM_ROUND_TOWARD_ZERO: roundup = 0; break; case RM_ROUND_TOWARD_POS_INF: roundup = (sign ? 0 : 1); break; case RM_ROUND_TOWARD_NEG_INF: roundup = sign; break; } /* end switch(rounding) */ /* Convert HFP zero to BFP zero and return cond code 0 */ if (fract == 0) /* a = -0 or +0 */ { *result_sign = sign; *result_exp = 0; *result_fract = 0; return 0; } /* Set the condition code */ cc = sign ? 1 : 2; /* Convert the HFP characteristic to a true binary exponent */ expo = (expo - 64) * 4; /* Convert true binary exponent to a biased exponent */ expo += bfp_ebias; /* Shift the fraction left until leftmost 1 is in bit 8 */ while ((fract & 0x0080000000000000ULL) == 0) { fract <<= 1; expo -= 1; } /* Convert 56-bit fraction to 55-bit with implied 1 */ expo--; fract &= 0x007FFFFFFFFFFFFFULL; if (expo < -(bfp_fractbits-1)) /* |a| < Dmin */ { if (expo == -(bfp_fractbits-1) - 1) { if (rounding == RM_BIASED_ROUND_TO_NEAREST || rounding == RM_ROUND_TO_NEAREST) roundup = 1; } if (roundup) { expo = 0; fract = 1; } /* Dmin */ else { expo = 0; fract = 0; } /* Zero */ } else if (expo < 1) /* Dmin <= |a| < Nmin */ { /* Reinstate implied 1 in preparation for denormalization */ fract |= 0x0080000000000000ULL; /* Denormalize to get exponent back in range */ fract >>= (expo + (bfp_fractbits-1)); expo = 0; } else if (expo > (bfp_emax+bfp_ebias)) /* |a| > Nmax */ { cc = 3; if (roundup) { /* Inf */ expo = (bfp_emax+bfp_ebias) + 1; fract = 0; } else { /* Nmax */ expo = (bfp_emax+bfp_ebias); fract = 0x007FFFFFFFFFFFFFULL - (((U64)1<<(1+(55-bfp_fractbits)))-1); } /* Nmax */ } /* end Nmax < |a| */ /* Set the result sign and exponent */ *result_sign = sign; *result_exp = expo; /* Apply rounding before truncating to final fraction length */ b = ( (U64)1 ) << ( 55 - bfp_fractbits); if (roundup && (fract & b)) { fract += b; } /* Convert 55-bit fraction to result fraction length */ *result_fract = fract >> (55-bfp_fractbits); return cc; } /* end function cnvt_hfp_to_bfp */ #define _CBH_FUNC #endif /*!defined(_CBH_FUNC)*/ /*-------------------------------------------------------------------*/ /* B359 THDR - CONVERT BFP TO HFP (long) [RRE] */ /* Roger Bowler, 19 July 2003 */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_long_to_float_long_reg) { int r1, r2; float64 op2; RRE(inst, regs, r1, r2); //logmsg("THDR r1=%d r2=%d\n", r1, r2); HFPREG2_CHECK(r1, r2, regs); /* Load long BFP operand from R2 register */ get_float64(&op2, regs->fpr + FPR2I(r2)); /* Convert to HFP register and set condition code */ regs->psw.cc = cnvt_bfp_to_hfp (&op2, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_bfp_long_to_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B358 THDER - CONVERT BFP TO HFP (short to long) [RRE] */ /* Roger Bowler, 19 July 2003 */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_short_to_float_long_reg) { int r1, r2; float32 op2; float64 lbfp_op2; RRE(inst, regs, r1, r2); //logmsg("THDER r1=%d r2=%d\n", r1, r2); HFPREG2_CHECK(r1, r2, regs); /* Load short BFP operand from R2 register */ get_float32(&op2, regs->fpr + FPR2I(r2)); /* Lengthen short BFP operand to long BFP */ lbfp_op2 = float32_to_float64(op2); /* Convert to HFP register and set condition code */ regs->psw.cc = cnvt_bfp_to_hfp (&lbfp_op2, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_bfp_short_to_float_long_reg) */ /*-------------------------------------------------------------------*/ /* B351 TBDR - CONVERT HFP TO BFP (long) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_long_to_bfp_long_reg) { int r1, r2, m3; float64 op1; int sign, exp; U64 fract; RRF_M(inst, regs, r1, r2, m3); //logmsg("TBDR r1=%d r2=%d\n", r1, r2); HFPREG2_CHECK(r1, r2, regs); BFPRM_CHECK(m3,regs); regs->psw.cc = cnvt_hfp_to_bfp (regs->fpr + FPR2I(r2), m3, /*fractbits*/52, /*emax*/1023, /*ebias*/1023, &sign, &exp, &fract); op1 = float64_build(sign, exp, fract); put_float64(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_float_long_to_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B350 TBEDR - CONVERT HFP TO BFP (long to short) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_float_long_to_bfp_short_reg) { int r1, r2, m3; float32 op1; int sign, exp; U64 fract; RRF_M(inst, regs, r1, r2, m3); //logmsg("TBEDR r1=%d r2=%d\n", r1, r2); HFPREG2_CHECK(r1, r2, regs); BFPRM_CHECK(m3,regs); regs->psw.cc = cnvt_hfp_to_bfp (regs->fpr + FPR2I(r2), m3, /*fractbits*/23, /*emax*/127, /*ebias*/127, &sign, &exp, &fract); op1 = float32_build(sign, exp, (U32)fract); put_float32(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_float_long_to_bfp_short_reg) */ #endif /*defined(FEATURE_FPS_EXTENSIONS)*/ /* * Chapter 19. Binary-Floating-Point Instructions * Most of these instructions were defined as an update to ESA/390. * z/Architecture has added instructions for 64-bit integers. */ /*-------------------------------------------------------------------*/ /* ADD (extended) */ /*-------------------------------------------------------------------*/ static int add_ebfp(float128 *op1, float128 *op2, REGS *regs) { int code; float128 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float128_add(*op1, *op2); code = float_exception(regs); *op1 = result; regs->psw.cc = float128_is_nan(result) ? 3 : float128_is_zero(result) ? 0 : float128_is_neg(result) ? 1 : 2; return code; } /* end function add_ebfp */ /*-------------------------------------------------------------------*/ /* B34A AXBR - ADD (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_bfp_ext_reg) { int r1, r2; float128 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("AXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op1, regs->fpr + FPR2I(r1)); get_float128(&op2, regs->fpr + FPR2I(r2)); pgm_check = add_ebfp(&op1, &op2, regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(add_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* ADD (long) */ /*-------------------------------------------------------------------*/ static int add_lbfp(float64 *op1, float64 *op2, REGS *regs) { int code; float64 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float64_add(*op1, *op2); code = float_exception(regs); *op1 = result; regs->psw.cc = float64_is_nan(result) ? 3 : float64_is_zero(result) ? 0 : float64_is_neg(result) ? 1 : 2; return code; } /* end function add_lbfp */ /*-------------------------------------------------------------------*/ /* B31A ADBR - ADD (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_bfp_long_reg) { int r1, r2; float64 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("ADBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); pgm_check = add_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(add_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED1A ADB - ADD (long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_bfp_long) { int r1, b2; VADR effective_addr2; float64 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("ADB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); pgm_check = add_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(add_bfp_long) */ /*-------------------------------------------------------------------*/ /* ADD (short) */ /*-------------------------------------------------------------------*/ static int add_sbfp(float32 *op1, float32 *op2, REGS *regs) { int code; float32 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float32_add(*op1, *op2); code = float_exception(regs); *op1 = result; regs->psw.cc = float32_is_nan(result) ? 3 : float32_is_zero(result) ? 0 : float32_is_neg(result) ? 1 : 2; return code; } /* end function add_sbfp */ /*-------------------------------------------------------------------*/ /* B30A AEBR - ADD (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_bfp_short_reg) { int r1, r2; float32 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("AEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); pgm_check = add_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(add_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED0A AEB - ADD (short BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(add_bfp_short) { int r1, b2; VADR effective_addr2; float32 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("AEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); pgm_check = add_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(add_bfp_short) */ /*-------------------------------------------------------------------*/ /* COMPARE (extended) */ /*-------------------------------------------------------------------*/ static int compare_ebfp(float128 *op1, float128 *op2, int sig, REGS *regs) { int code = 0; float_clear_exception_flags(); if (float128_is_signaling_nan(*op1) || float128_is_signaling_nan(*op2) || (sig && (float128_is_nan(*op1) || float128_is_nan(*op2)))) { float_raise(float_flag_invalid); code = float_exception(regs); if (code) { return code; } } regs->psw.cc = (float128_is_nan(*op1) || float128_is_nan(*op2)) ? 3 : float128_eq(*op1, *op2) ? 0 : float128_lt_quiet(*op1, *op2) ? 1 : 2; return code; } /* end function compare_ebfp */ /*-------------------------------------------------------------------*/ /* B349 CXBR - COMPARE (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_bfp_ext_reg) { int r1, r2; float128 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("CXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op1, regs->fpr + FPR2I(r1)); get_float128(&op2, regs->fpr + FPR2I(r2)); pgm_check = compare_ebfp(&op1, &op2, 0, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* COMPARE (long) */ /*-------------------------------------------------------------------*/ static int compare_lbfp(float64 *op1, float64 *op2, int sig, REGS *regs) { int code = 0; float_clear_exception_flags(); if (float64_is_signaling_nan(*op1) || float64_is_signaling_nan(*op2) || (sig && (float64_is_nan(*op1) || float64_is_nan(*op2)))) { float_raise(float_flag_invalid); code = float_exception(regs); if (code) { return code; } } regs->psw.cc = (float64_is_nan(*op1) || float64_is_nan(*op2)) ? 3 : float64_eq(*op1, *op2) ? 0 : float64_lt_quiet(*op1, *op2) ? 1 : 2; return code; } /* end function compare_lbfp */ /*-------------------------------------------------------------------*/ /* B319 CDBR - COMPARE (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_bfp_long_reg) { int r1, r2; float64 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("CDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); pgm_check = compare_lbfp(&op1, &op2, 0, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED19 CDB - COMPARE (long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_bfp_long) { int r1, b2; VADR effective_addr2; float64 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("CDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); pgm_check = compare_lbfp(&op1, &op2, 0, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_bfp_long) */ /*-------------------------------------------------------------------*/ /* COMPARE (short) */ /*-------------------------------------------------------------------*/ static int compare_sbfp(float32 *op1, float32 *op2, int sig, REGS *regs) { int code = 0; float_clear_exception_flags(); if (float32_is_signaling_nan(*op1) || float32_is_signaling_nan(*op2) || (sig && (float32_is_nan(*op1) || float32_is_nan(*op2)))) { float_raise(float_flag_invalid); code = float_exception(regs); if (code) { return code; } } regs->psw.cc = (float32_is_nan(*op1) || float32_is_nan(*op2)) ? 3 : float32_eq(*op1, *op2) ? 0 : float32_lt_quiet(*op1, *op2) ? 1 : 2; return code; } /* end function compare_sbfp */ /*-------------------------------------------------------------------*/ /* B309 CEBR - COMPARE (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_bfp_short_reg) { int r1, r2; float32 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("CEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); pgm_check = compare_sbfp(&op1, &op2, 0, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED09 CEB - COMPARE (short BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_bfp_short) { int r1, b2; VADR effective_addr2; float32 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("CEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); pgm_check = compare_sbfp(&op1, &op2, 0, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_bfp_short) */ /*-------------------------------------------------------------------*/ /* B348 KXBR - COMPARE AND SIGNAL (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_signal_bfp_ext_reg) { int r1, r2; float128 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("KXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op1, regs->fpr + FPR2I(r1)); get_float128(&op2, regs->fpr + FPR2I(r2)); pgm_check = compare_ebfp(&op1, &op2, 1, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_and_signal_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B318 KDBR - COMPARE AND SIGNAL (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_signal_bfp_long_reg) { int r1, r2; float64 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("KDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); pgm_check = compare_lbfp(&op1, &op2, 1, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_and_signal_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED18 KDB - COMPARE AND SIGNAL (long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_signal_bfp_long) { int r1, b2; VADR effective_addr2; float64 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("KDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); pgm_check = compare_lbfp(&op1, &op2, 1, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_and_signal_bfp_long) */ /*-------------------------------------------------------------------*/ /* B308 KEBR - COMPARE AND SIGNAL (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_signal_bfp_short_reg) { int r1, r2; float32 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("KEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); pgm_check = compare_sbfp(&op1, &op2, 1, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_and_signal_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED08 KEB - COMPARE AND SIGNAL (short BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_signal_bfp_short) { int r1, b2; VADR effective_addr2; float32 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("KEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); pgm_check = compare_sbfp(&op1, &op2, 1, regs); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(compare_and_signal_bfp_short) */ /*-------------------------------------------------------------------*/ /* B396 CXFBR - CONVERT FROM FIXED (32 to extended BFP) [RRE] */ /* B396 CXFBRA - CONVERT FROM FIXED (32 to extended BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix32_to_bfp_ext_reg) { int r1, r2, m3, m4; float128 op1; S32 op2; RRE_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CXFBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); BFPRM_CHECK(m3, regs); op2 = regs->GR_L(r2); op1 = int32_to_float128(op2); put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_fix32_to_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B395 CDFBR - CONVERT FROM FIXED (32 to long BFP) [RRE] */ /* B395 CDFBRA - CONVERT FROM FIXED (32 to long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix32_to_bfp_long_reg) { int r1, r2, m3, m4; float64 op1; S32 op2; RRE_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CDFBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3, regs); op2 = regs->GR_L(r2); op1 = int32_to_float64(op2); put_float64(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_fix32_to_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B394 CEFBR - CONVERT FROM FIXED (32 to short BFP) [RRE] */ /* B394 CEFBRA - CONVERT FROM FIXED (32 to short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix32_to_bfp_short_reg) { int r1, r2, m3, m4; float32 op1; S32 op2; int pgm_check; RRE_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CEFBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3, regs); op2 = regs->GR_L(r2); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = int32_to_float32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_fix32_to_bfp_short_reg) */ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*-------------------------------------------------------------------*/ /* B392 CXLFBR - CONVERT FROM LOGICAL (32 to extended BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u32_to_bfp_ext_reg) { int r1, r2, m3, m4; float128 op1; U32 op2; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CXLFBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_L(r2); op1 = uint32_to_float128(op2); put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_u32_to_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B391 CDLFBR - CONVERT FROM LOGICAL (32 to long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u32_to_bfp_long_reg) { int r1, r2, m3, m4; float64 op1; U32 op2; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CDLFBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_L(r2); op1 = uint32_to_float64(op2); put_float64(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_u32_to_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B390 CELFBR - CONVERT FROM LOGICAL (32 to short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u32_to_bfp_short_reg) { int r1, r2, m3, m4; float32 op1; U32 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CELFBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_L(r2); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = uint32_to_float32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_u32_to_bfp_short_reg) */ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3A6 CXGBR - CONVERT FROM FIXED (64 to extended BFP) [RRE] */ /* B3A6 CXGBRA - CONVERT FROM FIXED (64 to extended BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_bfp_ext_reg) { int r1, r2, m3, m4; float128 op1; S64 op2; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CXGBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_G(r2); op1 = int64_to_float128(op2); put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_fix64_to_bfp_ext_reg) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3A5 CDGBR - CONVERT FROM FIXED (64 to long BFP) [RRE] */ /* B3A5 CDGBRA - CONVERT FROM FIXED (64 to long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_bfp_long_reg) { int r1, r2, m3, m4; float64 op1; S64 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CDGBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_G(r2); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = int64_to_float64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_fix64_to_bfp_long_reg) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3A4 CEGBR - CONVERT FROM FIXED (64 to short BFP) [RRE] */ /* B3A4 CEGBRA - CONVERT FROM FIXED (64 to short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_bfp_short_reg) { int r1, r2, m3, m4; float32 op1; S64 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CEGBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_G(r2); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = int64_to_float32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_fix64_to_bfp_short_reg) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3A2 CXLGBR - CONVERT FROM LOGICAL (64 to extended BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u64_to_bfp_ext_reg) { int r1, r2, m3, m4; float128 op1; U64 op2; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CXLGBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_G(r2); op1 = uint64_to_float128(op2); put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(convert_u64_to_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3A1 CDLGBR - CONVERT FROM LOGICAL (64 to long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u64_to_bfp_long_reg) { int r1, r2, m3, m4; float64 op1; U64 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CDLGBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_G(r2); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = uint64_to_float64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_u64_to_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3A0 CELGBR - CONVERT FROM LOGICAL (64 to short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u64_to_bfp_short_reg) { int r1, r2, m3, m4; float32 op1; U64 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CELGBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); op2 = regs->GR_G(r2); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = uint64_to_float32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_u64_to_bfp_short_reg) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*-------------------------------------------------------------------*/ /* B39A CFXBR - CONVERT TO FIXED (extended BFP to 32) [RRF] */ /* B39A CFXBRA - CONVERT TO FIXED (extended BFP to 32) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_ext_to_fix32_reg) { int r1, r2, m3, m4; S32 op1; float128 op2; int pgm_check; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CFXBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r2, regs); BFPRM_CHECK(m3,regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float128_to_int32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_L(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float128_is_zero(op2) ? 0 : float128_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_ext_to_fix32_reg) */ /*-------------------------------------------------------------------*/ /* B399 CFDBR - CONVERT TO FIXED (long BFP to 32) [RRF] */ /* B399 CFDBRA - CONVERT TO FIXED (long BFP to 32) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_long_to_fix32_reg) { int r1, r2, m3, m4; S32 op1; float64 op2; int pgm_check; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CFDBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float64(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float64_to_int32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_L(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float64_is_zero(op2) ? 0 : float64_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_long_to_fix32_reg) */ /*-------------------------------------------------------------------*/ /* B398 CFEBR - CONVERT TO FIXED (short BFP to 32) [RRF] */ /* B398 CFEBRA - CONVERT TO FIXED (short BFP to 32) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_short_to_fix32_reg) { int r1, r2, m3, m4; S32 op1; float32 op2; int pgm_check; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CFEBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float32(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float32_to_int32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_L(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float32_is_zero(op2) ? 0 : float32_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_short_to_fix32_reg) */ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*-------------------------------------------------------------------*/ /* B39E CLFXBR - CONVERT TO LOGICAL (extended BFP to 32) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_ext_to_u32_reg) { int r1, r2, m3, m4; U32 op1; float128 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CLFXBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r2, regs); BFPRM_CHECK(m3,regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float128_to_uint32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_L(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float128_is_zero(op2) ? 0 : float128_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_ext_to_u32_reg) */ /*-------------------------------------------------------------------*/ /* B39D CLFDBR - CONVERT TO LOGICAL (long BFP to 32) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_long_to_u32_reg) { int r1, r2, m3, m4; U32 op1; float64 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CLFDBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float64(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float64_to_uint32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_L(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float64_is_zero(op2) ? 0 : float64_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_long_to_u32_reg) */ /*-------------------------------------------------------------------*/ /* B39C CLFEBR - CONVERT TO LOGICAL (short BFP to 32) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_short_to_u32_reg) { int r1, r2, m3, m4; U32 op1; float32 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CLFEBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float32(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float32_to_uint32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_L(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float32_is_zero(op2) ? 0 : float32_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_short_to_u32_reg) */ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3AA CGXBR - CONVERT TO FIXED (extended BFP to 64) [RRF] */ /* B3AA CGXBRA - CONVERT TO FIXED (extended BFP to 64) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_ext_to_fix64_reg) { int r1, r2, m3, m4; S64 op1; float128 op2; int pgm_check; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CGXBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r2, regs); BFPRM_CHECK(m3,regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float128_to_int64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_G(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float128_is_zero(op2) ? 0 : float128_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_ext_to_fix64_reg) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3A9 CGDBR - CONVERT TO FIXED (long BFP to 64) [RRF] */ /* B3A9 CGDBRA - CONVERT TO FIXED (long BFP to 64) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_long_to_fix64_reg) { int r1, r2, m3, m4; S64 op1; float64 op2; int pgm_check; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CGDBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float64(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float64_to_int64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_G(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float64_is_zero(op2) ? 0 : float64_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_long_to_fix64_reg) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3A8 CGEBR - CONVERT TO FIXED (short BFP to 64) [RRF] */ /* B3A8 CGEBRA - CONVERT TO FIXED (short BFP to 64) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_short_to_fix64_reg) { int r1, r2, m3, m4; S64 op1; float32 op2; int pgm_check; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("CGEBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float32(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float32_to_int64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_G(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float32_is_zero(op2) ? 0 : float32_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_short_to_fix64_reg) */ #endif /*defined(FEATURE_ESAME)*/ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) #if defined(FEATURE_ESAME) /*-------------------------------------------------------------------*/ /* B3AE CLGXBR - CONVERT TO LOGICAL (extended BFP to 64) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_ext_to_u64_reg) { int r1, r2, m3, m4; U64 op1; float128 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CLGXBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r2, regs); BFPRM_CHECK(m3,regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float128_to_uint64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_G(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float128_is_zero(op2) ? 0 : float128_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_ext_to_u64_reg) */ /*-------------------------------------------------------------------*/ /* B3AD CLGDBR - CONVERT TO LOGICAL (long BFP to 64) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_long_to_u64_reg) { int r1, r2, m3, m4; U64 op1; float64 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CLGDBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float64(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float64_to_uint64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_G(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float64_is_zero(op2) ? 0 : float64_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_long_to_u64_reg) */ /*-------------------------------------------------------------------*/ /* B3AC CLGEBR - CONVERT TO LOGICAL (short BFP to 64) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_bfp_short_to_u64_reg) { int r1, r2, m3, m4; U64 op1; float32 op2; int pgm_check; RRF_MM(inst, regs, r1, r2, m3, m4); //logmsg("CLGEBR r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float32(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float32_to_uint64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); regs->GR_G(r1) = op1; regs->psw.cc = (float_get_exception_flags() & float_flag_invalid) ? 3 : float32_is_zero(op2) ? 0 : float32_is_neg(op2) ? 1 : 2; if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(convert_bfp_short_to_u64_reg) */ #endif /*defined(FEATURE_ESAME)*/ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*-------------------------------------------------------------------*/ /* DIVIDE (extended) */ /*-------------------------------------------------------------------*/ static int divide_ebfp(float128 *op1, float128 *op2, REGS *regs) { int code; float128 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float128_div(*op1, *op2); code = float_exception(regs); *op1 = result; return code; } /* end function divide_ebfp */ /*-------------------------------------------------------------------*/ /* B34D DXBR - DIVIDE (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_bfp_ext_reg) { int r1, r2; float128 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("DXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op1, regs->fpr + FPR2I(r1)); get_float128(&op2, regs->fpr + FPR2I(r2)); pgm_check = divide_ebfp(&op1, &op2, regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(divide_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* DIVIDE (long) */ /*-------------------------------------------------------------------*/ static int divide_lbfp(float64 *op1, float64 *op2, REGS *regs) { int code; float64 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float64_div(*op1, *op2); code = float_exception(regs); *op1 = result; return code; } /* end function divide_lbfp */ /*-------------------------------------------------------------------*/ /* B31D DDBR - DIVIDE (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_bfp_long_reg) { int r1, r2; float64 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("DDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); pgm_check = divide_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(divide_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED1D DDB - DIVIDE (long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_bfp_long) { int r1, b2; VADR effective_addr2; float64 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("DDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); pgm_check = divide_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(divide_bfp_long) */ /*-------------------------------------------------------------------*/ /* DIVIDE (short) */ /*-------------------------------------------------------------------*/ static int divide_sbfp(float32 *op1, float32 *op2, REGS *regs) { int code; float32 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float32_div(*op1, *op2); code = float_exception(regs); *op1 = result; return code; } /* end function divide_sbfp */ /*-------------------------------------------------------------------*/ /* B30D DEBR - DIVIDE (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_bfp_short_reg) { int r1, r2; float32 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("DEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); pgm_check = divide_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(divide_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED0D DEB - DIVIDE (short BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_bfp_short) { int r1, b2; VADR effective_addr2; float32 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("DEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); pgm_check = divide_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(divide_bfp_short) */ /*-------------------------------------------------------------------*/ /* B342 LTXBR - LOAD AND TEST (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_bfp_ext_reg) { int r1, r2; float128 op1, op2; int pgm_check = 0; RRE(inst, regs, r1, r2); //logmsg("LTXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); if (float128_is_signaling_nan(op2)) { float_raise(float_flag_invalid); pgm_check = float_exception(regs); op1 = float128_snan_to_qnan(op2); } else { op1 = op2; } if (pgm_check) { regs->program_interrupt(regs, pgm_check); } regs->psw.cc = float128_is_nan(op1) ? 3 : float128_is_zero(op1) ? 0 : float128_is_neg(op1) ? 1 : 2; put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_and_test_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B312 LTDBR - LOAD AND TEST (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_bfp_long_reg) { int r1, r2; float64 op1, op2; int pgm_check = 0; RRE(inst, regs, r1, r2); //logmsg("LTDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); if (float64_is_signaling_nan(op2)) { float_raise(float_flag_invalid); pgm_check = float_exception(regs); op1 = float64_snan_to_qnan(op2); } else { op1 = op2; } if (pgm_check) { regs->program_interrupt(regs, pgm_check); } regs->psw.cc = float64_is_nan(op1) ? 3 : float64_is_zero(op1) ? 0 : float64_is_neg(op1) ? 1 : 2; put_float64(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_and_test_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B302 LTEBR - LOAD AND TEST (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_bfp_short_reg) { int r1, r2; float32 op1, op2; int pgm_check = 0; RRE(inst, regs, r1, r2); //logmsg("LTEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); if (float32_is_signaling_nan(op2)) { float_raise(float_flag_invalid); pgm_check = float_exception(regs); op1 = float32_snan_to_qnan(op2); } else { op1 = op2; } if (pgm_check) { regs->program_interrupt(regs, pgm_check); } regs->psw.cc = float32_is_nan(op1) ? 3 : float32_is_zero(op1) ? 0 : float32_is_neg(op1) ? 1 : 2; put_float32(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_and_test_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* B357 FIEBR - LOAD FP INTEGER (short BFP) [RRF] */ /* B357 FIEBRA - LOAD FP INTEGER (short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_bfp_short_reg) { int r1, r2, m3, m4, pgm_check; float32 op1, op2; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("FIEBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float32(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float32_round_to_int(op2); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); pgm_check = float_exception_masked(regs, m4); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_fp_int_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* B35F FIDBR - LOAD FP INTEGER (long BFP) [RRF] */ /* B35F FIDBRA - LOAD FP INTEGER (long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_bfp_long_reg) { int r1, r2, m3, m4, pgm_check; float64 op1, op2; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("FIDBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3,regs); get_float64(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float64_round_to_int(op2); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); pgm_check = float_exception_masked(regs, m4); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_fp_int_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B347 FIXBR - LOAD FP INTEGER (extended BFP) [RRF] */ /* B347 FIXBRA - LOAD FP INTEGER (extended BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_bfp_ext_reg) { int r1, r2, m3, m4, pgm_check; float128 op1, op2; RRF_MMA(inst, regs, r1, r2, m3, m4); //logmsg("FIXBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); BFPRM_CHECK(m3,regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float128_round_to_int(op2); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); pgm_check = float_exception_masked(regs, m4); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_fp_int_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B29D LFPC - LOAD FPC [S] */ /* This instruction is in module esame.c */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* B304 LDEBR - LOAD LENGTHENED (short to long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_bfp_short_to_long_reg) { int r1, r2; float64 op1; float32 op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("LDEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); float_clear_exception_flags(); get_float32(&op2, regs->fpr + FPR2I(r2)); op1 = float32_to_float64(op2); pgm_check = float_exception(regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_lengthened_bfp_short_to_long_reg) */ /*-------------------------------------------------------------------*/ /* ED04 LDEB - LOAD LENGTHENED (short to long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_bfp_short_to_long) { int r1, b2; VADR effective_addr2; float64 op1; float32 op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("LDEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); float_clear_exception_flags(); vfetch_float32(&op2, effective_addr2, b2, regs); op1 = float32_to_float64(op2); pgm_check = float_exception(regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_lengthened_bfp_short_to_long) */ /*-------------------------------------------------------------------*/ /* B305 LXDBR - LOAD LENGTHENED (long to extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_bfp_long_to_ext_reg) { int r1, r2; float128 op1; float64 op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("LXDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); float_clear_exception_flags(); get_float64(&op2, regs->fpr + FPR2I(r2)); op1 = float64_to_float128(op2); pgm_check = float_exception(regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_lengthened_bfp_long_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* ED05 LXDB - LOAD LENGTHENED (long to extended BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_bfp_long_to_ext) { int r1, b2; VADR effective_addr2; float128 op1; float64 op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("LXDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); float_clear_exception_flags(); vfetch_float64(&op2, effective_addr2, b2, regs); op1 = float64_to_float128(op2); pgm_check = float_exception(regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_lengthened_bfp_long_to_ext) */ /*-------------------------------------------------------------------*/ /* B306 LXEBR - LOAD LENGTHENED (short to extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_bfp_short_to_ext_reg) { int r1, r2; float128 op1; float32 op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("LXEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); float_clear_exception_flags(); get_float32(&op2, regs->fpr + FPR2I(r2)); op1 = float32_to_float128(op2); pgm_check = float_exception(regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_lengthened_bfp_short_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* ED06 LXEB - LOAD LENGTHENED (short to extended BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_bfp_short_to_ext) { int r1, b2; VADR effective_addr2; float128 op1; float32 op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("LXEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); float_clear_exception_flags(); vfetch_float32(&op2, effective_addr2, b2, regs); op1 = float32_to_float128(op2); pgm_check = float_exception(regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_lengthened_bfp_short_to_ext) */ /*-------------------------------------------------------------------*/ /* B341 LNXBR - LOAD NEGATIVE (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_bfp_ext_reg) { int r1, r2; float128 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LNXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op2, regs->fpr + FPR2I(r2)); op1 = float128_neg(op2); regs->psw.cc = float128_is_nan(op1) ? 3 : float128_is_zero(op1) ? 0 : 1; put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_negative_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B311 LNDBR - LOAD NEGATIVE (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_bfp_long_reg) { int r1, r2; float64 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LNDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op2, regs->fpr + FPR2I(r2)); op1 = float64_neg(op2); regs->psw.cc = float64_is_nan(op1) ? 3 : float64_is_zero(op1) ? 0 : 1; put_float64(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_negative_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B301 LNEBR - LOAD NEGATIVE (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_bfp_short_reg) { int r1, r2; float32 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LNEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op2, regs->fpr + FPR2I(r2)); op1 = float32_neg(op2); regs->psw.cc = float32_is_nan(op1) ? 3 : float32_is_zero(op1) ? 0 : 1; put_float32(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_negative_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* B343 LCXBR - LOAD COMPLEMENT (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_bfp_ext_reg) { int r1, r2; float128 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LCXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op2, regs->fpr + FPR2I(r2)); op1 = float128_is_neg(op2) ? float128_pos(op2) : float128_neg(op2); regs->psw.cc = float128_is_nan(op1) ? 3 : float128_is_zero(op1) ? 0 : float128_is_neg(op1) ? 1 : 2; put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_complement_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B313 LCDBR - LOAD COMPLEMENT (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_bfp_long_reg) { int r1, r2; float64 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LCDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op2, regs->fpr + FPR2I(r2)); op1 = float64_is_neg(op2) ? float64_pos(op2) : float64_neg(op2); regs->psw.cc = float64_is_nan(op1) ? 3 : float64_is_zero(op1) ? 0 : float64_is_neg(op1) ? 1 : 2; put_float64(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_complement_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B303 LCEBR - LOAD COMPLEMENT (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_bfp_short_reg) { int r1, r2; float32 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LCEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op2, regs->fpr + FPR2I(r2)); op1 = float32_is_neg(op2) ? float32_pos(op2) : float32_neg(op2); regs->psw.cc = float32_is_nan(op1) ? 3 : float32_is_zero(op1) ? 0 : float32_is_neg(op1) ? 1 : 2; put_float32(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_complement_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* B340 LPXBR - LOAD POSITIVE (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_bfp_ext_reg) { int r1, r2; float128 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LPXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op2, regs->fpr + FPR2I(r2)); op1 = float128_pos(op2); regs->psw.cc = float128_is_nan(op1) ? 3 : float128_is_zero(op1) ? 0 : 2; put_float128(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_positive_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B310 LPDBR - LOAD POSITIVE (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_bfp_long_reg) { int r1, r2; float64 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LPDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op2, regs->fpr + FPR2I(r2)); op1 = float64_pos(op2); regs->psw.cc = float64_is_nan(op1) ? 3 : float64_is_zero(op1) ? 0 : 2; put_float64(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_positive_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B300 LPEBR - LOAD POSITIVE (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_bfp_short_reg) { int r1, r2; float32 op1, op2; RRE(inst, regs, r1, r2); //logmsg("LPEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op2, regs->fpr + FPR2I(r2)); op1 = float32_pos(op2); regs->psw.cc = float32_is_nan(op1) ? 3 : float32_is_zero(op1) ? 0 : 2; put_float32(&op1, regs->fpr + FPR2I(r1)); } /* end DEF_INST(load_positive_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* B344 LEDBR - LOAD ROUNDED (long to short BFP) [RRE] */ /* B344 LEDBRA - LOAD ROUNDED (long to short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_bfp_long_to_short_reg) { int r1, r2, m3, m4; float32 op1; float64 op2; int pgm_check; RRE_MMA(inst, regs, r1, r2, m3, m4); //logmsg("LEDBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPRM_CHECK(m3, regs); get_float64(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float64_to_float32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check && (regs->fpc & (FPC_DXC_O | FPC_DXC_U))) { op2 = float32_to_float64(op1); put_float64(&op2, regs->fpr + FPR2I(r1)); } if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_rounded_bfp_long_to_short_reg) */ /*-------------------------------------------------------------------*/ /* B345 LDXBR - LOAD ROUNDED (extended to long BFP) [RRE] */ /* B345 LDXBRA - LOAD ROUNDED (extended to long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_bfp_ext_to_long_reg) { int r1, r2, m3, m4; float64 op1; float128 op2; int pgm_check; RRE_MMA(inst, regs, r1, r2, m3, m4); //logmsg("LDXBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); BFPRM_CHECK(m3, regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float128_to_float64(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check && (regs->fpc & (FPC_DXC_O | FPC_DXC_U))) { op2 = float64_to_float128(op1); put_float128(&op2, regs->fpr + FPR2I(r1)); } if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_rounded_bfp_ext_to_long_reg) */ /*-------------------------------------------------------------------*/ /* B346 LEXBR - LOAD ROUNDED (extended to short BFP) [RRE] */ /* B346 LEXBRA - LOAD ROUNDED (extended to short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_bfp_ext_to_short_reg) { int r1, r2, m3, m4; float32 op1; float128 op2; int pgm_check; RRE_MMA(inst, regs, r1, r2, m3, m4); //logmsg("LEXBR(A) r1=%d r2=%d m3=%d m4=%d\n", r1, r2, m3, m4); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); BFPRM_CHECK(m3, regs); get_float128(&op2, regs->fpr + FPR2I(r2)); float_clear_exception_flags(); set_rounding_mode(regs->fpc, m3); op1 = float128_to_float32(op2); pgm_check = float_exception_masked(regs, m4); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check && (regs->fpc & (FPC_DXC_O | FPC_DXC_U))) { op2 = float32_to_float128(op1); put_float128(&op2, regs->fpr + FPR2I(r1)); } if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(load_rounded_bfp_ext_to_short_reg) */ /*-------------------------------------------------------------------*/ /* MULTIPLY (extended) */ /*-------------------------------------------------------------------*/ static int multiply_ebfp(float128 *op1, float128 *op2, REGS *regs) { int code; float128 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float128_mul(*op1, *op2); code = float_exception(regs); *op1 = result; return code; } /* end function multiply_ebfp */ /*-------------------------------------------------------------------*/ /* B34C MXBR - MULTIPLY (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_ext_reg) { int r1, r2; float128 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("MXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op1, regs->fpr + FPR2I(r1)); get_float128(&op2, regs->fpr + FPR2I(r2)); pgm_check = multiply_ebfp(&op1, &op2, regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B307 MXDBR - MULTIPLY (long to extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_long_to_ext_reg) { int r1, r2; float64 op1, op2; float128 eb1, eb2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("MXDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); eb1 = float64_to_float128(op1); eb2 = float64_to_float128(op2); pgm_check = multiply_ebfp(&eb1, &eb2, regs); put_float128(&eb1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_long_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* ED07 MXDB - MULTIPLY (long to extended BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_long_to_ext) { int r1, b2; VADR effective_addr2; float64 op1, op2; float128 eb1, eb2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("MXDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); eb1 = float64_to_float128(op1); eb2 = float64_to_float128(op2); pgm_check = multiply_ebfp(&eb1, &eb2, regs); put_float128(&eb1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_long_to_ext) */ /*-------------------------------------------------------------------*/ /* MULTIPLY (long) */ /*-------------------------------------------------------------------*/ static int multiply_lbfp(float64 *op1, float64 *op2, REGS *regs) { int code; float64 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float64_mul(*op1, *op2); code = float_exception(regs); *op1 = result; return code; } /* end function multiply_lbfp */ /*-------------------------------------------------------------------*/ /* B31C MDBR - MULTIPLY (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_long_reg) { int r1, r2; float64 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("MDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); pgm_check = multiply_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED1C MDB - MULTIPLY (long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_long) { int r1, b2; VADR effective_addr2; float64 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("MDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); pgm_check = multiply_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_long) */ /*-------------------------------------------------------------------*/ /* B30C MDEBR - MULTIPLY (short to long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_short_to_long_reg) { int r1, r2; float32 op1, op2; float64 lb1, lb2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("MDEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); lb1 = float32_to_float64(op1); lb2 = float32_to_float64(op2); pgm_check = multiply_lbfp(&lb1, &lb2, regs); put_float64(&lb1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_short_to_long_reg) */ /*-------------------------------------------------------------------*/ /* ED0C MDEB - MULTIPLY (short to long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_short_to_long) { int r1, b2; VADR effective_addr2; float32 op1, op2; float64 lb1, lb2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("MDEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); lb1 = float32_to_float64(op1); lb2 = float32_to_float64(op2); pgm_check = multiply_lbfp(&lb1, &lb2, regs); put_float64(&lb1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_short_to_long) */ /*-------------------------------------------------------------------*/ /* MULTIPLY (short) */ /*-------------------------------------------------------------------*/ static int multiply_sbfp(float32 *op1, float32 *op2, REGS *regs) { int code; float32 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float32_mul(*op1, *op2); code = float_exception(regs); *op1 = result; return code; } /* end function multiply_sbfp */ /*-------------------------------------------------------------------*/ /* B317 MEEBR - MULTIPLY (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_short_reg) { int r1, r2; float32 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("MEEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); pgm_check = multiply_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED17 MEEB - MULTIPLY (short BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_bfp_short) { int r1, b2; VADR effective_addr2; float32 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("MEEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); pgm_check = multiply_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_bfp_short) */ /*-------------------------------------------------------------------*/ /* MULTIPLY AND ADD (long) */ /*-------------------------------------------------------------------*/ static int multiply_add_lbfp(float64 *op1, float64 *op2, float64 *op3, REGS *regs) { int code; float64 product, result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); product = float64_mul(*op2, *op3); result = float64_add(product, *op1); code = float_exception(regs); *op1 = result; return code; } /* end function multiply_add_lbfp */ /*-------------------------------------------------------------------*/ /* B31E MADBR - MULTIPLY AND ADD (long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_bfp_long_reg) { int r1, r2, r3; float64 op1, op2, op3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); //logmsg("MADBR r1=%d r3=%d r2=%d\n", r1, r3, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); get_float64(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_add_lbfp(&op1, &op2, &op3, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_add_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED1E MADB - MULTIPLY AND ADD (long BFP) [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_bfp_long) { int r1, r3, b2; VADR effective_addr2; float64 op1, op2, op3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); //logmsg("MADB r1=%d r3=%d b2=%d\n", r1, r3, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); get_float64(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_add_lbfp(&op1, &op2, &op3, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_add_bfp_long) */ /*-------------------------------------------------------------------*/ /* MULTIPLY AND ADD (short) */ /*-------------------------------------------------------------------*/ static int multiply_add_sbfp(float32 *op1, float32 *op2, float32 *op3, REGS *regs) { int code; float32 product, result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); product = float32_mul(*op2, *op3); result = float32_add(product, *op1); code = float_exception(regs); *op1 = result; return code; } /* end function multiply_add_sbfp */ /*-------------------------------------------------------------------*/ /* B30E MAEBR - MULTIPLY AND ADD (short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_bfp_short_reg) { int r1, r2, r3; float32 op1, op2, op3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); //logmsg("MAEBR r1=%d r3=%d r2=%d\n", r1, r3, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); get_float32(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_add_sbfp(&op1, &op2, &op3, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_add_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED0E MAEB - MULTIPLY AND ADD (short BFP) [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_add_bfp_short) { int r1, r3, b2; VADR effective_addr2; float32 op1, op2, op3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); //logmsg("MAEB r1=%d r3=%d b2=%d\n", r1, r3, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); get_float32(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_add_sbfp(&op1, &op2, &op3, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_add_bfp_short) */ /*-------------------------------------------------------------------*/ /* MULTIPLY AND SUBTRACT (long) */ /*-------------------------------------------------------------------*/ static int multiply_subtract_lbfp(float64 *op1, float64 *op2, float64 *op3, REGS *regs) { int code; float64 product, result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); product = float64_mul(*op2, *op3); result = float64_sub(product, *op1); code = float_exception(regs); *op1 = result; return code; } /* end function multiply_subtract_lbfp */ /*-------------------------------------------------------------------*/ /* B31F MSDBR - MULTIPLY AND SUBTRACT (long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_bfp_long_reg) { int r1, r2, r3; float64 op1, op2, op3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); //logmsg("MSDBR r1=%d r3=%d r2=%d\n", r1, r3, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); get_float64(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_subtract_lbfp(&op1, &op2, &op3, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_subtract_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED1F MSDB - MULTIPLY AND SUBTRACT (long BFP) [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_bfp_long) { int r1, r3, b2; VADR effective_addr2; float64 op1, op2, op3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); //logmsg("MSDB r1=%d r3=%d b2=%d\n", r1, r3, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); get_float64(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_subtract_lbfp(&op1, &op2, &op3, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_subtract_bfp_long) */ /*-------------------------------------------------------------------*/ /* MULTIPLY AND SUBTRACT (short) */ /*-------------------------------------------------------------------*/ static int multiply_subtract_sbfp(float32 *op1, float32 *op2, float32 *op3, REGS *regs) { int code; float32 product, result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); product = float32_mul(*op2, *op3); result = float32_sub(product, *op1); code = float_exception(regs); *op1 = result; return code; } /* end function multiply_subtract_sbfp */ /*-------------------------------------------------------------------*/ /* B30F MSEBR - MULTIPLY AND SUBTRACT (short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_bfp_short_reg) { int r1, r2, r3; float32 op1, op2, op3; int pgm_check; RRF_R(inst, regs, r1, r2, r3); //logmsg("MSEBR r1=%d r3=%d r2=%d\n", r1, r3, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); get_float32(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_subtract_sbfp(&op1, &op2, &op3, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_subtract_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED0F MSEB - MULTIPLY AND SUBTRACT (short BFP) [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_subtract_bfp_short) { int r1, r3, b2; VADR effective_addr2; float32 op1, op2, op3; int pgm_check; RXF(inst, regs, r1, r3, b2, effective_addr2); //logmsg("MSEB r1=%d r3=%d b2=%d\n", r1, r3, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); get_float32(&op3, regs->fpr + FPR2I(r3)); pgm_check = multiply_subtract_sbfp(&op1, &op2, &op3, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(multiply_subtract_bfp_short) */ /*-------------------------------------------------------------------*/ /* B384 SFPC - SET FPC [RRE] */ /* This instruction is in module esame.c */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* B299 SRNM - SET BFP ROUNDING MODE (2-BIT) [S] */ /* B2B8 SRNMB - SET BFP ROUNDING MODE (3-BIT) [S] */ /* These instructions are in module esame.c */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* SQUARE ROOT (extended) */ /*-------------------------------------------------------------------*/ static int squareroot_ebfp(float128 *op, REGS *regs) { int code; float128 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float128_sqrt(*op); code = float_exception(regs); *op = result; return code; } /* end function squareroot_ebfp */ /*-------------------------------------------------------------------*/ /* B316 SQXBR - SQUARE ROOT (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_bfp_ext_reg) { int r1, r2; float128 op; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("SQXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op, regs->fpr + FPR2I(r2)); pgm_check = squareroot_ebfp(&op, regs); put_float128(&op, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(squareroot_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* SQUARE ROOT (long) */ /*-------------------------------------------------------------------*/ static int squareroot_lbfp(float64 *op, REGS *regs) { int code; float64 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float64_sqrt(*op); code = float_exception(regs); *op = result; return code; } /* end function squareroot_lbfp */ /*-------------------------------------------------------------------*/ /* B315 SQDBR - SQUARE ROOT (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_bfp_long_reg) { int r1, r2; float64 op; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("SQDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op, regs->fpr + FPR2I(r2)); pgm_check = squareroot_lbfp(&op, regs); put_float64(&op, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(squareroot_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED15 SQDB - SQUARE ROOT (long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_bfp_long) { int r1, b2; VADR effective_addr2; float64 op; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("SQDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); vfetch_float64(&op, effective_addr2, b2, regs); pgm_check = squareroot_lbfp(&op, regs); put_float64(&op, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(squareroot_bfp_long) */ /*-------------------------------------------------------------------*/ /* SQUARE ROOT (short) */ /*-------------------------------------------------------------------*/ static int squareroot_sbfp(float32 *op, REGS *regs) { int code; float32 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float32_sqrt(*op); code = float_exception(regs); *op = result; return code; } /* end function squareroot_sbfp */ /*-------------------------------------------------------------------*/ /* B314 SQEBR - SQUARE ROOT (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_bfp_short_reg) { int r1, r2; float32 op; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("SQEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op, regs->fpr + FPR2I(r2)); pgm_check = squareroot_sbfp(&op, regs); put_float32(&op, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(squareroot_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED14 SQEB - SQUARE ROOT (short BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(squareroot_bfp_short) { int r1, b2; VADR effective_addr2; float32 op; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("SQEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); vfetch_float32(&op, effective_addr2, b2, regs); pgm_check = squareroot_sbfp(&op, regs); put_float32(&op, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(squareroot_bfp_short) */ /*-------------------------------------------------------------------*/ /* B29C STFPC - STORE FPC [S] */ /* This instruction is in module esame.c */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* SUBTRACT (extended) */ /*-------------------------------------------------------------------*/ static int subtract_ebfp(float128 *op1, float128 *op2, REGS *regs) { int code; float128 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float128_sub(*op1, *op2); code = float_exception(regs); *op1 = result; regs->psw.cc = float128_is_nan(result) ? 3 : float128_is_zero(result) ? 0 : float128_is_neg(result) ? 1 : 2; return code; } /* end function subtract_ebfp */ /*-------------------------------------------------------------------*/ /* B34B SXBR - SUBTRACT (extended BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_bfp_ext_reg) { int r1, r2; float128 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("SXBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); BFPREGPAIR2_CHECK(r1, r2, regs); get_float128(&op1, regs->fpr + FPR2I(r1)); get_float128(&op2, regs->fpr + FPR2I(r2)); pgm_check = subtract_ebfp(&op1, &op2, regs); put_float128(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(subtract_bfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* SUBTRACT (long) */ /*-------------------------------------------------------------------*/ static int subtract_lbfp(float64 *op1, float64 *op2, REGS *regs) { int code; float64 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float64_sub(*op1, *op2); code = float_exception(regs); *op1 = result; regs->psw.cc = float64_is_nan(result) ? 3 : float64_is_zero(result) ? 0 : float64_is_neg(result) ? 1 : 2; return code; } /* end function subtract_lbfp */ /*-------------------------------------------------------------------*/ /* B31B SDBR - SUBTRACT (long BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_bfp_long_reg) { int r1, r2; float64 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("SDBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); pgm_check = subtract_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(subtract_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED1B SDB - SUBTRACT (long BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_bfp_long) { int r1, b2; VADR effective_addr2; float64 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("SDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); vfetch_float64(&op2, effective_addr2, b2, regs); pgm_check = subtract_lbfp(&op1, &op2, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(subtract_bfp_long) */ /*-------------------------------------------------------------------*/ /* SUBTRACT (short) */ /*-------------------------------------------------------------------*/ static int subtract_sbfp(float32 *op1, float32 *op2, REGS *regs) { int code; float32 result; float_clear_exception_flags(); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); result = float32_sub(*op1, *op2); code = float_exception(regs); *op1 = result; regs->psw.cc = float32_is_nan(result) ? 3 : float32_is_zero(result) ? 0 : float32_is_neg(result) ? 1 : 2; return code; } /* end function subtract_sbfp */ /*-------------------------------------------------------------------*/ /* B30B SEBR - SUBTRACT (short BFP) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_bfp_short_reg) { int r1, r2; float32 op1, op2; int pgm_check; RRE(inst, regs, r1, r2); //logmsg("SEBR r1=%d r2=%d\n", r1, r2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); pgm_check = subtract_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(subtract_bfp_short_reg) */ /*-------------------------------------------------------------------*/ /* ED0B SEB - SUBTRACT (short BFP) [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_bfp_short) { int r1, b2; VADR effective_addr2; float32 op1, op2; int pgm_check; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("SEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); vfetch_float32(&op2, effective_addr2, b2, regs); pgm_check = subtract_sbfp(&op1, &op2, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(subtract_bfp_short) */ /*-------------------------------------------------------------------*/ /* ED10 TCEB - TEST DATA CLASS (short BFP) [RXE] */ /* Per Jessen, Willem Konynenberg, 20 September 2001 */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_class_bfp_short) { int r1, b2; VADR effective_addr2; float32 op1; int bit; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("TCEB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float32(&op1, regs->fpr + FPR2I(r1)); if (float32_is_signaling_nan(op1)) bit=30; else if (float32_is_nan(op1)) bit=28; else if (float32_is_inf(op1)) bit=26; else if (float32_is_subnormal(op1)) bit=24; else if (float32_is_zero(op1)) bit=20; else bit=22; if (float32_is_neg(op1)) bit++; bit=31-bit; regs->psw.cc = (effective_addr2>>bit) & 1; } /* end DEF_INST(test_data_class_bfp_short) */ /*-------------------------------------------------------------------*/ /* ED11 TCDB - TEST DATA CLASS (long BFP) [RXE] */ /* Per Jessen, Willem Konynenberg, 20 September 2001 */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_class_bfp_long) { int r1, b2; VADR effective_addr2; float64 op1; int bit; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("TCDB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); get_float64(&op1, regs->fpr + FPR2I(r1)); if (float64_is_signaling_nan(op1)) bit=30; else if (float64_is_nan(op1)) bit=28; else if (float64_is_inf(op1)) bit=26; else if (float64_is_subnormal(op1)) bit=24; else if (float64_is_zero(op1)) bit=20; else bit=22; if (float64_is_neg(op1)) bit++; bit=31-bit; regs->psw.cc = (effective_addr2>>bit) & 1; } /* end DEF_INST(test_data_class_bfp_long) */ /*-------------------------------------------------------------------*/ /* ED12 TCXB - TEST DATA CLASS (extended BFP) [RXE] */ /* Per Jessen, Willem Konynenberg, 20 September 2001 */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_class_bfp_ext) { int r1, b2; VADR effective_addr2; float128 op1; int bit; RXE(inst, regs, r1, b2, effective_addr2); //logmsg("TCXB r1=%d b2=%d\n", r1, b2); BFPINST_CHECK(regs); BFPREGPAIR_CHECK(r1, regs); get_float128(&op1, regs->fpr + FPR2I(r1)); if (float128_is_signaling_nan(op1)) bit=30; else if (float128_is_nan(op1)) bit=28; else if (float128_is_inf(op1)) bit=26; else if (float128_is_subnormal(op1)) bit=24; else if (float128_is_zero(op1)) bit=20; else bit=22; if (float128_is_neg(op1)) bit++; bit=31-bit; regs->psw.cc = (effective_addr2>>bit) & 1; } /* end DEF_INST(test_data_class_bfp_ext) */ /*-------------------------------------------------------------------*/ /* DIVIDE TO INTEGER (long) */ /*-------------------------------------------------------------------*/ static int divint_lbfp(float64 *op1, float64 *op2, float64 *op3, int mode, REGS *regs) { int code; int cc; int flags; int divsign, dvrsign; float128 xop1, xop2, xop3, xtemp; float128 xmaxint64 = {0x4034000000000000ULL, 0ULL}; // 2**53 float128 xfract64 = {0xFFFFFFFFFFFFFFFFULL, 0xF000000000000000ULL}; // sign+exp+52 bits divsign = float64_is_neg(*op1) ? 1 : 0; dvrsign = float64_is_neg(*op2) ? 1 : 0; float_clear_exception_flags(); if (float64_is_signaling_nan(*op1)) { float_raise(float_flag_invalid); code = float_exception(regs); *op1 = float64_snan_to_qnan(*op1); *op3 = float64_snan_to_qnan(*op1); regs->psw.cc = 1; return code; } if (float64_is_signaling_nan(*op2)) { float_raise(float_flag_invalid); code = float_exception(regs); *op1 = float64_snan_to_qnan(*op2); *op3 = float64_snan_to_qnan(*op2); regs->psw.cc = 1; return code; } if (float64_is_nan(*op1)) { *op3 = *op1; regs->psw.cc = 1; return 0; } if (float64_is_nan(*op2)) { *op1 = *op2; *op3 = *op2; regs->psw.cc = 1; return 0; } if (float64_is_inf(*op1) || float64_is_zero(*op2)) { float_raise(float_flag_invalid); code = float_exception(regs); *op1 = float64_default_nan; *op3 = float64_default_nan; regs->psw.cc = 1; return code; } if (float64_is_inf(*op2)) { *op3 = (divsign != dvrsign) ? 0x8000000000000000ULL : 0ULL; regs->psw.cc = 0; return 0; } xop1 = float64_to_float128(*op1); xop2 = float64_to_float128(*op2); set_rounding_mode(regs->fpc, RM_ROUND_TOWARD_ZERO); xtemp = float128_div(xop1, xop2); flags = float_get_exception_flags(); if ((flags & float_flag_inexact) && (float128_le(xmaxint64, float128_pos(xtemp)))) { /* If quotient exceeds 2**53, truncate it to form a partial quotient consisting of an implied 1 with 52 fraction bits, and set the condition code to 2 */ xop3.high = xtemp.high & xfract64.high; xop3.low = xtemp.low & xfract64.low; cc = 2; } else { /* Otherwise round it to an integer according to the specified rounding mode, and set the condition code to 0 */ set_rounding_mode(regs->fpc, mode); float_clear_exception_flags(); xop3 = float128_round_to_int(xtemp); cc = 0; } set_rounding_mode(regs->fpc, RM_ROUND_TOWARD_ZERO); float_clear_exception_flags(); xtemp = float128_mul(xop2, xop3); float_clear_exception_flags(); xop1 = float128_sub(xop1, xtemp); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); float_clear_exception_flags(); code = float_exception(regs); if (float128_exp(xop3) > FLOAT128_BIAS + FLOAT64_BIAS) { /* If quotient exponent exceeds maximum for float64, reduce the exponent by 1536 and increase condition code by 1 */ xop3 = float128_build(float128_is_neg(xop3) ? 1 : 0, float128_exp(xop3) - 1536, float128_fract_high(xop3), float128_fract_low(xop3)); cc += 1; } *op1 = float128_to_float64(xop1); *op3 = float128_to_float64(xop3); /* A zero remainder is negative if the dividend is negative */ if (float64_is_zero(*op1)) { *op1 = divsign ? 0x8000000000000000ULL : 0ULL; } /* A zero quotient is negative if dividend and divisor have different signs */ if (float64_is_zero(*op3)) { *op3 = (divsign != dvrsign) ? 0x8000000000000000ULL : 0ULL; } regs->psw.cc = cc; return code; } /* end function divint_lbfp */ /*-------------------------------------------------------------------*/ /* B35B DIDBR - DIVIDE TO INTEGER (long BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_integer_bfp_long_reg) { int r1, r2, r3, m4; float64 op1, op2, op3; int pgm_check; RRF_RM(inst, regs, r1, r2, r3, m4); //logmsg("DIDBR r1=%d r3=%d r2=%d m4=%d\n", r1, r3, r2, m4); BFPINST_CHECK(regs); if (r1 == r2 || r2 == r3 || r1 == r3) { regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION); } BFPRM_CHECK(m4,regs); get_float64(&op1, regs->fpr + FPR2I(r1)); get_float64(&op2, regs->fpr + FPR2I(r2)); pgm_check = divint_lbfp(&op1, &op2, &op3, m4, regs); put_float64(&op1, regs->fpr + FPR2I(r1)); put_float64(&op3, regs->fpr + FPR2I(r3)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(divide_integer_bfp_long_reg) */ /*-------------------------------------------------------------------*/ /* DIVIDE TO INTEGER (short) */ /*-------------------------------------------------------------------*/ static int divint_sbfp(float32 *op1, float32 *op2, float32 *op3, int mode, REGS *regs) { int code; int cc; int flags; int divsign, dvrsign; float128 xop1, xop2, xop3, xtemp; float128 xmaxint32 = {0x4017000000000000ULL, 0ULL}; // 2**24 float128 xfract32 = {0xFFFFFFFFFE000000ULL, 0ULL}; // sign+exp+23 bits divsign = float32_is_neg(*op1) ? 1 : 0; dvrsign = float32_is_neg(*op2) ? 1 : 0; float_clear_exception_flags(); if (float32_is_signaling_nan(*op1)) { float_raise(float_flag_invalid); code = float_exception(regs); *op1 = float32_snan_to_qnan(*op1); *op3 = float32_snan_to_qnan(*op1); regs->psw.cc = 1; return code; } if (float32_is_signaling_nan(*op2)) { float_raise(float_flag_invalid); code = float_exception(regs); *op1 = float32_snan_to_qnan(*op2); *op3 = float32_snan_to_qnan(*op2); regs->psw.cc = 1; return code; } if (float32_is_nan(*op1)) { *op3 = *op1; regs->psw.cc = 1; return 0; } if (float32_is_nan(*op2)) { *op1 = *op2; *op3 = *op2; regs->psw.cc = 1; return 0; } if (float32_is_inf(*op1) || float32_is_zero(*op2)) { float_raise(float_flag_invalid); code = float_exception(regs); *op1 = float32_default_nan; *op3 = float32_default_nan; regs->psw.cc = 1; return code; } if (float32_is_inf(*op2)) { *op3 = (divsign != dvrsign) ? 0x80000000 : 0; regs->psw.cc = 0; return 0; } xop1 = float32_to_float128(*op1); xop2 = float32_to_float128(*op2); set_rounding_mode(regs->fpc, RM_ROUND_TOWARD_ZERO); xtemp = float128_div(xop1, xop2); //logmsg("DIEBR div flags=%2.2X\n", float_get_exception_flags()); flags = float_get_exception_flags(); if ((flags & float_flag_inexact) && (float128_le(xmaxint32, float128_pos(xtemp)))) { /* If quotient exceeds 2**24, truncate it to form a partial quotient consisting of an implied 1 with 23 fraction bits, and set the condition code to 2 */ xop3.high = xtemp.high & xfract32.high; xop3.low = 0; cc = 2; } else { /* Otherwise round it to an integer according to the specified rounding mode, and set the condition code to 0 */ set_rounding_mode(regs->fpc, mode); float_clear_exception_flags(); xop3 = float128_round_to_int(xtemp); //logmsg("DIEBR rou flags=%2.2X\n", float_get_exception_flags()); cc = 0; } set_rounding_mode(regs->fpc, RM_ROUND_TOWARD_ZERO); float_clear_exception_flags(); xtemp = float128_mul(xop2, xop3); //logmsg("DIEBR mul flags=%2.2X\n", float_get_exception_flags()); float_clear_exception_flags(); xop1 = float128_sub(xop1, xtemp); //logmsg("DIEBR sub flags=%2.2X\n", float_get_exception_flags()); set_rounding_mode(regs->fpc, RM_DEFAULT_ROUNDING); float_clear_exception_flags(); code = float_exception(regs); if (float128_exp(xop3) > FLOAT128_BIAS + FLOAT32_BIAS) { /* If quotient exponent exceeds maximum for float32, reduce the exponent by 192 and increase condition code by 1 */ xop3 = float128_build(float128_is_neg(xop3) ? 1 : 0, float128_exp(xop3) - 192, float128_fract_high(xop3), float128_fract_low(xop3)); cc += 1; } *op1 = float128_to_float32(xop1); *op3 = float128_to_float32(xop3); /* A zero remainder is negative if the dividend is negative */ if (float32_is_zero(*op1)) { *op1 = divsign ? 0x80000000 : 0; } /* A zero quotient is negative if dividend and divisor have different signs */ if (float32_is_zero(*op3)) { *op3 = (divsign != dvrsign) ? 0x80000000 : 0; } regs->psw.cc = cc; return code; } /* end function divint_sbfp */ /*-------------------------------------------------------------------*/ /* B353 DIEBR - DIVIDE TO INTEGER (short BFP) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_integer_bfp_short_reg) { int r1, r2, r3, m4; float32 op1, op2, op3; int pgm_check; RRF_RM(inst, regs, r1, r2, r3, m4); //logmsg("DIEBR r1=%d r3=%d r2=%d m4=%d\n", r1, r3, r2, m4); BFPINST_CHECK(regs); if (r1 == r2 || r2 == r3 || r1 == r3) { regs->program_interrupt(regs, PGM_SPECIFICATION_EXCEPTION); } BFPRM_CHECK(m4,regs); get_float32(&op1, regs->fpr + FPR2I(r1)); get_float32(&op2, regs->fpr + FPR2I(r2)); pgm_check = divint_sbfp(&op1, &op2, &op3, m4, regs); put_float32(&op1, regs->fpr + FPR2I(r1)); put_float32(&op3, regs->fpr + FPR2I(r3)); if (pgm_check) { regs->program_interrupt(regs, pgm_check); } } /* end DEF_INST(divide_integer_bfp_short_reg) */ #endif /* FEATURE_BINARY_FLOATING_POINT */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "ieee.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "ieee.c" #endif #endif /*!defined(_GEN_ARCH) */ /* end of ieee.c */ hercules-3.12/dfp.c0000664000175000017500000060322612564723224011131 00000000000000/* DFP.C (c) Copyright Roger Bowler, 2007-2009 */ /* Decimal Floating Point instructions */ /*-------------------------------------------------------------------*/ /* This module implements the Decimal Floating Point instructions */ /* and the Floating Point Support Enhancement Facility instructions */ /* described in the z/Architecture Principles of Operation manual. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_DFP_C_) #define _DFP_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #if defined(FEATURE_DECIMAL_FLOATING_POINT) #include "decimal128.h" #include "decimal64.h" #include "decimal32.h" #include "decPacked.h" #endif /*defined(FEATURE_DECIMAL_FLOATING_POINT)*/ #if defined(FEATURE_FPS_ENHANCEMENT) /*===================================================================*/ /* FLOATING POINT SUPPORT INSTRUCTIONS */ /*===================================================================*/ /* Note: the Floating Point Support instructions use the HFPREG_CHECK and HFPREG2_CHECK macros to enforce an AFP-register data exception if an FPS instruction attempts to use one of the 12 additional FPR registers when the AFP-register-control bit in CR0 is zero. */ /*-------------------------------------------------------------------*/ /* B370 LPDFR - Load Positive FPR Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_positive_fpr_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* FP register subscripts */ RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, clear the sign bit */ regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF; regs->fpr[i1+1] = regs->fpr[i2+1]; } /* end DEF_INST(load_positive_fpr_long_reg) */ /*-------------------------------------------------------------------*/ /* B371 LNDFR - Load Negative FPR Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_negative_fpr_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* FP register subscripts */ RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, set the sign bit */ regs->fpr[i1] = regs->fpr[i2] | 0x80000000; regs->fpr[i1+1] = regs->fpr[i2+1]; } /* end DEF_INST(load_negative_fpr_long_reg) */ /*-------------------------------------------------------------------*/ /* B372 CPSDR - Copy Sign FPR Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(copy_sign_fpr_long_reg) { int r1, r2, r3; /* Values of R fields */ int i1, i2, i3; /* FP register subscripts */ U32 sign; /* Work area for sign bit */ RRF_M(inst, regs, r1, r2, r3); HFPREG2_CHECK(r1, r2, regs); HFPREG_CHECK(r3, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); i3 = FPR2I(r3); /* Copy the sign bit from r3 register */ sign = regs->fpr[i3] & 0x80000000; /* Copy r2 register contents to r1 register */ regs->fpr[i1] = regs->fpr[i2]; regs->fpr[i1+1] = regs->fpr[i2+1]; /* Insert the sign bit into r1 register */ regs->fpr[i1] &= 0x7FFFFFFF; regs->fpr[i1] |= sign; } /* end DEF_INST(copy_sign_fpr_long_reg) */ /*-------------------------------------------------------------------*/ /* B373 LCDFR - Load Complement FPR Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_complement_fpr_long_reg) { int r1, r2; /* Values of R fields */ int i1, i2; /* FP register subscripts */ RRE(inst, regs, r1, r2); HFPREG2_CHECK(r1, r2, regs); i1 = FPR2I(r1); i2 = FPR2I(r2); /* Copy register contents, invert sign bit */ regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000; regs->fpr[i1+1] = regs->fpr[i2+1]; } /* end DEF_INST(load_complement_fpr_long_reg) */ /*-------------------------------------------------------------------*/ /* B3C1 LDGR - Load FPR from GR Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fpr_from_gr_long_reg) { int r1, r2; /* Values of R fields */ int i1; /* FP register subscript */ RRE(inst, regs, r1, r2); HFPREG_CHECK(r1, regs); i1 = FPR2I(r1); /* Load FP register contents from general register */ regs->fpr[i1] = regs->GR_H(r2); regs->fpr[i1+1] = regs->GR_L(r2); } /* end DEF_INST(load_fpr_from_gr_long_reg) */ /*-------------------------------------------------------------------*/ /* B3CD LGDR - Load GR from FPR Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_gr_from_fpr_long_reg) { int r1, r2; /* Values of R fields */ int i2; /* FP register subscript */ RRE(inst, regs, r1, r2); HFPREG_CHECK(r2, regs); i2 = FPR2I(r2); /* Load general register contents from FP register */ regs->GR_H(r1) = regs->fpr[i2]; regs->GR_L(r1) = regs->fpr[i2+1]; } /* end DEF_INST(load_gr_from_fpr_long_reg) */ /*-------------------------------------------------------------------*/ /* B2B9 SRNMT - Set DFP Rounding Mode [S] */ /*-------------------------------------------------------------------*/ DEF_INST(set_dfp_rounding_mode) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ S(inst, regs, b2, effective_addr2); DFPINST_CHECK(regs); /* Set DFP rounding mode in FPC register from address bits 61-63 */ regs->fpc &= ~(FPC_DRM); regs->fpc |= ((effective_addr2 << FPC_DRM_SHIFT) & FPC_DRM); } /* end DEF_INST(set_dfp_rounding_mode) */ #endif /*defined(FEATURE_FPS_ENHANCEMENT)*/ #if defined(FEATURE_IEEE_EXCEPTION_SIMULATION) /*===================================================================*/ /* IEEE-EXCEPTION-SIMULATION FACILITY INSTRUCTIONS */ /*===================================================================*/ #if !defined(_IXS_ARCH_INDEPENDENT_) /*-------------------------------------------------------------------*/ /* Check if a simulated-IEEE-exception event is to be recognized */ /* */ /* This subroutine is called by the LFAS and SFASR instructions to */ /* determine whether the instruction should raise a data exception */ /* at the end of the instruction and, if so, the DXC code to be set. */ /* */ /* Input: */ /* cur_fpc Current value of the FPC register */ /* src_fpc Value of instruction source operand */ /* Output: */ /* The return value is the data exception code (DXC), or */ /* zero if no simulated-IEEE-exception event is recognized */ /*-------------------------------------------------------------------*/ static BYTE fpc_signal_check(U32 cur_fpc, U32 src_fpc) { U32 ff, sm, enabled_flags; /* Mask and flag work areas */ BYTE dxc; /* Data exception code or 0 */ /* AND the current FPC flags with the source FPC mask */ ff = (cur_fpc & FPC_FLAG) >> FPC_FLAG_SHIFT; sm = (src_fpc & FPC_MASK) >> FPC_MASK_SHIFT; enabled_flags = (ff & sm) << FPC_FLAG_SHIFT; /* A simulated-IEEE-exception event is recognized if any current flag corresponds to the source mask */ if (enabled_flags & FPC_FLAG_SFI) { dxc = DXC_IEEE_INV_OP_IISE; } else if (enabled_flags & FPC_FLAG_SFZ) { dxc = DXC_IEEE_DIV_ZERO_IISE; } else if (enabled_flags & FPC_FLAG_SFO) { dxc = (cur_fpc & FPC_FLAG_SFX) ? DXC_IEEE_OF_INEX_IISE : DXC_IEEE_OF_EXACT_IISE; } else if (enabled_flags & FPC_FLAG_SFU) { dxc = (cur_fpc & FPC_FLAG_SFX) ? DXC_IEEE_UF_INEX_IISE : DXC_IEEE_UF_EXACT_IISE; } else if (enabled_flags & FPC_FLAG_SFX) { dxc = DXC_IEEE_INEXACT_IISE; } else { dxc = 0; } /* Return data exception code or zero */ return dxc; } /* end function fpc_signal_check */ #define _IXS_ARCH_INDEPENDENT_ #endif /*!defined(_IXS_ARCH_INDEPENDENT_)*/ /*-------------------------------------------------------------------*/ /* B2BD LFAS - Load FPC and Signal [S] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fpc_and_signal) { int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ U32 src_fpc, new_fpc; /* New value for FPC */ BYTE dxc; /* Data exception code */ S(inst, regs, b2, effective_addr2); DFPINST_CHECK(regs); /* Load new FPC register contents from operand location */ src_fpc = ARCH_DEP(vfetch4) (effective_addr2, b2, regs); /* Program check if reserved bits are non-zero */ FPC_CHECK(src_fpc, regs); /* OR the flags from the current FPC register */ new_fpc = src_fpc | (regs->fpc & FPC_FLAG); /* Determine whether an event is to be signaled */ dxc = fpc_signal_check(regs->fpc, src_fpc); /* Update the FPC register */ regs->fpc = new_fpc; /* Signal a simulated-IEEE-exception event if needed */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_fpc_and_signal) */ /*-------------------------------------------------------------------*/ /* B385 SFASR - Set FPC and Signal [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(set_fpc_and_signal) { int r1, unused; /* Values of R fields */ U32 src_fpc, new_fpc; /* New value for FPC */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, unused); DFPINST_CHECK(regs); /* Load new FPC register contents from R1 register bits 32-63 */ src_fpc = regs->GR_L(r1); /* Program check if reserved bits are non-zero */ FPC_CHECK(src_fpc, regs); /* OR the flags from the current FPC register */ new_fpc = src_fpc | (regs->fpc & FPC_FLAG); /* Determine whether an event is to be signaled */ dxc = fpc_signal_check(regs->fpc, src_fpc); /* Update the FPC register */ regs->fpc = new_fpc; /* Signal a simulated-IEEE-exception event if needed */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(set_fpc_and_signal) */ #endif /*defined(FEATURE_IEEE_EXCEPTION_SIMULATION)*/ #if defined(FEATURE_DECIMAL_FLOATING_POINT) /*===================================================================*/ /* DECIMAL FLOATING POINT INSTRUCTIONS */ /*===================================================================*/ /* Note: the DFP instructions use the DFPINST_CHECK macro to check the setting of the AFP-register-control bit in CR0. If this bit is zero then the macro generates a DFP-instruction data exception. */ #if !defined(_DFP_ARCH_INDEPENDENT_) /*-------------------------------------------------------------------*/ /* Extract the leftmost digit from a decimal32/64/128 structure */ /*-------------------------------------------------------------------*/ static const int dfp_lmdtable[32] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, 0, 0}; static inline int dfp32_extract_lmd(decimal32 *xp) { unsigned int cf = (((FW*)xp)->F & 0x7C000000) >> 26; return dfp_lmdtable[cf]; } /* end function dfp32_extract_lmd */ static inline int dfp64_extract_lmd(decimal64 *xp) { unsigned int cf = (((DW*)xp)->F.H.F & 0x7C000000) >> 26; return dfp_lmdtable[cf]; } /* end function dfp64_extract_lmd */ static inline int dfp128_extract_lmd(decimal128 *xp) { unsigned int cf = (((QW*)xp)->F.HH.F & 0x7C000000) >> 26; return dfp_lmdtable[cf]; } /* end function dfp128_extract_lmd */ /*-------------------------------------------------------------------*/ /* Clear the CF and BXCF fields of a decimal32/64/128 structure */ /*-------------------------------------------------------------------*/ static inline void dfp32_clear_cf_and_bxcf(decimal32 *xp) { ((FW*)xp)->F &= 0x800FFFFF; /* Clear CF and BXCF fields */ } /* end function dfp32_clear_cf_and_bxcf */ static inline void dfp64_clear_cf_and_bxcf(decimal64 *xp) { ((DW*)xp)->F.H.F &= 0x8003FFFF; /* Clear CF and BXCF fields */ } /* end function dfp64_clear_cf_and_bxcf */ static inline void dfp128_clear_cf_and_bxcf(decimal128 *xp) { ((QW*)xp)->F.HH.F &= 0x80003FFF; /* Clear CF and BXCF fields */ } /* end function dfp128_clear_cf_and_bxcf */ /*-------------------------------------------------------------------*/ /* Set the CF and BXCF fields of a decimal32/64/128 structure */ /* Input: */ /* xp Pointer to a decimal32/64/128 structure */ /* cfs A 32-bit value, of which bits 0-25 are ignored, */ /* bits 26-30 contain the new CF field value (5-bits), */ /* bit 31 is the new BXCF signaling indicator (1-bit). */ /* Output: */ /* The CF field and the high-order bit of the BXCF field in */ /* the decimal32/64/128 structure are set to the indicated */ /* values and the remaining bits of the BXCF field are cleared. */ /*-------------------------------------------------------------------*/ #define DFP_CFS_INF ((30<<1)|0) /* CF and BXCF-S for Inf */ #define DFP_CFS_QNAN ((31<<1)|0) /* CF and BXCF-S for QNaN */ #define DFP_CFS_SNAN ((31<<1)|1) /* CF and BXCF-S for SNaN */ static inline void dfp32_set_cf_and_bxcf(decimal32 *xp, U32 cfs) { ((FW*)xp)->F &= 0x800FFFFF; /* Clear CF and BXCF fields */ ((FW*)xp)->F |= (cfs & 0x3F) << 25; /* Set CF and BXCF S-bit */ } /* end function dfp32_set_cf_and_bxcf */ static inline void dfp64_set_cf_and_bxcf(decimal64 *xp, U32 cfs) { ((DW*)xp)->F.H.F &= 0x8003FFFF; /* Clear CF and BXCF fields */ ((DW*)xp)->F.H.F |= (cfs & 0x3F) << 25; /* Set CF and BXCF S-bit */ } /* end function dfp64_set_cf_and_bxcf */ static inline void dfp128_set_cf_and_bxcf(decimal128 *xp, U32 cfs) { ((QW*)xp)->F.HH.F &= 0x80003FFF; /* Clear CF and BXCF fields */ ((QW*)xp)->F.HH.F |= (cfs & 0x3F) << 25; /* Set CF and BXCF S-bit */ } /* end function dfp128_set_cf_and_bxcf */ /*-------------------------------------------------------------------*/ /* Compare exponent and return condition code */ /* */ /* This subroutine is called by the CEETR, CEDTR, and CEXTR */ /* instructions. It compares the exponents of two decimal */ /* numbers and returns a condition code. */ /* */ /* Input: */ /* d1,d2 Pointers to decimal number structures */ /* Output: */ /* The return value is the condition code */ /*-------------------------------------------------------------------*/ static inline int dfp_compare_exponent(decNumber *d1, decNumber *d2) { int cc; /* Condition code */ if (decNumberIsNaN(d1) && decNumberIsNaN(d2)) cc = 0; else if (decNumberIsNaN(d1) || decNumberIsNaN(d2)) cc = 3; else if (decNumberIsInfinite(d1) && decNumberIsInfinite(d2)) cc = 0; else if (decNumberIsInfinite(d1) || decNumberIsInfinite(d2)) cc = 3; else cc = (d1->exponent == d2->exponent) ? 0 : (d1->exponent < d2->exponent) ? 1 : 2 ; return cc; } /* end function dfp_compare_exponent */ /*-------------------------------------------------------------------*/ /* Convert 64-bit signed binary integer to decimal number */ /* */ /* This subroutine is called by the CDGTR and CXGTR instructions. */ /* It converts a 64-bit signed binary integer value into a */ /* decimal number structure. The inexact condition will be set */ /* in the decimal context structure if the number is rounded to */ /* fit the maximum number of digits specified in the context. */ /* */ /* Input: */ /* dn Pointer to decimal number structure */ /* n 64-bit signed binary integer value */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The decimal number structure is updated. */ /*-------------------------------------------------------------------*/ static void dfp_number_from_fix64(decNumber *dn, S64 n, decContext *pset) { int sign = 0; /* Sign of binary integer */ int i; /* Counter */ char zoned[32]; /* Zoned decimal work area */ static char maxnegzd[]="-9223372036854775808"; static U64 maxneg64 = 0x8000000000000000ULL; /* Handle maximum negative number as special case */ if (n == (S64)maxneg64) { decNumberFromString(dn, maxnegzd, pset); return; } /* Convert binary value to zoned decimal */ if (n < 0) { n = -n; sign = 1; } i = sizeof(zoned) - 1; zoned[i] = '\0'; do { zoned[--i] = (n % 10) + '0'; n /= 10; } while(i > 1 && n > 0); if (sign) zoned[--i] = '-'; /* Convert zoned decimal value to decimal number structure */ decNumberFromString(dn, zoned+i, pset); } /* end function dfp_number_from_fix64 */ /*-------------------------------------------------------------------*/ /* Convert decimal number to 64-bit signed binary integer */ /* */ /* This subroutine is called by the CGDTR and CGXTR instructions. */ /* It converts a decimal number structure to a 64-bit signed */ /* binary integer value. The inexact condition will be set in */ /* the decimal context structure if the number is rounded to */ /* an integer. The invalid operation condition will be set if */ /* the decimal value is outside the range of a 64-bit integer. */ /* */ /* Input: */ /* b Pointer to decimal number structure */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The return value is the 64-bit signed binary integer result */ /*-------------------------------------------------------------------*/ static S64 dfp_number_to_fix64(decNumber *b, decContext *pset) { S64 n; /* 64-bit signed result */ int32_t scale; /* Scaling factor */ unsigned i; /* Array subscript */ BYTE packed[17]; /* 33-digit packed work area */ decNumber p, c; /* Working decimal numbers */ static U64 mp64 = 0x7FFFFFFFFFFFFFFFULL; /* Max pos fixed 64 */ static U64 mn64 = 0x8000000000000000ULL; /* Max neg fixed 64 */ static char mpzd[]="9223372036854775807"; /* Max pos zoned dec */ static char mnzd[]="-9223372036854775808"; /* Max neg zoned dec */ static BYTE mpflag = 0; /* 1=mp,mn are initialized */ static decNumber mp, mn; /* Decimal maximum pos,neg */ decContext setmax; /* Working context for mp,mn */ /* Prime the decimal number structures representing the maximum positive and negative numbers representable in 64 bits. Use a 128-bit DFP working context because these numbers are too big to be represented in the 32-bit and 64-bit DFP formats */ if (mpflag == 0) { decContextDefault(&setmax, DEC_INIT_DECIMAL128); decNumberFromString(&mp, mpzd, &setmax); decNumberFromString(&mn, mnzd, &setmax); mpflag = 1; } /* If operand is a NaN then set invalid operation and return maximum negative result */ if (decNumberIsNaN(b)) { pset->status |= DEC_IEEE_854_Invalid_operation; return (S64)mn64; } /* Remove fractional part of decimal number */ decNumberToIntegralValue(&p, b, pset); /* Special case if operand is less than maximum negative number (including where operand is negative infinity) */ decNumberCompare(&c, b, &mn, pset); if (decNumberIsNegative(&c)) { /* If rounded value is less than maximum negative number then set invalid operation otherwise set inexact */ decNumberCompare(&c, &p, &mn, pset); if (decNumberIsNegative(&c)) pset->status |= DEC_IEEE_854_Invalid_operation; else pset->status |= DEC_IEEE_854_Inexact; /* Return maximum negative result */ return (S64)mn64; } /* Special case if operand is greater than maximum positive number (including where operand is positive infinity) */ decNumberCompare(&c, b, &mp, pset); if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0) { /* If rounded value is greater than maximum positive number then set invalid operation otherwise set inexact */ decNumberCompare(&c, &p, &mp, pset); if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0) pset->status |= DEC_IEEE_854_Invalid_operation; else pset->status |= DEC_IEEE_854_Inexact; /* Return maximum positive result */ return (S64)mp64; } /* Raise inexact condition if result was rounded */ decNumberCompare(&c, &p, b, pset); if (decNumberIsZero(&c) == 0) { pset->status |= DEC_IEEE_854_Inexact; if (decNumberIsNegative(&c) == decNumberIsNegative(b)) pset->status |= DEC_Rounded; } /* Convert decimal number structure to packed decimal */ decPackedFromNumber(packed, sizeof(packed), &scale, &p); /* Convert packed decimal to binary value */ for (i = 0, n = 0; i < sizeof(packed)-1; i++) { n = n * 10 + ((packed[i] & 0xF0) >> 4); n = n * 10 + (packed[i] & 0x0F); } n = n * 10 + ((packed[i] & 0xF0) >> 4); while (scale++) n *= 10; if ((packed[i] & 0x0F) == 0x0D) n = -n; /* Return 64-bit signed result */ return n; } /* end function dfp_number_to_fix64 */ #define MAXDECSTRLEN DECIMAL128_String /* Maximum string length */ /*-------------------------------------------------------------------*/ /* Shift decimal coefficient left or right */ /* */ /* This subroutine is called by the SLDT, SLXT, SRDT and SRXT */ /* instructions. It shifts the coefficient digits of a decimal */ /* number left or right. For a left shift, zeroes are appended */ /* to the coefficient. For a right shift, digits are dropped */ /* from the end of the coefficient. No rounding is performed. */ /* The sign and exponent of the number remain unchanged. */ /* */ /* Input: */ /* pset Pointer to decimal number context structure */ /* dn Pointer to decimal number structure to be shifted */ /* count Number of digits to shift (+ve=left, -ve=right) */ /* Output: */ /* The decimal number structure is updated. */ /*-------------------------------------------------------------------*/ static inline void dfp_shift_coeff(decContext *pset, decNumber *dn, int count) { int len; /* String length */ int maxlen; /* Maximum coefficient length*/ int32_t exp; /* Original exponent */ uint8_t bits; /* Original flag bits */ char zd[MAXDECSTRLEN+64]; /* Zoned decimal work area */ /* Save original exponent and sign/Inf/NaN bits */ exp = dn->exponent; bits = dn->bits; /* Clear exponent and sign/Inf/NaN bits */ dn->exponent = 0; dn->bits &= ~(DECNEG | DECSPECIAL); /* Convert coefficient digits to zoned decimal */ decNumberToString(dn, zd); len = (int)strlen(zd); /* Shift zoned digits left or right */ if (count > 0) memset(zd + len, '0', count); len += count; maxlen = (bits & DECSPECIAL) ? pset->digits - 1 : pset->digits; if (len > maxlen) { memmove(zd, zd + len - maxlen, maxlen); len = maxlen; } else if (len < 1) { zd[0] = '0'; len = 1; } zd[len] = '\0'; /* Convert shifted coefficient to decimal number structure */ decNumberFromString(dn, zd, pset); /* Restore original exponent and sign/Inf/NaN bits */ dn->exponent = exp; dn->bits |= bits & (DECNEG | DECSPECIAL); } /* end function dfp_shift_coeff */ /* Bit numbers for Test Data Class instructions */ #define DFP_TDC_ZERO 52 #define DFP_TDC_SUBNORMAL 54 #define DFP_TDC_NORMAL 56 #define DFP_TDC_INFINITY 58 #define DFP_TDC_QUIET_NAN 60 #define DFP_TDC_SIGNALING_NAN 62 /*-------------------------------------------------------------------*/ /* Test data class and return condition code */ /* */ /* This subroutine is called by the TDCET, TDCDT, and TDCXT */ /* instructions. It tests the data class and sign of a decimal */ /* number. Each combination of data class and sign corresponds */ /* to one of 12 possible bits in a bitmask. The value (0 or 1) */ /* of the corresponding bit is returned. */ /* */ /* Input: */ /* pset Pointer to decimal number context structure */ /* dn Pointer to decimal number structure to be tested */ /* bits Bitmask in rightmost 12 bits */ /* Output: */ /* The return value is 0 or 1. */ /*-------------------------------------------------------------------*/ static inline int dfp_test_data_class(decContext *pset, decNumber *dn, U32 bits) { int bitn; /* Bit number */ decNumber dm; /* Normalized value of dn */ if (decNumberIsZero(dn)) bitn = DFP_TDC_ZERO; else if (decNumberIsInfinite(dn)) bitn = DFP_TDC_INFINITY; else if (decNumberIsQNaN(dn)) bitn = DFP_TDC_QUIET_NAN; else if (decNumberIsSNaN(dn)) bitn = DFP_TDC_SIGNALING_NAN; else { decNumberNormalize(&dm, dn, pset); bitn = (dm.exponent < pset->emin) ? DFP_TDC_SUBNORMAL : DFP_TDC_NORMAL ; } if (decNumberIsNegative(dn)) bitn++; return (bits >> (63 - bitn)) & 0x01; } /* end function dfp_test_data_class */ /* Bit numbers for Test Data Group instructions */ #define DFP_TDG_SAFE_ZERO 52 #define DFP_TDG_EXTREME_ZERO 54 #define DFP_TDG_EXTREME_NONZERO 56 #define DFP_TDG_SAFE_NZ_LMD_Z 58 #define DFP_TDG_SAFE_NZ_LMD_NZ 60 #define DFP_TDG_SPECIAL 62 /*-------------------------------------------------------------------*/ /* Test data group and return condition code */ /* */ /* This subroutine is called by the TDGET, TDGDT, and TDGXT */ /* instructions. It tests the exponent and leftmost coefficient */ /* digit of a decimal number to determine which of 12 possible */ /* groups the number corresponds to. Each group corresponds to */ /* one of 12 possible bits in a bitmask. The value (0 or 1) of */ /* the corresponding bit is returned. */ /* */ /* Input: */ /* pset Pointer to decimal number context structure */ /* dn Pointer to decimal number structure to be tested */ /* lmd Leftmost digit of decimal FP number */ /* bits Bitmask in rightmost 12 bits */ /* Output: */ /* The return value is 0 or 1. */ /*-------------------------------------------------------------------*/ static inline int dfp_test_data_group(decContext *pset, decNumber *dn, int lmd, U32 bits) { int bitn; /* Bit number */ int extreme; /* 1=exponent is min or max */ int exp; /* Adjusted exponent */ exp = dn->exponent + pset->digits - 1; extreme = (exp == pset->emin) || (exp == pset->emax); if (decNumberIsZero(dn)) bitn = extreme ? DFP_TDG_EXTREME_ZERO : DFP_TDG_SAFE_ZERO ; else if (decNumberIsInfinite(dn) || decNumberIsNaN(dn)) bitn = DFP_TDG_SPECIAL; else if (extreme) bitn = DFP_TDG_EXTREME_NONZERO; else { bitn = (lmd == 0) ? DFP_TDG_SAFE_NZ_LMD_Z : DFP_TDG_SAFE_NZ_LMD_NZ ; } if (decNumberIsNegative(dn)) bitn++; return (bits >> (63 - bitn)) & 0x01; } /* end function dfp_test_data_group */ #define _DFP_ARCH_INDEPENDENT_ #endif /*!defined(_DFP_ARCH_INDEPENDENT_)*/ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ #if !defined(_DFP_FPE_ARCH_INDEPENDENT_) /*-------------------------------------------------------------------*/ /* Convert 32-bit signed binary integer to decimal number */ /* */ /* This subroutine is called by the CDFTR and CXFTR instructions. */ /* It converts a 32-bit signed binary integer value into a */ /* decimal number structure. The inexact condition will be set */ /* in the decimal context structure if the number is rounded to */ /* fit the maximum number of digits specified in the context. */ /* */ /* Input: */ /* dn Pointer to decimal number structure */ /* n 32-bit signed binary integer value */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The decimal number structure is updated. */ /*-------------------------------------------------------------------*/ static void dfp_number_from_fix32(decNumber *dn, S32 n, decContext *pset) { int sign = 0; /* Sign of binary integer */ int i; /* Counter */ char zoned[32]; /* Zoned decimal work area */ static char maxnegzd[]="-2147483648"; static U32 maxneg32 = 0x80000000UL; /* Handle maximum negative number as special case */ if (n == (S32)maxneg32) { decNumberFromString(dn, maxnegzd, pset); return; } /* Convert binary value to zoned decimal */ if (n < 0) { n = -n; sign = 1; } i = sizeof(zoned) - 1; zoned[i] = '\0'; do { zoned[--i] = (n % 10) + '0'; n /= 10; } while(i > 1 && n > 0); if (sign) zoned[--i] = '-'; /* Convert zoned decimal value to decimal number structure */ decNumberFromString(dn, zoned+i, pset); } /* end function dfp_number_from_fix32 */ /*-------------------------------------------------------------------*/ /* Convert 32-bit unsigned binary integer to decimal number */ /* */ /* This subroutine is called by the CDLFTR and CXLFTR instructions. */ /* It converts a 32-bit unsigned binary integer value into a */ /* decimal number structure. The inexact condition will be set */ /* in the decimal context structure if the number is rounded to */ /* fit the maximum number of digits specified in the context. */ /* */ /* Input: */ /* dn Pointer to decimal number structure */ /* n 32-bit unsigned binary integer value */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The decimal number structure is updated. */ /*-------------------------------------------------------------------*/ static void dfp_number_from_u32(decNumber *dn, U32 n, decContext *pset) { int i; /* Counter */ char zoned[32]; /* Zoned decimal work area */ /* Convert unsigned binary value to zoned decimal */ i = sizeof(zoned) - 1; zoned[i] = '\0'; do { zoned[--i] = (n % 10) + '0'; n /= 10; } while(i > 1 && n > 0); /* Convert zoned decimal value to decimal number structure */ decNumberFromString(dn, zoned+i, pset); } /* end function dfp_number_from_u32 */ /*-------------------------------------------------------------------*/ /* Convert 64-bit unsigned binary integer to decimal number */ /* */ /* This subroutine is called by the CDLGTR and CXLGTR instructions. */ /* It converts a 64-bit unsigned binary integer value into a */ /* decimal number structure. The inexact condition will be set */ /* in the decimal context structure if the number is rounded to */ /* fit the maximum number of digits specified in the context. */ /* */ /* Input: */ /* dn Pointer to decimal number structure */ /* n 64-bit unsigned binary integer value */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The decimal number structure is updated. */ /*-------------------------------------------------------------------*/ static void dfp_number_from_u64(decNumber *dn, U64 n, decContext *pset) { int i; /* Counter */ char zoned[32]; /* Zoned decimal work area */ /* Convert unsigned binary value to zoned decimal */ i = sizeof(zoned) - 1; zoned[i] = '\0'; do { zoned[--i] = (n % 10) + '0'; n /= 10; } while(i > 1 && n > 0); /* Convert zoned decimal value to decimal number structure */ decNumberFromString(dn, zoned+i, pset); } /* end function dfp_number_from_u64 */ /*-------------------------------------------------------------------*/ /* Convert decimal number to 32-bit signed binary integer */ /* */ /* This subroutine is called by the CFDTR and CFXTR instructions. */ /* It converts a decimal number structure to a 32-bit signed */ /* binary integer value. The inexact condition will be set in */ /* the decimal context structure if the number is rounded to */ /* an integer. The invalid operation condition will be set if */ /* the decimal value is outside the range of a 32-bit integer. */ /* */ /* Input: */ /* b Pointer to decimal number structure */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The return value is the 32-bit signed binary integer result */ /*-------------------------------------------------------------------*/ static S32 dfp_number_to_fix32(decNumber *b, decContext *pset) { S32 n; /* 32-bit signed result */ int32_t scale; /* Scaling factor */ unsigned i; /* Array subscript */ BYTE packed[17]; /* 33-digit packed work area */ decNumber p, c; /* Working decimal numbers */ static U32 mp32 = 0x7FFFFFFFUL; /* Max positive fixed 32 */ static U32 mn32 = 0x80000000UL; /* Max negative fixed 32 */ static char mp32zd[]="2147483647"; /* Max positive zoned dec */ static char mn32zd[]="-2147483648"; /* Max negative zoned dec */ static BYTE mp32flag = 0; /* 1=mp32dn,mn32dn inited */ static decNumber mp32dn, mn32dn; /* Decimal maximum pos,neg */ decContext setmax; /* Working context */ /* Prime the decimal number structures representing the maximum positive and negative numbers representable in 32 bits. Use a 64-bit DFP working context because these numbers are too big to be represented in the 32-bit DFP format */ if (mp32flag == 0) { decContextDefault(&setmax, DEC_INIT_DECIMAL64); decNumberFromString(&mp32dn, mp32zd, &setmax); decNumberFromString(&mn32dn, mn32zd, &setmax); mp32flag = 1; } /* If operand is a NaN then set invalid operation and return maximum negative result */ if (decNumberIsNaN(b)) { pset->status |= DEC_IEEE_854_Invalid_operation; return (S32)mn32; } /* Remove fractional part of decimal number */ decNumberToIntegralValue(&p, b, pset); /* Special case if operand is less than maximum negative number (including where operand is negative infinity) */ decNumberCompare(&c, b, &mn32dn, pset); if (decNumberIsNegative(&c)) { /* If rounded value is less than maximum negative number then set invalid operation otherwise set inexact */ decNumberCompare(&c, &p, &mn32dn, pset); if (decNumberIsNegative(&c)) pset->status |= DEC_IEEE_854_Invalid_operation; else pset->status |= DEC_IEEE_854_Inexact; /* Return maximum negative result */ return (S32)mn32; } /* Special case if operand is greater than maximum positive number (including where operand is positive infinity) */ decNumberCompare(&c, b, &mp32dn, pset); if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0) { /* If rounded value is greater than maximum positive number then set invalid operation otherwise set inexact */ decNumberCompare(&c, &p, &mp32dn, pset); if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0) pset->status |= DEC_IEEE_854_Invalid_operation; else pset->status |= DEC_IEEE_854_Inexact; /* Return maximum positive result */ return (S32)mp32; } /* Raise inexact condition if result was rounded */ decNumberCompare(&c, &p, b, pset); if (decNumberIsZero(&c) == 0) { pset->status |= DEC_IEEE_854_Inexact; if (decNumberIsNegative(&c) == decNumberIsNegative(b)) pset->status |= DEC_Rounded; } /* Convert decimal number structure to packed decimal */ decPackedFromNumber(packed, sizeof(packed), &scale, &p); /* Convert packed decimal to binary value */ for (i = 0, n = 0; i < sizeof(packed)-1; i++) { n = n * 10 + ((packed[i] & 0xF0) >> 4); n = n * 10 + (packed[i] & 0x0F); } n = n * 10 + ((packed[i] & 0xF0) >> 4); while (scale++) n *= 10; if ((packed[i] & 0x0F) == 0x0D) n = -n; /* Return 32-bit signed result */ return n; } /* end function dfp_number_to_fix32 */ /*-------------------------------------------------------------------*/ /* Convert decimal number to 32-bit unsigned binary integer */ /* */ /* This subroutine is called by the CLFDTR and CLFXTR instructions. */ /* It converts a decimal number structure to a 32-bit unsigned */ /* binary integer value. The inexact condition will be set in */ /* the decimal context structure if the number is rounded to */ /* an integer. The invalid operation condition will be set if */ /* the decimal value is outside the range of a 32-bit unsigned int. */ /* */ /* Input: */ /* b Pointer to decimal number structure */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The return value is the 32-bit unsigned integer result */ /*-------------------------------------------------------------------*/ static U32 dfp_number_to_u32(decNumber *b, decContext *pset) { U32 n; /* 32-bit unsigned result */ int32_t scale; /* Scaling factor */ unsigned i; /* Array subscript */ BYTE packed[17]; /* 33-digit packed work area */ decNumber p, c; /* Working decimal numbers */ static U32 mu32 = 0xFFFFFFFFUL; /* Max unsigned integer */ static char mu32zd[]="4294967295"; /* Max unsigned zoned dec */ static BYTE mu32flag = 0; /* 1=mu32dn is initialized */ static decNumber mu32dn; /* Decimal maximum unsigned */ decContext setmax; /* Working context */ /* Prime the decimal number structure representing the maximum unsigned number representable in 32 bits. Use a 64-bit DFP working context because this number is too big to be represented in the 32-bit DFP format */ if (mu32flag == 0) { decContextDefault(&setmax, DEC_INIT_DECIMAL64); decNumberFromString(&mu32dn, mu32zd, &setmax); mu32flag = 1; } /* If operand is a NaN then set invalid operation and return zero result */ if (decNumberIsNaN(b)) { pset->status |= DEC_IEEE_854_Invalid_operation; return (U32)0; } /* Round decimal number to integer using current rounding mode */ decNumberToIntegralValue(&p, b, pset); /* If rounded value is less than zero then set invalid operation and return zero result */ if (decNumberIsNegative(&p)) { pset->status |= DEC_IEEE_854_Invalid_operation; return (U32)0; } /* If rounded value is greater than maximum unsigned number (including where operand is positive infinity) then set invalid operation and return maximum unsigned result */ decNumberCompare(&c, &p, &mu32dn, pset); if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0) { pset->status |= DEC_IEEE_854_Invalid_operation; return (U32)mu32; } /* Raise inexact condition if result was rounded */ decNumberCompare(&c, &p, b, pset); if (decNumberIsZero(&c) == 0) { pset->status |= DEC_IEEE_854_Inexact; if (decNumberIsNegative(&c) == decNumberIsNegative(b)) pset->status |= DEC_Rounded; } /* Convert decimal number structure to packed decimal */ decPackedFromNumber(packed, sizeof(packed), &scale, &p); /* Convert packed decimal to binary value */ for (i = 0, n = 0; i < sizeof(packed)-1; i++) { n = n * 10 + ((packed[i] & 0xF0) >> 4); n = n * 10 + (packed[i] & 0x0F); } n = n * 10 + ((packed[i] & 0xF0) >> 4); while (scale++) n *= 10; /* Return 32-bit unsigned result */ return n; } /* end function dfp_number_to_u32 */ /*-------------------------------------------------------------------*/ /* Convert decimal number to 64-bit unsigned binary integer */ /* */ /* This subroutine is called by the CLGDTR and CLGXTR instructions. */ /* It converts a decimal number structure to a 64-bit unsigned */ /* binary integer value. The inexact condition will be set in */ /* the decimal context structure if the number is rounded to */ /* an integer. The invalid operation condition will be set if */ /* the decimal value is outside the range of a 64-bit unsigned int. */ /* */ /* Input: */ /* b Pointer to decimal number structure */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The return value is the 64-bit unsigned integer result */ /*-------------------------------------------------------------------*/ static U64 dfp_number_to_u64(decNumber *b, decContext *pset) { U64 n; /* 64-bit unsigned result */ int32_t scale; /* Scaling factor */ unsigned i; /* Array subscript */ BYTE packed[17]; /* 33-digit packed work area */ decNumber p, c; /* Working decimal numbers */ static U64 mu64 = 0xFFFFFFFFFFFFFFFFULL; /* Max unsigned int */ static char mu64zd[]="18446744073709551615"; /* Max zoned dec */ static BYTE mu64flag = 0; /* 1=mu64dn is initialized */ static decNumber mu64dn; /* Decimal maximum unsigned */ decContext setmax; /* Working context */ /* Prime the decimal number structure representing the maximum unsigned number representable in 64 bits. Use a 128-bit DFP working context because this number is too big to be represented in the 32-bit or 64-bit DFP format */ if (mu64flag == 0) { decContextDefault(&setmax, DEC_INIT_DECIMAL128); decNumberFromString(&mu64dn, mu64zd, &setmax); mu64flag = 1; } /* If operand is a NaN then set invalid operation and return zero result */ if (decNumberIsNaN(b)) { pset->status |= DEC_IEEE_854_Invalid_operation; return (U64)0; } /* Round decimal number to integer using current rounding mode */ decNumberToIntegralValue(&p, b, pset); /* If rounded value is less than zero then set invalid operation and return zero result */ if (decNumberIsNegative(&p)) { pset->status |= DEC_IEEE_854_Invalid_operation; return (U64)0; } /* If rounded value is greater than maximum unsigned number (including where operand is positive infinity) then set invalid operation and return maximum unsigned result */ decNumberCompare(&c, &p, &mu64dn, pset); if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0) { pset->status |= DEC_IEEE_854_Invalid_operation; return (U64)mu64; } /* Raise inexact condition if result was rounded */ decNumberCompare(&c, &p, b, pset); if (decNumberIsZero(&c) == 0) { pset->status |= DEC_IEEE_854_Inexact; if (decNumberIsNegative(&c) == decNumberIsNegative(b)) pset->status |= DEC_Rounded; } /* Convert decimal number structure to packed decimal */ decPackedFromNumber(packed, sizeof(packed), &scale, &p); /* Convert packed decimal to binary value */ for (i = 0, n = 0; i < sizeof(packed)-1; i++) { n = n * 10 + ((packed[i] & 0xF0) >> 4); n = n * 10 + (packed[i] & 0x0F); } n = n * 10 + ((packed[i] & 0xF0) >> 4); while (scale++) n *= 10; /* Return 64-bit unsigned result */ return n; } /* end function dfp_number_to_u64 */ #define _DFP_FPE_ARCH_INDEPENDENT_ #endif /*!defined(_DFP_FPE_ARCH_INDEPENDENT_)*/ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ #if defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY) /*912*/ #if !defined(_DFP_ZONED_ARCH_INDEPENDENT_) #define CDZT_MAXLEN 16 /* CDZT maximum operand len */ #define CXZT_MAXLEN 34 /* CXZT maximum operand len */ /*-------------------------------------------------------------------*/ /* Convert zoned decimal to decimal number */ /* */ /* This subroutine is called by the CDZT and CXZT instructions. */ /* It converts a zoned decimal value into a decimal number */ /* structure. The length of the zoned decimal value should not */ /* exceed the maximum number of digits specified in the context. */ /* */ /* Input: */ /* dn Pointer to decimal number structure */ /* zoned zoned decimal input area */ /* len length-1 of zoned decimal input */ /* mask mask field: 0x8=signed */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The decimal number structure is updated. */ /* Return value: 0=success, 1=data exception */ /*-------------------------------------------------------------------*/ static int dfp_number_from_zoned(decNumber *dn, char *zoned, int len, int mask, decContext *pset) { int i; /* Array subscript */ int signflag; /* 1=signed decimal operand */ char zwork[1+CXZT_MAXLEN+1]; /* Sign + digits + null */ char *pzw = zwork; /* Addr next byte in zwork */ char c; /* Character work area */ /* Set the signed flag if indicated by the mask */ signflag = (mask & 0x8) ? 1 : 0; /* Set the sign according to the operand sign code */ if (signflag) { switch ((zoned[len] & 0xF0) >> 4) { case 0xB: case 0xD: *pzw++ = '-'; break; case 0xA: case 0xC: case 0xE: case 0xF: break; default: /* Data exception if invalid sign code */ return 1; } } /* Convert zoned number to a decimal string */ for (i=0; i <= len; i++) { c = zoned[i] & 0x0F; /* Data exception if invalid digit */ if (c > 0x09) return 1; *pzw++ = c + '0'; } *pzw = '\0'; /* Convert decimal string to decimal number structure */ decNumberFromString(dn, zwork, pset); return 0; } /* end function dfp_number_from_zoned */ #define CZDT_MAXLEN 16 /* CZDT maximum operand len */ #define CZXT_MAXLEN 34 /* CZXT maximum operand len */ /*-------------------------------------------------------------------*/ /* Convert decimal number to zoned decimal */ /* */ /* This subroutine is called by the CZDT and CZXT instructions. */ /* It converts a decimal number to a zoned decimal string. */ /* */ /* Input: */ /* dn Pointer to decimal number structure */ /* representing original DFP value */ /* dc Pointer to decimal number structure */ /* containing only coeffecient of DFP value */ /* zoned zoned decimal output area */ /* len length-1 of zoned decimal output area */ /* mask mask field: 0x8=signed, 0x4=ASCII, */ /* 0x2=plus sign is F, 0x1=zero is always positive */ /* pset Pointer to decimal number context structure */ /* Output: */ /* The zoned decimal area is updated. */ /* Return value is the condition code: */ /* 0=zero; 1=negative; 2=positive; 3=Inf, NaN, or overflow */ /*-------------------------------------------------------------------*/ static int dfp_number_to_zoned(decNumber *dn, decNumber *dc, char *zoned, int len, int mask, decContext *pset) { int i; /* Array subscript */ int pad; /* Number of padding bytes */ int cc; /* Condition code */ int sign; /* 1=negative number */ char zwork[MAXDECSTRLEN+64]; /* Decimal string work area */ int zwlen; /* Length of zwork string */ int zwind; /* Index into zwork string */ UNREFERENCED(pset); /* Determine if the number is negative or positive */ sign = (decNumberIsNegative(dn)) ? 1 : 0; /* Force plus zero if mask bit 3 is set */ if ((mask & 0x1) && decNumberIsZero(dn)) sign = 0; /* Convert decimal number to string */ if (decNumberIsNaN(dn) || (decNumberIsInfinite(dn))) { /* For NaN or Inf set cc=3 and use coefficient only */ cc = 3; dc->exponent = 0; dc->bits &= ~(DECNEG); decNumberToString(dc, zwork); } else { /* For finite numbers set cc=0, 1, or 2 and convert digits */ cc = (decNumberIsZero(dn)) ? 0 : (decNumberIsNegative(dn)) ? 1 : 2; dn->exponent = 0; dn->bits &= ~(DECNEG); decNumberToString(dn, zwork); } /* Calculate the number of padding bytes needed, and set condition code 3 if significant digits will be lost */ zwlen = (int)(strlen(zwork)); if (zwlen <= len + 1) { zwind = 0; pad = len + 1 - zwlen; } else { zwind = zwlen - len - 1; pad = 0; cc = 3; } /* Copy digits to zoned decimal result area */ for (i = 0; i <= len; i++) { /* Pad with zero or copy digit from work string */ zoned[i] = (pad > 0) ? 0x00 : zwork[zwind++] - '0'; if (pad > 0) pad--; /* Set ASCII or EBCDIC zone according to mask bit 1 */ zoned[i] |= (mask & 0x4) ? 0x30 : 0xF0; } /* Replace final zone by EBCDIC sign if mask bit 0 is one */ if (mask & 0x8) { /* -ve sign is D, +ve sign is F or C depending on mask bit 2 */ zoned[i-1] &= 0x0F; zoned[i-1] |= (sign) ? 0xD0 : (mask & 0x2) ? 0xF0 : 0xC0; } /* Return the condition code */ return cc; } /* end function dfp_number_to_zoned */ #define _DFP_ZONED_ARCH_INDEPENDENT_ #endif /*!defined(_DFP_ZONED_ARCH_INDEPENDENT_)*/ #endif /*defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY)*/ /*912*/ /*-------------------------------------------------------------------*/ /* Set rounding mode in decimal context structure */ /* */ /* Input: */ /* pset Pointer to decimal number context structure */ /* mask 4-bit mask value */ /* regs CPU register context */ /* Output: */ /* If mask bit X'08' is one then the rounding mode in the */ /* context structure is set according to the value (0 to 7) */ /* indicated by the low-order three bits of the mask. */ /* If mask bit X'08' is zero then the rounding mode in the */ /* context structure is set according to the value (0 to 7) */ /* of the DRM field in the FPC register. */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(dfp_rounding_mode) (decContext *pset, int mask, REGS *regs) { BYTE drm; /* Decimal rounding mode */ /* Load DRM from mask or from FPC register */ if (mask & 0x08) drm = mask & 0x07; else drm = (regs->fpc & FPC_DRM) >> FPC_DRM_SHIFT; /* Set rounding mode according to DRM value */ switch (drm) { case DRM_RNE: pset->round = DEC_ROUND_HALF_EVEN; break; case DRM_RTZ: pset->round = DEC_ROUND_DOWN; break; case DRM_RTPI: pset->round = DEC_ROUND_CEILING; break; case DRM_RTMI: pset->round = DEC_ROUND_FLOOR; break; case DRM_RNAZ: pset->round = DEC_ROUND_HALF_UP; break; case DRM_RNTZ: pset->round = DEC_ROUND_HALF_DOWN; break; case DRM_RAFZ: pset->round = DEC_ROUND_UP; break; case DRM_RFSP: /* Rounding mode DRM_RFSP is not supported by the decNumber library, so we arbitrarily convert it to another mode instead... */ pset->round = DEC_ROUND_DOWN; break; } /* end switch(drm) */ } /* end function dfp_rounding_mode */ /*-------------------------------------------------------------------*/ /* Copy a DFP short register into a decimal32 structure */ /* */ /* Input: */ /* rn FP register number */ /* xp Pointer to decimal32 structure */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(dfp_reg_to_decimal32) (int rn, decimal32 *xp, REGS *regs) { int i; /* FP register subscript */ FW *fwp; /* Fullword pointer */ i = FPR2I(rn); /* Register index */ fwp = (FW*)xp; /* Convert to FW pointer */ fwp->F = regs->fpr[i]; /* Copy FPR bits 0-31 */ } /* end function dfp_reg_to_decimal32 */ /*-------------------------------------------------------------------*/ /* Load a DFP short register from a decimal32 structure */ /* */ /* Input: */ /* rn FP register number (left register of pair) */ /* xp Pointer to decimal32 structure */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(dfp_reg_from_decimal32) (int rn, decimal32 *xp, REGS *regs) { int i; /* FP register subscript */ FW *fwp; /* Fullword pointer */ i = FPR2I(rn); /* Register index */ fwp = (FW*)xp; /* Convert to FW pointer */ regs->fpr[i] = fwp->F; /* Load FPR bits 0-31 */ } /* end function dfp_reg_from_decimal32 */ /*-------------------------------------------------------------------*/ /* Copy a DFP long register into a decimal64 structure */ /* */ /* Input: */ /* rn FP register number */ /* xp Pointer to decimal64 structure */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(dfp_reg_to_decimal64) (int rn, decimal64 *xp, REGS *regs) { int i; /* FP register subscript */ DW *dwp; /* Doubleword pointer */ i = FPR2I(rn); /* Register index */ dwp = (DW*)xp; /* Convert to DW pointer */ dwp->F.H.F = regs->fpr[i]; /* Copy FPR bits 0-31 */ dwp->F.L.F = regs->fpr[i+1]; /* Copy FPR bits 32-63 */ } /* end function dfp_reg_to_decimal64 */ /*-------------------------------------------------------------------*/ /* Load a DFP long register from a decimal64 structure */ /* */ /* Input: */ /* rn FP register number (left register of pair) */ /* xp Pointer to decimal64 structure */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(dfp_reg_from_decimal64) (int rn, decimal64 *xp, REGS *regs) { int i; /* FP register subscript */ DW *dwp; /* Doubleword pointer */ i = FPR2I(rn); /* Register index */ dwp = (DW*)xp; /* Convert to DW pointer */ regs->fpr[i] = dwp->F.H.F; /* Load FPR bits 0-31 */ regs->fpr[i+1] = dwp->F.L.F; /* Load FPR bits 32-63 */ } /* end function dfp_reg_from_decimal64 */ /*-------------------------------------------------------------------*/ /* Copy a DFP extended register into a decimal128 structure */ /* */ /* Input: */ /* rn FP register number (left register of pair) */ /* xp Pointer to decimal128 structure */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(dfp_reg_to_decimal128) (int rn, decimal128 *xp, REGS *regs) { int i, j; /* FP register subscripts */ QW *qwp; /* Quadword pointer */ i = FPR2I(rn); /* Left register index */ j = i + FPREX; /* Right register index */ qwp = (QW*)xp; /* Convert to QW pointer */ qwp->F.HH.F = regs->fpr[i]; /* Copy FPR bits 0-31 */ qwp->F.HL.F = regs->fpr[i+1]; /* Copy FPR bits 32-63 */ qwp->F.LH.F = regs->fpr[j]; /* Copy FPR bits 64-95 */ qwp->F.LL.F = regs->fpr[j+1]; /* Copy FPR bits 96-127 */ } /* end function dfp_reg_to_decimal128 */ /*-------------------------------------------------------------------*/ /* Load a DFP extended register from a decimal128 structure */ /* */ /* Input: */ /* rn FP register number (left register of pair) */ /* xp Pointer to decimal128 structure */ /* regs CPU register context */ /*-------------------------------------------------------------------*/ static inline void ARCH_DEP(dfp_reg_from_decimal128) (int rn, decimal128 *xp, REGS *regs) { int i, j; /* FP register subscripts */ QW *qwp; /* Quadword pointer */ i = FPR2I(rn); /* Left register index */ j = i + FPREX; /* Right register index */ qwp = (QW*)xp; /* Convert to QW pointer */ regs->fpr[i] = qwp->F.HH.F; /* Load FPR bits 0-31 */ regs->fpr[i+1] = qwp->F.HL.F; /* Load FPR bits 32-63 */ regs->fpr[j] = qwp->F.LH.F; /* Load FPR bits 64-95 */ regs->fpr[j+1] = qwp->F.LL.F; /* Load FPR bits 96-127 */ } /* end function dfp_reg_from_decimal128 */ /*-------------------------------------------------------------------*/ /* Check for DFP exception conditions */ /* */ /* This subroutine is called by the DFP instruction processing */ /* routines after the calculation has been performed but before */ /* the result is loaded into the result register (or before any */ /* storage location is updated, as the case may be). */ /* */ /* The purpose of this subroutine is to check whether any DFP */ /* exception conditions are indicated by the decimal context */ /* structure, and to initiate the appropriate action if so. */ /* */ /* Input: */ /* set Decimal number context */ /* regs CPU register context */ /* */ /* Output: */ /* Return value is DXC (data exception code) or zero. */ /* */ /* When no exception conditions are indicated, the return value */ /* is zero indicating that the instruction may proceed normally. */ /* */ /* When an exception condition exists and the corresponding mask */ /* bit in the FPC register is zero, then the corresponding flag */ /* bit is set in the FPC register. The return value is zero to */ /* indicate that the instruction may proceed normally. */ /* */ /* When an exception condition exists and the corresponding mask */ /* bit in the FPC register is one, then the DXC is set according */ /* to the type of exception, and one of two actions is taken: */ /* - if the exception is of a type which causes the instruction */ /* to be suppressed, then this subroutine raises a program */ /* exception and does not return to the calling instruction */ /* - if the exception is of a type which causes the instruction */ /* to be completed, then this subroutine returns with the */ /* DXC code as its return value. The calling instruction will */ /* then raise a program exception after storing its results. */ /*-------------------------------------------------------------------*/ static BYTE ARCH_DEP(dfp_status_check) (decContext *pset, REGS *regs) { BYTE dxc = 0; /* Data exception code */ int suppress = 0; /* 1=suppress, 0=complete */ if (pset->status & DEC_IEEE_854_Invalid_operation) { /* An IEEE-invalid-operation condition was recognized */ if ((regs->fpc & FPC_MASK_IMI) == 0) { regs->fpc |= FPC_FLAG_SFI; } else { dxc = DXC_IEEE_INVALID_OP; suppress = 1; } } else if (pset->status & DEC_IEEE_854_Division_by_zero) { /* An IEEE-division-by-zero condition was recognized */ if ((regs->fpc & FPC_MASK_IMZ) == 0) { /* Division-by-zero mask is zero */ regs->fpc |= FPC_FLAG_SFZ; } else { /* Division-by-zero mask is one */ dxc = DXC_IEEE_DIV_ZERO; suppress = 1; } } else if (pset->status & DEC_IEEE_854_Overflow) { /* An IEEE-overflow condition was recognized */ if ((regs->fpc & FPC_MASK_IMO) == 0) { /* Overflow mask is zero */ regs->fpc |= FPC_FLAG_SFO; } else { /* Overflow mask is one */ dxc = (pset->status & DEC_IEEE_854_Inexact) ? ((pset->status & DEC_Rounded) ? DXC_IEEE_OF_INEX_INCR : DXC_IEEE_OF_INEX_TRUNC ) : DXC_IEEE_OF_EXACT ; } } else if (pset->status & DEC_IEEE_854_Underflow) { /* An IEEE-underflow condition was recognized */ if ((regs->fpc & FPC_MASK_IMU) == 0) { /* Underflow mask is zero */ if (pset->status & DEC_IEEE_854_Inexact) { if ((regs->fpc & FPC_MASK_IMX) == 0) { /* Inexact result with inexact mask zero */ regs->fpc |= (FPC_FLAG_SFU | FPC_FLAG_SFX); } else { /* Inexact result with inexact mask one */ regs->fpc |= FPC_FLAG_SFU; dxc = (pset->status & DEC_Rounded) ? DXC_IEEE_INEXACT_INCR : DXC_IEEE_INEXACT_TRUNC ; } } } else { /* Underflow mask is one */ if (pset->status & DEC_IEEE_854_Inexact) { /* Underflow with inexact result */ dxc = (pset->status & DEC_Rounded) ? DXC_IEEE_UF_INEX_INCR : DXC_IEEE_UF_INEX_TRUNC ; } else { /* Underflow with exact result */ dxc = DXC_IEEE_UF_EXACT; } } } else if (pset->status & DEC_IEEE_854_Inexact) { /* An IEEE-inexact condition was recognized */ if ((regs->fpc & FPC_MASK_IMX) == 0) { /* Inexact mask is zero */ regs->fpc |= FPC_FLAG_SFX; } else { /* Inexact mask is one */ dxc = (pset->status & DEC_Rounded) ? DXC_IEEE_INEXACT_INCR : DXC_IEEE_INEXACT_TRUNC ; } } /* If suppression is indicated, raise a data exception */ if (suppress) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Otherwise return to complete the instruction */ return dxc; } /* end function dfp_status_check */ /*-------------------------------------------------------------------*/ /* B3DA AXTR - Add DFP Extended Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_dfp_ext_reg) { int r1, r2, r3; /* Values of R fields */ decimal128 x1, x2, x3; /* Extended DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); DFPREGPAIR3_CHECK(r1, r2, r3, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Add FP register r3 to FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); decimal128ToNumber(&x2, &d2); decimal128ToNumber(&x3, &d3); decNumberAdd(&d1, &d2, &d3, &set); decimal128FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&d1) ? 3 : decNumberIsZero(&d1) ? 0 : decNumberIsNegative(&d1) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(add_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3D2 ADTR - Add DFP Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(add_dfp_long_reg) { int r1, r2, r3; /* Values of R fields */ decimal64 x1, x2, x3; /* Long DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Add FP register r3 to FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); decimal64ToNumber(&x2, &d2); decimal64ToNumber(&x3, &d3); decNumberAdd(&d1, &d2, &d3, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&d1) ? 3 : decNumberIsZero(&d1) ? 0 : decNumberIsNegative(&d1) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(add_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3EC CXTR - Compare DFP Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_dfp_ext_reg) { int r1, r2; /* Values of R fields */ decimal128 x1, x2; /* Extended DFP values */ decNumber d1, d2, dr; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Compare FP register r1 with FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs); ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x1, &d1); decimal128ToNumber(&x2, &d2); decNumberCompare(&dr, &d1, &d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&dr) ? 3 : decNumberIsZero(&dr) ? 0 : decNumberIsNegative(&dr) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3E4 CDTR - Compare DFP Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_dfp_long_reg) { int r1, r2; /* Values of R fields */ decimal64 x1, x2; /* Long DFP values */ decNumber d1, d2, dr; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Compare FP register r1 with FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs); ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x1, &d1); decimal64ToNumber(&x2, &d2); decNumberCompare(&dr, &d1, &d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&dr) ? 3 : decNumberIsZero(&dr) ? 0 : decNumberIsNegative(&dr) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3E8 KXTR - Compare and Signal DFP Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_signal_dfp_ext_reg) { int r1, r2; /* Values of R fields */ decimal128 x1, x2; /* Extended DFP values */ decNumber d1, d2, dr; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Compare FP register r1 with FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs); ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x1, &d1); decimal128ToNumber(&x2, &d2); decNumberCompare(&dr, &d1, &d2, &set); /* Force signaling condition if result is a NaN */ if (decNumberIsNaN(&dr)) set.status |= DEC_IEEE_854_Invalid_operation; /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&dr) ? 3 : decNumberIsZero(&dr) ? 0 : decNumberIsNegative(&dr) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_and_signal_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3E0 KDTR - Compare and Signal DFP Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_and_signal_dfp_long_reg) { int r1, r2; /* Values of R fields */ decimal64 x1, x2; /* Long DFP values */ decNumber d1, d2, dr; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Compare FP register r1 with FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs); ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x1, &d1); decimal64ToNumber(&x2, &d2); decNumberCompare(&dr, &d1, &d2, &set); /* Force signaling condition if result is a NaN */ if (decNumberIsNaN(&dr)) set.status |= DEC_IEEE_854_Invalid_operation; /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&dr) ? 3 : decNumberIsZero(&dr) ? 0 : decNumberIsNegative(&dr) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(compare_and_signal_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3FC CEXTR - Compare Exponent DFP Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_exponent_dfp_ext_reg) { int r1, r2; /* Values of R fields */ decimal128 x1, x2; /* Extended DFP values */ decNumber d1, d2; /* Working decimal numbers */ decContext set; /* Working context */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Convert FP register values to numbers */ ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs); ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x1, &d1); decimal128ToNumber(&x2, &d2); /* Compare exponents and set condition code */ regs->psw.cc = dfp_compare_exponent(&d1, &d2); } /* end DEF_INST(compare_exponent_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3F4 CEDTR - Compare Exponent DFP Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(compare_exponent_dfp_long_reg) { int r1, r2; /* Values of R fields */ decimal64 x1, x2; /* Long DFP values */ decNumber d1, d2; /* Working decimal numbers */ decContext set; /* Working context */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Convert FP register values to numbers */ ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs); ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x1, &d1); decimal64ToNumber(&x2, &d2); /* Compare exponents and set condition code */ regs->psw.cc = dfp_compare_exponent(&d1, &d2); } /* end DEF_INST(compare_exponent_dfp_long_reg) */ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B959 CXFTR - Convert from fixed 32 to DFP Extended Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix32_to_dfp_ext_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ S32 n2; /* Value of R2 register */ decimal128 x1; /* Extended DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load 32-bit binary integer value from r2 register */ n2 = (S32)(regs->GR_L(r2)); /* Convert binary integer to extended DFP format */ dfp_number_from_fix32(&d1, n2, &set); decimal128FromNumber(&x1, &d1, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(convert_fix32_to_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B951 CDFTR - Convert from fixed 32 to DFP Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix32_to_dfp_long_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ S32 n2; /* Value of R2 register */ decimal64 x1; /* Long DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load 32-bit binary integer value from r2 register */ n2 = (S32)(regs->GR_L(r2)); /* Convert binary integer to long DFP format */ dfp_number_from_fix32(&d1, n2, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(convert_fix32_to_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B95B CXLFTR - Convert from unsigned 32 to DFP Ext Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u32_to_dfp_ext_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U32 n2; /* Value of R2 register */ decimal128 x1; /* Extended DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load 32-bit unsigned value from r2 register */ n2 = regs->GR_L(r2); /* Convert unsigned binary integer to extended DFP format */ dfp_number_from_u32(&d1, n2, &set); decimal128FromNumber(&x1, &d1, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(convert_u32_to_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B953 CDLFTR - Convert from unsigned 32 to DFP Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u32_to_dfp_long_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U32 n2; /* Value of R2 register */ decimal64 x1; /* Long DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load 32-bit unsigned value from r2 register */ n2 = regs->GR_L(r2); /* Convert unsigned binary integer to long DFP format */ dfp_number_from_u32(&d1, n2, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(convert_u32_to_dfp_long_reg) */ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ /*-------------------------------------------------------------------*/ /* B3F9 CXGTR - Convert from fixed 64 to DFP Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_dfp_ext_reg) { int r1, r2; /* Values of R fields */ S64 n2; /* Value of R2 register */ decimal128 x1; /* Extended DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Load 64-bit binary integer value from r2 register */ n2 = (S64)(regs->GR_G(r2)); /* Convert binary integer to extended DFP format */ dfp_number_from_fix64(&d1, n2, &set); decimal128FromNumber(&x1, &d1, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(convert_fix64_to_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3F1 CDGTR - Convert from fixed 64 to DFP Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_fix64_to_dfp_long_reg) { int r1, r2; /* Values of R fields */ S64 n2; /* Value of R2 register */ decimal64 x1; /* Long DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Load 64-bit binary integer value from r2 register */ n2 = (S64)(regs->GR_G(r2)); /* Convert binary integer to long DFP format */ dfp_number_from_fix64(&d1, n2, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_fix64_to_dfp_long_reg) */ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B95A CXLGTR - Convert from unsigned 64 to DFP Ext Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u64_to_dfp_ext_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U64 n2; /* Value of R2 register */ decimal128 x1; /* Extended DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load 64-bit unsigned value from r2 register */ n2 = regs->GR_G(r2); /* Convert unsigned binary integer to extended DFP format */ dfp_number_from_u64(&d1, n2, &set); decimal128FromNumber(&x1, &d1, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(convert_u64_to_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B952 CDLGTR - Convert from unsigned 64 to DFP Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_u64_to_dfp_long_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U64 n2; /* Value of R2 register */ decimal64 x1; /* Long DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load 64-bit unsigned value from r2 register */ n2 = regs->GR_G(r2); /* Convert unsigned binary integer to long DFP format */ dfp_number_from_u64(&d1, n2, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(convert_u64_to_dfp_long_reg) */ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ /*-------------------------------------------------------------------*/ /* B3FB CXSTR - Convert from signed BCD (128-bit to DFP ext) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_sbcd128_to_dfp_ext_reg) { int r1, r2; /* Values of R fields */ decimal128 x1; /* Extended DFP values */ decNumber dwork, *dp; /* Working decimal numbers */ decContext set; /* Working context */ BYTE pwork[16]; /* 31-digit packed work area */ int32_t scale = 0; /* Scaling factor */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); ODD_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Store general register pair in work area */ STORE_DW(pwork, regs->GR_G(r2)); STORE_DW(pwork+8, regs->GR_G(r2+1)); /* Convert signed BCD to internal number format */ dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork); /* Data exception if digits or sign was invalid */ if (dp == NULL) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Convert internal number to DFP extended format */ decimal128FromNumber(&x1, &dwork, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(convert_sbcd128_to_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3F3 CDSTR - Convert from signed BCD (64-bit to DFP long) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_sbcd64_to_dfp_long_reg) { int r1, r2; /* Values of R fields */ decimal64 x1; /* Long DFP values */ decNumber dwork, *dp; /* Working decimal numbers */ decContext set; /* Working context */ BYTE pwork[8]; /* 15-digit packed work area */ int32_t scale = 0; /* Scaling factor */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Store general register in work area */ STORE_DW(pwork, regs->GR_G(r2)); /* Convert signed BCD to internal number format */ dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork); /* Data exception if digits or sign was invalid */ if (dp == NULL) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Convert internal number to DFP long format */ decimal64FromNumber(&x1, &dwork, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(convert_sbcd64_to_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3FA CXUTR - Convert from unsigned BCD (128-bit to DFP ext) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_ubcd128_to_dfp_ext_reg) { unsigned i; /* Array subscript */ int r1, r2; /* Values of R fields */ decimal128 x1; /* Extended DFP values */ decNumber dwork, *dp; /* Working decimal numbers */ decContext set; /* Working context */ BYTE pwork[17]; /* 33-digit packed work area */ int32_t scale = 0; /* Scaling factor */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); ODD_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Store general register pair in work area */ pwork[0] = 0; STORE_DW(pwork+1, regs->GR_G(r2)); STORE_DW(pwork+9, regs->GR_G(r2+1)); /* Convert unsigned BCD to signed BCD */ for (i = 0; i < sizeof(pwork)-1; i++) pwork[i] = ((pwork[i] & 0x0F) << 4) | (pwork[i+1] >> 4); pwork[i] = ((pwork[i] & 0x0F) << 4) | 0x0F; /* Convert signed BCD to internal number format */ dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork); /* Data exception if digits invalid */ if (dp == NULL) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Convert internal number to DFP extended format */ decimal128FromNumber(&x1, &dwork, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(convert_ubcd128_to_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3F2 CDUTR - Convert from unsigned BCD (64-bit to DFP long) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_ubcd64_to_dfp_long_reg) { unsigned i; /* Array subscript */ int r1, r2; /* Values of R fields */ decimal64 x1; /* Long DFP values */ decNumber dwork, *dp; /* Working decimal numbers */ decContext set; /* Working context */ BYTE pwork[9]; /* 17-digit packed work area */ int32_t scale = 0; /* Scaling factor */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Store general register in work area */ pwork[0] = 0; STORE_DW(pwork+1, regs->GR_G(r2)); /* Convert unsigned BCD to signed BCD */ for (i = 0; i < sizeof(pwork)-1; i++) pwork[i] = ((pwork[i] & 0x0F) << 4) | (pwork[i+1] >> 4); pwork[i] = ((pwork[i] & 0x0F) << 4) | 0x0F; /* Convert signed BCD to internal number format */ dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork); /* Data exception if digits or sign was invalid */ if (dp == NULL) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Convert internal number to DFP long format */ decimal64FromNumber(&x1, &dwork, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(convert_ubcd64_to_dfp_long_reg) */ #if defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY) /*912*/ /*-------------------------------------------------------------------*/ /* EDAB CXZT - Convert from zoned to DFP Extended [RSL] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_zoned_to_dfp_ext) /*912*/ { int rc; /* Return code */ int r1, m3; /* Values of R and M fields */ int l2; /* Operand length minus 1 */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal128 x1; /* Extended DFP value */ decNumber d; /* Working decimal number */ decContext set; /* Working context */ char zoned[CXZT_MAXLEN]; /* Zoned decimal operand */ RSL_RM(inst, regs, r1, l2, b2, effective_addr2, m3); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Program check if operand length exceeds maximum */ if (l2 > CXZT_MAXLEN-1) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Fetch the zoned decimal operand into the work area */ ARCH_DEP(vfetchc) (zoned, l2, effective_addr2, b2, regs); /* Convert zoned decimal to decimal number structure */ rc = dfp_number_from_zoned(&d, zoned, l2, m3, &set); /* Program check if data exception is indicated */ if (rc != 0) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Convert decimal number to extended DFP format */ decimal128FromNumber(&x1, &d, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(convert_zoned_to_dfp_ext) */ /*-------------------------------------------------------------------*/ /* EDAA CDZT - Convert from zoned to DFP Long [RSL] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_zoned_to_dfp_long) /*912*/ { int rc; /* Return code */ int r1, m3; /* Values of R and M fields */ int l2; /* Operand length minus 1 */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal64 x1; /* Long DFP value */ decNumber d; /* Working decimal number */ decContext set; /* Working context */ char zoned[CDZT_MAXLEN]; /* Zoned decimal operand */ RSL_RM(inst, regs, r1, l2, b2, effective_addr2, m3); DFPINST_CHECK(regs); /* Program check if operand length exceeds maximum */ if (l2 > CDZT_MAXLEN-1) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Fetch the zoned decimal operand into the work area */ ARCH_DEP(vfetchc) (zoned, l2, effective_addr2, b2, regs); /* Convert zoned decimal to decimal number structure */ rc = dfp_number_from_zoned(&d, zoned, l2, m3, &set); /* Program check if data exception is indicated */ if (rc != 0) { regs->dxc = DXC_DECIMAL; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } /* Convert decimal number to long DFP format */ decimal64FromNumber(&x1, &d, &set); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(convert_zoned_to_dfp_long) */ #endif /*defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY)*/ /*912*/ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B949 CFXTR - Convert from DFP Extended Register to fixed 32 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_ext_to_fix32_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ S32 n1; /* Result value */ decimal128 x2; /* Extended DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load extended DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &d2); /* Convert decimal number to 32-bit binary integer */ n1 = dfp_number_to_fix32(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_L(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_ext_to_fix32_reg) */ /*-------------------------------------------------------------------*/ /* B941 CFDTR - Convert from DFP Long Register to fixed 32 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_long_to_fix32_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ S32 n1; /* Result value */ decimal64 x2; /* Long DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load long DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d2); /* Convert decimal number to 32-bit binary integer */ n1 = dfp_number_to_fix32(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_L(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_long_to_fix32_reg) */ /*-------------------------------------------------------------------*/ /* B94B CLFXTR - Convert from DFP Ext Register to unsigned 32 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_ext_to_u32_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U32 n1; /* Result value */ decimal128 x2; /* Extended DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load extended DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &d2); /* Convert decimal number to 32-bit unsigned integer */ n1 = dfp_number_to_u32(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_L(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_ext_to_u32_reg) */ /*-------------------------------------------------------------------*/ /* B943 CLFDTR - Convert from DFP Long Register to unsigned 32 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_long_to_u32_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U32 n1; /* Result value */ decimal64 x2; /* Long DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load long DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d2); /* Convert decimal number to 32-bit unsigned integer */ n1 = dfp_number_to_u32(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_L(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_long_to_u32_reg) */ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ /*-------------------------------------------------------------------*/ /* B3E9 CGXTR - Convert from DFP Extended Register to fixed 64 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_ext_to_fix64_reg) { int r1, r2; /* Values of R fields */ int m3; /* Values of M fields */ S64 n1; /* Result value */ decimal128 x2; /* Extended DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_M(inst, regs, r1, r2, m3); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load extended DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &d2); /* Convert decimal number to 64-bit binary integer */ n1 = dfp_number_to_fix64(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_G(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_ext_to_fix64_reg) */ /*-------------------------------------------------------------------*/ /* B3E1 CGDTR - Convert from DFP Long Register to fixed 64 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_long_to_fix64_reg) { int r1, r2; /* Values of R fields */ int m3; /* Values of M fields */ S64 n1; /* Result value */ decimal64 x2; /* Long DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_M(inst, regs, r1, r2, m3); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load long DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d2); /* Convert decimal number to 64-bit binary integer */ n1 = dfp_number_to_fix64(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_G(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_long_to_fix64_reg) */ #if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/ /*-------------------------------------------------------------------*/ /* B94A CLGXTR - Convert from DFP Ext Register to unsigned 64 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_ext_to_u64_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U64 n1; /* Result value */ decimal128 x2; /* Extended DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load extended DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &d2); /* Convert decimal number to 64-bit unsigned integer */ n1 = dfp_number_to_u64(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_G(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_ext_to_u64_reg) */ /*-------------------------------------------------------------------*/ /* B942 CLGDTR - Convert from DFP Long Register to unsigned 64 [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_long_to_u64_reg) { int r1, r2; /* Values of R fields */ int m3, m4; /* Values of M fields */ U64 n1; /* Result value */ decimal64 x2; /* Long DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load long DFP value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d2); /* Convert decimal number to 64-bit unsigned integer */ n1 = dfp_number_to_u64(&d2, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into general register r1 */ regs->GR_G(r1) = n1; /* Set condition code */ regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 : decNumberIsZero(&d2) ? 0 : decNumberIsNegative(&d2) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(convert_dfp_long_to_u64_reg) */ #endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/ /*-------------------------------------------------------------------*/ /* B3EB CSXTR - Convert to signed BCD (DFP ext to 128-bit) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_ext_to_sbcd128_reg) { int r1, r2; /* Values of R fields */ int m4; /* Values of M fields */ decimal128 x2; /* Extended DFP values */ decNumber dwork; /* Working decimal number */ decContext set; /* Working context */ int32_t scale; /* Scaling factor */ BYTE pwork[17]; /* 33-digit packed work area */ RRF_M4(inst, regs, r1, r2, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); ODD_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &dwork); /* If NaN or Inf then use coefficient only */ if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork))) { dfp128_clear_cf_and_bxcf(&x2); decimal128ToNumber(&x2, &dwork); } /* Convert number to signed BCD in work area */ decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork); /* Make the plus-sign X'F' if m4 bit 3 is one */ if ((m4 & 0x01) && !decNumberIsNegative(&dwork)) pwork[sizeof(pwork)-1] |= 0x0F; /* Load general register pair r1 and r1+1 from rightmost 31 packed decimal digits of work area */ FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-16); FETCH_DW(regs->GR_G(r1+1), pwork+sizeof(pwork)-8); } /* end DEF_INST(convert_dfp_ext_to_sbcd128_reg) */ /*-------------------------------------------------------------------*/ /* B3E3 CSDTR - Convert to signed BCD (DFP long to 64-bit) [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_long_to_sbcd64_reg) { int r1, r2; /* Values of R fields */ int m4; /* Values of M fields */ decimal64 x2; /* Long DFP values */ decNumber dwork; /* Working decimal number */ decContext set; /* Working context */ int32_t scale; /* Scaling factor */ BYTE pwork[9]; /* 17-digit packed work area */ RRF_M4(inst, regs, r1, r2, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &dwork); /* If NaN or Inf then use coefficient only */ if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork))) { dfp64_clear_cf_and_bxcf(&x2); decimal64ToNumber(&x2, &dwork); } /* Convert number to signed BCD in work area */ decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork); /* Make the plus-sign X'F' if m4 bit 3 is one */ if ((m4 & 0x01) && !decNumberIsNegative(&dwork)) pwork[sizeof(pwork)-1] |= 0x0F; /* Load general register r1 from rightmost 15 packed decimal digits of work area */ FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-8); } /* end DEF_INST(convert_dfp_long_to_sbcd64_reg) */ /*-------------------------------------------------------------------*/ /* B3EA CUXTR - Convert to unsigned BCD (DFP ext to 128-bit) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_ext_to_ubcd128_reg) { int i; /* Array subscript */ int r1, r2; /* Values of R fields */ decimal128 x2; /* Extended DFP values */ decNumber dwork; /* Working decimal number */ decContext set; /* Working context */ int32_t scale; /* Scaling factor */ BYTE pwork[17]; /* 33-digit packed work area */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); ODD_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &dwork); /* If NaN or Inf then use coefficient only */ if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork))) { dfp128_clear_cf_and_bxcf(&x2); decimal128ToNumber(&x2, &dwork); } /* Convert number to signed BCD in work area */ decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork); /* Convert signed BCD to unsigned BCD */ for (i = sizeof(pwork)-1; i > 0; i--) pwork[i] = (pwork[i] >> 4) | ((pwork[i-1] & 0x0F) << 4); /* Load general register pair r1 and r1+1 from rightmost 32 packed decimal digits of work area */ FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-16); FETCH_DW(regs->GR_G(r1+1), pwork+sizeof(pwork)-8); } /* end DEF_INST(convert_dfp_ext_to_ubcd128_reg) */ /*-------------------------------------------------------------------*/ /* B3E2 CUDTR - Convert to unsigned BCD (DFP long to 64-bit) [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_long_to_ubcd64_reg) { int i; /* Array subscript */ int r1, r2; /* Values of R fields */ decimal64 x2; /* Long DFP values */ decNumber dwork; /* Working decimal number */ decContext set; /* Working context */ int32_t scale; /* Scaling factor */ BYTE pwork[9]; /* 17-digit packed work area */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &dwork); /* If NaN or Inf then use coefficient only */ if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork))) { dfp64_clear_cf_and_bxcf(&x2); decimal64ToNumber(&x2, &dwork); } /* Convert number to signed BCD in work area */ decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork); /* Convert signed BCD to unsigned BCD */ for (i = sizeof(pwork)-1; i > 0; i--) pwork[i] = (pwork[i] >> 4) | ((pwork[i-1] & 0x0F) << 4); /* Load general register r1 from rightmost 16 packed decimal digits of work area */ FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-8); } /* end DEF_INST(convert_dfp_long_to_ubcd64_reg) */ #if defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY) /*912*/ /*-------------------------------------------------------------------*/ /* EDA9 CZXT - Convert to zoned from DFP Extended [RSL] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_ext_to_zoned) /*912*/ { int r1, m3; /* Values of R and M fields */ int l2; /* Operand length minus 1 */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal128 x1; /* Extended DFP value */ decNumber dwork, dcoeff; /* Working decimal numbers */ decContext set; /* Working context */ int cc; /* Condition code */ char zoned[CZXT_MAXLEN]; /* Zoned decimal result */ RSL_RM(inst, regs, r1, l2, b2, effective_addr2, m3); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Program check if operand length exceeds 34 */ if (l2 > CZXT_MAXLEN-1) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r1 */ ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs); decimal128ToNumber(&x1, &dwork); /* Extract coefficient only for Inf and NaN */ if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork))) { dfp128_clear_cf_and_bxcf(&x1); decimal128ToNumber(&x1, &dcoeff); } /* Convert number to zoned decimal and set condition code */ cc = dfp_number_to_zoned(&dwork, &dcoeff, zoned, l2, m3, &set); /* Store the zoned decimal result at the operand location */ ARCH_DEP(vstorec) (zoned, l2, effective_addr2, b2, regs); /* Set the condition code in the PSW */ regs->psw.cc = cc; } /* end DEF_INST(convert_dfp_ext_to_zoned) */ /*-------------------------------------------------------------------*/ /* EDA8 CZDT - Convert to zoned from DFP Long [RSL] */ /*-------------------------------------------------------------------*/ DEF_INST(convert_dfp_long_to_zoned) /*912*/ { int r1, m3; /* Values of R and M fields */ int l2; /* Operand length minus 1 */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal64 x1; /* Long DFP value */ decNumber dwork, dcoeff; /* Working decimal numbers */ decContext set; /* Working context */ int cc; /* Condition code */ char zoned[CZDT_MAXLEN]; /* Zoned decimal result */ RSL_RM(inst, regs, r1, l2, b2, effective_addr2, m3); DFPINST_CHECK(regs); /* Program check if operand length exceeds 16 */ if (l2 > CZDT_MAXLEN-1) { ARCH_DEP(program_interrupt) (regs, PGM_SPECIFICATION_EXCEPTION); } /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r1 */ ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs); decimal64ToNumber(&x1, &dwork); /* Extract coefficient only for Inf and NaN */ if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork))) { dfp64_clear_cf_and_bxcf(&x1); decimal64ToNumber(&x1, &dcoeff); } /* Convert number to zoned decimal and set condition code */ cc = dfp_number_to_zoned(&dwork, &dcoeff, zoned, l2, m3, &set); /* Store the zoned decimal result at the operand location */ ARCH_DEP(vstorec) (zoned, l2, effective_addr2, b2, regs); /* Set the condition code in the PSW */ regs->psw.cc = cc; } /* end DEF_INST(convert_dfp_long_to_zoned) */ #endif /*defined(FEATURE_DFP_ZONED_CONVERSION_FACILITY)*/ /*912*/ /*-------------------------------------------------------------------*/ /* B3D9 DXTR - Divide DFP Extended Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_dfp_ext_reg) { int r1, r2, r3; /* Values of R fields */ decimal128 x1, x2, x3; /* Extended DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); DFPREGPAIR3_CHECK(r1, r2, r3, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Divide FP register r2 by FP register r3 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); decimal128ToNumber(&x2, &d2); decimal128ToNumber(&x3, &d3); decNumberDivide(&d1, &d2, &d3, &set); decimal128FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(divide_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3D1 DDTR - Divide DFP Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(divide_dfp_long_reg) { int r1, r2, r3; /* Values of R fields */ decimal64 x1, x2, x3; /* Long DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Divide FP register r2 by FP register r3 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); decimal64ToNumber(&x2, &d2); decimal64ToNumber(&x3, &d3); decNumberDivide(&d1, &d2, &d3, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(divide_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3ED EEXTR - Extract Biased Exponent DFP Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_biased_exponent_dfp_ext_to_fix64_reg) { int r1, r2; /* Values of R fields */ decimal128 x2; /* Extended DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ S64 exponent; /* Biased exponent */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); /* Convert to internal decimal number format */ decimal128ToNumber(&x2, &d2); /* Calculate the biased exponent */ if (decNumberIsInfinite(&d2)) exponent = -1; else if (decNumberIsQNaN(&d2)) exponent = -2; else if (decNumberIsSNaN(&d2)) exponent = -3; else exponent = d2.exponent + DECIMAL128_Bias; /* Load result into general register r1 */ regs->GR(r1) = exponent; } /* end DEF_INST(extract_biased_exponent_dfp_ext_to_fix64_reg) */ /*-------------------------------------------------------------------*/ /* B3E5 EEDTR - Extract Biased Exponent DFP Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_biased_exponent_dfp_long_to_fix64_reg) { int r1, r2; /* Values of R fields */ decimal64 x2; /* Long DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ S64 exponent; /* Biased exponent */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); /* Convert to internal decimal number format */ decimal64ToNumber(&x2, &d2); /* Calculate the biased exponent */ if (decNumberIsInfinite(&d2)) exponent = -1; else if (decNumberIsQNaN(&d2)) exponent = -2; else if (decNumberIsSNaN(&d2)) exponent = -3; else exponent = d2.exponent + DECIMAL64_Bias; /* Load result into general register r1 */ regs->GR(r1) = exponent; } /* end DEF_INST(extract_biased_exponent_dfp_long_to_fix64_reg) */ /*-------------------------------------------------------------------*/ /* B3EF ESXTR - Extract Significance DFP Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_significance_dfp_ext_reg) { int r1, r2; /* Values of R fields */ decimal128 x2; /* Extended DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ S64 digits; /* Number of decimal digits */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); /* Convert to internal decimal number format */ decimal128ToNumber(&x2, &d2); /* Calculate number of significant digits */ if (decNumberIsZero(&d2)) digits = 0; else if (decNumberIsInfinite(&d2)) digits = -1; else if (decNumberIsQNaN(&d2)) digits = -2; else if (decNumberIsSNaN(&d2)) digits = -3; else digits = d2.digits; /* Load result into general register r1 */ regs->GR(r1) = digits; } /* end DEF_INST(extract_significance_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3E7 ESDTR - Extract Significance DFP Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(extract_significance_dfp_long_reg) { int r1, r2; /* Values of R fields */ decimal64 x2; /* Long DFP value */ decNumber d2; /* Working decimal number */ decContext set; /* Working context */ S64 digits; /* Number of decimal digits */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); /* Convert to internal decimal number format */ decimal64ToNumber(&x2, &d2); /* Calculate number of significant digits */ if (decNumberIsZero(&d2)) digits = 0; else if (decNumberIsInfinite(&d2)) digits = -1; else if (decNumberIsQNaN(&d2)) digits = -2; else if (decNumberIsSNaN(&d2)) digits = -3; else digits = d2.digits; /* Load result into general register r1 */ regs->GR(r1) = digits; } /* end DEF_INST(extract_significance_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3FE IEXTR - Insert Biased Exponent DFP Extended Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_biased_exponent_fix64_to_dfp_ext_reg) { int r1, r2, r3; /* Values of R fields */ decimal128 x1, x3; /* Extended DFP values */ decNumber d; /* Working decimal number */ decContext set; /* Working context */ S64 bexp; /* Biased exponent */ RRF_M(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r3, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load biased exponent from general register r2 */ bexp = (S64)(regs->GR(r2)); /* Load DFP extended number from FP register r3 */ ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); /* Insert biased exponent into number */ if (bexp > DECIMAL128_Ehigh || bexp == -2 || bexp <= -4) { /* Result is a QNaN with re-encoded coefficient-continuation */ dfp128_clear_cf_and_bxcf(&x3); decimal128ToNumber(&x3, &d); decimal128FromNumber(&x1, &d, &set); dfp128_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); } else if (bexp == -3) { /* Result is a SNaN with re-encoded coefficient-continuation */ dfp128_clear_cf_and_bxcf(&x3); decimal128ToNumber(&x3, &d); decimal128FromNumber(&x1, &d, &set); dfp128_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); } else if (bexp == -1) /* Infinity */ { /* Result is Infinity with re-encoded coefficient-continuation */ dfp128_clear_cf_and_bxcf(&x3); decimal128ToNumber(&x3, &d); decimal128FromNumber(&x1, &d, &set); dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF); } else { decimal128ToNumber(&x3, &d); /* Clear CF and BXCF if source is Infinity or NaN */ if (decNumberIsInfinite(&d) || decNumberIsNaN(&d)) { dfp128_clear_cf_and_bxcf(&x3); decimal128ToNumber(&x3, &d); } /* Update exponent and re-encode coefficient-continuation */ d.exponent = bexp - DECIMAL128_Bias; decimal128FromNumber(&x1, &d, &set); } /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(insert_biased_exponent_fix64_to_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3F6 IEDTR - Insert Biased Exponent DFP Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(insert_biased_exponent_fix64_to_dfp_long_reg) { int r1, r2, r3; /* Values of R fields */ decimal64 x1, x3; /* Long DFP values */ decNumber d; /* Working decimal number */ decContext set; /* Working context */ S64 bexp; /* Biased exponent */ RRF_M(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load biased exponent from general register r2 */ bexp = (S64)(regs->GR(r2)); /* Load DFP long number from FP register r3 */ ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); /* Insert biased exponent into number */ if (bexp > DECIMAL64_Ehigh || bexp == -2 || bexp <= -4) { /* Result is a QNaN with re-encoded coefficient-continuation */ dfp64_clear_cf_and_bxcf(&x3); decimal64ToNumber(&x3, &d); decimal64FromNumber(&x1, &d, &set); dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); } else if (bexp == -3) { /* Result is a SNaN with re-encoded coefficient-continuation */ dfp64_clear_cf_and_bxcf(&x3); decimal64ToNumber(&x3, &d); decimal64FromNumber(&x1, &d, &set); dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); } else if (bexp == -1) /* Infinity */ { /* Result is Infinity with re-encoded coefficient-continuation */ dfp64_clear_cf_and_bxcf(&x3); decimal64ToNumber(&x3, &d); decimal64FromNumber(&x1, &d, &set); dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF); } else { decimal64ToNumber(&x3, &d); /* Clear CF and BXCF if source is Infinity or NaN */ if (decNumberIsInfinite(&d) || decNumberIsNaN(&d)) { dfp64_clear_cf_and_bxcf(&x3); decimal64ToNumber(&x3, &d); } /* Update exponent and re-encode coefficient-continuation */ d.exponent = bexp - DECIMAL64_Bias; decimal64FromNumber(&x1, &d, &set); } /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(insert_biased_exponent_fix64_to_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3DE LTXTR - Load and Test DFP Extended Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_dfp_ext_reg) { int r1, r2; /* Values of R fields */ decimal128 x1, x2; /* Extended DFP values */ decNumber d; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &d); /* For SNaN, force signaling condition and convert to QNaN */ if (decNumberIsSNaN(&d)) { set.status |= DEC_IEEE_854_Invalid_operation; d.bits &= ~DECSNAN; d.bits |= DECNAN; } /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Reencode value and load into FP register r1 */ decimal128FromNumber(&x1, &d, &set); ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&d) ? 3 : decNumberIsZero(&d) ? 0 : decNumberIsNegative(&d) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_and_test_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3D6 LTDTR - Load and Test DFP Long Register [RRE] */ /*-------------------------------------------------------------------*/ DEF_INST(load_and_test_dfp_long_reg) { int r1, r2; /* Values of R fields */ decimal64 x1, x2; /* Long DFP values */ decNumber d; /* Working decimal number */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRE(inst, regs, r1, r2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load value from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d); /* For SNaN, force signaling condition and convert to QNaN */ if (decNumberIsSNaN(&d)) { set.status |= DEC_IEEE_854_Invalid_operation; d.bits &= ~DECSNAN; d.bits |= DECNAN; } /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Reencode value and load into FP register r1 */ decimal64FromNumber(&x1, &d, &set); ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&d) ? 3 : decNumberIsZero(&d) ? 0 : decNumberIsNegative(&d) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_and_test_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3DF FIXTR - Load FP Integer DFP Extended Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_dfp_ext_reg) { int r1, r2, m3, m4; /* Values of R and M fields */ decimal128 x1, x2; /* Extended DFP values */ decNumber d1, d2, dc; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load decimal number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &d2); if (decNumberIsInfinite(&d2) == 0 && decNumberIsNaN(&d2) == 0) { /* Remove fractional part of decimal number */ decNumberToIntegralValue(&d1, &d2, &set); /* Raise inexact condition if M4 bit 1 is zero and result differs in value from original value */ if ((m4 & 0x04) == 0) { decNumberCompare(&dc, &d1, &d2, &set); if (decNumberIsZero(&dc) == 0) { set.status |= DEC_IEEE_854_Inexact; if (decNumberIsNegative(&dc) == decNumberIsNegative(&d2)) set.status |= DEC_Rounded; } } } else { /* Propagate NaN or default infinity */ decNumberCopy(&d1, &d2); /* For SNaN, force signaling condition and convert to QNaN */ if (decNumberIsSNaN(&d2)) { set.status |= DEC_IEEE_854_Invalid_operation; d1.bits &= ~DECSNAN; d1.bits |= DECNAN; } } /* Convert result to extended DFP format */ decimal128FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_fp_int_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3D7 FIDTR - Load FP Integer DFP Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_fp_int_dfp_long_reg) { int r1, r2, m3, m4; /* Values of R and M fields */ decimal64 x1, x2; /* Long DFP values */ decNumber d1, d2, dc; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load decimal number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d2); if (decNumberIsInfinite(&d2) == 0 && decNumberIsNaN(&d2) == 0) { /* Remove fractional part of decimal number */ decNumberToIntegralValue(&d1, &d2, &set); /* Raise inexact condition if M4 bit 1 is zero and result differs in value from original value */ if ((m4 & 0x04) == 0) { decNumberCompare(&dc, &d1, &d2, &set); if (decNumberIsZero(&dc) == 0) { set.status |= DEC_IEEE_854_Inexact; if (decNumberIsNegative(&dc) == decNumberIsNegative(&d2)) set.status |= DEC_Rounded; } } } else { /* Propagate NaN or default infinity */ decNumberCopy(&d1, &d2); /* For SNaN, force signaling condition and convert to QNaN */ if (decNumberIsSNaN(&d2)) { set.status |= DEC_IEEE_854_Invalid_operation; d1.bits &= ~DECSNAN; d1.bits |= DECNAN; } } /* Convert result to long DFP format */ decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_fp_int_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3DC LXDTR - Load Lengthened DFP Long to Extended Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_dfp_long_to_ext_reg) { int r1, r2, m4; /* Values of R and M fields */ decimal128 x1; /* Extended DFP value */ decimal64 x2; /* Long DFP value */ decNumber d1, d2; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_M4(inst, regs, r1, r2, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP long number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d2); /* Convert number to DFP extended format */ if (decNumberIsInfinite(&d2) && (m4 & 0x08)) { /* For Inf with mask bit 0 set, propagate the digits */ dfp64_clear_cf_and_bxcf(&x2); decimal64ToNumber(&x2, &d1); decimal128FromNumber(&x1, &d1, &set); dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF); } else if (decNumberIsNaN(&d2)) { decimal64ToNumber(&x2, &d1); /* For SNaN with mask bit 0 off, convert to a QNaN and raise signaling condition */ if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0) { set.status |= DEC_IEEE_854_Invalid_operation; d1.bits &= ~DECSNAN; d1.bits |= DECNAN; } decimal128FromNumber(&x1, &d1, &set); } else { decNumberCopy(&d1, &d2); decimal128FromNumber(&x1, &d1, &set); } /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_lengthened_dfp_long_to_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3D4 LDETR - Load Lengthened DFP Short to Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_lengthened_dfp_short_to_long_reg) { int r1, r2, m4; /* Values of R and M fields */ decimal64 x1; /* Long DFP value */ decimal32 x2; /* Short DFP value */ decNumber d1, d2; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_M4(inst, regs, r1, r2, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP short number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal32)(r2, &x2, regs); decimal32ToNumber(&x2, &d2); /* Convert number to DFP long format */ if (decNumberIsInfinite(&d2) && (m4 & 0x08)) { /* For Inf with mask bit 0 set, propagate the digits */ dfp32_clear_cf_and_bxcf(&x2); decimal32ToNumber(&x2, &d1); decimal64FromNumber(&x1, &d1, &set); dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF); } else if (decNumberIsNaN(&d2)) { decimal32ToNumber(&x2, &d1); /* For SNaN with mask bit 0 off, convert to a QNaN and raise signaling condition */ if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0) { set.status |= DEC_IEEE_854_Invalid_operation; d1.bits &= ~DECSNAN; d1.bits |= DECNAN; } decimal64FromNumber(&x1, &d1, &set); } else { decNumberCopy(&d1, &d2); decimal64FromNumber(&x1, &d1, &set); } /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_lengthened_dfp_short_to_long_reg) */ /*-------------------------------------------------------------------*/ /* B3DD LDXTR - Load Rounded DFP Extended to Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_dfp_ext_to_long_reg) { int r1, r2, m3, m4; /* Values of R and M fields */ decimal64 x1; /* Long DFP value */ decimal128 x2; /* Extended DFP value */ decNumber d1, d2; /* Working decimal numbers */ decContext set; /* Working context */ int32_t scale; /* Scaling factor */ BYTE pwork[17]; /* 33-digit packed work area */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r2, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load DFP extended number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); decimal128ToNumber(&x2, &d2); /* Convert number to DFP long format */ if ((decNumberIsInfinite(&d2) && (m4 & 0x08)) || decNumberIsNaN(&d2)) { /* For Inf with mask bit 0 set, or for QNan or SNan, propagate the low 15 digits */ dfp128_clear_cf_and_bxcf(&x2); decimal128ToNumber(&x2, &d1); decPackedFromNumber(pwork, sizeof(pwork), &scale, &d1); scale = 0; decPackedToNumber(pwork+sizeof(pwork)-8, 8, &scale, &d1); decimal64FromNumber(&x1, &d1, &set); if (decNumberIsInfinite(&d2)) { dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF); } else if (decNumberIsQNaN(&d2)) { dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); } else /* it is an SNaN */ { /* For SNaN with mask bit 0 off, convert to a QNaN and raise signaling condition */ if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0) { dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); set.status |= DEC_IEEE_854_Invalid_operation; } else { dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); } } } else { /* For finite number, load value rounded to long DFP format, or for Inf with mask bit 0 not set, load default infinity */ decNumberCopy(&d1, &d2); decimal64FromNumber(&x1, &d1, &set); } /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_rounded_dfp_ext_to_long_reg) */ /*-------------------------------------------------------------------*/ /* B3D5 LEDTR - Load Rounded DFP Long to Short Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(load_rounded_dfp_long_to_short_reg) { int r1, r2, m3, m4; /* Values of R and M fields */ decimal32 x1; /* Short DFP value */ decimal64 x2; /* Long DFP value */ decNumber d1, d2; /* Working decimal numbers */ decContext set; /* Working context */ int32_t scale; /* Scaling factor */ BYTE pwork[9]; /* 17-digit packed work area */ BYTE dxc; /* Data exception code */ RRF_MM(inst, regs, r1, r2, m3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m3, regs); /* Load DFP long number from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); decimal64ToNumber(&x2, &d2); /* Convert number to DFP short format */ if ((decNumberIsInfinite(&d2) && (m4 & 0x08)) || decNumberIsNaN(&d2)) { /* For Inf with mask bit 0 set, or for QNan or SNan, propagate the low 6 digits */ dfp64_clear_cf_and_bxcf(&x2); decimal64ToNumber(&x2, &d1); decPackedFromNumber(pwork, sizeof(pwork), &scale, &d1); scale = 0; decPackedToNumber(pwork+sizeof(pwork)-4, 4, &scale, &d1); decimal32FromNumber(&x1, &d1, &set); if (decNumberIsInfinite(&d2)) { dfp32_set_cf_and_bxcf(&x1, DFP_CFS_INF); } else if (decNumberIsQNaN(&d2)) { dfp32_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); } else /* it is an SNaN */ { /* For SNaN with mask bit 0 off, convert to a QNaN and raise signaling condition */ if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0) { dfp32_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); set.status |= DEC_IEEE_854_Invalid_operation; } else { dfp32_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); } } } else { /* For finite number, load value rounded to short DFP format, or for Inf with mask bit 0 not set, load default infinity */ decNumberCopy(&d1, &d2); decimal32FromNumber(&x1, &d1, &set); } /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal32)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(load_rounded_dfp_long_to_short_reg) */ /*-------------------------------------------------------------------*/ /* B3D8 MXTR - Multiply DFP Extended Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_dfp_ext_reg) { int r1, r2, r3; /* Values of R fields */ decimal128 x1, x2, x3; /* Extended DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); DFPREGPAIR3_CHECK(r1, r2, r3, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Multiply FP register r2 by FP register r3 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); decimal128ToNumber(&x2, &d2); decimal128ToNumber(&x3, &d3); decNumberMultiply(&d1, &d2, &d3, &set); decimal128FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(multiply_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3D0 MDTR - Multiply DFP Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(multiply_dfp_long_reg) { int r1, r2, r3; /* Values of R fields */ decimal64 x1, x2, x3; /* Long DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Multiply FP register r2 by FP register r3 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); decimal64ToNumber(&x2, &d2); decimal64ToNumber(&x3, &d3); decNumberMultiply(&d1, &d2, &d3, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(multiply_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3FD QAXTR - Quantize DFP Extended Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(quantize_dfp_ext_reg) { int r1, r2, r3, m4; /* Values of R and M fields */ decimal128 x1, x2, x3; /* Extended DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_RM(inst, regs, r1, r2, r3, m4); DFPINST_CHECK(regs); DFPREGPAIR3_CHECK(r1, r2, r3, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m4, regs); /* Quantize FP register r3 using FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); decimal128ToNumber(&x2, &d2); decimal128ToNumber(&x3, &d3); decNumberQuantize(&d1, &d2, &d3, &set); decimal128FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(quantize_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3F5 QADTR - Quantize DFP Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(quantize_dfp_long_reg) { int r1, r2, r3, m4; /* Values of R and M fields */ decimal64 x1, x2, x3; /* Long DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_RM(inst, regs, r1, r2, r3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m4, regs); /* Quantize FP register r3 using FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); decimal64ToNumber(&x2, &d2); decimal64ToNumber(&x3, &d3); decNumberQuantize(&d1, &d2, &d3, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(quantize_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* B3FF RRXTR - Reround DFP Extended Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(reround_dfp_ext_reg) { int signif; /* Requested significance */ int r1, r2, r3, m4; /* Values of R and M fields */ decimal128 x1, x3; /* Extended DFP values */ decNumber d1, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_RM(inst, regs, r1, r2, r3, m4); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r3, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, m4, regs); /* Load significance from bits 58-63 of general register r2 */ signif = regs->GR_L(r2) & 0x3F; /* Reround FP register r3 */ ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); decimal128ToNumber(&x3, &d3); if (decNumberIsInfinite(&d3) || decNumberIsNaN(&d3) || decNumberIsZero(&d3) || signif == 0 || d3.digits <= signif) { decNumberCopy(&d1, &d3); } else { set.digits = signif; decNumberPlus(&d1, &d3, &set); } decimal128FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(reround_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3F7 RRDTR - Reround DFP Long Register [RRF] */ /*-------------------------------------------------------------------*/ DEF_INST(reround_dfp_long_reg) { int signif; /* Requested significance */ int r1, r2, r3, m4; /* Values of R and M fields */ decimal64 x1, x3; /* Long DFP values */ decNumber d1, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRF_RM(inst, regs, r1, r2, r3, m4); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, m4, regs); /* Load significance from bits 58-63 of general register r2 */ signif = regs->GR_L(r2) & 0x3F; /* Reround FP register r3 */ ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); decimal64ToNumber(&x3, &d3); if (decNumberIsInfinite(&d3) || decNumberIsNaN(&d3) || decNumberIsZero(&d3) || signif == 0 || d3.digits <= signif) { decNumberCopy(&d1, &d3); } else { set.digits = signif; decNumberPlus(&d1, &d3, &set); } decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(reround_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED48 SLXT - Shift Coefficient Left DFP Extended [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_coefficient_left_dfp_ext) { int r1, r3; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal128 x1, x3; /* Extended DFP values */ decNumber d1, d3; /* Working decimal numbers */ decContext set; /* Working context */ int n; /* Number of bits to shift */ RXF(inst, regs, r1, r3, b2, effective_addr2); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r3, regs); /* Isolate rightmost 6 bits of second operand address */ n = effective_addr2 & 0x3F; /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r3 */ ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); /* Convert to internal decimal number format */ decimal128ToNumber(&x3, &d3); /* For NaN and Inf use coefficient continuation digits only */ if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3)) { dfp128_clear_cf_and_bxcf(&x3); decimal128ToNumber(&x3, &d1); } else { decNumberCopy(&d1, &d3); } /* Shift coefficient left n digit positions */ dfp_shift_coeff(&set, &d1, n); /* Convert result to DFP extended format */ decimal128FromNumber(&x1, &d1, &set); /* Restore Nan or Inf indicators in the result */ if (decNumberIsQNaN(&d3)) dfp128_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); else if (decNumberIsSNaN(&d3)) dfp128_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); else if (decNumberIsInfinite(&d3)) dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(shift_coefficient_left_dfp_ext) */ /*-------------------------------------------------------------------*/ /* ED40 SLDT - Shift Coefficient Left DFP Long [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_coefficient_left_dfp_long) { int r1, r3; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal64 x1, x3; /* Long DFP values */ decNumber d1, d3; /* Working decimal numbers */ decContext set; /* Working context */ int n; /* Number of bits to shift */ RXF(inst, regs, r1, r3, b2, effective_addr2); DFPINST_CHECK(regs); /* Isolate rightmost 6 bits of second operand address */ n = effective_addr2 & 0x3F; /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r3 */ ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); /* Convert to internal decimal number format */ decimal64ToNumber(&x3, &d3); /* For NaN and Inf use coefficient continuation digits only */ if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3)) { dfp64_clear_cf_and_bxcf(&x3); decimal64ToNumber(&x3, &d1); } else { decNumberCopy(&d1, &d3); } /* Shift coefficient left n digit positions */ dfp_shift_coeff(&set, &d1, n); /* Convert result to DFP long format */ decimal64FromNumber(&x1, &d1, &set); /* Restore Nan or Inf indicators in the result */ if (decNumberIsQNaN(&d3)) dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); else if (decNumberIsSNaN(&d3)) dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); else if (decNumberIsInfinite(&d3)) dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(shift_coefficient_left_dfp_long) */ /*-------------------------------------------------------------------*/ /* ED49 SRXT - Shift Coefficient Right DFP Extended [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_coefficient_right_dfp_ext) { int r1, r3; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal128 x1, x3; /* Extended DFP values */ decNumber d1, d3; /* Working decimal numbers */ decContext set; /* Working context */ int n; /* Number of bits to shift */ RXF(inst, regs, r1, r3, b2, effective_addr2); DFPINST_CHECK(regs); DFPREGPAIR2_CHECK(r1, r3, regs); /* Isolate rightmost 6 bits of second operand address */ n = effective_addr2 & 0x3F; /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r3 */ ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); /* Convert to internal decimal number format */ decimal128ToNumber(&x3, &d3); /* For NaN and Inf use coefficient continuation digits only */ if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3)) { dfp128_clear_cf_and_bxcf(&x3); decimal128ToNumber(&x3, &d1); } else { decNumberCopy(&d1, &d3); } /* Shift coefficient right n digit positions */ dfp_shift_coeff(&set, &d1, -n); /* Convert result to DFP extended format */ decimal128FromNumber(&x1, &d1, &set); /* Restore Nan or Inf indicators in the result */ if (decNumberIsQNaN(&d3)) dfp128_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); else if (decNumberIsSNaN(&d3)) dfp128_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); else if (decNumberIsInfinite(&d3)) dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); } /* end DEF_INST(shift_coefficient_right_dfp_ext) */ /*-------------------------------------------------------------------*/ /* ED41 SRDT - Shift Coefficient Right DFP Long [RXF] */ /*-------------------------------------------------------------------*/ DEF_INST(shift_coefficient_right_dfp_long) { int r1, r3; /* Values of R fields */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal64 x1, x3; /* Long DFP values */ decNumber d1, d3; /* Working decimal numbers */ decContext set; /* Working context */ int n; /* Number of bits to shift */ RXF(inst, regs, r1, r3, b2, effective_addr2); DFPINST_CHECK(regs); /* Isolate rightmost 6 bits of second operand address */ n = effective_addr2 & 0x3F; /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r3 */ ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); /* Convert to internal decimal number format */ decimal64ToNumber(&x3, &d3); /* For NaN and Inf use coefficient continuation digits only */ if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3)) { dfp64_clear_cf_and_bxcf(&x3); decimal64ToNumber(&x3, &d1); } else { decNumberCopy(&d1, &d3); } /* Shift coefficient right n digit positions */ dfp_shift_coeff(&set, &d1, -n); /* Convert result to DFP long format */ decimal64FromNumber(&x1, &d1, &set); /* Restore Nan or Inf indicators in the result */ if (decNumberIsQNaN(&d3)) dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN); else if (decNumberIsSNaN(&d3)) dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN); else if (decNumberIsInfinite(&d3)) dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); } /* end DEF_INST(shift_coefficient_right_dfp_long) */ /*-------------------------------------------------------------------*/ /* B3DB SXTR - Subtract DFP Extended Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_dfp_ext_reg) { int r1, r2, r3; /* Values of R fields */ decimal128 x1, x2, x3; /* Extended DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); DFPREGPAIR3_CHECK(r1, r2, r3, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Subtract FP register r3 from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs); decimal128ToNumber(&x2, &d2); decimal128ToNumber(&x3, &d3); decNumberSubtract(&d1, &d2, &d3, &set); decimal128FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&d1) ? 3 : decNumberIsZero(&d1) ? 0 : decNumberIsNegative(&d1) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(subtract_dfp_ext_reg) */ /*-------------------------------------------------------------------*/ /* B3D3 SDTR - Subtract DFP Long Register [RRR] */ /*-------------------------------------------------------------------*/ DEF_INST(subtract_dfp_long_reg) { int r1, r2, r3; /* Values of R fields */ decimal64 x1, x2, x3; /* Long DFP values */ decNumber d1, d2, d3; /* Working decimal numbers */ decContext set; /* Working context */ BYTE dxc; /* Data exception code */ RRR(inst, regs, r1, r2, r3); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); ARCH_DEP(dfp_rounding_mode)(&set, 0, regs); /* Subtract FP register r3 from FP register r2 */ ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs); ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs); decimal64ToNumber(&x2, &d2); decimal64ToNumber(&x3, &d3); decNumberSubtract(&d1, &d2, &d3, &set); decimal64FromNumber(&x1, &d1, &set); /* Check for exception condition */ dxc = ARCH_DEP(dfp_status_check)(&set, regs); /* Load result into FP register r1 */ ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs); /* Set condition code */ regs->psw.cc = decNumberIsNaN(&d1) ? 3 : decNumberIsZero(&d1) ? 0 : decNumberIsNegative(&d1) ? 1 : 2; /* Raise data exception if error occurred */ if (dxc != 0) { regs->dxc = dxc; ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION); } } /* end DEF_INST(subtract_dfp_long_reg) */ /*-------------------------------------------------------------------*/ /* ED58 TDCXT - Test Data Class DFP Extended [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_class_dfp_ext) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal128 x1; /* Extended DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ U32 bits; /* Low 12 bits of address */ RXE(inst, regs, r1, b2, effective_addr2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Convert FP register r1 to decimal number format */ ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs); decimal128ToNumber(&x1, &d1); /* Isolate rightmost 12 bits of second operand address */ bits = effective_addr2 & 0xFFF; /* Test data class and set condition code */ regs->psw.cc = dfp_test_data_class(&set, &d1, bits); } /* end DEF_INST(test_data_class_dfp_ext) */ /*-------------------------------------------------------------------*/ /* ED54 TDCDT - Test Data Class DFP Long [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_class_dfp_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal64 x1; /* Long DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ U32 bits; /* Low 12 bits of address */ RXE(inst, regs, r1, b2, effective_addr2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Convert FP register r1 to decimal number format */ ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs); decimal64ToNumber(&x1, &d1); /* Isolate rightmost 12 bits of second operand address */ bits = effective_addr2 & 0xFFF; /* Test data class and set condition code */ regs->psw.cc = dfp_test_data_class(&set, &d1, bits); } /* end DEF_INST(test_data_class_dfp_long) */ /*-------------------------------------------------------------------*/ /* ED50 TDCET - Test Data Class DFP Short [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_class_dfp_short) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal32 x1; /* Short DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ U32 bits; /* Low 12 bits of address */ RXE(inst, regs, r1, b2, effective_addr2); DFPINST_CHECK(regs); /* Initialise the context for short DFP */ decContextDefault(&set, DEC_INIT_DECIMAL32); /* Convert FP register r1 to decimal number format */ ARCH_DEP(dfp_reg_to_decimal32)(r1, &x1, regs); decimal32ToNumber(&x1, &d1); /* Isolate rightmost 12 bits of second operand address */ bits = effective_addr2 & 0xFFF; /* Test data class and set condition code */ regs->psw.cc = dfp_test_data_class(&set, &d1, bits); } /* end DEF_INST(test_data_class_dfp_short) */ /*-------------------------------------------------------------------*/ /* ED59 TDGXT - Test Data Group DFP Extended [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_group_dfp_ext) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal128 x1; /* Extended DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ U32 bits; /* Low 12 bits of address */ int lmd; /* Leftmost digit */ RXE(inst, regs, r1, b2, effective_addr2); DFPINST_CHECK(regs); DFPREGPAIR_CHECK(r1, regs); /* Initialise the context for extended DFP */ decContextDefault(&set, DEC_INIT_DECIMAL128); /* Load DFP extended number from FP register r1 */ ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs); /* Extract the leftmost digit from FP register r1 */ lmd = dfp128_extract_lmd(&x1); /* Convert to internal decimal number format */ decimal128ToNumber(&x1, &d1); /* Isolate rightmost 12 bits of second operand address */ bits = effective_addr2 & 0xFFF; /* Test data group and set condition code */ regs->psw.cc = dfp_test_data_group(&set, &d1, lmd, bits); } /* end DEF_INST(test_data_group_dfp_ext) */ /*-------------------------------------------------------------------*/ /* ED55 TDGDT - Test Data Group DFP Long [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_group_dfp_long) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal64 x1; /* Long DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ U32 bits; /* Low 12 bits of address */ int lmd; /* Leftmost digit */ RXE(inst, regs, r1, b2, effective_addr2); DFPINST_CHECK(regs); /* Initialise the context for long DFP */ decContextDefault(&set, DEC_INIT_DECIMAL64); /* Load DFP long number from FP register r1 */ ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs); /* Extract the leftmost digit from FP register r1 */ lmd = dfp64_extract_lmd(&x1); /* Convert to internal decimal number format */ decimal64ToNumber(&x1, &d1); /* Isolate rightmost 12 bits of second operand address */ bits = effective_addr2 & 0xFFF; /* Test data group and set condition code */ regs->psw.cc = dfp_test_data_group(&set, &d1, lmd, bits); } /* end DEF_INST(test_data_group_dfp_long) */ /*-------------------------------------------------------------------*/ /* ED51 TDGET - Test Data Group DFP Short [RXE] */ /*-------------------------------------------------------------------*/ DEF_INST(test_data_group_dfp_short) { int r1; /* Value of R field */ int b2; /* Base of effective addr */ VADR effective_addr2; /* Effective address */ decimal32 x1; /* Short DFP value */ decNumber d1; /* Working decimal number */ decContext set; /* Working context */ U32 bits; /* Low 12 bits of address */ int lmd; /* Leftmost digit */ RXE(inst, regs, r1, b2, effective_addr2); DFPINST_CHECK(regs); /* Initialise the context for short DFP */ decContextDefault(&set, DEC_INIT_DECIMAL32); /* Load DFP short number from FP register r1 */ ARCH_DEP(dfp_reg_to_decimal32)(r1, &x1, regs); /* Extract the leftmost digit from FP register r1 */ lmd = dfp32_extract_lmd(&x1); /* Convert to internal decimal number format */ decimal32ToNumber(&x1, &d1); /* Isolate rightmost 12 bits of second operand address */ bits = effective_addr2 & 0xFFF; /* Test data group and set condition code */ regs->psw.cc = dfp_test_data_group(&set, &d1, lmd, bits); } /* end DEF_INST(test_data_group_dfp_short) */ #endif /*defined(FEATURE_DECIMAL_FLOATING_POINT)*/ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "dfp.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "dfp.c" #endif #endif /*!defined(_GEN_ARCH)*/ /* end of dfp.c */ hercules-3.12/machdep.h0000664000175000017500000005635312564723224011771 00000000000000/* MACHDEP.H (c) Copyright Greg Smith, 2001-2010 */ /* Hercules machine specific code */ /*-------------------------------------------------------------------*/ /* */ /* This header file contains the following functions, defined as */ /* either normal unoptimzed C code, or else as hand-tuned optimized */ /* assembler-assisted functions for the given machine architecture: */ /* */ /* */ /* Atomic COMPARE-AND-EXCHANGE functions: */ /* */ /* cmpxchg1, cmpxchg4, cmpxchg8, cmpxchg16 */ /* */ /* */ /* Atomic word/double-word FETCH/STORE functions: */ /* */ /* fetch_hw, fetch_hw_noswap, store_hw, store_hw_noswap */ /* fetch_fw, fetch_fw_noswap, store_fw, store_fw_noswap */ /* fetch_dw, fetch_dw_noswap, store_dw, store_dw_noswap */ /* */ /* 64 bit architectures would normally not need to specify */ /* any of the fetch_ or store_ macros. */ /* */ /* 32 bit architectures should specify one of the `fetch_dw' */ /* and `store_dw' macros. Little-endian machines should specify */ /* the `noswap' macros. Big-endian machines can specify either, */ /* both being the same. */ /* */ /*-------------------------------------------------------------------*/ #ifndef _HERCULES_MACHDEP_H #define _HERCULES_MACHDEP_H 1 #include "opcode.h" // (need CSWAP32, et.al macros, etc) #include "htypes.h" // (need Hercules fixed-size data types) /*------------------------------------------------------------------- * Microsoft Visual C/C++... *-------------------------------------------------------------------*/ #if defined( _MSVC_ ) // PROGRAMMING NOTE: Optimizations normally only apply for release // builds, but we support optionally enabling them for debug too, // as well as purposely DISABLING them for troubleshooting... #define OPTION_ENABLE_MSVC_OPTIMIZATIONS_FOR_DEBUG_BUILDS_TOO // #define OPTION_DISABLE_MSVC_OPTIMIZATIONS #undef GEN_MSC_ASSISTS #if defined( DEBUG) || defined( _DEBUG ) #if defined(OPTION_ENABLE_MSVC_OPTIMIZATIONS_FOR_DEBUG_BUILDS_TOO) && \ !defined(OPTION_DISABLE_MSVC_OPTIMIZATIONS) #define GEN_MSC_ASSISTS #endif #else // (presumed RELEASE build) #if !defined(OPTION_DISABLE_MSVC_OPTIMIZATIONS) #define GEN_MSC_ASSISTS #endif #endif // (debug or release) #undef MSC_X86_32BIT // any 32-bit X86 (Pentium Pro, Pentium II, Pentium III or better) #undef MSC_X86_64BIT // any 64-bit X86 (AMD64 or Intel Itanium) #undef MSC_X86_AMD64 // AMD64 only #undef MSC_X86_IA64 // Intel Itanium only #if defined( _M_IX86 ) && ( _M_IX86 >= 600 ) #define MSC_X86_32BIT #endif #if defined( _M_AMD64 ) #define MSC_X86_AMD64 #define MSC_X86_64BIT #endif #if defined( _M_IA64 ) #define MSC_X86_IA64 #define MSC_X86_64BIT #endif #if defined(GEN_MSC_ASSISTS) && (defined(MSC_X86_32BIT) || defined(MSC_X86_64BIT)) // Any X86 at all (both 32/64-bit) #pragma intrinsic ( _InterlockedCompareExchange ) #define cmpxchg1( x, y, z ) cmpxchg1_x86( x, y, z ) #define cmpxchg4( x, y, z ) cmpxchg4_x86( x, y, z ) #define cmpxchg8( x, y, z ) cmpxchg8_x86( x, y, z ) #if ( _MSC_VER < 1400 ) // PROGRAMMING NOTE: compiler versions earlier than VS8 2005 // do not have the _InterlockedCompareExchange64 intrinsic so // we use our own hand-coded inline assembler routine instead. // Also note that we can't use __fastcall here since doing so // would interfere with our register usage. static __inline BYTE cmpxchg8_x86 ( U64 *pOldVal, U64 u64NewVal, volatile void *pTarget ) { // returns 0 == success, 1 otherwise BYTE rc; U32 u32NewValHigh = u64NewVal >> 32; U32 u32NewValLow = u64NewVal & 0xffffffff; __asm { mov esi, [pOldVal] mov eax, [esi + 0] mov edx, [esi + 4] mov ebx, [u32NewValLow] mov ecx, [u32NewValHigh] mov esi, [pTarget] #ifdef OPTION_SMP lock cmpxchg8b qword ptr [esi] #else cmpxchg8b qword ptr [esi] #endif setne rc jz success mov esi, [pOldVal] mov [esi + 0], eax mov [esi + 4], edx }; success: return rc; } #else // ( _MSC_VER >= 1400 ) #pragma intrinsic ( _InterlockedCompareExchange64 ) static __inline BYTE __fastcall cmpxchg8_x86 ( U64 *old, U64 new, volatile void *ptr ) { // returns 0 == success, 1 otherwise U64 tmp = *old; *old = _InterlockedCompareExchange64( ptr, new, *old ); return ((tmp == *old) ? 0 : 1); } #endif // ( _MSC_VER >= 1400 ) static __inline BYTE __fastcall cmpxchg4_x86 ( U32 *old, U32 new, volatile void *ptr ) { // returns 0 == success, 1 otherwise U32 tmp = *old; *old = _InterlockedCompareExchange( ptr, new, *old ); return ((tmp == *old) ? 0 : 1); } // (must follow cmpxchg4 since it uses it) static __inline BYTE __fastcall cmpxchg1_x86 ( BYTE *old, BYTE new, volatile void *ptr ) { // returns 0 == success, 1 otherwise LONG_PTR off, shift; BYTE cc; U32 *ptr4, val4, old4, new4; off = (LONG_PTR)ptr & 3; shift = (3 - off) * 8; ptr4 = (U32*)(((BYTE*)ptr) - off); val4 = CSWAP32(*ptr4); old4 = CSWAP32((val4 & ~(0xff << shift)) | (*old << shift)); new4 = CSWAP32((val4 & ~(0xff << shift)) | ( new << shift)); cc = cmpxchg4( &old4, new4, ptr4 ); *old = (CSWAP32(old4) >> shift) & 0xff; return cc; } #if defined(MSC_X86_32BIT) #define fetch_dw_noswap(_p) fetch_dw_x86_noswap((_p)) // (must follow cmpxchg8 since it uses it) static __inline U64 __fastcall fetch_dw_x86_noswap ( volatile void *ptr ) { U64 value = *(U64*)ptr; cmpxchg8( &value, value, (U64*)ptr ); return value; } #define store_dw_noswap(_p, _v) store_dw_x86_noswap( (_p), (_v)) // (must follow cmpxchg8 since it uses it) static __inline void __fastcall store_dw_x86_noswap ( volatile void *ptr, U64 value ) { U64 orig = *(U64*)ptr; while ( cmpxchg8( &orig, value, (U64*)ptr ) ); } #endif /* defined(MSC_X86_32BIT) */ #endif // defined(GEN_MSC_ASSISTS) && (defined(MSC_X86_32BIT) || defined(MSC_X86_64BIT)) // ------------------------------------------------------------------ #if defined(GEN_MSC_ASSISTS) && defined(MSC_X86_IA64) // (64-bit Itanium assists only) // ZZ FIXME: we should probably use the 'cmpxchg16b' instruction here // instead if the processor supports it (CPUID instruction w/EAX function // code 1 == Feature Information --> ECX bit 13 = CMPXCHG16B available) #pragma intrinsic ( _AcquireSpinLock ) #pragma intrinsic ( _ReleaseSpinLock ) #pragma intrinsic ( _ReadWriteBarrier ) #define cmpxchg16( x1, x2, y1, y2, z ) \ cmpxchg16_x86( x1, x2, y1, y2, z ) static __inline int __fastcall cmpxchg16_x86 ( U64 *old1, U64 *old2, U64 new1, U64 new2, volatile void *ptr ) { // returns 0 == success, 1 otherwise static unsigned __int64 lock = 0; int code; _AcquireSpinLock( &lock ); _ReadWriteBarrier(); if (*old1 == *(U64*)ptr && *old2 == *((U64*)ptr + 1)) { *(U64*)ptr = new1; *((U64*)ptr + 1) = new2; code = 0; } else { *old1 = *((U64*)ptr); *old2 = *((U64*)ptr + 1); code = 1; } _ReleaseSpinLock( &lock ); return code; } #endif // defined(GEN_MSC_ASSISTS) && defined(MSC_X86_IA64) #else // !defined( _MSVC_ ) /*------------------------------------------------------------------- * GNU C or other compiler... (i.e. NON-Microsoft C/C++) *-------------------------------------------------------------------*/ #if defined(__i686__) || defined(__pentiumpro__) || \ defined(__pentium4__) || defined(__athlon__) || \ defined(__athlon) #define _ext_ia32 #endif #if defined(__amd64__) #define _ext_amd64 #endif #if defined(__powerpc__) || defined(__ppc__) || \ defined(__POWERPC__) || defined(__PPC__) || \ defined(_POWER) #define _ext_ppc #endif /*------------------------------------------------------------------- * Intel pentiumpro/i686 *-------------------------------------------------------------------*/ #if defined(_ext_ia32) #undef LOCK_PREFIX #ifdef OPTION_SMP #define LOCK_PREFIX "lock\n\t" #else #define LOCK_PREFIX "" #endif /* * If PIC is defined then ebx is used as the `thunk' reg * However cmpxchg8b requires ebx * In this case we load the value into esi and then * exchange esi and ebx before and after cmpxchg8b */ #undef BREG #undef XCHG_BREG #if defined(PIC) && !defined(__CYGWIN__) #define BREG "S" #define XCHG_BREG "xchgl %%ebx,%%esi\n\t" #else #define BREG "b" #define XCHG_BREG "" #endif #define cmpxchg1(x,y,z) cmpxchg1_i686(x,y,z) static __inline__ BYTE cmpxchg1_i686(BYTE *old, BYTE new, void *ptr) { BYTE code; __asm__ __volatile__ ( LOCK_PREFIX "cmpxchgb %b3,%4\n\t" "setnz %b0" : "=q"(code), "=a"(*old) : "1" (*old), "q" (new), "m" (*(BYTE *)ptr) : "cc" ); return code; } #define cmpxchg4(x,y,z) cmpxchg4_i686(x,y,z) static __inline__ BYTE cmpxchg4_i686(U32 *old, U32 new, void *ptr) { BYTE code; __asm__ __volatile__ ( LOCK_PREFIX "cmpxchgl %3,%4\n\t" "setnz %b0" : "=q"(code), "=a"(*old) : "1" (*old), "q" (new), "m" (*(U32 *)ptr) : "cc" ); return code; } #define cmpxchg8(x,y,z) cmpxchg8_i686(x,y,z) static __inline__ BYTE cmpxchg8_i686(U64 *old, U64 new, void *ptr) { BYTE code; __asm__ __volatile__ ( XCHG_BREG LOCK_PREFIX "cmpxchg8b %5\n\t" XCHG_BREG "setnz %b0" : "=q"(code), "=A"(*old) : "1" (*old), BREG ((unsigned long)new), "c" ((unsigned long)(new >> 32)), "m" (*(U64 *)ptr) : "cc"); return code; } #define fetch_dw_noswap(x) fetch_dw_i686_noswap(x) static __inline__ U64 fetch_dw_i686_noswap(void *ptr) { U64 value = *(U64 *)ptr; __asm__ __volatile__ ( XCHG_BREG LOCK_PREFIX "cmpxchg8b (%4)\n\t" XCHG_BREG : "=A" (value) : "0" (value), BREG ((unsigned long)value), "c" ((unsigned long)(value >> 32)), "D" (ptr)); return value; } #define store_dw_noswap(x,y) store_dw_i686_noswap(x,y) static __inline__ void store_dw_i686_noswap(void *ptr, U64 value) { __asm__ __volatile__ ( XCHG_BREG "1:\t" LOCK_PREFIX "cmpxchg8b %3\n\t" "jne 1b\n\t" XCHG_BREG : : "A" (*(U64 *)ptr), BREG ((unsigned long)value), "c" ((unsigned long)(value >> 32)), "m" (*(U64 *)ptr)); } #if defined(OPTION_MULTI_BYTE_ASSIST) && defined(__linux__) #define MULTI_BYTE_ASSIST #define MULTI_BYTE_ASSIST_IA32 #endif #endif /* defined(_ext_ia32) */ /*------------------------------------------------------------------- * AMD64 *-------------------------------------------------------------------*/ #if defined(_ext_amd64) #define cmpxchg1(x,y,z) cmpxchg1_amd64(x,y,z) static __inline__ BYTE cmpxchg1_amd64(BYTE *old, BYTE new, void *ptr) { /* returns zero on success otherwise returns 1 */ BYTE code; BYTE *ptr_data=ptr; __asm__ __volatile__ ( "lock; cmpxchgb %b2,%4\n\t" "setnz %b0\n\t" : "=q"(code), "=a"(*old) : "q"(new), "1"(*old), "m"(*ptr_data) : "cc"); return code; } #define cmpxchg4(x,y,z) cmpxchg4_amd64(x,y,z) static __inline__ BYTE cmpxchg4_amd64(U32 *old, U32 new, void *ptr) { /* returns zero on success otherwise returns 1 */ BYTE code; U32 *ptr_data=ptr; __asm__ __volatile__ ( "lock; cmpxchgl %2,%4\n\t" "setnz %b0\n\t" : "=q"(code), "=a"(*old) : "q"(new), "1"(*old), "m"(*ptr_data) : "cc"); return code; } #define cmpxchg8(x,y,z) cmpxchg8_amd64(x,y,z) static __inline__ BYTE cmpxchg8_amd64(U64 *old, U64 new, void *ptr) { /* returns zero on success otherwise returns 1 */ BYTE code; U64 *ptr_data=ptr; __asm__ __volatile__ ( "lock; cmpxchgq %2,%4\n\t" "setnz %b0\n\t" : "=q"(code), "=a"(*old) : "q"(new), "1"(*old), "m"(*ptr_data) : "cc"); return code; } #endif /* defined(_ext_amd64) */ /*------------------------------------------------------------------- * PowerPC *-------------------------------------------------------------------*/ #if defined(_ext_ppc) /* From /usr/src/linux/include/asm-ppc/system.h */ /* NOTE: IBM's VisualAge compiler likes 1: style labels but GNU's gcc compiler running on AIX does not. */ #if !defined( __GNUC__ ) // (VisualAge presumed) #define LABEL1 "1:\n" #define LABEL2 "2:\n" #define BRNCH2 "2f" #define BRNCH1 "1b" #else // (else gcc...) #define LABEL1 "loop%=:\n" #define LABEL2 "exit%=:\n" #define BRNCH2 "exit%=" #define BRNCH1 "loop%=" #endif /* NOTE: Both VisualAge *and* gcc define __64BIT__ see: http://gmplib.org/list-archives/gmp-discuss/2008-July/003339.html */ #if defined( __64BIT__ ) static __inline__ U64 __cmpxchg_u64(volatile U64 *p, U64 old, U64 new) { U64 prev; __asm__ __volatile__ ("\n" LABEL1 " ldarx %0,0,%2\n\ cmpd 0,%0,%3\n\ bne "BRNCH2"\n\ stdcx. %4,0,%2\n\ bne- "BRNCH1"\n" #ifdef OPTION_SMP " sync\n" #endif /* OPTION_SMP */ LABEL2 : "=&r" (prev), "=m" (*p) : "r" (p), "r" (old), "r" (new), "m" (*p) : "cc", "memory"); return prev; } #define cmpxchg8(x,y,z) cmpxchg8_ppc(x,y,z) static __inline__ BYTE cmpxchg8_ppc(U64 *old, U64 new, void *ptr) { /* returns zero on success otherwise returns 1 */ U64 prev = *old; return (prev != (*old = __cmpxchg_u64((U64*)ptr, prev, new))); } #endif // defined( __64BIT__ ) static __inline__ U32 __cmpxchg_u32(volatile U32 *p, U32 old, U32 new) { U32 prev; __asm__ __volatile__ ("\n" LABEL1 " lwarx %0,0,%2\n\ cmpw 0,%0,%3\n\ bne "BRNCH2"\n\ stwcx. %4,0,%2\n\ bne- "BRNCH1"\n" #ifdef OPTION_SMP " sync\n" #endif /* OPTION_SMP */ LABEL2 : "=&r" (prev), "=m" (*p) : "r" (p), "r" (old), "r" (new), "m" (*p) : "cc", "memory"); return prev; } #define cmpxchg4(x,y,z) cmpxchg4_ppc(x,y,z) static __inline__ BYTE cmpxchg4_ppc(U32 *old, U32 new, void *ptr) { /* returns zero on success otherwise returns 1 */ U32 prev = *old; return (prev != (*old = __cmpxchg_u32((U32*)ptr, prev, new))); } #define cmpxchg1(x,y,z) cmpxchg1_ppc(x,y,z) static __inline__ BYTE cmpxchg1_ppc(BYTE *old, BYTE new, void *ptr) { /* returns zero on success otherwise returns 1 */ long off, shift; BYTE cc; U32 *ptr4, val4, old4, new4; off = (long)ptr & 3; shift = (3 - off) * 8; ptr4 = ptr - off; val4 = *ptr4; old4 = (val4 & ~(0xff << shift)) | (*old << shift); new4 = (val4 & ~(0xff << shift)) | (new << shift); cc = cmpxchg4_ppc(&old4, new4, ptr4); *old = (old4 >> shift) & 0xff; return cc; } #endif /* defined(_ext_ppc) */ #endif // !defined( _MSVC_ ) /*------------------------------------------------------------------- * Define the ASSIST_ macros *-------------------------------------------------------------------*/ #if defined(cmpxchg1) #define ASSIST_CMPXCHG1 #endif #if defined(cmpxchg4) #define ASSIST_CMPXCHG4 #endif #if defined(cmpxchg8) #define ASSIST_CMPXCHG8 #endif #if defined(cmpxchg16) #define ASSIST_CMPXCHG16 #endif #if defined(fetch_dw) || defined(fetch_dw_noswap) #define ASSIST_FETCH_DW #endif #if defined(store_dw) || defined(store_dw_noswap) #define ASSIST_STORE_DW #endif /*------------------------------------------------------------------- * Decide if strict alignment is required *-------------------------------------------------------------------*/ #if !defined(OPTION_STRICT_ALIGNMENT) && !defined(OPTION_NO_STRICT_ALIGNMENT) #if !defined(_MSVC_) && !defined(_ext_ia32) && !defined(_ext_amd64) \ && !defined(_ext_ppc) #define OPTION_STRICT_ALIGNMENT #endif #endif /*------------------------------------------------------------------- * fetch_hw_noswap and fetch_hw *-------------------------------------------------------------------*/ #if !defined(fetch_hw_noswap) #if defined(fetch_hw) #define fetch_hw_noswap(_p) CSWAP16(fetch_hw((_p))) #else #if !defined(OPTION_STRICT_ALIGNMENT) static __inline__ U16 fetch_hw_noswap(void *ptr) { return *(U16 *)ptr; } #else static __inline__ U16 fetch_hw_noswap(void *ptr) { U16 value; memcpy(&value, (BYTE *)ptr, 2); return value; } #endif #endif #endif #if !defined(fetch_hw) #define fetch_hw(_p) CSWAP16(fetch_hw_noswap((_p))) #endif /*------------------------------------------------------------------- * store_hw_noswap and store_hw *-------------------------------------------------------------------*/ #if !defined(store_hw_noswap) #if defined(store_hw) #define store_hw_noswap(_p, _v) store_hw((_p), CSWAP16(_v)) #else #if !defined(OPTION_STRICT_ALIGNMENT) static __inline__ void store_hw_noswap(void *ptr, U16 value) { *(U16 *)ptr = value; } #else static __inline__ void store_hw_noswap(void *ptr, U16 value) { memcpy((BYTE *)ptr, (BYTE *)&value, 2); } #endif #endif #endif #if !defined(store_hw) #define store_hw(_p, _v) store_hw_noswap((_p), CSWAP16((_v))) #endif /*------------------------------------------------------------------- * fetch_fw_noswap and fetch_fw *-------------------------------------------------------------------*/ #if !defined(fetch_fw_noswap) #if defined(fetch_fw) #define fetch_fw_noswap(_p) CSWAP32(fetch_fw((_p))) #else #if !defined(OPTION_STRICT_ALIGNMENT) static __inline__ U32 fetch_fw_noswap(const void *ptr) { return *(U32 *)ptr; } #else static __inline__ U32 fetch_fw_noswap(const void *ptr) { U32 value; memcpy(&value, (BYTE *)ptr, 4); return value; } #endif #endif #endif #if !defined(fetch_fw) #define fetch_fw(_p) CSWAP32(fetch_fw_noswap((_p))) #endif /*------------------------------------------------------------------- * store_fw_noswap and store_fw *-------------------------------------------------------------------*/ #if !defined(store_fw_noswap) #if defined(store_fw) #define store_fw_noswap(_p, _v) store_fw((_p), CSWAP32(_v)) #else #if !defined(OPTION_STRICT_ALIGNMENT) static __inline__ void store_fw_noswap(void *ptr, U32 value) { *(U32 *)ptr = value; } #else static __inline__ void store_fw_noswap(void *ptr, U32 value) { memcpy((BYTE *)ptr, (BYTE *)&value, 4); } #endif #endif #endif #if !defined(store_fw) #define store_fw(_p, _v) store_fw_noswap((_p), CSWAP32((_v))) #endif /*------------------------------------------------------------------- * fetch_dw_noswap and fetch_dw *-------------------------------------------------------------------*/ #if !defined(fetch_dw_noswap) #if defined(fetch_dw) #define fetch_dw_noswap(_p) CSWAP64(fetch_dw((_p))) #else #if !defined(OPTION_STRICT_ALIGNMENT) static __inline__ U64 fetch_dw_noswap(void *ptr) { return *(U64 *)ptr; } #else static __inline__ U64 fetch_dw_noswap(void *ptr) { U64 value; memcpy(&value, (BYTE *)ptr, 8); return value; } #endif #endif #endif #if !defined(fetch_dw) #define fetch_dw(_p) CSWAP64(fetch_dw_noswap((_p))) #endif /*------------------------------------------------------------------- * store_dw_noswap and store_dw *-------------------------------------------------------------------*/ #if !defined(store_dw_noswap) #if defined(store_dw) #define store_dw_noswap(_p, _v) store_dw((_p), CSWAP64(_v)) #else #if !defined(OPTION_STRICT_ALIGNMENT) static __inline__ void store_dw_noswap(void *ptr, U64 value) { *(U64 *)ptr = value; } #else static __inline__ void store_dw_noswap(void *ptr, U64 value) { memcpy((BYTE *)ptr, (BYTE *)&value, 8); } #endif #endif #endif #if !defined(store_dw) #define store_dw(_p, _v) store_dw_noswap((_p), CSWAP64((_v))) #endif /*------------------------------------------------------------------- * cmpxchg1 *-------------------------------------------------------------------*/ #ifndef cmpxchg1 static __inline__ BYTE cmpxchg1(BYTE *old, BYTE new, volatile void *ptr) { BYTE code; if (*old == *(BYTE *)ptr) { *(BYTE *)ptr = new; code = 0; } else { *old = *(BYTE *)ptr; code = 1; } return code; } #endif /*------------------------------------------------------------------- * cmpxchg4 *-------------------------------------------------------------------*/ #ifndef cmpxchg4 static __inline__ BYTE cmpxchg4(U32 *old, U32 new, volatile void *ptr) { BYTE code; if (*old == *(U32 *)ptr) { *(U32 *)ptr = new; code = 0; } else { *old = *(U32 *)ptr; code = 1; } return code; } #endif /*------------------------------------------------------------------- * cmpxchg8 *-------------------------------------------------------------------*/ #ifndef cmpxchg8 static __inline__ BYTE cmpxchg8(U64 *old, U64 new, volatile void *ptr) { BYTE code; if (*old == *(U64 *)ptr) { *(U64 *)ptr = new; code = 0; } else { *old = *(U64 *)ptr; code = 1; } return code; } #endif /*------------------------------------------------------------------- * cmpxchg16 *-------------------------------------------------------------------*/ #ifndef cmpxchg16 static __inline__ int cmpxchg16(U64 *old1, U64 *old2, U64 new1, U64 new2, volatile void *ptr) { int code; if (*old1 == *(U64 *)ptr && *old2 == *((U64 *)ptr + 1)) { *(U64 *)ptr = new1; *((U64 *)ptr + 1) = new2; code = 0; } else { *old1 = *((U64 *)ptr); *old2 = *((U64 *)ptr + 1); code = 1; } return code; } #endif #ifndef BIT #define BIT(nr) (1<<(nr)) #endif #endif /* _HERCULES_MACHDEP_H */ hercules-3.12/httpserv.c0000664000175000017500000006111212564723224012227 00000000000000/* HTTPSERV.C (c)Copyright Jan Jaeger, 2002-2009 */ /* HTTP Server */ /* This file contains all code required for the HTTP server, */ /* when the http_server thread is started it will listen on */ /* the HTTP port specified on the HTTPPORT config statement. */ /* */ /* When a request comes in a http_request thread is started, */ /* which will handle the request. */ /* */ /* When authentification is required (auth parm on the HTTPPORT */ /* statement) then the user will be authenticated based on the */ /* userid and password supplied on the HTTPPORT statement, if */ /* these where not supplied then the userid and password of the */ /* that hercules is running under will be used. In the latter case */ /* the root userid/password will also be accepted. */ /* */ /* If the request is for a /cgi-bin/ path, then the cgibin */ /* directory in cgibin.c will be searched, for any other request */ /* the sysblk.httproot (/usr/local/hercules) will be used as the */ /* root to find the specified file. */ /* */ /* As realpath() is used to verify that the files are from within */ /* the sysblk.httproot tree symbolic links that refer to files */ /* outside the sysblk.httproot tree are not supported. */ /* */ /* */ /* Jan Jaeger - 28/03/2002 */ #include "hstdinc.h" #define _HTTPSERV_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "httpmisc.h" #include "hostinfo.h" #if defined(OPTION_HTTP_SERVER) /* External reference to the cgi-bin directory in cgibin.c */ extern CGITAB cgidir[]; static MIMETAB mime_types[] = { { NULL, NULL }, /* No suffix entry */ { "txt", "text/plain" }, { "jcl", "text/plain" }, { "gif", "image/gif" }, { "jpg", "image/jpeg" }, { "css", "text/css" }, { "html", "text/html" }, { "htm", "text/html" }, /* This one should be: { "ico", "image/vnd.microsoft.icon" }, but Apache 2 sets it as: */ { "ico", "image/x-icon" }, /* so we'll go with what's actually in use. --JRM */ { NULL, NULL } }; /* Default suffix entry */ DLL_EXPORT int html_include(WEBBLK *webblk, char *filename) { FILE *inclfile; char fullname[HTTP_PATH_LENGTH]; char buffer[HTTP_PATH_LENGTH]; int ret; strlcpy( fullname, sysblk.httproot, sizeof(fullname) ); strlcat( fullname, filename, sizeof(fullname) ); inclfile = fopen(fullname,"rb"); if (!inclfile) { logmsg(_("HHCHT011E html_include: Cannot open %s: %s\n"), fullname,strerror(errno)); hprintf(webblk->sock,_("ERROR: Cannot open %s: %s\n"), filename,strerror(errno)); return FALSE; } while (!feof(inclfile)) { ret = fread(buffer, 1, sizeof(buffer), inclfile); if (ret <= 0) break; hwrite(webblk->sock,buffer, ret); } fclose(inclfile); return TRUE; } DLL_EXPORT void html_header(WEBBLK *webblk) { if (webblk->request_type != REQTYPE_POST) hprintf(webblk->sock,"Expires: 0\n"); hprintf(webblk->sock,"Content-type: text/html\n\n"); if (!html_include(webblk,HTML_HEADER)) hprintf(webblk->sock,"\n\nHercules\n\n\n\n"); } DLL_EXPORT void html_footer(WEBBLK *webblk) { if (!html_include(webblk,HTML_FOOTER)) hprintf(webblk->sock,"\n\n\n"); } static void http_exit(WEBBLK *webblk) { CGIVAR *cgivar; int rc; if(webblk) { /* MS SDK docs state: "To assure that all data is sent and received on a connected socket before it is closed, an application should use shutdown to close connection before calling closesocket. For example, to initiate a graceful disconnect: 1, Call WSAAsyncSelect to register for FD_CLOSE notification. 2. Call shutdown with how=SD_SEND. 3. When FD_CLOSE received, call recv until zero returned, or SOCKET_ERROR. 4. Call closesocket. Note: The shutdown function does not block regardless of the SO_LINGER setting on the socket." */ // Notify other end of connection to not expect any more data from us. // They should detect this via their own 'recv' returning zero bytes // (thus letting them know they've thus received all the data from us // they're ever going to receive). They should then do their own // 'shutdown(s,SHUT_WR)' at their end letting US know we're also not // going to be receiving any more data from THEM. This is called a // "graceful close" of the connection... shutdown( webblk->sock, SHUT_WR ); // Now wait for them to shudown THEIR end of the connection (i.e. wait // for them to do their own 'shutdown(s,SHUT_WR)') by "hanging" on a // 'recv' call until we either eventually detect they've shutdown their // end of the connection (0 bytes received) or else an error occurs... do { BYTE c; rc = read_socket( webblk->sock, &c, 1 ); } while ( rc > 0 ); // NOW we can SAFELY close the socket since we now KNOW for CERTAIN // that they've received ALL of the data we previously sent to them... // (otherwise they wouldn't have close their connection on us!) close_socket( webblk->sock ); if(webblk->user) free(webblk->user); if(webblk->request) free(webblk->request); cgivar = webblk->cgivar; while(cgivar) { CGIVAR *tmpvar = cgivar->next; free(cgivar->name); free(cgivar->value); free(cgivar); cgivar = tmpvar; } free(webblk); } exit_thread(NULL); } static void http_error(WEBBLK *webblk, char *err, char *header, char *info) { hprintf(webblk->sock,"HTTP/1.0 %s\n%sConnection: close\n" "Content-Type: text/html\n\n" "%s" "

%s

%s\n\n", err, header, err, err, info); http_exit(webblk); } static char *http_timestring(char *time_buff,int buff_size, time_t t) { struct tm *tm = localtime(&t); strftime(time_buff, buff_size, "%a, %d %b %Y %H:%M:%S %Z", tm); return time_buff; } static void http_decode_base64(char *s) { char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int bit_o, byte_o, idx, i, n; unsigned char *d = (unsigned char *)s; char *p; n = i = 0; while (*s && (p = strchr(b64, *s))) { idx = (int)(p - b64); byte_o = (i*6)/8; bit_o = (i*6)%8; d[byte_o] &= ~((1<<(8-bit_o))-1); if (bit_o < 3) { d[byte_o] |= (idx << (2-bit_o)); n = byte_o+1; } else { d[byte_o] |= (idx >> (bit_o-2)); d[byte_o+1] = 0; d[byte_o+1] |= (idx << (8-(bit_o-2))) & 0xFF; n = byte_o+2; } s++; i++; } /* null terminate */ d[n] = 0; } static char *http_unescape(char *buffer) { char *pointer = buffer; while ( (pointer = strchr(pointer,'+')) ) *pointer = ' '; pointer = buffer; while (pointer && *pointer && (pointer = strchr(pointer,'%'))) { int highnibble = pointer[1]; int lownibble = pointer[2]; if (highnibble >= '0' && highnibble <= '9') highnibble = highnibble - '0'; else if (highnibble >= 'A' && highnibble <= 'F') highnibble = 10 + highnibble - 'A'; else if (highnibble >= 'a' && highnibble <= 'f') highnibble = 10 + highnibble - 'a'; else { pointer++; continue; } if (lownibble >= '0' && lownibble <= '9') lownibble = lownibble - '0'; else if (lownibble >= 'A' && lownibble <= 'F') lownibble = 10 + lownibble - 'A'; else if (lownibble >= 'a' && lownibble <= 'f') lownibble = 10 + lownibble - 'a'; else { pointer++; continue; } *pointer = (highnibble<<4) | lownibble; memmove(pointer+1, pointer+3, strlen(pointer+3)+1); pointer++; } return buffer; } static void http_interpret_variable_string(WEBBLK *webblk, char *qstring, int type) { char *name; char *value; char *strtok_str; CGIVAR **cgivar; for (cgivar = &(webblk->cgivar); *cgivar; cgivar = &((*cgivar)->next)); for (name = strtok_r(qstring,"&; ",&strtok_str); name; name = strtok_r(NULL,"&; ",&strtok_str)) { if(!(value = strchr(name,'='))) continue; *value++ = '\0'; (*cgivar) = malloc(sizeof(CGIVAR)); (*cgivar)->next = NULL; (*cgivar)->name = strdup(http_unescape(name)); (*cgivar)->value = strdup(http_unescape(value)); (*cgivar)->type = type; cgivar = &((*cgivar)->next); } } #if 0 static void http_dump_cgi_variables(WEBBLK *webblk) { CGIVAR *cv; for(cv = webblk->cgivar; cv; cv = cv->next) logmsg(_("HHCHT012I cgi_var_dump: pointer(%p) name(%s) value(%s) type(%d)\n"), cv, cv->name, cv->value, cv->type); } #endif DLL_EXPORT char *http_variable(WEBBLK *webblk, char *name, int type) { CGIVAR *cv; for(cv = webblk->cgivar; cv; cv = cv->next) if((cv->type & type) && !strcmp(name,cv->name)) return cv->value; return NULL; } static void http_verify_path(WEBBLK *webblk, char *path) { char resolved_path[HTTP_PATH_LENGTH]; #if 0 int i; for (i = 0; path[i]; i++) if (!isalnum((int)path[i]) && !strchr("/.-_", path[i])) http_error(webblk, "404 File Not Found","", "Illegal character in filename"); #endif if (!realpath( path, resolved_path )) http_error(webblk, "404 File Not Found","", "Invalid pathname"); // The following verifies the specified file does not lie // outside the specified httproot (Note: sysblk.httproot // was previously resolved to an absolute path by config.c) if (strncmp( sysblk.httproot, resolved_path, strlen(sysblk.httproot))) http_error(webblk, "404 File Not Found","", "Invalid pathname"); } static int http_authenticate(WEBBLK *webblk, char *type, char *userpass) { char *pointer ,*user, *passwd; if (!strcasecmp(type,"Basic")) { if(userpass) { http_decode_base64(userpass); /* the format is now user:password */ if ((pointer = strchr(userpass,':'))) { *pointer = 0; user = userpass; passwd = pointer+1; /* Hardcoded userid and password in configuration file */ if(sysblk.httpuser && sysblk.httppass) { if(!strcmp(user,sysblk.httpuser) && !strcmp(passwd,sysblk.httppass)) { webblk->user = strdup(user); return TRUE; } } #if !defined(WIN32) else { struct passwd *pass = NULL; /* unix userid and password check, the userid must be the same as that hercules is currently running under */ // ZZ INCOMPLETE // ZZ No password check is being performed yet... if((pass = getpwnam(user)) && (pass->pw_uid == 0 || pass->pw_uid == getuid())) { webblk->user = strdup(user); return TRUE; } } #endif /*!defined(WIN32)*/ } } } webblk->user = NULL; return FALSE; } static void http_download(WEBBLK *webblk, char *filename) { char buffer[HTTP_PATH_LENGTH]; char tbuf[80]; int fd, length; char *filetype; char fullname[HTTP_PATH_LENGTH]; struct stat st; MIMETAB *mime_type = mime_types; strlcpy( fullname, sysblk.httproot, sizeof(fullname) ); strlcat( fullname, filename, sizeof(fullname) ); http_verify_path(webblk,fullname); if(stat(fullname,&st)) http_error(webblk, "404 File Not Found","", strerror(errno)); if(!S_ISREG(st.st_mode)) http_error(webblk, "404 File Not Found","", "The requested file is not a regular file"); fd = hopen(fullname,O_RDONLY|O_BINARY,0); if (fd == -1) http_error(webblk, "404 File Not Found","", strerror(errno)); hprintf(webblk->sock,"HTTP/1.0 200 OK\n"); if ((filetype = strrchr(filename,'.'))) for(mime_type++;mime_type->suffix && strcasecmp(mime_type->suffix,filetype + 1); mime_type++); if(mime_type->type) hprintf(webblk->sock,"Content-Type: %s\n", mime_type->type); hprintf(webblk->sock,"Expires: %s\n", http_timestring(tbuf,sizeof(tbuf),time(NULL)+HTML_STATIC_EXPIRY_TIME)); hprintf(webblk->sock,"Content-Length: %d\n\n", (int)st.st_size); while ((length = read(fd, buffer, sizeof(buffer))) > 0) hwrite(webblk->sock,buffer, length); close(fd); http_exit(webblk); } static void *http_request(int sock) { WEBBLK *webblk; int authok = !sysblk.httpauth; char line[HTTP_PATH_LENGTH]; char *url = NULL; char *pointer; char *strtok_str; CGITAB *cgient; int content_length = 0; if(!(webblk = malloc(sizeof(WEBBLK)))) http_exit(webblk); memset(webblk,0,sizeof(WEBBLK)); webblk->sock = sock; while (hgets(line, sizeof(line), webblk->sock)) { if (*line == '\r' || *line == '\n') break; if((pointer = strtok_r(line," \t\r\n",&strtok_str))) { if(!strcasecmp(pointer,"GET")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) { webblk->request_type = REQTYPE_GET; url = strdup(pointer); } } else if(!strcasecmp(pointer,"POST")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) { webblk->request_type = REQTYPE_POST; url = strdup(pointer); } } else if(!strcasecmp(pointer,"PUT")) { http_error(webblk,"400 Bad Request", "", "This server does not accept PUT requests"); } else if(!strcasecmp(pointer,"Authorization:")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) authok = http_authenticate(webblk,pointer, strtok_r(NULL," \t\r\n",&strtok_str)); } else if(!strcasecmp(pointer,"Cookie:")) { if((pointer = strtok_r(NULL,"\r\n",&strtok_str))) http_interpret_variable_string(webblk, pointer, VARTYPE_COOKIE); } else if(!strcasecmp(pointer,"Content-Length:")) { if((pointer = strtok_r(NULL," \t\r\n",&strtok_str))) content_length = atoi(pointer); } } } webblk->request = url; if(webblk->request_type == REQTYPE_POST && content_length != 0) { char *post_arg; if((pointer = post_arg = malloc(content_length + 1))) { int i; for(i = 0; i < content_length; i++) { *pointer = hgetc(webblk->sock); if(*pointer != '\n' && *pointer != '\r') pointer++; } *pointer = '\0'; http_interpret_variable_string(webblk, post_arg, VARTYPE_POST); free(post_arg); } } if (!authok) http_error(webblk, "401 Authorization Required", "WWW-Authenticate: Basic realm=\"HERCULES\"\n", "You must be authenticated to use this service"); if (!url) http_error(webblk,"400 Bad Request", "", "You must specify a GET or POST request"); /* anything following a ? in the URL is part of the get arguments */ if ((pointer=strchr(url,'?'))) { *pointer++ = 0; http_interpret_variable_string(webblk, pointer, VARTYPE_GET); } while(url[0] == '/' && url[1] == '/') url++; webblk->baseurl = url; if(!strcasecmp("/",url)) url = HTTP_WELCOME; if(strncasecmp("/cgi-bin/",url,9)) http_download(webblk,url); else url += 9; while(*url == '/') url++; #if 0 http_dump_cgi_variables(webblk); #endif for(cgient = cgidir; cgient->path; cgient++) { if(!strcmp(cgient->path, url)) { char tbuf[80]; hprintf(webblk->sock,"HTTP/1.0 200 OK\nConnection: close\n"); hprintf(webblk->sock,"Date: %s\n", http_timestring(tbuf,sizeof(tbuf),time(NULL))); (cgient->cgibin) (webblk); http_exit(webblk); } } #if defined(OPTION_DYNAMIC_LOAD) { zz_cgibin dyncgi; if( (dyncgi = HDL_FINDSYM(webblk->baseurl)) ) { char tbuf[80]; hprintf(webblk->sock,"HTTP/1.0 200 OK\nConnection: close\n"); hprintf(webblk->sock,"Date: %s\n", http_timestring(tbuf,sizeof(tbuf),time(NULL))); dyncgi(webblk); http_exit(webblk); } } #endif /*defined(OPTION_DYNAMIC_LOAD)*/ http_error(webblk, "404 File Not Found","", "The requested file was not found"); return NULL; } void *http_server (void *arg) { int rc; /* Return code */ int lsock; /* Socket for listening */ int csock; /* Socket for conversation */ struct sockaddr_in server; /* Server address structure */ fd_set selset; /* Read bit map for select */ int optval; /* Argument for setsockopt */ TID httptid; /* Negotiation thread id */ UNREFERENCED(arg); /* Display thread started message on control panel */ logmsg (_("HHCHT001I HTTP listener thread started: " "tid="TIDPAT", pid=%d\n"), thread_id(), getpid()); /* If the HTTP root directory is not specified, use a reasonable default */ if (!sysblk.httproot) { #if defined(_MSVC_) char process_dir[HTTP_PATH_LENGTH]; if (get_process_directory(process_dir,HTTP_PATH_LENGTH) > 0) { strlcat(process_dir,"\\html",HTTP_PATH_LENGTH); sysblk.httproot = strdup(process_dir); } else #endif /*defined(WIN32)*/ sysblk.httproot = strdup(HTTP_ROOT); } /* Convert the specified HTTPROOT value to an absolute path ending with a '/' and save in sysblk.httproot. */ { char absolute_httproot_path[HTTP_PATH_LENGTH]; int rc; #if defined(_MSVC_) /* Expand any embedded %var% environ vars */ rc = expand_environ_vars( sysblk.httproot, absolute_httproot_path, sizeof(absolute_httproot_path) ); if (rc == 0) { free(sysblk.httproot); sysblk.httproot = strdup(absolute_httproot_path); } #endif /* defined(_MSVC_) */ /* Convert to absolute path */ if (!realpath(sysblk.httproot,absolute_httproot_path)) { logmsg( _("HHCCF066E Invalid HTTPROOT: \"%s\": %s\n"), sysblk.httproot, strerror(errno)); return NULL; } /* Verify that the absolute path is valid */ // mode: 0 = exist only, 2 = write, 4 = read, 6 = read/write // rc: 0 = success, -1 = error (errno = cause) // ENOENT = File name or path not found. if (access( absolute_httproot_path, R_OK ) != 0) { logmsg( _("HHCCF066E Invalid HTTPROOT: \"%s\": %s\n"), absolute_httproot_path, strerror(errno)); return NULL; } /* Append trailing [back]slash, but only if needed */ rc = strlen(absolute_httproot_path); if (absolute_httproot_path[rc-1] != *HTTP_PS) strlcat(absolute_httproot_path,HTTP_PS,sizeof(absolute_httproot_path)); /* Save the absolute path */ free(sysblk.httproot); sysblk.httproot = strdup(absolute_httproot_path); logmsg(_("HHCHT013I Using HTTPROOT directory \"%s\"\n"),sysblk.httproot); } /* Obtain a socket */ lsock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (lsock < 0) { logmsg(_("HHCHT002E socket: %s\n"), strerror(HSO_errno)); return NULL; } /* Allow previous instance of socket to be reused */ optval = 1; setsockopt (lsock, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(optval)); /* Prepare the sockaddr structure for the bind */ memset (&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = sysblk.httpport; server.sin_port = htons(server.sin_port); /* Attempt to bind the socket to the port */ while (TRUE) { rc = bind (lsock, (struct sockaddr *)&server, sizeof(server)); if (rc == 0 || HSO_errno != HSO_EADDRINUSE) break; logmsg (_("HHCHT003W Waiting for port %u to become free\n"), sysblk.httpport); SLEEP(10); } /* end while */ if (rc != 0) { logmsg(_("HHCHT004E bind: %s\n"), strerror(HSO_errno)); return NULL; } /* Put the socket into listening state */ rc = listen (lsock, 32); if (rc < 0) { logmsg(_("HHCHT005E listen: %s\n"), strerror(HSO_errno)); return NULL; } logmsg(_("HHCHT006I Waiting for HTTP requests on port %u\n"), sysblk.httpport); /* Handle http requests */ while (sysblk.httpport) { /* Initialize the select parameters */ FD_ZERO (&selset); FD_SET (lsock, &selset); /* Wait for a file descriptor to become ready */ rc = select ( lsock+1, &selset, NULL, NULL, NULL ); if (rc == 0) continue; if (rc < 0 ) { if (HSO_errno == HSO_EINTR) continue; logmsg(_("HHCHT007E select: %s\n"), strerror(HSO_errno)); break; } /* If a http request has arrived then accept it */ if (FD_ISSET(lsock, &selset)) { /* Accept the connection and create conversation socket */ csock = accept (lsock, NULL, NULL); if (csock < 0) { logmsg(_("HHCHT008E accept: %s\n"), strerror(HSO_errno)); continue; } /* Create a thread to execute the http request */ if ( create_thread (&httptid, DETACHED, http_request, (void *)(uintptr_t)csock, "http_request") ) { logmsg(_("HHCHT010E http_request create_thread: %s\n"), strerror(errno)); close_socket (csock); } } /* end if(lsock) */ } /* end while */ /* Close the listening socket */ close_socket (lsock); /* Display thread started message on control panel */ logmsg (_("HHCHT009I HTTP listener thread ended: " "tid="TIDPAT", pid=%d\n"), thread_id(), getpid()); sysblk.httptid = 0; return NULL; } /* end function http_server */ #endif /*defined(OPTION_HTTP_SERVER)*/ hercules-3.12/cgibin.c0000664000175000017500000012615012564723224011607 00000000000000/* CGIBIN.C (c)Copyright Jan Jaeger, 2002-2010 */ /* HTTP cgi-bin routines */ /* This file contains all cgi routines that may be executed on the */ /* server (ie under control of a hercules thread) */ /* */ /* */ /* All cgi-bin routines are identified in the directory at the end */ /* of this file */ /* */ /* */ /* The cgi-bin routines may call the following HTTP service routines */ /* */ /* char *cgi_variable(WEBBLK *webblk, char *name); */ /* This call returns a pointer to the cgi variable requested */ /* or a NULL pointer if the variable is not found */ /* */ /* char *cgi_cookie(WEBBLK *webblk, char *name); */ /* This call returns a pointer to the cookie requested */ /* or a NULL pointer if the cookie is not found */ /* */ /* char *cgi_username(WEBBLK *webblk); */ /* Returns the username for which the user has been authenticated */ /* or NULL if not authenticated (refer to auth/noauth parameter */ /* on the HTTPPORT configuration statement) */ /* */ /* char *cgi_baseurl(WEBBLK *webblk); */ /* Returns the url as requested by the user */ /* */ /* */ /* void html_header(WEBBLK *webblk); */ /* Sets up the standard html header, and includes the */ /* html/header.htmlpart file. */ /* */ /* void html_footer(WEBBLK *webblk); */ /* Sets up the standard html footer, and includes the */ /* html/footer.htmlpart file. */ /* */ /* int html_include(WEBBLK *webblk, char *filename); */ /* Includes an html file */ /* */ /* */ /* Jan Jaeger - 28/03/2002 */ #include "hstdinc.h" #define _CGIBIN_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "httpmisc.h" #if defined(OPTION_HTTP_SERVER) void cgibin_reg_control(WEBBLK *webblk) { int i; REGS *regs; regs = sysblk.regs[sysblk.pcpu]; if (!regs) regs = &sysblk.dummyregs; html_header(webblk); hprintf(webblk->sock, "

Control Registers

\n"); hprintf(webblk->sock, "
\n");
    if(regs->arch_mode != ARCH_900)
        for (i = 0; i < 16; i++)
            hprintf(webblk->sock, "CR%2.2d=%8.8X%s", i, regs->CR_L(i),
                ((i & 0x03) == 0x03) ? "\n" : "\t");
    else
        for (i = 0; i < 16; i++)
            hprintf(webblk->sock, "CR%1.1X=%16.16" I64_FMT "X%s", i,
                (U64)regs->CR_G(i), ((i & 0x03) == 0x03) ? "\n" : " ");

    hprintf(webblk->sock, "
\n"); html_footer(webblk); } void cgibin_reg_general(WEBBLK *webblk) { int i; REGS *regs; regs = sysblk.regs[sysblk.pcpu]; if (!regs) regs = &sysblk.dummyregs; html_header(webblk); hprintf(webblk->sock, "

General Registers

\n"); hprintf(webblk->sock, "
\n");
    if(regs->arch_mode != ARCH_900)
        for (i = 0; i < 16; i++)
            hprintf(webblk->sock, "GR%2.2d=%8.8X%s", i, regs->GR_L(i),
                ((i & 0x03) == 0x03) ? "\n" : "\t");
    else
        for (i = 0; i < 16; i++)
            hprintf(webblk->sock, "GR%1.1X=%16.16" I64_FMT "X%s", i,
                (U64)regs->GR_G(i), ((i & 0x03) == 0x03) ? "\n" : " ");

    hprintf(webblk->sock, "
\n"); html_footer(webblk); } // void copy_psw (REGS *regs, BYTE *addr); void cgibin_psw(WEBBLK *webblk) { REGS *regs; QWORD qword; /* quadword work area */ char *value; int autorefresh=0; int refresh_interval=5; regs = sysblk.regs[sysblk.pcpu]; if (!regs) regs = &sysblk.dummyregs; html_header(webblk); if (cgi_variable(webblk,"autorefresh")) autorefresh = 1; else if (cgi_variable(webblk,"norefresh")) autorefresh = 0; else if (cgi_variable(webblk,"refresh")) autorefresh = 1; if ((value = cgi_variable(webblk,"refresh_interval"))) refresh_interval = atoi(value); hprintf(webblk->sock, "

Program Status Word

\n"); hprintf(webblk->sock, "
\n"); if (!autorefresh) { hprintf(webblk->sock, "\n"); hprintf(webblk->sock, "Refresh Interval: "); hprintf(webblk->sock, "\n", refresh_interval); } else { hprintf(webblk->sock, "\n"); hprintf(webblk->sock, "Refresh Interval: %d\n", refresh_interval); hprintf(webblk->sock, "\n",refresh_interval); } hprintf(webblk->sock, "
\n"); hprintf(webblk->sock, "

\n"); if( regs->arch_mode != ARCH_900 ) { copy_psw (regs, qword); hprintf(webblk->sock, "PSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X\n", qword[0], qword[1], qword[2], qword[3], qword[4], qword[5], qword[6], qword[7]); } else { copy_psw (regs, qword); hprintf(webblk->sock, "PSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X " "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X\n", qword[0], qword[1], qword[2], qword[3], qword[4], qword[5], qword[6], qword[7], qword[8], qword[9], qword[10], qword[11], qword[12], qword[13], qword[14], qword[15]); } if (autorefresh) { /* JavaScript to cause automatic page refresh */ hprintf(webblk->sock, "\n"); } html_footer(webblk); } void cgibin_syslog(WEBBLK *webblk) { int num_bytes; int logbuf_idx; char *logbuf_ptr; char *command; char *value; int autorefresh = 0; int refresh_interval = 5; int msgcount = 22; if ((command = cgi_variable(webblk,"command"))) { panel_command(command); // Wait a bit before proceeding in case // the command issues a lot of messages usleep(50000); } if((value = cgi_variable(webblk,"msgcount"))) msgcount = atoi(value); else if((value = cgi_cookie(webblk,"msgcount"))) msgcount = atoi(value); if ((value = cgi_variable(webblk,"refresh_interval"))) refresh_interval = atoi(value); if (cgi_variable(webblk,"autorefresh")) autorefresh = 1; else if (cgi_variable(webblk,"norefresh")) autorefresh = 0; else if (cgi_variable(webblk,"refresh")) autorefresh = 1; html_header(webblk); hprintf(webblk->sock,"\n", msgcount); hprintf(webblk->sock, "

Hercules System Log

\n"); hprintf(webblk->sock, "
\n");

    // Get the index to our desired starting message...

    logbuf_idx = msgcount ? log_line( msgcount ) : -1;

    // Now read the logfile starting at that index. The return
    // value is the total #of bytes of messages data there is.

    if ( (num_bytes = log_read( &logbuf_ptr, &logbuf_idx, LOG_NOBLOCK )) > 0 )
    {
        // Copy the message data to a work buffer for processing.
        // This is to allow for the possibility, however remote,
        // that the logfile buffer actually wraps around and over-
        // lays the message data we were going to display (which
        // could happen if there's a sudden flood of messages)

        int   sav_bytes  =         num_bytes;
        char *wrk_bufptr = malloc( num_bytes );

        if ( wrk_bufptr ) strncpy( wrk_bufptr,  logbuf_ptr, num_bytes );
        else                       wrk_bufptr = logbuf_ptr;

        // We need to convert certain characters that might
        // possibly be erroneously interpretted as HTML code

#define  AMP_LT    "<"       // (HTML code for '<')
#define  AMP_GT    ">"       // (HTML code for '>')
#define  AMP_AMP   "&"      // (HTML code for '&')

        while ( num_bytes-- )
        {
            switch ( *wrk_bufptr )
            {
            case '<':
                hwrite( webblk->sock, AMP_LT     , sizeof(AMP_LT) );
                break;
            case '>':
                hwrite( webblk->sock, AMP_GT     , sizeof(AMP_GT) );
                break;
            case '&':
                hwrite( webblk->sock, AMP_AMP    , sizeof(AMP_AMP));
                break;
            default:
                hwrite( webblk->sock, wrk_bufptr , 1              );
                break;
            }

            wrk_bufptr++;
        }

        // (free our work buffer if it's really ours)

        if ( ( wrk_bufptr -= sav_bytes ) != logbuf_ptr )
            free( wrk_bufptr );
    }

    hprintf(webblk->sock, "
\n"); hprintf(webblk->sock, "
Command:\n"); hprintf(webblk->sock, "\n"); hprintf(webblk->sock, "\n"); hprintf(webblk->sock, "\n",autorefresh ? "auto" : "no"); hprintf(webblk->sock, "\n",refresh_interval); hprintf(webblk->sock, "\n",msgcount); hprintf(webblk->sock, "
\n
\n"); hprintf(webblk->sock, "\n"); hprintf(webblk->sock, "
\n"); if(!autorefresh) { hprintf(webblk->sock, "\n"); hprintf(webblk->sock, "Refresh Interval: "); hprintf(webblk->sock, "\n", refresh_interval); } else { hprintf(webblk->sock, "\n"); hprintf(webblk->sock, "\n",refresh_interval); hprintf(webblk->sock, " Refresh Interval: %2d \n", refresh_interval); } hprintf(webblk->sock, "\n",msgcount); hprintf(webblk->sock, "
\n"); hprintf(webblk->sock, "
\n"); hprintf(webblk->sock, "Only show last "); hprintf(webblk->sock, "",msgcount); hprintf(webblk->sock, " lines (zero for all loglines)\n"); hprintf(webblk->sock, "\n",autorefresh ? "auto" : "no"); hprintf(webblk->sock, "\n",refresh_interval); hprintf(webblk->sock, "
\n"); if (autorefresh) { /* JavaScript to cause automatic page refresh */ hprintf(webblk->sock, "\n"); } html_footer(webblk); } void cgibin_debug_registers(WEBBLK *webblk) { int i, cpu = 0; int select_gr, select_cr, select_ar; char *value; REGS *regs; if((value = cgi_variable(webblk,"cpu"))) cpu = atoi(value); if((value = cgi_variable(webblk,"select_gr")) && *value == 'S') select_gr = 1; else select_gr = 0; if((value = cgi_variable(webblk,"select_cr")) && *value == 'S') select_cr = 1; else select_cr = 0; if((value = cgi_variable(webblk,"select_ar")) && *value == 'S') select_ar = 1; else select_ar = 0; /* Validate cpu number */ if (cpu < 0 || cpu >= MAX_CPU || !IS_CPU_ONLINE(cpu)) for (cpu = 0; cpu < MAX_CPU; cpu++) if(IS_CPU_ONLINE(cpu)) break; if(cpu < MAX_CPU) regs = sysblk.regs[cpu]; else regs = sysblk.regs[sysblk.pcpu]; if (!regs) regs = &sysblk.dummyregs; if((value = cgi_variable(webblk,"alter_gr")) && *value == 'A') { for(i = 0; i < 16; i++) { char regname[16]; sprintf(regname,"alter_gr%d",i); if((value = cgi_variable(webblk,regname))) { if(regs->arch_mode != ARCH_900) sscanf(value,"%"I32_FMT"x",&(regs->GR_L(i))); else sscanf(value,"%"I64_FMT"x",&(regs->GR_G(i))); } } } if((value = cgi_variable(webblk,"alter_cr")) && *value == 'A') { for(i = 0; i < 16; i++) { char regname[16]; sprintf(regname,"alter_cr%d",i); if((value = cgi_variable(webblk,regname))) { if(regs->arch_mode != ARCH_900) sscanf(value,"%"I32_FMT"x",&(regs->CR_L(i))); else sscanf(value,"%"I64_FMT"x",&(regs->CR_G(i))); } } } if((value = cgi_variable(webblk,"alter_ar")) && *value == 'A') { for(i = 0; i < 16; i++) { char regname[16]; sprintf(regname,"alter_ar%d",i); if((value = cgi_variable(webblk,regname))) sscanf(value,"%x",&(regs->AR(i))); } } html_header(webblk); hprintf(webblk->sock,"
\n" "\n" "\n" "\n" "\n" "\n" "\n", cpu, select_gr?'S':'H',select_cr?'S':'H',select_ar?'S':'H'); hprintf(webblk->sock,"Mode: %s\n",get_arch_mode_string(regs)); hprintf(webblk->sock,"
\n"); if(!select_gr) { hprintf(webblk->sock,"
\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_cr?'S':'H',select_ar?'S':'H'); } else { hprintf(webblk->sock,"
\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_cr?'S':'H',select_ar?'S':'H'); hprintf(webblk->sock,"
\n" "\n"); for(i = 0; i < 16; i++) { if(regs->arch_mode != ARCH_900) hprintf(webblk->sock,"%s\n%s", (i&3)==0?"\n":"",i,i,regs->GR_L(i),((i&3)==3)?"\n":""); else hprintf(webblk->sock,"%s\n%s", (i&3)==0?"\n":"",i,i,(U64)regs->GR_G(i),((i&3)==3)?"\n":""); } hprintf(webblk->sock,"
GR%d
GR%d
\n" "\n" "\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_cr?'S':'H',select_ar?'S':'H'); } if(!select_cr) { hprintf(webblk->sock,"
\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_gr?'S':'H',select_ar?'S':'H'); } else { hprintf(webblk->sock,"
\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_gr?'S':'H',select_ar?'S':'H'); hprintf(webblk->sock,"
\n" "\n"); for(i = 0; i < 16; i++) { if(regs->arch_mode != ARCH_900) hprintf(webblk->sock,"%s\n%s", (i&3)==0?"\n":"",i,i,regs->CR_L(i),((i&3)==3)?"\n":""); else hprintf(webblk->sock,"%s\n%s", (i&3)==0?"\n":"",i,i,(U64)regs->CR_G(i),((i&3)==3)?"\n":""); } hprintf(webblk->sock,"
CR%d
CR%d
\n" "\n" "\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_gr?'S':'H',select_ar?'S':'H'); } if(regs->arch_mode != ARCH_370) { if(!select_ar) { hprintf(webblk->sock,"
\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_gr?'S':'H',select_cr?'S':'H'); } else { hprintf(webblk->sock,"
\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_gr?'S':'H',select_cr?'S':'H'); hprintf(webblk->sock,"
\n" "\n"); for(i = 0; i < 16; i++) { hprintf(webblk->sock,"%s\n%s", (i&3)==0?"\n":"",i,i,regs->AR(i),((i&3)==3)?"\n":""); } hprintf(webblk->sock,"
AR%d
\n" "\n" "\n" "\n" "\n" "\n" "\n" "
\n",cpu,select_gr?'S':'H',select_cr?'S':'H'); } } html_footer(webblk); } void cgibin_debug_storage(WEBBLK *webblk) { int i, j; char *value; U32 addr = 0; /* INCOMPLETE * no storage alter * no storage type (abs/real/prim virt/sec virt/access reg virt) * no cpu selection for storage other then abs */ if((value = cgi_variable(webblk,"alter_a0"))) sscanf(value,"%x",&addr); addr &= ~0x0F; html_header(webblk); hprintf(webblk->sock,"
\n" "\n"); if(addr > sysblk.mainsize || (addr + 128) > sysblk.mainsize) addr = sysblk.mainsize - 128; for(i = 0; i < 128;) { if(i == 0) hprintf(webblk->sock,"\n" "\n" "\n", i + addr, i + addr); else hprintf(webblk->sock,"\n" "\n" "\n", i + addr); for(j = 0; j < 4; i += 4, j++) { U32 m; FETCH_FW(m,sysblk.mainstor + i + addr); hprintf(webblk->sock,"\n",i,m); } hprintf(webblk->sock,"\n"); } hprintf(webblk->sock,"
" "
%8.8X
\n" "
\n"); html_footer(webblk); } void cgibin_ipl(WEBBLK *webblk) { int i; char *value; DEVBLK *dev; U16 ipldev; int iplcpu; U32 doipl; html_header(webblk); hprintf(webblk->sock,"

Perform Initial Program Load

\n"); if(cgi_variable(webblk,"doipl")) doipl = 1; else doipl = 0; if((value = cgi_variable(webblk,"device"))) sscanf(value,"%hx",&ipldev); else ipldev = sysblk.ipldev; if((value = cgi_variable(webblk,"cpu"))) sscanf(value,"%x",&iplcpu); else iplcpu = sysblk.iplcpu; if((value = cgi_variable(webblk,"loadparm"))) set_loadparm(value); /* Validate CPU number */ if(iplcpu >= MAX_CPU) doipl = 0; if(!doipl) { /* Present IPL parameters */ hprintf(webblk->sock,"
\n" "\n" "\n"); hprintf(webblk->sock,"Loadparm:\n", str_loadparm()); hprintf(webblk->sock,"\n" "
\n"); } else { OBTAIN_INTLOCK(NULL); /* Perform IPL function */ if( load_ipl(0, ipldev, iplcpu,0) ) { hprintf(webblk->sock,"

IPL failed, see the " "system log " "for details

\n"); } else { hprintf(webblk->sock,"

IPL completed

\n"); } RELEASE_INTLOCK(NULL); } html_footer(webblk); } void cgibin_debug_device_list(WEBBLK *webblk) { DEVBLK *dev; char *class; html_header(webblk); hprintf(webblk->sock,"

Attached Device List

\n" "\n" "" "" "" "" "\n"); for(dev = sysblk.firstdev; dev; dev = dev->nextdev) if(dev->pmcw.flag5 & PMCW5_V) { (dev->hnd->query)(dev, &class, 0, NULL); hprintf(webblk->sock,"" "" "" "" "" "" "\n", dev->devnum, dev->subchan,dev->subchan, class, dev->devtype, (dev->fd > 2 ? "open " : ""), (dev->busy ? "busy " : ""), (IOPENDING(dev) ? "pending " : "")); } hprintf(webblk->sock,"
NumberSubchannelClassTypeStatus
%4.4X%4.4X%s%4.4X%s%s%s
\n"); html_footer(webblk); } void cgibin_debug_device_detail(WEBBLK *webblk) { DEVBLK *sel, *dev = NULL; char *value; int subchan; html_header(webblk); if((value = cgi_variable(webblk,"subchan")) && sscanf(value,"%x",&subchan) == 1) for(dev = sysblk.firstdev; dev; dev = dev->nextdev) if(dev->subchan == subchan) break; hprintf(webblk->sock,"

Subchannel Details

\n"); hprintf(webblk->sock,"
\n" "\n" "\n" "
\n"); if(dev) { hprintf(webblk->sock,"\n" "\n"); hprintf(webblk->sock,"\n"); hprintf(webblk->sock,"\n", dev->pmcw.intparm[0], dev->pmcw.intparm[1], dev->pmcw.intparm[2], dev->pmcw.intparm[3]); hprintf(webblk->sock,"" "" "" "" "" "" "" "" "" "" "" "\n"); hprintf(webblk->sock,"" "" "" "" "" "" "" "" "" "" "" "\n", ((dev->pmcw.flag4 & PMCW4_Q) >> 7), ((dev->pmcw.flag4 & PMCW4_ISC) >> 3), (dev->pmcw.flag4 & 1), ((dev->pmcw.flag5 >> 7) & 1), ((dev->pmcw.flag5 >> 6) & 1), ((dev->pmcw.flag5 >> 5) & 1), ((dev->pmcw.flag5 >> 4) & 1), ((dev->pmcw.flag5 >> 3) & 1), ((dev->pmcw.flag5 >> 2) & 1), ((dev->pmcw.flag5 >> 1) & 1), (dev->pmcw.flag5 & 1), dev->pmcw.devnum[0], dev->pmcw.devnum[1]); hprintf(webblk->sock,"" "" "" "\n"); hprintf(webblk->sock,"" "" "" "\n", dev->pmcw.lpm, dev->pmcw.pnom, dev->pmcw.lpum, dev->pmcw.pim); hprintf(webblk->sock,"" "" "\n"); hprintf(webblk->sock,"" "" "\n", dev->pmcw.mbi[0], dev->pmcw.mbi[1], dev->pmcw.pom, dev->pmcw.pam); hprintf(webblk->sock,"" "" "" "\n"); hprintf(webblk->sock,"" "" "" "\n", dev->pmcw.chpid[0], dev->pmcw.chpid[1], dev->pmcw.chpid[2], dev->pmcw.chpid[3]); hprintf(webblk->sock,"" "" "" "\n"); hprintf(webblk->sock,"" "" "" "\n", dev->pmcw.chpid[4], dev->pmcw.chpid[5], dev->pmcw.chpid[6], dev->pmcw.chpid[7]); hprintf(webblk->sock,"" "" "" "" "" "" "\n"); hprintf(webblk->sock,"" "" "" "" "" "" "\n", dev->pmcw.zone, (dev->pmcw.flag25 & PMCW25_VISC), (dev->pmcw.flag27 & PMCW27_I) >> 7, (dev->pmcw.flag27 & PMCW27_S)); hprintf(webblk->sock,"
" "

Path Management Control Word

" "
Interruption Parameter
%2.2X%2.2X%2.2X%2.2X
Q0ISC00AELMMMDTVDEVNUM
%d%d%d%d%d%d%d%d%d%d%d%2.2X%2.2X
LPMPNOMLPUMPIM
%2.2X%2.2X%2.2X%2.2X
MBIPOMPAM
%2.2X%2.2X%2.2X%2.2X
CHPID=0CHPID=1CHPID=2CHPID=3
%2.2X%2.2X%2.2X%2.2X
CHPID=4CHPID=5CHPID=6CHPID=7
%2.2X%2.2X%2.2X%2.2X
ZONE00000VISC00000000I000000S
%2.2X%d%d%d
\n"); } html_footer(webblk); } void cgibin_debug_misc(WEBBLK *webblk) { int zone; html_header(webblk); hprintf(webblk->sock,"

Miscellaneous Registers

\n"); hprintf(webblk->sock,"\n" "\n"); hprintf(webblk->sock,"" "" "" "" "" "" "\n"); for(zone = 0; zone < FEATURE_SIE_MAXZONES; zone++) { hprintf(webblk->sock,"" "" "" "" "" "" "\n", zone, #if defined(_FEATURE_SIE) (U32)sysblk.zpb[zone].mso << 20, ((U32)sysblk.zpb[zone].msl << 20) | 0xFFFFF, (U32)sysblk.zpb[zone].eso << 20, ((U32)sysblk.zpb[zone].esl << 20) | 0xFFFFF, (U32)sysblk.zpb[zone].mbo, sysblk.zpb[zone].mbk #else 0, 0, 0, 0, 0, 0 #endif ); } hprintf(webblk->sock,"
" "

Zone related Registers

" "
ZoneCS OriginCS LimitES OriginES LimitMeasurement BlockKey
%2.2X%8.8X%8.8X%8.8X%8.8X%8.8X%2.2X
\n"); hprintf(webblk->sock,"\n" "\n"); hprintf(webblk->sock,"" "\n"); hprintf(webblk->sock,"" "\n", (U32)sysblk.mbo, sysblk.mbk); hprintf(webblk->sock,"
" "

Alternate Measurement

" "
Measurement BlockKey
%8.8X%2.2X
\n"); hprintf(webblk->sock,"\n" "\n"); hprintf(webblk->sock,"\n", (U32)sysblk.addrlimval); hprintf(webblk->sock,"
" "

Address Limit Register

" "
%8.8X
\n"); html_footer(webblk); } void cgibin_configure_cpu(WEBBLK *webblk) { int i,j; html_header(webblk); hprintf(webblk->sock,"

Configure CPU

\n"); for(i = 0; i < MAX_CPU; i++) { char cpuname[8], *cpustate; int cpuonline = -1; sprintf(cpuname,"cpu%d",i); if((cpustate = cgi_variable(webblk,cpuname))) sscanf(cpustate,"%d",&cpuonline); OBTAIN_INTLOCK(NULL); switch(cpuonline) { case 0: if(IS_CPU_ONLINE(i)) deconfigure_cpu(i); break; case 1: if(!IS_CPU_ONLINE(i)) configure_cpu(i); break; } RELEASE_INTLOCK(NULL); } for(i = 0; i < MAX_CPU; i++) { hprintf(webblk->sock,"

CPU%4.4X\n" "

\n" "\n" "\n" "
\n"); } html_footer(webblk); } void cgibin_debug_version_info(WEBBLK *webblk) { html_header(webblk); hprintf(webblk->sock,"

Hercules Version Information

\n" "
\n");
    display_version_2(NULL,"Hercules HTTP Server ", TRUE,webblk->sock);
    hprintf(webblk->sock,"
\n"); html_footer(webblk); } #if defined(OPTION_MIPS_COUNTING) /* contributed by Tim Pinkawa [timpinkawa@gmail.com] */ void cgibin_xml_rates_info(WEBBLK *webblk) { hprintf(webblk->sock,"Expires: 0\n"); hprintf(webblk->sock,"Content-type: text/xml;\n\n"); /* XML document */ hprintf(webblk->sock,"\n"); hprintf(webblk->sock,"\n"); hprintf(webblk->sock,"\t%d\n", sysblk.arch_mode); hprintf(webblk->sock,"\t%.1d.%.2d\n", sysblk.mipsrate / 1000000, (sysblk.mipsrate % 1000000) / 10000); hprintf(webblk->sock,"\t%d\n", sysblk.siosrate); hprintf(webblk->sock,"\n"); } #endif /*defined(OPTION_MIPS_COUNTING)*/ // cgibin_hwrite: helper function to output HTML void cgibin_hwrite(WEBBLK *webblk, char *msg, int msg_len) { char buffer[1024]; char *new_str; int buf_used = 0; int new_len; int i; if ((msg == NULL) || (msg_len < 1)) return; // Output message, accounting for http special characters. // Method: rather than doing an hwrite for every character, // buffer the message, expanding special characters. // Output the buffer when full, then reuse it. // Note that sizeof(X) where X is a #define string literal is 1 greater // than strlen(X). for (i = 0; i < msg_len; i++) { switch (msg[i]) { case '<': new_len = sizeof(AMP_LT) - 1; new_str = AMP_LT; break; case '>': new_len = sizeof(AMP_GT) - 1; new_str = AMP_GT; break; case '&': new_len = sizeof(AMP_AMP) - 1; new_str = AMP_AMP; break; default: new_len = 1; new_str = &(msg[i]); break; } if ((buf_used + new_len) > (int)sizeof(buffer)) { // new piece won't fit, write forced hwrite(webblk->sock, buffer, buf_used); buf_used = 0; } while (new_len > 0) { buffer[buf_used++] = *new_str++; new_len--; } } if (buf_used > 0) { // write out final/partial buffer hwrite(webblk->sock, buffer, buf_used); } } // cgibin_cmd_cmd: issue panel command and return response only // without the rest of the syslog, and without most of the HTML wrapping void cgibin_cmd_cmd(WEBBLK *webblk, char *command) { char * response; while (isspace(*command)) command++; if (*command == 0) { return; /* command is all blank, ignore */ } response = log_capture(panel_command, command); if (response == NULL) { return; /* command failed to execute */ } html_header(webblk); hprintf(webblk->sock, "
\n");

    cgibin_hwrite(webblk, response, strlen (response));

    hprintf(webblk->sock, "
\n"); html_footer(webblk); // Ensure command and response is visible on Hercules console panel logmsg ("%s", response); free (response); } // handle http requests of the form: // http://localhost:8081/cgi-bin/tasks/cmd?cmd=qcpuid void cgibin_cmd(WEBBLK *webblk) { char *command; if ((command = cgi_variable(webblk,"cmd"))) { /* "cmd" issues a single command */ cgibin_cmd_cmd (webblk, command); return; } } /* The following table is the cgi-bin directory, which */ /* associates directory filenames with cgibin routines */ CGITAB cgidir[] = { { "tasks/cmd", &cgibin_cmd }, { "tasks/syslog", &cgibin_syslog }, { "tasks/ipl", &cgibin_ipl }, { "configure/cpu", &cgibin_configure_cpu }, { "debug/registers", &cgibin_debug_registers }, { "debug/storage", &cgibin_debug_storage }, { "debug/misc", &cgibin_debug_misc }, { "debug/version_info", &cgibin_debug_version_info }, { "debug/device/list", &cgibin_debug_device_list }, { "debug/device/detail", &cgibin_debug_device_detail }, { "registers/general", &cgibin_reg_general }, { "registers/control", &cgibin_reg_control }, { "registers/psw", &cgibin_psw }, #if defined(OPTION_MIPS_COUNTING) { "xml/rates", &cgibin_xml_rates_info }, #endif /*defined(OPTION_MIPS_COUNTING)*/ { NULL, NULL } }; #endif /*defined(OPTION_HTTP_SERVER)*/ hercules-3.12/loadparm.c0000664000175000017500000002547212564723224012160 00000000000000/* LOADPARM.C (c) Copyright Jan Jaeger, 2004-2009 */ /* SCLP / MSSF loadparm */ /*-------------------------------------------------------------------*/ /* This module contains functions which set, copy, and retrieve the */ /* values of the LOADPARM and various other environmental parameters */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _HENGINE_DLL_ #define _LOADPARM_C_ #include "hercules.h" /*-------------------------------------------------------------------*/ /* SUBROUTINE TO COPY A STRINGZ TO A FIXED-LENGTH EBCDIC FIELD */ /*-------------------------------------------------------------------*/ static void copy_stringz_to_ebcdic(BYTE* fld, size_t len, char *name) { size_t i; for(i = 0; name && i < strlen(name) && i < len; i++) if(isprint(name[i])) fld[i] = host_to_guest((int)(islower(name[i]) ? toupper(name[i]) : name[i])); else fld[i] = 0x40; for(; i < len; i++) fld[i] = 0x40; } /*-------------------------------------------------------------------*/ /* LOAD PARAMETER */ /* Set by: LOADPARM configuration statement or panel command */ /* Retrieved by: SERVC and MSSF_CALL instructions */ /*-------------------------------------------------------------------*/ static BYTE loadparm[8] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; void set_loadparm(char *name) { size_t i; for(i = 0; name && i < strlen(name) && i < sizeof(loadparm); i++) if(isprint(name[i])) loadparm[i] = host_to_guest((int)(islower(name[i]) ? toupper(name[i]) : name[i])); else loadparm[i] = 0x40; for(; i < sizeof(loadparm); i++) loadparm[i] = 0x40; } void get_loadparm(BYTE *dest) { memcpy(dest, loadparm, sizeof(loadparm)); } char *str_loadparm() { static char ret_loadparm[sizeof(loadparm)+1]; int i; ret_loadparm[sizeof(loadparm)] = '\0'; for(i = sizeof(loadparm) - 1; i >= 0; i--) { ret_loadparm[i] = guest_to_host((int)loadparm[i]); if(isspace(ret_loadparm[i]) && !ret_loadparm[i+1]) ret_loadparm[i] = '\0'; } return ret_loadparm; } /*-------------------------------------------------------------------*/ /* LOGICAL PARTITION NAME */ /* Set by: LPARNAME configuration statement */ /* Retrieved by: STSI and MSSF_CALL instructions */ /*-------------------------------------------------------------------*/ static BYTE lparname[8] = {0xC8, 0xC5, 0xD9, 0xC3, 0xE4, 0xD3, 0xC5, 0xE2}; /* HERCULES */ void set_lparname(char *name) { size_t i; for(i = 0; name && i < strlen(name) && i < sizeof(lparname); i++) if(isprint(name[i])) lparname[i] = host_to_guest((int)(islower(name[i]) ? toupper(name[i]) : name[i])); else lparname[i] = 0x40; for(; i < sizeof(lparname); i++) lparname[i] = 0x40; } void get_lparname(BYTE *dest) { memcpy(dest, lparname, sizeof(lparname)); } LOADPARM_DLL_IMPORT char *str_lparname() { static char ret_lparname[sizeof(lparname)+1]; int i; ret_lparname[sizeof(lparname)] = '\0'; for(i = sizeof(lparname) - 1; i >= 0; i--) { ret_lparname[i] = guest_to_host((int)lparname[i]); if(isspace(ret_lparname[i]) && !ret_lparname[i+1]) ret_lparname[i] = '\0'; } return ret_lparname; } /*-------------------------------------------------------------------*/ /* MANUFACTURER NAME */ /* Set by: MANUFACTURER configuration statement */ /* Retrieved by: STSI instruction */ /*-------------------------------------------------------------------*/ /* "H R C" */ static BYTE manufact[16] = { 0xC8,0xD9,0xC3,0x40,0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 }; void set_manufacturer(char *name) { size_t i; for(i = 0; name && i < strlen(name) && i < sizeof(manufact); i++) if(isprint(name[i])) manufact[i] = host_to_guest((int)(islower(name[i]) ? toupper(name[i]) : name[i])); else manufact[i] = 0x40; for(; i < sizeof(manufact); i++) manufact[i] = 0x40; } void get_manufacturer(BYTE *dest) { memcpy(dest, manufact, sizeof(manufact)); } /*-------------------------------------------------------------------*/ /* MANUFACTURING PLANT NAME */ /* Set by: PLANT configuration statement */ /* Retrieved by: STSI instruction */ /*-------------------------------------------------------------------*/ /* "Z Z" */ static BYTE plant[4] = { 0xE9,0xE9,0x40,0x40 }; void set_plant(char *name) { size_t i; for(i = 0; name && i < strlen(name) && i < sizeof(plant); i++) if(isprint(name[i])) plant[i] = host_to_guest((int)(islower(name[i]) ? toupper(name[i]) : name[i])); else plant[i] = 0x40; for(; i < sizeof(plant); i++) plant[i] = 0x40; } void get_plant(BYTE *dest) { memcpy(dest, plant, sizeof(plant)); } /*-------------------------------------------------------------------*/ /* MODEL IDENTIFICATION */ /* Set by: MODEL configuration statement */ /* Retrieved by: STSI instruction */ /*-------------------------------------------------------------------*/ /* "E M U L A T O R" */ static BYTE model[16] = { 0xC5,0xD4,0xE4,0xD3,0xC1,0xE3,0xD6,0xD9, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 }; static BYTE modelcapa[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static BYTE modelperm[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static BYTE modeltemp[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; void set_model(int argc, char *m1, char *m2, char *m3, char *m4) { if (argc > 1 && m1 != NULL) copy_stringz_to_ebcdic(model, sizeof(model), m1); if (argc > 2 && m2 != NULL) copy_stringz_to_ebcdic(modelcapa, sizeof(modelcapa), m2); if (argc > 3 && m3 != NULL) copy_stringz_to_ebcdic(modelperm, sizeof(modelperm), m3); if (argc > 4 && m4 != NULL) copy_stringz_to_ebcdic(modeltemp, sizeof(modeltemp), m4); } void get_model(BYTE *dest) { memcpy(dest, model, sizeof(model)); } void get_modelcapa(BYTE *dest) { memcpy(dest, modelcapa, sizeof(modelcapa)); } void get_modelperm(BYTE *dest) { memcpy(dest, modelperm, sizeof(modelperm)); } void get_modeltemp(BYTE *dest) { memcpy(dest, modeltemp, sizeof(modeltemp)); } /*-------------------------------------------------------------------*/ /* SYSTEM TYPE IDENTIFICATION */ /* Set by: SERVC instruction */ /* Retrieved by: DIAG204 instruction */ /*-------------------------------------------------------------------*/ static BYTE systype[8] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 }; void set_systype(BYTE *src) { memcpy(systype, src, sizeof(systype)); } void get_systype(BYTE *dst) { memcpy(dst, systype, sizeof(systype)); } /*-------------------------------------------------------------------*/ /* SYSTEM NAME */ /* Set by: SERVC instruction */ /* Retrieved by: DIAG204 instruction */ /*-------------------------------------------------------------------*/ static BYTE sysname[8] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 }; void set_sysname(BYTE *src) { memcpy(sysname, src, sizeof(sysname)); } void get_sysname(BYTE *dst) { memcpy(dst, sysname, sizeof(sysname)); } /*-------------------------------------------------------------------*/ /* SYSPLEX NAME */ /* Set by: SERVC instruction */ /* Retrieved by: DIAG204 instruction */ /*-------------------------------------------------------------------*/ static BYTE sysplex[8] = { 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40 }; void set_sysplex(BYTE *src) { memcpy(sysplex, src, sizeof(sysplex)); } void get_sysplex(BYTE *dst) { memcpy(dst, sysplex, sizeof(sysplex)); } /*-------------------------------------------------------------------*/ /* Retrieve Multiprocessing CPU-Capability Adjustment Factors */ /* */ /* This function retrieves the Multiprocessing CPU-Capability */ /* Adjustment Factor values for SYSIB (System Information Block) */ /* 1.2.2 as described in the Principles of Operations manual for */ /* the STORE SYSTEM INFORMATION instruction. */ /* */ /* Input: */ /* dest Address of where to store the information. */ /* Output: */ /* The requested MP Factor values at the address specified. */ /* Used by: */ /* B27D STSI Store System Information (Basic-machine All CPUs) */ /* B220 SERVC Service Call (read_scpinfo) */ /*-------------------------------------------------------------------*/ void get_mpfactors(BYTE *dest) { /*-------------------------------------------------------------------*/ /* The new z10 machine will use a denominator of 65535 for better */ /* granularity. But this will mess up old software. We will stick */ /* to the old value of 100. Bernard Feb 26, 2010. */ /*-------------------------------------------------------------------*/ #define MPFACTOR_DENOMINATOR 100 #define MPFACTOR_PERCENT 95 static U16 mpfactors[MAX_CPU_ENGINES-1] = {0}; static BYTE didthis = 0; if (!didthis) { /* First time: initialize array... */ U32 mpfactor = MPFACTOR_DENOMINATOR; size_t i; for (i=0; i < arraysize( mpfactors ); i++) { /* Calculate the value of each subsequent entry as percentage of the previous entry's value. */ mpfactor = (mpfactor * MPFACTOR_PERCENT) / 100; STORE_HW( &mpfactors[i], (U16) mpfactor ); } didthis = 1; } /* Return the requested information... */ memcpy( dest, &mpfactors[0], (MAX_CPU-1) * sizeof(U16) ); } hercules-3.12/hsccmd.c0000664000175000017500000067264512564723224011634 00000000000000/* HSCCMD.C (c) Copyright Roger Bowler, 1999-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* Execute Hercules System Commands */ /* */ /* Released under the Q Public License */ /* (http://www.hercules-390.org/herclic.html) as modifications to */ /* Hercules. */ /*-------------------------------------------------------------------*/ /* This module implements the various Hercules System Console */ /* (i.e. hardware console) commands that the emulator supports. */ /* To define a new commmand, add an entry to the "Commands" CMDTAB */ /* table pointing to the command processing function, and optionally */ /* add additional help text to the HelpTab HELPTAB. Both tables are */ /* near the end of this module. */ /*-------------------------------------------------------------------*/ /* Standard conventions are: argc contains the number of elements in argv[] argv[0] contains the actual command argv[1..argc-1] contains the optional arguments cmdline contains the original command line returncode: 0 = Success < 0 Error: Command not executed > 1 Failure: one or more functions could not complete int test_cmd(int argc, char *argv[],char *cmdline) { . . . return rc } */ #include "hstdinc.h" #define _HSCCMD_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "history.h" #include "httpmisc.h" #if defined(OPTION_FISHIO) #include "w32chan.h" #endif /* defined(OPTION_FISHIO) */ #include "tapedev.h" #include "dasdtab.h" #include "ctcadpt.h" // (forward references, etc) #define MAX_DEVLIST_DEVICES 1024 #if defined(FEATURE_ECPSVM) extern void ecpsvm_command(int argc, char **argv); #endif int ProcessPanelCommand(char*); int process_script_file(char *, int); static void fcb_dump(DEVBLK*, char *, unsigned int); /* $test_cmd - do something or other */ #ifdef _MSVC_ #pragma optimize( "", off ) #endif int test_p = 0; int test_n = 0; int test_t = 0; TID test_tid = 0; int test_msg_num = 0; char* test_p_msg = "Test protected message %d...\n"; char* test_n_msg = "Test normal message %d...\n"; void do_test_msgs() { int i; for (i=0; i < test_n; i++) logmsg( test_n_msg, test_msg_num++ ); if ( !test_p) return; for (i=0; i < test_p; i++) logmsg( test_p_msg, test_msg_num++ ); if ( !test_n) return; for (i=0; i < test_n; i++) logmsg( test_n_msg, test_msg_num++ ); } void* test_thread(void* parg) { UNREFERENCED(parg); logmsg("test thread: STARTING\n"); SLEEP( 5 ); do_test_msgs(); logmsg("test thread: EXITING\n"); test_tid = 0; return NULL; } /*-------------------------------------------------------------------*/ /* test command */ /*-------------------------------------------------------------------*/ int test_cmd(int argc, char *argv[],char *cmdline) { // UNREFERENCED(argc); // UNREFERENCED(argv); UNREFERENCED(cmdline); // cause_crash(); if (test_tid) { logmsg("ERROR: test thread still running!\n"); return 0; } if (argc < 2 || argc > 4) { logmsg("Format: \"$test p=#msgs n=#msgs &\" (args can be in any order)\n"); return 0; } test_p = 0; test_n = 0; test_t = 0; if (argc > 1) { if (strncasecmp(argv[1], "p=",2) == 0) test_p = atoi( &argv[1][2] ); if (strncasecmp(argv[1], "n=",2) == 0) test_n = atoi( &argv[1][2] ); if (argv[1][0] == '&') test_t = 1; } if (argc > 2) { if (strncasecmp(argv[2], "p=",2) == 0) test_p = atoi( &argv[2][2] ); if (strncasecmp(argv[2], "n=",2) == 0) test_n = atoi( &argv[2][2] ); if (argv[2][0] == '&') test_t = 1; } if (argc > 3) { if (strncasecmp(argv[3], "p=",2) == 0) test_p = atoi( &argv[3][2] ); if (strncasecmp(argv[3], "n=",2) == 0) test_n = atoi( &argv[3][2] ); if (argv[3][0] == '&') test_t = 1; } if (test_t) create_thread( &test_tid, DETACHED, test_thread, NULL, "test thread" ); else do_test_msgs(); return 0; } #ifdef _MSVC_ #pragma optimize( "", on ) #endif /* Issue generic Device not found error message */ static inline int devnotfound_msg(U16 lcss,U16 devnum) { logmsg(_("HHCPN181E Device number %d:%4.4X not found\n"),lcss,devnum); return -1; } /* Issue generic Missing device number message */ static inline void missing_devnum() { logmsg( _("HHCPN031E Missing device number\n") ); } /* maxrates command - report maximum seen mips/sios rates */ #ifdef OPTION_MIPS_COUNTING /*-------------------------------------------------------------------*/ /* maxrates command */ /*-------------------------------------------------------------------*/ int maxrates_cmd(int argc, char *argv[],char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { int bError = FALSE; if (argc > 2) { logmsg( _("Improper command format") ); bError = TRUE; } else { int interval = 0; BYTE c; if ( sscanf( argv[1], "%d%c", &interval, &c ) != 1 || interval < 1 ) { logmsg( _("\"%s\": invalid maxrates interval"), argv[1] ); bError = TRUE; } else { maxrates_rpt_intvl = interval; logmsg( _("Maxrates interval set to %d minutes.\n"), maxrates_rpt_intvl ); } } if (bError) logmsg( _("; enter \"help maxrates\" for help.\n") ); } else { char* pszPrevIntervalStartDateTime; char* pszCurrIntervalStartDateTime; char* pszCurrentDateTime; time_t current_time; current_time = time( NULL ); pszPrevIntervalStartDateTime = strdup( ctime( &prev_int_start_time ) ); pszCurrIntervalStartDateTime = strdup( ctime( &curr_int_start_time ) ); pszCurrentDateTime = strdup( ctime( ¤t_time ) ); logmsg ( "Highest observed MIPS/SIOS rates:\n\n" " From: %s" " To: %s\n" ,pszPrevIntervalStartDateTime ,pszCurrIntervalStartDateTime ); logmsg ( " MIPS: %2.1d.%2.2d\n" " SIOS: %d\n\n" ,prev_high_mips_rate / 1000000 ,prev_high_mips_rate % 1000000 ,prev_high_sios_rate ); logmsg ( " From: %s" " To: %s\n" ,pszCurrIntervalStartDateTime ,pszCurrentDateTime ); logmsg ( " MIPS: %2.1d.%2.2d\n" " SIOS: %d\n\n" ,curr_high_mips_rate / 1000000 ,curr_high_mips_rate % 1000000 ,curr_high_sios_rate ); logmsg ( "Current interval = %d minutes.\n" ,maxrates_rpt_intvl ); free( pszPrevIntervalStartDateTime ); free( pszCurrIntervalStartDateTime ); free( pszCurrentDateTime ); } return 0; // (make compiler happy) } #endif // OPTION_MIPS_COUNTING /*-------------------------------------------------------------------*/ /* message command - Display a line of text at the console */ /*-------------------------------------------------------------------*/ int message_cmd(int argc,char *argv[], char *cmdline,int withhdr) { char *msgtxt; time_t mytime; struct tm *mytm; int toskip,state,i; msgtxt=NULL; toskip=3; if(argc>2) { if(strcasecmp(argv[2],"AT")==0) { toskip=5; } } for(state=0,i=0;cmdline[i];i++) { if(!state) { if(cmdline[i]!=' ') { state=1; toskip--; if(!toskip) break; } } else { if(cmdline[i]==' ') { state=0; if(toskip==1) { i++; toskip=0; break; } } } } if(!toskip) { msgtxt=&cmdline[i]; } if(msgtxt && strlen(msgtxt)>0) { if(withhdr) { time(&mytime); mytm=localtime(&mytime); logmsg( #if defined(OPTION_MSGCLR) "" #endif " %2.2u:%2.2u:%2.2u * MSG FROM HERCULES: %s\n", mytm->tm_hour, mytm->tm_min, mytm->tm_sec, msgtxt); } else { logmsg( #if defined(OPTION_MSGCLR) "" #endif "%s\n",msgtxt); } } return 0; } /*-------------------------------------------------------------------*/ /* msg command - Display a line of text at the console */ /*-------------------------------------------------------------------*/ int msg_cmd(int argc,char *argv[], char *cmdline) { return(message_cmd(argc,argv,cmdline,1)); } /*-------------------------------------------------------------------*/ /* msgnoh command - Display a line of text at the console */ /*-------------------------------------------------------------------*/ int msgnoh_cmd(int argc,char *argv[], char *cmdline) { return(message_cmd(argc,argv,cmdline,0)); } /*-------------------------------------------------------------------*/ /* comment command - do absolutely nothing */ /*-------------------------------------------------------------------*/ int comment_cmd(int argc, char *argv[],char *cmdline) { UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); // Do nothing; command has already been echo'ed to console... return 0; // (make compiler happy) } /*-------------------------------------------------------------------*/ /* quit or exit command - terminate the emulator */ /*-------------------------------------------------------------------*/ int quit_cmd(int argc, char *argv[],char *cmdline) { UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); do_shutdown(); return 0; /* (make compiler happy) */ } /*-------------------------------------------------------------------*/ /* history command */ /*-------------------------------------------------------------------*/ int History(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* last stored command is for sure command 'hst' so remove it this is the only place where history_remove is called */ history_remove(); history_requested = 1; /* only 'hst' called */ if (argc == 1) { if (history_relative_line(-1) == -1) history_requested = 0; return 0; } /* hst with argument called */ if (argc == 2) { int x; switch (argv[1][0]) { case 'l': history_show(); history_requested = 0; break; default: x = atoi(argv[1]); if (x>0) { if (history_absolute_line(x) == -1) history_requested = 0; } else { if (x<0) { if (history_relative_line(x) == -1) history_requested = 0; } else { /* x == 0 */ history_show(); history_requested = 0; } } } } return 0; } /*-------------------------------------------------------------------*/ /* log command - direct log output */ /*-------------------------------------------------------------------*/ int log_cmd(int argc, char *argv[],char *cmdline) { UNREFERENCED(cmdline); if(argc > 1) { if(strcasecmp("off",argv[1])) log_sethrdcpy(argv[1]); else log_sethrdcpy(NULL); } else logmsg(_("HHCPN160E no argument\n")); return 0; } /*-------------------------------------------------------------------*/ /* logopt command - change log options */ /*-------------------------------------------------------------------*/ int logopt_cmd(int argc, char *argv[],char *cmdline) { UNREFERENCED(cmdline); if(argc < 2) { logmsg(_("HHCPN195I Log options:%s\n"), sysblk.logoptnotime ? " NOTIMESTAMP" : " TIMESTAMP" ); } else { while (argc > 1) { argv++; argc--; if (strcasecmp(argv[0],"timestamp") == 0 || strcasecmp(argv[0],"time" ) == 0) { sysblk.logoptnotime = 0; logmsg(_("HHCPN197I Log option set: TIMESTAMP\n")); continue; } if (strcasecmp(argv[0],"notimestamp") == 0 || strcasecmp(argv[0],"notime" ) == 0) { sysblk.logoptnotime = 1; logmsg(_("HHCPN197I Log option set: NOTIMESTAMP\n")); continue; } logmsg(_("HHCPN196E Invalid logopt value %s\n"), argv[0]); } /* while (argc > 1) */ } return 0; } /*-------------------------------------------------------------------*/ /* uptime command - display how long Hercules has been running */ /*-------------------------------------------------------------------*/ int uptime_cmd(int argc, char *argv[],char *cmdline) { time_t now; unsigned uptime, weeks, days, hours, mins, secs; UNREFERENCED( cmdline ); UNREFERENCED( argc ); UNREFERENCED( argv ); time( &now ); uptime = (unsigned) difftime( now, sysblk.impltime ); #define SECS_PER_MIN ( 60 ) #define SECS_PER_HOUR ( 60 * SECS_PER_MIN ) #define SECS_PER_DAY ( 24 * SECS_PER_HOUR ) #define SECS_PER_WEEK ( 7 * SECS_PER_DAY ) weeks = uptime / SECS_PER_WEEK; uptime %= SECS_PER_WEEK; days = uptime / SECS_PER_DAY; uptime %= SECS_PER_DAY; hours = uptime / SECS_PER_HOUR; uptime %= SECS_PER_HOUR; mins = uptime / SECS_PER_MIN; uptime %= SECS_PER_MIN; secs = uptime; if (weeks) { logmsg(_("Hercules has been up for %u week%s, %u day%s, %02u:%02u:%02u.\n"), weeks, weeks > 1 ? "s" : "", days, days != 1 ? "s" : "", hours, mins, secs); } else if (days) { logmsg(_("Hercules has been up for %u day%s, %02u:%02u:%02u.\n"), days, days != 1 ? "s" : "", hours, mins, secs); } else { logmsg(_("Hercules has been up for %02u:%02u:%02u.\n"), hours, mins, secs); } return 0; } /*-------------------------------------------------------------------*/ /* version command - display version information */ /*-------------------------------------------------------------------*/ int version_cmd(int argc, char *argv[],char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); display_version (stdout, "Hercules ", TRUE); return 0; } /*-------------------------------------------------------------------*/ /* fcb - display or load */ /*-------------------------------------------------------------------*/ int fcb_cmd(int argc, char *argv[], char *cmdline) { U16 devnum; U16 lcss; DEVBLK* dev; char* devclass; int rc; int iarg,jarg; int chan; int line; char wbuf[150]; int wlpi; int windex; int wlpp; int wffchan; int wfcb[FCBSIZE+1]; char *ptr, *nxt; UNREFERENCED(cmdline); /* process specified printer device */ if (argc < 2) { logmsg( _("HHCPN021E Missing device address\n")) ; return -1 ; } rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } if (!(dev = find_device_by_devnum (lcss,devnum))) { devnotfound_msg(lcss,devnum); return -1; } (dev->hnd->query)(dev, &devclass, 0, NULL); if (strcasecmp(devclass,"PRT")) { logmsg( _("HHCPNzzzE Device %d:%4.4X is not a printer device\n"), lcss, devnum ); return -1; } if ( argc == 2 ) { fcb_dump(dev, wbuf, sizeof(wbuf)); logmsg("HHCPN210I %d:%4.4X %s\n", lcss, devnum, wbuf); return 0; } if ( !dev->stopprt ) { logmsg( _("HHCPNzzzE Device %d:%4.4X not stopped \n"), lcss, devnum ); return -1; } wlpi = dev->lpi; windex = dev->index; wlpp = dev->lpp; wffchan = dev->ffchan; for (line = 0; line <= FCBSIZE; line++) wfcb[line] = dev->fcb[line]; for (iarg = 2; iarg < argc; iarg++) { if (strncasecmp("lpi=", argv[iarg], 4) == 0) { ptr = argv[iarg]+4; errno = 0; wlpi = (int) strtoul(ptr,&nxt,10) ; if (errno != 0 || nxt == ptr || *nxt != 0 || ( wlpi != 6 && wlpi != 8 && wlpi != 10) ) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } continue; } if (strncasecmp("index=", argv[iarg], 6) == 0) { if (0x3211 != dev->devtype ) { logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, 1); return -1; } ptr = argv[iarg]+6; errno = 0; windex = (int) strtoul(ptr,&nxt,10) ; if (errno != 0 || nxt == ptr || *nxt != 0 || ( windex < 0 || windex > 15) ) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } continue; } if (strncasecmp("lpp=", argv[iarg], 4) == 0) { ptr = argv[iarg]+4; errno = 0; wlpp = (int) strtoul(ptr,&nxt,10) ; if (errno != 0 || nxt == ptr || *nxt != 0 ||wlpp > FCBSIZE) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } continue; } #if 0 if (strncasecmp("ffchan=", argv[iarg], 7) == 0) { ptr = argv[iarg]+7; errno = 0; wffchan = (int) strtoul(ptr,&nxt,10) ; if (errno != 0 || nxt == ptr || *nxt != 0 || wffchan < 1 || wffchan > 12) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } continue ; } #endif if (strncasecmp("fcb=", argv[iarg], 4) == 0) { for (line = 0 ; line <= FCBSIZE; line++) wfcb[line] = 0; /* check for simple mode */ if ( strstr(argv[iarg],":") ) { /* ':" found ==> new mode */ ptr = argv[iarg]+4; while (*ptr) { errno = 0; line = (int) strtoul(ptr,&nxt,10) ; if (errno != 0 || *nxt != ':' || nxt == ptr || line > wlpp || wfcb[line] != 0 ) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } ptr = nxt + 1 ; errno = 0; chan = (int) strtoul(ptr,&nxt,10) ; if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || chan < 1 || chan > 12 ) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } wfcb[line] = chan; if ( nxt == 0 ) break ; ptr = nxt + 1; } } else { /* ':" NOT found ==> old mode */ ptr = argv[iarg]+4; chan = 0; while (*ptr) { errno = 0; line = (int) strtoul(ptr,&nxt,10) ; if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || line > wlpp || wfcb[line] != 0 ) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } chan += 1; if ( chan > 12 ) { jarg = ptr - argv[iarg] ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } wfcb[line] = chan; if ( nxt == 0 ) break ; ptr = nxt + 1; } if ( chan != 12 ) { jarg = 5 ; logmsg("HHCPN103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, jarg); return -1; } } continue; } logmsg("HHCPN102E %d:%4.4X Printer: parameter %s in argument %d is invalid\n", SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1); return -1; } /* It's all ok, copy it to the dev block */ dev->lpi = wlpi; dev->index = windex ; dev->lpp = wlpp; dev->ffchan = wffchan; for (line = 0; line <= FCBSIZE; line++) dev->fcb[line] = wfcb[line]; fcb_dump(dev, wbuf, sizeof(wbuf)); logmsg("HHCPN210I %d:%4.4X %s\n", lcss, devnum, wbuf ); return 0; } static void fcb_dump(DEVBLK* dev, char *buf, unsigned int buflen) { int i; char wrk[16]; char sep[1]; sep[0] = '='; snprintf( buf, buflen, "lpi=%d index=%d lpp=%d fcb", dev->lpi, dev->index, dev->lpp ); for (i = 1; i <= dev->lpp; i++) { if (dev->fcb[i] != 0) { sprintf(wrk, "%c%d:%d", sep[0], i, dev->fcb[i]); sep[0] = ',' ; if (strlen(buf) + strlen(wrk) >= buflen - 4) { /* Too long, truncate it */ strcat(buf, ",..."); return; } strcat(buf, wrk); } } return; } /*-------------------------------------------------------------------*/ /* start command - start CPU (or printer device if argument given) */ /*-------------------------------------------------------------------*/ int start_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc < 2) { OBTAIN_INTLOCK(NULL); if (IS_CPU_ONLINE(sysblk.pcpu)) { REGS *regs = sysblk.regs[sysblk.pcpu]; regs->opinterv = 0; regs->cpustate = CPUSTATE_STARTED; regs->checkstop = 0; WAKEUP_CPU(regs); } RELEASE_INTLOCK(NULL); } else { /* start specified printer device */ U16 devnum; U16 lcss; int stopprt; DEVBLK* dev; char* devclass; int rc; rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } if (!(dev = find_device_by_devnum (lcss,devnum))) { devnotfound_msg(lcss,devnum); return -1; } (dev->hnd->query)(dev, &devclass, 0, NULL); if (strcasecmp(devclass,"PRT")) { logmsg( _("HHCPN017E Device %d:%4.4X is not a printer device\n"), lcss, devnum ); return -1; } /* un-stop the printer and raise attention interrupt */ stopprt = dev->stopprt; dev->stopprt = 0; rc = device_attention (dev, CSW_ATTN); if (rc) dev->stopprt = stopprt; switch (rc) { case 0: logmsg(_("HHCPN018I Printer %d:%4.4X started\n"), lcss,devnum); break; case 1: logmsg(_("HHCPN019E Printer %d:%4.4X not started: " "busy or interrupt pending\n"), lcss, devnum); break; case 2: logmsg(_("HHCPN020E Printer %d:%4.4X not started: " "attention request rejected\n"), lcss, devnum); break; case 3: logmsg(_("HHCPN021E Printer %d:%4.4X not started: " "subchannel not enabled\n"), lcss, devnum); break; } } return 0; } /*-------------------------------------------------------------------*/ /* g command - turn off single stepping and start CPU */ /*-------------------------------------------------------------------*/ int g_cmd(int argc, char *argv[], char *cmdline) { int i; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); OBTAIN_INTLOCK(NULL); sysblk.inststep = 0; SET_IC_TRACE; for (i = 0; i < HI_CPU; i++) if (IS_CPU_ONLINE(i) && sysblk.regs[i]->stepwait) { sysblk.regs[i]->cpustate = CPUSTATE_STARTED; WAKEUP_CPU(sysblk.regs[i]); } RELEASE_INTLOCK(NULL); return 0; } /*-------------------------------------------------------------------*/ /* stop command - stop CPU (or printer device if argument given) */ /*-------------------------------------------------------------------*/ int stop_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc < 2) { OBTAIN_INTLOCK(NULL); if (IS_CPU_ONLINE(sysblk.pcpu)) { REGS *regs = sysblk.regs[sysblk.pcpu]; regs->opinterv = 1; regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); WAKEUP_CPU (regs); } RELEASE_INTLOCK(NULL); } else { /* stop specified printer device */ U16 devnum; U16 lcss; DEVBLK* dev; char* devclass; int rc; rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } if (!(dev = find_device_by_devnum (lcss, devnum))) { devnotfound_msg(lcss,devnum); return -1; } (dev->hnd->query)(dev, &devclass, 0, NULL); if (strcasecmp(devclass,"PRT")) { logmsg( _("HHCPN024E Device %d:%4.4X is not a printer device\n"), lcss, devnum ); return -1; } dev->stopprt = 1; logmsg( _("HHCPN025I Printer %d:%4.4X stopped\n"), lcss, devnum ); } return 0; } /*-------------------------------------------------------------------*/ /* startall command - start all CPU's */ /*-------------------------------------------------------------------*/ int startall_cmd(int argc, char *argv[], char *cmdline) { int i; CPU_BITMAP mask; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); OBTAIN_INTLOCK(NULL); mask = (~sysblk.started_mask) & sysblk.config_mask; for (i = 0; mask; i++) { if (mask & 1) { REGS *regs = sysblk.regs[i]; regs->opinterv = 0; regs->cpustate = CPUSTATE_STARTED; signal_condition(®s->intcond); } mask >>= 1; } RELEASE_INTLOCK(NULL); return 0; } /*-------------------------------------------------------------------*/ /* stopall command - stop all CPU's */ /*-------------------------------------------------------------------*/ DLL_EXPORT int stopall_cmd(int argc, char *argv[], char *cmdline) { int i; CPU_BITMAP mask; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); OBTAIN_INTLOCK(NULL); mask = sysblk.started_mask; for (i = 0; mask; i++) { if (mask & 1) { REGS *regs = sysblk.regs[i]; regs->opinterv = 1; regs->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(regs); signal_condition(®s->intcond); } mask >>= 1; } RELEASE_INTLOCK(NULL); return 0; } #ifdef _FEATURE_CPU_RECONFIG /*-------------------------------------------------------------------*/ /* cf command - configure/deconfigure a CPU */ /*-------------------------------------------------------------------*/ int cf_cmd(int argc, char *argv[], char *cmdline) { int on = -1; UNREFERENCED(cmdline); if (argc == 2) { if (!strcasecmp(argv[1],"on")) on = 1; else if (!strcasecmp(argv[1], "off")) on = 0; } OBTAIN_INTLOCK(NULL); if (IS_CPU_ONLINE(sysblk.pcpu)) { if (on < 0) logmsg(_("HHCPN152I CPU%4.4X online\n"), sysblk.pcpu); else if (on == 0) deconfigure_cpu(sysblk.pcpu); } else { if (on < 0) logmsg(_("HHCPN153I CPU%4.4X offline\n"), sysblk.pcpu); else if (on > 0) configure_cpu(sysblk.pcpu); } RELEASE_INTLOCK(NULL); if (on >= 0) cf_cmd (0, NULL, NULL); return 0; } /*-------------------------------------------------------------------*/ /* cfall command - configure/deconfigure all CPU's */ /*-------------------------------------------------------------------*/ int cfall_cmd(int argc, char *argv[], char *cmdline) { int i; int on = -1; UNREFERENCED(cmdline); if (argc == 2) { if (!strcasecmp(argv[1],"on")) on = 1; else if (!strcasecmp(argv[1], "off")) on = 0; } OBTAIN_INTLOCK(NULL); for (i = 0; i < MAX_CPU_ENGINES; i++) if (IS_CPU_ONLINE(i)) { if (on < 0) logmsg(_("HHCPN154I CPU%4.4X online\n"), i); else if (on == 0) deconfigure_cpu(i); } else { if (on < 0) logmsg(_("HHCPN155I CPU%4.4X offline\n"), i); else if (on > 0 && i < MAX_CPU) configure_cpu(i); } RELEASE_INTLOCK(NULL); if (on >= 0) cfall_cmd (0, NULL, NULL); return 0; } #endif /*_FEATURE_CPU_RECONFIG*/ /*-------------------------------------------------------------------*/ /* quiet command - quiet PANEL */ /*-------------------------------------------------------------------*/ int quiet_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); #ifdef EXTERNALGUI if (extgui) { logmsg( _("HHCPN026W Ignored. (external GUI active)\n") ); return 0; } #endif /*EXTERNALGUI*/ sysblk.npquiet = !sysblk.npquiet; logmsg( _("HHCPN027I Automatic refresh %s.\n"), sysblk.npquiet ? _("disabled") : _("enabled") ); return 0; } /* format_tod - generate displayable date from TOD value */ /* always uses epoch of 1900 */ char * format_tod(char *buf, U64 tod, int flagdate) { int leapyear, years, days, hours, minutes, seconds, microseconds; if(tod >= TOD_YEAR) { tod -= TOD_YEAR; years = (tod / TOD_4YEARS * 4) + 1; tod %= TOD_4YEARS; if((leapyear = tod / TOD_YEAR) == 4) { tod %= TOD_YEAR; years--; tod += TOD_YEAR; } else tod %= TOD_YEAR; years += leapyear; } else years = 0; days = tod / TOD_DAY; tod %= TOD_DAY; hours = tod / TOD_HOUR; tod %= TOD_HOUR; minutes = tod / TOD_MIN; tod %= TOD_MIN; seconds = tod / TOD_SEC; microseconds = (tod % TOD_SEC) / TOD_USEC; if (flagdate) { years += 1900; days += 1; } sprintf(buf,"%4d.%03d %02d:%02d:%02d.%06d", years,days,hours,minutes,seconds,microseconds); return buf; } /*-------------------------------------------------------------------*/ /* timerint - display or set the timer interval */ /*-------------------------------------------------------------------*/ int timerint_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { if (!strcasecmp(argv[1],"default")) sysblk.timerint = DEFAULT_TIMER_REFRESH_USECS; else if (!strcasecmp(argv[1],"reset")) sysblk.timerint = DEFAULT_TIMER_REFRESH_USECS; else { int timerint = 0; BYTE c; if (1 && sscanf(argv[1], "%d%c", &timerint, &c) == 1 && timerint >= 1 && timerint <= 1000000 ) { sysblk.timerint = timerint; } } } else logmsg( _("HHCPN037I Timer update interval = %d microsecond(s)\n"), sysblk.timerint ); return 0; } /*-------------------------------------------------------------------*/ /* clocks command - display tod clkc and cpu timer */ /*-------------------------------------------------------------------*/ int clocks_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; char clock_buf[30]; U64 tod_now; U64 hw_now; S64 epoch_now; U64 epoch_now_abs; char epoch_sign; U64 clkc_now; S64 cpt_now; #if defined(_FEATURE_SIE) U64 vtod_now = 0; S64 vepoch_now = 0; U64 vepoch_now_abs = 0; char vepoch_sign = ' '; U64 vclkc_now = 0; S64 vcpt_now = 0; char sie_flag = 0; #endif U32 itimer = 0; char itimer_formatted[20]; char arch370_flag = 0; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; /* Get the clock values all at once for consistency and so we can release the CPU lock more quickly. */ tod_now = (tod_clock(regs) << 8) >> 8; hw_now = hw_tod; epoch_now = regs->tod_epoch; clkc_now = regs->clkc; cpt_now = CPU_TIMER(regs); #if defined(_FEATURE_SIE) if(regs->sie_active) { vtod_now = (TOD_CLOCK(regs->guestregs) << 8) >> 8; vepoch_now = regs->guestregs->tod_epoch; vclkc_now = regs->guestregs->clkc; vcpt_now = CPU_TIMER(regs->guestregs); sie_flag = 1; } #endif if (regs->arch_mode == ARCH_370) { itimer = INT_TIMER(regs); /* The interval timer counts 76800 per second, or one every 13.0208 microseconds. */ sprintf(itimer_formatted,"%02u:%02u:%02u.%06u", (itimer/(76800*60*60)),((itimer%(76800*60*60))/(76800*60)), ((itimer%(76800*60))/76800),((itimer%76800)*13)); arch370_flag = 1; } release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN028I tod = %16.16" I64_FMT "X %s\n"), (tod_now << 8),format_tod(clock_buf,tod_now,TRUE)); logmsg( _(" h/w = %16.16" I64_FMT "X %s\n"), (hw_now << 8),format_tod(clock_buf,hw_now,TRUE)); if (epoch_now < 0) { epoch_now_abs = -(epoch_now); epoch_sign = '-'; } else { epoch_now_abs = epoch_now; epoch_sign = ' '; } logmsg( _(" off = %16.16" I64_FMT "X %c%s\n"), (epoch_now << 8),epoch_sign, format_tod(clock_buf,epoch_now_abs,FALSE)); logmsg( _(" ckc = %16.16" I64_FMT "X %s\n"), (clkc_now << 8),format_tod(clock_buf,clkc_now,TRUE)); if (regs->cpustate != CPUSTATE_STOPPED) logmsg( _(" cpt = %16.16" I64_FMT "X\n"), cpt_now << 8); else logmsg( _(" cpt = not decrementing\n")); #if defined(_FEATURE_SIE) if(sie_flag) { logmsg( _(" vtod = %16.16" I64_FMT "X %s\n"), (vtod_now << 8),format_tod(clock_buf,vtod_now,TRUE)); if (epoch_now < 0) { epoch_now_abs = -(epoch_now); epoch_sign = '-'; } else { epoch_now_abs = epoch_now; epoch_sign = ' '; } logmsg( _(" voff = %16.16" I64_FMT "X %c%s\n"), (vepoch_now << 8),vepoch_sign, format_tod(clock_buf,vepoch_now_abs,FALSE)); logmsg( _(" vckc = %16.16" I64_FMT "X %s\n"), (vclkc_now << 8),format_tod(clock_buf,vclkc_now,TRUE)); logmsg( _(" vcpt = %16.16" I64_FMT "X\n"),vcpt_now << 8); } #endif if (arch370_flag) { logmsg( _(" itm = %8.8" I32_FMT "X %s\n"), itimer, itimer_formatted ); } return 0; } #ifdef OPTION_IODELAY_KLUDGE /*-------------------------------------------------------------------*/ /* iodelay command - display or set I/O delay value */ /*-------------------------------------------------------------------*/ int iodelay_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { int iodelay = 0; BYTE c; /* Character work area */ if (sscanf(argv[1], "%d%c", &iodelay, &c) != 1) logmsg( _("HHCPN029E Invalid I/O delay value: %s\n"), argv[1] ); else sysblk.iodelay = iodelay; } else logmsg( _("HHCPN030I I/O delay = %d\n"), sysblk.iodelay ); return 0; } #endif /*OPTION_IODELAY_KLUDGE*/ #if defined( OPTION_TAPE_AUTOMOUNT ) /*-------------------------------------------------------------------*/ /* automount_cmd - show or update AUTOMOUNT directories list */ /*-------------------------------------------------------------------*/ int automount_cmd(int argc, char *argv[], char *cmdline) { int rc; UNREFERENCED(cmdline); if (argc < 2) { logmsg(_("HHCPN200E Missing operand; enter 'HELP AUTOMOUNT' for syntax.\n")); return -1; } if (strcasecmp(argv[1],"list") == 0) { TAMDIR* pTAMDIR = sysblk.tamdir; if (argc != 2) { logmsg(_("HHCPN201E Invalid syntax; enter 'HELP AUTOMOUNT' for help.\n")); return -1; } if (!pTAMDIR) { logmsg(_("HHCPN202E Empty list.\n")); return -1; } // List all entries... for (; pTAMDIR; pTAMDIR = pTAMDIR->next) logmsg(_("HHCPN203I \"%c%s\"\n") ,pTAMDIR->rej ? '-' : '+' ,pTAMDIR->dir ); return 0; } if (strcasecmp(argv[1],"add") == 0 || *argv[1] == '+') { char *argv2; char tamdir[MAX_PATH+1]; /* +1 for optional '+' or '-' prefix */ TAMDIR* pTAMDIR = NULL; // int was_empty = (sysblk.tamdir == NULL); if(*argv[1] == '+') { argv2 = argv[1] + 1; if (argc != 2 ) { logmsg(_("HHCPN204E Invalid syntax; enter 'HELP AUTOMOUNT' for help.\n")); return -1; } } else { argv2 = argv[2]; if (argc != 3 ) { logmsg(_("HHCPN204E Invalid syntax; enter 'HELP AUTOMOUNT' for help.\n")); return -1; } } // Add the requested entry... strlcpy (tamdir, argv2, sizeof(tamdir)); rc = add_tamdir( tamdir, &pTAMDIR ); // Did that work? switch (rc) { default: /* (oops!) */ { logmsg( _("HHCPN205E **LOGIC ERROR** file \"%s\", line %d\n"), __FILE__, __LINE__); return -1; } case 5: /* ("out of memory") */ { logmsg( _("HHCPN206E Out of memory!\n")); return -1; } case 1: /* ("unresolvable path") */ case 2: /* ("path inaccessible") */ { logmsg( _("HHCPN207E Invalid AUTOMOUNT directory: \"%s\": %s\n"), tamdir, strerror(errno)); return -1; } case 3: /* ("conflict w/previous") */ { logmsg( _("HHCPN208E AUTOMOUNT directory \"%s\"" " conflicts with previous specification\n"), tamdir); return -1; } case 4: /* ("duplicates previous") */ { logmsg( _("HHCPN209E AUTOMOUNT directory \"%s\"" " duplicates previous specification\n"), tamdir); return -1; } case 0: /* ("success") */ { logmsg(_("HHCPN210I %s%s AUTOMOUNT directory = \"%s\"\n"), pTAMDIR->dir == sysblk.defdir ? "Default " : "", pTAMDIR->rej ? "Disallowed" : "Allowed", pTAMDIR->dir); /* Define default AUTOMOUNT directory if needed */ if (sysblk.defdir == NULL) { static char cwd[ MAX_PATH ]; VERIFY( getcwd( cwd, sizeof(cwd) ) != NULL ); rc = strlen( cwd ); if (cwd[rc-1] != *PATH_SEP) strlcat (cwd, PATH_SEP, sizeof(cwd)); if (!(pTAMDIR = malloc( sizeof(TAMDIR) ))) { logmsg( _("HHCPN211E Out of memory!\n")); sysblk.defdir = cwd; /* EMERGENCY! */ } else { pTAMDIR->dir = strdup (cwd); pTAMDIR->len = strlen (cwd); pTAMDIR->rej = 0; pTAMDIR->next = sysblk.tamdir; sysblk.tamdir = pTAMDIR; sysblk.defdir = pTAMDIR->dir; } logmsg(_("HHCPN212I Default Allowed AUTOMOUNT directory = \"%s\"\n"), sysblk.defdir); } return 0; } } } if (strcasecmp(argv[1],"del") == 0 || *argv[1] == '-') { char *argv2; char tamdir1[MAX_PATH+1] = {0}; // (resolved path) char tamdir2[MAX_PATH+1] = {0}; // (expanded but unresolved path) char workdir[MAX_PATH+1] = {0}; // (work) char *tamdir = tamdir1; // (-> tamdir2 on retry) TAMDIR* pPrevTAMDIR = NULL; TAMDIR* pCurrTAMDIR = sysblk.tamdir; // int was_empty = (sysblk.tamdir == NULL); if(*argv[1] == '-') { argv2 = argv[1] + 1; if (argc != 2 ) { logmsg(_("HHCPN213E Invalid syntax; enter 'HELP AUTOMOUNT' for help.\n")); return -1; } } else { argv2 = argv[2]; if (argc != 3 ) { logmsg(_("HHCPN213E Invalid syntax; enter 'HELP AUTOMOUNT' for help.\n")); return -1; } } // Convert argument to absolute path ending with a slash strlcpy( tamdir2, argv2, sizeof(tamdir2) ); if (tamdir2[0] == '-') memmove (&tamdir2[0], &tamdir2[1], MAX_PATH); else if (tamdir2[0] == '+') memmove (&tamdir2[0], &tamdir2[1], MAX_PATH); #if defined(_MSVC_) // (expand any embedded %var% environment variables) rc = expand_environ_vars( tamdir2, workdir, MAX_PATH ); if (rc == 0) strlcpy (tamdir2, workdir, MAX_PATH); #endif // _MSVC_ if (sysblk.defdir == NULL #if defined(_MSVC_) || tamdir2[1] == ':' // (fullpath given?) #else // !_MSVC_ || tamdir2[0] == '/' // (fullpath given?) #endif // _MSVC_ || tamdir2[0] == '.' // (relative path given?) ) tamdir1[0] = 0; // (then use just given spec) else // (else prepend with default) strlcpy( tamdir1, sysblk.defdir, sizeof(tamdir1) ); // (finish building path to be resolved) strlcat( tamdir1, tamdir2, sizeof(tamdir1) ); // (try resolving it to an absolute path and // append trailing path separator if needed) if (realpath(tamdir1, workdir) != NULL) { strlcpy (tamdir1, workdir, MAX_PATH); rc = strlen( tamdir1 ); if (tamdir1[rc-1] != *PATH_SEP) strlcat (tamdir1, PATH_SEP, MAX_PATH); tamdir = tamdir1; // (try tamdir1 first) } else tamdir = tamdir2; // (try only tamdir2) rc = strlen( tamdir2 ); if (tamdir2[rc-1] != *PATH_SEP) strlcat (tamdir2, PATH_SEP, MAX_PATH); // Find entry to be deleted... for (;;) { for (pCurrTAMDIR = sysblk.tamdir, pPrevTAMDIR = NULL; pCurrTAMDIR; pPrevTAMDIR = pCurrTAMDIR, pCurrTAMDIR = pCurrTAMDIR->next) { if (strfilenamecmp( pCurrTAMDIR->dir, tamdir ) == 0) { int def = (sysblk.defdir == pCurrTAMDIR->dir); // Delete the found entry... if (pPrevTAMDIR) pPrevTAMDIR->next = pCurrTAMDIR->next; else sysblk.tamdir = pCurrTAMDIR->next; free( pCurrTAMDIR->dir ); free( pCurrTAMDIR ); // (point back to list begin) pCurrTAMDIR = sysblk.tamdir; logmsg(_("HHCPN214I Ok.%s\n"), pCurrTAMDIR ? "" : " (list now empty)"); // Default entry just deleted? if (def) { if (!pCurrTAMDIR) sysblk.defdir = NULL; // (no default) else { // Set new default entry... for (; pCurrTAMDIR; pCurrTAMDIR = pCurrTAMDIR->next) { if (pCurrTAMDIR->rej == 0) { sysblk.defdir = pCurrTAMDIR->dir; break; } } // If we couldn't find an existing allowable // directory entry to use as the new default, // then add the current directory and use it. if (!pCurrTAMDIR) { static char cwd[ MAX_PATH ] = {0}; VERIFY( getcwd( cwd, sizeof(cwd) ) != NULL ); rc = strlen( cwd ); if (cwd[rc-1] != *PATH_SEP) strlcat (cwd, PATH_SEP, sizeof(cwd)); if (!(pCurrTAMDIR = malloc( sizeof(TAMDIR) ))) { logmsg( _("HHCPN215E Out of memory!\n")); sysblk.defdir = cwd; /* EMERGENCY! */ } else { pCurrTAMDIR->dir = strdup (cwd); pCurrTAMDIR->len = strlen (cwd); pCurrTAMDIR->rej = 0; pCurrTAMDIR->next = sysblk.tamdir; sysblk.tamdir = pCurrTAMDIR; sysblk.defdir = pCurrTAMDIR->dir; } } logmsg(_("HHCPN216I Default Allowed AUTOMOUNT directory = \"%s\"\n"), sysblk.defdir); } } return 0; // (success) } } // (not found; try tamdir2 if we haven't yet) if (tamdir == tamdir2) break; tamdir = tamdir2; } if (sysblk.tamdir == NULL) logmsg(_("HHCPN217E Empty list.\n")); else logmsg(_("HHCPN218E Entry not found.\n")); return -1; } logmsg(_("HHCPN219E Unsupported function; enter 'HELP AUTOMOUNT' for syntax.\n")); return 0; } #endif /* OPTION_TAPE_AUTOMOUNT */ #if defined( OPTION_SCSI_TAPE ) // (helper function for 'scsimount' and 'devlist' commands) static void try_scsi_refresh( DEVBLK* dev ) { // PROGRAMMING NOTE: we can only ever cause the auto-scsi-mount // thread to startup or shutdown [according to the current user // setting] if the current drive status is "not mounted". // What we unfortunately CANNOT do (indeed MUST NOT do!) however // is actually "force" a refresh of a current [presumably bogus] // "mounted" status (to presumably detect that a tape that was // once mounted has now been manually unmounted for example). // The reasons for why this is not possible is clearly explained // in the 'update_status_scsitape' function in 'scsitape.c'. // If the user manually unloaded a mounted tape (such that there // is now no longer a tape mounted even though the drive status // says there is), then they unfortunately have no choice but to // manually issue the 'devinit' command themselves, because, as // explained, we unfortunately cannot refresh a mounted status // for them (due to the inherent danger of doing so as explained // by comments in 'update_status_scsitape' in member scsitape.c). GENTMH_PARMS gen_parms; gen_parms.action = GENTMH_SCSI_ACTION_UPDATE_STATUS; gen_parms.dev = dev; VERIFY( dev->tmh->generic( &gen_parms ) == 0 ); // (maybe update status) usleep(10*1000); // (let thread start/end) } /*-------------------------------------------------------------------*/ /* scsimount command - display or adjust the SCSI auto-mount option */ /*-------------------------------------------------------------------*/ int scsimount_cmd(int argc, char *argv[], char *cmdline) { char* eyecatcher = "*************************************************************************************************"; DEVBLK* dev; int tapeloaded; char* tapemsg=""; char volname[7]; BYTE mountreq, unmountreq; char* label_type; // Unused.. // int old_auto_scsi_mount_secs = sysblk.auto_scsi_mount_secs; UNREFERENCED(cmdline); if (argc > 1) { if ( strcasecmp( argv[1], "no" ) == 0 ) { sysblk.auto_scsi_mount_secs = 0; } else if ( strcasecmp( argv[1], "yes" ) == 0 ) { sysblk.auto_scsi_mount_secs = DEFAULT_AUTO_SCSI_MOUNT_SECS; } else { int auto_scsi_mount_secs; BYTE c; if ( sscanf( argv[1], "%d%c", &auto_scsi_mount_secs, &c ) != 1 || auto_scsi_mount_secs < 0 || auto_scsi_mount_secs > 99 ) { logmsg ( _( "HHCCF068E Invalid value: %s; Enter \"help scsimount\" for help.\n" ) ,argv[1] ); return 0; } sysblk.auto_scsi_mount_secs = auto_scsi_mount_secs; } } if ( sysblk.auto_scsi_mount_secs ) logmsg( _("SCSI auto-mount queries = every %d seconds (when needed)\n"), sysblk.auto_scsi_mount_secs ); else logmsg( _("SCSI auto-mount queries are disabled.\n") ); // Scan the device list looking for all SCSI tape devices // with either an active scsi mount thread and/or an out- // standing tape mount request... for ( dev = sysblk.firstdev; dev; dev = dev->nextdev ) { if ( !dev->allocated || TAPEDEVT_SCSITAPE != dev->tapedevt ) continue; // (not an active SCSI tape device; skip) try_scsi_refresh( dev ); // (see comments in function) logmsg ( _("thread %s active for drive %u:%4.4X = %s.\n") ,dev->stape_mntdrq.link.Flink ? "IS" : "is NOT" ,SSID_TO_LCSS(dev->ssid) ,dev->devnum ,dev->filename ); if (!dev->tdparms.displayfeat) continue; mountreq = FALSE; // (default) unmountreq = FALSE; // (default) if (0 || TAPEDISPTYP_MOUNT == dev->tapedisptype || TAPEDISPTYP_UNMOUNT == dev->tapedisptype || TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype ) { tapeloaded = dev->tmh->tapeloaded( dev, NULL, 0 ); if ( TAPEDISPTYP_MOUNT == dev->tapedisptype && !tapeloaded ) { mountreq = TRUE; unmountreq = FALSE; tapemsg = dev->tapemsg1; } else if ( TAPEDISPTYP_UNMOUNT == dev->tapedisptype && tapeloaded ) { unmountreq = TRUE; mountreq = FALSE; tapemsg = dev->tapemsg1; } else // ( TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype ) { if (tapeloaded) { if ( !(dev->tapedispflags & TAPEDISPFLG_MESSAGE2) ) { unmountreq = TRUE; mountreq = FALSE; tapemsg = dev->tapemsg1; } } else // (!tapeloaded) { mountreq = TRUE; unmountreq = FALSE; tapemsg = dev->tapemsg2; } } } if ((mountreq || unmountreq) && ' ' != *tapemsg) { switch (*(tapemsg+7)) { case 'A': label_type = "ascii-standard"; break; case 'S': label_type = "standard"; break; case 'N': label_type = "non"; break; case 'U': label_type = "un"; break; default : label_type = "??"; break; } volname[0]=0; if (*(tapemsg+1)) { strncpy( volname, tapemsg+1, 6 ); volname[6]=0; } logmsg ( _("\n%s\nHHCCF069I %s of %s-labeled volume \"%s\" pending for drive %u:%4.4X = %s\n%s\n\n") ,eyecatcher ,mountreq ? "Mount" : "Dismount" ,label_type ,volname ,SSID_TO_LCSS(dev->ssid) ,dev->devnum ,dev->filename ,eyecatcher ); } else { logmsg( _("No mount/dismount requests pending for drive %u:%4.4X = %s.\n"), SSID_TO_LCSS(dev->ssid),dev->devnum, dev->filename ); } } return 0; } #endif /* defined( OPTION_SCSI_TAPE ) */ /*-------------------------------------------------------------------*/ /* cckd command */ /*-------------------------------------------------------------------*/ int cckd_cmd(int argc, char *argv[], char *cmdline) { char* p = strtok(cmdline+4," \t"); UNREFERENCED(argc); UNREFERENCED(argv); return cckd_command(p,1); } /*-------------------------------------------------------------------*/ /* ctc command - enable/disable CTC debugging */ /*-------------------------------------------------------------------*/ int ctc_cmd( int argc, char *argv[], char *cmdline ) { DEVBLK* dev; CTCBLK* pCTCBLK; LCSDEV* pLCSDEV; LCSBLK* pLCSBLK; U16 lcss; U16 devnum; BYTE onoff; UNREFERENCED( cmdline ); // Format: "ctc debug { on | off } [ | ALL ]" if (0 || argc < 3 || strcasecmp( argv[1], "debug" ) != 0 || (1 && strcasecmp( argv[2], "on" ) != 0 && strcasecmp( argv[2], "off" ) != 0 ) || argc > 4 || (1 && argc == 4 && strcasecmp( argv[3], "ALL" ) != 0 && parse_single_devnum( argv[3], &lcss, &devnum) < 0 ) ) { panel_command ("help ctc"); return -1; } onoff = (strcasecmp( argv[2], "on" ) == 0); if (argc < 4 || strcasecmp( argv[3], "ALL" ) == 0) { for ( dev = sysblk.firstdev; dev; dev = dev->nextdev ) { if (0 || !dev->allocated || 0x3088 != dev->devtype || (CTC_CTCI != dev->ctctype && CTC_LCS != dev->ctctype) ) continue; if (CTC_CTCI == dev->ctctype) { pCTCBLK = dev->dev_data; pCTCBLK->fDebug = onoff; } else // (CTC_LCS == dev->ctctype) { pLCSDEV = dev->dev_data; pLCSBLK = pLCSDEV->pLCSBLK; pLCSBLK->fDebug = onoff; } } logmsg( _("HHCPNXXXI CTC debugging now %s for all CTCI/LCS device groups.\n"), onoff ? _("ON") : _("OFF") ); } else { int i; DEVGRP* pDEVGRP; DEVBLK* pDEVBLK; if (!(dev = find_device_by_devnum ( lcss, devnum ))) { devnotfound_msg( lcss, devnum ); return -1; } pDEVGRP = dev->group; if (CTC_CTCI == dev->ctctype) { for (i=0; i < pDEVGRP->acount; i++) { pDEVBLK = pDEVGRP->memdev[i]; pCTCBLK = pDEVBLK->dev_data; pCTCBLK->fDebug = onoff; } } else if (CTC_LCS == dev->ctctype) { for (i=0; i < pDEVGRP->acount; i++) { pDEVBLK = pDEVGRP->memdev[i]; pLCSDEV = pDEVBLK->dev_data; pLCSBLK = pLCSDEV->pLCSBLK; pLCSBLK->fDebug = onoff; } } else { logmsg( _("HHCPN034E Device %d:%4.4X is not a CTCI or LCS device\n"), lcss, devnum ); return -1; } logmsg( _("HHCPNXXXI CTC debugging now %s for %s device %d:%4.4X group.\n"), onoff ? _("ON") : _("OFF"), CTC_LCS == dev->ctctype ? "LCS" : "CTCI", lcss, devnum ); } return 0; } #if defined(OPTION_W32_CTCI) /*-------------------------------------------------------------------*/ /* tt32 command - control/query CTCI-W32 functionality */ /*-------------------------------------------------------------------*/ int tt32_cmd( int argc, char *argv[], char *cmdline ) { int rc = 0; U16 devnum; U16 lcss; DEVBLK* dev; UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN188E Missing arguments; enter 'help tt32' for help.\n") ); rc = -1; } else if (strcasecmp(argv[1],"stats") == 0) { if (argc < 3) { missing_devnum(); return -1; } if ((rc = parse_single_devnum(argv[2], &lcss, &devnum)) < 0) return -1; if (!(dev = find_device_by_devnum (lcss, devnum)) && !(dev = find_device_by_devnum (lcss, devnum ^ 0x01))) { devnotfound_msg(lcss,devnum); return -1; } if (CTC_CTCI != dev->ctctype && CTC_LCS != dev->ctctype) { logmsg( _("HHCPN034E Device %d:%4.4X is not a CTCI or LCS device\n"), lcss, devnum ); return -1; } if (debug_tt32_stats) rc = debug_tt32_stats (dev->fd); else { logmsg( _("(error)\n") ); rc = -1; } } else if (strcasecmp(argv[1],"debug") == 0) { if (debug_tt32_tracing) { debug_tt32_tracing(1); // 1=ON rc = 0; logmsg( _("HHCPN189I TT32 debug tracing messages enabled\n") ); } else { logmsg( _("(error)\n") ); rc = -1; } } else if (strcasecmp(argv[1],"nodebug") == 0) { if (debug_tt32_tracing) { debug_tt32_tracing(0); // 0=OFF rc = 0; logmsg( _("HHCPN189I TT32 debug tracing messages disabled\n") ); } else { logmsg( _("(error)\n") ); rc = -1; } } else { logmsg( _("HHCPN187E Invalid argument\n") ); rc = -1; } return rc; } #endif /* defined(OPTION_W32_CTCI) */ /*-------------------------------------------------------------------*/ /* store command - store CPU status at absolute zero */ /*-------------------------------------------------------------------*/ int store_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; /* Command is valid only when CPU is stopped */ if (regs->cpustate != CPUSTATE_STOPPED) { logmsg( _("HHCPN035E store status rejected: CPU not stopped\n") ); return -1; } /* Store status in 512 byte block at absolute location 0 */ store_status (regs, 0); release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg (_("HHCCP010I CPU%4.4X store status completed.\n"), regs->cpuad); return 0; } /*-------------------------------------------------------------------*/ /* sclproot command - set SCLP base directory */ /*-------------------------------------------------------------------*/ int sclproot_cmd(int argc, char *argv[], char *cmdline) { char *basedir; UNREFERENCED(cmdline); if (argc > 1) if (!strcasecmp(argv[1],"none")) set_sce_dir(NULL); else set_sce_dir(argv[1]); else if((basedir = get_sce_dir())) logmsg(_("SCLPROOT %s\n"),basedir); else logmsg(_("SCLP DISK I/O Disabled\n")); return 0; } #if defined(OPTION_HTTP_SERVER) /*-------------------------------------------------------------------*/ /* httproot command - set HTTP server base directory */ /*-------------------------------------------------------------------*/ int httproot_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { if (sysblk.httproot) free(sysblk.httproot); sysblk.httproot = strdup(argv[1]); } else if(sysblk.httproot) logmsg(_("HHCnnxxxI HTTPROOT %s\n"),sysblk.httproot); else logmsg(_("HHCnnxxxI HTTPROOT not specified\n")); return 0; } /*-------------------------------------------------------------------*/ /* httpport command - set HTTP server port */ /*-------------------------------------------------------------------*/ int httpport_cmd(int argc, char *argv[], char *cmdline) { char c; UNREFERENCED(cmdline); if (argc > 1) { if (!strcasecmp(argv[1],"none")) { if(sysblk.httpport) { sysblk.httpport = 0; signal_thread(sysblk.httptid, SIGUSR2); } } else if(sysblk.httpport) { logmsg(_("HHCCF040S HTTP server already active\n")); return -1; } else { if (sscanf(argv[1], "%hu%c", &sysblk.httpport, &c) != 1 || sysblk.httpport == 0 || (sysblk.httpport < 1024 && sysblk.httpport != 80) ) { logmsg(_("HHCCF029S Invalid HTTP port number %s\n"), argv[1]); return -1; } if (argc > 2) { if (!strcasecmp(argv[2],"auth")) sysblk.httpauth = 1; else if (strcasecmp(argv[2],"noauth")) { logmsg(_("HHCCF005S Unrecognized argument %s\n"),argv[2]); return -1; } } if (argc > 3) { if (sysblk.httpuser) free(sysblk.httpuser); sysblk.httpuser = strdup(argv[3]); } if (argc > 4) { if (sysblk.httppass) free(sysblk.httppass); sysblk.httppass = strdup(argv[4]); } /* Start the http server connection thread */ if ( create_thread (&sysblk.httptid, DETACHED, http_server, NULL, "http_server") ) { logmsg(_("HHCCF041S Cannot create http_server thread: %s\n"), strerror(errno)); return -1; } } } else logmsg(_("HHCCF049I HTTPPORT %d\n"),sysblk.httpport); return 0; } #if defined( HTTP_SERVER_CONNECT_KLUDGE ) /*-------------------------------------------------------------------*/ /* http_server_kludge_msecs */ /*-------------------------------------------------------------------*/ int httpskm_cmd(int argc, char *argv[], char *cmdline) { char c; UNREFERENCED(cmdline); if (argc > 1) { int http_server_kludge_msecs; if ( sscanf( argv[1], "%d%c", &http_server_kludge_msecs, &c ) != 1 || http_server_kludge_msecs <= 0 || http_server_kludge_msecs > 50 ) { logmsg(_("HHCCF066S Invalid HTTP_SERVER_CONNECT_KLUDGE value: %s\n" ),argv[1]); return -1; } sysblk.http_server_kludge_msecs = http_server_kludge_msecs; } else logmsg(_("HHCCF042S HTTP_SERVER_CONNECT_KLUDGE value: %s\n" ) ,sysblk.http_server_kludge_msecs); return 0; } #endif // defined( HTTP_SERVER_CONNECT_KLUDGE ) #endif /*defined(OPTION_HTTP_SERVER)*/ #if defined(_FEATURE_ASN_AND_LX_REUSE) /*-------------------------------------------------------------------*/ /* alrf command - display or set asn_and_lx_reuse */ /*-------------------------------------------------------------------*/ int alrf_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { if(strcasecmp(argv[1],"enable")==0) sysblk.asnandlxreuse=1; else { if(strcasecmp(argv[1],"disable")==0) sysblk.asnandlxreuse=0; else { logmsg(_("HHCCF067S Incorrect keyword %s for the ASN_AND_LX_REUSE statement.\n"), argv[1]); return -1; } } } else logmsg(_("HHCCF0028I ASN and LX reuse is %s\n"),sysblk.asnandlxreuse ? "Enabled" : "Disabled"); return 0; } #endif /*defined(_FEATURE_ASN_AND_LX_REUSE)*/ /*-------------------------------------------------------------------*/ /* toddrag command - display or set TOD clock drag factor */ /*-------------------------------------------------------------------*/ int toddrag_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { double toddrag = -1.0; sscanf(argv[1], "%lf", &toddrag); if (toddrag >= 0.0001 && toddrag <= 10000.0) { /* Set clock steering based on drag factor */ set_tod_steering(-(1.0-(1.0/toddrag))); } } else logmsg( _("HHCPN036I TOD clock drag factor = %lf\n"), (1.0/(1.0+get_tod_steering()))); return 0; } #ifdef PANEL_REFRESH_RATE /*-------------------------------------------------------------------*/ /* panrate command - display or set rate at which console refreshes */ /*-------------------------------------------------------------------*/ int panrate_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { if (!strcasecmp(argv[1],"fast")) sysblk.panrate = PANEL_REFRESH_RATE_FAST; else if (!strcasecmp(argv[1],"slow")) sysblk.panrate = PANEL_REFRESH_RATE_SLOW; else { int trate = 0; sscanf(argv[1],"%d", &trate); if (trate >= (1000 / CLK_TCK) && trate < 5001) sysblk.panrate = trate; } } else logmsg( _("HHCPN037I Panel refresh rate = %d millisecond(s)\n"), sysblk.panrate ); return 0; } #endif /*PANEL_REFRESH_RATE */ /*-------------------------------------------------------------------*/ /* pantitle xxxxxxxx command - set console title */ /*-------------------------------------------------------------------*/ int pantitle_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Update pantitle if operand is specified */ if (argc > 1) { if (sysblk.pantitle) free(sysblk.pantitle); sysblk.pantitle = strdup(argv[1]); } else logmsg( _("HHCCF100I pantitle = %s\n"),sysblk.pantitle); return 0; } #ifdef OPTION_MSGHLD /*-------------------------------------------------------------------*/ /* msghld command - display or set rate at which console refreshes */ /*-------------------------------------------------------------------*/ int msghld_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if(argc == 2) { if(!strcasecmp(argv[1], "info")) { logmsg("HHCCF101I Current message held time is %d seconds.\n", sysblk.keep_timeout_secs); return(0); } else if(!strcasecmp(argv[1], "clear")) { expire_kept_msgs(1); logmsg("HHCCF102I Held messages cleared.\n"); return(0); } else { int new_timeout; if(sscanf(argv[1], "%d", &new_timeout) && new_timeout >= 0) { sysblk.keep_timeout_secs = new_timeout; logmsg("HHCCF103I The message held time is set to %d seconds.\n", sysblk.keep_timeout_secs); return(0); } } } logmsg("msghld: Invalid usage\n"); return(0); } #endif // OPTION_MSGHLD /*-------------------------------------------------------------------*/ /* shell command */ /*-------------------------------------------------------------------*/ int sh_cmd(int argc, char *argv[], char *cmdline) { char* cmd; UNREFERENCED(argc); UNREFERENCED(argv); if (sysblk.shcmdopt & SHCMDOPT_DISABLE) { logmsg( _("HHCPN180E shell commands are disabled\n")); return -1; } cmd = cmdline + 2; while (isspace(*cmd)) cmd++; if (*cmd) return herc_system (cmd); return -1; } /*-------------------------------------------------------------------*/ /* change directory command */ /*-------------------------------------------------------------------*/ int cd_cmd(int argc, char *argv[], char *cmdline) { char* path; char cwd [ MAX_PATH ]; UNREFERENCED(argc); UNREFERENCED(argv); if (sysblk.shcmdopt & SHCMDOPT_DISABLE) { logmsg( _("HHCPN180E shell commands are disabled\n")); return -1; } path = cmdline + 2; while (isspace(*path)) path++; chdir(path); getcwd( cwd, sizeof(cwd) ); logmsg("%s\n",cwd); HDC1( debug_cd_cmd, cwd ); return 0; } /*-------------------------------------------------------------------*/ /* print working directory command */ /*-------------------------------------------------------------------*/ int pwd_cmd(int argc, char *argv[], char *cmdline) { char cwd [ MAX_PATH ]; UNREFERENCED(argv); UNREFERENCED(cmdline); if (sysblk.shcmdopt & SHCMDOPT_DISABLE) { logmsg( _("HHCPN180E shell commands are disabled\n")); return -1; } if (argc > 1) { logmsg( _("HHCPN163E Invalid format. Command does not support any arguments.\n")); return -1; } getcwd( cwd, sizeof(cwd) ); logmsg("%s\n",cwd); return 0; } /*-------------------------------------------------------------------*/ /* gpr command - display or alter general purpose registers */ /*-------------------------------------------------------------------*/ int gpr_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(cmdline); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; if (argc > 1) { int reg_num; BYTE equal_sign, c; U64 reg_value; if (argc > 2) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN162E Invalid format. Enter \"help gpr\" for help.\n")); return 0; } if (0 || sscanf( argv[1], "%d%c%"I64_FMT"x%c", ®_num, &equal_sign, ®_value, &c ) != 3 || 0 > reg_num || 15 < reg_num || '=' != equal_sign ) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN162E Invalid format. .Enter \"help gpr\" for help.\n")); return 0; } if ( ARCH_900 == regs->arch_mode ) regs->GR_G(reg_num) = (U64) reg_value; else regs->GR_L(reg_num) = (U32) reg_value; } display_regs (regs); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* fpr command - display floating point registers */ /*-------------------------------------------------------------------*/ int fpr_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; display_fregs (regs); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* fpc command - display floating point control register */ /*-------------------------------------------------------------------*/ int fpc_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; logmsg( "FPC=%8.8"I32_FMT"X\n", regs->fpc ); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* cr command - display or alter control registers */ /*-------------------------------------------------------------------*/ int cr_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; int cr_num; BYTE equal_sign, c; U64 cr_value; UNREFERENCED(cmdline); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; if (argc > 1) { if (argc > 2 || sscanf( argv[1], "%d%c%"I64_FMT"x%c", &cr_num, &equal_sign, &cr_value, &c ) != 3 || '=' != equal_sign || cr_num < 0 || cr_num > 15) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN164E Invalid format. .Enter \"help cr\" for help.\n")); return 0; } if ( ARCH_900 == regs->arch_mode ) regs->CR_G(cr_num) = (U64)cr_value; else regs->CR_G(cr_num) = (U32)cr_value; } display_cregs (regs); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* ar command - display access registers */ /*-------------------------------------------------------------------*/ int ar_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; display_aregs (regs); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* pr command - display prefix register */ /*-------------------------------------------------------------------*/ int pr_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; if(regs->arch_mode == ARCH_900) logmsg( "Prefix=%16.16" I64_FMT "X\n", (long long)regs->PX_G ); else logmsg( "Prefix=%8.8X\n", regs->PX_L ); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* psw command - display or alter program status word */ /*-------------------------------------------------------------------*/ int psw_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; BYTE c; U64 newia=0; int newam=0, newas=0, newcc=0, newcmwp=0, newpk=0, newpm=0, newsm=0; int updia=0, updas=0, updcc=0, updcmwp=0, updpk=0, updpm=0, updsm=0; int n, errflag, stopflag=0, modflag=0; UNREFERENCED(cmdline); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; /* Process optional operands */ for (n = 1; n < argc; n++) { modflag = 1; errflag = 0; if (strncasecmp(argv[n],"sm=",3) == 0) { /* PSW system mask operand */ if (sscanf(argv[n]+3, "%x%c", &newsm, &c) == 1 && newsm >= 0 && newsm <= 255) updsm = 1; else errflag = 1; } else if (strncasecmp(argv[n],"pk=",3) == 0) { /* PSW protection key operand */ if (sscanf(argv[n]+3, "%d%c", &newpk, &c) == 1 && newpk >= 0 && newpk <= 15) updpk = 1; else errflag = 1; } else if (strncasecmp(argv[n],"cmwp=",5) == 0) { /* PSW CMWP bits operand */ if (sscanf(argv[n]+5, "%x%c", &newcmwp, &c) == 1 && newcmwp >= 0 && newcmwp <= 15) updcmwp = 1; else errflag = 1; } else if (strncasecmp(argv[n],"as=",3) == 0) { /* PSW address-space control operand */ if (strcasecmp(argv[n]+3,"pri") == 0) newas = PSW_PRIMARY_SPACE_MODE; else if (strcmp(argv[n]+3,"ar") == 0) newas = PSW_ACCESS_REGISTER_MODE; else if (strcmp(argv[n]+3,"sec") == 0) newas = PSW_SECONDARY_SPACE_MODE; else if (strcmp(argv[n]+3,"home") == 0) newas = PSW_HOME_SPACE_MODE; else errflag = 1; if (errflag == 0) updas = 1; } else if (strncasecmp(argv[n],"cc=",3) == 0) { /* PSW condition code operand */ if (sscanf(argv[n]+3, "%d%c", &newcc, &c) == 1 && newcc >= 0 && newcc <= 3) updcc = 1; else errflag = 1; } else if (strncasecmp(argv[n],"pm=",3) == 0) { /* PSW program mask operand */ if (sscanf(argv[n]+3, "%x%c", &newpm, &c) == 1 && newpm >= 0 && newpm <= 15) updpm = 1; else errflag = 1; } else if (strncasecmp(argv[n],"am=",3) == 0) { /* PSW addressing mode operand */ if (strcmp(argv[n]+3,"24") == 0) newam = 24; else if (strcmp(argv[n]+3,"31") == 0 && (sysblk.arch_mode == ARCH_390 || sysblk.arch_mode == ARCH_900)) newam = 31; else if (strcmp(argv[n]+3,"64") == 0 && sysblk.arch_mode == ARCH_900) newam = 64; else errflag = 1; } else if (strncasecmp(argv[n],"ia=",3) == 0) { /* PSW instruction address operand */ if (sscanf(argv[n]+3, "%"I64_FMT"x%c", &newia, &c) == 1) updia = 1; else errflag = 1; } else /* unknown operand keyword */ errflag = 1; /* Error message if this operand was invalid */ if (errflag) { logmsg( _("HHCPN165E Invalid operand %s\n"), argv[n]); stopflag = 1; } } /* end for(n) */ /* Finish now if any errors occurred */ if (stopflag) { release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /* Update the PSW system mask, if specified */ if (updsm) { regs->psw.sysmask = newsm; } /* Update the PSW protection key, if specified */ if (updpk) { regs->psw.pkey = newpk << 4; } /* Update the PSW CMWP bits, if specified */ if (updcmwp) { regs->psw.states = newcmwp; } /* Update the PSW address-space control mode, if specified */ if (updas && (ECMODE(®s->psw) || sysblk.arch_mode == ARCH_390 || sysblk.arch_mode == ARCH_900)) { regs->psw.asc = newas; } /* Update the PSW condition code, if specified */ if (updcc) { regs->psw.cc = newcc; } /* Update the PSW program mask, if specified */ if (updpm) { regs->psw.progmask = newpm; } /* Update the PSW addressing mode, if specified */ switch(newam) { case 64: regs->psw.amode = regs->psw.amode64 = 1; regs->psw.AMASK_G = AMASK64; break; case 31: regs->psw.amode = 1; regs->psw.amode64 = 0; regs->psw.AMASK_G = AMASK31; break; case 24: regs->psw.amode = regs->psw.amode64 = 0; regs->psw.AMASK_G = AMASK24; break; } /* end switch(newam) */ /* Update the PSW instruction address, if specified */ if (updia) { regs->psw.IA_G = newia; } /* If any modifications were made, reapply the addressing mode mask to the instruction address and invalidate the instruction pointer */ if (modflag) { regs->psw.IA_G &= regs->psw.AMASK_G; regs->aie = NULL; } /* Display the PSW field by field */ logmsg("psw sm=%2.2X pk=%d cmwp=%X as=%s cc=%d pm=%X am=%s ia=%"I64_FMT"X\n", regs->psw.sysmask, regs->psw.pkey >> 4, regs->psw.states, (regs->psw.asc == PSW_PRIMARY_SPACE_MODE ? "pri" : regs->psw.asc == PSW_ACCESS_REGISTER_MODE ? "ar" : regs->psw.asc == PSW_SECONDARY_SPACE_MODE ? "sec" : regs->psw.asc == PSW_HOME_SPACE_MODE ? "home" : "???"), regs->psw.cc, regs->psw.progmask, (regs->psw.amode == 0 && regs->psw.amode64 == 0 ? "24" : regs->psw.amode == 1 && regs->psw.amode64 == 0 ? "31" : regs->psw.amode == 1 && regs->psw.amode64 == 1 ? "64" : "???"), regs->psw.IA_G); /* Display the PSW */ display_psw (regs); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* restart command - generate restart interrupt */ /*-------------------------------------------------------------------*/ int restart_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); /* Check that target processor type allows IPL */ if (sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_IFA || sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_SUP) { logmsg(_("HHCPN052E Target CPU %d type %d" " does not allow ipl nor restart\n"), sysblk.pcpu, sysblk.ptyp[sysblk.pcpu]); return -1; } logmsg( _("HHCPN038I Restart key depressed\n") ); /* Obtain the interrupt lock */ OBTAIN_INTLOCK(NULL); if (!IS_CPU_ONLINE(sysblk.pcpu)) { RELEASE_INTLOCK(NULL); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu ); return 0; } /* Indicate that a restart interrupt is pending */ ON_IC_RESTART(sysblk.regs[sysblk.pcpu]); /* Ensure that a stopped CPU will recognize the restart */ if (sysblk.regs[sysblk.pcpu]->cpustate == CPUSTATE_STOPPED) sysblk.regs[sysblk.pcpu]->cpustate = CPUSTATE_STOPPING; sysblk.regs[sysblk.pcpu]->checkstop = 0; /* Signal CPU that an interrupt is pending */ WAKEUP_CPU (sysblk.regs[sysblk.pcpu]); /* Release the interrupt lock */ RELEASE_INTLOCK(NULL); return 0; } /*-------------------------------------------------------------------*/ /* r command - display or alter real storage */ /*-------------------------------------------------------------------*/ int r_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; alter_display_real (cmdline+1, regs); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* u command - disassemble */ /*-------------------------------------------------------------------*/ int u_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; disasm_stor (regs, cmdline+2); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* v command - display or alter virtual storage */ /*-------------------------------------------------------------------*/ int v_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(argc); UNREFERENCED(argv); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; alter_display_virt (cmdline+1, regs); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* tracing commands: t, t+, t-, t?, s, s+, s-, s?, b */ /*-------------------------------------------------------------------*/ int trace_cmd(int argc, char *argv[], char *cmdline) { int on = 0, off = 0, query = 0; int trace = 0; int rc; BYTE c[2]; U64 addr[2]; char range[256]; trace = cmdline[0] == 't'; if (strlen(cmdline) > 1) { on = cmdline[1] == '+' || (cmdline[0] == 'b' && cmdline[1] == ' '); off = cmdline[1] == '-'; query = cmdline[1] == '?'; } if (argc > 2 || (off && argc > 1) || (query && argc > 1)) { logmsg( _("HHCPN039E Invalid arguments\n") ); return -1; } /* Get address range */ if (argc == 2) { rc = sscanf(argv[1], "%"I64_FMT"x%c%"I64_FMT"x%c", &addr[0], &c[0], &addr[1], &c[1]); if (rc == 1) { c[0] = '-'; addr[1] = addr[0]; } else if (rc != 3 || (c[0] != '-' && c[0] != ':' && c[0] != '.')) { logmsg( _("HHCPN039E Invalid arguments\n") ); return -1; } if (c[0] == '.') addr[1] += addr[0] - 1; if (trace) { sysblk.traceaddr[0] = addr[0]; sysblk.traceaddr[1] = addr[1]; } else { sysblk.stepaddr[0] = addr[0]; sysblk.stepaddr[1] = addr[1]; } } else c[0] = '-'; /* Set tracing/stepping bit on or off */ if (on || off) { OBTAIN_INTLOCK(NULL); if (trace) sysblk.insttrace = on; else sysblk.inststep = on; SET_IC_TRACE; RELEASE_INTLOCK(NULL); } /* Build range for message */ range[0] = '\0'; if (trace && (sysblk.traceaddr[0] != 0 || sysblk.traceaddr[1] != 0)) sprintf(range, "range %" I64_FMT "x%c%" I64_FMT "x", sysblk.traceaddr[0], c[0], c[0] != '.' ? sysblk.traceaddr[1] : sysblk.traceaddr[1] - sysblk.traceaddr[0] + 1); else if (!trace && (sysblk.stepaddr[0] != 0 || sysblk.stepaddr[1] != 0)) sprintf(range, "range %" I64_FMT "x%c%" I64_FMT "x", sysblk.stepaddr[0], c[0], c[0] != '.' ? sysblk.stepaddr[1] : sysblk.stepaddr[1] - sysblk.stepaddr[0] + 1); /* Determine if this trace is on or off for message */ on = (trace && sysblk.insttrace) || (!trace && sysblk.inststep); /* Display message */ logmsg(_("HHCPN040I Instruction %s %s %s\n"), cmdline[0] == 't' ? _("tracing") : cmdline[0] == 's' ? _("stepping") : _("break"), on ? _("on") : _("off"), range); return 0; } /*-------------------------------------------------------------------*/ /* i command - generate I/O attention interrupt for device */ /*-------------------------------------------------------------------*/ int i_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; int rc = 0; U16 devnum; U16 lcss; DEVBLK* dev; UNREFERENCED(cmdline); if (argc < 2) { missing_devnum(); return -1; } rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } if (!(dev = find_device_by_devnum (lcss, devnum))) { devnotfound_msg(lcss,devnum); return -1; } rc = device_attention (dev, CSW_ATTN); switch (rc) { case 0: logmsg(_("HHCPN045I Device %4.4X attention request raised\n"), devnum); break; case 1: logmsg(_("HHCPN046E Device %4.4X busy or interrupt pending\n"), devnum); break; case 2: logmsg(_("HHCPN047E Device %4.4X attention request rejected\n"), devnum); break; case 3: logmsg(_("HHCPN048E Device %4.4X subchannel not enabled\n"), devnum); break; } regs = sysblk.regs[sysblk.pcpu]; if (rc == 3 && IS_CPU_ONLINE(sysblk.pcpu) && CPUSTATE_STOPPED == regs->cpustate) logmsg( _("HHCPN049W Are you sure you didn't mean 'ipl %4.4X' " "instead?\n"), devnum ); return rc; } /*-------------------------------------------------------------------*/ /* ext command - generate external interrupt */ /*-------------------------------------------------------------------*/ int ext_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); OBTAIN_INTLOCK(NULL); ON_IC_INTKEY; logmsg( _("HHCPN050I Interrupt key depressed\n") ); /* Signal waiting CPUs that an interrupt is pending */ WAKEUP_CPUS_MASK (sysblk.waiting_mask); RELEASE_INTLOCK(NULL); return 0; } /*-------------------------------------------------------------------*/ /* pgmprdos config command */ /*-------------------------------------------------------------------*/ int pgmprdos_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Parse program product OS allowed */ if (argc > 1) { if (strcasecmp (argv[1], "LICENSED") == 0) { losc_set(PGM_PRD_OS_LICENSED); } /* Handle silly British spelling. */ else if (strcasecmp (argv[1], "LICENCED") == 0) { losc_set(PGM_PRD_OS_LICENSED); } else if (strcasecmp (argv[1], "RESTRICTED") == 0) { losc_set(PGM_PRD_OS_RESTRICTED); } else { logmsg( _("HHCCF028S Invalid program product OS license setting %s\n"), argv[1]); } } else return -1; return 0; } /*-------------------------------------------------------------------*/ /* diag8cmd command */ /*-------------------------------------------------------------------*/ int diag8_cmd(int argc, char *argv[], char *cmdline) { int i; UNREFERENCED(cmdline); /* Parse diag8cmd operand */ if(argc > 1) for(i = 1; i < argc; i++) { if(strcasecmp(argv[i],"echo")==0) sysblk.diag8cmd |= DIAG8CMD_ECHO; else if(strcasecmp(argv[i],"noecho")==0) sysblk.diag8cmd &= ~DIAG8CMD_ECHO; else if(strcasecmp(argv[i],"enable")==0) sysblk.diag8cmd |= DIAG8CMD_ENABLE; else if(strcasecmp(argv[i],"disable")==0) // disable implies no echo sysblk.diag8cmd &= ~(DIAG8CMD_ENABLE | DIAG8CMD_ECHO); else { logmsg(_("HHCCF052S DIAG8CMD invalid option: %s\n"),argv[i]); return -1; } } else logmsg(_("HHCCF054S DIAG8CMD: %sable, %secho\n"), (sysblk.diag8cmd & DIAG8CMD_ENABLE) ? "en" : "dis", (sysblk.diag8cmd & DIAG8CMD_ECHO) ? "" : "no"); return 0; } /*-------------------------------------------------------------------*/ /* shcmdopt command */ /*-------------------------------------------------------------------*/ int shcmdopt_cmd(int argc, char *argv[], char *cmdline) { int i; UNREFERENCED(cmdline); /* Parse SHCMDOPT operand */ if (argc > 1) for(i = 1; i < argc; i++) { if (strcasecmp (argv[i], "enable") == 0) sysblk.shcmdopt &= ~SHCMDOPT_DISABLE; else if (strcasecmp (argv[i], "diag8") == 0) sysblk.shcmdopt &= ~SHCMDOPT_NODIAG8; else if (strcasecmp (argv[i], "disable") == 0) sysblk.shcmdopt |= SHCMDOPT_DISABLE; else if (strcasecmp (argv[i], "nodiag8") == 0) sysblk.shcmdopt |= SHCMDOPT_NODIAG8; else { logmsg(_("HHCCF053I SHCMDOPT invalid option: %s\n"), argv[i]); return -1; } } else logmsg(_("HHCCF053I SCHMDOPT %sabled%s\n"), (sysblk.shcmdopt&SHCMDOPT_DISABLE)?"Dis":"En", (sysblk.shcmdopt&SHCMDOPT_NODIAG8)?" NoDiag8":""); return 0; } /*-------------------------------------------------------------------*/ /* legacysenseid command */ /*-------------------------------------------------------------------*/ int lsid_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Parse Legacy SenseID option */ if (argc > 1) { if(strcasecmp(argv[1],"enable") == 0) sysblk.legacysenseid = 1; else if(strcasecmp(argv[1],"on") == 0) sysblk.legacysenseid = 1; else if(strcasecmp(argv[1],"disable") == 0) sysblk.legacysenseid = 0; else if(strcasecmp(argv[1],"off") == 0) sysblk.legacysenseid = 0; else { logmsg(_("HHCCF110E Legacysenseid invalid option: %s\n"), argv[1]); return -1; } } else logmsg(_("HHCCF111I Legacysenseid %sabled\n"), sysblk.legacysenseid?"En":"Dis"); return 0; } /*-------------------------------------------------------------------*/ /* codepage xxxxxxxx command */ /*-------------------------------------------------------------------*/ int codepage_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Update LPAR name if operand is specified */ if (argc > 1) set_codepage(argv[1]); else { logmsg( _("Usage %s \n"),argv[0]); return -1; } return 0; } #if defined(OPTION_SET_STSI_INFO) /*-------------------------------------------------------------------*/ /* model config statement */ /* operands: hardware_model [capacity_model [perm_model temp_model]] */ /*-------------------------------------------------------------------*/ int stsi_model_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Update model name if operand is specified */ if (argc > 1) set_model(argc, argv[1], argv[2], argv[3], argv[4]); else { logmsg( _("HHCCF113E MODEL: no model code\n")); return -1; } return 0; } /*-------------------------------------------------------------------*/ /* plant config statement */ /*-------------------------------------------------------------------*/ int stsi_plant_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Update model name if operand is specified */ if (argc > 1) set_plant(argv[1]); else { logmsg( _("HHCCF114E PLANT: no plant code\n")); return -1; } return 0; } /*-------------------------------------------------------------------*/ /* manufacturer config statement */ /*-------------------------------------------------------------------*/ int stsi_mfct_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Update model name if operand is specified */ if (argc > 1) set_manufacturer(argv[1]); else { logmsg( _("HHCCF115E MANUFACTURER: no manufacturer code\n")); return -1; } return 0; } #endif /* defined(OPTION_SET_STSI_INFO) */ /*-------------------------------------------------------------------*/ /* lparname - set or display LPAR name */ /*-------------------------------------------------------------------*/ int lparname_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Update LPAR name if operand is specified */ if (argc > 1) set_lparname(argv[1]); else logmsg( _("HHCPN056I LPAR name = %s\n"),str_lparname()); return 0; } /*-------------------------------------------------------------------*/ /* lparnum command - set or display LPAR identification number */ /*-------------------------------------------------------------------*/ int lparnum_cmd(int argc, char *argv[], char *cmdline) { U16 id; BYTE c; UNREFERENCED(cmdline); /* Update LPAR identification number if operand is specified */ if (argc > 1) { if (argv[1] != NULL && strlen(argv[1]) >= 1 && strlen(argv[1]) <= 2 && sscanf(argv[1], "%hx%c", &id, &c) == 1) { sysblk.lparnum = id; sysblk.lparnuml = strlen(argv[1]); } else { logmsg( _("HHCPN058E LPARNUM must be one or two hex digits\n")); return -1; } } else logmsg( _("HHCPN060I LPAR number = %"I16_FMT"X\n"), sysblk.lparnum); return 0; } /*-------------------------------------------------------------------*/ /* loadparm - set or display IPL parameter */ /*-------------------------------------------------------------------*/ int loadparm_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); /* Update IPL parameter if operand is specified */ if (argc > 1) set_loadparm(argv[1]); else logmsg( _("HHCPN051I LOADPARM=%s\n"),str_loadparm()); return 0; } /*-------------------------------------------------------------------*/ /* system reset/system reset clear function */ /*-------------------------------------------------------------------*/ static int reset_cmd(int ac,char *av[],char *cmdline,int clear) { int i; UNREFERENCED(ac); UNREFERENCED(av); UNREFERENCED(cmdline); OBTAIN_INTLOCK(NULL); for (i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i) && sysblk.regs[i]->cpustate != CPUSTATE_STOPPED) { RELEASE_INTLOCK(NULL); logmsg( _("HHCPN053E System reset/clear rejected: All CPU's must be stopped\n") ); return -1; } system_reset (sysblk.pcpu, clear); RELEASE_INTLOCK(NULL); return 0; } /*-------------------------------------------------------------------*/ /* system reset command */ /*-------------------------------------------------------------------*/ int sysr_cmd(int ac,char *av[],char *cmdline) { return(reset_cmd(ac,av,cmdline,0)); } /*-------------------------------------------------------------------*/ /* system reset clear command */ /*-------------------------------------------------------------------*/ int sysc_cmd(int ac,char *av[],char *cmdline) { return(reset_cmd(ac,av,cmdline,1)); } /*-------------------------------------------------------------------*/ /* ipl function */ /*-------------------------------------------------------------------*/ int ipl_cmd2(int argc, char *argv[], char *cmdline, int clear) { BYTE c; /* Character work area */ int rc; /* Return code */ int i; #if defined(OPTION_IPLPARM) int j; size_t maxb; #endif U16 lcss; U16 devnum; char *cdev, *clcss; /* Check that target processor type allows IPL */ if (sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_IFA || sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_SUP) { logmsg(_("HHCPN052E Target CPU %d type %d" " does not allow ipl nor restart\n"), sysblk.pcpu, sysblk.ptyp[sysblk.pcpu]); return -1; } /* Check the parameters of the IPL command */ if (argc < 2) { missing_devnum(); return -1; } #if defined(OPTION_IPLPARM) #define MAXPARMSTRING sizeof(sysblk.iplparmstring) sysblk.haveiplparm=0; maxb=0; if(argc>2) { if(strcasecmp(argv[2],"parm")==0) { memset(sysblk.iplparmstring,0,MAXPARMSTRING); sysblk.haveiplparm=1; for(i=3;icpustate != CPUSTATE_STOPPED) { RELEASE_INTLOCK(NULL); logmsg( _("HHCPN053E ipl rejected: All CPU's must be stopped\n") ); return -1; } /* The ipl device number might be in format lcss:devnum */ if((cdev = strchr(argv[1],':'))) { clcss = argv[1]; cdev++; } else { clcss = NULL; cdev = argv[1]; } /* If the ipl device is not a valid hex number we assume */ /* This is a load from the service processor */ if (sscanf(cdev, "%hx%c", &devnum, &c) != 1) rc = load_hmc(strtok(cmdline+3+clear," \t"), sysblk.pcpu, clear); else { *--cdev = '\0'; if(clcss) { if (sscanf(clcss, "%hd%c", &lcss, &c) != 1) { logmsg( _("HHCPN059E LCSS id %s is invalid\n"), clcss ); return -1; } } else lcss = 0; rc = load_ipl (lcss, devnum, sysblk.pcpu, clear); } RELEASE_INTLOCK(NULL); return rc; } /*-------------------------------------------------------------------*/ /* ipl command */ /*-------------------------------------------------------------------*/ int ipl_cmd(int argc, char *argv[], char *cmdline) { return(ipl_cmd2(argc,argv,cmdline,0)); } /*-------------------------------------------------------------------*/ /* ipl clear command */ /*-------------------------------------------------------------------*/ int iplc_cmd(int argc, char *argv[], char *cmdline) { return(ipl_cmd2(argc,argv,cmdline,1)); } /*-------------------------------------------------------------------*/ /* cpu command - define target cpu for panel display and commands */ /*-------------------------------------------------------------------*/ int cpu_cmd(int argc, char *argv[], char *cmdline) { BYTE c; /* Character work area */ int cpu; UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN054E Missing argument\n") ); return -1; } if (sscanf(argv[1], "%x%c", &cpu, &c) != 1 || cpu < 0 || cpu >= MAX_CPU) { logmsg( _("HHCPN055E Target CPU %s is invalid\n"), argv[1] ); return -1; } sysblk.dummyregs.cpuad = cpu; sysblk.pcpu = cpu; return 0; } static int SortDevBlkPtrsAscendingByDevnum(const void* pDevBlkPtr1, const void* pDevBlkPtr2) { return ((int)((*(DEVBLK**)pDevBlkPtr1)->devnum) - (int)((*(DEVBLK**)pDevBlkPtr2)->devnum)); } /*-------------------------------------------------------------------*/ /* devlist command - list devices */ /*-------------------------------------------------------------------*/ int devlist_cmd(int argc, char *argv[], char *cmdline) { DEVBLK* dev; char* devclass; char devnam[1024]; DEVBLK** pDevBlkPtr; DEVBLK** orig_pDevBlkPtrs; size_t nDevCount, i; int bTooMany = 0; U16 lcss; U16 ssid=0; U16 devnum; int single_devnum = 0; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); if (argc >= 2) { single_devnum = 1; if (parse_single_devnum(argv[1], &lcss, &devnum) < 0) { // (error message already issued) return -1; } if (!(dev = find_device_by_devnum (lcss, devnum))) { devnotfound_msg(lcss, devnum); return -1; } ssid = LCSS_TO_SSID(lcss); } // Since we wish to display the list of devices in ascending device // number order, we build our own private a sorted array of DEVBLK // pointers and use that instead to make the devlist command wholly // immune from the actual order/sequence of the actual DEVBLK chain. // Note too that there is no lock to lock access to ALL device blocks // (even though there really SHOULD be), only one to lock an individual // DEVBLK (which doesn't do us much good here). if (!(orig_pDevBlkPtrs = malloc(sizeof(DEVBLK*) * MAX_DEVLIST_DEVICES))) { logmsg( _("HHCPN146E Work buffer malloc failed: %s\n"), strerror(errno) ); return -1; } nDevCount = 0; pDevBlkPtr = orig_pDevBlkPtrs; for (dev = sysblk.firstdev; dev && nDevCount <= MAX_DEVLIST_DEVICES; dev = dev->nextdev) { if (dev->allocated) // (valid device?) { if (single_devnum && (dev->ssid != ssid || dev->devnum != devnum)) continue; if (nDevCount < MAX_DEVLIST_DEVICES) { *pDevBlkPtr = dev; // (save ptr to DEVBLK) nDevCount++; // (count array entries) pDevBlkPtr++; // (bump to next entry) if (single_devnum) break; } else { bTooMany = 1; // (no more room) break; // (no more room) } } } ASSERT(nDevCount <= MAX_DEVLIST_DEVICES); // (sanity check) // Sort the DEVBLK pointers into ascending sequence by device number. qsort(orig_pDevBlkPtrs, nDevCount, sizeof(DEVBLK*), SortDevBlkPtrsAscendingByDevnum); // Now use our sorted array of DEVBLK pointers // to display our sorted list of devices... for (i = nDevCount, pDevBlkPtr = orig_pDevBlkPtrs; i; --i, pDevBlkPtr++) { dev = *pDevBlkPtr; // --> DEVBLK /* Call device handler's query definition function */ #if defined(OPTION_SCSI_TAPE) if (TAPEDEVT_SCSITAPE == dev->tapedevt) try_scsi_refresh( dev ); // (see comments in function) #endif dev->hnd->query( dev, &devclass, sizeof(devnam), devnam ); /* Display the device definition and status */ logmsg( "%d:%4.4X %4.4X %s %s%s%s\n", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->devtype, devnam, (dev->fd > 2 ? _("open ") : ""), (dev->busy ? _("busy ") : ""), (IOPENDING(dev) ? _("pending ") : "") ); if (dev->bs) { char *clientip, *clientname; get_connected_client(dev,&clientip,&clientname); if (clientip) { logmsg( _(" (client %s (%s) connected)\n"), clientip, clientname ); } else { logmsg( _(" (no one currently connected)\n") ); } if (clientip) free(clientip); if (clientname) free(clientname); } } free ( orig_pDevBlkPtrs ); if (bTooMany) { logmsg( _("HHCPN147W Warning: not all devices shown (max %d)\n"), MAX_DEVLIST_DEVICES); return -1; // (treat as error) } return 0; } /*-------------------------------------------------------------------*/ /* qd command - query dasd */ /*-------------------------------------------------------------------*/ int qd_cmd(int argc, char *argv[], char *cmdline) { DEVBLK* dev; DEVBLK** pDevBlkPtr; DEVBLK** orig_pDevBlkPtrs; size_t nDevCount, i, j, num; int bTooMany = 0; U16 lcss; U16 ssid=0; U16 devnum; int single_devnum = 0; BYTE iobuf[256]; BYTE cbuf[17]; UNREFERENCED(cmdline); if (argc >= 2) { single_devnum = 1; if (parse_single_devnum(argv[1], &lcss, &devnum) < 0) return -1; if (!(dev = find_device_by_devnum (lcss, devnum))) { devnotfound_msg(lcss, devnum); return -1; } ssid = LCSS_TO_SSID(lcss); } if (!(orig_pDevBlkPtrs = malloc(sizeof(DEVBLK*) * MAX_DEVLIST_DEVICES))) { logmsg( _("HHCPN146E Work buffer malloc failed: %s\n"), strerror(errno) ); return -1; } nDevCount = 0; pDevBlkPtr = orig_pDevBlkPtrs; for (dev = sysblk.firstdev; dev && nDevCount <= MAX_DEVLIST_DEVICES; dev = dev->nextdev) { if (dev->allocated) // (valid device?) { if (single_devnum && (dev->ssid != ssid || dev->devnum != devnum)) continue; if (!dev->ckdcyls) continue; if (nDevCount < MAX_DEVLIST_DEVICES) { *pDevBlkPtr = dev; // (save ptr to DEVBLK) nDevCount++; // (count array entries) pDevBlkPtr++; // (bump to next entry) if (single_devnum) break; } else { bTooMany = 1; // (no more room) break; // (no more room) } } } // Sort the DEVBLK pointers into ascending sequence by device number. qsort(orig_pDevBlkPtrs, nDevCount, sizeof(DEVBLK*), SortDevBlkPtrsAscendingByDevnum); // Now use our sorted array of DEVBLK pointers // to display our sorted list of devices... for (i = nDevCount, pDevBlkPtr = orig_pDevBlkPtrs; i; --i, pDevBlkPtr++) { dev = *pDevBlkPtr; // --> DEVBLK /* Display sense-id */ for (j = 0; j < dev->numdevid; j++) { if (j == 0) logmsg("%d:%4.4x SNSID 00 ", SSID_TO_LCSS(dev->ssid), dev->devnum); else if (j%16 == 0) logmsg("\n %2.2x ", j); if (j%4 == 0) logmsg(" "); logmsg("%2.2x", dev->devid[j]); } logmsg("\n"); /* Display device characteristics */ for (j = 0; j < dev->numdevchar; j++) { if (j == 0) logmsg("%d:%4.4x RDC 00 ", SSID_TO_LCSS(dev->ssid), dev->devnum); else if (j%16 == 0) logmsg("\n %2.2x ", j); if (j%4 == 0) logmsg(" "); logmsg("%2.2x", dev->devchar[j]); } logmsg("\n"); /* Display configuration data */ dasd_build_ckd_config_data (dev, iobuf, 256); cbuf[16]=0; for (j = 0; j < 256; j++) { if (j == 0) logmsg("%4.4x RCD 00 ",dev->devnum); else if (j%16 == 0) logmsg(" |%s|\n %2.2x ", cbuf, j); if (j%4 == 0) logmsg(" "); logmsg("%2.2x", iobuf[j]); cbuf[j%16] = isprint(guest_to_host(iobuf[j])) ? guest_to_host(iobuf[j]) : '.'; } logmsg(" |%s|\n", cbuf); /* Display subsystem status */ num = dasd_build_ckd_subsys_status(dev, iobuf, 44); for (j = 0; j < num; j++) { if (j == 0) logmsg("%4.4x SNSS 00 ",dev->devnum); else if (j%16 == 0) logmsg("\n %2.2x ", j); if (j%4 == 0) logmsg(" "); logmsg("%2.2x", iobuf[j]); } logmsg("\n"); } free ( orig_pDevBlkPtrs ); if (bTooMany) { logmsg( _("HHCPN147W Warning: not all devices shown (max %d)\n"), MAX_DEVLIST_DEVICES); return -1; // (treat as error) } return 0; #undef myssid #undef CONFIG_DATA_SIZE } /*-------------------------------------------------------------------*/ /* attach command - configure a device */ /*-------------------------------------------------------------------*/ int attach_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc < 3) { logmsg( _("HHCPN057E Missing argument(s)\n") ); return -1; } return parse_and_attach_devices(argv[1],argv[2],argc-3,&argv[3]); #if 0 if((cdev = strchr(argv[1],':'))) { clcss = argv[1]; *cdev++ = '\0'; } else { clcss = NULL; cdev = argv[1]; } if (sscanf(cdev, "%hx%c", &devnum, &c) != 1) { logmsg( _("HHCPN059E Device number %s is invalid\n"), cdev ); return -1; } if(clcss) { if (sscanf(clcss, "%hd%c", &lcss, &c) != 1) { logmsg( _("HHCPN059E LCSS id %s is invalid\n"), clcss ); return -1; } } else lcss = 0; #if 0 /* JAP - Breaks the whole idea behind devtype.c */ if (sscanf(argv[2], "%hx%c", &dummy_devtype, &c) != 1) { logmsg( _("Device type %s is invalid\n"), argv[2] ); return -1; } #endif return attach_device (lcss, devnum, argv[2], argc-3, &argv[3]); #endif } /*-------------------------------------------------------------------*/ /* detach command - remove device */ /*-------------------------------------------------------------------*/ int detach_cmd(int argc, char *argv[], char *cmdline) { U16 devnum; U16 lcss; int rc; UNREFERENCED(cmdline); if (argc < 2) { missing_devnum(); return -1; } rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } return detach_device (lcss, devnum); } /*-------------------------------------------------------------------*/ /* define command - rename a device */ /*-------------------------------------------------------------------*/ int define_cmd(int argc, char *argv[], char *cmdline) { U16 devnum, newdevn; U16 lcss,newlcss; int rc; UNREFERENCED(cmdline); if (argc < 3) { logmsg( _("HHCPN062E Missing argument(s)\n") ); return -1; } rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } rc=parse_single_devnum(argv[2],&newlcss,&newdevn); if (rc<0) { return -1; } if(lcss!=newlcss) { logmsg(_("HHCPN182E Device numbers can only be redefined within the same Logical channel subsystem\n")); return -1; } return define_device (lcss, devnum, newdevn); } /*-------------------------------------------------------------------*/ /* pgmtrace command - trace program interrupts */ /*-------------------------------------------------------------------*/ int pgmtrace_cmd(int argc, char *argv[], char *cmdline) { int abs_rupt_num, rupt_num; BYTE c; /* Character work area */ UNREFERENCED(cmdline); if (argc < 2) { if (sysblk.pgminttr == 0xFFFFFFFFFFFFFFFFULL) logmsg("pgmtrace == all\n"); else if (sysblk.pgminttr == 0) logmsg("pgmtrace == none\n"); else { char flags[64+1]; int i; for (i=0; i < 64; i++) flags[i] = (sysblk.pgminttr & (1ULL << i)) ? ' ' : '*'; flags[64] = 0; logmsg ( " * = Tracing suppressed; otherwise tracing enabled\n" " 0000000000000001111111111111111222222222222222233333333333333334\n" " 123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0\n" " %s\n" ,flags ); } return 0; } if (sscanf(argv[1], "%x%c", &rupt_num, &c) != 1) { logmsg( _("HHCPN066E Program interrupt number %s is invalid\n"), argv[1] ); return -1; } if ((abs_rupt_num = abs(rupt_num)) < 1 || abs_rupt_num > 0x40) { logmsg( _("HHCPN067E Program interrupt number out of range (%4.4X)\n"), abs_rupt_num ); return -1; } /* Add to, or remove interruption code from mask */ if (rupt_num < 0) sysblk.pgminttr &= ~((U64)1 << (abs_rupt_num - 1)); else sysblk.pgminttr |= ((U64)1 << (abs_rupt_num - 1)); return 0; } /*-------------------------------------------------------------------*/ /* ostailor command - trace program interrupts */ /*-------------------------------------------------------------------*/ int ostailor_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc < 2) { char* sostailor = "(custom)"; if (sysblk.pgminttr == OS_OS390 ) sostailor = "OS/390"; if (sysblk.pgminttr == OS_ZOS ) sostailor = "z/OS"; if (sysblk.pgminttr == OS_VSE ) sostailor = "VSE"; if (sysblk.pgminttr == OS_VM ) sostailor = "VM"; if (sysblk.pgminttr == OS_LINUX ) sostailor = "LINUX"; if (sysblk.pgminttr == OS_OPENSOLARIS ) sostailor = "OpenSolaris"; if (sysblk.pgminttr == 0xFFFFFFFFFFFFFFFFULL) sostailor = "NULL"; if (sysblk.pgminttr == 0 ) sostailor = "QUIET"; logmsg( _("OSTAILOR %s\n"),sostailor); return 0; } if (strcasecmp (argv[1], "OS/390") == 0) { sysblk.pgminttr = OS_OS390; return 0; } if (strcasecmp (argv[1], "+OS/390") == 0) { sysblk.pgminttr &= OS_OS390; return 0; } if (strcasecmp (argv[1], "-OS/390") == 0) { sysblk.pgminttr |= ~OS_OS390; return 0; } if (strcasecmp (argv[1], "Z/OS") == 0) { sysblk.pgminttr = OS_ZOS; return 0; } if (strcasecmp (argv[1], "+Z/OS") == 0) { sysblk.pgminttr &= OS_ZOS; return 0; } if (strcasecmp (argv[1], "-Z/OS") == 0) { sysblk.pgminttr |= ~OS_ZOS; return 0; } if (strcasecmp (argv[1], "VSE") == 0) { sysblk.pgminttr = OS_VSE; return 0; } if (strcasecmp (argv[1], "+VSE") == 0) { sysblk.pgminttr &= OS_VSE; return 0; } if (strcasecmp (argv[1], "-VSE") == 0) { sysblk.pgminttr |= ~OS_VSE; return 0; } if (strcasecmp (argv[1], "VM") == 0) { sysblk.pgminttr = OS_VM; return 0; } if (strcasecmp (argv[1], "+VM") == 0) { sysblk.pgminttr &= OS_VM; return 0; } if (strcasecmp (argv[1], "-VM") == 0) { sysblk.pgminttr |= ~OS_VM; return 0; } if (strcasecmp (argv[1], "LINUX") == 0) { sysblk.pgminttr = OS_LINUX; return 0; } if (strcasecmp (argv[1], "+LINUX") == 0) { sysblk.pgminttr &= OS_LINUX; return 0; } if (strcasecmp (argv[1], "-LINUX") == 0) { sysblk.pgminttr |= ~OS_LINUX; return 0; } if (strcasecmp (argv[1], "OpenSolaris") == 0) { sysblk.pgminttr = OS_OPENSOLARIS; return 0; } if (strcasecmp (argv[1], "+OpenSolaris") == 0) { sysblk.pgminttr &= OS_OPENSOLARIS; return 0; } if (strcasecmp (argv[1], "-OpenSolaris") == 0) { sysblk.pgminttr |= ~OS_OPENSOLARIS; return 0; } if (strcasecmp (argv[1], "NULL") == 0) { sysblk.pgminttr = 0xFFFFFFFFFFFFFFFFULL; return 0; } if (strcasecmp (argv[1], "QUIET") == 0) { sysblk.pgminttr = 0; return 0; } logmsg( _("Unknown OS tailor specification %s\n"), argv[1] ); return -1; } /*-------------------------------------------------------------------*/ /* k command - print out cckd internal trace */ /*-------------------------------------------------------------------*/ int k_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); cckd_print_itrace (); return 0; } /*-------------------------------------------------------------------*/ /* ds - display subchannel */ /*-------------------------------------------------------------------*/ int ds_cmd(int argc, char *argv[], char *cmdline) { DEVBLK* dev; U16 devnum; U16 lcss; int rc; UNREFERENCED(cmdline); if (argc < 2) { missing_devnum(); return -1; } rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } if (!(dev = find_device_by_devnum (lcss,devnum))) { devnotfound_msg(lcss,devnum); return -1; } display_subchannel (dev); return 0; } /*-------------------------------------------------------------------*/ /* syncio command - list syncio devices statistics */ /*-------------------------------------------------------------------*/ int syncio_cmd(int argc, char *argv[], char *cmdline) { DEVBLK* dev; U64 syncios = 0, asyncios = 0; int found = 0; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { if (!dev->syncio) continue; found = 1; logmsg( _("HHCPN072I %4.4X synchronous: %12" I64_FMT "d " "asynchronous: %12" I64_FMT "d\n"), dev->devnum, (long long)dev->syncios, (long long)dev->asyncios ); syncios += dev->syncios; asyncios += dev->asyncios; } if (!found) logmsg( _("HHCPN073I No synchronous I/O devices found\n") ); else logmsg( _("HHCPN074I TOTAL synchronous: %12" I64_FMT "d " "asynchronous: %12" I64_FMT "d %3" I64_FMT "d%%\n"), (long long)syncios, (long long)asyncios, (long long)((syncios * 100) / (syncios + asyncios + 1)) ); return 0; } #if !defined(OPTION_FISHIO) void *device_thread(void *arg); #endif /* !defined(OPTION_FISHIO) */ /*-------------------------------------------------------------------*/ /* devtmax command - display or set max device threads */ /*-------------------------------------------------------------------*/ int devtmax_cmd(int argc, char *argv[], char *cmdline) { int devtmax = -2; #if defined(OPTION_FISHIO) UNREFERENCED(cmdline); /* Note: no need to lock scheduler vars since WE are * the only one that updates "ios_devtmax" (the scheduler * just references it) and we only display (but not update) * all the other variables. */ if (argc > 1) { sscanf(argv[1], "%d", &devtmax); if (devtmax >= -1) ios_devtmax = devtmax; else { logmsg( _("HHCPN075E Invalid max device threads value " "(must be -1 to n)\n") ); return -1; } TrimDeviceThreads(); /* (enforce newly defined threshold) */ } else logmsg( _("HHCPN076I Max device threads: %d, current: %d, most: %d, " "waiting: %d, max exceeded: %d\n"), ios_devtmax, ios_devtnbr, ios_devthwm, (int)ios_devtwait, ios_devtunavail ); #else /* !defined(OPTION_FISHIO) */ TID tid; UNREFERENCED(cmdline); if (argc > 1) { sscanf(argv[1], "%d", &devtmax); if (devtmax >= -1) sysblk.devtmax = devtmax; else { logmsg( _("HHCPN077E Invalid max device threads value " "(must be -1 to n)\n") ); return -1; } /* Create a new device thread if the I/O queue is not NULL and more threads can be created */ /* the IOQ lock is obtained in order to write to sysblk.devtwait */ obtain_lock(&sysblk.ioqlock); if (sysblk.ioq && (!sysblk.devtmax || sysblk.devtnbr < sysblk.devtmax)) create_thread(&tid, DETACHED, device_thread, NULL, "idle device thread"); /* Wakeup threads in case they need to terminate */ sysblk.devtwait=0; broadcast_condition (&sysblk.ioqcond); release_lock(&sysblk.ioqlock); } else logmsg( _("HHCPN078E Max device threads %d current %d most %d " "waiting %d total I/Os queued %d\n"), sysblk.devtmax, sysblk.devtnbr, sysblk.devthwm, sysblk.devtwait, sysblk.devtunavail ); #endif /* defined(OPTION_FISHIO) */ return 0; } /*-------------------------------------------------------------------*/ /* sf commands - shadow file add/remove/set/compress/display */ /*-------------------------------------------------------------------*/ int ShadowFile_cmd(int argc, char *argv[], char *cmdline) { char action; /* Action character `+-cd' */ char *devascii; /* -> Device name */ DEVBLK *dev; /* -> Device block */ U16 devnum; /* Device number */ U16 lcss; /* Logical CSS */ int flag = 1; /* sf- flag (default merge) */ int level = 2; /* sfk level (default 2) */ TID tid; /* sf command thread id */ char c; /* work for sscan */ UNREFERENCED(cmdline); if (strlen(argv[0]) < 3 || strchr ("+-cdk", argv[0][2]) == NULL) { logmsg( _("HHCPN091E Command must be 'sf+', 'sf-', " "'sfc', 'sfk' or 'sfd'\n") ); return -1; } action = argv[0][2]; /* * device name either follows the action character or is the * next operand */ if (strlen(argv[0]) > 3) devascii = argv[0] + 3; else { argv++; argc--; if (argc <= 0 || (devascii = argv[0]) == NULL) { missing_devnum(); return -1; } } /* device name can be `*' meaning all cckd devices */ if (strcmp (devascii, "*") == 0) { for (dev=sysblk.firstdev; dev && !dev->cckd_ext; dev=dev->nextdev); /* nothing */ if (!dev) { logmsg( _("HHCPN081E No cckd devices found\n") ); return -1; } dev = NULL; } else { if (parse_single_devnum(devascii,&lcss,&devnum) < 0) return -1; if ((dev = find_device_by_devnum (lcss,devnum)) == NULL) return devnotfound_msg(lcss,devnum); if (dev->cckd_ext == NULL) { logmsg( _("HHCPN084E Device number %d:%4.4X " "is not a cckd device\n"), lcss, devnum ); return -1; } } /* For `sf-' the operand can be `nomerge', `merge' or `force' */ if (action == '-' && argc > 1) { if (strcmp(argv[1], "nomerge") == 0) flag = 0; else if (strcmp(argv[1], "merge") == 0) flag = 1; else if (strcmp(argv[1], "force") == 0) flag = 2; else { logmsg( _("HHCPN087E Operand must be " "`merge', `nomerge' or `force'\n") ); return -1; } argv++; argc--; } /* For `sfk' the operand is an integer -1 .. 4 */ if (action == 'k' && argc > 1) { if (sscanf(argv[1], "%d%c", &level, &c) != 1 || level < -1 || level > 4) { logmsg( _("HHCPN087E Operand must be a number -1 .. 4\n")); return -1; } argv++; argc--; } /* No other operands allowed */ if (argc > 1) { logmsg( _("HHCPN089E Unexpected operand: %s\n"), argv[1] ); return -1; } /* Set sf- flags in either cckdblk or the cckd extension */ if (action == '-') { if (dev) { CCKDDASD_EXT *cckd = dev->cckd_ext; cckd->sfmerge = flag == 1; cckd->sfforce = flag == 2; } else { cckdblk.sfmerge = flag == 1; cckdblk.sfforce = flag == 2; } } /* Set sfk level in either cckdblk or the cckd extension */ else if (action == 'k') { if (dev) { CCKDDASD_EXT *cckd = dev->cckd_ext; cckd->sflevel = level; } else cckdblk.sflevel = level; } /* Process the command */ switch (action) { case '+': if (create_thread(&tid, DETACHED, cckd_sf_add, dev, "sf+ command")) cckd_sf_add(dev); break; case '-': if (create_thread(&tid, DETACHED, cckd_sf_remove, dev, "sf- command")) cckd_sf_remove(dev); break; case 'c': if (create_thread(&tid, DETACHED, cckd_sf_comp, dev, "sfc command")) cckd_sf_comp(dev); break; case 'd': if (create_thread(&tid, DETACHED, cckd_sf_stats, dev, "sfd command")) cckd_sf_stats(dev); break; case 'k': if (create_thread(&tid, DETACHED, cckd_sf_chk, dev, "sfk command")) cckd_sf_chk(dev); break; } return 0; } /*-------------------------------------------------------------------*/ /* mounted_tape_reinit statement */ /*-------------------------------------------------------------------*/ int mnttapri_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if(argc > 1) { if ( !strcasecmp( argv[1], "disallow" ) ) sysblk.nomountedtapereinit = 1; else if ( !strcasecmp( argv[1], "allow" ) ) sysblk.nomountedtapereinit = 0; else { logmsg( _("HHCCF052S %s: %s invalid argument\n"),argv[0],argv[1]); return -1; } } else logmsg( _("Tape mount reinit %sallowed\n"),sysblk.nomountedtapereinit?"dis":""); return 0; } #if defined( OPTION_SCSI_TAPE ) /*-------------------------------------------------------------------*/ /* auto_scsi_mount statement */ /*-------------------------------------------------------------------*/ int ascsimnt_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if(argc > 1) { if ( !strcasecmp( argv[1], "no" ) ) sysblk.auto_scsi_mount_secs = 0; else if ( !strcasecmp( argv[1], "yes" ) ) sysblk.auto_scsi_mount_secs = DEFAULT_AUTO_SCSI_MOUNT_SECS; else { int secs; char c; if ( sscanf( argv[1], "%d%c", &secs, &c ) != 1 || secs <= 0 || secs > 99 ) { logmsg( _("HHCCF052S %s: %s invalid argument\n"),argv[0],argv[1]); return -1; } else sysblk.auto_scsi_mount_secs = secs; } } else logmsg( _("Auto SCSI mount %d seconds\n"),sysblk.auto_scsi_mount_secs); return 0; } #endif /*defined( OPTION_SCSI_TAPE )*/ /*-------------------------------------------------------------------*/ /* devinit command - assign/open a file for a configured device */ /*-------------------------------------------------------------------*/ int devinit_cmd(int argc, char *argv[], char *cmdline) { DEVBLK* dev; U16 devnum; U16 lcss; int i, rc; int init_argc; char **init_argv; UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN093E Missing argument(s)\n") ); return -1; } rc=parse_single_devnum(argv[1],&lcss,&devnum); if (rc<0) { return -1; } if (!(dev = find_device_by_devnum (lcss, devnum))) { devnotfound_msg(lcss,devnum); return -1; } /* Obtain the device lock */ obtain_lock (&dev->lock); /* Reject if device is busy or interrupt pending */ if (dev->busy || IOPENDING(dev) || (dev->scsw.flag3 & SCSW3_SC_PEND)) { release_lock (&dev->lock); logmsg( _("HHCPN096E Device %d:%4.4X busy or interrupt pending\n"), lcss, devnum ); return -1; } /* Close the existing file, if any */ if (dev->fd < 0 || dev->fd > 2) { (dev->hnd->close)(dev); } /* Build the device initialization arguments array */ if (argc > 2) { /* Use the specified new arguments */ init_argc = argc-2; init_argv = &argv[2]; } else { /* Use the same arguments as originally used */ init_argc = dev->argc; if (init_argc) { init_argv = malloc ( init_argc * sizeof(char*) ); for (i = 0; i < init_argc; i++) if (dev->argv[i]) init_argv[i] = strdup(dev->argv[i]); else init_argv[i] = NULL; } else init_argv = NULL; } /* Call the device init routine to do the hard work */ if ((rc = (dev->hnd->init)(dev, init_argc, init_argv)) < 0) { logmsg( _("HHCPN097E Initialization failed for device %d:%4.4X\n"), lcss, devnum ); } else { logmsg( _("HHCPN098I Device %d:%4.4X initialized\n"), lcss, devnum ); } /* Save arguments for next time */ if (rc == 0) { for (i = 0; i < dev->argc; i++) if (dev->argv[i]) free(dev->argv[i]); if (dev->argv) free(dev->argv); dev->argc = init_argc; if (init_argc) { dev->argv = malloc ( init_argc * sizeof(char*) ); for (i = 0; i < init_argc; i++) if (init_argv[i]) dev->argv[i] = strdup(init_argv[i]); else dev->argv[i] = NULL; } else dev->argv = NULL; } /* Release the device lock */ release_lock (&dev->lock); /* Raise unsolicited device end interrupt for the device */ if (rc == 0) rc = device_attention (dev, CSW_DE); return rc; } /*-------------------------------------------------------------------*/ /* savecore filename command - save a core image to file */ /*-------------------------------------------------------------------*/ int savecore_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; char *fname; /* -> File name (ASCIIZ) */ char *loadaddr; /* loadcore memory address */ U32 aaddr; /* Absolute storage address */ U32 aaddr2; /* Absolute storage address */ int fd; /* File descriptor */ int len; /* Number of bytes read */ BYTE c; /* (dummy sscanf work area) */ char pathname[MAX_PATH]; /* fname in host path format */ UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN099E savecore rejected: filename missing\n") ); return -1; } fname = argv[1]; obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; if (argc < 3 || '*' == *(loadaddr = argv[2])) { for (aaddr = 0; aaddr < sysblk.mainsize && !(STORAGE_KEY(aaddr, regs) & STORKEY_CHANGE); aaddr += 4096) { ; /* (nop) */ } if (aaddr >= sysblk.mainsize) aaddr = 0; else aaddr &= ~0xFFF; } else if (sscanf(loadaddr, "%x%c", &aaddr, &c) !=1 || aaddr >= sysblk.mainsize ) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN100E savecore: invalid starting address: %s \n"), loadaddr ); return -1; } if (argc < 4 || '*' == *(loadaddr = argv[3])) { for (aaddr2 = sysblk.mainsize - 4096; aaddr2 > 0 && !(STORAGE_KEY(aaddr2, regs) & STORKEY_CHANGE); aaddr2 -= 4096) { ; /* (nop) */ } if ( STORAGE_KEY(aaddr2, regs) & STORKEY_CHANGE ) aaddr2 |= 0xFFF; else { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN148E savecore: no modified storage found\n") ); return -1; } } else if (sscanf(loadaddr, "%x%c", &aaddr2, &c) !=1 || aaddr2 >= sysblk.mainsize ) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN101E savecore: invalid ending address: %s \n"), loadaddr ); return -1; } /* Command is valid only when CPU is stopped */ if (CPUSTATE_STOPPED != regs->cpustate) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN102E savecore rejected: CPU not stopped\n") ); return -1; } if (aaddr > aaddr2) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN103E invalid range: %8.8X-%8.8X\n"), aaddr, aaddr2 ); return -1; } /* Save the file from absolute storage */ logmsg( _("HHCPN104I Saving locations %8.8X-%8.8X to %s\n"), aaddr, aaddr2, fname ); hostpath(pathname, fname, sizeof(pathname)); if ((fd = hopen(pathname, O_CREAT|O_WRONLY|O_EXCL|O_BINARY, S_IREAD|S_IWRITE|S_IRGRP)) < 0) { int saved_errno = errno; release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN105E savecore error creating %s: %s\n"), fname, strerror(saved_errno) ); return -1; } if ((len = write(fd, regs->mainstor + aaddr, (aaddr2 - aaddr) + 1)) < 0) logmsg( _("HHCPN106E savecore error writing to %s: %s\n"), fname, strerror(errno) ); else if((U32)len < (aaddr2 - aaddr) + 1) logmsg( _("HHCPN107E savecore: unable to save %d bytes\n"), ((aaddr2 - aaddr) + 1) - len ); close(fd); release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN170I savecore command complete.\n")); return 0; } /*-------------------------------------------------------------------*/ /* loadcore filename command - load a core image file */ /*-------------------------------------------------------------------*/ int loadcore_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; char *fname; /* -> File name (ASCIIZ) */ struct stat statbuff; /* Buffer for file status */ char *loadaddr; /* loadcore memory address */ U32 aaddr; /* Absolute storage address */ int len; /* Number of bytes read */ char pathname[MAX_PATH]; /* file in host path format */ UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN108E loadcore rejected: filename missing\n") ); return -1; } fname = argv[1]; hostpath(pathname, fname, sizeof(pathname)); if (stat(pathname, &statbuff) < 0) { logmsg( _("HHCPN109E Cannot open %s: %s\n"), fname, strerror(errno)); return -1; } if (argc < 3) aaddr = 0; else { loadaddr = argv[2]; if (sscanf(loadaddr, "%x", &aaddr) !=1) { logmsg( _("HHCPN110E invalid address: %s \n"), loadaddr ); return -1; } } obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; /* Command is valid only when CPU is stopped */ if (CPUSTATE_STOPPED != regs->cpustate) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN111E loadcore rejected: CPU not stopped\n") ); return -1; } /* Read the file into absolute storage */ logmsg( _("HHCPN112I Loading %s to location %x \n"), fname, aaddr ); len = load_main(fname, aaddr); release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN113I %d bytes read from %s\n"), len, fname ); return 0; } /*-------------------------------------------------------------------*/ /* loadtext filename command - load a text deck file */ /*-------------------------------------------------------------------*/ int loadtext_cmd(int argc, char *argv[], char *cmdline) { char *fname; /* -> File name (ASCIIZ) */ char *loadaddr; /* loadcore memory address */ U32 aaddr; /* Absolute storage address */ int fd; /* File descriptor */ BYTE buf[80]; /* Read buffer */ int len; /* Number of bytes read */ int n; REGS *regs; char pathname[MAX_PATH]; UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN114E loadtext rejected: filename missing\n") ); return -1; } fname = argv[1]; if (argc < 3) aaddr = 0; else { loadaddr = argv[2]; if (sscanf(loadaddr, "%x", &aaddr) !=1) { logmsg( _("HHCPN115E invalid address: %s \n"), loadaddr ); return -1; } } obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; if (aaddr > regs->mainlim) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN116E Address greater than mainstore size\n") ); return -1; } /* Command is valid only when CPU is stopped */ if (CPUSTATE_STOPPED != regs->cpustate) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN117E loadtext rejected: CPU not stopped\n") ); return -1; } /* Open the specified file name */ hostpath(pathname, fname, sizeof(pathname)); if ((fd = open (pathname, O_RDONLY | O_BINARY)) < 0) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN118E Cannot open %s: %s\n"), fname, strerror(errno)); return -1; } for ( n = 0; ; ) { /* Read 80 bytes into buffer */ if ((len = read (fd, buf, 80)) < 0) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN119E Cannot read %s: %s\n"), fname, strerror(errno)); close (fd); return -1; } /* if record is "END" then break out of loop */ if (0xC5 == buf[1] && 0xD5 == buf[2] && 0xC4 == buf[3]) break; /* if record is "TXT" then copy bytes to mainstore */ if (0xE3 == buf[1] && 0xE7 == buf[2] && 0xE3 == buf[3]) { n = buf[5]*65536 + buf[6]*256 + buf[7]; len = buf[11]; memcpy(regs->mainstor + aaddr + n, &buf[16], len); STORAGE_KEY(aaddr + n, regs) |= (STORKEY_REF | STORKEY_CHANGE); STORAGE_KEY(aaddr + n + len - 1, regs) |= (STORKEY_REF | STORKEY_CHANGE); } } /* Close file and issue status message */ close (fd); logmsg( _("HHCPN120I Finished loading TEXT deck file\n") ); logmsg( _(" Last 'TXT' record had address: %3.3X\n"), n ); release_lock(&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* ipending command - display pending interrupts */ /*-------------------------------------------------------------------*/ int ipending_cmd(int argc, char *argv[], char *cmdline) { DEVBLK *dev; /* -> Device block */ IOINT *io; /* -> I/O interrupt entry */ unsigned i; char sysid[12]; BYTE curpsw[16]; char *states[] = { "?(0)", "STARTED", "STOPPING", "STOPPED" }; UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); for (i = 0; i < MAX_CPU_ENGINES; i++) { if (!IS_CPU_ONLINE(i)) { logmsg(_("HHCPN123I CPU%4.4X: offline\n"), i); continue; } // /*DEBUG*/logmsg( _("CPU%4.4X: Any cpu interrupt %spending\n"), // /*DEBUG*/ sysblk.regs[i]->cpuad, sysblk.regs[i]->cpuint ? "" : _("not ") ); logmsg( _("HHCPN123I CPU%4.4X: CPUint=%8.8X " "(State:%8.8X)&(Mask:%8.8X)\n"), sysblk.regs[i]->cpuad, IC_INTERRUPT_CPU(sysblk.regs[i]), sysblk.regs[i]->ints_state, sysblk.regs[i]->ints_mask ); logmsg( _(" CPU%4.4X: Interrupt %spending\n"), sysblk.regs[i]->cpuad, IS_IC_INTERRUPT(sysblk.regs[i]) ? "" : _("not ") ); logmsg( _(" CPU%4.4X: I/O interrupt %spending\n"), sysblk.regs[i]->cpuad, IS_IC_IOPENDING ? "" : _("not ") ); logmsg( _(" CPU%4.4X: Clock comparator %spending\n"), sysblk.regs[i]->cpuad, IS_IC_CLKC(sysblk.regs[i]) ? "" : _("not ") ); logmsg( _(" CPU%4.4X: CPU timer %spending\n"), sysblk.regs[i]->cpuad, IS_IC_PTIMER(sysblk.regs[i]) ? "" : _("not ") ); #if defined(_FEATURE_INTERVAL_TIMER) logmsg( _(" CPU%4.4X: Interval timer %spending\n"), sysblk.regs[i]->cpuad, IS_IC_ITIMER(sysblk.regs[i]) ? "" : _("not ") ); #if defined(_FEATURE_ECPSVM) logmsg( _(" CPU%4.4X: ECPS vtimer %spending\n"), sysblk.regs[i]->cpuad, IS_IC_ECPSVTIMER(sysblk.regs[i]) ? "" : _("not ") ); #endif /*defined(_FEATURE_ECPSVM)*/ #endif /*defined(_FEATURE_INTERVAL_TIMER)*/ logmsg( _(" CPU%4.4X: External call %spending\n"), sysblk.regs[i]->cpuad, IS_IC_EXTCALL(sysblk.regs[i]) ? "" : _("not ") ); logmsg( _(" CPU%4.4X: Emergency signal %spending\n"), sysblk.regs[i]->cpuad, IS_IC_EMERSIG(sysblk.regs[i]) ? "" : _("not ") ); logmsg( _(" CPU%4.4X: Machine check interrupt %spending\n"), sysblk.regs[i]->cpuad, IS_IC_MCKPENDING(sysblk.regs[i]) ? "" : _("not ") ); logmsg( _(" CPU%4.4X: Service signal %spending\n"), sysblk.regs[i]->cpuad, IS_IC_SERVSIG ? "" : _("not ") ); logmsg( _(" CPU%4.4X: Mainlock held: %s\n"), sysblk.regs[i]->cpuad, sysblk.regs[i]->cpuad == sysblk.mainowner ? _("yes") : _("no") ); logmsg( _(" CPU%4.4X: Intlock held: %s\n"), sysblk.regs[i]->cpuad, sysblk.regs[i]->cpuad == sysblk.intowner ? _("yes") : _("no") ); logmsg( _(" CPU%4.4X: Waiting for intlock: %s\n"), sysblk.regs[i]->cpuad, sysblk.regs[i]->intwait && !(sysblk.waiting_mask & CPU_BIT(i)) ? _("yes") : _("no") ); logmsg( _(" CPU%4.4X: lock %sheld\n"), sysblk.regs[i]->cpuad, test_lock(&sysblk.cpulock[i]) ? "" : _("not ") ); if (ARCH_370 == sysblk.arch_mode) { if (0xFFFF == sysblk.regs[i]->chanset) logmsg( _(" CPU%4.4X: No channelset connected\n"), sysblk.regs[i]->cpuad ); else logmsg( _(" CPU%4.4X: Connected to channelset " "%4.4X\n"), sysblk.regs[i]->cpuad,sysblk.regs[i]->chanset ); } logmsg( _(" CPU%4.4X: state %s\n"), sysblk.regs[i]->cpuad,states[sysblk.regs[i]->cpustate]); logmsg( _(" CPU%4.4X: instcount %" I64_FMT "d\n"), sysblk.regs[i]->cpuad,(long long)INSTCOUNT(sysblk.regs[i])); logmsg( _(" CPU%4.4X: siocount %" I64_FMT "d\n"), sysblk.regs[i]->cpuad,(long long)sysblk.regs[i]->siototal); copy_psw(sysblk.regs[i], curpsw); logmsg( _(" CPU%4.4X: psw %2.2x%2.2x%2.2x%2.2x %2.2x%2.2x%2.2x%2.2x"), sysblk.regs[i]->cpuad,curpsw[0],curpsw[1],curpsw[2],curpsw[3], curpsw[4],curpsw[5],curpsw[6],curpsw[7]); if (ARCH_900 == sysblk.arch_mode) logmsg( _(" %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x"), curpsw[8],curpsw[9],curpsw[10],curpsw[11], curpsw[12],curpsw[13],curpsw[14],curpsw[15]); logmsg("\n"); if (sysblk.regs[i]->sie_active) { logmsg( _("HHCPN123I SIE%4.4X: CPUint=%8.8X " "(State:%8.8X)&(Mask:%8.8X)\n"), sysblk.regs[i]->guestregs->cpuad, IC_INTERRUPT_CPU(sysblk.regs[i]->guestregs), sysblk.regs[i]->guestregs->ints_state, sysblk.regs[i]->guestregs->ints_mask ); logmsg( _(" SIE%4.4X: Interrupt %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_INTERRUPT(sysblk.regs[i]->guestregs) ? "" : _("not ") ); logmsg( _(" SIE%4.4X: I/O interrupt %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_IOPENDING ? "" : _("not ") ); logmsg( _(" SIE%4.4X: Clock comparator %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_CLKC(sysblk.regs[i]->guestregs) ? "" : _("not ") ); logmsg( _(" SIE%4.4X: CPU timer %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_PTIMER(sysblk.regs[i]->guestregs) ? "" : _("not ") ); logmsg( _(" SIE%4.4X: Interval timer %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_ITIMER(sysblk.regs[i]->guestregs) ? "" : _("not ") ); logmsg( _(" SIE%4.4X: External call %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_EXTCALL(sysblk.regs[i]->guestregs) ? "" : _("not ") ); logmsg( _(" SIE%4.4X: Emergency signal %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_EMERSIG(sysblk.regs[i]->guestregs) ? "" : _("not ") ); logmsg( _(" SIE%4.4X: Machine check interrupt %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_MCKPENDING(sysblk.regs[i]->guestregs) ? "" : _("not ") ); logmsg( _(" SIE%4.4X: Service signal %spending\n"), sysblk.regs[i]->guestregs->cpuad, IS_IC_SERVSIG ? "" : _("not ") ); logmsg( _(" SIE%4.4X: lock %sheld\n"), sysblk.regs[i]->guestregs->cpuad, test_lock(&sysblk.cpulock[i]) ? "" : _("not ") ); if (ARCH_370 == sysblk.arch_mode) { if (0xFFFF == sysblk.regs[i]->guestregs->chanset) logmsg( _(" SIE%4.4X: No channelset connected\n"), sysblk.regs[i]->guestregs->cpuad ); else logmsg( _(" SIE%4.4X: Connected to channelset " "%4.4X\n"), sysblk.regs[i]->guestregs->cpuad,sysblk.regs[i]->guestregs->chanset ); } logmsg( _(" SIE%4.4X: state %s\n"), sysblk.regs[i]->guestregs->cpuad,states[sysblk.regs[i]->guestregs->cpustate]); logmsg( _(" SIE%4.4X: instcount %" I64_FMT "d\n"), sysblk.regs[i]->guestregs->cpuad,(long long)sysblk.regs[i]->guestregs->instcount); logmsg( _(" SIE%4.4X: siocount %" I64_FMT "d\n"), sysblk.regs[i]->guestregs->cpuad,(long long)sysblk.regs[i]->guestregs->siototal); copy_psw(sysblk.regs[i]->guestregs, curpsw); logmsg( _(" SIE%4.4X: psw %2.2x%2.2x%2.2x%2.2x %2.2x%2.2x%2.2x%2.2x"), sysblk.regs[i]->guestregs->cpuad,curpsw[0],curpsw[1],curpsw[2],curpsw[3], curpsw[4],curpsw[5],curpsw[6],curpsw[7]); if (ARCH_900 == sysblk.regs[i]->guestregs->arch_mode) logmsg( _(" %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x"), curpsw[8],curpsw[9],curpsw[10],curpsw[11], curpsw[12],curpsw[13],curpsw[14],curpsw[15]); logmsg("\n"); } } logmsg( _(" Config mask "F_CPU_BITMAP " started mask "F_CPU_BITMAP " waiting mask "F_CPU_BITMAP"\n"), sysblk.config_mask, sysblk.started_mask, sysblk.waiting_mask ); logmsg( _(" Syncbc mask "F_CPU_BITMAP" %s\n"), sysblk.sync_mask, sysblk.syncing ? _("Sync in progress") : "" ); logmsg( _(" Signaling facility %sbusy\n"), test_lock(&sysblk.sigplock) ? "" : _("not ") ); logmsg( _(" TOD lock %sheld\n"), test_lock(&sysblk.todlock) ? "" : _("not ") ); logmsg( _(" Mainlock %sheld; owner %4.4x\n"), test_lock(&sysblk.mainlock) ? "" : _("not "), sysblk.mainowner ); logmsg( _(" Intlock %sheld; owner %4.4x\n"), test_lock(&sysblk.intlock) ? "" : _("not "), sysblk.intowner ); #if !defined(OPTION_FISHIO) logmsg( _(" Ioq lock %sheld\n"), test_lock(&sysblk.ioqlock) ? "" : _("not ") ); #endif for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { if (dev->ioactive == DEV_SYS_NONE) strcpy (sysid, "(none)"); else if (dev->ioactive == DEV_SYS_LOCAL) strcpy (sysid, "local"); else sprintf (sysid, "id=%d", dev->ioactive); if (dev->busy && !(dev->suspended && dev->ioactive == DEV_SYS_NONE)) logmsg( _(" DEV %d:%4.4X: busy %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, sysid ); if (dev->reserved) logmsg( _(" DEV %d:%4.4X: reserved %s\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, sysid ); if (dev->suspended) logmsg( _(" DEV %d:%4.4X: suspended\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); if (dev->pending && (dev->pmcw.flag5 & PMCW5_V)) logmsg( _(" DEV %d:%4.4X: I/O pending\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); if (dev->pcipending && (dev->pmcw.flag5 & PMCW5_V)) logmsg( _(" DEV %d:%4.4X: PCI pending\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); if (dev->attnpending && (dev->pmcw.flag5 & PMCW5_V)) logmsg( _(" DEV %d:%4.4X: Attn pending\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); if ((dev->crwpending) && (dev->pmcw.flag5 & PMCW5_V)) logmsg( _(" DEV %d:%4.4X: CRW pending\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); if (test_lock(&dev->lock) && (dev->pmcw.flag5 & PMCW5_V)) logmsg( _(" DEV %d:%4.4X: lock held\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); } logmsg( _(" I/O interrupt queue: ") ); if (!sysblk.iointq) logmsg( _("(NULL)") ); logmsg("\n"); for (io = sysblk.iointq; io; io = io->next) logmsg ( _(" DEV %d:%4.4X,%s%s%s%s, pri %d\n") ,SSID_TO_LCSS(io->dev->ssid) ,io->dev->devnum ,io->pending ? " normal" : "" ,io->pcipending ? " PCI" : "" ,io->attnpending ? " ATTN" : "" ,!IOPENDING(io) ? " unknown" : "" ,io->priority ); return 0; } #if defined(OPTION_INSTRUCTION_COUNTING) /*-------------------------------------------------------------------*/ /* icount command - display instruction counts */ /*-------------------------------------------------------------------*/ int icount_cmd(int argc, char *argv[], char *cmdline) { int i, i1, i2, i3; unsigned char *opcode1; unsigned char *opcode2; U64 *count; U64 total; UNREFERENCED(cmdline); obtain_lock( &sysblk.icount_lock ); if (argc > 1 && !strcasecmp(argv[1], "clear")) { memset(IMAP_FIRST,0,IMAP_SIZE); logmsg( _("HHCPN124I Instruction counts reset to zero.\n") ); release_lock( &sysblk.icount_lock ); return 0; } #define MAX_ICOUNT_INSTR 1000 /* Maximum number of instructions in architecture instruction set */ if(argc > 1 && !strcasecmp(argv[1], "sort")) { /* Allocate space */ if(!(opcode1 = malloc(MAX_ICOUNT_INSTR * sizeof(unsigned char)))) { logmsg("Sorry, not enough memory\n"); release_lock( &sysblk.icount_lock ); return 0; } if(!(opcode2 = malloc(MAX_ICOUNT_INSTR * sizeof(unsigned char)))) { logmsg("Sorry, not enough memory\n"); free(opcode1); release_lock( &sysblk.icount_lock ); return 0; } if(!(count = malloc(MAX_ICOUNT_INSTR * sizeof(U64)))) { logmsg("Sorry, not enough memory\n"); free(opcode1); free(opcode2); release_lock( &sysblk.icount_lock ); return(0); } for(i = 0; i < (MAX_ICOUNT_INSTR-1); i++) { opcode1[i] = 0; opcode2[i] = 0; count[i] = 0; } /* Collect */ i = 0; total = 0; for(i1 = 0; i1 < 256; i1++) { switch(i1) { case 0x01: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imap01[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imap01[i2]; total += sysblk.imap01[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xA4: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imapa4[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapa4[i2]; total += sysblk.imapa4[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xA5: { for(i2 = 0; i2 < 16; i2++) { if(sysblk.imapa5[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapa5[i2]; total += sysblk.imapa5[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xA6: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imapa6[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapa6[i2]; total += sysblk.imapa6[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xA7: { for(i2 = 0; i2 < 16; i2++) { if(sysblk.imapa7[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapa7[i2]; total += sysblk.imapa7[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xB2: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imapb2[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapb2[i2]; total += sysblk.imapb2[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xB3: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imapb3[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapb3[i2]; total += sysblk.imapb3[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xB9: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imapb9[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapb9[i2]; total += sysblk.imapb9[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xC0: { for(i2 = 0; i2 < 16; i2++) { if(sysblk.imapc0[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapc0[i2]; total += sysblk.imapc0[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xC2: { for(i2 = 0; i2 < 16; i2++) { if(sysblk.imapc2[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapc2[i2]; total += sysblk.imapc2[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xC4: { for(i2 = 0; i2 < 16; i2++) { if(sysblk.imapc4[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapc4[i2]; total += sysblk.imapc4[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xC6: { for(i2 = 0; i2 < 16; i2++) { if(sysblk.imapc6[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapc6[i2]; total += sysblk.imapc6[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xC8: { for(i2 = 0; i2 < 16; i2++) { if(sysblk.imapc8[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapc8[i2]; total += sysblk.imapc8[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xE3: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imape3[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imape3[i2]; total += sysblk.imape3[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xE4: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imape4[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imape4[i2]; total += sysblk.imape4[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xE5: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imape5[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imape5[i2]; total += sysblk.imape5[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xEB: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imapeb[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapeb[i2]; total += sysblk.imapeb[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xEC: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imapec[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imapec[i2]; total += sysblk.imapec[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } case 0xED: { for(i2 = 0; i2 < 256; i2++) { if(sysblk.imaped[i2]) { opcode1[i] = i1; opcode2[i] = i2; count[i++] = sysblk.imaped[i2]; total += sysblk.imaped[i2]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } } break; } default: { if(sysblk.imapxx[i1]) { opcode1[i] = i1; opcode2[i] = 0; count[i++] = sysblk.imapxx[i1]; total += sysblk.imapxx[i1]; if(i == (MAX_ICOUNT_INSTR-1)) { logmsg("Sorry, too many instructions\n"); free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } } break; } } } /* Sort */ for(i1 = 0; i1 < i; i1++) { /* Find Highest */ for(i2 = i1, i3 = i1; i2 < i; i2++) { if(count[i2] > count[i3]) i3 = i2; } /* Exchange */ opcode1[(MAX_ICOUNT_INSTR-1)] = opcode1[i1]; opcode2[(MAX_ICOUNT_INSTR-1)] = opcode2[i1]; count [(MAX_ICOUNT_INSTR-1)] = count [i1]; opcode1[i1] = opcode1[i3]; opcode2[i1] = opcode2[i3]; count [i1] = count [i3]; opcode1[i3] = opcode1[(MAX_ICOUNT_INSTR-1)]; opcode2[i3] = opcode2[(MAX_ICOUNT_INSTR-1)]; count [i3] = count [(MAX_ICOUNT_INSTR-1)]; } #define ICOUNT_WIDTH "12" /* Print field width */ /* Print */ logmsg(_("HHCPN125I Sorted instruction count display:\n")); for(i1 = 0; i1 < i; i1++) { switch(opcode1[i1]) { case 0x01: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xA4: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xA5: { logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xA6: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xA7: { logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xB2: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xB3: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xB9: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xC0: { logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xC2: { logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xC4: { logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xC6: { logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xC8: { logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xE3: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xE4: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xE5: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xEB: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xEC: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } case 0xED: { logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], opcode2[i1], count[i1], (int) (count[i1] * 100 / total)); break; } default: { logmsg(" INST=%2.2X \tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\t(%2d%%)\n", opcode1[i1], count[i1], (int) (count[i1] * 100 / total)); break; } } } free(opcode1); free(opcode2); free(count); release_lock( &sysblk.icount_lock ); return 0; } logmsg(_("HHCPN125I Instruction count display:\n")); for (i1 = 0; i1 < 256; i1++) { switch (i1) { case 0x01: for(i2 = 0; i2 < 256; i2++) if(sysblk.imap01[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imap01[i2]); break; case 0xA4: for(i2 = 0; i2 < 256; i2++) if(sysblk.imapa4[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapa4[i2]); break; case 0xA5: for(i2 = 0; i2 < 16; i2++) if(sysblk.imapa5[i2]) logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapa5[i2]); break; case 0xA6: for(i2 = 0; i2 < 256; i2++) if(sysblk.imapa6[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapa6[i2]); break; case 0xA7: for(i2 = 0; i2 < 16; i2++) if(sysblk.imapa7[i2]) logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapa7[i2]); break; case 0xB2: for(i2 = 0; i2 < 256; i2++) if(sysblk.imapb2[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapb2[i2]); break; case 0xB3: for(i2 = 0; i2 < 256; i2++) if(sysblk.imapb3[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapb3[i2]); break; case 0xB9: for(i2 = 0; i2 < 256; i2++) if(sysblk.imapb9[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapb9[i2]); break; case 0xC0: for(i2 = 0; i2 < 16; i2++) if(sysblk.imapc0[i2]) logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapc0[i2]); break; case 0xC2: /*@Z9*/ for(i2 = 0; i2 < 16; i2++) /*@Z9*/ if(sysblk.imapc2[i2]) /*@Z9*/ logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", /*@Z9*/ i1, i2, sysblk.imapc2[i2]); /*@Z9*/ break; /*@Z9*/ case 0xC4: for(i2 = 0; i2 < 16; i2++) if(sysblk.imapc4[i2]) logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapc4[i2]); break; case 0xC6: for(i2 = 0; i2 < 16; i2++) if(sysblk.imapc6[i2]) logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapc6[i2]); break; case 0xC8: for(i2 = 0; i2 < 16; i2++) if(sysblk.imapc8[i2]) logmsg(" INST=%2.2Xx%1.1X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapc8[i2]); break; case 0xE3: for(i2 = 0; i2 < 256; i2++) if(sysblk.imape3[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imape3[i2]); break; case 0xE4: for(i2 = 0; i2 < 256; i2++) if(sysblk.imape4[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imape4[i2]); break; case 0xE5: for(i2 = 0; i2 < 256; i2++) if(sysblk.imape5[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imape5[i2]); break; case 0xEB: for(i2 = 0; i2 < 256; i2++) if(sysblk.imapeb[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapeb[i2]); break; case 0xEC: for(i2 = 0; i2 < 256; i2++) if(sysblk.imapec[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imapec[i2]); break; case 0xED: for(i2 = 0; i2 < 256; i2++) if(sysblk.imaped[i2]) logmsg(" INST=%2.2X%2.2X\tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, i2, sysblk.imaped[i2]); break; default: if(sysblk.imapxx[i1]) logmsg(" INST=%2.2X \tCOUNT=%" ICOUNT_WIDTH I64_FMT "u\n", i1, sysblk.imapxx[i1]); break; } } release_lock( &sysblk.icount_lock ); return 0; } #endif /*defined(OPTION_INSTRUCTION_COUNTING)*/ #if defined(OPTION_CONFIG_SYMBOLS) /*-------------------------------------------------------------------*/ /* defsym command - define substitution symbol */ /*-------------------------------------------------------------------*/ int defsym_cmd(int argc, char *argv[], char *cmdline) { char* sym; char* value; UNREFERENCED(cmdline); if (argc < 2) { list_all_symbols(); return 0; } /* point to symbol name */ sym = argv[1]; if (argc > 3) { logmsg(_("HHCCF060S DEFSYM requires a single value" " (use quotes if necessary)\n")); return -1; } /* point to symbol value if specified, otherwise set to blank */ value = (argc > 2) ? argv[2] : ""; /* define the symbol */ set_symbol(sym,value); return 0; } #endif // defined(OPTION_CONFIG_SYMBOLS) /*-------------------------------------------------------------------*/ /* archmode command - set architecture mode */ /*-------------------------------------------------------------------*/ int archmode_cmd(int argc, char *argv[], char *cmdline) { int i; UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN126I Architecture mode = %s\n"), get_arch_mode_string(NULL) ); return 0; } OBTAIN_INTLOCK(NULL); /* Make sure all CPUs are deconfigured or stopped */ for (i = 0; i < MAX_CPU_ENGINES; i++) if (IS_CPU_ONLINE(i) && CPUSTATE_STOPPED != sysblk.regs[i]->cpustate) { RELEASE_INTLOCK(NULL); logmsg( _("HHCPN127E All CPU's must be stopped to change " "architecture\n") ); return -1; } #if defined(_370) if (!strcasecmp (argv[1], arch_name[ARCH_370])) { sysblk.arch_mode = ARCH_370; sysblk.maxcpu = sysblk.numcpu; } else #endif #if defined(_390) if (!strcasecmp (argv[1], arch_name[ARCH_390])) { sysblk.arch_mode = ARCH_390; #if defined(_FEATURE_CPU_RECONFIG) sysblk.maxcpu = MAX_CPU_ENGINES; #else sysblk.maxcpu = sysblk.numcpu; #endif } else #endif #if defined(_900) if (0 || !strcasecmp (argv[1], arch_name[ARCH_900]) || !strcasecmp (argv[1], "ESAME") ) { sysblk.arch_mode = ARCH_900; #if defined(_FEATURE_CPU_RECONFIG) sysblk.maxcpu = MAX_CPU_ENGINES; #else sysblk.maxcpu = sysblk.numcpu; #endif } else #endif { RELEASE_INTLOCK(NULL); logmsg( _("HHCPN128E Invalid architecture mode %s\n"), argv[1] ); return -1; } if (sysblk.pcpu >= MAX_CPU) sysblk.pcpu = 0; sysblk.dummyregs.arch_mode = sysblk.arch_mode; #if defined(OPTION_FISHIO) ios_arch_mode = sysblk.arch_mode; #endif /* defined(OPTION_FISHIO) */ /* Indicate if z/Architecture is supported */ sysblk.arch_z900 = sysblk.arch_mode != ARCH_390; #if defined(_FEATURE_CPU_RECONFIG) && defined(_S370) /* Configure CPUs for S/370 mode */ if (sysblk.archmode == ARCH_370) for (i = MAX_CPU_ENGINES - 1; i >= 0; i--) if (i < MAX_CPU && !IS_CPU_ONLINE(i)) configure_cpu(i); else if (i >= MAX_CPU && IS_CPU_ONLINE(i)) deconfigure_cpu(i); #endif RELEASE_INTLOCK(NULL); return 0; } /*-------------------------------------------------------------------*/ /* x+ and x- commands - turn switches on or off */ /*-------------------------------------------------------------------*/ int OnOffCommand(int argc, char *argv[], char *cmdline) { char *cmd = cmdline; /* Copy of panel command */ int oneorzero; /* 1=x+ command, 0=x- */ char *onoroff; /* "on" or "off" */ U32 aaddr; /* Absolute storage address */ DEVBLK* dev; U16 devnum; U16 lcss; REGS *regs; BYTE c; /* Character work area */ UNREFERENCED(argc); UNREFERENCED(argv); if (cmd[1] == '+') { oneorzero = 1; onoroff = _("on"); } else { oneorzero = 0; onoroff = _("off"); } OBTAIN_INTLOCK(NULL); if (!IS_CPU_ONLINE(sysblk.pcpu)) { RELEASE_INTLOCK(NULL); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs=sysblk.regs[sysblk.pcpu]; // f- and f+ commands - mark frames unusable/usable if ((cmd[0] == 'f') && sscanf(cmd+2, "%x%c", &aaddr, &c) == 1) { if (aaddr > regs->mainlim) { RELEASE_INTLOCK(NULL); logmsg( _("HHCPN130E Invalid frame address %8.8X\n"), aaddr ); return -1; } STORAGE_KEY(aaddr, regs) &= ~(STORKEY_BADFRM); if (!oneorzero) STORAGE_KEY(aaddr, regs) |= STORKEY_BADFRM; RELEASE_INTLOCK(NULL); logmsg( _("HHCPN131I Frame %8.8X marked %s\n"), aaddr, oneorzero ? _("usable") : _("unusable") ); return 0; } #ifdef OPTION_CKD_KEY_TRACING // t+ckd and t-ckd commands - turn CKD_KEY tracing on/off if ((cmd[0] == 't') && (strcasecmp(cmd+2, "ckd") == 0)) { for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) { if (dev->devchar[10] == 0x20) dev->ckdkeytrace = oneorzero; } RELEASE_INTLOCK(NULL); logmsg( _("HHCPN134I CKD KEY trace is now %s\n"), onoroff ); return 0; } #endif // t+devn and t-devn commands - turn CCW tracing on/off // s+devn and s-devn commands - turn CCW stepping on/off if ((cmd[0] == 't' || cmd[0] == 's') && parse_single_devnum_silent(&cmd[2],&lcss,&devnum)==0 ) { dev = find_device_by_devnum (lcss, devnum); if (dev == NULL) { devnotfound_msg(lcss,devnum); RELEASE_INTLOCK(NULL); return -1; } if (cmd[0] == 't') { dev->ccwtrace = oneorzero; logmsg( _("HHCPN136I CCW tracing is now %s for device %d:%4.4X\n"), onoroff, lcss, devnum ); } else { dev->ccwstep = oneorzero; logmsg( _("HHCPN137I CCW stepping is now %s for device %d:%4.4X\n"), onoroff, lcss, devnum ); } RELEASE_INTLOCK(NULL); return 0; } RELEASE_INTLOCK(NULL); logmsg( _("HHCPN138E Unrecognized +/- command.\n") ); return -1; } static inline char *aea_mode_str(BYTE mode) { static char *name[] = { "DAT-Off", "Primary", "AR", "Secondary", "Home", 0, 0, 0, "PER/DAT-Off", "PER/Primary", "PER/AR", "PER/Secondary", "PER/Home" }; return name[(mode & 0x0f) | ((mode & 0xf0) ? 8 : 0)]; } /*-------------------------------------------------------------------*/ /* aea - display aea values */ /*-------------------------------------------------------------------*/ int aea_cmd(int argc, char *argv[], char *cmdline) { int i; /* Index */ REGS *regs; UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; logmsg ("aea mode %s\n",aea_mode_str(regs->aea_mode)); logmsg ("aea ar "); for (i = 16; i < 21; i++) if(regs->aea_ar[i] > 0) logmsg(" %2.2x",regs->aea_ar[i]); else logmsg(" %2d",regs->aea_ar[i]); for (i = 0; i < 16; i++) if(regs->aea_ar[i] > 0) logmsg(" %2.2x",regs->aea_ar[i]); else logmsg(" %2d",regs->aea_ar[i]); logmsg ("\n"); logmsg ("aea common "); if(regs->aea_common[32] > 0) logmsg(" %2.2x",regs->aea_common[32]); else logmsg(" %2d",regs->aea_common[32]); for (i = 0; i < 16; i++) if(regs->aea_common[i] > 0) logmsg(" %2.2x",regs->aea_common[i]); else logmsg(" %2d",regs->aea_common[i]); logmsg ("\n"); logmsg ("aea cr[1] %16.16" I64_FMT "x\n cr[7] %16.16" I64_FMT "x\n" " cr[13] %16.16" I64_FMT "x\n", regs->CR_G(1),regs->CR_G(7),regs->CR_G(13)); logmsg (" cr[r] %16.16" I64_FMT "x\n", regs->CR_G(CR_ASD_REAL)); for(i = 0; i < 16; i++) if(regs->aea_ar[i] > 15) logmsg (" alb[%d] %16.16" I64_FMT "x\n", regs->cr[CR_ALB_OFFSET + i]); if (regs->sie_active) { regs = regs->guestregs; logmsg ("aea SIE\n"); logmsg ("aea mode %s\n",aea_mode_str(regs->aea_mode)); logmsg ("aea ar "); for (i = 16; i < 21; i++) if(regs->aea_ar[i] > 0) logmsg(" %2.2x",regs->aea_ar[i]); else logmsg(" %2d",regs->aea_ar[i]); for (i = 0; i < 16; i++) if(regs->aea_ar[i] > 0) logmsg(" %2.2x",regs->aea_ar[i]); else logmsg(" %2d",regs->aea_ar[i]); logmsg ("\n"); logmsg ("aea common "); if(regs->aea_common[32] > 0) logmsg(" %2.2x",regs->aea_common[32]); else logmsg(" %2d",regs->aea_common[32]); for (i = 0; i < 16; i++) if(regs->aea_common[i] > 0) logmsg(" %2.2x",regs->aea_common[i]); else logmsg(" %2d",regs->aea_common[i]); logmsg ("\n"); logmsg ("aea cr[1] %16.16" I64_FMT "x\n cr[7] %16.16" I64_FMT "x\n" " cr[13] %16.16" I64_FMT "x\n", regs->CR_G(1),regs->CR_G(7),regs->CR_G(13)); logmsg (" cr[r] %16.16" I64_FMT "x\n", regs->CR_G(CR_ASD_REAL)); for(i = 0; i < 16; i++) if(regs->aea_ar[i] > 15) logmsg (" alb[%d] %16.16" I64_FMT "x\n", regs->cr[CR_ALB_OFFSET + i]); } release_lock (&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* aia - display aia values */ /*-------------------------------------------------------------------*/ DLL_EXPORT int aia_cmd(int argc, char *argv[], char *cmdline) { REGS *regs; UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; logmsg ("AIV %16.16" I64_FMT "x aip %p ip %p aie %p aim %p\n", regs->aiv,regs->aip,regs->ip,regs->aie,(BYTE *)regs->aim); if (regs->sie_active) { regs = regs->guestregs; logmsg ("SIE:\n"); logmsg ("AIV %16.16" I64_FMT "x aip %p ip %p aie %p\n", regs->aiv,regs->aip,regs->ip,regs->aie); } release_lock (&sysblk.cpulock[sysblk.pcpu]); return 0; } /*-------------------------------------------------------------------*/ /* tlb - display tlb table */ /*-------------------------------------------------------------------*/ /* */ /* NOTES: */ /* The "tlbid" field is part of TLB_VADDR so it must be extracted */ /* whenever it's used or displayed. The TLB_VADDR does not contain */ /* all of the effective address bits so they are created on-the-fly*/ /* with (i << shift) The "main" field of the tlb contains an XOR */ /* hash of effective address. So MAINADDR() macro is used to remove*/ /* the hash before it's displayed. */ /* */ int tlb_cmd(int argc, char *argv[], char *cmdline) { int i; /* Index */ int shift; /* Number of bits to shift */ int bytemask; /* Byte mask */ U64 pagemask; /* Page mask */ int matches = 0; /* Number aeID matches */ REGS *regs; UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); obtain_lock(&sysblk.cpulock[sysblk.pcpu]); if (!IS_CPU_ONLINE(sysblk.pcpu)) { release_lock(&sysblk.cpulock[sysblk.pcpu]); logmsg( _("HHCPN160W CPU%4.4X not configured\n"), sysblk.pcpu); return 0; } regs = sysblk.regs[sysblk.pcpu]; shift = regs->arch_mode == ARCH_370 ? 11 : 12; bytemask = regs->arch_mode == ARCH_370 ? 0x1FFFFF : 0x3FFFFF; pagemask = regs->arch_mode == ARCH_370 ? 0x00E00000 : regs->arch_mode == ARCH_390 ? 0x7FC00000 : 0xFFFFFFFFFFC00000ULL; logmsg ("tlbID 0x%6.6x mainstor %p\n",regs->tlbID,regs->mainstor); logmsg (" ix asd vaddr pte id c p r w ky main\n"); for (i = 0; i < TLBN; i++) { logmsg("%s%3.3x %16.16" I64_FMT "x %16.16" I64_FMT "x %16.16" I64_FMT "x %4.4x %1d %1d %1d %1d %2.2x %8.8x\n", ((regs->tlb.TLB_VADDR_G(i) & bytemask) == regs->tlbID ? "*" : " "), i,regs->tlb.TLB_ASD_G(i), ((regs->tlb.TLB_VADDR_G(i) & pagemask) | (i << shift)), regs->tlb.TLB_PTE_G(i),(int)(regs->tlb.TLB_VADDR_G(i) & bytemask), regs->tlb.common[i],regs->tlb.protect[i], (regs->tlb.acc[i] & ACC_READ) != 0,(regs->tlb.acc[i] & ACC_WRITE) != 0, regs->tlb.skey[i], MAINADDR(regs->tlb.main[i], ((regs->tlb.TLB_VADDR_G(i) & pagemask) | (i << shift))) - regs->mainstor); matches += ((regs->tlb.TLB_VADDR(i) & bytemask) == regs->tlbID); } logmsg("%d tlbID matches\n", matches); if (regs->sie_active) { regs = regs->guestregs; shift = regs->guestregs->arch_mode == ARCH_370 ? 11 : 12; bytemask = regs->arch_mode == ARCH_370 ? 0x1FFFFF : 0x3FFFFF; pagemask = regs->arch_mode == ARCH_370 ? 0x00E00000 : regs->arch_mode == ARCH_390 ? 0x7FC00000 : 0xFFFFFFFFFFC00000ULL; logmsg ("\nSIE: tlbID 0x%4.4x mainstor %p\n",regs->tlbID,regs->mainstor); logmsg (" ix asd vaddr pte id c p r w ky main\n"); for (i = matches = 0; i < TLBN; i++) { logmsg("%s%3.3x %16.16" I64_FMT "x %16.16" I64_FMT "x %16.16" I64_FMT "x %4.4x %1d %1d %1d %1d %2.2x %p\n", ((regs->tlb.TLB_VADDR_G(i) & bytemask) == regs->tlbID ? "*" : " "), i,regs->tlb.TLB_ASD_G(i), ((regs->tlb.TLB_VADDR_G(i) & pagemask) | (i << shift)), regs->tlb.TLB_PTE_G(i),(int)(regs->tlb.TLB_VADDR_G(i) & bytemask), regs->tlb.common[i],regs->tlb.protect[i], (regs->tlb.acc[i] & ACC_READ) != 0,(regs->tlb.acc[i] & ACC_WRITE) != 0, regs->tlb.skey[i], MAINADDR(regs->tlb.main[i], ((regs->tlb.TLB_VADDR_G(i) & pagemask) | (i << shift))) - regs->mainstor); matches += ((regs->tlb.TLB_VADDR(i) & bytemask) == regs->tlbID); } logmsg("SIE: %d tlbID matches\n", matches); } release_lock (&sysblk.cpulock[sysblk.pcpu]); return 0; } #if defined(SIE_DEBUG_PERFMON) /*-------------------------------------------------------------------*/ /* spm - SIE performance monitor table */ /*-------------------------------------------------------------------*/ int spm_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); sie_perfmon_disp(); return 0; } #endif #if defined(_FEATURE_SYSTEM_CONSOLE) /*-------------------------------------------------------------------*/ /* ssd - signal shutdown command */ /*-------------------------------------------------------------------*/ int ssd_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); signal_quiesce(0, 0); return 0; } #endif #if defined(OPTION_COUNTING) /*-------------------------------------------------------------------*/ /* count - display counts */ /*-------------------------------------------------------------------*/ int count_cmd(int argc, char *argv[], char *cmdline) { int i; /* Index */ U64 instcount = 0; /* Instruction count */ UNREFERENCED(argc); UNREFERENCED(argv); UNREFERENCED(cmdline); if (argc > 1 && strcasecmp(argv[1],"clear") == 0) { for (i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i)) sysblk.regs[i]->instcount = sysblk.regs[i]->prevcount = 0; for (i = 0; i < OPTION_COUNTING; i++) sysblk.count[i] = 0; } for (i = 0; i < MAX_CPU; i++) if (IS_CPU_ONLINE(i)) instcount += INSTCOUNT(sysblk.regs[i]); logmsg (" i: %12" I64_FMT "d\n", instcount); for (i = 0; i < OPTION_COUNTING; i++) logmsg ("%3d: %12" I64_FMT "d\n", i, sysblk.count[i]); return 0; } #endif #if defined(OPTION_DYNAMIC_LOAD) /*-------------------------------------------------------------------*/ /* ldmod - load a module */ /*-------------------------------------------------------------------*/ int ldmod_cmd(int argc, char *argv[], char *cmdline) { int i; /* Index */ UNREFERENCED(cmdline); if(argc <= 1) { logmsg("Usage: %s \n",argv[0]); return -1; } for(i = 1; i < argc; i++) { logmsg(_("HHCHD100I Loading %s ...\n"),argv[i]); if(!hdl_load(argv[i], 0)) logmsg(_("HHCHD101I Module %s loaded\n"),argv[i]); } return 0; } /*-------------------------------------------------------------------*/ /* rmmod - delete a module */ /*-------------------------------------------------------------------*/ int rmmod_cmd(int argc, char *argv[], char *cmdline) { int i; /* Index */ UNREFERENCED(cmdline); if(argc <= 1) { logmsg("Usage: %s \n",argv[0]); return -1; } for(i = 1; i < argc; i++) { logmsg(_("HHCHD102I Unloading %s ...\n"),argv[i]); if(!hdl_dele(argv[i])) logmsg(_("HHCHD103I Module %s unloaded\n"),argv[i]); } return 0; } /*-------------------------------------------------------------------*/ /* lsmod - list dynamic modules */ /*-------------------------------------------------------------------*/ int lsmod_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); hdl_list(HDL_LIST_DEFAULT); return 0; } /*-------------------------------------------------------------------*/ /* lsdep - list module dependencies */ /*-------------------------------------------------------------------*/ int lsdep_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); hdl_dlst(); return 0; } /*-------------------------------------------------------------------*/ /* modpath - set module path */ /*-------------------------------------------------------------------*/ int modpath_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if(argc <= 1) { logmsg("Usage: %s \n",argv[0]); return -1; } else { hdl_setpath(strdup(argv[1])); return 0; } } #endif /*defined(OPTION_DYNAMIC_LOAD)*/ #ifdef FEATURE_ECPSVM /*-------------------------------------------------------------------*/ /* evm - ECPS:VM command */ /*-------------------------------------------------------------------*/ int evm_cmd_1(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); logmsg(_("HHCPN150W evm command is deprecated. Use \"ecpsvm\" instead\n")); ecpsvm_command(argc,argv); return 0; } /*-------------------------------------------------------------------*/ /* evm - ECPS:VM command */ /*-------------------------------------------------------------------*/ int evm_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); ecpsvm_command(argc,argv); return 0; } #endif /*-------------------------------------------------------------------*/ /* herclogo - Set the hercules logo file */ /*-------------------------------------------------------------------*/ int herclogo_cmd(int argc,char *argv[], char *cmdline) { UNREFERENCED(cmdline); if(argc<2) { sysblk.logofile=NULL; clearlogo(); return 0; } return readlogo(argv[1]); } /*-------------------------------------------------------------------*/ /* sizeof - Display sizes of various structures/tables */ /*-------------------------------------------------------------------*/ int sizeof_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); logmsg(_("HHCPN161I (void *) ..........%7d\n"),sizeof(void *)); logmsg(_("HHCPN161I (unsigned int) ....%7d\n"),sizeof(unsigned int)); logmsg(_("HHCPN161I (long) ............%7d\n"),sizeof(long)); logmsg(_("HHCPN161I (long long) .......%7d\n"),sizeof(long long)); logmsg(_("HHCPN161I (size_t) ..........%7d\n"),sizeof(size_t)); logmsg(_("HHCPN161I (off_t) ...........%7d\n"),sizeof(off_t)); logmsg(_("HHCPN161I SYSBLK ............%7d\n"),sizeof(SYSBLK)); logmsg(_("HHCPN161I REGS ..............%7d\n"),sizeof(REGS)); logmsg(_("HHCPN161I REGS (copy len) ...%7d\n"),sysblk.regs_copy_len); logmsg(_("HHCPN161I PSW ...............%7d\n"),sizeof(PSW)); logmsg(_("HHCPN161I DEVBLK ............%7d\n"),sizeof(DEVBLK)); logmsg(_("HHCPN161I TLB entry .........%7d\n"),sizeof(TLB)/TLBN); logmsg(_("HHCPN161I TLB table .........%7d\n"),sizeof(TLB)); logmsg(_("HHCPN161I FILENAME_MAX ......%7d\n"),FILENAME_MAX); logmsg(_("HHCPN161I PATH_MAX ..........%7d\n"),PATH_MAX); logmsg(_("HHCPN161I CPU_BITMAP ........%7d\n"),sizeof(CPU_BITMAP)); logmsg(_("HHCPN161I FD_SETSIZE ........%7d\n"),FD_SETSIZE); return 0; } #if defined(OPTION_HAO) /*-------------------------------------------------------------------*/ /* hao - Hercules Automatic Operator */ /*-------------------------------------------------------------------*/ int hao_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(argc); UNREFERENCED(argv); hao_command(cmdline); /* (actual HAO code is in module hao.c) */ return 0; } #endif /* defined(OPTION_HAO) */ /*-------------------------------------------------------------------*/ /* conkpalv - set console session TCP keep-alive values */ /*-------------------------------------------------------------------*/ int conkpalv_cmd( int argc, char *argv[], char *cmdline ) { int idle, intv, cnt; UNREFERENCED( cmdline ); idle = sysblk.kaidle; intv = sysblk.kaintv; cnt = sysblk.kacnt; if(argc < 2) logmsg( _("HHCPN190I Keep-alive = (%d,%d,%d)\n"),idle,intv,cnt); else { if (argc == 2 && parse_conkpalv( argv[1], &idle, &intv, &cnt ) == 0) { sysblk.kaidle = idle; sysblk.kaintv = intv; sysblk.kacnt = cnt; } else { logmsg( _("HHCPN192E Invalid format. Enter \"help conkpalv\" for help.\n")); return -1; } } return 0; } /*-------------------------------------------------------------------*/ /* traceopt - perform display_inst traditionally or new */ /*-------------------------------------------------------------------*/ int traceopt_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); if (argc > 1) { if (strcasecmp(argv[1], "traditional") == 0) { sysblk.showregsfirst = 0; sysblk.showregsnone = 0; } if (strcasecmp(argv[1], "regsfirst") == 0) { sysblk.showregsfirst = 1; sysblk.showregsnone = 0; } if (strcasecmp(argv[1], "noregs") == 0) { sysblk.showregsfirst = 0; sysblk.showregsnone = 1; } } else logmsg(_("HHCPN162I Hercules instruction trace displayed in %s mode\n"), sysblk.showregsnone ? _("noregs") : sysblk.showregsfirst ? _("regsfirst") : _("traditional")); return 0; } #ifdef OPTION_CMDTGT /*-------------------------------------------------------------------*/ /* cmdtgt - Specify the command target */ /*-------------------------------------------------------------------*/ int cmdtgt_cmd(int argc, char *argv[], char *cmdline) { int print = 1; UNREFERENCED(cmdline); if(argc == 2) { if(!strcasecmp(argv[1], "herc")) sysblk.cmdtgt = 0; else if(!strcasecmp(argv[1], "scp")) sysblk.cmdtgt = 1; else if(!strcasecmp(argv[1], "pscp")) sysblk.cmdtgt = 2; else if(!strcasecmp(argv[1], "?")) ; else print = 0; } else print = 0; if(print) { switch(sysblk.cmdtgt) { case 0: { logmsg("cmdtgt: Commands are sent to hercules\n"); break; } case 1: { logmsg("cmdtgt: Commands are sent to scp\n"); break; } case 2: { logmsg("cmdtgt: Commands are sent as priority messages to scp\n"); break; } } } else logmsg("cmdtgt: Use cmdtgt [herc | scp | pscp | ?]\n"); return 0; } /*-------------------------------------------------------------------*/ /* scp - Send scp command in any mode */ /*-------------------------------------------------------------------*/ int scp_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(argv); if(argc == 1) scp_command(" ", 0); else scp_command(&cmdline[4], 0); return 0; } /*-------------------------------------------------------------------*/ /* pscp - Send a priority message in any mode */ /*-------------------------------------------------------------------*/ int prioscp_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(argv); if(argc == 1) scp_command(" ", 1); else scp_command(&cmdline[5], 1); return 0; } /*-------------------------------------------------------------------*/ /* herc - Send a Hercules command in any mode */ /*-------------------------------------------------------------------*/ int herc_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(argv); if(argc == 1) ProcessPanelCommand(" "); else ProcessPanelCommand(&cmdline[5]); return 0; } #endif // OPTION_CMDTGT /* PATCH ISW20030220 - Script command support */ static int scr_recursion=0; /* Recursion count (set to 0) */ static int scr_aborted=0; /* Script abort flag */ static int scr_uaborted=0; /* Script user abort flag */ TID scr_tid=0; int scr_recursion_level() { return scr_recursion; } /*-------------------------------------------------------------------*/ /* cancel script command */ /*-------------------------------------------------------------------*/ int cscript_cmd(int argc, char *argv[], char *cmdline) { UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); if(scr_tid!=0) { scr_uaborted=1; } return 0; } /*-------------------------------------------------------------------*/ /* script command */ /*-------------------------------------------------------------------*/ int script_cmd(int argc, char *argv[], char *cmdline) { int i; UNREFERENCED(cmdline); if(argc<2) { logmsg(_("HHCPN996E The script command requires a filename\n")); return 1; } if(scr_tid==0) { scr_tid=thread_id(); scr_aborted=0; scr_uaborted=0; } else { if(scr_tid!=thread_id()) { logmsg(_("HHCPN997E Only 1 script may be invoked from the panel at any time\n")); return 1; } } for(i=1;i=10) { logmsg(_("HHCPN998E Script aborted : Script recursion level exceeded\n")); scr_aborted=1; return 0; } /* Open RC file */ hostpath(pathname, script_name, sizeof(pathname)); if (!(scrfp = fopen(pathname, "r"))) { int save_errno = errno; if (!isrcfile) { if (ENOENT != errno) logmsg(_("HHCPN007E Script file \"%s\" open failed: %s\n"), script_name, strerror(errno)); else logmsg(_("HHCPN995E Script file \"%s\" not found\n"), script_name); } else /* (this IS the .rc file...) */ { if (ENOENT != errno) logmsg(_("HHCPN007E Script file \"%s\" open failed: %s\n"), script_name, strerror(errno)); } errno = save_errno; return -1; } scr_recursion++; if(isrcfile) { logmsg(_("HHCPN008I Script file processing started using file \"%s\"\n"), script_name); } /* Obtain storage for the SCRIPT file buffer */ if (!(scrbuf = malloc (scrbufsize))) { logmsg(_("HHCPN009E Script file buffer malloc failed: %s\n"), strerror(errno)); fclose(scrfp); return 0; } for (; ;) { script_test_userabort(); if(scr_aborted) { break; } /* Read a complete line from the SCRIPT file */ if (!fgets(scrbuf, scrbufsize, scrfp)) break; /* Remove trailing whitespace */ for (scrlen = strlen(scrbuf); scrlen && isspace(scrbuf[scrlen-1]); scrlen--); scrbuf[scrlen] = 0; /* Remove any # comments on the line before processing */ if ((p = strchr(scrbuf,'#')) && p > scrbuf) do *p = 0; while (isspace(*--p) && p >= scrbuf); if (strncasecmp(scrbuf,"pause",5) == 0) { sscanf(scrbuf+5, "%d", &scr_pause_amt); if (scr_pause_amt < 0 || scr_pause_amt > 999) { logmsg(_("HHCPN010W Ignoring invalid SCRIPT file pause " "statement: %s\n"), scrbuf+5); continue; } logmsg (_("HHCPN011I Pausing SCRIPT file processing for %d " "seconds...\n"), scr_pause_amt); SLEEP(scr_pause_amt); logmsg (_("HHCPN012I Resuming SCRIPT file processing...\n")); continue; } /* Process the command */ for (p = scrbuf; isspace(*p); p++); panel_command(p); script_test_userabort(); if(scr_aborted) { break; } } if (feof(scrfp)) logmsg (_("HHCPN013I EOF reached on SCRIPT file. Processing complete.\n")); else { if(!scr_aborted) { logmsg (_("HHCPN014E I/O error reading SCRIPT file: %s\n"), strerror(errno)); } else { logmsg (_("HHCPN999I Script \"%s\" aborted due to previous conditions\n"), script_name); scr_uaborted=1; } } fclose(scrfp); scr_recursion--; /* Decrement recursion count */ if(scr_recursion==0) { scr_aborted=0; /* reset abort flag */ scr_tid=0; /* reset script thread id */ } return 0; } /* END PATCH ISW20030220 */ hercules-3.12/cmdtab.c0000664000175000017500000003165612564723224011614 00000000000000/* CMDTAB.C (c) Copyright Roger Bowler, 1999-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* (c) Copyright Jan Jaeger, 2003-2009 */ /* Route all Hercules configuration statements */ /* and panel commands to the appropriate functions */ #include "hstdinc.h" #define _CMDTAB_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "history.h" // Handle externally defined commands... // (for use in CMDTAB COMMAND entry further below) #define EXT_CMD(xxx_cmd) call_ ## xxx_cmd // (for defining routing function immediately below) #define CALL_EXT_CMD(xxx_cmd) \ int call_ ## xxx_cmd ( int argc, char *argv[], char *cmdline ) { \ return xxx_cmd ( argc, argv, cmdline ); } // Externally defined commands routing functions... CALL_EXT_CMD ( ptt_cmd ) CALL_EXT_CMD ( cache_cmd ) CALL_EXT_CMD ( shared_cmd ) /*-------------------------------------------------------------------*/ /* Create forward references for all commands in the command table */ /*-------------------------------------------------------------------*/ #define _FW_REF #define COMMAND(_stmt, _type, _func, _sdesc, _ldesc) \ int (_func)(int argc, char *argv[], char *cmdline); #define CMDABBR(_stmt, _abbr, _type, _func, _sdesc, _ldesc) \ int (_func)(int argc, char *argv[], char *cmdline); #include "cmdtab.h" #undef COMMAND #undef CMDABBR #undef _FW_REF typedef int CMDFUNC(int argc, char *argv[], char *cmdline); /* Layout of command routing table */ typedef struct _CMDTAB { const char *statement; /* statement */ const size_t statminlen; /* min abbreviation */ int type; /* statement type */ #define DISABLED 0x00 /* disabled statement */ #define CONFIG 0x01 /* config statement */ #define PANEL 0x02 /* command statement */ CMDFUNC *function; /* handler function */ const char *shortdesc; /* description */ const char *longdesc; /* detaled description */ } CMDTAB; #define COMMAND(_stmt, _type, _func, _sdesc, _ldesc) \ { (_stmt), (0), (_type), (_func), (_sdesc), (_ldesc) }, #define CMDABBR(_stmt, _abbr, _type, _func, _sdesc, _ldesc) \ { (_stmt), (_abbr), (_type), (_func), (_sdesc), (_ldesc) }, static CMDTAB cmdtab[] = { #include "cmdtab.h" COMMAND ( NULL, 0, NULL, NULL, NULL ) /* End of table */ }; /*-------------------------------------------------------------------*/ /* $zapcmd - internal debug - may cause havoc - use with caution */ /*-------------------------------------------------------------------*/ int zapcmd_cmd(int argc, char *argv[], char *cmdline) { CMDTAB* cmdent; int i; UNREFERENCED(cmdline); if (argc > 1) { for (cmdent = cmdtab; cmdent->statement; cmdent++) { if(!strcasecmp(argv[1], cmdent->statement)) { if(argc > 2) for(i = 2; i < argc; i++) { if(!strcasecmp(argv[i],"Cfg")) cmdent->type |= CONFIG; else if(!strcasecmp(argv[i],"NoCfg")) cmdent->type &= ~CONFIG; else if(!strcasecmp(argv[i],"Cmd")) cmdent->type |= PANEL; else if(!strcasecmp(argv[i],"NoCmd")) cmdent->type &= ~PANEL; else { logmsg(_("Invalid arg: %s: %s %s [(No)Cfg|(No)Cmd]\n"),argv[i],argv[0],argv[1]); return -1; } } else logmsg(_("%s: %s(%sCfg,%sCmd)\n"),argv[0],cmdent->statement, (cmdent->type&CONFIG)?"":"No",(cmdent->type&PANEL)?"":"No"); return 0; } } logmsg(_("%s: %s not in command table\n"),argv[0],argv[1]); return -1; } else logmsg(_("Usage: %s [(No)Cfg|(No)Cmd]\n"),argv[0]); return -1; } CMDT_DLL_IMPORT int ProcessConfigCommand (int argc, char **argv, char *cmdline) { CMDTAB* cmdent; if (argc) for (cmdent = cmdtab; cmdent->statement; cmdent++) if(cmdent->function && (cmdent->type & CONFIG)) if(!strcasecmp(argv[0], cmdent->statement)) return cmdent->function(argc, argv, cmdline); return -1; } /*-------------------------------------------------------------------*/ /* Main panel command processing function */ /*-------------------------------------------------------------------*/ int OnOffCommand(int argc, char *argv[], char *cmdline); int ShadowFile_cmd(int argc, char *argv[], char *cmdline); int cmd_argc; char* cmd_argv[MAX_ARGS]; int ProcessPanelCommand (char* pszCmdLine) { CMDTAB* pCmdTab = NULL; char* pszSaveCmdLine = NULL; char* cl = NULL; int rc = -1; int cmdl; if (!pszCmdLine || !*pszCmdLine) { /* [enter key] by itself: start the CPU (ignore if not instruction stepping) */ if (sysblk.inststep) rc = start_cmd(0,NULL,NULL); goto ProcessPanelCommandExit; } #if defined(OPTION_CONFIG_SYMBOLS) /* Perform variable substitution */ /* First, set some 'dynamic' symbols to their own values */ set_symbol("CUU","$(CUU)"); set_symbol("cuu","$(cuu)"); set_symbol("CCUU","$(CCUU)"); set_symbol("ccuu","$(ccuu)"); cl=resolve_symbol_string(pszCmdLine); #else cl=pszCmdLine; #endif /* Save unmodified copy of the command line in case its format is unusual and needs customized parsing. */ pszSaveCmdLine = strdup(cl); /* Parse the command line into its individual arguments... Note: original command line now sprinkled with nulls */ parse_args (cl, MAX_ARGS, cmd_argv, &cmd_argc); /* If no command was entered (i.e. they entered just a comment (e.g. "# comment")) then ignore their input */ if ( !cmd_argv[0] ) goto ProcessPanelCommandExit; #if defined(OPTION_DYNAMIC_LOAD) if(system_command) if((rc = system_command(cmd_argc, (char**)cmd_argv, pszSaveCmdLine))) goto ProcessPanelCommandExit; #endif /* Route standard formatted commands from our routing table... */ if (cmd_argc) for (pCmdTab = cmdtab; pCmdTab->function; pCmdTab++) { if(pCmdTab->function && (pCmdTab->type & PANEL)) { if (!pCmdTab->statminlen) { if(!strcasecmp(cmd_argv[0], pCmdTab->statement)) { rc = pCmdTab->function(cmd_argc, (char**)cmd_argv, pszSaveCmdLine); goto ProcessPanelCommandExit; } } else { cmdl=MAX(strlen(cmd_argv[0]),pCmdTab->statminlen); if(!strncasecmp(cmd_argv[0],pCmdTab->statement,cmdl)) { rc = pCmdTab->function(cmd_argc, (char**)cmd_argv, pszSaveCmdLine); goto ProcessPanelCommandExit; } } } } /* Route non-standard formatted commands... */ /* sf commands - shadow file add/remove/set/compress/display */ if (0 || !strncasecmp(pszSaveCmdLine,"sf+",3) || !strncasecmp(pszSaveCmdLine,"sf-",3) || !strncasecmp(pszSaveCmdLine,"sfc",3) || !strncasecmp(pszSaveCmdLine,"sfd",3) || !strncasecmp(pszSaveCmdLine,"sfk",3) ) { rc = ShadowFile_cmd(cmd_argc,(char**)cmd_argv,pszSaveCmdLine); goto ProcessPanelCommandExit; } /* x+ and x- commands - turn switches on or off */ if ('+' == pszSaveCmdLine[1] || '-' == pszSaveCmdLine[1]) { rc = OnOffCommand(cmd_argc,(char**)cmd_argv,pszSaveCmdLine); goto ProcessPanelCommandExit; } /* Error: unknown/unsupported command... */ ASSERT( cmd_argv[0] ); logmsg( _("HHCPN139E Command \"%s\" not found; enter '?' for list.\n"), cmd_argv[0] ); ProcessPanelCommandExit: /* Free our saved copy */ free(pszSaveCmdLine); #if defined(OPTION_CONFIG_SYMBOLS) if (cl != pszCmdLine) free(cl); #endif return rc; } /*-------------------------------------------------------------------*/ /* help command - display additional help for a given command */ /*-------------------------------------------------------------------*/ int HelpCommand(int argc, char *argv[], char *cmdline) { CMDTAB* pCmdTab; UNREFERENCED(cmdline); if (argc < 2) { logmsg( _("HHCPN140I Valid panel commands are...\n\n") ); logmsg( " %-9.9s %s \n", "Command", "Description..." ); logmsg( " %-9.9s %s \n", "-------", "-----------------------------------------------" ); /* List standard formatted commands from our routing table... */ for (pCmdTab = cmdtab; pCmdTab->statement; pCmdTab++) { if ( (pCmdTab->type & PANEL) && (pCmdTab->shortdesc)) logmsg( _(" %-9.9s %s \n"), pCmdTab->statement, pCmdTab->shortdesc ); } } else { for (pCmdTab = cmdtab; pCmdTab->statement; pCmdTab++) { if (!strcasecmp(pCmdTab->statement,argv[1]) && (pCmdTab->type & PANEL) ) { logmsg( _("%s: %s\n"),pCmdTab->statement,pCmdTab->shortdesc); if(pCmdTab->longdesc) logmsg( _("%s\n"),pCmdTab->longdesc ); return 0; } } logmsg( _("HHCPN142I Command %s not found - no help available\n"),argv[1]); return -1; } return 0; } int scr_recursion_level(); #if defined(OPTION_DYNAMIC_LOAD) DLL_EXPORT void *panel_command_r (void *cmdline) #else void *panel_command (void *cmdline) #endif { #define MAX_CMD_LEN (32768) char cmd[MAX_CMD_LEN]; /* Copy of panel command */ char *pCmdLine; unsigned i; int noredisp; pCmdLine = cmdline; ASSERT(pCmdLine); /* every command will be stored in history list */ /* except null commands and script commands */ if (*pCmdLine != 0 && scr_recursion_level() == 0) history_add(cmdline); /* Copy panel command to work area, skipping leading blanks */ /* If the command starts with a -, then strip it and indicate * we do not want command redisplay */ noredisp=0; while (*pCmdLine && isspace(*pCmdLine)) pCmdLine++; i = 0; while (*pCmdLine && i < (MAX_CMD_LEN-1)) { if(i==0 && *pCmdLine=='-') { noredisp=1; /* and remove blanks again.. */ while (*pCmdLine && isspace(*pCmdLine)) pCmdLine++; } else { cmd[i] = *pCmdLine; i++; } pCmdLine++; } cmd[i] = 0; /* Ignore null commands (just pressing enter) unless instruction stepping is enabled or commands are being sent to the SCP by default. */ if (!sysblk.inststep && (sysblk.cmdtgt == 0) && (0 == cmd[0])) return NULL; /* Echo the command to the control panel */ if(!noredisp) { logmsg( "%s\n", cmd); } #ifdef OPTION_CMDTGT /* check for herc, scp or pscp command */ /* Please note that cmdtgt is a hercules command! */ /* Changing the target to her in scp mode is done by using herc cmdtgt herc */ if(!strncasecmp(cmd, "herc ", 5) || !strncasecmp(cmd, "scp ", 4) || !strncasecmp(cmd, "pscp ", 5)) { ProcessPanelCommand(cmd); return NULL; } /* Send command to the selected command target */ switch(sysblk.cmdtgt) { case 0: // cmdtgt herc { /* Stay compatible */ #ifdef _FEATURE_SYSTEM_CONSOLE if(cmd[0] == '.' || cmd[0] == '!') { if(!cmd[1]) { cmd[1] = ' '; cmd[2] = 0; } scp_command(cmd + 1, cmd[0] == '!'); } else #endif /*_FEATURE_SYSTEM_CONSOLE*/ ProcessPanelCommand(cmd); break; } case 1: // cmdtgt scp { if(!cmd[0]) { cmd[0] = ' '; cmd[1] = 0; } scp_command(cmd, 0); break; } case 2: // cmdtgt pscp { if(!cmd[0]) { cmd[0] = ' '; cmd[1] = 0; } scp_command(cmd, 1); break; } } #else // OPTION_CMDTGT #ifdef _FEATURE_SYSTEM_CONSOLE if ('.' == cmd[0] || '!' == cmd[0]) { if (!cmd[1]) { cmd[1]=' '; cmd[2]=0; } scp_command (cmd+1, cmd[0] == '!'); return NULL; } #endif /*_FEATURE_SYSTEM_CONSOLE*/ ProcessPanelCommand(cmd); #endif // OPTION_CMDTGT return NULL; } hercules-3.12/hao.c0000664000175000017500000005247212564723224011130 00000000000000/* HAO.C (c) Copyright Bernard van der Helm, 2002-2009 */ /* Hercules Automatic Operator Implementation */ /*---------------------------------------------------------------------------*/ /* file: hao.c */ /* */ /* Implementation of the automatic operator within the Hercules emulator. */ /* */ /* (c) Copyright Bernard van der Helm, 2002-2009 */ /* Noordwijkerhout, The Netherlands. */ /* */ /*---------------------------------------------------------------------------*/ #include "hstdinc.h" #define _HAO_C_ #define _HENGINE_DLL_ #include "hercules.h" #if defined(OPTION_HAO) /*---------------------------------------------------------------------------*/ /* constants */ /*---------------------------------------------------------------------------*/ #define HHCAO001I "HHCAO001I Hercules Automatic Operator thread started;\n" \ " tid="TIDPAT", pri=%d, pid=%d\n" #define HHCAO002I "HHCAO002I Hercules Automatic Operator thread ended\n" #define HHCAO003I "HHCAO003I Firing command: '%s'\n" #define HHCAO004I "HHCAO004I The defined Automatic Operator rule(s) are:\n" #define HHCAO005I "HHCAO005I %02d: '%s' -> '%s'\n" #define HHCAO006I "HHCAO006I %d rule(s) displayed\n" #define HHCAO007E "HHCAO007E Unknown hao command, valid commands are:\n" \ " hao tgt : define target rule (pattern) to react on\n" \ " hao cmd : define command for previously defined rule\n" \ " hao list : list all rules/commands or only at index \n" \ " hao del : delete the rule at index \n" \ " hao clear : delete all rules (stops automatic operator)\n" #define HHCAO008E "HHCAO008E No rule defined at index %d\n" #define HHCAO009E "HHCAO009E Invalid index, index must be between 0 and %d\n" #define HHCAO010E "HHCAO010E Target not added, table full\n" #define HHCAO011E "HHCAO011E Tgt command given, but cmd command expected\n" #define HHCAO012E "HHCAO012E Empty target specified\n" #define HHCAO013E "HHCAO013E Target not added, duplicate found in table\n" #define HHCAO014E "HHCAO014E %s\n" #define HHCAO015E "HHCAO015E %s\n" #define HHCAO016I "HHCAO016I Target placed at index %d\n" #define HHCAO017E "HHCAO017E Cmd command given, but tgt command expected\n" #define HHCAO018E "HHCAO018E Empty command specified\n" #define HHCAO019E "HHCAO019E Command not added; causes loop with target at index %d\n" #define HHCAO020I "HHCAO020I Command placed at index %d\n" #define HHCAO021E "HHCAO021E Target not added, causes loop with command at index %d\n" #define HHCAO022I "HHCAO022I All automatic operation rules cleared\n" #define HHCAO023E "HHCAO023E hao del command given without a valid index\n" #define HHCAO024E "HHCAO024E Rule at index %d not deleted, already empty\n" #define HHCAO025I "HHCAO025I Rule at index %d succesfully deleted\n" #define HHCA0026E "HHCA0026E Command not added, may cause dead locks\n" #define HAO_WKLEN 256 /* (maximum message length able to tolerate) */ #define HAO_MAXRULE 64 /* (purely arbitrary and easily increasable) */ #define HAO_MAXCAPT 9 /* (maximum number of capturing groups) */ /*---------------------------------------------------------------------------*/ /* local variables */ /*---------------------------------------------------------------------------*/ static LOCK ao_lock; static regex_t ao_preg[HAO_MAXRULE]; static char *ao_cmd[HAO_MAXRULE]; static char *ao_tgt[HAO_MAXRULE]; static char ao_msgbuf[LOG_DEFSIZE+1]; /* (plus+1 for NULL termination) */ /*---------------------------------------------------------------------------*/ /* function prototypes */ /*---------------------------------------------------------------------------*/ DLL_EXPORT int hao_initialize(void); DLL_EXPORT void hao_command(char *cmd); DLL_EXPORT void hao_message(char *buf); static void hao_clear(void); static void hao_cmd(char *arg); static void hao_cpstrp(char *dest, char *src); static void hao_del(char *arg); static void hao_list(char *arg); static void hao_tgt(char *arg); static void* hao_thread(void* dummy); /*---------------------------------------------------------------------------*/ /* void hao_initialize(void) */ /* */ /* This function is called at system startup by impl.c 'process_rc_file' */ /* It initializes all global variables. */ /*---------------------------------------------------------------------------*/ DLL_EXPORT int hao_initialize(void) { int i = 0; initialize_lock(&ao_lock); /* serialize */ obtain_lock(&ao_lock); /* initialize variables */ for(i = 0; i < HAO_MAXRULE; i++) { ao_cmd[i] = NULL; ao_tgt[i] = NULL; } /* initialize message buffer */ memset(ao_msgbuf, 0, sizeof(ao_msgbuf)); /* Start message monitoring thread */ if ( create_thread (&sysblk.haotid, JOINABLE, hao_thread, NULL, "hao_thread") ) { i = FALSE; } else i = TRUE; release_lock(&ao_lock); return(i); } /*---------------------------------------------------------------------------*/ /* void hao_command(char *cmd) */ /* */ /* Within panel this function is called when a command is given that starts */ /* with the string hao. Here we check if a correct hao command is requested, */ /* otherwise a help is printed. */ /*---------------------------------------------------------------------------*/ DLL_EXPORT void hao_command(char *cmd) { char work[HAO_WKLEN]; char work2[HAO_WKLEN]; /* copy and strip spaces */ hao_cpstrp(work, cmd); /* again without starting hao */ hao_cpstrp(work2, &work[3]); if(!strncasecmp(work2, "tgt", 3)) { /* again without starting tgt */ hao_cpstrp(work, &work2[3]); hao_tgt(work); return; } if(!strncasecmp(work2, "cmd", 3)) { /* again without starting cmd */ hao_cpstrp(work, &work2[3]); hao_cmd(work); return; } if(!strncasecmp(work2, "del", 3)) { /* again without starting del */ hao_cpstrp(work, &work2[3]); hao_del(work); return; } if(!strncasecmp(work2, "list", 4)) { /* again without starting list */ hao_cpstrp(work, &work2[4]); hao_list(work); return; } if(!strncasecmp(work2, "clear", 4)) { hao_clear(); return; } logmsg(HHCAO007E); } /*---------------------------------------------------------------------------*/ /* hao_cpstrp(char *dest, char *src) */ /* */ /* This function copies the string from src to dest, without the trailing */ /* and ending spaces. */ /*---------------------------------------------------------------------------*/ static void hao_cpstrp(char *dest, char *src) { int i; for(i = 0; src[i] == ' '; i++); strncpy(dest, &src[i], HAO_WKLEN); dest[HAO_WKLEN-1] = 0; for(i = strlen(dest); i && dest[i - 1] == ' '; i--); dest[i] = 0; } /*---------------------------------------------------------------------------*/ /* void hao_tgt(char *arg) */ /* */ /* This function is given when the hao tgt command is given. A free slot is */ /* to be found and filled with the rule. There will be loop checking. */ /*---------------------------------------------------------------------------*/ static void hao_tgt(char *arg) { int i; int j; int rc; char work[HAO_WKLEN]; /* serialize */ obtain_lock(&ao_lock); /* find a free slot */ for(i = 0; ao_tgt[i] && i < HAO_MAXRULE; i++) /* check for table full */ if(i == HAO_MAXRULE) { release_lock(&ao_lock); logmsg(HHCAO010E); return; } /* check if not command is expected */ for(j = 0; j < HAO_MAXRULE; j++) { if(ao_tgt[j] && !ao_cmd[j]) { release_lock(&ao_lock); logmsg(HHCAO011E); return; } } /* check for empty target */ if(!strlen(arg)) { release_lock(&ao_lock); logmsg(HHCAO012E); return; } /* check for duplicate targets */ for(j = 0; j < HAO_MAXRULE; j++) { if(ao_tgt[j] && !strcmp(arg, ao_tgt[j])) { release_lock(&ao_lock); logmsg(HHCAO013E); return; } } /* compile the target string */ rc = regcomp(&ao_preg[i], arg, REG_EXTENDED); /* check for error */ if(rc) { release_lock(&ao_lock); /* place error in work */ regerror(rc, (const regex_t *) &ao_preg[i], work, HAO_WKLEN); logmsg(HHCAO014E, work); return; } /* check for possible loop */ for(j = 0; j < HAO_MAXRULE; j++) { if(ao_cmd[j] && !regexec(&ao_preg[i], ao_cmd[j], 0, NULL, 0)) { release_lock(&ao_lock); regfree(&ao_preg[i]); logmsg(HHCAO021E, i); return; } } /* duplicate the target */ ao_tgt[i] = strdup(arg); /* check duplication */ if(!ao_tgt[i]) { release_lock(&ao_lock); regfree(&ao_preg[i]); logmsg(HHCAO015E, strerror(ENOMEM)); return; } release_lock(&ao_lock); logmsg(HHCAO016I, i); } /*---------------------------------------------------------------------------*/ /* void hao_cmd(char *arg) */ /* */ /* This function is called when the hao cmd command is given. It searches */ /* the index of the last given hao tgt command. Does some checking and fills */ /* the entry with the given command. There will be loop checking */ /*---------------------------------------------------------------------------*/ static void hao_cmd(char *arg) { int i; int j; /* serialize */ obtain_lock(&ao_lock); /* find the free slot */ for(i = 0; ao_cmd[i] && i < HAO_MAXRULE; i++); /* check for table full -> so tgt cmd expected */ if(i == HAO_MAXRULE) { release_lock(&ao_lock); logmsg(HHCAO017E); return; } /* check if target is given */ if(!ao_tgt[i]) { release_lock(&ao_lock); logmsg(HHCAO017E); return; } /* check for empty cmd string */ if(!strlen(arg)) { release_lock(&ao_lock); logmsg(HHCAO018E); return; } /* check for hao command, prevent deadlock */ for(j = 0; !strncasecmp(&arg[j], "herc ", 4); j += 5); if(!strcasecmp(&arg[j], "hao") || !strncasecmp(&arg[j], "hao ", 4)) { release_lock(&ao_lock); logmsg(HHCA0026E); return; } /* check for possible loop */ for(j = 0; j < HAO_MAXRULE; j++) { if(ao_tgt[j] && !regexec(&ao_preg[j], arg, 0, NULL, 0)) { release_lock(&ao_lock); logmsg(HHCAO019E, j); return; } } /* duplicate the string */ ao_cmd[i] = strdup(arg); /* check duplication */ if(!ao_cmd[i]) { release_lock(&ao_lock); logmsg(HHCAO015E, strerror(ENOMEM)); return; } release_lock(&ao_lock); logmsg(HHCAO020I, i); } /*---------------------------------------------------------------------------*/ /* void hao_del(char *arg) */ /* */ /* This function is called when the command hao del is given. the rule in */ /* the given index is cleared. */ /*---------------------------------------------------------------------------*/ static void hao_del(char *arg) { int i; int rc; /* read the index number to delete */ rc = sscanf(arg, "%d", &i); if(!rc || rc == -1) { logmsg(HHCAO023E); return; } /* check if index is valid */ if(i < 0 || i >= HAO_MAXRULE) { logmsg(HHCAO009E, HAO_MAXRULE - 1); return; } /* serialize */ obtain_lock(&ao_lock); /* check if entry exists */ if(!ao_tgt[i]) { release_lock(&ao_lock); logmsg(HHCAO024E, i); return; } /* delete the entry */ free(ao_tgt[i]); ao_tgt[i] = NULL; regfree(&ao_preg[i]); if(ao_cmd[i]) { free(ao_cmd[i]); ao_cmd[i] = NULL; } release_lock(&ao_lock); logmsg(HHCAO025I, i); } /*---------------------------------------------------------------------------*/ /* void hao_list(char *arg) */ /* */ /* this function is called when the hao list command is given. It lists all */ /* rules. When given an index, only that index will be showed. */ /*---------------------------------------------------------------------------*/ static void hao_list(char *arg) { int i; int rc; int size; rc = sscanf(arg, "%d", &i); if(!rc || rc == -1) { /* list all rules */ logmsg(HHCAO004I); size = 0; /* serialize */ obtain_lock(&ao_lock); for(i = 0; i < HAO_MAXRULE; i++) { if(ao_tgt[i]) { logmsg(HHCAO005I, i, ao_tgt[i], (ao_cmd[i] ? ao_cmd[i] : "")); size++; } } release_lock(&ao_lock); logmsg(HHCAO006I, size); } else { /* list specific index */ if(i < 0 || i >= HAO_MAXRULE) logmsg(HHCAO009E, HAO_MAXRULE - 1); else { /* serialize */ obtain_lock(&ao_lock); if(!ao_tgt[i]) logmsg(HHCAO008E, i); else logmsg(HHCAO005I, i, ao_tgt[i], (ao_cmd[i] ? ao_cmd[i] : "not specified")); release_lock(&ao_lock); } } } /*---------------------------------------------------------------------------*/ /* void hao_clear(void) */ /* */ /* This function is called when the hao clear command is given. This */ /* function just clears all defined rules. Handy command for panic */ /* situations. */ /*---------------------------------------------------------------------------*/ static void hao_clear(void) { int i; /* serialize */ obtain_lock(&ao_lock); /* clear all defined rules */ for(i = 0; i < HAO_MAXRULE; i++) { if(ao_tgt[i]) { free(ao_tgt[i]); ao_tgt[i] = NULL; regfree(&ao_preg[i]); } if(ao_cmd[i]) { free(ao_cmd[i]); ao_cmd[i] = NULL; } } release_lock(&ao_lock); logmsg(HHCAO022I); } /*---------------------------------------------------------------------------*/ /* void* hao_thread(void* dummy) */ /* */ /* This thread is created by hao_initialize. It examines every message */ /* printed. Here we check if a rule applies to the message. If so we fire */ /* the command within the rule. */ /*---------------------------------------------------------------------------*/ static void* hao_thread(void* dummy) { char* msgbuf = NULL; int msgidx = -1; int msgamt = 0; char* msgend = NULL; char svchar = 0; int bufamt = 0; UNREFERENCED(dummy); logmsg(HHCAO001I, thread_id(), getpriority(PRIO_PROCESS,0), getpid()); /* Wait for panel thread to engage */ while (!sysblk.panel_init && !sysblk.shutdown) usleep( 10 * 1000 ); /* Do until shutdown */ while (!sysblk.shutdown && msgamt >= 0) { /* wait for message data */ if ((msgamt = log_read(&msgbuf, &msgidx, LOG_BLOCK)) > 0 ) { /* append to existing data */ if (msgamt > (int)((sizeof(ao_msgbuf) - 1) - bufamt) ) msgamt = (int)((sizeof(ao_msgbuf) - 1) - bufamt); strncpy( &ao_msgbuf[bufamt], msgbuf, msgamt ); ao_msgbuf[bufamt += msgamt] = 0; msgbuf = ao_msgbuf; /* process only complete messages */ while (NULL != (msgend = strchr(msgbuf,'\n'))) { /* null terminate message */ svchar = *(msgend+1); *(msgend+1) = 0; /* process message */ hao_message(msgbuf); /* restore destroyed byte */ *(msgend+1) = svchar; msgbuf = msgend+1; } /* shift message buffer */ memmove( ao_msgbuf, msgbuf, bufamt -= (msgbuf - ao_msgbuf) ); } } logmsg(HHCAO002I); return NULL; } /*---------------------------------------------------------------------------*/ /* size_t hao_subst(char *str, size_t soff, size_t eoff, */ /* char *cmd, size_t coff, size_t csize) */ /* */ /* This function copies a substring of the original string into */ /* the command buffer. The input parameters are: */ /* str the original string */ /* soff starting offset of the substring in the original string */ /* eoff offset of the first character following the substring */ /* cmd the destination command buffer */ /* coff offset in the command buffer to copy the substring */ /* csize size of the command buffer (including terminating zero) */ /* The return value is the number of characters copied. */ /*---------------------------------------------------------------------------*/ static size_t hao_subst(char *str, size_t soff, size_t eoff, char *cmd, size_t coff, size_t csize) { size_t len = eoff - soff; if (soff + len > strlen(str)) len = strlen(str) - soff; if (coff + len > csize-1) len = csize-1 - coff; memcpy(cmd + coff, str + soff, len); return len; } /*---------------------------------------------------------------------------*/ /* void hao_message(char *buf) */ /* */ /* This function is called by hao_thread whenever a message is about to be */ /* printed. Here we check if a rule applies to the message. If so we fire */ /* the command within the rule. */ /*---------------------------------------------------------------------------*/ DLL_EXPORT void hao_message(char *buf) { char work[HAO_WKLEN]; char cmd[HAO_WKLEN]; regmatch_t rm[HAO_MAXCAPT+1]; int i, j, k, numcapt; size_t n; char *p; /* copy and strip spaces */ hao_cpstrp(work, buf); /* strip the herc prefix */ while(!strncmp(work, "herc", 4)) hao_cpstrp(work, &work[4]); /* don't react on own messages */ if(!strncmp(work, "HHCAO", 5)) return; /* don't react on own commands */ if(!strncasecmp(work, "hao", 3)) return; /* also from the .rc file */ if(!strncasecmp(work, "> hao", 5)) return; /* serialize */ obtain_lock(&ao_lock); /* check all defined rules */ for(i = 0; i < HAO_MAXRULE; i++) { if(ao_tgt[i] && ao_cmd[i]) /* complete rule defined in this slot? */ { /* does this rule match our message? */ if (regexec(&ao_preg[i], work, HAO_MAXCAPT+1, rm, 0) == 0) { /* count the capturing group matches */ for (j = 0; j <= HAO_MAXCAPT && rm[j].rm_so >= 0; j++); numcapt = j - 1; /* copy the command and process replacement patterns */ for (n=0, p=ao_cmd[i]; *p && n < sizeof(cmd)-1; ) { /* replace $$ by $ */ if (*p == '$' && p[1] == '$') { cmd[n++] = '$'; p += 2; continue; } /* replace $` by characters to the left of the match */ if (*p == '$' && p[1] == '`') { n += hao_subst(work, 0, rm[0].rm_so, cmd, n, sizeof(cmd)); p += 2; continue; } /* replace $' by characters to the right of the match */ if (*p == '$' && p[1] == '\'') { n += hao_subst(work, rm[0].rm_eo, strlen(work), cmd, n, sizeof(cmd)); p += 2; continue; } /* replace $1..$99 by the corresponding capturing group */ if (*p == '$' && isdigit(p[1])) { if (isdigit(p[2])) { j = (p[1]-'0') * 10 + (p[2]-'0'); k = 3; } else { j = p[1]-'0'; k = 2; } if (j > 0 && j <= numcapt) { n += hao_subst(work, rm[j].rm_so, rm[j].rm_eo, cmd, n, sizeof(cmd)); p += k; continue; } } /* otherwise copy one character */ cmd[n++] = *p++; } cmd[n] = '\0'; /* issue command for this rule */ logmsg(HHCAO003I, cmd); panel_command(cmd); } } } release_lock(&ao_lock); } #endif /* defined(OPTION_HAO) */ hercules-3.12/hscmisc.c0000664000175000017500000013773712564723224012022 00000000000000/* HSCMISC.C (c) Copyright Roger Bowler, 1999-2009 */ /* (c) Copyright Jan Jaeger, 1999-2009 */ /* Miscellaneous System Command Routines */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_HSCMISC_C_) #define _HSCMISC_C_ #endif #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "inline.h" #define DISPLAY_INSTRUCTION_OPERANDS #if !defined(_HSCMISC_C) #define _HSCMISC_C /*-------------------------------------------------------------------*/ /* System Shutdown Processing */ /*-------------------------------------------------------------------*/ /* The following 'sigq' functions are responsible for ensuring all of the CPUs are stopped ("quiesced") before continuing with Hercules shutdown processing, and should NEVER be called directly. Instead, they are called by the main 'do_shutdown' (or 'do_shutdown_wait') function(s) (defined further below) as needed and/or appropriate. */ static int wait_sigq_pending = 0; static int is_wait_sigq_pending() { int pending; OBTAIN_INTLOCK(NULL); pending = wait_sigq_pending; RELEASE_INTLOCK(NULL); return pending; } static void wait_sigq_resp() { int pending, i; /* Wait for all CPU's to stop */ do { OBTAIN_INTLOCK(NULL); wait_sigq_pending = 0; for (i = 0; i < MAX_CPU_ENGINES; i++) if (IS_CPU_ONLINE(i) && sysblk.regs[i]->cpustate != CPUSTATE_STOPPED) wait_sigq_pending = 1; pending = wait_sigq_pending; RELEASE_INTLOCK(NULL); if(pending) SLEEP(1); } while(is_wait_sigq_pending()); } static void cancel_wait_sigq() { OBTAIN_INTLOCK(NULL); wait_sigq_pending = 0; RELEASE_INTLOCK(NULL); } /* do_shutdown_now This is the main shutdown processing function. It is NEVER called directly, but is instead ONLY called by either the 'do_shutdown' or 'do_shutdown_wait' functions after all CPUs have been stopped. It is responsible for releasing the device configuration and then calling the Hercules Dynamic Loader "hdl_shut" function to invoke all registered "Hercules at-exit/termination functions" (similar to 'atexit' but unique to Hercules) (to perform any other needed miscellaneous shutdown related processing). Only after the above three tasks have been completed (stopping the CPUs, releasing the device configuration, calling registered term- ination routines/functions) can Hercules then be safely terminated. Note too that, *technically*, this function *should* wait for *all* other threads to finish terminating first before either exiting or returning back to the caller, but we don't currently enforce that (since that's *really* what hdl_adsc + hdl_shut is designed for!). At the moment, as long as the three previously mentioned three most important shutdown tasks have been completed (stop cpus, release device config, call term funcs), then we consider the brunt of our shutdown processing to be completed and thus exit (or return back to the caller to let them exit instead). If there happen to be any threads still running when that happens, they will be automatically terminated by the operating sytem as normal when a process exits. SO... If there are any threads that must be terminated completely and cleanly before Hercules can safely terminate, then you better add code to this function to ENSURE that your thread is terminated properly! (and/or add a call to 'hdl_adsc' at the appropriate place in the startup sequence). For this purpose, the use of "join_thread" is *strongly* encouraged as it *ensures* that your thread will not continue until the thread in question has completely exited first. */ static void do_shutdown_now() { logmsg("HHCIN900I Begin Hercules shutdown\n"); ASSERT( !sysblk.shutfini ); // (sanity check) sysblk.shutfini = 0; // (shutdown NOT finished yet) sysblk.shutdown = 1; // (system shutdown initiated) logmsg("HHCIN901I Releasing configuration\n"); { release_config(); } logmsg("HHCIN902I Configuration release complete\n"); logmsg("HHCIN903I Calling termination routines\n"); { hdl_shut(); } logmsg("HHCIN904I All termination routines complete\n"); /* logmsg("HHCIN905I Terminating threads\n"); { // (none we really care about at the moment...) } logmsg("HHCIN906I Threads terminations complete\n"); */ logmsg("HHCIN909I Hercules shutdown complete\n"); sysblk.shutfini = 1; // (shutdown is now complete) // PROGRAMMING NOTE // If we're NOT in "daemon_mode" (i.e. panel_display in control), // -OR- if a daemon_task DOES exist, then THEY are in control of // shutdown; THEY are responsible for exiting the system whenever // THEY feel it's proper to do so (by simply returning back to the // caller thereby allowing 'main' to return back to the operating // system). // OTHEWRWISE we ARE in "daemon_mode", but a daemon_task does NOT // exist, which means the main thread (tail end of 'impl.c') is // stuck in a loop reading log messages and writing them to the // logfile, so we need to do the exiting here since it obviously // cannot. if ( sysblk.daemon_mode #if defined(OPTION_DYNAMIC_LOAD) && !daemon_task #endif /*defined(OPTION_DYNAMIC_LOAD)*/ ) { #ifdef _MSVC_ socket_deinit(); #endif #ifdef DEBUG fprintf(stdout, _("DO_SHUTDOWN_NOW EXIT\n")); #endif fprintf(stdout, _("HHCIN099I Hercules terminated\n")); fflush(stdout); exit(0); } } /* do_shutdown_wait This function simply waits for the CPUs to stop and then calls the above do_shutdown_now function to perform the actual shutdown (which releases the device configuration, etc) */ static void do_shutdown_wait() { logmsg(_("HHCIN098I Shutdown initiated\n")); wait_sigq_resp(); do_shutdown_now(); } /* ***** do_shutdown ***** This is the main system shutdown function, and the ONLY function that should EVER be called to shut the system down. It calls one or more of the above static helper functions as needed. */ void do_shutdown() { TID tid; #if defined(_MSVC_) if ( sysblk.shutimmed ) do_shutdown_now(); else { #endif // defined(_MSVC_) if(is_wait_sigq_pending()) cancel_wait_sigq(); else if(can_signal_quiesce() && !signal_quiesce(0,0)) create_thread(&tid, DETACHED, do_shutdown_wait, NULL, "do_shutdown_wait"); else do_shutdown_now(); #if defined(_MSVC_) } #endif // defined(_MSVC_) } /*-------------------------------------------------------------------*/ /* The following 2 routines display an array of 32/64 registers */ /* 1st parameter is the register type (GR, CR, AR, etc..) */ /* 2nd parameter is the CPU Address involved */ /* 3rd parameter is an array of 32/64 bit regs */ /* NOTE : 32 bit regs are displayed 4 by 4, while 64 bit regs are */ /* displayed 2 by 2. Change the modulo if to change this */ /* behaviour. */ /* These routines are intended to be invoked by display_regs, */ /* display_cregs and display_aregs */ /* Ivan Warren 2005/11/07 */ /*-------------------------------------------------------------------*/ static void display_regs32(char *hdr,U16 cpuad,U32 *r,int numcpus) { int i; for(i=0;i<16;i++) { if(!(i%4)) { if(i) { logmsg("\n"); } if(numcpus>1) { logmsg("CPU%4.4X: ",cpuad); } } if(i%4) { logmsg(" "); } logmsg("%s%2.2d=%8.8"I32_FMT"X",hdr,i,r[i]); } logmsg("\n"); } #if defined(_900) static void display_regs64(char *hdr,U16 cpuad,U64 *r,int numcpus) { int i; int rpl; if(numcpus>1) { rpl=2; } else { rpl=4; } for(i=0;i<16;i++) { if(!(i%rpl)) { if(i) { logmsg("\n"); } if(numcpus>1) { logmsg("CPU%4.4X: ",cpuad); } } if(i%rpl) { logmsg(" "); } logmsg("%s%1.1X=%16.16"I64_FMT"X",hdr,i,r[i]); } logmsg("\n"); } #endif /*-------------------------------------------------------------------*/ /* Display registers for the instruction display */ /*-------------------------------------------------------------------*/ void display_inst_regs (REGS *regs, BYTE *inst, BYTE opcode) { /* Display the general purpose registers */ if (!(opcode == 0xB3 || (opcode >= 0x20 && opcode <= 0x3F)) || (opcode == 0xB3 && ( (inst[1] >= 0x80 && inst[1] <= 0xCF) || (inst[1] >= 0xE1 && inst[1] <= 0xFE) ))) { display_regs (regs); if (sysblk.showregsfirst) logmsg("\n"); } /* Display control registers if appropriate */ if (!REAL_MODE(®s->psw) || opcode == 0xB2) { display_cregs (regs); if (sysblk.showregsfirst) logmsg("\n"); } /* Display access registers if appropriate */ if (!REAL_MODE(®s->psw) && ACCESS_REGISTER_MODE(®s->psw)) { display_aregs (regs); if (sysblk.showregsfirst) logmsg("\n"); } /* Display floating-point registers if appropriate */ if (opcode == 0xB3 || opcode == 0xED || (opcode >= 0x20 && opcode <= 0x3F) || (opcode >= 0x60 && opcode <= 0x70) || (opcode >= 0x78 && opcode <= 0x7F) || (opcode == 0xB2 && inst[1] == 0x2D) /*DXR*/ || (opcode == 0xB2 && inst[1] == 0x44) /*SQDR*/ || (opcode == 0xB2 && inst[1] == 0x45) /*SQER*/ ) { display_fregs (regs); if (sysblk.showregsfirst) logmsg("\n"); } } /*-------------------------------------------------------------------*/ /* Display general purpose registers */ /*-------------------------------------------------------------------*/ void display_regs (REGS *regs) { int i; U32 gprs[16]; #if defined(_900) U64 ggprs[16]; #endif #if defined(_900) if(regs->arch_mode != ARCH_900) { #endif for(i=0;i<16;i++) { gprs[i]=regs->GR_L(i); } display_regs32("GR",regs->cpuad,gprs,sysblk.cpus); #if defined(_900) } else { for(i=0;i<16;i++) { ggprs[i]=regs->GR_G(i); } display_regs64("R",regs->cpuad,ggprs,sysblk.cpus); } #endif } /* end function display_regs */ /*-------------------------------------------------------------------*/ /* Display control registers */ /*-------------------------------------------------------------------*/ void display_cregs (REGS *regs) { int i; U32 crs[16]; #if defined(_900) U64 gcrs[16]; #endif #if defined(_900) if(regs->arch_mode != ARCH_900) { #endif for(i=0;i<16;i++) { crs[i]=regs->CR_L(i); } display_regs32("CR",regs->cpuad,crs,sysblk.cpus); #if defined(_900) } else { for(i=0;i<16;i++) { gcrs[i]=regs->CR_G(i); } display_regs64("C",regs->cpuad,gcrs,sysblk.cpus); } #endif } /* end function display_cregs */ /*-------------------------------------------------------------------*/ /* Display access registers */ /*-------------------------------------------------------------------*/ void display_aregs (REGS *regs) { int i; U32 ars[16]; for(i=0;i<16;i++) { ars[i]=regs->AR(i); } display_regs32("AR",regs->cpuad,ars,sysblk.cpus); } /* end function display_aregs */ /*-------------------------------------------------------------------*/ /* Display floating point registers */ /*-------------------------------------------------------------------*/ void display_fregs (REGS *regs) { char cpustr[10] = {0}; /* "CPU:nnnn " or "" */ if(sysblk.cpus>1) sprintf(cpustr, "CPU%4.4X: ", regs->cpuad); if(regs->CR(0) & CR0_AFP) logmsg ( "%sFPR0=%8.8X %8.8X FPR2=%8.8X %8.8X\n" "%sFPR1=%8.8X %8.8X FPR3=%8.8X %8.8X\n" "%sFPR4=%8.8X %8.8X FPR6=%8.8X %8.8X\n" "%sFPR5=%8.8X %8.8X FPR7=%8.8X %8.8X\n" "%sFPR8=%8.8X %8.8X FP10=%8.8X %8.8X\n" "%sFPR9=%8.8X %8.8X FP11=%8.8X %8.8X\n" "%sFP12=%8.8X %8.8X FP14=%8.8X %8.8X\n" "%sFP13=%8.8X %8.8X FP15=%8.8X %8.8X\n" ,cpustr, regs->fpr[0], regs->fpr[1], regs->fpr[4], regs->fpr[5] ,cpustr, regs->fpr[2], regs->fpr[3], regs->fpr[6], regs->fpr[7] ,cpustr, regs->fpr[8], regs->fpr[9], regs->fpr[12], regs->fpr[13] ,cpustr, regs->fpr[10], regs->fpr[11], regs->fpr[14], regs->fpr[15] ,cpustr, regs->fpr[16], regs->fpr[17], regs->fpr[20], regs->fpr[21] ,cpustr, regs->fpr[18], regs->fpr[19], regs->fpr[22], regs->fpr[23] ,cpustr, regs->fpr[24], regs->fpr[25], regs->fpr[28], regs->fpr[29] ,cpustr, regs->fpr[26], regs->fpr[27], regs->fpr[30], regs->fpr[31] ); else logmsg ( "%sFPR0=%8.8X %8.8X FPR2=%8.8X %8.8X\n" "%sFPR4=%8.8X %8.8X FPR6=%8.8X %8.8X\n" ,cpustr, regs->fpr[0], regs->fpr[1], regs->fpr[2], regs->fpr[3] ,cpustr, regs->fpr[4], regs->fpr[5], regs->fpr[6], regs->fpr[7] ); } /* end function display_fregs */ /*-------------------------------------------------------------------*/ /* Display subchannel */ /*-------------------------------------------------------------------*/ void display_subchannel (DEVBLK *dev) { logmsg ("%4.4X:D/T=%4.4X", dev->devnum, dev->devtype); if (ARCH_370 == sysblk.arch_mode) { logmsg (" CSW=Flags:%2.2X CCW:%2.2X%2.2X%2.2X " "Stat:%2.2X%2.2X Count:%2.2X%2.2X\n", dev->csw[0], dev->csw[1], dev->csw[2], dev->csw[3], dev->csw[4], dev->csw[5], dev->csw[6], dev->csw[7]); } else { logmsg (" Subchannel_Number=%4.4X\n", dev->subchan); logmsg (" PMCW=IntParm:%2.2X%2.2X%2.2X%2.2X Flags:%2.2X%2.2X" " Dev:%2.2X%2.2X" " LPM:%2.2X PNOM:%2.2X LPUM:%2.2X PIM:%2.2X\n" " MBI:%2.2X%2.2X POM:%2.2X PAM:%2.2X" " CHPIDs:%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X" " Misc:%2.2X%2.2X%2.2X%2.2X\n", dev->pmcw.intparm[0], dev->pmcw.intparm[1], dev->pmcw.intparm[2], dev->pmcw.intparm[3], dev->pmcw.flag4, dev->pmcw.flag5, dev->pmcw.devnum[0], dev->pmcw.devnum[1], dev->pmcw.lpm, dev->pmcw.pnom, dev->pmcw.lpum, dev->pmcw.pim, dev->pmcw.mbi[0], dev->pmcw.mbi[1], dev->pmcw.pom, dev->pmcw.pam, dev->pmcw.chpid[0], dev->pmcw.chpid[1], dev->pmcw.chpid[2], dev->pmcw.chpid[3], dev->pmcw.chpid[4], dev->pmcw.chpid[5], dev->pmcw.chpid[6], dev->pmcw.chpid[7], dev->pmcw.zone, dev->pmcw.flag25, dev->pmcw.flag26, dev->pmcw.flag27); logmsg (" SCSW=Flags:%2.2X%2.2X SCHC:%2.2X%2.2X " "Stat:%2.2X%2.2X Count:%2.2X%2.2X " "CCW:%2.2X%2.2X%2.2X%2.2X\n", dev->scsw.flag0, dev->scsw.flag1, dev->scsw.flag2, dev->scsw.flag3, dev->scsw.unitstat, dev->scsw.chanstat, dev->scsw.count[0], dev->scsw.count[1], dev->scsw.ccwaddr[0], dev->scsw.ccwaddr[1], dev->scsw.ccwaddr[2], dev->scsw.ccwaddr[3]); } } /* end function display_subchannel */ /*-------------------------------------------------------------------*/ /* Parse a storage range or storage alteration operand */ /* */ /* Valid formats for a storage range operand are: */ /* startaddr */ /* startaddr-endaddr */ /* startaddr.length */ /* where startaddr, endaddr, and length are hexadecimal values. */ /* */ /* Valid format for a storage alteration operand is: */ /* startaddr=hexstring (up to 32 pairs of digits) */ /* */ /* Return values: */ /* 0 = operand contains valid storage range display syntax; */ /* start/end of range is returned in saddr and eaddr */ /* >0 = operand contains valid storage alteration syntax; */ /* return value is number of bytes to be altered; */ /* start/end/value are returned in saddr, eaddr, newval */ /* -1 = error message issued */ /*-------------------------------------------------------------------*/ static int parse_range (char *operand, U64 maxadr, U64 *sadrp, U64 *eadrp, BYTE *newval) { U64 opnd1, opnd2; /* Address/length operands */ U64 saddr, eaddr; /* Range start/end addresses */ int rc; /* Return code */ int n; /* Number of bytes altered */ int h1, h2; /* Hexadecimal digits */ char *s; /* Alteration value pointer */ BYTE delim; /* Operand delimiter */ BYTE c; /* Character work area */ rc = sscanf(operand, "%"I64_FMT"x%c%"I64_FMT"x%c", &opnd1, &delim, &opnd2, &c); /* Process storage alteration operand */ if (rc > 2 && delim == '=' && newval) { s = strchr (operand, '='); for (n = 0; n < 32;) { h1 = *(++s); if (h1 == '\0' || h1 == '#' ) break; if (h1 == SPACE || h1 == '\t') continue; h1 = toupper(h1); h2 = *(++s); h2 = toupper(h2); h1 = (h1 >= '0' && h1 <= '9') ? h1 - '0' : (h1 >= 'A' && h1 <= 'F') ? h1 - 'A' + 10 : -1; h2 = (h2 >= '0' && h2 <= '9') ? h2 - '0' : (h2 >= 'A' && h2 <= 'F') ? h2 - 'A' + 10 : -1; if (h1 < 0 || h2 < 0 || n >= 32) { logmsg (_("HHCPN143E Invalid value: %s\n"), s); return -1; } newval[n++] = (h1 << 4) | h2; } /* end for(n) */ saddr = opnd1; eaddr = saddr + n - 1; } else { /* Process storage range operand */ saddr = opnd1; if (rc == 1) { /* If only starting address is specified, default to 64 byte display, or less if near end of storage */ eaddr = saddr + 0x3F; if (eaddr > maxadr) eaddr = maxadr; } else { /* Ending address or length is specified */ if (rc != 3 || !(delim == '-' || delim == '.')) { logmsg (_("HHCPN144E Invalid operand: %s\n"), operand); return -1; } eaddr = (delim == '.') ? saddr + opnd2 - 1 : opnd2; } /* Set n=0 to indicate storage display only */ n = 0; } /* Check for valid range */ if (saddr > maxadr || eaddr > maxadr || eaddr < saddr) { logmsg (_("HHCPN145E Invalid range: %s\n"), operand); return -1; } /* Return start/end addresses and number of bytes altered */ *sadrp = saddr; *eadrp = eaddr; return n; } /* end function parse_range */ /*-------------------------------------------------------------------*/ /* get_connected_client return IP address and hostname of the */ /* client that is connected to this device */ /*-------------------------------------------------------------------*/ void get_connected_client (DEVBLK* dev, char** pclientip, char** pclientname) { *pclientip = NULL; *pclientname = NULL; obtain_lock (&dev->lock); if (dev->bs /* if device is a socket device, */ && dev->fd != -1) /* and a client is connected to it */ { *pclientip = strdup(dev->bs->clientip); *pclientname = strdup(dev->bs->clientname); } release_lock (&dev->lock); } /*-------------------------------------------------------------------*/ /* Return the address of a regs structure to be used for address */ /* translation. This address should be freed by the caller. */ /*-------------------------------------------------------------------*/ static REGS *copy_regs (REGS *regs) { REGS *newregs, *hostregs; size_t size; size = (SIE_MODE(regs) || SIE_ACTIVE(regs)) ? 2*sizeof(REGS) : sizeof(REGS); newregs = malloc(size); if (newregs == NULL) { logmsg(_("HHCMS001E malloc failed for REGS copy: %s\n"), strerror(errno)); return NULL; } /* Perform partial copy and clear the TLB */ memcpy(newregs, regs, sysblk.regs_copy_len); memset(&newregs->tlb.vaddr, 0, TLBN * sizeof(DW)); newregs->tlbID = 1; newregs->ghostregs = 1; newregs->hostregs = newregs; newregs->guestregs = NULL; newregs->sie_active=0; /* Copy host regs if in SIE mode */ /* newregs is a SIE Guest REGS */ if(SIE_MODE(newregs)) { hostregs = newregs + 1; memcpy(hostregs, regs->hostregs, sysblk.regs_copy_len); memset(&hostregs->tlb.vaddr, 0, TLBN * sizeof(DW)); hostregs->tlbID = 1; hostregs->ghostregs = 1; hostregs->hostregs = hostregs; hostregs->guestregs = newregs; newregs->hostregs = hostregs; newregs->guestregs = newregs; } return newregs; } #endif /*!defined(_HSCMISC_C)*/ /*-------------------------------------------------------------------*/ /* Convert virtual address to absolute address */ /* */ /* Input: */ /* vaddr Virtual address to be translated */ /* arn Access register number */ /* regs CPU register context */ /* acctype Type of access (ACCTYPE_INSTFETCH, ACCTYPE_READ, */ /* or ACCTYPE_LRA) */ /* Output: */ /* aaptr Points to word in which abs address is returned */ /* siptr Points to word to receive indication of which */ /* STD or ASCE was used to perform the translation */ /* Return value: */ /* 0=translation successful, non-zero=exception code */ /* Note: */ /* To avoid unwanted alteration of the CPU register context */ /* during translation (for example, the TEA will be updated */ /* if a translation exception occurs), the translation is */ /* performed using a temporary copy of the CPU registers. */ /*-------------------------------------------------------------------*/ static U16 ARCH_DEP(virt_to_abs) (RADR *raptr, int *siptr, VADR vaddr, volatile int arn, REGS *regs, int acctype) { int icode; if( !(icode = setjmp(regs->progjmp)) ) { int temp_arn = arn; // bypass longjmp clobber warning if (acctype == ACCTYPE_INSTFETCH) temp_arn = USE_INST_SPACE; if (SIE_MODE(regs)) memcpy(regs->hostregs->progjmp, regs->progjmp, sizeof(jmp_buf)); ARCH_DEP(logical_to_main) (vaddr, temp_arn, regs, acctype, 0); } *siptr = regs->dat.stid; *raptr = regs->hostregs->dat.raddr; return icode; } /* end function virt_to_abs */ /*-------------------------------------------------------------------*/ /* Display real storage (up to 16 bytes, or until end of page) */ /* Prefixes display by Rxxxxx: if draflag is 1 */ /* Returns number of characters placed in display buffer */ /*-------------------------------------------------------------------*/ static int ARCH_DEP(display_real) (REGS *regs, RADR raddr, char *buf, int draflag) { RADR aaddr; /* Absolute storage address */ int i, j; /* Loop counters */ int n = 0; /* Number of bytes in buffer */ char hbuf[40]; /* Hexadecimal buffer */ BYTE cbuf[17]; /* Character buffer */ BYTE c; /* Character work area */ #if defined(FEATURE_INTERVAL_TIMER) if(ITIMER_ACCESS(raddr,16)) ARCH_DEP(store_int_timer)(regs); #endif if (draflag) { n = sprintf (buf, "R:"F_RADR":", raddr); } aaddr = APPLY_PREFIXING (raddr, regs->PX); if (aaddr > regs->mainlim) { n += sprintf (buf+n, " Real address is not valid"); return n; } n += sprintf (buf+n, "K:%2.2X=", STORAGE_KEY(aaddr, regs)); memset (hbuf, SPACE, sizeof(hbuf)); memset (cbuf, SPACE, sizeof(cbuf)); for (i = 0, j = 0; i < 16; i++) { c = regs->mainstor[aaddr++]; j += sprintf (hbuf+j, "%2.2X", c); if ((aaddr & 0x3) == 0x0) hbuf[j++] = SPACE; c = guest_to_host(c); if (!isprint(c)) c = '.'; cbuf[i] = c; if ((aaddr & PAGEFRAME_BYTEMASK) == 0x000) break; } /* end for(i) */ n += sprintf (buf+n, "%36.36s %16.16s", hbuf, cbuf); return n; } /* end function display_real */ /*-------------------------------------------------------------------*/ /* Display virtual storage (up to 16 bytes, or until end of page) */ /* Returns number of characters placed in display buffer */ /*-------------------------------------------------------------------*/ static int ARCH_DEP(display_virt) (REGS *regs, VADR vaddr, char *buf, int ar, int acctype) { RADR raddr; /* Real address */ int n; /* Number of bytes in buffer */ int stid; /* Segment table indication */ U16 xcode; /* Exception code */ n = sprintf (buf, "%c:"F_VADR":", ar == USE_REAL_ADDR ? 'R' : 'V', vaddr); xcode = ARCH_DEP(virt_to_abs) (&raddr, &stid, vaddr, ar, regs, acctype); if (xcode == 0) { n += ARCH_DEP(display_real) (regs, raddr, buf+n, 0); } else n += sprintf (buf+n," Translation exception %4.4hX",xcode); return n; } /* end function display_virt */ /*-------------------------------------------------------------------*/ /* Disassemble real */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(disasm_stor) (REGS *regs, char *opnd) { U64 saddr, eaddr; /* Range start/end addresses */ U64 maxadr; /* Highest real storage addr */ RADR raddr; /* Real storage address */ RADR aaddr; /* Absolute storage address */ int stid = -1; int len; /* Number of bytes to alter */ int i; /* Loop counter */ int ilc; BYTE inst[6]; /* Storage alteration value */ BYTE opcode; U16 xcode; char type; char buf[80]; /* Set limit for address range */ #if defined(FEATURE_ESAME) maxadr = 0xFFFFFFFFFFFFFFFFULL; #else /*!defined(FEATURE_ESAME)*/ maxadr = 0x7FFFFFFF; #endif /*!defined(FEATURE_ESAME)*/ while((opnd && *opnd != '\0') && (*opnd == ' ' || *opnd == '\t')) opnd++; if(REAL_MODE(®s->psw)) type = 'R'; else type = 'V'; switch(toupper(*opnd)) { case 'R': /* real */ case 'V': /* virtual */ case 'P': /* primary */ case 'H': /* home */ type = toupper(*opnd); opnd++; } /* Parse the range or alteration operand */ len = parse_range (opnd, maxadr, &saddr, &eaddr, NULL); if (len < 0) return; /* Display real storage */ for (i = 0; i < 999 && saddr <= eaddr; i++) { if(type == 'R') raddr = saddr; else { if((xcode = ARCH_DEP(virt_to_abs) (&raddr, &stid, saddr, 0, regs, ACCTYPE_INSTFETCH) )) { logmsg(_("Storage not accessible code = %4.4X\n"), xcode); return; } } aaddr = APPLY_PREFIXING (raddr, regs->PX); if (aaddr > regs->mainlim) { logmsg(_("Addressing exception\n")); return; } opcode = regs->mainstor[aaddr]; ilc = ILC(opcode); if (aaddr + ilc > regs->mainlim) { logmsg(_("Addressing exception\n")); return; } memcpy(inst, regs->mainstor + aaddr, ilc); logmsg("%c" F_RADR ": %2.2X%2.2X", stid == TEA_ST_PRIMARY ? 'P' : stid == TEA_ST_HOME ? 'H' : stid == TEA_ST_SECNDRY ? 'S' : 'R', raddr, inst[0], inst[1]); if(ilc > 2) { logmsg("%2.2X%2.2X", inst[2], inst[3]); if(ilc > 4) logmsg("%2.2X%2.2X ", inst[4], inst[5]); else logmsg(" "); } else logmsg(" "); DISASM_INSTRUCTION(inst, buf); logmsg("%s\n", buf); saddr += ilc; } /* end for(i) */ } /* end function disasm_stor */ /*-------------------------------------------------------------------*/ /* Process real storage alter/display command */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(alter_display_real) (char *opnd, REGS *regs) { U64 saddr, eaddr; /* Range start/end addresses */ U64 maxadr; /* Highest real storage addr */ RADR raddr; /* Real storage address */ RADR aaddr; /* Absolute storage address */ int len; /* Number of bytes to alter */ int i; /* Loop counter */ BYTE newval[32]; /* Storage alteration value */ char buf[100]; /* Message buffer */ /* Set limit for address range */ #if defined(FEATURE_ESAME) maxadr = 0xFFFFFFFFFFFFFFFFULL; #else /*!defined(FEATURE_ESAME)*/ maxadr = 0x7FFFFFFF; #endif /*!defined(FEATURE_ESAME)*/ /* Parse the range or alteration operand */ len = parse_range (opnd, maxadr, &saddr, &eaddr, newval); if (len < 0) return; raddr = saddr; /* Alter real storage */ if (len > 0) { for (i = 0; i < len && raddr+i <= regs->mainlim; i++) { aaddr = raddr + i; aaddr = APPLY_PREFIXING (aaddr, regs->PX); regs->mainstor[aaddr] = newval[i]; STORAGE_KEY(aaddr, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* end for(i) */ } /* Display real storage */ for (i = 0; i < 999 && raddr <= eaddr; i++) { ARCH_DEP(display_real) (regs, raddr, buf, 1); logmsg ("%s\n", buf); raddr += 16; } /* end for(i) */ } /* end function alter_display_real */ /*-------------------------------------------------------------------*/ /* Process virtual storage alter/display command */ /*-------------------------------------------------------------------*/ static void ARCH_DEP(alter_display_virt) (char *opnd, REGS *regs) { U64 saddr, eaddr; /* Range start/end addresses */ U64 maxadr; /* Highest virt storage addr */ VADR vaddr; /* Virtual storage address */ RADR raddr; /* Real storage address */ RADR aaddr; /* Absolute storage address */ int stid; /* Segment table indication */ int len; /* Number of bytes to alter */ int i; /* Loop counter */ int n; /* Number of bytes in buffer */ int arn = 0; /* Access register number */ U16 xcode; /* Exception code */ BYTE newval[32]; /* Storage alteration value */ char buf[100]; /* Message buffer */ /* Set limit for address range */ #if defined(FEATURE_ESAME) maxadr = 0xFFFFFFFFFFFFFFFFULL; #else /*!defined(FEATURE_ESAME)*/ maxadr = 0x7FFFFFFF; #endif /*!defined(FEATURE_ESAME)*/ while((opnd && *opnd != '\0') && (*opnd == ' ' || *opnd == '\t')) opnd++; switch(toupper(*opnd)) { case 'P': /* primary */ arn = USE_PRIMARY_SPACE; opnd++; break; case 'S': /* secondary */ arn = USE_SECONDARY_SPACE; opnd++; break; case 'H': /* home */ arn = USE_HOME_SPACE; opnd++; break; } /* Parse the range or alteration operand */ len = parse_range (opnd, maxadr, &saddr, &eaddr, newval); if (len < 0) return; vaddr = saddr; /* Alter virtual storage */ if (len > 0 && ARCH_DEP(virt_to_abs) (&raddr, &stid, vaddr, arn, regs, ACCTYPE_LRA) == 0 && ARCH_DEP(virt_to_abs) (&raddr, &stid, eaddr, arn, regs, ACCTYPE_LRA) == 0) { for (i = 0; i < len && raddr+i <= regs->mainlim; i++) { ARCH_DEP(virt_to_abs) (&raddr, &stid, vaddr+i, arn, regs, ACCTYPE_LRA); aaddr = APPLY_PREFIXING (raddr, regs->PX); regs->mainstor[aaddr] = newval[i]; STORAGE_KEY(aaddr, regs) |= (STORKEY_REF | STORKEY_CHANGE); } /* end for(i) */ } /* Display virtual storage */ for (i = 0; i < 999 && vaddr <= eaddr; i++) { if (i == 0 || (vaddr & PAGEFRAME_BYTEMASK) < 16) { xcode = ARCH_DEP(virt_to_abs) (&raddr, &stid, vaddr, arn, regs, ACCTYPE_LRA); n = sprintf (buf, "V:"F_VADR" ", vaddr); if (REAL_MODE(®s->psw)) n += sprintf (buf+n, "(dat off)"); else if (stid == TEA_ST_PRIMARY) n += sprintf (buf+n, "(primary)"); else if (stid == TEA_ST_SECNDRY) n += sprintf (buf+n, "(secondary)"); else if (stid == TEA_ST_HOME) n += sprintf (buf+n, "(home)"); else n += sprintf (buf+n, "(AR%2.2d)", arn); if (xcode == 0) n += sprintf (buf+n, " R:"F_RADR, raddr); logmsg ("%s\n", buf); } ARCH_DEP(display_virt) (regs, vaddr, buf, arn, ACCTYPE_LRA); logmsg ("%s\n", buf); vaddr += 16; } /* end for(i) */ } /* end function alter_display_virt */ /*-------------------------------------------------------------------*/ /* Display instruction */ /*-------------------------------------------------------------------*/ void ARCH_DEP(display_inst) (REGS *iregs, BYTE *inst) { QWORD qword; /* Doubleword work area */ BYTE opcode; /* Instruction operation code*/ int ilc; /* Instruction length */ #ifdef DISPLAY_INSTRUCTION_OPERANDS int b1=-1, b2=-1, x1; /* Register numbers */ VADR addr1 = 0, addr2 = 0; /* Operand addresses */ #endif /*DISPLAY_INSTRUCTION_OPERANDS*/ char buf[256]; /* Message buffer */ int n; /* Number of bytes in buffer */ REGS *regs; /* Copied regs */ if (iregs->ghostregs) regs = iregs; else if ((regs = copy_regs(iregs)) == NULL) return; #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) logmsg(_("SIE: ")); #endif /*defined(_FEATURE_SIE)*/ #if 0 #if _GEN_ARCH == 370 logmsg("S/370 "); #elif _GEN_ARCH == 390 logmsg("ESA/390 "); #else logmsg("Z/Arch "); #endif #endif /* Display the PSW */ memset (qword, 0x00, sizeof(qword)); copy_psw (regs, qword); if(sysblk.cpus>1) { n=sprintf(buf,"CPU%4.4X: ",regs->cpuad); } else { n=0; } n += sprintf (buf+n, "PSW=%2.2X%2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X ", qword[0], qword[1], qword[2], qword[3], qword[4], qword[5], qword[6], qword[7]); #if defined(FEATURE_ESAME) n += sprintf (buf + n, "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X ", qword[8], qword[9], qword[10], qword[11], qword[12], qword[13], qword[14], qword[15]); #endif /*defined(FEATURE_ESAME)*/ /* Exit if instruction is not valid */ if (inst == NULL) { logmsg (_("%sInstruction fetch error\n"), buf); display_regs (regs); if (!iregs->ghostregs) free(regs); return; } /* Extract the opcode and determine the instruction length */ opcode = inst[0]; ilc = ILC(opcode); /* Show registers associated with the instruction */ if (sysblk.showregsfirst) display_inst_regs (regs, inst, opcode); /* Display the instruction */ n += sprintf (buf+n, "INST=%2.2X%2.2X", inst[0], inst[1]); if (ilc > 2) n += sprintf (buf+n, "%2.2X%2.2X", inst[2], inst[3]); if (ilc > 4) n += sprintf (buf+n, "%2.2X%2.2X", inst[4], inst[5]); logmsg ("%s %s", buf,(ilc<4) ? " " : (ilc<6) ? " " : ""); DISASM_INSTRUCTION(inst, buf); logmsg("%s\n", buf); #ifdef DISPLAY_INSTRUCTION_OPERANDS /* Process the first storage operand */ if (ilc > 2 && opcode != 0x84 && opcode != 0x85 && opcode != 0xA5 && opcode != 0xA7 && opcode != 0xB3 && opcode != 0xC0 && opcode != 0xC4 && opcode != 0xC6 && opcode != 0xEC) { /* Calculate the effective address of the first operand */ b1 = inst[2] >> 4; addr1 = ((inst[2] & 0x0F) << 8) | inst[3]; if (b1 != 0) { addr1 += regs->GR(b1); addr1 &= ADDRESS_MAXWRAP(regs); } /* Apply indexing for RX/RXE/RXF instructions */ if ((opcode >= 0x40 && opcode <= 0x7F) || opcode == 0xB1 || opcode == 0xE3 || opcode == 0xED) { x1 = inst[1] & 0x0F; if (x1 != 0) { addr1 += regs->GR(x1); addr1 &= ADDRESS_MAXWRAP(regs); } } } /* Process the second storage operand */ if (ilc > 4 && opcode != 0xC0 && opcode != 0xC4 && opcode != 0xC6 && opcode != 0xE3 && opcode != 0xEB && opcode != 0xEC && opcode != 0xED) { /* Calculate the effective address of the second operand */ b2 = inst[4] >> 4; addr2 = ((inst[4] & 0x0F) << 8) | inst[5]; if (b2 != 0) { addr2 += regs->GR(b2); addr2 &= ADDRESS_MAXWRAP(regs); } } /* Calculate the operand addresses for MVCL(E) and CLCL(E) */ if (opcode == 0x0E || opcode == 0x0F || opcode == 0xA8 || opcode == 0xA9) { b1 = inst[1] >> 4; addr1 = regs->GR(b1) & ADDRESS_MAXWRAP(regs); b2 = inst[1] & 0x0F; addr2 = regs->GR(b2) & ADDRESS_MAXWRAP(regs); } /* Calculate the operand addresses for RRE instructions */ if ((opcode == 0xB2 && ((inst[1] >= 0x20 && inst[1] <= 0x2F) || (inst[1] >= 0x40 && inst[1] <= 0x6F) || (inst[1] >= 0xA0 && inst[1] <= 0xAF))) || opcode == 0xB9) { b1 = inst[3] >> 4; addr1 = regs->GR(b1) & ADDRESS_MAXWRAP(regs); b2 = inst[3] & 0x0F; if (inst[1] >= 0x29 && inst[1] <= 0x2C) addr2 = regs->GR(b2) & ADDRESS_MAXWRAP_E(regs); else if (inst[1] >= 0x29 && inst[1] <= 0x2C) addr2 = regs->GR(b2) & ADDRESS_MAXWRAP(regs); else addr2 = regs->GR(b2) & ADDRESS_MAXWRAP(regs); } /* Calculate the operand address for RIL_A instructions */ if ((opcode == 0xC0 && ((inst[1] & 0x0F) == 0x00 || (inst[1] & 0x0F) == 0x04 || (inst[1] & 0x0F) == 0x05)) || opcode == 0xC4 || opcode == 0xC6) { S64 offset = 2LL*(S32)(fetch_fw(inst+2)); addr1 = (likely(!regs->execflag)) ? PSW_IA(regs, offset) : \ (regs->ET + offset) & ADDRESS_MAXWRAP(regs); b1 = 0; } /* Display storage at first storage operand location */ if (b1 >= 0) { if(REAL_MODE(®s->psw)) n = ARCH_DEP(display_virt) (regs, addr1, buf, USE_REAL_ADDR, ACCTYPE_READ); else n = ARCH_DEP(display_virt) (regs, addr1, buf, b1, (opcode == 0x44 #if defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY) || (opcode == 0xc6 && !(inst[1] & 0x0f)) #endif /*defined(FEATURE_EXECUTE_EXTENSIONS_FACILITY)*/ ? ACCTYPE_INSTFETCH : opcode == 0xB1 ? ACCTYPE_LRA : ACCTYPE_READ)); if(sysblk.cpus>1) { logmsg ("CPU%4.4X: ", regs->cpuad); } logmsg ("%s\n", buf); } /* Display storage at second storage operand location */ if (b2 >= 0) { if( (REAL_MODE(®s->psw) || (opcode == 0xB2 && inst[1] == 0x4B) /*LURA*/ || (opcode == 0xB2 && inst[1] == 0x46) /*STURA*/ || (opcode == 0xB9 && inst[1] == 0x05) /*LURAG*/ || (opcode == 0xB9 && inst[1] == 0x25))) /*STURG*/ n = ARCH_DEP(display_virt) (regs, addr2, buf, USE_REAL_ADDR, ACCTYPE_READ); else n = ARCH_DEP(display_virt) (regs, addr2, buf, b2, ACCTYPE_READ); if(sysblk.cpus>1) { logmsg ("CPU%4.4X: ", regs->cpuad); } logmsg ("%s\n", buf); } #endif /*DISPLAY_INSTRUCTION_OPERANDS*/ /* Show registers associated with the instruction */ if (!sysblk.showregsfirst && !sysblk.showregsnone) display_inst_regs (regs, inst, opcode); if (!iregs->ghostregs) free (regs); } /* end function display_inst */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "hscmisc.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "hscmisc.c" #endif /*-------------------------------------------------------------------*/ /* Wrappers for architecture-dependent functions */ /*-------------------------------------------------------------------*/ void alter_display_real (char *opnd, REGS *regs) { switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: s370_alter_display_real (opnd, regs); break; #endif #if defined(_390) case ARCH_390: s390_alter_display_real (opnd, regs); break; #endif #if defined(_900) case ARCH_900: z900_alter_display_real (opnd, regs); break; #endif } } /* end function alter_display_real */ void alter_display_virt (char *opnd, REGS *iregs) { REGS *regs; if (iregs->ghostregs) regs = iregs; else if ((regs = copy_regs(iregs)) == NULL) return; switch(sysblk.arch_mode) { #if defined(_370) case ARCH_370: s370_alter_display_virt (opnd, regs); break; #endif #if defined(_390) case ARCH_390: s390_alter_display_virt (opnd, regs); break; #endif #if defined(_900) case ARCH_900: z900_alter_display_virt (opnd, regs); break; #endif } if (!iregs->ghostregs) free(regs); } /* end function alter_display_virt */ void display_inst(REGS *iregs, BYTE *inst) { REGS *regs; if (iregs->ghostregs) regs = iregs; else if ((regs = copy_regs(iregs)) == NULL) return; switch(regs->arch_mode) { #if defined(_370) case ARCH_370: s370_display_inst(regs,inst); break; #endif #if defined(_390) case ARCH_390: s390_display_inst(regs,inst); break; #endif #if defined(_900) case ARCH_900: z900_display_inst(regs,inst); break; #endif } if (!iregs->ghostregs) free (regs); } void disasm_stor(REGS *iregs, char *opnd) { REGS *regs; if (iregs->ghostregs) regs = iregs; else if ((regs = copy_regs(iregs)) == NULL) return; switch(regs->arch_mode) { #if defined(_370) case ARCH_370: s370_disasm_stor(regs,opnd); break; #endif #if defined(_390) case ARCH_390: s390_disasm_stor(regs,opnd); break; #endif #if defined(_900) case ARCH_900: z900_disasm_stor(regs,opnd); break; #endif } if (!iregs->ghostregs) free(regs); } /*-------------------------------------------------------------------*/ /* Execute a Unix or Windows command */ /* Returns the system command status code */ /*-------------------------------------------------------------------*/ int herc_system (char* command) { #if HOW_TO_IMPLEMENT_SH_COMMAND == USE_ANSI_SYSTEM_API_FOR_SH_COMMAND return system(command); #elif HOW_TO_IMPLEMENT_SH_COMMAND == USE_W32_POOR_MANS_FORK #define SHELL_CMD_SHIM_PGM "conspawn " int rc = (int)(strlen(SHELL_CMD_SHIM_PGM) + strlen(command) + 1); char* pszNewCommandLine = malloc( rc ); strlcpy( pszNewCommandLine, SHELL_CMD_SHIM_PGM, rc ); strlcat( pszNewCommandLine, command, rc ); rc = w32_poor_mans_fork( pszNewCommandLine, NULL ); free( pszNewCommandLine ); return rc; #elif HOW_TO_IMPLEMENT_SH_COMMAND == USE_FORK_API_FOR_SH_COMMAND extern char **environ; int pid, status; if (command == 0) return 1; pid = fork(); if (pid == -1) return -1; if (pid == 0) { char *argv[4]; /* Redirect stderr (screen) to hercules log task */ dup2(STDOUT_FILENO, STDERR_FILENO); /* Drop ROOT authority (saved uid) */ SETMODE(TERM); DROP_ALL_CAPS(); argv[0] = "sh"; argv[1] = "-c"; argv[2] = command; argv[3] = 0; execve("/bin/sh", argv, environ); exit(127); } do { if (waitpid(pid, &status, 0) == -1) { if (errno != EINTR) return -1; } else return status; } while(1); #else #error 'HOW_TO_IMPLEMENT_SH_COMMAND' not #defined correctly #endif } /* end function herc_system */ #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/sr.c0000664000175000017500000013061712564723224011003 00000000000000/* SR.C (c)Copyright Greg Smith, 2005-2009 */ /* Suspend/Resume a Hercules session */ #include "hstdinc.h" #define _HERCULES_SR_C #define _HENGINE_DLL_ #include "hercules.h" #include "opcode.h" #ifdef OPTION_FISHIO #include "w32chan.h" #endif #include "sr.h" /* subroutine to check for active devices */ DEVBLK *sr_active_devices() { DEVBLK *dev; for (dev = sysblk.firstdev; dev; dev = dev->nextdev) { obtain_lock (&dev->lock); if (dev->busy && !dev->suspended) { if (dev->devtype != 0x3088) { release_lock (&dev->lock); return dev; } else { usleep(50000); dev->busy = 0; } } release_lock (&dev->lock); } return NULL; } int suspend_cmd(int argc, char *argv[],char *cmdline) { char *fn = SR_DEFAULT_FILENAME; SR_FILE file; CPU_BITMAP started_mask; struct timeval tv; time_t tt; int i, j, rc; REGS *regs; DEVBLK *dev; IOINT *ioq; BYTE psw[16]; UNREFERENCED(cmdline); if (argc > 2) { logmsg( _("HHCSR101E Too many arguments\n")); return -1; } if (argc == 2) fn = argv[1]; file = SR_OPEN (fn, "wb"); if (file == NULL) { logmsg( _("HHCSR102E %s open error: %s\n"),fn,strerror(errno)); return -1; } /* Save CPU state and stop all CPU's */ OBTAIN_INTLOCK(NULL); started_mask = sysblk.started_mask; while (sysblk.started_mask) { for (i = 0; i < MAX_CPU_ENGINES; i++) { if (IS_CPU_ONLINE(i)) { sysblk.regs[i]->cpustate = CPUSTATE_STOPPING; ON_IC_INTERRUPT(sysblk.regs[i]); signal_condition(&sysblk.regs[i]->intcond); } } RELEASE_INTLOCK(NULL); usleep (1000); OBTAIN_INTLOCK(NULL); } RELEASE_INTLOCK(NULL); /* Wait for I/O queue to clear out */ #ifdef OPTION_FISHIO SLEEP (2); #else obtain_lock (&sysblk.ioqlock); while (sysblk.ioq) { release_lock (&sysblk.ioqlock); usleep (1000); obtain_lock (&sysblk.ioqlock); } release_lock (&sysblk.ioqlock); #endif /* Wait for active I/Os to complete */ for (i = 1; i < 5000; i++) { dev = sr_active_devices(); if (dev == NULL) break; if (i % 500 == 0) logmsg( _("HHCSR103W Waiting for device %4.4X\n"), dev->devnum); usleep (10000); } if (dev != NULL) logmsg( _("HHCSR104W Device %4.4X still busy, proceeding anyway\n"), dev->devnum); /* Write header */ SR_WRITE_STRING(file, SR_HDR_ID, SR_ID); SR_WRITE_STRING(file, SR_HDR_VERSION, VERSION); gettimeofday(&tv, NULL); tt = tv.tv_sec; SR_WRITE_STRING(file, SR_HDR_DATE, ctime(&tt)); /* Write system data */ SR_WRITE_STRING(file,SR_SYS_ARCH_NAME,arch_name[sysblk.arch_mode]); SR_WRITE_VALUE (file,SR_SYS_STARTED_MASK,started_mask,sizeof(started_mask)); SR_WRITE_VALUE (file,SR_SYS_MAINSIZE,sysblk.mainsize,sizeof(sysblk.mainsize)); SR_WRITE_BUF (file,SR_SYS_MAINSTOR,sysblk.mainstor,sysblk.mainsize); SR_WRITE_VALUE (file,SR_SYS_SKEYSIZE,sysblk.mainsize/STORAGE_KEY_UNITSIZE,sizeof(int)); SR_WRITE_BUF (file,SR_SYS_STORKEYS,sysblk.storkeys,sysblk.mainsize/STORAGE_KEY_UNITSIZE); SR_WRITE_VALUE (file,SR_SYS_XPNDSIZE,sysblk.xpndsize,sizeof(sysblk.xpndsize)); SR_WRITE_BUF (file,SR_SYS_XPNDSTOR,sysblk.xpndstor,sysblk.xpndsize); SR_WRITE_VALUE (file,SR_SYS_CPUID,sysblk.cpuid,sizeof(sysblk.cpuid)); SR_WRITE_VALUE (file,SR_SYS_IPLDEV,sysblk.ipldev,sizeof(sysblk.ipldev)); SR_WRITE_VALUE (file,SR_SYS_IPLCPU,sysblk.iplcpu,sizeof(sysblk.iplcpu)); SR_WRITE_VALUE (file,SR_SYS_MBO,sysblk.mbo,sizeof(sysblk.mbo)); SR_WRITE_VALUE (file,SR_SYS_MBK,sysblk.mbk,sizeof(sysblk.mbk)); SR_WRITE_VALUE (file,SR_SYS_MBM,sysblk.mbm,sizeof(sysblk.mbm)); SR_WRITE_VALUE (file,SR_SYS_MBD,sysblk.mbd,sizeof(sysblk.mbd)); for (ioq = sysblk.iointq; ioq; ioq = ioq->next) if (ioq->pcipending) { SR_WRITE_VALUE(file,SR_SYS_PCIPENDING_LCSS, SSID_TO_LCSS(ioq->dev->ssid),sizeof(U16)); SR_WRITE_VALUE(file,SR_SYS_PCIPENDING, ioq->dev->devnum,sizeof(ioq->dev->devnum)); } else if (ioq->attnpending) { SR_WRITE_VALUE(file,SR_SYS_ATTNPENDING_LCSS, SSID_TO_LCSS(ioq->dev->ssid),sizeof(U16)); SR_WRITE_VALUE(file,SR_SYS_ATTNPENDING, ioq->dev->devnum,sizeof(ioq->dev->devnum)); } else { SR_WRITE_VALUE(file,SR_SYS_IOPENDING_LCSS, SSID_TO_LCSS(ioq->dev->ssid),sizeof(U16)); SR_WRITE_VALUE(file,SR_SYS_IOPENDING, ioq->dev->devnum,sizeof(ioq->dev->devnum)); } for (i = 0; i < 8; i++) SR_WRITE_VALUE(file,SR_SYS_CHP_RESET+i,sysblk.chp_reset[i],sizeof(sysblk.chp_reset[0])); SR_WRITE_VALUE (file,SR_SYS_SERVPARM,sysblk.servparm,sizeof(sysblk.servparm)); SR_WRITE_VALUE (file,SR_SYS_SIGINTREQ,sysblk.sigintreq,1); SR_WRITE_STRING(file,SR_SYS_LOADPARM,str_loadparm()); SR_WRITE_VALUE (file,SR_SYS_INTS_STATE,sysblk.ints_state,sizeof(sysblk.ints_state)); SR_WRITE_HDR(file, SR_DELIMITER, 0); /* Save service console state */ SR_WRITE_HDR(file, SR_SYS_SERVC, 0); servc_hsuspend(file); SR_WRITE_HDR(file, SR_DELIMITER, 0); /* Save clock state */ SR_WRITE_HDR(file, SR_SYS_CLOCK, 0); clock_hsuspend(file); SR_WRITE_HDR(file, SR_DELIMITER, 0); /* Write CPU data */ for (i = 0; i < MAX_CPU_ENGINES; i++) { if (!IS_CPU_ONLINE(i)) continue; regs = sysblk.regs[i]; SR_WRITE_VALUE(file, SR_CPU, i, sizeof(i)); SR_WRITE_VALUE(file, SR_CPU_ARCHMODE, regs->arch_mode,sizeof(regs->arch_mode)); SR_WRITE_VALUE(file, SR_CPU_PX, regs->PX_G,sizeof(regs->PX_G)); copy_psw (regs, psw); SR_WRITE_BUF(file, SR_CPU_PSW, psw, 16); for (j = 0; j < 16; j++) SR_WRITE_VALUE(file, SR_CPU_GR+j, regs->GR_G(j),sizeof(regs->GR_G(0))); for (j = 0; j < 16; j++) SR_WRITE_VALUE(file, SR_CPU_CR+j, regs->CR_G(j),sizeof(regs->CR_G(0))); for (j = 0; j < 16; j++) SR_WRITE_VALUE(file, SR_CPU_AR+j, regs->ar[j],sizeof(regs->ar[0])); for (j = 0; j < 32; j++) SR_WRITE_VALUE(file, SR_CPU_FPR+j, regs->fpr[j],sizeof(regs->fpr[0])); SR_WRITE_VALUE(file, SR_CPU_FPC, regs->fpc, sizeof(regs->fpc)); SR_WRITE_VALUE(file, SR_CPU_DXC, regs->dxc, sizeof(regs->dxc)); SR_WRITE_VALUE(file, SR_CPU_MC, regs->MC_G, sizeof(regs->MC_G)); SR_WRITE_VALUE(file, SR_CPU_EA, regs->EA_G, sizeof(regs->EA_G)); SR_WRITE_VALUE(file, SR_CPU_PTIMER, cpu_timer(regs), sizeof(S64)); SR_WRITE_VALUE(file, SR_CPU_CLKC, regs->clkc, sizeof(regs->clkc)); SR_WRITE_VALUE(file, SR_CPU_CHANSET, regs->chanset, sizeof(regs->chanset)); SR_WRITE_VALUE(file, SR_CPU_TODPR, regs->todpr, sizeof(regs->todpr)); SR_WRITE_VALUE(file, SR_CPU_MONCLASS, regs->monclass, sizeof(regs->monclass)); SR_WRITE_VALUE(file, SR_CPU_EXCARID, regs->excarid, sizeof(regs->excarid)); SR_WRITE_VALUE(file, SR_CPU_BEAR, regs->bear, sizeof(regs->bear)); SR_WRITE_VALUE(file, SR_CPU_OPNDRID, regs->opndrid, sizeof(regs->opndrid)); SR_WRITE_VALUE(file, SR_CPU_CHECKSTOP, regs->checkstop, 1); SR_WRITE_VALUE(file, SR_CPU_HOSTINT, regs->hostint, 1); SR_WRITE_VALUE(file, SR_CPU_EXECFLAG, regs->execflag, 1); // SR_WRITE_VALUE(file, SR_CPU_INSTVALID, regs->instvalid, 1); SR_WRITE_VALUE(file, SR_CPU_PERMODE, regs->permode, 1); SR_WRITE_VALUE(file, SR_CPU_LOADSTATE, regs->loadstate, 1); SR_WRITE_VALUE(file, SR_CPU_INVALIDATE, regs->invalidate, 1); SR_WRITE_VALUE(file, SR_CPU_SIGPRESET, regs->sigpreset, 1); SR_WRITE_VALUE(file, SR_CPU_SIGPIRESET, regs->sigpireset, 1); SR_WRITE_VALUE(file, SR_CPU_INTS_STATE, regs->ints_state, sizeof(regs->ints_state)); SR_WRITE_VALUE(file, SR_CPU_INTS_MASK, regs->ints_mask, sizeof(regs->ints_mask)); for (j = 0; j < MAX_CPU_ENGINES; j++) SR_WRITE_VALUE(file, SR_CPU_MALFCPU+j, regs->malfcpu[j], sizeof(regs->malfcpu[0])); for (j = 0; j < MAX_CPU_ENGINES; j++) SR_WRITE_VALUE(file, SR_CPU_EMERCPU+j, regs->emercpu[j], sizeof(regs->emercpu[0])); SR_WRITE_VALUE(file, SR_CPU_EXTCCPU, regs->extccpu, sizeof(regs->extccpu)); SR_WRITE_HDR(file, SR_DELIMITER, 0); } /* Write Device data */ for (dev = sysblk.firstdev; dev; dev = dev->nextdev) { if (!(dev->pmcw.flag5 & PMCW5_V)) continue; /* These fields must come first so the device could be attached */ SR_WRITE_VALUE(file, SR_DEV, dev->devnum, sizeof(dev->devnum)); SR_WRITE_VALUE(file, SR_DEV_LCSS, SSID_TO_LCSS(dev->ssid), sizeof(U16)); SR_WRITE_VALUE(file, SR_DEV_ARGC, dev->argc, sizeof(dev->argc)); for (i = 0; i < dev->argc; i++) if (dev->argv[i]) { SR_WRITE_STRING(file, SR_DEV_ARGV, dev->argv[i]); } else { SR_WRITE_STRING(file, SR_DEV_ARGV, ""); } SR_WRITE_STRING(file, SR_DEV_TYPNAME, dev->typname); /* Common device fields */ SR_WRITE_BUF (file, SR_DEV_ORB, &dev->orb, sizeof(ORB)); SR_WRITE_BUF (file, SR_DEV_PMCW, &dev->pmcw, sizeof(PMCW)); SR_WRITE_BUF (file, SR_DEV_SCSW, &dev->scsw, sizeof(SCSW)); SR_WRITE_BUF (file, SR_DEV_PCISCSW, &dev->pciscsw, sizeof(SCSW)); SR_WRITE_BUF (file, SR_DEV_ATTNSCSW, &dev->attnscsw, sizeof(SCSW)); SR_WRITE_BUF (file, SR_DEV_CSW, dev->csw, 8); SR_WRITE_BUF (file, SR_DEV_PCICSW, dev->pcicsw, 8); SR_WRITE_BUF (file, SR_DEV_ATTNCSW, dev->attncsw, 8); SR_WRITE_BUF (file, SR_DEV_ESW, &dev->esw, sizeof(ESW)); SR_WRITE_BUF (file, SR_DEV_ECW, dev->ecw, 32); SR_WRITE_BUF (file, SR_DEV_SENSE, dev->sense, 32); SR_WRITE_VALUE(file, SR_DEV_PGSTAT, dev->pgstat, sizeof(dev->pgstat)); SR_WRITE_BUF (file, SR_DEV_PGID, dev->pgid, 11); /* By Adrian - SR_DEV_DRVPWD */ SR_WRITE_BUF (file, SR_DEV_DRVPWD, dev->drvpwd, 11); SR_WRITE_VALUE(file, SR_DEV_BUSY, dev->busy, 1); SR_WRITE_VALUE(file, SR_DEV_RESERVED, dev->reserved, 1); SR_WRITE_VALUE(file, SR_DEV_SUSPENDED, dev->suspended, 1); SR_WRITE_VALUE(file, SR_DEV_PCIPENDING, dev->pcipending, 1); SR_WRITE_VALUE(file, SR_DEV_ATTNPENDING, dev->attnpending, 1); SR_WRITE_VALUE(file, SR_DEV_PENDING, dev->pending, 1); SR_WRITE_VALUE(file, SR_DEV_STARTPENDING, dev->startpending, 1); SR_WRITE_VALUE(file, SR_DEV_CRWPENDING, dev->crwpending, 1); SR_WRITE_VALUE(file, SR_DEV_CCWADDR, dev->ccwaddr, sizeof(dev->ccwaddr)); SR_WRITE_VALUE(file, SR_DEV_IDAPMASK, dev->idapmask, sizeof(dev->idapmask)); SR_WRITE_VALUE(file, SR_DEV_IDAWFMT, dev->idawfmt, sizeof(dev->idawfmt)); SR_WRITE_VALUE(file, SR_DEV_CCWFMT, dev->ccwfmt, sizeof(dev->ccwfmt)); SR_WRITE_VALUE(file, SR_DEV_CCWKEY, dev->ccwkey, sizeof(dev->ccwkey)); /* Device type specific data */ SR_WRITE_VALUE(file, SR_DEV_DEVTYPE, dev->devtype, sizeof(dev->devtype)); if (dev->hnd->hsuspend) { rc = (dev->hnd->hsuspend) (dev, file); if (rc < 0) goto sr_error_exit; } SR_WRITE_HDR(file, SR_DELIMITER, 0); } SR_WRITE_HDR(file, SR_EOF, 0); SR_CLOSE (file); /* Shutdown */ do_shutdown(); return 0; sr_write_error: logmsg(_("HHCSR010E write error: %s\n"), strerror(errno)); goto sr_error_exit; sr_value_error: logmsg(_("HHCSR013E value error, incorrect length\n")); goto sr_error_exit; sr_string_error: logmsg(_("HHCSR014E string error, incorrect length\n")); goto sr_error_exit; sr_error_exit: logmsg(_("HHCSR015E error processing file %s\n"),fn); SR_CLOSE (file); return -1; } int resume_cmd(int argc, char *argv[],char *cmdline) { char *fn = SR_DEFAULT_FILENAME; SR_FILE file; U32 key = 0, len = 0; CPU_BITMAP started_mask = 0; int i, rc; REGS *regs = NULL; U16 devnum=0; U16 lcss=0; U16 hw; int devargc=0; char *devargv[16]; int devargx=0; DEVBLK *dev = NULL; IOINT *ioq = NULL; char buf[SR_MAX_STRING_LENGTH+1]; char zeros[16]; S64 dreg; UNREFERENCED(cmdline); if (argc > 2) { logmsg( _("HHCSR101E Too many arguments\n")); return -1; } if (argc == 2) fn = argv[1]; memset (zeros, 0, sizeof(zeros)); /* Make sure all CPUs are deconfigured or stopped */ OBTAIN_INTLOCK(NULL); for (i = 0; i < MAX_CPU_ENGINES; i++) if (IS_CPU_ONLINE(i) && CPUSTATE_STOPPED != sysblk.regs[i]->cpustate) { RELEASE_INTLOCK(NULL); logmsg( _("HHCSR103E All CPU's must be stopped to resume\n") ); return -1; } RELEASE_INTLOCK(NULL); file = SR_OPEN (fn, "rb"); if (file == NULL) { logmsg( _("HHCSR102E %s open error: %s\n"),fn,strerror(errno)); return -1; } /* First key must be SR_HDR_ID and string must match SR_ID */ SR_READ_HDR(file, key, len); if (key == SR_HDR_ID) SR_READ_STRING(file, buf, len); if (key != SR_HDR_ID || strcmp(buf, SR_ID)) { logmsg( _("HHCSR104E File identifier error\n")); goto sr_error_exit; } /* Deconfigure all CPUs */ OBTAIN_INTLOCK(NULL); for (i = 0; i < MAX_CPU_ENGINES; i++) if (IS_CPU_ONLINE(i)) deconfigure_cpu(i); RELEASE_INTLOCK(NULL); while (key != SR_EOF) { SR_READ_HDR(file, key, len); switch (key) { case SR_HDR_DATE: SR_READ_STRING(file, buf, len); logmsg( _("HHCSR001I Resuming suspended file created %s"), buf); break; case SR_SYS_STARTED_MASK: SR_READ_VALUE(file, len, &started_mask, sizeof(started_mask)); break; case SR_SYS_ARCH_NAME: SR_READ_STRING(file, buf, len); i = -1; #if defined (_370) if (strcasecmp (buf, arch_name[ARCH_370]) == 0) { i = ARCH_370; sysblk.maxcpu = sysblk.numcpu; } #endif #if defined (_390) if (strcasecmp (buf, arch_name[ARCH_390]) == 0) { i = ARCH_390; #if defined(_FEATURE_CPU_RECONFIG) sysblk.maxcpu = MAX_CPU_ENGINES; #else sysblk.maxcpu = sysblk.numcpu; #endif } #endif #if defined (_900) if (0 || strcasecmp (buf, arch_name[ARCH_900]) == 0 || strcasecmp (buf, "ESAME") == 0 ) { i = ARCH_900; #if defined(_FEATURE_CPU_RECONFIG) sysblk.maxcpu = MAX_CPU_ENGINES; #else sysblk.maxcpu = sysblk.numcpu; #endif } #endif if (i < 0) { logmsg( _("HHCSR105E Archmode %s not supported\n"), buf); goto sr_error_exit; } sysblk.arch_mode = i; #if defined (_900) sysblk.arch_z900 = sysblk.arch_mode != ARCH_390; #endif sysblk.pcpu = 0; sysblk.dummyregs.arch_mode = sysblk.arch_mode; #if defined(OPTION_FISHIO) ios_arch_mode = sysblk.arch_mode; #endif break; case SR_SYS_MAINSIZE: SR_READ_VALUE(file, len, &len, sizeof(len)); if (len > sysblk.mainsize) { logmsg( _("HHCSR106E Mainsize mismatch: %d" "M expected %d" "M\n"), len / (1024*1024), sysblk.mainsize / (1024*1024)); goto sr_error_exit; } break; case SR_SYS_MAINSTOR: if (len > sysblk.mainsize) { logmsg( _("HHCSR107E Mainsize mismatch: %d" "M expected %d" "M\n"), len / (1024*1024), sysblk.mainsize / (1024*1024)); goto sr_error_exit; } SR_READ_BUF(file, sysblk.mainstor, len); break; case SR_SYS_SKEYSIZE: SR_READ_VALUE(file, len, &len, sizeof(len)); if (len > sysblk.mainsize/STORAGE_KEY_UNITSIZE) { logmsg( _("HHCSR108E Storkey size mismatch: %d expected %d\n"), len, sysblk.mainsize/STORAGE_KEY_UNITSIZE); goto sr_error_exit; } break; case SR_SYS_STORKEYS: if (len > sysblk.mainsize/STORAGE_KEY_UNITSIZE) { logmsg( _("HHCSR109E Storkey size mismatch: %d expected %d\n"), len, sysblk.mainsize/STORAGE_KEY_UNITSIZE); goto sr_error_exit; } SR_READ_BUF(file, sysblk.storkeys, len); break; case SR_SYS_XPNDSIZE: SR_READ_VALUE(file, len, &len, sizeof(len)); if (len > sysblk.xpndsize) { logmsg( _("HHCSR110E Xpndsize mismatch: %d" "M expected %d" "M\n"), len / (1024*1024), sysblk.xpndsize / (1024*1024)); goto sr_error_exit; } break; case SR_SYS_XPNDSTOR: if (len > sysblk.xpndsize) { logmsg( _("HHCSR111E Xpndsize mismatch: %d" "M expected %d" "M\n"), len / (1024*1024), sysblk.xpndsize / (1024*1024)); goto sr_error_exit; } SR_READ_BUF(file, sysblk.xpndstor, len); break; case SR_SYS_IPLDEV: SR_READ_VALUE(file, len, &sysblk.ipldev, sizeof(sysblk.ipldev)); break; case SR_SYS_IPLCPU: SR_READ_VALUE(file, len, &sysblk.iplcpu, sizeof(sysblk.iplcpu)); break; case SR_SYS_MBO: SR_READ_VALUE(file, len, &sysblk.mbo, sizeof(sysblk.mbo)); break; case SR_SYS_MBK: SR_READ_VALUE(file, len, &sysblk.mbk, sizeof(sysblk.mbk)); break; case SR_SYS_MBM: SR_READ_VALUE(file, len, &sysblk.mbm, sizeof(sysblk.mbm)); break; case SR_SYS_MBD: SR_READ_VALUE(file, len, &sysblk.mbd, sizeof(sysblk.mbd)); break; case SR_SYS_IOPENDING_LCSS: SR_READ_VALUE(file,len,&lcss,sizeof(lcss)); break; case SR_SYS_IOPENDING: SR_READ_VALUE(file, len, &hw, sizeof(hw)); dev = find_device_by_devnum(lcss,hw); if (dev == NULL) break; if (ioq == NULL) sysblk.iointq = &dev->ioint; else ioq->next = &dev->ioint; ioq = &dev->ioint; dev = NULL; lcss = 0; break; case SR_SYS_PCIPENDING_LCSS: SR_READ_VALUE(file,len,&lcss,sizeof(lcss)); break; case SR_SYS_PCIPENDING: SR_READ_VALUE(file, len, &hw, sizeof(hw)); dev = find_device_by_devnum(lcss,hw); if (dev == NULL) break; if (ioq == NULL) sysblk.iointq = &dev->pciioint; else ioq->next = &dev->pciioint; ioq = &dev->pciioint; dev = NULL; lcss = 0; break; case SR_SYS_ATTNPENDING_LCSS: SR_READ_VALUE(file,len,&lcss,sizeof(lcss)); break; case SR_SYS_ATTNPENDING: SR_READ_VALUE(file, len, &hw, sizeof(hw)); dev = find_device_by_devnum(lcss,hw); if (dev == NULL) break; if (ioq == NULL) sysblk.iointq = &dev->attnioint; else ioq->next = &dev->attnioint; ioq = &dev->attnioint; dev = NULL; lcss = 0; break; case SR_SYS_CHP_RESET_0: case SR_SYS_CHP_RESET_1: case SR_SYS_CHP_RESET_2: case SR_SYS_CHP_RESET_3: case SR_SYS_CHP_RESET_4: case SR_SYS_CHP_RESET_5: case SR_SYS_CHP_RESET_6: case SR_SYS_CHP_RESET_7: i = key - SR_SYS_CHP_RESET; SR_READ_VALUE(file, len, &sysblk.chp_reset[i], sizeof(sysblk.chp_reset[0])); break; case SR_SYS_SERVPARM: SR_READ_VALUE(file, len, &sysblk.servparm, sizeof(sysblk.servparm)); break; case SR_SYS_SIGINTREQ: SR_READ_VALUE(file, len, &rc, sizeof(rc)); sysblk.sigintreq = rc; break; case SR_SYS_LOADPARM: SR_READ_STRING(file, buf, len); set_loadparm ((char *)buf); break; case SR_SYS_SERVC: rc = servc_hresume(file); if (rc < 0) goto sr_error_exit; break; case SR_SYS_CLOCK: rc = clock_hresume(file); if (rc < 0) goto sr_error_exit; break; case SR_CPU: SR_READ_VALUE(file, len, &i, sizeof(i)); if (i >= MAX_CPU_ENGINES) { logmsg( _("HHCSR113E CPU%4.4d exceeds max allowed cpu (%d)\n"), i, MAX_CPU_ENGINES-1); goto sr_error_exit; } OBTAIN_INTLOCK(NULL); if (IS_CPU_ONLINE(i)) { RELEASE_INTLOCK(NULL); logmsg( _("HHCSR114E CPU%4.4d already configured\n"), i); goto sr_error_exit; } rc = configure_cpu(i); RELEASE_INTLOCK(NULL); if (rc < 0) { logmsg( _("HHCSR115E CPU%4.4d unable to configure online\n"), i); goto sr_error_exit; } regs = sysblk.regs[i]; break; case SR_CPU_PX: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->px, sizeof(regs->px)); break; case SR_CPU_PSW: if (regs == NULL) goto sr_null_regs_exit; if (len != 8 && len != 16) { logmsg( _("HHCSR116E CPU%4.4d invalid psw length (%d)\n"), regs->cpuad, len); goto sr_error_exit; } memset(buf, 0, 16); SR_READ_BUF(file, buf, len); switch (regs->arch_mode) { #if defined (_370) case ARCH_370: len = 8; rc = s370_load_psw(regs, (BYTE *)&buf); break; #endif #if defined (_390) case ARCH_390: len = 8; rc = s390_load_psw(regs, (BYTE *)&buf); break; #endif #if defined (_900) case ARCH_900: len = 16; rc = z900_load_psw(regs, (BYTE *)&buf); break; #endif default: /* regs->arch_mode not valid (should not occur) */ rc = 99; } /* switch (regs->arch_mode) */ if (rc != 0 && memcmp(buf, zeros, len)) { logmsg( _("HHCSR117E CPU%4.4d error loading psw (%d)\n"), regs->cpuad, rc); goto sr_error_exit; } break; case SR_CPU_GR_0: case SR_CPU_GR_1: case SR_CPU_GR_2: case SR_CPU_GR_3: case SR_CPU_GR_4: case SR_CPU_GR_5: case SR_CPU_GR_6: case SR_CPU_GR_7: case SR_CPU_GR_8: case SR_CPU_GR_9: case SR_CPU_GR_10: case SR_CPU_GR_11: case SR_CPU_GR_12: case SR_CPU_GR_13: case SR_CPU_GR_14: case SR_CPU_GR_15: if (regs == NULL) goto sr_null_regs_exit; i = key - SR_CPU_GR; SR_READ_VALUE(file, len, ®s->gr[i], sizeof(regs->gr[0])); break; case SR_CPU_CR_0: case SR_CPU_CR_1: case SR_CPU_CR_2: case SR_CPU_CR_3: case SR_CPU_CR_4: case SR_CPU_CR_5: case SR_CPU_CR_6: case SR_CPU_CR_7: case SR_CPU_CR_8: case SR_CPU_CR_9: case SR_CPU_CR_10: case SR_CPU_CR_11: case SR_CPU_CR_12: case SR_CPU_CR_13: case SR_CPU_CR_14: case SR_CPU_CR_15: if (regs == NULL) goto sr_null_regs_exit; i = key - SR_CPU_CR; SR_READ_VALUE(file, len, ®s->cr[i], sizeof(regs->cr[0])); break; case SR_CPU_AR_0: case SR_CPU_AR_1: case SR_CPU_AR_2: case SR_CPU_AR_3: case SR_CPU_AR_4: case SR_CPU_AR_5: case SR_CPU_AR_6: case SR_CPU_AR_7: case SR_CPU_AR_8: case SR_CPU_AR_9: case SR_CPU_AR_10: case SR_CPU_AR_11: case SR_CPU_AR_12: case SR_CPU_AR_13: case SR_CPU_AR_14: case SR_CPU_AR_15: if (regs == NULL) goto sr_null_regs_exit; i = key - SR_CPU_AR; SR_READ_VALUE(file, len, ®s->ar[i], sizeof(regs->ar[0])); break; case SR_CPU_FPR_0: case SR_CPU_FPR_1: case SR_CPU_FPR_2: case SR_CPU_FPR_3: case SR_CPU_FPR_4: case SR_CPU_FPR_5: case SR_CPU_FPR_6: case SR_CPU_FPR_7: case SR_CPU_FPR_8: case SR_CPU_FPR_9: case SR_CPU_FPR_10: case SR_CPU_FPR_11: case SR_CPU_FPR_12: case SR_CPU_FPR_13: case SR_CPU_FPR_14: case SR_CPU_FPR_15: case SR_CPU_FPR_16: case SR_CPU_FPR_17: case SR_CPU_FPR_18: case SR_CPU_FPR_19: case SR_CPU_FPR_20: case SR_CPU_FPR_21: case SR_CPU_FPR_22: case SR_CPU_FPR_23: case SR_CPU_FPR_24: case SR_CPU_FPR_25: case SR_CPU_FPR_26: case SR_CPU_FPR_27: case SR_CPU_FPR_28: case SR_CPU_FPR_29: case SR_CPU_FPR_30: case SR_CPU_FPR_31: if (regs == NULL) goto sr_null_regs_exit; i = key - SR_CPU_FPR; SR_READ_VALUE(file, len, ®s->fpr[i], sizeof(regs->fpr[0])); break; case SR_CPU_FPC: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->fpc, sizeof(regs->fpc)); break; case SR_CPU_DXC: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->dxc, sizeof(regs->dxc)); break; case SR_CPU_MC: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->mc, sizeof(regs->mc)); break; case SR_CPU_EA: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->ea, sizeof(regs->ea)); break; case SR_CPU_PTIMER: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, &dreg, sizeof(S64)); set_cpu_timer(regs, dreg); break; case SR_CPU_CLKC: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->clkc, sizeof(regs->clkc)); break; case SR_CPU_CHANSET: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->chanset, sizeof(regs->chanset)); break; case SR_CPU_TODPR: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->todpr, sizeof(regs->todpr)); break; case SR_CPU_MONCLASS: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->monclass, sizeof(regs->monclass)); break; case SR_CPU_EXCARID: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->excarid, sizeof(regs->excarid)); break; case SR_CPU_BEAR: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->bear, sizeof(regs->bear)); break; case SR_CPU_OPNDRID: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->opndrid, sizeof(regs->opndrid)); break; case SR_CPU_CHECKSTOP: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, &rc, sizeof(rc)); regs->checkstop = rc; break; case SR_CPU_HOSTINT: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, &rc, sizeof(rc)); regs->hostint = rc; break; case SR_CPU_LOADSTATE: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, &rc, sizeof(rc)); regs->loadstate = rc; break; case SR_CPU_INVALIDATE: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, &rc, sizeof(rc)); regs->invalidate = rc; break; case SR_CPU_SIGPRESET: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, &rc, sizeof(rc)); regs->sigpreset = rc; break; case SR_CPU_SIGPIRESET: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, &rc, sizeof(rc)); regs->sigpireset = rc; break; case SR_CPU_INTS_STATE: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->ints_state, sizeof(regs->ints_state)); /* Force CPU to examine the interrupt state */ ON_IC_INTERRUPT(regs); break; case SR_CPU_INTS_MASK: if (regs == NULL) goto sr_null_regs_exit; SR_READ_VALUE(file, len, ®s->ints_mask, sizeof(regs->ints_mask)); break; case SR_CPU_MALFCPU_0: case SR_CPU_MALFCPU_1: case SR_CPU_MALFCPU_2: case SR_CPU_MALFCPU_3: case SR_CPU_MALFCPU_4: case SR_CPU_MALFCPU_5: case SR_CPU_MALFCPU_6: case SR_CPU_MALFCPU_7: case SR_CPU_MALFCPU_8: case SR_CPU_MALFCPU_9: case SR_CPU_MALFCPU_10: case SR_CPU_MALFCPU_11: case SR_CPU_MALFCPU_12: case SR_CPU_MALFCPU_13: case SR_CPU_MALFCPU_14: case SR_CPU_MALFCPU_15: case SR_CPU_MALFCPU_16: case SR_CPU_MALFCPU_17: case SR_CPU_MALFCPU_18: case SR_CPU_MALFCPU_19: case SR_CPU_MALFCPU_20: case SR_CPU_MALFCPU_21: case SR_CPU_MALFCPU_22: case SR_CPU_MALFCPU_23: case SR_CPU_MALFCPU_24: case SR_CPU_MALFCPU_25: case SR_CPU_MALFCPU_26: case SR_CPU_MALFCPU_27: case SR_CPU_MALFCPU_28: case SR_CPU_MALFCPU_29: case SR_CPU_MALFCPU_30: case SR_CPU_MALFCPU_31: if (regs == NULL) goto sr_null_regs_exit; i = key - SR_CPU_MALFCPU; if (i < MAX_CPU_ENGINES) SR_READ_VALUE(file, len, ®s->malfcpu[i], sizeof(regs->malfcpu[0])); break; case SR_CPU_EMERCPU_0: case SR_CPU_EMERCPU_1: case SR_CPU_EMERCPU_2: case SR_CPU_EMERCPU_3: case SR_CPU_EMERCPU_4: case SR_CPU_EMERCPU_5: case SR_CPU_EMERCPU_6: case SR_CPU_EMERCPU_7: case SR_CPU_EMERCPU_8: case SR_CPU_EMERCPU_9: case SR_CPU_EMERCPU_10: case SR_CPU_EMERCPU_11: case SR_CPU_EMERCPU_12: case SR_CPU_EMERCPU_13: case SR_CPU_EMERCPU_14: case SR_CPU_EMERCPU_15: case SR_CPU_EMERCPU_16: case SR_CPU_EMERCPU_17: case SR_CPU_EMERCPU_18: case SR_CPU_EMERCPU_19: case SR_CPU_EMERCPU_20: case SR_CPU_EMERCPU_21: case SR_CPU_EMERCPU_22: case SR_CPU_EMERCPU_23: case SR_CPU_EMERCPU_24: case SR_CPU_EMERCPU_25: case SR_CPU_EMERCPU_26: case SR_CPU_EMERCPU_27: case SR_CPU_EMERCPU_28: case SR_CPU_EMERCPU_29: case SR_CPU_EMERCPU_30: case SR_CPU_EMERCPU_31: if (regs == NULL) goto sr_null_regs_exit; i = key - SR_CPU_EMERCPU; if (i < MAX_CPU_ENGINES) SR_READ_VALUE(file, len, ®s->emercpu[i], sizeof(regs->emercpu[0])); break; case SR_DEV: SR_READ_VALUE(file, len, &devnum, sizeof(devnum)); lcss=0; break; case SR_DEV_LCSS: SR_READ_VALUE(file, len, &lcss, sizeof(U16)); break; case SR_DEV_ARGC: SR_READ_VALUE(file, len, &devargc, sizeof(devargc)); if (devargc > 16) devargc = 16; for (i = 0; i < devargc; i++) devargv[i] = NULL; devargx = 0; break; case SR_DEV_ARGV: SR_READ_STRING(file, buf, len); if (devargx < devargc) devargv[devargx++] = strdup(buf); break; case SR_DEV_TYPNAME: SR_READ_STRING(file, buf, len); dev = find_device_by_devnum(lcss,devnum); if (dev == NULL) { if (attach_device (lcss, devnum, buf, devargc, devargv)) { logmsg( _("HHCSR118W Device %4.4X initialization failed\n"), devnum); } } else if (strcmp(dev->typname, buf)) { logmsg( _("HHCSR119W Device %4.4X type mismatch; %s expected %s\n"), devnum, buf, dev->typname); dev = NULL; } for (i = 0; i < devargx; i++) { if (devargv[i]) free(devargv[i]); devargv[i] = NULL; } devnum = devargc = devargx = 0; break; case SR_DEV_ORB: SR_SKIP_NULL_DEV(dev, file, len); if (len != sizeof(ORB)) { logmsg( _("HHCSR120E Device %4.4X ORB size mismatch: %d expected %d\n"), dev->devnum, len, sizeof(ORB)); goto sr_error_exit; } SR_READ_BUF(file, &dev->orb, len); break; case SR_DEV_PMCW: SR_SKIP_NULL_DEV(dev, file, len); if (len != sizeof(PMCW)) { logmsg( _("HHCSR121E Device %4.4X PMCW size mismatch: %d expected %d\n"), dev->devnum, len, sizeof(PMCW)); goto sr_error_exit; } SR_READ_BUF(file, &dev->pmcw, len); break; case SR_DEV_SCSW: SR_SKIP_NULL_DEV(dev, file, len); if (len != sizeof(SCSW)) { logmsg( _("HHCSR122E Device %4.4X SCSW size mismatch: %d expected %d\n"), dev->devnum, len, sizeof(SCSW)); goto sr_error_exit; } SR_READ_BUF(file, &dev->scsw, len); break; case SR_DEV_PCISCSW: SR_SKIP_NULL_DEV(dev, file, len); if (len != sizeof(SCSW)) { logmsg( _("HHCSR123E Device %4.4X PCI SCSW size mismatch: %d expected %d\n"), dev->devnum, len, sizeof(SCSW)); goto sr_error_exit; } SR_READ_BUF(file, &dev->pciscsw, len); break; case SR_DEV_ATTNSCSW: SR_SKIP_NULL_DEV(dev, file, len); if (len != sizeof(SCSW)) { logmsg( _("HHCSR124E Device %4.4X Attn SCSW size mismatch: %d expected %d\n"), dev->devnum, len, sizeof(SCSW)); goto sr_error_exit; } SR_READ_BUF(file, &dev->attnscsw, len); break; case SR_DEV_CSW: SR_SKIP_NULL_DEV(dev, file, len); if (len != 8) { logmsg( _("HHCSR125E Device %4.4X CSW size mismatch: %d expected %d\n"), dev->devnum, len, 8); goto sr_error_exit; } SR_READ_BUF(file, &dev->csw, len); break; case SR_DEV_PCICSW: SR_SKIP_NULL_DEV(dev, file, len); if (len != 8) { logmsg( _("HHCSR126E Device %4.4X PCI CSW size mismatch: %d expected %d\n"), dev->devnum, len, 8); goto sr_error_exit; } SR_READ_BUF(file, &dev->pcicsw, len); break; case SR_DEV_ATTNCSW: SR_SKIP_NULL_DEV(dev, file, len); if (len != 8) { logmsg( _("HHCSR127E Device %4.4X Attn CSW size mismatch: %d expected %d\n"), dev->devnum, len, 8); goto sr_error_exit; } SR_READ_BUF(file, &dev->attncsw, len); break; case SR_DEV_ESW: SR_SKIP_NULL_DEV(dev, file, len); if (len != sizeof(ESW)) { logmsg( _("HHCSR128E Device %4.4X ESW size mismatch: %d expected %d\n"), dev->devnum, len, sizeof(ESW)); goto sr_error_exit; } SR_READ_BUF(file, &dev->esw, len); break; case SR_DEV_ECW: SR_SKIP_NULL_DEV(dev, file, len); if (len != 32) { logmsg( _("HHCSR129E Device %4.4X ECW size mismatch: %d expected %d\n"), dev->devnum, len, 32); goto sr_error_exit; } SR_READ_BUF(file, &dev->ecw, len); break; case SR_DEV_SENSE: SR_SKIP_NULL_DEV(dev, file, len); if (len != 32) { logmsg( _("HHCSR130E Device %4.4X Sense size mismatch: %d expected %d\n"), dev->devnum, len, 32); goto sr_error_exit; } SR_READ_BUF(file, &dev->ecw, len); break; case SR_DEV_PGSTAT: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &dev->pgstat, sizeof(dev->pgstat)); break; case SR_DEV_PGID: SR_SKIP_NULL_DEV(dev, file, len); if (len != 11) { logmsg( _("HHCSR131E Device %4.4X PGID size mismatch: %d expected %d\n"), dev->devnum, len, 11); goto sr_error_exit; } SR_READ_BUF(file, &dev->pgid, len); break; /* By Adrian - SR_DEV_DRVPWD */ case SR_DEV_DRVPWD: SR_SKIP_NULL_DEV(dev, file, len); if (len != 11) { logmsg( _("HHCSR134E Device %4.4X DRVPWD size mismatch: %d expected %d\n"), dev->devnum, len, 11); goto sr_error_exit; } SR_READ_BUF(file, &dev->drvpwd, len); break; case SR_DEV_BUSY: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->busy = rc; break; case SR_DEV_RESERVED: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->reserved = rc; break; case SR_DEV_SUSPENDED: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->suspended = rc; break; case SR_DEV_PENDING: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->pending = rc; QUEUE_IO_INTERRUPT(&dev->ioint); break; case SR_DEV_PCIPENDING: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->pcipending = rc; QUEUE_IO_INTERRUPT(&dev->pciioint); break; case SR_DEV_ATTNPENDING: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->attnpending = rc; QUEUE_IO_INTERRUPT(&dev->attnioint); break; case SR_DEV_STARTPENDING: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->startpending = rc; break; case SR_DEV_CRWPENDING: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->crwpending = rc; break; case SR_DEV_CCWADDR: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &dev->ccwaddr, sizeof(dev->ccwaddr)); break; case SR_DEV_IDAPMASK: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &dev->idapmask, sizeof(dev->idapmask)); break; case SR_DEV_IDAWFMT: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &dev->idawfmt, sizeof(dev->idawfmt)); break; case SR_DEV_CCWFMT: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &dev->ccwfmt, sizeof(dev->ccwfmt)); break; case SR_DEV_CCWKEY: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &dev->ccwkey, sizeof(dev->ccwkey)); break; /* This is the trigger to call the device dependent resume routine */ case SR_DEV_DEVTYPE: SR_SKIP_NULL_DEV(dev, file, len); SR_READ_VALUE(file, len, &hw, sizeof(hw)); if (hw != dev->devtype) { logmsg( _("HHCSR132E Device %4.4X type mismatch: %4.4x expected %4.4x\n"), dev->devnum, hw, dev->devtype); goto sr_error_exit; } if (dev->hnd->hresume) { rc = (dev->hnd->hresume) (dev, file); if (rc < 0) goto sr_error_exit; } break; default: if ((key & SR_KEY_ID_MASK) != SR_KEY_ID) { logmsg( _("HHCSR999E Invalid key %8.8x\n"), key); goto sr_error_exit; } SR_READ_SKIP(file, len); break; } /* switch (key) */ } /* while (key != SR_EOF) */ /* For all suspended devices, resume the `suspended' state */ for (dev = sysblk.firstdev; dev; dev = dev->nextdev) { if (dev->suspended && (dev->pmcw.flag5 & PMCW5_V)) { dev->resumesuspended=1; switch (sysblk.arch_mode) { #if defined(_370) case ARCH_370: rc = create_thread (&dev->tid, DETACHED, s370_execute_ccw_chain, dev, "device thread"); break; #endif #if defined(_390) case ARCH_390: rc = create_thread (&dev->tid, DETACHED, s390_execute_ccw_chain, dev, "device thread"); break; #endif #if defined(_900) case ARCH_900: rc = create_thread (&dev->tid, DETACHED, z900_execute_ccw_chain, dev, "device thread"); break; #endif default: /* sysblk.arch_mode not valid (should not occur) */ rc = 99; } /* switch (sysblk.arch_mode) */ if (rc != 0) { logmsg( _("HHCSR133E %4.4X Unable to resume suspended device: %s\n"), dev->devnum, strerror(errno)); goto sr_error_exit; } } /* If suspended device */ } /* For each device */ /* Indicate crw pending for any new devices */ #if defined(_370) if (sysblk.arch_mode != ARCH_370) #endif machine_check_crwpend(); /* Start the CPUs */ OBTAIN_INTLOCK(NULL); ON_IC_IOPENDING; for (i = 0; i < MAX_CPU_ENGINES; i++) if (IS_CPU_ONLINE(i) && (started_mask & CPU_BIT(i))) { sysblk.regs[i]->opinterv = 0; sysblk.regs[i]->cpustate = CPUSTATE_STARTED; sysblk.regs[i]->checkstop = 0; WAKEUP_CPU(sysblk.regs[i]); } RELEASE_INTLOCK(NULL); return 0; sr_read_error: logmsg(_("HHCSR011E read error: %s\n"), strerror(errno)); goto sr_error_exit; /* sr_seek_error: logmsg(_("HHCSR012E seek error: %s\n"), strerror(errno)); goto sr_error_exit; */ sr_string_error: logmsg(_("HHCSR014E string error, incorrect length\n")); goto sr_error_exit; sr_value_error: logmsg(_("HHCSR001E value error, incorrect length\n"), fn); goto sr_error_exit; sr_null_regs_exit: logmsg(_("HHCSR016E CPU key %8.8x found but no active CPU\n"), key); goto sr_error_exit; sr_error_exit: logmsg(_("HHCSR015E Error processing file %s\n"), fn); SR_CLOSE (file); return -1; } hercules-3.12/w32chan.c0000664000175000017500000006237112564723224011625 00000000000000//////////////////////////////////////////////////////////////////////////////////// // w32chan.c Fish's new i/o scheduling logic //////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2001-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// #include "hstdinc.h" #define _W32CHAN_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "w32chan.h" #if defined(OPTION_FISHIO) ///////////////////////////////////////////////////////////////////////////// // Internal scheduler helper macros... #define LockScheduler() (EnterCriticalSection(&IOSchedulerLock)) #define LockThreadParms(pThreadParms) (EnterCriticalSection(&pThreadParms->IORequestListLock)) #define UnlockScheduler() (LeaveCriticalSection(&IOSchedulerLock)) #define UnlockThreadParms(pThreadParms) (LeaveCriticalSection(&pThreadParms->IORequestListLock)) ///////////////////////////////////////////////////////////////////////////// // i/o scheduler variables... (some private, some externally visible) int ios_arch_mode = 0; // current architecture mode int ios_devthread_timeout = 30; // max device thread wait time int* ios_devthread_prio = NULL; // pointer to sysblk.devprio LIST_ENTRY ThreadListHeadListEntry; // anchor for DEVTHREADPARMS linked list CRITICAL_SECTION IOSchedulerLock; // lock for accessing above list // and below variables long ios_devtwait = 0; // #of threads currently idle int ios_devtnbr = 0; // #of threads currently active int ios_devthwm = 0; // max #of threads that WERE active int ios_devtmax = 0; // max #of threads there can be int ios_devtunavail = 0; // #of times 'idle' thread unavailable ///////////////////////////////////////////////////////////////////////////// // initialize i/o scheduler variables and work areas... void InitIOScheduler ( int arch_mode, // (for calling execute_ccw_chain) int* devt_prio, // (ptr to device thread priority) int devt_timeout, // (MAX_DEVICE_THREAD_IDLE_SECS) long devt_max // (maximum #of device threads allowed) ) { ios_arch_mode = arch_mode; ios_devthread_prio = devt_prio; ios_devthread_timeout = devt_timeout; ios_devtmax = devt_max; InitializeListHead(&ThreadListHeadListEntry); MyInitializeCriticalSection(&IOSchedulerLock); } ///////////////////////////////////////////////////////////////////////////// // device_thread parms block... typedef struct _DevThreadParms { DWORD dwThreadID; // device_thread thread id LIST_ENTRY ThreadListLinkingListEntry; // (just a link in the chain) HANDLE hShutdownEvent; // tells device thread to exit HANDLE hRequestQueuedEvent; // tells device thread it has work LIST_ENTRY IORequestListHeadListEntry; // anchor for DEVIOREQUEST list CRITICAL_SECTION IORequestListLock; // (for accessing above list) BOOL bThreadIsDead; // TRUE = thread has exited } DEVTHREADPARMS; ///////////////////////////////////////////////////////////////////////////// // i/o request block... typedef struct _DevIORequest { LIST_ENTRY IORequestListLinkingListEntry; // (just a link in the chain) void* pDevBlk; // (ptr to device block) int* pnDevPrio; // (ptr to device i/o priority) unsigned short wDevNum; // (device number for debugging) } DEVIOREQUEST; ///////////////////////////////////////////////////////////////////////////// // (forward references for some of our functions...) DEVTHREADPARMS* SelectDeviceThread(); DEVTHREADPARMS* CreateDeviceThread(unsigned short wDevNum); void AdjustThreadPriority(int* pCurPrio, int* pNewPrio); void* DeviceThread(void* pThreadParms); void RemoveDeadThreadsFromList(); void RemoveThisThreadFromOurList(DEVTHREADPARMS* pThreadParms); ///////////////////////////////////////////////////////////////////////////// // Schedule a DeviceThread for this i/o request... (called by the 'startio' // function whenever the startio or start subchannel instruction is executed) int ScheduleIORequest(void* pDevBlk, unsigned short wDevNum, int* pnDevPrio) { ///////////////////////////////////////////////////////////////// // PROGRAMMING NOTE: The various errors that can occur in this // function should probably be reported by returning cc1 with // 'channel control check' set (or something similar), but until // I can work out the details, I'm going to be lazy and just // return cc2 (subchannel busy) for now to allow the system to // retry the i/o request if it so desires. Hopefully the problem // was only intermittent and will work the second time around. ///////////////////////////////////////////////////////////////// DEVIOREQUEST* pIORequest; // ptr to i/o request DEVTHREADPARMS* pThreadParms; // ptr to device_thread parameters // Create an i/o request queue entry for this i/o request pIORequest = (DEVIOREQUEST*) malloc(sizeof(DEVIOREQUEST)); if (!pIORequest) { logmsg(_("HHCCP084E malloc(DEVIOREQUEST) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); return 2; } InitializeListLink(&pIORequest->IORequestListLinkingListEntry); pIORequest->pDevBlk = pDevBlk; pIORequest->wDevNum = wDevNum; pIORequest->pnDevPrio = pnDevPrio; // Schedule a device_thread to process this i/o request LockScheduler(); // (lock scheduler vars) if (ios_devtmax < 0) { // Create new "one time only" thread each time... // (Note: the device thread's parms will automatically // be locked upon return if creation was successful.) RemoveDeadThreadsFromList(); // (prevent runaway list) if (!(pThreadParms = CreateDeviceThread(wDevNum))) { UnlockScheduler(); // (unlock scheduler vars) free(pIORequest); // (discard i/o request) return 2; // (return device busy) } } else { // Select a non-busy device thread to handle this i/o request... // (Note: the device thread's parms will automatically // be locked upon return if selection was successful.) if (!(pThreadParms = SelectDeviceThread())) { // All threads are currently busy or no threads exist yet. // Since the possibility of a deadlock[1] can easily occur if we schedule // an i/o request to a currently busy device thread[2], we have no choice // but to create another device thread. // [1] Not an actual programmatic deadlock of course, but nonetheless // a deadlock from the guest operating system's point of view. // [2] A curently busy device thread could easily have its channel program // suspended and thus would never see the queued request until such time // its suspended channel program was resumed and allowed to complete, and // if the request we queued (that would end up waiting to be processed // by the currently suspended device thread) just so happens to be one // that the operating system needs to have completed before it can resume // the currently suspended channel program, then the operating system will // obviously hang. (It would end up waiting for an i/o to complete that // would never complete until the currently suspended channel program was // resumed, which would never be resumed until the queued i/o completes, // which would never even be processed until the currently suspended // channel program is resumed ..... etc.) if (ios_devtmax && ios_devtnbr >= ios_devtmax) // max threads already created? { logmsg(_("HHCCP085W *WARNING* max device threads exceeded.\n")); ios_devtunavail++; // (count occurrences) } // Create a new device thread for this i/o request... // (Note: the device thread's parms will automatically // be locked upon return if creation was successful.) if (!(pThreadParms = CreateDeviceThread(wDevNum))) { UnlockScheduler(); // (unlock scheduler vars) free(pIORequest); // (discard i/o request) return 2; // (return device busy) } } } // (Note: the thread parms lock should still be held at this point) // Queue the i/o request to the selected device_thread's i/o request queue... InsertListTail(&pThreadParms->IORequestListHeadListEntry,&pIORequest->IORequestListLinkingListEntry); // Tell device_thread it has work (must do this while its request list is still // locked to prevent it from prematurely exiting in case it's just about to die) MySetEvent(pThreadParms->hRequestQueuedEvent); // Now unlock its request queue so it can process the request we just gave it UnlockThreadParms(pThreadParms); // (let it proceed) // We're done, so unlock the scheduler vars so another cpu thread // in the configuration can schedule and i/o request and then exit // back the the startio function... UnlockScheduler(); // (unlock vars and exit; we're done) return 0; // (success) } ///////////////////////////////////////////////////////////////////////////// // Select a non-busy DeviceThread... // NOTE! the IOSchedulerLock must be acquired before calling this function! // NOTE! the selected thread's parms will be locked upon return! DEVTHREADPARMS* SelectDeviceThread() { DEVTHREADPARMS* pThreadParms; // ptr to selected device thread LIST_ENTRY* pListEntry; // (work) pListEntry = ThreadListHeadListEntry.Flink; while (pListEntry != &ThreadListHeadListEntry) { pThreadParms = CONTAINING_RECORD(pListEntry,DEVTHREADPARMS,ThreadListLinkingListEntry); LockThreadParms(pThreadParms); // (freeze moving target) if (pThreadParms->bThreadIsDead) { UnlockThreadParms(pThreadParms); RemoveThisThreadFromOurList(pThreadParms); pListEntry = ThreadListHeadListEntry.Flink; continue; } if (!IsEventSet(pThreadParms->hRequestQueuedEvent)) { RemoveListEntry(pListEntry); InsertListTail(&ThreadListHeadListEntry,pListEntry); return pThreadParms; } UnlockThreadParms(pThreadParms); // (can't use this one) pListEntry = pListEntry->Flink; } return NULL; // (all of them are busy) } ///////////////////////////////////////////////////////////////////////////// // create a new device thread and add it to the list... // NOTE! the IOSchedulerLock must be acquired before calling this function! // NOTE! the created thread's parms will be locked upon return! DEVTHREADPARMS* CreateDeviceThread(unsigned short wDevNum) { DEVTHREADPARMS* pThreadParms; // ptr to returned device_thread parameters DWORD dwThreadID; // (work) pThreadParms = malloc(sizeof(DEVTHREADPARMS)); // (allocate structure) if (!pThreadParms) { logmsg(_("HHCCP086E malloc(DEVTHREADPARMS) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); return NULL; // (error) } pThreadParms->hShutdownEvent = MyCreateEvent(NULL,TRUE,FALSE,NULL); if (!pThreadParms->hShutdownEvent) { logmsg(_("HHCCP087E CreateEvent(hShutdownEvent) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); free(pThreadParms); return NULL; // (error) } pThreadParms->hRequestQueuedEvent = MyCreateEvent(NULL,TRUE,FALSE,NULL); if (!pThreadParms->hRequestQueuedEvent) { logmsg(_("HHCCP088E CreateEvent(hRequestQueuedEvent) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); MyCloseHandle(pThreadParms->hShutdownEvent); free(pThreadParms); return NULL; // (error) } MyInitializeCriticalSection(&pThreadParms->IORequestListLock); InitializeListLink(&pThreadParms->ThreadListLinkingListEntry); InitializeListHead(&pThreadParms->IORequestListHeadListEntry); pThreadParms->bThreadIsDead = FALSE; pThreadParms->dwThreadID = 0; if (fthread_create(&dwThreadID,NULL,DeviceThread,pThreadParms,"DeviceThread") != 0) { logmsg(_("HHCCP089E fthread_create(DeviceThread) failed; device=%4.4X, strerror=\"%s\"\n"), wDevNum,strerror(errno)); MyCloseHandle(pThreadParms->hShutdownEvent); MyCloseHandle(pThreadParms->hRequestQueuedEvent); MyDeleteCriticalSection(&pThreadParms->IORequestListLock); free(pThreadParms); return NULL; // (error) } // Add the newly created device_thread to the end of our list of managed threads. InsertListTail(&ThreadListHeadListEntry,&pThreadParms->ThreadListLinkingListEntry); if (++ios_devtnbr > ios_devthwm) ios_devthwm = ios_devtnbr; LockThreadParms(pThreadParms); // (lock thread parms before using) return pThreadParms; // (success) } ///////////////////////////////////////////////////////////////////////////// // helper function to set a thread's priority to its proper value void AdjustThreadPriority(int* pCurPrio, int* pNewPrio) { if (*pCurPrio != *pNewPrio) { setpriority(PRIO_PROCESS, 0, *pNewPrio); *pCurPrio = *pNewPrio; } } ///////////////////////////////////////////////////////////////////////////// // the device_thread itself... (processes queued i/o request // by calling "execute_ccw_chain" function in channel.c...) extern void call_execute_ccw_chain(int arch_mode, void* pDevBlk); void* DeviceThread (void* pArg) { DEVTHREADPARMS* pThreadParms; // ptr to thread parms LIST_ENTRY* pListEntry; // (work) DEVIOREQUEST* pIORequest; // ptr to i/o request void* pDevBlk; // ptr to device block int* pnDevPrio; // ptr to device i/o priority int nCurPrio; // current thread priority pThreadParms = (DEVTHREADPARMS*) pArg; pThreadParms->dwThreadID = GetCurrentThreadId(); nCurPrio = getpriority(PRIO_PROCESS, 0); AdjustThreadPriority(&nCurPrio,ios_devthread_prio); for (;;) { // Wait for an i/o request to be queued... InterlockedIncrement(&ios_devtwait); MyWaitForSingleObject(pThreadParms->hRequestQueuedEvent,ios_devthread_timeout * 1000); InterlockedDecrement(&ios_devtwait); if (IsEventSet(pThreadParms->hShutdownEvent)) break; // Lock our queue so it doesn't change while we take a look at it... LockThreadParms(pThreadParms); // (freeze moving target) // Check to see if we have any work... if (IsListEmpty(&pThreadParms->IORequestListHeadListEntry)) { // We've waited long enough... pThreadParms->bThreadIsDead = TRUE; // (keep scheduler informed) UnlockThreadParms(pThreadParms); // (let go of our parms block) return NULL; // (return, NOT break!) } // Remove the i/o request from our queue... // It's important that we remove the request from our queue but // NOT reset our flag (if the list is now empty) until AFTER we've // processed the request (see further below for details as to why). pListEntry = RemoveListHead(&pThreadParms->IORequestListHeadListEntry); UnlockThreadParms(pThreadParms); // (done with thread parms for now) pIORequest = CONTAINING_RECORD(pListEntry,DEVIOREQUEST,IORequestListLinkingListEntry); pDevBlk = pIORequest->pDevBlk; // (need ptr to devblk) pnDevPrio = pIORequest->pnDevPrio; // (need ptr to devprio) free(pIORequest); // (not needed anymore) // Process the i/o request by calling the proper 'execute_ccw_chain' // function (based on architectural mode) in source module channel.c // Set thread priority to requested device level AdjustThreadPriority(&nCurPrio,pnDevPrio); call_execute_ccw_chain(ios_arch_mode, pDevBlk); // (process i/o request) // Reset thread priority, if necessary if (nCurPrio > *ios_devthread_prio) AdjustThreadPriority(&nCurPrio,ios_devthread_prio); //////////////////////////////////////////////////////////////////////////// // // * * * I M P O R T A N T * * * // // It's important that we reset our flag AFTER we're done with our request // in order to prevent the scheduler from trying to give us more work while // we're still busy processing the current i/o request (in case the channel // program we're processing gets suspended). If the channel program we're // processing gets suspended and the scheduler places another request in our // queue, it won't ever get processed until our suspended channel program is // resumed, and if the request that was placed in our queue was a request // for an i/o to another device that the operating system needs to complete // in order to obtain the information needed to resume our suspended channel // program, a deadlock will occur! (i.e. if the operating system needs to // read data from another device before it can resume our channel program, // then the i/o request to read from that device better not be given to us // because we're suspended and will never get around to executing it until // we're resumed, which will never happen until the i/o request waiting in // our queue is completed, which will never happend until we're resumed, // etc...) // //////////////////////////////////////////////////////////////////////////// // Now that we're done this i/o, reset our flag. LockThreadParms(pThreadParms); // (freeze moving target) if (IsListEmpty(&pThreadParms->IORequestListHeadListEntry)) MyResetEvent(pThreadParms->hRequestQueuedEvent); UnlockThreadParms(pThreadParms); // (thaw moving target) if (IsEventSet(pThreadParms->hShutdownEvent)) break; // If we're a "one time only" thread, then we're done. if (ios_devtmax < 0) { // Note: no need to lock our thread parms before setting 'dead' flag // since the scheduler should never queue us another request anyway // because we're a "one-time-only" thread. pThreadParms->bThreadIsDead = TRUE; // (let garbage collector discard us) return NULL; // (return, NOT break!) } } // The only time we reach here is if the shutdown event was signalled (i.e. we // were manually "cancelled" or asked to stop processing; i.e. the i/o subsystem // was reset). Discard all i/o requests that may still be remaining in our queue. TRACE("** DeviceThread %8.8X: shutdown detected\n", (unsigned int)pThreadParms->dwThreadID); LockThreadParms(pThreadParms); // (freeze moving target) // Discard all queued i/o requests... while (!IsListEmpty(&pThreadParms->IORequestListHeadListEntry)) { pListEntry = RemoveListHead(&pThreadParms->IORequestListHeadListEntry); pIORequest = CONTAINING_RECORD(pListEntry,DEVIOREQUEST,IORequestListLinkingListEntry); TRACE("** DeviceThread %8.8X: discarding i/o request for device %4.4X\n", (unsigned int)pThreadParms->dwThreadID,pIORequest->wDevNum); free(pIORequest); } pThreadParms->bThreadIsDead = TRUE; // (tell scheduler we've died) TRACE("** DeviceThread %8.8X: shutdown complete\n", (unsigned int)pThreadParms->dwThreadID); UnlockThreadParms(pThreadParms); // (thaw moving target) return NULL; } ///////////////////////////////////////////////////////////////////////////// // shutdown idle threads (if possible) until number drops below threshold... void TrimDeviceThreads() { DEVTHREADPARMS* pThreadParms; BOOL bThreadIsBusy; LIST_ENTRY* pListEntry; LockScheduler(); // (lock scheduler vars) pListEntry = ThreadListHeadListEntry.Flink; while (pListEntry != &ThreadListHeadListEntry && ios_devtnbr > ios_devtmax) { pThreadParms = CONTAINING_RECORD(pListEntry,DEVTHREADPARMS,ThreadListLinkingListEntry); pListEntry = pListEntry->Flink; LockThreadParms(pThreadParms); bThreadIsBusy = IsEventSet(pThreadParms->hRequestQueuedEvent); UnlockThreadParms(pThreadParms); if (bThreadIsBusy) continue; // Thread is currently idle and awaiting work. Tell it to exit. // (Note: we need to signal the hRequestQueuedEvent event too so that // it can wake up and notice that the hShutdownEvent event is signaled) MySetEvent(pThreadParms->hShutdownEvent); MySetEvent(pThreadParms->hRequestQueuedEvent); // (wakeup thread) Sleep(10); // (give it time to die) RemoveDeadThreadsFromList(); } UnlockScheduler(); // (unlock shceduler vars) } #if 0 // (the following is not needed yet) ///////////////////////////////////////////////////////////////////////////// // ask all device_threads to exit... (i.e. i/o subsystem reset) void KillAllDeviceThreads() { DEVTHREADPARMS* pThreadParms; LIST_ENTRY* pListEntry; TRACE("** ENTRY KillAllDeviceThreads\n"); LockScheduler(); // (lock scheduler vars) RemoveDeadThreadsFromList(); // (discard dead threads) while (!IsListEmpty(&ThreadListHeadListEntry)) { pListEntry = ThreadListHeadListEntry.Flink; // (get starting link in chain) while (pListEntry != &ThreadListHeadListEntry) // (while not end of chain reached...) { pThreadParms = CONTAINING_RECORD(pListEntry,DEVTHREADPARMS,ThreadListLinkingListEntry); // (Note: we need to signal the hRequestQueuedEvent event too so that // it can wake up and notice that the hShutdownEvent event is signaled) TRACE("** KillAllDeviceThreads: setting shutdown event for thread %8.8X\n", pThreadParms->dwThreadID); LockThreadParms(pThreadParms); // (lock thread parms) MySetEvent(pThreadParms->hShutdownEvent); // (request shutdown) MySetEvent(pThreadParms->hRequestQueuedEvent); // (wakeup thread) UnlockThreadParms(pThreadParms); // (unlock thread parms) pListEntry = pListEntry->Flink; // (go on to next link in chain) } UnlockScheduler(); // (unlock scheduler vars) TRACE("** KillAllDeviceThreads: waiting for thread(s) to shutdown\n"); Sleep(10); // (give them time to die) LockScheduler(); // (re-lock scheduler vars) RemoveDeadThreadsFromList(); // (discard dead threads) } UnlockScheduler(); // (unlock scheduler vars) TRACE("** EXIT KillAllDeviceThreads\n"); } #endif // (the preceding is not needed yet) ///////////////////////////////////////////////////////////////////////////// // remove all dead threads from our list of threads... // NOTE! the IOSchedulerLock must be acquired before calling this function! void RemoveDeadThreadsFromList() { DEVTHREADPARMS* pThreadParms; BOOL bThreadIsDead; LIST_ENTRY* pListEntry = ThreadListHeadListEntry.Flink; while (pListEntry != &ThreadListHeadListEntry) { pThreadParms = CONTAINING_RECORD(pListEntry,DEVTHREADPARMS,ThreadListLinkingListEntry); pListEntry = pListEntry->Flink; LockThreadParms(pThreadParms); bThreadIsDead = pThreadParms->bThreadIsDead; UnlockThreadParms(pThreadParms); if (bThreadIsDead) RemoveThisThreadFromOurList(pThreadParms); } } ///////////////////////////////////////////////////////////////////////////// // private function to remove an entry from our list and discard it... // NOTE! the IOSchedulerLock must be acquired before calling this function! void RemoveThisThreadFromOurList(DEVTHREADPARMS* pThreadParms) { RemoveListEntry(&pThreadParms->ThreadListLinkingListEntry); MyCloseHandle(pThreadParms->hShutdownEvent); MyCloseHandle(pThreadParms->hRequestQueuedEvent); MyDeleteCriticalSection(&pThreadParms->IORequestListLock); free(pThreadParms); ios_devtnbr--; // (track number of active device_thread) } ///////////////////////////////////////////////////////////////////////////// #endif // !defined(OPTION_FISHIO) hercules-3.12/sllib.c0000664000175000017500000012037412564723224011463 00000000000000/* SLLIB.C (c) Copyright Leland Lucius, 2000-2009 */ /* Library for managing Standard Label tapes */ /* || ---------------------------------------------------------------------------- || || SLLIB.C (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Library for managing Standard Label tapes. || || ---------------------------------------------------------------------------- */ #include "hstdinc.h" #define _SLLIB_C_ #define _HTAPE_DLL_ #include "hercules.h" #include "sllib.h" /* || Local constant data */ /* || Label IDs in EBCDIC */ static const char *sl_elabs[] = { "\x00\x00\x00", /* Placeholder */ "\xE5\xD6\xD3", /* EBCDIC characters "VOL" */ "\xC8\xC4\xD9", /* EBCDIC characters "HDR" */ "\xE4\xC8\xD3", /* EBCDIC characters "UHL" */ "\xC5\xD6\xC6", /* EBCDIC characters "EOF" */ "\xC5\xD6\xE5", /* EBCDIC characters "EOV" */ "\xE4\xE3\xD3", /* EBCDIC characters "UTL" */ }; #define SL_ELABS_MAX ( sizeof( sl_elabs ) / sizeof( sl_elabs[ 0 ] ) ) /* || Label IDs in ASCII */ static const char *sl_alabs[] = { "\x00\x00\x00", /* Placeholder */ "\x56\x4f\x4c", /* ASCII characters "VOL" */ "\x48\x44\x52", /* ASCII characters "HDR" */ "\x55\x48\x4c", /* ASCII characters "UHL" */ "\x45\x4f\x46", /* ASCII characters "EOF" */ "\x45\x4f\x56", /* ASCII characters "EOV" */ "\x55\x54\x4c", /* ASCII characters "UTL" */ }; #define SL_ALABS_MAX ( sizeof( sl_alabs ) / sizeof( sl_alabs[ 0 ] ) ) /* || Minimum and maximum ranges for each label type */ static const struct { int min; int max; } sl_ranges[] = { { 0, 0 }, /* Placeholder */ { 1, 1 }, /* ASCII characters "VOL" */ { 1, 2 }, /* ASCII characters "HDR" */ { 1, 8 }, /* ASCII characters "UHL" */ { 1, 2 }, /* ASCII characters "EOF" */ { 1, 2 }, /* ASCII characters "EOV" */ { 1, 8 }, /* ASCII characters "UTL" */ }; /* || Text descriptions for errors */ static const char *sl_errstr[] = { "No error", "Block size out of range", "Data set sequence out of range", "Invalid expiration date", "Missing or invalid job name", "Missing or invalid record length", "Owner string invalid or too long", "Missing or invalid record format", "Missing or invalid step name", "Invalid recording technique", "Volume sequence out of range", "Missing or invalid volume serial", "User data too long", "Label type invalid", "Label number invalid", "Invalid error code", }; #define SL_ERRSTR_MAX ( sizeof( sl_errstr) / sizeof( sl_errstr[ 0 ] ) ) /* || Valid characters for a Standard Label || (from: SC26-4565-01 "3.4 Label Definition and Organization") */ static const char sl_cset[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !\"%&'()*+,-./:;<=>?" }; /* || Valid record formats */ static const struct { char *recfm; char f; char b; char c; } valfm[] = { { "U", 'U', ' ', ' ' }, { "UA", 'U', ' ', 'A' }, { "UM", 'U', ' ', 'M' }, { "F", 'F', ' ', ' ' }, { "FA", 'F', ' ', 'A' }, { "FM", 'F', ' ', 'M' }, { "FB", 'F', 'B', ' ' }, { "FBA", 'F', 'B', 'A' }, { "FBM", 'F', 'B', 'M' }, { "FS", 'F', 'S', ' ' }, { "FSA", 'F', 'S', 'A' }, { "FSM", 'F', 'S', 'M' }, { "FBS", 'F', 'R', ' ' }, { "FBSA", 'F', 'R', 'A' }, { "FBSM", 'F', 'R', 'M' }, { "V", 'V', ' ', ' ' }, { "VA", 'V', ' ', 'A' }, { "VM", 'V', ' ', 'M' }, { "VB", 'V', 'B', ' ' }, { "VBA", 'V', 'B', 'A' }, { "VBM", 'V', 'B', 'M' }, { "VS", 'V', 'S', ' ' }, { "VSA", 'V', 'S', 'A' }, { "VSM", 'V', 'S', 'M' }, { "VBS", 'V', 'R', ' ' }, { "VBSA", 'V', 'R', 'A' }, { "VBSM", 'V', 'R', 'M' }, }; #define VALFMCNT ( sizeof( valfm ) / sizeof( valfm[ 0 ] ) ) /*==DOC== NAME sl_atoe - Translate input buffer from ASCII to EBCDIC SYNOPSIS #include "sllib.h" char *sl_atoe( void *dbuf, void *sbuf, int slen ) DESCRIPTION Translates, and optionally copies, "sbuf" from ASCII to EBCDIC for "slen" characters. If "dbuf" is specified as NULL, then "sbuf" is translated in place. Otherwise, "dbuf" specifies the buffer where the translated characters will be stored. RETURN VALUE The return value will be either "sbuf" or "dbuf" depending on whether "dbuf" was passed as NULL. EXAMPLE // // Convert buffer // #include "sllib.h" unsigned char ascii[] = "\x48\x65\x72\x63\x75\x6c\x65\x73\x2e\x2e\x2e" "\x20\x52\x65\x73\x75\x72\x72\x65\x63\x74\x69" "\x6e\x67\x20\x74\x68\x65\x20\x64\x69\x6e\x6f" "\x73\x61\x75\x72\x73\x21"; unsigned char ebcdic[ sizeof( ascii ) ]; int main( int argc, char *argv[] ) { int len; int i; len = strlen( ascii ); sl_atoe( ebcdic, ascii, len ); printf( "ascii string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ascii[ i ] ); } printf( "\nebcdic string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ebcdic[ i ] ); } printf( "\n" ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT char * sl_atoe( void *dbuf, void *sbuf, int slen ) { unsigned char *sptr; unsigned char *dptr; sptr = sbuf; dptr = dbuf; if( dptr == NULL ) { dptr = sptr; } while( slen > 0 ) { slen--; dptr[ slen ] = host_to_guest( sptr[ slen ] ); } return( (char *)dptr ); } /*==DOC== NAME sl_etoa - Translate input buffer from EBCDIC to ASCII SYNOPSIS #include "sllib.h" char *sl_etoa( void *dbuf, void *sbuf, int slen ) DESCRIPTION Translates, and optionally copies, "sbuf" from EBCDIC to ASCII for "slen" characters. If "dbuf" is specified as NULL, then "sbuf" is translated in place. Otherwise, "dbuf" specifies the buffer where the translated characters will be stored. RETURN VALUE The return value will be either "sbuf" or "dbuf" depending on whether "dbuf" was passed as NULL. EXAMPLE // // Convert buffer // #include "sllib.h" unsigned char ebcdic[] = "\xc8\x85\x99\x83\xa4\x93\x85\xa2\x4b\x4b\x4b" "\x40\xd9\x85\xa2\xa4\x99\x99\x85\x83\xa3\x89" "\x95\x87\x40\xa3\x88\x85\x40\x84\x89\x95\x96" "\xa2\x81\xa4\x99\xa2\x5a"; unsigned char ascii[ sizeof( ebcdic ) ]; int main( int argc, char *argv[] ) { int len; int i; len = strlen( ebcdic ); sl_etoa( ascii, ebcdic, len ); printf( "ebcdic string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ebcdic[ i ] ); } printf( "\nascii string: " ); for( i = 0 ; i < len ; i++ ) { printf( "%02x ", ascii[ i ] ); } printf( "\n" ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT char * sl_etoa( void *dbuf, void *sbuf, int slen ) { unsigned char *sptr; unsigned char *dptr; sptr = sbuf; dptr = dbuf; if( dptr == NULL ) { dptr = sptr; } while( slen > 0 ) { slen--; dptr[ slen ] = guest_to_host( sptr[ slen ] ); } return( (char *)dptr ); } /*==DOC== NAME sl_islabel - Determines if passed data represents a standard label SYNOPSIS #include "sllib.h" int sl_islabel( SLLABEL *dlab, void *buf, int len ) DESCRIPTION This function performs several tests to determine if the "buf" parameter points to a valid standard label. The "len" parameter must be the length of the data pointed to by the "buf" parameter. If "dlab" does not contain NULL, then the data pointed to by "buf" will be converted to ASCII and placed at the "dlab" location. RETURN VALUE TRUE is returned if the data appears to be a standard label. Otherwise, FALSE is returned. NOTES The input label may be in either ASCII or EBCDIC. Currently, the tests are quite trival, but they may become more strict. EXAMPLE // // Test validity of a label // #include "sllib.h" int main( int argc, char *argv[] ) { SLLABEL sllab = { 0 }; printf( "Label is%s valid\n", ( sl_islabel( NULL, &sllab, sizeof( sllab ) ? "" : " not" ) ); sl_vol1( &sllab, "HET001", "HERCULES" ); printf( "Label is: %s valid\n", ( sl_islabel( NULL, &sllab, sizeof( sllab ) ? "" : " not" ) ); return( 0 ); } SEE ALSO sl_vol1() ==DOC==*/ DLL_EXPORT int sl_islabel( SLLABEL *lab, void *buf, int len ) { int i; int num; unsigned char *ptr; if( len != sizeof( SLLABEL ) ) { return FALSE; } for( i = 1 ; i < (int)SL_ELABS_MAX ; i++ ) { if( memcmp( sl_elabs[ i ], buf, 3 ) == 0 ) { ptr = buf; num = ptr[ 3 ] - (unsigned char) '\xF0'; if( ( num >= sl_ranges[ i ].min ) && ( num <= sl_ranges[ i ].max ) ) { if( lab != NULL ) { sl_etoa( lab, buf, len ); } return( TRUE ); } } if( memcmp( sl_alabs[ i ], buf, 3 ) == 0 ) { ptr = buf; num = ptr[ 3 ] - (unsigned char) '\x30'; if( ( num >= sl_ranges[ i ].min ) && ( num <= sl_ranges[ i ].max ) ) { if( lab != NULL ) { memcpy( lab, buf, len ); } return( TRUE ); } } } return( FALSE ); } /*==DOC== NAME sl_istype - Verifies data is of specified standard label type SYNOPSIS #include "sllib.h" int sl_istype( void *buf, int type, int num ) DESCRIPTION This function verifies that the data pointed to by the "buf" parameter contains a standard label as determined by the "type" and "num" parameters. The "type" parameter can be one of the "SLT_*" defines found in the "sllib.h" header file. The "num" parameter further defines the type and is usually 1 or 2. However, 0 may be specified to only test using the "type" parameter. RETURN VALUE TRUE is returned if the data is of the given type. Otherwise, FALSE is returned. NOTES The input data may be in either ASCII or EBCDIC. This routine is "usually" not called directly by user programs. The "sl_is*" macros in "sllib.h" should be used instead. EXAMPLE // // Determine if data is a VOL1 or HDR2 label. // #include "sllib.h" int main( int argc, char *argv[] ) { SLLABEL sllab = { 0 }; sl_vol1( &sllab, "HET001", "HERCULES" ); printf( "Label is%s a VOL1\n", ( sl_istype( &sllab, SLT_VOL, 1 ) ? "" : " not" ) ); printf( "Label is%s a HDR2\n", ( sl_istype( &sllab, SLT_HDR, 2 ) ? "" : " not" ) ); return( 0 ); } SEE ALSO sl_vol1() ==DOC==*/ DLL_EXPORT int sl_istype( void *buf, int type, int num ) { unsigned char *ptr; ptr = buf; /* || Check EBCDIC table */ if( memcmp( buf, sl_elabs[ type ], 3 ) == 0 ) { if( ( num == 0 ) || ( ptr[ 3 ] == ( ( (unsigned char) '\xF0' ) + num ) ) ) { return( TRUE ); } } /* || Check ASCII table */ if( memcmp( buf, sl_alabs[ type ], 3 ) == 0 ) { if( ( num == 0 ) || ( ptr[ 3 ] == ( ( (unsigned char) '\x30') + num ) ) ) { return( TRUE ); } } return( FALSE ); } /*==DOC== NAME sl_fmtdate - Converts dates to/from SL format SYNOPSIS #include "sllib.h" char *sl_fmtdate( char *dest, char *src, int fromto ) DESCRIPTION Converts the "src" date from or to the SL format and places the result at the "dest" location. If the "src" parameter is specified as NULL, then the current date will automatically be supplied. The "fromto" parameter controls the type of conversion. Specify FALSE to convert to SL format and TRUE from convert from SL format. When converting to the SL format, the "src" parameter must contain a valid Julian date in one of the following formats: YYDDD YY.DDD YYYYDDD YYYY.DDD RETURN VALUE If "src" contains an invalid date, then NULL will be returned. Otherwise, the "dest" value is returned. EXAMPLE // // Convert julian date to SL format // #include "sllib.h" char sldate[ SL_DATELEN ]; char jdate[] = "1998.212"; int main( int argc, char *argv[] ) { sl_fmtdate( sldate, jdate, FALSE ); printf( "Julian date : %s\n", jdate ); printf( "SL date : %-6.6s\n", sldate ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT char * sl_fmtdate( char *dest, char *src, int fromto ) { char wbuf[ 9 ]; char sbuf[ 9 ]; char *ptr; time_t curtime; struct tm tm; int ret; /* || If source represents an SL date, then convert it to julian */ if( fromto ) { if( src == NULL ) { return( NULL ); } if( src[ 5 ] == '0' ) { dest[ 0 ] = src[ 1 ]; dest[ 1 ] = src[ 2 ]; } else if( src[ 0 ] == ' ' ) { dest[ 0 ] = '1'; dest[ 1 ] = '9'; } else { dest[ 0 ] = '2'; dest[ 1 ] = src[ 0 ]; } memcpy( &dest[ 2 ], &src[ 1 ] , 2 ); dest[ 4 ] = '.'; memcpy( &dest[ 5 ], &src[ 3 ] , 3 ); } else { /* || Supply current date if source is null */ if( src == NULL ) { strftime( sbuf, sizeof( sbuf ), "%Y%j", localtime( &curtime ) ); src = sbuf; } /* || Base initial guess at format on length of src date */ switch( strlen( src ) ) { case 5: ptr = "%2u%3u"; break; case 6: ptr = "%2u.%3u"; break; case 7: ptr = "%4u%3u"; break; case 8: ptr = "%4u.%3u"; break; default: return( NULL ); break; } /* || Convert src to "tm" format */ ret = sscanf( src, ptr, &tm.tm_year, &tm.tm_yday ); if( ret != 2 || tm.tm_yday < 1 || tm.tm_yday > 366 ) { return( NULL ); } tm.tm_yday--; /* || Now, convert to SL tape format */ strftime( wbuf, sizeof( wbuf ), "%Y%j", &tm ); if( tm.tm_year < 100 ) { /* || 1900s are indicated by a blank. */ wbuf[ 1 ] = ' '; } /* || Finally, copy SL date to destination */ memcpy( dest, &wbuf[ 1 ], 6 ); } /* || Return dest pointer */ return( dest ); } /*==DOC== NAME sl_fmtlab - Transforms an SL label from raw to cooked format SYNOPSIS #include "sllib.h" void sl_fmtlab( SLFMT *fmt, SLLABEL *lab ) DESCRIPTION Converts the SL label specified by "lab" into a "cooked" format that's easier to process. Text descriptions are supplied for each field are also supplied. RETURN VALUE Nothing is returned. NOTES The input label may be in either ASCII or EBCDIC. It will be converted to ASCII before building the cooked version. The first two fields of the SLFMT structure are arrays that contain the text description and value for each field based on the label type. The arrays are terminated with NULL pointers. EXAMPLE // // Convert an SL label to cooked format // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_vol1( &sllab, "HET001", "HERCULES" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_vol1() ==DOC==*/ #define lab2fmt( i1, f2, l3, k4 ) \ fmt->key[ i1 ] = k4; \ fmt->val[ i1 ] = fmt->f2; \ memcpy( fmt->f2, lab->f2, l3 ); DLL_EXPORT void sl_fmtlab( SLFMT *fmt, SLLABEL *lab ) { SLLABEL templab; /* || Initialize */ memset( fmt, 0, sizeof( SLFMT ) ); /* || If label appears to be EBCDIC, convert to ASCII before processing */ if( sl_islabel( &templab, lab, sizeof( SLLABEL ) ) == FALSE ) { return; } lab = &templab; /* || Store label type (combine ID and NUM) */ fmt->key[ 0 ] = "Label"; fmt->val[ 0 ] = fmt->type; memcpy( fmt->type, lab->id, 4 ); /* || Build remaining fields based on label type */ if( memcmp( lab->id, "VOL", 3 ) == 0 ) { if( lab->num[ 0 ] == '1' ) { lab2fmt( 1, slvol.volser, 6, "Volume Serial" ); lab2fmt( 2, slvol.idrc, 1, "Improved Data Rec." ); lab2fmt( 3, slvol.owner, 10, "Owner Code" ); } } else if( ( memcmp( lab->id, "HDR", 3 ) == 0 ) || ( memcmp( lab->id, "EOF", 3 ) == 0 ) || ( memcmp( lab->id, "EOV", 3 ) == 0 ) ) { if( lab->num[ 0 ] == '1' ) { lab2fmt( 1, slds1.dsid, 17, "Dataset ID" ); lab2fmt( 2, slds1.volser, 6, "Volume Serial" ); lab2fmt( 3, slds1.volseq, 4, "Volume Sequence" ); lab2fmt( 4, slds1.dsseq, 4, "Dataset Sequence" ); lab2fmt( 5, slds1.genno, 4, "GDG Number" ); lab2fmt( 6, slds1.verno, 2, "GDG Version" ); lab2fmt( 7, slds1.crtdt, 6, "Creation Date" ); lab2fmt( 8, slds1.expdt, 6, "Expiration Date" ); lab2fmt( 9, slds1.dssec, 1, "Dataset Security" ); lab2fmt( 10, slds1.blklo, 6, "Block Count Low" ); lab2fmt( 11, slds1.syscd, 13, "System Code" ); lab2fmt( 12, slds1.blkhi, 4, "Block Count High" ); } else if( lab->num[ 0 ] == '2' ) { lab2fmt( 1, slds2.recfm, 1, "Record Format" ); lab2fmt( 2, slds2.blksize, 5, "Block Size" ); lab2fmt( 3, slds2.lrecl, 5, "Record Length" ); lab2fmt( 4, slds2.den, 1, "Density" ); lab2fmt( 5, slds2.dspos, 1, "Dataset Position" ); lab2fmt( 6, slds2.jobid, 17, "Job/Step ID" ); lab2fmt( 7, slds2.trtch, 2, "Recording Technique" ); lab2fmt( 8, slds2.ctrl, 1, "Control Character" ); lab2fmt( 9, slds2.blkattr, 1, "Block Attribute" ); lab2fmt( 10, slds2.devser, 6, "Device Serial" ); lab2fmt( 11, slds2.ckptid, 1, "Checkpoint ID" ); lab2fmt( 12, slds2.lblkln, 10, "Large Block Length" ); } } else if( memcmp( lab->id, "USR", 3 ) == 0 ) { lab2fmt( 1, slusr.data, 76, "User Data" ); } return; } #undef lab2fmt /*==DOC== NAME sl_vol - Generate a volume label SYNOPSIS #include "sllib.h" int sl_vol( SLLABEL *lab, char *volser, char *owner ) DESCRIPTION This function builds a volume label based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The remaining parameters correspond to fields within the label and are converted to EBCDIC before storing. The "owner" parameter may be specified as NULL, in which case blanks are supplied. RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_VOLSER Missing or invalid volume serial SLE_OWNER Owner string too long NOTES This routine is normally accessed using the supplied "sl_vol1" macro. Only the "most common" label fields have corresponding parameters so the user must supply any other desired values. EXAMPLE // // Create a VOL1 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_vol( &sllab, "HET001", "HERCULES" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_vol( SLLABEL *lab, char *volser, char *owner ) { size_t len; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ memcpy( lab->id, sl_alabs[ SLT_VOL ], 3 ); /* || Label number */ lab->num[ 0 ] = '1'; /* || Volser */ if( volser == NULL ) { return( SLE_VOLSER ); } len = strlen( volser ); if( ( len > 6 ) || ( strspn( volser, sl_cset ) != len ) ) { return( SLE_VOLSER ); } memcpy( lab->slvol.volser, volser, len ); /* || Owner */ if( owner != NULL ) { len = strlen( owner ); if( len > 10 ) { return( SLE_OWNER ); } memcpy( lab->slvol.owner, owner, len ); } /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_ds1 - Generate a data set label 1 SYNOPSIS #include "sllib.h" int sl_ds1( SLLABEL *lab, int type, char *dsn, char *volser, int volseq, int dsseq, char *expdt, int blocks ) DESCRIPTION This function builds a data set label 1 based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The "type" parameter must be "SLT_HDR", "SLT_EOF", or "SLT_EOV". The remaining parameters correspond to fields within the label and are converted to EBCDIC before storing. The "dsn" parameter may be set to "SL_INITDSN" if "SLT_HDR" is specified for the "type" parameter. This will create an IEHINITT format HDR1 label. The "blocks" parameter is forced to 0 for "SLT_HDR" types. RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_INVALIDTYPE Invalid label type specified SLE_VOLSER Missing or invalid volume serial SLE_OWNER Owner string too long NOTES This routine is normally accessed using the supplied "sl_hdr1", "sl_eof1", or "sl_eov1" macros. Only the "most common" label fields have corresponding parameters so the user must supply any other desired values. EXAMPLE // // Create a EOF1 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_ds1( &sllab, SLT_EOF, "HERCULES.TAPE.G0010V00", "HERC01", 1, 1, "2001.321", 289 ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_ds1( SLLABEL *lab, int type, char *dsn, char *volser, int volseq, int dsseq, char *expdt, int blocks ) { int gdg; size_t len; size_t ndx; char wbuf[ 80 ]; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ if( ( type != SLT_HDR ) && ( type != SLT_EOF ) && ( type != SLT_EOV ) ) { return( SLE_INVALIDTYPE ); } memcpy( lab->id, sl_alabs[ type ], 3 ); /* || Label number */ lab->num[ 0 ] = '1'; /* || Special IEHINITT dataset name? */ if( ( type == SLT_HDR ) && ( strcmp( dsn, SL_INITDSN ) == 0 ) ) { memset( &lab->slds1, '0', sizeof( lab->slds1 ) ); sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return( 0 ); } /* || Dataset ID */ ndx = 0; len = strlen( dsn ); if( len > 17 ) { ndx = len - 17; len = 17; } memcpy( lab->slds1.dsid, &dsn[ ndx ], len ); /* || GDG generation and version */ if( len > 9 ) { gdg = 0; gdg += ( dsn[ len - 9 ] == '.' ); gdg += ( dsn[ len - 8 ] == 'G' ); gdg += ( isdigit( dsn[ len - 7 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 6 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 5 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 4 ] ) != 0 ); gdg += ( dsn[ len - 3 ] == 'V' ); gdg += ( isdigit( dsn[ len - 2 ] ) != 0 ); gdg += ( isdigit( dsn[ len - 1 ] ) != 0 ); if( gdg == 9 ) { memcpy( lab->slds1.genno, &dsn[ len - 7 ], 4 ); memcpy( lab->slds1.verno, &dsn[ len - 2 ], 2 ); } } /* || Volser */ len = strlen( volser ); if( len > 6 ) { return( SLE_VOLSER ); } memcpy( lab->slds1.volser, volser, len ); /* || Volume sequence */ if( volseq > 9999 ) { return( SLE_VOLSEQ ); } sprintf( wbuf, "%04u", volseq ); memcpy( lab->slds1.volseq, wbuf, 4 ); /* || Dataset sequence */ if( dsseq > 9999 ) { return( SLE_DSSEQ ); } sprintf( wbuf, "%04u", dsseq ); memcpy( lab->slds1.dsseq, wbuf, 4 ); /* || Creation Date */ sl_fmtdate( lab->slds1.crtdt, NULL, FALSE ); /* || Expiration Date */ if( sl_fmtdate( lab->slds1.expdt, expdt, FALSE ) == NULL ) { return( SLE_EXPDT ); } /* || Dataset security */ memset( lab->slds1.dssec, '0', 1 ); /* || Block count - low */ if( type == SLT_HDR ) { blocks = 0; } sprintf( wbuf, "%010u", blocks ); memcpy( lab->slds1.blklo, &wbuf[ 4 ], 6 ); /* || System code */ memcpy( lab->slds1.syscd, "IBM OS/VS 370", 13 ); /* || Block count - high */ sprintf( wbuf, "%10u", blocks ); memcpy( lab->slds1.blkhi, wbuf, 4 ); /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_ds2 - Generate a data set label 2 SYNOPSIS #include "sllib.h" int sl_ds2( SLLABEL *lab, int type, char *recfm, int lrecl, int blksize, char *jobname, char *stepname, char *trtch ) DESCRIPTION This function builds a data set label 2 based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The "type" parameter must be "SLT_HDR", "SLT_EOF", or "SLT_EOV". The remaining parameters correspond to fields within the label and are converted to EBCDIC before storing. The "recfm" parameter may be one of the following: F FS V VS U FA FSA VA VSA UA FM FSM VM VSM UM FB FBS VB VBS FBA FBSA VBA VBSA FBM FBSM VBM VBSM The "trtch" parameter may be blank or one of the following: T C E ET P RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_INVALIDTYPE Invalid label type specified SLE_RECFM Missing or invalid record format SLE_LRECL Invalid record length SLE_BLKSIZE Block size out of range SLE_JOBNAME Missing or invalid job name SLE_STEPNAME Missing or invalid step name SLE_TRTCH Invalid recording technique NOTES This routine is normally accessed using the supplied "sl_hdr1", "sl_eof1", or "sl_eov1" macros. Only the "most common" label fields have corresponding parameters so the user must supply any other desired values. EXAMPLE // // Create a EOV2 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_ds2( &sllab, SLT_EOF, "FB", 80, 32720, "HERCJOB", "HERCSTEP", "P" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_ds2( SLLABEL *lab, int type, char *recfm, int lrecl, int blksize, char *jobname, char *stepname, char *trtch ) { int i; size_t len; char wbuf[ 80 ]; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ if( ( type != SLT_HDR ) && ( type != SLT_EOF ) && ( type != SLT_EOV ) ) { return( SLE_INVALIDTYPE ); } memcpy( lab->id, sl_alabs[ type ], 3 ); /* || Label number */ lab->num[ 0 ] = '1'; /* || Record format/Block Attribute/Control */ if( recfm == NULL ) { return( SLE_RECFM ); } for( i = 0 ; i < (int)VALFMCNT ; i++ ) { if( strcmp( recfm, valfm[ i ].recfm ) == 0 ) { break; } } if( i == VALFMCNT ) { return( SLE_RECFM ); } lab->slds2.recfm[ 0 ] = valfm[ i ].f; lab->slds2.blkattr[ 0 ] = valfm[ i ].b; lab->slds2.ctrl[ 0 ] = valfm[ i ].c; /* || Block size */ if( blksize == 0 ) { return( SLE_BLKSIZE ); } if( blksize > 32760 ) { sprintf( wbuf, "%10u", blksize ); memcpy( lab->slds2.lblkln, wbuf, 10 ); memcpy( lab->slds2.blksize, "00000", 5 ); } else { sprintf( wbuf, "%05u", blksize ); memcpy( lab->slds2.blksize, wbuf, 5 ); } /* || Logical record length */ switch( lab->slds2.recfm[ 0 ] ) { case 'F': if( ( valfm[ i ].b == 'S' ) || ( valfm[ i ].b == ' ' ) ) { if( lrecl != blksize ) { return( SLE_LRECL ); } } else { if( ( blksize % lrecl ) != 0 ) { return( SLE_LRECL ); } } break; case 'V': if( valfm[ i ].b == ' ' ) { if( ( lrecl + 4 ) != blksize ) { return( SLE_LRECL ); } } else if( valfm[ i ].b == 'B' ) { if( ( lrecl + 4 ) > blksize ) { return( SLE_LRECL ); } } break; case 'U': if( lrecl != 0 ) { return( SLE_LRECL ); } break; } sprintf( wbuf, "%05u", lrecl ); memcpy( lab->slds2.lrecl, wbuf, 5 ); /* || Jobname and stepname */ if( jobname != NULL ) { if( stepname == NULL ) { return( SLE_STEPNAME ); } len = strlen( jobname ); if( len > 8 ) { return( SLE_JOBNAME ); } len = strlen( stepname ); if( len > 8 ) { return( SLE_STEPNAME ); } } else { if( stepname != NULL ) { return( SLE_JOBNAME ); } } sprintf( wbuf, "%-8.8s/%-8.8s", jobname, stepname ); memcpy( lab->slds2.jobid, wbuf, 17 ); /* || Density */ lab->slds2.den[ 0 ] = '0'; /* || Dataset position */ lab->slds2.dspos[ 0 ] = '0'; /* || Tape recording technique */ if( trtch != NULL ) { len = strlen( trtch ); if( len < 1 || len > 2 ) { return( SLE_TRTCH ); } switch( trtch[ 0 ] ) { case 'T': case 'C': case 'P': case ' ': lab->slds2.trtch[ 0 ] = trtch[ 0 ]; break; case 'E': lab->slds2.trtch[ 0 ] = trtch[ 0 ]; if( len == 2 ) { if( trtch[ 1 ] != 'T' ) { return( SLE_TRTCH ); } lab->slds2.trtch[ 1 ] = trtch[ 1 ]; } break; default: return( SLE_TRTCH ); break; } } /* || Device serial number */ sprintf( wbuf, "%06u", rand() ); memcpy( lab->slds2.devser, wbuf, 6 ); /* || Checkpoint dataset identifier */ lab->slds2.ckptid[ 0 ] = ' '; /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_usr - Generate a user label SYNOPSIS #include "sllib.h" int sl_usr( SLLABEL *lab, int type, int num, char *data ) DESCRIPTION This function builds a user label based on the parameters provided and places it at the location pointed to by the "lab" parameter in EBCDIC. The "type" parameter must be "SLT_UHL" or "SLT_UTL" and the "num" parameter must be 1 through 8. The remaining parameter corresponds to fields within the label and is converted to EBCDIC before storing. RETURN VALUE The return value will be >= 0 if no errors are detected. If an error is detected, then the return value will be < 0 and will be one of the following: SLE_DATA Missing or invalid user data NOTES This routine is normally accessed using the supplied "sl_uhl*" or "sl_utl*" macros. EXAMPLE // // Create a UHL6 label // #include "sllib.h" int main( int argc, char *argv[] ) { SLFMT slfmt; SLLABEL sllab; int i; sl_usr( &sllab, SLT_EOF, 6, "Hercules Emulated Tape" ); sl_fmtlab( &slfmt, &sllab ); for( i = 0 ; slfmt.key[ i ] != NULL ; i++ ) { printf("%-20.20s: '%s'\n", slfmt.key[ i ] , slfmt.val[ i ] ); } return( 0 ); } SEE ALSO sl_fmtlab() ==DOC==*/ DLL_EXPORT int sl_usr( SLLABEL *lab, int type, int num, char *data ) { size_t len; /* || Initialize */ memset( lab, ' ', sizeof( SLLABEL ) ); /* || Label ID */ if( ( type != SLT_UHL ) && ( type != SLT_UTL ) ) { return( SLE_INVALIDTYPE ); } memcpy( lab->id, sl_elabs[ type ], 3 ); /* || Label number */ if( ( num < 1 ) || ( num > 8 ) ) { return( SLE_INVALIDNUM ); } lab->num[ 0 ] = '0' + num; /* || User data */ if( data == NULL ) { return( SLE_DATA ); } len = strlen( data ); if( len == 0 || len > 76 ) { return( SLE_DATA ); } memcpy( lab->slusr.data, data, len ); /* || Convert to EBCDIC */ sl_atoe( NULL, lab, sizeof( SLLABEL ) ); return 0; } /*==DOC== NAME sl_error - Returns a text message for an SL error code SYNOPSIS #include "sllib.h" char *sl_error( int rc ) DESCRIPTION Simply returns a pointer to a string that describes the error code passed in the "rc" parameter. RETURN VALUE The return value is always valid and no errors are returned. EXAMPLE // // Print text for SLE_DSSEQ. // #include "sllib.h" int main( int argc, char *argv[] ) { printf( "SLLIB error: %d = %s\n", SLE_DSSEQ, sl_error( SLE_DSSEQ ) ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT const char * sl_error( int rc ) { /* || If not an error just return the "OK" string */ if( rc >= 0 ) { rc = 0; } /* || Turn it into an index */ rc = -rc; /* || Within range? */ if( rc >= (int)SL_ERRSTR_MAX ) { rc = SL_ERRSTR_MAX - 1; } /* || Return string */ return( sl_errstr[ rc ] ); } hercules-3.12/hetlib.c0000664000175000017500000015316612564723224011632 00000000000000/* HETLIB.C (c) Copyright Leland Lucius, 2000-2009 */ /* Library for managing Hercules Emulated Tapes */ /* || ---------------------------------------------------------------------------- || || HETLIB.C (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Library for managing Hercules Emulated Tapes. || || ---------------------------------------------------------------------------- */ #include "hstdinc.h" #define _HETLIB_C_ #define _HTAPE_DLL_ #include "hercules.h" #include "hetlib.h" #undef HETDEBUGR #undef HETDEBUGW /* || Local constant data */ static const char *het_errstr[] = { "No error", "File error", "Tapemark read", "Beginning of tape", "End of tape", "BOR not found", "EOR not found", "Unexpected tapemark", "Buffer not big enough", "Premature EOF", "Decompression error", "Unknown compression method", "Compression error", "Specified length to big", "Write protected", "Bad function code passed", "Bad compression method", "Bad compression level", "Bad write chunk size", "Invalid direction specified", "Insufficient memory", "Couldn't read block header", "Inconsistent compression flags", "Invalid error code", }; #define HET_ERRSTR_MAX ( sizeof( het_errstr) / sizeof( het_errstr[ 0 ] ) ) /*==DOC== NAME het_open - Open an HET format file SYNOPSIS #include "hetlib.h" int het_open( HETB **hetb, char *filename, int flags ) DESCRIPTION The het_open() function opens the file indicated by the "filename" parameter and, if successful, places the address of an HETB at the location pointed to by the "hetb" parameter. Currently, "HETOPEN_CREATE" is the only flag available and has the same function as the O_CREAT flag of the open(3) function. @ISW@ Added flag HETOPEN_READONLY HETOPEN_CREATE and HETOPEN_READONLY are mutually exclusive. When HETOPEN_READONLY is set, the het file must exist. It is opened read only. Any attempt to write will fail. RETURN VALUE If no errors are detected then the return value will be >= 0 and the address of the newly allocated HETB will be place at the "hetb" location. If an error occurs, then the return value will be < 0 and will be one of the following: HETE_NOMEM Insufficient memory to allocate an HETB HETE_ERROR File system error - check errno(3) For other possible errors, see: het_read_header() het_tapemark() het_rewind() NOTES Even if het_open() fails, you should still call het_close(). EXAMPLE // // Create an NL tape // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE ); if( rc < 0 ) { printf( "het_open() returned: %d\n", rc ); } else { printf( "%s successfully created\n", argv[ 1 ] ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_read_header(), het_tapemark(), het_rewind(), het_close() ==DOC==*/ DLL_EXPORT int het_open( HETB **hetb, char *filename, int flags ) { HETB *thetb; char *omode; int rc; int fd; int oflags; char pathname[MAX_PATH]; /* || Initialize */ *hetb = NULL; hostpath(pathname, filename, sizeof(pathname)); /* || Allocate a new HETB */ thetb = calloc( 1, sizeof( HETB ) ); if( thetb == NULL ) { return( HETE_NOMEM ); } /* || Set defaults */ thetb->compress = HETDFLT_COMPRESS; thetb->decompress = HETDFLT_DECOMPRESS; thetb->method = HETDFLT_METHOD; thetb->level = HETDFLT_LEVEL; thetb->chksize = HETDFLT_CHKSIZE; /* || clear HETOPEN_CREATE if HETOPEN_READONLY is specified */ if(flags & HETOPEN_READONLY) { flags&=~HETOPEN_CREATE; } /* || Translate HET create flag to filesystem flag */ oflags = ( ( flags & HETOPEN_CREATE ) ? O_CREAT : 0 ); /* || Open the tape file */ omode = "r+b"; if(!(flags & HETOPEN_READONLY)) { fd = hopen( pathname, O_RDWR | O_BINARY | oflags, S_IRUSR | S_IWUSR | S_IRGRP ); } if( (flags & HETOPEN_READONLY) || (fd == -1 && (errno == EROFS || errno == EACCES) ) ) { /* || Retry open if file resides on readonly file system */ omode = "rb"; thetb->writeprotect = TRUE; fd = hopen( pathname, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP ); } /* || Error out if both opens failed */ if( fd == -1 ) { free( thetb ); return( HETE_ERROR ); } /* || Associate stream with file descriptor */ thetb->fd = fdopen( fd, omode ); if( thetb->fd == NULL ) { rc = errno; close( fd ); errno = rc; free( thetb ); return( HETE_ERROR ); } /* || If uninitialized tape, write 2 tapemarks to make it a valid NL tape */ rc = het_read_header( thetb ); if( rc < 0 && rc != HETE_TAPEMARK ) { if( rc != HETE_EOT ) { return( rc ); } rc = het_tapemark( thetb ); if( rc < 0 ) { return( rc ); } rc = het_tapemark( thetb ); if( rc < 0 ) { return( rc ); } } /* || Reposition tape to load point */ rc = het_rewind( thetb ); if( rc < 0 ) { return( rc ); } /* || Give the caller the new HETB */ *hetb = thetb; return( 0 ); } /*==DOC== NAME het_close - Close an HET file SYNOPSIS #include "hetlib.h" int het_close( HETB **hetb ) DESCRIPTION The het_close() function closes an HET file and releases the HETB. RETURN VALUE If no errors are detected then the return value will be >= 0 and the location specified by the "hetb" parameter will be set to NULL. If an error occurs, then the return value will be < 0. At this time, no errors will be returned. EXAMPLE // // Create an NL tape // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE ); if( rc < 0 ) { printf( "het_open() returned: %d\n", rc ); } else { printf( "%s successfully created\n", argv[ 1 ] ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open() ==DOC==*/ DLL_EXPORT int het_close( HETB **hetb ) { /* || Only free the HETB if we have one */ if( *(hetb) != NULL ) { /* || Only close the file if opened */ if( (*hetb)->fd != NULL ) { fclose( (*hetb)->fd ); } free( *(hetb) ); } /* || Reinitialize pointer */ *hetb = NULL; return( 0 ); } /*==DOC== NAME het_cntl - Control HET file behavior SYNOPSIS #include "hetlib.h" int het_cntl( HETB *hetb, int func, unsigned long val ) DESCRIPTION The het_cntl() function allows you to get/set several values that control how an HET file behaves. The value of the "val" parameter depends on the function code. The possible modes are: HETCNTL_GET Should be ORed (|) with the function codes to retrieve the current setting. (Default) HETCNTL_SET Should be ORed (|) with the function codes to set a new value. The possible function codes are: HETCNTL_COMPRESS val=TRUE to enable write compression (see notes) Values: FALSE (disable) TRUE (enable) Default: HETDFLT_COMPRESS (TRUE) HETCNTL_DECOMPRESS val=TRUE to enable read decompression Values: FALSE (disable) TRUE (enable) Default: HETDFLT_DECOMPRESS (TRUE) HETCNTL_METHOD val=Compression method to use Values: HETMETH_ZLIB (1) HETMETH_BZLIB (2) Default: HETDFLT_METHOD (HETMETH_ZLIB) HETCNTL_LEVEL val=Level of compression Min: HETMIN_LEVEL (1) Max: HETMAX_LEVEL (9) Default: HETDFLT_LEVEL (4) HETCNTL_CHUNKSIZE val=Size of output chunks (see notes) Min: HETMIN_CHUNKSIZE (4096) Max: HETMAX_CHUNKSIZE (65535) Default: HETDFLT_CHUNKSIZE (65535) RETURN VALUE If no errors are detected then the return value will be either the current setting for a "get" request or >= 0 for a "set" request. If an error occurs, then the return value will be < 0 and can be one of the following: HETE_BADMETHOD Specified method out of range HETE_BADLEVEL Specified level out of range HETE_BADCHUNKSIZE Specified chunk size out of range HETE_BADFUNC Unrecognized function code NOTES Each block on an HET file is made up of "HETCNTL_CHUNKSIZE" sized chunks. There can be 1 or many chunks per block. If you wish to create an AWSTAPE compatible file, specify a chunk size of 4096 and disable write compression. EXAMPLE // // Create an NL tape and write an uncompressed string to it // #include "hetlib.h" char data[] = "This is a test"; int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE ); if( rc >= 0 ) { rc = het_cntl( hetb, HETCNTL_SET | HETCNTL_COMPRESS, FALSE ); if( rc >= 0 ) { rc = het_write( hetb, data, sizeof( data ) ); if( rc >= 0 ) { printf( "Data successfully written\n" ); } } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_cntl(), het_write(), het_close() ==DOC==*/ DLL_EXPORT int het_cntl( HETB *hetb, int func, unsigned long val ) { int mode; /* || Isolate the mode */ mode = func & HETCNTL_SET; /* || Process the requested function */ switch( func & ( ~( HETCNTL_GET | HETCNTL_SET ) ) ) { case HETCNTL_COMPRESS: if( mode == HETCNTL_GET ) { return( hetb->compress ); } hetb->compress = ( val ? TRUE : FALSE ); break; case HETCNTL_DECOMPRESS: if( mode == HETCNTL_GET ) { return( hetb->decompress ); } hetb->decompress = ( val ? TRUE : FALSE ); break; case HETCNTL_METHOD: if( mode == HETCNTL_GET ) { return( hetb->method ); } if( val < HETMIN_METHOD || val > HETMAX_METHOD ) { return( HETE_BADMETHOD ); } hetb->method = val; break; case HETCNTL_LEVEL: if( mode == HETCNTL_GET ) { return( hetb->level ); } if( val < HETMIN_LEVEL || val > HETMAX_LEVEL ) { return( HETE_BADLEVEL ); } hetb->level = val; break; case HETCNTL_CHUNKSIZE: if( mode == HETCNTL_GET ) { return( hetb->chksize ); } if( val < HETMIN_CHUNKSIZE || val > HETMAX_CHUNKSIZE ) { return( HETE_BADSIZE ); } hetb->chksize = val; break; default: return( HETE_BADFUNC ); break; } /* || Success */ return( 0 ); } /*==DOC== NAME het_read_header - Retrieve the next chunk header from an HET file SYNOPSIS #include "hetlib.h" int het_read_header( HETB *hetb ) DESCRIPTION Retrieves the next chunk header and stores it in the HETB. RETURN VALUE If no errors are detected then the return value will be >= 0 and the current block count will be incremented. If an error occurs, then the return value will be < 0 and can be one of the following: HETE_EOT End of tape encountered HETE_ERROR File system error - check errno(3) HETE_TAPEMARK Tape mark encountered NOTES This function is not normally called from user programs and its behavior may change. EXAMPLE // // Read a chunk header from an HET file. // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_read_header( hetb ); if( rc >= 0 ) { printf( "Header read:\n" ); printf( " Current length: %d\n", HETHDR_CLEN( hetb ) ); printf( " Previous length: %d\n", HETHDR_PLEN( hetb ) ); printf( " Flags1: %x\n", hetb->flags1 ); printf( " Flags2: %x\n", hetb->flags2 ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_close() ==DOC==*/ DLL_EXPORT int het_read_header( HETB *hetb ) { int rc; /* || Read in a headers worth of data */ rc = fread( &hetb->chdr, sizeof( HETHDR ), 1, hetb->fd ); if( rc != 1 ) { /* || Return EOT if at end of physical file */ if( feof( hetb->fd ) ) { return( HETE_EOT ); } /* || Something else must've happened */ return( HETE_ERROR ); } #if defined( HETDEBUGR ) printf("read hdr: pl=%d, cl=%d, f1=%02x, f2=%02x\n", HETHDR_PLEN( hetb ), HETHDR_CLEN( hetb ), hetb->chdr.flags1, hetb->chdr.flags2); #endif /* || Bump block number if done with entire block */ if( hetb->chdr.flags1 & ( HETHDR_FLAGS1_EOR | HETHDR_FLAGS1_TAPEMARK ) ) { hetb->cblk++; } /* || Check for tape marks */ if( hetb->chdr.flags1 & HETHDR_FLAGS1_TAPEMARK ) { return( HETE_TAPEMARK ); } /* || Success */ return( 0 ); } /*==DOC== NAME het_read - Retrieve the next block from an HET file SYNOPSIS #include "hetlib.h" int het_read( HETB *hetb, void *sbuf ) DESCRIPTION Read the next block of data into the "sbuf" memory location. The length of "sbuf" should be at least HETMAX_BLOCKSIZE bytes. RETURN VALUE If no errors are detected then the return value will be the size of the block read. This will be either the compressed or uncompressed length depending on the current AWSCNTL_DECOMPRESS setting. If an error occurs, then the return value will be < 0 and can be one of the following: HETE_ERROR File system error - check errno(3) HETE_BADBOR Beginning of record expected but not found HETE_BADCOMPRESS Compression mismatch between related chunks HETE_OVERFLOW Record too large for buffer HETE_PREMEOF Premature EOF on file HETE_DECERR Decompression error (stored in errno(3)) HETE_UNKMETH Unknown compression method encountered For other possible errors, see: het_read_header() EXAMPLE // // Read a block from an HET file. // #include "hetlib.h" char buffer[ HETMAX_BLOCKSIZE ]; int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_read( hetb, buffer ); if( rc >= 0 ) { printf( "Block read - length: %d\n", rc ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_read_header(), het_close() ==DOC==*/ DLL_EXPORT int het_read( HETB *hetb, void *sbuf ) { char *tptr; int rc; unsigned long slen; int flags1, flags2; unsigned long tlen; char tbuf[ HETMAX_BLOCKSIZE ]; /* || Initialize */ flags1 = flags2 = 0; tlen = 0; tptr = sbuf; /* || Read chunks until entire block has been read */ do { /* || Get a header */ rc = het_read_header( hetb ); if( rc < 0 ) { return( rc ); } /* || Have we seen a BOR chunk yet? */ if( !( flags1 & HETHDR_FLAGS1_BOR ) ) { /* || Nope, so this chunk MUST have the BOR set */ if( !( hetb->chdr.flags1 & HETHDR_FLAGS1_BOR ) ) { return( HETE_BADBOR ); } /* || If block is compressed (and decompression is desired), set || destination pointer. */ if( hetb->decompress ) { if( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS || hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS ) { if( ( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS ) && ( hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS ) ) { return( HETE_BADCOMPRESS ); } tptr = tbuf; } } /* || Save flags for later validation */ flags1 = hetb->chdr.flags1; flags2 = hetb->chdr.flags2; } else { /* || Yep, so this chunk MUST NOT have the BOR flag set */ if( hetb->chdr.flags1 & HETHDR_FLAGS1_BOR ) { return( HETE_BADBOR ); } } /* || Compression flags from related chunks must match */ if( ( flags1 & HETHDR_FLAGS1_COMPRESS ) != ( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS ) ) { return( HETE_BADCOMPRESS ); } if( ( flags2 & HETHDR_FLAGS2_COMPRESS ) != ( hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS ) ) { return( HETE_BADCOMPRESS ); } /* || Calculate running length */ slen = HETHDR_CLEN( hetb ); tlen += slen; /* || Can't be bigger than HETMAX_BLOCKSIZE */ if( tlen > HETMAX_BLOCKSIZE ) { return( HETE_OVERFLOW ); } /* || Finally read in the chunk data */ rc = fread( tptr, 1, slen, hetb->fd ); if( rc != (int)slen ) { if( feof( hetb->fd ) ) { return( HETE_PREMEOF ); } return( HETE_ERROR ); } /* || Bump destination pointer to next possible location */ tptr += slen; } while( !( hetb->chdr.flags1 & HETHDR_FLAGS1_EOR ) ); /* || Save compressed length (means cblksize size and ublksize will be the || same for uncompressed data) */ hetb->cblksize = tlen; /* || Decompress data if requested */ if( hetb->decompress ) { switch( hetb->chdr.flags1 & HETHDR_FLAGS1_COMPRESS ) { case 0: switch( hetb->chdr.flags2 & HETHDR_FLAGS2_COMPRESS ) { case 0: break; #if defined( HAVE_LIBZ ) case HETHDR_FLAGS2_ZLIB_BUSTECH: slen = HETMAX_BLOCKSIZE; rc = uncompress( sbuf, &slen, (unsigned char *)tbuf, tlen ); if( rc != Z_OK ) { errno = rc; return( HETE_DECERR ); } tlen = slen; break; #endif /* defined( HAVE_LIBZ ) */ default: return( HETE_UNKMETH ); break; } break; #if defined( HAVE_LIBZ ) case HETHDR_FLAGS1_ZLIB: slen = HETMAX_BLOCKSIZE; rc = uncompress( sbuf, &slen, (unsigned char *)tbuf, tlen ); if( rc != Z_OK ) { errno = rc; return( HETE_DECERR ); } tlen = slen; break; #endif /* defined( HAVE_LIBZ ) */ #if defined( HET_BZIP2 ) case HETHDR_FLAGS1_BZLIB: slen = HETMAX_BLOCKSIZE; rc = BZ2_bzBuffToBuffDecompress( sbuf, (void *) &slen, tbuf, tlen, 0, 0 ); if (rc != BZ_OK) { errno = rc; return( HETE_DECERR ); } tlen = slen; break; #endif /* defined( HET_BZIP2 ) */ default: return( HETE_UNKMETH ); break; } } /* || Save uncompressed length */ hetb->ublksize = tlen; /* || Success */ return( tlen ); } /*==DOC== NAME het_write_header - Write a chunk header to an HET file SYNOPSIS #include "hetlib.h" int het_write_header( HETB *hetb, int len, int flags1, int flags2 ) DESCRIPTION Constructs and writes a chunk header to an HET file. RETURN VALUE If no errors are detected then the return value will be >= 0 and the current block count will be incremented. If an error occurs, then the return value will be < 0 and can be one of the following: HETE_BADLEN "len" parameter out of range HETE_PROTECTED File is write protected HETE_ERROR File system error - check errno(3) NOTES This function is not normally called from user programs and its behavior may change. If this function is called and the tape is not positioned at the end, then the file will be truncated to the current position. This means that rewriting blocks is not currently possible. EXAMPLE // // Write a chunk header to an HET file. // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_write_header( hetb, 0, HETHDR_TAPEMARK, 0 ); if( rc >= 0 ) { printf( "Header written\n" ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_close() ==DOC==*/ int het_write_header( HETB *hetb, int len, int flags1, int flags2 ) { int rc; off_t rcoff; #if defined( HETDEBUGW ) printf("write hdr: pl=%d, cl=%d, f1=%02x, f2=%02x\n", HETHDR_PLEN( hetb ), HETHDR_CLEN( hetb ), hetb->chdr.flags1, hetb->chdr.flags2); #endif /* || Validate length */ if( len > HETMAX_CHUNKSIZE ) { return( HETE_BADLEN ); } /* || Can't write anything on readonly media */ if( hetb->writeprotect ) { return( HETE_PROTECTED ); } /* || For tapemarks, length must be zero. */ if( flags1 & HETHDR_FLAGS1_TAPEMARK ) { len = 0; } /* || According to Linux fopen() man page, a positioning function is required || between reads and writes. Is this REALLY necessary??? */ if( !hetb->readlast ) { fseek( hetb->fd, 0, SEEK_CUR ); hetb->readlast = FALSE; } /* || If this is the first write, truncate the file */ if( !hetb->truncated ) { rcoff = ftell( hetb->fd ); if( rcoff == -1 ) { return( HETE_ERROR ); } rc = ftruncate( fileno( hetb->fd ), rcoff ); if( rc == -1 ) { return( HETE_ERROR ); } hetb->truncated = TRUE; } /* || Construct the header */ hetb->chdr.plen[ 0 ] = hetb->chdr.clen[ 0 ]; hetb->chdr.plen[ 1 ] = hetb->chdr.clen[ 1 ]; hetb->chdr.clen[ 0 ] = len & 0xFF; hetb->chdr.clen[ 1 ] = ( len >> 8 ) & 0xFF; hetb->chdr.flags1 = flags1; hetb->chdr.flags2 = flags2; /* || Write it out */ rc = fwrite( &hetb->chdr, sizeof( HETHDR ), 1, hetb->fd ); if( rc != 1 ) { return( HETE_ERROR ); } /* || Bump block count if done with entire block */ if( hetb->chdr.flags1 & ( HETHDR_FLAGS1_EOR | HETHDR_FLAGS1_TAPEMARK ) ) { hetb->cblk++; } /* || Success */ return 0; } /*==DOC== NAME het_write - Write a block to an HET file SYNOPSIS #include "hetlib.h" int het_write( HETB *hetb, void *sbuf, int slen ) DESCRIPTION Writes a block of data specified by "sbuf" with a length of "slen" to an HET file. Depending on the current HETCNTL_COMPRESS setting, the data may be compressed prior to writing. RETURN VALUE If no errors are detected then the return value will be the size of the block written. This will be either the compressed or uncompressed length depending on the current AWSCNTL_COMPRESS setting. If an error occurs, then the return value will be < 0 and can be one of the following: HETE_ERROR File system error - check errno(3) HETE_BADLEN "slen" parameter out of range HETE_BADCOMPRESS Compression mismatch between related chunks For other possible errors, see: het_write_header() EXAMPLE // // Create an NL tape and write a string to it // #include "hetlib.h" char data[] = "This is a test"; int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE ); if( rc >= 0 ) { rc = het_write( hetb, data, sizeof( data ) ); if( rc >= 0 ) { printf( "Block written - length: %d\n", rc ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_write_header(), het_close() ==DOC==*/ DLL_EXPORT int het_write( HETB *hetb, void *sbuf, int slen ) { int rc; int flags; unsigned long tlen; #if defined(HAVE_LIBZ) || defined( HET_BZIP2 ) char tbuf[ ((((HETMAX_BLOCKSIZE * 1001) + 999) / 1000) + 12) ]; #endif /* || Validate */ if( slen > HETMAX_BLOCKSIZE ) { return( HETE_BADLEN ); } /* || Initialize */ flags = HETHDR_FLAGS1_BOR; /* || Save uncompressed length */ hetb->ublksize = slen; /* || Compress data if requested */ if( hetb->compress ) { switch( hetb->method ) { #if defined(HAVE_LIBZ) case HETHDR_FLAGS1_ZLIB: tlen = sizeof( tbuf ); rc = compress2( (unsigned char *)tbuf, &tlen, sbuf, slen, hetb->level ); if( rc != Z_OK ) { errno = rc; return( HETE_COMPERR ); } if( (int)tlen < slen ) { sbuf = tbuf; slen = tlen; flags |= HETHDR_FLAGS1_ZLIB; } break; #endif #if defined( HET_BZIP2 ) case HETHDR_FLAGS1_BZLIB: tlen = sizeof( tbuf ); rc = BZ2_bzBuffToBuffCompress( tbuf, (void *) &tlen, sbuf, slen, hetb->level, 0, 0 ); if( rc != BZ_OK ) { errno = rc; return( HETE_COMPERR ); } if( (int)tlen < slen ) { sbuf = tbuf; slen = tlen; flags |= HETHDR_FLAGS1_BZLIB; } break; #endif /* defined( HET_BZIP2 ) */ } } /* || Save compressed length */ hetb->cblksize = slen; /* || Write block, breaking it into "chksize" chunks */ do { /* || Last chunk for this block? */ if( slen <= (int)hetb->chksize ) { flags |= HETHDR_FLAGS1_EOR; tlen = slen; } else { tlen = hetb->chksize; } /* || Write the header */ rc = het_write_header( hetb, tlen, flags, 0 ); if( rc < 0 ) { return( rc ); } /* || Write the block */ rc = fwrite( sbuf, 1, tlen, hetb->fd ); if( rc != (int)tlen ) { return( HETE_ERROR ); } /* || Bump pointers and turn off BOR flag */ { char *csbuf; csbuf=(char *)sbuf; csbuf+=tlen; sbuf=(void *)csbuf; } slen -= tlen; flags &= (~HETHDR_FLAGS1_BOR); } while( slen > 0 ); /* || Set new physical EOF */ do rc = ftruncate( fileno( hetb->fd ), ftell( hetb->fd ) ); while (EINTR == rc); if (rc != 0) { return( HETE_ERROR ); } /* || Success */ return( hetb->cblksize ); } /*==DOC== NAME het_tapemark - Write a tape mark to an HET file SYNOPSIS #include "hetlib.h" int het_tapemark( HETB *hetb ) DESCRIPTION Writes a special chunk header to an HET file to simulate a tape mark. RETURN VALUE If no errors are detected then the return value will be >= 0. If an error occurs, then the return value will be < 0 and will be the same as those returned by het_write_header(). EXAMPLE // // Write a tapemark to an HET file // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE ); if( rc >= 0 ) { rc = het_tapemark( hetb ); if( rc >= 0 ) { printf( "Tape mark written\n" ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_write_header(), het_close() ==DOC==*/ DLL_EXPORT int het_tapemark( HETB *hetb ) { int rc; /* || Just write a tapemark header */ rc = het_write_header( hetb, 0, HETHDR_FLAGS1_TAPEMARK, 0 ); if( rc < 0 ) { return( rc ); } /* || Set new physical EOF */ do rc = ftruncate( fileno( hetb->fd ), ftell( hetb->fd ) ); while (EINTR == rc); if (rc != 0) { return( HETE_ERROR ); } /* || Success */ return( 0 ); } /*==DOC== NAME het_sync - commit/flush a HET file's buffers to disk SYNOPSIS #include "hetlib.h" int het_sync( HETB *hetb ) DESCRIPTION Calls the file system's "fdatasync" (or fsync) function to cause all data for the HET file to be transferred to disk by forcing a physical write of all data from the file's buffers or the file- system's cache, to the disk, thereby assuring that after a system crash or other failure, that all data up to the time of the call is thus recorded on the disk. RETURN VALUE If no errors are detected then the return value will be >= 0. If an error occurs, then the return value will be < 0 and will be one of the following: HETE_PROTECTED File is write protected HETE_ERROR File system error - check errno(3) EXAMPLE // // Flush a HET file's buffers to disk // #include "hetlib.h" char data[] = "This is a test"; int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], HETOPEN_CREATE ); if( rc >= 0 ) { rc = het_write( hetb, data, sizeof( data ) ); if( rc >= 0 ) { printf( "Block successfully written\n" ); rc = het_sync( &hetb ); if( rc >= 0 ) { printf( "Block successfully committed\n" ); } } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_write(), het_close() ==DOC==*/ DLL_EXPORT int het_sync( HETB *hetb ) { int rc; /* || Can't sync to readonly media */ if( hetb->writeprotect ) { return( HETE_PROTECTED ); } /* || Perform the sync */ do rc = fdatasync( fileno( hetb->fd ) ); while (EINTR == rc); if (rc != 0) { return( HETE_ERROR ); } /* || Success */ return( 0 ); } /*==DOC== NAME het_locate - Locate a block within an HET file SYNOPSIS #include "hetlib.h" int het_locate( HETB *hetb, int block ) DESCRIPTION Repositions the HET file to the start of the block specified by the "block" parameter. RETURN VALUE If no errors are detected then the return value will be >= 0 and represents the new current block number. If an error occurs, then the return value will be < 0 and will the same as those returned by: het_rewind() het_fsb() NOTES Block numbers start at 0. EXAMPLE // // Seek to block #4 in HET file // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_locate( hetb, 4 ); if( rc >= 0 ) { printf( "New tape position: %d\n", rc ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_rewind(), het_fsb(), het_close() ==DOC==*/ DLL_EXPORT int het_locate( HETB *hetb, int block ) { int rc; /* || Start the search from the beginning */ rc = het_rewind( hetb ); if( rc < 0 ) { return( rc ); } /* || Forward space until we reach the desired block */ while( (int)hetb->cblk < block ) { rc = het_fsb( hetb ); if( rc < 0 && HETE_TAPEMARK != rc ) { return( rc ); } } return( hetb->cblk ); } /*==DOC== NAME het_bsb - Backspace a block in an HET file SYNOPSIS #include "hetlib.h" int het_bsb( HETB *hetb ) DESCRIPTION Repositions the current block pointer in an HET file to the previous block. RETURN VALUE If no errors are detected then the return value will be >= 0 and will be the new block number. If an error occurs, then the return value will be < 0 and can be one of the following: HETE_ERROR File system error - check errno(3) HETE_BOT Beginning of tape HETE_TAPEMARK Tape mark encountered For other possible errors, see: het_rewind() het_read_header() EXAMPLE // // Backspace a block in an HET file // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_fsb( hetb ); if( rc >= 0 ) { rc = het_bsb( hetb ); if( rc >= 0 ) { printf( "New block number = %d\n", rc ); } } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_rewind(), het_read_header(), het_fsb(), het_close() ==DOC==*/ DLL_EXPORT int het_bsb( HETB *hetb ) { int rc; int newblk; int offset; // (note: safe to use 'int' as offset here // since we only ever seek from SEEK_CUR) int tapemark = FALSE; /* || Error if at BOT */ if( hetb->cblk == 0 ) { return( HETE_BOT ); } /* || Get new block number */ newblk = hetb->cblk - 1; /* || If new block is first on, then just rewind */ if( newblk == 0 ) { return( het_rewind( hetb ) ); } /* || Calculate offset to get back to beginning of current block */ offset = -((int)( HETHDR_CLEN( hetb ) + sizeof( HETHDR ) )); /* || Search backwards an entire block. If the block is a tapemark, we can't || just return to caller since we must load the chunk header preceding it || to maintain the chdr in the HET. */ do { /* || Reposition to start of chunk */ rc = fseek( hetb->fd, offset, SEEK_CUR ); if( rc == -1 ) { return( HETE_ERROR ); } /* || Read header, ignoring tapemarks */ rc = het_read_header( hetb ); if( rc < 0 && rc != HETE_TAPEMARK ) { return( rc ); } /* || Recalculate offset */ offset = -((int)( HETHDR_PLEN( hetb ) + ( sizeof( HETHDR ) * 2 ) )); } while( hetb->chdr.flags1 & !( HETHDR_FLAGS1_BOR | HETHDR_FLAGS1_TAPEMARK ) ); /* || Remember whether it's a tapemark or not */ tapemark = ( hetb->chdr.flags1 & HETHDR_FLAGS1_TAPEMARK ); /* || Reposition to chunk header preceding this one so we can load keep the || chdr in the HET current. */ rc = fseek( hetb->fd, offset, SEEK_CUR ); if( rc == -1 ) { return( HETE_ERROR ); } /* || Read header (ignore tapemarks) */ rc = het_read_header( hetb ); if( rc < 0 && ( rc != HETE_TAPEMARK ) ) { return( rc ); } /* || Finally reposition back to the where we should be */ rc = fseek( hetb->fd, HETHDR_CLEN( hetb ), SEEK_CUR ); if( rc == -1 ) { return( HETE_ERROR ); } /* || Store new block number */ hetb->cblk = newblk; /* || Was it a tapemark? */ if( tapemark ) { return( HETE_TAPEMARK ); } /* || Reset flag to force truncation if a write occurs */ hetb->truncated = FALSE; /* || Return block number */ return( hetb->cblk ); } /*==DOC== NAME het_fsb - Foward space a block in an HET file SYNOPSIS #include "hetlib.h" int het_fsb( HETB *hetb ) DESCRIPTION Repositions the current block pointer in an HET file to the next block. RETURN VALUE If no errors are detected then the return value will be >= 0 and will be the new block number. If an error occurs, then the return value will be < 0 and can be one of the following: HETE_ERROR File system error - check errno(3) For other possible errors, see: het_read_header() EXAMPLE // // Forward space a block in an HET file // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_fsb( hetb ); if( rc >= 0 ) { printf( "New block number = %d\n", rc ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_read_header(), het_close() ==DOC==*/ DLL_EXPORT int het_fsb( HETB *hetb ) { int rc; /* || Loop until we've processed an entire block */ do { /* || Read header to get length of next chunk */ rc = het_read_header( hetb ); if( rc < 0 ) { return( rc ); } /* || Seek to next chunk */ rc = fseek( hetb->fd, HETHDR_CLEN( hetb ), SEEK_CUR ); if( rc == -1 ) { return( HETE_ERROR ); } } while( !( hetb->chdr.flags1 & HETHDR_FLAGS1_EOR ) ); /* || Reset flag to force truncation if a write occurs */ hetb->truncated = FALSE; /* || Return block number */ return( hetb->cblk ); } /*==DOC== NAME het_bsf - Backspace a file in an HET file SYNOPSIS #include "hetlib.h" int het_bsf( HETB *hetb ) DESCRIPTION Repositions the current block pointer in an HET file to the previous tapemark. RETURN VALUE If no errors are detected then the return value will be >= 0 and will be the new block number. If an error occurs, then the return value will be < 0 and will be the same as those returned by het_bsb() with the exception that HETE_TAPEMARK and HETE_BOT will not occur. EXAMPLE // // Backspace a file in an HET file // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_fsf( hetb ); if( rc >= 0 ) { rc = het_bsf( hetb ); if( rc >= 0 ) { printf( "Backspaced (sort of :-))\n" ); } } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_bsb(), het_fsf(), het_close() ==DOC==*/ DLL_EXPORT int het_bsf( HETB *hetb ) { int rc; /* || Backspace until we hit a tapemark */ do { rc = het_bsb( hetb ); } while( rc >= 0 ); /* || Success */ if( ( rc == HETE_BOT ) || ( rc == HETE_TAPEMARK ) ) { return( hetb->cblk ); } /* || Failure */ return( rc ); } /*==DOC== NAME het_fsf - Forward space a file in an HET file SYNOPSIS #include "hetlib.h" int het_fsf( HETB *hetb ) DESCRIPTION Repositions the current block pointer in an HET file to the next tapemark. RETURN VALUE If no errors are detected then the return value will be >= 0 and will be the new block number. If an error occurs, then the return value will be < 0 and will be the same as those returned by het_fsb() with the exception that HETE_TAPEMARK will not occur. EXAMPLE // // Forward space a file in an HET file // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_fsf( hetb ); if( rc >= 0 ) { printf( "Forward spaced\n" ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_fsb(), het_close() ==DOC==*/ DLL_EXPORT int het_fsf( HETB *hetb ) { int rc; /* || Forward space until we hit a tapemark */ do { rc = het_fsb( hetb ); } while( rc >= 0 ); /* || Success */ if( rc == HETE_TAPEMARK ) { return( hetb->cblk ); } /* || Failure */ return( rc ); } /*==DOC== NAME het_rewind - Rewind an HET file SYNOPSIS #include "hetlib.h" int het_rewind( HETB *hetb ) DESCRIPTION Repositions the current block pointer in an HET file to the load point. RETURN VALUE If no errors are detected then the return value will be >= 0 and represents the new block number (always 0). If an error occurs, then the return value will be < 0 and will be one of the following: HETE_ERROR File system error - check errno(3) EXAMPLE // // Rewind an HET file to the load point. // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rc = het_rewind( hetb ); if( rc >= 0 ) { printf( "Tape rewound\n" ); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO het_open(), het_close() ==DOC==*/ DLL_EXPORT int het_rewind( HETB *hetb ) { int rc; /* || Just seek to the beginning of the file */ rc = fseek( hetb->fd, 0, SEEK_SET ); if( rc == -1 ) { return( HETE_ERROR ); } /* || Reset current block */ hetb->cblk = 0; /* || Clear header for the heck of it */ memset( &hetb->chdr, 0, sizeof( hetb->chdr ) ); /* || Reset flag to force truncation if a write occurs */ hetb->truncated = FALSE; /* || Return block number */ return( hetb->cblk ); } /*==DOC== NAME het_error - Returns a text message for an HET error code SYNOPSIS #include "hetlib.h" char *het_error( int rc ) DESCRIPTION Simply returns a pointer to a string that describes the error code passed in the "rc" parameter. RETURN VALUE The return value is always valid and no errors are returned. EXAMPLE // // Print text of HETE_BADLEN. // #include "hetlib.h" int main( int argc, char *argv[] ) { printf( "HETLIB error: %d = %s\n", HETE_BADLEN, het_error( HETE_BADLEN ) ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT const char * het_error( int rc ) { /* || If not an error just return the "OK" string */ if( rc >= 0 ) { rc = 0; } /* || Turn it into an index */ rc = -rc; /* || Within range? */ if( rc >= (int)HET_ERRSTR_MAX ) { rc = HET_ERRSTR_MAX - 1; } /* || Return string */ return( het_errstr[ rc ] ); } /*==DOC== NAME het_tell - Returns the current read/write pointer offset SYNOPSIS #include "hetlib.h" off_t het_tell( HETB *hetb ) DESCRIPTION Returns a off_t describing the actual read/write cursor within the HET file RETURN VALUE >=0 The actual cursor offset <0 An error occured. Possible errors are : HETE_ERROR - File system error occured EXAMPLE // // Get the current HET pointer // #include "hetlib.h" int main( int argc, char *argv[] ) { HETB *hetb; int rc; off_t rwptr; rc = het_open( &hetb, argv[ 1 ], 0 ); if( rc >= 0 ) { rwptr = het_tell( hetb ); if( rwptr >= 0 ) { printf( "Current offset is %" I64_FMT "d\n" , (U64)rwptr); } } if( rc < 0 ) { printf( "HETLIB error: %d\n", rc ); } het_close( &hetb ); return( 0 ); } SEE ALSO ==DOC==*/ DLL_EXPORT off_t het_tell( HETB *hetb ) { off_t rwptr = ftell( hetb->fd ); if ( rwptr < 0 ) { return HETE_ERROR; } return rwptr; } hercules-3.12/ecpsvm.c0000664000175000017500000027404612564723224011661 00000000000000/*ECPSVM.C (c) Copyright Ivan Warren, 2003-2009 */ /* Hercules ECPS:VM Support */ /***********************************************************/ /* */ /* General guidelines about E6XX instruction class */ /* this is an implementation of ECPS:VM Level 20 */ /* */ /* General rule is : Only do what is safe to do. In doubt, */ /* give control to CP back (and act as */ /* a NO-OP). All instructions have this */ /* behaviour, therefore allowing only */ /* partial implementation, or bypassing */ /* tricky cases */ /* */ /* NOTE : ECPS:VM is only available for S/370 architecture */ /* */ /* In order for CP ASSIST to be active, a CONFIGURATION */ /* statement is added : ECPS:VM lvl|no */ /* lvl is the ASSIST level (20 is recommended) */ /* no means CP ASSIST is disabled (default) */ /* */ /* Currently supported CP ASSIST instructions : */ /* +-----+-------+----------------------------------------+*/ /* |opc | Mnemo | Function |*/ /* +-----+-------+----------------------------------------+*/ /* |E602 | LCKPG | Lock Page in core table |*/ /* |E603 | ULKPG | Unlock page in core table |*/ /* |E608 | TRBRG | LRA + Basic checks on VPAGE |*/ /* |E609 | TRLOK | Same as TRBRG + Lock page in core |*/ /* |E60E | SCNRU | Scan Real Unit control blocks |*/ /* |E612 | STLVL | Store ECPS:VM Level |*/ /* |E614 | FREEX | Allocate CP FREE Storage from subpool |*/ /* |E615 | FRETX | Release CP FREE Storage to subpool |*/ /* +-----+-------+----------------------------------------+*/ /* */ /* Currently supported VM ASSIST instructions : */ /* +-----+-------+----------------------------------------+*/ /* |opc | Mnemo | Function |*/ /* +-----+-------+----------------------------------------+*/ /* |0A | SVC | Virtual SVC Assist |*/ /* |80 | SSM | Virtual SSM Assist |*/ /* |82 | LPSW | Virtual LPSW Assist |*/ /* +-----+-------+----------------------------------------+*/ /* */ /***********************************************************/ // $Log$ // Revision 1.68 2007/06/23 00:04:09 ivan // Update copyright notices to include current year (2007) // // Revision 1.67 2007/01/13 07:18:14 bernard // backout ccmask // // Revision 1.66 2007/01/12 15:22:37 bernard // ccmask phase 1 // // Revision 1.65 2006/12/31 17:53:48 gsmith // 2006 Dec 31 Update ecpsvm.c for new psw IA scheme // // Revision 1.64 2006/12/08 09:43:20 jj // Add CVS message log // #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #if !defined(_ECPSVM_C_) #define _ECPSVM_C_ #endif #include "hercules.h" #include "opcode.h" #include "inline.h" #include "ecpsvm.h" #ifdef FEATURE_ECPSVM ECPSVM_CMDENT *ecpsvm_getcmdent(char *cmd); struct _ECPSVM_CPSTATS { ECPSVM_STAT_DCL(SVC); ECPSVM_STAT_DCL(SSM); ECPSVM_STAT_DCL(LPSW); ECPSVM_STAT_DCL(STNSM); ECPSVM_STAT_DCL(STOSM); ECPSVM_STAT_DCL(SIO); ECPSVM_STAT_DCL(VTIMER); ECPSVM_STAT_DCL(STCTL); ECPSVM_STAT_DCL(LCTL); ECPSVM_STAT_DCL(DIAG); ECPSVM_STAT_DCL(IUCV); } ecpsvm_sastats={ ECPSVM_STAT_DEF(SVC), ECPSVM_STAT_DEF(SSM), ECPSVM_STAT_DEF(LPSW), ECPSVM_STAT_DEFU(STNSM), ECPSVM_STAT_DEFU(STOSM), ECPSVM_STAT_DEFU(SIO), ECPSVM_STAT_DEF(VTIMER), ECPSVM_STAT_DEFU(STCTL), ECPSVM_STAT_DEF(LCTL), ECPSVM_STAT_DEFU(DIAG), ECPSVM_STAT_DEFU(IUCV), }; struct _ECPSVM_SASTATS { ECPSVM_STAT_DCL(FREE); ECPSVM_STAT_DCL(FRET); ECPSVM_STAT_DCL(LCKPG); ECPSVM_STAT_DCL(ULKPG); ECPSVM_STAT_DCL(SCNRU); ECPSVM_STAT_DCL(SCNVU); ECPSVM_STAT_DCL(DISP0); ECPSVM_STAT_DCL(DISP1); ECPSVM_STAT_DCL(DISP2); ECPSVM_STAT_DCL(DNCCW); ECPSVM_STAT_DCL(DFCCW); ECPSVM_STAT_DCL(FCCWS); ECPSVM_STAT_DCL(CCWGN); ECPSVM_STAT_DCL(UXCCW); ECPSVM_STAT_DCL(TRBRG); ECPSVM_STAT_DCL(TRLOK); ECPSVM_STAT_DCL(VIST); ECPSVM_STAT_DCL(VIPT); ECPSVM_STAT_DCL(STEVL); ECPSVM_STAT_DCL(FREEX); ECPSVM_STAT_DCL(FRETX); ECPSVM_STAT_DCL(PMASS); ECPSVM_STAT_DCL(LCSPG); } ecpsvm_cpstats={ ECPSVM_STAT_DEFU(FREE), ECPSVM_STAT_DEFU(FRET), ECPSVM_STAT_DEF(LCKPG), ECPSVM_STAT_DEF(ULKPG), ECPSVM_STAT_DEF(SCNRU), ECPSVM_STAT_DEF(SCNVU), ECPSVM_STAT_DEF(DISP0), ECPSVM_STAT_DEF(DISP1), ECPSVM_STAT_DEF(DISP2), ECPSVM_STAT_DEFU(DNCCW), ECPSVM_STAT_DEFU(DFCCW), ECPSVM_STAT_DEFU(FCCWS), ECPSVM_STAT_DEFU(CCWGN), ECPSVM_STAT_DEFU(UXCCW), ECPSVM_STAT_DEF(TRBRG), ECPSVM_STAT_DEF(TRLOK), ECPSVM_STAT_DEFU(VIST), ECPSVM_STAT_DEFU(VIPT), ECPSVM_STAT_DEF(STEVL), ECPSVM_STAT_DEF(FREEX), ECPSVM_STAT_DEF(FRETX), ECPSVM_STAT_DEFU(PMASS), ECPSVM_STAT_DEFU(LCSPG), }; #define DEBUG_CPASSIST #define DEBUG_SASSIST #define DODEBUG_ASSIST(_cond,x) \ { \ if((_cond)) \ { \ x; \ }\ } #if defined(DEBUG_SASSIST) #define DEBUG_SASSISTX(_inst,x) \ { \ DODEBUG_ASSIST(ecpsvm_sastats._inst.debug,x) \ } #else #define DEBUG_SASSISTX(_cond,x) #endif #if defined(DEBUG_CPASSIST) #define DEBUG_CPASSISTX(_inst,x) \ { \ DODEBUG_ASSIST(ecpsvm_cpstats._inst.debug,x) \ } #else #define DEBUG_CPASSISTX(_cond,x) #endif /* Utility macros because I am very lazy */ #define EVM_IC( x ) ARCH_DEP(vfetchb) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_LH( x ) ARCH_DEP(vfetch2) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_L( x ) ARCH_DEP(vfetch4) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_LD( x ) ARCH_DEP(vfetch8) ( ( ( x ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_STD( x , y ) ARCH_DEP(vstore8) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_ST( x , y ) ARCH_DEP(vstore4) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_STH( x , y ) ARCH_DEP(vstore2) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_STC( x , y ) ARCH_DEP(vstoreb) ( ( x ) , ( ( y ) & ADDRESS_MAXWRAP(regs) ) , USE_REAL_ADDR , regs ) #define EVM_MVC( x , y , z ) ARCH_DEP(vfetchc) ( ( x ) , ( z ) , ( y ) , USE_REAL_ADDR , regs ) #define BR14 UPD_PSW_IA(regs, regs->GR_L(14)) #define INITPSEUDOIP(_regs) \ do { \ (_regs).ip=(BYTE*)"\0\0"; \ } while(0) #define INITPSEUDOREGS(_regs) \ do { \ memset(&(_regs),0,sysblk.regs_copy_len); \ INITPSEUDOIP((_regs)); \ } while(0) #define CPASSIST_HIT(_stat) ecpsvm_cpstats._stat.hit++ #define SASSIST_HIT(_stat) ecpsvm_sastats._stat.hit++ #define SASSIST_LPSW(_regs) \ do { \ SET_PSW_IA(&(_regs)); \ UPD_PSW_IA(regs, _regs.psw.IA); \ regs->psw.cc=_regs.psw.cc; \ regs->psw.pkey=_regs.psw.pkey; \ regs->psw.progmask=_regs.psw.progmask; \ } \ while(0) #define SASSIST_PROLOG( _instname) \ VADR amicblok; \ VADR vpswa; \ BYTE *vpswa_p; \ REGS vpregs; \ BYTE micpend; \ U32 CR6; \ ECPSVM_MICBLOK micblok; \ BYTE micevma; \ BYTE micevma2; \ BYTE micevma3; \ BYTE micevma4; \ if(SIE_STATE(regs)) \ return(1); \ if(!PROBSTATE(®s->psw)) \ { \ return(1); \ } \ if(!sysblk.ecpsvm.available) \ { \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" ECPS:VM Disabled in configuration\n"))); \ return(1); \ } \ if(!ecpsvm_sastats._instname.enabled) \ { \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" ECPS:VM Disabled by command\n"))); \ return(1); \ } \ CR6=regs->CR_L(6); \ regs->ecps_vtmrpt = NULL; /* Assume vtimer off until validated */ \ if(!(CR6 & ECPSVM_CR6_VMASSIST)) \ { \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : EVMA Disabled by guest\n"))); \ return(1); \ } \ /* Increment call now (don't count early misses) */ \ ecpsvm_sastats._instname.call++; \ amicblok=CR6 & ECPSVM_CR6_MICBLOK; \ /* Ensure MICBLOK resides on a single 2K page */ \ /* Then set ref bit by calling LOG_TO_ABS */ \ if((amicblok & 0x007ff) > 0x7e0) \ { \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" Micblok @ %6.6X crosses page frame\n"),amicblok)); \ return(1); \ } \ /* Load the micblok copy */ \ micblok.MICRSEG=EVM_L(amicblok); \ micblok.MICCREG=EVM_L(amicblok+4); \ micblok.MICVPSW=EVM_L(amicblok+8); \ micblok.MICWORK=EVM_L(amicblok+12); \ micblok.MICVTMR=EVM_L(amicblok+16); \ micblok.MICACF=EVM_L(amicblok+20); \ micpend=(micblok.MICVPSW >> 24); \ vpswa=micblok.MICVPSW & ADDRESS_MAXWRAP(regs); \ micevma=(micblok.MICACF >> 24); \ micevma2=((micblok.MICACF & 0x00ff0000) >> 16); \ micevma3=((micblok.MICACF & 0x0000ff00) >> 8); \ micevma4=(micblok.MICACF & 0x000000ff); \ if((CR6 & ECPSVM_CR6_VIRTTIMR)) \ { \ regs->ecps_vtmrpt = MADDR(micblok.MICVTMR,USE_REAL_ADDR,regs,ACCTYPE_READ,0); \ } \ /* Set ref bit on page where Virtual PSW is stored */ \ vpswa_p=MADDR(vpswa,USE_REAL_ADDR,regs,ACCTYPE_READ,0); \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" VPSWA= %8.8X Virtual "),vpswa)); \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" CR6= %8.8X\n"),CR6)); \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" MICVTMR= %8.8X\n"),micblok.MICVTMR)); \ DEBUG_SASSISTX(_instname,logmsg(_("HHCEV300D : SASSIST "#_instname" Real "))); \ DEBUG_SASSISTX(_instname,display_psw(regs)); \ /* Load the Virtual PSW in a temporary REGS structure */ \ INITPSEUDOREGS(vpregs); \ ARCH_DEP(load_psw) (&vpregs,vpswa_p); \ DEBUG_SASSISTX(_instname,display_psw(&vpregs)); \ #define ECPSVM_PROLOG(_inst) \ int b1, b2; \ VADR effective_addr1, \ effective_addr2; \ SSE(inst, regs, b1, effective_addr1, b2, effective_addr2); \ PRIV_CHECK(regs); \ SIE_INTERCEPT(regs); \ if(!sysblk.ecpsvm.available) \ { \ DEBUG_CPASSISTX(_inst,logmsg(_("HHCEV300D : CPASSTS "#_inst" ECPS:VM Disabled in configuration "))); \ ARCH_DEP(program_interrupt) (regs, PGM_OPERATION_EXCEPTION); \ } \ PRIV_CHECK(regs); /* No problem state please */ \ if(!ecpsvm_cpstats._inst.enabled) \ { \ DEBUG_CPASSISTX(_inst,logmsg(_("HHCEV300D : CPASSTS "#_inst" Disabled by command"))); \ return; \ } \ if(!(regs->CR_L(6) & 0x02000000)) \ { \ return; \ } \ ecpsvm_cpstats._inst.call++; \ DEBUG_CPASSISTX(_inst,logmsg(_("HHCEV300D : "#_inst" called\n"))); /* DISPx Utility macros */ #define STPT(_x) \ { \ EVM_STD(cpu_timer(regs),_x); \ } #define SPT(_x) \ { \ set_cpu_timer(regs,EVM_LD(_x)); \ OBTAIN_INTLOCK(regs); \ if(CPU_TIMER(regs) < 0) \ { \ ON_IC_PTIMER(regs); \ } \ else \ { \ OFF_IC_PTIMER(regs); \ } \ RELEASE_INTLOCK(regs); \ } #define CHARGE_STOP(_x) \ { \ STPT(_x+VMTTIME); \ } #define CHARGE_START(_x) \ { \ SPT(_x+VMTTIME); \ } #define CHARGE_SWITCH(_x,_y) \ { \ CHARGE_STOP(_x); \ CHARGE_START(_y); \ (_x)=(_y); \ } int ecpsvm_do_fretx(REGS *regs,VADR block,U16 numdw,VADR maxsztbl,VADR fretl); /* CPASSIST FREE (Basic) Not supported */ /* This is part of ECPS:VM Level 18 and 19 */ /* ECPS:VM Level 20 use FREEX */ DEF_INST(ecpsvm_basic_freex) { ECPSVM_PROLOG(FREE); } /* CPASSIST FRET (Basic) Not supported */ /* This is part of ECPS:VM Level 18 and 19 */ /* ECPS:VM Level 20 use FRETX */ DEF_INST(ecpsvm_basic_fretx) { ECPSVM_PROLOG(FRET); } /* Lockpage common code (LCKPG/TRLOK) */ static void ecpsvm_lockpage1(REGS *regs,RADR cortab,RADR pg) { BYTE corcode; VADR corte; U32 lockcount; RADR cortbl; DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG coreptr = "F_RADR" Frame = "F_RADR"\n"),cortab,pg)); cortbl=EVM_L(cortab); corte=cortbl+((pg & 0xfff000)>>8); DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG corete = %6.6X\n"),corte)); corcode=EVM_IC(corte+8); if(corcode & 0x80) { lockcount=EVM_L(corte+4); lockcount++; } else { lockcount=1; corcode|=0x80; EVM_STC(corcode,corte+8); } EVM_ST(lockcount,corte+4); DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG Page locked. Count = %6.6X\n"),lockcount)); return; } /* E602 LCKPG Instruction */ /* LCKPG D1(R1,B1),D2(R2,B2) */ /* 1st operand : PTR_PL -> Address of coretable */ /* 2nd Operand : Page address to be locked */ DEF_INST(ecpsvm_lock_page) { VADR ptr_pl; VADR pg; ECPSVM_PROLOG(LCKPG); ptr_pl=effective_addr1; pg=effective_addr2; DEBUG_CPASSISTX(LCKPG,logmsg(_("HHCEV300D : LKPG PAGE=%6.6X, PTRPL=%6.6X\n"),pg,ptr_pl)); ecpsvm_lockpage1(regs,ptr_pl,pg); regs->psw.cc=0; BR14; CPASSIST_HIT(LCKPG); return; } /* E603 ULKPG Instruction */ /* ULKPG D1(R1,B1),D2(R2,B2) */ /* 1st operand : PTR_PL -> +0 - Maxsize, +4 Coretable */ /* 2nd Operand : Page address to be unlocked */ DEF_INST(ecpsvm_unlock_page) { VADR ptr_pl; VADR pg; VADR corsz; VADR cortbl; VADR corte; BYTE corcode; U32 lockcount; ECPSVM_PROLOG(ULKPG); ptr_pl=effective_addr1; pg=effective_addr2; DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG PAGE=%6.6X, PTRPL=%6.6X\n"),pg,ptr_pl)); corsz=EVM_L(ptr_pl); cortbl=EVM_L(ptr_pl+4); if((pg+4095)>corsz) { DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG Page beyond core size of %6.6X\n"),corsz)); return; } corte=cortbl+((pg & 0xfff000)>>8); corcode=EVM_IC(corte+8); if(corcode & 0x80) { lockcount=EVM_L(corte+4); lockcount--; } else { DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG Attempting to unlock page that is not locked\n"))); return; } if(lockcount==0) { corcode &= ~(0x80|0x02); EVM_STC(corcode,corte+8); DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG now unlocked\n"))); } else { DEBUG_CPASSISTX(ULKPG,logmsg(_("HHCEV300D : ULKPG Page still locked. Count = %6.6X\n"),lockcount)); } EVM_ST(lockcount,corte+4); CPASSIST_HIT(ULKPG); BR14; return; } /* DNCCW : Not supported */ DEF_INST(ecpsvm_decode_next_ccw) { ECPSVM_PROLOG(DNCCW); } /* FCCWS : Not supported */ DEF_INST(ecpsvm_free_ccwstor) { ECPSVM_PROLOG(FCCWS); } /* SCNVU : Scan for Virtual Device blocks */ DEF_INST(ecpsvm_locate_vblock) { U32 vdev; U32 vchix; U32 vcuix; U32 vdvix; VADR vchtbl; VADR vch; VADR vcu; VADR vdv; ECPSVM_PROLOG(SCNVU); vdev=regs->GR_L(1); vchtbl=effective_addr1; vchix=EVM_LH(vchtbl+((vdev & 0xf00)>>7)); /* Get Index */ if(vchix & 0x8000) { DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU Virtual Device %4.4X has no VCHAN block\n"),vdev)); return; } vch=EVM_L(effective_addr2)+vchix; vcuix=EVM_LH(vch+8+((vdev & 0xf0)>>3)); if(vcuix & 0x8000) { DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU Virtual Device %4.4X has no VCU block\n"),vdev)); return; } vcu=EVM_L(effective_addr2+4)+vcuix; vdvix=EVM_LH(vcu+8+((vdev & 0xf)<<1)); if(vdvix & 0x8000) { DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU Virtual Device %4.4X has no VDEV block\n"),vdev)); return; } vdv=EVM_L(effective_addr2+8)+vdvix; DEBUG_CPASSISTX(SCNVU,logmsg(_("HHCEV300D SCNVU %4.4X : VCH = %8.8X, VCU = %8.8X, VDEV = %8.8X\n"), vdev, vch, vcu, vdv)); regs->GR_L(6)=vch; regs->GR_L(7)=vcu; regs->GR_L(8)=vdv; regs->psw.cc=0; CPASSIST_HIT(SCNVU); BR14; return; } /* DISP1 Core */ /* rc : 0 - Done */ /* rc : 1 - No-op */ /* rc : 2 - Invoke DISP2 */ int ecpsvm_do_disp1(REGS *regs,VADR dl,VADR el) { VADR vmb; U32 F_VMFLGS; /* Aggregate for quick test */ U32 F_SCHMASK; /* Flags to test */ U32 F_SCHMON; /* Flags allowed on for quick dispatch */ VADR F_ASYSVM; /* System VMBLOK */ VADR SCHDL; /* SCHDL Exit */ BYTE B_VMOSTAT; BYTE B_VMQSTAT; BYTE B_VMRSTAT; vmb=regs->GR_L(11); DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Data list = %6.6X VM=%6.6X\n",dl,vmb)); F_VMFLGS=EVM_L(vmb+VMRSTAT); F_SCHMASK=EVM_L(dl+64); F_SCHMON=EVM_L(dl+68); if((F_VMFLGS & F_SCHMASK) == F_SCHMON) { DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Quick Check complete\n")); return(2); } else { DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Quick Check failed : %8.8X != %8.8X\n",(F_VMFLGS & F_SCHMASK),F_SCHMON)); } F_ASYSVM=EVM_L(ASYSVM); if(vmb==F_ASYSVM) { DEBUG_CPASSISTX(DISP1,logmsg("DISP1 VMB is SYSTEM VMBLOCK\n")); return(2); } SCHDL=EVM_L(el+4); B_VMOSTAT=EVM_IC(vmb+VMOSTAT); if(!(B_VMOSTAT & VMKILL)) { DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Call SCHEDULE because VMKILL not set\n")); UPD_PSW_IA(regs, SCHDL); return(0); } B_VMQSTAT=EVM_IC(vmb+VMQSTAT); if(!(B_VMQSTAT & VMCFREAD)) { if(B_VMOSTAT & VMCF) { DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Call SCHEDULE because VMKILL & VMCF & !VMCFREAD set\n")); UPD_PSW_IA(regs, SCHDL); return(0); } } /* At DSP - OFF */ B_VMQSTAT &= ~VMCFREAD; B_VMOSTAT &= ~VMKILL; EVM_STC(B_VMQSTAT,vmb+VMQSTAT); EVM_STC(B_VMOSTAT,vmb+VMOSTAT); B_VMRSTAT=EVM_IC(vmb+VMRSTAT); if(B_VMRSTAT & VMLOGOFF) { DEBUG_CPASSISTX(DISP1,logmsg("DISP1 Continue because already logging off\n")); return(2); } B_VMRSTAT |= VMLOGOFF; EVM_STC(B_VMRSTAT,vmb+VMRSTAT); UPD_PSW_IA(regs, EVM_L(el+0)); DEBUG_CPASSISTX(DISP1,logmsg("DISP1 : Call USOFF\n")); return(0); } /* DISP2 Core */ int ecpsvm_do_disp2(REGS *regs,VADR dl,VADR el) { VADR vmb; /* Current VMBLOK */ VADR svmb; /* ASYSVM */ VADR runu; /* RUNUSER */ VADR lastu; /* LASTUSER */ VADR F_TRQB; VADR F_CPEXB; VADR F,B; U16 HW1; U32 FW1; U64 DW1; U32 CPEXBKUP[15]; /* CPEXBLOK Regs backup except GPR15 which is useless */ VADR F_ECBLOK; /* Pointer to user's EC block for extended VM */ VADR F_CPEXADD; U32 F_QUANTUM; REGS wregs; /* Work REGS structure of PSW manipulation for Virtual PSW */ REGS rregs; /* Work REGS structure of PSW manipulation for Real PSW */ int i; BYTE B_VMDSTAT,B_VMRSTAT,B_VMESTAT,B_VMPSTAT,B_VMMCR6,B_MICVIP; BYTE B_VMOSTAT,B_VMPEND; VADR F_MICBLOK; U32 F_VMIOINT,F_VMPXINT; U32 F_VMVCR0; U32 NCR0,NCR1; BYTE *work_p; vmb=regs->GR_L(11); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Data list=%6.6X VM=%6.6X\n",dl,vmb)); CHARGE_STOP(vmb); if(EVM_IC(XTENDLOCK) == XTENDLOCKSET) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Exit 8 : System extending\n")); /* System in Extend process */ UPD_PSW_IA(regs, EVM_L(el+8)); return(0); } if(EVM_IC(APSTAT2) & CPMCHLK) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Exit 8 : MCH Recovery\n")); /* Machine Check recovery in progress */ UPD_PSW_IA(regs, EVM_L(el+8)); return(0); } svmb=EVM_L(ASYSVM); /* Check IOB/TRQ for dispatch */ F_TRQB=EVM_L(dl+8); if(F_TRQB!=dl) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 TRQ/IOB @ %6.6X Exit being routed\n",F_TRQB)); /* We have a TRQ/IOB */ /* Update stack */ F=EVM_L(F_TRQB+8); B=EVM_L(F_TRQB+12); EVM_ST(F,B+8); EVM_ST(B,F+12); /* Get VMBLOK Responsible for this block */ vmb=EVM_L(F_TRQB+0x18); /* Update stack count for the VMBLOK */ HW1=EVM_LH(vmb+VMSTKCNT); HW1--; EVM_STH(HW1,vmb+VMSTKCNT); /* Start charging user for processor time */ CHARGE_START(vmb); EVM_ST(vmb,STACKVM); /* Update registers for TRQ/IOB exit */ regs->GR_L(10)=F_TRQB; regs->GR_L(11)=vmb; regs->GR_L(12)=EVM_L(F_TRQB+0x1C); UPD_PSW_IA(regs, regs->GR_L(12)); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 TRQ/IOB @ %6.6X IA = %6.6X\n",F_TRQB,regs->GR_L(12))); return(0); } /* Check CPEX BLOCK for dispatch */ F_CPEXB=EVM_L(dl+0); if(F_CPEXB!=dl) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 CPEXBLOK Exit being routed CPEX=%6.6X\n",F_CPEXB)); /* We have a CPEXBLOCK */ /* Update stack */ F=EVM_L(F_CPEXB+0); B=EVM_L(F_CPEXB+4); EVM_ST(F,B+0); EVM_ST(B,F+4); vmb=EVM_L(F_CPEXB+0x10+(11*4)); HW1=EVM_LH(vmb+VMSTKCNT); HW1--; EVM_STH(HW1,vmb+VMSTKCNT); CHARGE_START(vmb); /* Copy CPEXBLOCK Contents, and attempt FRET */ /* If fret fails, use exit #12 */ for(i=0;i<15;i++) { CPEXBKUP[i]=EVM_L(F_CPEXB+0x10+(i*4)); } F_CPEXADD=EVM_L(F_CPEXB+0x0C); if(ecpsvm_do_fretx(regs,F_CPEXB,10,EVM_L(dl+28),EVM_L(dl+32))!=0) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 CPEXBLOK CPEX=%6.6X Fret Failed\n",F_CPEXB)); regs->GR_L(0)=10; regs->GR_L(1)=F_CPEXB; for(i=2;i<12;i++) { regs->GR_L(i)=CPEXBKUP[i]; } /* Save GPRS 12-1 (wraping) in DSPSAVE (datalist +40) */ /* So that LM 12,1,DSPSAVE in DMKDSP works after call to DMKFRET */ EVM_ST(dl+40,CPEXBKUP[12]); EVM_ST(dl+44,CPEXBKUP[13]); EVM_ST(dl+48,CPEXBKUP[14]); EVM_ST(dl+52,EVM_L(F_CPEXB+12)); /* DSPSAVE + 12 = CPEXADD */ EVM_ST(dl+56,CPEXBKUP[0]); EVM_ST(dl+60,CPEXBKUP[1]); /* Note : DMKDSP Is wrong - SCHMASK is at +64 (not +60) */ /* Upon taking this exit, GPRS 12-15 are same as entry */ UPD_PSW_IA(regs, EVM_L(el+12)); return(0); } for(i=0;i<15;i++) { regs->GR_L(i)=CPEXBKUP[i]; } regs->GR_L(15)=F_CPEXADD; UPD_PSW_IA(regs, F_CPEXADD); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 CPEXBLOK CPEX=%6.6X IA=%6.6X\n",F_CPEXB,F_CPEXADD)); return(0); /* CPEXBLOCK Branch taken */ } /* Check for a USER run */ /* AT DMKDSP - DONE */ if(EVM_IC(CPSTAT2) & CPSHRLK) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 Exit 24 : CPSHRLK Set in CPSTAT2\n")); UPD_PSW_IA(regs, EVM_L(el+24)); /* IDLEECPS */ return(0); } /* Scan Scheduler IN-Q */ DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Scanning Scheduler IN-Queue\n")); FW1=EVM_L(dl+24); for(vmb=EVM_L(FW1);vmb!=FW1;vmb=EVM_L(vmb)) { if(!(EVM_IC(vmb+VMDSTAT) & VMRUN)) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Not eligible : VMRUN not set\n",vmb)); continue; } if(EVM_IC(vmb+VMRSTAT) & VMCPWAIT) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Not eligible : VMCPWAIT set\n",vmb)); continue; } if(EVM_IC(vmb+VMNOECPS)) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Exit 20 : VMB @ %6.6X Has VMNOECPS Set to %2.2X\n",vmb,EVM_IC(vmb+VMNOECPS))); regs->GR_L(1)=vmb; regs->GR_L(11)=EVM_L(ASYSVM); UPD_PSW_IA(regs, EVM_L(el+20)); /* FREELOCK */ return(0); } DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Will now be dispatched\n",vmb)); runu=EVM_L(RUNUSER); F_QUANTUM=EVM_L(QUANTUM); if(vmb!=runu) { /* User switching */ /* DMKDSP - FNDUSRD */ DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : User switch from %6.6X to %6.6X\n",runu,vmb)); runu=EVM_L(RUNUSER); EVM_STC(EVM_IC(runu+VMDSTAT) & ~VMDSP,runu+VMDSTAT); lastu=EVM_L(LASTUSER); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : RUNU=%6.6X, LASTU=%6.6X\n",runu,lastu)); if(lastu!=svmb && lastu!=vmb) { if(EVM_IC(lastu+VMOSTAT) & VMSHR) /* Running shared sys */ { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Exit 16 : LASTU=%6.6X has shared sys & LCSHPG not impl\n",lastu)); CHARGE_START(lastu); /* LCSHRPG not implemented yet */ regs->GR_L(10)=vmb; regs->GR_L(11)=lastu; UPD_PSW_IA(regs, EVM_L(el+16)); return(0); /* A CHARGE_STOP(runu) is due when LCSHRPG is implemented */ } } } if(vmb!=runu || (vmb==runu && (F_QUANTUM & 0x80000000))) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Restarting Time Slice\n")); F_QUANTUM=EVM_L(dl+16); if(EVM_IC(vmb+VMQLEVEL) & VMCOMP) { F_QUANTUM <<= 2; } } EVM_ST(F_QUANTUM,INTTIMER); CHARGE_START(vmb); EVM_ST(vmb,LASTUSER); EVM_ST(vmb,RUNUSER); /*** Prepare to run a user ***/ /* Cache some important VMBLOK flag bytes */ B_VMDSTAT=EVM_IC(vmb+VMDSTAT); B_VMRSTAT=EVM_IC(vmb+VMRSTAT); B_VMPSTAT=EVM_IC(vmb+VMPSTAT); B_VMESTAT=EVM_IC(vmb+VMESTAT); B_VMOSTAT=EVM_IC(vmb+VMOSTAT); B_VMPEND =EVM_IC(vmb+VMPEND); B_VMMCR6=EVM_IC(vmb+VMMCR6); F_MICBLOK=EVM_L(vmb+VMMCR6) & ADDRESS_MAXWRAP(regs); /* LOAD FPRS */ for(i=0;i<8;i+=2) { FW1=EVM_L(vmb+VMFPRS+(i*16)); regs->fpr[i*4]=FW1; FW1=EVM_L(vmb+VMFPRS+(i*16)+4); regs->fpr[i*4+1]=FW1; FW1=EVM_L(vmb+VMFPRS+(i*16)+8); regs->fpr[i*4+2]=FW1; FW1=EVM_L(vmb+VMFPRS+(i*16)+12); regs->fpr[i*4+3]=FW1; } INITPSEUDOREGS(wregs); work_p=MADDR(vmb+VMPSW,0,regs,USE_REAL_ADDR,0); ARCH_DEP(load_psw) (&wregs,work_p); /* Load user's Virtual PSW in work structure */ SET_PSW_IA(&wregs); /* Build REAL PSW */ INITPSEUDOREGS(rregs); /* Copy IAR */ UPD_PSW_IA(&rregs, wregs.psw.IA); /* Copy CC, PSW KEYs and PGM Mask */ rregs.psw.cc=wregs.psw.cc; rregs.psw.pkey=wregs.psw.pkey; /* Indicate Translation + I/O + Ext + Ecmode + Problem + MC */ rregs.psw.sysmask=0x07; /* I/O + EXT + Trans */ rregs.psw.states = BIT(PSW_EC_BIT) /* ECMODE */ | BIT(PSW_PROB_BIT) /* Problem state */ | BIT(PSW_MACH_BIT); /* MC Enabled */ rregs.psw.intcode=0; /* Clear intcode */ rregs.psw.progmask=wregs.psw.progmask; NCR0=EVM_L(CPCREG0); /* Assume for now */ NCR1=EVM_L(vmb+VMSEG); /* Ditto */ /* Disable ECPS:VM in VM-REAL CR6 For now */ B_VMMCR6&=~(VMMSHADT|VMMPROB|VMMNOSK|VMMFE); /* We load VMECEXT Even if it's not a ECMODE VM */ /* in which case F_ECBLOK is also Virtual CR0 */ F_ECBLOK=EVM_L(vmb+VMECEXT); /* ECMODE VM ? */ if(B_VMPSTAT & VMV370R) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X has ECMODE ON\n",vmb)); /* Is this an ECMODE PSW Machine ? */ if(B_VMESTAT & VMEXTCM) { if((B_VMESTAT & (VMINVSEG|VMNEWCR0)) == (VMINVSEG|VMNEWCR0)) { /* CP Say this is NOT good */ /* Take exit 28 */ logmsg(_("HHCEV004W : Abend condition detected in DISP2 instr\n")); UPD_PSW_IA(regs, EVM_L(el+28)); return(0); } /* Check 3rd level translation */ if(wregs.psw.sysmask & 0x04) { NCR0=EVM_L(F_ECBLOK+EXTSHCR0); NCR1=EVM_L(F_ECBLOK+EXTSHCR1); B_VMMCR6|=VMMSHADT; /* re-enable Shadow Table management in CR6 */ } } } /* Invalidate Shadow Tables if necessary */ if(B_VMESTAT & (VMINVPAG | VMSHADT)) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Refusing to simulate DMKVATAB\n",vmb)); /* Really looks like DMKVATAB is a huge thing to simulate */ /* My belief is that the assist can't handle this one */ /* Return to caller as a NO-OP on this one */ return(1); /* ecpsvm_inv_shadtab_pages(regs,vmb); */ } B_VMESTAT&=~VMINVPAG; B_VMDSTAT|=VMDSP; /* Test for CPMICON in DMKDSP useless here */ /* if CPMICON was off, we would have never */ /* been called anyway */ if(F_MICBLOK!=0) /* That is SET ASSIST ON */ { B_MICVIP=0; /* Check tracing (incompatible with assist) */ if(!(EVM_IC(vmb+VMTRCTL) & (VMTRSVC|VMTRPRV|VMTRBRIN))) { B_VMMCR6|=VMMFE; if(B_VMOSTAT & VMSHR) { /* Cannot allow ISK/SSK in shared sys VM */ B_VMMCR6|=VMMNOSK; } if(PROBSTATE(&wregs.psw)) { B_VMMCR6|=VMMPROB; } /* Set MICPEND if necessary */ /* (assist stuff to ensure LPSW/SSM/SVC sim */ /* does not re-enable VPSW when an interrupt */ /* is pending) */ while(1) { B_MICVIP=0; F_VMIOINT=EVM_LH(vmb+VMIOINT); if(EVM_LH(vmb+VMIOINT)!=0) { F_VMIOINT<<=16; if(B_VMESTAT & VMEXTCM) { if(F_VMIOINT&=EVM_L(F_ECBLOK)) { B_MICVIP|=0x80; break; } } else { B_MICVIP|=0x80; break; } } if(B_VMESTAT & VMEXTCM) { if(B_VMPEND & VMPGPND) { B_MICVIP|=0x80; } } if(B_VMPSTAT & VMV370R) { F_VMVCR0=EVM_L(F_ECBLOK+0); } else { F_VMVCR0=F_ECBLOK; } for(F_VMPXINT=EVM_L(vmb+VMPXINT);F_VMPXINT;F_VMPXINT=EVM_L(F_VMPXINT)) /* XINTNEXT at +0 */ { if(F_VMVCR0 & EVM_LH(F_VMPXINT+10)) { B_MICVIP|=0x80; break; } } break; /* Terminate dummy while loop */ } /* While dummy loop for MICPEND */ } /* if(Not tracing) */ EVM_STC(B_MICVIP,F_MICBLOK+8); /* Save new MICVIP */ } /* if(F_MICBLOCK!=0) */ /* If an Extended VM, Load CRs 3-13 */ /* CR6 Will be overwritten in a second */ if(B_VMESTAT & VMV370R) { for(i=4;i<14;i++) { regs->CR_L(i)=EVM_L(F_ECBLOK+(3*4)+(i*4)); } } /* Update VMMICRO */ EVM_STC(B_VMMCR6,vmb+VMMCR6); /* Update PER Control */ if(EVM_IC(vmb+VMTRCTL) & VMTRPER) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : PER ON\n")); FW1=EVM_L(vmb+VMTREXT); regs->CR_L( 9)=EVM_L(FW1+0x1C); regs->CR_L(10)=EVM_L(FW1+0x20); regs->CR_L(11)=EVM_L(FW1+0x24); rregs.psw.sysmask |= 0x40; /* PER Mask in PSW */ } /* Update CR6 */ regs->CR_L(6)=EVM_L(vmb+VMMCR6); /* Insure proper re-entry */ EVM_ST(0,STACKVM); /* Update PROBLEM Start time */ DW1=EVM_LD(vmb+VMTMOUTQ); EVM_STD(DW1,PROBSTRT); /* Checkpoint Interval Timer */ FW1=EVM_L(INTTIMER); EVM_ST(FW1,QUANTUM); /* Update REAL CR0/CR1 */ regs->CR_L(0)=NCR0; regs->CR_L(1)=NCR1; /* Indicate RUNNING a user */ EVM_STC(CPRUN,CPSTATUS); /* Update real PSW with working PSW */ /* Update regs */ for(i=0;i<16;i++) { regs->GR_L(i)=EVM_L(vmb+VMGPRS+(i*4)); } /* Clear I/O Old PSW Byte 0 */ EVM_STC(0,IOOPSW); /* Issue PTLB if necessary */ if(EVM_IC(APSTAT2) & CPPTLBR) { DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Purging TLB\n")); ARCH_DEP(purge_tlb)(regs); EVM_STC(EVM_IC(APSTAT2) & ~CPPTLBR,APSTAT2); } /* Update cached VMBLOK flags */ EVM_STC(B_VMDSTAT,vmb+VMDSTAT); EVM_STC(B_VMRSTAT,vmb+VMRSTAT); EVM_STC(B_VMESTAT,vmb+VMESTAT); EVM_STC(B_VMPSTAT,vmb+VMPSTAT); EVM_STC(B_VMOSTAT,vmb+VMOSTAT); work_p=MADDR(vmb+VMPSW,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0); \ ARCH_DEP(store_psw) (&wregs,work_p); /* Stop charging current VM Block for Supervisor time */ CHARGE_STOP(vmb); /* Rest goes for problem state */ SPT(vmb+VMTMOUTQ); /* Save RUNCR0, RUNCR1 & RUNPSW */ /* Might be used by later CP Modules (including DMKPRV) */ EVM_ST(NCR0,RUNCR0); EVM_ST(NCR1,RUNCR1); work_p=MADDR(RUNPSW,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0); \ ARCH_DEP(store_psw) (&rregs,work_p); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Entry Real ")); DEBUG_CPASSISTX(DISP2,display_psw(regs)); ARCH_DEP(load_psw) (regs,work_p); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : VMB @ %6.6X Now being dispatched\n",vmb)); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Real ")); DEBUG_CPASSISTX(DISP2,display_psw(regs)); DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Virtual ")); DEBUG_CPASSISTX(DISP2,display_psw(&wregs)); /* TEST */ ARCH_DEP(purge_tlb)(regs); SET_IC_MASK(regs); SET_AEA_MODE(regs); SET_AEA_COMMON(regs); SET_PSW_IA(regs); /* Dispatch..... */ DEBUG_CPASSISTX(DISP2,logmsg(_("HHCPEV300D : DISP2 - Next Instruction : %2.2X\n"),ARCH_DEP(vfetchb)(regs->psw.IA,USE_PRIMARY_SPACE,regs))); DEBUG_CPASSISTX(DISP2,display_regs(regs)); DEBUG_CPASSISTX(DISP2,display_cregs(regs)); return(2); /* OK - Perform INTCHECK */ } /* Nothing else to do - wait state */ DEBUG_CPASSISTX(DISP2,logmsg("DISP2 : Nothing to dispatch - IDLEECPS\n")); UPD_PSW_IA(regs, EVM_L(el+24)); /* IDLEECPS */ return(0); } /* DISP1 : Early tests part 2 */ /* DISP1 Checks if the user is OK to run */ /* early tests part 1 already done by DISP0 */ DEF_INST(ecpsvm_disp1) { ECPSVM_PROLOG(DISP1); switch(ecpsvm_do_disp1(regs,effective_addr1,effective_addr2)) { case 0: /* Done */ CPASSIST_HIT(DISP1); return; case 1: /* No-op */ break; case 2: /* Call DISP2 - INTCHECK NOT needed */ switch(ecpsvm_do_disp2(regs,effective_addr1,effective_addr2)) { case 0: CPASSIST_HIT(DISP1); return; case 1: return; case 2: CPASSIST_HIT(DISP1); RETURN_INTCHECK(regs); default: break; } return; default: return; } } static int ecpsvm_int_lra(REGS *regs,VADR pgadd,RADR *raddr) { int cc; cc = ARCH_DEP(translate_addr) (pgadd , USE_PRIMARY_SPACE, regs, ACCTYPE_LRA); *raddr = regs->dat.raddr; return cc; } /* TRANBRNG/TRANLOCK Common code */ static int ecpsvm_tranbrng(REGS *regs,VADR cortabad,VADR pgadd,RADR *raddr) { int cc; int corcode; #if defined(FEATURE_2K_STORAGE_KEYS) RADR pg1,pg2; #endif VADR cortab; cc=ecpsvm_int_lra(regs,pgadd,raddr); if(cc!=0) { DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Tranbring : LRA cc = %d\n"),cc)); return(1); } /* Get the core table entry from the Real address */ cortab=EVM_L( cortabad ); cortab+=((*raddr) & 0xfff000) >> 8; corcode=EVM_IC(cortab+8); if(!(corcode & 0x08)) { DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Page not shared - OK %d\n"),cc)); return(0); /* Page is NOT shared.. All OK */ } #if defined(FEATURE_2K_STORAGE_KEYS) pg1=(*raddr & 0xfff000); pg2=pg1+0x800; DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Checking 2K Storage keys @"F_RADR" & "F_RADR"\n"),pg1,pg2)); if((STORAGE_KEY(pg1,regs) & STORKEY_CHANGE) || (STORAGE_KEY(pg2,regs) & STORKEY_CHANGE)) { #else DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Checking 4K Storage keys @"F_RADR"\n"),*raddr)); if(STORAGE_KEY(*raddr,regs) & STORKEY_CHANGE) { #endif DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Page shared and changed\n"))); return(1); /* Page shared AND changed */ } DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : Page shared but not changed\n"))); return(0); /* All done */ } /* TRBRG : Translate a page address */ /* TRBRG D1(R1,B1),D2(R2,B2) */ /* 1st operand : Coretable address */ /* 2nd operand : Virtual address */ /* Note : CR1 Contains the relevant segment table */ /* pointers */ /* The REAL address is resolved. If the page is flagged */ /* as shared in the core table, the page is checked for */ /* the change bit */ /* If no unusual condition is detected, control is returned */ /* to the address in GPR 14. Otherwise, TRBRG is a no-op */ DEF_INST(ecpsvm_tpage) { int rc; RADR raddr; ECPSVM_PROLOG(TRBRG); DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : TRANBRNG\n"))); rc=ecpsvm_tranbrng(regs,effective_addr1,regs->GR_L(1),&raddr); if(rc) { DEBUG_CPASSISTX(TRBRG,logmsg(_("HHCEV300D : TRANBRNG - Back to CP\n"))); return; /* Something not right : NO OP */ } regs->psw.cc=0; regs->GR_L(2)=raddr; UPD_PSW_IA(regs, effective_addr2); CPASSIST_HIT(TRBRG); return; } /* TRLOK : Translate a page address and lock */ /* TRLOK D1(R1,B1),D2(R2,B2) */ /* See TRBRG. */ /* If sucessfull, the page is also locked in the core table */ DEF_INST(ecpsvm_tpage_lock) { int rc; RADR raddr; ECPSVM_PROLOG(TRLOK); DEBUG_CPASSISTX(TRLOK,logmsg(_("HHCEV300D : TRANLOCK\n"))); rc=ecpsvm_tranbrng(regs,effective_addr1,regs->GR_L(1),&raddr); if(rc) { DEBUG_CPASSISTX(TRLOK,logmsg(_("HHCEV300D : TRANLOCK - Back to CP\n"))); return; /* Something not right : NO OP */ } /* * Lock the page in Core Table */ ecpsvm_lockpage1(regs,effective_addr1,raddr); regs->psw.cc=0; regs->GR_L(2)=raddr; UPD_PSW_IA(regs, effective_addr2); CPASSIST_HIT(TRLOK); return; } /* VIST : Not supported */ DEF_INST(ecpsvm_inval_segtab) { ECPSVM_PROLOG(VIST); } /* VIPT : Not supported */ DEF_INST(ecpsvm_inval_ptable) { ECPSVM_PROLOG(VIPT); } /* DFCCW : Not Supported */ DEF_INST(ecpsvm_decode_first_ccw) { ECPSVM_PROLOG(DFCCW); } /* DISP0 Utility functions */ /* DMKDSP - INCPROBT */ static int ecpsvm_disp_incprobt(REGS *regs,VADR vmb) { U64 tspent; U64 DW_VMTMOUTQ; U64 DW_PROBSTRT; U64 DW_PROBTIME; DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Entry : VMBLOK @ %8.8X\n",vmb)); DW_VMTMOUTQ=EVM_LD(vmb+VMTMOUTQ); DW_PROBSTRT=EVM_LD(PROBSTRT); DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Entry : VMTMOUTQ = %16.16" I64_FMT "x\n",DW_VMTMOUTQ)); DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Entry : PROBSTRT = %16.16" I64_FMT "x\n",DW_PROBSTRT)); if(DW_VMTMOUTQ==DW_PROBSTRT) { DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT Already performed")); return(2); /* continue */ } tspent=DW_PROBSTRT-DW_VMTMOUTQ; DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT TSPENT = %16.16" I64_FMT "x\n",tspent)); DW_PROBTIME=EVM_LD(PROBTIME); DW_PROBTIME-=tspent; EVM_STD(DW_PROBTIME,PROBTIME); DEBUG_CPASSISTX(DISP0,logmsg("INCPROBT NEW PROBTIME = %16.16" I64_FMT "x\n",DW_PROBTIME)); return(2); } /* DMKDSP RUNTIME */ static int ecpsvm_disp_runtime(REGS *regs,VADR *vmb_p,VADR dlist,VADR exitlist) { U64 DW_VMTTIME; U64 DW_VMTMINQ; BYTE B_VMDSTAT; BYTE B_VMTLEVEL; BYTE B_VMMCR6; U32 F_QUANTUM; U32 F_QUANTUMR; U32 F_ITIMER; int cc; RADR raddr; VADR tmraddr; U32 oldtimer,newtimer; VADR vmb; VADR runu; vmb=*vmb_p; DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME Entry : VMBLOK @ %8.8X\n",vmb)); runu=EVM_L(RUNUSER); /* BAL RUNTIME Processing */ EVM_STC(CPEX+CPSUPER,CPSTATUS); CHARGE_STOP(vmb); if(vmb!=runu) { DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME Switching to RUNUSER VMBLOK @ %8.8X\n",runu)); CHARGE_SWITCH(vmb,runu); /* Charge RUNUSER */ F_ITIMER=EVM_L(QUANTUMR); *vmb_p=vmb; } else { F_ITIMER=EVM_L(INTTIMER); } DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : VMBLOK @ %8.8X\n",vmb)); /* vmb is now RUNUSER */ /* Check if time slice is over */ if(F_ITIMER & 0x80000000) { B_VMDSTAT=EVM_IC(vmb+VMDSTAT); B_VMDSTAT&=~VMDSP; B_VMDSTAT|=VMTSEND; EVM_STC(B_VMDSTAT,vmb+VMDSTAT); } /* Check if still eligible for current run Q */ DW_VMTTIME=EVM_LD(vmb+VMTTIME); DW_VMTMINQ=EVM_LD(vmb+VMTMINQ); /* Check 1st 5 bytes */ if((DW_VMTTIME & 0xffffffffff000000ULL) < (DW_VMTMINQ & 0xffffffffff000000ULL)) { B_VMDSTAT=EVM_IC(vmb+VMDSTAT); B_VMDSTAT&=~VMDSP; B_VMDSTAT|=VMQSEND; EVM_STC(B_VMDSTAT,vmb+VMDSTAT); } ecpsvm_disp_incprobt(regs,vmb); F_QUANTUM=EVM_L(QUANTUM); EVM_ST(F_ITIMER,QUANTUM); /* Check if Virtual Timer assist is active */ B_VMMCR6=EVM_IC(vmb+VMMCR6); if(B_VMMCR6 & 0x01) /* Virtual Timer Flag */ { DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - VTIMER Assist active\n")); return(2); /* End of "RUNTIME" here */ } /* Check SET TIMER ON or SET TIMER REAL */ B_VMTLEVEL=EVM_IC(vmb+VMTLEVEL); if(!(B_VMTLEVEL & (VMTON | VMRON))) { DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - SET TIMER OFF\n")); return(2); } /* Update virtual interval timer */ F_QUANTUMR=EVM_L(QUANTUMR); F_QUANTUM-=F_QUANTUMR; if(F_QUANTUM & 0x80000000) { /* Abend condition detected during virtual time update - exit at +32 */ DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Bad ITIMER - Taking Exist #32\n")); UPD_PSW_IA(regs, EVM_L(exitlist+32)); return(0); } /* Load CR1 with the vmblock's VMSEG */ regs->CR_L(1)=EVM_L(vmb+VMSEG); /* Do LRA - Don't access the page directly yet - Could yield a Paging fault */ cc = ecpsvm_int_lra(regs,INTTIMER,&raddr); if(cc!=0) { /* Update VMTIMER instead */ tmraddr=vmb+VMTIMER; } else { tmraddr=(VADR)raddr; } oldtimer=EVM_L(tmraddr); newtimer=oldtimer-F_QUANTUM; EVM_ST(newtimer,tmraddr); if((newtimer & 0x80000000) != (oldtimer & 0x80000000)) { /* Indicate XINT to be generated (exit + 8) */ /* Setup a few regs 1st */ regs->GR_L(3)=0; regs->GR_L(4)=0x00800080; regs->GR_L(9)=EVM_L(dlist+4); regs->GR_L(11)=vmb; UPD_PSW_IA(regs, EVM_L(exitlist+8)); DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - Taking exit #8\n")); return(0); } /* Return - Continue DISP0 Processing */ DEBUG_CPASSISTX(DISP0,logmsg("RUNTIME : Complete - ITIMER Updated\n")); return(2); } /* DISP0 : Operand 1 : DISP0 Data list, Operand 2 : DISP0 Exit list */ /* R11 : User to dispatch */ DEF_INST(ecpsvm_dispatch_main) { VADR dlist; VADR elist; VADR vmb; /* PSA Fetched Values */ BYTE B_CPSTATUS; BYTE B_VMDSTAT; BYTE B_VMPSTAT; BYTE B_VMRSTAT; BYTE B_VMPEND; BYTE B_VMESTAT; VADR F_VMPXINT; VADR OXINT; /* Back chain ptr for exit 20 */ U32 F_VMPSWHI; U32 F_VMVCR0; U32 F_VMIOINT; U32 F_VMVCR2; U32 DISPCNT; U16 H_XINTMASK; U32 iomask; BYTE extendmsk; /* Extended I/O mask */ ECPSVM_PROLOG(DISP0); dlist=effective_addr1; elist=effective_addr2; vmb=regs->GR_L(11); DISPCNT=EVM_L(dlist); DISPCNT++; /* Question #1 : Are we currently running a user */ B_CPSTATUS=EVM_IC(CPSTATUS); if((B_CPSTATUS & CPRUN)) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CPRUN On\n")); switch(ecpsvm_disp_runtime(regs,&vmb,dlist,elist)) { case 0: /* Exit taken - success */ EVM_ST(DISPCNT,dlist); CPASSIST_HIT(DISP0); return; case 1: /* no-op DISP0 */ return; default: /* Continue processing */ break; } /* Load VMDSTAT */ B_VMDSTAT=EVM_IC(vmb+VMDSTAT); /* Check if I/O Old PSW has tranlation on */ if(regs->mainstor[0x38] & 0x04) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : I/O Old as XLATE on\n")); /* Yes - I/O Interrupt while running a USER */ if(B_VMDSTAT & VMDSP) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VMDSP on in VMBLOK - Clean status (Exit #36)\n")); /* Clean status - Do exit 36 */ regs->GR_L(11)=vmb; UPD_PSW_IA(regs, EVM_L(elist+36)); EVM_ST(DISPCNT,dlist); CPASSIST_HIT(DISP0); return; } } } else { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CPRUN Off\n")); /* Check if was in Wait State */ if(B_CPSTATUS & CPWAIT) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CPWAIT On : Exit #4\n")); /* Take exit #4 : Coming out of wait state */ /* DMKDSPC3 */ /* No need to update R11 */ CPASSIST_HIT(DISP0); UPD_PSW_IA(regs, EVM_L(elist+4)); EVM_ST(DISPCNT,dlist); return; } } /* VMB is now either original GPR11 or RUNUSER */ /* DMKDSP - UNSTACK */ DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : At UNSTACK : VMBLOK = %8.8X\n",vmb)); B_VMRSTAT=EVM_IC(vmb+VMRSTAT); if(B_VMRSTAT & VMCPWAIT) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VMRSTAT VMCPWAIT On (%2.2X) - Taking exit #12\n",B_VMRSTAT)); /* Take Exit 12 */ regs->GR_L(11)=vmb; UPD_PSW_IA(regs, EVM_L(elist+12)); CPASSIST_HIT(DISP0); EVM_ST(DISPCNT,dlist); return; } /* Check for PER/PPF (CKPEND) */ B_VMPEND=EVM_IC(vmb+VMPEND); if(B_VMPEND & (VMPERPND | VMPGPND)) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : PER/PPF Pending - Taking exit #16\n")); /* Take Exit 16 */ regs->GR_L(11)=vmb; UPD_PSW_IA(regs, EVM_L(elist+16)); CPASSIST_HIT(DISP0); EVM_ST(DISPCNT,dlist); return; } /* Now, check if we should unstack an external int */ /* 1st check if VMPXINT is NULL */ F_VMPSWHI=EVM_L(vmb+VMPSW); /* Load top of virt PSW - Will need it */ B_VMPSTAT=EVM_IC(vmb+VMPSTAT); /* Will need VMPSTAT for I/O ints too */ F_VMPXINT=EVM_L(vmb+VMPXINT); DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : Checking for EXT; Base VMPXINT=%8.8X\n",F_VMPXINT)); /* This is DMKDSP - CKEXT */ if(F_VMPXINT!=0) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VPSW HI = %8.8X\n",F_VMPSWHI)); OXINT=vmb+VMPXINT; /* Check if Virtual PSW enabled for Externals */ /* (works in both BC & EC modes) */ if(F_VMPSWHI & 0x01000000) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : PSW Enabled for EXT\n")); /* Use VMVCR0 or CR0 in ECBLOK */ F_VMVCR0=EVM_L(vmb+VMVCR0); /* CR0 or ECBLOK Address */ if(B_VMPSTAT & VMV370R) /* SET ECMODE ON ?? */ { F_VMVCR0=EVM_L(F_VMVCR0+0); /* EXTCR0 at disp +0 in ECBLOK */ } DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : CR0 = %8.8X\n",F_VMVCR0)); /* scan the XINTBLOKS for a mask match */ /* Save OXINT in the loop for exit 20 */ for(;F_VMPXINT;OXINT=F_VMPXINT,F_VMPXINT=EVM_L(F_VMPXINT)) /* XINTNEXT @ +0 in XINTBLOK */ { H_XINTMASK=EVM_LH(F_VMPXINT+10); /* Get interrupt subclass in XINTBLOK */ DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : XINTMASK = %4.4X\n",H_XINTMASK)); H_XINTMASK &= F_VMVCR0; if(H_XINTMASK) /* Check against CR0 (External subclass mask) */ { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : EXT Hit - Taking exit #20\n")); /* Enabled for this external */ /* Take exit 20 */ regs->GR_L(4)=H_XINTMASK; /* Enabled subclass bits */ regs->GR_L(5)=OXINT; /* XINTBLOK Back pointer (or VMPXINT) */ regs->GR_L(6)=F_VMPXINT; /* Current XINTBLOK */ regs->GR_L(11)=vmb; /* RUNUSER */ UPD_PSW_IA(regs, EVM_L(elist+20)); /* Exit +20 */ EVM_ST(DISPCNT,dlist); CPASSIST_HIT(DISP0); return; } } } } /* After CKEXT : No external pending/reflectable */ /* This is DMKDSP UNSTIO */ /* Check for pending I/O Interrupt */ /* Load PIM */ F_VMIOINT=EVM_LH(vmb+VMIOINT); DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : Checking for I/O; VMIOINT=%8.8X\n",F_VMIOINT)); if(F_VMIOINT!=0) /* If anything in the pipe */ { F_VMIOINT <<=16; /* Put IOINT mask in bits 0-15 */ /* Is V-PSW in EC Mode ? */ iomask=0; extendmsk=0; B_VMESTAT=EVM_L(VMESTAT); if(B_VMESTAT & VMEXTCM) /* Implies VMV370R on */ { /* Check I/O bit */ if(F_VMPSWHI & 0x02000000) { iomask=0; extendmsk=1; } } else { /* BC Mode PSW */ /* Isolate channel masks for channels 0-5 */ iomask=F_VMPSWHI & 0xfc000000; if(B_VMPSTAT & VMV370R) /* SET ECMODE ON ? */ { if(F_VMPSWHI & 0x02000000) { extendmsk=1; } } } if(extendmsk) { F_VMVCR2=EVM_L(vmb+VMECEXT); F_VMVCR2=EVM_L(F_VMVCR2+8); iomask |= F_VMVCR2; } if(iomask & 0xffff0000) { F_VMIOINT&=iomask; if(F_VMIOINT) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : I/O Hit - Taking exit #24\n")); /* Take Exit 24 */ regs->GR_L(7)=F_VMIOINT; regs->GR_L(11)=vmb; UPD_PSW_IA(regs, EVM_L(elist+24)); /* Exit +24 */ EVM_ST(DISPCNT,dlist); CPASSIST_HIT(DISP0); return; } } } /* DMKDSP - CKWAIT */ /* Clear Wait / Idle bits in VMRSTAT */ B_VMRSTAT=EVM_IC(vmb+VMRSTAT); B_VMRSTAT &= ~(VMPSWAIT | VMIDLE); EVM_STC(B_VMRSTAT,vmb+VMRSTAT); if(F_VMPSWHI & 0x00020000) { DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : VWAIT - Taking exit #28\n")); /* Take exit 28 */ regs->GR_L(11)=vmb; UPD_PSW_IA(regs, EVM_L(elist+28)); /* Exit +28 */ CPASSIST_HIT(DISP0); EVM_ST(DISPCNT,dlist); return; } /* Take exit 0 (DISPATCH) */ DEBUG_CPASSISTX(DISP0,logmsg("DISP0 : DISPATCH - Taking exit #0\n")); regs->GR_L(11)=vmb; UPD_PSW_IA(regs, EVM_L(elist+0)); /* Exit +0 */ CPASSIST_HIT(DISP0); EVM_ST(DISPCNT,dlist); return; } /******************************************************/ /* SCNRU Instruction : Scan Real Unit */ /* Invoked by DMKSCN */ /* E60D */ /* SCNRU D1(R1,B1),D2(R2,B2) */ /* */ /* Operations */ /* The Device Address specified in operand 1 is */ /* the real device address for which control block */ /* addresses are to be returned. The storage area */ /* designated as the 2nd operand is a list of 4 */ /* consecutive fullword (note : the 2nd operand is */ /* treated as a Real Address, regardless of any */ /* translation mode that may be in effect) */ /* +--------------------+-------------------+ */ /* | CHNLINDEX | RCHTABLE | */ /* +--------------------+-------------------+ */ /* | RCUTABLE | RDVTABLE | */ /* +--------------------+-------------------+ */ /* CHNLINDEX is an array of 16 halfwords, each */ /* representing the offset of the target's device */ /* channel's RCHBLOCK. If the channel is not defined */ /* in the RIO table, the index has bit 0, byte 0 set */ /* to 1 */ /* */ /* The RCHBLOK has at offset +X'20' a table of */ /* 32 possible control unit indices */ /* the device's address bit 8 to 12 are used to fetch */ /* the index specified at the table. If it has */ /* bit 0 byte 0 set, then the same operation is */ /* attempted with bits 8 to 11 */ /* The RCUBLOK then fetched from RCUTABLE + the index */ /* fetched from the RCHBLOK has a DEVICE index table */ /* at offset +X'28' which can be fetched by using */ /* bits 5-7 */ /* If the RCUBLOK designates an alternate control */ /* unit block, (Offset +X'5' bit 1 set), then */ /* the primary RCUBLOK is fetched from offset X'10' */ /* */ /* If no RCHBLOK is found, R6,R7 and R8 contain -1 */ /* and Condition Code 3 is set */ /* */ /* if no RCUBLOK is found, R6 contains the RCHBLOK, */ /* R7 and R8 contain -1, and Condition Code 2 is set */ /* */ /* if no RDVBLOK is found, R6 contains the RCHBLOK, */ /* R7 contains the RCUBLOK and R8 contains -1, and */ /* condition code 1 is set */ /* */ /* If all 3 control blocks are found, R6 contains the */ /* the RCHBLOK, R7 Contains the RCUBLOK and R8 cont- */ /* ains the RDVBLOK. Condition code 0 is set */ /* */ /* If the instruction is sucesfull, control is */ /* returned at the address specified by GPR14. */ /* Otherwise, the next sequential instruction is */ /* executed, and no GPR or condition code is changed. */ /* */ /* Exceptions : */ /* Operation Exception : ECPS:VM Disabled */ /* Priviledged Exception : PSW in problem state */ /* */ /* Note : no access exception is generated for */ /* the second operand. */ /* */ /* Note : as of yet, for any other situation than */ /* finding all 3 control blocks, SCNRU acts */ /* as a NO-OP */ /******************************************************/ DEF_INST(ecpsvm_locate_rblock) { U32 chix; /* offset of RCH in RCH Array */ U32 cuix; /* Offset of RCU in RCU Array */ U32 dvix; /* Offset of RDV in RDV Array */ VADR rchixtbl; /* RCH Index Table */ VADR rchtbl; /* RCH Array */ VADR rcutbl; /* RCU Array */ VADR rdvtbl; /* RDV Array */ VADR arioct; /* Data list for SCNRU */ VADR rchblk; /* Effective RCHBLOK Address */ VADR rcublk; /* Effective RCUBLOK Address */ VADR rdvblk; /* Effective RDVBLOK Address */ U16 rdev; ECPSVM_PROLOG(SCNRU); /* Obtain the Device address */ rdev=(effective_addr1 & 0xfff); /* And the DMKRIO tables addresses */ arioct=effective_addr2; DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU called; RDEV=%4.4X ARIOCT=%6.6X\n"),effective_addr1,arioct)); /* Get the Channel Index Table */ rchixtbl= EVM_L(effective_addr2); /* Obtain the RCH offset */ chix=EVM_LH(rchixtbl+((rdev & 0xf00) >> 7)); DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RCH IX = %x\n"),chix)); /* Check if Bit 0 set (no RCH) */ if(chix & 0x8000) { // logmsg(_("HHCEV300D : ECPS:VM SCNRU : NO CHANNEL\n")); /* regs->GR_L(6)=~0; regs->GR_L(7)=~0; regs->GR_L(8)=~0; UPD_PSW_IA(regs, regs->GR_L(14)); regs->psw.cc=1; */ /* Right now, let CP handle the case */ return; } /* Obtain the RCH Table pointer */ rchtbl=EVM_L(arioct+4); /* Add the RCH Index offset */ rchblk=rchtbl+chix; /* Try to obtain RCU index with bits 8-12 of the device */ cuix=EVM_LH(rchblk+0x20+((rdev & 0xf8)>>2)); if(cuix & 0x8000) { /* Try with bits 8-11 */ cuix=EVM_LH(rchblk+0x20+((rdev & 0xf0)>>2)); if(cuix & 0x8000) { // logmsg(_("HHCEV300D : ECPS:VM SCNRU : NO CONTROL UNIT\n")); /* regs->GR_L(6)=rchblk; regs->GR_L(7)=~0; regs->GR_L(8)=~0; UPD_PSW_IA(regs, regs->GR_L(14)); regs->psw.cc=2; */ return; } } DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RCU IX = %x\n"),cuix)); rcutbl=EVM_L(arioct+8); rcublk=rcutbl+cuix; dvix=EVM_LH(rcublk+0x28+((rdev & 0x00f)<<1)); if(EVM_IC(rcublk+5)&0x40) { rcublk=EVM_L(rcublk+0x10); } if(dvix & 0x8000) { // logmsg(_("HHCEV300D : ECPS:VM SCNRU : NO RDEVBLOK\n")); /* regs->GR_L(6)=rchblk; regs->GR_L(7)=rcublk; regs->GR_L(8)=~0; UPD_PSW_IA(regs, regs->GR_L(14)); regs->psw.cc=3; */ return; } DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RDV IX = %x\n"),dvix)); dvix<<=3; rdvtbl=EVM_L(arioct+12); rdvblk=rdvtbl+dvix; DEBUG_CPASSISTX(SCNRU,logmsg(_("HHCEV300D : ECPS:VM SCNRU : RCH = %6.6X, RCU = %6.6X, RDV = %6.6X\n"),rchblk,rcublk,rdvblk)); regs->GR_L(6)=rchblk; regs->GR_L(7)=rcublk; regs->GR_L(8)=rdvblk; regs->psw.cc=0; regs->GR_L(15)=0; BR14; CPASSIST_HIT(SCNRU); } /* CCWGN : Not supported */ DEF_INST(ecpsvm_comm_ccwproc) { ECPSVM_PROLOG(CCWGN); } /* UXCCW : Not supported */ DEF_INST(ecpsvm_unxlate_ccw) { ECPSVM_PROLOG(UXCCW); } /* DISP2 : Not supported */ DEF_INST(ecpsvm_disp2) { ECPSVM_PROLOG(DISP2); switch(ecpsvm_do_disp2(regs,effective_addr1,effective_addr2)) { case 0: /* Done */ CPASSIST_HIT(DISP2); return; case 1: /* No-op */ return; case 2: /* Done */ CPASSIST_HIT(DISP2); RETURN_INTCHECK(regs); } return; } /* STEVL : Store ECPS:VM support level */ /* STEVL D1(R1,B1),D2(R2,B2) */ /* 1st operand : Fullword address in which to store ECPS:VM Support level */ /* 2nd operand : ignored */ DEF_INST(ecpsvm_store_level) { ECPSVM_PROLOG(STEVL); EVM_ST(sysblk.ecpsvm.level,effective_addr1); DEBUG_CPASSISTX(STEVL,logmsg(_("HHCEV300D : ECPS:VM STORE LEVEL %d called\n"),sysblk.ecpsvm.level)); CPASSIST_HIT(STEVL); } /* LCSPG : Locate Changed Shared Page */ /* LCSPG : Not supported */ DEF_INST(ecpsvm_loc_chgshrpg) { ECPSVM_PROLOG(LCSPG); } /*************************************************************/ /* FREEX : Allocate CP Storage Extended */ /* FREEX B1(R1,B1),D2(R2,B2) */ /* 1st operand : Address of FREEX Parameter list */ /* +0 : Maxsize = Max number of DW allocatable */ /* with FREEX */ /* +4- : Subpool index table */ /* 2nd operand : Subpool table (indexed) */ /* GPR 0 : Number of DWs to allocate */ /* */ /* Each allocatable block is forward chained */ /* if the subpool is empty, return to caller */ /* if the subpool has an entry, allocate from the subpool */ /* and save the next block address as the subpool chain head */ /* return allocated block in GPR1. return at address in GPR14*/ /* if allocation succeeded */ /* if allocate fails, return at next sequential instruction */ /*************************************************************/ DEF_INST(ecpsvm_extended_freex) { U32 maxdw; U32 numdw; U32 maxsztbl; U32 spixtbl; BYTE spix; U32 freeblock; U32 nextblk; ECPSVM_PROLOG(FREEX); numdw=regs->GR_L(0); spixtbl=effective_addr2; maxsztbl=effective_addr1; DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : ECPS:VM FREEX DW = %4.4X\n"),numdw)); if(numdw==0) { return; } DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : MAXSIZE ADDR = %6.6X, SUBPOOL INDEX TABLE = %6.6X\n"),maxsztbl,spixtbl)); /* E1 = @ of MAXSIZE (maximum # of DW allocatable by FREEX from subpools) */ /* followed by subpool pointers */ /* E2 = @ of subpool indices */ maxdw=EVM_L(maxsztbl); if(regs->GR_L(0)>maxdw) { DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : FREEX request beyond subpool capacity\n"))); return; } /* Fetch subpool index */ spix=EVM_IC(spixtbl+numdw); DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : Subpool index = %X\n"),spix)); /* Fetch value */ freeblock=EVM_L(maxsztbl+4+spix); DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : Value in subpool table = %6.6X\n"),freeblock)); if(freeblock==0) { /* Can't fullfill request here */ return; } nextblk=EVM_L(freeblock); EVM_ST(nextblk,maxsztbl+4+spix); DEBUG_CPASSISTX(FREEX,logmsg(_("HHCEV300D : New Value in subpool table = %6.6X\n"),nextblk)); regs->GR_L(1)=freeblock; regs->psw.cc=0; BR14; CPASSIST_HIT(FREEX); return; } /*************************************************************/ /* FRETX : Return CP Free storage */ /* FRETX D1(R1,B1),R2(D2,B2) */ /* 1st operand : Max DW for subpool free/fret */ /* 2nd Operand : FRET PLIST */ /* +0 Coretable address */ /* +4 CL4'FREE' */ /* +8 Maxsize (same as operand 1) */ /* +12 Subpool Table Index */ /* The block is checked VS the core table to check if it */ /* is eligible to be returned to the subpool chains */ /* If it is, then it is returned. Control is returned at */ /* the address in GPR 14. Otherwise, if anything cannot */ /* be resolved, control is returned at the next sequential */ /* Instruction */ /*************************************************************/ int ecpsvm_do_fretx(REGS *regs,VADR block,U16 numdw,VADR maxsztbl,VADR fretl) { U32 cortbl; U32 maxdw; U32 cortbe; /* Core table Page entry for fretted block */ U32 prevblk; BYTE spix; DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : X fretx called AREA=%6.6X, DW=%4.4X\n"),regs->GR_L(1),regs->GR_L(0))); if(numdw==0) { DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : DWORDS = 0\n"))); return(1); } maxdw=EVM_L(maxsztbl); if(numdw>maxdw) { DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : DWORDS = %d > MAXDW %d\n"),numdw,maxdw)); return(1); } cortbl=EVM_L(fretl); cortbe=cortbl+((block & 0xfff000)>>8); if(EVM_L(cortbe)!=EVM_L(fretl+4)) { DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : Area not in Core Free area\n"))); return(1); } if(EVM_IC(cortbe+8)!=0x02) { DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : Area flag != 0x02\n"))); return(1); } spix=EVM_IC(fretl+11+numdw); prevblk=EVM_L(maxsztbl+4+spix); if(prevblk==block) { DEBUG_CPASSISTX(FRETX,logmsg(_("HHCEV300D : ECPS:VM Cannot FRETX : fretted block already on subpool chain\n"))); return(1); } EVM_ST(block,maxsztbl+4+spix); EVM_ST(prevblk,block); return(0); } DEF_INST(ecpsvm_extended_fretx) { U32 fretl; U32 maxsztbl; U32 numdw; U32 block; ECPSVM_PROLOG(FRETX); numdw=regs->GR_L(0); block=regs->GR_L(1) & ADDRESS_MAXWRAP(regs); maxsztbl=effective_addr1 & ADDRESS_MAXWRAP(regs); fretl=effective_addr2 & ADDRESS_MAXWRAP(regs); if(ecpsvm_do_fretx(regs,block,numdw,maxsztbl,fretl)==0) { BR14; CPASSIST_HIT(FRETX); } return; } DEF_INST(ecpsvm_prefmach_assist) { ECPSVM_PROLOG(PMASS); } /**********************************/ /* VM ASSISTS */ /**********************************/ /******************************************************************/ /* LPSW/SSM/STxSM : */ /* Not sure about the current processing .. */ /* *MAYBE* we need to invoke DMKDSPCH when the newly loaded PSW */ /* does not need further checking. Now.. I wonder what the point */ /* is to return to CP anyway, as we have entirelly validated the */ /* new PSW (i.e. for most of it, this is essentially a BRANCH */ /* However... */ /* Maybe we should call DMKDSPCH (from the DMKPRVMA list) */ /* only if re-enabling bits (and no Int pending) */ /* */ /* For the time being, we do THIS : */ /* If the new PSW 'disables' bits or enables bit but MICPEND=0 */ /* we just update the VPSW and continue */ /* Same for LPSW.. But we also update the IA */ /* If we encounter ANY issue, we just return to caller (which will*/ /* generate a PRIVOP) thus invoking CP like for non-EVMA */ /******************************************************************/ /******************************************************************/ /* Check psw Transition validity */ /******************************************************************/ /* NOTE : oldr/newr Only have the PSW field valid (the rest is not initialised) */ int ecpsvm_check_pswtrans(REGS *regs,ECPSVM_MICBLOK *micblok, BYTE micpend, REGS *oldr, REGS *newr) { UNREFERENCED(micblok); UNREFERENCED(regs); SET_PSW_IA(newr); SET_PSW_IA(oldr); /* Check for a switch from BC->EC or EC->BC */ if(ECMODE(&oldr->psw)!=ECMODE(&newr->psw)) { DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New and Old PSW have a EC/BC transition\n"))); return(1); } /* Check if PER or DAT is being changed */ if(ECMODE(&newr->psw)) { if((newr->psw.sysmask & 0x44) != (oldr->psw.sysmask & 0x44)) { DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW Enables DAT or PER\n"))); return(1); } } /* Check if a Virtual interrupt is pending and new interrupts are being enabled */ if(micpend & 0x80) { if(ECMODE(&newr->psw)) { if(((~oldr->psw.sysmask) & 0x03) & newr->psw.sysmask) { DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW Enables interrupts and MICPEND (EC)\n"))); return(1); } } else { if(~oldr->psw.sysmask & newr->psw.sysmask) { DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW Enables interrupts and MICPEND (BC)\n"))); return(1); } } } if(WAITSTATE(&newr->psw)) { DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW is a WAIT PSW\n"))); return(1); } if(ECMODE(&newr->psw)) { if(newr->psw.sysmask & 0xb8) { DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW sysmask incorrect\n"))); return(1); } } if(newr->psw.IA & 0x01) { DEBUG_SASSISTX(LPSW,logmsg(_("HHCEV300D : New PSW has ODD IA\n"))); return(1); } return(0); } int ecpsvm_dossm(REGS *regs,int b2,VADR effective_addr2) { BYTE reqmask; BYTE *cregs; U32 creg0; REGS npregs; SASSIST_PROLOG(SSM); /* Reject if V PSW is in problem state */ if(CR6 & ECPSVM_CR6_VIRTPROB) { DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM reject : V PB State\n")); return(1); } /* if(!(micevma & MICSTSM)) { DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM reject : SSM Disabled in MICEVMA; EVMA=%2.2X\n",micevma)); return(1); } */ /* Get CR0 - set ref bit on fetched CR0 (already done in prolog for MICBLOK) */ cregs=MADDR(micblok.MICCREG,USE_REAL_ADDR,regs,ACCTYPE_READ,0); FETCH_FW(creg0,cregs); /* Reject if V CR0 specifies SSM Suppression */ if(creg0 & 0x40000000) { DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM reject : V SSM Suppr\n")); return(1); } /* Load the requested SSM Mask */ /* USE Normal vfetchb here ! not only do we want tranlsation */ /* but also fetch protection control, ref bit, etc.. */ reqmask=ARCH_DEP(vfetchb) (effective_addr2,b2,regs); INITPSEUDOREGS(npregs); /* Load the virtual PSW AGAIN in a new structure */ ARCH_DEP(load_psw) (&npregs,vpswa_p); npregs.psw.sysmask=reqmask; if(ecpsvm_check_pswtrans(regs,&micblok,micpend,&vpregs,&npregs)) /* Check PSW transition capability */ { DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM Reject : New PSW too complex\n")); return(1); /* Something in the NEW PSW we can't handle.. let CP do it */ } /* While we are at it, set the IA in the V PSW */ SET_PSW_IA(regs); UPD_PSW_IA(&npregs, regs->psw.IA); /* Set the change bit */ MADDR(vpswa,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0); /* store the new PSW */ ARCH_DEP(store_psw) (&npregs,vpswa_p); DEBUG_SASSISTX(SSM,logmsg("HHCEV300D : SASSIST SSM Complete : new SM = %2.2X\n",reqmask)); DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST SSM New VIRT ")); DEBUG_SASSISTX(LPSW,display_psw(&npregs)); DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST SSM New REAL ")); DEBUG_SASSISTX(LPSW,display_psw(regs)); SASSIST_HIT(SSM); return(0); } int ecpsvm_dosvc(REGS *regs,int svccode) { PSA_3XX *psa; REGS newr; SASSIST_PROLOG(SVC); if(svccode==76) /* NEVER trap SVC 76 */ { DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Reject : SVC 76\n")); return(1); } if(CR6 & ECPSVM_CR6_SVCINHIB) { DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Reject : SVC Assist Inhibit\n")); return(1); /* SVC SASSIST INHIBIT ON */ } /* Get what the NEW PSW should be */ psa=(PSA_3XX *)MADDR((VADR)0 , USE_PRIMARY_SPACE, regs, ACCTYPE_READ, 0); /* Use all around access key 0 */ /* Also sets reference bit */ INITPSEUDOREGS(newr); ARCH_DEP(load_psw) (&newr, (BYTE *)&psa->svcnew); /* Ref bit set above */ DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC NEW VIRT ")); DEBUG_SASSISTX(SVC,display_psw(&newr)); /* Get some stuff from the REAL Running PSW to put in OLD SVC PSW */ SET_PSW_IA(regs); UPD_PSW_IA(&vpregs, regs->psw.IA); /* Instruction Address */ vpregs.psw.cc=regs->psw.cc; /* Condition Code */ vpregs.psw.pkey=regs->psw.pkey; /* Protection Key */ vpregs.psw.progmask=regs->psw.progmask; /* Program Mask */ vpregs.psw.intcode=svccode; /* SVC Interrupt code */ DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC OLD VIRT ")); DEBUG_SASSISTX(SVC,display_psw(&vpregs)); if(ecpsvm_check_pswtrans(regs,&micblok,micpend,&vpregs,&newr)) /* Check PSW transition capability */ { DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Reject : Cannot make transition to new PSW\n")); return(1); /* Something in the NEW PSW we can't handle.. let CP do it */ } /* Store the OLD SVC PSW */ // ZZ psa=(PSA_3XX *)MADDR((VADR)0, USE_PRIMARY_SPACE, regs, ACCTYPE_WRITE, 0); /* Use all around access key 0 */ /* Also sets change bit */ /* Set intcode in PSW (for BC mode) */ ARCH_DEP(store_psw) (&vpregs, (BYTE *)&psa->svcold); if(ECMODE(&vpregs.psw)) { /* Also set SVC interrupt code */ /* and ILC */ STORE_FW((BYTE *)&psa->svcint,0x00020000 | svccode); } /* * Now, update some stuff in the REAL PSW */ SASSIST_LPSW(newr); /* * Now store the new PSW in the area pointed by the MICBLOK */ ARCH_DEP(store_psw) (&newr,vpswa_p); DEBUG_SASSISTX(SVC,logmsg("HHCEV300D : SASSIST SVC Done\n")); SASSIST_HIT(SVC); return(0); } /* LPSW Assist */ int ecpsvm_dolpsw(REGS *regs,int b2,VADR e2) { BYTE * nlpsw; REGS nregs; SASSIST_PROLOG(LPSW); /* Reject if V PSW is in problem state */ if(CR6 & ECPSVM_CR6_VIRTPROB) { DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW reject : V PB State\n")); return(1); } /* Reject if MICEVMA says not to do LPSW sim */ if(!(micevma & MICLPSW)) { DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW reject : LPSW disabled in MICEVMA\n")); return(1); } if(e2&0x03) { DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW %6.6X - Alignement error\n",e2)); return(1); } nlpsw=MADDR(e2,b2,regs,ACCTYPE_READ,regs->psw.pkey); INITPSEUDOREGS(nregs); ARCH_DEP(load_psw) (&nregs,nlpsw); if(ecpsvm_check_pswtrans(regs,&micblok,micpend,&vpregs,&nregs)) { DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW Rejected - Cannot make PSW transition\n")); return(1); } SASSIST_LPSW(nregs); MADDR(vpswa,USE_REAL_ADDR,regs,ACCTYPE_WRITE,0); /* Set ref bit in address pointed by MICBLOK */ ARCH_DEP(store_psw) (&nregs,vpswa_p); DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW New VIRT ")); DEBUG_SASSISTX(LPSW,display_psw(&nregs)); DEBUG_SASSISTX(LPSW,logmsg("HHCEV300D : SASSIST LPSW New REAL ")); DEBUG_SASSISTX(LPSW,display_psw(regs)); SASSIST_HIT(LPSW); return(0); } int ecpsvm_virttmr_ext(REGS *regs) { DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Checking if we can IRPT\n")); DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Virtual")); DEBUG_SASSISTX(VTIMER,display_psw(regs)); if(IS_IC_ECPSVTIMER(regs)) { DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Not pending\n")); return(1); } if(!PROBSTATE(®s->psw)) { DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Not dispatching a VM\n")); return(1); } if(!(regs->psw.sysmask & PSW_EXTMASK)) { DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Test int : Not enabled for EXT\n")); return(1); } if(!(regs->CR_L(6) & ECPSVM_CR6_VIRTTIMR)) { DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Test int : Not enabled for VTIMER\n")); return(1); } DEBUG_SASSISTX(VTIMER,logmsg("HHCEV300D : SASSIST VTIMER Please, do\n")); return(0); } /* SIO/SIOF Assist */ int ecpsvm_dosio(REGS *regs,int b2,VADR e2) { SASSIST_PROLOG(SIO); UNREFERENCED(b2); UNREFERENCED(e2); return(1); } int ecpsvm_dostnsm(REGS *regs,int b1,VADR effective_addr1,int imm2) { SASSIST_PROLOG(STNSM); UNREFERENCED(b1); UNREFERENCED(effective_addr1); UNREFERENCED(imm2); return(1); } int ecpsvm_dostosm(REGS *regs,int b1,VADR effective_addr1,int imm2) { SASSIST_PROLOG(STOSM); UNREFERENCED(b1); UNREFERENCED(effective_addr1); UNREFERENCED(imm2); return(1); } int ecpsvm_dostctl(REGS *regs,int r1,int r3,int b2,VADR effective_addr2) { SASSIST_PROLOG(STCTL); UNREFERENCED(r1); UNREFERENCED(r3); UNREFERENCED(b2); UNREFERENCED(effective_addr2); return(1); } int ecpsvm_dolctl(REGS *regs,int r1,int r3,int b2,VADR effective_addr2) { U32 crs[16]; /* New CRs */ U32 rcrs[16]; /* REAL CRs */ U32 ocrs[16]; /* Old CRs */ BYTE *ecb_p; VADR F_ECBLOK,vmb; BYTE B_VMPSTAT; int i,j,numcrs; SASSIST_PROLOG(LCTL); if(effective_addr2 & 0x03) { DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : Not aligned\n")); return(1); } vmb=vpswa-0xA8; B_VMPSTAT=EVM_IC(vmb+VMPSTAT); if((!(B_VMPSTAT & VMV370R)) && ((r1!=r3) || (r1!=0))) { DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : BC Mode VM & LCTL != 0,0\n")); return(1); } /* Determine the range of CRs to be loaded */ if(r1>r3) { numcrs=(r3+16)-r1; } else { numcrs=r3-r1; } numcrs++; for(j=r1,i=0;i15) { j-=16; } crs[j]=ARCH_DEP(vfetch4)((effective_addr2+(i*4)) & ADDRESS_MAXWRAP(regs),b2,regs); } if(B_VMPSTAT & VMV370R) { F_ECBLOK=fetch_fw(regs->mainstor+vmb+VMECEXT); for(i=0;i<16;i++) { ecb_p=MADDR(F_ECBLOK+(i*4),USE_REAL_ADDR,regs,ACCTYPE_READ,0); ocrs[i]=fetch_fw(ecb_p); } } else { F_ECBLOK=vmb+VMECEXT; /* Update ECBLOK ADDRESS for VCR0 Update */ ecb_p=MADDR(F_ECBLOK,USE_REAL_ADDR,regs,ACCTYPE_READ,0); /* Load OLD CR0 From VMBLOK */ ocrs[0]=fetch_fw(ecb_p); } for(i=0;i<16;i++) { rcrs[i]=regs->CR_L(i); } /* Source safely loaded into "crs" array */ /* Load the CRS - exit from loop if it's not possible */ DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL %d,%d : Modifying %d cregs\n",r1,r3,numcrs)); for(j=r1,i=0;i15) { j-=16; } switch(j) { case 0: /* CR0 Case */ /* Check 1st 2 bytes of CR0 - No change allowed */ if((ocrs[0] & 0xffff0000) != (crs[0] & 0xffff0000)) { DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR0 High changed\n")); return 1; } /* Not allowed if : NEW mask is being enabled AND MICPEND AND PSW has EXT enabled */ if(vpregs.psw.sysmask & 0x01) { if(micpend & 0x80) { if((~(ocrs[0] & 0xffff)) & (crs[0] & 0xffff)) { DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR0 EXTSM Enables new EXTS\n")); return 1; } } } ocrs[0]=crs[0]; break; case 1: if(ocrs[1] != crs[1]) { DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR1 Updates shadow table\n")); return 1; } break; case 2: /* Not allowed if : NEW Channel mask is turned on AND micpend AND PSW Extended I/O Mask is on */ if(vpregs.psw.sysmask & 0x02) { if((~ocrs[2]) & crs[2]) { if(micpend & 0x80) { DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : CR2 IOCSM Enables I/O Ints\n")); return(1); } } } ocrs[2]=crs[2]; break; case 3: /* DAS Control regs (not used under VM/370) */ case 4: case 5: case 7: ocrs[j]=crs[j]; rcrs[j]=crs[j]; break; case 6: /* VCR6 Ignored on real machine */ ocrs[j]=crs[j]; break; case 8: /* Monitor Calls */ DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : MC CR8 Update\n")); return(1); case 9: /* PER Control Regs */ case 10: case 11: DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL Reject : PER CR%d Update\n",j)); return(1); case 12: case 13: /* 12-13 : Unused */ ocrs[j]=crs[j]; rcrs[j]=crs[j]; break; case 14: case 15: /* 14-15 Machine Check & I/O Logout control (plus DAS) */ ocrs[j]=crs[j]; break; default: break; } } /* Update REAL Control regs */ for(i=0;i<16;i++) { regs->CR_L(i)=rcrs[i]; } /* Update ECBLOK/VMBLOK Control regs */ /* Note : if F_ECBLOK addresses VMVCR0 in the VMBLOCK */ /* check has already been done to make sure */ /* r1=0 and numcrs=1 */ for(j=r1,i=0;i15) { j-=16; } ecb_p=MADDR(F_ECBLOK+(j*4),USE_REAL_ADDR,regs,ACCTYPE_WRITE,0); store_fw(ecb_p,ocrs[j]); } DEBUG_SASSISTX(LCTL,logmsg("HHCEV300D : SASSIST LCTL %d,%d Done\n",r1,r3)); SASSIST_HIT(LCTL); return 0; } int ecpsvm_doiucv(REGS *regs,int b2,VADR effective_addr2) { SASSIST_PROLOG(IUCV); UNREFERENCED(b2); UNREFERENCED(effective_addr2); return(1); } int ecpsvm_dodiag(REGS *regs,int r1,int r3,int b2,VADR effective_addr2) { SASSIST_PROLOG(DIAG); UNREFERENCED(r1); UNREFERENCED(r3); UNREFERENCED(b2); UNREFERENCED(effective_addr2); return(1); } static char *ecpsvm_stat_sep="HHCEV003I +-----------+----------+----------+-------+\n"; static int ecpsvm_sortstats(const void *a,const void *b) { ECPSVM_STAT *ea,*eb; ea=(ECPSVM_STAT *)a; eb=(ECPSVM_STAT *)b; return(eb->call-ea->call); } static void ecpsvm_showstats2(ECPSVM_STAT *ar,size_t count) { char *sep=ecpsvm_stat_sep; char nname[32]; int havedisp=0; int notshown=0; size_t unsupcc=0; int haveunsup=0; int callt=0; int hitt=0; size_t i; for(i=0;iname)==0) { *fclass="VM ASSIST"; return(es); } } esl=(ECPSVM_STAT *)&ecpsvm_cpstats; fcount=sizeof(ecpsvm_cpstats)/sizeof(ECPSVM_STAT); for(i=0;iname)==0) { *fclass="CP ASSIST"; return(es); } } return(NULL); } void ecpsvm_enadisaall(char *fclass,ECPSVM_STAT *tbl,size_t count,int onoff,int debug) { ECPSVM_STAT *es; size_t i; char *enadisa,*debugonoff; enadisa=onoff?"Enabled":"Disabled"; debugonoff=debug?"On":"Off"; for(i=0;i=0) { es->enabled=onoff; logmsg(_("HHCEV015I ECPS:VM %s feature %s %s\n"),fclass,es->name,enadisa); } if(debug>=0) { es->debug=debug; logmsg(_("HHCEV015I ECPS:VM %s feature %s Debug %s\n"),fclass,es->name,debugonoff); } } if(onoff>=0) { logmsg(_("HHCEV016I All ECPS:VM %s features %s\n"),fclass,enadisa); } if(debug>=0) { logmsg(_("HHCEV016I All ECPS:VM %s features Debug %s\n"),fclass,debugonoff); } } void ecpsvm_enable_disable(int ac,char **av,int onoff,int debug) { char *fclass; char *enadisa,*debugonoff; int i; size_t sacount,cpcount; ECPSVM_STAT *es; ECPSVM_STAT *sal,*cpl; sal=(ECPSVM_STAT *)&ecpsvm_sastats; cpl=(ECPSVM_STAT *)&ecpsvm_cpstats; sacount=sizeof(ecpsvm_sastats)/sizeof(ECPSVM_STAT); cpcount=sizeof(ecpsvm_cpstats)/sizeof(ECPSVM_STAT); enadisa=onoff?"Enabled":"Disabled"; debugonoff=debug?"On":"Off"; if(ac==1) { ecpsvm_enadisaall("VM ASSIST",sal,sacount,onoff,debug); ecpsvm_enadisaall("CP ASSIST",cpl,cpcount,onoff,debug); if(debug>=0) { sysblk.ecpsvm.debug=debug; logmsg(_("HHCEV013I ECPS:VM Global Debug %s\n"),debugonoff); } return; } for(i=1;i=0) { es->enabled=onoff; logmsg(_("HHCEV014I ECPS:VM %s feature %s %s\n"),fclass,es->name,enadisa); } if(debug>=0) { es->debug=onoff; logmsg(_("HHCEV014I ECPS:VM %s feature %s Debug %s\n"),fclass,es->name,debugonoff); } } else { logmsg(_("HHCEV014I Unknown ECPS:VM feature %s; Ignored\n"),av[i]); } } } void ecpsvm_disable(int ac,char **av) { ecpsvm_enable_disable(ac,av,0,-1); } void ecpsvm_enable(int ac,char **av) { ecpsvm_enable_disable(ac,av,1,-1); } void ecpsvm_debug(int ac,char **av) { ecpsvm_enable_disable(ac,av,-1,1); } void ecpsvm_nodebug(int ac,char **av) { ecpsvm_enable_disable(ac,av,-1,0); } void ecpsvm_level(int ac,char **av) { int lvl; if(sysblk.ecpsvm.available) { logmsg(_("HHCEV016I Current reported ECPS:VM Level is %d\n"),sysblk.ecpsvm.level); } else { logmsg(_("HHCEV016I Current reported ECPS:VM Level is %d\n"),sysblk.ecpsvm.level); logmsg(_("HHCEV017I But ECPS:VM is currently disabled\n")); } if(ac>1) { lvl=atoi(av[1]); logmsg(_("HHCEV016I Level reported to guest program is now %d\n"),lvl); sysblk.ecpsvm.level=lvl; } if(sysblk.ecpsvm.level!=20) { logmsg(_("HHCEV017W WARNING ! current level (%d) is not supported\n"),sysblk.ecpsvm.level); logmsg(_("HHCEV018W WARNING ! Unpredictable results may occur\n")); logmsg(_("HHCEV019I The microcode support level is 20\n")); } } static void ecpsvm_helpcmd(int,char **); static ECPSVM_CMDENT ecpsvm_cmdtab[]={ {"Help",1,ecpsvm_helpcmd,"Show help","format : \"evm help [cmd]\" Shows help on the specified\n" " ECPSVM subcommand\n"}, {"STats",2,ecpsvm_showstats,"Show statistical counters","format : evm stats : Shows various ECPS:VM Counters\n"}, {"DIsable",2,ecpsvm_disable,"Disable ECPS:VM Features","format : evm disable [ALL|feat1[ feat2|...]\n"}, {"ENable",2,ecpsvm_enable,"Enable ECPS:VM Features","format : evm enable [ALL|feat1[ feat2|...]\n"}, #if defined(DEBUG_SASSIST) || defined(DEBUG_CPASSIST) {"DEBUG",5,ecpsvm_debug,"Debug ECPS:VM Features","format : evm debug [ALL|feat1[ feat2|...]\n"}, {"NODebug",3,ecpsvm_nodebug,"Turn Debug off for ECPS:VM Features","format : evm NODebug [ALL|feat1[ feat2|...]\n"}, #endif {"Level",1,ecpsvm_level,"Set/Show ECPS:VM level","format : evm Level [nn]\n"}, {NULL,0,NULL,NULL,NULL}}; static void ecpsvm_helpcmdlist(void) { int i; ECPSVM_CMDENT *ce; for(i=0;ecpsvm_cmdtab[i].name;i++) { ce=&ecpsvm_cmdtab[i]; logmsg(_("HHCEV010I : %s : %s\n"),ce->name,ce->expl); } return; } void ecpsvm_helpcmd(int ac,char **av) { ECPSVM_CMDENT *ce; if(ac==1) { ecpsvm_helpcmdlist(); return; } ce=ecpsvm_getcmdent(av[1]); if(ce==NULL) { logmsg(_("HHCEV011E Unknown subcommand %s - valid subcommands are :\n"),av[1]); ecpsvm_helpcmdlist(); return; } logmsg(_("HHCEV012I : %s : %s"),ce->name,ce->help); return; } ECPSVM_CMDENT *ecpsvm_getcmdent(char *cmd) { ECPSVM_CMDENT *ce; int i; int clen; for(i=0;ecpsvm_cmdtab[i].name;i++) { ce=&ecpsvm_cmdtab[i]; if(strlen(cmd)<=strlen(ce->name) && strlen(cmd)>=(size_t)ce->abbrev) { clen=strlen(cmd); if(strncasecmp(cmd,ce->name,clen)==0) { return(ce); } } } return(NULL); } void ecpsvm_command(int ac,char **av) { ECPSVM_CMDENT *ce; logmsg(_("HHCEV011I ECPS:VM Command processor invoked\n")); if(ac==1) { logmsg(_("HHCEV008E NO EVM subcommand. Type \"evm help\" for a list of valid subcommands\n")); return; } ce=ecpsvm_getcmdent(av[1]); if(ce==NULL) { logmsg(_("HHCEV008E Unknown EVM subcommand %s\n"),av[1]); return; } ce->fun(ac-1,av+1); logmsg(_("HHCEV011I ECPS:VM Command processor complete\n")); } #endif /* ifdef FEATURE_ECPSVM */ /* Note : The following forces inclusion for S/390 & z/ARCH */ /* This is necessary just in order to properly define */ /* S/390 auxialiary routines invoked by S/370 routines */ /* because of SIE */ #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "ecpsvm.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "ecpsvm.c" #endif #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/fthreads.c0000664000175000017500000016526412564723224012165 00000000000000/* FTHREADS.C (c) Copyright "Fish" (David B. Trout), 2001-2009 */ /* Fish's WIN32 version of pthreads */ //////////////////////////////////////////////////////////////////////////////////// // (c) Copyright "Fish" (David B. Trout), 2001-2009. Released under the Q Public License // (http://www.hercules-390.org/herclic.html) as modifications to Hercules. //////////////////////////////////////////////////////////////////////////////////// #include "hstdinc.h" #define _FTHREADS_C_ #define _HUTIL_DLL_ #include "hercules.h" #include "fthreads.h" #if defined(OPTION_FTHREADS) //////////////////////////////////////////////////////////////////////////////////// // Private internal fthreads structures... typedef struct _tagFT_MUTEX // fthread "mutex" structure { CRITICAL_SECTION MutexLock; // (lock for accessing this data) DWORD dwMutexMagic; // (magic number) HANDLE hUnlockedEvent; // (signalled while NOT locked) DWORD dwMutexType; // (type of mutex (normal, etc)) DWORD dwLockOwner; // (thread-id of who owns it) int nLockedCount; // (#of times lock acquired) } FT_MUTEX, *PFT_MUTEX; typedef struct _tagFT_COND_VAR // fthread "condition variable" structure { CRITICAL_SECTION CondVarLock; // (lock for accessing this data) DWORD dwCondMagic; // (magic number) HANDLE hSigXmitEvent; // set during signal transmission HANDLE hSigRecvdEvent; // set once signal received by every- // one that's supposed to receive it. BOOL bBroadcastSig; // TRUE = "broadcast", FALSE = "signal" int nNumWaiting; // #of threads waiting to receive signal } FT_COND_VAR, *PFT_COND_VAR; //////////////////////////////////////////////////////////////////////////////////// // So we can tell whether our structures have been properly initialized or not... #define FT_MUTEX_MAGIC 0x4D767478 // "Mutx" in ASCII #define FT_COND_MAGIC 0x436F6E64 // "Cond" in ASCII #define FT_ATTR_MAGIC 0x41747472 // "Attr" in ASCII //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // Private internal fthreads functions... static BOOL IsValidMutexType ( DWORD dwMutexType ) { return (0 // || FTHREAD_MUTEX_DEFAULT == dwMutexType // (FTHREAD_MUTEX_RECURSIVE) || FTHREAD_MUTEX_RECURSIVE == dwMutexType || FTHREAD_MUTEX_ERRORCHECK == dwMutexType // || FTHREAD_MUTEX_NORMAL == dwMutexType // (not currently supported) ); } //////////////////////////////////////////////////////////////////////////////////// static FT_MUTEX* MallocFT_MUTEX ( ) { FT_MUTEX* pFT_MUTEX = (FT_MUTEX*) malloc ( sizeof ( FT_MUTEX ) ); if ( !pFT_MUTEX ) return NULL; memset ( pFT_MUTEX, 0xCD, sizeof ( FT_MUTEX ) ); return pFT_MUTEX; } //////////////////////////////////////////////////////////////////////////////////// static BOOL InitializeFT_MUTEX ( FT_MUTEX* pFT_MUTEX, DWORD dwMutexType ) { // Note: UnlockedEvent created initially signalled if ( !(pFT_MUTEX->hUnlockedEvent = MyCreateEvent ( NULL, TRUE, TRUE, NULL )) ) { memset ( pFT_MUTEX, 0xCD, sizeof ( FT_MUTEX ) ); return FALSE; } MyInitializeCriticalSection ( &pFT_MUTEX->MutexLock ); pFT_MUTEX->dwMutexMagic = FT_MUTEX_MAGIC; pFT_MUTEX->dwMutexType = dwMutexType; pFT_MUTEX->dwLockOwner = 0; pFT_MUTEX->nLockedCount = 0; return TRUE; } //////////////////////////////////////////////////////////////////////////////////// static BOOL UninitializeFT_MUTEX ( FT_MUTEX* pFT_MUTEX ) { if ( pFT_MUTEX->nLockedCount > 0 ) return FALSE; // (still in use) ASSERT( IsEventSet ( pFT_MUTEX->hUnlockedEvent ) ); MyDeleteEvent ( pFT_MUTEX->hUnlockedEvent ); MyDeleteCriticalSection ( &pFT_MUTEX->MutexLock ); memset ( pFT_MUTEX, 0xCD, sizeof ( FT_MUTEX ) ); return TRUE; } //////////////////////////////////////////////////////////////////////////////////// static FT_COND_VAR* MallocFT_COND_VAR ( ) { FT_COND_VAR* pFT_COND_VAR = (FT_COND_VAR*) malloc ( sizeof ( FT_COND_VAR ) ); if ( !pFT_COND_VAR ) return NULL; memset ( pFT_COND_VAR, 0xCD, sizeof ( FT_COND_VAR ) ); return pFT_COND_VAR; } //////////////////////////////////////////////////////////////////////////////////// static BOOL InitializeFT_COND_VAR ( FT_COND_VAR* pFT_COND_VAR ) { if ( ( pFT_COND_VAR->hSigXmitEvent = MyCreateEvent ( NULL, TRUE, FALSE, NULL ) ) ) { // Note: hSigRecvdEvent created initially signaled if ( ( pFT_COND_VAR->hSigRecvdEvent = MyCreateEvent ( NULL, TRUE, TRUE, NULL ) ) ) { MyInitializeCriticalSection ( &pFT_COND_VAR->CondVarLock ); pFT_COND_VAR->dwCondMagic = FT_COND_MAGIC; pFT_COND_VAR->bBroadcastSig = FALSE; pFT_COND_VAR->nNumWaiting = 0; return TRUE; } MyDeleteEvent ( pFT_COND_VAR->hSigXmitEvent ); } memset ( pFT_COND_VAR, 0xCD, sizeof ( FT_COND_VAR ) ); return FALSE; } //////////////////////////////////////////////////////////////////////////////////// static BOOL UninitializeFT_COND_VAR ( FT_COND_VAR* pFT_COND_VAR ) { if (0 || pFT_COND_VAR->nNumWaiting || IsEventSet ( pFT_COND_VAR->hSigXmitEvent ) || !IsEventSet ( pFT_COND_VAR->hSigRecvdEvent ) ) return FALSE; MyDeleteEvent ( pFT_COND_VAR->hSigXmitEvent ); MyDeleteEvent ( pFT_COND_VAR->hSigRecvdEvent ); MyDeleteCriticalSection ( &pFT_COND_VAR->CondVarLock ); memset ( pFT_COND_VAR, 0xCD, sizeof ( FT_COND_VAR ) ); return TRUE; } //////////////////////////////////////////////////////////////////////////////////// static BOOL TryEnterFT_MUTEX ( FT_MUTEX* pFT_MUTEX ) { BOOL bSuccess; DWORD dwThreadId = GetCurrentThreadId(); if ( hostinfo.trycritsec_avail ) { bSuccess = MyTryEnterCriticalSection ( &pFT_MUTEX->MutexLock ); if ( bSuccess ) { pFT_MUTEX->nLockedCount++; ASSERT( pFT_MUTEX->nLockedCount > 0 ); pFT_MUTEX->dwLockOwner = dwThreadId; } } else { MyEnterCriticalSection ( &pFT_MUTEX->MutexLock ); ASSERT ( pFT_MUTEX->nLockedCount >= 0 ); bSuccess = ( pFT_MUTEX->nLockedCount <= 0 || pFT_MUTEX->dwLockOwner == dwThreadId ); if ( bSuccess ) { pFT_MUTEX->nLockedCount++; ASSERT ( pFT_MUTEX->nLockedCount > 0 ); pFT_MUTEX->dwLockOwner = dwThreadId; MyResetEvent ( pFT_MUTEX->hUnlockedEvent ); } MyLeaveCriticalSection ( &pFT_MUTEX->MutexLock ); } return bSuccess; } //////////////////////////////////////////////////////////////////////////////////// static void EnterFT_MUTEX ( FT_MUTEX* pFT_MUTEX ) { DWORD dwThreadId = GetCurrentThreadId(); if ( hostinfo.trycritsec_avail ) { MyEnterCriticalSection ( &pFT_MUTEX->MutexLock ); pFT_MUTEX->dwLockOwner = dwThreadId; pFT_MUTEX->nLockedCount++; ASSERT ( pFT_MUTEX->nLockedCount > 0 ); } else { for (;;) { MyEnterCriticalSection ( &pFT_MUTEX->MutexLock ); ASSERT ( pFT_MUTEX->nLockedCount >= 0 ); if ( pFT_MUTEX->nLockedCount <= 0 || pFT_MUTEX->dwLockOwner == dwThreadId ) break; MyLeaveCriticalSection ( &pFT_MUTEX->MutexLock ); MyWaitForSingleObject ( pFT_MUTEX->hUnlockedEvent, INFINITE ); } MyResetEvent ( pFT_MUTEX->hUnlockedEvent ); pFT_MUTEX->dwLockOwner = dwThreadId; pFT_MUTEX->nLockedCount++; ASSERT ( pFT_MUTEX->nLockedCount > 0 ); MyLeaveCriticalSection ( &pFT_MUTEX->MutexLock ); } } //////////////////////////////////////////////////////////////////////////////////// static void LeaveFT_MUTEX ( FT_MUTEX* pFT_MUTEX ) { if ( hostinfo.trycritsec_avail ) { ASSERT ( pFT_MUTEX->nLockedCount > 0 ); pFT_MUTEX->nLockedCount--; if ( pFT_MUTEX->nLockedCount <= 0 ) pFT_MUTEX->dwLockOwner = 0; MyLeaveCriticalSection ( &pFT_MUTEX->MutexLock ); } else { MyEnterCriticalSection ( &pFT_MUTEX->MutexLock ); ASSERT ( pFT_MUTEX->nLockedCount > 0 ); pFT_MUTEX->nLockedCount--; if ( pFT_MUTEX->nLockedCount <= 0 ) { pFT_MUTEX->dwLockOwner = 0; MySetEvent ( pFT_MUTEX->hUnlockedEvent ); } MyLeaveCriticalSection ( &pFT_MUTEX->MutexLock ); } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // Now we get to the "meat" of fthreads... // // The below function atomically releases the caller's mutex and registers the fact // that the caller wishes to wait on their condition variable (or rather the other // way around: it first registers the fact that the caller wishes to wait on the // condition by first acquiring the condition variable lock and then registering // the wait and THEN afterwards (once the wait has been registered and condition // variable lock acquired) releases the original mutex). This ensures that no one // can "sneak a signal past us" from the time this function is called until we can // manage to register the wait request since no signals can ever be sent while the // condition variable is locked. static int BeginWait ( FT_COND_VAR* pFT_COND_VAR, fthread_mutex_t* pFTUSER_MUTEX ) { int rc; FT_MUTEX* pFT_MUTEX; if (0 || !pFT_COND_VAR // (invalid ptr) || pFT_COND_VAR -> dwCondMagic != FT_COND_MAGIC // (not initialized) || !pFTUSER_MUTEX // (invalid ptr) || pFTUSER_MUTEX-> dwMutexMagic != FT_MUTEX_MAGIC // (not initialized) || !(pFT_MUTEX = pFTUSER_MUTEX->hMutex) // (invalid ptr) // || !pFT_MUTEX // (invalid ptr) || pFT_MUTEX -> dwMutexMagic != FT_MUTEX_MAGIC // (not initialized) ) return RC(EINVAL); if (0 || pFT_MUTEX -> dwLockOwner != GetCurrentThreadId() // (mutex not owned) || pFT_MUTEX -> nLockedCount <= 0 // (mutex not locked) ) return RC(EPERM); // First, acquire the fthreads condition variable lock... for (;;) { MyEnterCriticalSection ( &pFT_COND_VAR->CondVarLock ); // It is always safe to proceed if the prior signal was completely // processed (received by everyone who was supposed to receive it) if ( IsEventSet ( pFT_COND_VAR->hSigRecvdEvent ) ) break; // Prior signal not completely received yet... Verify that it is // still being transmitted... ASSERT ( IsEventSet ( pFT_COND_VAR->hSigXmitEvent ) ); // If no one is currently waiting to receive [this signal not yet // completely received and still being transmitted], then we can // go ahead and receive it right now *regardless* of what type of // signal it is ("signal" or "broadcast") since we're *obviously* // the one who is supposed to receive it (since we ARE trying to // wait on it after all and it IS being transmitted. The 'xmit' // event is *always* turned off once everyone [who is *supposed* // to receive the signal] *has* received the signal. Thus, since // it's still being transmitted, that means *not* everyone who // *should* receive it *has* received it yet, and thus we can be // absolutely certain that we indeed *should* therefore receive it // since we *are* after all waiting for it). // Otherwise (prior signal not completely processed AND there are // still others waiting to receive it too (as well as us)), then if // it's a "broadcast" type signal, we can go ahead and receive that // type of signal too as well (along with the others); we just came // to the party a little bit late (but nevertheless in the nick of // time!), that's all... if ( !pFT_COND_VAR->nNumWaiting || pFT_COND_VAR->bBroadcastSig ) break; // Otherwise it's a "signal" type signal (and not a broadcast type) // that hasn't been completely received yet, meaning only ONE thread // should be released. Thus, since there's already a thread (or more // than one thread) already waiting/trying to receive it, we need to // let [one of] THEM receive it and NOT US. Thus we go back to sleep // and wait for the signal processing currently in progress to finish // releasing the proper number of threads first. Only once that has // happened can we then be allowed to try and catch whatever signal // happens to come along next... MyLeaveCriticalSection ( &pFT_COND_VAR->CondVarLock ); // (Programming Note: technically we should really be checking our // return code from the below wait call too) MyWaitForSingleObject ( pFT_COND_VAR->hSigRecvdEvent, INFINITE ); } // Register the caller's wait request while we still have control // over this condition variable... pFT_COND_VAR->nNumWaiting++; // (register wait request) // Now release the original mutex and thus any potential signalers... // (but note that no signal can actually ever be sent per se until // the condition variable which we currently have locked is first // released, which gets done in the WaitForTransmission function). if ( ( rc = fthread_mutex_unlock ( pFTUSER_MUTEX ) ) != 0 ) { // Oops! Something went wrong. We couldn't release the original // caller's original mutex. Since we've already registered their // wait and already have the condition variable locked, we need // to first de-register their wait and release the condition var- // iable lock before returning our error (i.e. we essentially // need to back out what we previously did just above). logmsg("fthreads: BeginWait: fthread_mutex_unlock failed! rc=%d\n" ,rc ); pFT_COND_VAR->nNumWaiting--; // (de-register wait request) MyLeaveCriticalSection ( &pFT_COND_VAR->CondVarLock ); return RC(rc); } // Our "begin-to-wait-on-condition-variable" task has been successfully // completed. We have essentially atomically released the originally mutex // and "begun our wait" on it (by registering the fact that there's someone // wanting to wait on it). Return to OUR caller with the condition variable // still locked (so no signals can be sent nor any threads released until // our caller calls the below WaitForTransmission function)... return RC(0); // (success) } //////////////////////////////////////////////////////////////////////////////////// // Wait for the condition variable in question to receive a transmission... static int WaitForTransmission ( FT_COND_VAR* pFT_COND_VAR, struct timespec* pTimeTimeout // (NULL == INFINITE wait) ) { DWORD dwWaitRetCode, dwWaitMilliSecs; // If the signal has already arrived (i.e. is still being transmitted) // then there's no need to wait for it. Simply return success with the // condition variable still locked... if ( IsEventSet ( pFT_COND_VAR->hSigXmitEvent ) ) { // There's no need to wait for the signal (transmission) // to arrive because it's already been sent! Just return. return 0; // (transmission received!) } // Our loop to wait for our transmission to arrive... do { // Release condition var lock (so signal (transmission) can // be sent) and then wait for the signal (transmission)... MyLeaveCriticalSection ( &pFT_COND_VAR->CondVarLock ); // Need to calculate a timeout value if this is a // timed condition wait as opposed to a normal wait... // Note that we unfortunately need to do this on each iteration // because Window's wait API requires a relative timeout value // rather than an absolute TOD timeout value like pthreads... if ( !pTimeTimeout ) { dwWaitMilliSecs = INFINITE; } else { struct timeval TimeNow; gettimeofday ( &TimeNow, NULL ); if (TimeNow.tv_sec > pTimeTimeout->tv_sec || ( TimeNow.tv_sec == pTimeTimeout->tv_sec && (TimeNow.tv_usec * 1000) > pTimeTimeout->tv_nsec ) ) { dwWaitMilliSecs = 0; } else { dwWaitMilliSecs = ((pTimeTimeout->tv_sec - TimeNow.tv_sec) * 1000) + ((pTimeTimeout->tv_nsec - (TimeNow.tv_usec * 1000)) / 1000000); } } // Finally we get to do the actual wait... dwWaitRetCode = MyWaitForSingleObject ( pFT_COND_VAR->hSigXmitEvent, dwWaitMilliSecs ); // A signal (transmission) has been sent; reacquire our condition var lock // and receive the transmission (if it's still being transmitted that is)... MyEnterCriticalSection ( &pFT_COND_VAR->CondVarLock ); // The "WAIT_OBJECT_0 == dwWaitRetCode && ..." clause in the below 'while' // statement ensures that we will always break out of our wait loop whenever // either a timeout occurs or our actual MyWaitForSingleObject call fails // for any reason. As long as dwWaitRetCode is WAIT_OBJECT_0 though *AND* // our event has still not been signaled yet, then we'll continue looping // to wait for a signal (transmission) that we're supposed to receive... // Also note that one might at first think/ask: "Gee, Fish, why do we need // to check to see if the condition variable's "hSigXmitEvent" event has // been set each time (via the 'IsEventSet' macro)? Shouldn't it *always* // be set if the above MyWaitForSingleObject call returns??" The answer is // of course no, it might NOT [still] be signaled. This is because whenever // someone *does* happen to signal it, we will of course be released from // our wait (the above MyWaitForSingleObject call) BUT... someone else who // was also waiting for it may have managed to grab our condition variable // lock before we could and they could have reset it. Thus we need to check // it again each time. } while ( WAIT_OBJECT_0 == dwWaitRetCode && !IsEventSet( pFT_COND_VAR->hSigXmitEvent ) ); // Our signal (transmission) has either [finally] arrived or else we got // tired of waiting for it (i.e. we timed out) or else there was an error... if ( WAIT_OBJECT_0 == dwWaitRetCode ) return RC(0); if ( WAIT_TIMEOUT == dwWaitRetCode ) return RC(ETIMEDOUT); // Our wait failed! Something is VERY wrong! Maybe the condition variable // was prematurely destroyed by someone? In any case there's not // much we can do about it other than log the fact that it occurred and // return the error back to the caller. Their wait request has, believe // it or not, actually been completed (although not as they expected it // would in all likelihood!)... logmsg ( "fthreads: WaitForTransmission: MyWaitForSingleObject failed! dwWaitRetCode=%d (0x%8.8X)\n" ,dwWaitRetCode ,dwWaitRetCode ); return RC(EFAULT); } //////////////////////////////////////////////////////////////////////////////////// // Send a "signal" or "broadcast" to a condition variable... static int QueueTransmission ( FT_COND_VAR* pFT_COND_VAR, BOOL bXmitType ) { if (0 || !pFT_COND_VAR // (invalid ptr) || pFT_COND_VAR->dwCondMagic != FT_COND_MAGIC // (not initialized) ) { return RC(EINVAL); // (invalid parameters were passed) } // Wait for the condition variable to become free so we can begin transmitting // our signal... If the condition variable is still "busy" (in use), then that // means threads are still in the process of being released as a result of some // prior signal (transmission). Thus we must wait until that work is completed // first before we can send our new signal (transmission)... for (;;) { MyEnterCriticalSection ( &pFT_COND_VAR->CondVarLock ); if ( IsEventSet ( pFT_COND_VAR->hSigRecvdEvent ) ) break; MyLeaveCriticalSection ( &pFT_COND_VAR->CondVarLock ); MyWaitForSingleObject ( pFT_COND_VAR->hSigRecvdEvent, INFINITE ); } // Turn on our transmitter... (i.e. start transmitting our "signal" to // all threads who might be waiting to receive it (if there are any)... // If no one has registered their interest in receiving any transmissions // associated with this particular condition variable, then they are unfor- // tunately a little too late in doing so because we're ready to start our // transmission right now! If there's no one to receive our transmission, // then it simply gets lost (i.e. a "missed signal" situation has essenti- // ally occurred), but then that's not our concern here; our only concern // here is to transmit the signal (transmission) and nothing more. Tough // beans if there's no one listening to receive it... if ( pFT_COND_VAR->nNumWaiting ) // (anyone interested?) { pFT_COND_VAR->bBroadcastSig = bXmitType; // (yep! set xmit type) MySetEvent ( pFT_COND_VAR->hSigXmitEvent ); // (turn on transmitter) MyResetEvent ( pFT_COND_VAR->hSigRecvdEvent ); // (serialize reception) } MyLeaveCriticalSection ( &pFT_COND_VAR->CondVarLock ); return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // A thread has been released as a result of someone's signal or broadcast... static void ReceiveXmission ( FT_COND_VAR* pFT_COND_VAR ) { // If we were the only ones supposed to receive the transmission, (or // if no one remains to receive any transmissions), then turn off the // transmitter (i.e. stop sending the signal) and indicate that it has // been completely received all interested parties (i.e. by everyone // who was supposed to receive it)... pFT_COND_VAR->nNumWaiting--; // (de-register wait since transmission // has been successfully received now) // Determine whether any more waiters (threads) should also receive // this transmission (i.e. also be released) or whether we should // reset (turn off) our transmitter so as to not release any other // thread(s) besides ourselves... if (0 || !pFT_COND_VAR->bBroadcastSig // ("signal" == only us) || pFT_COND_VAR->nNumWaiting <= 0 // (no one else == only us) ) { MyResetEvent ( pFT_COND_VAR->hSigXmitEvent ); // (turn off transmitter) MySetEvent ( pFT_COND_VAR->hSigRecvdEvent ); // (transmission complete) } } //////////////////////////////////////////////////////////////////////////////////// // The following function is called just before returning back to the caller. It // first releases the condition variable lock (since we're now done with it) and // then reacquires the caller's original mutex before returning [back to the caller]. // We MUST do things in that order! 1) release our condition variable lock, and THEN // 2) try to reacquire the caller's original mutex. Otherwise a deadlock could occur! // If we still had the condition variable locked before trying to acquire the caller's // original mutex, we could easily become blocked if some other thread still already // owned (had locked) the caller's mutex. We would then be unable to ever release our // condition variable lock until whoever had the mutex locked first released it, but // they would never be able to release it because we still had the condition variable // still locked! Recall that upon entry to a wait call (see previous BeginWait function) // we acquire the condition variable lock *first* (in order to register the caller's // wait) before releasing their mutex. Thus, we MUST therefore release our condition // variable lock FIRST and THEN try reacquiring their original mutex before returning. static int ReturnFromWait ( FT_COND_VAR* pFT_COND_VAR, fthread_mutex_t* pFTUSER_MUTEX, int nRetCode ) { int rc; FT_MUTEX* pFT_MUTEX; if (0 || !pFT_COND_VAR // (invalid ptr) || pFT_COND_VAR -> dwCondMagic != FT_COND_MAGIC // (not initialized) || !pFTUSER_MUTEX // (invalid ptr) || pFTUSER_MUTEX-> dwMutexMagic != FT_MUTEX_MAGIC // (not initialized) || !(pFT_MUTEX = pFTUSER_MUTEX->hMutex) // (invalid ptr) // || !pFT_MUTEX // (invalid ptr) || pFT_MUTEX -> dwMutexMagic != FT_MUTEX_MAGIC // (not initialized) ) return RC(EINVAL); // (let other threads access this condition variable now...) MyLeaveCriticalSection ( &pFT_COND_VAR->CondVarLock ); // (reacquire original mutex before returning back to the original caller...) if ( ( rc = fthread_mutex_lock ( pFTUSER_MUTEX ) ) != 0 ) { // Oops! We were unable to reacquire the caller's original mutex! This // is actually a catastrophic type of error! The caller expects their // mutex to still be owned (locked) by themselves upon return, but we // were unable to reacquire it for them! Unfortunately there's nothing // we can do about this; the system is essentially hosed at this point. // Just log the fact that something went wrong and return. logmsg("fthreads: ReturnFromWait: fthread_mutex_lock failed! rc=%d\n" ,rc ); return RC(rc); // (what went wrong) } // Return to caller with the requested return code. (The caller passes to us // the return code they wish to pass back to the original caller, so we just // return that same return code back to OUR caller (so they can then pass it // back to the original fthreads caller)). return RC(nRetCode); // (as requested) } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // Threading functions... LIST_ENTRY ThreadListHead; // head list entry of list of joinable threads CRITICAL_SECTION ThreadListLock; // lock for accessing list of joinable threads #define LockThreadsList() EnterCriticalSection ( &ThreadListLock ) #define UnlockThreadsList() LeaveCriticalSection ( &ThreadListLock ) //////////////////////////////////////////////////////////////////////////////////// // internal joinable thread information typedef struct _tagFTHREAD { LIST_ENTRY ThreadListLink; // (links entries together in a chain) DWORD dwThreadID; // (thread-id) HANDLE hThreadHandle; // (Win32 thread handle) BOOL bJoinable; // (whether thread is joinable or detached) int nJoinedCount; // (#of threads that did join on this one) void* ExitVal; // (saved thread exit value) jmp_buf JumpBuf; // (jump buffer for fthread_exit) } FTHREAD, *PFTHREAD; //////////////////////////////////////////////////////////////////////////////////// // (Note: returns with thread list lock still held if found; not held if not found) static FTHREAD* FindFTHREAD ( DWORD dwThreadID ) { FTHREAD* pFTHREAD; LIST_ENTRY* pListEntry; LockThreadsList(); // (acquire thread list lock) pListEntry = ThreadListHead.Flink; while ( pListEntry != &ThreadListHead ) { pFTHREAD = CONTAINING_RECORD ( pListEntry, FTHREAD, ThreadListLink ); pListEntry = pListEntry->Flink; if ( pFTHREAD->dwThreadID != dwThreadID ) continue; return pFTHREAD; // (return with thread list lock still held) } UnlockThreadsList(); // (release thread list lock) return NULL; // (not found) } //////////////////////////////////////////////////////////////////////////////////// typedef struct _ftCallThreadParms { PFT_THREAD_FUNC pfnTheirThreadFunc; void* pvTheirThreadArgs; char* pszTheirThreadName; FTHREAD* pFTHREAD; } FT_CALL_THREAD_PARMS; //---------------------------------------------------------------------------------- static DWORD __stdcall FTWin32ThreadFunc ( void* pMyArgs ) { FT_CALL_THREAD_PARMS* pCallTheirThreadParms; PFT_THREAD_FUNC pfnTheirThreadFunc; void* pvTheirThreadArgs; FTHREAD* pFTHREAD; pCallTheirThreadParms = (FT_CALL_THREAD_PARMS*) pMyArgs; pfnTheirThreadFunc = pCallTheirThreadParms->pfnTheirThreadFunc; pvTheirThreadArgs = pCallTheirThreadParms->pvTheirThreadArgs; pFTHREAD = pCallTheirThreadParms->pFTHREAD; // PROGRAMMING NOTE: -1 == "current calling thread" SET_THREAD_NAME_ID ( -1, pCallTheirThreadParms->pszTheirThreadName ); free ( pCallTheirThreadParms ); if ( setjmp ( pFTHREAD->JumpBuf ) == 0 ) pFTHREAD->ExitVal = pfnTheirThreadFunc ( pvTheirThreadArgs ); LockThreadsList(); if ( !pFTHREAD->bJoinable ) { // If we are not a joinable thread, we must free our // own resources ourselves, but ONLY IF the 'joined' // count is zero. If the 'joined' count is NOT zero, // then, however it occurred, there is still someone // waiting in the join function for us to exit, and // thus, we cannot free our resources at this time // (since the thread that did the join and which is // waiting for us to exit still needs access to our // resources). In such a situation the actual freeing // of resources is deferred and will be done by the // join function itself whenever it's done with them. if ( pFTHREAD->nJoinedCount <= 0 ) { CloseHandle ( pFTHREAD->hThreadHandle ); RemoveListEntry ( &pFTHREAD->ThreadListLink ); free ( pFTHREAD ); } } UnlockThreadsList(); MyExitThread ( 0 ); return 0; // (make compiler happy) } //////////////////////////////////////////////////////////////////////////////////// // Create a new thread... DLL_EXPORT int fthread_create ( fthread_t* pdwThreadID, fthread_attr_t* pThreadAttr, PFT_THREAD_FUNC pfnThreadFunc, void* pvThreadArgs, char* pszThreadName ) { static BOOL bDidInit = FALSE; FT_CALL_THREAD_PARMS* pCallTheirThreadParms; size_t nStackSize; int nDetachState; FTHREAD* pFTHREAD; HANDLE hThread; DWORD dwThreadID; if ( !bDidInit ) { bDidInit = TRUE; InitializeListHead ( &ThreadListHead ); InitializeCriticalSection ( &ThreadListLock ); } if (0 || !pdwThreadID || !pfnThreadFunc ) return RC(EINVAL); if ( pThreadAttr ) { if ( pThreadAttr->dwAttrMagic != FT_ATTR_MAGIC || ( pThreadAttr->nDetachState != FTHREAD_CREATE_DETACHED && pThreadAttr->nDetachState != FTHREAD_CREATE_JOINABLE ) ) return RC(EINVAL); nStackSize = pThreadAttr->nStackSize; nDetachState = pThreadAttr->nDetachState; } else { nStackSize = 0; nDetachState = FTHREAD_CREATE_DEFAULT; } pCallTheirThreadParms = (FT_CALL_THREAD_PARMS*) malloc ( sizeof ( FT_CALL_THREAD_PARMS ) ); if ( !pCallTheirThreadParms ) { logmsg("fthread_create: malloc(FT_CALL_THREAD_PARMS) failed\n"); return RC(ENOMEM); // (out of memory) } pFTHREAD = (FTHREAD*) malloc ( sizeof( FTHREAD ) ); if ( !pFTHREAD ) { logmsg("fthread_create: malloc(FTHREAD) failed\n"); free ( pCallTheirThreadParms ); return RC(ENOMEM); // (out of memory) } pCallTheirThreadParms->pfnTheirThreadFunc = pfnThreadFunc; pCallTheirThreadParms->pvTheirThreadArgs = pvThreadArgs; pCallTheirThreadParms->pszTheirThreadName = pszThreadName; pCallTheirThreadParms->pFTHREAD = pFTHREAD; InitializeListLink(&pFTHREAD->ThreadListLink); pFTHREAD->dwThreadID = 0; pFTHREAD->hThreadHandle = NULL; pFTHREAD->bJoinable = ((FTHREAD_CREATE_JOINABLE == nDetachState) ? (TRUE) : (FALSE)); pFTHREAD->nJoinedCount = 0; pFTHREAD->ExitVal = NULL; LockThreadsList(); hThread = MyCreateThread ( NULL, nStackSize, FTWin32ThreadFunc, pCallTheirThreadParms, 0, &dwThreadID ); if ( !hThread ) { UnlockThreadsList(); logmsg("fthread_create: MyCreateThread failed\n"); free ( pCallTheirThreadParms ); free ( pFTHREAD ); return RC(EAGAIN); // (unable to obtain required resources) } pFTHREAD->hThreadHandle = hThread; pFTHREAD->dwThreadID = dwThreadID; *pdwThreadID = dwThreadID; InsertListHead ( &ThreadListHead, &pFTHREAD->ThreadListLink ); UnlockThreadsList(); return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Exit from a thread... DLL_EXPORT void fthread_exit ( void* ExitVal ) { FTHREAD* pFTHREAD; VERIFY ( pFTHREAD = FindFTHREAD ( GetCurrentThreadId() ) ); pFTHREAD->ExitVal = ExitVal; UnlockThreadsList(); longjmp ( pFTHREAD->JumpBuf, 1 ); } //////////////////////////////////////////////////////////////////////////////////// // Join a thread (i.e. wait for a thread's termination)... DLL_EXPORT int fthread_join ( fthread_t dwThreadID, void** pExitVal ) { HANDLE hThread; FTHREAD* pFTHREAD; if ( GetCurrentThreadId() == dwThreadID ) return RC(EDEADLK); // (can't join self!) if ( !(pFTHREAD = FindFTHREAD ( dwThreadID ) ) ) return RC(ESRCH); // (thread not found) // (Note: threads list lock still held at this point // since thread was found...) if ( !pFTHREAD->bJoinable ) { UnlockThreadsList(); return RC(EINVAL); // (not a joinable thread) } ASSERT ( pFTHREAD->nJoinedCount >= 0 ); pFTHREAD->nJoinedCount++; hThread = pFTHREAD->hThreadHandle; // Wait for thread to exit... UnlockThreadsList(); { WaitForSingleObject ( hThread, INFINITE ); } LockThreadsList(); if ( pExitVal ) *pExitVal = pFTHREAD->ExitVal; // (pass back thread's exit value) ASSERT ( pFTHREAD->nJoinedCount > 0 ); pFTHREAD->nJoinedCount--; // If this is the last thread to be resumed after having been suspended // (as a result of doing the join), then we need to do the detach (i.e. // to free resources), BUT ONLY IF the detach for the thread in question // has already been done by someone (which can be determined by virtue of // the "joinable" flag having already been changed back to non-joinable). // The idea here is that the 'detach' function purposely does not free // the resources unless the 'joined' count is zero. If the joined count // is NOT zero whenever the detach function is called, then the resources // cannot be freed since there's still a thread waiting to be resumed // from its join (perhaps us!), and it obviously still needs access to // the resources in question. Thus, in such a situation (i.e. there still // being a thread remaining to be woken up from its join when the detach // is done), the freeing of resources normally done by the detach function // is deferred so that WE can do the resource freeing ourselves once we // are done with them. if ( !pFTHREAD->bJoinable && pFTHREAD->nJoinedCount <= 0 ) { CloseHandle ( pFTHREAD->hThreadHandle ); RemoveListEntry ( &pFTHREAD->ThreadListLink ); free ( pFTHREAD ); } UnlockThreadsList(); return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Detach a thread (i.e. ignore a thread's termination)... DLL_EXPORT int fthread_detach ( fthread_t dwThreadID ) { FTHREAD* pFTHREAD; if ( !( pFTHREAD = FindFTHREAD ( dwThreadID ) ) ) return RC(ESRCH); // (thread not found) // (Note: threads list lock still held at this point // since thread was found...) if ( !pFTHREAD->bJoinable ) { UnlockThreadsList(); return RC(EINVAL); // (not a joinable thread) } // If the thread has not yet exited, then IT will free its // own resources itself whenever it eventually does exit by // virtue of our changing it to a non-joinable thread type. pFTHREAD->bJoinable = FALSE; // (indicate detach was done) // Otherwise we need to free its resources ourselves since // it obviously can't (since it has already exited). // Note that we cannot free the resources ourselves even if the // thread has already exited if there are still other threads // waiting to be woken up from their own join (since they will // still need to have access to the resources). In other words, // even if the thread has already exited (and thus it would seem // that our freeing the resources would be the proper thing to // do), we CANNOT do so if the 'join' count is non-zero. // In such a situation (the join count being non-zero indicating // there is still another thread waiting to be resumed from its // own join), we simply defer the actual freeing of resources to // the thread still waiting to be woken up from its join. Whenever // it does eventually wake up from its join, it will free the // resources for us, as long as we remember to reset the 'joinable' // flag back to non-joinable (which we've already done just above). if ( IsEventSet ( pFTHREAD->hThreadHandle ) && pFTHREAD->nJoinedCount <= 0 ) { CloseHandle ( pFTHREAD->hThreadHandle ); RemoveListEntry ( &pFTHREAD->ThreadListLink ); free ( pFTHREAD ); } UnlockThreadsList(); return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Initialize a "thread attribute"... DLL_EXPORT int fthread_attr_init ( fthread_attr_t* pThreadAttr ) { if ( !pThreadAttr ) return RC(EINVAL); // (invalid ptr) if ( FT_ATTR_MAGIC == pThreadAttr->dwAttrMagic ) return RC(EBUSY); // (already initialized) pThreadAttr->dwAttrMagic = FT_ATTR_MAGIC; pThreadAttr->nDetachState = FTHREAD_CREATE_DEFAULT; pThreadAttr->nStackSize = 0; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Destroy a "thread attribute"... DLL_EXPORT int fthread_attr_destroy ( fthread_attr_t* pThreadAttr ) { if ( !pThreadAttr ) return RC(EINVAL); // (invalid ptr) if ( FT_ATTR_MAGIC != pThreadAttr->dwAttrMagic ) return RC(EINVAL); // (not initialized) pThreadAttr->dwAttrMagic = 0; pThreadAttr->nDetachState = 0; pThreadAttr->nStackSize = 0; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Set a thread's "detachstate" attribute... DLL_EXPORT int fthread_attr_setdetachstate ( fthread_attr_t* pThreadAttr, int nDetachState ) { if ( !pThreadAttr ) return RC(EINVAL); // (invalid ptr) if ( FT_ATTR_MAGIC != pThreadAttr->dwAttrMagic ) return RC(EINVAL); // (not initialized) if ( FTHREAD_CREATE_DETACHED != nDetachState && FTHREAD_CREATE_JOINABLE != nDetachState ) return RC(EINVAL); // (invalid detach state) pThreadAttr->nDetachState = nDetachState; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Retrieve a thread's "detachstate" attribute... DLL_EXPORT int fthread_attr_getdetachstate ( const fthread_attr_t* pThreadAttr, int* pnDetachState ) { if ( !pThreadAttr || !pnDetachState ) return RC(EINVAL); // (invalid ptr) if ( FT_ATTR_MAGIC != pThreadAttr->dwAttrMagic ) return RC(EINVAL); // (not initialized) if ( FTHREAD_CREATE_DETACHED != pThreadAttr->nDetachState && FTHREAD_CREATE_JOINABLE != pThreadAttr->nDetachState ) return RC(EINVAL); // (invalid detach state) *pnDetachState = pThreadAttr->nDetachState; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Set a thread's initial stack size... DLL_EXPORT int fthread_attr_setstacksize ( fthread_attr_t* pThreadAttr, size_t nStackSize ) { if ( !pThreadAttr ) return RC(EINVAL); // (invalid ptr) if ( FT_ATTR_MAGIC != pThreadAttr->dwAttrMagic ) return RC(EINVAL); // (not initialized) pThreadAttr->nStackSize = nStackSize; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Retrieve a thread's initial stack size... DLL_EXPORT int fthread_attr_getstacksize ( const fthread_attr_t* pThreadAttr, size_t* pnStackSize ) { if ( !pThreadAttr || !pnStackSize ) return RC(EINVAL); // (invalid ptr) if ( FT_ATTR_MAGIC != pThreadAttr->dwAttrMagic ) return RC(EINVAL); // (not initialized) *pnStackSize = pThreadAttr->nStackSize; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // (thread signalling not [currently] supported (yet); always returns ENOTSUP...) DLL_EXPORT int fthread_kill // FIXME: TODO: ( int dummy1, int dummy2 ) { UNREFERENCED ( dummy1 ); UNREFERENCED ( dummy2 ); return RC(ENOTSUP); } //////////////////////////////////////////////////////////////////////////////////// // Return thread-id... DLL_EXPORT fthread_t fthread_self () { return GetCurrentThreadId(); } //////////////////////////////////////////////////////////////////////////////////// // Compare thread-ids... DLL_EXPORT int fthread_equal ( fthread_t pdwThreadID_1, fthread_t pdwThreadID_2 ) { return ( pdwThreadID_1 == pdwThreadID_2 ); } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // Initialize a lock... DLL_EXPORT int fthread_mutex_init ( fthread_mutex_t* pFTUSER_MUTEX, const fthread_mutexattr_t* pFT_MUTEX_ATTR ) { DWORD dwMutexType = 0; if ( !pFTUSER_MUTEX ) return RC(EINVAL); // (invalid mutex ptr) if ( FT_MUTEX_MAGIC == pFTUSER_MUTEX->dwMutexMagic ) return RC(EBUSY); // (mutex already initialized) if ( pFT_MUTEX_ATTR && !IsValidMutexType ( dwMutexType = *pFT_MUTEX_ATTR ) ) return RC(EINVAL); // (invalid mutex attr ptr or mutex attr type) if ( !(pFTUSER_MUTEX->hMutex = MallocFT_MUTEX()) ) return RC(ENOMEM); // (out of memory) if ( !InitializeFT_MUTEX ( pFTUSER_MUTEX->hMutex, pFT_MUTEX_ATTR ? dwMutexType : FTHREAD_MUTEX_DEFAULT )) { free ( pFTUSER_MUTEX->hMutex ); pFTUSER_MUTEX->dwMutexMagic = 0; pFTUSER_MUTEX->hMutex = NULL; return RC(EAGAIN); // (unable to obtain required resources) } pFTUSER_MUTEX->dwMutexMagic = FT_MUTEX_MAGIC; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Destroy a lock... DLL_EXPORT int fthread_mutex_destroy ( fthread_mutex_t* pFTUSER_MUTEX ) { if ( !pFTUSER_MUTEX ) return RC(EINVAL); // (invalid ptr) if ( FT_MUTEX_MAGIC != pFTUSER_MUTEX->dwMutexMagic ) return RC(EINVAL); // (not initialized) if ( !UninitializeFT_MUTEX ( pFTUSER_MUTEX->hMutex )) return RC(EBUSY); // (still in use) free ( pFTUSER_MUTEX->hMutex ); pFTUSER_MUTEX->dwMutexMagic = 0; pFTUSER_MUTEX->hMutex = NULL; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Try to lock a "mutex"... DLL_EXPORT int fthread_mutex_trylock ( fthread_mutex_t* pFTUSER_MUTEX ) { if ( !pFTUSER_MUTEX ) return RC(EINVAL); // (invalid ptr) if ( FT_MUTEX_MAGIC != pFTUSER_MUTEX->dwMutexMagic ) return RC(EINVAL); // (not initialized) // Try to acquire the requested mutex... if ( !TryEnterFT_MUTEX ( pFTUSER_MUTEX->hMutex ) ) // We could not acquire the mutex; return 'busy'... return RC(EBUSY); // We successfully acquired the mutex... If the mutex type is recursive, // or, if not recursive (i.e. error-check), if this was the first/initial // lock on the mutex, then return success... if (0 || FTHREAD_MUTEX_RECURSIVE == ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->dwMutexType || ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->nLockedCount <= 1 ) return RC(0); ASSERT ( FTHREAD_MUTEX_ERRORCHECK == ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->dwMutexType && ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->nLockedCount > 1 ); // The mutex type is error-check and we already previously had the mutex locked // before (i.e. this was the *second* time we acquired this same mutex). Return // 'busy' after first releasing the mutex once (to decrement the locked count // back down to what it was (i.e. 1 (one))). LeaveFT_MUTEX ( pFTUSER_MUTEX->hMutex ); return RC(EBUSY); } //////////////////////////////////////////////////////////////////////////////////// // Lock a "mutex"... DLL_EXPORT int fthread_mutex_lock ( fthread_mutex_t* pFTUSER_MUTEX ) { if ( !pFTUSER_MUTEX ) return RC(EINVAL); // (invalid ptr) if ( FT_MUTEX_MAGIC != pFTUSER_MUTEX->dwMutexMagic ) return RC(EINVAL); // (not initialized) // Try to acquire the requested mutex... if ( !TryEnterFT_MUTEX ( pFTUSER_MUTEX->hMutex ) ) { // We could not acquire the mutex. This means someone already owns the mutex, // so just do a normal acquire on the mutex. Both recursive and error-check // types will block until such time as the mutex is successfully acquired... EnterFT_MUTEX ( pFTUSER_MUTEX->hMutex ); return RC(0); } // We successfully acquired the mutex... If the mutex type is recursive, // or, if not recursive (i.e. error-check), if this was the first/initial // lock on the mutex, then return success... if (0 || FTHREAD_MUTEX_RECURSIVE == ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->dwMutexType || ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->nLockedCount <= 1 ) return RC(0); ASSERT ( FTHREAD_MUTEX_ERRORCHECK == ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->dwMutexType && ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->nLockedCount > 1 ); // The mutex type is error-check and we already previously had the mutex locked // before (i.e. this was the *second* time we acquired this same mutex). Return // 'deadlock' after first releasing the mutex once (to decrement the locked count // back down to what it was (i.e. 1 (one))). LeaveFT_MUTEX ( pFTUSER_MUTEX->hMutex ); return RC(EDEADLK); } //////////////////////////////////////////////////////////////////////////////////// // Unlock a "mutex"... DLL_EXPORT int fthread_mutex_unlock ( fthread_mutex_t* pFTUSER_MUTEX ) { if (0 || !pFTUSER_MUTEX // (invalid ptr) || FT_MUTEX_MAGIC != pFTUSER_MUTEX->dwMutexMagic // (not initialized) ) return RC(EINVAL); if (0 || GetCurrentThreadId() != ((PFT_MUTEX)pFTUSER_MUTEX->hMutex)->dwLockOwner // (not owned) || ((PFT_MUTEX)pFTUSER_MUTEX->hMutex)->nLockedCount <= 0 // (not locked) ) return RC(EPERM); ASSERT ( ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->nLockedCount <= 1 || FTHREAD_MUTEX_RECURSIVE == ((FT_MUTEX*)pFTUSER_MUTEX->hMutex)->dwMutexType ); LeaveFT_MUTEX ( pFTUSER_MUTEX->hMutex ); return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Initialize a "condition"... DLL_EXPORT int fthread_cond_init ( fthread_cond_t* pFT_COND_VAR ) { if ( !pFT_COND_VAR ) return RC(EINVAL); // (invalid ptr) if ( FT_COND_MAGIC == pFT_COND_VAR->dwCondMagic ) return RC(EBUSY); // (already initialized) if ( !(pFT_COND_VAR->hCondVar = MallocFT_COND_VAR()) ) return RC(ENOMEM); // (out of memory) if ( !InitializeFT_COND_VAR ( pFT_COND_VAR->hCondVar )) { free ( pFT_COND_VAR->hCondVar ); pFT_COND_VAR->dwCondMagic = 0; pFT_COND_VAR->hCondVar = NULL; return RC(EAGAIN); // (unable to obtain required resources) } pFT_COND_VAR->dwCondMagic = FT_COND_MAGIC; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Destroy a "condition"... DLL_EXPORT int fthread_cond_destroy ( fthread_cond_t* pFT_COND_VAR ) { if ( !pFT_COND_VAR ) return RC(EINVAL); // (invalid ptr) if ( FT_COND_MAGIC != pFT_COND_VAR->dwCondMagic ) return RC(EINVAL); // (not initialized) if ( !UninitializeFT_COND_VAR ( pFT_COND_VAR->hCondVar )) return RC(EBUSY); // (still in use) free ( pFT_COND_VAR->hCondVar ); pFT_COND_VAR->dwCondMagic = 0; pFT_COND_VAR->hCondVar = NULL; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // 'Signal' a "condition"... (causes ONE waiting thread to be released) DLL_EXPORT int fthread_cond_signal ( fthread_cond_t* pFT_COND_VAR ) { if ( !pFT_COND_VAR ) return RC(EINVAL); // (invalid ptr) if ( FT_COND_MAGIC != pFT_COND_VAR->dwCondMagic ) return RC(EINVAL); // (not initialized) return QueueTransmission ( pFT_COND_VAR->hCondVar, FALSE // (FALSE == not "broadcast") ); } //////////////////////////////////////////////////////////////////////////////////// // 'Broadcast' a "condition"... (causes ALL waiting threads to be released) DLL_EXPORT int fthread_cond_broadcast ( fthread_cond_t* pFT_COND_VAR ) { if ( !pFT_COND_VAR ) return RC(EINVAL); // (invalid ptr) if ( FT_COND_MAGIC != pFT_COND_VAR->dwCondMagic ) return RC(EINVAL); // (not initialized) return QueueTransmission ( pFT_COND_VAR->hCondVar, TRUE // (TRUE == "broadcast" type) ); } //////////////////////////////////////////////////////////////////////////////////// // Wait for a "condition" to occur... DLL_EXPORT int fthread_cond_wait ( fthread_cond_t* pFT_COND_VAR, fthread_mutex_t* pFTUSER_MUTEX ) { int rc; if (0 || !pFT_COND_VAR // (invalid ptr) || FT_COND_MAGIC != pFT_COND_VAR -> dwCondMagic // (not initialized) || !pFTUSER_MUTEX // (invalid ptr) || FT_MUTEX_MAGIC != pFTUSER_MUTEX -> dwMutexMagic // (not initialized) ) return RC(EINVAL); // The following call essentially atomically releases the caller's mutex // and does a wait. Of course, it doesn't really do the wait though; that's // actually done further below. BUT, it does atomically register the fact // that this thread *wishes* to do a wait by acquiring the condition variable // lock and then incrementing the #of waiters counter before it releases the // original mutex. Thus, whenever the below function call returns back to us, // we can be assured that: 1) our request to wait on this condition variable // has been registered AND 2) we have control of the condition variable in // question (i.e. we still hold the condition variable lock thus preventing // anyone from trying to send a signal just yet)... if ( ( rc = BeginWait ( pFT_COND_VAR -> hCondVar, pFTUSER_MUTEX ) ) != 0 ) { // OOPS! Something went wrong. The original mutex has NOT been released // and we did NOT acquire our condition variable lock (and thus our wait // was not registered). Thus we can safely return back to the caller with // the original mutex still owned (held) by the caller. return RC(rc); // (return error code to caller; their wait failed) } // We only reach here if the condition var was successfully acquired AND our // wait was registered AND the original mutex was released so the signal can // be sent (but the signal (transmission) of course cannot ever be sent until // we first release our lock on our condition variable, which is of course is // what the below WaitForTransmission function call does within its wait loop)... rc = WaitForTransmission // (wait for "signal" or "broadcast"...) ( pFT_COND_VAR->hCondVar, NULL ); // A signal (transmission) was sent and we're one of the ones (or the // only one) that's supposed to receive it... // If we're the only one that's supposed to receive this transmission, // then we need to turn off the transmitter (stop "sending" the signal) // so that no other threads get "woken up" (released) as a result of // this particular "signal" (transmission)... // (Note that the below call also de-registers our wait too) ReceiveXmission // (reset transmitter) ( pFT_COND_VAR->hCondVar ); // Release the condition var lock (since we're done with it) and then // reacquire the caller's original mutex (if possible) and then return // back to the original caller with their original mutex held with what- // ever return code got set by the above wait call... return ReturnFromWait ( pFT_COND_VAR -> hCondVar, pFTUSER_MUTEX, rc ); } //////////////////////////////////////////////////////////////////////////////////// // Wait (but not forever) for a "condition" to occur... // Refer to the comments in the above 'fthread_cond_wait' function (as well as all // of our other internal functions too of course (BeginWait, WaitForTransmission, // ReceiveXmission and ReturnFromWait)) for details regarding what's going on here // (i.e. what we're doing below and why). The below function is essentially identical // to the above 'fthread_cond_wait' function except that we don't wait forever; we // only wait for a limited amount of time. Other than that they're exactly identical // so there's no sense in repeating myself here... DLL_EXPORT int fthread_cond_timedwait ( fthread_cond_t* pFT_COND_VAR, fthread_mutex_t* pFTUSER_MUTEX, struct timespec* pTimeTimeout ) { int rc; if (0 || !pFT_COND_VAR || FT_COND_MAGIC != pFT_COND_VAR -> dwCondMagic || !pFTUSER_MUTEX || FT_MUTEX_MAGIC != pFTUSER_MUTEX -> dwMutexMagic || !pTimeTimeout ) return RC(EINVAL); if ( ( rc = BeginWait ( pFT_COND_VAR -> hCondVar, pFTUSER_MUTEX ) ) != 0 ) return rc; rc = WaitForTransmission ( pFT_COND_VAR->hCondVar, pTimeTimeout ); ReceiveXmission ( pFT_COND_VAR->hCondVar ); return ReturnFromWait ( pFT_COND_VAR -> hCondVar, pFTUSER_MUTEX, rc ); } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // Initialize a "mutex" attribute... DLL_EXPORT int fthread_mutexattr_init ( fthread_mutexattr_t* pFT_MUTEX_ATTR ) { if ( !pFT_MUTEX_ATTR ) return RC(EINVAL); *pFT_MUTEX_ATTR = FTHREAD_MUTEX_DEFAULT; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Destroy a "mutex" attribute... DLL_EXPORT int fthread_mutexattr_destroy ( fthread_mutexattr_t* pFT_MUTEX_ATTR ) { if ( !pFT_MUTEX_ATTR ) return RC(EINVAL); *pFT_MUTEX_ATTR = 0xCDCDCDCD; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Retrieve "mutex" attribute type... DLL_EXPORT int fthread_mutexattr_gettype ( const fthread_mutexattr_t* pFT_MUTEX_ATTR, int* pnMutexType ) { DWORD dwMutexType; if ( !pFT_MUTEX_ATTR || !pnMutexType || !IsValidMutexType ( dwMutexType = *pFT_MUTEX_ATTR ) ) return RC(EINVAL); *pnMutexType = (int) dwMutexType; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// // Set "mutex" attribute type... DLL_EXPORT int fthread_mutexattr_settype ( fthread_mutexattr_t* pFT_MUTEX_ATTR, int nMutexType ) { if ( !pFT_MUTEX_ATTR || !IsValidMutexType ( (DWORD) nMutexType ) ) return RC(EINVAL); *pFT_MUTEX_ATTR = (DWORD) nMutexType; return RC(0); } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// #endif // !defined(OPTION_FTHREADS) hercules-3.12/memrchr.c0000664000175000017500000000203112564723224012000 00000000000000/* MEMRCHR.C (c) Copyright Volker Bandke, 2003 */ /* Hercules Right to Left memory scan */ /*-------------------------------------------------------------------*/ /* Scans the memory block and reports the last occurrence of */ /* the specified byte in the buffer. Returns a pointer to */ /* the byte if found, or NULL if not found. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _MEMRCHR_C_ #define _HUTIL_DLL_ #include "hercules.h" #if !defined( HAVE_MEMRCHR ) #include "memrchr.h" DLL_EXPORT void *memrchr(const void *buf, int c, size_t num) { unsigned char *pMem; if (num == 0) { return NULL; } for (pMem = (unsigned char *) buf + num - 1; pMem >= (unsigned char *) buf; pMem--) { if (*pMem == (unsigned char) c) break; } if (pMem >= (unsigned char *) buf) { return ((void *) pMem); } return NULL; } #endif // !defined(HAVE_MEMRCHR) hercules-3.12/ltdl.c0000664000175000017500000031077412564723224011322 00000000000000/* ltdl.c -- system independent dlopen wrapper Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. Originally by Thomas Tanner This file is part of GNU Libtool. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. As a special exception to the GNU Lesser General Public License, if you distribute this file as part of a program or library that is built using GNU libtool, you may include it under the same distribution terms that you use for the rest of that program. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define UNREFERENCED(x) ((void)(x)) #if HAVE_CONFIG_H #include "config.h" // Hercules build configuration options/settings #endif #if defined(HDL_USE_LIBTOOL) #if HAVE_UNISTD_H # include #endif #if HAVE_STDIO_H # include #endif #if HAVE_STDLIB_H # include #endif #if HAVE_STRING_H # include #else # if HAVE_STRINGS_H # include # endif #endif #if HAVE_CTYPE_H # include #endif #if HAVE_MALLOC_H # include #endif #if HAVE_MEMORY_H # include #endif #if HAVE_ERRNO_H # include #endif #ifndef __WINDOWS__ # ifdef __WIN32__ # define __WINDOWS__ # endif #endif #undef LT_USE_POSIX_DIRENT #ifdef HAVE_CLOSEDIR # ifdef HAVE_OPENDIR # ifdef HAVE_READDIR # ifdef HAVE_DIRENT_H # define LT_USE_POSIX_DIRENT # endif /* HAVE_DIRENT_H */ # endif /* HAVE_READDIR */ # endif /* HAVE_OPENDIR */ #endif /* HAVE_CLOSEDIR */ #undef LT_USE_WINDOWS_DIRENT_EMULATION #ifndef LT_USE_POSIX_DIRENT # ifdef __WINDOWS__ # define LT_USE_WINDOWS_DIRENT_EMULATION # endif /* __WINDOWS__ */ #endif /* LT_USE_POSIX_DIRENT */ #ifdef LT_USE_POSIX_DIRENT # include # define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) #else # ifdef LT_USE_WINDOWS_DIRENT_EMULATION # define LT_D_NAMLEN(dirent) (strlen((dirent)->d_name)) # else # define dirent direct # define LT_D_NAMLEN(dirent) ((dirent)->d_namlen) # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif # endif #endif #if HAVE_ARGZ_H # include #endif #if HAVE_ASSERT_H # include #else # define assert(arg) ((void) 0) #endif #include "ltdl.h" #if WITH_DMALLOC # include #endif /* --- WINDOWS SUPPORT --- */ #if defined(DLL_EXPORT) && defined(WIN32) # define LT_GLOBAL_DATA __declspec(dllexport) #else # define LT_GLOBAL_DATA #endif /* fopen() mode flags for reading a text file */ #undef LT_READTEXT_MODE #ifdef __WINDOWS__ # define LT_READTEXT_MODE "rt" #else # define LT_READTEXT_MODE "r" #endif #ifdef LT_USE_WINDOWS_DIRENT_EMULATION #include #define dirent lt_dirent #define DIR lt_DIR struct dirent { char d_name[2048]; int d_namlen; }; typedef struct _DIR { HANDLE hSearch; WIN32_FIND_DATA Win32FindData; BOOL firsttime; struct dirent file_info; } DIR; #endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ /* --- MANIFEST CONSTANTS --- */ /* Standard libltdl search path environment variable name */ #undef LTDL_SEARCHPATH_VAR #define LTDL_SEARCHPATH_VAR "LTDL_LIBRARY_PATH" /* Standard libtool archive file extension. */ #undef LTDL_ARCHIVE_EXT #define LTDL_ARCHIVE_EXT ".la" /* max. filename length */ #ifndef LT_FILENAME_MAX # define LT_FILENAME_MAX 1024 #endif /* This is the maximum symbol size that won't require malloc/free */ #undef LT_SYMBOL_LENGTH #define LT_SYMBOL_LENGTH 128 /* This accounts for the _LTX_ separator */ #undef LT_SYMBOL_OVERHEAD #define LT_SYMBOL_OVERHEAD 5 /* --- MEMORY HANDLING --- */ /* These are the functions used internally. In addition to making use of the associated function pointers above, they also perform error handling. */ static char *lt_estrdup LT_PARAMS((const char *str)); static lt_ptr lt_emalloc LT_PARAMS((size_t size)); static lt_ptr lt_erealloc LT_PARAMS((lt_ptr addr, size_t size)); /* static lt_ptr rpl_realloc LT_PARAMS((lt_ptr ptr, size_t size)); */ #define rpl_realloc realloc /* These are the pointers that can be changed by the caller: */ LT_GLOBAL_DATA lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)) = (lt_ptr (*) LT_PARAMS((size_t))) malloc; LT_GLOBAL_DATA lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size)) = (lt_ptr (*) LT_PARAMS((lt_ptr, size_t))) rpl_realloc; LT_GLOBAL_DATA void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)) = (void (*) LT_PARAMS((lt_ptr))) free; /* The following macros reduce the amount of typing needed to cast assigned memory. */ #if WITH_DMALLOC #define LT_DLMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) #define LT_DLREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) #define LT_DLFREE(p) \ LT_STMT_START { if (p) (p) = (xfree (p), (lt_ptr) 0); } LT_STMT_END #define LT_EMALLOC(tp, n) ((tp *) xmalloc ((n) * sizeof(tp))) #define LT_EREALLOC(tp, p, n) ((tp *) xrealloc ((p), (n) * sizeof(tp))) #else #define LT_DLMALLOC(tp, n) ((tp *) lt_dlmalloc ((n) * sizeof(tp))) #define LT_DLREALLOC(tp, p, n) ((tp *) lt_dlrealloc ((p), (n) * sizeof(tp))) #define LT_DLFREE(p) \ LT_STMT_START { if (p) (p) = (lt_dlfree (p), (lt_ptr) 0); } LT_STMT_END #define LT_EMALLOC(tp, n) ((tp *) lt_emalloc ((n) * sizeof(tp))) #define LT_EREALLOC(tp, p, n) ((tp *) lt_erealloc ((p), (n) * sizeof(tp))) #endif #define LT_DLMEM_REASSIGN(p, q) LT_STMT_START { \ if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; } \ } LT_STMT_END /* --- REPLACEMENT FUNCTIONS --- */ #undef strdup #define strdup rpl_strdup static char *strdup LT_PARAMS((const char *str)); static char * strdup(str) const char *str; { char *tmp = 0; if (str) { tmp = LT_DLMALLOC (char, 1+ strlen (str)); if (tmp) { strcpy(tmp, str); } } return tmp; } #if ! HAVE_STRCMP #undef strcmp #define strcmp rpl_strcmp static int strcmp LT_PARAMS((const char *str1, const char *str2)); static int strcmp (str1, str2) const char *str1; const char *str2; { if (str1 == str2) return 0; if (str1 == 0) return -1; if (str2 == 0) return 1; for (;*str1 && *str2; ++str1, ++str2) { if (*str1 != *str2) break; } return (int)(*str1 - *str2); } #endif #if ! HAVE_STRCHR # if HAVE_INDEX # define strchr index # else # define strchr rpl_strchr static const char *strchr LT_PARAMS((const char *str, int ch)); static const char* strchr(str, ch) const char *str; int ch; { const char *p; for (p = str; *p != (char)ch && *p != LT_EOS_CHAR; ++p) /*NOWORK*/; return (*p == (char)ch) ? p : 0; } # endif #endif /* !HAVE_STRCHR */ #if ! HAVE_STRRCHR # if HAVE_RINDEX # define strrchr rindex # else # define strrchr rpl_strrchr static const char *strrchr LT_PARAMS((const char *str, int ch)); static const char* strrchr(str, ch) const char *str; int ch; { const char *p, *q = 0; for (p = str; *p != LT_EOS_CHAR; ++p) { if (*p == (char) ch) { q = p; } } return q; } # endif #endif /* NOTE: Neither bcopy nor the memcpy implementation below can reliably handle copying in overlapping areas of memory. Use memmove (for which there is a fallback implmentation below) if you need that behaviour. */ #if ! HAVE_MEMCPY # if HAVE_BCOPY # define memcpy(dest, src, size) bcopy (src, dest, size) # else # define memcpy rpl_memcpy static lt_ptr memcpy LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); static lt_ptr memcpy (dest, src, size) lt_ptr dest; const lt_ptr src; size_t size; { size_t i = 0; for (i = 0; i < size; ++i) { dest[i] = src[i]; } return dest; } # endif /* !HAVE_BCOPY */ #endif /* !HAVE_MEMCPY */ #if ! HAVE_MEMMOVE # define memmove rpl_memmove static lt_ptr memmove LT_PARAMS((lt_ptr dest, const lt_ptr src, size_t size)); static lt_ptr memmove (dest, src, size) lt_ptr dest; const lt_ptr src; size_t size; { size_t i; if (dest < src) for (i = 0; i < size; ++i) { dest[i] = src[i]; } else if (dest > src) for (i = size -1; i >= 0; --i) { dest[i] = src[i]; } return dest; } #endif /* !HAVE_MEMMOVE */ #ifdef LT_USE_WINDOWS_DIRENT_EMULATION static void closedir LT_PARAMS((DIR *entry)); static void closedir(entry) DIR *entry; { assert(entry != (DIR *) NULL); FindClose(entry->hSearch); lt_dlfree((lt_ptr)entry); } static DIR * opendir LT_PARAMS((const char *path)); static DIR* opendir (path) const char *path; { char file_specification[LT_FILENAME_MAX]; DIR *entry; assert(path != (char *) NULL); (void) strncpy(file_specification,path,LT_FILENAME_MAX-1); (void) strcat(file_specification,"\\"); entry = LT_DLMALLOC (DIR,sizeof(DIR)); if (entry != (DIR *) 0) { entry->firsttime = TRUE; entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); } if (entry->hSearch == INVALID_HANDLE_VALUE) { (void) strcat(file_specification,"\\*.*"); entry->hSearch = FindFirstFile(file_specification,&entry->Win32FindData); if (entry->hSearch == INVALID_HANDLE_VALUE) { LT_DLFREE (entry); return (DIR *) 0; } } return(entry); } static struct dirent *readdir LT_PARAMS((DIR *entry)); static struct dirent *readdir(entry) DIR *entry; { int status; if (entry == (DIR *) 0) return((struct dirent *) 0); if (!entry->firsttime) { status = FindNextFile(entry->hSearch,&entry->Win32FindData); if (status == 0) return((struct dirent *) 0); } entry->firsttime = FALSE; (void) strncpy(entry->file_info.d_name,entry->Win32FindData.cFileName, LT_FILENAME_MAX-1); entry->file_info.d_namlen = strlen(entry->file_info.d_name); return(&entry->file_info); } #endif /* LT_USE_WINDOWS_DIRENT_EMULATION */ /* According to Alexandre Oliva , ``realloc is not entirely portable'' In any case we want to use the allocator supplied by the user without burdening them with an lt_dlrealloc function pointer to maintain. Instead implement our own version (with known boundary conditions) using lt_dlmalloc and lt_dlfree. */ /* #undef realloc #define realloc rpl_realloc */ #if 0 /* You can't (re)define realloc unless you also (re)define malloc. Right now, this code uses the size of the *destination* to decide how much to copy. That's not right, but you can't know the size of the source unless you know enough about, or wrote malloc. So this code is disabled... */ static lt_ptr realloc (ptr, size) lt_ptr ptr; size_t size; { if (size == 0) { /* For zero or less bytes, free the original memory */ if (ptr != 0) { lt_dlfree (ptr); } return (lt_ptr) 0; } else if (ptr == 0) { /* Allow reallocation of a NULL pointer. */ return lt_dlmalloc (size); } else { /* Allocate a new block, copy and free the old block. */ lt_ptr mem = lt_dlmalloc (size); if (mem) { memcpy (mem, ptr, size); lt_dlfree (ptr); } /* Note that the contents of PTR are not damaged if there is insufficient memory to realloc. */ return mem; } } #endif #if ! HAVE_ARGZ_APPEND # define argz_append rpl_argz_append static error_t argz_append LT_PARAMS((char **pargz, size_t *pargz_len, const char *buf, size_t buf_len)); static error_t argz_append (pargz, pargz_len, buf, buf_len) char **pargz; size_t *pargz_len; const char *buf; size_t buf_len; { size_t argz_len; char *argz; assert (pargz); assert (pargz_len); assert ((*pargz && *pargz_len) || (!*pargz && !*pargz_len)); /* If nothing needs to be appended, no more work is required. */ if (buf_len == 0) return 0; /* Ensure there is enough room to append BUF_LEN. */ argz_len = *pargz_len + buf_len; argz = LT_DLREALLOC (char, *pargz, argz_len); if (!argz) return ENOMEM; /* Copy characters from BUF after terminating '\0' in ARGZ. */ memcpy (argz + *pargz_len, buf, buf_len); /* Assign new values. */ *pargz = argz; *pargz_len = argz_len; return 0; } #endif /* !HAVE_ARGZ_APPEND */ #if ! HAVE_ARGZ_CREATE_SEP # define argz_create_sep rpl_argz_create_sep static error_t argz_create_sep LT_PARAMS((const char *str, int delim, char **pargz, size_t *pargz_len)); static error_t argz_create_sep (str, delim, pargz, pargz_len) const char *str; int delim; char **pargz; size_t *pargz_len; { size_t argz_len; char *argz = 0; assert (str); assert (pargz); assert (pargz_len); /* Make a copy of STR, but replacing each occurence of DELIM with '\0'. */ argz_len = 1+ LT_STRLEN (str); if (argz_len) { const char *p; char *q; argz = LT_DLMALLOC (char, argz_len); if (!argz) return ENOMEM; for (p = str, q = argz; *p != LT_EOS_CHAR; ++p) { if (*p == delim) { /* Ignore leading delimiters, and fold consecutive delimiters in STR into a single '\0' in ARGZ. */ if ((q > argz) && (q[-1] != LT_EOS_CHAR)) *q++ = LT_EOS_CHAR; else --argz_len; } else *q++ = *p; } /* Copy terminating LT_EOS_CHAR. */ *q = *p; } /* If ARGZ_LEN has shrunk to nothing, release ARGZ's memory. */ if (!argz_len) LT_DLFREE (argz); /* Assign new values. */ *pargz = argz; *pargz_len = argz_len; return 0; } #endif /* !HAVE_ARGZ_CREATE_SEP */ #if ! HAVE_ARGZ_INSERT # define argz_insert rpl_argz_insert static error_t argz_insert LT_PARAMS((char **pargz, size_t *pargz_len, char *before, const char *entry)); static error_t argz_insert (pargz, pargz_len, before, entry) char **pargz; size_t *pargz_len; char *before; const char *entry; { assert (pargz); assert (pargz_len); assert (entry && *entry); /* No BEFORE address indicates ENTRY should be inserted after the current last element. */ if (!before) return argz_append (pargz, pargz_len, entry, 1+ LT_STRLEN (entry)); /* This probably indicates a programmer error, but to preserve semantics, scan back to the start of an entry if BEFORE points into the middle of it. */ while ((before > *pargz) && (before[-1] != LT_EOS_CHAR)) --before; { size_t entry_len = 1+ LT_STRLEN (entry); size_t argz_len = *pargz_len + entry_len; size_t offset = before - *pargz; char *argz = LT_DLREALLOC (char, *pargz, argz_len); if (!argz) return ENOMEM; /* Make BEFORE point to the equivalent offset in ARGZ that it used to have in *PARGZ incase realloc() moved the block. */ before = argz + offset; /* Move the ARGZ entries starting at BEFORE up into the new space at the end -- making room to copy ENTRY into the resulting gap. */ memmove (before + entry_len, before, *pargz_len - offset); memcpy (before, entry, entry_len); /* Assign new values. */ *pargz = argz; *pargz_len = argz_len; } return 0; } #endif /* !HAVE_ARGZ_INSERT */ #if ! HAVE_ARGZ_NEXT # define argz_next rpl_argz_next static char *argz_next LT_PARAMS((char *argz, size_t argz_len, const char *entry)); static char * argz_next (argz, argz_len, entry) char *argz; size_t argz_len; const char *entry; { assert ((argz && argz_len) || (!argz && !argz_len)); if (entry) { /* Either ARGZ/ARGZ_LEN is empty, or ENTRY points into an address within the ARGZ vector. */ assert ((!argz && !argz_len) || ((argz <= entry) && (entry < (argz + argz_len)))); /* Move to the char immediately after the terminating '\0' of ENTRY. */ entry = 1+ strchr (entry, LT_EOS_CHAR); /* Return either the new ENTRY, or else NULL if ARGZ is exhausted. */ return (entry >= argz + argz_len) ? 0 : (char *) entry; } else { /* This should probably be flagged as a programmer error, since starting an argz_next loop with the iterator set to ARGZ is safer. To preserve semantics, handle the NULL case by returning the start of ARGZ (if any). */ if (argz_len > 0) return argz; else return 0; } } #endif /* !HAVE_ARGZ_NEXT */ #if ! HAVE_ARGZ_STRINGIFY # define argz_stringify rpl_argz_stringify static void argz_stringify LT_PARAMS((char *argz, size_t argz_len, int sep)); static void argz_stringify (argz, argz_len, sep) char *argz; size_t argz_len; int sep; { assert ((argz && argz_len) || (!argz && !argz_len)); if (sep) { --argz_len; /* don't stringify the terminating EOS */ while (--argz_len > 0) { if (argz[argz_len] == LT_EOS_CHAR) argz[argz_len] = sep; } } } #endif /* !HAVE_ARGZ_STRINGIFY */ /* --- TYPE DEFINITIONS -- */ /* This type is used for the array of caller data sets in each handler. */ typedef struct { lt_dlcaller_id key; lt_ptr data; } lt_caller_data; /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */ /* Extract the diagnostic strings from the error table macro in the same order as the enumerated indices in ltdl.h. */ static const char *lt_dlerror_strings[] = { #define LT_ERROR(name, diagnostic) (diagnostic), lt_dlerror_table #undef LT_ERROR 0 }; /* This structure is used for the list of registered loaders. */ struct lt_dlloader { struct lt_dlloader *next; const char *loader_name; /* identifying name for each loader */ const char *sym_prefix; /* prefix for symbols */ lt_module_open *module_open; lt_module_close *module_close; lt_find_sym *find_sym; lt_dlloader_exit *dlloader_exit; lt_user_data dlloader_data; }; struct lt_dlhandle_struct { struct lt_dlhandle_struct *next; lt_dlloader *loader; /* dlopening interface */ lt_dlinfo info; int depcount; /* number of dependencies */ lt_dlhandle *deplibs; /* dependencies */ lt_module module; /* system module handle */ lt_ptr system; /* system specific data */ lt_caller_data *caller_data; /* per caller associated data */ int flags; /* various boolean stats */ }; /* Various boolean flags can be stored in the flags field of an lt_dlhandle_struct... */ #define LT_DLGET_FLAG(handle, flag) (((handle)->flags & (flag)) == (flag)) #define LT_DLSET_FLAG(handle, flag) ((handle)->flags |= (flag)) #define LT_DLRESIDENT_FLAG (0x01 << 0) /* ...add more flags here... */ #define LT_DLIS_RESIDENT(handle) LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG) #define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)] static const char objdir[] = LTDL_OBJDIR; static const char archive_ext[] = LTDL_ARCHIVE_EXT; #ifdef LTDL_SHLIB_EXT static const char shlib_ext[] = LTDL_SHLIB_EXT; #endif #ifdef LTDL_SYSSEARCHPATH static const char sys_search_path[] = LTDL_SYSSEARCHPATH; #endif /* --- MUTEX LOCKING --- */ /* Macros to make it easier to run the lock functions only if they have been registered. The reason for the complicated lock macro is to ensure that the stored error message from the last error is not accidentally erased if the current function doesn't generate an error of its own. */ #define LT_DLMUTEX_LOCK() LT_STMT_START { \ if (lt_dlmutex_lock_func) (*lt_dlmutex_lock_func)(); \ } LT_STMT_END #define LT_DLMUTEX_UNLOCK() LT_STMT_START { \ if (lt_dlmutex_unlock_func) (*lt_dlmutex_unlock_func)();\ } LT_STMT_END #define LT_DLMUTEX_SETERROR(errormsg) LT_STMT_START { \ if (lt_dlmutex_seterror_func) \ (*lt_dlmutex_seterror_func) (errormsg); \ else lt_dllast_error = (errormsg); } LT_STMT_END #define LT_DLMUTEX_GETERROR(errormsg) LT_STMT_START { \ if (lt_dlmutex_seterror_func) \ (errormsg) = (*lt_dlmutex_geterror_func) (); \ else (errormsg) = lt_dllast_error; } LT_STMT_END /* The mutex functions stored here are global, and are necessarily the same for all threads that wish to share access to libltdl. */ static lt_dlmutex_lock *lt_dlmutex_lock_func = 0; static lt_dlmutex_unlock *lt_dlmutex_unlock_func = 0; static lt_dlmutex_seterror *lt_dlmutex_seterror_func = 0; static lt_dlmutex_geterror *lt_dlmutex_geterror_func = 0; static const char *lt_dllast_error = 0; /* Either set or reset the mutex functions. Either all the arguments must be valid functions, or else all can be NULL to turn off locking entirely. The registered functions should be manipulating a static global lock from the lock() and unlock() callbacks, which needs to be reentrant. */ int lt_dlmutex_register (lock, unlock, seterror, geterror) lt_dlmutex_lock *lock; lt_dlmutex_unlock *unlock; lt_dlmutex_seterror *seterror; lt_dlmutex_geterror *geterror; { lt_dlmutex_unlock *old_unlock = unlock; int errors = 0; /* Lock using the old lock() callback, if any. */ LT_DLMUTEX_LOCK (); if ((lock && unlock && seterror && geterror) || !(lock || unlock || seterror || geterror)) { lt_dlmutex_lock_func = lock; lt_dlmutex_unlock_func = unlock; lt_dlmutex_geterror_func = geterror; } else { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS)); ++errors; } /* Use the old unlock() callback we saved earlier, if any. Otherwise record any errors using internal storage. */ if (old_unlock) (*old_unlock) (); /* Return the number of errors encountered during the execution of this function. */ return errors; } /* --- ERROR HANDLING --- */ static const char **user_error_strings = 0; static int errorcount = LT_ERROR_MAX; int lt_dladderror (diagnostic) const char *diagnostic; { int errindex = 0; int result = -1; const char **temp = (const char **) 0; assert (diagnostic); LT_DLMUTEX_LOCK (); errindex = errorcount - LT_ERROR_MAX; temp = LT_EREALLOC (const char *, user_error_strings, 1 + errindex); if (temp) { user_error_strings = temp; user_error_strings[errindex] = diagnostic; result = errorcount++; } LT_DLMUTEX_UNLOCK (); return result; } int lt_dlseterror (errindex) int errindex; { int errors = 0; LT_DLMUTEX_LOCK (); if (errindex >= errorcount || errindex < 0) { /* Ack! Error setting the error message! */ LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); ++errors; } else if (errindex < LT_ERROR_MAX) { /* No error setting the error message! */ LT_DLMUTEX_SETERROR (lt_dlerror_strings[errindex]); } else { /* No error setting the error message! */ LT_DLMUTEX_SETERROR (user_error_strings[errindex - LT_ERROR_MAX]); } LT_DLMUTEX_UNLOCK (); return errors; } static lt_ptr lt_emalloc (size) size_t size; { lt_ptr mem = lt_dlmalloc (size); if (size && !mem) LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return mem; } static lt_ptr lt_erealloc (addr, size) lt_ptr addr; size_t size; { lt_ptr mem = lt_dlrealloc (addr, size); if (size && !mem) LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return mem; } static char * lt_estrdup (str) const char *str; { char *copy = strdup (str); if (LT_STRLEN (str) && !copy) LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return copy; } /* --- DLOPEN() INTERFACE LOADER --- */ #if HAVE_LIBDL /* dynamic linking with dlopen/dlsym */ #if HAVE_DLFCN_H # include #endif #if HAVE_SYS_DL_H # include #endif #ifdef RTLD_GLOBAL # define LT_GLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_GLOBAL DL_GLOBAL # endif #endif /* !RTLD_GLOBAL */ #ifndef LT_GLOBAL # define LT_GLOBAL 0 #endif /* !LT_GLOBAL */ /* We may have to define LT_LAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_LAZY_OR_NOW # ifdef RTLD_LAZY # define LT_LAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_LAZY_OR_NOW DL_LAZY # endif # endif /* !RTLD_LAZY */ #endif #ifndef LT_LAZY_OR_NOW # ifdef RTLD_NOW # define LT_LAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_LAZY_OR_NOW DL_NOW # endif # endif /* !RTLD_NOW */ #endif #ifndef LT_LAZY_OR_NOW # define LT_LAZY_OR_NOW 0 #endif /* !LT_LAZY_OR_NOW */ #if HAVE_DLERROR # define DLERROR(arg) dlerror () #else # define DLERROR(arg) LT_DLSTRERROR (arg) #endif static lt_module sys_dl_open (loader_data, filename) lt_user_data loader_data; const char *filename; { lt_module module = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW); UNREFERENCED(loader_data); if (!module) { LT_DLMUTEX_SETERROR (DLERROR (CANNOT_OPEN)); } return module; } static int sys_dl_close (loader_data, module) lt_user_data loader_data; lt_module module; { int errors = 0; UNREFERENCED(loader_data); if (dlclose (module) != 0) { LT_DLMUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); ++errors; } return errors; } static lt_ptr sys_dl_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol; { lt_ptr address = dlsym (module, symbol); UNREFERENCED(loader_data); if (!address) { LT_DLMUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); } return address; } static struct lt_user_dlloader sys_dl = { # ifdef NEED_USCORE "_", # else 0, # endif sys_dl_open, sys_dl_close, sys_dl_sym, 0, 0 }; #endif /* HAVE_LIBDL */ /* --- SHL_LOAD() INTERFACE LOADER --- */ #if HAVE_SHL_LOAD /* dynamic linking with shl_load (HP-UX) (comments from gmodule) */ #ifdef HAVE_DL_H # include #endif /* some flags are missing on some systems, so we provide * harmless defaults. * * Mandatory: * BIND_IMMEDIATE - Resolve symbol references when the library is loaded. * BIND_DEFERRED - Delay code symbol resolution until actual reference. * * Optionally: * BIND_FIRST - Place the library at the head of the symbol search * order. * BIND_NONFATAL - The default BIND_IMMEDIATE behavior is to treat all * unsatisfied symbols as fatal. This flag allows * binding of unsatisfied code symbols to be deferred * until use. * [Perl: For certain libraries, like DCE, deferred * binding often causes run time problems. Adding * BIND_NONFATAL to BIND_IMMEDIATE still allows * unresolved references in situations like this.] * BIND_NOSTART - Do not call the initializer for the shared library * when the library is loaded, nor on a future call to * shl_unload(). * BIND_VERBOSE - Print verbose messages concerning possible * unsatisfied symbols. * * hp9000s700/hp9000s800: * BIND_RESTRICTED - Restrict symbols visible by the library to those * present at library load time. * DYNAMIC_PATH - Allow the loader to dynamically search for the * library specified by the path argument. */ #ifndef DYNAMIC_PATH # define DYNAMIC_PATH 0 #endif #ifndef BIND_RESTRICTED # define BIND_RESTRICTED 0 #endif #define LT_BIND_FLAGS (BIND_IMMEDIATE | BIND_NONFATAL | DYNAMIC_PATH) static lt_module sys_shl_open (loader_data, filename) lt_user_data loader_data; const char *filename; { static shl_t self = (shl_t) 0; lt_module module = shl_load (filename, LT_BIND_FLAGS, 0L); /* Since searching for a symbol against a NULL module handle will also look in everything else that was already loaded and exported with the -E compiler flag, we always cache a handle saved before any modules are loaded. */ if (!self) { lt_ptr address; shl_findsym (&self, "main", TYPE_UNDEFINED, &address); } if (!filename) { module = self; } else { module = shl_load (filename, LT_BIND_FLAGS, 0L); if (!module) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); } } return module; } static int sys_shl_close (loader_data, module) lt_user_data loader_data; lt_module module; { int errors = 0; if (module && (shl_unload ((shl_t) (module)) != 0)) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } return errors; } static lt_ptr sys_shl_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol; { lt_ptr address = 0; /* sys_shl_open should never return a NULL module handle */ if (module == (lt_module) 0) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); } else if (!shl_findsym((shl_t*) &module, symbol, TYPE_UNDEFINED, &address)) { if (!address) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } } return address; } static struct lt_user_dlloader sys_shl = { 0, sys_shl_open, sys_shl_close, sys_shl_sym, 0, 0 }; #endif /* HAVE_SHL_LOAD */ /* --- LOADLIBRARY() INTERFACE LOADER --- */ #ifdef __WINDOWS__ /* dynamic linking for Win32 */ #include /* Forward declaration; required to implement handle search below. */ static lt_dlhandle handles; static lt_module sys_wll_open (loader_data, filename) lt_user_data loader_data; const char *filename; { lt_dlhandle cur; lt_module module = 0; const char *errormsg = 0; char *searchname = 0; char *ext; char self_name_buf[MAX_PATH]; if (!filename) { /* Get the name of main module */ *self_name_buf = 0; GetModuleFileName (NULL, self_name_buf, sizeof (self_name_buf)); filename = ext = self_name_buf; } else { ext = strrchr (filename, '.'); } if (ext) { /* FILENAME already has an extension. */ searchname = lt_estrdup (filename); } else { /* Append a `.' to stop Windows from adding an implicit `.dll' extension. */ searchname = LT_EMALLOC (char, 2+ LT_STRLEN (filename)); if (searchname) sprintf (searchname, "%s.", filename); } if (!searchname) return 0; #if __CYGWIN__ { char wpath[MAX_PATH]; cygwin_conv_to_full_win32_path(searchname, wpath); module = LoadLibrary(wpath); } #else module = LoadLibrary (searchname); #endif LT_DLFREE (searchname); /* libltdl expects this function to fail if it is unable to physically load the library. Sadly, LoadLibrary will search the loaded libraries for a match and return one of them if the path search load fails. We check whether LoadLibrary is returning a handle to an already loaded module, and simulate failure if we find one. */ LT_DLMUTEX_LOCK (); cur = handles; while (cur) { if (!cur->module) { cur = 0; break; } if (cur->module == module) { break; } cur = cur->next; } LT_DLMUTEX_UNLOCK (); if (cur || !module) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); module = 0; } return module; } static int sys_wll_close (loader_data, module) lt_user_data loader_data; lt_module module; { int errors = 0; if (FreeLibrary(module) == 0) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } return errors; } static lt_ptr sys_wll_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol; { lt_ptr address = GetProcAddress (module, symbol); if (!address) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } return address; } static struct lt_user_dlloader sys_wll = { 0, sys_wll_open, sys_wll_close, sys_wll_sym, 0, 0 }; #endif /* __WINDOWS__ */ /* --- LOAD_ADD_ON() INTERFACE LOADER --- */ #ifdef __BEOS__ /* dynamic linking for BeOS */ #include static lt_module sys_bedl_open (loader_data, filename) lt_user_data loader_data; const char *filename; { image_id image = 0; if (filename) { image = load_add_on (filename); } else { image_info info; int32 cookie = 0; if (get_next_image_info (0, &cookie, &info) == B_OK) image = load_add_on (info.name); } if (image <= 0) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); image = 0; } return (lt_module) image; } static int sys_bedl_close (loader_data, module) lt_user_data loader_data; lt_module module; { int errors = 0; if (unload_add_on ((image_id) module) != B_OK) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } return errors; } static lt_ptr sys_bedl_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol; { lt_ptr address = 0; image_id image = (image_id) module; if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); address = 0; } return address; } static struct lt_user_dlloader sys_bedl = { 0, sys_bedl_open, sys_bedl_close, sys_bedl_sym, 0, 0 }; #endif /* __BEOS__ */ /* --- DLD_LINK() INTERFACE LOADER --- */ #if HAVE_DLD /* dynamic linking with dld */ #if HAVE_DLD_H #include #endif static lt_module sys_dld_open (loader_data, filename) lt_user_data loader_data; const char *filename; { lt_module module = strdup (filename); if (dld_link (filename) != 0) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); LT_DLFREE (module); module = 0; } return module; } static int sys_dld_close (loader_data, module) lt_user_data loader_data; lt_module module; { int errors = 0; if (dld_unlink_by_file ((char*)(module), 1) != 0) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); ++errors; } else { LT_DLFREE (module); } return errors; } static lt_ptr sys_dld_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol; { lt_ptr address = dld_get_func (symbol); if (!address) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } return address; } static struct lt_user_dlloader sys_dld = { 0, sys_dld_open, sys_dld_close, sys_dld_sym, 0, 0 }; #endif /* HAVE_DLD */ /* --- DYLD() MACOSX/DARWIN INTERFACE LOADER --- */ #if HAVE_DYLD #if HAVE_MACH_O_DYLD_H #if !defined(__APPLE_CC__) && !defined(__MWERKS__) && !defined(__private_extern__) /* Is this correct? Does it still function properly? */ #define __private_extern__ extern #endif # include #endif #include /* We have to put some stuff here that isn't in older dyld.h files */ #ifndef ENUM_DYLD_BOOL # define ENUM_DYLD_BOOL # undef FALSE # undef TRUE enum DYLD_BOOL { FALSE, TRUE }; #endif #ifndef LC_REQ_DYLD # define LC_REQ_DYLD 0x80000000 #endif #ifndef LC_LOAD_WEAK_DYLIB # define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) #endif static const struct mach_header * (*ltdl_NSAddImage)(const char *image_name, unsigned long options) = 0; static NSSymbol (*ltdl_NSLookupSymbolInImage)(const struct mach_header *image,const char *symbolName, unsigned long options) = 0; static enum DYLD_BOOL (*ltdl_NSIsSymbolNameDefinedInImage)(const struct mach_header *image, const char *symbolName) = 0; static enum DYLD_BOOL (*ltdl_NSMakePrivateModulePublic)(NSModule module) = 0; #ifndef NSADDIMAGE_OPTION_NONE #define NSADDIMAGE_OPTION_NONE 0x0 #endif #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1 #endif #ifndef NSADDIMAGE_OPTION_WITH_SEARCHING #define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2 #endif #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4 #endif #ifndef NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME #define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8 #endif #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0 #endif #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1 #endif #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2 #endif #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4 #endif static const char * lt_int_dyld_error(othererror) char* othererror; { /* return the dyld error string, or the passed in error string if none */ NSLinkEditErrors ler; int lerno; const char *errstr; const char *file; NSLinkEditError(&ler,&lerno,&file,&errstr); if (!errstr || !strlen(errstr)) errstr = othererror; return errstr; } static const struct mach_header * lt_int_dyld_get_mach_header_from_nsmodule(module) NSModule module; { /* There should probably be an apple dyld api for this */ int i=_dyld_image_count(); int j; const char *modname=NSNameOfModule(module); const struct mach_header *mh=NULL; if (!modname) return NULL; for (j = 0; j < i; j++) { if (!strcmp(_dyld_get_image_name(j),modname)) { mh=_dyld_get_image_header(j); break; } } return mh; } static const char* lt_int_dyld_lib_install_name(mh) const struct mach_header *mh; { /* NSAddImage is also used to get the loaded image, but it only works if the lib is installed, for uninstalled libs we need to check the install_names against each other. Note that this is still broken if DYLD_IMAGE_SUFFIX is set and a different lib was loaded as a result */ int j; struct load_command *lc; unsigned long offset = sizeof(struct mach_header); const char* retStr=NULL; for (j = 0; j < mh->ncmds; j++) { lc = (struct load_command*)(((unsigned long)mh) + offset); if (LC_ID_DYLIB == lc->cmd) { retStr=(char*)(((struct dylib_command*)lc)->dylib.name.offset + (unsigned long)lc); } offset += lc->cmdsize; } return retStr; } static const struct mach_header * lt_int_dyld_match_loaded_lib_by_install_name(const char *name) { int i=_dyld_image_count(); int j; const struct mach_header *mh=NULL; const char *id=NULL; for (j = 0; j < i; j++) { id=lt_int_dyld_lib_install_name(_dyld_get_image_header(j)); if ((id) && (!strcmp(id,name))) { mh=_dyld_get_image_header(j); break; } } return mh; } static NSSymbol lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh) const char *symbol; const struct mach_header *mh; { /* Safe to assume our mh is good */ int j; struct load_command *lc; unsigned long offset = sizeof(struct mach_header); NSSymbol retSym = 0; const struct mach_header *mh1; if ((ltdl_NSLookupSymbolInImage) && NSIsSymbolNameDefined(symbol) ) { for (j = 0; j < mh->ncmds; j++) { lc = (struct load_command*)(((unsigned long)mh) + offset); if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd)) { mh1=lt_int_dyld_match_loaded_lib_by_install_name((char*)(((struct dylib_command*)lc)->dylib.name.offset + (unsigned long)lc)); if (!mh1) { /* Maybe NSAddImage can find it */ mh1=ltdl_NSAddImage((char*)(((struct dylib_command*)lc)->dylib.name.offset + (unsigned long)lc), NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED + NSADDIMAGE_OPTION_WITH_SEARCHING + NSADDIMAGE_OPTION_RETURN_ON_ERROR ); } if (mh1) { retSym = ltdl_NSLookupSymbolInImage(mh1, symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ); if (retSym) break; } } offset += lc->cmdsize; } } return retSym; } static int sys_dyld_init() { int retCode = 0; int err = 0; if (!_dyld_present()) { retCode=1; } else { err = _dyld_func_lookup("__dyld_NSAddImage",(unsigned long*)<dl_NSAddImage); err = _dyld_func_lookup("__dyld_NSLookupSymbolInImage",(unsigned long*)<dl_NSLookupSymbolInImage); err = _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",(unsigned long*)<dl_NSIsSymbolNameDefinedInImage); err = _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",(unsigned long*)<dl_NSMakePrivateModulePublic); } return retCode; } static lt_module sys_dyld_open (loader_data, filename) lt_user_data loader_data; const char *filename; { lt_module module = 0; NSObjectFileImage ofi = 0; NSObjectFileImageReturnCode ofirc; if (!filename) return (lt_module)-1; ofirc = NSCreateObjectFileImageFromFile(filename, &ofi); switch (ofirc) { case NSObjectFileImageSuccess: module = NSLinkModule(ofi, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_BINDNOW); NSDestroyObjectFileImage(ofi); if (module) ltdl_NSMakePrivateModulePublic(module); break; case NSObjectFileImageInappropriateFile: if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) { module = (lt_module)ltdl_NSAddImage(filename, NSADDIMAGE_OPTION_RETURN_ON_ERROR); break; } default: LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); return 0; } if (!module) LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_OPEN))); return module; } static int sys_dyld_close (loader_data, module) lt_user_data loader_data; lt_module module; { int retCode = 0; int flags = 0; if (module == (lt_module)-1) return 0; #ifdef __BIG_ENDIAN__ if (((struct mach_header *)module)->magic == MH_MAGIC) #else if (((struct mach_header *)module)->magic == MH_CIGAM) #endif { LT_DLMUTEX_SETERROR("Can not close a dylib"); retCode = 1; } else { #if 1 /* Currently, if a module contains c++ static destructors and it is unloaded, we get a segfault in atexit(), due to compiler and dynamic loader differences of opinion, this works around that. */ if ((const struct section *)NULL != getsectbynamefromheader(lt_int_dyld_get_mach_header_from_nsmodule(module), "__DATA","__mod_term_func")) { flags += NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; } #endif #ifdef __ppc__ flags += NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES; #endif if (!NSUnLinkModule(module,flags)) { retCode=1; LT_DLMUTEX_SETERROR (lt_int_dyld_error(LT_DLSTRERROR(CANNOT_CLOSE))); } } return retCode; } static lt_ptr sys_dyld_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol; { lt_ptr address = 0; NSSymbol *nssym = 0; void *unused; const struct mach_header *mh=NULL; char saveError[256] = "Symbol not found"; if (module == (lt_module)-1) { _dyld_lookup_and_bind(symbol,(unsigned long*)&address,&unused); return address; } #ifdef __BIG_ENDIAN__ if (((struct mach_header *)module)->magic == MH_MAGIC) #else if (((struct mach_header *)module)->magic == MH_CIGAM) #endif { if (ltdl_NSIsSymbolNameDefinedInImage && ltdl_NSLookupSymbolInImage) { mh=module; if (ltdl_NSIsSymbolNameDefinedInImage((struct mach_header*)module,symbol)) { nssym = ltdl_NSLookupSymbolInImage((struct mach_header*)module, symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ); } } } else { nssym = NSLookupSymbolInModule(module, symbol); } if (!nssym) { strncpy(saveError, lt_int_dyld_error(LT_DLSTRERROR(SYMBOL_NOT_FOUND)), 255); saveError[255] = 0; if (!mh) mh=lt_int_dyld_get_mach_header_from_nsmodule(module); nssym = lt_int_dyld_NSlookupSymbolInLinkedLibs(symbol,mh); } if (!nssym) { LT_DLMUTEX_SETERROR (saveError); return NULL; } return NSAddressOfSymbol(nssym); } static struct lt_user_dlloader sys_dyld = { "_", sys_dyld_open, sys_dyld_close, sys_dyld_sym, 0, 0 }; #endif /* HAVE_DYLD */ /* --- DLPREOPEN() INTERFACE LOADER --- */ /* emulate dynamic linking using preloaded_symbols */ typedef struct lt_dlsymlists_t { struct lt_dlsymlists_t *next; const lt_dlsymlist *syms; } lt_dlsymlists_t; static const lt_dlsymlist *default_preloaded_symbols = 0; static lt_dlsymlists_t *preloaded_symbols = 0; static int presym_init (loader_data) lt_user_data loader_data; { int errors = 0; UNREFERENCED(loader_data); LT_DLMUTEX_LOCK (); preloaded_symbols = 0; if (default_preloaded_symbols) { errors = lt_dlpreload (default_preloaded_symbols); } LT_DLMUTEX_UNLOCK (); return errors; } static int presym_free_symlists () { lt_dlsymlists_t *lists; LT_DLMUTEX_LOCK (); lists = preloaded_symbols; while (lists) { lt_dlsymlists_t *tmp = lists; lists = lists->next; LT_DLFREE (tmp); } preloaded_symbols = 0; LT_DLMUTEX_UNLOCK (); return 0; } static int presym_exit (loader_data) lt_user_data loader_data; { UNREFERENCED(loader_data); presym_free_symlists (); return 0; } static int presym_add_symlist (preloaded) const lt_dlsymlist *preloaded; { lt_dlsymlists_t *tmp; lt_dlsymlists_t *lists; int errors = 0; LT_DLMUTEX_LOCK (); lists = preloaded_symbols; while (lists) { if (lists->syms == preloaded) { goto done; } lists = lists->next; } tmp = LT_EMALLOC (lt_dlsymlists_t, 1); if (tmp) { memset (tmp, 0, sizeof(lt_dlsymlists_t)); tmp->syms = preloaded; tmp->next = preloaded_symbols; preloaded_symbols = tmp; } else { ++errors; } done: LT_DLMUTEX_UNLOCK (); return errors; } static lt_module presym_open (loader_data, filename) lt_user_data loader_data; const char *filename; { lt_dlsymlists_t *lists; lt_module module = (lt_module) 0; UNREFERENCED(loader_data); LT_DLMUTEX_LOCK (); lists = preloaded_symbols; if (!lists) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS)); goto done; } /* Can't use NULL as the reflective symbol header, as NULL is used to mark the end of the entire symbol list. Self-dlpreopened symbols follow this magic number, chosen to be an unlikely clash with a real module name. */ if (!filename) { filename = "@PROGRAM@"; } while (lists) { const lt_dlsymlist *syms = lists->syms; while (syms->name) { if (!syms->address && strcmp(syms->name, filename) == 0) { module = (lt_module) syms; goto done; } ++syms; } lists = lists->next; } LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); done: LT_DLMUTEX_UNLOCK (); return module; } static int presym_close (loader_data, module) lt_user_data loader_data; lt_module module; { /* Just to silence gcc -Wall */ UNREFERENCED(loader_data); UNREFERENCED(module); return 0; } static lt_ptr presym_sym (loader_data, module, symbol) lt_user_data loader_data; lt_module module; const char *symbol; { lt_dlsymlist *syms = (lt_dlsymlist*) module; UNREFERENCED(loader_data); ++syms; while (syms->address) { if (strcmp(syms->name, symbol) == 0) { return syms->address; } ++syms; } LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); return 0; } static struct lt_user_dlloader presym = { 0, presym_open, presym_close, presym_sym, presym_exit, 0 }; /* --- DYNAMIC MODULE LOADING --- */ /* The type of a function used at each iteration of foreach_dirinpath(). */ typedef int foreach_callback_func LT_PARAMS((char *filename, lt_ptr data1, lt_ptr data2)); static int foreach_dirinpath LT_PARAMS((const char *search_path, const char *base_name, foreach_callback_func *func, lt_ptr data1, lt_ptr data2)); static int find_file_callback LT_PARAMS((char *filename, lt_ptr data, lt_ptr ignored)); static int find_handle_callback LT_PARAMS((char *filename, lt_ptr data, lt_ptr ignored)); static int foreachfile_callback LT_PARAMS((char *filename, lt_ptr data1, lt_ptr data2)); static int canonicalize_path LT_PARAMS((const char *path, char **pcanonical)); static int argzize_path LT_PARAMS((const char *path, char **pargz, size_t *pargz_len)); static FILE *find_file LT_PARAMS((const char *search_path, const char *base_name, char **pdir)); static lt_dlhandle *find_handle LT_PARAMS((const char *search_path, const char *base_name, lt_dlhandle *handle)); static int find_module LT_PARAMS((lt_dlhandle *handle, const char *dir, const char *libdir, const char *dlname, const char *old_name, int installed)); static int free_vars LT_PARAMS((char *dlname, char *oldname, char *libdir, char *deplibs)); static int load_deplibs LT_PARAMS((lt_dlhandle handle, char *deplibs)); static int trim LT_PARAMS((char **dest, const char *str)); static int try_dlopen LT_PARAMS((lt_dlhandle *handle, const char *filename)); static int tryall_dlopen LT_PARAMS((lt_dlhandle *handle, const char *filename)); static int unload_deplibs LT_PARAMS((lt_dlhandle handle)); static int lt_argz_insert LT_PARAMS((char **pargz, size_t *pargz_len, char *before, const char *entry)); static int lt_argz_insertinorder LT_PARAMS((char **pargz, size_t *pargz_len, const char *entry)); static int lt_argz_insertdir LT_PARAMS((char **pargz, size_t *pargz_len, const char *dirnam, struct dirent *dp)); static int lt_dlpath_insertdir LT_PARAMS((char **ppath, char *before, const char *dir)); static int list_files_by_dir LT_PARAMS((const char *dirnam, char **pargz, size_t *pargz_len)); static int file_not_found LT_PARAMS((void)); static char *user_search_path= 0; static lt_dlloader *loaders = 0; static lt_dlhandle handles = 0; static int initialized = 0; /* Initialize libltdl. */ int lt_dlinit () { int errors = 0; LT_DLMUTEX_LOCK (); /* Initialize only at first call. */ if (++initialized == 1) { handles = 0; user_search_path = 0; /* empty search path */ #if HAVE_LIBDL errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dl, "dlopen"); #endif #if HAVE_SHL_LOAD errors += lt_dlloader_add (lt_dlloader_next (0), &sys_shl, "dlopen"); #endif #ifdef __WINDOWS__ errors += lt_dlloader_add (lt_dlloader_next (0), &sys_wll, "dlopen"); #endif #ifdef __BEOS__ errors += lt_dlloader_add (lt_dlloader_next (0), &sys_bedl, "dlopen"); #endif #if HAVE_DLD errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dld, "dld"); #endif #if HAVE_DYLD errors += lt_dlloader_add (lt_dlloader_next (0), &sys_dyld, "dyld"); errors += sys_dyld_init(); #endif errors += lt_dlloader_add (lt_dlloader_next (0), &presym, "dlpreload"); if (presym_init (presym.dlloader_data)) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); ++errors; } else if (errors != 0) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); ++errors; } } LT_DLMUTEX_UNLOCK (); return errors; } int lt_dlpreload (preloaded) const lt_dlsymlist *preloaded; { int errors = 0; if (preloaded) { errors = presym_add_symlist (preloaded); } else { presym_free_symlists(); LT_DLMUTEX_LOCK (); if (default_preloaded_symbols) { errors = lt_dlpreload (default_preloaded_symbols); } LT_DLMUTEX_UNLOCK (); } return errors; } int lt_dlpreload_default (preloaded) const lt_dlsymlist *preloaded; { LT_DLMUTEX_LOCK (); default_preloaded_symbols = preloaded; LT_DLMUTEX_UNLOCK (); return 0; } int lt_dlexit () { /* shut down libltdl */ lt_dlloader *loader; int errors = 0; LT_DLMUTEX_LOCK (); loader = loaders; if (!initialized) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); ++errors; goto done; } /* shut down only at last call. */ if (--initialized == 0) { int level; while (handles && LT_DLIS_RESIDENT (handles)) { handles = handles->next; } /* close all modules */ for (level = 1; handles; ++level) { lt_dlhandle cur = handles; int saw_nonresident = 0; while (cur) { lt_dlhandle tmp = cur; cur = cur->next; if (!LT_DLIS_RESIDENT (tmp)) saw_nonresident = 1; if (!LT_DLIS_RESIDENT (tmp) && tmp->info.ref_count <= level) { if (lt_dlclose (tmp)) { ++errors; } } } /* done if only resident modules are left */ if (!saw_nonresident) break; } /* close all loaders */ while (loader) { lt_dlloader *next = loader->next; lt_user_data data = loader->dlloader_data; if (loader->dlloader_exit && loader->dlloader_exit (data)) { ++errors; } LT_DLMEM_REASSIGN (loader, next); } loaders = 0; } done: LT_DLMUTEX_UNLOCK (); return errors; } static int tryall_dlopen (handle, filename) lt_dlhandle *handle; const char *filename; { lt_dlhandle cur; lt_dlloader *loader; const char *saved_error; int errors = 0; LT_DLMUTEX_GETERROR (saved_error); LT_DLMUTEX_LOCK (); cur = handles; loader = loaders; /* check whether the module was already opened */ while (cur) { /* try to dlopen the program itself? */ if (!cur->info.filename && !filename) { break; } if (cur->info.filename && filename && strcmp (cur->info.filename, filename) == 0) { break; } cur = cur->next; } if (cur) { ++cur->info.ref_count; *handle = cur; goto done; } cur = *handle; if (filename) { /* Comment out the check of file permissions using access. This call seems to always return -1 with error EACCES. */ /* We need to catch missing file errors early so that file_not_found() can detect what happened. if (access (filename, R_OK) != 0) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); ++errors; goto done; } */ cur->info.filename = lt_estrdup (filename); if (!cur->info.filename) { ++errors; goto done; } } else { cur->info.filename = 0; } while (loader) { lt_user_data data = loader->dlloader_data; cur->module = loader->module_open (data, filename); if (cur->module != 0) { break; } loader = loader->next; } if (!loader) { LT_DLFREE (cur->info.filename); ++errors; goto done; } cur->loader = loader; LT_DLMUTEX_SETERROR (saved_error); done: LT_DLMUTEX_UNLOCK (); return errors; } static int tryall_dlopen_module (handle, prefix, dirname, dlname) lt_dlhandle *handle; const char *prefix; const char *dirname; const char *dlname; { int error = 0; char *filename = 0; size_t filename_len = 0; size_t dirname_len = LT_STRLEN (dirname); assert (handle); assert (dirname); assert (dlname); #ifdef LT_DIRSEP_CHAR /* Only canonicalized names (i.e. with DIRSEP chars already converted) should make it into this function: */ assert (strchr (dirname, LT_DIRSEP_CHAR) == 0); #endif if (dirname_len > 0) if (dirname[dirname_len -1] == '/') --dirname_len; filename_len = dirname_len + 1 + LT_STRLEN (dlname); /* Allocate memory, and combine DIRNAME and MODULENAME into it. The PREFIX (if any) is handled below. */ filename = LT_EMALLOC (char, dirname_len + 1 + filename_len + 1); if (!filename) return 1; sprintf (filename, "%.*s/%s", (int) dirname_len, dirname, dlname); /* Now that we have combined DIRNAME and MODULENAME, if there is also a PREFIX to contend with, simply recurse with the arguments shuffled. Otherwise, attempt to open FILENAME as a module. */ if (prefix) { error += tryall_dlopen_module (handle, (const char *) 0, prefix, filename); } else if (tryall_dlopen (handle, filename) != 0) { ++error; } LT_DLFREE (filename); return error; } static int find_module (handle, dir, libdir, dlname, old_name, installed) lt_dlhandle *handle; const char *dir; const char *libdir; const char *dlname; const char *old_name; int installed; { /* Try to open the old library first; if it was dlpreopened, we want the preopened version of it, even if a dlopenable module is available. */ if (old_name && tryall_dlopen (handle, old_name) == 0) { return 0; } /* Try to open the dynamic library. */ if (dlname) { /* try to open the installed module */ if (installed && libdir) { if (tryall_dlopen_module (handle, (const char *) 0, libdir, dlname) == 0) return 0; } /* try to open the not-installed module */ if (!installed) { if (tryall_dlopen_module (handle, dir, objdir, dlname) == 0) return 0; } /* maybe it was moved to another directory */ { if (tryall_dlopen_module (handle, (const char *) 0, dir, dlname) == 0) return 0; } } return 1; } static int canonicalize_path (path, pcanonical) const char *path; char **pcanonical; { char *canonical = 0; assert (path && *path); assert (pcanonical); canonical = LT_EMALLOC (char, 1+ LT_STRLEN (path)); if (!canonical) return 1; { size_t dest = 0; size_t src; for (src = 0; path[src] != LT_EOS_CHAR; ++src) { /* Path separators are not copied to the beginning or end of the destination, or if another separator would follow immediately. */ if (path[src] == LT_PATHSEP_CHAR) { if ((dest == 0) || (path[1+ src] == LT_PATHSEP_CHAR) || (path[1+ src] == LT_EOS_CHAR)) continue; } /* Anything other than a directory separator is copied verbatim. */ if ((path[src] != '/') #ifdef LT_DIRSEP_CHAR && (path[src] != LT_DIRSEP_CHAR) #endif ) { canonical[dest++] = path[src]; } /* Directory separators are converted and copied only if they are not at the end of a path -- i.e. before a path separator or NULL terminator. */ else if ((path[1+ src] != LT_PATHSEP_CHAR) && (path[1+ src] != LT_EOS_CHAR) #ifdef LT_DIRSEP_CHAR && (path[1+ src] != LT_DIRSEP_CHAR) #endif && (path[1+ src] != '/')) { canonical[dest++] = '/'; } } /* Add an end-of-string marker at the end. */ canonical[dest] = LT_EOS_CHAR; } /* Assign new value. */ *pcanonical = canonical; return 0; } static int argzize_path (path, pargz, pargz_len) const char *path; char **pargz; size_t *pargz_len; { error_t error; assert (path); assert (pargz); assert (pargz_len); if ((error = argz_create_sep (path, LT_PATHSEP_CHAR, pargz, pargz_len))) { switch (error) { case ENOMEM: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); break; default: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); break; } return 1; } return 0; } /* Repeatedly call FUNC with each LT_PATHSEP_CHAR delimited element of SEARCH_PATH and references to DATA1 and DATA2, until FUNC returns non-zero or all elements are exhausted. If BASE_NAME is non-NULL, it is appended to each SEARCH_PATH element before FUNC is called. */ static int foreach_dirinpath (search_path, base_name, func, data1, data2) const char *search_path; const char *base_name; foreach_callback_func *func; lt_ptr data1; lt_ptr data2; { int result = 0; size_t filenamesize = 0; size_t lenbase = LT_STRLEN (base_name); size_t argz_len = 0; char *argz = 0; char *filename = 0; char *canonical = 0; LT_DLMUTEX_LOCK (); if (!search_path || !*search_path) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); goto cleanup; } if (canonicalize_path (search_path, &canonical) != 0) goto cleanup; if (argzize_path (canonical, &argz, &argz_len) != 0) goto cleanup; { char *dir_name = 0; while ((dir_name = argz_next (argz, argz_len, dir_name))) { size_t lendir = LT_STRLEN (dir_name); if (lendir +1 +lenbase >= filenamesize) { LT_DLFREE (filename); filenamesize = lendir +1 +lenbase +1; /* "/d" + '/' + "f" + '\0' */ filename = LT_EMALLOC (char, filenamesize); if (!filename) goto cleanup; } assert (filenamesize > lendir); strcpy (filename, dir_name); if (base_name && *base_name) { if (filename[lendir -1] != '/') filename[lendir++] = '/'; strcpy (filename +lendir, base_name); } if ((result = (*func) (filename, data1, data2))) { break; } } } cleanup: LT_DLFREE (argz); LT_DLFREE (canonical); LT_DLFREE (filename); LT_DLMUTEX_UNLOCK (); return result; } /* If FILEPATH can be opened, store the name of the directory component in DATA1, and the opened FILE* structure address in DATA2. Otherwise DATA1 is unchanged, but DATA2 is set to a pointer to NULL. */ static int find_file_callback (filename, data1, data2) char *filename; lt_ptr data1; lt_ptr data2; { char **pdir = (char **) data1; FILE **pfile = (FILE **) data2; int is_done = 0; assert (filename && *filename); assert (pdir); assert (pfile); if ((*pfile = fopen (filename, LT_READTEXT_MODE))) { char *dirend = strrchr (filename, '/'); if (dirend > filename) *dirend = LT_EOS_CHAR; LT_DLFREE (*pdir); *pdir = lt_estrdup (filename); is_done = (*pdir == 0) ? -1 : 1; } return is_done; } static FILE * find_file (search_path, base_name, pdir) const char *search_path; const char *base_name; char **pdir; { FILE *file = 0; foreach_dirinpath (search_path, base_name, find_file_callback, pdir, &file); return file; } static int find_handle_callback (filename, data, ignored) char *filename; lt_ptr data; lt_ptr ignored; { lt_dlhandle *handle = (lt_dlhandle *) data; int notfound = access (filename, R_OK); UNREFERENCED(ignored); /* Bail out if file cannot be read... */ if (notfound) return 0; /* Try to dlopen the file, but do not continue searching in any case. */ if (tryall_dlopen (handle, filename) != 0) *handle = 0; return 1; } /* If HANDLE was found return it, otherwise return 0. If HANDLE was found but could not be opened, *HANDLE will be set to 0. */ static lt_dlhandle * find_handle (search_path, base_name, handle) const char *search_path; const char *base_name; lt_dlhandle *handle; { if (!search_path) return 0; if (!foreach_dirinpath (search_path, base_name, find_handle_callback, handle, 0)) return 0; return handle; } static int load_deplibs (handle, deplibs) lt_dlhandle handle; char *deplibs; { #if LTDL_DLOPEN_DEPLIBS char *p, *save_search_path = 0; int depcount = 0; int i; char **names = 0; #endif int errors = 0; UNREFERENCED(deplibs); handle->depcount = 0; #if LTDL_DLOPEN_DEPLIBS if (!deplibs) { return errors; } ++errors; LT_DLMUTEX_LOCK (); if (user_search_path) { save_search_path = lt_estrdup (user_search_path); if (!save_search_path) goto cleanup; } /* extract search paths and count deplibs */ p = deplibs; while (*p) { if (!isspace ((int) *p)) { char *end = p+1; while (*end && !isspace((int) *end)) { ++end; } if (strncmp(p, "-L", 2) == 0 || strncmp(p, "-R", 2) == 0) { char save = *end; *end = 0; /* set a temporary string terminator */ if (lt_dladdsearchdir(p+2)) { goto cleanup; } *end = save; } else { ++depcount; } p = end; } else { ++p; } } /* restore the old search path */ LT_DLFREE (user_search_path); user_search_path = save_search_path; LT_DLMUTEX_UNLOCK (); if (!depcount) { errors = 0; goto cleanup; } names = LT_EMALLOC (char *, depcount * sizeof (char*)); if (!names) goto cleanup; /* now only extract the actual deplibs */ depcount = 0; p = deplibs; while (*p) { if (isspace ((int) *p)) { ++p; } else { char *end = p+1; while (*end && !isspace ((int) *end)) { ++end; } if (strncmp(p, "-L", 2) != 0 && strncmp(p, "-R", 2) != 0) { char *name; char save = *end; *end = 0; /* set a temporary string terminator */ if (strncmp(p, "-l", 2) == 0) { size_t name_len = 3+ /* "lib" */ LT_STRLEN (p + 2); name = LT_EMALLOC (char, 1+ name_len); if (name) sprintf (name, "lib%s", p+2); } else name = lt_estrdup(p); if (!name) goto cleanup_names; names[depcount++] = name; *end = save; } p = end; } } /* load the deplibs (in reverse order) At this stage, don't worry if the deplibs do not load correctly, they may already be statically linked into the loading application for instance. There will be a more enlightening error message later on if the loaded module cannot resolve all of its symbols. */ if (depcount) { int j = 0; handle->deplibs = (lt_dlhandle*) LT_EMALLOC (lt_dlhandle *, depcount); if (!handle->deplibs) goto cleanup; for (i = 0; i < depcount; ++i) { handle->deplibs[j] = lt_dlopenext(names[depcount-1-i]); if (handle->deplibs[j]) { ++j; } } handle->depcount = j; /* Number of successfully loaded deplibs */ errors = 0; } cleanup_names: for (i = 0; i < depcount; ++i) { LT_DLFREE (names[i]); } cleanup: LT_DLFREE (names); #endif return errors; } static int unload_deplibs (handle) lt_dlhandle handle; { int i; int errors = 0; if (handle->depcount) { for (i = 0; i < handle->depcount; ++i) { if (!LT_DLIS_RESIDENT (handle->deplibs[i])) { errors += lt_dlclose (handle->deplibs[i]); } } } return errors; } static int trim (dest, str) char **dest; const char *str; { /* remove the leading and trailing "'" from str and store the result in dest */ const char *end = strrchr (str, '\''); size_t len = LT_STRLEN (str); char *tmp; LT_DLFREE (*dest); if (len > 3 && str[0] == '\'') { tmp = LT_EMALLOC (char, end - str); if (!tmp) return 1; strncpy(tmp, &str[1], (end - str) - 1); tmp[len-3] = LT_EOS_CHAR; *dest = tmp; } else { *dest = 0; } return 0; } static int free_vars (dlname, oldname, libdir, deplibs) char *dlname; char *oldname; char *libdir; char *deplibs; { LT_DLFREE (dlname); LT_DLFREE (oldname); LT_DLFREE (libdir); LT_DLFREE (deplibs); return 0; } static int try_dlopen (phandle, filename) lt_dlhandle *phandle; const char *filename; { const char * ext = 0; const char * saved_error = 0; char * canonical = 0; char * base_name = 0; char * dir = 0; char * name = 0; int errors = 0; lt_dlhandle newhandle; assert (phandle); assert (*phandle == 0); LT_DLMUTEX_GETERROR (saved_error); /* dlopen self? */ if (!filename) { *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); if (*phandle == 0) return 1; memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); newhandle = *phandle; /* lt_dlclose()ing yourself is very bad! Disallow it. */ LT_DLSET_FLAG (*phandle, LT_DLRESIDENT_FLAG); if (tryall_dlopen (&newhandle, 0) != 0) { LT_DLFREE (*phandle); return 1; } goto register_handle; } assert (filename && *filename); /* Doing this immediately allows internal functions to safely assume only canonicalized paths are passed. */ if (canonicalize_path (filename, &canonical) != 0) { ++errors; goto cleanup; } /* If the canonical module name is a path (relative or absolute) then split it into a directory part and a name part. */ base_name = strrchr (canonical, '/'); if (base_name) { size_t dirlen = (1+ base_name) - canonical; dir = LT_EMALLOC (char, 1+ dirlen); if (!dir) { ++errors; goto cleanup; } strncpy (dir, canonical, dirlen); dir[dirlen] = LT_EOS_CHAR; ++base_name; } else LT_DLMEM_REASSIGN (base_name, canonical); assert (base_name && *base_name); /* Check whether we are opening a libtool module (.la extension). */ ext = strrchr (base_name, '.'); if (ext && strcmp (ext, archive_ext) == 0) { /* this seems to be a libtool module */ FILE * file = 0; char * dlname = 0; char * old_name = 0; char * libdir = 0; char * deplibs = 0; char * line = 0; size_t line_len; /* if we can't find the installed flag, it is probably an installed libtool archive, produced with an old version of libtool */ int installed = 1; /* extract the module name from the file name */ name = LT_EMALLOC (char, ext - base_name + 1); if (!name) { ++errors; goto cleanup; } /* canonicalize the module name */ { size_t i; for (i = 0; i < (unsigned int)(ext - base_name); ++i) { if (isalnum ((int)(base_name[i]))) { name[i] = base_name[i]; } else { name[i] = '_'; } } name[ext - base_name] = LT_EOS_CHAR; } /* Now try to open the .la file. If there is no directory name component, try to find it first in user_search_path and then other prescribed paths. Otherwise (or in any case if the module was not yet found) try opening just the module name as passed. */ if (!dir) { const char *search_path; LT_DLMUTEX_LOCK (); search_path = user_search_path; if (search_path) file = find_file (user_search_path, base_name, &dir); LT_DLMUTEX_UNLOCK (); if (!file) { search_path = getenv (LTDL_SEARCHPATH_VAR); if (search_path) file = find_file (search_path, base_name, &dir); } #ifdef LTDL_SHLIBPATH_VAR if (!file) { search_path = getenv (LTDL_SHLIBPATH_VAR); if (search_path) file = find_file (search_path, base_name, &dir); } #endif #ifdef LTDL_SYSSEARCHPATH if (!file) { file = find_file (sys_search_path, base_name, &dir); } #endif } if (!file) { file = fopen (filename, LT_READTEXT_MODE); } /* If we didn't find the file by now, it really isn't there. Set the status flag, and bail out. */ if (!file) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); ++errors; goto cleanup; } line_len = LT_FILENAME_MAX; line = LT_EMALLOC (char, line_len); if (!line) { fclose (file); ++errors; goto cleanup; } /* read the .la file */ while (!feof (file)) { if (!fgets (line, (int) line_len, file)) { break; } /* Handle the case where we occasionally need to read a line that is longer than the initial buffer size. */ while ((line[LT_STRLEN(line) -1] != '\n') && (!feof (file))) { line = LT_DLREALLOC (char, line, line_len *2); if (!fgets (&line[line_len -1], (int) line_len +1, file)) { break; } line_len *= 2; } if (line[0] == '\n' || line[0] == '#') { continue; } #undef STR_DLNAME #define STR_DLNAME "dlname=" if (strncmp (line, STR_DLNAME, sizeof (STR_DLNAME) - 1) == 0) { errors += trim (&dlname, &line[sizeof (STR_DLNAME) - 1]); } #undef STR_OLD_LIBRARY #define STR_OLD_LIBRARY "old_library=" else if (strncmp (line, STR_OLD_LIBRARY, sizeof (STR_OLD_LIBRARY) - 1) == 0) { errors += trim (&old_name, &line[sizeof (STR_OLD_LIBRARY) - 1]); } #undef STR_LIBDIR #define STR_LIBDIR "libdir=" else if (strncmp (line, STR_LIBDIR, sizeof (STR_LIBDIR) - 1) == 0) { errors += trim (&libdir, &line[sizeof(STR_LIBDIR) - 1]); } #undef STR_DL_DEPLIBS #define STR_DL_DEPLIBS "dependency_libs=" else if (strncmp (line, STR_DL_DEPLIBS, sizeof (STR_DL_DEPLIBS) - 1) == 0) { errors += trim (&deplibs, &line[sizeof (STR_DL_DEPLIBS) - 1]); } else if (strcmp (line, "installed=yes\n") == 0) { installed = 1; } else if (strcmp (line, "installed=no\n") == 0) { installed = 0; } #undef STR_LIBRARY_NAMES #define STR_LIBRARY_NAMES "library_names=" else if (! dlname && strncmp (line, STR_LIBRARY_NAMES, sizeof (STR_LIBRARY_NAMES) - 1) == 0) { char *last_libname; errors += trim (&dlname, &line[sizeof (STR_LIBRARY_NAMES) - 1]); if (!errors && dlname && (last_libname = strrchr (dlname, ' ')) != 0) { last_libname = lt_estrdup (last_libname + 1); if (!last_libname) { ++errors; goto cleanup; } LT_DLMEM_REASSIGN (dlname, last_libname); } } if (errors) break; } fclose (file); LT_DLFREE (line); /* allocate the handle */ *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); if (*phandle == 0) ++errors; if (errors) { free_vars (dlname, old_name, libdir, deplibs); LT_DLFREE (*phandle); goto cleanup; } assert (*phandle); memset (*phandle, 0, sizeof(struct lt_dlhandle_struct)); if (load_deplibs (*phandle, deplibs) == 0) { newhandle = *phandle; /* find_module may replace newhandle */ if (find_module (&newhandle, dir, libdir, dlname, old_name, installed)) { unload_deplibs (*phandle); ++errors; } } else { ++errors; } free_vars (dlname, old_name, libdir, deplibs); if (errors) { LT_DLFREE (*phandle); goto cleanup; } if (*phandle != newhandle) { unload_deplibs (*phandle); } } else { /* not a libtool module */ *phandle = (lt_dlhandle) LT_EMALLOC (struct lt_dlhandle_struct, 1); if (*phandle == 0) { ++errors; goto cleanup; } memset (*phandle, 0, sizeof (struct lt_dlhandle_struct)); newhandle = *phandle; /* If the module has no directory name component, try to find it first in user_search_path and then other prescribed paths. Otherwise (or in any case if the module was not yet found) try opening just the module name as passed. */ if ((dir || (!find_handle (user_search_path, base_name, &newhandle) && !find_handle (getenv (LTDL_SEARCHPATH_VAR), base_name, &newhandle) #ifdef LTDL_SHLIBPATH_VAR && !find_handle (getenv (LTDL_SHLIBPATH_VAR), base_name, &newhandle) #endif #ifdef LTDL_SYSSEARCHPATH && !find_handle (sys_search_path, base_name, &newhandle) #endif ))) { if (tryall_dlopen (&newhandle, filename) != 0) { newhandle = NULL; } } if (!newhandle) { LT_DLFREE (*phandle); ++errors; goto cleanup; } } register_handle: LT_DLMEM_REASSIGN (*phandle, newhandle); if ((*phandle)->info.ref_count == 0) { (*phandle)->info.ref_count = 1; LT_DLMEM_REASSIGN ((*phandle)->info.name, name); LT_DLMUTEX_LOCK (); (*phandle)->next = handles; handles = *phandle; LT_DLMUTEX_UNLOCK (); } LT_DLMUTEX_SETERROR (saved_error); cleanup: LT_DLFREE (dir); LT_DLFREE (name); LT_DLFREE (canonical); return errors; } lt_dlhandle lt_dlopen (filename) const char *filename; { lt_dlhandle handle = 0; /* Just incase we missed a code path in try_dlopen() that reports an error, but forgets to reset handle... */ if (try_dlopen (&handle, filename) != 0) return 0; return handle; } /* If the last error messge store was `FILE_NOT_FOUND', then return non-zero. */ static int file_not_found () { const char *error = 0; LT_DLMUTEX_GETERROR (error); if (error == LT_DLSTRERROR (FILE_NOT_FOUND)) return 1; return 0; } /* If FILENAME has an ARCHIVE_EXT or SHLIB_EXT extension, try to open the FILENAME as passed. Otherwise try appending ARCHIVE_EXT, and if a file is still not found try again with SHLIB_EXT appended instead. */ lt_dlhandle lt_dlopenext (filename) const char *filename; { lt_dlhandle handle = 0; char * tmp = 0; char * ext = 0; size_t len; int errors = 0; if (!filename) { return lt_dlopen (filename); } assert (filename); len = LT_STRLEN (filename); ext = strrchr (filename, '.'); /* If FILENAME already bears a suitable extension, there is no need to try appending additional extensions. */ if (ext && ((strcmp (ext, archive_ext) == 0) #ifdef LTDL_SHLIB_EXT || (strcmp (ext, shlib_ext) == 0) #endif )) { return lt_dlopen (filename); } /* First try appending ARCHIVE_EXT. */ tmp = LT_EMALLOC (char, len + strlen (archive_ext) + 1); if (!tmp) return 0; strcpy (tmp, filename); strcat (tmp, archive_ext); errors = try_dlopen (&handle, tmp); /* If we found FILENAME, stop searching -- whether we were able to load the file as a module or not. If the file exists but loading failed, it is better to return an error message here than to report FILE_NOT_FOUND when the alternatives (foo.so etc) are not in the module search path. */ if (handle || ((errors > 0) && !file_not_found ())) { LT_DLFREE (tmp); return handle; } #ifdef LTDL_SHLIB_EXT /* Try appending SHLIB_EXT. */ if (LT_STRLEN (shlib_ext) > strlen (archive_ext)) { LT_DLFREE (tmp); tmp = LT_EMALLOC (char, len + LT_STRLEN (shlib_ext) + 1); if (!tmp) return 0; strcpy (tmp, filename); } else { tmp[len] = LT_EOS_CHAR; } strcat(tmp, shlib_ext); errors = try_dlopen (&handle, tmp); /* As before, if the file was found but loading failed, return now with the current error message. */ if (handle || ((errors > 0) && !file_not_found ())) { LT_DLFREE (tmp); return handle; } #endif /* Still here? Then we really did fail to locate any of the file names we tried. */ LT_DLMUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); LT_DLFREE (tmp); return 0; } static int lt_argz_insert (pargz, pargz_len, before, entry) char **pargz; size_t *pargz_len; char *before; const char *entry; { error_t error; if ((error = argz_insert (pargz, pargz_len, before, entry))) { switch (error) { case ENOMEM: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); break; default: LT_DLMUTEX_SETERROR (LT_DLSTRERROR (UNKNOWN)); break; } return 1; } return 0; } static int lt_argz_insertinorder (pargz, pargz_len, entry) char **pargz; size_t *pargz_len; const char *entry; { char *before = 0; assert (pargz); assert (pargz_len); assert (entry && *entry); if (*pargz) while ((before = argz_next (*pargz, *pargz_len, before))) { int cmp = strcmp (entry, before); if (cmp < 0) break; if (cmp == 0) return 0; /* No duplicates! */ } return lt_argz_insert (pargz, pargz_len, before, entry); } static int lt_argz_insertdir (pargz, pargz_len, dirnam, dp) char **pargz; size_t *pargz_len; const char *dirnam; struct dirent *dp; { char *buf = 0; size_t buf_len = 0; char *end = 0; size_t end_offset = 0; size_t dir_len = 0; int errors = 0; assert (pargz); assert (pargz_len); assert (dp); dir_len = LT_STRLEN (dirnam); end = dp->d_name + LT_D_NAMLEN(dp); /* Ignore version numbers. */ { char *p; for (p = end; p -1 > dp->d_name; --p) if (strchr (".0123456789", p[-1]) == 0) break; if (*p == '.') end = p; } /* Ignore filename extension. */ { char *p; for (p = end -1; p > dp->d_name; --p) if (*p == '.') { end = p; break; } } /* Prepend the directory name. */ end_offset = end - dp->d_name; buf_len = dir_len + 1+ end_offset; buf = LT_EMALLOC (char, 1+ buf_len); if (!buf) return ++errors; assert (buf); strcpy (buf, dirnam); strcat (buf, "/"); strncat (buf, dp->d_name, end_offset); buf[buf_len] = LT_EOS_CHAR; /* Try to insert (in order) into ARGZ/ARGZ_LEN. */ if (lt_argz_insertinorder (pargz, pargz_len, buf) != 0) ++errors; LT_DLFREE (buf); return errors; } static int list_files_by_dir (dirnam, pargz, pargz_len) const char *dirnam; char **pargz; size_t *pargz_len; { DIR *dirp = 0; int errors = 0; assert (dirnam && *dirnam); assert (pargz); assert (pargz_len); assert (dirnam[LT_STRLEN(dirnam) -1] != '/'); dirp = opendir (dirnam); if (dirp) { struct dirent *dp = 0; while ((dp = readdir (dirp))) if (dp->d_name[0] != '.') if (lt_argz_insertdir (pargz, pargz_len, dirnam, dp)) { ++errors; break; } closedir (dirp); } else ++errors; return errors; } /* If there are any files in DIRNAME, call the function passed in DATA1 (with the name of each file and DATA2 as arguments). */ static int foreachfile_callback (dirname, data1, data2) char *dirname; lt_ptr data1; lt_ptr data2; { int (*func) LT_PARAMS((const char *filename, lt_ptr data)) = (int (*) LT_PARAMS((const char *filename, lt_ptr data))) data1; int is_done = 0; char *argz = 0; size_t argz_len = 0; if (list_files_by_dir (dirname, &argz, &argz_len) != 0) goto cleanup; if (!argz) goto cleanup; { char *filename = 0; while ((filename = argz_next (argz, argz_len, filename))) if ((is_done = (*func) (filename, data2))) break; } cleanup: LT_DLFREE (argz); return is_done; } /* Call FUNC for each unique extensionless file in SEARCH_PATH, along with DATA. The filenames passed to FUNC would be suitable for passing to lt_dlopenext. The extensions are stripped so that individual modules do not generate several entries (e.g. libfoo.la, libfoo.so, libfoo.so.1, libfoo.so.1.0.0). If SEARCH_PATH is NULL, then the same directories that lt_dlopen would search are examined. */ int lt_dlforeachfile (search_path, func, data) const char *search_path; int (*func) LT_PARAMS ((const char *filename, lt_ptr data)); lt_ptr data; { int is_done = 0; if (search_path) { /* If a specific path was passed, search only the directories listed in it. */ is_done = foreach_dirinpath (search_path, 0, foreachfile_callback, func, data); } else { /* Otherwise search the default paths. */ is_done = foreach_dirinpath (user_search_path, 0, foreachfile_callback, func, data); if (!is_done) { is_done = foreach_dirinpath (getenv("LTDL_LIBRARY_PATH"), 0, foreachfile_callback, func, data); } #ifdef LTDL_SHLIBPATH_VAR if (!is_done) { is_done = foreach_dirinpath (getenv(LTDL_SHLIBPATH_VAR), 0, foreachfile_callback, func, data); } #endif #ifdef LTDL_SYSSEARCHPATH if (!is_done) { is_done = foreach_dirinpath (getenv(LTDL_SYSSEARCHPATH), 0, foreachfile_callback, func, data); } #endif } return is_done; } int lt_dlclose (handle) lt_dlhandle handle; { lt_dlhandle cur, last; int errors = 0; LT_DLMUTEX_LOCK (); /* check whether the handle is valid */ last = cur = handles; while (cur && handle != cur) { last = cur; cur = cur->next; } if (!cur) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); ++errors; goto done; } handle->info.ref_count--; /* Note that even with resident modules, we must track the ref_count correctly incase the user decides to reset the residency flag later (even though the API makes no provision for that at the moment). */ if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle)) { lt_user_data data = handle->loader->dlloader_data; if (handle != handles) { last->next = handle->next; } else { handles = handle->next; } errors += handle->loader->module_close (data, handle->module); errors += unload_deplibs(handle); /* It is up to the callers to free the data itself. */ LT_DLFREE (handle->caller_data); LT_DLFREE (handle->info.filename); LT_DLFREE (handle->info.name); LT_DLFREE (handle); goto done; } if (LT_DLIS_RESIDENT (handle)) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); ++errors; } done: LT_DLMUTEX_UNLOCK (); return errors; } lt_ptr lt_dlsym (handle, symbol) lt_dlhandle handle; const char *symbol; { size_t lensym; char lsym[LT_SYMBOL_LENGTH]; char *sym; lt_ptr address; lt_user_data data; if (!handle) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return 0; } if (!symbol) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); return 0; } lensym = LT_STRLEN (symbol) + LT_STRLEN (handle->loader->sym_prefix) + LT_STRLEN (handle->info.name); if (lensym + LT_SYMBOL_OVERHEAD < LT_SYMBOL_LENGTH) { sym = lsym; } else { sym = LT_EMALLOC (char, lensym + LT_SYMBOL_OVERHEAD + 1); if (!sym) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); return 0; } } data = handle->loader->dlloader_data; if (handle->info.name) { const char *saved_error; LT_DLMUTEX_GETERROR (saved_error); /* this is a libtool module */ if (handle->loader->sym_prefix) { strcpy(sym, handle->loader->sym_prefix); strcat(sym, handle->info.name); } else { strcpy(sym, handle->info.name); } strcat(sym, "_LTX_"); strcat(sym, symbol); /* try "modulename_LTX_symbol" */ address = handle->loader->find_sym (data, handle->module, sym); if (address) { if (sym != lsym) { LT_DLFREE (sym); } return address; } LT_DLMUTEX_SETERROR (saved_error); } /* otherwise try "symbol" */ if (handle->loader->sym_prefix) { strcpy(sym, handle->loader->sym_prefix); strcat(sym, symbol); } else { strcpy(sym, symbol); } address = handle->loader->find_sym (data, handle->module, sym); if (sym != lsym) { LT_DLFREE (sym); } return address; } const char * lt_dlerror () { const char *error; LT_DLMUTEX_GETERROR (error); LT_DLMUTEX_SETERROR (0); return error ? error : LT_DLSTRERROR (UNKNOWN); } static int lt_dlpath_insertdir (ppath, before, dir) char **ppath; char *before; const char *dir; { int errors = 0; char *canonical = 0; char *argz = 0; size_t argz_len = 0; assert (ppath); assert (dir && *dir); if (canonicalize_path (dir, &canonical) != 0) { ++errors; goto cleanup; } assert (canonical && *canonical); /* If *PPATH is empty, set it to DIR. */ if (*ppath == 0) { assert (!before); /* BEFORE cannot be set without PPATH. */ assert (dir); /* Without DIR, don't call this function! */ *ppath = lt_estrdup (dir); if (*ppath == 0) ++errors; return errors; } assert (ppath && *ppath); if (argzize_path (*ppath, &argz, &argz_len) != 0) { ++errors; goto cleanup; } /* Convert BEFORE into an equivalent offset into ARGZ. This only works if *PPATH is already canonicalized, and hence does not change length with respect to ARGZ. We canonicalize each entry as it is added to the search path, and don't call this function with (uncanonicalized) user paths, so this is a fair assumption. */ if (before) { assert (*ppath <= before); assert (before - *ppath <= (int)strlen (*ppath)); before = before - *ppath + argz; } if (lt_argz_insert (&argz, &argz_len, before, dir) != 0) { ++errors; goto cleanup; } argz_stringify (argz, argz_len, LT_PATHSEP_CHAR); LT_DLMEM_REASSIGN (*ppath, argz); cleanup: LT_DLFREE (canonical); LT_DLFREE (argz); return errors; } int lt_dladdsearchdir (search_dir) const char *search_dir; { int errors = 0; if (search_dir && *search_dir) { LT_DLMUTEX_LOCK (); if (lt_dlpath_insertdir (&user_search_path, 0, search_dir) != 0) ++errors; LT_DLMUTEX_UNLOCK (); } return errors; } int lt_dlinsertsearchdir (before, search_dir) const char *before; const char *search_dir; { int errors = 0; if (before) { LT_DLMUTEX_LOCK (); if ((before < user_search_path) || (before >= user_search_path + LT_STRLEN (user_search_path))) { LT_DLMUTEX_UNLOCK (); LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_POSITION)); return 1; } LT_DLMUTEX_UNLOCK (); } if (search_dir && *search_dir) { LT_DLMUTEX_LOCK (); if (lt_dlpath_insertdir (&user_search_path, (char *) before, search_dir) != 0) { ++errors; } LT_DLMUTEX_UNLOCK (); } return errors; } int lt_dlsetsearchpath (search_path) const char *search_path; { int errors = 0; LT_DLMUTEX_LOCK (); LT_DLFREE (user_search_path); LT_DLMUTEX_UNLOCK (); if (!search_path || !LT_STRLEN (search_path)) { return errors; } LT_DLMUTEX_LOCK (); if (canonicalize_path (search_path, &user_search_path) != 0) ++errors; LT_DLMUTEX_UNLOCK (); return errors; } const char * lt_dlgetsearchpath () { const char *saved_path; LT_DLMUTEX_LOCK (); saved_path = user_search_path; LT_DLMUTEX_UNLOCK (); return saved_path; } int lt_dlmakeresident (handle) lt_dlhandle handle; { int errors = 0; if (!handle) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); ++errors; } else { LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); } return errors; } int lt_dlisresident (handle) lt_dlhandle handle; { if (!handle) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return -1; } return LT_DLIS_RESIDENT (handle); } /* --- MODULE INFORMATION --- */ const lt_dlinfo * lt_dlgetinfo (handle) lt_dlhandle handle; { if (!handle) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return 0; } return &(handle->info); } lt_dlhandle lt_dlhandle_next (place) lt_dlhandle place; { return place ? place->next : handles; } int lt_dlforeach (func, data) int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data)); lt_ptr data; { int errors = 0; lt_dlhandle cur; LT_DLMUTEX_LOCK (); cur = handles; while (cur) { lt_dlhandle tmp = cur; cur = cur->next; if ((*func) (tmp, data)) { ++errors; break; } } LT_DLMUTEX_UNLOCK (); return errors; } lt_dlcaller_id lt_dlcaller_register () { static lt_dlcaller_id last_caller_id = 0; int result; LT_DLMUTEX_LOCK (); result = ++last_caller_id; LT_DLMUTEX_UNLOCK (); return result; } lt_ptr lt_dlcaller_set_data (key, handle, data) lt_dlcaller_id key; lt_dlhandle handle; lt_ptr data; { int n_elements = 0; lt_ptr stale = (lt_ptr) 0; int i; /* This needs to be locked so that the caller data can be updated simultaneously by different threads. */ LT_DLMUTEX_LOCK (); if (handle->caller_data) while (handle->caller_data[n_elements].key) ++n_elements; for (i = 0; i < n_elements; ++i) { if (handle->caller_data[i].key == key) { stale = handle->caller_data[i].data; break; } } /* Ensure that there is enough room in this handle's caller_data array to accept a new element (and an empty end marker). */ if (i == n_elements) { lt_caller_data *temp = LT_DLREALLOC (lt_caller_data, handle->caller_data, 2+ n_elements); if (!temp) { stale = 0; goto done; } handle->caller_data = temp; /* We only need this if we needed to allocate a new caller_data. */ handle->caller_data[i].key = key; handle->caller_data[1+ i].key = 0; } handle->caller_data[i].data = data; done: LT_DLMUTEX_UNLOCK (); return stale; } lt_ptr lt_dlcaller_get_data (key, handle) lt_dlcaller_id key; lt_dlhandle handle; { lt_ptr result = (lt_ptr) 0; /* This needs to be locked so that the caller data isn't updated by another thread part way through this function. */ LT_DLMUTEX_LOCK (); /* Locate the index of the element with a matching KEY. */ { int i; for (i = 0; handle->caller_data[i].key; ++i) { if (handle->caller_data[i].key == key) { result = handle->caller_data[i].data; break; } } } LT_DLMUTEX_UNLOCK (); return result; } /* --- USER MODULE LOADER API --- */ int lt_dlloader_add (place, dlloader, loader_name) lt_dlloader *place; const struct lt_user_dlloader *dlloader; const char *loader_name; { int errors = 0; lt_dlloader *node = 0, *ptr = 0; if ((dlloader == 0) /* diagnose null parameters */ || (dlloader->module_open == 0) || (dlloader->module_close == 0) || (dlloader->find_sym == 0)) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); return 1; } /* Create a new dlloader node with copies of the user callbacks. */ node = LT_EMALLOC (lt_dlloader, 1); if (!node) return 1; node->next = 0; node->loader_name = loader_name; node->sym_prefix = dlloader->sym_prefix; node->dlloader_exit = dlloader->dlloader_exit; node->module_open = dlloader->module_open; node->module_close = dlloader->module_close; node->find_sym = dlloader->find_sym; node->dlloader_data = dlloader->dlloader_data; LT_DLMUTEX_LOCK (); if (!loaders) { /* If there are no loaders, NODE becomes the list! */ loaders = node; } else if (!place) { /* If PLACE is not set, add NODE to the end of the LOADERS list. */ for (ptr = loaders; ptr->next; ptr = ptr->next) { /*NOWORK*/; } ptr->next = node; } else if (loaders == place) { /* If PLACE is the first loader, NODE goes first. */ node->next = place; loaders = node; } else { /* Find the node immediately preceding PLACE. */ for (ptr = loaders; ptr->next != place; ptr = ptr->next) { /*NOWORK*/; } if (ptr->next != place) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); ++errors; } else { /* Insert NODE between PTR and PLACE. */ node->next = place; ptr->next = node; } } LT_DLMUTEX_UNLOCK (); return errors; } int lt_dlloader_remove (loader_name) const char *loader_name; { lt_dlloader *place = lt_dlloader_find (loader_name); lt_dlhandle handle; int errors = 0; if (!place) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); return 1; } LT_DLMUTEX_LOCK (); /* Fail if there are any open modules which use this loader. */ for (handle = handles; handle; handle = handle->next) { if (handle->loader == place) { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); ++errors; goto done; } } if (place == loaders) { /* PLACE is the first loader in the list. */ loaders = loaders->next; } else { /* Find the loader before the one being removed. */ lt_dlloader *prev; for (prev = loaders; prev->next; prev = prev->next) { if (!strcmp (prev->next->loader_name, loader_name)) { break; } } place = prev->next; prev->next = prev->next->next; } if (place->dlloader_exit) { errors = place->dlloader_exit (place->dlloader_data); } LT_DLFREE (place); done: LT_DLMUTEX_UNLOCK (); return errors; } lt_dlloader * lt_dlloader_next (place) lt_dlloader *place; { lt_dlloader *next; LT_DLMUTEX_LOCK (); next = place ? place->next : loaders; LT_DLMUTEX_UNLOCK (); return next; } const char * lt_dlloader_name (place) lt_dlloader *place; { const char *name = 0; if (place) { LT_DLMUTEX_LOCK (); name = place ? place->loader_name : 0; LT_DLMUTEX_UNLOCK (); } else { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); } return name; } lt_user_data * lt_dlloader_data (place) lt_dlloader *place; { lt_user_data *data = 0; if (place) { LT_DLMUTEX_LOCK (); data = place ? &(place->dlloader_data) : 0; LT_DLMUTEX_UNLOCK (); } else { LT_DLMUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); } return data; } lt_dlloader * lt_dlloader_find (loader_name) const char *loader_name; { lt_dlloader *place = 0; LT_DLMUTEX_LOCK (); for (place = loaders; place; place = place->next) { if (strcmp (place->loader_name, loader_name) == 0) { break; } } LT_DLMUTEX_UNLOCK (); return place; } #endif hercules-3.12/ckddasd.c0000664000175000017500000066442212564723224011762 00000000000000/* CKDDASD.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 CKD Direct Access Storage Device Handler */ /*-------------------------------------------------------------------*/ /* This module contains device handling functions for emulated */ /* count-key-data direct access storage devices. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Write Update Key and Data CCW by Jan Jaeger */ /* Track overflow support added by Jay Maynard */ /* Track overflow fixes by Jay Maynard, suggested by Valery */ /* Pogonchenko */ /* Track overflow write fix by Roger Bowler, thanks to Valery */ /* Pogonchenko and Volker Bandke V1.71 16/01/2001 */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _CKDDASD_C_ #define _HDASD_DLL_ #include "hercules.h" #include "devtype.h" #include "sr.h" /*-------------------------------------------------------------------*/ /* Bit definitions for File Mask */ /*-------------------------------------------------------------------*/ #define CKDMASK_WRCTL 0xC0 /* Write control bits... */ #define CKDMASK_WRCTL_INHWR0 0x00 /* ...inhibit write HA/R0 */ #define CKDMASK_WRCTL_INHWRT 0x40 /* ...inhibit all writes */ #define CKDMASK_WRCTL_ALLWRU 0x80 /* ...write update only */ #define CKDMASK_WRCTL_ALLWRT 0xC0 /* ...allow all writes */ #define CKDMASK_RESV 0x20 /* Reserved bits - must be 0 */ #define CKDMASK_SKCTL 0x18 /* Seek control bits... */ #define CKDMASK_SKCTL_ALLSKR 0x00 /* ...allow all seek/recalib */ #define CKDMASK_SKCTL_CYLHD 0x08 /* ...allow seek cyl/head */ #define CKDMASK_SKCTL_HEAD 0x10 /* ...allow seek head only */ #define CKDMASK_SKCTL_INHSMT 0x18 /* ...inhibit seek and MT */ #define CKDMASK_AAUTH 0x06 /* Access auth bits... */ #define CKDMASK_AAUTH_NORMAL 0x00 /* ...normal authorization */ #define CKDMASK_AAUTH_DSF 0x02 /* ...device support auth */ #define CKDMASK_AAUTH_DIAG 0x04 /* ...diagnostic auth */ #define CKDMASK_AAUTH_DSFNCR 0x06 /* ...device support with no correction or retry */ #define CKDMASK_PCI_FETCH 0x01 /* PCI fetch mode */ /*-------------------------------------------------------------------*/ /* Bit definitions for Define Extent global attributes byte */ /*-------------------------------------------------------------------*/ #define CKDGATR_ARCH 0xC0 /* Architecture mode... */ #define CKDGATR_ARCH_ECKD 0xC0 /* ...extended CKD mode */ #define CKDGATR_CKDCONV 0x20 /* CKD conversion mode */ #define CKDGATR_SSOP 0x1C /* Subsystem operation mode..*/ #define CKDGATR_SSOP_NORMAL 0x00 /* ...normal cache */ #define CKDGATR_SSOP_BYPASS 0x04 /* ...bypass cache */ #define CKDGATR_SSOP_INHIBIT 0x08 /* ...inhibit cache loading */ #define CKDGATR_SSOP_SEQACC 0x0C /* ...sequential access */ #define CKDGATR_SSOP_LOGGING 0x10 /* ...logging mode */ #define CKDGATR_USE_CACHE_FW 0x02 /* Use cache fast write */ #define CKDGATR_INH_DASD_FW 0x01 /* Inhibit DASD fast write */ /*-------------------------------------------------------------------*/ /* Bit definitions for Locate operation byte */ /*-------------------------------------------------------------------*/ #define CKDOPER_ORIENTATION 0xC0 /* Orientation bits... */ #define CKDOPER_ORIENT_COUNT 0x00 /* ...orient to count */ #define CKDOPER_ORIENT_HOME 0x40 /* ...orient to home address */ #define CKDOPER_ORIENT_DATA 0x80 /* ...orient to data area */ #define CKDOPER_ORIENT_INDEX 0xC0 /* ...orient to index */ #define CKDOPER_CODE 0x3F /* Operation code bits... */ #define CKDOPER_ORIENT 0x00 /* ...orient */ #define CKDOPER_WRITE 0x01 /* ...write data */ #define CKDOPER_FORMAT 0x03 /* ...format write */ #define CKDOPER_RDDATA 0x06 /* ...read data */ #define CKDOPER_WRTANY 0x09 /* ...write any */ #define CKDOPER_RDANY 0x0A /* ...read any */ #define CKDOPER_WRTTRK 0x0B /* ...write track */ #define CKDOPER_RDTRKS 0x0C /* ...read tracks */ #define CKDOPER_RDTSET 0x0E /* ...read track set */ #define CKDOPER_READ 0x16 /* ...read */ #define CKDOPER_EXTOP 0x3F /* ...extended operation */ /*-------------------------------------------------------------------*/ /* Bit definitions for Locate auxiliary byte */ /*-------------------------------------------------------------------*/ #define CKDLAUX_TLFVALID 0x80 /* TLF field is valid */ #define CKDLAUX_RESV 0x7E /* Reserved bits - must be 0 */ #define CKDLAUX_RDCNTSUF 0x01 /* Suffixed read count CCW */ /*-------------------------------------------------------------------*/ /* Definitions for ckdorient field in device block */ /*-------------------------------------------------------------------*/ #define CKDORIENT_NONE 0 /* Orientation unknown */ #define CKDORIENT_INDEX 1 /* Oriented after track hdr */ #define CKDORIENT_COUNT 2 /* Oriented after count field*/ #define CKDORIENT_KEY 3 /* Oriented after key field */ #define CKDORIENT_DATA 4 /* Oriented after data field */ #define CKDORIENT_EOT 5 /* Oriented after end of trk */ /* Path state byte for Sense Path Group ID command */ #define SPG_PATHSTAT 0xC0 /* Pathing status bits... */ #define SPG_PATHSTAT_RESET 0x00 /* ...reset */ #define SPG_PATHSTAT_RESV 0x40 /* ...reserved bit setting */ #define SPG_PATHSTAT_UNGROUPED 0x80 /* ...ungrouped */ #define SPG_PATHSTAT_GROUPED 0xC0 /* ...grouped */ #define SPG_PARTSTAT 0x30 /* Partitioning status bits..*/ #define SPG_PARTSTAT_IENABLED 0x00 /* ...implicitly enabled */ #define SPG_PARTSTAT_RESV 0x10 /* ...reserved bit setting */ #define SPG_PARTSTAT_DISABLED 0x20 /* ...disabled */ #define SPG_PARTSTAT_XENABLED 0x30 /* ...explicitly enabled */ #define SPG_PATHMODE 0x08 /* Path mode bit... */ #define SPG_PATHMODE_SINGLE 0x00 /* ...single path mode */ #define SPG_PATHMODE_RESV 0x08 /* ...reserved bit setting */ #define SPG_RESERVED 0x07 /* Reserved bits, must be 0 */ /* Function control byte for Set Path Group ID command */ #define SPG_SET_MULTIPATH 0x80 /* Set multipath mode */ #define SPG_SET_COMMAND 0x60 /* Set path command bits... */ #define SPG_SET_ESTABLISH 0x00 /* ...establish group */ #define SPG_SET_DISBAND 0x20 /* ...disband group */ #define SPG_SET_RESIGN 0x40 /* ...resign from group */ #define SPG_SET_COMMAND_RESV 0x60 /* ...reserved bit setting */ #define SPG_SET_RESV 0x1F /* Reserved bits, must be 0 */ /*-------------------------------------------------------------------*/ /* Bit definitions for Diagnostic Control subcommand byte */ /*-------------------------------------------------------------------*/ #define DIAGCTL_INHIBIT_WRITE 0x02 /* Inhibit Write */ #define DIAGCTL_SET_GUAR_PATH 0x04 /* Set Guaranteed Path */ #define DIAGCTL_ENABLE_WRITE 0x08 /* Enable Write */ #define DIAGCTL_3380_TC_MODE 0x09 /* 3380 Track Compat Mode */ #define DIAGCTL_INIT_SUBSYS 0x0B /* Diagnostic Init Subsys */ #define DIAGCTL_UNFENCE 0x0C /* Unfence */ #define DIAGCTL_ACCDEV_UNKCOND 0x0F /* Access Device Unknown Cond*/ #define DIAGCTL_MAINT_RESERVE 0x10 /* Media Maintenance Reserve */ #define DIAGCTL_MAINT_RELEASE 0x11 /* Media Maintenance Release */ #define DIAGCTL_MAINT_QUERY 0x12 /* Media Maintenance Query */ /*-------------------------------------------------------------------*/ /* Definitions for sense data format codes and message codes */ /*-------------------------------------------------------------------*/ #define FORMAT_0 0 /* Program or System Checks */ #define FORMAT_1 1 /* Device Equipment Checks */ #define FORMAT_2 2 /* 3990 Equipment Checks */ #define FORMAT_3 3 /* 3990 Control Checks */ #define FORMAT_4 4 /* Data Checks */ #define FORMAT_5 5 /* Data Check + Displacement */ #define FORMAT_6 6 /* Usage Stats/Overrun Errors*/ #define FORMAT_7 7 /* Device Control Checks */ #define FORMAT_8 8 /* Device Equipment Checks */ #define FORMAT_9 9 /* Device Rd/Wrt/Seek Checks */ #define FORMAT_F 15 /* Cache Storage Checks */ #define MESSAGE_0 0 /* Message 0 */ #define MESSAGE_1 1 /* Message 1 */ #define MESSAGE_2 2 /* Message 2 */ #define MESSAGE_3 3 /* Message 3 */ #define MESSAGE_4 4 /* Message 4 */ #define MESSAGE_5 5 /* Message 5 */ #define MESSAGE_6 6 /* Message 6 */ #define MESSAGE_7 7 /* Message 7 */ #define MESSAGE_8 8 /* Message 8 */ #define MESSAGE_9 9 /* Message 9 */ #define MESSAGE_A 10 /* Message A */ #define MESSAGE_B 11 /* Message B */ #define MESSAGE_C 12 /* Message C */ #define MESSAGE_D 13 /* Message D */ #define MESSAGE_E 14 /* Message E */ #define MESSAGE_F 15 /* Message F */ /*-------------------------------------------------------------------*/ /* Definitions for Read Configuration Data command */ /*-------------------------------------------------------------------*/ #define CONFIG_DATA_SIZE 256 /* Number of bytes returned by Read Config Data CCW */ /* * ISW20060207 * EXTENT_CHECK0 is just to shut up a stupid gcc 4 warning.. * It doesn't hurt otherwise * EXTENT_CHECK0(dev) is the same as EXTENT_CHECK(dev,0,0) */ #define EXTENT_CHECK0(_dev) ((_dev)->ckdxbcyl > 0 \ || ((_dev)->ckdxbcyl==0 && (_dev)->ckdxbhead>0)) #define EXTENT_CHECK(_dev, _cyl, _head) \ ( (_cyl) < (_dev)->ckdxbcyl || (_cyl) > (_dev)->ckdxecyl \ || ((_cyl) == (_dev)->ckdxbcyl && (_head) < (_dev)->ckdxbhead) \ || ((_cyl) == (_dev)->ckdxecyl && (_head) > (_dev)->ckdxehead) ) /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; /*-------------------------------------------------------------------*/ /* Initialize the device handler */ /*-------------------------------------------------------------------*/ int ckddasd_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { int rc; /* Return code */ struct stat statbuf; /* File information */ CKDDASD_DEVHDR devhdr; /* Device header */ CCKDDASD_DEVHDR cdevhdr; /* Compressed device header */ int i; /* Loop index */ int fileseq; /* File sequence number */ char *sfxptr; /* -> Last char of file name */ char sfxchar; /* Last char of file name */ int heads; /* #of heads in CKD file */ int trksize; /* Track size of CKD file */ int trks; /* #of tracks in CKD file */ int cyls; /* #of cylinders in CKD file */ int highcyl; /* Highest cyl# in CKD file */ char *cu = NULL; /* Specified control unit */ char *kw; /* Argument keyword */ int cckd=0; /* 1 if compressed CKD */ char pathname[MAX_PATH]; /* file path in host format */ if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x3380; /* The first argument is the file name */ if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1) { logmsg (_("HHCDA001E File name missing or invalid\n")); return -1; } /* Save the file name in the device block */ hostpath(pathname, argv[0], sizeof(pathname)); strcpy (dev->filename, pathname); /* Device is shareable */ dev->shared = 1; /* Check for possible remote device */ hostpath(pathname, dev->filename, sizeof(pathname)); if (stat(pathname, &statbuf) < 0) { rc = shared_ckd_init ( dev, argc, argv); if (rc < 0) { logmsg (_("HHCDA002E %4.4X:File not found or invalid '%s'\n"), dev->devnum,dev->filename); return -1; } else return rc; } /* Default to synchronous I/O */ dev->syncio = 1; /* No active track or cache entry */ dev->bufcur = dev->cache = -1; /* Locate and save the last character of the file name */ sfxptr = strrchr (dev->filename, '/'); if (sfxptr == NULL) sfxptr = dev->filename + 1; sfxptr = strchr (sfxptr, '.'); if (sfxptr == NULL) sfxptr = dev->filename + strlen(dev->filename); sfxptr--; sfxchar = *sfxptr; /* process the remaining arguments */ for (i = 1; i < argc; i++) { if (strcasecmp ("lazywrite", argv[i]) == 0) { dev->ckdnolazywr = 0; continue; } if (strcasecmp ("nolazywrite", argv[i]) == 0) { dev->ckdnolazywr = 1; continue; } if (strcasecmp ("fulltrackio", argv[i]) == 0 || strcasecmp ("fulltrkio", argv[i]) == 0 || strcasecmp ("ftio", argv[i]) == 0) { dev->ckdnolazywr = 0; continue; } if (strcasecmp ("nofulltrackio", argv[i]) == 0 || strcasecmp ("nofulltrkio", argv[i]) == 0 || strcasecmp ("noftio", argv[i]) == 0) { dev->ckdnolazywr = 1; continue; } if (strcasecmp ("readonly", argv[i]) == 0 || strcasecmp ("rdonly", argv[i]) == 0 || strcasecmp ("ro", argv[i]) == 0) { dev->ckdrdonly = 1; continue; } if (strcasecmp ("fakewrite", argv[i]) == 0 || strcasecmp ("fakewrt", argv[i]) == 0 || strcasecmp ("fw", argv[i]) == 0) { dev->ckdfakewr = 1; continue; } if (strlen (argv[i]) > 3 && memcmp ("sf=", argv[i], 3) == 0) { if ('\"' == argv[i][3]) argv[i]++; hostpath(pathname, argv[i]+3, sizeof(pathname)); dev->dasdsfn = strdup(pathname); if (dev->dasdsfn) { /* Set the pointer to the suffix character */ dev->dasdsfx = strrchr (dev->dasdsfn, '/'); if (dev->dasdsfx == NULL) dev->dasdsfx = dev->dasdsfn + 1; dev->dasdsfx = strchr (dev->dasdsfx, '.'); if (dev->dasdsfx == NULL) dev->dasdsfx = dev->dasdsfn + strlen(dev->dasdsfn); dev->dasdsfx--; } continue; } if (strlen (argv[i]) > 3 && memcmp("cu=", argv[i], 3) == 0) { kw = strtok (argv[i], "="); cu = strtok (NULL, " \t"); continue; } if (strcasecmp ("nosyncio", argv[i]) == 0 || strcasecmp ("nosyio", argv[i]) == 0) { dev->syncio = 0; continue; } if (strcasecmp ("syncio", argv[i]) == 0 || strcasecmp ("syio", argv[i]) == 0) { dev->syncio = 1; continue; } logmsg (_("HHCDA003E parameter %d is invalid: %s\n"), i + 1, argv[i]); return -1; } /* Initialize the total tracks and cylinders */ dev->ckdtrks = 0; dev->ckdcyls = 0; /* Open all of the CKD image files which comprise this volume */ if (dev->ckdrdonly) logmsg (_("HHCDA004I opening %s readonly%s\n"), dev->filename, dev->ckdfakewr ? " with fake writing" : ""); for (fileseq = 1;;) { /* Open the CKD image file */ hostpath(pathname, dev->filename, sizeof(pathname)); dev->fd = hopen(pathname, dev->ckdrdonly ? O_RDONLY|O_BINARY : O_RDWR|O_BINARY); if (dev->fd < 0) { /* Try read-only if shadow file present */ if (!dev->ckdrdonly && dev->dasdsfn != NULL) dev->fd = hopen(pathname, O_RDONLY|O_BINARY); if (dev->fd < 0) { logmsg (_("HHCDA005E %s open error: %s\n"), dev->filename, strerror(errno)); return -1; } } /* If shadow file, only one base file is allowed */ if (fileseq > 1 && dev->dasdsfn != NULL) { logmsg (_("HHCDA006E %s not in a single file for shadowing\n"), dev->filename); return -1; } /* Determine the device size */ rc = fstat (dev->fd, &statbuf); if (rc < 0) { logmsg (_("HHCDA007E %s fstat error: %s\n"), dev->filename, strerror(errno)); return -1; } /* Read the device header */ rc = read (dev->fd, &devhdr, CKDDASD_DEVHDR_SIZE); if (rc < (int)CKDDASD_DEVHDR_SIZE) { if (rc < 0) logmsg (_("HHCDA008E %s read error: %s\n"), dev->filename, strerror(errno)); else logmsg (_("HHCDA09E %s CKD header incomplete\n"), dev->filename); return -1; } /* Check the device header identifier */ if (memcmp(devhdr.devid, "CKD_P370", 8) != 0) { if (memcmp(devhdr.devid, "CKD_C370", 8) != 0) { logmsg (_("HHCDA010E %s CKD header invalid\n"), dev->filename); return -1; } else { cckd = 1; if (fileseq != 1) { logmsg (_("HHCDA011E %s Only 1 CCKD file allowed\n"), dev->filename); return -1; } } } /* Read the compressed device header */ if ( cckd ) { rc = read (dev->fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); if (rc < (int)CCKDDASD_DEVHDR_SIZE) { if (rc < 0) { logmsg (_("HHCDA012E %s read error: %s\n"), dev->filename, strerror(errno)); } else { logmsg (_("HHCDA013E %s CCKD header incomplete\n"), dev->filename); } return -1; } } /* Extract fields from device header */ heads = ((U32)(devhdr.heads[3]) << 24) | ((U32)(devhdr.heads[2]) << 16) | ((U32)(devhdr.heads[1]) << 8) | (U32)(devhdr.heads[0]); trksize = ((U32)(devhdr.trksize[3]) << 24) | ((U32)(devhdr.trksize[2]) << 16) | ((U32)(devhdr.trksize[1]) << 8) | (U32)(devhdr.trksize[0]); highcyl = ((U32)(devhdr.highcyl[1]) << 8) | (U32)(devhdr.highcyl[0]); if (cckd == 0) { if (dev->dasdcopy == 0) { trks = (statbuf.st_size - CKDDASD_DEVHDR_SIZE) / trksize; cyls = trks / heads; if (fileseq == 1 && highcyl == cyls) { devhdr.fileseq = 0; highcyl = 0; } } else { /* * For dasdcopy we get the number of cylinders and tracks from * the highcyl in the device header. The last file will have * a sequence number of 0xFF. */ cyls = highcyl - dev->ckdcyls + 1; trks = cyls * heads; if (devhdr.fileseq == 0xFF) { devhdr.fileseq = fileseq == 1 ? 0 : fileseq; highcyl = 0; devhdr.highcyl[0] = devhdr.highcyl[1] = 0; lseek (dev->fd, 0, SEEK_SET); rc = write (dev->fd, &devhdr, CKDDASD_DEVHDR_SIZE); } } } else { cyls = ((U32)(cdevhdr.cyls[3]) << 24) | ((U32)(cdevhdr.cyls[2]) << 16) | ((U32)(cdevhdr.cyls[1]) << 8) | (U32)(cdevhdr.cyls[0]); trks = cyls * heads; } /* Check for correct file sequence number */ if (devhdr.fileseq != fileseq && !(devhdr.fileseq == 0 && fileseq == 1)) { logmsg (_("HHCDA014E %s CKD file out of sequence\n"), dev->filename); return -1; } if (devhdr.fileseq > 0) { logmsg (_("HHCDA015I %s seq=%d cyls=%d-%d\n"), dev->filename, devhdr.fileseq, dev->ckdcyls, (highcyl > 0 ? highcyl : dev->ckdcyls + cyls - 1)); } /* Save device geometry of first file, or check that device geometry of subsequent files matches that of first file */ if (fileseq == 1) { dev->ckdheads = heads; dev->ckdtrksz = trksize; } else if (heads != dev->ckdheads || trksize != dev->ckdtrksz) { logmsg (_("HHCDA016E %s heads=%d trklen=%d, " "expected heads=%d trklen=%d\n"), dev->filename, heads, trksize, dev->ckdheads, dev->ckdtrksz); return -1; } /* Consistency check device header */ if (cckd == 0 && dev->dasdcopy == 0 && (cyls * heads != trks || ((off_t)trks * trksize) + CKDDASD_DEVHDR_SIZE != statbuf.st_size || (highcyl != 0 && highcyl != dev->ckdcyls + cyls - 1))) { logmsg (_("HHCDA017E %s CKD header inconsistent with file size\n"), dev->filename); return -1; } /* Check for correct high cylinder number */ if (highcyl != 0 && highcyl != dev->ckdcyls + cyls - 1) { logmsg (_("HHCDA018E %s CKD header high cylinder incorrect\n"), dev->filename); return -1; } /* Accumulate total volume size */ dev->ckdtrks += trks; dev->ckdcyls += cyls; /* Save file descriptor and high track number */ dev->ckdfd[fileseq-1] = dev->fd; dev->ckdhitrk[fileseq-1] = dev->ckdtrks; dev->ckdnumfd = fileseq; /* Exit loop if this is the last file */ if (highcyl == 0) break; /* Increment the file sequence number */ fileseq++; /* Alter the file name suffix ready for the next file */ if (fileseq <= 9) *sfxptr = '0' + fileseq; else *sfxptr = 'A' - 10 + fileseq; /* Check that maximum files has not been exceeded */ if (fileseq > CKD_MAXFILES) { logmsg (_("HHCDA019E %s exceeds maximum %d CKD files\n"), dev->filename, CKD_MAXFILES); return -1; } } /* end for(fileseq) */ /* Restore the last character of the file name */ *sfxptr = sfxchar; /* Log the device geometry */ logmsg (_("HHCDA020I %s cyls=%d heads=%d tracks=%d trklen=%d\n"), dev->filename, dev->ckdcyls, dev->ckdheads, dev->ckdtrks, dev->ckdtrksz); /* Locate the CKD dasd table entry */ dev->ckdtab = dasd_lookup (DASD_CKDDEV, NULL, dev->devtype, dev->ckdcyls); if (dev->ckdtab == NULL) { logmsg (_("HHCDA021E %4.4X device type %4.4X not found in dasd table\n"), dev->devnum, dev->devtype); return -1; } /* Locate the CKD control unit dasd table entry */ dev->ckdcu = dasd_lookup (DASD_CKDCU, cu ? cu : dev->ckdtab->cu, 0, 0); if (dev->ckdcu == NULL) { logmsg (_("HHCDA022E %4.4X control unit %s not found in dasd table\n"), dev->devnum, cu ? cu : dev->ckdtab->cu); return -1; } /* Set number of sense bytes according to controller specification */ dev->numsense = dev->ckdcu->senselength; /* Set flag bit if 3990 controller */ if (dev->ckdcu->devt == 0x3990) dev->ckd3990 = 1; /* Build the devid area */ dev->numdevid = dasd_build_ckd_devid (dev->ckdtab, dev->ckdcu, (BYTE *)&dev->devid); /* Build the devchar area */ dev->numdevchar = dasd_build_ckd_devchar (dev->ckdtab, dev->ckdcu, (BYTE *)&dev->devchar, dev->ckdcyls); /* Clear the DPA */ memset(dev->pgid, 0, sizeof(dev->pgid)); /* Activate I/O tracing */ // dev->ccwtrace = 1; /* Request the channel to merge data chained write CCWs into a single buffer before passing data to the device handler */ dev->cdwmerge = 1; if (!cckd) return 0; else return cckddasd_init_handler(dev, argc, argv); } /* end function ckddasd_init_handler */ /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ void ckddasd_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "DASD", dev, class, buflen, buffer ); snprintf (buffer, buflen, "%s [%d cyls]", dev->filename, dev->ckdcyls); } /* end function ckddasd_query_device */ /*-------------------------------------------------------------------*/ /* Release cache entries */ /*-------------------------------------------------------------------*/ int ckddasd_purge_cache (int *answer, int ix, int i, void *data) { U16 devnum; /* Cached device number */ int trk; /* Cached track */ DEVBLK *dev = data; /* -> device block */ UNREFERENCED(answer); CKD_CACHE_GETKEY(i, devnum, trk); if (dev->devnum == devnum) cache_release (ix, i, CACHE_FREEBUF); return 0; } static int ckddasd_read_track (DEVBLK *dev, int trk, BYTE *unitstat); /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ int ckddasd_close_device ( DEVBLK *dev ) { int i; /* Index */ BYTE unitstat; /* Unit Status */ /* Write the last track image if it's modified */ (dev->hnd->read) (dev, -1, &unitstat); /* Free the cache */ cache_lock(CACHE_DEVBUF); cache_scan(CACHE_DEVBUF, ckddasd_purge_cache, dev); cache_unlock(CACHE_DEVBUF); if (!dev->batch) logmsg (_("HHCDA023I %4.4X cache hits %d, misses %d, waits %d\n"), dev->devnum, dev->cachehits, dev->cachemisses, dev->cachewaits); /* Close all of the CKD image files */ for (i = 0; i < dev->ckdnumfd; i++) if (dev->ckdfd[i] > 2) close (dev->ckdfd[i]); dev->buf = NULL; dev->bufsize = 0; return 0; } /* end function ckddasd_close_device */ /*-------------------------------------------------------------------*/ /* Read a track image at CCHH */ /*-------------------------------------------------------------------*/ static int ckd_read_cchh (DEVBLK *dev, int cyl, int head, BYTE *unitstat) { int rc; /* Return code */ int trk; /* Track number */ /* Command reject if seek position is outside volume */ if (cyl >= dev->ckdcyls || head >= dev->ckdheads) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Calculate the track number */ trk = cyl * dev->ckdheads + head; /* Call the read exit */ rc = (dev->hnd->read) (dev, trk, unitstat); return rc; } /* end function ckd_read_cchh */ /*-------------------------------------------------------------------*/ /* Return track image length */ /*-------------------------------------------------------------------*/ int ckd_trklen (DEVBLK *dev, BYTE *buf) { int sz; /* Size so far */ for (sz = CKDDASD_TRKHDR_SIZE; memcmp (buf + sz, &eighthexFF, 8) != 0; ) { /* add length of count, key, and data fields */ sz += CKDDASD_RECHDR_SIZE + buf[sz+5] + (buf[sz+6] << 8) + buf[sz+7]; if (sz > dev->ckdtrksz - 8) break; } /* add length for end-of-track indicator */ sz += CKDDASD_RECHDR_SIZE; if (sz > dev->ckdtrksz) sz = dev->ckdtrksz; return sz; } /*-------------------------------------------------------------------*/ /* Read a track image */ /*-------------------------------------------------------------------*/ static int ckddasd_read_track (DEVBLK *dev, int trk, BYTE *unitstat) { int rc; /* Return code */ int cyl; /* Cylinder */ int head; /* Head */ off_t offset; /* File offsets */ int i,o,f; /* Indexes */ int active; /* 1=Synchronous I/O active */ CKDDASD_TRKHDR *trkhdr; /* -> New track header */ logdevtr (dev, _("HHCDA024I read trk %d cur trk %d\n"), trk, dev->bufcur); /* Calculate cylinder and head */ cyl = trk / dev->ckdheads; head = trk % dev->ckdheads; /* Reset buffer offsets */ dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; /* Return if reading the same track image */ if (trk >= 0 && trk == dev->bufcur) return 0; /* Turn off the synchronous I/O bit if trk overflow or trk 0 */ active = dev->syncio_active; if (dev->ckdtrkof || trk <= 0) dev->syncio_active = 0; /* Write the previous track image if modified */ if (dev->bufupd) { /* Retry if synchronous I/O */ if (dev->syncio_active) { dev->syncio_retry = 1; return -1; } logdevtr (dev, _("HHCDA025I read track: updating track %d\n"), dev->bufcur); dev->bufupd = 0; /* Seek to the old track image offset */ offset = (off_t)(dev->ckdtrkoff + dev->bufupdlo); offset = lseek (dev->fd, offset, SEEK_SET); if (offset < 0) { /* Handle seek error condition */ logmsg (_("HHCDA026E error writing trk %d: lseek error: %s\n"), dev->bufcur, strerror(errno)); ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; cache_lock(CACHE_DEVBUF); cache_setflag(CACHE_DEVBUF, dev->cache, ~CKD_CACHE_ACTIVE, 0); cache_unlock(CACHE_DEVBUF); dev->bufupdlo = dev->bufupdhi = 0; dev->bufcur = dev->cache = -1; return -1; } /* Write the portion of the track image that was modified */ rc = write (dev->fd, &dev->buf[dev->bufupdlo], dev->bufupdhi - dev->bufupdlo); if (rc < dev->bufupdhi - dev->bufupdlo) { /* Handle seek error condition */ logmsg (_("HHCDA027E error writing trk %d: write error: %s\n"), dev->bufcur, strerror(errno)); ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; cache_lock(CACHE_DEVBUF); cache_setflag(CACHE_DEVBUF, dev->cache, ~CKD_CACHE_ACTIVE, 0); cache_unlock(CACHE_DEVBUF); dev->bufupdlo = dev->bufupdhi = 0; dev->bufcur = dev->cache = -1; return -1; } dev->bufupdlo = dev->bufupdhi = 0; } cache_lock (CACHE_DEVBUF); /* Make the previous cache entry inactive */ if (dev->cache >= 0) cache_setflag(CACHE_DEVBUF, dev->cache, ~CKD_CACHE_ACTIVE, 0); dev->bufcur = dev->cache = -1; /* Return on special case when called by the close handler */ if (trk < 0) { cache_unlock (CACHE_DEVBUF); return 0; } ckd_read_track_retry: /* Search the cache */ i = cache_lookup (CACHE_DEVBUF, CKD_CACHE_SETKEY(dev->devnum, trk), &o); /* Cache hit */ if (i >= 0) { cache_setflag(CACHE_DEVBUF, i, ~0, CKD_CACHE_ACTIVE); cache_setage(CACHE_DEVBUF, i); cache_unlock(CACHE_DEVBUF); logdevtr (dev, _("HHCDA028I read trk %d cache hit, using cache[%d]\n"), trk, i); dev->cachehits++; dev->cache = i; dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0); dev->bufcur = trk; dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; dev->buflen = ckd_trklen (dev, dev->buf); dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache); /* Set the file descriptor */ for (f = 0; f < dev->ckdnumfd; f++) if (trk < dev->ckdhitrk[f]) break; dev->fd = dev->ckdfd[f]; /* Calculate the track offset */ dev->ckdtrkoff = CKDDASD_DEVHDR_SIZE + (off_t)(trk - (f ? dev->ckdhitrk[f-1] : 0)) * dev->ckdtrksz; dev->syncio_active = active; return 0; } /* Retry if synchronous I/O */ if (dev->syncio_active) { cache_unlock(CACHE_DEVBUF); dev->syncio_retry = 1; return -1; } /* Wait if no available cache entry */ if (o < 0) { logdevtr (dev, _("HHCDA029I read trk %d no available cache entry, waiting\n"), trk); dev->cachewaits++; cache_wait(CACHE_DEVBUF); goto ckd_read_track_retry; } /* Cache miss */ logdevtr (dev, _("HHCDA030I read trk %d cache miss, using cache[%d]\n"), trk, o); dev->cachemisses++; /* Make this cache entry active */ cache_setkey (CACHE_DEVBUF, o, CKD_CACHE_SETKEY(dev->devnum, trk)); cache_setflag(CACHE_DEVBUF, o, 0, CKD_CACHE_ACTIVE|DEVBUF_TYPE_CKD); cache_setage (CACHE_DEVBUF, o); dev->buf = cache_getbuf(CACHE_DEVBUF, o, dev->ckdtrksz); cache_unlock (CACHE_DEVBUF); /* Set the file descriptor */ for (f = 0; f < dev->ckdnumfd; f++) if (trk < dev->ckdhitrk[f]) break; dev->fd = dev->ckdfd[f]; /* Calculate the track offset */ dev->ckdtrkoff = CKDDASD_DEVHDR_SIZE + (off_t)(trk - (f ? dev->ckdhitrk[f-1] : 0)) * dev->ckdtrksz; dev->syncio_active = active; logdevtr (dev, _("HHCDA031I read trk %d reading file %d offset %" I64_FMT "d len %d\n"), trk, f+1, (long long)dev->ckdtrkoff, dev->ckdtrksz); /* Seek to the track image offset */ offset = (off_t)dev->ckdtrkoff; offset = lseek (dev->fd, offset, SEEK_SET); if (offset < 0) { /* Handle seek error condition */ logmsg (_("HHCDA032E error reading trk %d: lseek error: %s\n"), trk, strerror(errno)); ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->bufcur = dev->cache = -1; cache_lock(CACHE_DEVBUF); cache_release(CACHE_DEVBUF, o, 0); cache_unlock(CACHE_DEVBUF); return -1; } /* Read the track image */ if (dev->dasdcopy == 0) { rc = read (dev->fd, dev->buf, dev->ckdtrksz); if (rc < dev->ckdtrksz) { /* Handle read error condition */ logmsg (_("HHCDA033E error reading trk %d: read error: %s\n"), trk, (rc < 0 ? strerror(errno) : "unexpected end of file")); ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->bufcur = dev->cache = -1; cache_lock(CACHE_DEVBUF); cache_release(CACHE_DEVBUF, o, 0); cache_unlock(CACHE_DEVBUF); return -1; } } else { trkhdr = (CKDDASD_TRKHDR *)dev->buf; trkhdr->bin = 0; trkhdr->cyl[0] = (cyl >> 8); trkhdr->cyl[1] = (cyl & 0xFF); trkhdr->head[0] = (head >> 8); trkhdr->head[1] = (head & 0xFF); memset (dev->buf + CKDDASD_TRKHDR_SIZE, 0xFF, 8); } /* Validate the track header */ logdevtr (dev, _("HHCDA034I read trk %d trkhdr %2.2x %2.2x%2.2x %2.2x%2.2x\n"), trk, dev->buf[0], dev->buf[1], dev->buf[2], dev->buf[3], dev->buf[4]); trkhdr = (CKDDASD_TRKHDR *)dev->buf; if (trkhdr->bin != 0 || trkhdr->cyl[0] != (cyl >> 8) || trkhdr->cyl[1] != (cyl & 0xFF) || trkhdr->head[0] != (head >> 8) || trkhdr->head[1] != (head & 0xFF)) { logmsg (_("HHCDA035E %4.4X invalid track header for cyl %d head %d " " %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cyl, head, trkhdr->bin,trkhdr->cyl[0],trkhdr->cyl[1],trkhdr->head[0],trkhdr->head[1]); ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->bufcur = dev->cache = -1; cache_lock(CACHE_DEVBUF); cache_release(CACHE_DEVBUF, o, 0); cache_unlock(CACHE_DEVBUF); return -1; } dev->cache = o; dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0); dev->bufcur = trk; dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; dev->buflen = ckd_trklen (dev, dev->buf); dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache); return 0; } /* end function ckdread_read_track */ /*-------------------------------------------------------------------*/ /* Update a track image */ /*-------------------------------------------------------------------*/ static int ckddasd_update_track (DEVBLK *dev, int trk, int off, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Immediately return if fake writing */ if (dev->ckdfakewr) return len; /* Error if opened read-only */ if (dev->ckdrdonly) { ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Read the track if it's not current */ if (trk != dev->bufcur) { rc = (dev->hnd->read) (dev, trk, unitstat); if (rc < 0) { dev->bufcur = dev->cache = -1; return -1; } } /* Invalid track format if going past buffer end */ if (off + len > dev->bufoffhi) { ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Copy the data into the buffer */ if (buf) memcpy (dev->buf + off, buf, len); /* Set low and high updated offsets */ if (!dev->bufupd || off < dev->bufupdlo) dev->bufupdlo = off; if (off + len > dev->bufupdhi) dev->bufupdhi = off + len; /* Indicate track image has been modified */ if (!dev->bufupd) { dev->bufupd = 1; shared_update_notify (dev, trk); } return len; } /* end function ckd_update_track */ /*-------------------------------------------------------------------*/ /* CKD start/resume channel program */ /*-------------------------------------------------------------------*/ void ckddasd_start (DEVBLK *dev) { /* Reset buffer offsets */ dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; } /*-------------------------------------------------------------------*/ /* CKD end/suspend channel program */ /*-------------------------------------------------------------------*/ void ckddasd_end (DEVBLK *dev) { BYTE unitstat; /* Unit Status */ /* Write the last track image if it's modified */ (dev->hnd->read) (dev, -1, &unitstat); } /*-------------------------------------------------------------------*/ /* Return used cylinders */ /*-------------------------------------------------------------------*/ int ckddasd_used (DEVBLK *dev) { return dev->ckdcyls; } /*-------------------------------------------------------------------*/ /* Hercules suspend/resume text unit key values */ /*-------------------------------------------------------------------*/ #define SR_DEV_CKD_BUFCUR ( SR_DEV_CKD | 0x001 ) #define SR_DEV_CKD_BUFOFF ( SR_DEV_CKD | 0x002 ) #define SR_DEV_CKD_CURCYL ( SR_DEV_CKD | 0x003 ) #define SR_DEV_CKD_CURHEAD ( SR_DEV_CKD | 0x004 ) #define SR_DEV_CKD_CURREC ( SR_DEV_CKD | 0x005 ) #define SR_DEV_CKD_CURKL ( SR_DEV_CKD | 0x006 ) #define SR_DEV_CKD_ORIENT ( SR_DEV_CKD | 0x007 ) #define SR_DEV_CKD_CUROPER ( SR_DEV_CKD | 0x008 ) #define SR_DEV_CKD_CURDL ( SR_DEV_CKD | 0x009 ) #define SR_DEV_CKD_REM ( SR_DEV_CKD | 0x00a ) #define SR_DEV_CKD_POS ( SR_DEV_CKD | 0x00b ) #define SR_DEV_CKD_DXBLKSZ ( SR_DEV_CKD | 0x010 ) #define SR_DEV_CKD_DXBCYL ( SR_DEV_CKD | 0x011 ) #define SR_DEV_CKD_DXBHEAD ( SR_DEV_CKD | 0x012 ) #define SR_DEV_CKD_DXECYL ( SR_DEV_CKD | 0x013 ) #define SR_DEV_CKD_DXEHEAD ( SR_DEV_CKD | 0x014 ) #define SR_DEV_CKD_DXFMASK ( SR_DEV_CKD | 0x015 ) #define SR_DEV_CKD_DXGATTR ( SR_DEV_CKD | 0x016 ) #define SR_DEV_CKD_LRTRANLF ( SR_DEV_CKD | 0x020 ) #define SR_DEV_CKD_LROPER ( SR_DEV_CKD | 0x021 ) #define SR_DEV_CKD_LRAUX ( SR_DEV_CKD | 0x022 ) #define SR_DEV_CKD_LRCOUNT ( SR_DEV_CKD | 0x023 ) #define SR_DEV_CKD_3990 ( SR_DEV_CKD | 0x040 ) #define SR_DEV_CKD_XTDEF ( SR_DEV_CKD | 0x041 ) #define SR_DEV_CKD_SETFM ( SR_DEV_CKD | 0x042 ) #define SR_DEV_CKD_LOCAT ( SR_DEV_CKD | 0x043 ) #define SR_DEV_CKD_SPCNT ( SR_DEV_CKD | 0x044 ) #define SR_DEV_CKD_SEEK ( SR_DEV_CKD | 0x045 ) #define SR_DEV_CKD_SKCYL ( SR_DEV_CKD | 0x046 ) #define SR_DEV_CKD_RECAL ( SR_DEV_CKD | 0x047 ) #define SR_DEV_CKD_RDIPL ( SR_DEV_CKD | 0x048 ) #define SR_DEV_CKD_XMARK ( SR_DEV_CKD | 0x049 ) #define SR_DEV_CKD_HAEQ ( SR_DEV_CKD | 0x04a ) #define SR_DEV_CKD_IDEQ ( SR_DEV_CKD | 0x04b ) #define SR_DEV_CKD_KYEQ ( SR_DEV_CKD | 0x04c ) #define SR_DEV_CKD_WCKD ( SR_DEV_CKD | 0x04d ) #define SR_DEV_CKD_TRKOF ( SR_DEV_CKD | 0x04e ) #define SR_DEV_CKD_SSI ( SR_DEV_CKD | 0x04f ) #define SR_DEV_CKD_WRHA ( SR_DEV_CKD | 0x050 ) /*-------------------------------------------------------------------*/ /* Hercules suspend */ /*-------------------------------------------------------------------*/ int ckddasd_hsuspend(DEVBLK *dev, void *file) { if (dev->bufcur >= 0) { SR_WRITE_VALUE(file, SR_DEV_CKD_BUFCUR, dev->bufcur, sizeof(dev->bufcur)); SR_WRITE_VALUE(file, SR_DEV_CKD_BUFOFF, dev->bufoff, sizeof(dev->bufoff)); } SR_WRITE_VALUE(file, SR_DEV_CKD_CURCYL, dev->ckdcurcyl, sizeof(dev->ckdcurcyl)); SR_WRITE_VALUE(file, SR_DEV_CKD_CURHEAD, dev->ckdcurhead, sizeof(dev->ckdcurhead)); SR_WRITE_VALUE(file, SR_DEV_CKD_CURREC, dev->ckdcurrec, sizeof(dev->ckdcurrec)); SR_WRITE_VALUE(file, SR_DEV_CKD_CURKL, dev->ckdcurkl, sizeof(dev->ckdcurkl)); SR_WRITE_VALUE(file, SR_DEV_CKD_ORIENT, dev->ckdorient, sizeof(dev->ckdorient)); SR_WRITE_VALUE(file, SR_DEV_CKD_CUROPER, dev->ckdcuroper, sizeof(dev->ckdcuroper)); SR_WRITE_VALUE(file, SR_DEV_CKD_CURDL, dev->ckdcurdl, sizeof(dev->ckdcurdl)); SR_WRITE_VALUE(file, SR_DEV_CKD_REM, dev->ckdrem, sizeof(dev->ckdrem)); SR_WRITE_VALUE(file, SR_DEV_CKD_POS, dev->ckdpos, sizeof(dev->ckdpos)); SR_WRITE_VALUE(file, SR_DEV_CKD_DXBLKSZ, dev->ckdxblksz, sizeof(dev->ckdxblksz)); SR_WRITE_VALUE(file, SR_DEV_CKD_DXBCYL, dev->ckdxbcyl, sizeof(dev->ckdxbcyl)); SR_WRITE_VALUE(file, SR_DEV_CKD_DXBHEAD, dev->ckdxbhead, sizeof(dev->ckdxbhead)); SR_WRITE_VALUE(file, SR_DEV_CKD_DXECYL, dev->ckdxecyl, sizeof(dev->ckdxecyl)); SR_WRITE_VALUE(file, SR_DEV_CKD_DXEHEAD, dev->ckdxehead, sizeof(dev->ckdxehead)); SR_WRITE_VALUE(file, SR_DEV_CKD_DXFMASK, dev->ckdfmask, sizeof(dev->ckdfmask)); SR_WRITE_VALUE(file, SR_DEV_CKD_DXGATTR, dev->ckdxgattr, sizeof(dev->ckdxgattr)); SR_WRITE_VALUE(file, SR_DEV_CKD_LRTRANLF, dev->ckdltranlf, sizeof(dev->ckdltranlf)); SR_WRITE_VALUE(file, SR_DEV_CKD_LROPER, dev->ckdloper, sizeof(dev->ckdloper)); SR_WRITE_VALUE(file, SR_DEV_CKD_LRAUX, dev->ckdlaux, sizeof(dev->ckdlaux)); SR_WRITE_VALUE(file, SR_DEV_CKD_LRCOUNT, dev->ckdlcount, sizeof(dev->ckdlcount)); SR_WRITE_VALUE(file, SR_DEV_CKD_3990, dev->ckd3990, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_XTDEF, dev->ckdxtdef, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_SETFM, dev->ckdsetfm, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_LOCAT, dev->ckdlocat, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_SPCNT, dev->ckdspcnt, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_SEEK, dev->ckdseek, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_SKCYL, dev->ckdskcyl, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_RECAL, dev->ckdrecal, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_RDIPL, dev->ckdrdipl, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_XMARK, dev->ckdxmark, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_HAEQ, dev->ckdhaeq, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_IDEQ, dev->ckdideq, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_KYEQ, dev->ckdkyeq, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_WCKD, dev->ckdwckd, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_TRKOF, dev->ckdtrkof, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_SSI, dev->ckdssi, 1); SR_WRITE_VALUE(file, SR_DEV_CKD_WRHA, dev->ckdwrha, 1); return 0; } /*-------------------------------------------------------------------*/ /* Hercules resume */ /*-------------------------------------------------------------------*/ int ckddasd_hresume(DEVBLK *dev, void *file) { u_int rc; size_t key, len; BYTE byte; do { SR_READ_HDR(file, key, len); switch (key) { case SR_DEV_CKD_BUFCUR: SR_READ_VALUE(file, len, &rc, sizeof(rc)); rc = (dev->hnd->read) ? (dev->hnd->read)(dev, rc, &byte) : -1; if ((int)rc < 0) return -1; break; case SR_DEV_CKD_BUFOFF: SR_READ_VALUE(file, len, &dev->bufoff, sizeof(dev->bufoff)); break; case SR_DEV_CKD_CURCYL: SR_READ_VALUE(file, len, &dev->ckdcurcyl, sizeof(dev->ckdcurcyl)); break; case SR_DEV_CKD_CURHEAD: SR_READ_VALUE(file, len, &dev->ckdcurhead, sizeof(dev->ckdcurhead)); break; case SR_DEV_CKD_CURREC: SR_READ_VALUE(file, len, &dev->ckdcurrec, sizeof(dev->ckdcurrec)); break; case SR_DEV_CKD_CURKL: SR_READ_VALUE(file, len, &dev->ckdcurkl, sizeof(dev->ckdcurkl)); break; case SR_DEV_CKD_ORIENT: SR_READ_VALUE(file, len, &dev->ckdorient, sizeof(dev->ckdorient)); break; case SR_DEV_CKD_CUROPER: SR_READ_VALUE(file, len, &dev->ckdcuroper, sizeof(dev->ckdcuroper)); break; case SR_DEV_CKD_CURDL: SR_READ_VALUE(file, len, &dev->ckdcurdl, sizeof(dev->ckdcurdl)); break; case SR_DEV_CKD_REM: SR_READ_VALUE(file, len, &dev->ckdrem, sizeof(dev->ckdrem)); break; case SR_DEV_CKD_POS: SR_READ_VALUE(file, len, &dev->ckdpos, sizeof(dev->ckdpos)); break; case SR_DEV_CKD_DXBLKSZ: SR_READ_VALUE(file, len, &dev->ckdxblksz, sizeof(dev->ckdxblksz)); break; case SR_DEV_CKD_DXBCYL: SR_READ_VALUE(file, len, &dev->ckdxbcyl, sizeof(dev->ckdxbcyl)); break; case SR_DEV_CKD_DXBHEAD: SR_READ_VALUE(file, len, &dev->ckdxbhead, sizeof(dev->ckdxbhead)); break; case SR_DEV_CKD_DXECYL: SR_READ_VALUE(file, len, &dev->ckdxecyl, sizeof(dev->ckdxecyl)); break; case SR_DEV_CKD_DXEHEAD: SR_READ_VALUE(file, len, &dev->ckdxehead, sizeof(dev->ckdxehead)); break; case SR_DEV_CKD_DXFMASK: SR_READ_VALUE(file, len, &dev->ckdfmask, sizeof(dev->ckdfmask)); break; case SR_DEV_CKD_DXGATTR: SR_READ_VALUE(file, len, &dev->ckdxgattr, sizeof(dev->ckdxgattr)); break; case SR_DEV_CKD_LRTRANLF: SR_READ_VALUE(file, len, &dev->ckdltranlf, sizeof(dev->ckdltranlf)); break; case SR_DEV_CKD_LROPER: SR_READ_VALUE(file, len, &dev->ckdloper, sizeof(dev->ckdloper)); break; case SR_DEV_CKD_LRAUX: SR_READ_VALUE(file, len, &dev->ckdlaux, sizeof(dev->ckdlaux)); break; case SR_DEV_CKD_LRCOUNT: SR_READ_VALUE(file, len, &dev->ckdltranlf, sizeof(dev->ckdltranlf)); break; case SR_DEV_CKD_3990: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckd3990 = rc; break; case SR_DEV_CKD_XTDEF: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdxtdef = rc; break; case SR_DEV_CKD_SETFM: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdsetfm = rc; break; case SR_DEV_CKD_LOCAT: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdlocat = rc; break; case SR_DEV_CKD_SPCNT: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdspcnt = rc; break; case SR_DEV_CKD_SEEK: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdseek = rc; break; case SR_DEV_CKD_SKCYL: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdskcyl = rc; break; case SR_DEV_CKD_RECAL: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdrecal = rc; break; case SR_DEV_CKD_RDIPL: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdrdipl = rc; break; case SR_DEV_CKD_XMARK: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdxmark = rc; break; case SR_DEV_CKD_HAEQ: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdhaeq = rc; break; case SR_DEV_CKD_IDEQ: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdideq = rc; break; case SR_DEV_CKD_KYEQ: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdkyeq = rc; break; case SR_DEV_CKD_WCKD: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdwckd = rc; break; case SR_DEV_CKD_TRKOF: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdtrkof = rc; break; case SR_DEV_CKD_SSI: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdssi = rc; break; case SR_DEV_CKD_WRHA: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->ckdwrha = rc; break; default: SR_READ_SKIP(file, len); break; } /* switch (key) */ } while ((key & SR_DEV_MASK) == SR_DEV_CKD); return 0; } /*-------------------------------------------------------------------*/ /* Build sense data */ /*-------------------------------------------------------------------*/ void ckd_build_sense ( DEVBLK *dev, BYTE sense0, BYTE sense1, BYTE sense2, BYTE format, BYTE message ) { int shift; /* num of bits to shift left 'high cyl' in sense6 */ /* Clear the sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Sense bytes 0-2 are specified by caller */ dev->sense[0] = sense0; dev->sense[1] = sense1; dev->sense[2] = sense2; /* Sense byte 3 contains the residual locate record count if imprecise ending is indicated in sense byte 1 */ if (sense1 & SENSE1_IE) { if (dev->ckdtrkof) dev->sense[3] = dev->ckdcuroper; else dev->sense[3] = dev->ckdlcount; } /* Sense byte 4 is the physical device address */ dev->sense[4] = 0; if (dev->devtype == 0x2305) { /* 0x40=ONLINE 0x04=END OF CYL */ dev->sense[3] = (((dev->sense[1]) & 0x20) >> 3) | 0x40; } if (dev->devtype == 0x2311) { /* 0x80=READY, 0x40=ONLINE 0x08=ONLINE 0x04=END OF CYL */ dev->sense[3] = (((dev->sense[1]) & 0x20) >> 3) | 0xC8; } if (dev->devtype == 0x2314) { /* 0x40=ONLINE 0x04=END OF CYL */ dev->sense[3] = (((dev->sense[1]) & 0x20) >> 3) | 0x40; } if (dev->devtype == 0x3330) { /* bits 0-1 = controller address */ /* bits 2-7: drive A = 111000, B = 110001, ... H = 000111 */ dev->sense[4] = (dev->devnum & 0x07) | ((~(dev->devnum) & 0x07) << 3); } if (dev->devtype == 0x3340) { /* X'01' = 35 MB drive, X'02' = 70 MB drive (same as 'model') */ /* X'80' RPS feature installed */ dev->sense[2] |= 0x80 | dev->devid[6]; /* RPS + model */ /* drive A = bit 0 (0x80), ... drive H = bit 7 (0x01) */ dev->sense[4] = 0x80 >> (dev->devnum & 0x07); } if (dev->devtype == 0x3350) { /* drive 0 = bit 0 (0x80), ... drive 7 = bit 7 (0x01) */ dev->sense[4] = 0x80 >> (dev->devnum & 0x07); } if (dev->devtype == 0x3375) { /* bits 3-4 = controller address, bits 5-7 = device address */ dev->sense[4] = dev->devnum & 0x07; } if (dev->devtype == 0x3380) { /* bits 4-7 = device address */ dev->sense[4] = dev->devnum & 0x0F; } /* Sense byte 5 contains bits 8-15 of the cylinder address and sense byte 6 contains bits 4-7 of the cylinder address followed by bits 12-15 of the head address, unless the device has more than 4095 cylinders, in which case sense bytes 5 and 6 both contain X'FF' */ if (dev->ckdcyls > 4095) { dev->sense[5] = 0xFF; dev->sense[6] = 0xFF; } else { if ((dev->devtype == 0x2311 ) || (dev->devtype == 0x2314 ) || (dev->devtype == 0x2305 )) { } else { dev->sense[5] = dev->ckdcurcyl & 0xFF; /* sense byte 6 bits c = cyl high byte, h=head */ /* 0 1 2 3 4 5 6 7 shift */ /* 3330-1 - c - h h h h h 6 */ /* 3330-11 3350 - c c h h h h h 5 */ /* 3340 - c c - h h h h 5 */ /* 3375 c c - - h h h h 6 */ /* 3380 c c c c h h h h 4 */ switch (dev->devtype) { case 0x3330: if (dev->devid[6] == 0x01) shift = 6; /* 3330-1 */ else shift = 5; /* 3330-11 */ case 0x3340: case 0x3350: shift = 5; case 0x3375: shift = 6; default: shift = 4; } dev->sense[6] = ( (dev->ckdcurcyl >> 8) << shift ) | (dev->ckdcurhead & 0x1F); } } /* Sense byte 7 contains the format code and message type */ dev->sense[7] = (format << 4) | (message & 0x0F); /* Sense bytes 8-23 depend on the format code */ switch (format) { case FORMAT_4: /* Data check */ case FORMAT_5: /* Data check with displacement information */ /* Sense bytes 8-12 contain the CCHHR of the record in error */ dev->sense[8] = dev->ckdcurcyl >> 8; dev->sense[9] = dev->ckdcurcyl & 0xFF; dev->sense[10] = dev->ckdcurhead >> 8; dev->sense[11] = dev->ckdcurhead & 0xFF; dev->sense[12] = dev->ckdcurrec; break; } /* end switch(format) */ /* Sense byte 27 bit 0 indicates 24-byte compatability sense data*/ dev->sense[27] = 0x80; /* Sense bytes 29-30 contain the cylinder address */ dev->sense[29] = dev->ckdcurcyl >> 8; dev->sense[30] = dev->ckdcurcyl & 0xFF; /* Sense byte 31 contains the head address */ dev->sense[31] = dev->ckdcurhead & 0xFF; } /* end function ckd_build_sense */ /*-------------------------------------------------------------------*/ /* Seek to a specified cylinder and head */ /*-------------------------------------------------------------------*/ static int ckd_seek ( DEVBLK *dev, int cyl, int head, CKDDASD_TRKHDR *trkhdr, BYTE *unitstat ) { int rc; /* Return code */ logdevtr (dev, _("HHCDA038I seeking to cyl %d head %d\n"), cyl, head); /* Read the track image */ rc = ckd_read_cchh (dev, cyl, head, unitstat); if (rc < 0) return -1; /* Set device orientation fields */ dev->ckdcurcyl = cyl; dev->ckdcurhead = head; dev->ckdcurrec = 0; dev->ckdcurkl = 0; dev->ckdcurdl = 0; dev->ckdrem = 0; dev->ckdorient = CKDORIENT_INDEX; /* Copy the track header */ if (trkhdr) memcpy (trkhdr, &dev->buf[dev->bufoff], CKDDASD_TRKHDR_SIZE); /* Increment offset past the track header */ dev->bufoff += CKDDASD_TRKHDR_SIZE; return 0; } /* end function ckd_seek */ /*-------------------------------------------------------------------*/ /* Advance to next track for multitrack operation */ /*-------------------------------------------------------------------*/ static int mt_advance ( DEVBLK *dev, BYTE *unitstat, int trks ) { int rc; /* Return code */ int cyl; /* Next cyl for multitrack */ int head; /* Next head for multitrack */ /* File protect error if not within domain of Locate Record and file mask inhibits seek and multitrack operations */ if (dev->ckdlcount == 0 && (dev->ckdfmask & CKDMASK_SKCTL) == CKDMASK_SKCTL_INHSMT) { logdevtr (dev, _("HHCDA039E MT advance error: " "locate record %d file mask %2.2X\n"), dev->ckdlcount, dev->ckdfmask); if (dev->ckdtrkof) ckd_build_sense (dev, 0, SENSE1_FP | SENSE1_IE, 0, 0, 0); else ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* End of cylinder error if not within domain of Locate Record and current track is last track of cylinder */ if (dev->ckdlcount == 0 && dev->ckdcurhead + trks >= dev->ckdheads) { if (dev->ckdtrkof) ckd_build_sense (dev, 0, SENSE1_EOC | SENSE1_IE, 0, 0, 0); else ckd_build_sense (dev, 0, SENSE1_EOC, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Advance to next track */ cyl = dev->ckdcurcyl; head = dev->ckdcurhead + trks; while (head >= dev->ckdheads) { head -= dev->ckdheads; cyl++; } logdevtr (dev, _("HHCDA040I MT advance to cyl %d head %d\n"), cyl, head); /* File protect error if next track is outside the limits of the device or outside the defined extent */ if ( EXTENT_CHECK(dev, cyl, head) ) { if (dev->ckdtrkof) ckd_build_sense (dev, 0, SENSE1_FP | SENSE1_IE, 0, 0, 0); else ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Seek to next track */ rc = ckd_seek (dev, cyl, head, NULL, unitstat); if (rc < 0) return -1; /* Successful return */ return 0; } /* end function mt_advance */ /*-------------------------------------------------------------------*/ /* Read count field */ /*-------------------------------------------------------------------*/ static int ckd_read_count ( DEVBLK *dev, BYTE code, CKDDASD_RECHDR *rechdr, BYTE *unitstat) { int rc; /* Return code */ int skipr0 = 0; /* 1=Skip record zero */ int cyl; /* Cylinder number for seek */ int head; /* Head number for seek */ char *orient[] = {"none", "index", "count", "key", "data", "eot"}; /* Skip record 0 for all operations except READ TRACK, READ R0, SEARCH ID EQUAL, SEARCH ID HIGH, SEARCH ID EQUAL OR HIGH, LOCATE RECORD, and WRITE CKD NEXT TRACK */ if (code != 0xDE && (code & 0x7F) != 0x16 && (code & 0x7F) != 0x31 && (code & 0x7F) != 0x51 && (code & 0x7F) != 0x71 && code != 0x47 && code != 0x4B && code != 0x9D) skipr0 = 1; logdevtr (dev, _("HHCDA041I read count orientation is %s\n"), orient[dev->ckdorient]); /* If orientation is at End-Of_Track then a multi-track advance failed previously during synchronous I/O */ if (dev->ckdorient == CKDORIENT_EOT) { rc = mt_advance (dev, unitstat, 1); if (rc < 0) return -1; } /* Search for next count field */ for ( ; ; ) { /* If oriented to count or key field, skip key and data */ if (dev->ckdorient == CKDORIENT_COUNT) dev->bufoff += dev->ckdcurkl + dev->ckdcurdl; else if (dev->ckdorient == CKDORIENT_KEY) dev->bufoff += dev->ckdcurdl; /* Make sure we don't copy past the end of the buffer */ if (dev->bufoff + CKDDASD_RECHDR_SIZE >= dev->bufoffhi) { /* Handle error condition */ logmsg (_("HHCDA042E attempt to read past end of track %d %d\n"), dev->bufoff, dev->bufoffhi); /* Set unit check with equipment check */ ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Copy the record header (count field) */ memcpy (rechdr, &dev->buf[dev->bufoff], CKDDASD_RECHDR_SIZE); dev->bufoff += CKDDASD_RECHDR_SIZE; /* Set the device orientation fields */ dev->ckdcurrec = rechdr->rec; dev->ckdrem = 0; dev->ckdorient = CKDORIENT_COUNT; dev->ckdcurkl = rechdr->klen; dev->ckdcurdl = (rechdr->dlen[0] << 8) + rechdr->dlen[1]; if(dev->ckdcyls < 32768) dev->ckdtrkof = (rechdr->cyl[0] == 0xFF) ? 0 : rechdr->cyl[0] >> 7; else dev->ckdtrkof = 0; logdevtr (dev, _("HHCDA043I cyl %d head %d record %d kl %d dl %d of %d\n"), dev->ckdcurcyl, dev->ckdcurhead, dev->ckdcurrec, dev->ckdcurkl, dev->ckdcurdl, dev->ckdtrkof); /* Skip record zero if user data record required */ if (skipr0 && rechdr->rec == 0) continue; /* Test for logical end of track and exit if not */ if (memcmp(rechdr, eighthexFF, 8) != 0) break; dev->ckdorient = CKDORIENT_EOT; /* For READ TRACK or READ MULTIPLE CKD, return with the end of track marker in the record header field */ if (code == 0xDE || code == 0x5E) break; /* End of track found, so terminate with no record found error if this is a LOCATE RECORD or WRITE CKD NEXT TRACK command; or if this is the second end of track in this channel program without an intervening read of the home address or data area and without an intervening write, sense, or control command -- -- except when multitrack READ or SEARCH [KEY?] command operates outside the domain of a locate record */ if (code == 0x47 || code == 0x4B || code == 0x9D || (dev->ckdxmark && !((dev->ckdlcount == 0) && ( (IS_CCW_READ(code) && (code&0x80)) || code==0xA9 || code==0xC9 || code==0xE9) ))) { ckd_build_sense (dev, 0, SENSE1_NRF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Test for multitrack operation */ if ((code & 0x80) == 0) { /* If non-multitrack, return to start of current track */ cyl = dev->ckdcurcyl; head = dev->ckdcurhead; rc = ckd_seek (dev, cyl, head, NULL, unitstat); if (rc < 0) return -1; /* Set index marker found flag */ dev->ckdxmark = 1; } else { /* If multitrack, attempt to advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) return -1; /* Set index marker flag if non-search command */ if ((code & 0x7F) != 0x31 && (code & 0x7F) != 0x51 && (code & 0x7F) != 0x71 && (code & 0x7F) != 0x29 && (code & 0x7F) != 0x49 && (code & 0x7F) != 0x69) dev->ckdxmark = 1; } } /* end for */ return 0; } /* end function ckd_read_count */ /*-------------------------------------------------------------------*/ /* Read key field */ /*-------------------------------------------------------------------*/ static int ckd_read_key ( DEVBLK *dev, BYTE code, BYTE *buf, BYTE *unitstat) { int rc; /* Return code */ CKDDASD_RECHDR rechdr; /* CKD record header */ /* If not oriented to count field, read next count field */ if (dev->ckdorient != CKDORIENT_COUNT) { rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) return rc; } logdevtr (dev, _("HHCDA044I read key %d bytes\n"), dev->ckdcurkl); /* Read key field */ if (dev->ckdcurkl > 0) { if (dev->bufoffhi - dev->bufoff < dev->ckdcurkl) { /* Handle error condition */ logmsg (_("ckddasd: attempt to read past end of track\n")); /* Set unit check with equipment check */ ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } memcpy (buf, &dev->buf[dev->bufoff], dev->ckdcurkl); dev->bufoff += dev->ckdcurkl; } /* Set the device orientation fields */ dev->ckdrem = 0; dev->ckdorient = CKDORIENT_KEY; return 0; } /* end function ckd_read_key */ /*-------------------------------------------------------------------*/ /* Read data field */ /*-------------------------------------------------------------------*/ static int ckd_read_data ( DEVBLK *dev, BYTE code, BYTE *buf, BYTE *unitstat) { int rc; /* Return code */ CKDDASD_RECHDR rechdr; /* Record header */ /* If not oriented to count or key field, read next count field */ if (dev->ckdorient != CKDORIENT_COUNT && dev->ckdorient != CKDORIENT_KEY) { rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) return rc; } /* If oriented to count field, skip the key field */ if (dev->ckdorient == CKDORIENT_COUNT) dev->bufoff += dev->ckdcurkl; logdevtr (dev, _("HHCDA045I read data %d bytes\n"), dev->ckdcurdl); /* Read data field */ if (dev->ckdcurdl > 0) { if (dev->bufoff + dev->ckdcurdl >= dev->bufoffhi) { /* Handle error condition */ logmsg (_("HHCDA046E attempt to read past end of track\n")); /* Set unit check with equipment check */ ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } memcpy (buf, &dev->buf[dev->bufoff], dev->ckdcurdl); dev->bufoff += dev->ckdcurdl; } /* Set the device orientation fields */ dev->ckdrem = 0; dev->ckdorient = CKDORIENT_DATA; return 0; } /* end function ckd_read_data */ /*-------------------------------------------------------------------*/ /* Erase remainder of track */ /*-------------------------------------------------------------------*/ static int ckd_erase ( DEVBLK *dev, BYTE *buf, int len, int *size, BYTE *unitstat) { int rc; /* Return code */ CKDDASD_RECHDR rechdr; /* CKD record header */ int keylen; /* Key length */ int datalen; /* Data length */ int ckdlen; /* Count+key+data length */ /* If oriented to count or key field, skip key and data */ if (dev->ckdorient == CKDORIENT_COUNT) dev->bufoff += dev->ckdcurkl + dev->ckdcurdl; else if (dev->ckdorient == CKDORIENT_KEY) dev->bufoff += dev->ckdcurdl; /* Copy the count field from the buffer */ memset (&rechdr, 0, CKDDASD_RECHDR_SIZE); memcpy (&rechdr, buf, (len < CKDDASD_RECHDR_SIZE) ? len : CKDDASD_RECHDR_SIZE); /* Extract the key length and data length */ keylen = rechdr.klen; datalen = (rechdr.dlen[0] << 8) + rechdr.dlen[1]; /* Calculate total count key and data size */ ckdlen = CKDDASD_RECHDR_SIZE + keylen + datalen; /* Check that there is enough space on the current track to contain the complete erase plus an end of track marker */ if (dev->bufoff + ckdlen + 8 >= dev->bufoffhi) { /* Unit check with invalid track format */ ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Logically erase rest of track by writing end of track marker */ rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, eighthexFF, 8, unitstat); if (rc < 0) return -1; /* Return total count key and data size */ *size = ckdlen; /* Set the device orientation fields */ dev->ckdrem = 0; dev->ckdorient = CKDORIENT_DATA; return 0; } /* end function ckd_erase */ /*-------------------------------------------------------------------*/ /* Write count key and data fields */ /*-------------------------------------------------------------------*/ static int ckd_write_ckd ( DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat, BYTE trk_ovfl) { int rc; /* Return code */ CKDDASD_RECHDR rechdr; /* CKD record header */ int recnum; /* Record number */ int keylen; /* Key length */ int datalen; /* Data length */ int ckdlen; /* Count+key+data length */ /* If oriented to count or key field, skip key and data */ if (dev->ckdorient == CKDORIENT_COUNT) dev->bufoff += dev->ckdcurkl + dev->ckdcurdl; else if (dev->ckdorient == CKDORIENT_KEY) dev->bufoff += dev->ckdcurdl; /* Copy the count field from the buffer */ memset (&rechdr, 0, CKDDASD_RECHDR_SIZE); memcpy (&rechdr, buf, (len < CKDDASD_RECHDR_SIZE) ? len : CKDDASD_RECHDR_SIZE); /* Extract the record number, key length and data length */ recnum = rechdr.rec; keylen = rechdr.klen; datalen = (rechdr.dlen[0] << 8) + rechdr.dlen[1]; /* Calculate total count key and data size */ ckdlen = CKDDASD_RECHDR_SIZE + keylen + datalen; if (dev->bufoff + ckdlen + 8 >= dev->bufoffhi) { /* Unit check with invalid track format */ ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Pad the I/O buffer with zeroes if necessary */ while (len < ckdlen) buf[len++] = '\0'; logdevtr (dev, _("HHCDA047I writing cyl %d head %d record %d kl %d dl %d\n"), dev->ckdcurcyl, dev->ckdcurhead, recnum, keylen, datalen); /* Set track overflow flag if called for */ if (trk_ovfl) { logdevtr (dev, _("HHCDA048I setting track overflow flag for " "cyl %d head %d record %d\n"), dev->ckdcurcyl, dev->ckdcurhead, recnum); buf[0] |= 0x80; } /* Write count key and data */ rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, buf, ckdlen, unitstat); if (rc < 0) return -1; dev->bufoff += ckdlen; /* Clear track overflow flag if we set it above */ if (trk_ovfl) { buf[0] &= 0x7F; } /* Logically erase rest of track by writing end of track marker */ rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, eighthexFF, 8, unitstat); if (rc < 0) return -1; /* Set the device orientation fields */ dev->ckdcurrec = recnum; dev->ckdcurkl = keylen; dev->ckdcurdl = datalen; dev->ckdrem = 0; dev->ckdorient = CKDORIENT_DATA; dev->ckdtrkof = dev->ckdcyls < 32768 ? trk_ovfl & 1 : 0; return 0; } /* end function ckd_write_ckd */ /*-------------------------------------------------------------------*/ /* Write key and data fields */ /*-------------------------------------------------------------------*/ static int ckd_write_kd ( DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ int kdlen; /* Key+data length */ /* Unit check if not oriented to count area */ if (dev->ckdorient != CKDORIENT_COUNT) { logmsg (_("HHCDA049E Write KD orientation error\n")); ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Calculate total key and data size */ kdlen = dev->ckdcurkl + dev->ckdcurdl; /* Pad the I/O buffer with zeroes if necessary */ while (len < kdlen) buf[len++] = '\0'; logdevtr (dev, _("HHCDA050I updating cyl %d head %d record %d kl %d dl %d\n"), dev->ckdcurcyl, dev->ckdcurhead, dev->ckdcurrec, dev->ckdcurkl, dev->ckdcurdl); /* Write key and data */ rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, buf, kdlen, unitstat); if (rc < 0) return -1; dev->bufoff += kdlen; /* Set the device orientation fields */ dev->ckdrem = 0; dev->ckdorient = CKDORIENT_DATA; return 0; } /* end function ckd_write_kd */ /*-------------------------------------------------------------------*/ /* Write data field */ /*-------------------------------------------------------------------*/ static int ckd_write_data ( DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Unit check if not oriented to count or key areas */ if (dev->ckdorient != CKDORIENT_COUNT && dev->ckdorient != CKDORIENT_KEY) { logmsg (_("HHCDA051E Write data orientation error\n")); ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* If oriented to count field, skip the key field */ if (dev->ckdorient == CKDORIENT_COUNT) dev->bufoff += dev->ckdcurkl; /* Pad the I/O buffer with zeroes if necessary */ while (len < dev->ckdcurdl) buf[len++] = '\0'; logdevtr (dev, _("HHCDA052I updating cyl %d head %d record %d dl %d\n"), dev->ckdcurcyl, dev->ckdcurhead, dev->ckdcurrec, dev->ckdcurdl); /* Write data */ rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, buf, dev->ckdcurdl, unitstat); if (rc < 0) return -1; dev->bufoff += dev->ckdcurdl; /* Set the device orientation fields */ dev->ckdrem = 0; dev->ckdorient = CKDORIENT_DATA; return 0; } /* end function ckd_write_data */ /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ void ckddasd_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { int rc; /* Return code */ int i, j; /* Loop index */ CKDDASD_TRKHDR trkhdr; /* CKD track header (HA) */ CKDDASD_RECHDR rechdr; /* CKD record header (count) */ int size; /* Number of bytes available */ int num; /* Number of bytes to move */ int offset; /* Offset into buf for I/O */ int bin; /* Bin number */ int cyl; /* Cylinder number */ int head; /* Head number */ BYTE cchhr[5]; /* Search argument */ BYTE sector; /* Sector number */ BYTE key[256]; /* Key for search operations */ BYTE trk_ovfl; /* == 1 if track ovfl write */ /* If this is a data-chained READ, then return any data remaining in the buffer which was not used by the previous CCW */ if (chained & CCW_FLAGS_CD) { memmove (iobuf, iobuf + dev->ckdpos, dev->ckdrem); num = (count < dev->ckdrem) ? count : dev->ckdrem; *residual = count - num; if (count < dev->ckdrem) *more = 1; dev->ckdrem -= num; dev->ckdpos = num; *unitstat = CSW_CE | CSW_DE; return; } /* Command reject if data chaining and command is not READ */ if ((flags & CCW_FLAGS_CD) && code != 0x02 && code != 0x5E && (code & 0x7F) != 0x1E && (code & 0x7F) != 0x1A && (code & 0x7F) != 0x16 && (code & 0x7F) != 0x12 && (code & 0x7F) != 0x0E && (code & 0x7F) != 0x06) { logmsg(_("HHCDA053E Data chaining not supported for CCW %2.2X\n"), code); ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1); *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* Reset flags at start of CCW chain */ if (chained == 0 && !dev->syncio_retry) { dev->ckdlocat = 0; dev->ckdspcnt = 0; dev->ckdseek = 0; dev->ckdskcyl = 0; dev->ckdrecal = 0; dev->ckdrdipl = 0; dev->ckdfmask = 0; dev->ckdxmark = 0; dev->ckdhaeq = 0; dev->ckdideq = 0; dev->ckdkyeq = 0; dev->ckdwckd = 0; dev->ckdlcount = 0; dev->ckdlmask = 0; dev->ckdtrkof = 0; /* ISW20030819-1 : Clear Write HA flag */ dev->ckdwrha = 0; dev->ckdssdlen = 0; /* Set initial define extent parameters */ dev->ckdxtdef = 0; dev->ckdsetfm = 0; dev->ckdfmask = 0; dev->ckdxgattr = 0; dev->ckdxblksz = 0; dev->ckdxbcyl = 0; dev->ckdxbhead = 0; dev->ckdxecyl = dev->ckdcyls - 1; dev->ckdxehead = dev->ckdheads - 1; } /* Reset ckdlmask on retry of LRE */ else if (dev->syncio_retry && code == 0x4B) dev->ckdlmask = 0; dev->syncio_retry = 0; /* Reset index marker flag if sense or control command, or any write command (other search ID or search key), or any read command except read sector -- -- and except single track Read Count */ if (IS_CCW_SENSE(code) || IS_CCW_CONTROL(code) || (IS_CCW_WRITE(code) && (code & 0x7F) != 0x31 && (code & 0x7F) != 0x51 && (code & 0x7F) != 0x71 && (code & 0x7F) != 0x29 && (code & 0x7F) != 0x49 && (code & 0x7F) != 0x69) || (IS_CCW_READ(code) && code != 0x12 && (code & 0x7F) != 0x22)) dev->ckdxmark = 0; /* Note current operation for track overflow sense byte 3 */ dev->ckdcuroper = (IS_CCW_READ(code)) ? 6 : ((IS_CCW_WRITE(code)) ? 5 : 0); /* If subsystem data has been prepared in the channel buffer by a previous Perform Subsystem Function command, generate a command reject if next command is not Read Subsystem Data */ if (dev->ckdssdlen > 0 && code != 0x3E) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* If within Locate Record Extended domain and not RT command reject with status that includes Unit Check (Command Reject, format X'02', Invalid Command Sequence) */ if (dev->ckdlmask && code != 0xDE) { ckd_build_sense (dev, SENSE_CR, 0, 0,FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* Process depending on CCW opcode */ switch (code) { case 0x02: /*---------------------------------------------------------------*/ /* READ IPL */ /*---------------------------------------------------------------*/ /* Command reject if preceded by a Define Extent or Set File Mask, or within the domain of a Locate Record */ if (dev->ckdxtdef || dev->ckdsetfm || dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* No more define extend allowed */ dev->ckdxtdef = 1; dev->ckdsetfm = 1; /* Set locate record parameters */ dev->ckdloper = CKDOPER_ORIENT_DATA | CKDOPER_RDDATA; dev->ckdlaux = 0; dev->ckdlcount = 2; dev->ckdltranlf = 0; /* Seek to start of cylinder zero track zero */ rc = ckd_seek (dev, 0, 0, &trkhdr, unitstat); if (rc < 0) break; /* Read count field for first record following R0 */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Calculate number of bytes to read and set residual count */ size = dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; /* Read data field */ rc = ckd_read_data (dev, code, iobuf, unitstat); if (rc < 0) break; /* Set command processed flag */ dev->ckdrdipl = 1; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return unit exception if data length is zero */ if (dev->ckdcurdl == 0) *unitstat = CSW_CE | CSW_DE | CSW_UX; else *unitstat = CSW_CE | CSW_DE; break; case 0x03: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record, */ /* except if Read IPL 2012-08-14 */ if (dev->ckdlcount > 0 && dev->prevcode != 0x02) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x17: /*---------------------------------------------------------------*/ /* RESTORE */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0xA6: //FIXME: 0xA6 ccw is undoc'd. We are treating it as 0x86 except // we will allow a DX ccw to follow. case 0x06: case 0x86: /*---------------------------------------------------------------*/ /* READ DATA */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* If not oriented to count or key field, read next count */ if (dev->ckdorient != CKDORIENT_COUNT && dev->ckdorient != CKDORIENT_KEY) { rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; } /* Calculate number of bytes to read and set residual count */ size = dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; offset = 0; /* Read data field */ rc = ckd_read_data (dev, code, iobuf, unitstat); if (rc < 0) break; /* If track overflow, keep reading */ while (dev->ckdtrkof) { /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the first count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Skip the key field if present */ if (dev->ckdcurkl > 0) dev->bufoff += dev->ckdcurkl; /* Set offset into buffer for this read */ offset += num; /* Account for size of this overflow record */ size = dev->ckdcurdl; num = (*residual < size) ? *residual : size; if (*residual < size) *more = 1; else *more = 0; *residual -= num; /* Read the next data field */ rc = ckd_read_data (dev, code, iobuf+offset, unitstat); if (rc < 0) break; } /* Bail out if track overflow produced I/O error */ if (rc < 0) break; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return unit exception if data length is zero */ if (dev->ckdcurdl == 0) *unitstat = CSW_CE | CSW_DE | CSW_UX; else *unitstat = CSW_CE | CSW_DE; break; case 0x0E: case 0x8E: /*---------------------------------------------------------------*/ /* READ KEY AND DATA */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { /* * 3990 reference says LRE CKDOPER_RDANY "must be followed * by a sequence of multi-track Read Count, Read Count Key * and Data, or Read Data commands". That is, it doesn't * mention Read Key and Data. */ if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA /* || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY */ || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* If not oriented to count field, read next count */ if (dev->ckdorient != CKDORIENT_COUNT) { rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; } /* Calculate number of bytes to read and set residual count */ size = dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; offset = dev->ckdcurkl; /* Read key field */ rc = ckd_read_key (dev, code, iobuf, unitstat); if (rc < 0) break; /* Read data field */ rc = ckd_read_data (dev, code, iobuf+dev->ckdcurkl, unitstat); if (rc < 0) break; /* If track overflow, keep reading */ while (dev->ckdtrkof) { /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the first count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Skip the key field if present */ if (dev->ckdcurkl > 0) dev->bufoff += dev->ckdcurkl; /* Set offset into buffer for this read */ offset += num; /* Account for size of this overflow record */ size = dev->ckdcurdl; num = (*residual < size) ? *residual : size; if (*residual < size) *more = 1; else *more = 0; *residual -= num; /* Read the next data field */ rc = ckd_read_data (dev, code, iobuf+offset, unitstat); if (rc < 0) break; } /* Bail out if track overflow produced I/O error */ if (rc < 0) break; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return unit exception if data length is zero */ if (dev->ckdcurdl == 0) *unitstat = CSW_CE | CSW_DE | CSW_UX; else *unitstat = CSW_CE | CSW_DE; break; case 0x12: case 0x92: /*---------------------------------------------------------------*/ /* READ COUNT */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE && (dev->ckdlaux & CKDLAUX_RDCNTSUF) && dev->ckdlcount == 1))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* Read next count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Calculate number of bytes to read and set residual count */ size = CKDDASD_RECHDR_SIZE; num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; /* Copy count field to I/O buffer */ memcpy (iobuf, &rechdr, CKDDASD_RECHDR_SIZE); /* Turn off track overflow flag in read record header */ if(dev->ckdcyls < 32768) *iobuf &= 0x7F; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x16: case 0x96: /*---------------------------------------------------------------*/ /* READ RECORD ZERO */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ && ((dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_HOME || (dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_INDEX )))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* For multitrack operation outside domain of a Locate Record, attempt to advance to the next track before reading R0 */ if ((code & 0x80) && dev->ckdlcount == 0) { rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; } /* Seek to beginning of track */ rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat); if (rc < 0) break; /* Read the count field for record zero */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Calculate number of bytes to read and set residual count */ size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; /* Copy count field to I/O buffer */ memcpy (iobuf, &rechdr, CKDDASD_RECHDR_SIZE); /* Turn off track overflow flag in read record header */ if(dev->ckdcyls < 32768) *iobuf &= 0x7F; /* Read key field */ rc = ckd_read_key (dev, code, iobuf + CKDDASD_RECHDR_SIZE, unitstat); if (rc < 0) break; /* Read data field */ rc = ckd_read_data (dev, code, iobuf + CKDDASD_RECHDR_SIZE + dev->ckdcurkl, unitstat); if (rc < 0) break; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return unit exception if data length is zero */ if (dev->ckdcurdl == 0) *unitstat = CSW_CE | CSW_DE | CSW_UX; else *unitstat = CSW_CE | CSW_DE; break; case 0x1A: case 0x9A: /*---------------------------------------------------------------*/ /* READ HOME ADDRESS */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ && (dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_INDEX ))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* For multitrack operation outside domain of a Locate Record, attempt to advance to the next track before reading HA */ if ((code & 0x80) && dev->ckdlcount == 0) { rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; } /* Seek to beginning of track */ rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat); if (rc < 0) break; /* Calculate number of bytes to read and set residual count */ size = CKDDASD_TRKHDR_SIZE; num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; /* Copy home address field to I/O buffer */ memcpy (iobuf, &trkhdr, CKDDASD_TRKHDR_SIZE); /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x19: /*---------------------------------------------------------------*/ /* WRITE HOME ADDRESS */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ && (dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_INDEX ))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* File protected if file mask does not allow Write HA */ if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Seek to beginning of track */ rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat); if (rc < 0) break; /* Calculate number of bytes to write and set residual count */ size = CKDDASD_TRKHDR_SIZE; num = (count < size) ? count : size; /* FIXME: what devices want 5 bytes, what ones want 7, and what ones want 11? Do this right when we figure that out */ /* ISW20030819-1 Indicate WRHA performed */ dev->ckdwrha=1; *residual = 0; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x1E: case 0x9E: /*---------------------------------------------------------------*/ /* READ COUNT KEY AND DATA */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* Read next count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Calculate number of bytes to read and set residual count */ size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; offset = CKDDASD_RECHDR_SIZE + dev->ckdcurkl; /* Copy count field to I/O buffer */ memcpy (iobuf, &rechdr, CKDDASD_RECHDR_SIZE); /* Turn off track overflow flag in read record header */ if(dev->ckdcyls < 32768) *iobuf &= 0x7F; /* Read key field */ rc = ckd_read_key (dev, code, iobuf + CKDDASD_RECHDR_SIZE, unitstat); if (rc < 0) break; /* Read data field */ rc = ckd_read_data (dev, code, iobuf + CKDDASD_RECHDR_SIZE + dev->ckdcurkl, unitstat); if (rc < 0) break; /* If track overflow, keep reading */ while (dev->ckdtrkof) { /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the first count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Skip the key field if present */ if (dev->ckdcurkl > 0) dev->bufoff += dev->ckdcurkl; /* Set offset into buffer for this read */ offset += num; /* Account for size of this overflow record */ size = dev->ckdcurdl; num = (*residual < size) ? *residual : size; if (*residual < size) *more = 1; else *more = 0; *residual -= num; /* Read the next data field */ rc = ckd_read_data (dev, code, iobuf+offset, unitstat); if (rc < 0) break; } /* Bail out if track overflow produced I/O error */ if (rc < 0) break; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return unit exception if data length is zero */ if (dev->ckdcurdl == 0) *unitstat = CSW_CE | CSW_DE | CSW_UX; else *unitstat = CSW_CE | CSW_DE; break; case 0x5E: /*---------------------------------------------------------------*/ /* READ MULTIPLE COUNT KEY AND DATA */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Read records into the I/O buffer until end of track */ for (size = 0; ; ) { /* Read next count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Exit if end of track marker was read */ if (memcmp (&rechdr, eighthexFF, 8) == 0) break; /* Copy count field to I/O buffer */ memcpy (iobuf + size, &rechdr, CKDDASD_RECHDR_SIZE); size += CKDDASD_RECHDR_SIZE; /* Turn off track overflow flag */ if(dev->ckdcyls < 32768) *(iobuf + size) &= 0x7F; /* Read key field */ rc = ckd_read_key (dev, code, iobuf + size, unitstat); if (rc < 0) break; size += dev->ckdcurkl; /* Read data field */ rc = ckd_read_data (dev, code, iobuf + size, unitstat); if (rc < 0) break; size += dev->ckdcurdl; } /* end for(size) */ /* Set the residual count */ num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0xDE: /*---------------------------------------------------------------*/ /* READ TRACK */ /*---------------------------------------------------------------*/ /* Command reject if not within the domain of a Locate Record that specifies a read tracks operation */ if (dev->ckdlcount == 0 || (((dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDTRKS) && ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDTSET))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if not chained from a Locate Record command or from another Read Track command */ if (chained == 0 || (prevcode != 0x47 && prevcode != 0x4B && prevcode != 0xDE)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Advance to next track if chained from previous read track */ if (prevcode == 0xDE) { j = 1; /* Skip tracks while hi bit off in ckdlmask */ if (dev->ckdlmask) { while (!(dev->ckdlmask & 0x8000)) { j++; dev->ckdlmask <<= 1; } } rc = mt_advance (dev, unitstat, j); if (rc < 0) break; } /* Shift read track set mask left a bit */ dev->ckdlmask <<= 1; /* Read each record on the track into the I/O buffer */ for (size = 0; ; ) { /* Read next count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Copy count field to I/O buffer */ memcpy (iobuf + size, &rechdr, CKDDASD_RECHDR_SIZE); size += CKDDASD_RECHDR_SIZE; /* Turn off track overflow flag */ if(dev->ckdcyls < 32768) *(iobuf+size) &= 0x7F; /* Exit if end of track marker was read */ if (memcmp (&rechdr, eighthexFF, 8) == 0) break; /* Read key field */ rc = ckd_read_key (dev, code, iobuf + size, unitstat); if (rc < 0) break; size += dev->ckdcurkl; /* Read data field */ rc = ckd_read_data (dev, code, iobuf + size, unitstat); if (rc < 0) break; size += dev->ckdcurdl; } /* end for(size) */ /* Set the residual count */ num = (count < size) ? count : size; *residual = count - num; if (count < size) *more = 1; /* Save size and offset of data not used by this CCW */ dev->ckdrem = size - num; dev->ckdpos = num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x27: /*---------------------------------------------------------------*/ /* PERFORM SUBSYSTEM FUNCTION */ /*---------------------------------------------------------------*/ /* If the control unit is not a 3990 then CCW code 0x27 is treated as a SEEK AND SET SECTOR (Itel 7330 controller) */ if (dev->ckd3990 == 0) goto seek_0x27; /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Use the order code to determine the required count */ num = (count < 2) ? 2 : (iobuf[0] == 0x10) ? 14 : (iobuf[0] == 0x11 || iobuf[0] == 0x18) ? 12 : (iobuf[0] == 0x12) ? 5 : (iobuf[0] == 0x13 || iobuf[0] == 0x14) ? 4 : (iobuf[0] == 0x16) ? 4 : (iobuf[0] == 0x1D) ? 66 : (iobuf[0] == 0xB0) ? 4 : 2; /* Command reject if count is less than required */ if (count < num) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set residual count */ *residual = count - num; #if 0 /* Command reject if SSI active */ if(dev->ckdssi) { /* Reset SSI condition */ dev->ckdssi = 0; ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_F); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } #endif /* Process depending on order code in byte 0 of data */ switch (iobuf[0]) { case 0x18: /* Prepare for Read Subsystem Data */ /* Command reject if bytes 1-5 not zero */ if (memcmp(&iobuf[1], "\x00\x00\x00\x00\x00", 5) != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Process suborder code in byte 6 of data */ switch (iobuf[6]) { case 0x00: /* Storage path status */ /* Prepare storage path status record */ memset (iobuf, 0x00, 16); iobuf[0] = 0xC0; /* Storage path valid and attached */ iobuf[1] = 0x80; /* Logical paths configured bitmap */ iobuf[2] = 0x00; /* Channels enabled bitmap */ iobuf[3] = 0x00; /* Channels fenced bitmap */ iobuf[16] = 1; /* #logical paths thru cluster 0 */ /* Indicate the length of subsystem data prepared */ dev->ckdssdlen = (dev->ckdcu->code==0x15) ? 24 : 16; break; case 0x01: /* Subsystem statistics */ /* Indicate the length of subsystem data prepared */ dev->ckdssdlen = (iobuf[8]==0x00) ? 96 : 192; /* Prepare subsystem statistics record */ memset (iobuf, 0x00, dev->ckdssdlen); iobuf[1] = dev->devnum & 0xFF; iobuf[94] = (myssid >> 8) & 0xff; iobuf[95] = myssid & 0xff; break; case 0x03: /* Read attention message for this path-group for the addressed device Return a "no message" message */ iobuf[0] = 0x00; // Message length iobuf[1] = 0x09; // ... iobuf[2] = 0x00; // No message iobuf[3] = 0x00; // Message code memcpy (iobuf+4, iobuf+8, 4); // Copy message identifier from bytes 8-11 iobuf[8] = 0x00; // Flags dev->ckdssdlen = 9; // Indicate length of subsystem data prepared break; case 0x0E: /* Unit address configuration */ /* Prepare unit address configuration record */ memset (iobuf, 0x00, 512); /* 256 pairs (UA type, base UA) */ /* Indicate the length of subsystem data prepared */ dev->ckdssdlen = 512; break; case 0x41: /* Feature codes */ /* Prepare feature codes record */ memset (iobuf, 0x00, 256); /* Indicate the length of subsystem data prepared */ dev->ckdssdlen = 256; break; default: /* Unknown suborder code */ ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(iobuf[6]) */ break; case 0x1B: /* Set Special Intercept Condition */ /* Command reject if not the first command in the chain or indeed if preceded by any command at all apart from Suspend Multipath Reconnection */ if (ccwseq > 1 || (chained && prevcode != 0x5B)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if flag byte is not zero */ if (iobuf[1] != 0x00) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if any command is chained from this command */ if (flags & CCW_FLAGS_CC) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Mark Set Special Intercept inactive */ dev->ckdssi = 1; break; case 0x1D: /* Set Subsystem Characteristics */ /* Command reject if flag byte is not zero */ if (iobuf[1] != 0x00) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } break; case 0xB0: /* Set Interface Identifier */ /* Command reject if flag byte bits 0-5 are not zero or bits 6-7 are 11 or 10 */ if ((iobuf[1] & 0xFE) != 0x00) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Prepare subsystem data (node descriptor record) */ memset (iobuf, 0x00, 96); /* Bytes 0-31 contain the subsystem node descriptor */ store_fw(&iobuf[0], 0x00000100); sprintf ((char *)&iobuf[4], "00%4.4X HRCZZ000000000001", dev->ckdcu->devt); for (i = 4; i < 30; i++) iobuf[i] = host_to_guest(iobuf[i]); /* Bytes 32-63 contain node qualifier data */ store_fw(&iobuf[32],0x00000000); // flags+zeros store_fw(&iobuf[40],0x00000000); store_fw(&iobuf[40],0x41010000); // start range store_fw(&iobuf[44],0x41010001); // end range store_fw(&iobuf[48],0x41010010); // start range store_fw(&iobuf[52],0x41010011); // end range /* Bytes 64-95 contain a 2nd subsystem node descriptor */ iobuf[64] = 0x00; /* Indicate the length of subsystem data prepared */ dev->ckdssdlen = (iobuf[1] & 0x03) ? 32 : 96; break; default: /* Unknown order code */ ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(iobuf[0]) */ /* Exit if unit check has already been set */ if (*unitstat & CSW_UC) break; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; seek_0x27: /* SEEK AND SET SECTOR (Itel 7330 controller only) */ case 0x07: /* SEEK */ case 0x0B: /* SEEK CYLINDER */ case 0x1B: /* SEEK HEAD */ /*---------------------------------------------------------------*/ /* SEEK */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* For 3990, command reject if Seek Head not preceded by Seek, Seek Cylinder, Locate Record, Read IPL, or Recalibrate */ if (code == 0x1B && dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* File protected if file mask does not allow requested seek */ if (((code == 0x07 || code == 0x27) && (dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_ALLSKR) || (code == 0x0B && (dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_ALLSKR && (dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_CYLHD) || (code == 0x1B && (dev->ckdfmask & CKDMASK_SKCTL) == CKDMASK_SKCTL_INHSMT)) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set residual count */ num = (count < 6) ? count : 6; *residual = count - num; /* Command reject if count is less than 6 */ if (count < 6) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Extract the BBCCHH seek address from the I/O buffer */ bin = (iobuf[0] << 8) | iobuf[1]; cyl = (iobuf[2] << 8) | iobuf[3]; head = (iobuf[4] << 8) | iobuf[5]; /* For Seek Head, use the current cylinder number */ if (code == 0x1B) cyl = dev->ckdcurcyl; /* Command reject if seek address is invalid */ if (bin != 0 || cyl >= dev->ckdcyls || head >= dev->ckdheads) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* File protected if outside defined extent */ if ( EXTENT_CHECK(dev, cyl, head) ) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Seek to specified cylinder and head */ rc = ckd_seek (dev, cyl, head, &trkhdr, unitstat); if (rc < 0) break; /* Set command processed flag */ dev->ckdseek = 1; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x13: /*---------------------------------------------------------------*/ /* RECALIBRATE */ /*---------------------------------------------------------------*/ /* Command reject if recalibrate is issued to a 3390 */ if (dev->devtype == 0x3390) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* File protected if the file mask does not allow recalibrate, or if the file mask specifies diagnostic authorization */ if ((dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_ALLSKR || (dev->ckdfmask & CKDMASK_AAUTH) == CKDMASK_AAUTH_DIAG) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* File protected if cyl 0 head 0 is outside defined extent */ if ( EXTENT_CHECK0(dev) ) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Seek to cylinder 0 head 0 */ rc = ckd_seek (dev, 0, 0, &trkhdr, unitstat); if (rc < 0) break; /* Set command processed flag */ dev->ckdrecal = 1; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x1F: /*---------------------------------------------------------------*/ /* SET FILE MASK */ /*---------------------------------------------------------------*/ /* Command reject if preceded by a Define Extent or Set File Mask, or within the domain of a Locate Record */ if (dev->ckdxtdef || dev->ckdsetfm || dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set residual count */ num = (count < 1) ? count : 1; *residual = count - num; /* Command reject if count is less than 1 */ if (count < 1) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Extract the file mask from the I/O buffer */ dev->ckdfmask = iobuf[0]; logdevtr (dev, _("HHCDA054I set file mask %2.2X\n"), dev->ckdfmask); /* Command reject if file mask is invalid */ if ((dev->ckdfmask & CKDMASK_RESV) != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set command processed flag */ dev->ckdsetfm = 1; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x22: /*---------------------------------------------------------------*/ /* READ SECTOR */ /*---------------------------------------------------------------*/ /* Command reject if non-RPS device */ if (dev->ckdtab->sectors == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set residual count */ num = (count < 1) ? count : 1; *residual = count - num; if (count < 1) *more = 1; /* Return sector number in I/O buffer */ iobuf[0] = 0; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x23: /*---------------------------------------------------------------*/ /* SET SECTOR */ /*---------------------------------------------------------------*/ /* Command reject if non-RPS device */ if (dev->ckdtab->sectors == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set residual count */ num = (count < 1) ? count : 1; *residual = count - num; /* Command reject if count is less than 1 */ if (count < 1) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x29: case 0xA9: /* SEARCH KEY EQUAL */ case 0x49: case 0xC9: /* SEARCH KEY HIGH */ case 0x69: case 0xE9: /* SEARCH KEY EQUAL OR HIGH */ /*---------------------------------------------------------------*/ /* SEARCH KEY */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Read next key */ rc = ckd_read_key (dev, code, key, unitstat); if (rc < 0) break; /* Calculate number of compare bytes and set residual count */ num = (count < dev->ckdcurkl) ? count : dev->ckdcurkl; *residual = count - num; /* Nothing to compare if key length is zero */ if (dev->ckdcurkl == 0) { *unitstat = CSW_CE | CSW_DE; break; } /* Compare key with search argument */ rc = memcmp(key, iobuf, num); /* Return status modifier if compare result matches */ if (((code & 0x20) && (rc == 0)) || ((code & 0x40) && (rc > 0))) *unitstat = CSW_SM | CSW_CE | CSW_DE; else *unitstat = CSW_CE | CSW_DE; #ifdef OPTION_CKD_KEY_TRACING /* If the search was successful, trace the first 8 bytes of the key, which will usually be a dataset name or member name and can provide useful debugging information */ if ((*unitstat & CSW_SM) && dev->ckdkeytrace && isprint(guest_to_host(iobuf[0]))) { BYTE module[45]; int i; for (i=0; i < (ssize_t)sizeof(module)-1 && i < num; i++) module[i] = guest_to_host(iobuf[i]); module[i] = '\0'; logmsg (_("HHCDA055I search key %s\n"), module); } #endif /*OPTION_CKD_KEY_TRACING*/ /* Set flag if entire key was equal for SEARCH KEY EQUAL */ if (rc == 0 && num == dev->ckdcurkl && (code & 0x7F) == 0x29) dev->ckdkyeq = 1; else dev->ckdkyeq = 0; break; case 0x31: case 0xB1: /* SEARCH ID EQUAL */ case 0x51: case 0xD1: /* SEARCH ID HIGH */ case 0x71: case 0xF1: /* SEARCH ID EQUAL OR HIGH */ /*---------------------------------------------------------------*/ /* SEARCH ID */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Read next count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Calculate number of compare bytes and set residual count */ num = (count < 5) ? count : 5; *residual = count - num; /* Turn off track overflow flag in record header if present */ if(dev->ckdcyls < 32768) rechdr.cyl[0] &= 0x7F; /* Compare count with search argument */ rc = memcmp(&rechdr, iobuf, num); /* Return status modifier if compare result matches */ if (((code & 0x20) && (rc == 0)) || ((code & 0x40) && (rc > 0))) *unitstat = CSW_SM | CSW_CE | CSW_DE; else *unitstat = CSW_CE | CSW_DE; /* Set flag if entire id compared equal for SEARCH ID EQUAL */ if (rc == 0 && num == 5 && (code & 0x7F) == 0x31) dev->ckdideq = 1; else dev->ckdideq = 0; break; case 0x39: case 0xB9: /*---------------------------------------------------------------*/ /* SEARCH HOME ADDRESS EQUAL */ /*---------------------------------------------------------------*/ /* For 3990, command reject if not preceded by Seek, Seek Cyl, Locate Record, Read IPL, or Recalibrate command */ if (dev->ckd3990 && dev->ckdseek == 0 && dev->ckdskcyl == 0 && dev->ckdlocat == 0 && dev->ckdrdipl == 0 && dev->ckdrecal == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* For multitrack operation, advance to next track */ if (code & 0x80) { rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; } /* Seek to beginning of track */ rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat); if (rc < 0) break; /* Calculate number of compare bytes and set residual count */ num = (count < 4) ? count : 4; *residual = count - num; /* Compare CCHH portion of track header with search argument */ rc = memcmp(&(trkhdr.cyl), iobuf, num); /* Return status modifier if compare result matches */ if (rc == 0) *unitstat = CSW_SM | CSW_CE | CSW_DE; else *unitstat = CSW_CE | CSW_DE; /* Set flag if entire home address compared equal */ if (rc == 0 && num == 4) dev->ckdhaeq = 1; else dev->ckdhaeq = 0; break; case 0x05: /*---------------------------------------------------------------*/ /* WRITE DATA */ /*---------------------------------------------------------------*/ /* Command reject if the current track is in the DSF area */ if (dev->ckdcurcyl >= dev->ckdcyls) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if not within the domain of a Locate Record and not preceded by either a Search ID Equal or Search Key Equal that compared equal on all bytes */ /*INCOMPLETE*/ /*Write CKD allows intervening Read/Write key and data commands, Write Data does not!!! Rethink the handling of these flags*/ if (dev->ckdlcount == 0 && dev->ckdideq == 0 && dev->ckdkyeq == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if file mask inhibits all write commands */ if ((dev->ckdfmask & CKDMASK_WRCTL) == CKDMASK_WRCTL_INHWRT) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!(((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE && dev->ckdlcount == (dev->ckdlaux & CKDLAUX_RDCNTSUF) ? 2 : 1) || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* If not operating in CKD conversion mode, check that the data length is equal to the transfer length factor, except when writing a R0 data area under the control of a Locate Record Write Track operation, in which case a transfer length factor of 8 is used instead */ if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0) { if ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK && dev->ckdcurrec == 0) num = 8; else num = dev->ckdltranlf; if (dev->ckdcurdl != num) { /* Unit check with invalid track format */ ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } } /* end if(ckdlcount) */ /* If data length is zero, terminate with unit exception */ if (dev->ckdcurdl == 0) { *unitstat = CSW_CE | CSW_DE | CSW_UX; break; } /* Calculate number of bytes written and set residual count */ size = dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; /* Write data */ rc = ckd_write_data (dev, iobuf, num, unitstat); if (rc < 0) break; /* If track overflow, keep writing */ offset = 0; while (dev->ckdtrkof) { /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the first count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Set offset into buffer for this write */ offset += size; /* Account for size of this overflow record */ size = dev->ckdcurdl; num = (*residual < size) ? *residual : size; *residual -= num; /* Write the next data field */ rc = ckd_write_data (dev, iobuf+offset, num, unitstat); if (rc < 0) break; } /* Bail out if track overflow produced I/O error */ if (rc < 0) break; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0xA5: //FIXME: 0xA5 ccw is undoc'd. We are treating it as 0x85 except // we will allow a DX ccw to follow. case 0x85: /*---------------------------------------------------------------*/ /* WRITE UPDATE DATA */ /*---------------------------------------------------------------*/ /* Command reject if not within the domain of a Locate Record that specifies the Write Data operation code */ if (dev->ckdlcount == 0 || ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTANY)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Orient to next user record count field */ if (dev->ckdorient != CKDORIENT_COUNT || dev->ckdcurrec == 0) { /* Read next count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; } /* If not operating in CKD conversion mode, check that the data length is equal to the transfer length factor */ if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0) { if (dev->ckdcurdl != dev->ckdltranlf) { /* Unit check with invalid track format */ ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* If data length is zero, terminate with unit exception */ if (dev->ckdcurdl == 0) { *unitstat = CSW_CE | CSW_DE | CSW_UX; break; } /* Calculate number of bytes written and set residual count */ size = dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; /* Write data */ rc = ckd_write_data (dev, iobuf, num, unitstat); if (rc < 0) break; /* If track overflow, keep writing */ offset = 0; while (dev->ckdtrkof) { /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the first count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Set offset into buffer for this write */ offset += size; /* Account for size of this overflow record */ size = dev->ckdcurdl; num = (*residual < size) ? *residual : size; *residual -= num; /* Write the next data field */ rc = ckd_write_data (dev, iobuf+offset, num, unitstat); if (rc < 0) break; } /* Bail out if track overflow produced I/O error */ if (rc < 0) break; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x0D: /*---------------------------------------------------------------*/ /* WRITE KEY AND DATA */ /*---------------------------------------------------------------*/ /* Command reject if the current track is in the DSF area */ if (dev->ckdcurcyl >= dev->ckdcyls) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if not within the domain of a Locate Record and not preceded by a Search ID Equal that compared equal on all bytes */ /*INCOMPLETE*/ /*Write CKD allows intervening Read/Write key and data commands, Write Key Data does not!!! Rethink the handling of these flags*/ if (dev->ckdlcount == 0 && dev->ckdideq == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if file mask inhibits all write commands */ if ((dev->ckdfmask & CKDMASK_WRCTL) == CKDMASK_WRCTL_INHWRT) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!(((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE && dev->ckdlcount == (dev->ckdlaux & CKDLAUX_RDCNTSUF) ? 2 : 1) || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* If not operating in CKD conversion mode, check that the key + data length equals the transfer length factor */ if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0 && dev->ckdcurkl + dev->ckdcurdl != dev->ckdltranlf) { /* Unit check with invalid track format */ ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* end if(ckdlcount) */ /* If data length is zero, terminate with unit exception */ if (dev->ckdcurdl == 0) { *unitstat = CSW_CE | CSW_DE | CSW_UX; break; } /* Calculate number of bytes written and set residual count */ size = dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; /* Write key and data */ rc = ckd_write_kd (dev, iobuf, num, unitstat); if (rc < 0) break; /* If track overflow, keep writing */ offset = dev->ckdcurkl; while (dev->ckdtrkof) { /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the first count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Set offset into buffer for this write */ offset += size; /* Account for size of this overflow record */ size = dev->ckdcurdl; num = (*residual < size) ? *residual : size; *residual -= num; /* Write the next data field */ rc = ckd_write_data (dev, iobuf+offset, num, unitstat); if (rc < 0) break; } /* Bail out if track overflow produced I/O error */ if (rc < 0) break; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x8D: /*---------------------------------------------------------------*/ /* WRITE UPDATE KEY AND DATA */ /*---------------------------------------------------------------*/ /* Command reject if not within the domain of a Locate Record that specifies the Write Data operation code */ if (dev->ckdlcount == 0 || (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Orient to next user record count field */ if (dev->ckdorient != CKDORIENT_COUNT || dev->ckdcurrec == 0) { /* Read next count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; } /* If not operating in CKD conversion mode, check that the data length is equal to the transfer length factor */ if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0) { if ((dev->ckdcurkl + dev->ckdcurdl) != dev->ckdltranlf) { /* Unit check with invalid track format */ ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* If data length is zero, terminate with unit exception */ if (dev->ckdcurdl == 0) { *unitstat = CSW_CE | CSW_DE | CSW_UX; break; } /* Calculate number of bytes written and set residual count */ size = dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; /* Write key and data */ rc = ckd_write_kd (dev, iobuf, num, unitstat); if (rc < 0) break; /* If track overflow, keep writing */ offset = dev->ckdcurkl; while (dev->ckdtrkof) { /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the first count field */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Set offset into buffer for this write */ offset += size; /* Account for size of this overflow record */ size = dev->ckdcurdl; num = (*residual < size) ? *residual : size; *residual -= num; /* Write the next data field */ rc = ckd_write_data (dev, iobuf+offset, num, unitstat); if (rc < 0) break; } /* Bail out if track overflow produced I/O error */ if (rc < 0) break; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x11: /*---------------------------------------------------------------*/ /* ERASE */ /*---------------------------------------------------------------*/ /* Command reject if the current track is in the DSF area */ if (dev->ckdcurcyl >= dev->ckdcyls) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if not within the domain of a Locate Record and not preceded by either a Search ID Equal or Search Key Equal that compared equal on all bytes, or a Write R0 or Write CKD not within the domain of a Locate Record */ if (dev->ckdlcount == 0 && dev->ckdideq == 0 && dev->ckdkyeq == 0 && dev->ckdwckd == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if file mask does not permit Write CKD */ if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT && (dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_INHWR0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTTRK) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* Write end of track marker */ rc = ckd_erase (dev, iobuf, count, &size, unitstat); if (rc < 0) break; /* Calculate number of bytes used and set residual count */ num = (count < size) ? count : size; *residual = count - num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x15: /*---------------------------------------------------------------*/ /* WRITE RECORD ZERO */ /*---------------------------------------------------------------*/ /* Command reject if the current track is in the DSF area */ if (dev->ckdcurcyl >= dev->ckdcyls) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg("DEBUG : WR0 OUTSIDE PACK\n"); break; } /* Command reject if not within the domain of a Locate Record and not preceded by either a Search Home Address that compared equal on all 4 bytes, or a Write Home Address not within the domain of a Locate Record */ /* ISW20030819-1 : Added check for previously issued WRHA */ if (dev->ckdlcount == 0 && dev->ckdhaeq == 0 && dev->ckdwrha==0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg("DEBUG : WR0 CASE 2\n"); break; } /* Command reject if file mask does not permit Write R0 */ if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg("DEBUG : WR0 BAD FM\n"); break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT && ((dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_HOME || (dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_INDEX ))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg("DEBUG : LOC REC 2\n"); break; } } /* Write R0 count key and data */ rc = ckd_write_ckd (dev, iobuf, count, unitstat, 0); if (rc < 0) break; /* Calculate number of bytes written and set residual count */ size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; /* Set flag if Write R0 outside domain of a locate record */ if (dev->ckdlcount == 0) dev->ckdwckd = 1; else dev->ckdwckd = 0; break; case 0x1D: /* WRITE CKD */ case 0x01: /* WRITE SPECIAL CKD */ /*---------------------------------------------------------------*/ /* WRITE COUNT KEY AND DATA */ /*---------------------------------------------------------------*/ /* Command reject if the current track is in the DSF area */ if (dev->ckdcurcyl >= dev->ckdcyls) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if previous command was a Write R0 that assigned an alternate track - not implemented */ /* Command reject if not within the domain of a Locate Record and not preceded by either a Search ID Equal or Search Key Equal that compared equal on all bytes, or a Write R0 or Write CKD not within the domain of a Locate Record */ if (dev->ckdlcount == 0 && dev->ckdideq == 0 && dev->ckdkyeq == 0 && dev->ckdwckd == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if file mask does not permit Write CKD */ if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT && (dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_INHWR0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if WRITE SPECIAL CKD to a 3380 or 3390 */ if ((code == 0x01) && ((dev->devtype == 0x3380) || (dev->devtype == 0x3390))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check operation code if within domain of a Locate Record */ if (dev->ckdlcount > 0) { if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* Set track overflow flag if WRITE SPECIAL CKD */ trk_ovfl = (dev->ckdcyls < 32768 && code==0x01) ? 1 : 0; /* Write count key and data */ rc = ckd_write_ckd (dev, iobuf, count, unitstat, trk_ovfl); if (rc < 0) break; /* Calculate number of bytes written and set residual count */ size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; /* Set flag if Write CKD outside domain of a locate record */ if (dev->ckdlcount == 0) dev->ckdwckd = 1; else dev->ckdwckd = 0; break; case 0x9D: /*---------------------------------------------------------------*/ /* WRITE COUNT KEY AND DATA NEXT TRACK */ /*---------------------------------------------------------------*/ /* Command reject if not within the domain of a Locate Record that specifies a format write operation */ if (dev->ckdlcount == 0 || (dev->ckdloper & CKDOPER_CODE) != CKDOPER_FORMAT) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if not chained from a Write CKD or another Write CKD Next Track command */ if (chained == 0 || (prevcode != 0x1D && prevcode != 0x9D)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Advance to next track */ rc = mt_advance (dev, unitstat, 1); if (rc < 0) break; /* Read the count field for record zero */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Write count key and data */ rc = ckd_write_ckd (dev, iobuf, count, unitstat, 0); if (rc < 0) break; /* Calculate number of bytes written and set residual count */ size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl; num = (count < size) ? count : size; *residual = count - num; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x47: /*---------------------------------------------------------------*/ /* LOCATE RECORD */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < 16) ? count : 16; *residual = count - num; /* Control information length must be at least 16 bytes */ if (count < 16) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record, or not preceded by a Define Extent or Read IPL command */ if (dev->ckdlcount > 0 || (dev->ckdxtdef == 0 && dev->ckdrdipl == 0)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Byte 0 contains the locate record operation byte */ dev->ckdloper = iobuf[0]; /* Validate the locate record operation code (bits 2-7) */ if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDTRKS || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check for valid combination of orientation and opcode */ if ( ((dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_HOME && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDTRKS || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) || ((dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_DATA && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) || ((dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_INDEX && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) ) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check for write operation on a read only disk */ if ( (dev->ckdrdonly && !dev->ckdfakewr && !dev->dasdsfn) && ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK) ) { ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Byte 1 contains the locate record auxiliary byte */ dev->ckdlaux = iobuf[1]; /* Validate the auxiliary byte */ if ((dev->ckdlaux & CKDLAUX_RESV) != 0 || ((dev->ckdlaux & CKDLAUX_RDCNTSUF) && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ)) ) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Byte 2 must contain zeroes */ if (iobuf[2] != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Byte 3 contains the locate record domain count */ dev->ckdlcount = iobuf[3]; /* Validate the locate record domain count */ if ( ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT && dev->ckdlcount != 0) || ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_ORIENT && dev->ckdlcount == 0) || ((dev->ckdlaux & CKDLAUX_RDCNTSUF) && dev->ckdlcount < 2) ) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 4-7 contain the seek address */ cyl = (iobuf[4] << 8) | iobuf[5]; head = (iobuf[6] << 8) | iobuf[7]; /* Command reject if seek address is not valid */ if (cyl >= dev->ckdcyls || head >= dev->ckdheads) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* File protect error if seek address is outside extent */ if ( EXTENT_CHECK(dev, cyl, head) ) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 8-12 contain the search argument */ memcpy (cchhr, iobuf+8, 5); /* Byte 13 contains the sector number */ sector = iobuf[13]; /* Command reject if sector number is not valid */ if (sector != 0xFF && sector >= dev->ckdtab->sectors) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 14-15 contain the transfer length factor */ dev->ckdltranlf = (iobuf[14] << 8) | iobuf[15]; /* Validate the transfer length factor */ if ( ((dev->ckdlaux & CKDLAUX_TLFVALID) == 0 && dev->ckdltranlf != 0) || ((dev->ckdlaux & CKDLAUX_TLFVALID) && dev->ckdltranlf == 0) || dev->ckdltranlf > dev->ckdxblksz) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* If transfer length factor is not supplied then use the blocksize from the define extent command */ if ((dev->ckdlaux & CKDLAUX_TLFVALID) == 0) dev->ckdltranlf = dev->ckdxblksz; /* Seek to the required track */ rc = ckd_seek (dev, cyl, head, &trkhdr, unitstat); if (rc < 0) { if (dev->syncio_retry) dev->ckdlcount = 0; break; } /* Set normal status */ *unitstat = CSW_CE | CSW_DE; /* Perform search according to specified orientation */ switch ((dev->ckdloper & CKDOPER_ORIENTATION)) { case CKDOPER_ORIENT_HOME: /* For home orientation, compare the search CCHH with the CCHH in the track header */ if (memcmp (&(trkhdr.cyl), cchhr, 4) != 0) { ckd_build_sense (dev, 0, SENSE1_NRF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; } break; case CKDOPER_ORIENT_COUNT: case CKDOPER_ORIENT_DATA: /* For count or data orientation, search the track for a count field matching the specified CCHHR */ while (1) { /* Read next count field and exit at end of track with sense data indicating no record found */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Turn off track overflow flag */ if(dev->ckdcyls < 32768) rechdr.cyl[0] &= 0x7F; /* Compare the count field with the search CCHHR */ if (memcmp (&rechdr, cchhr, 5) == 0) break; // NOTE: Code like this breaks VM mini-disks !!! #if 0 if (memcmp (&rechdr, cchhr, 4) != 0) { logmsg ("HHCDA999E wrong recordheader: cc hh r=%d %d %d," "should be:cc hh r=%d %d %d\n", (rechdr.cyl[0] << 8) | rechdr.cyl[1], (rechdr.head[0] << 8) | rechdr.head[1], rechdr.rec, (cchhr[0] << 8) | cchhr[1], (cchhr[2] << 8) | cchhr[3], cchhr[4]); break; } #endif } /* end while */ } /* end switch(CKDOPER_ORIENTATION) */ /* Exit if search ended with error status */ if (*unitstat != (CSW_CE | CSW_DE)) break; /* Reorient past data if data orientation is specified */ if ((dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_DATA) { /* Skip past key and data fields */ dev->bufoff += dev->ckdcurkl + dev->ckdcurdl; /* Set the device orientation fields */ dev->ckdrem = 0; dev->ckdorient = CKDORIENT_DATA; } /* Set locate record flag and return normal status */ dev->ckdlocat = 1; break; case 0x4B: /*---------------------------------------------------------------*/ /* LOCATE RECORD EXTENDED */ /*---------------------------------------------------------------*/ /* LRE only valid for 3990-3 or 3990-6 */ if (dev->ckdcu->devt != 0x3990 || (dev->ckdcu->model != 0xec && dev->ckdcu->model != 0xe9)) { /* Set command reject sense byte, and unit check status */ ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * The Storage Director initially requests 20 bytes of parameters * from the channel; if the channel provides fewer than 20 bytes, * execution is terminated with status that includes unit check * (Command Reject, format X'03', CCW byte count less than required). */ num = (count < 20) ? count : 20; *residual = count - num; if (count < 20) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * If Locate Record Extended is received within a Locate Record * domain, execution is terminated with status that includes unit * check (Command Reject, format X'02', Invalid Command Sequence). */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * If Locate Record Extended was not preceded by a Define Extent * or Read IPL command in the same channel program, execution is * terminated with status that includes unit check (Command Reject, * format X'02', Invalid Command Sequence). If any other operation * is specified, the command is terminated with status that * includes unit check (Command Reject, format X'02', Invalid * Command Sequence). */ //FIXME not sure what that last sentence means if (dev->ckdxtdef == 0 && dev->ckdrdipl == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Byte 0 contains the locate record operation byte */ dev->ckdloper = iobuf[0]; /* Validate the locate record operation code (byte 0 bits 2-7) */ if ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_FORMAT && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTTRK && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDTRKS && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_READ && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_EXTOP) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Validate the locate record extended operation code (byte 17) */ if ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_EXTOP) { if (iobuf[17] != CKDOPER_WRTANY && iobuf[17] != CKDOPER_RDANY && iobuf[17] != CKDOPER_RDTSET) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } dev->ckdloper &= CKDOPER_ORIENTATION; dev->ckdloper |= iobuf[17]; } else if (iobuf[17] != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check for write operation on a read only disk */ //FIXME Not sure if this is right here if ( (dev->ckdrdonly && !dev->ckdfakewr && !dev->dasdsfn) && ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTANY || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK) ) { ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * Check for valid combination of orientation and opcode * * +------------------------------------------------+ * | Operation Code Orientation Byte | * | Cnt HA Data Index 17 | * +------------------------------------------------+ * | Write Data 01 x 81 x 00 | * | Format Write 03 43 x C3 00 | * | Write Track 0B x x x 00 | * | Read Tracks 0C 4C x x 00 | * | Read 16 56 96 D6 00 | * | Write Any 3F x x x 09 | * | Read Any 3F x x x 0A | * | Read Trackset 3F 7F x x 0E | * +------------------------------------------------+ * | Note: x - Combination is not valid. | * +------------------------------------------------+ * Table: valid orientation + operation code values */ if (dev->ckdloper != 0x01 && dev->ckdloper != 0x81 && dev->ckdloper != 0x03 && dev->ckdloper != 0x43 && dev->ckdloper != 0xC3 && dev->ckdloper != 0x0B && dev->ckdloper != 0x0C && dev->ckdloper != 0x4C && dev->ckdloper != 0x16 && dev->ckdloper != 0x56 && dev->ckdloper != 0x96 && dev->ckdloper != 0xD6 && dev->ckdloper != 0x09 && dev->ckdloper != 0x0A && dev->ckdloper != 0x0E && dev->ckdloper != 0x4E) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * Byte 1 is the Auxiliary Byte * bit 0 = 0 : Bytes 14-15 are unused * 1 : Bytes 14-15 contain a TLF that overrides the * blocksize specified by the DX parameter. * bits 1-6 : Must be zero * If any of these bits are '1', the LRE is terminated * with status that includes unit check (Command Reject, * format X'04', Invalid Parameter). * bit 7 = 0 : No Read Count CCW is suffixed to the LR domain * 1 : A Read Count CCW is suffixed to the LR domain */ if ((iobuf[1] & CKDLAUX_RESV) != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * A Read Count command may only be suffixed to the domain of a LRE * that specifies a Write Data (01), Write Any (09), Read Any (0A), * or Read (16) operation code; if bit 7 = '1' when any other * Operation code is specified, Locate Record Extended is terminated * with status that includes unit check (Command Reject, format * X'04', Invalid Parameter). */ if ((iobuf[1] & CKDLAUX_RDCNTSUF) && ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTANY && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDANY && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_READ)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } dev->ckdlaux = iobuf[1]; /* Byte 2 must contain zeroes */ if (iobuf[2] != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * Byte 3 is the Count parameter. In general, the count parameter * specifies the number of records, or tracks to be operated on by * data transfer commands that follow Locate Record Extended. * Specific interpretation of the Count parameter depends upon the * operation code in byte 0. * * The Count must be nonzero. If Read Count Suffixing is specified * in a Locate Record, the count must be greater than 1. If the * Count is invalid, Locate Record Extended is terminated with * status that includes unit check (Command Reject, format X'04', * Invalid Parameter). */ if (iobuf[3] == 0 || ((dev->ckdlaux & CKDLAUX_RDCNTSUF) && iobuf[3] < 2)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } dev->ckdlcount = iobuf[3]; /* * The value in bytes 4-7 must be a valid track address for the * device and must be within the extent boundaries specified by the * preceding Define Extent command. * * If the Seek Address is not valid for the device or if the Extended * Operation code is Write Any or Read Any and the seek address does * not specify a primary track, Locate Record Extended is terminated * with status that includes unit check (Command Reject, format X'04', * Invalid Parameter). If the Seek Address is not within the defined * extent, Locate Record Extended is terminated with status that * includes unit check (File Protected). */ cyl = fetch_hw(iobuf+4); head = fetch_hw(iobuf+6); if (cyl >= dev->ckdcyls || head >= dev->ckdheads) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } if ( EXTENT_CHECK(dev, cyl, head) ) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * Bytes 8-12 specify a value to be used as a search argument for * the Locate Record Extended search operation. * * When the operation specified in byte 0 does not require * orientation to a specific record, no search operation is * performed and bytes 8-12 are ignored. When Home Address * orientation is specified, byte 12 is ignored. */ memcpy (cchhr, iobuf+8, 5); /* * Byte 13 contains a sector number to which the device is to be * positioned before the Storage Director establishes orientation. * * The sector number must be within the range of valid sector * numbers for the device. If the sector number is invalid, Locate * Record Extended is terminated with status that includes unit * check (Command Reject, format X'04', Invalid Parameter). * * A value of X'FF' is valid and specifies that sector positioning * is not to be performed prior to establishing orientation. */ if (iobuf[13] != 0xFF && iobuf[13] >= dev->ckdtab->sectors) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } sector = iobuf[13]; /* * When byte 1, bit 0 is '0', bytes 14-15 must contain zeros; if * bytes 14-15 are not zero, Locate Record Extended is terminated * with status that includes unit check (Command Reject, format * X'04', Invalid Parameter). * * When byte 1 bit 0 is '1', bytes 14-15 contain a Transfer Length * Factor (TLF). The Transfer Length Factor must be non-zero; if it * is zero, Locate Record Extended is terminated with status that * includes unit check (Command Reject, format X'04', Invalid * Parameter). * * If the Transfer Length Factor value is greater than the value * specified (or implied) in the Define Extent Blocksize parameter, * Locate Record Extended is terminated with status that includes * unit check (Command Reject, format X'04', Invalid Parameter). * * The Storage Director uses the TLF to determine the number of * data bytes to be requested from the channel for each write * command that follows a Locate Record Extended that specified the * Write Data (01) Operation code. The product of the value in * bytes 14-15 and the count parameter is used to determine the * total number of bytes to be transferred by data transfer commands * that are executed within the domain of a Locate Record Extended * that specified the Format Write (03), Write Track (0B), or * Read (16) Operation codes. * * The TLF value is not retained by the Storage Director after the * expiration of the Locate Record domain. * * If Locate Record Extended does not specify a Transfer Length * Factor, the Storage Director will use the value from the Define * Extent Blocksize parameter for any required data transfer length * calculation. */ if ((!(dev->ckdlaux & CKDLAUX_TLFVALID) && fetch_hw(iobuf+14)) || ( (dev->ckdlaux & CKDLAUX_TLFVALID) && !fetch_hw(iobuf+14)) || fetch_hw(iobuf+14) > dev->ckdxblksz) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } if ((dev->ckdlaux & CKDLAUX_TLFVALID) == 0) dev->ckdltranlf = dev->ckdxblksz; else dev->ckdltranlf = fetch_hw(iobuf+14); /* * Bytes 18-19 contain an unsigned 16-bit binary value that * specifies the total number of extended parameter bytes. The * format and content of the Extended Parameters are defined by * the Extended Operation code. * * The length for 3990 Mod 6 or 9390 for the Extended Operation * codes must be consistent with the Extended Operation code in * byte 17 as follows: * 09 0001 * 0A 0001 * 0E 0001 or 0002 * * If the operation code is any code other than those defined, the * extended parameter length count must be zero. If these conditions * are not met the Locate Record Extended is terminated with status * that includes unit check (Command Reject, format X'04', Invalid * Parameter). */ num = fetch_hw(iobuf+18); if ((iobuf[17] == CKDOPER_WRTANY && num != 1) || (iobuf[17] == CKDOPER_RDANY && num != 1) || (iobuf[17] == CKDOPER_RDTSET && (num != 1 && num != 2)) || (iobuf[17] != CKDOPER_WRTANY && iobuf[17] != CKDOPER_RDANY && iobuf[17] != CKDOPER_RDTSET && num)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * Request the extended parameter bytes from the channel. If the * channel provides fewer bytes, execution is terminated with status * that includes unit check (Command Reject, format X'03', CCW byte * count less than required). */ if (count < 20 + num) { *residual = 0; ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } *residual -= num; /* * For `Read Any' (0x0A) or `Write Any' (0x09) the extended * length must be one and the extended parameter value (set size) * must be one. Otherwise the Locate Record Extended command is * terminated with status that includes unit check (Command Reject, * format X'04', Invalid Parameter). */ if ((iobuf[17] == CKDOPER_WRTANY && iobuf[20] != 1) || (iobuf[17] == CKDOPER_RDANY && iobuf[20] != 1)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* * Read Trackset - X'0E': The Read Trackset Operation Code prepares * the Storage Director to transfer all records from one or more * tracks to the channel. The tracks to be transferred are * specified by the Extended Parameter and the number of tracks to * be transferred is specified by the Count Parameter (byte 3). * * The maximum length of the Extended Parameter is specified in byte * 43 of the Device Characteristics Information. * * The Extended Parameter contains a bit map that represents a set * of sequentially addressed tracks within the defined extent. Each * bit in the parameter represent one track. A '1' bit indicates the * data associated with the corresponding track is to be read. A '0' * bit indicates the track is to be skipped. * * The first bit must be a '1' and represents the track whose * address is specified in the Seek Address parameter (bytes 4-7). * Subsequent bits represent consecutively addressed tracks in * ascending order. If the first bit is not a '1', the Locate Record * Extended command is terminated with status that includes unit * check (Command Reject, format X'04', Invalid Parameter). * * The number of '1' bits in the bit map must be equal to the value * in the count parameter (byte 3); otherwise Locate Record Extended * is terminated with status that includes unit check (Command * Reject, format X'04', Invalid Parameter). * * All tracks in the bit map represented by the '1' bits must be * contained within the defined extent; otherwise the Locate Record * Extended command is terminated with status that includes unit * check (File Protected). * * Track access is initiated using the Seek Address and Sector * Number parameters. * * When track access is completed, the search operation specified by * the Search Argument and the orientation modifiers (byte 0, bits * 0-1) is performed. * * Locate Record Extended must be followed by the number of Read * Track commands specified in the count parameter (byte 3). If any * other command sequence is detected within the Locate Record * domain, the non-conforming command will be rejected with status * that includes Unit Check (Command Reject, format X'02', Invalid * Command Sequence). */ if (iobuf[17] == CKDOPER_RDTSET) { U16 lastcyl, lasthead; U16 mask = iobuf[20] << 8; if (num > 1) mask |= iobuf[21]; if (!(mask & 0x8000)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } dev->ckdlmask = mask; /* * Count the one bits in mask. There are elegant but obscure * ways to do this but just keeping it simple here. Plus we * also figure out the last track we will read. */ for (i = j = 0; mask; mask <<= 1) { j++; if (mask & 0x8000) i++; } /* Number of one bits must match count */ if (i != dev->ckdlcount) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Check extent of last track to be read */ lastcyl = cyl; lasthead = head + j - 1; while (lasthead >= dev->ckdheads) { lastcyl++; lasthead -= dev->ckdheads; } if ( EXTENT_CHECK(dev, lastcyl, lasthead) ) { ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* Seek to the required track */ rc = ckd_seek (dev, cyl, head, &trkhdr, unitstat); if (rc < 0) { if (dev->syncio_retry) dev->ckdlcount = 0; break; } /* Set normal status */ *unitstat = CSW_CE | CSW_DE; /* Perform search according to specified orientation */ switch ((dev->ckdloper & CKDOPER_ORIENTATION)) { case CKDOPER_ORIENT_HOME: /* For home orientation, compare the search CCHH with the CCHH in the track header */ if (memcmp (&(trkhdr.cyl), cchhr, 4) != 0) { ckd_build_sense (dev, 0, SENSE1_NRF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; } break; case CKDOPER_ORIENT_COUNT: case CKDOPER_ORIENT_DATA: /* For count or data orientation, search the track for a count field matching the specified CCHHR */ while (1) { /* Read next count field and exit at end of track with sense data indicating no record found */ rc = ckd_read_count (dev, code, &rechdr, unitstat); if (rc < 0) break; /* Turn off track overflow flag */ if(dev->ckdcyls < 32768) rechdr.cyl[0] &= 0x7F; /* For extended op code skip r0 */ if ((iobuf[0] & CKDOPER_CODE) == CKDOPER_EXTOP) { if (rechdr.rec != 0) break; } /* Compare the count field with the search CCHHR */ else if (memcmp (&rechdr, cchhr, 5) == 0) break; } /* end while */ } /* end switch(CKDOPER_ORIENTATION) */ /* Exit if search ended with error status */ if (*unitstat != (CSW_CE | CSW_DE)) break; /* Reorient past data if data orientation is specified */ if ((dev->ckdloper & CKDOPER_ORIENTATION) == CKDOPER_ORIENT_DATA) { /* Skip past key and data fields */ dev->bufoff += dev->ckdcurkl + dev->ckdcurdl; /* Set the device orientation fields */ dev->ckdrem = 0; dev->ckdorient = CKDORIENT_DATA; } /* Set locate record flag and return normal status */ dev->ckdlocat = 1; break; case 0x63: /*---------------------------------------------------------------*/ /* DEFINE EXTENT */ /*---------------------------------------------------------------*/ { U16 bcyl, bhead, ecyl, ehead, xblksz; BYTE fmask, xgattr; /* Calculate residual byte count */ num = (count < 16) ? count : 16; *residual = count - num; /* Control information length must be at least 16 bytes */ if (count < 16) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record, or preceded by Define Extent, Space Count, or Set File Mask, or (for 3390 only) preceded by Read IPL */ if (dev->ckdlcount > 0 #if 0 || dev->ckdxtdef #endif || dev->ckdsetfm || dev->ckdspcnt || (dev->ckdrdipl && dev->devtype == 0x3390)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 0-1 contain the file mask and global attributes */ fmask = iobuf[0]; xgattr = iobuf[1]; if(dev->ckdxtdef && (dev->ckdfmask != fmask || dev->ckdxgattr != xgattr) ) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } dev->ckdfmask = fmask; dev->ckdxgattr = xgattr; /* Validate the global attributes byte bits 0-1 */ if ((dev->ckdxgattr & CKDGATR_ARCH) != CKDGATR_ARCH_ECKD) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Validate the file mask */ if ((dev->ckdfmask & CKDMASK_RESV) != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 2-3 contain the extent block size */ xblksz = (iobuf[2] << 8) | iobuf[3]; /* If extent block size is zero then use the maximum R0 record length (as returned in device characteristics bytes 44 and 45) plus 8 */ if (xblksz == 0) xblksz = dev->ckdtab->r0 + 8; if(dev->ckdxtdef && dev->ckdxblksz != xblksz ) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } dev->ckdxblksz = xblksz; /* Validate the extent block */ if (dev->ckdxblksz > dev->ckdtab->r0 + 8) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 4-6 must contain zeroes */ if (iobuf[4] != 0 || iobuf[5] != 0 || iobuf[6] != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 8-11 contain the extent begin cylinder and head */ bcyl = (iobuf[8] << 8) | iobuf[9]; bhead = (iobuf[10] << 8) | iobuf[11]; /* Bytes 12-15 contain the extent end cylinder and head */ ecyl = (iobuf[12] << 8) | iobuf[13]; ehead = (iobuf[14] << 8) | iobuf[15]; /* Validate the extent description by checking that the ending track is not less than the starting track and that the extent does not exceed the already defined extent */ if ( bcyl > ecyl || (bcyl == ecyl && bhead > ehead) || EXTENT_CHECK(dev, bcyl, bhead) || EXTENT_CHECK(dev, ecyl, ehead) ) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, dev->ckdxtdef ? MESSAGE_2 : MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Define the new extent */ dev->ckdxbcyl = bcyl; dev->ckdxbhead = bhead; dev->ckdxecyl = ecyl; dev->ckdxehead = ehead; /* Set extent defined flag and return normal status */ dev->ckdxtdef = 1; *unitstat = CSW_CE | CSW_DE; break; } case 0x64: /*---------------------------------------------------------------*/ /* READ DEVICE CHARACTERISTICS */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if not 3380 or 3390 or 9345 */ if ((dev->devtype != 0x3380) && (dev->devtype != 0x3390) && (dev->devtype != 0x9345)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate residual byte count */ num = (count < dev->numdevchar) ? count : dev->numdevchar; *residual = count - num; if (count < dev->numdevchar) *more = 1; /* Copy device characteristics bytes to channel buffer */ memcpy (iobuf, dev->devchar, num); *unitstat = CSW_CE | CSW_DE; break; case 0x3E: /*---------------------------------------------------------------*/ /* READ SUBSYSTEM DATA */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record, or if subsystem data has not been prepared in the channel buffer by a previous Perform Subsystem Function command */ if (dev->ckdlcount > 0 || dev->ckdssdlen == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate residual byte count */ num = (count < dev->ckdssdlen) ? count : dev->ckdssdlen; *residual = count - num; if (count < dev->ckdssdlen) *more = 1; /* Subsystem data is already in the channel buffer, so just return channel end and device end */ *unitstat = CSW_CE | CSW_DE; break; case 0x5B: /*---------------------------------------------------------------*/ /* SUSPEND MULTIPATH RECONNECTION */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0xF3: /*---------------------------------------------------------------*/ /* DIAGNOSTIC CONTROL */ /*---------------------------------------------------------------*/ /* Command reject if SSI active */ if(dev->ckdssi) { /* Mark Set Special Intercept inactive */ dev->ckdssi = 0; ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_F); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate residual byte count */ num = (count < 4) ? count : 4; *residual = count - num; /* Control information length must be at least 4 bytes */ if (count < 4) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if byte 0 does not contain a valid subcommand code, or if bytes 2-3 are not zero */ if (!(iobuf[0] == DIAGCTL_MAINT_QUERY // || iobuf[0] == DIAGCTL_MAINT_RESERVE // || iobuf[0] == DIAGCTL_MAINT_RELEASE // || iobuf[0] == DIAGCTL_INHIBIT_WRITE // || iobuf[0] == DIAGCTL_SET_GUAR_PATH // || iobuf[0] == DIAGCTL_ENABLE_WRITE // || iobuf[0] == DIAGCTL_3380_TC_MODE // || iobuf[0] == DIAGCTL_INIT_SUBSYS // || iobuf[0] == DIAGCTL_UNFENCE // || iobuf[0] == DIAGCTL_ACCDEV_UNKCOND ) || iobuf[2] != 0 || iobuf[3] != 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if file mask does not specify diagnostic or device support authorization */ if ((dev->ckdfmask & CKDMASK_AAUTH) == CKDMASK_AAUTH_NORMAL) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_5); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x94: /*---------------------------------------------------------------*/ /* DEVICE RELEASE */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record, or preceded by Define Extent, Space Count, or Set File Mask, or (for 3390 only) preceded by Read IPL */ if (dev->ckdlcount > 0 || dev->ckdxtdef || dev->ckdspcnt || dev->ckdsetfm || (dev->ckdrdipl && dev->devtype == 0x3390)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Call the release exit and mark the device not reserved */ if (dev->hnd->release) (dev->hnd->release) (dev); obtain_lock (&dev->lock); dev->reserved = 0; release_lock (&dev->lock); /* Perform the operation of a sense command */ goto sense; case 0x14: /* UNCONDITIONAL RESERVE */ case 0xB4: /* DEVICE RESERVE */ /*---------------------------------------------------------------*/ /* DEVICE RESERVE */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record, or indeed if preceded by any command at all apart from Suspend Multipath Reconnection */ if (dev->ckdlcount > 0 || ccwseq > 1 || (chained && prevcode != 0x5B)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Mark the device reserved and call the reserve exit */ obtain_lock (&dev->lock); dev->reserved = 1; release_lock (&dev->lock); if (dev->hnd->reserve) (dev->hnd->reserve) (dev); /* Perform the operation of a sense command */ goto sense; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } sense: /* If sense bytes are cleared then build sense */ if ((dev->sense[0] == 0) & (dev->sense[1] == 0)) ckd_build_sense (dev, 0, 0, 0, 0, 0); /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* If numdevid is 0, then 0xE4 Sense ID is not supported */ if (dev->numdevid == 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0x34: /*---------------------------------------------------------------*/ /* SENSE PATH GROUP ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < 12) ? count : 12; *residual = count - num; if (count < 12) *more = 1; /* Byte 0 is the path group state byte */ iobuf[0] = SPG_PATHSTAT_RESET | SPG_PARTSTAT_IENABLED | SPG_PATHMODE_SINGLE; /* Bytes 1-11 contain the path group identifier */ memcpy (iobuf+1, dev->pgid, 11); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xAF: /*---------------------------------------------------------------*/ /* SET PATH GROUP ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < 12) ? count : 12; *residual = count - num; /* Control information length must be at least 12 bytes */ if (count < 12) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Byte 0 is the path group state byte */ if ((iobuf[0] & SPG_SET_COMMAND) == SPG_SET_ESTABLISH) { /* Only accept the new pathgroup id when 1) it has not yet been set (ie contains zeros) or 2) It is set, but we are setting the same value */ if(memcmp(dev->pgid, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 11) && memcmp(dev->pgid, iobuf+1, 11)) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Bytes 1-11 contain the path group identifier */ memcpy (dev->pgid, iobuf+1, 11); } /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0x54: /*---------------------------------------------------------------*/ /* SENSE SUBSYSTEM STATUS */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record, or if chained from any command unless the preceding command is Read Device Characteristics, Read Configuration Data, or a Suspend Multipath Reconnection command that was the first command in the chain */ if (dev->ckdlcount > 0 || (chained && prevcode != 0x64 && prevcode != 0xFA && prevcode != 0x5B) || (chained && prevcode == 0x5B && ccwseq > 1)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Build the basic subsystem status data in the I/O area */ num = dasd_build_ckd_subsys_status (dev, iobuf, count); /* Calculate residual byte count */ *residual = count < num ? 0 : count - num; *more = count < num; /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xA4: /*---------------------------------------------------------------*/ /* READ AND RESET BUFFERED LOG */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record, or if chained from any command unless the preceding command is Read Device Characteristics, Read Configuration Data, or a Suspend Multipath Reconnection command that was the first command in the chain */ if (dev->ckdlcount > 0 || (chained && prevcode != 0x64 && prevcode != 0xFA && prevcode != 0x5B) || (chained && prevcode == 0x5B && ccwseq > 1)) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate residual byte count */ num = (count < 32) ? count : 32; *residual = count - num; if (count < 32) *more = 1; /* Build the buffered error log in the I/O area */ memset (iobuf, 0x00, 32); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0x87: /*---------------------------------------------------------------*/ /* Set Subsystem Mode */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Command reject if not a cached device, first in chain, or */ /* immediately preceded by Suspend Multipath Connection */ /* */ /* TBD: Add first in chain and Suspend Multipath check */ /* */ if ((dev->ckdcu->devt != 0x3990 && dev->ckdcu->devt != 0x2105) || (dev->ckdcu->model & 0x07) == 0x02) /* 3990-1/2 */ { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate residual byte count */ num = (count < 2) ? count : 2; *residual = count - num; /* Control information length must be at least 2 bytes */ if (count < 2) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* TBD / MGD: Complete checks for Set Subsystem Mode */ /* covering message required flag and read */ /* message id check */ /* Validate operands -- Refer to 2105 validation sequence */ if (((iobuf[0] & 0x02) != 0) || ((iobuf[1] & 0x07) != 0) || ((iobuf[1] & 0x18) != 0) /* zero unless in TPF mode */ || ((iobuf[0] & 0xE0) > 0xA0) || ((iobuf[0] & 0x1C) > 0x14) || ((iobuf[1] & 0xE0) > 0xA0) || ((iobuf[1] & 0x18) == 0x18) /* TPF reserved */ || (((iobuf[0] & 0x10) != 0) && ( ((iobuf[0] & 0xE0) > 0x80) || ((iobuf[0] & 0xE0) < 0x40) || ((iobuf[0] & 0x1C) != 0x10) || ((iobuf[1] & 0xE0) > 0xA0) || ((iobuf[1] & 0xE0) < 0x40) || ((iobuf[1] & 0xE0) == 0x60))) || (((iobuf[0] & 0xE0) != 0) && ( ((iobuf[0] & 0x1C) != 0) || (iobuf[1] != 0))) || (((iobuf[0] & 0x1C) != 0) && (iobuf[1] != 0))) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* TBD / Future: Cache Fast Write Data Control */ /* Treat as NOP and Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xFA: /*---------------------------------------------------------------*/ /* READ CONFIGURATION DATA */ /*---------------------------------------------------------------*/ /* Command reject if within the domain of a Locate Record */ if (dev->ckdlcount > 0) { ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2); *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Build the configuration data area */ num = dasd_build_ckd_config_data (dev, iobuf, count); /* Calculate residual byte count */ *residual = count < num ? 0 : count - num; *more = count < num; /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1); *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ /* Return if synchronous I/O needs to be retried asynchronously */ if (dev->syncio_retry) return; /* Reset the flags which ensure correct positioning for write commands */ /* Reset search HA flag if command was not SEARCH HA EQUAL or WRITE HA */ if ((code & 0x7F) != 0x39 && (code & 0x7F) != 0x19) dev->ckdhaeq = 0; /* Reset search id flag if command was not SEARCH ID EQUAL, READ/WRITE KEY AND DATA, or READ/WRITE DATA */ if ((code & 0x7F) != 0x31 && (code & 0x7F) != 0x0E && (code & 0x7F) != 0x0D && (code & 0x7F) != 0x06 && (code & 0x7F) != 0x05) dev->ckdideq = 0; /* Reset search key flag if command was not SEARCH KEY EQUAL or READ/WRITE DATA */ if ((code & 0x7F) != 0x29 && (code & 0x7F) != 0x06 && (code & 0x7F) != 0x05) dev->ckdkyeq = 0; /* Reset write CKD flag if command was not WRITE R0 or WRITE CKD */ if (code != 0x15 && code != 0x1D) dev->ckdwckd = 0; /* If within the domain of a locate record then decrement the count of CCWs remaining to be processed within the domain */ if (dev->ckdlcount > 0 && code != 0x047 && code != 0x4B) { /* Decrement the count of CCWs remaining in the domain */ dev->ckdlcount--; /* Command reject with incomplete domain if CCWs remain but command chaining is not specified */ if (dev->ckdlcount > 0 && (flags & CCW_FLAGS_CC) == 0 && code != 0x02) { ckd_build_sense (dev, SENSE_CR | SENSE_OC, 0, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; } } /* end if(ckdlcount) */ } /* end function ckddasd_execute_ccw */ DLL_EXPORT DEVHND ckddasd_device_hndinfo = { &ckddasd_init_handler, /* Device Initialisation */ &ckddasd_execute_ccw, /* Device CCW execute */ &ckddasd_close_device, /* Device Close */ &ckddasd_query_device, /* Device Query */ &ckddasd_start, /* Device Start channel pgm */ &ckddasd_end, /* Device End channel pgm */ &ckddasd_start, /* Device Resume channel pgm */ &ckddasd_end, /* Device Suspend channel pgm */ &ckddasd_read_track, /* Device Read */ &ckddasd_update_track, /* Device Write */ &ckddasd_used, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Ouput */ &ckddasd_hsuspend, /* Hercules suspend */ &ckddasd_hresume /* Hercules resume */ }; hercules-3.12/fbadasd.c0000664000175000017500000016022512564723224011741 00000000000000/* FBADASD.C (c) Copyright Roger Bowler, 1999-2009 */ /* ESA/390 FBA Direct Access Storage Device Handler */ /*-------------------------------------------------------------------*/ /* This module contains device handling functions for emulated */ /* fixed block architecture direct access storage devices. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* 0671 device support by Jay Maynard */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _FBADASD_C_ #define _HDASD_DLL_ #include "hercules.h" #include "dasdblks.h" // (need #define DEFAULT_FBA_TYPE) #include "sr.h" /*-------------------------------------------------------------------*/ /* Bit definitions for Define Extent file mask */ /*-------------------------------------------------------------------*/ #define FBAMASK_CTL 0xC0 /* Operation control bits... */ #define FBAMASK_CTL_INHFMT 0x00 /* ...inhibit format writes */ #define FBAMASK_CTL_INHWRT 0x40 /* ...inhibit all writes */ #define FBAMASK_CTL_ALLWRT 0xC0 /* ...allow all writes */ #define FBAMASK_CTL_RESV 0x80 /* ...reserved bit setting */ #define FBAMASK_CE 0x08 /* CE field extent */ #define FBAMASK_DIAG 0x04 /* Permit diagnostic command */ #define FBAMASK_RESV 0x33 /* Reserved bits - must be 0 */ /*-------------------------------------------------------------------*/ /* Bit definitions for Locate operation byte */ /*-------------------------------------------------------------------*/ #define FBAOPER_RESV 0xE0 /* Reserved bits - must be 0 */ /* Note : Bit 3 seems to be */ /* The "suppress" bit but is */ /* apparently ignored */ /* It is therefore valid but */ /* not used. */ #define FBAOPER_CODE 0x0F /* Operation code bits... */ #define FBAOPER_WRITE 0x01 /* ...write data */ #define FBAOPER_READREP 0x02 /* ...read replicated data */ #define FBAOPER_FMTDEFC 0x04 /* ...format defective block */ #define FBAOPER_WRTVRFY 0x05 /* ...write data and verify */ #define FBAOPER_READ 0x06 /* ...read data */ #define FBA_BLKGRP_SIZE (120 * 512) /* Size of block group */ /*-------------------------------------------------------------------*/ /* Initialize the device handler */ /*-------------------------------------------------------------------*/ int fbadasd_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { int rc; /* Return code */ struct stat statbuf; /* File information */ int startblk; /* Device origin block number*/ int numblks; /* Device block count */ BYTE c; /* Character work area */ char *cu = NULL; /* Specified control unit */ char *kw; /* Argument keyword */ int cfba = 0; /* 1 = Compressed fba */ int i; /* Loop index */ CKDDASD_DEVHDR devhdr; /* Device header */ CCKDDASD_DEVHDR cdevhdr; /* Compressed device header */ char pathname[MAX_PATH]; /* file path in host format */ if (!dev->typname || !sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = DEFAULT_FBA_TYPE; /* The first argument is the file name */ if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1) { logmsg (_("HHCDA056E File name missing or invalid\n")); return -1; } /* Save the file name in the device block */ strcpy (dev->filename, argv[0]); /* Device is shareable */ dev->shared = 1; /* Check for possible remote device */ hostpath(pathname, dev->filename, sizeof(pathname)); if (stat(pathname, &statbuf) < 0) { rc = shared_fba_init ( dev, argc, argv); if (rc < 0) { logmsg (_("HHCDA057E %4.4X:File not found or invalid\n"), dev->devnum); return -1; } else return rc; } /* Open the device file */ hostpath(pathname, dev->filename, sizeof(pathname)); dev->fd = hopen(pathname, O_RDWR|O_BINARY); if (dev->fd < 0) { dev->fd = hopen(pathname, O_RDONLY|O_BINARY); if (dev->fd < 0) { logmsg (_("HHCDA058E File %s open error: %s\n"), dev->filename, strerror(errno)); return -1; } } /* Read the first block to see if it's compressed */ rc = read (dev->fd, &devhdr, CKDDASD_DEVHDR_SIZE); if (rc < (int)CKDDASD_DEVHDR_SIZE) { /* Handle read error condition */ if (rc < 0) logmsg (_("HHCDA059E Read error in file %s: %s\n"), dev->filename, strerror(errno)); else logmsg (_("HHCDA060E Unexpected end of file in %s\n"), dev->filename); close (dev->fd); dev->fd = -1; return -1; } /* Processing for compressed fba dasd */ if (memcmp (&devhdr.devid, "FBA_C370", 8) == 0) { cfba = 1; /* Read the compressed device header */ rc = read (dev->fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); if (rc < (int)CKDDASD_DEVHDR_SIZE) { /* Handle read error condition */ if (rc < 0) logmsg (_("HHCDA061E Read error in file %s: %s\n"), dev->filename, strerror(errno)); else logmsg (_("HHCDA062E Unexpected end of file in %s\n"), dev->filename); close (dev->fd); dev->fd = -1; return -1; } /* Set block size, device origin, and device size in blocks */ dev->fbablksiz = 512; dev->fbaorigin = 0; dev->fbanumblk = ((U32)(cdevhdr.cyls[3]) << 24) | ((U32)(cdevhdr.cyls[2]) << 16) | ((U32)(cdevhdr.cyls[1]) << 8) | (U32)(cdevhdr.cyls[0]); /* Default to synchronous I/O */ //FIXME: syncio is reported to be broken for fba // dev->syncio = 1; /* process the remaining arguments */ for (i = 1; i < argc; i++) { if (strlen (argv[i]) > 3 && memcmp ("sf=", argv[i], 3) == 0) { if ('\"' == argv[i][3]) argv[i]++; hostpath(pathname, argv[i]+3, sizeof(pathname)); dev->dasdsfn = strdup(pathname); if (dev->dasdsfn) { /* Set the pointer to the suffix character */ dev->dasdsfx = strrchr (dev->dasdsfn, '/'); if (dev->dasdsfx == NULL) dev->dasdsfx = dev->dasdsfn + 1; dev->dasdsfx = strchr (dev->dasdsfx, '.'); if (dev->dasdsfx == NULL) dev->dasdsfx = dev->dasdsfn + strlen(dev->dasdsfn); dev->dasdsfx--; } continue; } if (strlen (argv[i]) > 3 && memcmp("cu=", argv[i], 3) == 0) /* support for cu= added but */ { /* is ignored for the present */ kw = strtok (argv[i], "="); cu = strtok (NULL, " \t"); continue; } if (strcasecmp ("nosyncio", argv[i]) == 0 || strcasecmp ("nosyio", argv[i]) == 0) { dev->syncio = 0; continue; } if (strcasecmp ("syncio", argv[i]) == 0 || strcasecmp ("syio", argv[i]) == 0) { dev->syncio = 1; continue; } logmsg (_("HHCDA063E parameter %d is invalid: %s\n"), i + 1, argv[i]); return -1; } } /* Processing for regular fba dasd */ else { /* Determine the device size */ rc = fstat (dev->fd, &statbuf); if (rc < 0) { logmsg (_("HHCDA064E File %s fstat error: %s\n"), dev->filename, strerror(errno)); close (dev->fd); dev->fd = -1; return -1; } #if defined(OPTION_FBA_BLKDEVICE) && defined(BLKGETSIZE) if(S_ISBLK(statbuf.st_mode)) { rc=ioctl(dev->fd,BLKGETSIZE,&statbuf.st_size); if(rc<0) { logmsg (_("HHCDA082E File %s IOCTL BLKGETSIZE error: %s\n"), dev->filename, strerror(errno)); close (dev->fd); dev->fd = -1; return -1; } dev->fbablksiz = 512; dev->fbaorigin = 0; dev->fbanumblk = statbuf.st_size; logmsg("REAL FBA Opened\n"); } else #endif // defined(OPTION_FBA_BLKDEVICE) && defined(BLKGETSIZE) { /* Set block size, device origin, and device size in blocks */ dev->fbablksiz = 512; dev->fbaorigin = 0; dev->fbanumblk = statbuf.st_size / dev->fbablksiz; } /* The second argument is the device origin block number */ if (argc >= 2) { if (sscanf(argv[1], "%u%c", &startblk, &c) != 1 || startblk >= dev->fbanumblk) { logmsg (_("HHCDA065E Invalid device origin block number %s\n"), argv[1]); close (dev->fd); dev->fd = -1; return -1; } dev->fbaorigin = (off_t)startblk; dev->fbanumblk -= startblk; } /* The third argument is the device block count */ if (argc >= 3 && strcmp(argv[2],"*") != 0) { if (sscanf(argv[2], "%u%c", &numblks, &c) != 1 || numblks > dev->fbanumblk) { logmsg (_("HHCDA066E Invalid device block count %s\n"), argv[2]); close (dev->fd); dev->fd = -1; return -1; } dev->fbanumblk = numblks; } } dev->fbaend = (dev->fbaorigin + dev->fbanumblk) * dev->fbablksiz; logmsg (_("HHCDA067I %s origin=%lld blks=%d\n"), dev->filename, (long long)dev->fbaorigin, dev->fbanumblk); /* Set number of sense bytes */ dev->numsense = 24; /* Locate the FBA dasd table entry */ dev->fbatab = dasd_lookup (DASD_FBADEV, NULL, dev->devtype, dev->fbanumblk); if (dev->fbatab == NULL) { logmsg (_("HHCDA068E %4.4X device type %4.4X not found in dasd table\n"), dev->devnum, dev->devtype); close (dev->fd); dev->fd = -1; return -1; } /* Build the devid area */ dev->numdevid = dasd_build_fba_devid (dev->fbatab,(BYTE *)&dev->devid); /* Build the devchar area */ dev->numdevchar = dasd_build_fba_devchar (dev->fbatab, (BYTE *)&dev->devchar,dev->fbanumblk); /* Initialize current blkgrp and cache entry */ dev->bufcur = dev->cache = -1; /* Activate I/O tracing */ // dev->ccwtrace = 1; /* Call the compressed init handler if compressed fba */ if (cfba) return cckddasd_init_handler (dev, argc, argv); return 0; } /* end function fbadasd_init_handler */ /*-------------------------------------------------------------------*/ /* Query the device definition */ /*-------------------------------------------------------------------*/ void fbadasd_query_device (DEVBLK *dev, char **class, int buflen, char *buffer) { BEGIN_DEVICE_CLASS_QUERY( "DASD", dev, class, buflen, buffer ); snprintf (buffer, buflen, "%s [%lld,%d]", dev->filename, (long long)dev->fbaorigin, dev->fbanumblk); } /* end function fbadasd_query_device */ /*-------------------------------------------------------------------*/ /* Calculate length of an FBA block group */ /*-------------------------------------------------------------------*/ static int fba_blkgrp_len (DEVBLK *dev, int blkgrp) { off_t offset; /* Offset of block group */ offset = blkgrp * FBA_BLKGRP_SIZE; if (dev->fbaend - offset < FBA_BLKGRP_SIZE) return (int)(dev->fbaend - offset); else return FBA_BLKGRP_SIZE; } /*-------------------------------------------------------------------*/ /* Read fba block(s) */ /*-------------------------------------------------------------------*/ static int fba_read (DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ int blkgrp; /* Block group number */ int blklen; /* Length left in block group*/ int off; /* Device buffer offset */ int bufoff; /* Buffer offset */ int copylen; /* Length left to copy */ /* Command reject if referencing outside the volume */ if (dev->fbarba < dev->fbaorigin * dev->fbablksiz || dev->fbarba + len > dev->fbaend) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Read the block group */ blkgrp = dev->fbarba / FBA_BLKGRP_SIZE; rc = (dev->hnd->read) (dev, blkgrp, unitstat); if (rc < 0) return -1; off = dev->fbarba % FBA_BLKGRP_SIZE; blklen = dev->buflen - off; /* Initialize target buffer offset and length to copy */ bufoff = 0; copylen = len; /* Access multiple block groups asynchronously */ if (dev->syncio_active && copylen > blklen) { dev->syncio_retry = 1; return -1; } /* Copy from the device buffer to the target buffer */ while (copylen > 0) { int len = copylen < blklen ? copylen : blklen; /* Copy to the target buffer */ if (buf) memcpy (buf + bufoff, dev->buf + off, len); /* Update offsets and lengths */ bufoff += len; copylen -= blklen; /* Read the next block group if still more to copy */ if (copylen > 0) { blkgrp++; off = 0; rc = (dev->hnd->read) (dev, blkgrp, unitstat); if (rc < 0) return -1; blklen = fba_blkgrp_len (dev, blkgrp); } } /* Update the rba */ dev->fbarba += len; return len; } /* end function fba_read */ /*-------------------------------------------------------------------*/ /* Write fba block(s) */ /*-------------------------------------------------------------------*/ static int fba_write (DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ int blkgrp; /* Block group number */ int blklen; /* Length left in block group*/ int off; /* Target buffer offset */ int bufoff; /* Source buffer offset */ int copylen; /* Length left to copy */ /* Command reject if referencing outside the volume */ if (dev->fbarba < dev->fbaorigin * dev->fbablksiz || dev->fbarba + len > dev->fbaend) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Read the block group */ blkgrp = dev->fbarba / FBA_BLKGRP_SIZE; rc = (dev->hnd->read) (dev, blkgrp, unitstat); if (rc < 0) return -1; off = dev->fbarba % FBA_BLKGRP_SIZE; blklen = dev->buflen - off; /* Initialize source buffer offset and length to copy */ bufoff = 0; copylen = len; /* Access multiple block groups asynchronously */ if (dev->syncio_active && copylen > blklen) { dev->syncio_retry = 1; return -1; } /* Copy to the device buffer from the target buffer */ while (copylen > 0) { int len = copylen < blklen ? copylen : blklen; /* Write to the block group */ rc = (dev->hnd->write) (dev, blkgrp, off, buf + bufoff, len, unitstat); if (rc < 0) return -1; /* Update offsets and lengths */ bufoff += len; copylen -= len; blkgrp++; off = 0; blklen = fba_blkgrp_len (dev, blkgrp); } /* Update the rba */ dev->fbarba += len; return len; } /* end function fba_write */ /*-------------------------------------------------------------------*/ /* FBA read block group exit */ /*-------------------------------------------------------------------*/ static int fbadasd_read_blkgrp (DEVBLK *dev, int blkgrp, BYTE *unitstat) { int rc; /* Return code */ int i, o; /* Cache indexes */ int len; /* Length to read */ off_t offset; /* File offsets */ /* Return if reading the same block group */ if (blkgrp >= 0 && blkgrp == dev->bufcur) return 0; /* Write the previous block group if modified */ if (dev->bufupd) { /* Retry if synchronous I/O */ if (dev->syncio_active) { dev->syncio_retry = 1; return -1; } dev->bufupd = 0; /* Seek to the old block group offset */ offset = (off_t)(((S64)dev->bufcur * FBA_BLKGRP_SIZE) + dev->bufupdlo); offset = lseek (dev->fd, offset, SEEK_SET); if (offset < 0) { /* Handle seek error condition */ logmsg (_("HHCDA069E error writing blkgrp %d: lseek error: %s\n"), dev->bufcur, strerror(errno)); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; cache_lock(CACHE_DEVBUF); cache_setflag(CACHE_DEVBUF, dev->cache, ~FBA_CACHE_ACTIVE, 0); cache_unlock(CACHE_DEVBUF); dev->bufupdlo = dev->bufupdhi = 0; dev->bufcur = dev->cache = -1; return -1; } /* Write the portion of the block group that was modified */ rc = write (dev->fd, dev->buf + dev->bufupdlo, dev->bufupdhi - dev->bufupdlo); if (rc < dev->bufupdhi - dev->bufupdlo) { /* Handle write error condition */ logmsg (_("HHCDA070E error writing blkgrp %d: write error: %s\n"), dev->bufcur, strerror(errno)); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; cache_lock(CACHE_DEVBUF); cache_setflag(CACHE_DEVBUF, dev->cache, ~FBA_CACHE_ACTIVE, 0); cache_unlock(CACHE_DEVBUF); dev->bufupdlo = dev->bufupdhi = 0; dev->bufcur = dev->cache = -1; return -1; } dev->bufupdlo = dev->bufupdhi = 0; } cache_lock (CACHE_DEVBUF); /* Make the previous cache entry inactive */ if (dev->cache >= 0) cache_setflag(CACHE_DEVBUF, dev->cache, ~FBA_CACHE_ACTIVE, 0); dev->bufcur = dev->cache = -1; /* Return on special case when called by the close handler */ if (blkgrp < 0) { cache_unlock (CACHE_DEVBUF); return 0; } fba_read_blkgrp_retry: /* Search the cache */ i = cache_lookup (CACHE_DEVBUF, FBA_CACHE_SETKEY(dev->devnum, blkgrp), &o); /* Cache hit */ if (i >= 0) { cache_setflag(CACHE_DEVBUF, i, ~0, FBA_CACHE_ACTIVE); cache_setage(CACHE_DEVBUF, i); cache_unlock(CACHE_DEVBUF); logdevtr (dev, _("HHCDA071I read blkgrp %d cache hit, using cache[%d]\n"), blkgrp, i); dev->cachehits++; dev->cache = i; dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0); dev->bufcur = blkgrp; dev->bufoff = 0; dev->bufoffhi = fba_blkgrp_len (dev, blkgrp); dev->buflen = fba_blkgrp_len (dev, blkgrp); dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache); return 0; } /* Retry if synchronous I/O */ if (dev->syncio_active) { cache_unlock(CACHE_DEVBUF); dev->syncio_retry = 1; return -1; } /* Wait if no available cache entry */ if (o < 0) { logdevtr (dev, _("HHCDA072I read blkgrp %d no available cache entry, waiting\n"), blkgrp); dev->cachewaits++; cache_wait(CACHE_DEVBUF); goto fba_read_blkgrp_retry; } /* Cache miss */ logdevtr (dev, _("HHCDA073I read blkgrp %d cache miss, using cache[%d]\n"), blkgrp, o); dev->cachemisses++; /* Make this cache entry active */ cache_setkey (CACHE_DEVBUF, o, FBA_CACHE_SETKEY(dev->devnum, blkgrp)); cache_setflag(CACHE_DEVBUF, o, 0, FBA_CACHE_ACTIVE|DEVBUF_TYPE_FBA); cache_setage (CACHE_DEVBUF, o); dev->buf = cache_getbuf(CACHE_DEVBUF, o, FBA_BLKGRP_SIZE); cache_unlock (CACHE_DEVBUF); /* Get offset and length */ offset = (off_t)((S64)blkgrp * FBA_BLKGRP_SIZE); len = fba_blkgrp_len (dev, blkgrp); logdevtr (dev, _("HHCDA074I read blkgrp %d offset %" I64_FMT "d len %d\n"), blkgrp, (long long)offset, fba_blkgrp_len(dev, blkgrp)); /* Seek to the block group offset */ offset = lseek (dev->fd, offset, SEEK_SET); if (offset < 0) { /* Handle seek error condition */ logmsg (_("HHCDA075E error reading blkgrp %d: lseek error: %s\n"), blkgrp, strerror(errno)); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; cache_lock(CACHE_DEVBUF); cache_release(CACHE_DEVBUF, o, 0); cache_unlock(CACHE_DEVBUF); return -1; } /* Read the block group */ rc = read (dev->fd, dev->buf, len); if (rc < len) { /* Handle read error condition */ logmsg (_("HHCDA076E error reading blkgrp %d: read error: %s\n"), blkgrp, rc < 0 ? strerror(errno) : "end of file"); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; cache_lock(CACHE_DEVBUF); cache_release(CACHE_DEVBUF, o, 0); cache_unlock(CACHE_DEVBUF); return -1; } dev->cache = o; dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0); dev->bufcur = blkgrp; dev->bufoff = 0; dev->bufoffhi = fba_blkgrp_len (dev, blkgrp); dev->buflen = fba_blkgrp_len (dev, blkgrp); dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache); return 0; } /* end function fbadasd_read_blkgrp */ /*-------------------------------------------------------------------*/ /* FBA update block group exit */ /*-------------------------------------------------------------------*/ static int fbadasd_update_blkgrp (DEVBLK *dev, int blkgrp, int off, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Read the block group */ if (blkgrp != dev->bufcur) { rc = (dev->hnd->read) (dev, blkgrp, unitstat); if (rc < 0) { dev->bufcur = dev->cache = -1; return -1; } } /* Copy to the device buffer */ if (buf) memcpy (dev->buf + off, buf, len); /* Update high/low offsets */ if (!dev->bufupd || off < dev->bufupdlo) dev->bufupdlo = off; if (off + len > dev-> bufupdhi) dev->bufupdhi = off + len; /* Indicate block group has been modified */ if (!dev->bufupd) { dev->bufupd = 1; shared_update_notify (dev, blkgrp); } return len; } /* end function fbadasd_update_blkgrp */ /*-------------------------------------------------------------------*/ /* Channel program end exit */ /*-------------------------------------------------------------------*/ static void fbadasd_end (DEVBLK *dev) { BYTE unitstat; /* Forces updated buffer to be written */ (dev->hnd->read) (dev, -1, &unitstat); } /*-------------------------------------------------------------------*/ /* Release cache entries */ /*-------------------------------------------------------------------*/ int fbadasd_purge_cache (int *answer, int ix, int i, void *data) { U16 devnum; /* Cached device number */ int blkgrp; /* Cached block group */ DEVBLK *dev = data; /* -> device block */ UNREFERENCED(answer); FBA_CACHE_GETKEY(i, devnum, blkgrp); if (dev->devnum == devnum) cache_release (ix, i, CACHE_FREEBUF); return 0; } /*-------------------------------------------------------------------*/ /* Close the device */ /*-------------------------------------------------------------------*/ int fbadasd_close_device ( DEVBLK *dev ) { BYTE unitstat; /* Forces updated buffer to be written */ (dev->hnd->read) (dev, -1, &unitstat); /* Free the cache */ cache_lock(CACHE_DEVBUF); cache_scan(CACHE_DEVBUF, fbadasd_purge_cache, dev); cache_unlock(CACHE_DEVBUF); /* Close the device file */ close (dev->fd); dev->fd = -1; return 0; } /* end function fbadasd_close_device */ /*-------------------------------------------------------------------*/ /* Return used blocks */ /*-------------------------------------------------------------------*/ static int fbadasd_used (DEVBLK *dev) { return dev->fbanumblk; } /*-------------------------------------------------------------------*/ /* Execute a Channel Command Word */ /*-------------------------------------------------------------------*/ void fbadasd_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual ) { int rc; /* Return code */ int num; /* Number of bytes to move */ BYTE hexzeroes[512]; /* Bytes for zero fill */ int rem; /* Byte count for zero fill */ int repcnt; /* Replication count */ /* Reset extent flag at start of CCW chain */ if (chained == 0) dev->fbaxtdef = 0; /* Process depending on CCW opcode */ switch (code) { case 0x02: /*---------------------------------------------------------------*/ /* READ IPL */ /*---------------------------------------------------------------*/ /* Must be first CCW or chained from a previous READ IPL CCW */ if (chained && prevcode != 0x02) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Zeroize the file mask and set extent for entire device */ dev->fbamask = 0; dev->fbaxblkn = 0; dev->fbaxfirst = 0; dev->fbaxlast = dev->fbanumblk - 1; /* Seek to start of block zero */ dev->fbarba = dev->fbaorigin * dev->fbablksiz; /* Overrun if data chaining */ if ((flags & CCW_FLAGS_CD)) { dev->sense[0] = SENSE_OR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate number of bytes to read and set residual count */ num = (count < dev->fbablksiz) ? count : dev->fbablksiz; *residual = count - num; if (count < dev->fbablksiz) *more = 1; /* Read physical block into channel buffer */ rc = fba_read (dev, iobuf, num, unitstat); if (rc < num) break; /* Set extent defined flag */ dev->fbaxtdef = 1; /* Set normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x03: /*---------------------------------------------------------------*/ /* CONTROL NO-OPERATION */ /*---------------------------------------------------------------*/ *unitstat = CSW_CE | CSW_DE; break; case 0x41: /*---------------------------------------------------------------*/ /* WRITE */ /*---------------------------------------------------------------*/ /* Reject if previous command was not LOCATE */ if (prevcode != 0x43) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Reject if locate command did not specify write operation */ if ((dev->fbaoper & FBAOPER_CODE) != FBAOPER_WRITE && (dev->fbaoper & FBAOPER_CODE) != FBAOPER_WRTVRFY) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Prepare a block of zeroes for write padding */ memset (hexzeroes, 0, sizeof(hexzeroes)); /* Write physical blocks of data to the device */ while (dev->fbalcnum > 0) { /* Exit if data chaining and this CCW is exhausted */ if ((flags & CCW_FLAGS_CD) && count == 0) break; /* Overrun if data chaining within a physical block */ if ((flags & CCW_FLAGS_CD) && count < dev->fbablksiz) { dev->sense[0] = SENSE_OR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate number of bytes to write */ num = (count < dev->fbablksiz) ? count : dev->fbablksiz; if (num < dev->fbablksiz) *more = 1; /* Write physical block from channel buffer */ if (num > 0) { rc = fba_write (dev, iobuf, num, unitstat); if (rc < num) break; } /* Fill remainder of block with zeroes */ if (num < dev->fbablksiz) { rem = dev->fbablksiz - num; rc = fba_write (dev, hexzeroes, rem, unitstat); if (rc < rem) break; } /* Prepare to write next block */ count -= num; iobuf += num; dev->fbalcnum--; } /* end while */ /* Set residual byte count */ *residual = count; if (dev->fbalcnum > 0) *more = 1; /* Set ending status */ *unitstat |= CSW_CE | CSW_DE; break; case 0x42: /*---------------------------------------------------------------*/ /* READ */ /*---------------------------------------------------------------*/ /* Reject if previous command was not LOCATE or READ IPL */ if (prevcode != 0x43 && prevcode != 0x02) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Reject if locate command did not specify read operation */ if (prevcode != 0x02 && (dev->fbaoper & FBAOPER_CODE) != FBAOPER_READ && (dev->fbaoper & FBAOPER_CODE) != FBAOPER_READREP) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Read physical blocks of data from device */ while (dev->fbalcnum > 0 && count > 0) { /* Overrun if data chaining within a physical block */ if ((flags & CCW_FLAGS_CD) && count < dev->fbablksiz) { dev->sense[0] = SENSE_OR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Calculate number of bytes to read */ num = (count < dev->fbablksiz) ? count : dev->fbablksiz; if (num < dev->fbablksiz) *more = 1; /* Read physical block into channel buffer */ rc = fba_read (dev, iobuf, num, unitstat); if (rc < num) break; /* Prepare to read next block */ count -= num; iobuf += num; dev->fbalcnum--; } /* end while */ /* Set residual byte count */ *residual = count; if (dev->fbalcnum > 0) *more = 1; /* Set ending status */ *unitstat |= CSW_CE | CSW_DE; break; case 0x43: /*---------------------------------------------------------------*/ /* LOCATE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < 8) ? count : 8; *residual = count - num; /* Control information length must be at least 8 bytes */ if (count < 8) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* LOCATE must be preceded by DEFINE EXTENT or READ IPL */ if (dev->fbaxtdef == 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Save and validate the operation byte */ dev->fbaoper = iobuf[0]; if (dev->fbaoper & FBAOPER_RESV) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Validate and process operation code */ if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_WRITE || (dev->fbaoper & FBAOPER_CODE) == FBAOPER_WRTVRFY) { /* Reject command if file mask inhibits all writes */ if ((dev->fbamask & FBAMASK_CTL) == FBAMASK_CTL_INHWRT) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } else if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_READ || (dev->fbaoper & FBAOPER_CODE) == FBAOPER_READREP) { } else if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_FMTDEFC) { /* Reject command if file mask inhibits format writes */ if ((dev->fbamask & FBAMASK_CTL) == FBAMASK_CTL_INHFMT) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } else /* Operation code is invalid */ { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Byte 1 contains the replication count */ repcnt = iobuf[1]; /* Bytes 2-3 contain the block count */ dev->fbalcnum = fetch_hw(iobuf + 2); /* Bytes 4-7 contain the displacement of the first block relative to the start of the dataset */ dev->fbalcblk = fetch_fw(iobuf + 4); /* Verify that the block count is non-zero, and that the starting and ending blocks fall within the extent */ if ( dev->fbalcnum == 0 || dev->fbalcnum > dev->fbaxlast + 1 || dev->fbalcblk < dev->fbaxfirst || dev->fbalcblk > dev->fbaxlast + 1 - dev->fbalcnum) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* For replicated data, verify that the replication count is non-zero and is a multiple of the block count */ if ((dev->fbaoper & FBAOPER_CODE) == FBAOPER_READREP) { if (repcnt == 0 || repcnt % dev->fbalcnum != 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } } /* Position device to start of block */ dev->fbarba = (dev->fbaorigin + dev->fbaxblkn + dev->fbalcblk - dev->fbaxfirst ) * dev->fbablksiz; logdevtr (dev, _("HHCDA077I Positioning to %8.8" I64_FMT "X (%" I64_FMT "u)\n"), (long long unsigned int)dev->fbarba, (long long unsigned int)dev->fbarba); /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x63: /*---------------------------------------------------------------*/ /* DEFINE EXTENT */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < 16) ? count : 16; *residual = count - num; /* Control information length must be at least 16 bytes */ if (count < 16) { logmsg(_("HHCDA078E define extent data too short: %d bytes\n"), count); dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Reject if extent previously defined in this CCW chain */ if (dev->fbaxtdef) { logmsg(_("HHCDA079E second define extent in chain\n")); dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Save and validate the file mask */ dev->fbamask = iobuf[0]; if ((dev->fbamask & (FBAMASK_RESV | FBAMASK_CE)) || (dev->fbamask & FBAMASK_CTL) == FBAMASK_CTL_RESV) { logmsg(_("HHCDA080E invalid file mask %2.2X\n"), dev->fbamask); dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } // VM/ESA sends 0x00000200 0x00000000 0x00000000 0x0001404F // /* Verify that bytes 1-3 are zeroes */ // if (iobuf[1] != 0 || iobuf[2] != 0 || iobuf[3] != 0) // { // logmsg(_("fbadasd: invalid reserved bytes %2.2X %2.2X %2.2X\n"), // iobuf[1], iobuf[2], iobuf[3]); // dev->sense[0] = SENSE_CR; // *unitstat = CSW_CE | CSW_DE | CSW_UC; // break; // } /* Bytes 4-7 contain the block number of the first block of the extent relative to the start of the device */ dev->fbaxblkn = fetch_fw(iobuf + 4); /* Bytes 8-11 contain the block number of the first block of the extent relative to the start of the dataset */ dev->fbaxfirst = fetch_fw(iobuf + 8); /* Bytes 12-15 contain the block number of the last block of the extent relative to the start of the dataset */ dev->fbaxlast = fetch_fw(iobuf + 12); /* Validate the extent description by checking that the ending block is not less than the starting block and that the ending block does not exceed the device size */ if (dev->fbaxlast < dev->fbaxfirst || dev->fbaxblkn > (U32)dev->fbanumblk || dev->fbaxlast - dev->fbaxfirst >= dev->fbanumblk - dev->fbaxblkn) { logmsg(_("HHCDA081E invalid extent: first block %d, last block %d,\n"), dev->fbaxfirst, dev->fbaxlast); logmsg(_(" numblks %d, device size %d\n"), dev->fbaxblkn, dev->fbanumblk); dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set extent defined flag and return normal status */ dev->fbaxtdef = 1; *unitstat = CSW_CE | CSW_DE; break; case 0x64: /*---------------------------------------------------------------*/ /* READ DEVICE CHARACTERISTICS */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevchar) ? count : dev->numdevchar; *residual = count - num; if (count < dev->numdevchar) *more = 1; /* Copy device characteristics bytes to channel buffer */ memcpy (iobuf, dev->devchar, num); *unitstat = CSW_CE | CSW_DE; break; case 0x94: /*---------------------------------------------------------------*/ /* DEVICE RELEASE */ /*---------------------------------------------------------------*/ /* Reject if extent previously defined in this CCW chain */ if (dev->fbaxtdef) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } if (dev->hnd->release) (dev->hnd->release) (dev); obtain_lock (&dev->lock); dev->reserved = 0; release_lock (&dev->lock); /* Return sense information */ goto sense; case 0xB4: /*---------------------------------------------------------------*/ /* DEVICE RESERVE */ /*---------------------------------------------------------------*/ /* Reject if extent previously defined in this CCW chain */ if (dev->fbaxtdef) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Reserve device to the ID of the active channel program */ obtain_lock (&dev->lock); dev->reserved = 1; release_lock (&dev->lock); if (dev->hnd->reserve) (dev->hnd->reserve) (dev); /* Return sense information */ goto sense; case 0x14: /*---------------------------------------------------------------*/ /* UNCONDITIONAL RESERVE */ /*---------------------------------------------------------------*/ /* Reject if this is not the first CCW in the chain */ if (ccwseq > 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Reserve device to the ID of the active channel program */ obtain_lock (&dev->lock); dev->reserved = 1; release_lock (&dev->lock); if (dev->hnd->reserve) (dev->hnd->reserve) (dev); /* Return sense information */ goto sense; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ sense: /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xA4: /*---------------------------------------------------------------*/ /* READ AND RESET BUFFERED LOG */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < 24) ? count : 24; *residual = count - num; if (count < 24) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memset (iobuf, 0, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } /* end switch(code) */ } /* end function fbadasd_execute_ccw */ /*-------------------------------------------------------------------*/ /* Read Standard Block (used by Diagnose instructions) */ /*-------------------------------------------------------------------*/ DLL_EXPORT void fbadasd_read_block ( DEVBLK *dev, int blknum, int blksize, int blkfactor, BYTE *iobuf, BYTE *unitstat, U16 *residual ) { int rc; /* Return code */ int sector; /* First sector being read */ /* Unit check if block number is invalid */ sector = blknum * blkfactor; if (sector >= dev->fbanumblk) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* Seek to start of desired block */ dev->fbarba = ( dev->fbaorigin + sector ) * dev->fbablksiz; /* Read block into I/O buffer */ rc = fba_read (dev, iobuf, blksize, unitstat); if (rc < blksize) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* Return unit status and residual byte count */ *unitstat = CSW_CE | CSW_DE; *residual = 0; } /* end function fbadasd_read_block */ /*-------------------------------------------------------------------*/ /* Write Standard Block (used by Diagnose instructions) */ /*-------------------------------------------------------------------*/ DLL_EXPORT void fbadasd_write_block ( DEVBLK *dev, int blknum, int blksize, int blkfactor, BYTE *iobuf, BYTE *unitstat, U16 *residual ) { int rc; /* Return code from write function */ int sector; /* First sector being read */ #if 0 U64 rba; /* Large file size offset */ #endif /* Unit check if block number is invalid */ sector = blknum * blkfactor; if (sector >= dev->fbanumblk || sector < 0 ) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* Seek to start of desired block */ dev->fbarba = (off_t)(( dev->fbaorigin + sector ) * dev->fbablksiz); /* Read block into I/O buffer */ rc = fba_write (dev, iobuf, blksize, unitstat); if (rc < blksize) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* Return unit status and residual byte count */ *unitstat = CSW_CE | CSW_DE; *residual = 0; } /* end function fbadasd_write_block */ /* Deprecated: Will be replaced by fbadasd_read/write_block functions */ /*-------------------------------------------------------------------*/ /* Synchronous Fixed Block I/O (used by Diagnose instruction) */ /*-------------------------------------------------------------------*/ DLL_EXPORT void fbadasd_syncblk_io ( DEVBLK *dev, BYTE type, int blknum, int blksize, BYTE *iobuf, BYTE *unitstat, U16 *residual ) { int rc; /* Return code */ int blkfactor; /* Number of device blocks per logical block */ /* Calculate the blocking factor */ blkfactor = blksize / dev->fbablksiz; /* Unit check if block number is invalid */ if (blknum * blkfactor >= dev->fbanumblk) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; return; } /* Seek to start of desired block */ dev->fbarba = dev->fbaorigin * dev->fbablksiz; /* Process depending on operation type */ switch (type) { case 0x01: /* Write block from I/O buffer */ rc = fba_write (dev, iobuf, blksize, unitstat); if (rc < blksize) return; break; case 0x02: /* Read block into I/O buffer */ rc = fba_read (dev, iobuf, blksize, unitstat); if (rc < blksize) return; break; } /* end switch(type) */ /* Return unit status and residual byte count */ *unitstat = CSW_CE | CSW_DE; *residual = 0; } /* end function fbadasd_syncblk_io */ /*-------------------------------------------------------------------*/ /* Hercules suspend/resume text unit key values */ /*-------------------------------------------------------------------*/ #define SR_DEV_FBA_BUFCUR ( SR_DEV_FBA | 0x001 ) #define SR_DEV_FBA_BUFOFF ( SR_DEV_FBA | 0x002 ) #define SR_DEV_FBA_ORIGIN ( SR_DEV_FBA | 0x003 ) #define SR_DEV_FBA_NUMBLK ( SR_DEV_FBA | 0x004 ) #define SR_DEV_FBA_RBA ( SR_DEV_FBA | 0x005 ) #define SR_DEV_FBA_END ( SR_DEV_FBA | 0x006 ) #define SR_DEV_FBA_DXBLKN ( SR_DEV_FBA | 0x007 ) #define SR_DEV_FBA_DXFIRST ( SR_DEV_FBA | 0x008 ) #define SR_DEV_FBA_DXLAST ( SR_DEV_FBA | 0x009 ) #define SR_DEV_FBA_LCBLK ( SR_DEV_FBA | 0x00a ) #define SR_DEV_FBA_LCNUM ( SR_DEV_FBA | 0x00b ) #define SR_DEV_FBA_BLKSIZ ( SR_DEV_FBA | 0x00c ) #define SR_DEV_FBA_XTDEF ( SR_DEV_FBA | 0x00d ) #define SR_DEV_FBA_OPER ( SR_DEV_FBA | 0x00e ) #define SR_DEV_FBA_MASK ( SR_DEV_FBA | 0x00f ) /*-------------------------------------------------------------------*/ /* Hercules suspend */ /*-------------------------------------------------------------------*/ int fbadasd_hsuspend(DEVBLK *dev, void *file) { if (dev->bufcur >= 0) { SR_WRITE_VALUE(file, SR_DEV_FBA_BUFCUR, dev->bufcur, sizeof(dev->bufcur)); SR_WRITE_VALUE(file, SR_DEV_FBA_BUFOFF, dev->bufoff, sizeof(dev->bufoff)); } SR_WRITE_VALUE(file, SR_DEV_FBA_ORIGIN, dev->fbaorigin, sizeof(dev->fbaorigin)); SR_WRITE_VALUE(file, SR_DEV_FBA_NUMBLK, dev->fbanumblk, sizeof(dev->fbanumblk)); SR_WRITE_VALUE(file, SR_DEV_FBA_RBA, dev->fbarba, sizeof(dev->fbarba)); SR_WRITE_VALUE(file, SR_DEV_FBA_END, dev->fbaend, sizeof(dev->fbaend)); SR_WRITE_VALUE(file, SR_DEV_FBA_DXBLKN, dev->fbaxblkn, sizeof(dev->fbaxblkn)); SR_WRITE_VALUE(file, SR_DEV_FBA_DXFIRST, dev->fbaxfirst, sizeof(dev->fbaxfirst)); SR_WRITE_VALUE(file, SR_DEV_FBA_DXLAST, dev->fbaxlast, sizeof(dev->fbaxlast)); SR_WRITE_VALUE(file, SR_DEV_FBA_LCBLK, dev->fbalcblk, sizeof(dev->fbalcblk)); SR_WRITE_VALUE(file, SR_DEV_FBA_LCNUM, dev->fbalcnum, sizeof(dev->fbalcnum)); SR_WRITE_VALUE(file, SR_DEV_FBA_BLKSIZ, dev->fbablksiz, sizeof(dev->fbablksiz)); SR_WRITE_VALUE(file, SR_DEV_FBA_XTDEF, dev->fbaxtdef, 1); SR_WRITE_VALUE(file, SR_DEV_FBA_OPER, dev->fbaoper, sizeof(dev->fbaoper)); SR_WRITE_VALUE(file, SR_DEV_FBA_MASK, dev->fbamask, sizeof(dev->fbamask)); return 0; } /*-------------------------------------------------------------------*/ /* Hercules resume */ /*-------------------------------------------------------------------*/ int fbadasd_hresume(DEVBLK *dev, void *file) { int rc; size_t key, len; BYTE byte; do { SR_READ_HDR(file, key, len); switch (key) { case SR_DEV_FBA_BUFCUR: SR_READ_VALUE(file, len, &rc, sizeof(rc)); rc = (dev->hnd->read) ? (dev->hnd->read)(dev, rc, &byte) : -1; if ((int)rc < 0) return -1; break; case SR_DEV_FBA_BUFOFF: SR_READ_VALUE(file, len, &dev->bufoff, sizeof(dev->bufoff)); break; case SR_DEV_FBA_ORIGIN: SR_READ_VALUE(file, len, &rc, sizeof(rc)); if ((off_t)rc != dev->fbaorigin) { logmsg(_("HHCDA901E %4.4x FBA origin mismatch: %d, expected %d,\n"), rc, dev->fbaorigin); return -1; } break; case SR_DEV_FBA_NUMBLK: SR_READ_VALUE(file, len, &rc, sizeof(rc)); if ((int)rc != dev->fbanumblk) { logmsg(_("HHCDA902E %4.4x FBA numblk mismatch: %d, expected %d,\n"), rc, dev->fbanumblk); return -1; } break; case SR_DEV_FBA_RBA: SR_READ_VALUE(file, len, &dev->fbarba, sizeof(dev->fbarba)); break; case SR_DEV_FBA_END: SR_READ_VALUE(file, len, &dev->fbaend, sizeof(dev->fbaend)); break; case SR_DEV_FBA_DXBLKN: SR_READ_VALUE(file, len, &dev->fbaxblkn, sizeof(dev->fbaxblkn)); break; case SR_DEV_FBA_DXFIRST: SR_READ_VALUE(file, len, &dev->fbaxfirst, sizeof(dev->fbaxfirst)); break; case SR_DEV_FBA_DXLAST: SR_READ_VALUE(file, len, &dev->fbaxlast, sizeof(dev->fbaxlast)); break; case SR_DEV_FBA_LCBLK: SR_READ_VALUE(file, len, &dev->fbalcblk, sizeof(dev->fbalcblk)); break; case SR_DEV_FBA_LCNUM: SR_READ_VALUE(file, len, &dev->fbalcnum, sizeof(dev->fbalcnum)); break; case SR_DEV_FBA_BLKSIZ: SR_READ_VALUE(file, len, &rc, sizeof(rc)); if ((int)rc != dev->fbablksiz) { logmsg(_("HHCDA903E %4.4x FBA blksiz mismatch: %d, expected %d,\n"), rc, dev->fbablksiz); return -1; } break; case SR_DEV_FBA_XTDEF: SR_READ_VALUE(file, len, &rc, sizeof(rc)); dev->fbaxtdef = rc; break; case SR_DEV_FBA_OPER: SR_READ_VALUE(file, len, &dev->fbaoper, sizeof(dev->fbaoper)); break; case SR_DEV_FBA_MASK: SR_READ_VALUE(file, len, &dev->fbamask, sizeof(dev->fbamask)); break; default: SR_READ_SKIP(file, len); break; } /* switch (key) */ } while ((key & SR_DEV_MASK) == SR_DEV_FBA); return 0; } DLL_EXPORT DEVHND fbadasd_device_hndinfo = { &fbadasd_init_handler, /* Device Initialisation */ &fbadasd_execute_ccw, /* Device CCW execute */ &fbadasd_close_device, /* Device Close */ &fbadasd_query_device, /* Device Query */ NULL, /* Device Start channel pgm */ &fbadasd_end, /* Device End channel pgm */ NULL, /* Device Resume channel pgm */ &fbadasd_end, /* Device Suspend channel pgm */ &fbadasd_read_blkgrp, /* Device Read */ &fbadasd_update_blkgrp, /* Device Write */ &fbadasd_used, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Ouput */ &fbadasd_hsuspend, /* Hercules suspend */ &fbadasd_hresume /* Hercules resume */ }; hercules-3.12/cckddasd.c0000664000175000017500000061255312564723224012123 00000000000000/* CCKDDASD.C (c) Copyright Greg Smith, 2000-2009 */ /* Compressed CKD Direct Access Storage Device Handler */ /*-------------------------------------------------------------------*/ /* This module contains device functions for compressed emulated */ /* count-key-data direct access storage devices. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _CCKDDASD_C_ #define _HDASD_DLL_ #include "hercules.h" #include "devtype.h" #include "opcode.h" /*-------------------------------------------------------------------*/ /* Internal functions */ /*-------------------------------------------------------------------*/ int cckddasd_init(int argc, BYTE *argv[]); int cckddasd_term(); int cckddasd_init_handler( DEVBLK *dev, int argc, char *argv[] ); int cckddasd_close_device(DEVBLK *dev); void cckddasd_start(DEVBLK *dev); void cckddasd_end(DEVBLK *dev); int cckd_open (DEVBLK *dev, int sfx, int flags, mode_t mode); int cckd_close (DEVBLK *dev, int sfx); int cckd_read (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len); int cckd_write (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len); int cckd_ftruncate(DEVBLK *dev, int sfx, off_t off); void *cckd_malloc(DEVBLK *dev, char *id, size_t size); void *cckd_calloc(DEVBLK *dev, char *id, size_t n, size_t size); void *cckd_free(DEVBLK *dev, char *id,void *p); int cckd_read_track(DEVBLK *dev, int trk, BYTE *unitstat); int cckd_update_track(DEVBLK *dev, int trk, int off, BYTE *buf, int len, BYTE *unitstat); int cckd_used(DEVBLK *dev); int cfba_read_block(DEVBLK *dev, int blkgrp, BYTE *unitstat); int cfba_write_block(DEVBLK *dev, int blkgrp, int off, BYTE *buf, int wrlen, BYTE *unitstat); int cfba_used(DEVBLK *dev); int cckd_read_trk(DEVBLK *dev, int trk, int ra, BYTE *unitstat); void cckd_readahead(DEVBLK *dev, int trk); int cckd_readahead_scan(int *answer, int ix, int i, void *data); void cckd_ra(); void cckd_flush_cache(DEVBLK *dev); int cckd_flush_cache_scan(int *answer, int ix, int i, void *data); void cckd_flush_cache_all(); void cckd_purge_cache(DEVBLK *dev); int cckd_purge_cache_scan(int *answer, int ix, int i, void *data); void cckd_writer(void *arg); int cckd_writer_scan(int *o, int ix, int i, void *data); off_t cckd_get_space(DEVBLK *dev, int *size, int flags); void cckd_rel_space(DEVBLK *dev, off_t pos, int len, int size); void cckd_flush_space(DEVBLK *dev); int cckd_read_chdr(DEVBLK *dev); int cckd_write_chdr(DEVBLK *dev); int cckd_read_l1(DEVBLK *dev); int cckd_write_l1(DEVBLK *dev); int cckd_write_l1ent(DEVBLK *dev, int l1x); int cckd_read_init(DEVBLK *dev); int cckd_read_fsp(DEVBLK *dev); int cckd_write_fsp(DEVBLK *dev); int cckd_read_l2(DEVBLK *dev, int sfx, int l1x); void cckd_purge_l2(DEVBLK *dev); int cckd_purge_l2_scan(int *answer, int ix, int i, void *data); int cckd_steal_l2(); int cckd_steal_l2_scan(int *answer, int ix, int i, void *data); int cckd_write_l2(DEVBLK *dev); int cckd_read_l2ent(DEVBLK *dev, CCKD_L2ENT *l2, int trk); int cckd_write_l2ent(DEVBLK *dev, CCKD_L2ENT *l2, int trk); int cckd_read_trkimg(DEVBLK *dev, BYTE *buf, int trk, BYTE *unitstat); int cckd_write_trkimg(DEVBLK *dev, BYTE *buf, int len, int trk, int flags); int cckd_harden(DEVBLK *dev); int cckd_trklen(DEVBLK *dev, BYTE *buf); int cckd_null_trk(DEVBLK *dev, BYTE *buf, int trk, int nullfmt); int cckd_check_null_trk (DEVBLK *dev, BYTE *buf, int trk, int len); int cckd_cchh(DEVBLK *dev, BYTE *buf, int trk); int cckd_validate(DEVBLK *dev, BYTE *buf, int trk, int len); char *cckd_sf_name(DEVBLK *dev, int sfx); int cckd_sf_init(DEVBLK *dev); int cckd_sf_new(DEVBLK *dev); DLL_EXPORT void *cckd_sf_add(void *data); DLL_EXPORT void *cckd_sf_remove(void *data); DLL_EXPORT void *cckd_sf_comp(void *data); DLL_EXPORT void *cckd_sf_chk(void *data); DLL_EXPORT void *cckd_sf_stats(void *data); int cckd_disable_syncio(DEVBLK *dev); void cckd_lock_devchain(int flag); void cckd_unlock_devchain(); void cckd_gcol(); int cckd_gc_percolate(DEVBLK *dev, unsigned int size); int cckd_gc_l2(DEVBLK *dev, BYTE *buf); DEVBLK *cckd_find_device_by_devnum (U16 devnum); BYTE *cckd_uncompress(DEVBLK *dev, BYTE *from, int len, int maxlen, int trk); int cckd_uncompress_zlib(DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen); int cckd_uncompress_bzip2(DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen); int cckd_compress(DEVBLK *dev, BYTE **to, BYTE *from, int len, int comp, int parm); int cckd_compress_none(DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm); int cckd_compress_zlib(DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm); int cckd_compress_bzip2(DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm); void cckd_command_help(); void cckd_command_opts(); void cckd_command_stats(); void cckd_command_debug(); int cckd_command(char *op, int cmd); DLL_EXPORT void cckd_print_itrace(); void cckd_trace(DEVBLK *dev, char *msg, ...); /*-------------------------------------------------------------------*/ /* Definitions for sense data format codes and message codes */ /*-------------------------------------------------------------------*/ #define FORMAT_0 0 /* Program or System Checks */ #define FORMAT_1 1 /* Device Equipment Checks */ #define FORMAT_2 2 /* 3990 Equipment Checks */ #define FORMAT_3 3 /* 3990 Control Checks */ #define FORMAT_4 4 /* Data Checks */ #define FORMAT_5 5 /* Data Check + Displacement */ #define FORMAT_6 6 /* Usage Stats/Overrun Errors*/ #define FORMAT_7 7 /* Device Control Checks */ #define FORMAT_8 8 /* Device Equipment Checks */ #define FORMAT_9 9 /* Device Rd/Wrt/Seek Checks */ #define FORMAT_F 15 /* Cache Storage Checks */ #define MESSAGE_0 0 /* Message 0 */ #define MESSAGE_1 1 /* Message 1 */ #define MESSAGE_2 2 /* Message 2 */ #define MESSAGE_3 3 /* Message 3 */ #define MESSAGE_4 4 /* Message 4 */ #define MESSAGE_5 5 /* Message 5 */ #define MESSAGE_6 6 /* Message 6 */ #define MESSAGE_7 7 /* Message 7 */ #define MESSAGE_8 8 /* Message 8 */ #define MESSAGE_9 9 /* Message 9 */ #define MESSAGE_A 10 /* Message A */ #define MESSAGE_B 11 /* Message B */ #define MESSAGE_C 12 /* Message C */ #define MESSAGE_D 13 /* Message D */ #define MESSAGE_E 14 /* Message E */ #define MESSAGE_F 15 /* Message F */ /*-------------------------------------------------------------------*/ /* Data areas */ /*-------------------------------------------------------------------*/ static CCKD_L2ENT empty_l2[CKDDASD_NULLTRK_FMTMAX+1][256]; static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; DEVHND cckddasd_device_hndinfo; DEVHND cfbadasd_device_hndinfo; DLL_EXPORT CCKDBLK cckdblk; /* cckd global area */ /*-------------------------------------------------------------------*/ /* CCKD global initialization */ /*-------------------------------------------------------------------*/ int cckddasd_init (int argc, BYTE *argv[]) { int i, j; /* Loop indexes */ UNREFERENCED(argc); UNREFERENCED(argv); if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id)) == 0) return 0; /* Clear the cckdblk */ memset(&cckdblk, 0, sizeof(CCKDBLK)); /* Initialize locks and conditions */ memcpy (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id)); initialize_lock (&cckdblk.gclock); initialize_lock (&cckdblk.ralock); initialize_lock (&cckdblk.wrlock); initialize_lock (&cckdblk.devlock); initialize_condition (&cckdblk.gccond); initialize_condition (&cckdblk.racond); initialize_condition (&cckdblk.wrcond); initialize_condition (&cckdblk.devcond); initialize_condition (&cckdblk.termcond); /* Initialize some variables */ cckdblk.wrprio = 16; cckdblk.ranbr = CCKD_DEFAULT_RA_SIZE; cckdblk.ramax = CCKD_DEFAULT_RA; cckdblk.wrmax = CCKD_DEFAULT_WRITER; cckdblk.gcmax = CCKD_DEFAULT_GCOL; cckdblk.gcwait = CCKD_DEFAULT_GCOLWAIT; cckdblk.gcparm = CCKD_DEFAULT_GCOLPARM; cckdblk.readaheads = CCKD_DEFAULT_READAHEADS; cckdblk.freepend = CCKD_DEFAULT_FREEPEND; #ifdef HAVE_LIBZ cckdblk.comps |= CCKD_COMPRESS_ZLIB; #endif #ifdef CCKD_BZIP2 cckdblk.comps |= CCKD_COMPRESS_BZIP2; #endif cckdblk.comp = 0xff; cckdblk.compparm = -1; /* Initialize the readahead queue */ cckdblk.ra1st = cckdblk.ralast = -1; cckdblk.rafree = 0; for (i = 0; i < cckdblk.ranbr; i++) cckdblk.ra[i].next = i + 1; cckdblk.ra[cckdblk.ranbr - 1].next = -1; /* Clear the empty L2 tables */ for (i = 0; i <= CKDDASD_NULLTRK_FMTMAX; i++) for (j = 0; j < 256; j++) { empty_l2[i][j].pos = 0; empty_l2[i][j].len = empty_l2[i][j].size = i; } return 0; } /* end function cckddasd_init */ /*-------------------------------------------------------------------*/ /* CCKD dasd global termination */ /*-------------------------------------------------------------------*/ int cckddasd_term () { /* Terminate the readahead threads */ obtain_lock (&cckdblk.ralock); cckdblk.ramax = 0; if (cckdblk.ras) { broadcast_condition (&cckdblk.racond); wait_condition (&cckdblk.termcond, &cckdblk.ralock); } release_lock (&cckdblk.ralock); /* Terminate the garbage collection threads */ obtain_lock (&cckdblk.gclock); cckdblk.gcmax = 0; if (cckdblk.gcs) { broadcast_condition (&cckdblk.gccond); wait_condition (&cckdblk.termcond, &cckdblk.gclock); } release_lock (&cckdblk.gclock); /* Terminate the writer threads */ obtain_lock (&cckdblk.wrlock); cckdblk.wrmax = 0; if (cckdblk.wrs) { broadcast_condition (&cckdblk.wrcond); wait_condition (&cckdblk.termcond, &cckdblk.wrlock); } release_lock (&cckdblk.wrlock); memset(&cckdblk, 0, sizeof(CCKDBLK)); return 0; } /* end function cckddasd_term */ /*-------------------------------------------------------------------*/ /* CKD dasd initialization */ /*-------------------------------------------------------------------*/ int cckddasd_init_handler ( DEVBLK *dev, int argc, char *argv[] ) { CCKDDASD_EXT *cckd; /* -> cckd extension */ DEVBLK *dev2; /* -> device in cckd queue */ int i; /* Counter */ int fdflags; /* File flags */ UNREFERENCED(argc); UNREFERENCED(argv); /* Initialize the global cckd block if necessary */ if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id))) cckddasd_init (0, NULL); /* Obtain area for cckd extension */ dev->cckd_ext = cckd = cckd_calloc (dev, "ext", 1, sizeof(CCKDDASD_EXT)); if (cckd == NULL) return -1; /* Initialize locks and conditions */ initialize_lock (&cckd->iolock); initialize_lock (&cckd->filelock); initialize_condition (&cckd->iocond); /* Initialize some variables */ obtain_lock (&cckd->filelock); cckd->l1x = cckd->sfx = cckd->l2active = -1; dev->cache = cckd->free1st = -1; cckd->fd[0] = dev->fd; fdflags = get_file_accmode_flags( dev->fd ); cckd->open[0] = (fdflags & O_RDWR) ? CCKD_OPEN_RW : CCKD_OPEN_RO; for (i = 1; i <= CCKD_MAX_SF; i++) { cckd->fd[i] = -1; cckd->open[i] = CCKD_OPEN_NONE; } cckd->maxsize = sizeof(off_t) > 4 ? 0xffffffffll : 0x7fffffffll; /* call the chkdsk function */ if (cckd_chkdsk (dev, 0) < 0) return -1; /* Perform initial read */ if (cckd_read_init (dev) < 0) return -1; if (cckd->fbadasd) dev->ckdtrksz = CFBA_BLOCK_SIZE; /* open the shadow files */ if (cckd_sf_init (dev) < 0) { logmsg (_("HHCCD101E %4.4X error initializing shadow files\n"), dev->devnum); return -1; } /* Update the device handler routines */ if (cckd->ckddasd) dev->hnd = &cckddasd_device_hndinfo; else dev->hnd = &cfbadasd_device_hndinfo; release_lock (&cckd->filelock); /* Insert the device into the cckd device queue */ cckd_lock_devchain(1); for (cckd = NULL, dev2 = cckdblk.dev1st; dev2; dev2 = cckd->devnext) cckd = dev2->cckd_ext; if (cckd) cckd->devnext = dev; else cckdblk.dev1st = dev; cckd_unlock_devchain(); cckdblk.batch = dev->batch; if (cckdblk.batch) { cckdblk.nostress = 1; cckdblk.freepend = 0; cckdblk.linuxnull = 1; } return 0; } /* end function cckddasd_init_handler */ /*-------------------------------------------------------------------*/ /* Close a Compressed CKD Device */ /*-------------------------------------------------------------------*/ int cckddasd_close_device (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int i; /* Index */ cckd = dev->cckd_ext; /* Wait for readaheads to finish */ obtain_lock(&cckdblk.ralock); cckd->stopping = 1; while (cckd->ras) { release_lock(&cckdblk.ralock); usleep(1); obtain_lock(&cckdblk.ralock); } release_lock(&cckdblk.ralock); /* Flush the cache and wait for the writes to complete */ obtain_lock (&cckd->iolock); cckd->stopping = 1; cckd_flush_cache (dev); while (cckd->wrpending || cckd->ioactive) { cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; cckd_flush_cache (dev); } broadcast_condition (&cckd->iocond); cckd_purge_cache (dev); cckd_purge_l2 (dev); dev->bufcur = dev->cache = -1; if (cckd->newbuf) cckd_free (dev, "newbuf", cckd->newbuf); release_lock (&cckd->iolock); /* Remove the device from the cckd queue */ cckd_lock_devchain(1); if (dev == cckdblk.dev1st) cckdblk.dev1st = cckd->devnext; else { DEVBLK *dev2 = cckdblk.dev1st; CCKDDASD_EXT *cckd2 = dev2->cckd_ext; while (cckd2->devnext != dev) { dev2 = cckd2->devnext; cckd2 = dev2->cckd_ext; } cckd2->devnext = cckd->devnext; } cckd_unlock_devchain(); /* harden the file */ obtain_lock (&cckd->filelock); cckd_harden (dev); /* close the shadow files */ for (i = 1; i <= cckd->sfn; i++) { cckd_close (dev, i); cckd->open[i] = 0; } /* free the level 1 tables */ for (i = 0; i <= cckd->sfn; i++) cckd->l1[i] = cckd_free (dev, "l1", cckd->l1[i]); /* reset the device handler */ if (cckd->ckddasd) dev->hnd = &ckddasd_device_hndinfo; else dev->hnd = &fbadasd_device_hndinfo; /* write some statistics */ if (!dev->batch) cckd_sf_stats (dev); release_lock (&cckd->filelock); /* free the cckd extension */ dev->cckd_ext= cckd_free (dev, "ext", cckd); if (dev->dasdsfn) free (dev->dasdsfn); dev->dasdsfn = NULL; close (dev->fd); dev->fd = -1; /* If no more devices then perform global termination */ if (cckdblk.dev1st == NULL) cckddasd_term (); return 0; } /* end function cckddasd_close_device */ /*-------------------------------------------------------------------*/ /* Compressed ckd start/resume channel program */ /*-------------------------------------------------------------------*/ void cckddasd_start (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ U16 devnum = 0; /* Last active device number */ int trk = 0; /* Last active track */ cckd = dev->cckd_ext; cckd_trace (dev, "start i/o file[%d] bufcur %d cache[%d]\n", cckd->sfn, dev->bufcur, dev->cache); /* Reset buffer offsets */ dev->bufoff = 0; dev->bufoffhi = cckd->ckddasd ? dev->ckdtrksz : CFBA_BLOCK_SIZE; /* Check for merge - synchronous i/o should be disabled */ obtain_lock(&cckd->iolock); if (cckd->merging) { cckd_trace (dev, "start i/o waiting for merge%s\n",""); while (cckd->merging) { cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; } dev->bufcur = dev->cache = -1; } cckd->ioactive = 1; cache_lock(CACHE_DEVBUF); if (dev->cache >= 0) CCKD_CACHE_GETKEY(dev->cache, devnum, trk); /* Check if previous active entry is still valid and not busy */ if (dev->cache >= 0 && dev->devnum == devnum && dev->bufcur == trk && !(cache_getflag(CACHE_DEVBUF, dev->cache) & CCKD_CACHE_IOBUSY)) { /* Make the entry active again */ cache_setflag (CACHE_DEVBUF, dev->cache, ~0, CCKD_CACHE_ACTIVE); /* If the entry is pending write then change it to `updated' */ if (cache_getflag(CACHE_DEVBUF, dev->cache) & CCKD_CACHE_WRITE) { cache_setflag (CACHE_DEVBUF, dev->cache, ~CCKD_CACHE_WRITE, CCKD_CACHE_UPDATED); cckd->wrpending--; if (cckd->iowaiters && !cckd->wrpending) broadcast_condition (&cckd->iocond); } } else dev->bufcur = dev->cache = -1; cache_unlock (CACHE_DEVBUF); release_lock (&cckd->iolock); return; } /* end function cckddasd_start */ /*-------------------------------------------------------------------*/ /* Compressed ckd end/suspend channel program */ /*-------------------------------------------------------------------*/ void cckddasd_end (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ cckd = dev->cckd_ext; /* Update length if previous image was updated */ if (dev->bufupd && dev->bufcur >= 0 && dev->cache >= 0) { dev->buflen = cckd_trklen (dev, dev->buf); cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen); } dev->bufupd = 0; cckd_trace (dev, "end i/o bufcur %d cache[%d] waiters %d\n", dev->bufcur, dev->cache, cckd->iowaiters); obtain_lock (&cckd->iolock); cckd->ioactive = 0; /* Make the current entry inactive */ if (dev->cache >= 0) { cache_lock (CACHE_DEVBUF); cache_setflag (CACHE_DEVBUF, dev->cache, ~CCKD_CACHE_ACTIVE, 0); cache_unlock (CACHE_DEVBUF); } /* Cause writers to start after first update */ if (cckd->updated && (cckdblk.wrs == 0 || cckd->iowaiters != 0)) cckd_flush_cache (dev); else if (cckd->iowaiters) broadcast_condition (&cckd->iocond); release_lock (&cckd->iolock); } /* end function cckddasd_end */ /*-------------------------------------------------------------------*/ /* Open a cckd file */ /* */ /* If O_CREAT is not set and mode is non-zero then the error message */ /* will be supressed. */ /*-------------------------------------------------------------------*/ int cckd_open (DEVBLK *dev, int sfx, int flags, mode_t mode) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int err; /* 1 = issue error message */ char pathname[MAX_PATH]; /* file path in host format */ cckd = dev->cckd_ext; err = !((flags & O_CREAT) == 0 && mode != 0); if (cckd->fd[sfx] >= 0) cckd_close (dev, sfx); hostpath(pathname, cckd_sf_name (dev, sfx), sizeof(pathname)); cckd->fd[sfx] = hopen(pathname, flags, mode); if (sfx == 0) dev->fd = cckd->fd[sfx]; if (cckd->fd[sfx] >= 0) cckd->open[sfx] = flags & O_RDWR ? CCKD_OPEN_RW : cckd->open[sfx] == CCKD_OPEN_RW ? CCKD_OPEN_RD : CCKD_OPEN_RO; else { if (err) { logmsg (_("HHCCD130E %4.4X file[%d] %s open error: %s\n"), dev->devnum, sfx, cckd_sf_name (dev, sfx), strerror(errno)); cckd_trace (dev, "file[%d] fd[%d] open %s error flags %8.8x mode %8.8x\n", sfx, cckd->fd[sfx], cckd_sf_name (dev, sfx), flags, mode); cckd_print_itrace (); } cckd->open[sfx] = CCKD_OPEN_NONE; } cckd_trace (dev, "file[%d] fd[%d] open %s, flags %8.8x mode %8.8x\n", sfx, cckd->fd[sfx], cckd_sf_name (dev, sfx), flags, mode); return cckd->fd[sfx]; } /* end function cckd_open */ /*-------------------------------------------------------------------*/ /* Close a cckd file */ /*-------------------------------------------------------------------*/ int cckd_close (DEVBLK *dev, int sfx) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc = 0; /* Return code */ cckd = dev->cckd_ext; cckd_trace (dev, "file[%d] fd[%d] close %s\n", sfx, cckd->fd[sfx], cckd_sf_name(dev, sfx)); if (cckd->fd[sfx] >= 0) rc = close (cckd->fd[sfx]); if (rc < 0) { logmsg (_("HHCCD130E %4.4X file[%d] close error: %s\n"), dev->devnum, sfx, strerror(errno)); cckd_print_itrace (); } cckd->fd[sfx] = -1; if (sfx == 0) dev->fd = -1; return rc; } /* end function cckd_close */ /*-------------------------------------------------------------------*/ /* Read from a cckd file */ /*-------------------------------------------------------------------*/ int cckd_read (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ cckd = dev->cckd_ext; cckd_trace (dev, "file[%d] fd[%d] read, off 0x%" I64_FMT "x len %ld\n", sfx, cckd->fd[sfx], (long long)off, (long)len); /* Seek to specified offset */ if (lseek (cckd->fd[sfx], off, SEEK_SET) < 0) { logmsg (_("HHCCD130E %4.4X file[%d] lseek error, offset 0x%" I64_FMT "x: %s\n"), dev->devnum, sfx, (long long)off, strerror(errno)); cckd_print_itrace (); return -1; } /* Read the data */ rc = read (cckd->fd[sfx], buf, len); if (rc < (int)len) { if (rc < 0) logmsg (_("HHCCD130E %4.4X file[%d] read error, offset 0x%" I64_FMT "x: %s\n"), dev->devnum, sfx, (long long)off, strerror(errno)); else logmsg (_("HHCCD130E %4.4X file[%d] read incomplete, offset 0x%" I64_FMT "x: " "read %d expected %d\n"), dev->devnum, sfx, (long long)off, rc, len); cckd_print_itrace (); return -1; } return rc; } /* end function cckd_read */ /*-------------------------------------------------------------------*/ /* Write to a cckd file */ /*-------------------------------------------------------------------*/ int cckd_write (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc = 0; /* Return code */ cckd = dev->cckd_ext; cckd_trace (dev, "file[%d] fd[%d] write, off 0x%" I64_FMT "x len %ld\n", sfx, cckd->fd[sfx], (long long)off, (long)len); /* Seek to specified offset */ if (lseek (cckd->fd[sfx], off, SEEK_SET) < 0) { logmsg (_("HHCCD130E %4.4X file[%d] lseek error, offset 0x%" I64_FMT "x: %s\n"), dev->devnum, sfx, (long long)off, strerror(errno)); return -1; } /* Write the data */ rc = write (cckd->fd[sfx], buf, len); if (rc < (int)len) { if (rc < 0) logmsg (_("HHCCD130E %4.4X file[%d] write error, offset 0x%" I64_FMT "x: %s\n"), dev->devnum, sfx, (long long)off, strerror(errno)); else logmsg (_("HHCCD130E %4.4X file[%d] write incomplete, offset 0x%" I64_FMT "x: " "wrote %d expected %d\n"), dev->devnum, sfx, (long long)off, rc, len); cckd_print_itrace (); return -1; } return rc; } /* end function cckd_write */ /*-------------------------------------------------------------------*/ /* Truncate a cckd file */ /*-------------------------------------------------------------------*/ int cckd_ftruncate(DEVBLK *dev, int sfx, off_t off) { CCKDDASD_EXT *cckd; /* -> cckd extension */ cckd = dev->cckd_ext; cckd_trace (dev, "file[%d] fd[%d] ftruncate, off 0x%" I64_FMT "x\n", sfx, cckd->fd[sfx], (long long)off); /* Truncate the file */ if (ftruncate (cckd->fd[sfx], off) < 0) { logmsg (_("HHCCD130E %4.4X file[%d] ftruncate error, offset 0x%" I64_FMT "x: %s\n"), dev->devnum, sfx, (long long)off, strerror(errno)); cckd_print_itrace (); return -1; } return 0; } /* end function cckd_ftruncate */ /*-------------------------------------------------------------------*/ /* malloc */ /*-------------------------------------------------------------------*/ void *cckd_malloc (DEVBLK *dev, char *id, size_t size) { void *p; /* Pointer */ p = malloc (size); cckd_trace (dev, "%s malloc %p len %ld\n", id, p, (long)size); if (p == NULL) { logmsg (_("HHCCD130E %4.4X malloc error, size %d: %s\n"), dev ? dev->devnum : 0, size, strerror(errno)); cckd_print_itrace (); } return p; } /* end function cckd_malloc */ /*-------------------------------------------------------------------*/ /* calloc */ /*-------------------------------------------------------------------*/ void *cckd_calloc (DEVBLK *dev, char *id, size_t n, size_t size) { void *p; /* Pointer */ p = calloc (n, size); cckd_trace (dev, "%s calloc %p len %ld\n", id, p, n*(long)size); if (p == NULL) { logmsg (_("HHCCD130E %4.4X calloc error, size %d: %s\n"), dev ? dev->devnum : 0, n*size, strerror(errno)); cckd_print_itrace (); } return p; } /* end function cckd_calloc */ /*-------------------------------------------------------------------*/ /* free */ /*-------------------------------------------------------------------*/ void *cckd_free (DEVBLK *dev, char *id, void *p) { cckd_trace (dev, "%s free %p\n", id, p); if (p) free (p); return NULL; } /* end function cckd_free */ /*-------------------------------------------------------------------*/ /* Compressed ckd read track image */ /*-------------------------------------------------------------------*/ int cckd_read_track (DEVBLK *dev, int trk, BYTE *unitstat) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ int len; /* Compressed length */ BYTE *newbuf; /* Uncompressed buffer */ int cache; /* New active cache entry */ int syncio; /* Syncio indicator */ cckd = dev->cckd_ext; /* Update length if previous image was updated */ if (dev->bufupd && dev->bufcur >= 0 && dev->cache >= 0) { dev->buflen = cckd_trklen (dev, dev->buf); cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen); } /* Turn off the synchronous I/O bit if trk overflow or trk 0 */ syncio = dev->syncio_active; if (dev->ckdtrkof || trk == 0) dev->syncio_active = 0; /* Reset buffer offsets */ dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; /* Check if reading the same track image */ if (trk == dev->bufcur && dev->cache >= 0) { /* Track image may be compressed */ if ((dev->buf[0] & CCKD_COMPRESS_MASK) != 0 && (dev->buf[0] & dev->comps) == 0) { #if 0 /* Return if synchronous i/o */ if (dev->syncio_active) { cckd_trace (dev, "read trk %d syncio compressed\n", trk); cckdblk.stats_synciomisses++; dev->syncio_retry = 1; return -1; } #endif len = cache_getval(CACHE_DEVBUF, dev->cache); newbuf = cckd_uncompress (dev, dev->buf, len, dev->ckdtrksz, trk); if (newbuf == NULL) { ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->bufcur = dev->cache = -1; dev->syncio_active = syncio; return -1; } cache_setbuf (CACHE_DEVBUF, dev->cache, newbuf, dev->ckdtrksz); dev->buf = newbuf; dev->buflen = cckd_trklen (dev, newbuf); cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen); dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache); dev->bufupd = 0; cckd_trace (dev, "read trk %d uncompressed len %d\n", trk, dev->buflen); } dev->comp = dev->buf[0] & CCKD_COMPRESS_MASK; if (dev->comp != 0) dev->compoff = CKDDASD_TRKHDR_SIZE; return 0; } cckd_trace (dev, "read trk %d (%s)\n", trk, dev->syncio_active ? "synchronous" : "asynchronous"); /* read the new track */ dev->bufupd = 0; *unitstat = 0; cache = cckd_read_trk (dev, trk, 0, unitstat); if (cache < 0) { dev->bufcur = dev->cache = -1; return -1; } dev->cache = cache; dev->buf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0); dev->bufcur = trk; dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; dev->buflen = cache_getval (CACHE_DEVBUF, dev->cache); dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache); dev->comp = dev->buf[0] & CCKD_COMPRESS_MASK; if (dev->comp != 0) dev->compoff = CKDDASD_TRKHDR_SIZE; /* If the image is compressed then call ourself recursively to cause the image to get uncompressed */ if (dev->comp != 0 && (dev->comp & dev->comps) == 0) rc = cckd_read_track (dev, trk, unitstat); else rc = 0; dev->syncio_active = syncio; return rc; } /* end function cckd_read_track */ /*-------------------------------------------------------------------*/ /* Compressed ckd update track image */ /*-------------------------------------------------------------------*/ int cckd_update_track (DEVBLK *dev, int trk, int off, BYTE *buf, int len, BYTE *unitstat) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ cckd = dev->cckd_ext; /* Error if opened read-only */ if (dev->ckdrdonly && cckd->sfn == 0) { ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0,FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->bufcur = dev->cache = -1; return -1; } /* If the track is not current or compressed then read it. `dev->comps' is set to zero forcing the read routine to uncompress the image. */ if (trk != dev->bufcur || (dev->buf[0] & CCKD_COMPRESS_MASK) != 0) { dev->comps = 0; rc = (dev->hnd->read) (dev, trk, unitstat); if (rc < 0) { dev->bufcur = dev->cache = -1; return -1; } } /* Invalid track format if going past buffer end */ if (off + len > dev->ckdtrksz) { ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->bufcur = dev->cache = -1; return -1; } /* Copy the data into the buffer */ if (buf && len > 0) memcpy (dev->buf + off, buf, len); cckd_trace (dev, "updt trk %d offset %d length %d\n", trk, off, len); /* Update the cache entry */ cache_setflag (CACHE_DEVBUF, dev->cache, ~0, CCKD_CACHE_UPDATED | CCKD_CACHE_USED); cckd->updated = 1; /* Notify the shared server of the update */ if (!dev->bufupd) { dev->bufupd = 1; shared_update_notify (dev, trk); } return len; } /* end function cckd_update_track */ /*-------------------------------------------------------------------*/ /* Return used cylinders */ /*-------------------------------------------------------------------*/ int cckd_used (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ int l1x, l2x; /* Lookup table indexes */ int sfx; /* Shadow file suffix */ CCKD_L2ENT l2; /* Copied level 2 entry */ cckd = dev->cckd_ext; obtain_lock (&cckd->filelock); /* Find the last used level 1 table entry */ for (l1x = cckd->cdevhdr[0].numl1tab - 1; l1x > 0; l1x--) { sfx = cckd->sfn; while (cckd->l1[sfx][l1x] == 0xffffffff && sfx > 0) sfx--; if (cckd->l1[sfx][l1x]) break; } /* Find the last used level 2 table entry */ for (l2x = 255; l2x >= 0; l2x--) { rc = cckd_read_l2ent (dev, &l2, l1x * 256 + l2x); if (rc < 0 || l2.pos != 0) break; } release_lock (&cckd->filelock); return (l1x * 256 + l2x + dev->ckdheads) / dev->ckdheads; } /*-------------------------------------------------------------------*/ /* Compressed fba read block(s) */ /*-------------------------------------------------------------------*/ int cfba_read_block (DEVBLK *dev, int blkgrp, BYTE *unitstat) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ int cache; /* New active cache entry */ BYTE *cbuf; /* -> cache buffer */ BYTE *newbuf; /* Uncompressed buffer */ int len; /* Compressed length */ int maxlen; /* Size for cache entry */ cckd = dev->cckd_ext; if (dev->cache >= 0) cbuf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0); else cbuf = NULL; maxlen = CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE; /* Return if reading the same track image */ if (blkgrp == dev->bufcur && dev->cache >= 0) { /* Block group image may be compressed */ if ((cbuf[0] & CCKD_COMPRESS_MASK) != 0 && (cbuf[0] & dev->comps) == 0) { #if 0 /* Return if synchronous i/o */ if (dev->syncio_active) { cckd_trace (dev, "read blkgrp %d syncio compressed\n", blkgrp); cckdblk.stats_synciomisses++; dev->syncio_retry = 1; return -1; } #endif len = cache_getval(CACHE_DEVBUF, dev->cache) + CKDDASD_TRKHDR_SIZE; newbuf = cckd_uncompress (dev, cbuf, len, maxlen, blkgrp); if (newbuf == NULL) { dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->bufcur = dev->cache = -1; return -1; } cache_setbuf (CACHE_DEVBUF, dev->cache, newbuf, maxlen); cbuf = newbuf; dev->buf = newbuf + CKDDASD_TRKHDR_SIZE; dev->buflen = CFBA_BLOCK_SIZE; cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen); dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache); dev->bufupd = 0; cckd_trace (dev, "read bkgrp %d uncompressed len %d\n", blkgrp, dev->buflen); } dev->comp = cbuf[0] & CCKD_COMPRESS_MASK; return 0; } cckd_trace (dev, "read blkgrp %d (%s)\n", blkgrp, dev->syncio_active ? "synchronous" : "asynchronous"); /* Read the new blkgrp */ dev->bufupd = 0; *unitstat = 0; cache = cckd_read_trk (dev, blkgrp, 0, unitstat); if (cache < 0) { dev->bufcur = dev->cache = -1; return -1; } dev->cache = cache; cbuf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0); dev->buf = cbuf + CKDDASD_TRKHDR_SIZE; dev->bufcur = blkgrp; dev->bufoff = 0; dev->bufoffhi = CFBA_BLOCK_SIZE; dev->buflen = CFBA_BLOCK_SIZE; cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen); dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache); dev->comp = cbuf[0] & CCKD_COMPRESS_MASK; /* If the image is compressed then call ourself recursively to cause the image to get uncompressed. This is because `bufcur' will match blkgrp and `comps' won't match `comp' */ if (dev->comp != 0 && (dev->comp & dev->comps) == 0) rc = cfba_read_block (dev, blkgrp, unitstat); else rc = 0; return rc; } /* end function cfba_read_block */ /*-------------------------------------------------------------------*/ /* Compressed fba write block(s) */ /*-------------------------------------------------------------------*/ int cfba_write_block (DEVBLK *dev, int blkgrp, int off, BYTE *buf, int len, BYTE *unitstat) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ BYTE *cbuf; /* -> cache buffer */ cckd = dev->cckd_ext; if (dev->cache >= 0) cbuf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0); else cbuf = NULL; /* Read the block group if it's not current or compressed. `dev->comps' is set to zero forcing the read routine to uncompress the image. */ if (blkgrp != dev->bufcur || (cbuf[0] & CCKD_COMPRESS_MASK) != 0) { dev->comps = 0; rc = (dev->hnd->read) (dev, blkgrp, unitstat); if (rc < 0) { dev->bufcur = dev->cache = -1; return -1; } } /* Copy the data into the buffer */ if (buf) memcpy (dev->buf + off, buf, len); /* Update the cache entry */ cache_setflag (CACHE_DEVBUF, dev->cache, ~0, CCKD_CACHE_UPDATED|CCKD_CACHE_USED); cckd->updated = 1; /* Notify the shared server of the update */ if (!dev->bufupd) { dev->bufupd = 1; shared_update_notify (dev, blkgrp); } return len; } /* end function cfba_write_block */ /*-------------------------------------------------------------------*/ /* Return used blocks */ /*-------------------------------------------------------------------*/ int cfba_used (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ int l1x, l2x; /* Lookup table indexes */ int sfx; /* Shadow file suffix */ CCKD_L2ENT l2; /* Copied level 2 entry */ cckd = dev->cckd_ext; obtain_lock (&cckd->filelock); /* Find the last used level 1 table entry */ for (l1x = cckd->cdevhdr[0].numl1tab - 1; l1x > 0; l1x--) { sfx = cckd->sfn; while (cckd->l1[sfx][l1x] == 0xffffffff && sfx > 0) sfx--; if (cckd->l1[sfx][l1x]) break; } /* Find the last used level 2 table entry */ for (l2x = 255; l2x >= 0; l2x--) { rc = cckd_read_l2ent (dev, &l2, l1x * 256 + l2x); if (rc < 0 || l2.pos != 0) break; } release_lock (&cckd->filelock); return (l1x * 256 + l2x + CFBA_BLOCK_NUM) / CFBA_BLOCK_NUM; } /*-------------------------------------------------------------------*/ /* Read a track image */ /* */ /* This routine can be called by the i/o thread (`ra' == 0) or */ /* by readahead threads (0 < `ra' <= cckdblk.ramax). */ /* */ /*-------------------------------------------------------------------*/ int cckd_read_trk(DEVBLK *dev, int trk, int ra, BYTE *unitstat) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int fnd; /* Cache index for hit */ int lru; /* Oldest unused cache index */ int len; /* Length of track image */ int maxlen; /* Length for buffer */ int curtrk = -1; /* Current track (at entry) */ U16 devnum; /* Device number */ U32 oldtrk; /* Stolen track number */ U32 flag; /* Cache flag */ BYTE *buf; /* Read buffer */ cckd = dev->cckd_ext; cckd_trace (dev, "%d rdtrk %d\n", ra, trk); maxlen = cckd->ckddasd ? dev->ckdtrksz : CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE; if (!ra) obtain_lock (&cckd->iolock); cache_lock (CACHE_DEVBUF); /* Inactivate the old entry */ if (!ra) { curtrk = dev->bufcur; if (dev->cache >= 0) cache_setflag(CACHE_DEVBUF, dev->cache, ~CCKD_CACHE_ACTIVE, 0); dev->bufcur = dev->cache = -1; } cckd_read_trk_retry: /* scan the cache array for the track */ fnd = cache_lookup (CACHE_DEVBUF, CCKD_CACHE_SETKEY(dev->devnum, trk), &lru); /* check for cache hit */ if (fnd >= 0) { if (ra) /* readahead doesn't care about a cache hit */ { cache_unlock (CACHE_DEVBUF); return fnd; } /* If synchronous I/O and I/O is active then return with syncio_retry bit on */ if (dev->syncio_active) { if (cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_IOBUSY) { cckd_trace (dev, "%d rdtrk[%d] %d syncio %s\n", ra, fnd, trk, cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_READING ? "reading" : "writing"); cckdblk.stats_synciomisses++; dev->syncio_retry = 1; cache_unlock (CACHE_DEVBUF); release_lock (&cckd->iolock); return -1; } else cckdblk.stats_syncios++; } /* Mark the new entry active */ cache_setflag(CACHE_DEVBUF, fnd, ~0, CCKD_CACHE_ACTIVE | CCKD_CACHE_USED); cache_setage(CACHE_DEVBUF, fnd); /* If the entry is pending write then change it to `updated' */ if (cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_WRITE) { cache_setflag(CACHE_DEVBUF, fnd, ~CCKD_CACHE_WRITE, CCKD_CACHE_UPDATED); cckd->wrpending--; if (cckd->iowaiters && !cckd->wrpending) broadcast_condition (&cckd->iocond); } buf = cache_getbuf(CACHE_DEVBUF, fnd, 0); cache_unlock (CACHE_DEVBUF); cckd_trace (dev, "%d rdtrk[%d] %d cache hit buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n", ra, fnd, trk, buf, buf[0], buf[1], buf[2], buf[3], buf[4]); cckdblk.stats_switches++; cckd->switches++; cckdblk.stats_cachehits++; cckd->cachehits++; /* if read/write is in progress then wait for it to finish */ while (cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_IOBUSY) { cckdblk.stats_iowaits++; cckd_trace (dev, "%d rdtrk[%d] %d waiting for %s\n", ra, fnd, trk, cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_READING ? "read" : "write"); cache_setflag (CACHE_DEVBUF, fnd, ~0, CCKD_CACHE_IOWAIT); cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; cache_setflag (CACHE_DEVBUF, fnd, ~CCKD_CACHE_IOWAIT, 0); cckd_trace (dev, "%d rdtrk[%d] %d io wait complete\n", ra, fnd, trk); } release_lock (&cckd->iolock); /* Asynchrously schedule readaheads */ if (curtrk > 0 && trk > curtrk && trk <= curtrk + 2) cckd_readahead (dev, trk); return fnd; } /* cache hit */ /* If not readahead and synchronous I/O then retry */ if (!ra && dev->syncio_active) { cache_unlock(CACHE_DEVBUF); release_lock (&cckd->iolock); cckd_trace (dev, "%d rdtrk[%d] %d syncio cache miss\n", ra, lru, trk); cckdblk.stats_synciomisses++; dev->syncio_retry = 1; return -1; } cckd_trace (dev, "%d rdtrk[%d] %d cache miss\n", ra, lru, trk); /* If no cache entry was stolen, then flush all outstanding writes. This requires us to release our locks. cache_wait should be called with only the cache_lock held. Fortunately, cache waits occur very rarely. */ if (lru < 0) /* No available entry to be stolen */ { cckd_trace (dev, "%d rdtrk[%d] %d no available cache entry\n", ra, lru, trk); cache_unlock (CACHE_DEVBUF); if (!ra) release_lock (&cckd->iolock); cckd_flush_cache_all(); cache_lock (CACHE_DEVBUF); cckdblk.stats_cachewaits++; cache_wait (CACHE_DEVBUF); if (!ra) { cache_unlock (CACHE_DEVBUF); obtain_lock (&cckd->iolock); cache_lock (CACHE_DEVBUF); } goto cckd_read_trk_retry; } CCKD_CACHE_GETKEY(lru, devnum, oldtrk); if (devnum != 0) { cckd_trace (dev, "%d rdtrk[%d] %d dropping %4.4X:%d from cache\n", ra, lru, trk, devnum, oldtrk); if (!(cache_getflag(CACHE_DEVBUF, lru) & CCKD_CACHE_USED)) { cckdblk.stats_readaheadmisses++; cckd->misses++; } } /* Initialize the entry */ cache_setkey(CACHE_DEVBUF, lru, CCKD_CACHE_SETKEY(dev->devnum, trk)); cache_setflag(CACHE_DEVBUF, lru, 0, CCKD_CACHE_READING); cache_setage(CACHE_DEVBUF, lru); cache_setval(CACHE_DEVBUF, lru, 0); if (!ra) { cckdblk.stats_switches++; cckd->switches++; cckdblk.stats_cachemisses++; cache_setflag(CACHE_DEVBUF, lru, ~0, CCKD_CACHE_ACTIVE|CCKD_CACHE_USED); } cache_setflag(CACHE_DEVBUF, lru, ~CACHE_TYPE, cckd->ckddasd ? DEVBUF_TYPE_CCKD : DEVBUF_TYPE_CFBA); buf = cache_getbuf(CACHE_DEVBUF, lru, maxlen); cckd_trace (dev, "%d rdtrk[%d] %d buf %p len %d\n", ra, lru, trk, buf, cache_getlen(CACHE_DEVBUF, lru)); cache_unlock (CACHE_DEVBUF); if (!ra) release_lock (&cckd->iolock); /* Asynchronously schedule readaheads */ if (!ra && curtrk > 0 && trk > curtrk && trk <= curtrk + 2) cckd_readahead (dev, trk); /* Clear the buffer if batch mode */ if (dev->batch) memset(buf, 0, maxlen); /* Read the track image */ obtain_lock (&cckd->filelock); len = cckd_read_trkimg (dev, buf, trk, unitstat); release_lock (&cckd->filelock); cache_setval (CACHE_DEVBUF, lru, len); obtain_lock (&cckd->iolock); /* Turn off the READING bit */ cache_lock (CACHE_DEVBUF); flag = cache_setflag(CACHE_DEVBUF, lru, ~CCKD_CACHE_READING, 0); cache_unlock (CACHE_DEVBUF); /* Wakeup other thread waiting for this read */ if (cckd->iowaiters && (flag & CCKD_CACHE_IOWAIT)) { cckd_trace (dev, "%d rdtrk[%d] %d signalling read complete\n", ra, lru, trk); broadcast_condition (&cckd->iocond); } release_lock (&cckd->iolock); if (ra) { cckdblk.stats_readaheads++; cckd->readaheads++; } cckd_trace (dev, "%d rdtrk[%d] %d complete buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n", ra, lru, trk, buf, buf[0], buf[1], buf[2], buf[3], buf[4]); if (cache_busy_percent(CACHE_DEVBUF) > 80) cckd_flush_cache_all(); return lru; } /* end function cckd_read_trk */ /*-------------------------------------------------------------------*/ /* Schedule asynchronous readaheads */ /*-------------------------------------------------------------------*/ void cckd_readahead (DEVBLK *dev, int trk) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int i, r; /* Indexes */ TID tid; /* Readahead thread id */ cckd = dev->cckd_ext; if (cckdblk.ramax < 1 || cckdblk.readaheads < 1) return; obtain_lock (&cckdblk.ralock); /* Scan the cache to see if the tracks are already there */ memset(cckd->ralkup, 0, sizeof(cckd->ralkup)); cckd->ratrk = trk; cache_lock(CACHE_DEVBUF); cache_scan(CACHE_DEVBUF, cckd_readahead_scan, dev); cache_unlock(CACHE_DEVBUF); /* Scan the queue to see if the tracks are already there */ for (r = cckdblk.ra1st; r >= 0; r = cckdblk.ra[r].next) if (cckdblk.ra[r].dev == dev) { i = cckdblk.ra[r].trk - trk; if (i > 0 && i <= cckdblk.readaheads) cckd->ralkup[i-1] = 1; } /* Queue the tracks to the readahead queue */ for (i = 1; i <= cckdblk.readaheads && cckdblk.rafree >= 0; i++) { if (cckd->ralkup[i-1]) continue; if (trk + i >= dev->ckdtrks) break; r = cckdblk.rafree; cckdblk.rafree = cckdblk.ra[r].next; if (cckdblk.ralast < 0) { cckdblk.ra1st = cckdblk.ralast = r; cckdblk.ra[r].prev = cckdblk.ra[r].next = -1; } else { cckdblk.ra[cckdblk.ralast].next = r; cckdblk.ra[r].prev = cckdblk.ralast; cckdblk.ra[r].next = -1; cckdblk.ralast = r; } cckdblk.ra[r].trk = trk + i; cckdblk.ra[r].dev = dev; } /* Schedule the readahead if any are pending */ if (cckdblk.ra1st >= 0) { if (cckdblk.rawaiting) signal_condition (&cckdblk.racond); else if (cckdblk.ras < cckdblk.ramax) create_thread (&tid, JOINABLE, cckd_ra, NULL, "cckd_ra"); } release_lock (&cckdblk.ralock); } /* end function cckd_readahead */ int cckd_readahead_scan (int *answer, int ix, int i, void *data) { CCKDDASD_EXT *cckd; /* -> cckd extension */ U16 devnum; /* Cached device number */ U32 trk; /* Cached track */ DEVBLK *dev = data; /* -> device block */ int k; /* Index */ UNREFERENCED(answer); UNREFERENCED(ix); cckd = dev->cckd_ext; CCKD_CACHE_GETKEY(i, devnum, trk); if (devnum == dev->devnum) { k = (int)trk - cckd->ratrk; if (k > 0 && k <= cckdblk.readaheads) cckd->ralkup[k-1] = 1; } return 0; } /*-------------------------------------------------------------------*/ /* Asynchronous readahead thread */ /*-------------------------------------------------------------------*/ void cckd_ra () { CCKDDASD_EXT *cckd; /* -> cckd extension */ DEVBLK *dev; /* Readahead devblk */ int trk; /* Readahead track */ int ra; /* Readahead index */ int r; /* Readahead queue index */ TID tid; /* Readahead thread id */ obtain_lock (&cckdblk.ralock); ra = ++cckdblk.ras; /* Return without messages if too many already started */ if (ra > cckdblk.ramax) { --cckdblk.ras; release_lock (&cckdblk.ralock); return; } if (!cckdblk.batch) { logmsg (_("HHCCD001I Readahead thread %d started: tid="TIDPAT", pid=%d\n"), ra, thread_id(), getpid()); } while (ra <= cckdblk.ramax) { if (cckdblk.ra1st < 0) { cckdblk.rawaiting++; wait_condition (&cckdblk.racond, &cckdblk.ralock); cckdblk.rawaiting--; } /* Possibly shutting down if no writes pending */ if (cckdblk.ra1st < 0) continue; r = cckdblk.ra1st; trk = cckdblk.ra[r].trk; dev = cckdblk.ra[r].dev; cckd = dev->cckd_ext; /* Requeue the 1st entry to the readahead free queue */ cckdblk.ra1st = cckdblk.ra[r].next; if (cckdblk.ra[r].next > -1) cckdblk.ra[cckdblk.ra[r].next].prev = -1; else cckdblk.ralast = -1; cckdblk.ra[r].next = cckdblk.rafree; cckdblk.rafree = r; /* Schedule the other readaheads if any are still pending */ if (cckdblk.ra1st) { if (cckdblk.rawaiting) signal_condition (&cckdblk.racond); else if (cckdblk.ras < cckdblk.ramax) create_thread (&tid, JOINABLE, cckd_ra, dev, "cckd_ra"); } if (!cckd || cckd->stopping || cckd->merging) continue; cckd->ras++; release_lock (&cckdblk.ralock); /* Read the readahead track */ cckd_read_trk (dev, trk, ra, NULL); obtain_lock (&cckdblk.ralock); cckd->ras--; } if (!cckdblk.batch) logmsg (_("HHCCD011I Readahead thread %d stopping: tid="TIDPAT", pid=%d\n"), ra, thread_id(), getpid()); --cckdblk.ras; if (!cckdblk.ras) signal_condition(&cckdblk.termcond); release_lock(&cckdblk.ralock); } /* end thread cckd_ra_thread */ /*-------------------------------------------------------------------*/ /* Flush updated cache entries for a device */ /* */ /* Caller holds the cckd->iolock */ /* cckdblk.wrlock then cache_lock is obtained and released */ /*-------------------------------------------------------------------*/ void cckd_flush_cache(DEVBLK *dev) { int rc; /* Return code */ TID tid; /* Writer thread id */ /* Scan cache for updated cache entries */ obtain_lock (&cckdblk.wrlock); cache_lock (CACHE_DEVBUF); rc = cache_scan (CACHE_DEVBUF, cckd_flush_cache_scan, dev); cache_unlock (CACHE_DEVBUF); /* Schedule the writer if any writes are pending */ if (cckdblk.wrpending) { if (cckdblk.wrwaiting) signal_condition (&cckdblk.wrcond); else if (cckdblk.wrs < cckdblk.wrmax) { create_thread (&tid, JOINABLE, cckd_writer, NULL, "cckd_writer"); } } release_lock (&cckdblk.wrlock); } int cckd_flush_cache_scan (int *answer, int ix, int i, void *data) { CCKDDASD_EXT *cckd; /* -> cckd extension */ U16 devnum; /* Cached device number */ U32 trk; /* Cached track */ DEVBLK *dev = data; /* -> device block */ UNREFERENCED(answer); cckd = dev->cckd_ext; CCKD_CACHE_GETKEY(i, devnum, trk); if ((cache_getflag(ix,i) & CACHE_BUSY) == CCKD_CACHE_UPDATED && dev->devnum == devnum) { cache_setflag (ix, i, ~CCKD_CACHE_UPDATED, CCKD_CACHE_WRITE); ++cckd->wrpending; ++cckdblk.wrpending; cckd_trace (dev, "flush file[%d] cache[%d] %4.4X trk %d\n", cckd->sfn, i, devnum, trk); } return 0; } void cckd_flush_cache_all() { CCKDDASD_EXT *cckd; /* -> cckd extension */ DEVBLK *dev = NULL; /* -> device block */ cckd_lock_devchain(0); for (dev = cckdblk.dev1st; dev; dev = cckd->devnext) { cckd = dev->cckd_ext; obtain_lock (&cckd->iolock); if (!cckd->merging && !cckd->stopping) cckd_flush_cache(dev); release_lock (&cckd->iolock); } cckd_unlock_devchain(); } /*-------------------------------------------------------------------*/ /* Purge cache entries for a device */ /* */ /* Caller holds the iolock */ /* cache_lock is obtained and released */ /*-------------------------------------------------------------------*/ void cckd_purge_cache(DEVBLK *dev) { /* Scan cache and purge entries */ cache_lock (CACHE_DEVBUF); cache_scan (CACHE_DEVBUF, cckd_purge_cache_scan, dev); cache_unlock (CACHE_DEVBUF); } int cckd_purge_cache_scan (int *answer, int ix, int i, void *data) { U16 devnum; /* Cached device number */ U32 trk; /* Cached track */ DEVBLK *dev = data; /* -> device block */ UNREFERENCED(answer); CCKD_CACHE_GETKEY(i, devnum, trk); if (dev->devnum == devnum) { cache_release (ix, i, 0); cckd_trace (dev, "purge cache[%d] %4.4X trk %d purged\n", i, devnum, trk); } return 0; } /*-------------------------------------------------------------------*/ /* Writer thread */ /*-------------------------------------------------------------------*/ void cckd_writer(void *arg) { DEVBLK *dev; /* Device block */ CCKDDASD_EXT *cckd; /* -> cckd extension */ int writer; /* Writer identifier */ int o; /* Cache entry found */ U16 devnum; /* Device number */ BYTE *buf; /* Buffer */ BYTE *bufp; /* Buffer to be written */ int len, bufl; /* Buffer lengths */ int trk; /* Track number */ int comp; /* Compression algorithm */ int parm; /* Compression parameter */ TID tid; /* Writer thead id */ U32 flag; /* Cache flag */ static char *compress[] = {"none", "zlib", "bzip2"}; BYTE buf2[65536]; /* Compress buffer */ UNREFERENCED(arg); #ifndef WIN32 /* Set writer priority just below cpu priority to mimimize the compression effect */ if(cckdblk.wrprio >= 0) setpriority (PRIO_PROCESS, 0, cckdblk.wrprio); #endif obtain_lock (&cckdblk.wrlock); writer = ++cckdblk.wrs; /* Return without messages if too many already started */ if (writer > cckdblk.wrmax) { --cckdblk.wrs; release_lock (&cckdblk.wrlock); return; } if (!cckdblk.batch) { logmsg (_("HHCCD002I Writer thread %d started: tid="TIDPAT", pid=%d\n"), writer, thread_id(), getpid()); } while (writer <= cckdblk.wrmax || cckdblk.wrpending) { /* Wait for work */ if (cckdblk.wrpending == 0) { cckdblk.wrwaiting++; wait_condition (&cckdblk.wrcond, &cckdblk.wrlock); cckdblk.wrwaiting--; } /* Scan the cache for the oldest pending write */ cache_lock (CACHE_DEVBUF); o = cache_scan (CACHE_DEVBUF, cckd_writer_scan, NULL); /* Possibly shutting down if no writes pending */ if (o < 0) { cache_unlock (CACHE_DEVBUF); cckdblk.wrpending = 0; continue; } cache_setflag (CACHE_DEVBUF, o, ~CCKD_CACHE_WRITE, CCKD_CACHE_WRITING); cache_unlock (CACHE_DEVBUF); /* Schedule the other writers if any writes are still pending */ cckdblk.wrpending--; if (cckdblk.wrpending) { if (cckdblk.wrwaiting) signal_condition (&cckdblk.wrcond); else if (cckdblk.wrs < cckdblk.wrmax) { create_thread (&tid, JOINABLE, cckd_writer, NULL, "cckd_writer"); } } release_lock (&cckdblk.wrlock); /* Prepare to compress */ CCKD_CACHE_GETKEY(o, devnum, trk); dev = cckd_find_device_by_devnum (devnum); cckd = dev->cckd_ext; buf = cache_getbuf(CACHE_DEVBUF, o, 0); len = cckd_trklen (dev, buf); comp = len < CCKD_COMPRESS_MIN ? CCKD_COMPRESS_NONE : cckdblk.comp == 0xff ? cckd->cdevhdr[cckd->sfn].compress : cckdblk.comp; parm = cckdblk.compparm < 0 ? cckd->cdevhdr[cckd->sfn].compress_parm : cckdblk.compparm; cckd_trace (dev, "%d wrtrk[%d] %d len %d buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n", writer, o, trk, len, buf, buf[0], buf[1],buf[2],buf[3],buf[4]); /* Compress the image if not null */ if ((len = cckd_check_null_trk (dev, buf, trk, len)) > CKDDASD_NULLTRK_FMTMAX) { /* Stress adjustments */ if ((cache_waiters(CACHE_DEVBUF) || cache_busy(CACHE_DEVBUF) > 90) && !cckdblk.nostress) { cckdblk.stats_stresswrites++; comp = len < CCKD_STRESS_MINLEN ? CCKD_COMPRESS_NONE : CCKD_STRESS_COMP; parm = cache_busy(CACHE_DEVBUF) <= 95 ? CCKD_STRESS_PARM1 : CCKD_STRESS_PARM2; } /* Compress the track image */ cckd_trace (dev, "%d wrtrk[%d] %d comp %s parm %d\n", writer, o, trk, compress[comp], parm); bufp = (BYTE *)&buf2; bufl = cckd_compress(dev, &bufp, buf, len, comp, parm); cckd_trace (dev, "%d wrtrk[%d] %d compressed length %d\n", writer, o, trk, bufl); } else { bufp = buf; bufl = len; } obtain_lock (&cckd->filelock); /* Turn on read-write header bits if not already on */ if (!(cckd->cdevhdr[cckd->sfn].options & CCKD_OPENED)) { cckd->cdevhdr[cckd->sfn].options |= (CCKD_OPENED | CCKD_ORDWR); cckd_write_chdr (dev); } /* Write the track image */ cckd_write_trkimg (dev, bufp, bufl, trk, CCKD_SIZE_ANY); release_lock (&cckd->filelock); /* Schedule the garbage collector */ if (cckdblk.gcs < cckdblk.gcmax) create_thread (&tid, JOINABLE, cckd_gcol, NULL, "cckd_gcol"); obtain_lock (&cckd->iolock); cache_lock (CACHE_DEVBUF); flag = cache_setflag (CACHE_DEVBUF, o, ~CCKD_CACHE_WRITING, 0); cache_unlock (CACHE_DEVBUF); cckd->wrpending--; if (cckd->iowaiters && ((flag & CCKD_CACHE_IOWAIT) || !cckd->wrpending)) { cckd_trace (dev, "writer[%d] cache[%2.2d] %d signalling write complete\n", writer, o, trk); broadcast_condition (&cckd->iocond); } release_lock(&cckd->iolock); cckd_trace (dev, "%d wrtrk[%2.2d] %d complete flags:%8.8x\n", writer, o, trk, cache_getflag(CACHE_DEVBUF,o)); obtain_lock(&cckdblk.wrlock); } if (!cckdblk.batch) logmsg (_("HHCCD012I Writer thread %d stopping: tid="TIDPAT", pid=%d\n"), writer, thread_id(), getpid()); cckdblk.wrs--; if (cckdblk.wrs == 0) signal_condition(&cckdblk.termcond); release_lock(&cckdblk.wrlock); } /* end thread cckd_writer */ int cckd_writer_scan (int *o, int ix, int i, void *data) { UNREFERENCED(data); if ((cache_getflag(ix,i) & DEVBUF_TYPE_COMP) && (cache_getflag(ix,i) & CCKD_CACHE_WRITE) && (*o == -1 || cache_getage(ix, i) < cache_getage(ix, *o))) *o = i; return 0; } /*-------------------------------------------------------------------*/ /* Debug routine for checking the free space array */ /*-------------------------------------------------------------------*/ void cckd_chk_space(DEVBLK *dev) { #if 1 CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* Shadow file index */ int err = 0, n = 0, i, p; size_t largest=0; size_t total=0; off_t fpos; cckd = dev->cckd_ext; sfx = cckd->sfn; p = -1; fpos = cckd->cdevhdr[sfx].free; for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) { n++; total += cckd->free[i].len; if (n > cckd->freenbr) break; if (cckd->free[i].prev != p) err = 1; if (cckd->free[i].next >= 0) { if (fpos + cckd->free[i].len > cckd->free[i].pos) err = 1; } else { if (fpos + cckd->free[i].len > cckd->cdevhdr[sfx].size) err = 1; } if (cckd->free[i].pending == 0 && cckd->free[i].len > largest) largest = cckd->free[i].len; fpos = cckd->free[i].pos; p = i; } if (err || (cckd->cdevhdr[sfx].free != 0 && cckd->cdevhdr[sfx].free_number == 0) || (cckd->cdevhdr[sfx].free == 0 && cckd->cdevhdr[sfx].free_number != 0) || (n != cckd->cdevhdr[sfx].free_number) || (total != cckd->cdevhdr[sfx].free_total - cckd->cdevhdr[sfx].free_imbed) || (cckd->freelast != p) || (largest != cckd->cdevhdr[sfx].free_largest) ) { cckd_trace (dev, "cdevhdr[%d] size %10d used %10d free 0x%8.8x\n", sfx,cckd->cdevhdr[sfx].size,cckd->cdevhdr[sfx].used, cckd->cdevhdr[sfx].free); cckd_trace (dev, " nbr %10d total %10d imbed %10d largest %10d\n", cckd->cdevhdr[sfx].free_number, cckd->cdevhdr[sfx].free_total,cckd->cdevhdr[sfx].free_imbed, cckd->cdevhdr[sfx].free_largest); cckd_trace (dev, "free %p nbr %d 1st %d last %d avail %d\n", cckd->free,cckd->freenbr,cckd->free1st, cckd->freelast,cckd->freeavail); cckd_trace (dev, "found nbr %d total %ld largest %ld\n",n,(long)total,(long)largest); fpos = cckd->cdevhdr[sfx].free; for (n = 0, i = cckd->free1st; i >= 0; i = cckd->free[i].next) { if (++n > cckd->freenbr) break; cckd_trace (dev, "%4d: [%4d] prev[%4d] next[%4d] pos %8.8" I64_FMT "x len %8d %8.8" I64_FMT "x pend %d\n", n, i, cckd->free[i].prev, cckd->free[i].next, (long long)fpos, cckd->free[i].len, (long long)fpos + cckd->free[i].len, cckd->free[i].pending); fpos = cckd->free[i].pos; } cckd_print_itrace(); } #endif } /* end function cckd_chk_space */ /*-------------------------------------------------------------------*/ /* Get file space */ /*-------------------------------------------------------------------*/ off_t cckd_get_space(DEVBLK *dev, int *size, int flags) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int i,p,n; /* Free space indexes */ int len2; /* Other lengths */ off_t fpos; /* Free space offset */ unsigned int flen; /* Free space size */ int sfx; /* Shadow file index */ int len; /* Requested length */ cckd = dev->cckd_ext; sfx = cckd->sfn; len = *size; if (flags & CCKD_L2SPACE) { flags |= CCKD_SIZE_EXACT; len = *size = CCKD_L2TAB_SIZE; } cckd_trace (dev, "get_space len %d largest %d flags 0x%2.2x\n", len, cckd->cdevhdr[sfx].free_largest, flags); if (len <= CKDDASD_NULLTRK_FMTMAX) return 0; if (!cckd->free) cckd_read_fsp (dev); len2 = len + CCKD_FREEBLK_SIZE; /* Get space at the end if no space is large enough */ if (len2 > (int)cckd->cdevhdr[sfx].free_largest && len != (int)cckd->cdevhdr[sfx].free_largest) { cckd_get_space_atend: fpos = (off_t)cckd->cdevhdr[sfx].size; if ((long long)(fpos + len) > cckd->maxsize) { logmsg (_("HHCCD102E %4.4X file[%d] get space error, size exceeds %lldM\n"), dev->devnum, sfx, (cckd->maxsize >> 20) + 1); return -1; } cckd->cdevhdr[sfx].size += len; cckd->cdevhdr[sfx].used += len; cckd_trace (dev, "get_space atend 0x%" I64_FMT "x len %d\n",(long long)fpos, len); return fpos; } /* Scan free space chain */ fpos = (off_t)cckd->cdevhdr[sfx].free; for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) { if (cckd->free[i].pending == 0 && (len2 <= (int)cckd->free[i].len || len == (int)cckd->free[i].len) && ((flags & CCKD_L2SPACE) || fpos >= cckd->l2bounds)) break; fpos = (off_t)cckd->free[i].pos; } /* This can happen if largest comes before l2bounds */ if (i < 0) goto cckd_get_space_atend; flen = cckd->free[i].len; p = cckd->free[i].prev; n = cckd->free[i].next; /* * If `CCKD_SIZE_ANY' bit is set and the left over space is small * enough, then use the entire free space */ if ((flags & CCKD_SIZE_ANY) && flen <= cckd->freemin) *size = (int)flen; /* Remove the new space from free space */ if (*size < (int)flen) { cckd->free[i].len -= *size; if (p >= 0) cckd->free[p].pos += *size; else cckd->cdevhdr[sfx].free += *size; } else { cckd->cdevhdr[sfx].free_number--; /* Remove the free space entry from the chain */ if (p >= 0) { cckd->free[p].pos = cckd->free[i].pos; cckd->free[p].next = n; } else { cckd->cdevhdr[sfx].free = cckd->free[i].pos; cckd->free1st = n; } if (n >= 0) cckd->free[n].prev = p; else cckd->freelast = p; /* Add entry to the available queue */ cckd->free[i].next = cckd->freeavail; cckd->freeavail = i; } /* Find the largest free space if we got the largest */ if (flen >= cckd->cdevhdr[sfx].free_largest) { int i; cckd->cdevhdr[sfx].free_largest = 0; for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) if (cckd->free[i].len > cckd->cdevhdr[sfx].free_largest && cckd->free[i].pending == 0) cckd->cdevhdr[sfx].free_largest = cckd->free[i].len; } /* Update free space stats */ cckd->cdevhdr[sfx].used += len; cckd->cdevhdr[sfx].free_total -= len; cckd->cdevhdr[sfx].free_imbed += *size - len; cckd_trace (dev, "get_space found 0x%" I64_FMT "x len %d size %d\n", (long long)fpos, len, *size); return fpos; } /* end function cckd_get_space */ /*-------------------------------------------------------------------*/ /* Release file space */ /*-------------------------------------------------------------------*/ void cckd_rel_space(DEVBLK *dev, off_t pos, int len, int size) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* Shadow file index */ off_t ppos, npos; /* Prev/next free offsets */ int i, p, n; /* Free space indexes */ int pending; /* Calculated pending value */ int fsize = size; /* Free space size */ if (len <= CKDDASD_NULLTRK_FMTMAX || pos == 0 || pos == 0xffffffff) return; cckd = dev->cckd_ext; sfx = cckd->sfn; cckd_trace (dev, "rel_space offset %" I64_FMT "x len %d size %d\n", (long long)pos, len, size); if (!cckd->free) cckd_read_fsp (dev); // cckd_chk_space(dev); /* Scan free space chain */ ppos = -1; npos = cckd->cdevhdr[sfx].free; for (p = -1, n = cckd->free1st; n >= 0; n = cckd->free[n].next) { if (pos < npos) break; ppos = npos; npos = cckd->free[n].pos; p = n; } /* Calculate the `pending' value */ pending = cckdblk.freepend >= 0 ? cckdblk.freepend : 1 + (1 - cckdblk.fsync); /* If possible use previous adjacent free space otherwise get an available one */ if (p >= 0 && ppos + cckd->free[p].len == pos && cckd->free[p].pending == pending) { cckd->free[p].len += size; fsize = cckd->free[p].len; } else { /* Increase the size of the free space array if necessary */ if (cckd->freeavail < 0) { cckd->freeavail = cckd->freenbr; cckd->freenbr += 1024; cckd->free = realloc ( cckd->free, cckd->freenbr * CCKD_FREEBLK_ISIZE); for (i = cckd->freeavail; i < cckd->freenbr; i++) cckd->free[i].next = i + 1; cckd->free[i-1].next = -1; cckd->freemin = CCKD_FREE_MIN_SIZE + ((cckd->freenbr >> 10) * CCKD_FREE_MIN_INCR); } /* Get an available free space entry */ i = cckd->freeavail; cckd->freeavail = cckd->free[i].next; cckd->cdevhdr[sfx].free_number++; /* Update the new entry */ cckd->free[i].prev = p; cckd->free[i].next = n; cckd->free[i].len = size; cckd->free[i].pending = pending; /* Update the previous entry */ if (p >= 0) { cckd->free[i].pos = cckd->free[p].pos; cckd->free[p].pos = pos; cckd->free[p].next = i; } else { cckd->free[i].pos = cckd->cdevhdr[sfx].free; cckd->cdevhdr[sfx].free = pos; cckd->free1st = i; } /* Update the next entry */ if (n >= 0) cckd->free[n].prev = i; else cckd->freelast = i; } /* Update the free space statistics */ cckd->cdevhdr[sfx].used -= len; cckd->cdevhdr[sfx].free_total += len; cckd->cdevhdr[sfx].free_imbed -= size - len; if (!pending && (U32)fsize > cckd->cdevhdr[sfx].free_largest) cckd->cdevhdr[sfx].free_largest = (U32)fsize; // cckd_chk_space(dev); } /* end function cckd_rel_space */ /*-------------------------------------------------------------------*/ /* Flush pending free space */ /*-------------------------------------------------------------------*/ void cckd_flush_space(DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int p,i,n; /* Free free space indexes */ int sfx; /* Shadow file index */ U32 ppos, pos; /* Free space offsets */ cckd = dev->cckd_ext; sfx = cckd->sfn; cckd_trace (dev, "flush_space nbr %d\n",cckd->cdevhdr[sfx].free_number); /* Make sure the free space chain is built */ if (!cckd->free) cckd_read_fsp (dev); // cckd_chk_space(dev); if (cckd->cdevhdr[sfx].free_number == 0 || cckd->cdevhdr[sfx].free == 0) { cckd->cdevhdr[sfx].free_number = cckd->cdevhdr[sfx].free = 0; cckd->free1st = cckd->freelast = cckd->freeavail = -1; } pos = cckd->cdevhdr[sfx].free; ppos = p = -1; cckd->cdevhdr[sfx].free_number = cckd->cdevhdr[sfx].free_largest = 0; for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) { /* Decrement the pending count */ if (cckd->free[i].pending) --cckd->free[i].pending; /* Combine adjacent free spaces */ while (pos + cckd->free[i].len == cckd->free[i].pos) { n = cckd->free[i].next; if (cckd->free[n].pending > cckd->free[i].pending + 1 || cckd->free[n].pending < cckd->free[i].pending) break; cckd->free[i].pos = cckd->free[n].pos; cckd->free[i].len += cckd->free[n].len; cckd->free[i].next = cckd->free[n].next; cckd->free[n].next = cckd->freeavail; cckd->freeavail = n; n = cckd->free[i].next; if (n >= 0) cckd->free[n].prev = i; } ppos = pos; pos = cckd->free[i].pos; cckd->cdevhdr[sfx].free_number++; if (cckd->free[i].len > cckd->cdevhdr[sfx].free_largest && !cckd->free[i].pending) cckd->cdevhdr[sfx].free_largest = cckd->free[i].len; p = i; } cckd->freelast = p; cckd_trace (dev, "rel_flush_space nbr %d (after merge)\n", cckd->cdevhdr[sfx].free_number); /* If the last free space is at the end of the file then release it */ if (p >= 0 && ppos + cckd->free[p].len == cckd->cdevhdr[sfx].size && !cckd->free[p].pending) { i = p; p = cckd->free[i].prev; cckd_trace (dev, "file[%d] rel_flush_space atend 0x%" I64_FMT "x len %d\n", sfx, (long long)ppos, cckd->free[i].len); /* Remove the entry from the chain */ if (p >= 0) { cckd->free[p].pos = 0; cckd->free[p].next = -1; } else { cckd->cdevhdr[sfx].free = 0; cckd->free1st = -1; } cckd->freelast = p; /* Add the entry to the available chain */ cckd->free[i].next = cckd->freeavail; cckd->freeavail = i; /* Update the device header */ cckd->cdevhdr[sfx].size -= cckd->free[i].len; cckd->cdevhdr[sfx].free_total -= cckd->free[i].len; cckd->cdevhdr[sfx].free_number--; if (cckd->free[i].len >= cckd->cdevhdr[sfx].free_largest) { cckd->cdevhdr[sfx].free_largest = 0; for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) if (cckd->free[i].len > cckd->cdevhdr[sfx].free_largest && cckd->free[i].pending == 0) cckd->cdevhdr[sfx].free_largest = cckd->free[i].len; } /* Truncate the file */ cckd_ftruncate (dev, sfx, (off_t)cckd->cdevhdr[sfx].size); } /* Release space at end of the file */ // cckd_chk_space(dev); } /* end function cckd_flush_space */ /*-------------------------------------------------------------------*/ /* Read compressed dasd header */ /*-------------------------------------------------------------------*/ int cckd_read_chdr (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* File index */ cckd = dev->cckd_ext; sfx = cckd->sfn; cckd_trace (dev, "file[%d] read_chdr\n", sfx); memset (&cckd->cdevhdr[sfx], 0, CCKDDASD_DEVHDR_SIZE); /* Read the device header */ if (cckd_read (dev, sfx, CKDDASD_DEVHDR_SIZE, &cckd->cdevhdr[sfx], CCKDDASD_DEVHDR_SIZE) < 0) return -1; /* Check endian format */ cckd->swapend[sfx] = 0; if ((cckd->cdevhdr[sfx].options & CCKD_BIGENDIAN) != cckd_endian()) { if (cckd->open[sfx] == CCKD_OPEN_RW) { if (cckd_swapend (dev) < 0) return -1; cckd_swapend_chdr (&cckd->cdevhdr[sfx]); } else { cckd->swapend[sfx] = 1; cckd_swapend_chdr (&cckd->cdevhdr[sfx]); } } /* Set default null format */ if (cckd->cdevhdr[sfx].nullfmt > CKDDASD_NULLTRK_FMTMAX) cckd->cdevhdr[sfx].nullfmt = 0; if (cckd->cdevhdr[sfx].nullfmt == 0 && dev->oslinux && dev->devtype == 0x3390) cckd->cdevhdr[sfx].nullfmt = CKDDASD_NULLTRK_FMT2; if (cckd->cdevhdr[sfx].nullfmt == CKDDASD_NULLTRK_FMT2) dev->oslinux = 1; return 0; } /* end function cckd_read_chdr */ /*-------------------------------------------------------------------*/ /* Write compressed dasd header */ /*-------------------------------------------------------------------*/ int cckd_write_chdr (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* File index */ cckd = dev->cckd_ext; sfx = cckd->sfn; cckd_trace (dev, "file[%d] write_chdr\n", sfx); /* Set version.release.modlvl */ cckd->cdevhdr[sfx].vrm[0] = CCKD_VERSION; cckd->cdevhdr[sfx].vrm[1] = CCKD_RELEASE; cckd->cdevhdr[sfx].vrm[2] = CCKD_MODLVL; if (cckd_write (dev, sfx, CCKD_DEVHDR_POS, &cckd->cdevhdr[sfx], CCKD_DEVHDR_SIZE) < 0) return -1; return 0; } /* end function cckd_write_chdr */ /*-------------------------------------------------------------------*/ /* Read the level 1 table */ /*-------------------------------------------------------------------*/ int cckd_read_l1 (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* File index */ int len; /* Length of level 1 table */ int i; /* Work integer */ cckd = dev->cckd_ext; sfx = cckd->sfn; cckd_trace (dev, "file[%d] read_l1 offset 0x%"I64_FMT"x\n", sfx, (U64)CCKD_L1TAB_POS); /* Free the old level 1 table if it exists */ cckd->l1[sfx] = cckd_free (dev, "l1", cckd->l1[sfx]); /* Allocate the level 1 table */ len = cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE; if ((cckd->l1[sfx] = cckd_malloc (dev, "l1", len)) == NULL) return -1; memset(cckd->l1[sfx], sfx ? 0xFF : 0, len); /* Read the level 1 table */ if (cckd_read (dev, sfx, CCKD_L1TAB_POS, cckd->l1[sfx], len) < 0) return -1; /* Fix endianess */ if (cckd->swapend[sfx]) cckd_swapend_l1 (cckd->l1[sfx], cckd->cdevhdr[sfx].numl1tab); /* Determine bounds */ cckd->l2bounds = CCKD_L1TAB_POS + len; for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++) if (cckd->l1[sfx][i] != 0 && cckd->l1[sfx][i] != 0xffffffff) cckd->l2bounds += CCKD_L2TAB_SIZE; /* Check if all l2 tables are within bounds */ cckd->l2ok = 1; for (i = 0; i < cckd->cdevhdr[sfx].numl1tab && cckd->l2ok; i++) if (cckd->l1[sfx][i] != 0 && cckd->l1[sfx][i] != 0xffffffff) if (cckd->l1[sfx][i] > cckd->l2bounds - CCKD_L2TAB_SIZE) cckd->l2ok = 0; return 0; } /* end function cckd_read_l1 */ /*-------------------------------------------------------------------*/ /* Write the level 1 table */ /*-------------------------------------------------------------------*/ int cckd_write_l1 (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* File index */ int len; /* Length of level 1 table */ cckd = dev->cckd_ext; sfx = cckd->sfn; len = cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE; cckd_trace (dev, "file[%d] write_l1 0x%"I64_FMT"x len %d\n", sfx, (U64)CCKD_L1TAB_POS, len); if (cckd_write (dev, sfx, CCKD_L1TAB_POS, cckd->l1[sfx], len) < 0) return -1; return 0; } /* end function cckd_write_l1 */ /*-------------------------------------------------------------------*/ /* Update a level 1 table entry */ /*-------------------------------------------------------------------*/ int cckd_write_l1ent (DEVBLK *dev, int l1x) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* File index */ off_t off; /* Offset to l1 entry */ cckd = dev->cckd_ext; sfx = cckd->sfn; off = (off_t)(CCKD_L1TAB_POS + l1x * CCKD_L1ENT_SIZE); cckd_trace (dev, "file[%d] write_l1ent[%d] , 0x%" I64_FMT "x\n", sfx, l1x, (long long)off); if (cckd_write (dev, sfx, off, &cckd->l1[sfx][l1x], CCKD_L1ENT_SIZE) < 0) return -1; return 0; } /* end function cckd_write_l1ent */ /*-------------------------------------------------------------------*/ /* Initial read */ /*-------------------------------------------------------------------*/ int cckd_read_init (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* File index */ CKDDASD_DEVHDR devhdr; /* Device header */ cckd = dev->cckd_ext; sfx = cckd->sfn; cckd_trace (dev, "file[%d] read_init\n", sfx); /* Read the device header */ if (cckd_read (dev, sfx, 0, &devhdr, CKDDASD_DEVHDR_SIZE) < 0) return -1; /* Check the device hdr */ if (sfx == 0 && memcmp (&devhdr.devid, "CKD_C370", 8) == 0) cckd->ckddasd = 1; else if (sfx == 0 && memcmp (&devhdr.devid, "FBA_C370", 8) == 0) cckd->fbadasd = 1; else if (!(sfx && memcmp (&devhdr.devid, "CKD_S370", 8) == 0 && cckd->ckddasd) && !(sfx && memcmp (&devhdr.devid, "FBA_S370", 8) == 0 && cckd->fbadasd)) { logmsg (_("HHCCD110E %4.4X file[%d] devhdr id error\n"), dev->devnum, sfx); return -1; } /* Read the compressed header */ if (cckd_read_chdr (dev) < 0) return -1; /* Read the level 1 table */ if (cckd_read_l1 (dev) < 0) return -1; return 0; } /* end function cckd_read_init */ /*-------------------------------------------------------------------*/ /* Read free space */ /*-------------------------------------------------------------------*/ int cckd_read_fsp (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ off_t fpos; /* Free space offset */ int sfx; /* File index */ int i; /* Index */ CCKD_FREEBLK freeblk; /* First freeblk read */ cckd = dev->cckd_ext; sfx = cckd->sfn; cckd_trace (dev, "file[%d] read_fsp number %d\n", sfx, cckd->cdevhdr[sfx].free_number); cckd->free = cckd_free (dev, "free", cckd->free); cckd->free1st = cckd->freelast = cckd->freeavail = -1; /* Get storage for the internal free space chain * in a multiple of 1024 entries */ cckd->freenbr = (cckd->cdevhdr[sfx].free_number + 1023) & ~0x3FF; if (cckd->freenbr) if ((cckd->free = cckd_calloc (dev, "free", cckd->freenbr, CCKD_FREEBLK_ISIZE)) == NULL) return -1; /* Build the doubly linked internal free space chain */ if (cckd->cdevhdr[sfx].free_number) { cckd->free1st = 0; /* Read the first freeblk to determine old/new format */ fpos = (off_t)cckd->cdevhdr[sfx].free; if (cckd_read (dev, sfx, fpos, &freeblk, CCKD_FREEBLK_SIZE) < 0) return -1; if (memcmp(&freeblk, "FREE_BLK", 8) == 0) { /* new format free space */ CCKD_FREEBLK *fsp; U32 ofree = cckd->cdevhdr[sfx].free; int n = cckd->cdevhdr[sfx].free_number * CCKD_FREEBLK_SIZE; if ((fsp = cckd_malloc (dev, "fsp", n)) == NULL) return -1; fpos += CCKD_FREEBLK_SIZE; if (cckd_read (dev, sfx, fpos, fsp, n) < 0) return -1; for (i = 0; i < cckd->cdevhdr[sfx].free_number; i++) { if (i == 0) cckd->cdevhdr[sfx].free = fsp[i].pos; else cckd->free[i-1].pos = fsp[i].pos; cckd->free[i].pos = 0; cckd->free[i].len = fsp[i].len; cckd->free[i].prev = i - 1; cckd->free[i].next = i + 1; } cckd->free[i-1].next = -1; cckd->freelast = i-1; fsp = cckd_free (dev, "fsp", fsp); /* truncate if new format free space was at the end */ if (ofree == cckd->cdevhdr[sfx].size) { fpos = (off_t)cckd->cdevhdr[sfx].size; cckd_ftruncate(dev, sfx, fpos); } } /* new format free space */ else { /* old format free space */ fpos = (off_t)cckd->cdevhdr[sfx].free; for (i = 0; i < cckd->cdevhdr[sfx].free_number; i++) { if (cckd_read (dev, sfx, fpos, &cckd->free[i], CCKD_FREEBLK_SIZE) < 0) return -1; cckd->free[i].prev = i - 1; cckd->free[i].next = i + 1; fpos = (off_t)cckd->free[i].pos; } cckd->free[i-1].next = -1; cckd->freelast = i-1; } /* old format free space */ } /* if (cckd->cdevhdr[sfx].free_number) */ /* Build singly linked chain of available free space entries */ if (cckd->cdevhdr[sfx].free_number < cckd->freenbr) { cckd->freeavail = cckd->cdevhdr[sfx].free_number; for (i = cckd->freeavail; i < cckd->freenbr; i++) cckd->free[i].next = i + 1; cckd->free[i-1].next = -1; } /* Set minimum free space size */ cckd->freemin = CCKD_FREE_MIN_SIZE + ((cckd->freenbr >> 10) * CCKD_FREE_MIN_INCR); return 0; } /* end function cckd_read_fsp */ /*-------------------------------------------------------------------*/ /* Write the free space */ /*-------------------------------------------------------------------*/ int cckd_write_fsp (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ off_t fpos; /* Free space offset */ U32 ppos; /* Previous free space offset*/ int sfx; /* File index */ int i, j, n; /* Work variables */ int rc; /* Return code */ CCKD_FREEBLK *fsp = NULL; /* -> new format free space */ cckd = dev->cckd_ext; sfx = cckd->sfn; if (cckd->free == NULL) return 0; cckd_trace (dev, "file[%d] write_fsp number %d\n", sfx, cckd->cdevhdr[sfx].free_number); /* get rid of pending free space */ for (i = 0; i < CCKD_MAX_FREEPEND; i++) cckd_flush_space(dev); /* sanity checks */ if (cckd->cdevhdr[sfx].free_number == 0 || cckd->cdevhdr[sfx].free == 0) { cckd->cdevhdr[sfx].free_number = cckd->cdevhdr[sfx].free = 0; cckd->free1st = cckd->freelast = cckd->freeavail = -1; } /* Write any free spaces */ if (cckd->cdevhdr[sfx].free) { /* size needed for new format free space */ n = (cckd->cdevhdr[sfx].free_number+1) * CCKD_FREEBLK_SIZE; /* look for existing free space to fit new format free space */ fpos = 0; for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) if (n <= (int)cckd->free[i].len) break; if (i >= 0) fpos = cckd->free[i].prev < 0 ? (off_t)cckd->cdevhdr[sfx].free : (off_t)cckd->free[cckd->free[i].prev].pos; /* if no applicable space see if we can append to the file */ if (fpos == 0 && cckd->maxsize - cckd->cdevhdr[sfx].size >= n) fpos = (off_t)cckd->cdevhdr[sfx].size; if (fpos && (fsp = cckd_malloc (dev, "fsp", n)) == NULL) fpos = 0; if (fpos) { /* New format free space */ memcpy (&fsp[0], "FREE_BLK", 8); ppos = cckd->cdevhdr[sfx].free; for (i = cckd->free1st, j = 1; i >= 0; i = cckd->free[i].next) { fsp[j].pos = ppos; fsp[j++].len = cckd->free[i].len; ppos = cckd->free[i].pos; } rc = cckd_write (dev, sfx, fpos, fsp, n); fsp = cckd_free (dev, "fsp", fsp); if (rc < 0) return -1; cckd->cdevhdr[sfx].free = (U32)fpos; } /* new format free space */ else { /* Old format free space */ for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) { if (cckd_write (dev, sfx, fpos, &cckd->free[i], CCKD_FREEBLK_SIZE) < 0) return -1; fpos = (off_t)cckd->free[i].pos; } } /* old format free space */ } /* if (cckd->cdevhdr[sfx].free) */ /* Free the free space array */ cckd->free = cckd_free (dev, "free", cckd->free); cckd->freenbr = 0; cckd->free1st = cckd->freelast = cckd->freeavail = -1; return 0; } /* end function cckd_write_fsp */ /*-------------------------------------------------------------------*/ /* Read a new level 2 table */ /*-------------------------------------------------------------------*/ int cckd_read_l2 (DEVBLK *dev, int sfx, int l1x) { CCKDDASD_EXT *cckd; /* -> cckd extension */ off_t off; /* L2 file offset */ int fnd; /* Found cache */ int lru; /* Oldest available cache */ CCKD_L2ENT *buf; /* -> Cache buffer */ int i; /* Loop index */ int nullfmt; /* Null track format */ cckd = dev->cckd_ext; nullfmt = cckd->cdevhdr[cckd->sfn].nullfmt; cckd_trace (dev, "file[%d] read_l2 %d active %d %d %d\n", sfx, l1x, cckd->sfx, cckd->l1x, cckd->l2active); /* Return if table is already active */ if (sfx == cckd->sfx && l1x == cckd->l1x) return 0; cache_lock(CACHE_L2); /* Inactivate the previous entry */ if (cckd->l2active >= 0) cache_setflag(CACHE_L2, cckd->l2active, ~L2_CACHE_ACTIVE, 0); cckd->l2 = NULL; cckd->l2active = cckd->sfx = cckd->l1x = -1; /* scan the cache array for the l2tab */ fnd = cache_lookup (CACHE_L2, L2_CACHE_SETKEY(sfx, dev->devnum, l1x), &lru); /* check for level 2 cache hit */ if (fnd >= 0) { cckd_trace (dev, "l2[%d,%d] cache[%d] hit\n", sfx, l1x, fnd); cache_setflag (CACHE_L2, fnd, 0, L2_CACHE_ACTIVE); cache_setage (CACHE_L2, fnd); cckdblk.stats_l2cachehits++; cache_unlock (CACHE_L2); cckd->sfx = sfx; cckd->l1x = l1x; cckd->l2 = cache_getbuf(CACHE_L2, fnd, 0); cckd->l2active = fnd; return 1; } cckd_trace (dev, "l2[%d,%d] cache[%d] miss\n", sfx, l1x, lru); /* Steal an entry if all are busy */ if (lru < 0) lru = cckd_steal_l2(); /* Make the entry active */ cache_setkey (CACHE_L2, lru, L2_CACHE_SETKEY(sfx, dev->devnum, l1x)); cache_setflag (CACHE_L2, lru, 0, L2_CACHE_ACTIVE); cache_setage (CACHE_L2, lru); buf = cache_getbuf(CACHE_L2, lru, CCKD_L2TAB_SIZE); cckdblk.stats_l2cachemisses++; cache_unlock (CACHE_L2); if (buf == NULL) return -1; /* Check for null table */ if (cckd->l1[sfx][l1x] == 0) { memset(buf, 0, CCKD_L2TAB_SIZE); if (nullfmt) for (i = 0; i < 256; i++) buf[i].len = buf[i].size = nullfmt; cckd_trace (dev, "l2[%d,%d] cache[%d] null fmt[%d]\n", sfx, l1x, lru, nullfmt); } else if (cckd->l1[sfx][l1x] == 0xffffffff) { memset(buf, 0xff, CCKD_L2TAB_SIZE); cckd_trace (dev, "l2[%d,%d] cache[%d] null 0xff\n", sfx, l1x, lru); } /* Read the new level 2 table */ else { off = (off_t)cckd->l1[sfx][l1x]; if (cckd_read (dev, sfx, off, buf, CCKD_L2TAB_SIZE) < 0) { cache_lock(CACHE_L2); cache_setflag(CACHE_L2, lru, 0, 0); cache_unlock(CACHE_L2); return -1; } if (cckd->swapend[sfx]) cckd_swapend_l2 (buf); cckd_trace (dev, "file[%d] cache[%d] l2[%d] read offset 0x%" I64_FMT "x\n", sfx, lru, l1x, (long long)cckd->l1[sfx][l1x]); cckd->l2reads[sfx]++; cckd->totl2reads++; cckdblk.stats_l2reads++; } cckd->sfx = sfx; cckd->l1x = l1x; cckd->l2 = buf; cckd->l2active = lru; return 0; } /* end function cckd_read_l2 */ /*-------------------------------------------------------------------*/ /* Purge all l2tab cache entries for a given device */ /*-------------------------------------------------------------------*/ void cckd_purge_l2 (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ cckd = dev->cckd_ext; cckd_trace (dev, "purge_l2%s\n", ""); cache_lock (CACHE_L2); cckd->l2active = cckd->sfx = cckd->l1x = -1; cckd->l2 = NULL; cache_scan (CACHE_L2, cckd_purge_l2_scan, dev); cache_unlock (CACHE_L2); } int cckd_purge_l2_scan (int *answer, int ix, int i, void *data) { U16 sfx; /* Cached suffix */ U16 devnum; /* Cached device number */ U32 l1x; /* Cached level 1 index */ DEVBLK *dev = data; /* -> device block */ UNREFERENCED(answer); L2_CACHE_GETKEY(i, sfx, devnum, l1x); if (dev == NULL || devnum == dev->devnum) { cckd_trace (dev, "purge l2cache[%d] %4.4X sfx %d ix %d purged\n", i, devnum, sfx, l1x); cache_release(ix, i, 0); } return 0; } /*-------------------------------------------------------------------*/ /* Steal an l2tab cache entry */ /*-------------------------------------------------------------------*/ int cckd_steal_l2 () { DEVBLK *dev; /* -> device block */ CCKDDASD_EXT *cckd; /* -> cckd extension */ int i; /* Stolen cache index */ U16 sfx; /* Cached suffix */ U16 devnum; /* Cached device number */ U32 l1x; /* Cached level 1 index */ i = cache_scan (CACHE_L2, cckd_steal_l2_scan, NULL); L2_CACHE_GETKEY(i, sfx, devnum, l1x); dev = cckd_find_device_by_devnum(devnum); cckd = dev->cckd_ext; cckd->l2active = cckd->sfx = cckd->l1x = -1; cckd->l2 = NULL; cache_release(CACHE_L2, i, 0); return i; } int cckd_steal_l2_scan (int *answer, int ix, int i, void *data) { UNREFERENCED(data); if (*answer < 0) *answer = i; else if (cache_getage(ix, i) < cache_getage(ix, *answer)) *answer = i; return 0; } /*-------------------------------------------------------------------*/ /* Write the current level 2 table */ /*-------------------------------------------------------------------*/ int cckd_write_l2 (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx,l1x; /* Lookup table indices */ off_t off, old_off; /* New/old L2 file offsets */ int size = CCKD_L2TAB_SIZE; /* L2 table size */ int fix; /* Null format type */ cckd = dev->cckd_ext; sfx = cckd->sfn; l1x = cckd->l1x; fix = cckd->cdevhdr[sfx].nullfmt; cckd->l2ok = 0; cckd_trace (dev, "file[%d] write_l2 %d\n", sfx, l1x); if (sfx < 0 || l1x < 0) return -1; old_off = (off_t)cckd->l1[sfx][l1x]; if (cckd->l1[sfx][l1x] == 0 || cckd->l1[sfx][l1x] == 0xffffffff) cckd->l2bounds += CCKD_L2TAB_SIZE; /* Write the L2 table if it's not empty */ if (memcmp(cckd->l2, &empty_l2[fix], CCKD_L2TAB_SIZE)) { if ((off = cckd_get_space (dev, &size, CCKD_L2SPACE)) < 0) return -1; if (cckd_write (dev, sfx, off, cckd->l2, CCKD_L2TAB_SIZE) < 0) return -1; } else { off = 0; cckd->l2bounds -= CCKD_L2TAB_SIZE; } /* Free the old L2 space */ cckd_rel_space (dev, old_off, CCKD_L2TAB_SIZE, CCKD_L2TAB_SIZE); /* Update level 1 table */ cckd->l1[sfx][l1x] = (U32)off; if (cckd_write_l1ent (dev, l1x) < 0) return -1; return 0; } /* end function cckd_write_l2 */ /*-------------------------------------------------------------------*/ /* Return a level 2 entry */ /*-------------------------------------------------------------------*/ int cckd_read_l2ent (DEVBLK *dev, CCKD_L2ENT *l2, int trk) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx,l1x,l2x; /* Lookup table indices */ cckd = dev->cckd_ext; l1x = trk >> 8; l2x = trk & 0xff; if (l2 != NULL) l2->pos = l2->len = l2->size = 0; for (sfx = cckd->sfn; sfx >= 0; sfx--) { cckd_trace (dev, "file[%d] l2[%d,%d] trk[%d] read_l2ent 0x%x\n", sfx, l1x, l2x, trk, cckd->l1[sfx][l1x]); /* Continue if l2 table not in this file */ if (cckd->l1[sfx][l1x] == 0xffffffff) continue; /* Read l2 table from this file */ if (cckd_read_l2 (dev, sfx, l1x) < 0) return -1; /* Exit loop if track is in this file */ if (cckd->l2[l2x].pos != 0xffffffff) break; } cckd_trace (dev, "file[%d] l2[%d,%d] trk[%d] read_l2ent 0x%x %d %d\n", sfx, l1x, l2x, trk, sfx >= 0 ? cckd->l2[l2x].pos : 0, sfx >= 0 ? cckd->l2[l2x].len : 0, sfx >= 0 ? cckd->l2[l2x].size : 0); if (l2 != NULL && sfx >= 0) { l2->pos = cckd->l2[l2x].pos; l2->len = cckd->l2[l2x].len; l2->size = cckd->l2[l2x].size; } return sfx; } /* end function cckd_read_l2ent */ /*-------------------------------------------------------------------*/ /* Update a level 2 entry */ /*-------------------------------------------------------------------*/ int cckd_write_l2ent (DEVBLK *dev, CCKD_L2ENT *l2, int trk) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx,l1x,l2x; /* Lookup table indices */ off_t off; /* L2 entry offset */ cckd = dev->cckd_ext; /* Error return if no available level 2 table */ if (!cckd->l2) return -1; sfx = cckd->sfn; l1x = trk >> 8; l2x = trk & 0xff; /* Copy the new entry if passed */ if (l2) memcpy (&cckd->l2[l2x], l2, CCKD_L2ENT_SIZE); cckd_trace (dev, "file[%d] l2[%d,%d] trk[%d] write_l2ent 0x%x %d %d\n", sfx, l1x, l2x, trk, cckd->l2[l2x].pos, cckd->l2[l2x].len, cckd->l2[l2x].size); /* If no level 2 table for this file, then write a new one */ if (cckd->l1[sfx][l1x] == 0 || cckd->l1[sfx][l1x] == 0xffffffff) return cckd_write_l2 (dev); /* Write the level 2 table entry */ off = (off_t)(cckd->l1[sfx][l1x] + l2x * CCKD_L2ENT_SIZE); if (cckd_write (dev, sfx, off, &cckd->l2[l2x], CCKD_L2ENT_SIZE) < 0) return -1; return 0; } /* end function cckd_write_l2ent */ /*-------------------------------------------------------------------*/ /* Read a track image */ /*-------------------------------------------------------------------*/ int cckd_read_trkimg (DEVBLK *dev, BYTE *buf, int trk, BYTE *unitstat) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ int sfx; /* File index */ CCKD_L2ENT l2; /* Level 2 entry */ cckd = dev->cckd_ext; cckd_trace (dev, "trk[%d] read_trkimg\n", trk); /* Read level 2 entry for the track */ if ((sfx = cckd_read_l2ent (dev, &l2, trk)) < 0) goto cckd_read_trkimg_error; /* Read the track image or build a null track image */ if (l2.pos != 0) { rc = cckd_read (dev, sfx, (off_t)l2.pos, buf, (size_t)l2.len); if (rc < 0) goto cckd_read_trkimg_error; cckd->reads[sfx]++; cckd->totreads++; cckdblk.stats_reads++; cckdblk.stats_readbytes += rc; if (cckd->notnull == 0 && trk > 1) cckd->notnull = 1; } else rc = cckd_null_trk (dev, buf, trk, l2.len); /* Validate the track image */ if (cckd_cchh (dev, buf, trk) < 0) goto cckd_read_trkimg_error; return rc; cckd_read_trkimg_error: if (unitstat) { ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; } return cckd_null_trk (dev, buf, trk, 0); } /* end function cckd_read_trkimg */ /*-------------------------------------------------------------------*/ /* Write a track image */ /*-------------------------------------------------------------------*/ int cckd_write_trkimg (DEVBLK *dev, BYTE *buf, int len, int trk, int flags) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ off_t off; /* File offset */ CCKD_L2ENT l2, oldl2; /* Level 2 entries */ int sfx,l1x,l2x; /* Lookup table indices */ int after = 0; /* 1=New track after old */ int size; /* Size of new track */ cckd = dev->cckd_ext; sfx = cckd->sfn; l1x = trk >> 8; l2x = trk & 0xff; cckd_trace (dev, "file[%d] trk[%d] write_trkimg len %d buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n", sfx, trk, len, buf, buf[0], buf[1], buf[2], buf[3], buf[4]); /* Validate the new track image */ if (cckd_cchh (dev, buf, trk) < 0) return -1; /* Get the level 2 table for the track in the active file */ if (cckd_read_l2 (dev, sfx, l1x) < 0) return -1; /* Save the level 2 entry for the track */ oldl2.pos = cckd->l2[l2x].pos; oldl2.len = cckd->l2[l2x].len; oldl2.size = cckd->l2[l2x].size; cckd_trace (dev, "file[%d] trk[%d] write_trkimg oldl2 0x%x %d %d\n", sfx, trk, oldl2.pos,oldl2.len,oldl2.size); /* Check if writing a null track */ len = cckd_check_null_trk(dev, buf, trk, len); if (len > CKDDASD_NULLTRK_FMTMAX) { /* Get space for the track image */ size = len; if ((off = cckd_get_space (dev, &size, flags)) < 0) return -1; l2.pos = (U32)off; l2.len = (U16)len; l2.size = (U16)size; if (oldl2.pos != 0 && oldl2.pos != 0xffffffff && oldl2.pos < l2.pos) after = 1; /* Write the track image */ if ((rc = cckd_write (dev, sfx, off, buf, len)) < 0) return -1; cckd->writes[sfx]++; cckd->totwrites++; cckdblk.stats_writes++; cckdblk.stats_writebytes += rc; } else { l2.pos = 0; l2.len = l2.size = (U16)len; } /* Update the level 2 entry */ if (cckd_write_l2ent (dev, &l2, trk) < 0) return -1; /* Release the previous space */ cckd_rel_space (dev, (off_t)oldl2.pos, (int)oldl2.len, (int)oldl2.size); /* `after' is 1 if the new offset is after the old offset */ return after; } /* end function cckd_write_trkimg */ /*-------------------------------------------------------------------*/ /* Harden the file */ /*-------------------------------------------------------------------*/ int cckd_harden(DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc=0; /* Return code */ cckd = dev->cckd_ext; if ((dev->ckdrdonly && cckd->sfn == 0) || cckd->open[cckd->sfn] != CCKD_OPEN_RW) return 0; cckd_trace (dev, "file[%d] harden\n", cckd->sfn); /* Write the compressed device header */ if (cckd_write_chdr (dev) < 0) rc = -1; /* Write the level 1 table */ if (cckd_write_l1 (dev) < 0) rc = -1; /* Write the free space chain */ if (cckd_write_fsp (dev) < 0) rc = -1; /* Re-write the compressed device header */ cckd->cdevhdr[cckd->sfn].options &= ~CCKD_OPENED; if (cckd_write_chdr (dev) < 0) rc = -1; if (cckdblk.fsync) fdatasync (cckd->fd[cckd->sfn]); return rc; } /* cckd_harden */ /*-------------------------------------------------------------------*/ /* Return length of an uncompressed track image */ /*-------------------------------------------------------------------*/ int cckd_trklen (DEVBLK *dev, BYTE *buf) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int size; /* Track size */ cckd = dev->cckd_ext; if (cckd->fbadasd) return CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE; for (size = CKDDASD_TRKHDR_SIZE; memcmp (&buf[size], &eighthexFF, 8) != 0; ) { if (size > dev->ckdtrksz) break; /* add length of count, key, and data fields */ size += CKDDASD_RECHDR_SIZE + buf[size+5] + (buf[size+6] << 8) + buf[size+7]; } /* add length for end-of-track indicator */ size += CKDDASD_RECHDR_SIZE; /* check for missing end-of-track indicator */ if (size > dev->ckdtrksz || memcmp (&buf[size-CKDDASD_RECHDR_SIZE], &eighthexFF, 8) != 0) { logmsg (_("HHCCD121E %4.4X file[%d] trklen err for %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cckd->sfn, buf[0], buf[1], buf[2], buf[3], buf[4]); size = -1; } return size; } /*-------------------------------------------------------------------*/ /* Build a null track */ /*-------------------------------------------------------------------*/ int cckd_null_trk(DEVBLK *dev, BYTE *buf, int trk, int nullfmt) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int i; /* Loop counter */ CKDDASD_TRKHDR *trkhdr; /* -> Track header */ CKDDASD_RECHDR *rechdr; /* -> Record header */ U32 cyl; /* Cylinder number */ U32 head; /* Head number */ BYTE r; /* Record number */ BYTE *pos; /* -> Next position in buffer*/ int len; /* Length of null track */ cckd = dev->cckd_ext; if (nullfmt < 0 || nullfmt > CKDDASD_NULLTRK_FMTMAX) nullfmt = cckd->cdevhdr[cckd->sfn].nullfmt; // FIXME // Compatibility check for nullfmt bug and linux -- 18 May 2005 // Remove at some reasonable date in the future else if (nullfmt == 0 && cckd->cdevhdr[cckd->sfn].nullfmt == CKDDASD_NULLTRK_FMT2) nullfmt = CKDDASD_NULLTRK_FMT2; if (cckd->ckddasd) { /* cylinder and head calculations */ cyl = trk / dev->ckdheads; head = trk % dev->ckdheads; /* Build the track header */ trkhdr = (CKDDASD_TRKHDR*)buf; trkhdr->bin = 0; store_hw(&trkhdr->cyl, cyl); store_hw(&trkhdr->head, head); pos = buf + CKDDASD_TRKHDR_SIZE; /* Build record zero */ r = 0; rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 8); memset (pos, 0, 8); pos += 8; r++; /* Specific null track formatting */ if (nullfmt == CKDDASD_NULLTRK_FMT0) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 0); r++; } else if (nullfmt == CKDDASD_NULLTRK_FMT2) { for (i = 0; i < 12; i++) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 4096); r++; memset(pos, 0, 4096); pos += 4096; } } /* Build the end of track marker */ memcpy (pos, eighthexFF, 8); pos += 8; len = (int)(pos - buf); } else { memset (buf, 0, CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE); store_fw(buf+1, trk); len = CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE; } cckd_trace (dev, "null_trk %s %d format %d size %d\n", cckd->ckddasd ? "trk" : "blkgrp", trk, nullfmt, len); return len; } /* end function cckd_null_trk */ /*-------------------------------------------------------------------*/ /* Return a number 0 .. CKDDASD_NULLTRK_FMTMAX if track is null */ /* else return the original length */ /*-------------------------------------------------------------------*/ int cckd_check_null_trk (DEVBLK *dev, BYTE *buf, int trk, int len) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ BYTE buf2[65536]; /* Null track buffer */ cckd = dev->cckd_ext; rc = len; if (len == CKDDASD_NULLTRK_SIZE0) rc = CKDDASD_NULLTRK_FMT0; else if (len == CKDDASD_NULLTRK_SIZE1) rc = CKDDASD_NULLTRK_FMT1; else if (len == CKDDASD_NULLTRK_SIZE2 && dev->oslinux && (!cckd->notnull || cckdblk.linuxnull)) { cckd_null_trk (dev, buf2, trk, 0); if (memcmp(buf, buf2, len) == 0) rc = CKDDASD_NULLTRK_FMT2; } return rc; } /*-------------------------------------------------------------------*/ /* Verify a track/block header and return track/block number */ /*-------------------------------------------------------------------*/ int cckd_cchh (DEVBLK *dev, BYTE *buf, int trk) { CCKDDASD_EXT *cckd; /* -> cckd extension */ U16 cyl; /* Cylinder */ U16 head; /* Head */ int t; /* Calculated track */ BYTE badcomp=0; /* 1=Unsupported compression */ static char *comp[] = {"none", "zlib", "bzip2"}; cckd = dev->cckd_ext; /* CKD dasd header verification */ if (cckd->ckddasd) { cyl = fetch_hw (buf + 1); head = fetch_hw (buf + 3); t = cyl * dev->ckdheads + head; if (cyl < dev->ckdcyls && head < dev->ckdheads && (trk == -1 || t == trk)) { if (buf[0] & ~cckdblk.comps) { if (buf[0] & ~CCKD_COMPRESS_MASK) { if (cckdblk.bytemsgs++ < 10) logmsg (_("HHCCD122E %4.4X file[%d] invalid byte 0 trk %d: " "buf %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cckd->sfn, t, buf[0],buf[1],buf[2],buf[3],buf[4]); buf[0] &= CCKD_COMPRESS_MASK; } } if (buf[0] & ~cckdblk.comps) badcomp = 1; else return t; } } /* FBA dasd header verification */ else { t = fetch_fw (buf + 1); if (t < dev->fbanumblk && (trk == -1 || t == trk)) { if (buf[0] & ~cckdblk.comps) { if (buf[0] & ~CCKD_COMPRESS_MASK) { logmsg (_("HHCCD123E %4.4X file[%d] invalid byte 0 blkgrp %d: " "buf %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cckd->sfn, t, buf[0],buf[1],buf[2],buf[3],buf[4]); buf[0] &= CCKD_COMPRESS_MASK; } } if (buf[0] & ~cckdblk.comps) badcomp = 1; else return t; } } if (badcomp) { logmsg (_("HHCCD124E %4.4X file[%d] invalid %s hdr %s %d: " "%s compression unsupported\n"), dev->devnum, cckd->sfn, cckd->ckddasd ? "trk" : "blk", cckd->ckddasd ? "trk" : "blk", t, comp[buf[0]]); } else { logmsg (_("HHCCD125E %4.4X file[%d] invalid %s hdr %s %d " "buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cckd->sfn, cckd->ckddasd ? "trk" : "blk", cckd->ckddasd ? "trk" : "blk", trk, buf, buf[0], buf[1], buf[2], buf[3], buf[4]); cckd_print_itrace (); } return -1; } /* end function cckd_cchh */ /*-------------------------------------------------------------------*/ /* Validate a track image */ /*-------------------------------------------------------------------*/ int cckd_validate (DEVBLK *dev, BYTE *buf, int trk, int len) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int cyl; /* Cylinder */ int head; /* Head */ char cchh[4],cchh2[4]; /* Cyl, head big-endian */ int r; /* Record number */ int sz; /* Track size */ int vlen; /* Validation length */ int kl,dl; /* Key/Data lengths */ cckd = dev->cckd_ext; if (buf == NULL || len < 0) return -1; cckd_trace (dev, "validating %s %d len %d %2.2x%2.2x%2.2x%2.2x%2.2x " "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", cckd->ckddasd ? "trk" : "blkgrp", trk, len, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12]); /* FBA dasd check */ if (cckd->fbadasd) { if (len == CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE || len == 0) return len; cckd_trace (dev, "validation failed: bad length%s\n",""); return -1; } /* cylinder and head calculations */ cyl = trk / dev->ckdheads; head = trk % dev->ckdheads; cchh[0] = cyl >> 8; cchh[1] = cyl & 0xFF; cchh[2] = head >> 8; cchh[3] = head & 0xFF; /* validate record 0 */ memcpy (cchh2, &buf[5], 4); cchh2[0] &= 0x7f; /* fix for ovflow */ if (/* memcmp (cchh, cchh2, 4) != 0 || */ buf[9] != 0 || buf[10] != 0 || buf[11] != 0 || buf[12] != 8) { cckd_trace (dev, "validation failed: bad r0%s\n",""); return -1; } /* validate records 1 thru n */ vlen = len > 0 ? len : dev->ckdtrksz; for (r = 1, sz = 21; sz + 8 <= vlen; sz += 8 + kl + dl, r++) { if (memcmp (&buf[sz], eighthexFF, 8) == 0) break; kl = buf[sz+5]; dl = buf[sz+6] * 256 + buf[sz+7]; /* fix for track overflow bit */ memcpy (cchh2, &buf[sz], 4); cchh2[0] &= 0x7f; /* fix for funny formatted vm disks */ /* if (r == 1) memcpy (cchh, cchh2, 4); */ if (/*memcmp (cchh, cchh2, 4) != 0 ||*/ buf[sz+4] == 0 || sz + 8 + kl + dl >= vlen) { cckd_trace (dev, "validation failed: bad r%d " "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", r, buf[sz], buf[sz+1], buf[sz+2], buf[sz+3], buf[sz+4], buf[sz+5], buf[sz+6], buf[sz+7]); return -1; } } sz += 8; if ((sz != len && len > 0) || sz > vlen) { cckd_trace (dev, "validation failed: no eot%s\n",""); return -1; } return sz; } /* end function cckd_validate */ /*-------------------------------------------------------------------*/ /* Return shadow file name */ /*-------------------------------------------------------------------*/ char *cckd_sf_name (DEVBLK *dev, int sfx) { /* Return base file name if index is 0 */ if (sfx == 0) return dev->filename; /* Error if no shadow file name specified or number exceeded */ if (dev->dasdsfn == NULL || sfx > CCKD_MAX_SF) return NULL; /* Set the suffix character in the shadow file name */ if (sfx > 0) *dev->dasdsfx = '0' + sfx; else *dev->dasdsfx = '*'; return dev->dasdsfn; } /* end function cckd_sf_name */ /*-------------------------------------------------------------------*/ /* Initialize shadow files */ /*-------------------------------------------------------------------*/ int cckd_sf_init (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ int i; /* Index */ struct stat st; /* stat() buffer */ char pathname[MAX_PATH]; /* file path in host format */ cckd = dev->cckd_ext; /* return if no shadow files */ if (dev->dasdsfn == NULL) return 0; #if 1 /* Check for shadow file name collision */ for (i = 1; i <= CCKD_MAX_SF && dev->dasdsfn != NULL; i++) { DEVBLK *dev2; CCKDDASD_EXT *cckd2; int j; for (dev2 = cckdblk.dev1st; dev2; dev2 = cckd2->devnext) { cckd2 = dev2->cckd_ext; if (dev2 == dev) continue; for (j = 0; j <= CCKD_MAX_SF && dev2->dasdsfn != NULL; j++) { if (strcmp (cckd_sf_name(dev, i),cckd_sf_name(dev2, j)) == 0) { logmsg (_("HHCCD142E %4.4X file[%d] shadow file name %s\n" " collides with %4.4X file[%d] name %s\n"), dev->devnum, i, cckd_sf_name(dev, i), dev2->devnum, j, cckd_sf_name(dev2, j)); return -1; } } } } #endif /* open all existing shadow files */ for (cckd->sfn = 1; cckd->sfn <= CCKD_MAX_SF; cckd->sfn++) { hostpath(pathname, cckd_sf_name (dev, cckd->sfn), sizeof(pathname)); if (stat (pathname, &st) < 0) break; /* Try to open the shadow file read-write then read-only */ if (cckd_open (dev, cckd->sfn, O_RDWR|O_BINARY, 1) < 0) if (cckd_open (dev, cckd->sfn, O_RDONLY|O_BINARY, 0) < 0) break; /* Call the chkdsk function */ rc = cckd_chkdsk (dev, 0); if (rc < 0) return -1; /* Perform initial read */ rc = cckd_read_init (dev); } /* Backup to the last opened file number */ cckd->sfn--; /* If the last file was opened read-only then create a new one */ if (cckd->open[cckd->sfn] == CCKD_OPEN_RO) if (cckd_sf_new(dev) < 0) return -1; /* Re-open previous rdwr files rdonly */ for (i = 0; i < cckd->sfn; i++) { if (cckd->open[i] == CCKD_OPEN_RO) continue; if (cckd_open (dev, i, O_RDONLY|O_BINARY, 0) < 0) { logmsg (_("HHCCD151E %4.4X file[%d] error re-opening %s readonly\n %s\n"), dev->devnum, i, cckd_sf_name(dev, i), strerror(errno)); return -1; } } return 0; } /* end function cckd_sf_init */ /*-------------------------------------------------------------------*/ /* Create a new shadow file */ /*-------------------------------------------------------------------*/ int cckd_sf_new (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int l1size; /* Size of level 1 table */ CKDDASD_DEVHDR devhdr; /* Device header */ cckd = dev->cckd_ext; cckd_trace (dev, "file[%d] sf_new %s\n", cckd->sfn+1, cckd_sf_name(dev, cckd->sfn+1) ? (char *)cckd_sf_name(dev, cckd->sfn+1) : "(none)"); /* Error if no shadow file name */ if (dev->dasdsfn == NULL) { logmsg (_("HHCCD161E %4.4X file[%d] no shadow file name\n"), dev->devnum, cckd->sfn+1); return -1; } /* Error if max number of shadow files exceeded */ if (cckd->sfn+1 == CCKD_MAX_SF) { logmsg (_("HHCCD161E %4.4X file[%d] max shadow files exceeded\n"), dev->devnum, cckd->sfn+1); return -1; } /* Harden the current file */ cckd_harden (dev); /* Open the new shadow file */ if (cckd_open(dev, cckd->sfn+1, O_RDWR|O_CREAT|O_EXCL|O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP) < 0) return -1; /* Read previous file's device header */ if (cckd_read (dev, cckd->sfn, 0, &devhdr, CKDDASD_DEVHDR_SIZE) < 0) goto sf_new_error; /* Make sure identifier is CKD_S370 or FBA_S370 */ devhdr.devid[4] = 'S'; /* Write new file's device header */ if (cckd_write (dev, cckd->sfn+1, 0, &devhdr, CKDDASD_DEVHDR_SIZE) < 0) goto sf_new_error; /* Build the compressed device header */ memcpy (&cckd->cdevhdr[cckd->sfn+1], &cckd->cdevhdr[cckd->sfn], CCKDDASD_DEVHDR_SIZE); l1size = cckd->cdevhdr[cckd->sfn+1].numl1tab * CCKD_L1ENT_SIZE; cckd->cdevhdr[cckd->sfn+1].size = cckd->cdevhdr[cckd->sfn+1].used = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1size; cckd->cdevhdr[cckd->sfn+1].free = cckd->cdevhdr[cckd->sfn+1].free_total = cckd->cdevhdr[cckd->sfn+1].free_largest = cckd->cdevhdr[cckd->sfn+1].free_number = cckd->cdevhdr[cckd->sfn+1].free_imbed = 0; /* Init the level 1 table */ if ((cckd->l1[cckd->sfn+1] = cckd_malloc (dev, "l1", l1size)) == NULL) goto sf_new_error; memset (cckd->l1[cckd->sfn+1], 0xff, l1size); /* Make the new file active */ cckd->sfn++; /* Harden the new file */ if (cckd_harden (dev) < 0) { cckd->sfn--; goto sf_new_error; } /* Re-read the l1 to set l2bounds, l2ok */ cckd_read_l1 (dev); return 0; sf_new_error: cckd->l1[cckd->sfn+1] = cckd_free(dev, "l1", cckd->l1[cckd->sfn+1]); cckd_close (dev, cckd->sfn+1); cckd->open[cckd->sfn+1] = CCKD_OPEN_NONE; unlink (cckd_sf_name (dev, cckd->sfn+1)); /* Re-read the l1 to set l2bounds, l2ok */ cckd_read_l1 (dev); return -1; } /* end function cckd_sf_new */ /*-------------------------------------------------------------------*/ /* Add a shadow file (sf+) */ /*-------------------------------------------------------------------*/ void *cckd_sf_add (void *data) { DEVBLK *dev = data; /* -> DEVBLK */ CCKDDASD_EXT *cckd; /* -> cckd extension */ int syncio; /* Saved syncio bit */ if (dev == NULL) { int n = 0; for (dev=sysblk.firstdev; dev; dev=dev->nextdev) if (dev->cckd_ext) { logmsg( _("HHCCD207I Adding device %d:%4.4X\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); cckd_sf_add (dev); n++; } logmsg( _("HHCCD092I %d devices processed\n"), n ); return NULL; } cckd = dev->cckd_ext; if (!cckd) { logmsg (_("HHCCD160E %4.4X not a cckd device\n"), dev->devnum); return NULL; } /* Disable synchronous I/O for the device */ syncio = cckd_disable_syncio(dev); /* Schedule updated track entries to be written */ obtain_lock (&cckd->iolock); if (cckd->merging) { dev->syncio = syncio; release_lock (&cckd->iolock); logmsg (_("HHCCD165W %4.4X error adding shadow file, " "sf command busy on device\n"), dev->devnum,cckd->sfn); return NULL; } cckd->merging = 1; cckd_flush_cache (dev); while (cckd->wrpending || cckd->ioactive) { cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; cckd_flush_cache (dev); } cckd_purge_cache (dev); cckd_purge_l2 (dev); dev->bufcur = dev->cache = -1; release_lock (&cckd->iolock); /* Obtain control of the file */ obtain_lock (&cckd->filelock); /* Harden the current file */ cckd_harden (dev); /* Create a new shadow file */ if (cckd_sf_new (dev) < 0) { logmsg (_("HHCCD161E %4.4X file[%d] error adding shadow file\n"), dev->devnum, cckd->sfn+1); goto cckd_sf_add_exit; } /* Re-open the previous file if opened read-write */ if (cckd->open[cckd->sfn-1] == CCKD_OPEN_RW) cckd_open (dev, cckd->sfn-1, O_RDONLY|O_BINARY, 0); logmsg (_("HHCCD162I %4.4X file[%d] %s added\n"), dev->devnum, cckd->sfn, cckd_sf_name (dev, cckd->sfn)); cckd_sf_add_exit: /* Re-read the l1 to set l2bounds, l2ok */ cckd_read_l1 (dev); release_lock (&cckd->filelock); obtain_lock (&cckd->iolock); cckd->merging = 0; if (cckd->iowaiters) broadcast_condition (&cckd->iocond); dev->syncio = syncio; release_lock (&cckd->iolock); cckd_sf_stats (dev); return NULL; } /* end function cckd_sf_add */ /*-------------------------------------------------------------------*/ /* Remove a shadow file (sf-) */ /*-------------------------------------------------------------------*/ void *cckd_sf_remove (void *data) { DEVBLK *dev = data; /* -> DEVBLK */ CCKDDASD_EXT *cckd; /* -> cckd extension */ int syncio; /* Saved syncio bit */ int rc; /* Return code */ int from_sfx, to_sfx; /* From/to file index */ int fix; /* nullfmt index */ int add = 0; /* 1=Add shadow file back */ int l2updated = 0; /* 1=L2 table was updated */ int i,j; /* Loop indexes */ int merge, force; /* Flags */ off_t pos; /* File offset */ size_t len; /* Length to read/write */ int size; /* Image size */ int trk = -1; /* Track being read/written */ CCKD_L2ENT from_l2[256], /* Level 2 tables */ to_l2[256]; CCKD_L2ENT new_l2; /* New level 2 table entry */ BYTE buf[65536]; /* Buffer */ if (dev == NULL) { int n = 0; merge = cckdblk.sfmerge; force = cckdblk.sfforce; cckdblk.sfmerge = cckdblk.sfforce = 0; for (dev=sysblk.firstdev; dev; dev=dev->nextdev) if ((cckd = dev->cckd_ext)) { logmsg( _("HHCCD179I Merging device %d:%4.4X\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); cckd->sfmerge = merge; cckd->sfforce = force; cckd_sf_remove (dev); n++; } logmsg( _("HHCCD092I %d devices processed\n"), n ); return NULL; } cckd = dev->cckd_ext; if (!cckd) { logmsg (_("HHCCD170E %4.4X not a cckd device\n"), dev ? dev->devnum : 0); return NULL; } /* Set flags */ merge = cckd->sfmerge || cckd->sfforce; force = cckd->sfforce; cckd->sfmerge = cckd->sfforce = 0; cckd_trace (dev, "merge starting: %s %s\n", merge ? "merge" : "nomerge", force ? "force" : ""); /* Disable synchronous I/O for the device */ syncio = cckd_disable_syncio(dev); /* Schedule updated track entries to be written */ obtain_lock (&cckd->iolock); if (cckd->merging) { dev->syncio = syncio; release_lock (&cckd->iolock); logmsg (_("HHCCD175W %4.4X file[%d] merge failed, " "sf command busy on device\n"), dev->devnum,cckd->sfn); return NULL; } cckd->merging = 1; cckd_flush_cache (dev); while (cckd->wrpending || cckd->ioactive) { cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; cckd_flush_cache (dev); } cckd_purge_cache (dev); cckd_purge_l2 (dev); dev->bufcur = dev->cache = -1; release_lock (&cckd->iolock); obtain_lock (&cckd->filelock); if (cckd->sfn == 0) { dev->syncio = syncio; release_lock (&cckd->filelock); logmsg (_("HHCCD171E %4.4X file[%d] cannot remove base file\n"), dev->devnum,cckd->sfn); cckd->merging = 0; return NULL; } from_sfx = cckd->sfn; to_sfx = cckd->sfn - 1; fix = cckd->cdevhdr[to_sfx].nullfmt; /* Harden the `from' file */ if (cckd_harden (dev) < 0) { logmsg (_("HHCCD174E %4.4X file[%d] not merged, " "file[%d] not hardened\n"), dev->devnum, from_sfx, from_sfx); goto sf_remove_exit; } /* Attempt to re-open the `to' file read-write */ cckd_close (dev, to_sfx); if (to_sfx > 0 || !dev->ckdrdonly || force) cckd_open (dev, to_sfx, O_RDWR|O_BINARY, 1); if (cckd->fd[to_sfx] < 0) { /* `from' file can't be opened read-write */ cckd_open (dev, to_sfx, O_RDONLY|O_BINARY, 0); if (merge) { logmsg (_("HHCCD172E %4.4X file[%d] not merged, " "file[%d] cannot be opened read-write%s\n"), dev->devnum, from_sfx, to_sfx, to_sfx == 0 && dev->ckdrdonly && !force ? ", try `force'" : ""); goto sf_remove_exit; } else add = 1; } else { /* `from' file opened read-write */ cckd->sfn = to_sfx; if (cckd_chkdsk (dev, 0) < 0) { cckd->sfn = from_sfx; logmsg (_("HHCCD173E %4.4X file[%d] not merged, " "file[%d] check failed\n"), dev->devnum, to_sfx, to_sfx); goto sf_remove_exit; } } cckd->sfn = to_sfx; /* Perform backwards merge */ if (merge) { cckd_trace (dev, "merging to file[%d]\n", to_sfx); /* Make the target file the active file */ cckd->sfn = to_sfx; cckd->cdevhdr[to_sfx].options |= (CCKD_OPENED | CCKD_ORDWR); /* Loop for each level 1 table entry */ for (i = 0; i < cckd->cdevhdr[from_sfx].numl1tab; i++) { l2updated = 0; /* Continue if from L2 doesn't exist */ if (cckd->l1[from_sfx][i] == 0xffffffff || (cckd->l1[from_sfx][i] == 0 && cckd->l1[to_sfx][i] == 0)) continue; trk = i*256; /* Read `from' l2 table */ if (cckd->l1[from_sfx][i] == 0) memset (&from_l2, 0, CCKD_L2TAB_SIZE); else { pos = (off_t)cckd->l1[from_sfx][i]; if (cckd_read(dev, from_sfx, pos, &from_l2, CCKD_L2TAB_SIZE) < 0) goto sf_merge_error; } /* Read `to' l2 table */ if (cckd->l1[to_sfx][i] == 0) memset (&to_l2, 0, CCKD_L2TAB_SIZE); else if (cckd->l1[to_sfx][i] == 0xffffffff) memset (&to_l2, 0xff, CCKD_L2TAB_SIZE); else { pos = (off_t)cckd->l1[to_sfx][i]; if (cckd_read(dev, to_sfx, pos, &to_l2, CCKD_L2TAB_SIZE) < 0) goto sf_merge_error; } /* Loop for each level 2 table entry */ for (j = 0; j < 256; j++) { trk = i*256 + j; /* Continue if from L2 entry doesn't exist */ if (from_l2[j].pos == 0xffffffff || (from_l2[j].pos == 0 && to_l2[j].pos == 0)) continue; /* Read the `from' track/blkgrp image */ len = (int)from_l2[j].len; if (len > CKDDASD_NULLTRK_FMTMAX) { pos = (off_t)from_l2[j].pos; if (cckd_read (dev, from_sfx, pos, buf, len) < 0) goto sf_merge_error; /* Get space for the `to' track/blkgrp image */ size = len; if ((pos = cckd_get_space (dev, &size, CCKD_SIZE_EXACT)) < 0) goto sf_merge_error; new_l2.pos = (U32)pos; new_l2.len = (U16)len; new_l2.size = (U16)size; /* Write the `to' track/blkgrp image */ if (cckd_write(dev, to_sfx, pos, buf, len) < 0) goto sf_merge_error; } else { new_l2.pos = 0; new_l2.len = new_l2.size = (U16)len; } /* Release space occupied by old `to' entry */ cckd_rel_space (dev, (off_t)to_l2[j].pos, (int)to_l2[j].len, (int)to_l2[j].size); /* Update `to' l2 table entry */ l2updated = 1; to_l2[j].pos = new_l2.pos; to_l2[j].len = new_l2.len; to_l2[j].size = new_l2.size; } /* for each level 2 table entry */ /* Update the `to' level 2 table */ if (l2updated) { l2updated = 0; pos = (off_t)cckd->l1[to_sfx][i]; if (memcmp (&to_l2, &empty_l2[fix], CCKD_L2TAB_SIZE) == 0) { cckd_rel_space (dev, pos, CCKD_L2TAB_SIZE, CCKD_L2TAB_SIZE); pos = 0; } else { size = CCKD_L2TAB_SIZE; if (pos == 0 || pos == (off_t)0xffffffff) if ((pos = cckd_get_space (dev, &size, CCKD_L2SPACE)) < 0) goto sf_merge_error; if (cckd_write(dev, to_sfx, pos, &to_l2, CCKD_L2TAB_SIZE) < 0) goto sf_merge_error; } /* `to' level 2 table not null */ /* Update the level 1 table index */ cckd->l1[to_sfx][i] = (U32)pos; /* Flush free space */ cckd_flush_space (dev); } /* Update level 2 table */ } /* For each level 1 table entry */ /* Validate the merge */ cckd_harden (dev); cckd_chkdsk (dev, 0); cckd_read_init (dev); } /* if merge */ /* Remove the old file */ cckd_close (dev, from_sfx); cckd->l1[from_sfx] = cckd_free (dev, "l1", cckd->l1[from_sfx]); memset (&cckd->cdevhdr[from_sfx], 0, CCKDDASD_DEVHDR_SIZE); rc = unlink (cckd_sf_name (dev, from_sfx)); /* Add the file back if necessary */ if (add) rc = cckd_sf_new (dev) ; logmsg (_("HHCCD181I %4.4X shadow file [%d] successfully %s\n"), dev->devnum, from_sfx, merge ? "merged" : add ? "re-added" : "removed"); sf_remove_exit: /* Re-read the l1 to set l2bounds, l2ok */ cckd_read_l1 (dev); release_lock (&cckd->filelock); obtain_lock (&cckd->iolock); cckd_purge_cache (dev); cckd_purge_l2 (dev); dev->bufcur = dev->cache = -1; cckd->merging = 0; if (cckd->iowaiters) broadcast_condition (&cckd->iocond); dev->syncio = syncio; cckd_trace (dev, "merge complete%s\n",""); release_lock (&cckd->iolock); cckd_sf_stats (dev); return NULL; sf_merge_error: if (trk < 0) logmsg (_("HHCCD180E %4.4X file[%d] not merged, error during merge\n"), dev->devnum, from_sfx); else logmsg (_("HHCCD180E %4.4X file[%d] not merged, error processing trk %d\n"), dev->devnum, from_sfx, trk); if (l2updated && cckd->l1[to_sfx][i] && cckd->l1[to_sfx][i] != 0xffffffff) { l2updated = 0; pos = (off_t)cckd->l1[to_sfx][i]; cckd_write(dev, to_sfx, pos, &to_l2, CCKD_L2TAB_SIZE); } cckd_harden(dev); cckd_chkdsk (dev, 2); cckd->sfn = from_sfx; cckd_harden(dev); cckd_chkdsk (dev, 2); goto sf_remove_exit; } /* end function cckd_sf_remove */ /*-------------------------------------------------------------------*/ /* Check and compress a shadow file (sfc) */ /*-------------------------------------------------------------------*/ void *cckd_sf_comp (void *data) { DEVBLK *dev = data; /* -> DEVBLK */ CCKDDASD_EXT *cckd; /* -> cckd extension */ int syncio; /* Saved syncio bit */ int rc; /* Return code */ if (dev == NULL) { int n = 0; for (dev=sysblk.firstdev; dev; dev=dev->nextdev) if (dev->cckd_ext) { logmsg( _("HHCCD207I Compressing device %d:%4.4X\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); cckd_sf_comp (dev); n++; } logmsg( _("HHCCD092I %d devices processed\n"), n ); return NULL; } cckd = dev->cckd_ext; if (!cckd) { logmsg (_("HHCCD205W %4.4X device is not a cckd device\n"), dev->devnum); return NULL; } /* Disable synchronous I/O for the device */ syncio = cckd_disable_syncio(dev); /* schedule updated track entries to be written */ obtain_lock (&cckd->iolock); if (cckd->merging) { dev->syncio = syncio; release_lock (&cckd->iolock); logmsg (_("HHCCD206W %4.4X file[%d] compress failed, " "sf command busy on device\n"), dev->devnum,cckd->sfn); return NULL; } cckd->merging = 1; cckd_flush_cache (dev); while (cckd->wrpending || cckd->ioactive) { cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; cckd_flush_cache (dev); } cckd_purge_cache (dev); cckd_purge_l2 (dev); dev->bufcur = dev->cache = -1; release_lock (&cckd->iolock); /* obtain control of the file */ obtain_lock (&cckd->filelock); /* harden the current file */ cckd_harden (dev); /* Call the compress function */ rc = cckd_comp (dev); /* Perform initial read */ rc = cckd_read_init (dev); release_lock (&cckd->filelock); obtain_lock (&cckd->iolock); cckd->merging = 0; if (cckd->iowaiters) broadcast_condition (&cckd->iocond); dev->syncio = syncio; release_lock (&cckd->iolock); /* Display the shadow file statistics */ cckd_sf_stats (dev); return NULL; } /* end function cckd_sf_comp */ /*-------------------------------------------------------------------*/ /* Check a shadow file (sfk) */ /*-------------------------------------------------------------------*/ void *cckd_sf_chk (void *data) { DEVBLK *dev = data; /* -> DEVBLK */ CCKDDASD_EXT *cckd; /* -> cckd extension */ int syncio; /* Saved syncio bit */ int rc; /* Return code */ int level = 2; /* Check level */ if (dev == NULL) { int n = 0; level = cckdblk.sflevel; cckdblk.sflevel = 0; for (dev=sysblk.firstdev; dev; dev=dev->nextdev) if ((cckd = dev->cckd_ext)) { logmsg( _("HHCCD207I Checking device %d:%4.4X level %d\n"), SSID_TO_LCSS(dev->ssid), dev->devnum, level ); cckd->sflevel = level; cckd_sf_chk (dev); n++; } logmsg( _("HHCCD092I %d devices processed\n"), n ); return NULL; } cckd = dev->cckd_ext; if (!cckd) { logmsg (_("HHCCD205W %4.4X device is not a cckd device\n"), dev->devnum); return NULL; } level = cckd->sflevel; cckd->sflevel = 0; /* Disable synchronous I/O for the device */ syncio = cckd_disable_syncio(dev); /* schedule updated track entries to be written */ obtain_lock (&cckd->iolock); if (cckd->merging) { dev->syncio = syncio; release_lock (&cckd->iolock); logmsg (_("HHCCD206W %4.4X file[%d] check failed, " "sf command busy on device\n"), dev->devnum,cckd->sfn); return NULL; } cckd->merging = 1; cckd_flush_cache (dev); while (cckd->wrpending || cckd->ioactive) { cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; cckd_flush_cache (dev); } cckd_purge_cache (dev); cckd_purge_l2 (dev); dev->bufcur = dev->cache = -1; release_lock (&cckd->iolock); /* obtain control of the file */ obtain_lock (&cckd->filelock); /* harden the current file */ cckd_harden (dev); /* Call the chkdsk function */ rc = cckd_chkdsk (dev, level); /* Perform initial read */ rc = cckd_read_init (dev); release_lock (&cckd->filelock); obtain_lock (&cckd->iolock); cckd->merging = 0; if (cckd->iowaiters) broadcast_condition (&cckd->iocond); dev->syncio = syncio; release_lock (&cckd->iolock); /* Display the shadow file statistics */ cckd_sf_stats (dev); return NULL; } /* end function cckd_sf_chk */ /*-------------------------------------------------------------------*/ /* Display shadow file statistics (sfd) */ /*-------------------------------------------------------------------*/ void *cckd_sf_stats (void *data) { DEVBLK *dev = data; /* -> DEVBLK */ CCKDDASD_EXT *cckd; /* -> cckd extension */ struct stat st; /* File information */ int i; /* Index */ int rc; /* Return code */ char *ost[] = {" ", "ro", "rd", "rw"}; unsigned long long size=0,free=0; /* Total size, free space */ int freenbr=0; /* Total number free spaces */ if (dev == NULL) { int n = 0; for (dev=sysblk.firstdev; dev; dev=dev->nextdev) if (dev->cckd_ext) { logmsg( _("HHCCD208I Displaying device %d:%4.4X\n"), SSID_TO_LCSS(dev->ssid), dev->devnum ); cckd_sf_stats (dev); n++; } logmsg( _("HHCCD092I %d devices processed\n"), n ); return NULL; } cckd = dev->cckd_ext; if (!cckd) { logmsg (_("HHCCD209W %4.4X device is not a cckd device\n")); return NULL; } // obtain_lock (&cckd->filelock); /* Calculate totals */ rc = fstat (cckd->fd[0], &st); for (i = 0; i <= cckd->sfn; i++) { if (!i) size = st.st_size; else size += cckd->cdevhdr[i].size; free += cckd->cdevhdr[i].free_total; freenbr += cckd->cdevhdr[i].free_number; } /* header */ logmsg (_("HHCCD210I size free nbr st reads writes l2reads hits switches\n")); if (cckd->readaheads || cckd->misses) logmsg (_("HHCCD211I readaheads misses\n")); logmsg (_("HHCCD212I --------------------------------------------------------------------\n")); /* total statistics */ logmsg (_("HHCCD213I [*] %10" I64_FMT "d %3" I64_FMT "d%% %4d %7d %7d %7d %7d %7d\n"), size, (free * 100) / size, freenbr, cckd->totreads, cckd->totwrites, cckd->totl2reads, cckd->cachehits, cckd->switches); if (cckd->readaheads || cckd->misses) logmsg (_("HHCCD214I %7d %7d\n"), cckd->readaheads, cckd->misses); /* base file statistics */ logmsg (_("HHCCD215I %s\n"), dev->filename); logmsg (_("HHCCD216I [0] %10" I64_FMT "d %3" I64_FMT "d%% %4d %s %7d %7d %7d\n"), (long long)st.st_size, (long long)((long long)((long long)cckd->cdevhdr[0].free_total * 100) / st.st_size), cckd->cdevhdr[0].free_number, ost[cckd->open[0]], cckd->reads[0], cckd->writes[0], cckd->l2reads[0]); if (dev->dasdsfn != NULL && CCKD_MAX_SF > 0) logmsg (_("HHCCD217I %s\n"), cckd_sf_name(dev, -1)); /* shadow file statistics */ for (i = 1; i <= cckd->sfn; i++) { logmsg (_("HHCCD218I [%d] %10" I64_FMT "d %3" I64_FMT "d%% %4d %s %7d %7d %7d\n"), i, (long long)cckd->cdevhdr[i].size, (long long)((long long)((long long)cckd->cdevhdr[i].free_total * 100) / cckd->cdevhdr[i].size), cckd->cdevhdr[i].free_number, ost[cckd->open[i]], cckd->reads[i], cckd->writes[i], cckd->l2reads[i]); } // release_lock (&cckd->filelock); return NULL; } /* end function cckd_sf_stats */ /*-------------------------------------------------------------------*/ /* Disable synchronous I/O for a device */ /*-------------------------------------------------------------------*/ int cckd_disable_syncio(DEVBLK *dev) { if (!dev->syncio) return 0; obtain_lock(&dev->lock); while (dev->syncio_active) { release_lock(&dev->lock); usleep(500); obtain_lock(&dev->lock); } dev->syncio = 0; release_lock(&dev->lock); cckd_trace (dev, "syncio disabled%s\n",""); return 1; } /*-------------------------------------------------------------------*/ /* Lock/unlock the device chain */ /*-------------------------------------------------------------------*/ void cckd_lock_devchain(int flag) { //struct timespec tm; //struct timeval now; //int timeout; obtain_lock(&cckdblk.devlock); while ((flag && cckdblk.devusers != 0) || (!flag && cckdblk.devusers < 0)) { //gettimeofday(&now,NULL); //tm.tv_sec = now.tv_sec + 2; //tm.tv_nsec = now.tv_usec * 1000; cckdblk.devwaiters++; wait_condition(&cckdblk.devcond, &cckdblk.devlock); //timeout = timed_wait_condition(&cckdblk.devcond, &cckdblk.devlock, &tm); //if (timeout) cckd_print_itrace(); cckdblk.devwaiters--; } if (flag) cckdblk.devusers--; else cckdblk.devusers++; release_lock(&cckdblk.devlock); } void cckd_unlock_devchain() { obtain_lock(&cckdblk.devlock); if (cckdblk.devusers < 0) cckdblk.devusers++; else cckdblk.devusers--; if (cckdblk.devusers == 0 && cckdblk.devwaiters) signal_condition(&cckdblk.devcond); release_lock(&cckdblk.devlock); } /*-------------------------------------------------------------------*/ /* Garbage Collection thread */ /*-------------------------------------------------------------------*/ void cckd_gcol() { int gcol; /* Identifier */ int rc; /* Return code */ DEVBLK *dev; /* -> device block */ CCKDDASD_EXT *cckd; /* -> cckd extension */ long long size, fsiz; /* File size, free size */ struct timeval tv_now; /* Time-of-day (as timeval) */ time_t tt_now; /* Time-of-day (as time_t) */ struct timespec tm; /* Time-of-day to wait */ int gc; /* Garbage collection state */ int gctab[5]= { /* default gcol parameters */ 4096, /* critical 50% - 100% */ 2048, /* severe 25% - 50% */ 1024, /* moderate 12.5% - 25% */ 512, /* light 6.3% - 12.5% */ 256}; /* none 0% - 6.3% */ //char *gcstates[] = {"critical","severe","moderate","light","none"}; obtain_lock (&cckdblk.gclock); gcol = ++cckdblk.gcs; /* Return without messages if too many already started */ if (gcol > cckdblk.gcmax) { --cckdblk.gcs; release_lock (&cckdblk.gclock); return; } if (!cckdblk.batch) { logmsg (_("HHCCD003I Garbage collector thread started: tid="TIDPAT", pid=%d \n"), thread_id(), getpid()); } while (gcol <= cckdblk.gcmax) { cckd_lock_devchain(0); /* Perform collection on each device */ for (dev = cckdblk.dev1st; dev; dev = cckd->devnext) { cckd = dev->cckd_ext; obtain_lock (&cckd->iolock); /* Bypass if merging or stopping */ if (cckd->merging || cckd->stopping) { release_lock (&cckd->iolock); continue; } /* Bypass if not opened read-write */ if (cckd->open[cckd->sfn] != CCKD_OPEN_RW) { release_lock (&cckd->iolock); continue; } /* Free newbuf if it hasn't been used */ if (!cckd->ioactive && !cckd->bufused && cckd->newbuf) cckd->newbuf = cckd_free (dev, "newbuf", cckd->newbuf); cckd->bufused = 0; /* If OPENED bit not on then flush if updated */ if (!(cckd->cdevhdr[cckd->sfn].options & CCKD_OPENED)) { if (cckd->updated) cckd_flush_cache (dev); release_lock (&cckd->iolock); continue; } /* Determine garbage state */ size = (long long)cckd->cdevhdr[cckd->sfn].size; fsiz = (long long)cckd->cdevhdr[cckd->sfn].free_total; if (fsiz >= (size = size/2)) gc = 0; else if (fsiz >= (size = size/2)) gc = 1; else if (fsiz >= (size = size/2)) gc = 2; else if (fsiz >= (size = size/2)) gc = 3; else gc = 4; /* Adjust the state based on the number of free spaces */ if (cckd->cdevhdr[cckd->sfn].free_number > 800 && gc > 0) gc--; if (cckd->cdevhdr[cckd->sfn].free_number > 1800 && gc > 0) gc--; if (cckd->cdevhdr[cckd->sfn].free_number > 3000) gc = 0; /* Set the size */ if (cckdblk.gcparm > 0) size = gctab[gc] << cckdblk.gcparm; else if (cckdblk.gcparm < 0) size = gctab[gc] >> abs(cckdblk.gcparm); else size = gctab[gc]; if (size > cckd->cdevhdr[cckd->sfn].used >> 10) size = cckd->cdevhdr[cckd->sfn].used >> 10; if (size < 64) size = 64; release_lock (&cckd->iolock); /* Call the garbage collector */ cckd_gc_percolate (dev, (unsigned int)size); /* Schedule any updated tracks to be written */ obtain_lock (&cckd->iolock); cckd_flush_cache (dev); while (cckdblk.fsync && cckd->wrpending) { cckd->iowaiters++; wait_condition (&cckd->iocond, &cckd->iolock); cckd->iowaiters--; } release_lock (&cckd->iolock); /* Sync the file */ if (cckdblk.fsync && cckd->lastsync + 10 <= tv_now.tv_sec) { obtain_lock (&cckd->filelock); rc = fdatasync (cckd->fd[cckd->sfn]); cckd->lastsync = tv_now.tv_sec; release_lock (&cckd->filelock); } /* Flush the free space */ if (cckd->cdevhdr[cckd->sfn].free_number) { obtain_lock (&cckd->filelock); cckd_flush_space (dev); release_lock (&cckd->filelock); } } /* for each cckd device */ cckd_unlock_devchain(); /* wait a bit */ gettimeofday (&tv_now, NULL); tm.tv_sec = tv_now.tv_sec + cckdblk.gcwait; tm.tv_nsec = tv_now.tv_usec * 1000; tt_now = tv_now.tv_sec + ((tv_now.tv_usec + 500000)/1000000); cckd_trace (dev, "gcol wait %d seconds at %s", cckdblk.gcwait, ctime (&tt_now)); timed_wait_condition (&cckdblk.gccond, &cckdblk.gclock, &tm); } if (!cckdblk.batch) logmsg (_("HHCCD013I Garbage collector thread stopping: tid="TIDPAT", pid=%d\n"), thread_id(), getpid()); cckdblk.gcs--; if (!cckdblk.gcs) signal_condition (&cckdblk.termcond); release_lock (&cckdblk.gclock); } /* end thread cckd_gcol */ /*-------------------------------------------------------------------*/ /* Garbage Collection -- Percolate algorithm */ /*-------------------------------------------------------------------*/ int cckd_gc_percolate(DEVBLK *dev, unsigned int size) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int rc; /* Return code */ size_t moved = 0; /* Space moved */ int after = 0, a; /* New space after old */ int sfx; /* File index */ int i, j, l; /* Indexes */ int flags; /* Write trkimg flags */ off_t fpos, upos; /* File offsets */ size_t flen, ulen, len; /* Lengths */ int trk; /* Track number */ int l1x,l2x; /* Table Indexes */ CCKD_L2ENT l2; /* Copied level 2 entry */ BYTE buf[256*1024]; /* Buffer */ cckd = dev->cckd_ext; size = size << 10; /* Debug */ if (cckdblk.itracen) { cckd_trace (dev, "gcperc size %d 1st 0x%x nbr %d largest %u\n", size, cckd->cdevhdr[cckd->sfn].free, cckd->cdevhdr[cckd->sfn].free_number, cckd->cdevhdr[cckd->sfn].free_largest); fpos = (off_t)cckd->cdevhdr[cckd->sfn].free; for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) { cckd_trace (dev, "gcperc free[%4d]:%8.8x end %8.8x len %10d%cpend %d\n", i,(int)fpos,(int)(fpos+cckd->free[i].len),(int)cckd->free[i].len, fpos+(int)cckd->free[i].len == (int)cckd->free[i].pos ? '*' : ' ',cckd->free[i].pending); fpos = cckd->free[i].pos; } } if (!cckd->l2ok) cckd_gc_l2(dev, buf); /* garbage collection cycle */ while (moved < size && after < 4) { obtain_lock (&cckd->filelock); sfx = cckd->sfn; /* Exit if no more free space */ if (cckd->cdevhdr[sfx].free_total == 0) { release_lock (&cckd->filelock); return moved; } /* Make sure the free space chain is built */ if (!cckd->free) cckd_read_fsp (dev); /* Find a space to start with */ l = -1; upos = ulen = flen = 0; fpos = cckd->cdevhdr[sfx].free; /* First non-pending free space */ for (i = cckd->free1st; i >= 0; i = cckd->free[i].next) { if (!cckd->free[i].pending) { flen += cckd->free[i].len; break; } fpos = cckd->free[i].pos; } /* Continue to largest if non-zero `after' */ for ( ; i >= 0 && after; i = cckd->free[i].next) { l = i; if (!cckd->free[i].pending) flen += cckd->free[i].len; if (cckd->free[i].len == cckd->cdevhdr[sfx].free_largest) break; fpos = cckd->free[i].pos; } /* Skip following free spaces */ for ( ; i >= 0; i = cckd->free[i].next) { if (!cckd->free[i].pending) flen += cckd->free[i].len; if (fpos + cckd->free[i].len != cckd->free[i].pos) break; fpos = cckd->free[i].pos; } /* Space preceding largest if largest is at the end */ if (i < 0 && l >= 0) { if (!cckd->free[l].pending) flen -= cckd->free[i].len; for (i = cckd->free[l].prev; i >= 0; i = cckd->free[i].prev) { fpos = cckd->free[i].prev >= 0 ? cckd->free[cckd->free[i].prev].pos : cckd->cdevhdr[sfx].free; if (fpos + cckd->free[i].len < cckd->free[i].pos) break; if (!cckd->free[i].pending) flen -= cckd->free[i].len; } } /* Calculate the offset/length of the used space. * If only imbedded free space is left, then start * with the first used space that is not an l2 table. */ if (i >= 0) { upos = fpos + cckd->free[i].len; ulen = (cckd->free[i].pos ? cckd->free[i].pos : cckd->cdevhdr[sfx].size) - upos; } else if (!cckd->cdevhdr[sfx].free_number && cckd->cdevhdr[sfx].free_imbed) { upos = (off_t)(CCKD_L1TAB_POS + cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE); while (1) { for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++) if (cckd->l1[sfx][i] == (U32)upos) break; if (i >= cckd->cdevhdr[sfx].numl1tab) break; upos += CCKD_L2TAB_SIZE; } ulen = cckd->cdevhdr[sfx].size - upos; } /* Return if no applicable used space */ if (ulen == 0) { cckd_trace (dev, "gcperc no applicable space, moved %ld\n",(long)moved); release_lock (&cckd->filelock); return moved; } /* Reduce ulen size to minimize `after' relocations */ if (ulen > flen + 65536) ulen = flen + 65536; if (ulen > sizeof(buf)) ulen = sizeof(buf); cckd_trace (dev, "gcperc selected space 0x%" I64_FMT "x len %ld\n", (long long)upos, (long)ulen); if (cckd_read (dev, sfx, upos, buf, ulen) < 0) goto cckd_gc_perc_error; /* Process each space in the buffer */ flags = cckd->cdevhdr[sfx].free_number < 100 ? CCKD_SIZE_EXACT : CCKD_SIZE_ANY; for (i = a = 0; i + CKDDASD_TRKHDR_SIZE <= (int)ulen; i += len) { /* Check for level 2 table */ for (j = 0; j < cckd->cdevhdr[sfx].numl1tab; j++) if (cckd->l1[sfx][j] == (U32)(upos + i)) break; if (j < cckd->cdevhdr[sfx].numl1tab) { /* Moving a level 2 table */ len = CCKD_L2TAB_SIZE; if (i + len > ulen) break; cckd_trace (dev, "gcperc move l2tab[%d] at pos 0x%" I64_FMT "x len %ld\n", j, (unsigned long long)(upos + i), (long)len); /* Make the level 2 table active */ if (cckd_read_l2 (dev, sfx, j) < 0) goto cckd_gc_perc_error; /* Write the level 2 table */ if (cckd_write_l2 (dev) < 0) goto cckd_gc_perc_error; } else { /* Moving a track image */ if ((trk = cckd_cchh (dev, buf + i, -1)) < 0) goto cckd_gc_perc_space_error; l1x = trk >> 8; l2x = trk & 0xff; /* Read the lookup entry for the track */ if (cckd_read_l2ent (dev, &l2, trk) < 0) goto cckd_gc_perc_error; if (l2.pos != (U32)(upos + i)) goto cckd_gc_perc_space_error; len = (int)l2.size; if (i + l2.len > (int)ulen) break; cckd_trace (dev, "gcperc move trk %d at pos 0x%" I64_FMT "x len %d\n", trk, (long long)(upos + i), (int)l2.len); /* Relocate the track image somewhere else */ if ((rc = cckd_write_trkimg (dev, buf + i, (int)l2.len, trk, flags)) < 0) goto cckd_gc_perc_error; a += rc; } } /* for each space in the used space */ /* Set `after' to 1 if first time space was relocated after */ after += after ? a : (a > 0); moved += i; cckdblk.stats_gcolmoves++; cckdblk.stats_gcolbytes += i; release_lock (&cckd->filelock); } /* while (moved < size) */ cckd_trace (dev, "gcperc moved %ld 1st 0x%x nbr %d\n", (long)moved, cckd->cdevhdr[cckd->sfn].free,cckd->cdevhdr[cckd->sfn].free_number); return moved; cckd_gc_perc_space_error: logmsg (_("HHCCD190E %4.4X file[%d] offset 0x%" I64_FMT "x unknown space: " "%2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum,cckd->sfn,(long long)(upos + i), buf[i], buf[i+1],buf[i+2], buf[i+3], buf[i+4]); cckd->cdevhdr[cckd->sfn].options |= CCKD_SPERRS; cckd_print_itrace(); cckd_gc_perc_error: cckd_trace (dev, "gcperc exiting due to error, moved %ld\n", (long)moved); release_lock (&cckd->filelock); return moved; } /* end function cckd_gc_percolate */ /*-------------------------------------------------------------------*/ /* Garbage Collection -- Reposition level 2 tables */ /* */ /* General idea is to relocate all level 2 tables as close to the */ /* beginning of the file as possible. This can help speed up, for */ /* example, chkdsk processing. */ /* */ /* If any level 2 tables reside outside of the bounds (that is, if */ /* any level 2 table could be moved closer to the beginning of the */ /* file) then first we relocate all track images within the bounds. */ /* Note that cckd_get_space will not allocate space within the */ /* the bounds for track images. Next we try to relocate all level 2 */ /* tables outside the bounds. This may take a few iterations for */ /* the freed space within the bounds to become non-pending. */ /* */ /* The bounds can change as level 2 tables are added or removed. */ /* cckd_read_l1 sets the bounds and they are adjusted by */ /* cckd_write_l2. */ /*-------------------------------------------------------------------*/ int cckd_gc_l2(DEVBLK *dev, BYTE *buf) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int sfx; /* Shadow file index */ int i, j; /* Work variables */ int trk; /* Track number */ int len; /* Track length */ off_t pos, fpos; /* File offsets */ cckd = dev->cckd_ext; obtain_lock (&cckd->filelock); sfx = cckd->sfn; if (cckd->l2ok || cckd->cdevhdr[cckd->sfn].free_total == 0) goto cckd_gc_l2_exit; /* Find any level 2 table out of bounds */ for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++) if (cckd->l1[sfx][i] != 0 && cckd->l1[sfx][i] != 0xffffffff && cckd->l2bounds - CCKD_L2TAB_SIZE < (off_t)cckd->l1[sfx][i]) break; /* Return OK if no l2 tables out of bounds */ if (i >= cckd->cdevhdr[sfx].numl1tab) goto cckd_gc_l2_exit_ok; /* Relocate all track images within the bounds */ pos = CCKD_L1TAB_POS + (cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE); i = cckd->free1st; fpos = (off_t)cckd->cdevhdr[sfx].free; while (pos < cckd->l2bounds) { if (i >= 0 && pos == fpos) { pos += cckd->free[i].len; fpos = (off_t)cckd->free[i].pos; i = cckd->free[i].next; j = 0; } else { for (j = 0; j < cckd->cdevhdr[sfx].numl1tab; j++) if (pos == (off_t)cckd->l1[sfx][j]) { pos += CCKD_L2TAB_SIZE; break; } } if (j >= cckd->cdevhdr[sfx].numl1tab) { /* Found a track to relocate */ if (cckd_read (dev, sfx, pos, buf, CKDDASD_TRKHDR_SIZE) < 0) goto cckd_gc_l2_exit; if ((trk = cckd_cchh (dev, buf, -1)) < 0) goto cckd_gc_l2_exit; cckd_trace (dev, "gc_l2 relocate trk[%d] offset 0x%x\n", trk, pos); if ((len = cckd_read_trkimg (dev, buf, trk, NULL)) < 0) goto cckd_gc_l2_exit; if (cckd_write_trkimg (dev, buf, len, trk, CCKD_SIZE_EXACT) < 0) goto cckd_gc_l2_exit; /* Start over */ pos = CCKD_L1TAB_POS + (cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE); i = cckd->free1st; fpos = (off_t)cckd->cdevhdr[sfx].free; } } do { /* Find a level 2 table to relocate */ i = cckd->free1st; fpos = (off_t)cckd->cdevhdr[sfx].free; cckd_trace (dev, "gc_l2 first free[%d] pos 0x%x len %d pending %d\n", i, (int)fpos, i >= 0 ? (int)cckd->free[i].len : -1, i >= 0 ? cckd->free[i].pending : -1); if (i < 0 || fpos >= cckd->l2bounds || cckd->free[i].pending) goto cckd_gc_l2_exit; if (cckd->free[i].len < CCKD_L2TAB_SIZE || (cckd->free[i].len != CCKD_L2TAB_SIZE && cckd->free[i].len < CCKD_L2TAB_SIZE + CCKD_FREEBLK_SIZE ) ) { for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++) if (fpos + cckd->free[i].len == (off_t)cckd->l1[sfx][i]) break; } else { for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++) if (cckd->l2bounds - CCKD_L2TAB_SIZE < (off_t)cckd->l1[sfx][i] && cckd->l1[sfx][i] != 0xffffffff) break; } if (i < cckd->cdevhdr[sfx].numl1tab) { cckd_trace (dev, "gc_l2 relocate l2[%d] pos 0x%x\n", i, cckd->l1[sfx][i]); if (cckd_read_l2 (dev, sfx, i) < 0) goto cckd_gc_l2_exit; if (cckd_write_l2 (dev) < 0) goto cckd_gc_l2_exit; } } while (i < cckd->cdevhdr[sfx].numl1tab); cckd_gc_l2_exit: release_lock (&cckd->filelock); return 0; cckd_gc_l2_exit_ok: cckd_trace (dev, "gc_l2 ok%s\n", ""); cckd->l2ok = 1; goto cckd_gc_l2_exit; } /*-------------------------------------------------------------------*/ /* Find device by devnum */ /*-------------------------------------------------------------------*/ DEVBLK *cckd_find_device_by_devnum (U16 devnum) { DEVBLK *dev; CCKDDASD_EXT *cckd; cckd_lock_devchain (0); for (dev = cckdblk.dev1st; dev; dev = cckd->devnext) { if (dev->devnum == devnum) break; cckd = dev->cckd_ext; } cckd_unlock_devchain (); return dev; } /* end function cckd_find_device_by_devnum */ /*-------------------------------------------------------------------*/ /* Uncompress a track image */ /*-------------------------------------------------------------------*/ BYTE *cckd_uncompress (DEVBLK *dev, BYTE *from, int len, int maxlen, int trk) { CCKDDASD_EXT *cckd; BYTE *to = NULL; /* Uncompressed buffer */ int newlen; /* Uncompressed length */ BYTE comp; /* Compression type */ static char *compress[] = {"none", "zlib", "bzip2"}; cckd = dev->cckd_ext; cckd_trace (dev, "uncompress comp %d len %d maxlen %d trk %d\n", from[0] & CCKD_COMPRESS_MASK, len, maxlen, trk); /* Extract compression type */ comp = (from[0] & CCKD_COMPRESS_MASK); /* Get a buffer to uncompress into */ if (comp != CCKD_COMPRESS_NONE && cckd->newbuf == NULL) { cckd->newbuf = cckd_malloc (dev, "newbuf", maxlen); if (cckd->newbuf == NULL) return NULL; } /* Uncompress the track image */ switch (comp) { case CCKD_COMPRESS_NONE: newlen = cckd_trklen (dev, from); to = from; break; case CCKD_COMPRESS_ZLIB: to = cckd->newbuf; newlen = cckd_uncompress_zlib (dev, to, from, len, maxlen); break; case CCKD_COMPRESS_BZIP2: to = cckd->newbuf; newlen = cckd_uncompress_bzip2 (dev, to, from, len, maxlen); break; default: newlen = -1; break; } /* Validate the uncompressed track image */ newlen = cckd_validate (dev, to, trk, newlen); /* Return if successful */ if (newlen > 0) { if (to != from) { cckd->newbuf = from; cckd->bufused = 1; } return to; } /* Get a buffer now if we haven't gotten one */ if (cckd->newbuf == NULL) { cckd->newbuf = cckd_malloc (dev, "newbuf2", maxlen); if (cckd->newbuf == NULL) return NULL; } /* Try each uncompression routine in turn */ /* uncompressed */ newlen = cckd_trklen (dev, from); newlen = cckd_validate (dev, from, trk, newlen); if (newlen > 0) return from; /* zlib compression */ to = cckd->newbuf; newlen = cckd_uncompress_zlib (dev, to, from, len, maxlen); newlen = cckd_validate (dev, to, trk, newlen); if (newlen > 0) { cckd->newbuf = from; cckd->bufused = 1; return to; } /* bzip2 compression */ to = cckd->newbuf; newlen = cckd_uncompress_bzip2 (dev, to, from, len, maxlen); newlen = cckd_validate (dev, to, trk, newlen); if (newlen > 0) { cckd->newbuf = from; cckd->bufused = 1; return to; } /* Unable to uncompress */ logmsg (_("HHCCD193E %4.4X file[%d] uncompress error trk %d: %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cckd->sfn, trk, from[0], from[1], from[2], from[3], from[4]); if (comp & ~cckdblk.comps) logmsg (_("HHCCD194E %4.4X file[%d] %s compression not supported\n"), dev->devnum, cckd->sfn, compress[comp]); return NULL; } int cckd_uncompress_zlib (DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen) { #if defined(HAVE_LIBZ) unsigned long newlen; int rc; UNREFERENCED(dev); memcpy (to, from, CKDDASD_TRKHDR_SIZE); newlen = maxlen - CKDDASD_TRKHDR_SIZE; rc = uncompress(&to[CKDDASD_TRKHDR_SIZE], &newlen, &from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE); if (rc == Z_OK) { newlen += CKDDASD_TRKHDR_SIZE; to[0] = 0; } else newlen = -1; cckd_trace (dev, "uncompress zlib newlen %d rc %d\n",(int)newlen,rc); return (int)newlen; #else UNREFERENCED(dev); UNREFERENCED(to); UNREFERENCED(from); UNREFERENCED(len); UNREFERENCED(maxlen); return -1; #endif } int cckd_uncompress_bzip2 (DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen) { #if defined(CCKD_BZIP2) unsigned int newlen; int rc; UNREFERENCED(dev); memcpy (to, from, CKDDASD_TRKHDR_SIZE); newlen = maxlen - CKDDASD_TRKHDR_SIZE; rc = BZ2_bzBuffToBuffDecompress ( (void *)&to[CKDDASD_TRKHDR_SIZE], &newlen, (void *)&from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE, 0, 0); if (rc == BZ_OK) { newlen += CKDDASD_TRKHDR_SIZE; to[0] = 0; } else newlen = -1; cckd_trace (dev, "uncompress bz2 newlen %d rc %d\n",newlen,rc); return (int)newlen; #else UNREFERENCED(dev); UNREFERENCED(to); UNREFERENCED(from); UNREFERENCED(len); UNREFERENCED(maxlen); return -1; #endif } /*-------------------------------------------------------------------*/ /* Compress a track image */ /*-------------------------------------------------------------------*/ int cckd_compress (DEVBLK *dev, BYTE **to, BYTE *from, int len, int comp, int parm) { int newlen; switch (comp) { case CCKD_COMPRESS_NONE: newlen = cckd_compress_none (dev, to, from, len, parm); break; case CCKD_COMPRESS_ZLIB: newlen = cckd_compress_zlib (dev, to, from, len, parm); break; case CCKD_COMPRESS_BZIP2: newlen = cckd_compress_bzip2 (dev, to, from, len, parm); break; default: newlen = cckd_compress_bzip2 (dev, to, from, len, parm); break; } return newlen; } int cckd_compress_none (DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm) { UNREFERENCED(dev); UNREFERENCED(parm); *to = from; from[0] = CCKD_COMPRESS_NONE; return len; } int cckd_compress_zlib (DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm) { #if defined(HAVE_LIBZ) unsigned long newlen; int rc; BYTE *buf; UNREFERENCED(dev); buf = *to; from[0] = CCKD_COMPRESS_NONE; memcpy (buf, from, CKDDASD_TRKHDR_SIZE); buf[0] = CCKD_COMPRESS_ZLIB; newlen = 65535 - CKDDASD_TRKHDR_SIZE; rc = compress2 (&buf[CKDDASD_TRKHDR_SIZE], &newlen, &from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE, parm); newlen += CKDDASD_TRKHDR_SIZE; if (rc != Z_OK || (int)newlen >= len) { *to = from; newlen = len; } return (int)newlen; #else #if defined(CCKD_BZIP2) return cckd_compress_bzip2 (dev, to, from, len, parm); #else return cckd_compress_none (dev, to, from, len, parm); #endif #endif } int cckd_compress_bzip2 (DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm) { #if defined(CCKD_BZIP2) unsigned int newlen; int rc; BYTE *buf; UNREFERENCED(dev); buf = *to; from[0] = CCKD_COMPRESS_NONE; memcpy (buf, from, CKDDASD_TRKHDR_SIZE); buf[0] = CCKD_COMPRESS_BZIP2; newlen = 65535 - CKDDASD_TRKHDR_SIZE; rc = BZ2_bzBuffToBuffCompress ( (void *)&buf[CKDDASD_TRKHDR_SIZE], &newlen, (void *)&from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE, parm >= 1 && parm <= 9 ? parm : 5, 0, 0); newlen += CKDDASD_TRKHDR_SIZE; if (rc != BZ_OK || newlen >= (unsigned int)len) { *to = from; newlen = len; } return newlen; #else return cckd_compress_zlib (dev, to, from, len, parm); #endif } /*-------------------------------------------------------------------*/ /* cckd command help */ /*-------------------------------------------------------------------*/ void cckd_command_help() { logmsg ("cckd command parameters:\n" "help\t\tDisplay help message\n" "stats\t\tDisplay cckd statistics\n" "opts\t\tDisplay cckd options\n" "comp=\t\tOverride compression\t\t(-1 .. 2)\n" "compparm=\tOverride compression parm\t\t(-1 .. 9)\n" "ra=\t\tSet number readahead threads\t\t(1 .. 9)\n" "raq=\t\tSet readahead queue size\t\t(0 .. 16)\n" "rat=\t\tSet number tracks to read ahead\t\t(0 .. 16)\n" "wr=\t\tSet number writer threads\t\t(1 .. 9)\n" "gcint=\tSet garbage collector interval (sec)\t(1 .. 60)\n" "gcparm=\tSet garbage collector parameter\t\t(-8 .. 8)\n" "\t\t (least agressive ... most aggressive)\n" "nostress=\t1=Disable stress writes\n" "freepend=\tSet free pending cycles\t\t\t(-1 .. 4)\n" "fsync=\t1=Enable fsync()\n" "trace=\tSet trace table size\t\t\t(0 .. 200000)\n" ); } /* end function cckd_command_help */ /*-------------------------------------------------------------------*/ /* cckd command stats */ /*-------------------------------------------------------------------*/ void cckd_command_opts() { logmsg ("comp=%d,compparm=%d,ra=%d,raq=%d,rat=%d," "wr=%d,gcint=%d,gcparm=%d,nostress=%d,\n" "\tfreepend=%d,fsync=%d,trace=%d,linuxnull=%d\n", cckdblk.comp == 0xff ? -1 : cckdblk.comp, cckdblk.compparm, cckdblk.ramax, cckdblk.ranbr, cckdblk.readaheads, cckdblk.wrmax, cckdblk.gcwait, cckdblk.gcparm, cckdblk.nostress, cckdblk.freepend, cckdblk.fsync, cckdblk.itracen, cckdblk.linuxnull); } /* end function cckd_command_opts */ /*-------------------------------------------------------------------*/ /* cckd command stats */ /*-------------------------------------------------------------------*/ void cckd_command_stats() { logmsg("reads....%10" I64_FMT "d Kbytes...%10" I64_FMT "d writes...%10" I64_FMT "d Kbytes...%10" I64_FMT "d\n" "readaheads%9" I64_FMT "d misses...%10" I64_FMT "d syncios..%10" I64_FMT "d misses...%10" I64_FMT "d\n" "switches.%10" I64_FMT "d l2 reads.%10" I64_FMT "d stress writes...%10" I64_FMT "d\n" "cachehits%10" I64_FMT "d misses...%10" I64_FMT "d l2 hits..%10" I64_FMT "d misses...%10" I64_FMT "d\n" "waits i/o......%10" I64_FMT "d cache....%10" I64_FMT "d\n" "garbage collector moves....%10" I64_FMT "d Kbytes...%10" I64_FMT "d\n", cckdblk.stats_reads, cckdblk.stats_readbytes >> 10, cckdblk.stats_writes, cckdblk.stats_writebytes >> 10, cckdblk.stats_readaheads, cckdblk.stats_readaheadmisses, cckdblk.stats_syncios, cckdblk.stats_synciomisses, cckdblk.stats_switches, cckdblk.stats_l2reads, cckdblk.stats_stresswrites, cckdblk.stats_cachehits, cckdblk.stats_cachemisses, cckdblk.stats_l2cachehits, cckdblk.stats_l2cachemisses, cckdblk.stats_iowaits, cckdblk.stats_cachewaits, cckdblk.stats_gcolmoves, cckdblk.stats_gcolbytes >> 10); } /* end function cckd_command_stats */ /*-------------------------------------------------------------------*/ /* cckd command debug */ /*-------------------------------------------------------------------*/ void cckd_command_debug() { } /*-------------------------------------------------------------------*/ /* cckd command processor */ /*-------------------------------------------------------------------*/ DLL_EXPORT int cckd_command(char *op, int cmd) { char *kw, *p, c = '\0', buf[256]; int val, opts = 0; /* Display help for null operand */ if (op == NULL) { if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id)) == 0 && cmd) cckd_command_help(); return 0; } strcpy(buf, op); op = buf; /* Initialize the global cckd block if necessary */ if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id))) cckddasd_init (0, NULL); while (op) { /* Operands are delimited by commas */ kw = op; op = strchr (op, ','); if (op) *op++ = '\0'; /* Check for keyword = value */ if ((p = strchr (kw, '='))) { *p++ = '\0'; sscanf (p, "%d%c", &val, &c); } else val = -77; /* Parse the keyword */ if (strcasecmp (kw, "help") == 0) { if (!cmd) return 0; cckd_command_help(); } else if (strcasecmp (kw, "stats") == 0) { if (!cmd) return 0; cckd_command_stats (); } else if (strcasecmp (kw, "opts") == 0) { if (!cmd) return 0; cckd_command_opts(); } else if (strcasecmp (kw, "debug") == 0) { if (!cmd) return 0; cckd_command_debug(); } else if (strcasecmp (kw, "comp") == 0) { if (val < -1 || (val & ~cckdblk.comps) || c != '\0') { logmsg ("Invalid value for comp=\n"); return -1; } else { cckdblk.comp = val < 0 ? 0xff : val; opts = 1; } } else if (strcasecmp (kw, "compparm") == 0) { if (val < -1 || val > 9 || c != '\0') { logmsg ("Invalid value for compparm=\n"); return -1; } else { cckdblk.compparm = val; opts = 1; } } else if (strcasecmp (kw, "ra") == 0) { if (val < CCKD_MIN_RA || val > CCKD_MAX_RA || c != '\0') { logmsg ("Invalid value for ra=\n"); return -1; } else { cckdblk.ramax = val; opts = 1; } } else if (strcasecmp (kw, "raq") == 0) { if (val < 0 || val > CCKD_MAX_RA_SIZE || c != '\0') { logmsg ("Invalid value for raq=\n"); return -1; } else { cckdblk.ranbr = val; opts = 1; } } else if (strcasecmp (kw, "rat") == 0) { if (val < 0 || val > CCKD_MAX_RA_SIZE || c != '\0') { logmsg ("Invalid value for rat=\n"); return -1; } else { cckdblk.readaheads = val; opts = 1; } } else if (strcasecmp (kw, "wr") == 0) { if (val < CCKD_MIN_WRITER || val > CCKD_MAX_WRITER || c != '\0') { logmsg ("Invalid value for wr=\n"); return -1; } else { cckdblk.wrmax = val; opts = 1; } } else if (strcasecmp (kw, "gcint") == 0) { if (val < 1 || val > 60 || c != '\0') { logmsg ("Invalid value for gcint=\n"); return -1; } else { cckdblk.gcwait = val; opts = 1; } } else if (strcasecmp (kw, "gcparm") == 0) { if (val < -8 || val > 8 || c != '\0') { logmsg ("Invalid value for gcparm=\n"); return -1; } else { cckdblk.gcparm = val; opts = 1; } } else if (strcasecmp (kw, "nostress") == 0) { if (val < 0 || val > 1 || c != '\0') { logmsg ("Invalid value for nostress=\n"); return -1; } else { cckdblk.nostress = val; opts = 1; } } else if (strcasecmp (kw, "freepend") == 0) { if (val < -1 || val > CCKD_MAX_FREEPEND || c != '\0') { logmsg ("Invalid value for freepend=\n"); return -1; } else { cckdblk.freepend = val; opts = 1; } } else if (strcasecmp (kw, "fsync") == 0) { if (val < 0 || val > 1 || c != '\0') { logmsg ("Invalid value for fsync=\n"); return -1; } else { cckdblk.fsync = val; opts = 1; } } else if (strcasecmp (kw, "trace") == 0) { if (val < 0 || val > CCKD_MAX_TRACE || c != '\0') { logmsg ("Invalid value for trace=\n"); return -1; } else { /* Disable tracing in case it's already active */ CCKD_TRACE *p = cckdblk.itrace; cckdblk.itrace = NULL; if (p) { SLEEP (1); cckdblk.itrace = cckdblk.itracep = cckdblk.itracex = NULL; cckdblk.itracen = 0; cckd_free (NULL, "trace", p); } /* Get a new trace table */ if (val > 0) { p = cckd_calloc (NULL, "trace", val, sizeof(CCKD_TRACE)); if (p) { cckdblk.itracen = val; cckdblk.itracex = p + val; cckdblk.itracep = p; cckdblk.itrace = p; } } opts = 1; } } else if (strcasecmp (kw, "linuxnull") == 0) { if (val < 0 || val > 1 || c != '\0') { logmsg ("Invalid value for linuxnull=\n"); return -1; } else { cckdblk.linuxnull = val; opts = 1; } } else if (strcasecmp (kw, "gcstart") == 0) { DEVBLK *dev; CCKDDASD_EXT *cckd; TID tid; int flag = 0; cckd_lock_devchain(0); for (dev = cckdblk.dev1st; dev; dev = cckd->devnext) { cckd = dev->cckd_ext; obtain_lock (&cckd->filelock); if (cckd->cdevhdr[cckd->sfn].free_total) { cckd->cdevhdr[cckd->sfn].options |= (CCKD_OPENED | CCKD_ORDWR); cckd_write_chdr (dev); flag = 1; } release_lock (&cckd->filelock); } cckd_unlock_devchain(); if (flag && cckdblk.gcs < cckdblk.gcmax) create_thread (&tid, JOINABLE, cckd_gcol, NULL, "cckd_gcol"); } else { logmsg ("cckd invalid keyword: %s\n",kw); if (!cmd) return -1; cckd_command_help (); op = NULL; } } if (cmd && opts) cckd_command_opts(); return 0; } /* end function cckd_command */ /*-------------------------------------------------------------------*/ /* Print internal trace */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckd_print_itrace() { CCKD_TRACE *i, *p; /* Trace table pointers */ if (!cckdblk.itrace) return; logmsg (_("HHCCD900I print_itrace\n")); i = cckdblk.itrace; cckdblk.itrace = NULL; SLEEP (1); p = cckdblk.itracep; if (p >= cckdblk.itracex) p = i; do { if (p[0] != '\0') logmsg ("%s", (char *)p); if (++p >= cckdblk.itracex) p = i; } while (p != cckdblk.itracep); memset (i, 0, cckdblk.itracen * sizeof(CCKD_TRACE)); cckdblk.itracep = i; cckdblk.itrace = i; } /* end function cckd_print_itrace */ /*-------------------------------------------------------------------*/ /* Write internal trace entry */ /*-------------------------------------------------------------------*/ void cckd_trace(DEVBLK *dev, char *msg, ...) { va_list vl; struct timeval tv; time_t t; char tbuf[64]; CCKD_TRACE *p; int l; if (dev && (dev->ccwtrace||dev->ccwstep)) { char *bfr; int sz=1024,rc; bfr=malloc(1024); va_start(vl,msg); while(1) { rc=vsnprintf(bfr,sz,msg,vl); if(rc<0) { free(bfr); bfr=NULL; break; } if(rcdevnum,bfr); } va_end(vl); } /* ISW FIXME : The following code has a potential */ /* for heap overrun (vsprintf) */ if (cckdblk.itrace) { gettimeofday(&tv, NULL); t = tv.tv_sec; strcpy(tbuf, ctime(&t)); tbuf[19] = '\0'; va_start(vl,msg); p = cckdblk.itracep++; if (p >= cckdblk.itracex) { p = cckdblk.itrace; cckdblk.itracep = p + 1; } if (p) { l = sprintf ((char *)p, "%s" "." "%6.6ld %4.4X:", tbuf+11, (long)(tv.tv_usec), dev ? dev->devnum : 0); vsprintf ((char *)p + l, msg, vl); } } } /* end function cckd_trace */ DEVHND cckddasd_device_hndinfo = { &ckddasd_init_handler, /* Device Initialisation */ &ckddasd_execute_ccw, /* Device CCW execute */ &cckddasd_close_device, /* Device Close */ &ckddasd_query_device, /* Device Query */ &cckddasd_start, /* Device Start channel pgm */ &cckddasd_end, /* Device End channel pgm */ &cckddasd_start, /* Device Resume channel pgm */ &cckddasd_end, /* Device Suspend channel pgm */ &cckd_read_track, /* Device Read */ &cckd_update_track, /* Device Write */ &cckd_used, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Ouput */ &ckddasd_hsuspend, /* Hercules suspend */ &ckddasd_hresume /* Hercules resume */ }; DEVHND cfbadasd_device_hndinfo = { &fbadasd_init_handler, /* Device Initialisation */ &fbadasd_execute_ccw, /* Device CCW execute */ &cckddasd_close_device, /* Device Close */ &fbadasd_query_device, /* Device Query */ &cckddasd_start, /* Device Start channel pgm */ &cckddasd_end, /* Device End channel pgm */ &cckddasd_start, /* Device Resume channel pgm */ &cckddasd_end, /* Device Suspend channel pgm */ &cfba_read_block, /* Device Read */ &cfba_write_block, /* Device Write */ &cfba_used, /* Device Query used */ NULL, /* Device Reserve */ NULL, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Ouput */ &fbadasd_hsuspend, /* Hercules suspend */ &fbadasd_hresume /* Hercules resume */ }; hercules-3.12/cckdutil.c0000664000175000017500000030037112564723224012155 00000000000000/* CCKDUTIL.C (c) Copyright Greg Smith, 2000-2009 */ /* Compressed CKD Common routines */ /*-------------------------------------------------------------------*/ /* This module contains functions for compressed CKD devices */ /* used by more than 1 main program. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _CCKDUTIL_C_ #define _HDASD_DLL_ #include "hercules.h" #include "opcode.h" /*-------------------------------------------------------------------*/ typedef struct _SPCTAB { /* Space table */ BYTE typ; /* Type of space */ int val; /* Value for space */ U32 pos; /* Space offset */ U32 len; /* Space length */ U32 siz; /* Space size */ } SPCTAB; #define SPCTAB_NONE 0 /* Ignore this space entry */ #define SPCTAB_DEVHDR 1 /* Space is device header */ #define SPCTAB_CDEVHDR 2 /* Space is compressed hdr */ #define SPCTAB_L1 3 /* Space is level 1 table */ #define SPCTAB_L2 4 /* Space is level 2 table */ #define SPCTAB_TRK 5 /* Space is track image */ #define SPCTAB_BLKGRP 6 /* Space is blkgrp image */ #define SPCTAB_FREE 7 /* Space is free block */ #define SPCTAB_EOF 8 /* Space is end-of-file */ /*-------------------------------------------------------------------*/ /* Internal functions */ /*-------------------------------------------------------------------*/ static int comp_spctab_sort(const void *a, const void *b); static int cdsk_spctab_sort(const void *a, const void *b); static int cdsk_build_free_space(SPCTAB *spctab, int s); static int cdsk_valid_trk (int trk, BYTE *buf, int heads, int len); /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; static char *spaces[] = { "none", "devhdr", "cdevhdr", "l1", "l2", "trk", "blkgrp", "free", "eof" }; static char *comps[] = { "none", "zlib", "bzip2" }; /*-------------------------------------------------------------------*/ /* Change the endianess of a compressed file */ /*-------------------------------------------------------------------*/ DLL_EXPORT int cckd_swapend (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int fd; /* File descriptor */ int rc; /* Return code */ struct stat fst; /* File status buffer */ int i; /* Index */ int swapend; /* 1=swap space */ int len; /* Length */ off_t off, lopos, hipos; /* File offsets */ CCKD_DEVHDR cdevhdr; /* Compressed ckd header */ CCKD_L1ENT *l1 = NULL; /* Level 1 table */ CCKD_L2ENT l2[256]; /* Level 2 table */ CCKD_FREEBLK freeblk; /* Free block */ /* Get fd */ cckd = dev->cckd_ext; if (cckd == NULL) fd = dev->fd; else fd = cckd->fd[cckd->sfn]; /* Get file size */ if (fstat (fd, &fst) < 0) goto cswp_fstat_error; hipos = fst.st_size; /* Device header */ off = CCKD_DEVHDR_POS; if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; len = CCKD_DEVHDR_SIZE; if ((rc = read (fd, &cdevhdr, len)) != len) goto cswp_read_error; swapend = (cdevhdr.options & CCKD_BIGENDIAN) != cckd_endian(); cckd_swapend_chdr (&cdevhdr); cdevhdr.options |= CCKD_ORDWR; if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = write (fd, &cdevhdr, len)) != len) goto cswp_write_error; if (!swapend) cckd_swapend_chdr (&cdevhdr); /* l1 table */ len = cdevhdr.numl1tab * CCKD_L1ENT_SIZE; if ((l1 = malloc (len)) == NULL) goto cswp_malloc_error; off = CCKD_L1TAB_POS; if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = read (fd, l1, len)) != len) goto cswp_read_error; cckd_swapend_l1 (l1, (int)cdevhdr.numl1tab); if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = write (fd, l1, len)) != len) goto cswp_write_error; if (!swapend) cckd_swapend_l1 (l1, (int)cdevhdr.numl1tab); lopos = CCKD_L1TAB_POS + len; /* l2 tables */ for (i = 0; i < cdevhdr.numl1tab; i++) { if (l1[i] == 0 || l1[i] == 0xffffffff || l1[i] < lopos || l1[i] > hipos - CCKD_L2TAB_SIZE) continue; off = (off_t)l1[i]; if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; len = CCKD_L2TAB_SIZE; if ((rc = read (fd, l2, len)) != len) goto cswp_read_error; cckd_swapend_l2 (l2); if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = write (fd, l2, len)) != len) goto cswp_write_error; } free (l1); l1 = NULL; /* free space */ if (cdevhdr.free && cdevhdr.free >= lopos && cdevhdr.free <= hipos - CCKD_FREEBLK_SIZE) { off = (off_t)cdevhdr.free; if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; len = CCKD_FREEBLK_SIZE; if ((rc = read (fd, &freeblk, len)) != len) goto cswp_read_error; if (memcmp(&freeblk, "FREE_BLK", 8) == 0) { /* New format free space */ for (i = 0; i < cdevhdr.free_number; i++) { off += CCKD_FREEBLK_SIZE; if (off > hipos - CCKD_FREEBLK_SIZE) break; if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = read (fd, &freeblk, len)) != len) goto cswp_read_error; cckd_swapend_free (&freeblk); if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = write (fd, &freeblk, len)) != len) goto cswp_write_error; } /* for each free space */ } /* if new format free space */ else { /* Old format free space */ for (i = 0; i < cdevhdr.free_number; i++) { if (off < lopos || off > hipos - CCKD_FREEBLK_SIZE) break; if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = read (fd, &freeblk, len)) != len) goto cswp_read_error; cckd_swapend_free (&freeblk); if (lseek (fd, off, SEEK_SET) < 0) goto cswp_lseek_error; if ((rc = write (fd, &freeblk, len)) != len) goto cswp_write_error; if (!swapend) cckd_swapend_free (&freeblk); off = (off_t)freeblk.pos; } /* for each free space */ } /* else old format free space */ } /* if free space */ return 0; /* error exits */ cswp_fstat_error: cckdumsg (dev, 701, "fstat error: %s\n", strerror(errno)); goto cswp_error; cswp_lseek_error: cckdumsg (dev, 702, "lseek error, offset 0x%" I64_FMT "x: %s\n", (long long)off, strerror(errno)); goto cswp_error; cswp_read_error: cckdumsg (dev, 703, "read error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete"); goto cswp_error; cswp_write_error: cckdumsg (dev, 704, "write error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete"); goto cswp_error; cswp_malloc_error: cckdumsg (dev, 705, "malloc error, size %d: %s\n", len, strerror(errno)); goto cswp_error; cswp_error: if (l1) free(l1); return -1; } /*-------------------------------------------------------------------*/ /* Swap endian - compressed device header */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckd_swapend_chdr (CCKD_DEVHDR *cdevhdr) { /* fix the compressed ckd header */ cdevhdr->options ^= CCKD_BIGENDIAN; cckd_swapend4 ((char *) &cdevhdr->numl1tab); cckd_swapend4 ((char *) &cdevhdr->numl2tab); cckd_swapend4 ((char *) &cdevhdr->size); cckd_swapend4 ((char *) &cdevhdr->used); cckd_swapend4 ((char *) &cdevhdr->free); cckd_swapend4 ((char *) &cdevhdr->free_total); cckd_swapend4 ((char *) &cdevhdr->free_largest); cckd_swapend4 ((char *) &cdevhdr->free_number); cckd_swapend4 ((char *) &cdevhdr->free_imbed); cckd_swapend2 ((char *) &cdevhdr->compress_parm); } /*-------------------------------------------------------------------*/ /* Swap endian - level 1 table */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckd_swapend_l1 (CCKD_L1ENT *l1, int n) { int i; /* Index */ for (i = 0; i < n; i++) cckd_swapend4 ((char *) &l1[i]); } /*-------------------------------------------------------------------*/ /* Swap endian - level 2 table */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckd_swapend_l2 (CCKD_L2ENT *l2) { int i; /* Index */ for (i = 0; i < 256; i++) { cckd_swapend4 ((char *) &l2[i].pos); cckd_swapend2 ((char *) &l2[i].len); cckd_swapend2 ((char *) &l2[i].size); } } /*-------------------------------------------------------------------*/ /* Swap endian - free space entry */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckd_swapend_free (CCKD_FREEBLK *fb) { cckd_swapend4 ((char *) &fb->pos); cckd_swapend4 ((char *) &fb->len); } /*-------------------------------------------------------------------*/ /* Swap endian - 4 bytes */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckd_swapend4 (char *c) { char temp[4]; memcpy (&temp, c, 4); c[0] = temp[3]; c[1] = temp[2]; c[2] = temp[1]; c[3] = temp[0]; } /*-------------------------------------------------------------------*/ /* Swap endian - 2 bytes */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckd_swapend2 (char *c) { char temp[2]; memcpy (&temp, c, 2); c[0] = temp[1]; c[1] = temp[0]; } /*-------------------------------------------------------------------*/ /* Are we little or big endian? From Harbison&Steele. */ /*-------------------------------------------------------------------*/ DLL_EXPORT int cckd_endian() { union { long l; char c[sizeof (long)]; } u; u.l = 1; return u.c[sizeof (long) - 1] == 1 ? CCKD_BIGENDIAN : 0; } /*------------------------------------------------------------------- * Remove all free space from a compressed ckd file *-------------------------------------------------------------------*/ DLL_EXPORT int cckd_comp (DEVBLK *dev) { CCKDDASD_EXT *cckd; /* -> cckd extension */ int fd; /* File descriptor */ struct stat fst; /* File status buffer */ long long maxsize; /* Max cckd file size */ int rc; /* Return code */ off_t off; /* File offset */ off_t l2area; /* Boundary for l2 tables */ int len; /* Length */ int i, j, l, n; /* Work variables */ int relocate = 0; /* 1=spaces will be relocated*/ int l1size; /* l1 table size */ U32 next; /* offset of next space */ int s; /* space table index */ CKDDASD_DEVHDR devhdr; /* CKD device header */ CCKD_DEVHDR cdevhdr; /* CCKD device header */ CCKD_L1ENT *l1=NULL; /* -> l1 table */ CCKD_L2ENT **l2=NULL; /* -> l2 table array */ SPCTAB *spctab=NULL; /* -> space table */ BYTE *rbuf=NULL; /* Relocation buffer */ BYTE *p; /* -> relocation buffer */ int rlen=0; /* Relocation buffer length */ CCKD_L2ENT zero_l2[256]; /* Empty l2 table (zeros) */ CCKD_L2ENT ff_l2[256]; /* Empty l2 table (0xff's) */ BYTE buf[65536*4]; /* Buffer */ /*--------------------------------------------------------------- * Get fd *---------------------------------------------------------------*/ cckd = dev->cckd_ext; if (cckd == NULL) fd = dev->fd; else fd = cckd->fd[cckd->sfn]; /*--------------------------------------------------------------- * Get file statistics *---------------------------------------------------------------*/ if (fstat (fd, &fst) < 0) goto comp_fstat_error; maxsize = sizeof(off_t) == 4 ? 0x7fffffffll : 0xffffffffll; /*--------------------------------------------------------------- * Read device header *---------------------------------------------------------------*/ off = 0; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; len = CKDDASD_DEVHDR_SIZE; if ((rc = read (fd, &devhdr, len)) != len) goto comp_read_error; if (memcmp (devhdr.devid, "CKD_C370", 8) != 0 && memcmp (devhdr.devid, "CKD_S370", 8) != 0 && memcmp (devhdr.devid, "FBA_C370", 8) != 0 && memcmp (devhdr.devid, "FBA_S370", 8) != 0) { cckdumsg (dev, 999, "not a compressed dasd file\n"); goto comp_error; } comp_restart: /*--------------------------------------------------------------- * Read compressed device header *---------------------------------------------------------------*/ off = CCKD_DEVHDR_POS; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; len = CCKD_DEVHDR_SIZE; if ((rc = read (fd, &cdevhdr, len)) != len) goto comp_read_error; /*--------------------------------------------------------------- * Check the endianess of the file *---------------------------------------------------------------*/ if ((cdevhdr.options & CCKD_BIGENDIAN) != cckd_endian()) { cckdumsg (dev, 101, "converting to %s\n", cckd_endian() ? "big-endian" : "little-endian"); if (cckd_swapend (dev) < 0) goto comp_error; else goto comp_restart; } /*--------------------------------------------------------------- * Some header checks *---------------------------------------------------------------*/ if ((off_t)cdevhdr.size != fst.st_size || cdevhdr.size != cdevhdr.used || cdevhdr.free != 0 || cdevhdr.free_total != 0 || cdevhdr.free_largest != 0 || cdevhdr.free_number != 0 || cdevhdr.free_imbed != 0) relocate = 1; /*--------------------------------------------------------------- * Build empty l2 tables *---------------------------------------------------------------*/ memset (&zero_l2, 0, CCKD_L2TAB_SIZE); if (cdevhdr.nullfmt != 0) for (i = 0; i < 256; i++) zero_l2[i].len = zero_l2[i].size = cdevhdr.nullfmt; memset (&ff_l2, 0xff, CCKD_L2TAB_SIZE); /*--------------------------------------------------------------- * Read the l1 table *---------------------------------------------------------------*/ l1size = len = cdevhdr.numl1tab * CCKD_L1ENT_SIZE; if ((l1 = malloc (len)) == NULL) goto comp_malloc_error; off = CCKD_L1TAB_POS; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; if ((rc = read (fd, l1, len)) != len) goto comp_read_error; /*--------------------------------------------------------------- * Build the space table *---------------------------------------------------------------*/ n = 1 + 1 + 1 + cdevhdr.numl1tab + 1; for (i = 0; i < cdevhdr.numl1tab; i++) if (l1[i] != 0 && l1[i] != 0xffffffff) n += 256; len = sizeof(SPCTAB); if ((spctab = calloc (n, len)) == NULL) goto comp_calloc_error; s = 0; spctab[s].typ = SPCTAB_DEVHDR; spctab[s].val = -1; spctab[s].pos = 0; spctab[s].len = spctab[s].siz = CKDDASD_DEVHDR_SIZE; s++; spctab[s].typ = SPCTAB_CDEVHDR; spctab[s].val = -1; spctab[s].pos = CCKD_DEVHDR_POS; spctab[s].len = spctab[s].siz = CCKD_DEVHDR_SIZE; s++; spctab[s].typ = SPCTAB_L1; spctab[s].val = -1; spctab[s].pos = CCKD_L1TAB_POS; spctab[s].len = spctab[s].siz = l1size; s++; spctab[s].typ = SPCTAB_EOF; spctab[s].val = -1; spctab[s].pos = fst.st_size; spctab[s].len = spctab[s].siz = 0; s++; for (i = 0; i < cdevhdr.numl1tab; i++) if (l1[i] != 0 && l1[i] != 0xffffffff) { spctab[s].typ = SPCTAB_L2; spctab[s].val = i; spctab[s].pos = l1[i]; spctab[s].len = spctab[s].siz = CCKD_L2TAB_SIZE; s++; } qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort); /*--------------------------------------------------------------- * Read level 2 tables *---------------------------------------------------------------*/ n = cdevhdr.numl1tab; len = sizeof (void *); if ((l2 = calloc (n, len)) == NULL) goto comp_calloc_error; for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) { if (spctab[i].typ != SPCTAB_L2) continue; l = spctab[i].val; len = CCKD_L2TAB_SIZE; if ((l2[l] = malloc (len)) == NULL) goto comp_malloc_error; off = (off_t)spctab[i].pos; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; if ((rc = read (fd, l2[l], len)) != len) goto comp_read_error; for (j = 0; j < 256; j++) { if (l2[l][j].pos == 0 || l2[l][j].pos == 0xffffffff) continue; spctab[s].typ = SPCTAB_TRK; spctab[s].val = spctab[i].val*256 + j; spctab[s].pos = l2[l][j].pos; spctab[s].len = l2[l][j].len; spctab[s].siz = l2[l][j].size; s++; } /* for each l2 entry */ /* check if empty l2 table */ if (memcmp (l2[l], &zero_l2, CCKD_L2TAB_SIZE) == 0 || memcmp (l2[l], &ff_l2, CCKD_L2TAB_SIZE) == 0) { l1[l] = l2[l][0].pos; /* 0x00000000 or 0xffffffff */ spctab[i].typ = SPCTAB_NONE; free (l2[l]); l2[l] = NULL; relocate = 1; } } /* for each space */ qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort); while (spctab[s-1].typ == SPCTAB_NONE) s--; /* set relocate flag if last space is free space */ if (spctab[s-2].pos + spctab[s-2].len != spctab[s-1].pos) relocate = 1; /*--------------------------------------------------------------- * relocate l2 tables in order *---------------------------------------------------------------*/ /* determine l2 area */ l2area = CCKD_L1TAB_POS + l1size; for (i = 0; i < cdevhdr.numl1tab; i++) { if (l1[i] == 0 || l1[i] == 0xffffffff) continue; if (l1[i] != l2area) relocate = 1; l2area += CCKD_L2TAB_SIZE; } /* quick return if all l2 tables are orderered and no free space */ if (!relocate) { for (i = 1; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i-1].pos + spctab[i-1].len != spctab[i].pos) break; if (spctab[i].typ == SPCTAB_EOF) { cckdumsg (dev, 103, "file already compressed\n"); goto comp_return_ok; } } /* file will be updated */ cdevhdr.options |= CCKD_ORDWR; /* calculate track size within the l2 area */ for (i = rlen = 0; spctab[i].pos < l2area; i++) if (spctab[i].typ == SPCTAB_TRK) rlen += sizeof(spctab[i].val) + sizeof(spctab[i].len) + spctab[i].len; /* read any tracks in the l2area into rbuf */ if ((len = rlen) > 0) { if ((rbuf = malloc (len)) == NULL) goto comp_malloc_error; for (i = 0, p = rbuf; spctab[i].pos < l2area; i++) { if (spctab[i].typ != SPCTAB_TRK) continue; memcpy (p, &spctab[i].val, sizeof(spctab[i].val)); p += sizeof(spctab[i].val); memcpy (p, &spctab[i].len, sizeof(spctab[i].len)); p += sizeof(spctab[i].len); off = (off_t)spctab[i].pos; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; len = spctab[i].len; if ((rc = read (fd, p, len)) != len) goto comp_read_error; p += len; spctab[i].typ = SPCTAB_NONE; } /* for each space in the l2 area */ qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort); while (spctab[s-1].typ == SPCTAB_NONE) s--; } /* if any tracks to relocate */ /* remove all l2 tables from the space table */ for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].typ == SPCTAB_L2) spctab[i].typ = SPCTAB_NONE; qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort); while (spctab[s-1].typ == SPCTAB_NONE) s--; /* add all l2 tables at their ordered offsets */ off = CCKD_L1TAB_POS + l1size; for (i = 0; i < cdevhdr.numl1tab; i++) { if (l1[i] == 0 || l1[i] == 0xffffffff) continue; spctab[s].typ = SPCTAB_L2; spctab[s].val = i; spctab[s].pos = (U32)off; spctab[s].len = spctab[s].siz = CCKD_L2TAB_SIZE; s++; off += CCKD_L2TAB_SIZE; } qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort); /* set end-of-file position */ spctab[s-1].pos = spctab[s-2].pos + spctab[s-2].len; /*--------------------------------------------------------------- * Perform compression *---------------------------------------------------------------*/ /* move spaces left */ for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) { /* ignore contiguous spaces */ if (spctab[i].pos + spctab[i].len == spctab[i+1].pos) continue; /* found a gap */ off = (off_t)spctab[i+1].pos; /* figure out how much we can read */ for (len = 0, j = i + 1; spctab[j].typ != SPCTAB_EOF; j++) { if (len + spctab[j].len > sizeof(buf)) break; next = spctab[j].pos + spctab[j].len; spctab[j].pos = spctab[i].pos + spctab[i].len + len; spctab[j].siz = spctab[j].len; len += spctab[j].len; if (next != spctab[j+1].pos) break; } /* search for contiguous spaces */ /* this can happen if the next space is end-of-file */ if (len == 0) continue; /* read the image(s) to be relocated */ if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; if ((rc = read (fd, buf, len)) != len) goto comp_write_error; /* write the images */ off = (off_t)spctab[i].pos + spctab[i].len; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; if ((rc = write (fd, buf, len)) != len) goto comp_write_error; } /* adjust the size of the file */ spctab[s-1].pos = spctab[s-2].pos + spctab[s-2].len; /*--------------------------------------------------------------- * Write spaces relocated from the l2area to the end of the file *---------------------------------------------------------------*/ off = (off_t)spctab[s-1].pos; p = rbuf; while (rlen) { spctab[s].typ = SPCTAB_TRK; spctab[s].pos = (U32)off; memcpy (&spctab[s].val, p, sizeof(spctab[s].val)); p += sizeof(spctab[s].val); memcpy (&spctab[s].len, p, sizeof(spctab[s].len)); spctab[s].siz = spctab[s].len; p += sizeof(spctab[s].len); if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; len = spctab[s].len; if ((rc = write (fd, p, len)) != len) goto comp_write_error; p += len; off += len; rlen -= len + sizeof(spctab[s].val) + sizeof(spctab[s].len); s++; } /* for each relocated space in l2area */ /* adjust the space table */ if (rbuf) { free (rbuf); rbuf = NULL; qsort (spctab, s, sizeof(SPCTAB), comp_spctab_sort); spctab[s-1].pos = spctab[s-2].pos + spctab[s-2].len; } /*--------------------------------------------------------------- * Update the device header *---------------------------------------------------------------*/ cdevhdr.size = cdevhdr.used = spctab[s-1].pos; cdevhdr.free = cdevhdr.free_total = cdevhdr.free_largest = cdevhdr.free_number = cdevhdr.free_imbed = 0; cdevhdr.vrm[0] = CCKD_VERSION; cdevhdr.vrm[1] = CCKD_RELEASE; cdevhdr.vrm[2] = CCKD_MODLVL; /*--------------------------------------------------------------- * Update the lookup tables *---------------------------------------------------------------*/ for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].typ == SPCTAB_L2) l1[spctab[i].val] = spctab[i].pos; else if (spctab[i].typ == SPCTAB_TRK) { l = spctab[i].val / 256; j = spctab[i].val % 256; l2[l][j].pos = spctab[i].pos; l2[l][j].len = l2[l][j].size = spctab[i].len; } /*--------------------------------------------------------------- * Write the cdevhdr, l1 table and l2 tables *---------------------------------------------------------------*/ /* write cdevhdr */ off = CCKD_DEVHDR_POS; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; len = CCKD_DEVHDR_SIZE; if ((rc = write (fd, &cdevhdr, len)) != len) goto comp_write_error; /* write l1 table */ off = CCKD_L1TAB_POS; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; len = l1size; if ((rc = write (fd, l1, len)) != len) goto comp_write_error; /* write l2 tables */ for (i = 0; i < cdevhdr.numl1tab; i++) if (l1[i] != 0 && l1[i] != 0xffffffff) { off = (off_t)l1[i]; if (lseek (fd, off, SEEK_SET) < 0) goto comp_lseek_error; len = CCKD_L2TAB_SIZE; if ((rc = write (fd, l2[i], len)) != len) goto comp_lseek_error; } /* truncate the file */ off = (off_t)spctab[s-1].pos; if (off < fst.st_size) { ftruncate (fd, off); cckdumsg (dev, 102, "compress successful, %lld bytes released\n", (long long)fst.st_size - off); } else cckdumsg (dev, 102, "compress successful, L2 tables relocated\n"); /*--------------------------------------------------------------- * Return *---------------------------------------------------------------*/ comp_return_ok: rc = 0; comp_return: if (rbuf) free(rbuf); if (l2) { for (i = 0; i < cdevhdr.numl1tab; i++) if (l2[i]) free (l2[i]); free (l2); } if (l1) free (l1); if (spctab) free (spctab); return rc; /*--------------------------------------------------------------- * Error exits *---------------------------------------------------------------*/ comp_fstat_error: cckdumsg (dev, 701, "fstat error: %s\n", strerror(errno)); goto comp_error; comp_lseek_error: cckdumsg (dev, 702, "lseek error, offset 0x%" I64_FMT "x: %s\n", (long long)off, strerror(errno)); goto comp_error; comp_read_error: cckdumsg (dev, 703, "read error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete"); goto comp_error; comp_write_error: cckdumsg (dev, 704, "write error rc=%d, offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete"); goto comp_error; comp_malloc_error: cckdumsg (dev, 705, "malloc error, size %d: %s\n", len, strerror(errno)); goto comp_error; comp_calloc_error: cckdumsg (dev, 706, "calloc error, size %d: %s\n", n*len, strerror(errno)); goto comp_error; comp_error: rc = -1; goto comp_return; } /* cckd_comp() */ /*------------------------------------------------------------------- * cckd_comp() space table sort *-------------------------------------------------------------------*/ static int comp_spctab_sort(const void *a, const void *b) { const SPCTAB *x = a, *y = b; if (x->typ == SPCTAB_NONE) return 1; else if (y->typ == SPCTAB_NONE) return -1; else if (x->typ == SPCTAB_EOF) return 1; else if (y->typ == SPCTAB_EOF) return -1; else if (x->pos < y->pos) return -1; else return 1; } /*------------------------------------------------------------------- * Perform check function on a compressed ckd file * * check levels * -1 devhdr, cdevhdr, l1 table * 0 devhdr, cdevhdr, l1 table, l2 tables * 1 devhdr, cdevhdr, l1 table, l2 tables, free spaces * 2 devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkhdrs * 3 devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkimgs * 4 devhdr, cdevhdr. Build everything else from recovery *-------------------------------------------------------------------*/ DLL_EXPORT int cckd_chkdsk(DEVBLK *dev, int level) { CCKDDASD_EXT *cckd; /* -> ckd extension */ int fd; /* file descriptor */ struct stat fst; /* file status information */ int fdflags; /* file descriptor flags */ long long maxsize; /* max cckd file size */ int ro; /* 1=file opened read-only */ int f, i, j, l, n; /* work integers */ int l1x, l2x; /* l1, l2 table indexes */ BYTE compmask[256]; /* compression byte mask 00 - supported 0x - valid, not supported ff - invalid */ off_t off; /* file offset */ int len; /* length to read */ int rc; /* function return code */ int comp; /* trkhdr compression byte[0]*/ int cyl; /* trkhdr cyl bytes[1-2]*/ int head; /* trkhdr head bytes[3-4]*/ int trk; /* trkhdr calculated trk */ int cyls; /* number cylinders */ int heads; /* number heads/cylinder */ int trks; /* number tracks */ unsigned int trksz; /* track size */ int blks; /* number fba blocks */ int blkgrp; /* current block group nbr */ int blkgrps; /* number fba block groups */ unsigned int blkgrpsz; /* fba block group size */ int trktyp; /* track type (TRK, BLKGRP) */ int ckddasd=0; /* 1=ckd */ int fbadasd=0; /* 1= fba */ int shadow=0; /* 0xff=shadow file */ int hdrerr=0; /* non-zero: header errors */ int fsperr=0; /* 1=rebuild free space */ int comperrs=0; /* 1=unsupported comp found */ int recovery=0; /* 1=perform track recovery */ int valid; /* 1=valid trk recovered */ int l1size; /* size of l1 table */ int swapend=0; /* 1=call cckd_swapend */ U32 lopos, hipos; /* low/high file positions */ int pass; /* recovery pass number (fba)*/ int s; /* space table index */ SPCTAB *spctab=NULL; /* -> space table */ BYTE *l2errs=NULL; /* l2 error table */ BYTE *rcvtab=NULL; /* recovered tracks */ CKDDASD_DEVHDR devhdr; /* device header */ CCKD_DEVHDR cdevhdr; /* compressed device header */ CCKD_DEVHDR cdevhdr2; /* compressed device header 2*/ CCKD_L1ENT *l1=NULL; /* -> level 1 table */ CCKD_L2ENT l2ent; /* level 2 entry */ CCKD_L2ENT l2tab[256]; /* level 2 table */ CCKD_L2ENT **l2=NULL; /* -> level 2 table array */ CCKD_L2ENT empty_l2[256]; /* Empty l2 table */ CCKD_FREEBLK freeblk; /* free block */ CCKD_FREEBLK *fsp=NULL; /* free blocks (new format) */ BYTE buf[4*65536]; /* buffer */ /* Get fd */ cckd = dev->cckd_ext; if (cckd == NULL) fd = dev->fd; else fd = cckd->fd[cckd->sfn]; /* Get some file information */ if ( fstat (fd, &fst) < 0 ) goto cdsk_fstat_error; hipos = fst.st_size; maxsize = sizeof(off_t) == 4 ? 0x7fffffffll : 0xffffffffll; fdflags = get_file_accmode_flags(fd); ro = (fdflags & O_RDWR) == 0; /* Build table for compression byte test */ memset (compmask, 0xff, 256); compmask[0] = 0; #if defined(HAVE_LIBZ) compmask[CCKD_COMPRESS_ZLIB] = 0; #else compmask[CCKD_COMPRESS_ZLIB] = 1; #endif #if defined(CCKD_BZIP2) compmask[CCKD_COMPRESS_BZIP2] = 0; #else compmask[CCKD_COMPRESS_BZIP2] = 2; #endif /*--------------------------------------------------------------- * Header checks *---------------------------------------------------------------*/ /* Read the device header */ off = 0; if ( lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = CKDDASD_DEVHDR_SIZE; if ((rc = read (fd, &devhdr, len)) != len) goto cdsk_read_error; /* Device header checks */ if (memcmp(devhdr.devid, "CKD_C370", 8) == 0 || memcmp(devhdr.devid, "CKD_S370", 8) == 0 ) ckddasd = 1; else if (memcmp(devhdr.devid, "FBA_C370", 8) == 0 || memcmp(devhdr.devid, "FBA_S370", 8) == 0 ) fbadasd = 1; else { cckdumsg (dev, 999, "not a compressed dasd file\n"); goto cdsk_error; } if (memcmp(devhdr.devid, "CKD_S370", 8) == 0 || memcmp(devhdr.devid, "FBA_S370", 8) == 0 ) shadow = 0xff; trktyp = ckddasd ? SPCTAB_TRK : SPCTAB_BLKGRP; /* Read the cckd device header */ off = CCKD_DEVHDR_POS; if ( lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = CCKD_DEVHDR_SIZE; if ((rc = read (fd, &cdevhdr, len)) != len) goto cdsk_read_error; /* Endianess check */ if ((cdevhdr.options & CCKD_BIGENDIAN) != cckd_endian()) { if (!ro) { cckdumsg (dev, 101, "converting to %s\n", cckd_endian() ? "big-endian" : "little-endian"); if (cckd_swapend (dev) < 0) goto cdsk_error; if (level < 0) level = 0; swapend = 0; } else swapend = 1; cckd_swapend_chdr (&cdevhdr); } /* ckd checks */ if (ckddasd) { CKDDEV *ckd; heads = (devhdr.heads[3] << 24) + (devhdr.heads[2] << 16) + (devhdr.heads[1] << 8) + (devhdr.heads[0]); cyls = (cdevhdr.cyls[3] << 24) + (cdevhdr.cyls[2] << 16) + (cdevhdr.cyls[1] << 8) + (cdevhdr.cyls[0]); trks = heads * cyls; trksz = (devhdr.trksize[3] << 24) + (devhdr.trksize[2] << 16) + (devhdr.trksize[1] << 8) + (devhdr.trksize[0]); /* ckd dasd lookup */ ckd = dasd_lookup (DASD_CKDDEV, NULL, devhdr.devtype, cyls); if (ckd == NULL) { cckdumsg (dev, 900, "dasd lookup error type=%2.2X cyls=%d\n", devhdr.devtype, cyls); goto cdsk_error; } /* track size check */ n = sizeof(CKDDASD_TRKHDR) + sizeof(CKDDASD_RECHDR) + 8 /* r0 length */ + sizeof(CKDDASD_RECHDR) + ckd->r1 /* max data length */ + sizeof(eighthexFF); n = ((n+511)/512)*512; if ((int)trksz != n) { cckdumsg (dev, 901, "bad trksize: %d, expecting %d\n", trksz, n); goto cdsk_error; } /* number of heads check */ if (heads != ckd->heads) { cckdumsg (dev, 902, "bad number of heads: %d, expecting %d\n", heads, ckd->heads); goto cdsk_error; } } /* if (ckddasd) */ /* fba checks */ else { /* Note: cyls & heads are setup for ckd type hdr checks */ blks = (cdevhdr.cyls[3] << 24) + (cdevhdr.cyls[2] << 16) + (cdevhdr.cyls[1] << 8) + (cdevhdr.cyls[0]); trks = blks / CFBA_BLOCK_NUM; if (blks % CFBA_BLOCK_NUM) trks++; trksz = CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE; heads = 65536; cyls = trks / heads; if (trks % heads) cyls++; } /* fba variables */ blkgrps = trks; blkgrpsz = trksz; /* `numl1tab' check */ n = trks / 256; if (trks % 256) n++; if (cdevhdr.numl1tab != n && cdevhdr.numl1tab != n + 1) { cckdumsg (dev, 903, "bad `numl1tab': %d, expecting %d\n", cdevhdr.numl1tab, n); goto cdsk_error; } l1size = cdevhdr.numl1tab * CCKD_L1ENT_SIZE; if (CCKD_L1TAB_POS + l1size > fst.st_size) { cckdumsg (dev, 904, "file too small to contain L1 table: %d, need %d", fst.st_size, CCKD_L1TAB_POS + l1size); goto cdsk_error; } /* check level 2 if SPERRS bit on */ if (!ro && level < 2 && (cdevhdr.options & CCKD_SPERRS)) { level = 2; cckdumsg (dev, 600, "forcing check level %d; space error bit on\n", level); } /* cdevhdr inconsistencies check */ hdrerr = 0; hdrerr |= fst.st_size != (off_t)cdevhdr.size && cdevhdr.size != cdevhdr.free ? 0x0001 : 0; hdrerr |= cdevhdr.size != cdevhdr.used + cdevhdr.free_total ? 0x0002 : 0; hdrerr |= cdevhdr.free_largest > cdevhdr.free_total - cdevhdr.free_imbed ? 0x0004 : 0; hdrerr |= cdevhdr.free == 0 && cdevhdr.free_number != 0 ? 0x0008 : 0; hdrerr |= cdevhdr.free == 0 && cdevhdr.free_total != cdevhdr.free_imbed ? 0x0010 : 0; hdrerr |= cdevhdr.free != 0 && cdevhdr.free_total == 0 ? 0x0020 : 0; hdrerr |= cdevhdr.free != 0 && cdevhdr.free_number == 0 ? 0x0040 : 0; hdrerr |= cdevhdr.free_number == 0 && cdevhdr.free_total != cdevhdr.free_imbed ? 0x0080 : 0; hdrerr |= cdevhdr.free_number != 0 && cdevhdr.free_total <= cdevhdr.free_imbed ? 0x0100 : 0; hdrerr |= cdevhdr.free_imbed > cdevhdr.free_total ? 0x0200 : 0; /* Additional checking if header errors */ if (hdrerr != 0) { cckdumsg (dev, 601, "cdevhdr inconsistencies found, code=%4.4x\n", hdrerr); if (level < 1) { level = 1; cckdumsg (dev, 600, "forcing check level %d\n", level); } } /* Additional checking if not properly closed */ if (level < 1 && (cdevhdr.options & CCKD_OPENED)) { level = 1; cckdumsg (dev, 600, "forcing check level %d; file not closed\n", level); } /* Additional checking if last opened for read/write */ if (level < 0 && (cdevhdr.options & CCKD_ORDWR)) level = 0; /* Set check level -1 */ if (level == 0 && !dev->batch && !hdrerr && (cdevhdr.options & (CCKD_OPENED|CCKD_SPERRS)) == 0 && ((cdevhdr.options & (CCKD_ORDWR)) == 0 || ro)) level = -1; /* Build empty l2 table */ memset (&empty_l2, shadow, CCKD_L2TAB_SIZE); if (shadow == 0 && cdevhdr.nullfmt != 0) for (i = 0; i < 256; i++) empty_l2[i].len = empty_l2[i].size = cdevhdr.nullfmt; /*--------------------------------------------------------------- * read the level 1 table *---------------------------------------------------------------*/ len = l1size; if ((l1 = malloc (len)) == NULL) goto cdsk_error; off = CCKD_L1TAB_POS; if ( lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if ((rc = read (fd, l1, len)) != len) goto cdsk_read_error; if (swapend) cckd_swapend_l1 (l1, (int)cdevhdr.numl1tab); lopos = CCKD_L1TAB_POS + l1size; /*--------------------------------------------------------------- * initialize the space table *---------------------------------------------------------------*/ /* find number of non-null l1 entries */ for (i = n = 0; i < cdevhdr.numl1tab; i++) if (l1[i] != 0 && l1[i] != 0xffffffff) n++; if (level >= 4) n = cdevhdr.numl1tab; /* calculate max possible space table entries */ n = 1 + 1 + 1 // devhdr, cdevhdr, l1tab + n // l2tabs + (n * 256) // trk/blk images + (1 + n + (n * 256) + 1) // max possible free spaces + 1; // end-of-file /* obtain the space table */ len = sizeof(SPCTAB); if ((spctab = calloc (n, len)) == NULL) goto cdsk_calloc_error; /* populate the table with what we have */ s = 0; /* devhdr */ spctab[s].typ = SPCTAB_DEVHDR; spctab[s].val = -1; spctab[s].pos = 0; spctab[s].len = spctab[s].siz = CKDDASD_DEVHDR_SIZE; s++; /* cdevhdr */ spctab[s].typ = SPCTAB_CDEVHDR; spctab[s].val = -1; spctab[s].pos = CCKD_DEVHDR_POS; spctab[s].len = spctab[s].siz = CCKD_DEVHDR_SIZE; s++; /* l1 table */ spctab[s].typ = SPCTAB_L1; spctab[s].val = -1; spctab[s].pos = CCKD_L1TAB_POS; spctab[s].len = spctab[s].siz = l1size; s++; /* l2 tables */ for (i = 0; i < cdevhdr.numl1tab && level < 4; i++) { if (l1[i] == 0 || l1[i] == 0xffffffff) continue; spctab[s].typ = SPCTAB_L2; spctab[s].val = i; spctab[s].pos = l1[i]; spctab[s].len = spctab[s].siz = CCKD_L2TAB_SIZE; s++; } /* end-of-file */ spctab[s].typ = SPCTAB_EOF; spctab[s].val = -1; spctab[s].pos = (U32)fst.st_size; spctab[s].len = spctab[s].siz = 0; s++; qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); /*--------------------------------------------------------------- * Quick return if level -1 *---------------------------------------------------------------*/ if (level < 0) { int err = 0; /* check for overlaps */ for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].pos + spctab[i].siz > spctab[i+1].pos) err = 1; /* exit if no errors */ if (!err) goto cdsk_return_ok; } /*--------------------------------------------------------------- * obtain the l2errs table and recovery table *---------------------------------------------------------------*/ len = sizeof(BYTE); n = cdevhdr.numl1tab; if ((l2errs = calloc (n, len)) == NULL) goto cdsk_calloc_error; n = trks; if ((rcvtab = calloc (n, len)) == NULL) goto cdsk_calloc_error; /*--------------------------------------------------------------- * Special processing for level 4 (recover everything) *---------------------------------------------------------------*/ if (level == 4) { memset (l2errs, 1, cdevhdr.numl1tab); memset (rcvtab, 1, trks); goto cdsk_recovery; } /*--------------------------------------------------------------- * Read the level 2 tables *---------------------------------------------------------------*/ for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) { if (spctab[i].typ != SPCTAB_L2 || spctab[i].pos < lopos || spctab[i].pos > hipos) continue; off = spctab[i].pos; if ( lseek (fd, off, SEEK_SET) < 0 ) goto cdsk_lseek_error; len = CCKD_L2TAB_SIZE; if ((rc = read (fd, l2tab, len)) != len) goto cdsk_read_error; if (swapend) cckd_swapend_l2 (l2tab); /* add trks/blkgrps to the space table */ for (j = 0; j < 256; j++) { if (l2tab[j].pos != 0 && l2tab[j].pos != 0xffffffff) { spctab[s].typ = trktyp; spctab[s].val = spctab[i].val * 256 + j; spctab[s].pos = l2tab[j].pos; spctab[s].len = l2tab[j].len; spctab[s].siz = l2tab[j].size; s++; } } } qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); /*--------------------------------------------------------------- * Consistency checks. * * The space table is now populated with everything but free * space. Therefore we can infer what the free space should * be (ie gaps between allocated spaces). *---------------------------------------------------------------*/ lopos = CCKD_L1TAB_POS + l1size; hipos = fst.st_size; /* Make adjustment if new format free space is at the end */ len = spctab[s-1].pos - (spctab[s-2].pos + spctab[s-2].siz); if (len > 0 && cdevhdr.size == cdevhdr.free && cdevhdr.size + len == spctab[s-1].pos) { spctab[s-1].pos -= len; hipos -= len; } memset (&cdevhdr2, 0, CCKD_DEVHDR_SIZE); for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) { /* Calculate gap size */ len = spctab[i+1].pos - (spctab[i].pos + spctab[i].siz); /* Update space statistics */ cdevhdr2.size += spctab[i].siz + len; cdevhdr2.used += spctab[i].len; if (len > 0) { cdevhdr2.free_number++; cdevhdr2.free_total += len; if (cdevhdr2.free_largest < (U32)len) cdevhdr2.free_largest = (U32)len; } if (spctab[i].typ == trktyp) { cdevhdr2.free_total += spctab[i].siz - spctab[i].len; cdevhdr2.free_imbed += spctab[i].siz - spctab[i].len; } /* ignore devhdr, cdevhdr and l1 (these are `out of bounds') */ if (spctab[i].typ == SPCTAB_DEVHDR || spctab[i].typ == SPCTAB_CDEVHDR || spctab[i].typ == SPCTAB_L1 ) continue; /* check if the space is out of bounds */ valid = (off_t)spctab[i].pos >= lopos && (off_t)spctab[i].pos + spctab[i].siz <= hipos; /* Overlap check */ if (len < 0 || !valid) { char space1[32], space2[32]; recovery = 1; /* issue error message */ j = sprintf(space1, "%s", spaces[spctab[i].typ]); if (spctab[i].val >= 0) sprintf(space1+j, "[%d]", spctab[i].val); j = sprintf(space2, "%s", spaces[spctab[i+1].typ]); if (spctab[i+1].val >= 0) sprintf(space2+j, "[%d]", spctab[i+1].val); if (!valid) cckdumsg(dev, 602, "%s offset 0x%" I32_FMT "x len %d is out of bounds\n", space1, spctab[i].pos, spctab[i].siz); else cckdumsg(dev, 603, "%s offset 0x%" I32_FMT "x len %d overlaps %s offset 0x%" I32_FMT "x\n", space1, spctab[i].pos, spctab[i].siz, space2, spctab[i+1].pos); /* setup recovery */ if (spctab[i].typ == SPCTAB_L2) { l2errs[spctab[i].val] = 1; /* Mark all tracks for the l2 for recovery */ memset (rcvtab + (spctab[i].val*256), 1, 256); } else if (spctab[i].typ == trktyp) rcvtab[spctab[i].val] = 1; if (spctab[i+1].typ == SPCTAB_L2 && valid) { l2errs[spctab[i+1].val] = 1; memset (rcvtab + (spctab[i+1].val*256), 1, 256); } else if (spctab[i+1].typ == trktyp && valid) rcvtab[spctab[i+1].val] = 1; } /* if overlap or out of bounds */ /* Check image l2 entry consistency */ else if (spctab[i].typ == trktyp && (spctab[i].len < CKDDASD_TRKHDR_SIZE || spctab[i].len > spctab[i].siz || spctab[i].len > trksz)) { recovery = 1; /* issue error message */ cckdumsg(dev, 604, "%s[%d] l2 inconsistency: len %d, size %d\n", spaces[trktyp], spctab[i].val, spctab[i].len, spctab[i].siz); /* setup recovery */ rcvtab[spctab[i].val] = 1; } /* if inconsistent l2 */ } /* for each space */ /* remove any l2 tables or tracks in error from the space table */ for (i = 0; recovery && spctab[i].typ != SPCTAB_EOF; i++) if ((spctab[i].typ == SPCTAB_L2 && l2errs[spctab[i].val]) || (spctab[i].typ == trktyp && rcvtab[spctab[i].val])) spctab[i].typ = SPCTAB_NONE; /* overlaps are serious */ if (recovery && level < 3) { level = 3; cckdumsg (dev, 600, "forcing check level %d\n", level); } /* Rebuild free space if any errors */ if (recovery || hdrerr || cdevhdr.size != cdevhdr2.size || cdevhdr.used != cdevhdr2.used || cdevhdr.free_number != cdevhdr2.free_number || cdevhdr.free_largest != cdevhdr2.free_largest || cdevhdr.free_total != cdevhdr2.free_total || cdevhdr.free_imbed != cdevhdr2.free_imbed ) fsperr = 1; /*--------------------------------------------------------------- * read the free space *---------------------------------------------------------------*/ lopos = CCKD_L1TAB_POS + l1size; hipos = fst.st_size; if (level >= 1 && !fsperr) { while (cdevhdr.free) // `while' so code can break { fsperr = 1; // be pessimistic fsp = NULL; /* Read the free space */ off = (off_t)cdevhdr.free; len = CCKD_FREEBLK_SIZE; if (off < lopos || off + CCKD_FREEBLK_SIZE > hipos || lseek (fd, off, SEEK_SET) < 0 || (rc = read (fd, &freeblk, len)) != len) break; if (memcmp (&freeblk, "FREE_BLK", 8) == 0) { /* new format free space */ len = cdevhdr.free_number * CCKD_FREEBLK_SIZE; if ((fsp = malloc(len)) == NULL || (rc = read (fd, fsp, len)) != len) break; for (i = 0; i < cdevhdr.free_number; i++) { if (swapend) cckd_swapend_free (&fsp[i]); spctab[s].typ = SPCTAB_FREE; spctab[s].val = -1; spctab[s].pos = fsp[i].pos; spctab[s].len = spctab[s].siz = fsp[i].len; /* Free space should be ascending */ if (spctab[s].pos < lopos || spctab[s].pos + spctab[s].siz > hipos) break; lopos = spctab[s].pos + spctab[s].siz; s++; } /* for each free space */ if (i >= cdevhdr.free_number) fsperr = 0; } /* new format free space */ else { /* old format free space */ off = (off_t)cdevhdr.free; len = CCKD_FREEBLK_SIZE; for (i = 0; i < cdevhdr.free_number; i++) { if (off < lopos || off > hipos) break; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if ((rc = read (fd, &freeblk, len)) != len) goto cdsk_read_error; if (swapend) cckd_swapend_free (&freeblk); spctab[s].typ = SPCTAB_FREE; spctab[s].val = -1; spctab[s].pos = (U32)off; spctab[s].len = spctab[s].siz = freeblk.len; s++; lopos = off + freeblk.len; off = (off_t)freeblk.pos; } if (i >= cdevhdr.free_number && freeblk.pos == 0) fsperr = 0; } /* if old format free space */ if (fsp) free(fsp); fsp = NULL; /* Check for gaps/overlaps */ qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); for (i = 0; !fsperr && spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].pos + spctab[i].siz != spctab[i+1].pos) fsperr = 1; break; } /* while (cdevhdr.free) */ } /* if (level >= 1 && !fsperr) */ if (fsperr) cckdumsg (dev, 610, "free space errors detected\n"); /*--------------------------------------------------------------- * Read track headers/images *---------------------------------------------------------------*/ cdsk_space_check: if (level >= 2) { for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) { if (spctab[i].typ != trktyp) continue; /* read the header or image depending on the check level */ off = spctab[i].pos; if ( lseek (fd, off, SEEK_SET) < 0 ) goto cdsk_lseek_error; len = level < 3 ? CKDDASD_TRKHDR_SIZE : spctab[i].len; if ((rc = read (fd, buf, len)) != len) goto cdsk_read_error; /* Extract header info */ comp = buf[0]; cyl = fetch_hw (buf + 1); head = fetch_hw (buf + 3); trk = cyl * heads + head; /* Validate header info */ if (compmask[comp] == 0xff || cyl >= cyls || head >= heads || trk != spctab[i].val) { cckdumsg (dev, 620, "%s[%d] hdr error offset 0x%" I64_FMT "x: %2.2x%2.2x%2.2x%2.2x%2.2x\n", spaces[trktyp], spctab[i].val, (long long)off, buf[0],buf[1],buf[2],buf[3],buf[4]); /* recover this track */ rcvtab[spctab[i].val] = recovery = 1; spctab[i].typ = SPCTAB_NONE; /* Force level 3 checking */ if (level < 3) { level = 3; cckdumsg (dev, 600, "forcing check level %d\n", level); goto cdsk_space_check; } continue; } /* if invalid header info */ /* Check if compression supported */ if (compmask[comp]) { comperrs = 1; cckdumsg ( dev, 621, "%s[%d] compressed using %s, not supported\n", spaces[trktyp], trk, comps[compmask[comp]]); continue; } /* Validate the space if check level 3 */ if (level > 2) { if (!cdsk_valid_trk (trk, buf, heads, len)) { cckdumsg (dev, 622, "%s[%d] offset 0x%" I64_FMT "x len %d validation error\n", spaces[trktyp], trk, (long long)off, len); /* recover this track */ rcvtab[trk] = recovery = 1; spctab[i].typ = SPCTAB_NONE; } /* if invalid space */ else rcvtab[trk] = 0; } /* if level > 2 */ } /* for each space */ } /* if (level >= 2) */ /*--------------------------------------------------------------- * Recovery *---------------------------------------------------------------*/ cdsk_recovery: if (recovery || level == 4) { U32 flen, fpos; /*----------------------------------------------------------- * Phase 1 -- recover trk/blkgrp images *-----------------------------------------------------------*/ /* * Reset the end-of-file pos to the file size * It might have been changed if new format free space * occurred at the end of the file. */ qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); while (spctab[s-1].typ == SPCTAB_NONE) s--; spctab[s-1].pos = fst.st_size; /* count number tracks to be recovered */ for (i = n = 0; i < trks; i++) if (rcvtab[i] == 1) n++; /*----------------------------------------------------------- * ckd recovery *-----------------------------------------------------------*/ if (ckddasd) { /* recovery loop */ s = cdsk_build_free_space (spctab, s); for (f = 0; spctab[f].typ != SPCTAB_EOF && n; ) { /* next free space if too small */ if (spctab[f].typ != SPCTAB_FREE || spctab[f].siz <= CKDDASD_TRKHDR_SIZE+8) { for (f = f + 1; spctab[f].typ != SPCTAB_EOF; f++) if (spctab[f].typ == SPCTAB_FREE) break; continue; } fpos = spctab[f].pos; flen = spctab[f].siz; /* length to read */ len = flen < sizeof(buf) ? flen : sizeof(buf); /* read the free space */ off = (off_t)fpos; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if ((rc = read (fd, buf, len)) != len) goto cdsk_read_error; /* Scan the space for a trkhdr */ for (i = 0; i < len - (CKDDASD_TRKHDR_SIZE+8); i++) { /* Check compression byte */ if (compmask[buf[i]]) continue; /* Fetch possible trkhdr */ comp = buf[i]; cyl = fetch_hw (buf + i + 1); head = fetch_hw (buf + i + 3); trk = cyl * heads + head; /* Validate possible trkhdr */ if (cyl >= cyls || head >= heads || rcvtab[trk] != 1) continue; /* Quick validation for compress none */ if (comp == CCKD_COMPRESS_NONE && (fetch_hw (buf + i + 5) != cyl // r0 cyl || fetch_hw (buf + i + 7) != head // r0 head || buf[i + 9] != 0 // r0 record || buf[i + 10] != 0 // r0 key length || fetch_hw (buf + i + 11) != 8 // r0 data length ) ) continue; /* Quick validation for zlib */ else if (comp == CCKD_COMPRESS_ZLIB && fetch_hw(buf + i + 5) % 31 != 0) continue; /* Quick validation for bzip2 */ else if (comp == CCKD_COMPRESS_BZIP2 && (buf[i+5] != 'B' || buf[i+6] != 'Z')) continue; /* * If we are in `borrowed space' then start over * with the current position at the beginning */ if (flen > (U32)len && i > len - (int)trksz) break; /* Checks for comp none */ if (comp == CCKD_COMPRESS_NONE) { l = len - i; if ((l = cdsk_valid_trk (trk, buf+i, heads, -l))) goto cdsk_ckd_recover; else continue; } /* Check short `length' */ if (flen == (U32)len && (l = len - i) <= 1024) { if (cdsk_valid_trk (trk, buf+i, heads, l)) { while (cdsk_valid_trk (trk, buf+i, heads, --l)); l++; goto cdsk_ckd_recover; } } /* Scan for next trkhdr */ for (j = i + CKDDASD_TRKHDR_SIZE+8; j <= len - (CKDDASD_TRKHDR_SIZE+8); j++) { if (j - i > (int)trksz) break; if (compmask[buf[j]] != 0 || fetch_hw(buf+j+1) >= cyls || fetch_hw(buf+j+3) >= heads) continue; /* check uncompressed hdr */ if (buf[j] == CCKD_COMPRESS_NONE && (fetch_hw (buf+j+5) != fetch_hw(buf+j+1) || fetch_hw (buf+j+7) != fetch_hw(buf+j+3) || buf[j+9] != 0 || buf[j+10] != 0 || fetch_hw(buf+j+11) != 8)) continue; /* check zlib compressed header */ else if (buf[j] == CCKD_COMPRESS_ZLIB && fetch_hw(buf + j + 5) % 31 != 0) continue; /* check bzip2 compressed header */ else if (buf[j] == CCKD_COMPRESS_BZIP2 && (buf[j+5] != 'B' || buf[j+6] != 'Z')) continue; /* check to possible trkhdr */ l = j - i; if (cdsk_valid_trk (trk, buf+i, heads, l)) { #if 0 while (cdsk_valid_trk (trk, buf+i, heads, --l)); l++; #endif goto cdsk_ckd_recover; } } /* scan for next trkhdr */ /* Check `length' */ if (flen == (U32)len && (l = len - i) <= (int)trksz) { if (cdsk_valid_trk (trk, buf+i, heads, l)) { while (cdsk_valid_trk (trk, buf+i, heads, --l)); l++; goto cdsk_ckd_recover; } } /* Scan all lengths */ for (l = CKDDASD_TRKHDR_SIZE+8; i + l <= len; l++) { if (l > (int)trksz) break; if (cdsk_valid_trk (trk, buf+i, heads, l)) goto cdsk_ckd_recover; } /* for all lengths */ continue; cdsk_ckd_recover: cckdumsg (dev, 301, "%s[%d] recovered offset 0x%" I64_FMT "x len %d\n", spaces[trktyp], trk, (long long)off + i, l); n--; rcvtab[trk] = 2; /* add recovered track to the space table */ spctab[s].typ = trktyp; spctab[s].val = trk; spctab[s].pos = fpos + i; spctab[s].len = spctab[s].siz = l; s++; /* * adjust `i' knowing it will be incremented * in the `for' loop above. */ i += l - 1; } /* for each byte in the free space */ /* Adjust the free space for what we processed */ spctab[f].pos += i; spctab[f].len -= i; spctab[f].siz -= i; } /* for each free space */ } /* if ckddasd */ /*----------------------------------------------------------- * fba recovery *-----------------------------------------------------------*/ /* * FBA blkgrps are harder to recover than CKD tracks because * there is not any information within the blkgrp itself to * validate (unlike a track, which has count fields that * terminate in an end-of-track marker). * * On the first pass we recover all compressed blkgrps since * these are readily validated (they must uncompress to a * certain size, CFBA_BLOCK_SIZE+CKDDASD_TRKHDR_SIZE). We * also recover uncompressed blkgrps if they are followed by * a valid trkhdr (and don't occur to close to the beginning * of the file). * * On the second pass we recover all uncompressed blkgrps * that weren't recovered in the first pass. The only * criteria is that the compression byte is zero and the * 4 byte blkgrp number is in range and there are at least * CFBA_BLOCK_SIZE bytes following. */ for (pass = 0; fbadasd && pass < 2; pass++) { lopos = CCKD_L1TAB_POS + (cdevhdr.numl1tab * 4); if (pass == 0) lopos += (cdevhdr.numl1tab * CCKD_L2TAB_SIZE); /* recovery loop */ s = cdsk_build_free_space (spctab, s); for (f = 0; spctab[f].typ != SPCTAB_EOF && n > 0; ) { U32 flen, fpos; /* next free space if too small */ if (spctab[f].typ != SPCTAB_FREE || spctab[f].siz <= CKDDASD_TRKHDR_SIZE+8 || (pass == 1 && spctab[f].siz < blkgrpsz)) { for (f = f + 1; spctab[f].typ != SPCTAB_EOF; f++) if (spctab[f].typ == SPCTAB_FREE) break; continue; } fpos = spctab[f].pos; flen = spctab[f].siz; /* * calculate length to read * if flen > len then we only read part of the space */ len = flen < sizeof(buf) ? flen : sizeof(buf); /* read the free space */ off = (off_t)fpos; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if ((rc = read (fd, buf, len)) != len) goto cdsk_read_error; /* Scan the space */ for (i = 0; i < len - (CKDDASD_TRKHDR_SIZE+8); i++) { /* For pass 1 the size left must be at least blkgrpsz */ if (pass == 1 && len - i < (int)blkgrpsz) break; /* Check compression byte */ if ((pass == 0 && compmask[buf[i]]) || (pass == 1 && buf[i] != CCKD_COMPRESS_NONE)) continue; /* Fetch possible trkhdr */ comp = buf[i]; blkgrp = fetch_fw (buf + i + 1); /* Validate possible trkhdr */ if (blkgrp < 0 || blkgrp >= blkgrps || rcvtab[blkgrp] != 1) continue; /* Validation for compress none */ if (comp == CCKD_COMPRESS_NONE && flen == (U32)len && len - i < (int)blkgrpsz) continue; /* Quick validation for zlib */ else if (comp == CCKD_COMPRESS_ZLIB && fetch_hw(buf + i + 5) % 31 != 0) continue; /* Quick validation for bzip2 */ else if (comp == CCKD_COMPRESS_BZIP2 && (buf[i+5] != 'B' || buf[i+6] != 'Z')) continue; /* * If we are in `borrowed space' then start over * with the current position at the beginning */ if (flen > (U32)len && i > len - (int)blkgrpsz) break; /* Checks for comp none */ if (comp == CCKD_COMPRESS_NONE) { l = blkgrpsz; if (len - i < (int)blkgrpsz || fpos + i < lopos) continue; if (len - i == (int)blkgrpsz && flen == (U32)len) goto cdsk_fba_recover; /* Pass 0 checks */ if (pass == 0 && (len - i - l < CKDDASD_TRKHDR_SIZE+8 || compmask[buf[i+l]] || fetch_fw (buf+i+l+1) >= (unsigned int)blkgrps) ) continue; goto cdsk_fba_recover; } /* The tests below are for pass 0 only */ if (pass == 1) continue; /* Check short `length' */ if (flen == (U32)len && (l = len - i) <= 1024) { if (cdsk_valid_trk (blkgrp, buf+i, heads, l)) { while (cdsk_valid_trk (blkgrp, buf+i, heads, --l)); l++; goto cdsk_fba_recover; } } /* Scan for next trkhdr */ for (j = i + CKDDASD_TRKHDR_SIZE+8; j <= len - (CKDDASD_TRKHDR_SIZE+8); j++) { if (j - i > (int)blkgrpsz) break; if (compmask[buf[j]] != 0 || fetch_fw(buf+j+1) >= (unsigned int)blkgrps) continue; /* check zlib compressed header */ if (buf[j] == CCKD_COMPRESS_ZLIB && fetch_hw(buf + j + 5) % 31 != 0) continue; /* check bzip2 compressed header */ else if (buf[j] == CCKD_COMPRESS_BZIP2 && (buf[j+5] != 'B' || buf[j+6] != 'Z')) continue; /* check to possible trkhdr */ l = j - i; if (cdsk_valid_trk (blkgrp, buf+i, heads, l)) { #if 0 while (cdsk_valid_trk (blkgrp, buf+i, heads, --l)); l++; #endif goto cdsk_fba_recover; } } /* scan for next trkhdr */ /* Check `length' */ l = len - i; if (flen == (U32)len && l <= (int)blkgrpsz) { if (cdsk_valid_trk (blkgrp, buf+i, heads, l)) { while (cdsk_valid_trk (blkgrp, buf+i, heads, --l)); l++; goto cdsk_fba_recover; } } /* Scan all lengths */ for (l = CKDDASD_TRKHDR_SIZE+8; i + l <= len; l++) { if (l > (int)blkgrpsz) break; if (cdsk_valid_trk (blkgrp, buf+i, heads, l)) goto cdsk_fba_recover; } /* for all lengths */ continue; cdsk_fba_recover: cckdumsg (dev, 301, "%s[%d] recovered offset 0x%" I64_FMT "x len %d\n", spaces[trktyp], blkgrp, (long long)off + i, l); n--; rcvtab[blkgrp] = 2; /* Enable recovery of comp 0 blkgrps for pass 0 */ if (fpos + i < lopos) lopos = fpos + i; /* add recovered block group to the space table */ spctab[s].typ = trktyp; spctab[s].val = blkgrp; spctab[s].pos = fpos + i; spctab[s].len = spctab[s].siz = l; s++; /* * adjust `i' knowing it will be incremented * in the `for' loop above. */ i += l - 1; } /* for each byte in the free space */ /* Adjust the free space for what we processed */ spctab[f].pos += i; spctab[f].len -= i; spctab[f].siz -= i; } /* for each free space */ } /* if fbadasd */ for (i = n = 0; i < trks; i++) if (rcvtab[i] == 2) n++; cckdumsg (dev, 300, "%d %s images recovered\n", n, spaces[trktyp]); /*----------------------------------------------------------- * Phase 2 -- rebuild affected l2 tables *-----------------------------------------------------------*/ /* * Make sure there's at least one non-zero `rcvtab' entry * for l2 tables in `l2errs'. Space validation may have * turned off all `rcvtab' entries for an l2. */ for (i = 0; i < cdevhdr.numl1tab; i++) if (l2errs[i]) rcvtab[i*256] = 1; /* Get storage for the l2 table array */ n = cdevhdr.numl1tab; len = sizeof(void *); if ((l2 = calloc (n, len)) == NULL) goto cdsk_calloc_error; /* Get storage for the rebuilt l2 tables */ len = CCKD_L2TAB_SIZE; for (i = 0; i < trks; i++) { l1x = i / 256; if (rcvtab[i] != 0 && l2[l1x] == NULL) { if ((l2[l1x] = malloc (len)) == NULL) goto cdsk_malloc_error; l1[l1x] = shadow ? 0xffffffff : 0; memcpy (l2[l1x], &empty_l2, len); } } /* Rebuild the l2 tables */ qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) { if (spctab[i].typ == SPCTAB_L2 && l2[spctab[i].val]) spctab[i].typ = SPCTAB_NONE; else if (spctab[i].typ == trktyp && l2[spctab[i].val/256]) { l1x = spctab[i].val / 256; l2x = spctab[i].val % 256; l2[l1x][l2x].pos = spctab[i].pos; l2[l1x][l2x].len = spctab[i].len; l2[l1x][l2x].size = spctab[i].siz; } } /* for each space */ qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); while (spctab[s-1].typ == SPCTAB_NONE) s--; /* Look for empty l2 tables */ for (i = 0; i < cdevhdr.numl1tab; i++) if (l2[i] != NULL && memcmp (l2[i], &empty_l2, CCKD_L2TAB_SIZE) == 0) { free (l2[i]); l2[i] = NULL; } /* * `s-1' indexes the SPCTAB_EOF space table entry. * Set its `pos' to the maximum allowed value to ensure * there will be free space for the rebuilt l2 tables. */ spctab[s-1].pos = (U32)maxsize; /* Build the free space */ s = cdsk_build_free_space (spctab, s); /* Find space for the rebuilt l2 tables */ for (i = j = 0; i < cdevhdr.numl1tab; i++) { if (l2[i] == NULL) continue; /* find a free space */ for ( ; spctab[j].typ != SPCTAB_EOF; j++) if (spctab[j].typ == SPCTAB_FREE && spctab[j].siz >= CCKD_L2TAB_SIZE) break; /* weird error if no space */ if (spctab[j].typ == SPCTAB_EOF) { cckdumsg (dev, 905, "not enough file space for recovery\n"); goto cdsk_error; } /* add l2 space */ l1[i] = spctab[j].pos; spctab[s].typ = SPCTAB_L2; spctab[s].val = i; spctab[s].pos = spctab[j].pos; spctab[s].len = spctab[s].siz = CCKD_L2TAB_SIZE; s++; /* adjust the free space */ spctab[j].pos += CCKD_L2TAB_SIZE; spctab[j].len -= CCKD_L2TAB_SIZE; spctab[j].siz -= CCKD_L2TAB_SIZE; } /* for each l2 table */ /*----------------------------------------------------------- * Phase 3 -- write l1 and l2 tables *-----------------------------------------------------------*/ if (ro) { cckdumsg (dev, 500, "recovery not completed, file opened read-only\n"); goto cdsk_error; } if (comperrs) { cckdumsg (dev, 501, "recovery not completed, missing compression\n"); goto cdsk_error; } /* Write the l1 table */ off = CCKD_L1TAB_POS; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = l1size; if ((rc = write (fd, l1, len)) != len) goto cdsk_write_error; /* Write l2 tables */ qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) { l1x = spctab[i].val; if (spctab[i].typ != SPCTAB_L2 || l2[l1x] == NULL) continue; off = (off_t)l1[l1x]; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = CCKD_L2TAB_SIZE; if ((rc = write (fd, l2[l1x], len)) != len) goto cdsk_write_error; free (l2[l1x]); l2[l1x] = NULL; } /* for each space */ /* Free recovery related storage */ if (l2) { for (i = 0; i < cdevhdr.numl1tab; i++) if (l2[i]) free (l2[i]); free (l2); l2 = NULL; } free (l2errs); l2errs = NULL; free (rcvtab); rcvtab = NULL; /* Ensure we do free space recovery */ fsperr = 1; } /* if (recovery || level >= 4) */ /*--------------------------------------------------------------- * Rebuild free space *---------------------------------------------------------------*/ if (fsperr && ro) cckdumsg (dev, 502, "free space not rebuilt, file opened read-only\n"); else if (fsperr) { /*----------------------------------------------------------- * Phase 1 -- build the free space * make sure the last space isn't free space and * that each free space is long enough (8 bytes). *-----------------------------------------------------------*/ cdsk_fsperr_retry: s = cdsk_build_free_space (spctab, s); /* * spctab[s-1] is the SPCTAB_EOF entry. * if spctab[s-2] is SPCTAB_FREE then discard it */ if (spctab[s-2].typ == SPCTAB_FREE) { spctab[s-1].typ = SPCTAB_NONE; spctab[s-2].typ = SPCTAB_EOF; spctab[s-2].val = -1; spctab[s-2].len = spctab[s-2].siz = 0; s--; } /* * Check for short free spaces. * If found, shift left until the next free space or eof. */ for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].typ == SPCTAB_FREE && spctab[i].siz < CCKD_FREEBLK_SIZE) break; if (spctab[i].typ != SPCTAB_EOF) { /* Shift following space left */ l = spctab[i++].siz; while (spctab[i].typ != SPCTAB_FREE && spctab[i].typ != SPCTAB_EOF) { /* Read the space and write shifted to the left */ off = (off_t)spctab[i].pos; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = spctab[i].siz; if ((rc = read (fd, buf, len)) != len) goto cdsk_read_error; off -= l; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if ((rc = write (fd, buf, len)) != len) goto cdsk_write_error; spctab[i].pos -= l; /* Update the l2 or l1 table entry */ if (spctab[i].typ == trktyp) { l1x = spctab[i].val/256; l2x = spctab[i].val%256; off = (off_t)l1[l1x] + l2x * CCKD_L2ENT_SIZE; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = CCKD_L2ENT_SIZE; if ((rc = read (fd, &l2ent, len)) != len) goto cdsk_read_error; l2ent.pos -= l; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if ((rc = write (fd, &l2ent, len)) != len) goto cdsk_write_error; } /* trk/blkgrp relocated */ else if (spctab[i].typ == SPCTAB_L2) l1[spctab[i].val] -= l; i++; } /* while not FREE space or EOF */ goto cdsk_fsperr_retry; } /* if short free space found */ /*----------------------------------------------------------- * Phase 2 -- rebuild free space statistics *-----------------------------------------------------------*/ cdevhdr.vrm[0] = CCKD_VERSION; cdevhdr.vrm[1] = CCKD_RELEASE; cdevhdr.vrm[2] = CCKD_MODLVL; cdevhdr.size = cdevhdr.used = cdevhdr.free = cdevhdr.free_total = cdevhdr.free_largest = cdevhdr.free_number = cdevhdr.free_imbed = 0; for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].typ == SPCTAB_FREE) { cdevhdr.size += spctab[i].siz; if (spctab[i].siz > cdevhdr.free_largest) cdevhdr.free_largest = spctab[i].siz; cdevhdr.free_total += spctab[i].siz; cdevhdr.free_number++; } else { cdevhdr.size += spctab[i].siz; cdevhdr.used += spctab[i].len; cdevhdr.free_total += spctab[i].siz - spctab[i].len; cdevhdr.free_imbed += spctab[i].siz - spctab[i].len; } /*----------------------------------------------------------- * Phase 3 -- write the free space *-----------------------------------------------------------*/ if (cdevhdr.free_number) { /* size needed for new format free space */ len = (cdevhdr.free_number+1) * CCKD_FREEBLK_SIZE; /* look for existing free space to fit new format free space */ for (i = off = 0; !off && spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].typ == SPCTAB_FREE && len <= (int)spctab[i].siz) off = (off_t)spctab[i].pos; /* if no applicable space see if we can append to the file */ if (!off && maxsize - cdevhdr.size >= len) off = (off_t)cdevhdr.size; /* get free space buffer */ if (off && (fsp = malloc (len)) == NULL) off = 0; if (off) { /* new format free space */ memcpy (fsp, "FREE_BLK", 8); for (i = 0, j = 1; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].typ == SPCTAB_FREE) { fsp[j].pos = spctab[i].pos; fsp[j++].len = spctab[i].siz; } /* Write the free space */ if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if ((rc = write (fd, fsp, len)) != len) goto cdsk_write_error; cdevhdr.free = (U32)off; free (fsp); fsp = NULL; } /* new format free space */ else { /* old format free space */ len = CCKD_FREEBLK_SIZE; for (i = 0; spctab[i].typ != SPCTAB_FREE; i++); cdevhdr.free = spctab[i].pos; off = (off_t)spctab[i].pos; freeblk.pos = 0; freeblk.len = spctab[i].siz; for (i = i + 1; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].typ == SPCTAB_FREE) { freeblk.pos = spctab[i].pos; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if (write (fd, &freeblk, len) != len) goto cdsk_write_error; off = (off_t)spctab[i].pos; freeblk.pos = 0; freeblk.len = spctab[i].len; } if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; if (write (fd, &freeblk, len) != len) goto cdsk_write_error; } /* old format free space */ } /* if (cdevhdr.free_number) */ /* Write cdevhdr and l1 table */ off = CCKD_DEVHDR_POS; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = CCKD_DEVHDR_SIZE; if (write (fd, &cdevhdr, len) != len) goto cdsk_write_error; off = CCKD_L1TAB_POS; if (lseek (fd, off, SEEK_SET) < 0) goto cdsk_lseek_error; len = l1size; if (write (fd, l1, len) != len) goto cdsk_write_error; /* Truncate the file */ off = (off_t)cdevhdr.size; if (cdevhdr.free == cdevhdr.size) off += (cdevhdr.free_number+1) * CCKD_FREEBLK_SIZE; rc = ftruncate (fd, off); cckdumsg (dev, 104, "free space rebuilt\n"); } /* if (fsperr) */ /*--------------------------------------------------------------- * Return *---------------------------------------------------------------*/ cdsk_return_ok: rc = recovery ? 2 : fsperr ? 1 : 0; if (!ro && (cdevhdr.options & (CCKD_ORDWR|CCKD_OPENED|CCKD_SPERRS))) { /* * Leave the ORDWR bit on for now. This will prevent * old-format free space releases from doing a -1 check * on a file that has new-format free space */ #if 0 cdevhdr.options &= ~(CCKD_ORDWR|CCKD_OPENED|CCKD_SPERRS); #else cdevhdr.options &= ~(CCKD_OPENED|CCKD_SPERRS); #endif /* Set version.release.modlvl */ cdevhdr.vrm[0] = CCKD_VERSION; cdevhdr.vrm[1] = CCKD_RELEASE; cdevhdr.vrm[2] = CCKD_MODLVL; off = CCKD_DEVHDR_POS; if (lseek (fd, CCKD_DEVHDR_POS, SEEK_SET) >= 0) write (fd, &cdevhdr, CCKD_DEVHDR_SIZE); } cdsk_return: /* free all space */ if (l1) free (l1); if (spctab) free (spctab); if (l2errs) free (l2errs); if (rcvtab) free (rcvtab); if (fsp) free (fsp); if (l2) { for (i = 0; i < cdevhdr.numl1tab; i++) if (l2[i]) free (l2[i]); free (l2); } return rc; /*--------------------------------------------------------------- * Error exits *---------------------------------------------------------------*/ cdsk_fstat_error: cckdumsg (dev, 701, "fstat error: %s\n", strerror(errno)); goto cdsk_error; cdsk_lseek_error: cckdumsg (dev, 702, "lseek error offset 0x%" I64_FMT "x: %s\n", (long long)off, strerror(errno)); goto cdsk_error; cdsk_read_error: cckdumsg (dev, 703, "read error rc=%d offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete"); goto cdsk_error; cdsk_write_error: cckdumsg (dev, 704, "write error rc=%d offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)off, len, rc < 0 ? strerror(errno) : "incomplete"); goto cdsk_error; cdsk_malloc_error: cckdumsg (dev, 705, "malloc error, size=%d: %s\n", len, strerror(errno)); goto cdsk_error; cdsk_calloc_error: cckdumsg (dev, 706, "calloc error, size=%d: %s\n", n*len, strerror(errno)); goto cdsk_error; cdsk_error: rc = -1; goto cdsk_return; } /* end function cckd_chkdsk */ /*------------------------------------------------------------------- * cckd_chkdsk() space table sort *-------------------------------------------------------------------*/ static int cdsk_spctab_sort(const void *a, const void *b) { const SPCTAB *x = a, *y = b; if (x->typ == SPCTAB_NONE) return 1; else if (y->typ == SPCTAB_NONE) return -1; else if (x->typ == SPCTAB_EOF) return 1; else if (y->typ == SPCTAB_EOF) return -1; else if (x->pos < y->pos) return -1; else return 1; } /* end function cdsk_spctab_sort */ /*-------------------------------------------------------------------*/ /* Build free space in the space table */ /*-------------------------------------------------------------------*/ static int cdsk_build_free_space(SPCTAB *spctab, int s) { int i; for (i = 0; i < s; i++) if (spctab[i].typ == SPCTAB_FREE) spctab[i].typ = SPCTAB_NONE; qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); while (spctab[s-1].typ == SPCTAB_NONE) s--; for (i = 0; spctab[i].typ != SPCTAB_EOF; i++) if (spctab[i].pos + spctab[i].siz < spctab[i+1].pos) { spctab[s].typ = SPCTAB_FREE; spctab[s].val = -1; spctab[s].pos = spctab[i].pos + spctab[i].siz; spctab[s].len = spctab[s].siz = spctab[i+1].pos - spctab[s].pos; s++; } qsort (spctab, s, sizeof(SPCTAB), cdsk_spctab_sort); return s; } /*-------------------------------------------------------------------*/ /* Validate a track image */ /* */ /* If `len' is negative and compression is CCKD_COMPRESS_NONE then */ /* `len' indicates a buffer size containing the track image and the */ /* value returned is the actual track image length */ /*-------------------------------------------------------------------*/ static int cdsk_valid_trk (int trk, BYTE *buf, int heads, int len) { int i; /* Index */ int len2; /* Positive `len' */ int kl, dl; /* Key/Data lengths */ BYTE *bufp; /* Buffer pointer */ int bufl; /* Buffer length */ #ifdef HAVE_LIBZ uLongf zlen; #endif #ifdef CCKD_BZIP2 unsigned int bz2len; #endif #if defined(HAVE_LIBZ) || defined(CCKD_BZIP2) int rc; /* Return code */ BYTE buf2[65536]; /* Uncompressed buffer */ #endif /* Negative len only allowed for comp none */ len2 = len > 0 ? len : -len; if (len2 < CKDDASD_TRKHDR_SIZE + 8) return 0; /* Uncompress the track/block image */ switch (buf[0]) { case CCKD_COMPRESS_NONE: bufp = buf; bufl = len2; break; #ifdef HAVE_LIBZ case CCKD_COMPRESS_ZLIB: if (len < 0) return 0; bufp = (BYTE *)buf2; memcpy (buf2, buf, CKDDASD_TRKHDR_SIZE); zlen = sizeof(buf2) - CKDDASD_TRKHDR_SIZE; rc = uncompress (buf2 + CKDDASD_TRKHDR_SIZE, &zlen, buf + CKDDASD_TRKHDR_SIZE, len - CKDDASD_TRKHDR_SIZE); if (rc != Z_OK) return 0; bufl = (int)zlen + CKDDASD_TRKHDR_SIZE; break; #endif #ifdef CCKD_BZIP2 case CCKD_COMPRESS_BZIP2: if (len < 0) return 0; bufp = (BYTE *)buf2; memcpy (buf2, buf, CKDDASD_TRKHDR_SIZE); bz2len = sizeof(buf2) - CKDDASD_TRKHDR_SIZE; rc = BZ2_bzBuffToBuffDecompress ( (char *)&buf2[CKDDASD_TRKHDR_SIZE], &bz2len, (char *)&buf[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE, 0, 0); if (rc != BZ_OK) return 0; bufl = (int)bz2len + CKDDASD_TRKHDR_SIZE; break; #endif default: return 0; } /* switch (buf[0]) */ /* fba check */ if (heads == 65536) { if (bufl != CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE) return 0; else return len > 0 ? len : bufl; } /* Check length */ if (bufl <= 5 + 8 + 8 + 8 + 8) return 0; /* Check ha */ if (fetch_hw(bufp + 1) != trk / heads || fetch_hw(bufp + 3) != trk % heads) return 0; /* Check r0 */ if (fetch_hw(bufp + 1) != fetch_hw(bufp + 5) || fetch_hw(bufp + 3) != fetch_hw(bufp + 7) || bufp[9] != 0 || bufp[10] != 0 || fetch_hw(bufp +11) != 8) return 0; /* Check user records */ for (i = 21; i < bufl - 8; i += 8 + kl + dl) { if (fetch_hw(bufp + i + 2) >= heads || bufp[i + 4] == 0) break; kl = bufp[i + 5]; dl = fetch_hw(bufp + i + 6); } if (len < 0) bufl = i + 8; if (i != bufl - 8 || memcmp(bufp + i, eighthexFF, 8)) return 0; return len > 0 ? len : bufl; } /* end function cdsk_valid_trk */ /*-------------------------------------------------------------------*/ /* Message function */ /*-------------------------------------------------------------------*/ DLL_EXPORT void cckdumsg (DEVBLK *dev, int n, char *format, ...) { CCKDDASD_EXT *cckd; int sfx; int i; char *p; va_list vl; char msg[4096]; cckd = dev->cckd_ext; sfx = cckd ? cckd->sfn : -1; i = sprintf (msg, "HHCCU%3.3d%c ", n, n < 400 ? 'I' : n < 700 ? 'W' : 'E'); if (sfx >= 0) i += sprintf (msg+i, "%4.4X file[%d]: ", dev->devnum, sfx); else { if ((p = strrchr(dev->filename, '/')) == NULL && (p = strrchr(dev->filename, '\\')) == NULL) p = dev->filename; else p++; i += sprintf (msg+i, "%s: ", p); } va_start (vl, format); vsprintf (msg+i, format, vl); va_end (vl); if (dev->batch) fprintf(stdout,"%s",msg); else logmsg("%s",msg); } hercules-3.12/dasdtab.c0000664000175000017500000007316312564723224011763 00000000000000/* DASDTAB.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Supported DASD definitions */ /*-------------------------------------------------------------------*/ /* This module contains the tables that define the attributes of */ /* each DASD device and control unit supported by Hercules. */ /* Routines are also provided to perform table lookup and build the */ /* device identifier and characteristics areas. */ /* */ /* Note: source for most CKD/FBA device capacities take from SDI's */ /* device capacity page at: http://www.sdisw.com/dasd_capacity.html */ /* (used with permission) */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _DASDTAB_C_ #define _HDASD_DLL_ #include "hercules.h" /*-------------------------------------------------------------------*/ /* CKD device definitions */ /*-------------------------------------------------------------------*/ static CKDDEV ckdtab[] = { /* name type model clas code prime a hd r0 r1 har0 len sec rps f f1 f2 f3 f4 f5 f6 cu */ {"2305", 0x2305,0x00,0x20,0x00, 48,0, 8,14568,14136, 432,14568, 90,0x0000,-1,202,432, 0, 0, 0,0,"2835"}, {"2305-1", 0x2305,0x00,0x20,0x00, 48,0, 8,14568,14136, 432,14568, 90,0x0000,-1,202,432, 0, 0, 0,0,"2835"}, {"2305-2", 0x2305,0x02,0x20,0x00, 96,0, 8,14858,14660, 198,14858, 90,0x0000,-1, 91,198, 0, 0, 0,0,"2835"}, {"2311", 0x2311,0x00,0x20,0x00, 200,3,10, 0, 3625, 0, 3625, 0,0x0000,-2,20, 61, 537, 512, 0,0,"2841"}, {"2311-1", 0x2311,0x00,0x20,0x00, 200,3,10, 0, 3625, 0, 3625, 0,0x0000,-2,20, 61, 537, 512, 0,0,"2841"}, {"2314", 0x2314,0x00,0x20,0x00, 200,3,20, 0, 7294, 0, 7294, 0,0x0000,-2,45,101,2137,2048, 0,0,"2314"}, {"2314-1", 0x2314,0x00,0x20,0x00, 200,3,20, 0, 7294, 0, 7294, 0,0x0000,-2,45,101,2137,2048, 0,0,"2314"}, {"3330", 0x3330,0x01,0x20,0x00, 404,7,19,13165,13030, 135,13165,128,0x0000,-1,56,135, 0, 0, 0,0,"3830"}, {"3330-1", 0x3330,0x01,0x20,0x00, 404,7,19,13165,13030, 135,13165,128,0x0000,-1,56,135, 0, 0, 0,0,"3830"}, {"3330-2", 0x3330,0x11,0x20,0x00, 808,7,19,13165,13030, 135,13165,128,0x0000,-1,56,135, 0, 0, 0,0,"3830"}, {"3330-11", 0x3330,0x11,0x20,0x00, 808,7,19,13165,13030, 135,13165,128,0x0000,-1,56,135, 0, 0, 0,0,"3830"}, {"3340", 0x3340,0x01,0x20,0x00, 348,1,12, 8535, 8368, 167, 8535, 64,0x0000,-1,75,167, 0, 0, 0,0,"3830"}, {"3340-1", 0x3340,0x01,0x20,0x00, 348,1,12, 8535, 8368, 167, 8535, 64,0x0000,-1,75,167, 0, 0, 0,0,"3830"}, {"3340-35", 0x3340,0x01,0x20,0x00, 348,1,12, 8535, 8368, 167, 8535, 64,0x0000,-1,75,167, 0, 0, 0,0,"3830"}, {"3340-2", 0x3340,0x02,0x20,0x00, 696,2,12, 8535, 8368, 167, 8535, 64,0x0000,-1,75,167, 0, 0, 0,0,"3830"}, {"3340-70", 0x3340,0x02,0x20,0x00, 696,2,12, 8535, 8368, 167, 8535, 64,0x0000,-1,75,167, 0, 0, 0,0,"3830"}, {"3350", 0x3350,0x00,0x20,0x00, 555,5,30,19254,19069, 185,19254,128,0x0000,-1,82,185, 0, 0, 0,0,"3830"}, {"3350-1", 0x3350,0x00,0x20,0x00, 555,5,30,19254,19069, 185,19254,128,0x0000,-1,82,185, 0, 0, 0,0,"3830"}, /* name type model clas code prime a hd r0 r1 har0 len sec rps f f1 f2 f3 f4 f5 f6 cu */ {"3375", 0x3375,0x02,0x20,0x0e, 959,3,12,36000,35616, 832,36000,196,0x5007, 1, 32,384,160, 0, 0,0,"3880"}, {"3375-1", 0x3375,0x02,0x20,0x0e, 959,3,12,36000,35616, 832,36000,196,0x5007, 1, 32,384,160, 0, 0,0,"3880"}, {"3380", 0x3380,0x02,0x20,0x0e, 885,1,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-1", 0x3380,0x02,0x20,0x0e, 885,1,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-A", 0x3380,0x02,0x20,0x0e, 885,1,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-B", 0x3380,0x02,0x20,0x0e, 885,1,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-D", 0x3380,0x06,0x20,0x0e, 885,1,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-J", 0x3380,0x16,0x20,0x0e, 885,1,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-2", 0x3380,0x0a,0x20,0x0e, 1770,2,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-E", 0x3380,0x0a,0x20,0x0e, 1770,2,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-3", 0x3380,0x1e,0x20,0x0e, 2655,3,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"3380-K", 0x3380,0x1e,0x20,0x0e, 2655,3,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"EMC3380K+", 0x3380,0x1e,0x20,0x0e, 3339,3,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, {"EMC3380K++",0x3380,0x1e,0x20,0x0e, 3993,3,15,47988,47476,1088,47968,222,0x5007, 1, 32,492,236, 0, 0,0,"3880"}, /* name type model clas code prime a hd r0 r1 har0 len sec rps f f1 f2 f3 f4 f5 f6 cu */ {"3390", 0x3390,0x02,0x20,0x26, 1113,1,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-1", 0x3390,0x02,0x20,0x26, 1113,1,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-2", 0x3390,0x06,0x20,0x27, 2226,1,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-3", 0x3390,0x0a,0x20,0x24, 3339,1,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-9", 0x3390,0x0c,0x20,0x32,10017,3,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-27", 0x3390,0x0c,0x20,0x32,32760,3,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-J", 0x3390,0x0c,0x20,0x32,32760,3,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-54", 0x3390,0x0c,0x20,0x32,65520,3,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"3390-JJ", 0x3390,0x0c,0x20,0x32,65520,3,15,57326,56664,1428,58786,224,0x7708, 2, 34,19, 9, 6,116,6,"3990"}, {"9345", 0x9345,0x04,0x20,0x04, 1440,0,15,48174,46456,1184,48280,213,0x8b07, 2, 34,18, 7, 6,116,6,"9343"}, {"9345-1", 0x9345,0x04,0x20,0x04, 1440,0,15,48174,46456,1184,48280,213,0x8b07, 2, 34,18, 7, 6,116,6,"9343"}, {"9345-2", 0x9345,0x04,0x20,0x04, 2156,0,15,48174,46456,1184,48280,213,0x8b07, 2, 34,18, 7, 6,116,6,"9343"} /* name type model clas code prime a hd r0 r1 har0 len sec rps f f1 f2 f3 f4 f5 f6 cu */ } ; #define CKDDEV_NUM (sizeof(ckdtab)/CKDDEV_SIZE) /*-------------------------------------------------------------------*/ /* CKD control unit definitions */ /*-------------------------------------------------------------------*/ /* */ /* */ /* 3880, 3990, 2105 and higher coding */ /* ---------------------------------- */ /* */ /* Model coding bits (RDC byte 2): */ /* */ /* 11.. .... 3880 Speed Matching Buffer (LR support) */ /* ..1. .... Non-Gap-Synchronous mode */ /* .... 1... Cached */ /* .... .011 3880-3 */ /* .... .101 3880-3 Feature 3005 - 3380 AJ4/AK4 Attachment */ /* .... .010 3990-1/2 Nocache/Synchronous */ /* .... .100 3990-3/6/7 Basic Operation Mode */ /* .... .001 3990-6/7 Enhanced Mode */ /* */ /* */ /* Features (RDC bytes 6-9): */ /* */ /* Byte 6: */ /* 1... .... Multiple Burst ECC (ignored, 3380 devices) */ /* .1.. .... Locate Record, Read Tracks */ /* ..1. .... Reserved */ /* ...1 .... Locate Record, Read */ /* .... ...1 Reserved for VM minidisk use */ /* (testing this bit for zero is not reliable as an */ /* indicator that this is not a minidisk; can fail */ /* when minidisk is a fullpack minidisk) */ /* */ /* Byte 7 - Levels defining byte 8 format */ /* 0000 0000 Not supported by Hercules, must be zero */ /* */ /* Byte 8 - Added feature support */ /* 000. .... Not supported by Hercules, must be zero */ /* ...1 .... Data striping (required for VSAM Extended Format) */ /* .... 0000 Not supported by Hercules, must be zero */ /* */ /* Byte 9 - Subsystem Program Visible Facilities */ /* 1... .... Cache Fast Write supported (not supported, yet!) */ /* (non-retentive data) */ /* .1.. .... Lock Facility supported (not supported, yet!) */ /* ..1. .... Record Cache supported */ /* ...1 .... Track Cache supported */ /* .... 1... Dual Copy supported (not supported) */ /* .... .1.. DASD Fast Write supported (not supported) */ /* .... ..1. Reset Allegiance (not supported, yet!) */ /* .... ...1 24 Byte Compatibility Sense Format */ /* (set by code when 3380 on 3390 controller) */ /* */ /* */ /*-------------------------------------------------------------------*/ static CKDCU ckdcutab[] = { /* func/ type */ /* name type model code feat code features ciws --------- senselength */ {"2314", 0x2314,0x00,0x00,0x00,0x00,0x00000000,0,0,0,0,0,0,0,0,6}, {"2835", 0x2835,0x00,0x00,0x00,0x00,0x00000000,0,0,0,0,0,0,0,0,6}, {"2841", 0x2841,0x00,0x00,0x00,0x00,0x00000000,0,0,0,0,0,0,0,0,6}, {"3830", 0x3830,0x02,0x00,0x00,0x00,0x00000000,0,0,0,0,0,0,0,0,24}, {"3880", 0x3880,0x05,0x09,0x00,0x00,0x80000000,0,0,0,0,0,0,0,0,24}, {"3990", 0x3990,0xc2,0x10,0x00,0x00,0xd0000000,0x40fa0100,0,0,0,0,0,0,0,32}, {"3990-3", 0x3990,0xec,0x06,0x00,0x00,0xd0001010,0x40fa0100,0x41270004,0x423e0040,0,0,0,0,0,32}, {"3990-6", 0x3990,0xe9,0x15,0x48,0x15,0x50001010,0x40fa0100,0x41270004,0x423e0060,0,0,0,0,0,32}, {"9343", 0x9343,0xe0,0x11,0x00,0x00,0x80000000,0,0,0,0,0,0,0,0,32} /*"2105", 0x2105,0xe8,0x15,0x48,0x15,0x50000037,0x40fa0100,0x41270004,0x423e01a0,0x433e0008,0,0,0,0,32}, */ } ; #define CKDCU_NUM (sizeof(ckdcutab)/CKDCU_SIZE) /*-------------------------------------------------------------------*/ /* FBA device definitions - courtesy of Tomas Masek */ /*-------------------------------------------------------------------*/ static FBADEV fbatab[] = { /* name devt class type mdl bpg bpp size blks cu */ {"3310", 0x3310,0x21,0x01,0x01, 32,352,512, 125664,0x4331}, {"3310-1", 0x3310,0x21,0x01,0x01, 32,352,512, 125664,0x4331}, {"3310-x", 0x3310,0x21,0x01,0x01, 32,352,512, 0,0x4331}, {"3370", 0x3370,0x21,0x02,0x00, 62,744,512, 558000,0x3880}, {"3370-1", 0x3370,0x21,0x02,0x00, 62,744,512, 558000,0x3880}, {"3370-A1", 0x3370,0x21,0x02,0x00, 62,744,512, 558000,0x3880}, {"3370-B1", 0x3370,0x21,0x02,0x00, 62,744,512, 558000,0x3880}, {"3370-2", 0x3370,0x21,0x05,0x04, 62,744,512, 712752,0x3880}, {"3370-A2", 0x3370,0x21,0x05,0x04, 62,744,512, 712752,0x3880}, {"3370-B2", 0x3370,0x21,0x05,0x04, 62,744,512, 712752,0x3880}, {"3370-x", 0x3370,0x21,0x05,0x04, 62,744,512, 0,0x3880}, {"9332", 0x9332,0x21,0x07,0x00, 73,292,512, 360036,0x6310}, {"9332-400", 0x9332,0x21,0x07,0x00, 73,292,512, 360036,0x6310}, {"9332-600", 0x9332,0x21,0x07,0x01, 73,292,512, 554800,0x6310}, {"9332-x", 0x9332,0x21,0x07,0x01, 73,292,512, 0,0x6310}, {"9335", 0x9335,0x21,0x06,0x01, 71,426,512, 804714,0x6310}, {"9335-x", 0x9335,0x21,0x06,0x01, 71,426,512, 0,0x6310}, /*"9313", 0x9313,0x21,0x08,0x00, ??,???,512, 246240,0x????}, */ /*"9313-1, 0x9313,0x21,0x08,0x00, ??,???,512, 246240,0x????}, */ /*"9313-14", 0x9313,0x21,0x08,0x14, ??,???,512, 246240,0x????}, */ /* 246240=32*81*5*19 */ {"9313", 0x9313,0x21,0x08,0x00, 96,480,512, 246240,0x6310}, {"9313-x", 0x9313,0x21,0x08,0x00, 96,480,512, 0,0x6310}, /* 9336 Junior models 1,2,3 */ /*"9336-J1", 0x9336,0x21,0x11,0x00, 63,315,512, 920115,0x6310}, */ /*"9336-J2", 0x9336,0x21,0x11,0x04, ??,???,512, ?,0x6310}, */ /*"9336-J3", 0x9336,0x21,0x11,0x08, ??,???,512, ?,0x6310}, */ /* 9336 Senior models 1,2,3 */ /*"9336-S1", 0x9336,0x21,0x11,0x10,111,777,512,1672881,0x6310}, */ /*"9336-S2", 0x9336,0x21,0x11,0x14,???,???,512, ?,0x6310}, */ /*"9336-S3", 0x9336,0x21,0x11,0x18,???,???,512, ?,0x6310}, */ {"9336", 0x9336,0x21,0x11,0x00, 63,315,512, 920115,0x6310}, {"9336-10", 0x9336,0x21,0x11,0x00, 63,315,512, 920115,0x6310}, {"9336-20", 0x9336,0x21,0x11,0x10,111,777,512,1672881,0x6310}, {"9336-25", 0x9336,0x21,0x11,0x10,111,777,512,1672881,0x6310}, {"9336-x", 0x9336,0x21,0x11,0x10,111,777,512, 0,0x6310}, /* name devt class type mdl bpg bpp size blks cu */ {"0671-08", 0x0671,0x21,0x12,0x08, 63,504,512, 513072,0x6310}, {"0671", 0x0671,0x21,0x12,0x00, 63,504,512, 574560,0x6310}, {"0671-04", 0x0671,0x21,0x12,0x04, 63,504,512, 624456,0x6310}, {"0671-x", 0x0671,0x21,0x12,0x04, 63,504,512, 0,0x6310} } ; #define FBADEV_NUM (sizeof(fbatab)/FBADEV_SIZE) #if defined(FEATURE_VM_BLOCKIO) static BLKTAB blktab[] = { #if 0 /* Remove conditional compilation when CKD devices supported */ CKDIOT("2305",0x2305,15,10,5,3), CKDIOT("2311",0x2311,6,3,1,0), CKDIOT("2314",0x2314,11,6,3,1), CKDIOT("3330",0x3330,20,11,6,3), CKDIOT("3340",0x3340,12,7,3,2), CKDIOT("3350",0x3350,27,15,8,4), CKDIOT("3375",0x3375,40,25,14,8), CKDIOT("3380",0x3380,35,23,14,7), CKDIOT("3390",0x3390,49,33,21,12), CKDIOT("9345",0x9345,41,28,17,9), #endif FBAIOT("0671",0x0671), FBAIOT("3310",0x3310), FBAIOT("3370",0x3370), FBAIOT("9332",0x9332), FBAIOT("9335",0x9335), FBAIOT("9336",0x9336) }; #define BLKTAB_NUM (sizeof(blktab)/BLKTAB_SIZE) #endif /* defined(FEATURE_VM_BLOCKIO) */ /*-------------------------------------------------------------------*/ /* Lookup a table entry either by name or type */ /*-------------------------------------------------------------------*/ DLL_EXPORT void *dasd_lookup (int dtype, char *name, U32 devt, U32 size) { U32 i; /* Loop Index */ switch (dtype) { case DASD_CKDDEV: for (i = 0; i < (int)CKDDEV_NUM; i++) { if ((name && !strcmp(name, ckdtab[i].name)) || (((U32)devt == (U32)ckdtab[i].devt || (U32)devt == (U32)(ckdtab[i].devt & 0xff)) && (U32)size <= (U32)(ckdtab[i].cyls + ckdtab[i].altcyls))) return &ckdtab[i]; } return NULL; case DASD_CKDCU: for (i = 0; i < (int)CKDCU_NUM; i++) { if ((name != NULL && strcmp(name, ckdcutab[i].name) == 0) || devt == ckdcutab[i].devt) return &ckdcutab[i]; } return NULL; case DASD_FBADEV: for (i = 0; i < (int)FBADEV_NUM; i++) { if ((name && !strcmp(name, fbatab[i].name)) || (((U32)devt == (U32)fbatab[i].devt || (U32)devt == (U32)(fbatab[i].devt & 0xff)) && ((size <= fbatab[i].blks) || (fbatab[i].blks == 0)))) return &fbatab[i]; } return NULL; #if defined(FEATURE_VM_BLOCKIO) case DASD_STDBLK: for (i = 0; i < (int)BLKTAB_NUM; i++) { if ((name && !strcmp(name, blktab[i].name)) || (U32)devt == (U32)blktab[i].devt || (U32)devt == (U32)(blktab[i].devt & 0xff)) return &blktab[i]; } return NULL; #endif /* defined(FEATURE_VM_BLOCKIO) */ default: return NULL; } return NULL; } /*-------------------------------------------------------------------*/ /* Build CKD devid field */ /*-------------------------------------------------------------------*/ int dasd_build_ckd_devid (CKDDEV *ckd, CKDCU *cu, BYTE *devid) { int len; memset (devid, 0, 256); store_fw (devid + 0, 0xFF000000 | (cu->devt << 8) | cu->model); store_fw (devid + 4, (ckd->devt << 16) | (ckd->model << 8) | 0x00); store_fw (devid + 8, cu->ciw1); store_fw (devid +12, cu->ciw2); store_fw (devid +16, cu->ciw3); store_fw (devid +20, cu->ciw4); store_fw (devid +24, cu->ciw5); store_fw (devid +28, cu->ciw6); store_fw (devid +32, cu->ciw7); store_fw (devid +36, cu->ciw8); /* Set length */ if (cu->ciw8 != 0) len = 40; else if (cu->ciw7 != 0) len = 36; else if (cu->ciw6 != 0) len = 32; else if (cu->ciw5 != 0) len = 28; else if (cu->ciw4 != 0) len = 24; else if (cu->ciw3 != 0) len = 20; else if (cu->ciw2 != 0) len = 16; else if (cu->ciw1 != 0) len = 12; else len = 7; /* If LEGACYSENSEID ENABLE is not set and device is a 2311 or 2314, set devid length to zero to force command reject response to 0xE4 Sense ID command */ if (1 && !sysblk.legacysenseid && (0 || 0x2311 == ckd->devt || 0x2314 == ckd->devt ) ) { len = 0; } return len; } /*-------------------------------------------------------------------*/ /* Build CKD devchar field */ /*-------------------------------------------------------------------*/ int dasd_build_ckd_devchar (CKDDEV *ckd, CKDCU *cu, BYTE *devchar, int cyls) { int altcyls; /* Number alternate cyls */ if (cyls > ckd->cyls) altcyls = cyls - ckd->cyls; else altcyls = 0; memset (devchar, 0, 64); store_hw(devchar+0, cu->devt); // Storage control type devchar[2] = cu->model; // CU model store_hw(devchar+3, ckd->devt); // Device type devchar[5] = ckd->model; // Device model store_fw(devchar+6, cu->sctlfeat | // Device and SD facilities (cu->devt == 0x3990 && // ... or in 24-byte sense ckd->devt == 0x3380)); // ... compatability for 3380 // ... hosted on 3990 controller devchar[10] = ckd->class; // Device class code devchar[11] = ckd->code; // Device type code store_hw(devchar+12, cyls - altcyls); // Primary cylinders store_hw(devchar+14, ckd->heads); // Tracks per cylinder devchar[16] = (BYTE)(ckd->sectors); // Number of sectors store_hw(devchar+18, ckd->len); // Track length store_hw(devchar+20, ckd->har0); // Length of HA and R0 if (ckd->formula == 1) { devchar[22] = (BYTE)(ckd->formula); // Track capacity formula devchar[23] = (BYTE)(ckd->f1); // Factor F1 store_hw(devchar+24, ckd->f2); // Factor F2 store_hw(devchar+26, ckd->f3); // Factor F3 } else if (ckd->formula == 2) { devchar[22] = (BYTE)(ckd->formula); // Track capacity formula devchar[23] = (BYTE)(ckd->f1); // Factor F1 devchar[24] = (BYTE)(ckd->f2); // Factor F2 devchar[25] = (BYTE)(ckd->f3); // Factor F3 devchar[26] = (BYTE)(ckd->f4); // Factor F4 devchar[27] = (BYTE)(ckd->f5); // Factor F5 } if (altcyls > 0) { store_hw(devchar+28, cyls - altcyls); // Alternate cylinder & tracks store_hw(devchar+30, altcyls * ckd->heads); } devchar[40] = ckd->code; // MDR record ID devchar[41] = ckd->code; // OBR record ID devchar[42] = cu->code; // CU Type Code devchar[43] = 0x02; // Parameter length store_hw(devchar+44, ckd->r0); // Record 0 length devchar[47] = 0x01; // Track set devchar[48] = (BYTE)(ckd->f6); // F6 store_hw(devchar+49, ckd->rpscalc); // RPS factor /* Bytes 51-53 are required for VSAM Extended Format */ if (MODEL3(cu)) { // 3990-3 devchar[51] = 0x0f; // Feature buffer lower limit devchar[52] = 0x00; // Feature buffer upper limit devchar[53] = 0x3f; // Feature buffer upper limit } if (MODEL6(cu)) { // 3990-6 devchar[51] = 0x0f; // Feature buffer lower limit devchar[52] = 0x00; // Feature buffer upper limit devchar[53] = 0x7f; // Feature buffer upper limit } devchar[54] = cu->funcfeat; // device/CU functions/features devchar[56] = cu->typecode; // Real CU type code /*---------------------------------------------------------------*/ /* 2007/05/04 @kl */ /* The following line to set devchar[57] to 0xff was restored */ /* to circumvent a command reject when ICKDSF issues a Read */ /* Special Home Address (0x0a) to an alternate track. */ /* According to the IBM 3880 Storage Control Reference, */ /* GA16-1661-09, and the 3990/9330 Reference, GA32-0274-05, */ /* it should be 0x00 for real 3380 and 3390 devices. Setting */ /* it to 0xff makes the underlying real DASD look like a */ /* disk array (whose virtual 3380/3390 disks have no alternate */ /* tracks). This causes DSF to skip issuing the 0x0a channel */ /* command, which Hercules does not currently support, for */ /* alternate tracks. */ /*---------------------------------------------------------------*/ devchar[57] = 0xff; // real device type code return 64; } /*-------------------------------------------------------------------*/ /* Build CKD configuration data */ /*-------------------------------------------------------------------*/ DLL_EXPORT int dasd_build_ckd_config_data (DEVBLK *dev, BYTE *iobuf, int count) { int i; BYTE buf[256]; /* Clear the configuration data area */ memset (buf, 0, 256); /* Bytes 0-31: NED 1 Node element descriptor for the device */ store_fw (buf, 0xc4010100); sprintf ((char *)&buf[4], " %4.4X0%2.2XHRCZZ000000000001", dev->ckdtab->devt, dev->ckdtab->model); for (i = 4; i < 30; i++) buf[i] = host_to_guest(buf[i]); buf[30] = 0x00; buf[31] = (dev->devnum & 0xFF); /* Bytes 32-63: NED 2 Node element descriptor for the string */ store_fw (buf + 32, 0xc4000000); sprintf ((char *)&buf[36], " %4.4X0%2.2XHRCZZ000000000001", dev->ckdtab->devt, dev->ckdtab->model); for (i = 36; i < 62; i++) buf[i] = host_to_guest(buf[i]); store_hw (buf + 62, 0x0000); /* Bytes 64-95: NED 3 Node element descriptor for the storage director */ store_fw (buf + 64, 0xd4020000); sprintf ((char *)&buf[68], " %4.4X0%2.2XHRCZZ000000000001", dev->ckdcu->devt, dev->ckdcu->model); for (i = 68; i < 94; i++) buf[i] = host_to_guest(buf[i]); buf[94] = 0x00; buf[95] = (dev->devnum >> 8) & 0xFF; /* Bytes 96-127: NED 4 Node element descriptor for the subsystem */ store_fw (buf + 96, 0xF0000001); sprintf ((char *)&buf[100], " %4.4X HRCZZ000000000001", dev->ckdcu->devt); for (i = 100; i < 126; i++) buf[i] = host_to_guest(buf[i]); store_hw (buf + 126, 0x0000); /* Bytes 128-223: zeroes */ /* Bytes 224-255: NEQ Node Element Qualifier */ buf[224] = 0x80; // flags (general NEQ) buf[225] = 0; // record selector store_hw (buf + 226, IFID(dev)); // interface id store_hw (buf + 228, 0); // must be zero buf[230] = 0x1E; // primary missing interrupt timer interval buf[231] = 0x00; // secondary missing interrupt timer interval store_hw (buf + 232, SSID(dev)); // subsystem id buf[234] = 0x80; // path/cluster id buf[235] = (dev->devnum & 0xFF); // unit address buf[236] = (dev->devnum & 0xFF); // physical device id buf[237] = (dev->devnum & 0xFF); // physical device address buf[238] = buf[227]; // SA ID (same as interface ID, byte 227) store_hw (buf + 239, 0); // escon link address buf[241] = 0x80; // interface protocol type (parallel) // buf[241] = 0x40; // interface protocol type (escon) buf[242] = 0x80; // NEQ format flags buf[243] = (dev->devnum & 0xFF); // logical device address (LDA) // bytes 244-255 must be zero /* Copy data characteristics to the I/O buf */ count = count > 256 ? 256 : count; memcpy (iobuf, buf, count); return 256; } /*-------------------------------------------------------------------*/ /* Build CKD subsystem status */ /*-------------------------------------------------------------------*/ DLL_EXPORT int dasd_build_ckd_subsys_status (DEVBLK *dev, BYTE *iobuf, int count) { int num; BYTE buf[44]; /* Build the basic subsystem status data in the I/O area */ memset (buf, 0, 44); buf[1] = dev->devnum & 0xFF; buf[2] = DEVICES_PER_SUBSYS - 1; store_hw (buf + 38, SSID(dev)); num = 40; /* Build an additional 4 bytes of data for the 3990-6 */ if (MODEL6(dev->ckdcu)) { buf[0] = 0x01; /* Set 3990-6 enhanced flag */ num = 44; } /* end if(3990-6) */ /* Copy subsystem status to the I/O buf */ count = count > num ? num : count; memcpy (iobuf, buf, count); return num; } /*-------------------------------------------------------------------*/ /* Build FBA devid field */ /*-------------------------------------------------------------------*/ int dasd_build_fba_devid (FBADEV *fba, BYTE *devid) { memset (devid, 0, 256); devid[0] = 0xff; devid[1] = (fba->cu >> 8) & 0xff; devid[2] = fba->cu & 0xff; devid[3] = 0x01; /* assume model is 1 */ devid[4] = (fba->devt >> 8) & 0xff; devid[5] = fba->devt & 0xff; devid[6] = fba->model; return 7; } /*-------------------------------------------------------------------*/ /* Build FBA devchar field */ /*-------------------------------------------------------------------*/ int dasd_build_fba_devchar (FBADEV *fba, BYTE *devchar, int blks) { memset (devchar, 0, 64); devchar[0] = 0x30; // operation modes devchar[1] = 0x08; // features devchar[2] = fba->class; // device class devchar[3] = fba->type; // unit type devchar[4] = (fba->size >> 8) & 0xff; // block size devchar[5] = fba->size & 0xff; devchar[6] = (fba->bpg >> 24) & 0xff; // blks per cyclical group devchar[7] = (fba->bpg >> 16) & 0xff; devchar[8] = (fba->bpg >> 8) & 0xff; devchar[9] = fba->bpg & 0xff; devchar[10] = (fba->bpp >> 24) & 0xff; // blks per access position devchar[11] = (fba->bpp >> 16) & 0xff; devchar[12] = (fba->bpp >> 8) & 0xff; devchar[13] = fba->bpp & 0xff; devchar[14] = (blks >> 24) & 0xff; // blks under movable heads devchar[15] = (blks >> 16) & 0xff; devchar[16] = (blks >> 8) & 0xff; devchar[17] = blks & 0xff; devchar[18] = 0; // blks under fixed heads devchar[19] = 0; devchar[20] = 0; devchar[21] = 0; devchar[22] = 0; // blks in alternate area devchar[23] = 0; devchar[24] = 0; // blks in CE+SA areas devchar[25] = 0; devchar[26] = 0; // cyclic period in ms devchar[27] = 0; devchar[28] = 0; // min time to change access devchar[29] = 0; // position in ms devchar[30] = 0; // max to change access devchar[31] = 0; // position in ms return 32; } hercules-3.12/cache.c0000664000175000017500000003713512564723224011423 00000000000000/* CACHE.C (c)Copyright Greg Smith, 2002-2009 */ /* Dynamic cache manager for multi-threaded applications */ //FIXME ?? Dynamic resizing is disabled #include "hstdinc.h" #define _CACHE_C_ #define _HDASD_DLL_ #include "hercules.h" static CACHEBLK cacheblk[CACHE_MAX_INDEX]; /*-------------------------------------------------------------------*/ /* Public functions */ /*-------------------------------------------------------------------*/ int cache_nbr (int ix) { if (cache_check_ix(ix)) return -1; return cacheblk[ix].nbr; } int cache_busy (int ix) { if (cache_check_ix(ix)) return -1; return cacheblk[ix].busy; } int cache_empty (int ix) { if (cache_check_ix(ix)) return -1; return cacheblk[ix].empty; } int cache_waiters (int ix) { if (cache_check_ix(ix)) return -1; return cacheblk[ix].waiters; } long long cache_size (int ix) { if (cache_check_ix(ix)) return -1; return cacheblk[ix].size; } long long cache_hits (int ix) { if (cache_check_ix(ix)) return -1; return cacheblk[ix].hits; } long long cache_misses (int ix) { if (cache_check_ix(ix)) return -1; return cacheblk[ix].misses; } int cache_busy_percent (int ix) { if (cache_check_ix(ix)) return -1; return (cacheblk[ix].busy * 100) / cacheblk[ix].nbr; } int cache_empty_percent (int ix) { if (cache_check_ix(ix)) return -1; return (cacheblk[ix].empty * 100) / cacheblk[ix].nbr; } int cache_hit_percent (int ix) { long long total; if (cache_check_ix(ix)) return -1; total = cacheblk[ix].hits + cacheblk[ix].misses; if (total == 0) return -1; return (int)((cacheblk[ix].hits * 100) / total); } int cache_lookup (int ix, U64 key, int *o) { int i,p; if (o) *o = -1; if (cache_check_ix(ix)) return -1; /* `p' is the preferred index */ p = (int)(key % cacheblk[ix].nbr); if (cacheblk[ix].cache[p].key == key) { i = p; cacheblk[ix].fasthits++; } else { if (cache_isbusy(ix, p) || cacheblk[ix].age - cacheblk[ix].cache[p].age < 20) p = -2; for (i = 0; i < cacheblk[ix].nbr; i++) { if (cacheblk[ix].cache[i].key == key) break; if (o && !cache_isbusy(ix, i) && (*o < 0 || i == p || cacheblk[ix].cache[i].age < cacheblk[ix].cache[*o].age)) if (*o != p) *o = i; } } if (i >= cacheblk[ix].nbr) { i = -1; cacheblk[ix].misses++; } else cacheblk[ix].hits++; if (i < 0 && o && *o < 0) cache_adjust(ix,1); else cache_adjust(ix, 0); return i; } int cache_scan (int ix, CACHE_SCAN_RTN rtn, void *data) { int i; /* Cache index */ int rc; /* Return code */ int answer = -1; /* Answer from routine */ if (cache_check_ix(ix)) return -1; for (i = 0; i < cacheblk[ix].nbr; i++) { rc = (rtn)(&answer, ix, i, data); if (rc != 0) break; } return answer; } int cache_lock(int ix) { if (cache_check_cache(ix)) return -1; obtain_lock(&cacheblk[ix].lock); return 0; } int cache_unlock(int ix) { if (cache_check_ix(ix)) return -1; release_lock(&cacheblk[ix].lock); if (cacheblk[ix].empty == cacheblk[ix].nbr) cache_destroy(ix); return 0; } int cache_wait(int ix) { struct timeval now; struct timespec tm; if (cache_check_ix(ix)) return -1; if (cacheblk[ix].busy < cacheblk[ix].nbr) return 0; if (cache_adjust(ix, 1)) return 0; gettimeofday (&now, NULL); tm.tv_sec = now.tv_sec; tm.tv_nsec = (now.tv_usec + CACHE_WAITTIME) * 1000; tm.tv_sec += tm.tv_nsec / 1000000000; tm.tv_nsec = tm.tv_nsec % 1000000000; cacheblk[ix].waiters++; cacheblk[ix].waits++; #if 0 timed_wait_condition(&cacheblk[ix].waitcond, &cacheblk[ix].lock, &tm); #else wait_condition(&cacheblk[ix].waitcond, &cacheblk[ix].lock); #endif cacheblk[ix].waiters--; return 0; } U64 cache_getkey(int ix, int i) { if (cache_check(ix,i)) return (U64)-1; return cacheblk[ix].cache[i].key; } U64 cache_setkey(int ix, int i, U64 key) { U64 oldkey; int empty; if (cache_check(ix,i)) return (U64)-1; empty = cache_isempty(ix, i); oldkey = cacheblk[ix].cache[i].key; cacheblk[ix].cache[i].key = key; if (empty && !cache_isempty(ix, i)) cacheblk[ix].empty--; else if (!empty && cache_isempty(ix, i)) cacheblk[ix].empty++; return oldkey; } U32 cache_getflag(int ix, int i) { if (cache_check(ix,i)) return (U32)-1; return cacheblk[ix].cache[i].flag; } U32 cache_setflag(int ix, int i, U32 andbits, U32 orbits) { U32 oldflags; int empty; int busy; if (cache_check(ix,i)) return (U32)-1; empty = cache_isempty(ix, i); busy = cache_isbusy(ix, i); oldflags = cacheblk[ix].cache[i].flag; cacheblk[ix].cache[i].flag &= andbits; cacheblk[ix].cache[i].flag |= orbits; if (!cache_isbusy(ix, i) && cacheblk[ix].waiters > 0) signal_condition(&cacheblk[ix].waitcond); if (busy && !cache_isbusy(ix, i)) cacheblk[ix].busy--; else if (!busy && cache_isbusy(ix, i)) cacheblk[ix].busy++; if (empty && !cache_isempty(ix, i)) cacheblk[ix].empty--; else if (!empty && cache_isempty(ix, i)) cacheblk[ix].empty++; return oldflags; } U64 cache_getage(int ix, int i) { if (cache_check(ix,i)) return (U64)-1; return cacheblk[ix].cache[i].age; } U64 cache_setage(int ix, int i) { U64 oldage; int empty; if (cache_check(ix,i)) return (U64)-1; empty = cache_isempty(ix, i); oldage = cacheblk[ix].cache[i].age; cacheblk[ix].cache[i].age = ++cacheblk[ix].age; if (empty) cacheblk[ix].empty--; return oldage; } void *cache_getbuf(int ix, int i, int len) { if (cache_check(ix,i)) return NULL; if (len > 0 && cacheblk[ix].cache[i].buf != NULL && cacheblk[ix].cache[i].len < len) { cacheblk[ix].size -= cacheblk[ix].cache[i].len; free (cacheblk[ix].cache[i].buf); cacheblk[ix].cache[i].buf = NULL; cacheblk[ix].cache[i].len = 0; } if (cacheblk[ix].cache[i].buf == NULL && len > 0) cache_allocbuf (ix, i, len); return cacheblk[ix].cache[i].buf; } void *cache_setbuf(int ix, int i, void *buf, int len) { void *oldbuf; if (cache_check(ix,i)) return NULL; oldbuf = cacheblk[ix].cache[i].buf; cacheblk[ix].size -= cacheblk[ix].cache[i].len; cacheblk[ix].cache[i].buf = buf; cacheblk[ix].cache[i].len = len; cacheblk[ix].size += len; return oldbuf; } int cache_getlen(int ix, int i) { if (cache_check(ix,i)) return -1; return cacheblk[ix].cache[i].len; } int cache_getval(int ix, int i) { if (cache_check(ix,i)) return -1; return cacheblk[ix].cache[i].value; } int cache_setval(int ix, int i, int val) { int rc; if (cache_check(ix,i)) return -1; rc = cacheblk[ix].cache[i].value; cacheblk[ix].cache[i].value = val; return rc; } int cache_release(int ix, int i, int flag) { void *buf; int len; int empty; int busy; if (cache_check(ix,i)) return -1; empty = cache_isempty(ix, i); busy = cache_isbusy(ix, i); buf = cacheblk[ix].cache[i].buf; len = cacheblk[ix].cache[i].len; memset (&cacheblk[ix].cache[i], 0, sizeof(CACHE)); if ((flag & CACHE_FREEBUF) && buf != NULL) { free (buf); cacheblk[ix].size -= len; buf = NULL; len = 0; } cacheblk[ix].cache[i].buf = buf; cacheblk[ix].cache[i].len = len; if (cacheblk[ix].waiters > 0) signal_condition(&cacheblk[ix].waitcond); if (!empty) cacheblk[ix].empty++; if (busy) cacheblk[ix].busy--; return 0; } DLL_EXPORT int cache_cmd(int argc, char *argv[], char *cmdline) { int ix, i; UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); for (ix = 0; ix < CACHE_MAX_INDEX; ix++) { if (cacheblk[ix].magic != CACHE_MAGIC) { logmsg ("cache[%d] ....... not created\n", ix); continue; } logmsg ("\n" "cache............ %10d\n" "nbr ............. %10d\n" "busy ............ %10d\n" "busy%% ........... %10d\n" "empty ........... %10d\n" "waiters ......... %10d\n" "waits ........... %10d\n" "buf size ........ %10" I64_FMT "d\n" "hits ............ %10" I64_FMT "d\n" "fast hits ....... %10" I64_FMT "d\n" "misses .......... %10" I64_FMT "d\n" "hit%% ............ %10d\n" "age ............. %10" I64_FMT "d\n" "last adjusted ... %s" "last wait ....... %s" "adjustments ..... %10d\n", ix, cacheblk[ix].nbr, cacheblk[ix].busy, cache_busy_percent(ix), cacheblk[ix].empty, cacheblk[ix].waiters, cacheblk[ix].waits, cacheblk[ix].size, cacheblk[ix].hits, cacheblk[ix].fasthits, cacheblk[ix].misses, cache_hit_percent(ix), cacheblk[ix].age, ctime(&cacheblk[ix].atime), ctime(&cacheblk[ix].wtime), cacheblk[ix].adjusts); if (argc > 1) for (i = 0; i < cacheblk[ix].nbr; i++) logmsg ("[%4d] %16.16" I64_FMT "x %8.8x %10p %6d %10" I64_FMT "d\n", i, cacheblk[ix].cache[i].key, cacheblk[ix].cache[i].flag, cacheblk[ix].cache[i].buf, cacheblk[ix].cache[i].len, cacheblk[ix].cache[i].age); } return 0; } /*-------------------------------------------------------------------*/ /* Private functions */ /*-------------------------------------------------------------------*/ static int cache_create (int ix) { cache_destroy (ix); cacheblk[ix].magic = CACHE_MAGIC; //FIXME See the note in cache.h about CACHE_DEFAULT_L2_NBR cacheblk[ix].nbr = ix != CACHE_L2 ? CACHE_DEFAULT_NBR : CACHE_DEFAULT_L2_NBR; cacheblk[ix].empty = cacheblk[ix].nbr; initialize_lock (&cacheblk[ix].lock); initialize_condition (&cacheblk[ix].waitcond); cacheblk[ix].cache = calloc (cacheblk[ix].nbr, sizeof(CACHE)); if (cacheblk[ix].cache == NULL) { logmsg (_("HHCCH001E calloc failed cache[%d] size %d: %s\n"), ix, cacheblk[ix].nbr * sizeof(CACHE), strerror(errno)); return -1; } return 0; } static int cache_destroy (int ix) { int i; if (cacheblk[ix].magic == CACHE_MAGIC) { destroy_lock (&cacheblk[ix].lock); destroy_condition (&cacheblk[ix].waitcond); if (cacheblk[ix].cache) { for (i = 0; i < cacheblk[ix].nbr; i++) cache_release(ix, i, CACHE_FREEBUF); free (cacheblk[ix].cache); } } memset(&cacheblk[ix], 0, sizeof(CACHEBLK)); return 0; } static int cache_check_ix(int ix) { if (ix < 0 || ix >= CACHE_MAX_INDEX) return -1; return 0; } static int cache_check_cache(int ix) { if (cache_check_ix(ix) || (cacheblk[ix].magic != CACHE_MAGIC && cache_create(ix))) return -1; return 0; } static int cache_check(int ix, int i) { if (cache_check_ix(ix) || i < 0 || i >= cacheblk[ix].nbr) return -1; return 0; } static int cache_isbusy(int ix, int i) { return ((cacheblk[ix].cache[i].flag & CACHE_BUSY) != 0); } static int cache_isempty(int ix, int i) { return (cacheblk[ix].cache[i].key == 0 && cacheblk[ix].cache[i].flag == 0 && cacheblk[ix].cache[i].age == 0); } static int cache_adjust(int ix, int n) { #if 0 time_t now; int busypct, hitpct, nbr, empty, sz; now = time(NULL); busypct = cache_busy_percent(ix); hitpct = cache_hit_percent(ix); nbr = cacheblk[ix].nbr; empty = cache_empty(ix); sz = cacheblk[ix].size; if (n == 0) { /* Normal adjustments */ if (now - cacheblk[ix].atime < CACHE_ADJUST_INTERVAL) return 0; cacheblk[ix].atime = now; /* Increase cache if a lot of busy entries */ if (((nbr <= CACHE_ADJUST_NUMBER || sz < CACHE_ADJUST_SIZE) && busypct >= CACHE_ADJUST_BUSY1) || busypct > CACHE_ADJUST_BUSY2) return cache_resize(ix, CACHE_ADJUST_RESIZE); /* Decrease cache if too many empty entries */ if (nbr > CACHE_ADJUST_NUMBER && empty >= CACHE_ADJUST_EMPTY) return cache_resize(ix, -CACHE_ADJUST_RESIZE); /* Increase cache if hit percentage is too low */ if (hitpct > 0) { if ((nbr <= CACHE_ADJUST_NUMBER && hitpct < CACHE_ADJUST_HIT1) || hitpct < CACHE_ADJUST_HIT2) return cache_resize(ix, CACHE_ADJUST_RESIZE); } /* Decrease cache if hit percentage is ok and not many busy */ if (hitpct >= CACHE_ADJUST_HIT3 && busypct <= CACHE_ADJUST_BUSY3 && cacheblk[ix].size >= CACHE_ADJUST_SIZE) return cache_resize(ix, -CACHE_ADJUST_RESIZE); } else { /* All cache entries are busy */ if (nbr <= CACHE_ADJUST_NUMBER) return cache_resize(ix, CACHE_ADJUST_RESIZE); /* Increase cache if previous wait within this interval */ if (now - cacheblk[ix].wtime <= CACHE_ADJUST_WAITTIME) { return cache_resize(ix, CACHE_ADJUST_RESIZE); } cacheblk[ix].wtime = now; } #else UNREFERENCED(ix); UNREFERENCED(n); #endif return 0; } #if 0 static int cache_resize (int ix, int n) { CACHE *cache; int i; if (n == 0) return 0; else if (n > 0) { /* Increase cache size */ cache = realloc (cacheblk[ix].cache, (cacheblk[ix].nbr + n) * sizeof(CACHE)); if (cache == NULL) { logmsg (_("HHCCH002W realloc increase failed cache[%d] size %d: %s\n"), ix, (cacheblk[ix].nbr + n) * sizeof(CACHE), strerror(errno)); return 0; } cacheblk[ix].cache = cache; for (i = cacheblk[ix].nbr; i < cacheblk[ix].nbr +n; i++) memset(&cacheblk[ix].cache[i], 0, sizeof(CACHE)); cacheblk[ix].nbr += n; cacheblk[ix].empty += n; cacheblk[ix].adjusts++; } else if (n < 0) { /* Decrease cache size */ for (i = cacheblk[ix].nbr - 1; i >= cacheblk[ix].nbr + n; i--) if (cache_isbusy(ix, i)) break; else cache_release(ix, i, CACHE_FREEBUF); n = cacheblk[ix].nbr - i + 1; if (n == 0) return 0; cache = realloc (cacheblk[ix].cache, (cacheblk[ix].nbr - n) * sizeof(CACHE)); if (cache == NULL) { logmsg (_("HHCCH003W realloc decrease failed cache[%d] size %d: %s\n"), ix, (cacheblk[ix].nbr - n) * sizeof(CACHE), strerror(errno)); return 0; } cacheblk[ix].cache = cache; cacheblk[ix].nbr -= n; cacheblk[ix].empty -= n; cacheblk[ix].adjusts++; } return 1; } #endif static void cache_allocbuf(int ix, int i, int len) { cacheblk[ix].cache[i].buf = calloc (len, 1); if (cacheblk[ix].cache[i].buf == NULL) { logmsg (_("HHCCH004W buf calloc failed cache[%d] size %d: %s\n"), ix, len, strerror(errno)); logmsg (_("HHCCH005W releasing inactive buffer space\n")); for (i = 0; i < cacheblk[ix].nbr; i++) if (!cache_isbusy(ix, i)) cache_release(ix, i, CACHE_FREEBUF); cacheblk[ix].cache[i].buf = calloc (len, 1); if (cacheblk[ix].cache[i].buf == NULL) { logmsg (_("HHCCH006E Unable to calloc buf cache[%d] size %d: %s\n"), ix, len, strerror(errno)); return; } } cacheblk[ix].cache[i].len = len; cacheblk[ix].size += len; } hercules-3.12/dasdutil.c0000664000175000017500000025127212564723224012171 00000000000000/* DASDUTIL.C (c) Copyright Roger Bowler, 1999-2010 */ /* Hercules DASD Utilities: Common subroutines */ /*-------------------------------------------------------------------*/ /* This module contains common subroutines used by DASD utilities */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _DASDUTIL_C_ #define _HDASD_DLL_ #include "hercules.h" #include "dasdblks.h" #include "devtype.h" #include "opcode.h" /*-------------------------------------------------------------------*/ /* External references (defined in ckddasd.c) */ /*-------------------------------------------------------------------*/ extern DEVHND ckddasd_device_hndinfo; /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static int verbose = 0; /* Be chatty about reads etc. */ static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; static BYTE iplpsw[8] = {0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x0F}; static BYTE iplccw1[8] = {0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x01}; static BYTE iplccw2[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; static int nextnum = 0; #if 0 SYSBLK sysblk; /* Currently required for shared.c */ #endif /*-------------------------------------------------------------------*/ /* Subroutine to convert a null-terminated string to upper case */ /*-------------------------------------------------------------------*/ DLL_EXPORT void string_to_upper (char *source) { int i; /* Array subscript */ for (i = 0; source[i] != '\0'; i++) source[i] = toupper(source[i]); } /* end function string_to_upper */ /*-------------------------------------------------------------------*/ /* Subroutine to convert a null-terminated string to lower case */ /*-------------------------------------------------------------------*/ DLL_EXPORT void string_to_lower (char *source) { int i; /* Array subscript */ for (i = 0; source[i] != '\0'; i++) source[i] = tolower(source[i]); } /* end function string_to_lower */ /*-------------------------------------------------------------------*/ /* Subroutine to convert a string to EBCDIC and pad with blanks */ /*-------------------------------------------------------------------*/ DLL_EXPORT void convert_to_ebcdic (BYTE *dest, int len, char *source) { int i; /* Array subscript */ set_codepage(NULL); for (i = 0; i < len && source[i] != '\0'; i++) dest[i] = host_to_guest(source[i]); while (i < len) dest[i++] = 0x40; } /* end function convert_to_ebcdic */ /*-------------------------------------------------------------------*/ /* Subroutine to convert an EBCDIC string to an ASCIIZ string. */ /* Removes trailing blanks and adds a terminating null. */ /* Returns the length of the ASCII string excluding terminating null */ /*-------------------------------------------------------------------*/ DLL_EXPORT int make_asciiz (char *dest, int destlen, BYTE *src, int srclen) { int len; /* Result length */ set_codepage(NULL); for (len=0; len < srclen && len < destlen-1; len++) dest[len] = guest_to_host(src[len]); while (len > 0 && dest[len-1] == SPACE) len--; dest[len] = '\0'; return len; } /* end function make_asciiz */ /*-------------------------------------------------------------------*/ /* Subroutine to print a data block in hex and character format. */ /*-------------------------------------------------------------------*/ DLL_EXPORT void data_dump ( void *addr, int len ) { unsigned int maxlen = 2048; unsigned int i, xi, offset, startoff = 0; BYTE c; BYTE *pchar; char print_chars[17]; char hex_chars[64]; char prev_hex[64] = ""; int firstsame = 0; int lastsame = 0; set_codepage(NULL); pchar = (BYTE *)addr; for (offset=0; ; ) { if (offset >= maxlen && offset <= len - maxlen) { offset += 16; pchar += 16; prev_hex[0] = '\0'; continue; } if ( offset > 0 ) { if ( strcmp ( hex_chars, prev_hex ) == 0 ) { if ( firstsame == 0 ) firstsame = startoff; lastsame = startoff; } else { if ( firstsame != 0 ) { if ( lastsame == firstsame ) printf ("Line %4.4X same as above\n", firstsame ); else printf ("Lines %4.4X to %4.4X same as above\n", firstsame, lastsame ); firstsame = lastsame = 0; } printf ("+%4.4X %s %s\n", startoff, hex_chars, print_chars); strcpy ( prev_hex, hex_chars ); } } if ( offset >= (U32)len ) break; memset ( print_chars, 0, sizeof(print_chars) ); memset ( hex_chars, SPACE, sizeof(hex_chars) ); startoff = offset; for (xi=0, i=0; i < 16; i++) { c = *pchar++; if (offset < (U32)len) { sprintf(hex_chars+xi, "%2.2X", c); print_chars[i] = '.'; if (isprint(c)) print_chars[i] = c; c = guest_to_host(c); if (isprint(c)) print_chars[i] = c; } offset++; xi += 2; hex_chars[xi] = SPACE; if ((offset & 3) == 0) xi++; } /* end for(i) */ hex_chars[xi] = '\0'; } /* end for(offset) */ } /* end function data_dump */ /*-------------------------------------------------------------------*/ /* Subroutine to read a track from the CKD DASD image */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* cyl Cylinder number */ /* head Head number */ /* Output: */ /* The track is read into trkbuf, and curcyl and curhead */ /* are set to the cylinder and head number. */ /* */ /* Return value is 0 if successful, -1 if error */ /*-------------------------------------------------------------------*/ DLL_EXPORT int read_track (CIFBLK *cif, int cyl, int head) { int rc; /* Return code */ int trk; /* Track number */ DEVBLK *dev; /* -> CKD device block */ BYTE unitstat; /* Unit status */ /* Exit if required track is already in buffer */ if (cif->curcyl == cyl && cif->curhead == head) return 0; dev = &cif->devblk; if (cif->trkmodif) { cif->trkmodif = 0; if (verbose) /* Issue progress message */ fprintf (stdout, _("HHCDU001I Updating cyl %d head %d\n"), cif->curcyl, cif->curhead); trk = (cif->curcyl * cif->heads) + cif->curhead; rc = (dev->hnd->write)(dev, trk, 0, NULL, cif->trksz, &unitstat); if (rc < 0) { fprintf (stderr, _("HHCDU002E %s write track error: stat=%2.2X\n"), cif->fname, unitstat); return -1; } } if (verbose) /* Issue progress message */ fprintf (stdout, _("HHCDU003I Reading cyl %d head %d\n"), cyl, head); trk = (cyl * cif->heads) + head; rc = (dev->hnd->read)(dev, trk, &unitstat); if (rc < 0) { fprintf (stderr, _("HHCDU004E %s read track error: stat=%2.2X\n"), cif->fname, unitstat); return -1; } /* Set current buf, cylinder and head */ cif->trkbuf = dev->buf; cif->curcyl = cyl; cif->curhead = head; return 0; } /* end function read_track */ /*-------------------------------------------------------------------*/ /* Subroutine to read a block from the CKD DASD image */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* cyl Cylinder number of requested block */ /* head Head number of requested block */ /* rec Record number of requested block */ /* Output: */ /* keyptr Pointer to record key */ /* keylen Actual key length */ /* dataptr Pointer to record data */ /* datalen Actual data length */ /* */ /* Return value is 0 if successful, +1 if end of track, -1 if error */ /*-------------------------------------------------------------------*/ DLL_EXPORT int read_block (CIFBLK *cif, int cyl, int head, int rec, BYTE **keyptr, int *keylen, BYTE **dataptr, int *datalen) { int rc; /* Return code */ BYTE *ptr; /* -> byte in track buffer */ CKDDASD_RECHDR *rechdr; /* -> Record header */ int kl; /* Key length */ int dl; /* Data length */ /* Read the required track into the track buffer if necessary */ rc = read_track (cif, cyl, head); if (rc < 0) return -1; /* Search for the requested record in the track buffer */ ptr = cif->trkbuf; ptr += CKDDASD_TRKHDR_SIZE; while (1) { /* Exit with record not found if end of track */ if (memcmp(ptr, eighthexFF, 8) == 0) return +1; /* Extract key length and data length from count field */ rechdr = (CKDDASD_RECHDR*)ptr; kl = rechdr->klen; dl = (rechdr->dlen[0] << 8) | rechdr->dlen[1]; /* Exit if requested record number found */ if (rechdr->rec == rec) break; /* Issue progress message */ // fprintf (stdout, // "Skipping CCHHR=%2.2X%2.2X%2.2X%2.2X" // "%2.2X KL=%2.2X DL=%2.2X%2.2X\n", // rechdr->cyl[0], rechdr->cyl[1], // rechdr->head[0], rechdr->head[1], // rechdr->rec, rechdr->klen, // rechdr->dlen[0], rechdr->dlen[1]); /* Point past count key and data to next block */ ptr += CKDDASD_RECHDR_SIZE + kl + dl; } /* Return key and data pointers and lengths */ if (keyptr != NULL) *keyptr = ptr + CKDDASD_RECHDR_SIZE; if (keylen != NULL) *keylen = kl; if (dataptr != NULL) *dataptr = ptr + CKDDASD_RECHDR_SIZE + kl; if (datalen != NULL) *datalen = dl; return 0; } /* end function read_block */ /*-------------------------------------------------------------------*/ /* Subroutine to search a dataset for a specified key */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* key Key value */ /* keylen Key length */ /* noext Number of extents */ /* extent Dataset extent array */ /* Output: */ /* cyl Cylinder number of requested block */ /* head Head number of requested block */ /* rec Record number of requested block */ /* */ /* Return value is 0 if successful, +1 if key not found, -1 if error */ /*-------------------------------------------------------------------*/ DLL_EXPORT int search_key_equal (CIFBLK *cif, BYTE *key, int keylen, int noext, DSXTENT extent[], int *cyl, int *head, int *rec) { int rc; /* Return code */ int ccyl; /* Cylinder number */ int chead; /* Head number */ int cext; /* Extent sequence number */ int ecyl; /* Extent end cylinder */ int ehead; /* Extent end head */ BYTE *ptr; /* -> byte in track buffer */ CKDDASD_RECHDR *rechdr; /* -> Record header */ int kl; /* Key length */ int dl; /* Data length */ /* Start at first track of first extent */ cext = 0; ccyl = (extent[cext].xtbcyl[0] << 8) | extent[cext].xtbcyl[1]; chead = (extent[cext].xtbtrk[0] << 8) | extent[cext].xtbtrk[1]; ecyl = (extent[cext].xtecyl[0] << 8) | extent[cext].xtecyl[1]; ehead = (extent[cext].xtetrk[0] << 8) | extent[cext].xtetrk[1]; if (verbose) { fprintf (stdout, _("HHCDU005I Searching extent %d begin (%d,%d) end (%d,%d)\n"), cext, ccyl, chead, ecyl, ehead); } while (1) { /* Read the required track into the track buffer */ rc = read_track (cif, ccyl, chead); if (rc < 0) return -1; /* Search for the requested record in the track buffer */ ptr = cif->trkbuf; ptr += CKDDASD_TRKHDR_SIZE; while (1) { /* Exit loop at end of track */ if (memcmp(ptr, eighthexFF, 8) == 0) break; /* Extract key length and data length from count field */ rechdr = (CKDDASD_RECHDR*)ptr; kl = rechdr->klen; dl = (rechdr->dlen[0] << 8) | rechdr->dlen[1]; /* Return if requested record key found */ if (kl == keylen && memcmp(ptr + CKDDASD_RECHDR_SIZE, key, 44) == 0) { *cyl = ccyl; *head = chead; *rec = rechdr->rec; return 0; } /* Issue progress message */ // fprintf (stdout, // "Skipping CCHHR=%2.2X%2.2X%2.2X%2.2X" // "%2.2X KL=%2.2X DL=%2.2X%2.2X\n", // rechdr->cyl[0], rechdr->cyl[1], // rechdr->head[0], rechdr->head[1], // rechdr->rec, rechdr->klen, // rechdr->dlen[0], rechdr->dlen[1]); /* Point past count key and data to next block */ ptr += CKDDASD_RECHDR_SIZE + kl + dl; } /* end while */ /* Point to the next track */ chead++; if (chead >= cif->heads) { ccyl++; chead = 0; } /* Loop if next track is within current extent */ if (ccyl < ecyl || (ccyl == ecyl && chead <= ehead)) continue; /* Move to next extent */ cext++; if (cext >= noext) break; ccyl = (extent[cext].xtbcyl[0] << 8) | extent[cext].xtbcyl[1]; chead = (extent[cext].xtbtrk[0] << 8) | extent[cext].xtbtrk[1]; ecyl = (extent[cext].xtecyl[0] << 8) | extent[cext].xtecyl[1]; ehead = (extent[cext].xtetrk[0] << 8) | extent[cext].xtetrk[1]; if (verbose) { fprintf (stdout, _("HHCDU006I Searching extent %d begin (%d,%d) end (%d,%d)\n"), cext, ccyl, chead, ecyl, ehead); } } /* end while */ /* Return record not found at end of extents */ return +1; } /* end function search_key_equal */ /*-------------------------------------------------------------------*/ /* Subroutine to convert relative track to cylinder and head */ /* Input: */ /* tt Relative track number */ /* noext Number of extents in dataset */ /* extent Dataset extent array */ /* heads Number of tracks per cylinder */ /* Output: */ /* cyl Cylinder number */ /* head Head number */ /* */ /* Return value is 0 if successful, or -1 if error */ /*-------------------------------------------------------------------*/ DLL_EXPORT int convert_tt (int tt, int noext, DSXTENT extent[], int heads, int *cyl, int *head) { int i; /* Extent sequence number */ int trk; /* Relative track number */ int bcyl; /* Extent begin cylinder */ int btrk; /* Extent begin head */ int ecyl; /* Extent end cylinder */ int etrk; /* Extent end head */ int start; /* Extent begin track */ int end; /* Extent end track */ int extsize; /* Extent size in tracks */ for (i = 0, trk = tt; i < noext; i++) { bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1]; btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1]; ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1]; etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1]; start = (bcyl * heads) + btrk; end = (ecyl * heads) + etrk; extsize = end - start + 1; if (trk < extsize) { trk += start; *cyl = trk / heads; *head = trk % heads; return 0; } trk -= extsize; } /* end for(i) */ fprintf (stderr, _("HHCDU007E Track %d not found in extent table\n"), tt); return -1; } /* end function convert_tt */ /*-------------------------------------------------------------------*/ /* Subroutine to open a CKD image file */ /* Input: */ /* fname CKD image file name */ /* sfname xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* omode Open mode: O_RDONLY or O_RDWR */ /* dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* */ /* The CKD image file is opened, a track buffer is obtained, */ /* and a CKD image file descriptor structure is built. */ /* Return value is a pointer to the CKD image file descriptor */ /* structure if successful, or NULL if unsuccessful. */ /*-------------------------------------------------------------------*/ DLL_EXPORT CIFBLK* open_ckd_image (char *fname, char *sfname, int omode, int dasdcopy) { int fd; /* File descriptor */ int rc; /* Return code */ int len; /* Record length */ CKDDASD_DEVHDR devhdr; /* CKD device header */ CIFBLK *cif; /* CKD image file descriptor */ DEVBLK *dev; /* CKD device block */ CKDDEV *ckd; /* CKD DASD table entry */ char *rmtdev; /* Possible remote device */ char *argv[2]; /* Arguments to */ int argc=0; /* */ char sfxname[FILENAME_MAX*2];/* Suffixed file name */ char typname[64]; char pathname[MAX_PATH]; /* file path in host format */ /* Obtain storage for the file descriptor structure */ cif = (CIFBLK*) calloc (sizeof(CIFBLK), 1); if (cif == NULL) { fprintf (stderr, _("HHCDU008E Cannot obtain storage for device descriptor " "buffer: %s\n"), strerror(errno)); return NULL; } /* Initialize the devblk */ dev = &cif->devblk; if ((omode & O_RDWR) == 0) dev->ckdrdonly = 1; dev->fd = -1; dev->batch = 1; dev->dasdcopy = dasdcopy; /* If the filename has a `:' then it may be a remote device */ rmtdev = strchr(fname, ':'); /* Read the device header so we can determine the device type */ strcpy (sfxname, fname); hostpath(pathname, sfxname, sizeof(pathname)); fd = hopen(pathname, omode); if (fd < 0) { /* If no shadow file name was specified, then try opening the file with the file sequence number in the name */ if (sfname == NULL) { int i; char *s,*suffix; /* Look for last slash marking end of directory name */ s = strrchr (fname, '/'); if (s == NULL) s = fname; /* Insert suffix before first dot in file name, or append suffix to file name if there is no dot. If the filename already has a place for the suffix then use that. */ s = strchr (s, '.'); if (s != NULL) { i = s - fname; if (i > 2 && fname[i-2] == '_') suffix = sfxname + i - 1; else { strcpy (sfxname + i, "_1"); strcat (sfxname, fname + i); suffix = sfxname + i + 1; } } else { if (strlen(sfxname) < 2 || sfxname[strlen(sfxname)-2] != '_') strcat (sfxname, "_1"); suffix = sfxname + strlen(sfxname) - 1; } *suffix = '1'; hostpath(pathname, sfxname, sizeof(pathname)); fd = hopen(pathname, omode); } if (fd < 0 && rmtdev == NULL) { fprintf (stderr, _("HHCDU009E Cannot open %s: %s\n"), fname, strerror(errno)); free (cif); return NULL; } else if (fd < 0) strcpy (sfxname, fname); } /* If not a possible remote devic, check the dasd header and set the device type */ if (fd >= 0) { len = read (fd, &devhdr, CKDDASD_DEVHDR_SIZE); if (len < 0) { fprintf (stderr, _("HHCDU010E %s read error: %s\n"), fname, strerror(errno)); close (fd); free (cif); return NULL; } close (fd); if (len < (int)CKDDASD_DEVHDR_SIZE || (memcmp(devhdr.devid, "CKD_P370", 8) && memcmp(devhdr.devid, "CKD_C370", 8))) { fprintf (stderr, _("HHCDU011E %s CKD header invalid\n"), fname); free (cif); return NULL; } /* Set the device type */ ckd = dasd_lookup (DASD_CKDDEV, NULL, devhdr.devtype, 0); if (ckd == NULL) { fprintf(stderr, _("HHCDU012E DASD table entry not found for " "devtype 0x%2.2X\n"), devhdr.devtype); free (cif); return NULL; } dev->devtype = ckd->devt; snprintf(typname,64,"%4.4X",dev->devtype); dev->typname=typname; /* Makes HDL Happy */ } /* Set the device handlers */ dev->hnd = &ckddasd_device_hndinfo; /* Set the device number */ dev->devnum = ++nextnum; /* Build arguments for ckddasd_init_handler */ argv[0] = sfxname; argc++; if (sfname != NULL) { argv[1] = sfname; argc++; } /* Call the device handler initialization function */ rc = (dev->hnd->init)(dev, argc, argv); if (rc < 0) { fprintf (stderr, _("HHCDU013E CKD initialization failed for %s\n"), fname); free (cif); return NULL; } /* Call the device start exit */ if (dev->hnd->start) (dev->hnd->start) (dev); /* Set CIF fields */ cif->fname = fname; cif->fd = dev->fd; /* Extract the number of heads and the track size */ cif->heads = dev->ckdheads; cif->trksz = ((U32)(devhdr.trksize[3]) << 24) | ((U32)(devhdr.trksize[2]) << 16) | ((U32)(devhdr.trksize[1]) << 8) | (U32)(devhdr.trksize[0]); if (verbose) { fprintf (stderr, _("HHCDU014I %s heads=%d trklen=%d\n"), cif->fname, cif->heads, cif->trksz); } /* Indicate that the track buffer is empty */ cif->curcyl = -1; cif->curhead = -1; cif->trkmodif = 0; return cif; } /* end function open_ckd_image */ /*-------------------------------------------------------------------*/ /* Subroutine to close a CKD image file */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* */ /* The track buffer is flushed and released, the CKD image file */ /* is closed, and the file descriptor structure is released. */ /* Return value is 0 if successful, -1 if error */ /*-------------------------------------------------------------------*/ DLL_EXPORT int close_ckd_image (CIFBLK *cif) { int rc; /* Return code */ int trk; /* Track number */ DEVBLK *dev; /* -> CKD device block */ BYTE unitstat; /* Unit status */ dev = &cif->devblk; /* Write the last track if modified */ if (cif->trkmodif) { if (verbose) /* Issue progress message */ fprintf (stdout, _("HHCDU015I Updating cyl %d head %d\n"), cif->curcyl, cif->curhead); trk = (cif->curcyl * cif->heads) + cif->curhead; rc = (dev->hnd->write)(dev, trk, 0, NULL, cif->trksz, &unitstat); if (rc < 0) { fprintf (stderr, _("HHCDU016E %s write track error: stat=%2.2X\n"), cif->fname, unitstat); } } /* Call the END exit */ if (dev->hnd->end) (dev->hnd->end) (dev); /* Close the CKD image file */ (dev->hnd->close)(dev); /* Release the file descriptor structure */ free (cif); return 0; } /* end function close_ckd_image */ /*-------------------------------------------------------------------*/ /* Subroutine to open a FBA image file */ /* Input: */ /* fname FBA image file name */ /* sfname xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* omode Open mode: O_RDONLY or O_RDWR */ /* dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* */ /* The FBA image file is opened, a track buffer is obtained, */ /* and a FBA image file descriptor structure is built. */ /* Return value is a pointer to the FBA image file descriptor */ /* structure if successful, or NULL if unsuccessful. */ /*-------------------------------------------------------------------*/ DLL_EXPORT CIFBLK* open_fba_image (char *fname, char *sfname, int omode, int dasdcopy) { int rc; /* Return code */ CIFBLK *cif; /* FBA image file descriptor */ DEVBLK *dev; /* FBA device block */ FBADEV *fba; /* FBA DASD table entry */ char *argv[2]; /* Arguments to */ int argc=0; /* device open */ /* Obtain storage for the file descriptor structure */ cif = (CIFBLK*) calloc (sizeof(CIFBLK), 1); if (cif == NULL) { fprintf (stderr, _("HHCDU017E Cannot obtain storage for device descriptor " "buffer: %s\n"), strerror(errno)); return NULL; } /* Initialize the devblk */ dev = &cif->devblk; if ((omode & O_RDWR) == 0) dev->ckdrdonly = 1; dev->batch = 1; dev->dasdcopy = dasdcopy; /* Set the device type */ fba = dasd_lookup (DASD_FBADEV, NULL, DEFAULT_FBA_TYPE, 0); if (fba == NULL) { fprintf(stderr, _("HHCDU018E DASD table entry not found for " "devtype 0x%2.2X\n"), DEFAULT_FBA_TYPE); free (cif); return NULL; } dev->devtype = fba->devt; /* Set the device handlers */ dev->hnd = &fbadasd_device_hndinfo; /* Set the device number */ dev->devnum = ++nextnum; /* Build arguments for fbadasd_init_handler */ argv[0] = fname; argc++; if (sfname != NULL) { argv[1] = sfname; argc++; } /* Call the device handler initialization function */ rc = (dev->hnd->init)(dev, argc, argv); if (rc < 0) { fprintf (stderr, _("HHCDU019E FBA initialization failed for %s\n"), fname); free (cif); return NULL; } /* Set CIF fields */ cif->fname = fname; cif->fd = dev->fd; /* Extract the number of sectors and the sector size */ cif->heads = dev->fbanumblk; cif->trksz = dev->fbablksiz; if (verbose) { fprintf (stderr, _("HHCDU020I %s sectors=%d size=%d\n"), cif->fname, cif->heads, cif->trksz); } /* Indicate that the track buffer is empty */ cif->curcyl = -1; cif->curhead = -1; cif->trkmodif = 0; return cif; } /* end function open_fba_image */ /*-------------------------------------------------------------------*/ /* Subroutine to build extent array for specified dataset */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* dsnama -> Dataset name (ASCIIZ) */ /* Output: */ /* extent Extent array (up to 16 entries) */ /* noext Number of extents */ /* */ /* Return value is 0 if successful, or -1 if error */ /*-------------------------------------------------------------------*/ DLL_EXPORT int build_extent_array (CIFBLK *cif, char *dsnama, DSXTENT extent[], int *noext) { int rc; /* Return code */ int len; /* Record length */ int cyl; /* Cylinder number */ int head; /* Head number */ int rec; /* Record number */ BYTE *vol1data; /* -> Volume label */ FORMAT1_DSCB *f1dscb; /* -> Format 1 DSCB */ FORMAT3_DSCB *f3dscb; /* -> Format 3 DSCB */ FORMAT4_DSCB *f4dscb; /* -> Format 4 DSCB */ BYTE dsname[44]; /* Dataset name (EBCDIC) */ char volser[7]; /* Volume serial (ASCIIZ) */ /* Convert the dataset name to EBCDIC */ convert_to_ebcdic (dsname, sizeof(dsname), dsnama); /* Read the volume label */ rc = read_block (cif, 0, 0, 3, NULL, NULL, &vol1data, &len); if (rc < 0) return -1; if (rc > 0) { fprintf (stderr, _("HHCDU021E VOL1 record not found\n")); return -1; } /* Extract the volume serial and the CCHHR of the format 4 DSCB */ make_asciiz (volser, sizeof(volser), vol1data+4, 6); cyl = (vol1data[11] << 8) | vol1data[12]; head = (vol1data[13] << 8) | vol1data[14]; rec = vol1data[15]; if (verbose) { fprintf (stdout, _("HHCDU022I VOLSER=%s VTOC=%4.4X%4.4X%2.2X\n"), volser, cyl, head, rec); } /* Read the format 4 DSCB */ rc = read_block (cif, cyl, head, rec, (void *)&f4dscb, &len, NULL, NULL); if (rc < 0) return -1; if (rc > 0) { fprintf (stderr, _("HHCDU023E F4DSCB record not found\n")); return -1; } if (verbose) { fprintf (stdout, _("HHCDU023I VTOC start %2.2X%2.2X%2.2X%2.2X " "end %2.2X%2.2X%2.2X%2.2X\n"), f4dscb->ds4vtoce.xtbcyl[0], f4dscb->ds4vtoce.xtbcyl[1], f4dscb->ds4vtoce.xtbtrk[0], f4dscb->ds4vtoce.xtbtrk[1], f4dscb->ds4vtoce.xtecyl[0], f4dscb->ds4vtoce.xtecyl[1], f4dscb->ds4vtoce.xtetrk[0], f4dscb->ds4vtoce.xtetrk[1]); } /* Search for the requested dataset in the VTOC */ rc = search_key_equal (cif, dsname, sizeof(dsname), 1, &(f4dscb->ds4vtoce), &cyl, &head, &rec); if (rc < 0) return -1; if (rc > 0) { fprintf (stderr, _("HHCDU024E Dataset %s not found in VTOC\n"), dsnama); return -1; } if (verbose) { fprintf (stdout, _("HHCDU025I DSNAME=%s F1DSCB CCHHR=%4.4X%4.4X%2.2X\n"), dsnama, cyl, head, rec); } /* Read the format 1 DSCB */ rc = read_block (cif, cyl, head, rec, (void *)&f1dscb, &len, NULL, NULL); if (rc < 0) return -1; if (rc > 0) { fprintf (stderr, _("HHCDU026E F1DSCB record not found\n")); return -1; } /* Extract number of extents and first 3 extent descriptors */ *noext = f1dscb->ds1noepv; extent[0] = f1dscb->ds1ext1; extent[1] = f1dscb->ds1ext2; extent[2] = f1dscb->ds1ext3; /* Obtain additional extent descriptors */ if (f1dscb->ds1noepv > 3) { /* Read the format 3 DSCB */ cyl = (f1dscb->ds1ptrds[0] << 8) | f1dscb->ds1ptrds[1]; head = (f1dscb->ds1ptrds[2] << 8) | f1dscb->ds1ptrds[3]; rec = f1dscb->ds1ptrds[4]; rc = read_block (cif, cyl, head, rec, (void *)&f3dscb, &len, NULL, NULL); if (rc < 0) return -1; if (rc > 0) { fprintf (stderr, _("HHCDU027E F3DSCB record not found\n")); return -1; } /* Extract the next 13 extent descriptors */ extent[3] = f3dscb->ds3extnt[0]; extent[4] = f3dscb->ds3extnt[1]; extent[5] = f3dscb->ds3extnt[2]; extent[6] = f3dscb->ds3extnt[3]; extent[7] = f3dscb->ds3adext[0]; extent[8] = f3dscb->ds3adext[1]; extent[9] = f3dscb->ds3adext[2]; extent[10] = f3dscb->ds3adext[3]; extent[11] = f3dscb->ds3adext[4]; extent[12] = f3dscb->ds3adext[5]; extent[13] = f3dscb->ds3adext[6]; extent[14] = f3dscb->ds3adext[7]; extent[15] = f3dscb->ds3adext[8]; } return 0; } /* end function build_extent_array */ /*-------------------------------------------------------------------*/ /* Subroutine to calculate physical device track capacities */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* used Number of bytes used so far on track, */ /* excluding home address and record 0 */ /* keylen Key length of proposed new record */ /* datalen Data length of proposed new record */ /* Output: */ /* newused Number of bytes used including proposed new record */ /* trkbaln Number of bytes remaining on track */ /* physlen Number of bytes on physical track (=ds4devtk) */ /* kbconst Overhead for non-last keyed block (=ds4devi) */ /* lbconst Overhead for last keyed block (=ds4devl) */ /* nkconst Overhead difference for non-keyed block (=ds4devk) */ /* devflag Device flag byte for VTOC (=ds4devfg) */ /* tolfact Device tolerance factor (=ds4devtl) */ /* maxdlen Maximum data length for non-keyed record 1 */ /* numrecs Number of records of specified length per track */ /* numhead Number of tracks per cylinder */ /* numcyls Number of cylinders per volume */ /* Note: */ /* A NULL address may be specified for any of the output */ /* fields if the output value is not required. */ /* The return value is 0 if the record will fit on the track, */ /* +1 if record will not fit on track, or -1 if unknown devtype */ /* Note: */ /* Although the virtual DASD image file contains no interrecord */ /* gaps, this subroutine performs its calculations taking into */ /* account the gaps that would exist on a real device, so that */ /* the track capacities of the real device are not exceeded. */ /*-------------------------------------------------------------------*/ DLL_EXPORT int capacity_calc (CIFBLK *cif, int used, int keylen, int datalen, int *newused, int *trkbaln, int *physlen, int *kbconst, int *lbconst, int *nkconst, BYTE*devflag, int *tolfact, int *maxdlen, int *numrecs, int *numhead, int *numcyls) { CKDDEV *ckd; /* -> CKD device table entry */ int heads; /* Number of tracks/cylinder */ int cyls; /* Number of cyls/volume */ int trklen; /* Physical track length */ int maxlen; /* Maximum data length */ int devi, devl, devk; /* Overhead fields for VTOC */ BYTE devfg; /* Flag field for VTOC */ int devtl; /* Tolerance field for VTOC */ int b1; /* Bytes used by new record when last record on track */ int b2; /* Bytes used by new record when not last on track */ int nrecs; /* Number of record/track */ int c, d1, d2, x; /* 23xx/3330/3350 factors */ int f1, f2, f3, f4, f5, f6; /* 3380/3390/9345 factors */ int fl1, fl2, int1, int2; /* 3380/3390/9345 calculation*/ ckd = cif->devblk.ckdtab; trklen = ckd->len; maxlen = ckd->r1; heads = ckd->heads; cyls = ckd->cyls; switch (ckd->formula) { case -2: /* 2311, 2314 */ c = ckd->f1; x = ckd->f2; d1 = ckd->f3; d2 = ckd->f4; b1 = keylen + datalen + (keylen == 0 ? 0 : c); b2 = ((keylen + datalen) * d1 / d2) + (keylen == 0 ? 0 : c) + x; nrecs = (trklen - b1)/b2 + 1; devi = c + x; devl = c; devk = c; devtl = d1 / (d2/512); devfg = 0x01; break; case -1: /* 3330, 3340, 3350 */ c = ckd->f1; x = ckd->f2; b1 = b2 = keylen + datalen + (keylen == 0 ? 0 : c) + x; nrecs = trklen / b2; devi = c + x; devl = c + x; devk = c; devtl = 512; devfg = 0x01; break; case 1: /* 3375, 3380 */ f1 = ckd->f1; f2 = ckd->f2; f3 = ckd->f3; fl1 = datalen + f2; fl2 = (keylen == 0 ? 0 : keylen + f3); fl1 = ((fl1 + f1 - 1) / f1) * f1; fl2 = ((fl2 + f1 - 1) / f1) * f1; b1 = b2 = fl1 + fl2; nrecs = trklen / b2; devi = 0; devl = 0; devk = 0; devtl = 0; devfg = 0x30; break; case 2: /* 3390, 9345 */ f1 = ckd->f1; f2 = ckd->f2; f3 = ckd->f3; f4 = ckd->f4; f5 = ckd->f5; f6 = ckd->f6; int1 = ((datalen + f6) + (f5*2-1)) / (f5*2); int2 = ((keylen + f6) + (f5*2-1)) / (f5*2); fl1 = (f1 * f2) + datalen + f6 + f4*int1; fl2 = (keylen == 0 ? 0 : (f1 * f3) + keylen + f6 + f4*int2); fl1 = ((fl1 + f1 - 1) / f1) * f1; fl2 = ((fl2 + f1 - 1) / f1) * f1; b1 = b2 = fl1 + fl2; nrecs = trklen / b2; devi = 0; devl = 0; devk = 0; devtl = 0; devfg = 0x30; break; default: return -1; } /* end switch(ckd->formula) */ /* Return VTOC fields and maximum data length */ if (physlen != NULL) *physlen = trklen; if (kbconst != NULL) *kbconst = devi; if (lbconst != NULL) *lbconst = devl; if (nkconst != NULL) *nkconst = devk; if (devflag != NULL) *devflag = devfg; if (tolfact != NULL) *tolfact = devtl; if (maxdlen != NULL) *maxdlen = maxlen; /* Return number of records per track */ if (numrecs != NULL) *numrecs = nrecs; /* Return number of tracks per cylinder and usual number of cylinders per volume */ if (numhead != NULL) *numhead = heads; if (numcyls != NULL) *numcyls = cyls; /* Return if record will not fit on the track */ if (used + b1 > trklen) return +1; /* Calculate number of bytes used and track balance */ if (newused != NULL) *newused = used + b2; if (trkbaln != NULL) *trkbaln = (used + b2 > trklen) ? 0 : trklen - used - b2; return 0; } /* end function capacity_calc */ /*-------------------------------------------------------------------*/ /* Subroutine to create a CKD DASD image file */ /* Input: */ /* fname DASD image file name */ /* fseqn Sequence number of this file (1=first) */ /* devtype Device type */ /* heads Number of heads per cylinder */ /* trksize DADS image track length */ /* buf -> Track image buffer */ /* start Starting cylinder number for this file */ /* end Ending cylinder number for this file */ /* volcyls Total number of cylinders on volume */ /* volser Volume serial number */ /* comp Compression algorithm for a compressed device. */ /* Will be 0xff if device is not to be compressed. */ /* dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* nullfmt xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* rawflag create raw image (skip special track 0 handling) */ /*-------------------------------------------------------------------*/ static int create_ckd_file (char *fname, int fseqn, U16 devtype, U32 heads, U32 trksize, BYTE *buf, U32 start, U32 end, U32 volcyls, char *volser, BYTE comp, int dasdcopy, int nullfmt, int rawflag) { int rc; /* Return code */ off_t rcoff; /* Return value from lseek() */ int fd; /* File descriptor */ int i; /* Loop counter */ int n; /* Loop delimiter */ CKDDASD_DEVHDR devhdr; /* Device header */ CCKDDASD_DEVHDR cdevhdr; /* Compressed device header */ CCKD_L1ENT *l1=NULL; /* -> Primary lookup table */ CCKD_L2ENT l2[256]; /* Secondary lookup table */ CKDDASD_TRKHDR *trkhdr; /* -> Track header */ CKDDASD_RECHDR *rechdr; /* -> Record header */ U32 cyl; /* Cylinder number */ U32 head; /* Head number */ int trk = 0; /* Track number */ int trks; /* Total number tracks */ BYTE r; /* Record number */ BYTE *pos; /* -> Next position in buffer*/ U32 cpos = 0; /* Offset into cckd file */ int len = 0; /* Length used in track */ int keylen = 4; /* Length of keys */ int ipl1len = 24; /* Length of IPL1 data */ int ipl2len = 144; /* Length of IPL2 data */ int vol1len = 80; /* Length of VOL1 data */ int rec0len = 8; /* Length of R0 data */ int fileseq; /* CKD header sequence number*/ int highcyl; /* CKD header high cyl number*/ int x=O_EXCL; /* Open option */ CKDDEV *ckdtab; /* -> CKD table entry */ char pathname[MAX_PATH]; /* file path in host format */ /* Locate the CKD dasd table entry */ ckdtab = dasd_lookup (DASD_CKDDEV, NULL, devtype, volcyls); if (ckdtab == NULL) { fprintf (stderr, _("HHCDU028E device type %4.4X not found in dasd table\n"), devtype); return -1; } /* Set file sequence number to zero if this is the only file */ if (fseqn == 1 && end + 1 == volcyls) fileseq = 0; else fileseq = fseqn; /* Set high cylinder number to zero if this is the last file */ if (end + 1 == volcyls) highcyl = 0; else highcyl = end; cyl = end - start + 1; /* Special processing for ckd and dasdcopy */ if (comp == 0xFF && dasdcopy) { highcyl = end; if (end + 1 == volcyls) fileseq = 0xff; } trks = volcyls * heads; /* if `dasdcopy' > 1 then we can replace the existing file */ if (dasdcopy > 1) x = 0; /* Create the DASD image file */ hostpath(pathname, fname, sizeof(pathname)); fd = hopen(pathname, O_WRONLY | O_CREAT | x | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { fprintf (stderr, _("HHCDU028E %s open error: %s\n"), fname, strerror(errno)); return -1; } /* Create the device header */ memset(&devhdr, 0, CKDDASD_DEVHDR_SIZE); if (comp == 0xff) memcpy(devhdr.devid, "CKD_P370", 8); else memcpy(devhdr.devid, "CKD_C370", 8); devhdr.heads[3] = (heads >> 24) & 0xFF; devhdr.heads[2] = (heads >> 16) & 0xFF; devhdr.heads[1] = (heads >> 8) & 0xFF; devhdr.heads[0] = heads & 0xFF; devhdr.trksize[3] = (trksize >> 24) & 0xFF; devhdr.trksize[2] = (trksize >> 16) & 0xFF; devhdr.trksize[1] = (trksize >> 8) & 0xFF; devhdr.trksize[0] = trksize & 0xFF; devhdr.devtype = devtype & 0xFF; devhdr.fileseq = fileseq; devhdr.highcyl[1] = (highcyl >> 8) & 0xFF; devhdr.highcyl[0] = highcyl & 0xFF; /* Write the device header */ rc = write (fd, &devhdr, CKDDASD_DEVHDR_SIZE); if (rc < (int)CKDDASD_DEVHDR_SIZE) { fprintf (stderr, _("HHCDU029E %s device header write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Build a compressed CKD file */ if (comp != 0xff) { /* Create the compressed device header */ memset(&cdevhdr, 0, CCKDDASD_DEVHDR_SIZE); cdevhdr.vrm[0] = CCKD_VERSION; cdevhdr.vrm[1] = CCKD_RELEASE; cdevhdr.vrm[2] = CCKD_MODLVL; if (cckd_endian()) cdevhdr.options |= CCKD_BIGENDIAN; cdevhdr.options |= (CCKD_ORDWR | CCKD_NOFUDGE); cdevhdr.numl1tab = (volcyls * heads + 255) / 256; cdevhdr.numl2tab = 256; cdevhdr.cyls[3] = (volcyls >> 24) & 0xFF; cdevhdr.cyls[2] = (volcyls >> 16) & 0xFF; cdevhdr.cyls[1] = (volcyls >> 8) & 0xFF; cdevhdr.cyls[0] = volcyls & 0xFF; cdevhdr.compress = comp; cdevhdr.compress_parm = -1; cdevhdr.nullfmt = nullfmt; /* Write the compressed device header */ rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); if (rc < (int)CCKDDASD_DEVHDR_SIZE) { fprintf (stderr, _("HHCDU030E %s compressed device header " "write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Create the primary lookup table */ l1 = calloc (cdevhdr.numl1tab, CCKD_L1ENT_SIZE); if (l1 == NULL) { fprintf (stderr, _("HHCDU031E Cannot obtain l1tab buffer: %s\n"), strerror(errno)); return -1; } l1[0] = CCKD_L1TAB_POS + cdevhdr.numl1tab * CCKD_L1ENT_SIZE; /* Write the primary lookup table */ rc = write (fd, l1, cdevhdr.numl1tab * CCKD_L1ENT_SIZE); if (rc < (int)(cdevhdr.numl1tab * CCKD_L1ENT_SIZE)) { fprintf (stderr, _("HHCDU032E %s primary lookup table " "write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Create the secondary lookup table */ memset (&l2, 0, CCKD_L2TAB_SIZE); /* Write the seondary lookup table */ rc = write (fd, &l2, CCKD_L2TAB_SIZE); if (rc < (int)CCKD_L2TAB_SIZE) { fprintf (stderr, _("HHCDU033E %s secondary lookup table " "write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } cpos = l1[0] + CCKD_L2TAB_SIZE; } if (!dasdcopy) { /* Write each cylinder */ for (cyl = start; cyl <= end; cyl++) { /* Display progress message every 10 cylinders */ if (cyl && !(cyl % 10)) { #ifdef EXTERNALGUI if (extgui) fprintf (stderr, "CYL=%u\n", cyl); else #endif /*EXTERNALGUI*/ fprintf (stderr, "Writing cylinder %u\r", cyl); } for (head = 0; head < heads; head++) { /* Clear the track to zeroes */ memset (buf, 0, trksize); /* Build the track header */ trkhdr = (CKDDASD_TRKHDR*)buf; trkhdr->bin = 0; store_hw(&trkhdr->cyl, cyl); store_hw(&trkhdr->head, head); pos = buf + CKDDASD_TRKHDR_SIZE; /* Build record zero */ r = 0; rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, rec0len); pos += rec0len; r++; /* Track 0 contains IPL records and volume label */ if (!rawflag && fseqn == 1 && trk == 0) { /* Build the IPL1 record */ rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = keylen; store_hw(&rechdr->dlen, ipl1len); r++; convert_to_ebcdic (pos, keylen, "IPL1"); pos += keylen; memcpy (pos, iplpsw, 8); memcpy (pos+8, iplccw1, 8); memcpy (pos+16, iplccw2, 8); pos += ipl1len; /* Build the IPL2 record */ rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = keylen; store_hw(&rechdr->dlen, ipl2len); r++; convert_to_ebcdic (pos, keylen, "IPL2"); pos += keylen; pos += ipl2len; /* Build the VOL1 record */ rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = keylen; store_hw(&rechdr->dlen, vol1len); r++; convert_to_ebcdic (pos, keylen, "VOL1"); pos += keylen; convert_to_ebcdic (pos, 4, "VOL1"); //VOL1 convert_to_ebcdic (pos+4, 6, volser); //volser pos[10] = 0x40; //security store_hw(pos+11,0); //vtoc CC store_hw(pos+13,1); //vtoc HH pos[15] = 0x01; //vtoc R memset(pos+16, 0x40, 21); //reserved convert_to_ebcdic (pos+37, 14, " HERCULES"); //ownerid memset(pos+51, 0x40, 29); //reserved pos += vol1len; /* 9 4096 data blocks for linux volume */ if (nullfmt == CKDDASD_NULLTRK_FMT2) { for (i = 0; i < 9; i++) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 4096); pos += 4096; r++; } } } /* end if(trk == 0) */ /* Track 1 for linux contains an empty VTOC */ else if (fseqn == 1 && trk == 1 && nullfmt == CKDDASD_NULLTRK_FMT2) { /* build format 4 dscb */ rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; /* track 1 record 1 count */ store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 44; store_hw(&rechdr->dlen, 96); r++; /* track 1 record 1 key */ memset (pos, 0x04, 44); pos += 44; /* track 1 record 1 data */ memset (pos, 0, 96); pos[0] = 0xf4; // DS4IDFMT store_hw(pos + 6, 10); // DS4DSREC pos[14] = trks > 65535 ? 0xa0 : 0; // DS4VTOCI pos[15] = 1; // DS4NOEXT store_hw(pos+18, volcyls); // DS4DSCYL store_hw(pos+20, heads); // DS4DSTRK store_hw(pos+22, ckdtab->len); // DS4DEVTK pos[27] = 0x30; // DS4DEVFG pos[30] = 0x0c; // DS4DEVDT pos[61] = 0x01; // DS4VTOCE + 00 pos[66] = 0x01; // DS4VTOCE + 05 pos[70] = 0x01; // DS4VTOCE + 09 pos[81] = trks > 65535 ? 7 : 0; // DS4EFLVL pos[85] = trks > 65535 ? 1 : 0; // DS4EFPTR + 03 pos[86] = trks > 65535 ? 3 : 0; // DS4EFPTR + 04 pos += 96; /* build format 5 dscb */ rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; /* track 1 record 1 count */ store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 44; store_hw(&rechdr->dlen, 96); r++; /* track 1 record 2 key */ memset (pos, 0x05, 4); // DS5KEYID memset (pos+4, 0, 40); if (trks <= 65535) { store_hw(pos+4, 2); // DS5AVEXT + 00 store_hw(pos+6, volcyls - 1); // DS5AVEXT + 02 pos[8] = heads - 2; // DS5AVEXT + 04 } pos += 44; /* track 1 record 2 data */ memset (pos, 0, 96); pos[0] = 0xf5; // DS5FMTID pos += 96; /* build format 7 dscb */ if (trks > 65535) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; /* track 1 record 3 count */ store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 44; store_hw(&rechdr->dlen, 96); r++; /* track 1 record 2 key */ memset (pos, 0x07, 4); // DS7KEYID memset (pos+4, 0, 40); store_fw(pos+4, 2); // DS7EXTNT + 00 store_fw(pos+8, trks - 1); // DS7EXTNT + 04 pos += 44; /* track 1 record 2 data */ memset (pos, 0, 96); pos[0] = 0xf7; // DS7FMTID pos += 96; } n = 12 - r + 1; for (i = 0; i < n; i++) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 44; store_hw(&rechdr->dlen, 96); pos += 140; r++; } } /* Specific null track formatting */ else if (nullfmt == CKDDASD_NULLTRK_FMT0) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 0); r++; } else if (nullfmt == CKDDASD_NULLTRK_FMT2) { /* Other linux tracks have 12 4096 data records */ for (i = 0; i < 12; i++) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 4096); pos += 4096; r++; } } /* End-of-track marker */ memcpy (pos, eighthexFF, 8); pos += 8; /* Calculate length to write */ if (comp == 0xff) len = (int)trksize; else { len = (int)(pos - buf); l2[trk].pos = cpos; l2[trk].len = l2[trk].size = len; cpos += len; } /* Write the track to the file */ rc = write (fd, buf, len); if (rc != len) { fprintf (stderr, _("HHCDU035E %s cylinder %u head %u " "write error: %s\n"), fname, cyl, head, errno ? strerror(errno) : "incomplete"); return -1; } /* Exit if compressed disk and current track is 1 */ if (comp != 0xff && trk == 1) break; trk++; } /* end for(head) */ /* Exit if compressed disk */ if (comp != 0xff) break; } /* end for(cyl) */ } /* `dasdcopy' bit is off */ else cyl = end + 1; /* Complete building the compressed file */ if (comp != 0xff) { cdevhdr.size = cdevhdr.used = cpos; /* Rewrite the compressed device header */ rcoff = lseek (fd, CKDDASD_DEVHDR_SIZE, SEEK_SET); if (rcoff == -1) { fprintf (stderr, _("HHCDU036E %s compressed device header " "lseek error: %s\n"), fname, strerror(errno)); return -1; } rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); if (rc < (int)CCKDDASD_DEVHDR_SIZE) { fprintf (stderr, _("HHCDU037E %s compressed device header " "write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Rewrite the secondary lookup table */ rcoff = lseek (fd, (off_t)l1[0], SEEK_SET); if (rcoff == -1) { fprintf (stderr, _("HHCDU038E %s secondary lookup table " "lseek error: %s\n"), fname, strerror(errno)); return -1; } rc = write (fd, &l2, CCKD_L2TAB_SIZE); if (rc < (int)CCKD_L2TAB_SIZE) { fprintf (stderr, _("HHCDU039E %s secondary lookup table " "write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } rc = ftruncate(fd, (off_t)cdevhdr.size); free (l1); cyl = volcyls; } /* Close the DASD image file */ rc = close (fd); if (rc < 0) { fprintf (stderr, _("HHCDU040E %s close error: %s\n"), fname, strerror(errno)); return -1; } /* Display completion message */ fprintf (stderr, _("HHCDU041I %u cylinders successfully written to file %s\n"), cyl - start, fname); return 0; } /* end function create_ckd_file */ /*-------------------------------------------------------------------*/ /* Subroutine to create a CKD DASD image */ /* Input: */ /* fname DASD image file name */ /* devtype Device type */ /* heads Number of heads per cylinder */ /* maxdlen Maximum R1 record data length */ /* volcyls Total number of cylinders on volume */ /* volser Volume serial number */ /* comp Compression algorithm for a compressed device. */ /* Will be 0xff if device is not to be compressed. */ /* lfs build large (uncompressed) file (if supported) */ /* dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* nullfmt xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* rawflag create raw image (skip special track 0 handling) */ /* */ /* If the total number of cylinders exceeds the capacity of a 2GB */ /* file, then multiple CKD image files will be created, with the */ /* suffix _1, _2, etc suffixed to the specified file name. */ /* Otherwise a single file is created without a suffix. */ /*-------------------------------------------------------------------*/ DLL_EXPORT int create_ckd (char *fname, U16 devtype, U32 heads, U32 maxdlen, U32 volcyls, char *volser, BYTE comp, int lfs, int dasdcopy, int nullfmt, int rawflag) { int i; /* Array subscript */ int rc; /* Return code */ char *s; /* String pointer */ int fileseq; /* File sequence number */ char sfname[FILENAME_MAX]; /* Suffixed name of this file*/ char *suffix; /* -> Suffix character */ U32 endcyl; /* Last cylinder of this file*/ U32 cyl; /* Cylinder number */ U32 cylsize; /* Cylinder size in bytes */ BYTE *buf; /* -> Track data buffer */ U32 mincyls; /* Minimum cylinder count */ U32 maxcyls; /* Maximum cylinder count */ U32 maxcpif; /* Maximum number of cylinders in each CKD image file */ int rec0len = 8; /* Length of R0 data */ U32 trksize; /* DASD image track length */ /* Compute the DASD image track length */ trksize = sizeof(CKDDASD_TRKHDR) + sizeof(CKDDASD_RECHDR) + rec0len + sizeof(CKDDASD_RECHDR) + maxdlen + sizeof(eighthexFF); trksize = ROUND_UP(trksize,512); /* Compute minimum and maximum number of cylinders */ cylsize = trksize * heads; mincyls = 1; if (comp == 0xff && !lfs) { maxcpif = (0x7fffffff - CKDDASD_DEVHDR_SIZE + 1) / cylsize; maxcyls = maxcpif * CKD_MAXFILES; } else maxcpif = maxcyls = volcyls; if (maxcyls > 65536) maxcyls = 65536; /* Check for valid number of cylinders */ if (volcyls < mincyls || volcyls > maxcyls) { fprintf (stderr, _("HHCDU042E Cylinder count %u is outside range %u-%u\n"), volcyls, mincyls, maxcyls); return -1; } /* Obtain track data buffer */ buf = malloc(trksize); if (buf == NULL) { fprintf (stderr, _("HHCDU043E Cannot obtain track buffer: %s\n"), strerror(errno)); return -1; } /* Display progress message */ fprintf (stderr, _("HHCDU044I Creating %4.4X volume %s: %u cyls, " "%u trks/cyl, %u bytes/track\n"), devtype, rawflag ? "" : volser, volcyls, heads, trksize); /* Copy the unsuffixed DASD image file name */ strcpy (sfname, fname); suffix = NULL; /* Create the suffixed file name if volume will exceed 2GB */ if (volcyls > maxcpif) { /* Look for last slash marking end of directory name */ s = strrchr (fname, '/'); if (s == NULL) s = fname; /* Insert suffix before first dot in file name, or append suffix to file name if there is no dot. If the filename already has a place for the suffix then use that. */ s = strchr (s, '.'); if (s != NULL) { i = s - fname; if (i > 2 && fname[i-2] == '_') suffix = sfname + i - 1; else { strcpy (sfname + i, "_1"); strcat (sfname, fname + i); suffix = sfname + i + 1; } } else { if (strlen(sfname) < 2 || sfname[strlen(sfname)-2] == '_') strcat (sfname, "_1"); suffix = sfname + strlen(sfname) - 1; } } /* Create the DASD image files */ for (cyl = 0, fileseq = 1; cyl < volcyls; cyl += maxcpif, fileseq++) { /* Insert the file sequence number in the file name */ if (suffix) { if (fileseq <= 9) *suffix = '0' + fileseq; else *suffix = 'A' - 10 + fileseq; } /* Calculate the ending cylinder for this file */ if (cyl + maxcpif < volcyls) endcyl = cyl + maxcpif - 1; else endcyl = volcyls - 1; /* Create a CKD DASD image file */ rc = create_ckd_file (sfname, fileseq, devtype, heads, trksize, buf, cyl, endcyl, volcyls, volser, comp, dasdcopy, nullfmt, rawflag); if (rc < 0) return -1; } /* Release data buffer */ free (buf); return 0; } /* end function create_ckd */ /*-------------------------------------------------------------------*/ /* Subroutine to create an FBA DASD image file */ /* Input: */ /* fname DASD image file name */ /* devtype Device type */ /* sectsz Sector size */ /* sectors Number of sectors */ /* volser Volume serial number */ /* comp Compression algorithm for a compressed device. */ /* Will be 0xff if device is not to be compressed. */ /* lfs build large (uncompressed) file (if supported) */ /* dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* rawflag create raw image (skip sector 1 VOL1 processing) */ /*-------------------------------------------------------------------*/ DLL_EXPORT int create_fba (char *fname, U16 devtype, U32 sectsz, U32 sectors, char *volser, BYTE comp, int lfs, int dasdcopy, int rawflag) { int rc; /* Return code */ int fd; /* File descriptor */ U32 sectnum; /* Sector number */ BYTE *buf; /* -> Sector data buffer */ U32 minsect; /* Minimum sector count */ U32 maxsect; /* Maximum sector count */ int x=O_EXCL; /* Open option */ char pathname[MAX_PATH]; /* file path in host format */ /* Special processing for compressed fba */ if (comp != 0xff) { rc = create_compressed_fba (fname, devtype, sectsz, sectors, volser, comp, lfs, dasdcopy, rawflag); return rc; } /* Compute minimum and maximum number of sectors */ minsect = 64; maxsect = 0x80000000 / sectsz; /* Check for valid number of sectors */ if (sectors < minsect || (!lfs && sectors > maxsect)) { fprintf (stderr, _("HHCDU045E Sector count %u is outside range %u-%u\n"), sectors, minsect, maxsect); return -1; } /* Obtain sector data buffer */ buf = malloc(sectsz); if (buf == NULL) { fprintf (stderr, _("HHCDU046E Cannot obtain sector buffer: %s\n"), strerror(errno)); return -1; } /* Display progress message */ fprintf (stderr, _("HHCDU047I Creating %4.4X volume %s: " "%u sectors, %u bytes/sector\n"), devtype, rawflag ? "" : volser, sectors, sectsz); /* if `dasdcopy' > 1 then we can replace the existing file */ if (dasdcopy > 1) x = 0; /* Create the DASD image file */ hostpath(pathname, fname, sizeof(pathname)); fd = hopen(pathname, O_WRONLY | O_CREAT | x | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { fprintf (stderr, _("HHCDU048I %s open error: %s\n"), fname, strerror(errno)); return -1; } /* If the `dasdcopy' bit is on then simply allocate the space */ if (dasdcopy) { off_t sz = sectors * sectsz; rc = ftruncate (fd, sz); if (rc < 0) { fprintf (stderr, _("HHCDU049E %s dasdcopy ftruncate error: %s\n"), fname, strerror(errno)); return -1; } } /* Write each sector */ else { for (sectnum = 0; sectnum < sectors; sectnum++) { /* Clear the sector to zeroes */ memset (buf, 0, sectsz); /* Sector 1 contains the volume label */ if (!rawflag && sectnum == 1) { convert_to_ebcdic (buf, 4, "VOL1"); convert_to_ebcdic (buf+4, 6, volser); } /* end if(sectnum==1) */ /* Display progress message every 100 sectors */ if ((sectnum % 100) == 0) #ifdef EXTERNALGUI { if (extgui) fprintf (stderr, "BLK=%u\n", sectnum); else fprintf (stderr, "Writing sector %u\r", sectnum); } #else /*!EXTERNALGUI*/ fprintf (stderr, "Writing sector %u\r", sectnum); #endif /*EXTERNALGUI*/ /* Write the sector to the file */ rc = write (fd, buf, sectsz); if (rc < (int)sectsz) { fprintf (stderr, _("HHCDU050E %s sector %u write error: %s\n"), fname, sectnum, errno ? strerror(errno) : "incomplete"); return -1; } } /* end for(sectnum) */ } /* `dasdcopy' bit is off */ /* Close the DASD image file */ rc = close (fd); if (rc < 0) { fprintf (stderr, _("HHCDU051E %s close error: %s\n"), fname, strerror(errno)); return -1; } /* Release data buffer */ free (buf); /* Display completion message */ fprintf (stderr, _("HHCDU052I %u sectors successfully written to file %s\n"), sectors, fname); return 0; } /* end function create_fba */ /*-------------------------------------------------------------------*/ /* Subroutine to create a compressed FBA DASD image file */ /* Input: */ /* fname DASD image file name */ /* devtype Device type */ /* sectsz Sector size */ /* sectors Number of sectors */ /* volser Volume serial number */ /* comp Compression algorithm for a compressed device. */ /* lfs build large (uncompressed) file (if supported) */ /* dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* rawflag create raw image (skip sector 1 VOL1 processing) */ /*-------------------------------------------------------------------*/ int create_compressed_fba (char *fname, U16 devtype, U32 sectsz, U32 sectors, char *volser, BYTE comp, int lfs, int dasdcopy, int rawflag) { int rc; /* Return code */ off_t rcoff; /* Return value from lseek() */ int fd; /* File descriptor */ CKDDASD_DEVHDR devhdr; /* Device header */ CCKDDASD_DEVHDR cdevhdr; /* Compressed device header */ int blkgrps; /* Number block groups */ int numl1tab, l1tabsz; /* Level 1 entries, size */ CCKD_L1ENT *l1; /* Level 1 table pointer */ CCKD_L2ENT l2[256]; /* Level 2 table */ unsigned long len2; /* Compressed buffer length */ BYTE buf2[256]; /* Compressed buffer */ BYTE buf[65536]; /* Buffer */ int x=O_EXCL; /* Open option */ char pathname[MAX_PATH]; /* file path in host format */ UNREFERENCED(lfs); /* Calculate the size of the level 1 table */ blkgrps = (sectors / CFBA_BLOCK_NUM) + 1; numl1tab = (blkgrps + 255) / 256; l1tabsz = numl1tab * CCKD_L1ENT_SIZE; if (l1tabsz > 65536) { fprintf (stderr, _("HHCDU053E File size too large: %" I64_FMT "ud [%d]\n"), (U64)(sectors * sectsz), numl1tab); return -1; } /* if `dasdcopy' > 1 then we can replace the existing file */ if (dasdcopy > 1) x = 0; /* Create the DASD image file */ hostpath(pathname, fname, sizeof(pathname)); fd = hopen(pathname, O_WRONLY | O_CREAT | x | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { fprintf (stderr, _("HHCDU054E %s open error: %s\n"), fname, strerror(errno)); return -1; } /* Display progress message */ fprintf (stderr, _("HHCDU055I Creating %4.4X compressed volume %s: " "%u sectors, %u bytes/sector\n"), devtype, rawflag ? "" : volser, sectors, sectsz); /* Write the device header */ memset (&devhdr, 0, CKDDASD_DEVHDR_SIZE); memcpy (&devhdr.devid, "FBA_C370", 8); rc = write (fd, &devhdr, CKDDASD_DEVHDR_SIZE); if (rc < (int)CKDDASD_DEVHDR_SIZE) { fprintf (stderr, _("HHCDU056E %s devhdr write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Write the compressed device header */ memset (&cdevhdr, 0, CCKDDASD_DEVHDR_SIZE); cdevhdr.vrm[0] = CCKD_VERSION; cdevhdr.vrm[1] = CCKD_RELEASE; cdevhdr.vrm[2] = CCKD_MODLVL; if (cckd_endian()) cdevhdr.options |= CCKD_BIGENDIAN; cdevhdr.options |= (CCKD_ORDWR | CCKD_NOFUDGE); cdevhdr.numl1tab = numl1tab; cdevhdr.numl2tab = 256; cdevhdr.cyls[3] = (sectors >> 24) & 0xFF; cdevhdr.cyls[2] = (sectors >> 16) & 0xFF; cdevhdr.cyls[1] = (sectors >> 8) & 0xFF; cdevhdr.cyls[0] = sectors & 0xFF; cdevhdr.compress = comp; cdevhdr.compress_parm = -1; rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); if (rc < (int)CCKDDASD_DEVHDR_SIZE) { fprintf (stderr, _("HHCDU057E %s cdevhdr write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Write the level 1 table */ l1 = (CCKD_L1ENT *)&buf; memset (l1, 0, l1tabsz); l1[0] = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz; rc = write (fd, l1, l1tabsz); if (rc < l1tabsz) { fprintf (stderr, _("HHCDU058E %s l1tab write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Write the 1st level 2 table */ memset (&l2, 0, CCKD_L2TAB_SIZE); l2[0].pos = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz + CCKD_L2TAB_SIZE; rc = write (fd, &l2, CCKD_L2TAB_SIZE); if (rc < (int)CCKD_L2TAB_SIZE) { fprintf (stderr, _("HHCDU059E %s l2tab write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Write the 1st block group */ memset (&buf, 0, CKDDASD_DEVHDR_SIZE + CFBA_BLOCK_SIZE); if (!rawflag) { convert_to_ebcdic (&buf[CKDDASD_TRKHDR_SIZE+sectsz], 4, "VOL1"); convert_to_ebcdic (&buf[CKDDASD_TRKHDR_SIZE+sectsz+4], 6, volser); } len2 = sizeof(buf2); #ifdef HAVE_LIBZ rc = compress2 (&buf2[0], &len2, &buf[CKDDASD_TRKHDR_SIZE], CFBA_BLOCK_SIZE, -1); if (comp && rc == Z_OK) { buf[0] = CCKD_COMPRESS_ZLIB; rc = write (fd, &buf, CKDDASD_TRKHDR_SIZE); if (rc < (int)CKDDASD_TRKHDR_SIZE) { fprintf (stderr, _("HHCDU060E %s block header write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } rc = write (fd, &buf2, len2); if (rc < (int)len2) { fprintf (stderr, _("HHCDU061E %s block write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } l2[0].len = l2[0].size = CKDDASD_TRKHDR_SIZE + len2; cdevhdr.size = cdevhdr.used = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz + CCKD_L2TAB_SIZE + CKDDASD_TRKHDR_SIZE + len2; } else #endif // defined(HAVE_LIBZ) { rc = write (fd, &buf, CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE); if (rc < (int)(CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE)) { fprintf (stderr, _("HHCDU062E %s block write error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } l2[0].len = l2[0].size = CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE; cdevhdr.size = cdevhdr.used = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz + CCKD_L2TAB_SIZE + CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE; } /* Re-write the compressed device header */ rcoff = lseek (fd, CKDDASD_DEVHDR_SIZE, SEEK_SET); if (rcoff < 0) { fprintf (stderr, _("HHCDU063E %s cdevhdr lseek error: %s\n"), fname, strerror(errno)); return -1; } rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); if (rc < (int)CCKDDASD_DEVHDR_SIZE) { fprintf (stderr, _("HHCDU064E %s cdevhdr rewrite error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Re-write the 1st level 2 table */ rcoff = lseek (fd, CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz, SEEK_SET); if (rcoff < 0) { fprintf (stderr, _("HHCDU065E %s l2tab lseek error: %s\n"), fname, strerror(errno)); return -1; } rc = write (fd, &l2, CCKD_L2TAB_SIZE); if (rc < (int)CCKD_L2TAB_SIZE) { fprintf (stderr, _("HHCDU066E %s l2tab rewrite error: %s\n"), fname, errno ? strerror(errno) : "incomplete"); return -1; } /* Close the DASD image file */ rc = close (fd); if (rc < 0) { fprintf (stderr, _("HHCDU067E %s close error: %s\n"), fname, strerror(errno)); return -1; } /* Display completion message */ fprintf (stderr, _("HHCDU068I %u sectors successfully written to file %s\n"), sectors, fname); return 0; } /* end function create_compressed_fba */ int get_verbose_util(void) { return verbose; } DLL_EXPORT void set_verbose_util(int v) { verbose = v; } DLL_EXPORT int valid_dsname( const char *pszdsname ) { int i; int iLen = (int)strlen(pszdsname); if ( iLen > 44 || iLen == 0 ) return FALSE; for ( i = 0; i < iLen; i++ ) { BYTE c = pszdsname[i]; if ( isalnum( c ) ) continue; else if ( c == '$' ) continue; else if ( c == '@' ) continue; else if ( c == '#' ) continue; else if ( c == '-' ) continue; else if ( c == '.' ) continue; else if ( c == '{' ) continue; else if ( i > 1 && c == '\0' ) break; else return FALSE; } return TRUE; } hercules-3.12/shared.c0000664000175000017500000030420512564723224011621 00000000000000/* SHARED.C (c) Copyright Greg Smith, 2002-2009 */ /* Shared Device Server */ #include "hstdinc.h" #define _HERCULES_SHARED_C #define _SHARED_C_ #define _HDASD_DLL_ #include "hercules.h" #include "opcode.h" #include "devtype.h" #define FBA_BLKGRP_SIZE (120*512) /* Change the following to "define" when Shared FBA support is implemented */ #undef FBA_SHARED /*-------------------------------------------------------------------*/ /* Definitions for sense data format codes and message codes */ /*-------------------------------------------------------------------*/ #define FORMAT_0 0 /* Program or System Checks */ #define FORMAT_1 1 /* Device Equipment Checks */ #define FORMAT_2 2 /* 3990 Equipment Checks */ #define FORMAT_3 3 /* 3990 Control Checks */ #define FORMAT_4 4 /* Data Checks */ #define FORMAT_5 5 /* Data Check + Displacement */ #define FORMAT_6 6 /* Usage Stats/Overrun Errors*/ #define FORMAT_7 7 /* Device Control Checks */ #define FORMAT_8 8 /* Device Equipment Checks */ #define FORMAT_9 9 /* Device Rd/Wrt/Seek Checks */ #define FORMAT_F 15 /* Cache Storage Checks */ #define MESSAGE_0 0 /* Message 0 */ #define MESSAGE_1 1 /* Message 1 */ #define MESSAGE_2 2 /* Message 2 */ #define MESSAGE_3 3 /* Message 3 */ #define MESSAGE_4 4 /* Message 4 */ #define MESSAGE_5 5 /* Message 5 */ #define MESSAGE_6 6 /* Message 6 */ #define MESSAGE_7 7 /* Message 7 */ #define MESSAGE_8 8 /* Message 8 */ #define MESSAGE_9 9 /* Message 9 */ #define MESSAGE_A 10 /* Message A */ #define MESSAGE_B 11 /* Message B */ #define MESSAGE_C 12 /* Message C */ #define MESSAGE_D 13 /* Message D */ #define MESSAGE_E 14 /* Message E */ #define MESSAGE_F 15 /* Message F */ #if defined(OPTION_SHARED_DEVICES) DEVHND shared_ckd_device_hndinfo; DEVHND shared_fba_device_hndinfo; static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; /*------------------------------------------------------------------- * Update notify - called by device handlers for sharable devices *-------------------------------------------------------------------*/ int shared_update_notify (DEVBLK *dev, int block) { int i, j; /* Indexes */ /* Return if no remotes are connected */ if (dev->shrdconn == 0) return 0; for (i = 0; i < SHARED_MAX_SYS; i++) { /* Ignore the entry if it doesn't exist or if it's ours our if it's already maxed out */ if (dev->shrd[i] == NULL || dev->shrd[i]->id == dev->ioactive || dev->shrd[i]->purgen < 0) continue; /* Check if the block is already entered */ for (j = 0; j < dev->shrd[i]->purgen; j++) if (fetch_fw(dev->shrd[i]->purge[j]) == (U32)block) break; /* Add the block if it's not already there */ if (j >= dev->shrd[i]->purgen) { if (dev->shrd[i]->purgen >= SHARED_PURGE_MAX) dev->shrd[i]->purgen = -1; else store_fw (dev->shrd[i]->purge[dev->shrd[i]->purgen++], block); shrdtrc(dev,"notify %d added for id=%d, n=%d\n", block, dev->shrd[i]->id, dev->shrd[i]->purgen); } } /* for each possible remote system */ return 0; } /* shared_update_notify */ /*------------------------------------------------------------------- * CKD init exit (client side) *-------------------------------------------------------------------*/ int shared_ckd_init (DEVBLK *dev, int argc, char *argv[] ) { int rc; /* Return code */ int i; /* Loop index */ int retry; /* 1=Connection being retried*/ char *ipname; /* Remote name or address */ char *port = NULL; /* Remote port */ char *rmtnum = NULL; /* Remote device number */ struct hostent *he; /* -> hostent structure */ char *kw; /* Argument keyword */ char *op; /* Argument operand */ BYTE c; /* Used for parsing */ char *cu = NULL; /* Specified control unit */ FWORD cyls; /* Remote number cylinders */ char *p, buf[1024]; /* Work buffer */ retry = dev->connecting; /* Process the arguments */ if (!retry) { if (argc < 1 || strlen(argv[0]) >= sizeof(buf)) return -1; strcpy (buf, argv[0]); /* First argument is `ipname:port:devnum' */ ipname = buf; if (strchr(ipname,'/') || strchr(ipname,'\\')) return -1; p = strchr (buf, ':'); if (p) { *p = '\0'; port = p + 1; p = strchr (port, ':'); } if (p) { *p = '\0'; rmtnum = p + 1; } #if defined( HAVE_SYS_UN_H ) if ( strcmp (ipname, "localhost") == 0) dev->localhost = 1; else #endif { if ( (he = gethostbyname (ipname)) == NULL ) return -1; memcpy(&dev->rmtaddr, he->h_addr_list[0], sizeof(dev->rmtaddr)); } if (port && strlen(port)) { if (sscanf(port, "%hu%c", &dev->rmtport, &c) != 1) return -1; } else dev->rmtport = SHARED_DEFAULT_PORT; if (rmtnum && strlen(rmtnum)) { if (strlen (rmtnum) > 4 || sscanf (rmtnum, "%hx%c", &dev->rmtnum, &c) != 1) return -1; } else dev->rmtnum = dev->devnum; /* Process the remaining arguments */ for (i = 1; i < argc; i++) { if (strcasecmp ("readonly", argv[i]) == 0 || strcasecmp ("rdonly", argv[i]) == 0 || strcasecmp ("ro", argv[i]) == 0) { dev->ckdrdonly = 1; continue; } if (strcasecmp ("fakewrite", argv[i]) == 0 || strcasecmp ("fakewrt", argv[i]) == 0 || strcasecmp ("fw", argv[i]) == 0) { dev->ckdfakewr = 1; continue; } if (strlen (argv[i]) > 3 && memcmp("cu=", argv[i], 3) == 0) { kw = strtok (argv[i], "="); op = strtok (NULL, " \t"); cu = op; continue; } #ifdef HAVE_LIBZ if (strlen (argv[i]) > 5 && memcmp("comp=", argv[i], 5) == 0) { kw = strtok (argv[i], "="); op = strtok (NULL, " \t"); dev->rmtcomp = atoi (op); if (dev->rmtcomp < 0 || dev->rmtcomp > 9) dev->rmtcomp = 0; continue; } #endif logmsg (_("HHCSH001S parameter %d is invalid: %s\n"), i + 1, argv[i]); return -1; } } /* Set suported compression */ dev->rmtcomps = 0; #ifdef HAVE_LIBZ dev->rmtcomps |= SHRD_LIBZ; #endif #ifdef CCKD_BZIP2 dev->rmtcomps |= SHRD_BZIP2; #endif /* Update the device handler vector */ dev->hnd = &shared_ckd_device_hndinfo; dev->connecting = 1; init_retry: do { rc = clientConnect (dev, retry); if (rc < 0) { logmsg (_("HHCSH002W %4.4X connect pending to %s\n"), dev->devnum, dev->filename); if (retry) SLEEP(5); } } while (retry && rc < 0); /* Return if unable to connect */ if (rc < 0) return 0; dev->ckdnumfd = 1; dev->ckdfd[0] = dev->fd; /* Get the number of cylinders */ rc = clientRequest (dev, cyls, 4, SHRD_QUERY, SHRD_CKDCYLS, NULL, NULL); if (rc < 0) goto init_retry; else if (rc != 4) { logmsg (_("HHCSH003S %4.4X Error retrieving cylinders\n"), dev->devnum); return -1; } dev->ckdcyls = fetch_fw (cyls); /* Get the device characteristics */ rc = clientRequest (dev, dev->devchar, sizeof(dev->devchar), SHRD_QUERY, SHRD_DEVCHAR, NULL, NULL); if (rc < 0) goto init_retry; else if (rc == 0 || rc > (int)sizeof(dev->devchar)) { logmsg (_("HHCSH004S %4.4X Error retrieving device" " characteristics\n"), dev->devnum); return -1; } dev->numdevchar = rc; /* Get number of heads from devchar */ dev->ckdheads = fetch_hw (dev->devchar + 14); /* Calculate number of tracks */ dev->ckdtrks = dev->ckdcyls * dev->ckdheads; dev->ckdhitrk[0] = dev->ckdtrks; /* Check the device type */ if (dev->devtype == 0) dev->devtype = fetch_hw (dev->devchar + 3); else if (dev->devtype != fetch_hw (dev->devchar + 3)) { logmsg (_("HHCSH005S %4.4X Remote device %4.4X is a %4.4X\n"), dev->devnum, dev->rmtnum, fetch_hw (dev->devchar + 3)); return -1; } /* Get the device id */ rc = clientRequest (dev, dev->devid, sizeof(dev->devid), SHRD_QUERY, SHRD_DEVID, NULL, NULL); if (rc < 0) goto init_retry; else if (rc == 0 || rc > (int)sizeof(dev->devid)) { logmsg (_("HHCSH006S %4.4X Error retrieving device id\n"), dev->devnum); return -1; } dev->numdevid = rc; /* Indicate no active track */ dev->cache = dev->bufcur = -1; dev->buf = NULL; /* Set number of sense bytes */ dev->numsense = 32; /* Locate the CKD dasd table entry */ dev->ckdtab = dasd_lookup (DASD_CKDDEV, NULL, dev->devtype, dev->ckdcyls); if (dev->ckdtab == NULL) { logmsg (_("HHCSH007S %4.4X device type %4.4X not found in dasd table\n"), dev->devnum, dev->devtype); return -1; } /* Set the track size */ dev->ckdtrksz = (dev->ckdtab->r1 + 511) & ~511; /* Locate the CKD control unit dasd table entry */ dev->ckdcu = dasd_lookup (DASD_CKDCU, cu ? cu : dev->ckdtab->cu, 0, 0); if (dev->ckdcu == NULL) { logmsg (_("HHCSH008S %4.4X control unit %s not found in dasd table\n"), dev->devnum, cu ? cu : dev->ckdtab->cu); return -1; } /* Set flag bit if 3990 controller */ if (dev->ckdcu->devt == 0x3990) dev->ckd3990 = 1; /* Clear the DPA */ memset(dev->pgid, 0, sizeof(dev->pgid)); /* Request the channel to merge data chained write CCWs into a single buffer before passing data to the device handler */ dev->cdwmerge = 1; /* Purge the cache */ clientPurge (dev, 0, NULL); /* Log the device geometry */ if (!dev->batch) logmsg (_("HHCSH009I %s cyls=%d heads=%d tracks=%d trklen=%d\n"), dev->filename, dev->ckdcyls, dev->ckdheads, dev->ckdtrks, dev->ckdtrksz); dev->connecting = 0; return 0; } /* shared_ckd_init */ /*------------------------------------------------------------------- * CKD close exit (client side) *-------------------------------------------------------------------*/ static int shared_ckd_close ( DEVBLK *dev ) { /* Purge the cached entries */ clientPurge (dev, 0, NULL); /* Disconnect and close */ if (dev->fd >= 0) { clientRequest (dev, NULL, 0, SHRD_DISCONNECT, 0, NULL, NULL); close_socket (dev->fd); dev->fd = -1; } return 0; } /* shared_ckd_close */ /*------------------------------------------------------------------- * FBA init exit (client side) *-------------------------------------------------------------------*/ int shared_fba_init (DEVBLK *dev, int argc, char *argv[] ) { int rc; /* Return code */ int i; /* Loop index */ int retry; /* 1=Connection being retried*/ char *ipname; /* Remote name or address */ char *port = NULL; /* Remote port */ char *rmtnum = NULL; /* Remote device number */ struct hostent *he; /* -> hostent structure */ char *kw; /* Argument keyword */ char *op; /* Argument operand */ char c; /* Work for sscanf */ FWORD origin; /* FBA origin */ FWORD numblks; /* FBA number blocks */ FWORD blksiz; /* FBA block size */ char *p, buf[1024]; /* Work buffer */ retry = dev->connecting; /* Process the arguments */ if (!retry) { kw = op = NULL; if (argc < 1 || strlen(argv[0]) >= sizeof(buf)) return -1; strcpy (buf, argv[0]); /* First argument is `ipname:port:devnum' */ ipname = buf; p = strchr (buf, ':'); if (p) { *p = '\0'; port = p + 1; p = strchr (port, ':'); } if (p) { *p = '\0'; rmtnum = p + 1; } if ( (he = gethostbyname (ipname)) == NULL ) return -1; memcpy(&dev->rmtaddr, he->h_addr_list[0], sizeof(dev->rmtaddr)); if (port) { if (sscanf(port, "%hu%c", &dev->rmtport, &c) != 1) return -1; } else dev->rmtport = SHARED_DEFAULT_PORT; if (rmtnum) { if (strlen (rmtnum) > 4 || sscanf (rmtnum, "%hx%c", &dev->rmtnum, &c) != 0) return -1; } else dev->rmtnum = dev->devnum; /* Process the remaining arguments */ for (i = 1; i < argc; i++) { #ifdef HAVE_LIBZ if (strlen (argv[i]) > 5 && memcmp("comp=", argv[i], 5) == 0) { kw = strtok (argv[i], "="); op = strtok (NULL, " \t"); dev->rmtcomp = atoi (op); if (dev->rmtcomp < 0 || dev->rmtcomp > 9) dev->rmtcomp = 0; continue; } #endif logmsg (_("HHCSH010S parameter %d is invalid: %s\n"), i + 1, argv[i]); return -1; } } /* Set suported compression */ dev->rmtcomps = 0; #ifdef HAVE_LIBZ dev->rmtcomps |= SHRD_LIBZ; #endif #ifdef CCKD_BZIP2 dev->rmtcomps |= SHRD_BZIP2; #endif /* Update the device handler vector */ dev->hnd = &shared_fba_device_hndinfo; dev->connecting = 1; init_retry: do { rc = clientConnect (dev, retry); if (rc < 0) { logmsg (_("HHCSH011I %4.4X connect pending to %s\n"), dev->devnum, dev->filename); if (retry) SLEEP(5); } } while (retry && rc < 0); /* Return if unable to connect */ if (rc < 0) return 0; /* Get the fba origin */ rc = clientRequest (dev, origin, 4, SHRD_QUERY, SHRD_FBAORIGIN, NULL, NULL); if (rc < 0) goto init_retry; else if (rc != 4) { logmsg (_("HHCSH012S %4.4X Error retrieving fba origin\n"), dev->devnum); return -1; } dev->fbaorigin = fetch_fw (origin); /* Get the number of blocks */ rc = clientRequest (dev, numblks, 4, SHRD_QUERY, SHRD_FBANUMBLK, NULL, NULL); if (rc < 0) goto init_retry; else if (rc != 4) { logmsg (_("HHCSH013S %4.4X Error retrieving fba number blocks\n"), dev->devnum); return -1; } dev->fbanumblk = fetch_fw (numblks); /* Get the block size */ rc = clientRequest (dev, blksiz, 4, SHRD_QUERY, SHRD_FBABLKSIZ, NULL, NULL); if (rc < 0) goto init_retry; else if (rc != 4) { logmsg (_("HHCSH014S %4.4X Error retrieving fba block size\n"), dev->devnum); return -1; } dev->fbablksiz = fetch_fw (blksiz); dev->fbaend = (dev->fbaorigin + dev->fbanumblk) * dev->fbablksiz; /* Get the device id */ rc = clientRequest (dev, dev->devid, sizeof(dev->devid), SHRD_QUERY, SHRD_DEVID, NULL, NULL); if (rc < 0) goto init_retry; else if (rc == 0 || rc > (int)sizeof(dev->devid)) { logmsg (_("HHCSH015S %4.4X Error retrieving device id\n"), dev->devnum); return -1; } dev->numdevid = rc; /* Check the device type */ if (dev->devtype != fetch_hw (dev->devid + 4)) { logmsg (_("HHCSH016S %4.4X Remote device %4.4X is a %4.4X\n"), dev->devnum, dev->rmtnum, fetch_hw (dev->devid + 4)); return -1; } /* Get the device characteristics */ rc = clientRequest (dev, dev->devchar, sizeof(dev->devchar), SHRD_QUERY, SHRD_DEVCHAR, NULL, NULL); if (rc < 0) goto init_retry; else if (rc == 0 || rc > (int)sizeof(dev->devchar)) { logmsg (_("HHCSH017S %4.4X Error retrieving device" " characteristics\n"), dev->devnum); return -1; } dev->numdevchar = rc; /* Indicate no active track */ dev->cache = dev->bufcur = -1; dev->buf = NULL; /* Set number of sense bytes */ dev->numsense = 32; /* Locate the FBA dasd table entry */ dev->fbatab = dasd_lookup (DASD_FBADEV, NULL, dev->devtype, dev->fbanumblk); if (dev->fbatab == NULL) { logmsg (_("HHCSH018S %4.4X device type %4.4X not found in dasd table\n"), dev->devnum, dev->devtype); return -1; } /* Purge the cache */ clientPurge (dev, 0, NULL); /* Log the device geometry */ logmsg (_("HHCSH019I %s origin=%d blks=%d\n"), dev->filename, dev->fbaorigin, dev->fbanumblk); dev->connecting = 0; return 0; } /*------------------------------------------------------------------- * FBA close exit (client side) *-------------------------------------------------------------------*/ static int shared_fba_close (DEVBLK *dev) { /* Purge the cached entries */ clientPurge (dev, 0, NULL); /* Disconnect and close */ if (dev->fd >= 0) { clientRequest (dev, NULL, 0, SHRD_DISCONNECT, 0, NULL, NULL); close_socket (dev->fd); dev->fd = -1; } return 0; } /*------------------------------------------------------------------- * Start I/O exit (client side) *-------------------------------------------------------------------*/ static void shared_start(DEVBLK *dev) { int rc; /* Return code */ U16 devnum; /* Cache device number */ int trk; /* Cache track number */ int code; /* Response code */ BYTE buf[SHARED_PURGE_MAX * 4]; /* Purge list */ shrdtrc(dev,"start cur %d cache %d\n",dev->bufcur,dev->cache); /* Send the START request */ rc = clientRequest (dev, buf, sizeof(buf), SHRD_START, 0, &code, NULL); if (rc < 0) { logmsg(_("HHCSH020E %4.4X error during channel program start\n"), dev->devnum); clientPurge (dev, 0, NULL); dev->cache = dev->bufcur = -1; dev->buf = NULL; return; } /* Check for purge */ if (code & SHRD_PURGE) { if (rc / 4 > SHARED_PURGE_MAX) rc = 0; clientPurge (dev, rc / 4, buf); } /* Make previous active entry active again */ if (dev->cache >= 0) { cache_lock (CACHE_DEVBUF); SHRD_CACHE_GETKEY (dev->cache, devnum, trk); if (dev->devnum == devnum && dev->bufcur == trk) cache_setflag(CACHE_DEVBUF, dev->cache, ~0, SHRD_CACHE_ACTIVE); else { dev->cache = dev->bufcur = -1; dev->buf = NULL; } cache_unlock (CACHE_DEVBUF); } } /* shared_start */ /*------------------------------------------------------------------- * End I/O exit (client side) *-------------------------------------------------------------------*/ static void shared_end (DEVBLK *dev) { int rc; /* Return code */ shrdtrc(dev,"end cur %d cache %d\n",dev->bufcur,dev->cache); /* Write the previous active entry if it was updated */ if (dev->bufupd) clientWrite (dev, dev->bufcur); dev->bufupd = 0; /* Mark the active entry inactive */ if (dev->cache >= 0) { cache_lock (CACHE_DEVBUF); cache_setflag (CACHE_DEVBUF, dev->cache, ~SHRD_CACHE_ACTIVE, 0); cache_unlock (CACHE_DEVBUF); } /* Send the END request */ rc = clientRequest (dev, NULL, 0, SHRD_END, 0, NULL, NULL); if (rc < 0) { logmsg(_("HHCSH021E %4.4X error during channel program end\n"), dev->devnum); clientPurge (dev, 0, NULL); dev->cache = dev->bufcur = -1; dev->buf = NULL; return; } } /* shared_end */ /*------------------------------------------------------------------- * Shared ckd read track exit (client side) *-------------------------------------------------------------------*/ static int shared_ckd_read (DEVBLK *dev, int trk, BYTE *unitstat) { int rc; /* Return code */ int retries = 10; /* Number read retries */ int cache; /* Lookup index */ int lru; /* Available index */ int len; /* Response length */ int id; /* Response id */ BYTE *buf; /* Cache buffer */ BYTE code; /* Response code */ U16 devnum; /* Response device number */ BYTE hdr[SHRD_HDR_SIZE + 4]; /* Read request header */ /* Initialize the unit status */ *unitstat = 0; /* Return if reading the same track image */ if (trk == dev->bufcur && dev->cache >= 0) { dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; return 0; } shrdtrc(dev,"ckd_read trk %d\n",trk); /* Write the previous active entry if it was updated */ if (dev->bufupd) clientWrite (dev, dev->bufcur); dev->bufupd = 0; /* Reset buffer offsets */ dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; cache_lock (CACHE_DEVBUF); /* Inactivate the previous image */ if (dev->cache >= 0) cache_setflag (CACHE_DEVBUF, dev->cache, ~SHRD_CACHE_ACTIVE, 0); dev->cache = dev->bufcur = -1; cache_retry: /* Lookup the track in the cache */ cache = cache_lookup (CACHE_DEVBUF, SHRD_CACHE_SETKEY(dev->devnum, trk), &lru); /* Process cache hit */ if (cache >= 0) { cache_setflag (CACHE_DEVBUF, cache, ~0, SHRD_CACHE_ACTIVE); cache_unlock (CACHE_DEVBUF); dev->cachehits++; dev->cache = cache; dev->buf = cache_getbuf (CACHE_DEVBUF, cache, 0); dev->bufcur = trk; dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; dev->buflen = shared_ckd_trklen (dev, dev->buf); dev->bufsize = cache_getlen (CACHE_DEVBUF, cache); shrdtrc(dev,"ckd_read trk %d cache hit %d\n",trk,dev->cache); return 0; } /* Special processing if no available cache entry */ if (lru < 0) { shrdtrc(dev,"ckd_read trk %d cache wait\n",trk); dev->cachewaits++; cache_wait (CACHE_DEVBUF); goto cache_retry; } /* Process cache miss */ shrdtrc(dev,"ckd_read trk %d cache miss %d\n",trk,dev->cache); dev->cachemisses++; cache_setflag (CACHE_DEVBUF, lru, 0, SHRD_CACHE_ACTIVE|DEVBUF_TYPE_SCKD); cache_setkey (CACHE_DEVBUF, lru, SHRD_CACHE_SETKEY(dev->devnum, trk)); cache_setage (CACHE_DEVBUF, lru); buf = cache_getbuf (CACHE_DEVBUF, lru, dev->ckdtrksz); cache_unlock (CACHE_DEVBUF); read_retry: /* Send the read request for the track to the remote host */ SHRD_SET_HDR (hdr, SHRD_READ, 0, dev->rmtnum, dev->rmtid, 4); store_fw (hdr + SHRD_HDR_SIZE, trk); rc = clientSend (dev, hdr, NULL, 0); if (rc < 0) { ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg(_("HHCSH022E %4.4X error reading track %d\n"), dev->devnum, trk); return -1; } /* Read the track from the remote host */ rc = clientRecv (dev, hdr, buf, dev->ckdtrksz); SHRD_GET_HDR (hdr, code, *unitstat, devnum, id, len); if (rc < 0 || code & SHRD_ERROR) { if (rc < 0 && retries--) goto read_retry; ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg(_("HHCSH023E %4.4X error reading track %d\n"), dev->devnum, trk); return -1; } /* Read the sense data if an i/o error occurred */ if (code & SHRD_IOERR) clientRequest (dev, dev->sense, dev->numsense, SHRD_SENSE, 0, NULL, NULL); /* Read complete */ dev->cache = lru; dev->buf = cache_getbuf (CACHE_DEVBUF, lru, 0); dev->bufcur = trk; dev->bufoff = 0; dev->bufoffhi = dev->ckdtrksz; dev->buflen = shared_ckd_trklen (dev, dev->buf); dev->bufsize = cache_getlen (CACHE_DEVBUF, lru); dev->buf[0] = 0; return 0; } /* shared_ckd_read */ /*------------------------------------------------------------------- * Shared ckd write track exit (client side) *-------------------------------------------------------------------*/ static int shared_ckd_write (DEVBLK *dev, int trk, int off, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Immediately return if fake writing */ if (dev->ckdfakewr) return len; /* Error if opened read-only */ if (dev->ckdrdonly) { ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0, FORMAT_1, MESSAGE_0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } shrdtrc(dev,"ckd_write trk %d off %d len %d\n",trk,off,len); /* If the track is not current then read it */ if (trk != dev->bufcur) { rc = (dev->hnd->read) (dev, trk, unitstat); if (rc < 0) { dev->bufcur = dev->cache = -1; return -1; } } /* Invalid track format if going past buffer end */ if (off + len > dev->bufoffhi) { ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0); *unitstat = CSW_CE | CSW_DE | CSW_UC; return -1; } /* Copy the data into the buffer */ if (buf) memcpy (dev->buf + off, buf, len); /* Set low and high updated offsets */ if (!dev->bufupd || off < dev->bufupdlo) dev->bufupdlo = off; if (dev->bufoff + len > dev->bufupdhi) dev->bufupdhi = off + len; /* Indicate track image has been modified */ if (!dev->bufupd) { dev->bufupd = 1; shared_update_notify (dev, trk); } return len; } /* shared_ckd_write */ /*------------------------------------------------------------------- * Return track image length *-------------------------------------------------------------------*/ static int shared_ckd_trklen (DEVBLK *dev, BYTE *buf) { int sz; /* Size so far */ for (sz = CKDDASD_TRKHDR_SIZE; memcmp (buf + sz, &eighthexFF, 8) != 0; ) { /* add length of count, key, and data fields */ sz += CKDDASD_RECHDR_SIZE + buf[sz+5] + (buf[sz+6] << 8) + buf[sz+7]; if (sz > dev->ckdtrksz - 8) break; } /* add length for end-of-track indicator */ sz += CKDDASD_RECHDR_SIZE; if (sz > dev->ckdtrksz) sz = dev->ckdtrksz; return sz; } #if defined(FBA_SHARED) /*------------------------------------------------------------------- * Shared fba read block exit (client side) *-------------------------------------------------------------------*/ static int shared_fba_read (DEVBLK *dev, int blkgrp, BYTE *unitstat) { int rc; /* Return code */ int retries = 10; /* Number read retries */ int i, o; /* Cache indexes */ BYTE code; /* Response code */ U16 devnum; /* Response device number */ int len; /* Response length */ int id; /* Response id */ BYTE hdr[SHRD_HDR_SIZE + 4]; /* Read request header */ /* Return if reading the same block group */ if (blkgrp >= 0 && blkgrp == dev->bufcur) return 0; shrdtrc(dev,"fba_read blkrp %d\n",blkgrp); /* Write the previous active entry if it was updated */ if (dev->bufupd) clientWrite (dev, dev->bufcur); dev->bufupd = 0; /* Reset buffer offsets */ dev->bufoff = 0; dev->bufoffhi = FBA_BLKGRP_SIZE; cache_lock (CACHE_DEVBUF); /* Make the previous cache entry inactive */ if (dev->cache >= 0) cache_setflag(CACHE_DEVBUF, dev->cache, ~FBA_CACHE_ACTIVE, 0); dev->bufcur = dev->cache = -1; cache_retry: /* Search the cache */ i = cache_lookup (CACHE_DEVBUF, FBA_CACHE_SETKEY(dev->devnum, blkgrp), &o); /* Cache hit */ if (i >= 0) { cache_setflag(CACHE_DEVBUF, dev->cache, ~0, FBA_CACHE_ACTIVE); cache_setage(CACHE_DEVBUF, dev->cache); cache_unlock(CACHE_DEVBUF); dev->cachehits++; dev->cache = i; dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0); dev->bufcur = blkgrp; dev->bufoff = 0; dev->bufoffhi = shared_fba_blkgrp_len (dev, blkgrp); dev->buflen = shared_fba_blkgrp_len (dev, blkgrp); dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache); shrdtrc(dev,"fba_read blkgrp %d cache hit %d\n",blkgrp,dev->cache); return 0; } /* Wait if no available cache entry */ if (o < 0) { shrdtrc(dev,"fba_read blkgrp %d cache wait\n",blkgrp); dev->cachewaits++; cache_wait(CACHE_DEVBUF); goto cache_retry; } /* Cache miss */ shrdtrc(dev,"fba_read blkgrp %d cache miss %d\n",blkgrp,dev->cache); dev->cachemisses++; cache_setflag(CACHE_DEVBUF, o, 0, FBA_CACHE_ACTIVE|DEVBUF_TYPE_SFBA); cache_setkey (CACHE_DEVBUF, o, FBA_CACHE_SETKEY(dev->devnum, blkgrp)); cache_setage (CACHE_DEVBUF, o); dev->buf = cache_getbuf(CACHE_DEVBUF, o, FBA_BLKGRP_SIZE); cache_unlock (CACHE_DEVBUF); read_retry: /* Send the read request for the blkgrp to the remote host */ SHRD_SET_HDR (hdr, SHRD_READ, 0, dev->rmtnum, dev->rmtid, 4); store_fw (hdr + SHRD_HDR_SIZE, blkgrp); rc = clientSend (dev, hdr, NULL, 0); if (rc < 0) { dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg(_("HHCSH024E %4.4X error reading block group %d\n"), dev->devnum, blkgrp); return -1; } /* Read the blkgrp from the remote host */ rc = clientRecv (dev, hdr, dev->buf, FBA_BLKGRP_SIZE); SHRD_GET_HDR (hdr, code, *unitstat, devnum, id, len); if (rc < 0 || code & SHRD_ERROR) { if (rc < 0 && retries--) goto read_retry; dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; logmsg(_("HHCSH025E %4.4X error reading block group %d\n"), dev->devnum, blkgrp); return -1; } /* Read the sense data if an i/o error occurred */ if (code & SHRD_IOERR) clientRequest (dev, dev->sense, dev->numsense, SHRD_SENSE, 0, NULL, NULL); dev->cache = o; dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0); dev->buf[0] = 0; dev->bufcur = blkgrp; dev->bufoff = 0; dev->bufoffhi = shared_fba_blkgrp_len (dev, blkgrp); dev->buflen = shared_fba_blkgrp_len (dev, blkgrp); dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache); return 0; } /*------------------------------------------------------------------- * Shared fba write block exit (client side) *-------------------------------------------------------------------*/ static int shared_fba_write (DEVBLK *dev, int blkgrp, int off, BYTE *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Read the block group */ if (blkgrp != dev->bufcur) { rc = (dev->hnd->read) (dev, blkgrp, unitstat); if (rc < 0) { dev->bufcur = dev->cache = -1; return -1; } } /* Copy to the device buffer */ if (buf) memcpy (dev->buf + off, buf, len); /* Update high/low offsets */ if (!dev->bufupd || off < dev->bufupdlo) dev->bufupdlo = off; if (off + len > dev-> bufupdhi) dev->bufupdhi = off + len; /* Indicate block group has been modified */ if (!dev->bufupd) { dev->bufupd = 1; shared_update_notify (dev, blkgrp); } return len; } /*-------------------------------------------------------------------*/ /* Calculate length of an FBA block group */ /*-------------------------------------------------------------------*/ static int shared_fba_blkgrp_len (DEVBLK *dev, int blkgrp) { off_t offset; /* Offset of block group */ offset = blkgrp * FBA_BLKGRP_SIZE; if (dev->fbaend - offset < FBA_BLKGRP_SIZE) return (int)(dev->fbaend - offset); else return FBA_BLKGRP_SIZE; } #endif /* FBA_SHARED */ /*------------------------------------------------------------------- * Shared usage exit (client side) *-------------------------------------------------------------------*/ static int shared_used (DEVBLK *dev) { int rc; /* Return code */ FWORD usage; /* Usage buffer */ /* Get usage information */ rc = clientRequest (dev, usage, 4, SHRD_USED, 0, NULL, NULL); if (rc != 4) { logmsg (_("HHCSH026E %4.4X Error retrieving usage information\n"), dev->devnum); return -1; } return fetch_fw (usage); } /* shared_used */ /*------------------------------------------------------------------- * Shared reserve exit (client side) *-------------------------------------------------------------------*/ static void shared_reserve (DEVBLK *dev) { int rc; /* Return code */ /* Issue reserve request */ rc = clientRequest (dev, NULL, 0, SHRD_RESERVE, 0, NULL, NULL); } /* shared_reserve */ /*------------------------------------------------------------------- * Shared release exit (client side) *-------------------------------------------------------------------*/ static void shared_release (DEVBLK *dev) { int rc; /* Return code */ /* Issue release request */ rc = clientRequest (dev, NULL, 0, SHRD_RELEASE, 0, NULL, NULL); } /* shared_release */ /*------------------------------------------------------------------- * Write to host * * NOTE - writes are deferred until a switch occurs or the * channel program ends. We are called from either the * read exit or the end channel program exit. *-------------------------------------------------------------------*/ static int clientWrite (DEVBLK *dev, int block) { int rc; /* Return code */ int retries = 10; /* Number write retries */ int len; /* Data length */ BYTE hdr[SHRD_HDR_SIZE + 2 + 4]; /* Write header */ BYTE code; /* Response code */ int status; /* Response status */ int id; /* Response identifier */ U16 devnum; /* Response device number */ BYTE errmsg[SHARED_MAX_MSGLEN+1];/* Error message */ /* Calculate length to write */ len = dev->bufupdhi - dev->bufupdlo; if (len <= 0 || dev->bufcur < 0) { dev->bufupdlo = dev->bufupdhi = 0; return 0; } shrdtrc(dev,"write rcd %d off %d len %d\n",block,dev->bufupdlo,len); write_retry: /* The write request contains a 2 byte offset and 4 byte id, followed by the data */ SHRD_SET_HDR (hdr, SHRD_WRITE, 0, dev->rmtnum, dev->rmtid, len + 6); store_hw (hdr + SHRD_HDR_SIZE, dev->bufupdlo); store_fw (hdr + SHRD_HDR_SIZE + 2, block); rc = clientSend (dev, hdr, dev->buf + dev->bufupdlo, len); if (rc < 0) { logmsg(_("HHCSH027E %4.4X error writing track %d\n"), dev->devnum, dev->bufcur); dev->bufupdlo = dev->bufupdhi = 0; clientPurge (dev, 0, NULL); return -1; } /* Get the response */ rc = clientRecv (dev, hdr, errmsg, sizeof(errmsg)); SHRD_GET_HDR (hdr, code, status, devnum, id, len); if (rc < 0 || (code & SHRD_ERROR) || (code & SHRD_IOERR)) { if (rc < 0 && retries--) goto write_retry; logmsg(_("HHCSH028E %4.4X remote error writing track %d: " "%2.2X-%2.2X\n"), dev->devnum, dev->bufcur, code, status); dev->bufupdlo = dev->bufupdhi = 0; clientPurge (dev, 0, NULL); return -1; } dev->bufupdlo = dev->bufupdhi = 0; return rc; } /* clientWrite */ /*------------------------------------------------------------------- * Purge cache entries (client side) *-------------------------------------------------------------------*/ static void clientPurge (DEVBLK *dev, int n, void *buf) { cache_lock(CACHE_DEVBUF); dev->rmtpurgen = n; dev->rmtpurge = (FWORD *)buf; cache_scan (CACHE_DEVBUF, clientPurgescan, dev); cache_unlock(CACHE_DEVBUF); } static int clientPurgescan (int *answer, int ix, int i, void *data) { U16 devnum; /* Cached device number */ int trk; /* Cached track */ int p; /* Purge index */ DEVBLK *dev = data; /* -> device block */ UNREFERENCED(answer); SHRD_CACHE_GETKEY(i, devnum, trk); if (devnum == dev->devnum) { if (dev->rmtpurgen == 0) { cache_release (ix, i, 0); shrdtrc(dev,"purge %d\n",trk); } else { for (p = 0; p < dev->rmtpurgen; p++) { if (trk == (int)fetch_fw (dev->rmtpurge[p])) { shrdtrc(dev,"purge %d\n",trk); cache_release (ix, i, 0); break; } } } } return 0; } /* clientPurge */ /*------------------------------------------------------------------- * Connect to the server (client side) *-------------------------------------------------------------------*/ static int clientConnect (DEVBLK *dev, int retry) { int rc; /* Return code */ struct sockaddr *server; /* -> server descriptor */ int flag; /* Flags (version | release) */ int len; /* Length server descriptor */ struct sockaddr_in iserver; /* inet server descriptor */ #if defined( HAVE_SYS_UN_H ) struct sockaddr_un userver; /* unix server descriptor */ #endif int retries = 10; /* Number of retries */ HWORD id; /* Returned identifier */ HWORD comp; /* Returned compression parm */ do { /* Close previous connection */ if (dev->fd >= 0) close_socket (dev->fd); /* Get a socket */ if (dev->localhost) { #if defined( HAVE_SYS_UN_H ) dev->fd = dev->ckdfd[0] = socket (AF_UNIX, SOCK_STREAM, 0); #else // !defined( HAVE_SYS_UN_H ) dev->fd = dev->ckdfd[0] = -1; #endif // defined( HAVE_SYS_UN_H ) if (dev->fd < 0) { logmsg (_("HHCSH029E %4.4X socket failed: %s\n"), dev->devnum, strerror(HSO_errno)); return -1; } #if defined( HAVE_SYS_UN_H ) userver.sun_family = AF_UNIX; sprintf(userver.sun_path, "/tmp/hercules_shared.%d", dev->rmtport); server = (struct sockaddr *)&userver; len = sizeof(userver); #endif // !defined( HAVE_SYS_UN_H ) } else { dev->fd = dev->ckdfd[0] = socket (AF_INET, SOCK_STREAM, 0); if (dev->fd < 0) { logmsg (_("HHCSH030E %4.4X socket failed: %s\n"), dev->devnum, strerror(HSO_errno)); return -1; } iserver.sin_family = AF_INET; iserver.sin_port = htons(dev->rmtport); memcpy(&iserver.sin_addr.s_addr,&dev->rmtaddr,sizeof(struct in_addr)); server = (struct sockaddr *)&iserver; len = sizeof(iserver); } /* Connect to the server */ store_hw (id, dev->rmtid); rc = connect (dev->fd, server, len); shrdtrc(dev,"connect rc=%d errno=%d\n",rc, HSO_errno); if (rc >= 0) { if (!dev->batch) logmsg(_("HHCSH031I %4.4X Connected to %s\n"), dev->devnum, dev->filename); /* Request device connection */ flag = (SHARED_VERSION << 4) | SHARED_RELEASE; rc = clientRequest (dev, id, 2, SHRD_CONNECT, flag, NULL, &flag); if (rc >= 0) { dev->rmtid = fetch_hw (id); dev->rmtrel = flag & 0x0f; } /* * Negotiate compression - top 4 bits have the compression * algorithms we support (00010000 -> libz; 00100000 ->bzip2, * 00110000 -> both) and the bottom 4 bits indicates the * libz parm we want to use when sending data back & forth. * If the server returns `0' back, then we won't use libz to * compress data to the server. What the `compression * algorithms we support' means is that if the data source is * cckd or cfba then the server doesn't have to uncompress * the data for us if we support the compression algorithm. */ if (rc >= 0 && (dev->rmtcomp || dev->rmtcomps)) { rc = clientRequest (dev, comp, 2, SHRD_COMPRESS, (dev->rmtcomps << 4) | dev->rmtcomp, NULL, NULL); if (rc >= 0) dev->rmtcomp = fetch_hw (comp); } } else if (!retry) logmsg(_("HHCSH032E %4.4X Connect %s %d: %s\n"), dev->devnum, dev->filename, HSO_errno, strerror(HSO_errno)); if (rc < 0 && retry) usleep (20000); } while (retry && retries-- && rc < 0); return rc; } /* clientConnect */ /*------------------------------------------------------------------- * Send request to host and get the response * * No data is sent on the request, buf gets the response. * If an uncorrectable connection error occurs -1 is returned. * Otherwise *code and *status is set from the response header * * Since `buf' may be NULL or not very long, response data is * received in a temporary buffer. This enables us to receive * an error message from the remote system. *-------------------------------------------------------------------*/ static int clientRequest (DEVBLK *dev, BYTE *buf, int len, int cmd, int flags, int *code, int *status) { int rc; /* Return code */ int retries = 10; /* Number retries */ BYTE rcode; /* Request return code */ BYTE rstatus; /* Request return status */ U16 rdevnum; /* Request return devnum */ int rid; /* Request return id */ int rlen; /* Request return length */ BYTE hdr[SHRD_HDR_SIZE]; /* Header */ BYTE temp[256]; /* Temporary buffer */ retry : /* Send the request */ SHRD_SET_HDR(hdr, cmd, flags, dev->rmtnum, dev->rmtid, 0); shrdtrc(dev,"client_request %2.2x %2.2x %2.2x %d\n", cmd,flags,dev->rmtnum,dev->rmtid); rc = clientSend (dev, hdr, NULL, 0); if (rc < 0) return rc; /* Receive the response */ rc = clientRecv (dev, hdr, temp, sizeof(temp)); /* Retry recv errors */ if (rc < 0) { if (cmd != SHRD_CONNECT && retries--) { SLEEP (1); clientConnect (dev, 1); goto retry; } return -1; } /* Set code and status */ SHRD_GET_HDR(hdr, rcode, rstatus, rdevnum, rid, rlen); shrdtrc(dev,"client_response %2.2x %2.2x %2.2x %d %d\n", rcode,rstatus,rdevnum,rid,rlen); if (code) *code = rcode; if (status) *status = rstatus; /* Copy the data into the caller's buffer */ if (buf && len > 0 && rlen > 0) memcpy (buf, temp, len < rlen ? len : rlen); return rlen; } /* clientRequest */ /*------------------------------------------------------------------- * Send a request to the host * * `buf' may be NULL * `buflen' is the length in `buf' (should be 0 if `buf' is NULL) * `hdr' may contain additional data; this is detected by the * difference between `buflen' and the length in the header * * If `buf' is adjacent to `hdr' then `buf' should be NULL * *-------------------------------------------------------------------*/ static int clientSend (DEVBLK *dev, BYTE *hdr, BYTE *buf, int buflen) { int rc; /* Return code */ BYTE cmd; /* Header command */ BYTE flag; /* Header flags */ U16 devnum; /* Header device nu */ int len; /* Header length */ int id; /* Header identifier */ int hdrlen; /* Header length + other data*/ int off; /* Offset to buffer data */ BYTE *sendbuf; /* Send buffer */ int sendlen; /* Send length */ BYTE cbuf[SHRD_HDR_SIZE + 65536]; /* Combined buffer */ /* Make buf, buflen consistent if no additional data to be sent */ if (buf == NULL) buflen = 0; else if (buflen == 0) buf = NULL; /* Calculate length of header, may contain additional data */ SHRD_GET_HDR(hdr, cmd, flag, devnum, id, len); shrdtrc(dev,"client_send %2.2x %2.2x %2.2x %d %d\n", cmd,flag,devnum,id,len); hdrlen = SHRD_HDR_SIZE + (len - buflen); off = len - buflen; if (dev->fd < 0) { rc = clientConnect (dev, 1); if (rc < 0) return -1; } #ifdef HAVE_LIBZ /* Compress the buf */ if (dev->rmtcomp != 0 && flag == 0 && off <= SHRD_COMP_MAX_OFF && buflen >= SHARED_COMPRESS_MINLEN) { unsigned long newlen; newlen = 65536 - hdrlen; memcpy (cbuf, hdr, hdrlen); rc = compress2 (cbuf + hdrlen, &newlen, buf, buflen, dev->rmtcomp); if (rc == Z_OK && (int)newlen < buflen) { cmd |= SHRD_COMP; flag = (SHRD_LIBZ << 4) | off; hdr = cbuf; hdrlen += newlen; buf = NULL; buflen = 0; } } #endif /* Combine header and data unless there's no buffer */ if (buflen == 0) { sendbuf = hdr; sendlen = hdrlen; } else { memcpy (cbuf, hdr, hdrlen); memcpy (cbuf + hdrlen, buf, buflen); sendbuf = cbuf; sendlen = hdrlen + buflen; } SHRD_SET_HDR(sendbuf, cmd, flag, devnum, id, (U16)(sendlen - SHRD_HDR_SIZE)); if (cmd & SHRD_COMP) shrdtrc(dev,"client_send %2.2x %2.2x %2.2x %d %d (compressed)\n", cmd, flag, devnum, id, (int)(sendlen - SHRD_HDR_SIZE)); retry: /* Send the header and data */ rc = send (dev->fd, sendbuf, sendlen, 0); if (rc < 0) { rc = clientConnect (dev, 0); if (rc >= 0) goto retry; } /* Process return code */ if (rc < 0) { logmsg(_("HHCSH033E %4.4X send error %d for %2.2X-%2.2X: %s\n"), dev->devnum, HSO_errno, cmd, flag, strerror(HSO_errno)); return -1; } return rc; } /* clientSend */ /*------------------------------------------------------------------- * Receive a response (client side) *-------------------------------------------------------------------*/ static int clientRecv (DEVBLK *dev, BYTE *hdr, BYTE *buf, int buflen) { int rc; /* Return code */ BYTE code; /* Response code */ BYTE status; /* Response status */ U16 devnum; /* Response device number */ int id; /* Response identifier */ int len; /* Response length */ /* Clear the header to zeroes */ memset (hdr, 0, SHRD_HDR_SIZE); /* Return error if not connected */ if (dev->fd < 0) { logmsg(_("HHCSH034E %4.4X Not connected to %s\n"), dev->devnum, dev->filename); return -1; } /* Receive the header */ rc = recvData (dev->fd, hdr, buf, buflen, 0); if (rc < 0) { if (rc != -ENOTCONN) logmsg(_("HHCSH035E %4.4X recv error %d: %s\n"), dev->devnum, -rc, strerror(-rc)); return rc; } SHRD_GET_HDR(hdr, code, status, devnum, id, len); shrdtrc(dev,"client_recv %2.2x %2.2x %2.2x %d %d\n", code,status,devnum,id,len); /* Handle remote logical error */ if (code & SHRD_ERROR) { logmsg(_("HHCSH036E %4.4X Remote error %2.2X-%2.2X: %s\n"), dev->devnum, code, status, buf); len = 0; } /* Reset code/status if response was compressed */ if (len > 0 && code == SHRD_COMP) { code = SHRD_OK; status = 0; } /* Reset the header */ SHRD_SET_HDR(hdr, code, status, devnum, id, len); return len; } /* clientRecv */ /*------------------------------------------------------------------- * Receive data (server or client) *-------------------------------------------------------------------*/ static int recvData(int sock, BYTE *hdr, BYTE *buf, int buflen, int server) { int rc; /* Return code */ int rlen; /* Data length to recv */ int recvlen; /* Total length */ BYTE *recvbuf; /* Receive buffer */ BYTE cmd; /* Header command */ BYTE flag; /* Header flags */ U16 devnum; /* Header device number */ int id; /* Header identifier */ int len; /* Header length */ int comp = 0; /* Compression type */ int off = 0; /* Offset to compressed data */ DEVBLK *dev = NULL; /* For `shrdtrc' */ BYTE cbuf[65536]; /* Compressed buffer */ /* Receive the header */ for (recvlen = 0; recvlen < (int)SHRD_HDR_SIZE; recvlen += rc) { rc = recv (sock, hdr + recvlen, SHRD_HDR_SIZE - recvlen, 0); if (rc < 0) return -HSO_errno; else if (rc == 0) return -HSO_ENOTCONN; } SHRD_GET_HDR (hdr, cmd, flag, devnum, id, len); shrdtrc(dev,"recvData %2.2x %2.2x %2.2x %d %d\n", cmd, flag, devnum, id, len); /* Return if no data */ if (len == 0) return 0; /* Check for compressed data */ if ((server && (cmd & SHRD_COMP)) || (!server && cmd == SHRD_COMP)) { comp = (flag & SHRD_COMP_MASK) >> 4; off = flag & SHRD_COMP_OFF; cmd &= ~SHRD_COMP; flag = 0; recvbuf = cbuf; rlen = len; } else { recvbuf = buf; rlen = buflen < len ? buflen : len; } /* Receive the data */ for (recvlen = 0; recvlen < rlen; recvlen += rc) { rc = recv (sock, recvbuf + recvlen, len - recvlen, 0); if (rc < 0) return -HSO_errno; else if (rc == 0) return -HSO_ENOTCONN; } /* Flush any remaining data */ for (; rlen < len; rlen += rc) { BYTE buf[256]; rc = recv (sock, buf, len - rlen < 256 ? len - rlen : 256, 0); if (rc < 0) return -HSO_errno; else if (rc == 0) return -HSO_ENOTCONN; } /* Check for compression */ if (comp == SHRD_LIBZ) { #ifdef HAVE_LIBZ unsigned long newlen; if (off > 0) memcpy (buf, cbuf, off); newlen = buflen - off; rc = uncompress(buf + off, &newlen, cbuf + off, len - off); if (rc == Z_OK) recvlen = (int)newlen + off; else { logmsg(_("HHCSH037E uncompress error %d, off %d len %d\n"), rc, off, len - off); recvlen = -1; } #else logmsg(_("HHCSH038E data compressed using libz, unsupported\n")); recvlen = -1; #endif } else if (comp == SHRD_BZIP2) { #ifdef CCKD_BZIP2 unsigned int newlen; if (off > 0) memcpy (buf, cbuf, off); newlen = buflen - off; rc = BZ2_bzBuffToBuffDecompress((void *)(buf + off), &newlen, (void *)(cbuf + off), len - off, 0, 0); if (rc == BZ_OK) recvlen = (int)newlen + off; else { logmsg(_("HHCSH039E decompress error %d, off %d len %d\n"), rc, off, len - off); recvlen = -1; } #else logmsg(_("HHCSH040E data compressed using bzip2, unsupported\n")); recvlen = -1; #endif } if (recvlen > 0) { SHRD_SET_HDR (hdr, cmd, flag, devnum, id, recvlen); if (comp) shrdtrc(dev,"recvData %2.2x %2.2x %2.2x %d %d (uncompressed)\n", cmd, flag, devnum, id, recvlen); } return recvlen; } /* recvData */ /*------------------------------------------------------------------- * Process a request (server side) *-------------------------------------------------------------------*/ static void serverRequest (DEVBLK *dev, int ix, BYTE *hdr, BYTE *buf) { int rc; /* Return code */ int i; /* Loop index */ BYTE cmd; /* Header command */ BYTE flag; /* Header flags */ U16 devnum; /* Header device number */ int id; /* Header identifier */ int len; /* Header length */ int code; /* Response code */ int rcd; /* Record to read/write */ int off; /* Offset into record */ /* Extract header information */ SHRD_GET_HDR (hdr, cmd, flag, devnum, id, len); shrdtrc(dev,"server_request [%d] %2.2x %2.2x %2.2x %d %d\n", ix, cmd, flag, devnum, id, len); dev->shrd[ix]->time = time (NULL); switch (cmd) { case SHRD_CONNECT: if (dev->connecting) { serverError (dev, ix, SHRD_ERROR_NOTINIT, cmd, "device not initialized"); break; } if ((flag >> 4) != SHARED_VERSION) { serverError (dev, ix, SHRD_ERROR_BADVERS, cmd, "shared version mismatch"); break; } dev->shrd[ix]->release = flag & 0x0f; SHRD_SET_HDR (hdr, 0, (SHARED_VERSION << 4) | SHARED_RELEASE, dev->devnum, id, 2); store_hw (buf, id); serverSend (dev, ix, hdr, buf, 2); break; case SHRD_DISCONNECT: SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 0); serverSend (dev, ix, hdr, NULL, 0); dev->shrd[ix]->disconnect = 1; obtain_lock (&dev->lock); /* Make the device available if this system active on it */ if (dev->ioactive == id) { if (!dev->suspended) { dev->busy = 0; dev->ioactive = DEV_SYS_NONE; } else dev->ioactive = DEV_SYS_LOCAL; if (dev->iowaiters) signal_condition (&dev->iocond); } release_lock (&dev->lock); break; case SHRD_START: case SHRD_RESUME: obtain_lock (&dev->lock); /* If the device is suspended locally then grab it */ if (dev->ioactive == DEV_SYS_LOCAL && dev->suspended && !dev->reserved) dev->ioactive = id; /* Check if the device is busy */ if (dev->ioactive != id && dev->ioactive != DEV_SYS_NONE) { shrdtrc(dev,"server_request busy id=%d ioactive=%d reserved=%d\n", id,dev->ioactive,dev->reserved); /* If the `nowait' bit is on then respond `busy' */ if (flag & SHRD_NOWAIT) { release_lock (&dev->lock); SHRD_SET_HDR (hdr, SHRD_BUSY, 0, dev->devnum, id, 0); serverSend (dev, ix, hdr, NULL, 0); break; } dev->shrd[ix]->waiting = 1; /* Wait while the device is busy by the local system */ while (dev->ioactive == DEV_SYS_LOCAL && !dev->suspended) { dev->iowaiters++; wait_condition (&dev->iocond, &dev->lock); dev->iowaiters--; } /* Return with the `waiting' bit on if busy by a remote system */ if (dev->ioactive != DEV_SYS_NONE && dev->ioactive != DEV_SYS_LOCAL) { release_lock (&dev->lock); break; } dev->shrd[ix]->waiting = 0; } /* Make this system active on the device */ dev->ioactive = id; dev->busy = 1; dev->syncio_active = dev->syncio_retry = 0; sysblk.shrdcount++; shrdtrc(dev,"server_request active id=%d\n", id); release_lock(&dev->lock); /* Call the i/o start or resume exit */ if (cmd == SHRD_START && dev->hnd->start) (dev->hnd->start) (dev); else if (cmd == SHRD_RESUME && dev->hnd->resume) (dev->hnd->resume) (dev); /* Get the purge list */ if (dev->shrd[ix]->purgen == 0) code = len = 0; else { code = SHRD_PURGE; if (dev->shrd[ix]->purgen < 0) len = 0; else len = 4 * dev->shrd[ix]->purgen; } /* Send the response */ SHRD_SET_HDR (hdr, code, 0, dev->devnum, id, len); rc = serverSend (dev, ix, hdr, (BYTE *)dev->shrd[ix]->purge, len); if (rc >= 0) dev->shrd[ix]->purgen = 0; break; case SHRD_END: case SHRD_SUSPEND: /* Must be active on the device for this command */ if (dev->ioactive != id) { serverError (dev, ix, SHRD_ERROR_NOTACTIVE, cmd, "not active on this device"); break; } /* Call the I/O end/suspend exit */ if (cmd == SHRD_END && dev->hnd->end) (dev->hnd->end) (dev); else if (cmd == SHRD_SUSPEND && dev->hnd->suspend) (dev->hnd->suspend) (dev); obtain_lock (&dev->lock); /* Make the device available if it's not reserved */ if (!dev->reserved) { /* If locally suspended then return the device to local */ if (dev->suspended) { dev->ioactive = DEV_SYS_LOCAL; dev->busy = 1; } else { dev->ioactive = DEV_SYS_NONE; dev->busy = 0; } /* Reset any `waiting' bits */ for (i = 0; i < SHARED_MAX_SYS; i++) if (dev->shrd[i]) dev->shrd[i]->waiting = 0; /* Notify any waiters */ if (dev->iowaiters) signal_condition (&dev->iocond); } shrdtrc(dev,"server_request inactive id=%d\n", id); release_lock (&dev->lock); /* Send response back */ SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 0); serverSend (dev, ix, hdr, NULL, 0); break; case SHRD_RESERVE: /* Must be active on the device for this command */ if (dev->ioactive != id) { serverError (dev, ix, SHRD_ERROR_NOTACTIVE, cmd, "not active on this device"); break; } obtain_lock (&dev->lock); dev->reserved = 1; release_lock (&dev->lock); shrdtrc(dev,"server_request reserved id=%d\n", id); /* Call the I/O reserve exit */ if (dev->hnd->reserve) (dev->hnd->reserve) (dev); /* Send response back */ SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 0); serverSend (dev, ix, hdr, NULL, 0); break; case SHRD_RELEASE: /* Must be active on the device for this command */ if (dev->ioactive != id) { serverError (dev, ix, SHRD_ERROR_NOTACTIVE, cmd, "not active on this device"); break; } /* Call the I/O release exit */ if (dev->hnd->release) (dev->hnd->release) (dev); obtain_lock (&dev->lock); dev->reserved = 0; release_lock (&dev->lock); shrdtrc(dev,"server_request released id=%d\n", id); /* Send response back */ SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 0); serverSend (dev, ix, hdr, NULL, 0); break; case SHRD_READ: /* Must be active on the device for this command */ if (dev->ioactive != id) { serverError (dev, ix, SHRD_ERROR_NOTACTIVE, cmd, "not active on this device"); break; } /* Set the compressions client is willing to accept */ dev->comps = dev->shrd[ix]->comps; dev->comp = dev->compoff = 0; /* Call the I/O read exit */ rcd = (int)fetch_fw (buf); rc = (dev->hnd->read) (dev, rcd, &flag); shrdtrc(dev,"server_request read rcd %d flag %2.2x rc=%d\n", rcd, flag, rc); if (rc < 0) code = SHRD_IOERR; else { code = dev->comp ? SHRD_COMP : 0; flag = (dev->comp << 4) | dev->compoff; } /* Reset compression stuff */ dev->comps = dev->comp = dev->compoff = 0; SHRD_SET_HDR (hdr, code, flag, dev->devnum, id, dev->buflen); serverSend (dev, ix, hdr, dev->buf, dev->buflen); break; case SHRD_WRITE: /* Must be active on the device for this command */ if (dev->ioactive != id) { serverError (dev, ix, SHRD_ERROR_NOTACTIVE, cmd, "not active on this device"); break; } /* Call the I/O write exit */ off = fetch_hw (buf); rcd = fetch_fw (buf + 2); rc = (dev->hnd->write) (dev, rcd, off, buf + 6, len - 6, &flag); shrdtrc(dev,"server_request write rcd %d off %d len %d flag %2.2x rc=%d\n", rcd, off, len - 6, flag, rc); if (rc < 0) code = SHRD_IOERR; else code = 0; /* Send response back */ SHRD_SET_HDR (hdr, code, flag, dev->devnum, id, 0); serverSend (dev, ix, hdr, NULL, 0); break; case SHRD_SENSE: /* Must be active on the device for this command */ if (dev->ioactive != id) { serverError (dev, ix, SHRD_ERROR_NOTACTIVE, cmd, "not active on this device"); break; } /* Send the sense */ SHRD_SET_HDR (hdr, 0, CSW_CE | CSW_DE, dev->devnum, id, dev->numsense); serverSend (dev, ix, hdr, dev->sense, dev->numsense); memset (dev->sense, 0, sizeof(dev->sense)); dev->sns_pending = 0; break; case SHRD_QUERY: switch (flag) { case SHRD_USED: if (dev->hnd->used) rc = (dev->hnd->used) (dev); else rc = 0; store_fw (buf, rc); SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 4); serverSend (dev, ix, hdr, buf, 4); break; case SHRD_DEVCHAR: SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, dev->numdevchar); serverSend (dev, ix, hdr, dev->devchar, dev->numdevchar); break; case SHRD_DEVID: SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, dev->numdevid); serverSend (dev, ix, hdr, dev->devid, dev->numdevid); break; case SHRD_CKDCYLS: store_fw (buf, dev->ckdcyls); SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 4); serverSend (dev, ix, hdr, buf, 4); break; case SHRD_FBAORIGIN: store_fw (buf, dev->fbaorigin); SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 4); serverSend (dev, ix, hdr, buf, 4); break; case SHRD_FBANUMBLK: store_fw (buf, dev->fbanumblk); SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 4); serverSend (dev, ix, hdr, buf, 4); break; case SHRD_FBABLKSIZ: store_fw (buf, dev->fbablksiz); SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 4); serverSend (dev, ix, hdr, buf, 4); break; default: serverError (dev, ix, SHRD_ERROR_INVALID, cmd, "invalid query request"); break; } /* switch (flag) for SHRD_QUERY */ break; case SHRD_COMPRESS: #ifdef HAVE_LIBZ dev->shrd[ix]->comp = (flag & 0x0f); store_hw (buf, dev->shrd[ix]->comp); #else store_hw (buf, 0); #endif dev->shrd[ix]->comps = (flag & 0xf0) >> 4; SHRD_SET_HDR (hdr, 0, 0, dev->devnum, id, 2); serverSend (dev, ix, hdr, buf, 2); break; default: serverError (dev, ix, SHRD_ERROR_INVALID, cmd, "invalid request"); break; } /* switch (cmd) */ } /* serverRequest */ /*------------------------------------------------------------------- * Locate the SHRD block for a socket (server side) *-------------------------------------------------------------------*/ static int serverLocate (DEVBLK *dev, int id, int *avail) { int i; /* Loop index */ if (avail) *avail = -1; for (i = 0; i < SHARED_MAX_SYS; i++) { if (dev->shrd[i]) { if (dev->shrd[i]->id == id) return i; } else if (avail && *avail < 0) *avail = i; } return -1; } /* serverLocate */ /*------------------------------------------------------------------- * Return a new Identifier (server side) *-------------------------------------------------------------------*/ static int serverId (DEVBLK *dev) { int i; /* Loop index */ int id; /* Identifier */ do { ++dev->shrdid; dev->shrdid &= 0xffff; if (dev->shrdid == DEV_SYS_LOCAL || dev->shrdid == DEV_SYS_NONE) dev->shrdid = 1; id = dev->shrdid; for (i = 0; i < SHARED_MAX_SYS; i++) if (dev->shrd[i] && dev->shrd[i]->id == id) break; } while (i < SHARED_MAX_SYS); return id; } /* serverId */ /*------------------------------------------------------------------- * Respond with an error message (server side) *-------------------------------------------------------------------*/ static int serverError (DEVBLK *dev, int ix, int code, int status, char *msg) { int rc; /* Return code */ size_t len; /* Message length */ BYTE hdr[SHRD_HDR_SIZE]; /* Header */ /* Get message length */ len = strlen(msg) + 1; if (len > SHARED_MAX_MSGLEN) len = SHARED_MAX_MSGLEN; SHRD_SET_HDR (hdr, code, status, dev ? dev->devnum : 0, ix < 0 ? 0 : dev->shrd[ix]->id, (U16)len); shrdtrc(dev,"server_error %2.2x %2.2x: %s\n", code, status, msg); rc = serverSend (dev, ix, hdr, (BYTE *)msg, (int)len); return rc; } /* serverError */ /*------------------------------------------------------------------- * Send data (server side) *-------------------------------------------------------------------*/ static int serverSend (DEVBLK *dev, int ix, BYTE *hdr, BYTE *buf, int buflen) { int rc; /* Return code */ int sock; /* Socket number */ BYTE code; /* Header code */ BYTE status; /* Header status */ U16 devnum; /* Header device number */ int id; /* Header identifier */ int len; /* Header length */ int hdrlen; /* Header length + other data*/ BYTE *sendbuf = NULL; /* Send buffer */ int sendlen; /* Send length */ BYTE cbuf[SHRD_HDR_SIZE + 65536]; /* Combined buffer */ /* Make buf, buflen consistent if no additional data to be sent */ if (buf == NULL) buflen = 0; else if (buflen == 0) buf = NULL; /* Calculate length of header, may contain additional data */ SHRD_GET_HDR(hdr, code, status, devnum, id, len); hdrlen = SHRD_HDR_SIZE + (len - buflen); sendlen = hdrlen + buflen; /* Check if buf is adjacent to the header */ if (buf && hdr + hdrlen == buf) { hdrlen += buflen; buf = NULL; buflen = 0; } /* Send only the header buffer if `buf' is empty */ if (buflen == 0) sendbuf = hdr; /* Get socket number; if `ix' < 0 we don't have a device yet */ if (ix >= 0) sock = dev->shrd[ix]->fd; else { sock = -ix; dev = NULL; } shrdtrc(dev,"server_send %2.2x %2.2x %2.2x %d %d\n", code, status, devnum, id, len); #ifdef HAVE_LIBZ /* Compress the buf */ if (ix >= 0 && dev->shrd[ix]->comp != 0 && code == SHRD_OK && status == 0 && hdrlen - SHRD_HDR_SIZE <= SHRD_COMP_MAX_OFF && buflen >= SHARED_COMPRESS_MINLEN) { unsigned long newlen; int off = hdrlen - SHRD_HDR_SIZE; sendbuf = cbuf; newlen = sizeof(cbuf) - hdrlen; memcpy (cbuf, hdr, hdrlen); rc = compress2 (cbuf + hdrlen, &newlen, buf, buflen, dev->shrd[ix]->comp); if (rc == Z_OK && (int)newlen < buflen) { /* Setup to use the compressed buffer */ sendlen = hdrlen + newlen; buflen = 0; code = SHRD_COMP; status = (SHRD_LIBZ << 4) | off; SHRD_SET_HDR (cbuf, code, status, devnum, id, newlen + off); shrdtrc(dev,"server_send %2.2x %2.2x %2.2x %d %d (compressed)\n", code,status,devnum,id,(int)newlen+off); } } #endif /* Build combined (hdr + data) buffer */ if (buflen > 0) { sendbuf = cbuf; memcpy (cbuf, hdr, hdrlen); memcpy (cbuf + hdrlen, buf, buflen); } /* Send the combined header and data */ rc = send (sock, sendbuf, sendlen, 0); /* Process return code */ if (rc < 0) { logmsg(_("HHCSH041E %4.4X send error %d id=%d: %s\n"), dev->devnum, HSO_errno, id, strerror(HSO_errno)); dev->shrd[ix]->disconnect = 1; } return rc; } /* serverSend */ /*------------------------------------------------------------------- * Determine if a client can be disconnected (server side) *-------------------------------------------------------------------*/ static int serverDisconnectable (DEVBLK *dev, int ix) { if (dev->shrd[ix]->waiting || dev->shrd[ix]->pending || dev->ioactive == dev->shrd[ix]->id) return 0; else return 1; } /* serverDisconnectable */ /*------------------------------------------------------------------- * Disconnect a client (server side) * dev->lock *must* be held *-------------------------------------------------------------------*/ static void serverDisconnect (DEVBLK *dev, int ix) { int id; /* Client identifier */ int i; /* Loop index */ id = dev->shrd[ix]->id; //FIXME: Handle a disconnected busy client better // Perhaps a disconnect timeout value... this will // give the client time to reconnect. /* If the device is active by the client then extricate it. This is *not* a good situation */ if (dev->ioactive == id) { logmsg(_("HHCSH042W %4.4X busy client being removed id=%d %s\n"), dev->devnum, id, dev->reserved ? "reserved" : ""); /* Call the I/O release exit if reserved by this client */ if (dev->reserved && dev->hnd->release) (dev->hnd->release) (dev); /* Call the channel program end exit */ if (dev->hnd->end) (dev->hnd->end) (dev); /* Reset any `waiting' bits */ for (i = 0; i < SHARED_MAX_SYS; i++) if (dev->shrd[i]) dev->shrd[i]->waiting = 0; /* Make the device available */ if (dev->suspended) { dev->ioactive = DEV_SYS_LOCAL; dev->busy = 1; } else { dev->ioactive = DEV_SYS_NONE; dev->busy = 0; } /* Notify any waiters */ if (dev->iowaiters) signal_condition (&dev->iocond); } logmsg(_("HHCSH043I %s disconnected from %4.4X id=%d\n"), dev->shrd[ix]->ipaddr, dev->devnum, id); /* Release the SHRD block */ close_socket (dev->shrd[ix]->fd); free (dev->shrd[ix]->ipaddr); free (dev->shrd[ix]); dev->shrd[ix] = NULL; dev->shrdconn--; } /* serverDisconnect */ /*------------------------------------------------------------------- * Return client ip *-------------------------------------------------------------------*/ static char *clientip (int sock) { int rc; /* Return code */ struct sockaddr_in client; /* Client address structure */ socklen_t namelen; /* Length of client structure*/ namelen = sizeof(client); rc = getpeername (sock, (struct sockaddr *)&client, &namelen); return inet_ntoa(client.sin_addr); } /* clientip */ /*------------------------------------------------------------------- * Find device by device number *-------------------------------------------------------------------*/ static DEVBLK *findDevice (U16 devnum) { DEVBLK *dev; /* -> Device block */ for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev) if (dev->devnum == devnum) break; return dev; } /* findDevice */ /*------------------------------------------------------------------- * Connect a new client *-------------------------------------------------------------------*/ static void *serverConnect (int *psock) { int csock; /* Connection socket */ int rc; /* Return code */ BYTE cmd; /* Request command */ BYTE flag; /* Request flag */ U16 devnum; /* Request device number */ int id; /* Request id */ int len; /* Request data length */ int ix; /* Client index */ DEVBLK *dev=NULL; /* -> Device block */ time_t now; /* Current time */ fd_set selset; /* Read bit map for select */ int maxfd; /* Max fd for select */ struct timeval wait; /* Wait time for select */ BYTE hdr[SHRD_HDR_SIZE + 65536]; /* Header + buffer */ BYTE *buf = hdr + SHRD_HDR_SIZE; /* Buffer */ char *ipaddr = NULL; /* IP addr of connected peer */ csock = *psock; free (psock); ipaddr = clientip(csock); shrdtrc(dev,"server_connect %s sock %d\n",ipaddr,csock); rc = recvData(csock, hdr, buf, 65536, 1); if (rc < 0) { logmsg(_("HHCSH0474 %s connect failed\n"), ipaddr); close_socket (csock); return NULL; } SHRD_GET_HDR (hdr, cmd, flag, devnum, id, len); /* Error if not a connect request */ if (id == 0 && cmd != SHRD_CONNECT) { serverError (NULL, -csock, SHRD_ERROR_NOTCONN, cmd, "not a connect request"); close_socket (csock); return NULL; } /* Locate the device */ dev = findDevice (devnum); /* Error if device not found */ if (dev == NULL) { serverError (NULL, -csock, SHRD_ERROR_NODEVICE, cmd, "device not found"); close_socket (csock); return NULL; } /* Obtain the device lock */ obtain_lock (&dev->lock); /* Find an available slot for the connection */ rc = serverLocate (dev, id, &ix); /* Error if already connected */ if (rc >= 0) { release_lock (&dev->lock); serverError (NULL, -csock, SHRD_ERROR_NODEVICE, cmd, "already connected"); close_socket (csock); return NULL; } /* Error if no available slot */ if (ix < 0) { release_lock (&dev->lock); serverError (NULL, -csock, SHRD_ERROR_NOTAVAIL, cmd, "too many connections"); close_socket (csock); return NULL; } /* Obtain SHRD block */ dev->shrd[ix] = calloc (sizeof(SHRD), 1); /* Error if not obtained */ if (dev->shrd[ix] == NULL) { release_lock (&dev->lock); serverError (NULL, -csock, SHRD_ERROR_NOMEM, cmd, "calloc() failure"); close_socket (csock); return NULL; } /* Initialize the SHRD block */ dev->shrd[ix]->pending = 1; dev->shrd[ix]->havehdr = 1; if (id == 0) id = serverId (dev); dev->shrd[ix]->id = id; dev->shrd[ix]->fd = csock; dev->shrd[ix]->ipaddr = strdup(ipaddr); dev->shrd[ix]->time = time (NULL); dev->shrd[ix]->purgen = -1; dev->shrdconn++; SHRD_SET_HDR (dev->shrd[ix]->hdr, cmd, flag, devnum, id, len); logmsg (_("HHCSH053I %s connected to %4.4X id=%d\n"), ipaddr, devnum, id); /* Return if device thread already active */ if (dev->shrdtid) { if (dev->shrdwait) { signal_thread (dev->shrdtid, SIGUSR2); } release_lock (&dev->lock); return NULL; } dev->shrdtid = thread_id(); /* This thread will be the shared device thread */ logmsg (_("HHCSH045I Shared device %4.4X thread started: " "tid="TIDPAT", pid=%d\n"), dev->devnum, thread_id(), getpid()); while (dev->shrdconn) { FD_ZERO (&selset); maxfd = -1; /* Get the current time */ now = time (NULL); for (ix = 0; ix < SHARED_MAX_SYS; ix++) { if (dev->shrd[ix]) { /* Exit loop if pending and not waiting */ if (dev->shrd[ix]->pending && !dev->shrd[ix]->waiting) break; /* Disconnect if not a valid socket */ if ( !socket_is_socket( dev->shrd[ix]->fd ) ) dev->shrd[ix]->disconnect = 1; /* See if the connection can be timed out */ else if (now - dev->shrd[ix]->time > SHARED_TIMEOUT && serverDisconnectable (dev, ix)) dev->shrd[ix]->disconnect = 1; /* Disconnect if the disconnect bit is set */ if (dev->shrd[ix]->disconnect) serverDisconnect (dev, ix); /* Otherwise set the fd if not waiting */ else if (!dev->shrd[ix]->waiting) { FD_SET (dev->shrd[ix]->fd, &selset); if (dev->shrd[ix]->fd >= maxfd) maxfd = dev->shrd[ix]->fd + 1; shrdtrc(dev,"select set %d id=%d\n",dev->shrd[ix]->fd,dev->shrd[ix]->id); } } } /* Wait for a request if no pending requests */ if (ix >= SHARED_MAX_SYS) { /* Exit thread if nothing to select */ if (maxfd < 0) continue; /* Wait for a file descriptor to become busy */ wait.tv_sec = 10; /*SHARED_SELECT_WAIT;*/ wait.tv_usec = 0; release_lock (&dev->lock); dev->shrdwait = 1; rc = select ( maxfd, &selset, NULL, NULL, &wait ); dev->shrdwait = 0; obtain_lock (&dev->lock); shrdtrc(dev,"select rc %d\n",rc); if (rc == 0) continue; if (rc < 0 ) { if (HSO_errno == HSO_EINTR || HSO_errno == HSO_EBADF) continue; logmsg(_("HHCSH046E select: %s\n"), strerror(HSO_errno)); break; } /* Find any pending requests */ for (ix = 0; ix < SHARED_MAX_SYS; ix++) { if (dev->shrd[ix] && FD_ISSET(dev->shrd[ix]->fd, &selset)) { dev->shrd[ix]->pending = 1; shrdtrc(dev,"select isset %d id=%d\n",dev->shrd[ix]->fd,dev->shrd[ix]->id); } } continue; } /* Found a pending request */ release_lock (&dev->lock); shrdtrc(dev,"select ready %d id=%d\n",dev->shrd[ix]->fd,dev->shrd[ix]->id); if (dev->shrd[ix]->havehdr) { /* Copy the saved start/resume packet */ memcpy (hdr, dev->shrd[ix]->hdr, SHRD_HDR_SIZE); dev->shrd[ix]->havehdr = dev->shrd[ix]->waiting = 0; } else { /* Read the request packet */ rc = recvData (dev->shrd[ix]->fd, hdr, buf, 65536, 1); if (rc < 0) { logmsg(_("HHCSH047E %4.4X %s recv error id=%d\n"), dev->devnum, dev->shrd[ix]->ipaddr, dev->shrd[ix]->id); dev->shrd[ix]->disconnect = 1; dev->shrd[ix]->pending = 0; obtain_lock (&dev->lock); continue; } } /* Process the request */ serverRequest (dev, ix, hdr, buf); obtain_lock (&dev->lock); /* If the `waiting' bit is on then the start/resume request failed because the device is busy on some other remote system. We only need to save the header because the data is ignored for start/resume. */ if (dev->shrd[ix]->waiting) { memcpy (dev->shrd[ix]->hdr, hdr, SHRD_HDR_SIZE); dev->shrd[ix]->havehdr = 1; } else dev->shrd[ix]->pending = 0; } dev->shrdtid = 0; release_lock (&dev->lock); logmsg (_("HHCSH048I Shared device %4.4X thread stopping\n"), dev->devnum); return NULL; } /* serverConnect */ /*------------------------------------------------------------------- * General trace routine for shared devices *-------------------------------------------------------------------*/ static void shrdtrc (DEVBLK *dev, char *msg, ...) { int dt; struct timeval tv; SHRD_TRACE s; va_list vl; dt = (dev != NULL && (dev->ccwtrace||dev->ccwstep)); if (dt == 0 && sysblk.shrdtrace == 0) return; va_start(vl,msg); gettimeofday(&tv, NULL); sprintf ((char *)s, "%6.6ld" "." "%6.6ld %4.4X:", tv.tv_sec, (long)(tv.tv_usec), dev ? dev->devnum : 0); vsnprintf ((char *)s + strlen(s), sizeof(s) - strlen(s), msg, vl); if (dt) { logmsg (s+14); } if (sysblk.shrdtrace) { SHRD_TRACE *p = sysblk.shrdtracep++; if (p >= sysblk.shrdtracex) { p = sysblk.shrdtrace; sysblk.shrdtracep = p + 1; } if (p) memcpy(p, s, sizeof(*p)); } } /* shrdtrc */ /*------------------------------------------------------------------- * Shared device server *-------------------------------------------------------------------*/ DLL_EXPORT void *shared_server (void *arg) { int rc; /* Return code */ int hi; /* Hi fd for select */ int lsock; /* inet socket for listening */ int usock; /* unix socket for listening */ int rsock; /* Ready socket */ int csock; /* Socket for conversation */ int *psock; /* Pointer to socket */ struct sockaddr_in server; /* Server address structure */ #if defined( HAVE_SYS_UN_H ) struct sockaddr_un userver; /* Unix address structure */ #endif int optval; /* Argument for setsockopt */ fd_set selset; /* Read bit map for select */ TID tid; /* Negotiation thread id */ UNREFERENCED(arg); /* Display thread started message on control panel */ logmsg (_("HHCSH049I Shared device %d" "." "%d thread started: " "tid="TIDPAT", pid=%d\n"), SHARED_VERSION, SHARED_RELEASE, thread_id(), getpid()); /* Obtain a internet socket */ lsock = socket (AF_INET, SOCK_STREAM, 0); if (lsock < 0) { logmsg(_("HHCSH050E inet socket: %s\n"), strerror(HSO_errno)); return NULL; } /* Obtain a unix socket */ #if defined( HAVE_SYS_UN_H ) usock = socket (AF_UNIX, SOCK_STREAM, 0); if (usock < 0) { logmsg(_("HHCSH051W unix socket: %s\n"), strerror(HSO_errno)); } #else usock = -1; #endif /* Allow previous instance of socket to be reused */ optval = 1; setsockopt (lsock, SOL_SOCKET, SO_REUSEADDR, (GETSET_SOCKOPT_T*)&optval, sizeof(optval)); /* Prepare the sockaddr structure for the bind */ memset (&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = sysblk.shrdport; server.sin_port = htons(server.sin_port); /* Attempt to bind the internet socket to the port */ while (1) { rc = bind (lsock, (struct sockaddr *)&server, sizeof(server)); if (rc == 0 || HSO_errno != HSO_EADDRINUSE) break; logmsg (_("HHCSH052W Waiting for port %u to become free\n"), sysblk.shrdport); SLEEP(10); } /* end while */ if (rc != 0) { logmsg(_("HHCSH053E inet bind: %s\n"), strerror(HSO_errno)); close_socket(lsock); close_socket(usock); return NULL; } #if defined( HAVE_SYS_UN_H ) /* Bind the unix socket */ if (usock >= 0) { userver.sun_family = AF_UNIX; sprintf(userver.sun_path, "/tmp/hercules_shared.%d", sysblk.shrdport); unlink(userver.sun_path); fchmod (usock, 0700); rc = bind (usock, (struct sockaddr *)&userver, sizeof(userver)); if (rc < 0) { logmsg(_("HHCSH054W unix bind: %s\n"), strerror(errno)); close(usock); usock = -1; } } #endif // defined( HAVE_SYS_UN_H ) /* Put the sockets into listening state */ rc = listen (lsock, SHARED_MAX_SYS); if (rc < 0) { logmsg(_("HHCSH055E inet listen: %s\n"), strerror(HSO_errno)); close_socket(lsock); close_socket(usock); return NULL; } if (usock >= 0) { rc = listen (usock, SHARED_MAX_SYS); if (rc < 0) { logmsg(_("HHCSH056W unix listen: %s\n"), strerror(HSO_errno)); close_socket(usock); usock = -1; } } sysblk.shrdtid = thread_id(); csock = -1; if (lsock < usock) hi = usock + 1; else hi = lsock + 1; logmsg(_("HHCSH057I Waiting for shared device requests on port %u\n"), sysblk.shrdport); /* Handle connection requests and attention interrupts */ while (!sysblk.shutdown) { /* Initialize the select parameters */ FD_ZERO (&selset); FD_SET (lsock, &selset); if (usock >= 0) FD_SET (usock, &selset); /* Wait for a file descriptor to become ready */ rc = select ( hi, &selset, NULL, NULL, NULL ); if (rc == 0) continue; if (rc < 0 ) { if (HSO_errno == HSO_EINTR) continue; logmsg(_("HHCSH058E select: %s\n"), strerror(HSO_errno)); break; } /* If a client connection request has arrived then accept it */ if (FD_ISSET(lsock, &selset)) rsock = lsock; else if (usock >= 0 && FD_ISSET(usock, &selset)) rsock = usock; else rsock = -1; if (rsock > 0) { /* Accept a connection and create conversation socket */ csock = accept (rsock, NULL, NULL); if (csock < 0) { logmsg(_("HHCSH059E accept: %s\n"), strerror(HSO_errno)); continue; } psock = malloc (sizeof (csock)); if (psock == NULL) { logmsg(_("HHCSH060E malloc size %d: %s\n"), sizeof(csock), strerror(HSO_errno)); close_socket (csock); continue; } *psock = csock; /* Create a thread to complete the client connection */ if ( create_thread (&tid, DETACHED, serverConnect, psock, "serverConnect") ) { logmsg(_("HHCSH061E serverConnect create_thread: %s\n"), strerror(HSO_errno)); close_socket (csock); } } /* end if(rsock) */ } /* end while */ /* Close the listening sockets */ close_socket (lsock); #if defined( HAVE_SYS_UN_H ) if (usock >= 0) { close_socket (usock); unlink(userver.sun_path); } #endif sysblk.shrdtid = 0; return NULL; } /* end function shared_server */ /*------------------------------------------------------------------- * Shared device command processor *-------------------------------------------------------------------*/ DLL_EXPORT int shared_cmd(int argc, char *argv[], char *cmdline) { char buf[256]; char *kw, *op, c; UNREFERENCED(cmdline); /* Get keyword and operand */ if (argc != 2 || strlen(argv[1]) > 255) { logmsg (_("HHCSH062E Invalid or missing argument 1\n")); return 0; } strcpy (buf, argv[1]); kw = strtok (buf, "="); op = strtok (NULL, " \t"); if (kw == NULL) { logmsg (_("HHCSH063E Invalid or missing keyword 2\n")); return 0; } if (strcasecmp(kw, "trace") == 0) { int n; SHRD_TRACE *s, *p, *x, *i; s = sysblk.shrdtrace; p = sysblk.shrdtracep; x = sysblk.shrdtracex; n = sysblk.shrdtracen; /* Get a new trace table if an operand was specified */ if (op) { if (sscanf (op, "%d%c", &n, &c) != 1) { logmsg (_("HHCSH064E Invalid or missing value %s\n"),op); return 0; } if (s != NULL) { sysblk.shrdtrace = sysblk.shrdtracex = sysblk.shrdtracep = NULL; SLEEP (1); free (s); } sysblk.shrdtrace = sysblk.shrdtracex = sysblk.shrdtracep = NULL; sysblk.shrdtracen = 0; if (n > 0) { s = calloc (sizeof(SHRD_TRACE), n); if (s == NULL) { logmsg (_("HHCSH065E calloc() size=%d: %s\n"), sizeof(SHRD_TRACE) * n, strerror(errno)); return 0; } sysblk.shrdtracen = n; sysblk.shrdtrace = sysblk.shrdtracep = s; sysblk.shrdtracex = s + n; } return 0; } /* Print the trace table */ sysblk.shrdtrace = sysblk.shrdtracex = sysblk.shrdtracep = NULL; i = p; SLEEP(1); do { if (i[0] != '\0') logmsg ("%s",(char *)i); if (++i >= x) i = s; } while (i != p); memset (s, 0, n * sizeof(SHRD_TRACE)); sysblk.shrdtrace = s; sysblk.shrdtracep = s; sysblk.shrdtracex = x; sysblk.shrdtracen = n; } else { logmsg (_("HHCSH066E Invalid or missing keyword %s\n"), kw); return 0; } return 0; } DEVHND shared_ckd_device_hndinfo = { &shared_ckd_init, /* Device Initialisation */ &ckddasd_execute_ccw, /* Device CCW execute */ &shared_ckd_close, /* Device Close */ &ckddasd_query_device, /* Device Query */ &shared_start, /* Device Start channel pgm */ &shared_end, /* Device End channel pgm */ &shared_start, /* Device Resume channel pgm */ &shared_end, /* Device Suspend channel pgm */ &shared_ckd_read, /* Device Read */ &shared_ckd_write, /* Device Write */ &shared_used, /* Device Query used */ &shared_reserve, /* Device Reserve */ &shared_release, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ &ckddasd_hsuspend, /* Hercules suspend */ &ckddasd_hresume /* Hercules resume */ }; DEVHND shared_fba_device_hndinfo = { &shared_fba_init, /* Device Initialisation */ &fbadasd_execute_ccw, /* Device CCW execute */ &shared_fba_close, /* Device Close */ &fbadasd_query_device, /* Device Query */ &shared_start, /* Device Start channel pgm */ &shared_end, /* Device End channel pgm */ &shared_start, /* Device Resume channel pgm */ &shared_end, /* Device Suspend channel pgm */ &shared_ckd_read, /* Device Read */ &shared_ckd_write, /* Device Write */ &shared_used, /* Device Query used */ &shared_reserve, /* Device Reserve */ &shared_release, /* Device Release */ NULL, /* Device Attention */ NULL, /* Immediate CCW Codes */ NULL, /* Signal Adapter Input */ NULL, /* Signal Adapter Output */ &fbadasd_hsuspend, /* Hercules suspend */ &fbadasd_hresume /* Hercules resume */ }; #else int shared_update_notify (DEVBLK *dev, int block) { UNREFERENCED(dev); UNREFERENCED(block); return 0; } int shared_ckd_init (DEVBLK *dev, int argc, BYTE *argv[] ) { UNREFERENCED(dev); UNREFERENCED(argc); UNREFERENCED(argv); return -1; } int shared_fba_init (DEVBLK *dev, int argc, BYTE *argv[] ) { UNREFERENCED(dev); UNREFERENCED(argc); UNREFERENCED(argv); return -1; } void *shared_server (void *arg) { UNREFERENCED(arg); logmsg (_("HHCSH999E OPTION_SHARED_DEVICES not defined")); return NULL; } int shared_cmd(int argc, char *argv[], char *cmdline); UNREFERENCED(cmdline); UNREFERENCED(argc); UNREFERENCED(argv); logmsg (_("HHCSH999E OPTION_SHARED_DEVICES not defined")); return 0; } #endif /*defined(OPTION_SHARED_DEVICES)*/ hercules-3.12/hsys.c0000664000175000017500000000267712564723224011351 00000000000000/* HSYS.C (c) Copyright Roger Bowler, 1999-2012 */ /* Hercules hsys Header */ #include "hstdinc.h" #define _HSYS_C_ #include "hercules.h" DLL_EXPORT SYSBLK sysblk; #if defined(EXTERNALGUI) DLL_EXPORT int extgui = 0; #endif #if defined(OPTION_W32_CTCI) DLL_EXPORT int (*debug_tt32_stats)(int) = NULL; DLL_EXPORT void (*debug_tt32_tracing)(int) = NULL; #endif #if defined(OPTION_DYNAMIC_LOAD) DLL_EXPORT void *(*panel_command) (void *); DLL_EXPORT void (*panel_display) (void); DLL_EXPORT void (*daemon_task) (void); DLL_EXPORT int (*config_command) (int argc, char *argv[], char *cmdline); DLL_EXPORT int (*system_command) (int argc, char *argv[], char *cmdline); DLL_EXPORT void *(*debug_cpu_state) (REGS *); DLL_EXPORT void *(*debug_cd_cmd) (char *); DLL_EXPORT void *(*debug_device_state) (DEVBLK *); DLL_EXPORT void *(*debug_program_interrupt) (REGS *, int); DLL_EXPORT void *(*debug_diagnose) (U32, int, int, REGS *); DLL_EXPORT void *(*debug_iucv) (int, VADR, REGS *); DLL_EXPORT void *(*debug_sclp_unknown_command) (U32, void *, REGS *); DLL_EXPORT void *(*debug_sclp_unknown_event) (void *, void *, REGS *); DLL_EXPORT void *(*debug_sclp_unknown_event_mask) (void *, void *, REGS *); DLL_EXPORT void *(*debug_sclp_event_data) (void *, void *, REGS *); DLL_EXPORT void *(*debug_chsc_unknown_request) (void *, void *, REGS *); DLL_EXPORT void *(*debug_watchdog_signal) (REGS *); #endif hercules-3.12/version.c0000664000175000017500000001546512564723224012047 00000000000000/* VERSION.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules Version Display Module */ /*-------------------------------------------------------------------*/ /* This module displays the Hercules program name and version, */ /* copyright notice, build date and time, and build information. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _VERSION_C_ #define _HUTIL_DLL_ #include "hercules.h" #include "machdep.h" /*--------------------------------------------------*/ /* "Unusual" (i.e. noteworthy) build options... */ /*--------------------------------------------------*/ static const char *build_info[] = { #if defined(_MSVC_) "Windows (MSVC) " #if defined(DEBUG) "** DEBUG ** " #endif "build for " MSTRING(HOST_ARCH) #if defined(CUSTOM_BUILD_STRING) ": \"" CUSTOM_BUILD_STRING "\"" #endif , #elif defined(CUSTOM_BUILD_STRING) CUSTOM_BUILD_STRING, #endif #if !defined(_ARCHMODE2) "Mode:" #else "Modes:" #endif #if defined(_370) " " _ARCH_370_NAME #endif #if defined(_390) " " _ARCH_390_NAME #endif #if defined(_900) " " _ARCH_900_NAME #endif , "Max CPU Engines: " MSTRING(MAX_CPU_ENGINES), #if !defined(_MSVC_) #if defined(NO_SETUID) "No setuid support", #else "Using " #if defined(HAVE_SETRESUID) "setresuid()" #elif defined(HAVE_SETREUID) "setreuid()" #else "(UNKNOWN)" #endif " for setting privileges", #endif #endif #if defined(OPTION_FTHREADS) "Using fthreads instead of pthreads", #endif #if defined(OPTION_DYNAMIC_LOAD) "Dynamic loading support", #else "No Dynamic loading support", #endif #if defined(HDL_BUILD_SHARED) "Using shared libraries", #else "Using static libraries", #endif #if !defined(EXTERNALGUI) "No External GUI support", #endif #if defined(OPTION_HTTP_SERVER) "HTTP Server support", #if defined(PKGDATADIR) && defined(DEBUG) "HTTP document default root directory is "PKGDATADIR, #endif #endif #if defined(NO_SIGABEND_HANDLER) "No SIGABEND handler", #endif #if !defined(CCKD_BZIP2) "No CCKD BZIP2 support", #endif #if !defined(HAVE_LIBZ) "No ZLIB support", #endif #if defined(HAVE_REGEX_H) || defined(HAVE_PCRE) "Regular Expressions support", #endif #if defined(OPTION_HAO) "Automatic Operator support", #endif #if !defined(HET_BZIP2) "No HET BZIP2 support", #endif "Machine dependent assists:" #if !defined( ASSIST_CMPXCHG1 ) \ && !defined( ASSIST_CMPXCHG4 ) \ && !defined( ASSIST_CMPXCHG8 ) \ && !defined( ASSIST_CMPXCHG16 ) \ && !defined( ASSIST_FETCH_DW ) \ && !defined( ASSIST_STORE_DW ) \ && !defined( MULTI_BYTE_ASSIST) " (none)", #else #if defined( ASSIST_CMPXCHG1 ) " cmpxchg1" #endif #if defined( ASSIST_CMPXCHG4 ) " cmpxchg4" #endif #if defined( ASSIST_CMPXCHG8 ) " cmpxchg8" #endif #if defined( ASSIST_CMPXCHG16 ) " cmpxchg16" #endif #if defined( ASSIST_FETCH_DW ) " fetch_dw" #endif #if defined( ASSIST_STORE_DW ) " store_dw" #endif #if defined( MULTI_BYTE_ASSIST ) " multi_byte" #endif , #endif }; /*-------------------------------------------------------------------*/ /* Retrieve ptr to build information strings array... */ /* (returns #of entries in array) */ /*-------------------------------------------------------------------*/ DLL_EXPORT int get_buildinfo_strings(const char*** pppszBldInfoStr) { if (!pppszBldInfoStr) return 0; *pppszBldInfoStr = build_info; return ( sizeof(build_info) / sizeof(build_info[0]) ); } /*-------------------------------------------------------------------*/ /* Display version and copyright */ /*-------------------------------------------------------------------*/ DLL_EXPORT void display_version_2 (FILE *f, char *prog, const char verbose,int httpfd) { unsigned int i; const char** ppszBldInfoStr = NULL; #if defined(EXTERNALGUI) /* If external gui being used, set stdout & stderr streams to unbuffered so we don't have to flush them all the time in order to ensure consistent sequence of log messages. */ if (extgui) { setvbuf(stderr, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); } #endif /*EXTERNALGUI*/ /* Log version */ if ( f != stdout ) if(httpfd<0) fprintf (f, _("%sVersion %s\n"), prog, VERSION); else hprintf (httpfd, _("%sVersion %s\n"), prog, VERSION); else logmsg ( _("%sVersion %s\n"), prog, VERSION); /* Log Copyright */ if ( f != stdout ) if(httpfd<0) fprintf (f, "%s\n", HERCULES_COPYRIGHT); else hprintf (httpfd, "%s\n", HERCULES_COPYRIGHT); else logmsg ( "%s\n", HERCULES_COPYRIGHT); /* If we're being verbose, display the rest of the info */ if (verbose) { /* Log build date/time */ if ( f != stdout ) if(httpfd<0) fprintf (f, _("Built on %s at %s\n"), __DATE__, __TIME__); else hprintf (httpfd, _("Built on %s at %s\n"), __DATE__, __TIME__); else logmsg ( _("Built on %s at %s\n"), __DATE__, __TIME__); /* Log "unusual" build options */ if ( f != stdout ) if(httpfd<0) fprintf (f, _("Build information:\n")); else hprintf (httpfd, _("Build information:\n")); else logmsg ( _("Build information:\n")); if (!(i = get_buildinfo_strings( &ppszBldInfoStr ))) { if ( f != stdout ) if(httpfd<0) fprintf (f, " (none)\n"); else hprintf (httpfd, " (none)\n"); else logmsg ( " (none)\n"); } else { for(; i; i--, ppszBldInfoStr++ ) { if ( f != stdout ) if(httpfd<0) fprintf (f, " %s\n", *ppszBldInfoStr); else hprintf (httpfd, " %s\n", *ppszBldInfoStr); else logmsg ( " %s\n", *ppszBldInfoStr); } } if(f != stdout) if(httpfd<0) display_hostinfo( &hostinfo, f, -1 ); else display_hostinfo( &hostinfo, (FILE *)-1,httpfd ); else display_hostinfo( &hostinfo, f, -1 ); } } /* end function display_version */ DLL_EXPORT void display_version(FILE *f,char *prog,const char verbose) { display_version_2(f,prog,verbose,-1); } hercules-3.12/hscutl.c0000664000175000017500000005621512564723224011662 00000000000000/* HSCUTL.C (c) Copyright Ivan Warren & Others, 2003-2009 */ /* Hercules Platform Port & Misc Functions */ /*-------------------------------------------------------------------*/ /* Implementation of functions used in Hercules that may */ /* be missing on some platform ports, or other convenient */ /* miscellaneous global utility functions. */ /*-------------------------------------------------------------------*/ /* (c) 2003-2006 Ivan Warren & Others -- Released under the Q Public */ /* License -- This file is portion of the HERCULES S/370, S/390 and */ /* z/Architecture emulator */ #include "hstdinc.h" #define _HSCUTL_C_ #define _HUTIL_DLL_ #include "hercules.h" #if defined(NEED_GETOPT_WRAPPER) /* GETOPT DYNAMIC LINKING KLUDGE... For some odd reason, on some platforms (namely windows & possibly Darwin) dynamically linking to the libc imports STATIC versions of 'getopt' and 'getopt_long' into the link-edited shared library. If any program then link edits against BOTH the shared library AND libc, then the linker complains about 'getopt' and/or 'getopt_long' being defined multiple times. In an effort to overcome this, I am defining a stub version of 'getopt' and 'getop_long' that can be called by loadable modules instead. -- Ivan ** ZZ FIXME: the above needs to be re-verified to see whether it is ** still true or not. I suspect it may no longer be true due to the ** subtle bug fixed in the "_HC_CHECK_NEED_GETOPT_WRAPPER" m4 macro ** in the "./autoconf/hercules.m4" member. -- Fish, Feb 2005 */ int herc_opterr=0; char *herc_optarg=NULL; int herc_optopt=0; int herc_optind=1; #if defined(NEED_GETOPT_OPTRESET) int herc_optreset=0; #endif DLL_EXPORT int herc_getopt(int ac,char * const av[],const char *opt) { int rc; #if defined(NEED_GETOPT_OPTRESET) optreset=herc_optreset; #endif rc=getopt(ac,av,opt); #if defined(NEED_GETOPT_OPTRESET) herc_optreset=optreset; #endif herc_optarg=optarg; herc_optind=optind; herc_optopt=optind; herc_opterr=optind; return(rc); } #if defined(HAVE_GETOPT_LONG) struct option; // (fwd ref) int getopt_long (int, char *const *, const char *, const struct option *, int *); struct option; // (fwd ref) DLL_EXPORT int herc_getopt_long(int ac, char * const av[], const char *opt, const struct option *lo, int *li) { int rc; #if defined(NEED_GETOPT_OPTRESET) optreset=herc_optreset; #endif optind=herc_optind; rc=getopt_long(ac,av,opt,lo,li); #if defined(NEED_GETOPT_OPTRESET) herc_optreset=optreset; #endif herc_optarg=optarg; herc_optind=optind; herc_optopt=optind; herc_opterr=optind; return(rc); } #endif /* HAVE_GETOPT_LONG */ #endif /* NEED_GETOPT_WRAPPER */ #if !defined(WIN32) && !defined(HAVE_STRERROR_R) static LOCK strerror_lock; DLL_EXPORT void strerror_r_init(void) { initialize_lock(&strerror_lock); } DLL_EXPORT int strerror_r(int err,char *bfr,size_t sz) { char *wbfr; obtain_lock(&strerror_lock); wbfr=strerror(err); if(wbfr==NULL || (int)wbfr==-1) { release_lock(&strerror_lock); return(-1); } if(sz<=strlen(wbfr)) { errno=ERANGE; release_lock(&strerror_lock); return(-1); } strncpy(bfr,wbfr,sz); release_lock(&strerror_lock); return(0); } #endif // !defined(HAVE_STRERROR_R) #if !defined(HAVE_STRLCPY) /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */ /* ** NOTE ** returns 'size_t' and NOT 'char*' like strncpy! */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ /* ** NOTE ** returns 'size_t' and NOT 'char*' like strncpy! */ DLL_EXPORT size_t strlcpy(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif // !defined(HAVE_STRLCPY) #if !defined(HAVE_STRLCAT) /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */ /* ** NOTE ** returns 'size_t' and NOT 'char*' like strncpy! */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ /* ** NOTE ** returns 'size_t' and NOT 'char*' like strncat! */ DLL_EXPORT size_t strlcat(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif // !defined(HAVE_STRLCAT) #if defined(OPTION_CONFIG_SYMBOLS) /* The following structures are defined herein because they are private structures */ /* that MUST be opaque to the outside world */ typedef struct _SYMBOL_TOKEN { char *var; char *val; } SYMBOL_TOKEN; #define SYMBOL_TABLE_INCREMENT 256 #define SYMBOL_BUFFER_GROWTH 256 #define MAX_SYMBOL_SIZE 31 #define SYMBOL_QUAL_1 '$' #define SYMBOL_QUAL_2 '(' #define SYMBOL_QUAL_3 ')' static SYMBOL_TOKEN **symbols=NULL; static int symbol_count=0; static int symbol_max=0; /* This function retrieves or allocates a new SYMBOL_TOKEN */ static SYMBOL_TOKEN *get_symbol_token(const char *sym,int alloc) { SYMBOL_TOKEN *tok; int i; for(i=0;ivar,sym)==0) { return(symbols[i]); } } if(!alloc) { return(NULL); } if(symbol_count>=symbol_max) { symbol_max+=SYMBOL_TABLE_INCREMENT; if(symbols==NULL) { symbols=malloc(sizeof(SYMBOL_TOKEN *)*symbol_max); if(symbols==NULL) { symbol_max=0; symbol_count=0; return(NULL); } } else { symbols=realloc(symbols,sizeof(SYMBOL_TOKEN *)*symbol_max); if(symbols==NULL) { symbol_max=0; symbol_count=0; return(NULL); } } } tok=malloc(sizeof(SYMBOL_TOKEN)); if(tok==NULL) { return(NULL); } tok->var=malloc(MIN(MAX_SYMBOL_SIZE+1,strlen(sym)+1)); if(tok->var==NULL) { free(tok); return(NULL); } strncpy(tok->var,sym,MIN(MAX_SYMBOL_SIZE+1,strlen(sym)+1)); tok->val=NULL; symbols[symbol_count]=tok; symbol_count++; return(tok); } DLL_EXPORT void set_symbol(const char *sym,const char *value) { SYMBOL_TOKEN *tok; tok=get_symbol_token(sym,1); if(tok==NULL) { return; } if(tok->val!=NULL) { free(tok->val); } tok->val=malloc(strlen(value)+1); if(tok->val==NULL) { return; } strcpy(tok->val,value); return; } DLL_EXPORT const char *get_symbol(const char *sym) { char *val; SYMBOL_TOKEN *tok; tok=get_symbol_token(sym,0); if(tok==NULL) { val=getenv(sym); return(val); } return(tok->val); } static void buffer_addchar_and_alloc(char **bfr,char c,int *ix_p,int *max_p) { char *buf; int ix; int mx; buf=*bfr; ix=*ix_p; mx=*max_p; if((ix+1)>=mx) { mx+=SYMBOL_BUFFER_GROWTH; if(buf==NULL) { buf=malloc(mx); } else { buf=realloc(buf,mx); } *bfr=buf; *max_p=mx; } buf[ix++]=c; buf[ix]=0; *ix_p=ix; return; } static void append_string(char **bfr,char *text,int *ix_p,int *max_p) { int i; for(i=0;text[i]!=0;i++) { buffer_addchar_and_alloc(bfr,text[i],ix_p,max_p); } return; } static void append_symbol(char **bfr,char *sym,int *ix_p,int *max_p) { char *txt; txt=(char *)get_symbol(sym); if(txt==NULL) { txt="**UNRESOLVED**"; } append_string(bfr,txt,ix_p,max_p); return; } DLL_EXPORT char *resolve_symbol_string(const char *text) { char *resstr; int curix,maxix; char cursym[MAX_SYMBOL_SIZE+1]; int cursymsize=0; int q1,q2; int i; /* Quick check - look for QUAL1 ('$') or QUAL2 ('(').. if not found, return the string as-is */ if(!strchr(text,SYMBOL_QUAL_1) || !strchr(text,SYMBOL_QUAL_2)) { /* Malloc anyway - the caller will free() */ resstr=malloc(strlen(text)+1); strcpy(resstr,text); return(resstr); } q1=0; q2=0; curix=0; maxix=0; resstr=NULL; for(i=0;text[i]!=0;i++) { if(q1) { if(text[i]==SYMBOL_QUAL_2) { q2=1; q1=0; continue; } q1=0; buffer_addchar_and_alloc(&resstr,SYMBOL_QUAL_1,&curix,&maxix); buffer_addchar_and_alloc(&resstr,text[i],&curix,&maxix); continue; } if(q2) { if(text[i]==SYMBOL_QUAL_3) { append_symbol(&resstr,cursym,&curix,&maxix); cursymsize=0; q2=0; continue; } if(cursymsizevar, tok->val ? tok->val : ""); } return; } DLL_EXPORT void kill_all_symbols(void) { SYMBOL_TOKEN *tok; int i; for(i=0;ival); if(tok->var!=NULL) { free(tok->var); } free(tok); symbols[i]=NULL; } free(symbols); symbol_count=0; symbol_max=0; return; } #endif /* #if defined(OPTION_CONFIG_SYMBOLS) */ /* Subtract 'beg_timeval' from 'end_timeval' yielding 'dif_timeval' */ /* Return code: success == 0, error == -1 (difference was negative) */ DLL_EXPORT int timeval_subtract ( struct timeval *beg_timeval, struct timeval *end_timeval, struct timeval *dif_timeval ) { struct timeval begtime; struct timeval endtime; ASSERT ( beg_timeval -> tv_sec >= 0 && beg_timeval -> tv_usec >= 0 ); ASSERT ( end_timeval -> tv_sec >= 0 && end_timeval -> tv_usec >= 0 ); memcpy(&begtime,beg_timeval,sizeof(struct timeval)); memcpy(&endtime,end_timeval,sizeof(struct timeval)); dif_timeval->tv_sec = endtime.tv_sec - begtime.tv_sec; if (endtime.tv_usec >= begtime.tv_usec) { dif_timeval->tv_usec = endtime.tv_usec - begtime.tv_usec; } else { dif_timeval->tv_sec--; dif_timeval->tv_usec = (endtime.tv_usec + 1000000) - begtime.tv_usec; } return ((dif_timeval->tv_sec < 0 || dif_timeval->tv_usec < 0) ? -1 : 0); } /* Add 'dif_timeval' to 'accum_timeval' (use to accumulate elapsed times) */ /* Return code: success == 0, error == -1 (accum_timeval result negative) */ DLL_EXPORT int timeval_add ( struct timeval *dif_timeval, struct timeval *accum_timeval ) { ASSERT ( dif_timeval -> tv_sec >= 0 && dif_timeval -> tv_usec >= 0 ); ASSERT ( accum_timeval -> tv_sec >= 0 && accum_timeval -> tv_usec >= 0 ); accum_timeval->tv_sec += dif_timeval->tv_sec; accum_timeval->tv_usec += dif_timeval->tv_usec; if (accum_timeval->tv_usec > 1000000) { int nsec = accum_timeval->tv_usec / 1000000; accum_timeval->tv_sec += nsec; accum_timeval->tv_usec -= nsec * 1000000; } return ((accum_timeval->tv_sec < 0 || accum_timeval->tv_usec < 0) ? -1 : 0); } /* Easier to use timed_wait_condition that waits for the specified relative amount of time without you having to build an absolute timeout time yourself */ DLL_EXPORT int timed_wait_condition_relative_usecs ( COND* pCOND, // ptr to condition to wait on LOCK* pLOCK, // ptr to controlling lock (must be held!) U32 usecs, // max #of microseconds to wait struct timeval* pTV // [OPTIONAL] ptr to tod value (may be NULL) ) { struct timespec timeout_timespec; struct timeval now; if (!pTV) { pTV = &now; gettimeofday( pTV, NULL ); } timeout_timespec.tv_sec = pTV->tv_sec + ( usecs / 1000000 ); timeout_timespec.tv_nsec = pTV->tv_usec + ( usecs % 1000000 ); if ( timeout_timespec.tv_nsec > 1000000 ) { timeout_timespec.tv_sec += timeout_timespec.tv_nsec / 1000000; timeout_timespec.tv_nsec %= 1000000; } timeout_timespec.tv_nsec *= 1000; return timed_wait_condition( pCOND, pLOCK, &timeout_timespec ); } /********************************************************************* The following couple of Hercules 'utility' functions may be defined elsewhere depending on which host platform we're being built for... For Windows builds (e.g. MingW32), the functionality for the below functions is defined in 'w32util.c'. For other host build platforms (e.g. Linux, Apple, etc), the functionality for the below functions is defined right here in 'hscutil.c'... *********************************************************************/ #if !defined(_MSVC_) /* THIS module (hscutil.c) is to provide the below functionality.. */ /* Returns outpath as a host filesystem compatible filename path. This is a Cygwin-to-MSVC transitional period helper function. On non-Windows platforms it simply copies inpath to outpath. On Windows it converts inpath of the form "/cygdrive/x/foo.bar" to outpath in the form "x:/foo.bar" for Windows compatibility. */ DLL_EXPORT char *hostpath( char *outpath, const char *inpath, size_t buffsize ) { if (inpath && outpath && buffsize > 1) strlcpy( outpath, inpath, buffsize ); else if (outpath && buffsize) *outpath = 0; return outpath; } /* Poor man's "fcntl( fd, F_GETFL )"... */ /* (only returns access-mode flags and not any others) */ DLL_EXPORT int get_file_accmode_flags( int fd ) { int flags = fcntl( fd, F_GETFL ); return ( flags & O_ACCMODE ); } /* Set socket to blocking or non-blocking mode... */ DLL_EXPORT int socket_set_blocking_mode( int sfd, int blocking_mode ) { int flags = fcntl( sfd, F_GETFL ); if ( blocking_mode ) flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; return fcntl( sfd, F_SETFL, flags ); } /* Initialize/Deinitialize sockets package... */ int socket_init ( void ) { return 0; } DLL_EXPORT int socket_deinit ( void ) { return 0; } /* Determine whether a file descriptor is a socket or not... */ /* (returns 1==true if it's a socket, 0==false otherwise) */ DLL_EXPORT int socket_is_socket( int sfd ) { struct stat st; return ( fstat( sfd, &st ) == 0 && S_ISSOCK( st.st_mode ) ); } /* Set the SO_KEEPALIVE option and timeout values for a socket connection to detect when client disconnects */ void socket_keepalive( int sfd, int idle_time, int probe_interval, int probe_count ) { int rc, optval = 1; rc = setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)); if (rc) logmsg("HHCUT001I SO_KEEPALIVE rc=%d %s\n", rc, strerror(errno)); #if defined(TCP_KEEPALIVE) optval = idle_time; rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPALIVE, &optval, sizeof(optval)); if (rc) logmsg("HHCUT002I TCP_KEEPALIVE rc=%d %s\n", rc, strerror(errno)); #elif defined(TCP_KEEPIDLE) optval = idle_time; rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)); if (rc) logmsg("HHCUT003I TCP_KEEPIDLE rc=%d %s\n", rc, strerror(errno)); #else UNREFERENCED(idle_time); #endif #if defined(TCP_KEEPINTVL) optval = probe_interval; rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval)); if (rc) logmsg("HHCUT004I TCP_KEEPINTVL rc=%d %s\n", rc, strerror(errno)); #else UNREFERENCED(probe_interval); #endif #if defined(TCP_KEEPCNT) optval = probe_count; rc = setsockopt(sfd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval)); if (rc) logmsg("HHCUT005I TCP_KEEPCNT rc=%d %s\n", rc, strerror(errno)); #else UNREFERENCED(probe_count); #endif } /* Hercules file open */ DLL_EXPORT int hopen(const char* path, int oflag, ...) { int pmode = 0; if (oflag & O_CREAT) { va_list vargs; va_start(vargs, oflag); pmode = va_arg(vargs, int); } return open(path, oflag, pmode); } #endif // !defined(_MSVC_) ////////////////////////////////////////////////////////////////////////////////////////// // (testing) DLL_EXPORT void cause_crash() { static int x = 0; x = x / x - x; } ////////////////////////////////////////////////////////////////////////////////////////// /*******************************************/ /* Read/Write to socket functions */ /*******************************************/ DLL_EXPORT int hgetc(int s) { char c; int rc; rc=recv(s,&c,1,0); if(rc<1) { return EOF; } return c; } DLL_EXPORT char * hgets(char *b,size_t c,int s) { size_t ix=0; while(ixname && strcasecmp(codepage_conv->name,name); codepage_conv++); if(codepage_conv->name) { #if 0 logmsg(_("HHCCF072I Using internal codepage conversion table %s\n"), name); #endif } else { #if defined(HAVE_ICONV) if(!set_iconv_cp(name)) { #if 0 logmsg(_("HHCCF072I Using external codepage conversion table %s\n"), name); #endif } else #endif /*defined(HAVE_ICONV)*/ logmsg(_("HHCCF051E Codepage conversion table %s is not defined\n"), name); } } DLL_EXPORT unsigned char host_to_guest (unsigned char byte) { #if defined(HAVE_ICONV) char obyte; char *gbyte = &obyte; char *hbyte = (char *)&byte; size_t inbytes = 1, outbytes = 1; if(codepage_h2g) { iconv(codepage_h2g, (char**)&hbyte, &inbytes, &gbyte, &outbytes); return obyte; } else #endif /*defined(HAVE_ICONV)*/ return (unsigned char)codepage_conv->h2g[(unsigned int)byte]; } DLL_EXPORT unsigned char guest_to_host (unsigned char byte) { #if defined(HAVE_ICONV) char obyte; char *hbyte = &obyte; char *gbyte = (char *)&byte; size_t inbytes = 1, outbytes = 1; if(codepage_g2h) { iconv(codepage_g2h, (char**)&gbyte, &inbytes, &hbyte, &outbytes); return obyte; } else #endif /*defined(HAVE_ICONV)*/ return codepage_conv->g2h[byte]; } hercules-3.12/logger.c0000664000175000017500000004450112564723224011632 00000000000000/* LOGGER.C (c) Copyright Jan Jaeger, 2003-2009 */ /* System logger functions */ /* If standard output or standard error is redirected then the log */ /* is written to the redirection. */ /* If standard output and standard error are both redirected then */ /* the system log is written to the redirection of standard error */ /* the redirection of standard output is ignored in this case, */ /* and background mode is assumed. */ /* Any thread can determine background mode by inspecting stderr */ /* for isatty() */ #include "hstdinc.h" #define _LOGGER_C_ #define _HUTIL_DLL_ #include "hercules.h" #include "opcode.h" /* Required for SETMODE macro */ static COND logger_cond; static LOCK logger_lock; static TID logger_tid; static char *logger_buffer; static int logger_bufsize; static int logger_currmsg; static int logger_wrapped; static int logger_active=0; static FILE *logger_syslog[2]; /* Syslog read/write pipe */ int logger_syslogfd[2]; /* pairs */ static FILE *logger_hrdcpy; /* Hardcopy log or zero */ static int logger_hrdcpyfd; /* Hardcopt fd or -1 */ /* Find the index for a specific line number in the log, */ /* one being the most recent line */ /* Example: */ /* read the last 5 lines in the syslog: */ /* */ /* int msgnum; */ /* int msgidx; */ /* char *msgbuf; */ /* */ /* msgidx = log_line(5); */ /* while((msgcnt = log_read(&msgbuf, &msgidx, LOG_NOBLOCK))) */ /* function_to_process_log(msgbuf, msgcnt); */ /* */ DLL_EXPORT int log_line(int linenumber) { char *msgbuf[2] = {NULL, NULL}, *tmpbuf = NULL; int msgidx[2] = { -1, -1 }; int msgcnt[2] = {0, 0}; int i; if(!linenumber++) return logger_currmsg; /* Find the last two blocks in the log */ do { msgidx[0] = msgidx[1]; msgbuf[0] = msgbuf[1]; msgcnt[0] = msgcnt[1]; } while((msgcnt[1] = log_read(&msgbuf[1], &msgidx[1], LOG_NOBLOCK))); for(i = 0; i < 2 && linenumber; i++) if(msgidx[i] != -1) { for(; linenumber > 0; linenumber--) { if(!(tmpbuf = (void *)memrchr(msgbuf[i],'\n',msgcnt[i]))) break; msgcnt[i] = tmpbuf - msgbuf[i]; } if(!linenumber) break; } while(i < 2 && tmpbuf && (*tmpbuf == '\r' || *tmpbuf == '\n')) { tmpbuf++; msgcnt[i]++; } return i ? msgcnt[i] + msgidx[0] : msgcnt[i]; } /* log_read - read system log */ /* parameters: */ /* buffer - pointer to bufferpointer */ /* the bufferpointer will be returned */ /* msgindex - an index used on multiple read requests */ /* a value of -1 ensures that reading starts at the */ /* oldest entry in the log */ /* block - LOG_NOBLOCK - non blocking request */ /* LOG_BLOCK - blocking request */ /* returns: */ /* number of bytes in buffer or zero */ /* */ /* */ DLL_EXPORT int log_read(char **buffer, int *msgindex, int block) { int bytes_returned; obtain_lock(&logger_lock); if(*msgindex == logger_currmsg && block) { if(logger_active) { wait_condition(&logger_cond, &logger_lock); } else { *msgindex = logger_currmsg; *buffer = logger_buffer + logger_currmsg; release_lock(&logger_lock); return 0; } } if(*msgindex != logger_currmsg) { if(*msgindex < 0) *msgindex = logger_wrapped ? logger_currmsg : 0; if(*msgindex < 0 || *msgindex >= logger_bufsize) *msgindex = 0; *buffer = logger_buffer + *msgindex; if(*msgindex >= logger_currmsg) { bytes_returned = logger_bufsize - *msgindex; *msgindex = 0; } else { bytes_returned = logger_currmsg - *msgindex; *msgindex = logger_currmsg; } } else bytes_returned = 0; release_lock(&logger_lock); return bytes_returned; } static void logger_term(void *arg) { UNREFERENCED(arg); if(logger_active) { char* term_msg = _("HHCLG014I logger thread terminating\n"); size_t term_msg_len = strlen(term_msg); obtain_lock(&logger_lock); /* Flush all pending logger o/p before redirecting?? */ fflush(stdout); /* Redirect all output to stderr */ dup2(STDERR_FILENO, STDOUT_FILENO); /* Tell logger thread we want it to exit */ logger_active = 0; /* Send the logger a message to wake it up */ write_pipe( logger_syslogfd[LOG_WRITE], term_msg, term_msg_len ); release_lock(&logger_lock); /* Wait for the logger to terminate */ join_thread( logger_tid, NULL ); detach_thread( logger_tid ); } } static void logger_logfile_write( void* pBuff, size_t nBytes ) { if ( fwrite( pBuff, nBytes, 1, logger_hrdcpy ) != 1 ) { fprintf(logger_hrdcpy, _("HHCLG003E Error writing hardcopy log: %s\n"), strerror(errno)); } if ( sysblk.shutdown ) fflush ( logger_hrdcpy ); } #ifdef OPTION_TIMESTAMP_LOGFILE /* ZZ FIXME: * This should really be part of logmsg, as the timestamps have currently * the time when the logger reads the message from the log pipe. There can be * quite a delay at times when there is a high system activity. Moving the timestamp * to logmsg() will fix this. * The timestamp option should also NOT depend on anything like daemon mode. * logs entries should always be timestamped, in a fixed format, such that * log readers may decide to skip the timestamp when displaying (ie panel.c). */ static void logger_logfile_timestamp() { if (!sysblk.daemon_mode) { struct timeval now; time_t tt; char hhmmss[10]; gettimeofday( &now, NULL ); tt = now.tv_sec; strlcpy( hhmmss, ctime(&tt)+11, sizeof(hhmmss) ); logger_logfile_write( hhmmss, strlen(hhmmss) ); } } #endif static void logger_thread(void *arg) { int bytes_read; UNREFERENCED(arg); /* Set root mode in order to set priority */ SETMODE(ROOT); /* Set device thread priority; ignore any errors */ setpriority(PRIO_PROCESS, 0, sysblk.devprio); /* Back to user mode */ SETMODE(USER); #if !defined( _MSVC_ ) /* Redirect stdout to the logger */ if(dup2(logger_syslogfd[LOG_WRITE],STDOUT_FILENO) == -1) { if(logger_hrdcpy) fprintf(logger_hrdcpy, _("HHCLG001E Error redirecting stdout: %s\n"), strerror(errno)); exit(1); } #endif /* !defined( _MSVC_ ) */ setvbuf (stdout, NULL, _IONBF, 0); /* call logger_term on system shutdown */ hdl_adsc("logger_term",logger_term, NULL); obtain_lock(&logger_lock); logger_active = 1; /* Signal initialization complete */ signal_condition(&logger_cond); release_lock(&logger_lock); /* ZZ FIXME: We must empty the read pipe before we terminate */ /* (Couldn't we just loop waiting for a 'select(,&readset,,,timeout)' to return zero?? Or use the 'poll' function similarly?? - Fish) */ while(logger_active) { bytes_read = read_pipe(logger_syslogfd[LOG_READ],logger_buffer + logger_currmsg, ((logger_bufsize - logger_currmsg) > LOG_DEFSIZE ? LOG_DEFSIZE : logger_bufsize - logger_currmsg)); if(bytes_read == -1) { int read_pipe_errno = HSO_errno; // (ignore any/all errors at shutdown) if (sysblk.shutdown) continue; if (HSO_EINTR == read_pipe_errno) continue; if(logger_hrdcpy) fprintf(logger_hrdcpy, _("HHCLG002E Error reading syslog pipe: %s\n"), strerror(read_pipe_errno)); bytes_read = 0; } /* If Hercules is not running in daemon mode and panel initialization is not yet complete, write message to stderr so the user can see it on the terminal */ if (!sysblk.daemon_mode) { if (!sysblk.panel_init) { /* (ignore any errors; we did the best we could) */ fwrite( logger_buffer + logger_currmsg, bytes_read, 1, stderr ); } } /* Write log data to hardcopy file */ if (logger_hrdcpy) #if !defined( OPTION_TIMESTAMP_LOGFILE ) { char* pLeft2 = logger_buffer + logger_currmsg; int nLeft2 = bytes_read; #if defined( OPTION_MSGCLR ) /* Remove " 5 && strncasecmp( pLeft2, "', nLeft2-4 )) != NULL ) { pLeft2++; nLeft2 -= (pLeft2 - (logger_buffer + logger_currmsg)); } else { pLeft2 = logger_buffer + logger_currmsg; nLeft2 = bytes_read; } #endif // defined( OPTION_MSGCLR ) logger_logfile_write( pLeft2, nLeft2 ); } #else // defined( OPTION_TIMESTAMP_LOGFILE ) { /* Need to prefix each line with a timestamp. */ static int needstamp = 1; char* pLeft = logger_buffer + logger_currmsg; int nLeft = bytes_read; char* pRight = NULL; int nRight = 0; char* pNL = NULL; /* (pointer to NEWLINE character) */ if (needstamp) { if (!sysblk.logoptnotime) logger_logfile_timestamp(); needstamp = 0; } while ( (pNL = memchr( pLeft, '\n', nLeft )) != NULL ) { pRight = pNL + 1; nRight = nLeft - (pRight - pLeft); nLeft -= nRight; #if defined( OPTION_MSGCLR ) /* Remove "" color string if it exists */ { char* pLeft2 = pLeft; int nLeft2 = nLeft; if (1 && nLeft > 5 && strncasecmp( pLeft, "', nLeft-4 )) != NULL ) { pLeft2++; nLeft2 -= (pLeft2 - pLeft); } else { pLeft2 = pLeft; nLeft2 = nLeft; } logger_logfile_write( pLeft2, nLeft2 ); } #else // !defined( OPTION_MSGCLR ) logger_logfile_write( pLeft, nLeft ); #endif // defined( OPTION_MSGCLR ) pLeft = pRight; nLeft = nRight; if (!nLeft) { needstamp = 1; break; } if (!sysblk.logoptnotime) logger_logfile_timestamp(); } if (nLeft) logger_logfile_write( pLeft, nLeft ); } #endif // !defined( OPTION_TIMESTAMP_LOGFILE ) /* Increment buffer index to next available position */ logger_currmsg += bytes_read; if(logger_currmsg >= logger_bufsize) { logger_currmsg = 0; logger_wrapped = 1; } /* Notify all interested parties new log data is available */ obtain_lock(&logger_lock); broadcast_condition(&logger_cond); release_lock(&logger_lock); } /* Logger is now terminating */ obtain_lock(&logger_lock); /* Write final message to hardcopy file */ if (logger_hrdcpy) { char* term_msg = _("HHCLG014I logger thread terminating\n"); size_t term_msg_len = strlen(term_msg); #ifdef OPTION_TIMESTAMP_LOGFILE if (!sysblk.logoptnotime) logger_logfile_timestamp(); #endif logger_logfile_write( term_msg, term_msg_len ); } /* Redirect all msgs to stderr */ logger_syslog[LOG_WRITE] = stderr; logger_syslogfd[LOG_WRITE] = STDERR_FILENO; fflush(stderr); /* Signal any waiting tasks */ broadcast_condition(&logger_cond); release_lock(&logger_lock); } DLL_EXPORT void logger_init(void) { initialize_condition (&logger_cond); initialize_lock (&logger_lock); obtain_lock(&logger_lock); if(fileno(stdin)>=0 || fileno(stdout)>=0 || fileno(stderr)>=0) { logger_syslog[LOG_WRITE] = stderr; /* If standard error is redirected, then use standard error as the log file. */ if(!isatty(STDOUT_FILENO) && !isatty(STDERR_FILENO)) { /* Ignore standard output to the extent that it is treated as standard error */ logger_hrdcpyfd = dup(STDOUT_FILENO); if(dup2(STDERR_FILENO,STDOUT_FILENO) == -1) { fprintf(stderr, _("HHCLG004E Error duplicating stderr: %s\n"), strerror(errno)); exit(1); } } else { if(!isatty(STDOUT_FILENO)) { logger_hrdcpyfd = dup(STDOUT_FILENO); if(dup2(STDERR_FILENO,STDOUT_FILENO) == -1) { fprintf(stderr, _("HHCLG004E Error duplicating stderr: %s\n"), strerror(errno)); exit(1); } } if(!isatty(STDERR_FILENO)) { logger_hrdcpyfd = dup(STDERR_FILENO); if(dup2(STDOUT_FILENO,STDERR_FILENO) == -1) { fprintf(stderr, _("HHCLG005E Error duplicating stdout: %s\n"), strerror(errno)); exit(1); } } } if(logger_hrdcpyfd == -1) { logger_hrdcpyfd = 0; fprintf(stderr, _("HHCLG006E Duplicate error redirecting hardcopy log: %s\n"), strerror(errno)); } if(logger_hrdcpyfd) { if(!(logger_hrdcpy = fdopen(logger_hrdcpyfd,"w"))) fprintf(stderr, _("HHCLG007S Hardcopy log fdopen failed: %s\n"), strerror(errno)); } if(logger_hrdcpy) setvbuf(logger_hrdcpy, NULL, _IONBF, 0); } else { logger_syslog[LOG_WRITE]=fopen("LOG","a"); } logger_bufsize = LOG_DEFSIZE; if(!(logger_buffer = malloc(logger_bufsize))) { fprintf(stderr, _("HHCLG008S logbuffer malloc failed: %s\n"), strerror(errno)); exit(1); } if(create_pipe(logger_syslogfd)) { fprintf(stderr, _("HHCLG009S Syslog message pipe creation failed: %s\n"), strerror(errno)); exit(1); /* Hercules running without syslog */ } setvbuf (logger_syslog[LOG_WRITE], NULL, _IONBF, 0); if (create_thread (&logger_tid, JOINABLE, logger_thread, NULL, "logger_thread") ) { fprintf(stderr, _("HHCLG012E Cannot create logger thread: %s\n"), strerror(errno)); exit(1); } wait_condition(&logger_cond, &logger_lock); release_lock(&logger_lock); } DLL_EXPORT void log_sethrdcpy(char *filename) { FILE *temp_hrdcpy = logger_hrdcpy; FILE *new_hrdcpy; int new_hrdcpyfd; if(!filename) { if(!logger_hrdcpy) { logmsg(_("HHCLG014E log not active\n")); return; } else { obtain_lock(&logger_lock); logger_hrdcpy = 0; logger_hrdcpyfd = 0; release_lock(&logger_lock); fprintf(temp_hrdcpy,_("HHCLG015I log closed\n")); fclose(temp_hrdcpy); logmsg(_("HHCLG015I log closed\n")); return; } } else { char pathname[MAX_PATH]; hostpath(pathname, filename, sizeof(pathname)); new_hrdcpyfd = hopen(pathname, O_WRONLY | O_CREAT | O_TRUNC /* O_SYNC */, S_IRUSR | S_IWUSR | S_IRGRP); if(new_hrdcpyfd < 0) { logmsg(_("HHCLG016E Error opening logfile %s: %s\n"), filename,strerror(errno)); return; } else { if(!(new_hrdcpy = fdopen(new_hrdcpyfd,"w"))) { logmsg(_("HHCLG017S log file fdopen failed for %s: %s\n"), filename, strerror(errno)); return; } else { setvbuf(new_hrdcpy, NULL, _IONBF, 0); obtain_lock(&logger_lock); logger_hrdcpy = new_hrdcpy; logger_hrdcpyfd = new_hrdcpyfd; release_lock(&logger_lock); if(temp_hrdcpy) { fprintf(temp_hrdcpy,_("HHCLG018I log switched to %s\n"), filename); fclose(temp_hrdcpy); } } } } } /* log_wakeup - Wakeup any blocked threads. Useful during shutdown. */ DLL_EXPORT void log_wakeup(void *arg) { UNREFERENCED(arg); obtain_lock(&logger_lock); broadcast_condition(&logger_cond); release_lock(&logger_lock); } hercules-3.12/logmsg.c0000664000175000017500000001723412564723224011646 00000000000000/* LOGMSG.C (c) Copyright Ivan Warren, 2003-2006 */ /* logmsg frontend routing */ #include "hstdinc.h" #define _HUTIL_DLL_ #define _LOGMSG_C_ #include "hercules.h" #define BFR_CHUNKSIZE (256) /******************************************/ /* UTILITY MACRO BFR_VSNPRINTF */ /* Original design by Fish */ /* Modified by Jay Maynard */ /* Further modification by Ivan Warren */ /* */ /* Purpose : set 'bfr' to contain */ /* a C string based on a message format */ /* and a va_list of args. */ /* bfr must be free()d when over with */ /* this macro can ONLY be used from the */ /* topmost variable arg function */ /* that is the va_list cannot be passed */ /* as a parameter from another function */ /* since va_xxx functions behavio(u)r */ /* seems to be undefined in those cases */ /* char *bfr; must be originally defined */ /* int siz; must be defined and cont- */ /* ain a start size */ /* va_list vl; must be defined and init- */ /* ialised with va_start */ /* char *msg; is the message format */ /* int rc; to contain final size */ /******************************************/ #define BFR_VSNPRINTF() \ bfr=malloc(siz); \ rc=-1; \ while(bfr&&rc<0) \ { \ va_start(vl,msg); \ rc=vsnprintf(bfr,siz,msg,vl); \ va_end(vl); \ if(rc>=0 && rcccwtrace||dev->ccwstep) { logmsg("%4.4X:",dev->devnum); BFR_VSNPRINTF(); if(bfr) log_write(2,bfr); } #ifdef NEED_LOGMSG_FFLUSH fflush(stdout); #endif if(bfr) { free(bfr); } } /* end function logdevtr */ /* panel : 0 - No, 1 - Only, 2 - Also */ DLL_EXPORT void log_write(int panel,char *msg) { /* (log_write function proper starts here) */ int slot; log_route_init(); if(panel==1) { write_pipe( logger_syslogfd[LOG_WRITE], msg, strlen(msg) ); return; } obtain_lock(&log_route_lock); slot=log_route_search(thread_id()); release_lock(&log_route_lock); if(slot<0 || panel>0) { write_pipe( logger_syslogfd[LOG_WRITE], msg, strlen(msg) ); if(slot<0) return; } log_routes[slot].w(log_routes[slot].u,msg); return; } /* capture log output routine series */ /* log_capture is a sample of how to */ /* use log rerouting. */ /* log_capture takes 2 args : */ /* a ptr to a function taking 1 parm */ /* the function parm */ struct log_capture_data { char *obfr; size_t sz; }; DLL_EXPORT void log_capture_writer(void *vcd,char *msg) { struct log_capture_data *cd; if(!vcd||!msg)return; cd=(struct log_capture_data *)vcd; if(cd->sz==0) { cd->sz=strlen(msg)+1; cd->obfr=malloc(cd->sz); cd->obfr[0]=0; } else { cd->sz+=strlen(msg); cd->obfr=realloc(cd->obfr,cd->sz); } strcat(cd->obfr,msg); return; } DLL_EXPORT void log_capture_closer(void *vcd) { UNREFERENCED(vcd); return; } DLL_EXPORT char *log_capture(void *(*fun)(void *),void *p) { struct log_capture_data cd; cd.obfr=NULL; cd.sz=0; log_open(log_capture_writer,log_capture_closer,&cd); fun(p); log_close(); return(cd.obfr); } hercules-3.12/hdl.c0000664000175000017500000007366212564723224011134 00000000000000/* HDL.C (c) Copyright Jan Jaeger, 2003-2009 */ /* Hercules Dynamic Loader */ #include "hstdinc.h" #define _HDL_C_ #define _HUTIL_DLL_ #if !defined(WIN32) && !defined(__FreeBSD__) && !defined(__APPLE__) #define ZZ_NO_BACKLINK #endif #include "hercules.h" #ifdef ZZ_NO_BACKLINK #include "opcode.h" /* for the opcode tables */ #endif /* extern HDLPRE hdl_preload[]; */ #if defined(OPTION_DYNAMIC_LOAD) HDLPRE hdl_preload[] = { { "hdteq", HDL_LOAD_NOMSG }, { "dyncrypt", HDL_LOAD_NOMSG }, #if 0 { "dyn_test1", HDL_LOAD_DEFAULT }, { "dyn_test2", HDL_LOAD_NOMSG }, { "dyn_test3", HDL_LOAD_NOMSG | HDL_LOAD_NOUNLOAD }, #endif { NULL, 0 } }; #if 0 /* Forward definitions from hdlmain.c stuff */ /* needed because we cannot depend on dlopen(self) */ extern void *HDL_DEPC; extern void *HDL_INIT; extern void *HDL_RESO; extern void *HDL_DDEV; extern void *HDL_DINS; extern void *HDL_FINI; #endif static DLLENT *hdl_dll; /* dll chain */ static LOCK hdl_lock; /* loader lock */ static DLLENT *hdl_cdll; /* current dll (hdl_lock) */ static HDLDEP *hdl_depend; /* Version codes in hdlmain */ static char *hdl_modpath = NULL; #endif static LOCK hdl_sdlock; /* shutdown lock */ static HDLSHD *hdl_shdlist; /* Shutdown call list */ static void hdl_didf (int, int, char *, void *); #ifdef ZZ_NO_BACKLINK static void hdl_modify_opcode(int, HDLINS *); #endif /* Global hdl_device_type_equates */ DLL_EXPORT char *(*hdl_device_type_equates)(const char *); /* hdl_adsc - add shutdown call */ DLL_EXPORT void hdl_adsc (char* shdname, void * shdcall, void * shdarg) { HDLSHD *newcall; newcall = malloc(sizeof(HDLSHD)); newcall->shdname = shdname; newcall->shdcall = shdcall; newcall->shdarg = shdarg; newcall->next = hdl_shdlist; hdl_shdlist = newcall; } /* hdl_rmsc - remove shutdown call */ DLL_EXPORT int hdl_rmsc (void *shdcall, void *shdarg) { HDLSHD **tmpcall; for(tmpcall = &(hdl_shdlist); *tmpcall; tmpcall = &((*tmpcall)->next) ) { if( (*tmpcall)->shdcall == shdcall && (*tmpcall)->shdarg == shdarg ) { HDLSHD *frecall; frecall = *tmpcall; *tmpcall = (*tmpcall)->next; free(frecall); return 0; } } return -1; } /* hdl_shut - call all shutdown call entries in LIFO order */ DLL_EXPORT void hdl_shut (void) { HDLSHD *shdent; #if defined( _MSVC_ ) HDLSHD *loggercall; int logger_flag = 0; #endif // defined( _MSVC_ ) logmsg("HHCHD900I Begin shutdown sequence\n"); obtain_lock (&hdl_sdlock); for(shdent = hdl_shdlist; shdent; shdent = hdl_shdlist) { #if defined( _MSVC_ ) if ( strcmp( shdent->shdname, "logger_term" ) == 0 ) { loggercall = malloc(sizeof(HDLSHD)); loggercall->shdname = shdent->shdname; loggercall->shdcall = shdent->shdcall; loggercall->shdarg = shdent->shdarg; logger_flag = 1; } else #endif // defined( _MSVC_ ) { logmsg("HHCHD901I Calling %s\n",shdent->shdname); { (shdent->shdcall) (shdent->shdarg); } logmsg("HHCHD902I %s complete\n",shdent->shdname); } /* Remove shutdown call entry to ensure it is called once */ hdl_shdlist = shdent->next; free(shdent); } release_lock (&hdl_sdlock); #if defined( _MSVC_ ) if ( logger_flag == 1 ) { if ( sysblk.shutimmed ) /* shutdown of logger is skipped in a Windows Environment * because we still have messages to write to the log file */ logmsg("HHCHD903I (%s) skipped during Windows SHUTDOWN immediate\n", loggercall->shdname); else { logmsg("HHCHD901I Calling %s\n",loggercall->shdname); { (loggercall->shdcall) (loggercall->shdarg); } logmsg("HHCHD902I %s complete\n",loggercall->shdname); free(loggercall); } } #endif // defined( _MSVC_ ) logmsg("HHCHD909I Shutdown sequence complete\n"); } #if defined(OPTION_DYNAMIC_LOAD) /* hdl_setpath - set path for module load */ DLL_EXPORT void hdl_setpath(char *path) { if(hdl_modpath) free(hdl_modpath); hdl_modpath = strdup(path); logmsg(_("HHCHD018I Loadable module directory is %s\n"),hdl_modpath); } static void * hdl_dlopen(char *filename, int flag _HDL_UNUSED) { char *fullname; void *ret; size_t fulllen = 0; if(filename && *filename != '/' && *filename != '.') { if(hdl_modpath && *hdl_modpath) { fulllen = strlen(filename) + strlen(hdl_modpath) + 2 + HDL_SUFFIX_LENGTH; fullname = malloc(fulllen); strlcpy(fullname,hdl_modpath,fulllen); strlcat(fullname,"/",fulllen); strlcat(fullname,filename,fulllen); #if defined(HDL_MODULE_SUFFIX) strlcat(fullname,HDL_MODULE_SUFFIX,fulllen); #endif } else fullname = filename; if((ret = dlopen(fullname,flag))) { if(fulllen) free(fullname); return ret; } #if defined(HDL_MODULE_SUFFIX) fullname[strlen(fullname) - HDL_SUFFIX_LENGTH] = '\0'; if((ret = dlopen(fullname,flag))) { if(fulllen) free(fullname); return ret; } #endif if(fulllen) free(fullname); fulllen=0; } if(filename && *filename != '/' && *filename != '.') { fulllen = strlen(filename) + 1 + HDL_SUFFIX_LENGTH; fullname = malloc(fulllen); strlcpy(fullname,filename,fulllen); #if defined(HDL_MODULE_SUFFIX) strlcat(fullname,HDL_MODULE_SUFFIX,fulllen); #endif if((ret = dlopen(fullname,flag))) { if(fulllen) free(fullname); return ret; } #if defined(HDL_MODULE_SUFFIX) fullname[strlen(fullname) - HDL_SUFFIX_LENGTH] = '\0'; if((ret = dlopen(fullname,flag))) { if(fulllen) free(fullname); return ret; } #endif if(fulllen) free(fullname); fulllen=0; } return dlopen(filename,flag); } /* hdl_dvad - register device type */ DLL_EXPORT void hdl_dvad (char *devname, DEVHND *devhnd) { HDLDEV *newhnd; newhnd = malloc(sizeof(HDLDEV)); newhnd->name = strdup(devname); newhnd->hnd = devhnd; newhnd->next = hdl_cdll->hndent; hdl_cdll->hndent = newhnd; } /* hdl_fhnd - find registered device handler */ static DEVHND * hdl_fhnd (const char *devname) { DLLENT *dllent; HDLDEV *hndent; for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { for(hndent = dllent->hndent; hndent; hndent = hndent->next) { if(!strcasecmp(devname,hndent->name)) { return hndent->hnd; } } } return NULL; } /* hdl_bdnm - build device module name */ static char * hdl_bdnm (const char *ltype) { char *dtname; unsigned int n; dtname = malloc(strlen(ltype) + sizeof(HDL_HDTP_Q)); strcpy(dtname,HDL_HDTP_Q); strcat(dtname,ltype); for(n = 0; n < strlen(dtname); n++) if(isupper(dtname[n])) dtname[n] = tolower(dtname[n]); return dtname; } /* hdl_ghnd - obtain device handler */ DLL_EXPORT DEVHND * hdl_ghnd (const char *devtype) { DEVHND *hnd; char *hdtname; char *ltype; if((hnd = hdl_fhnd(devtype))) return hnd; hdtname = hdl_bdnm(devtype); if(hdl_load(hdtname,HDL_LOAD_NOMSG) || !hdl_fhnd(devtype)) { if(hdl_device_type_equates) { if((ltype = hdl_device_type_equates(devtype))) { free(hdtname); hdtname = hdl_bdnm(ltype); hdl_load(hdtname,HDL_LOAD_NOMSG); } } } free(hdtname); return hdl_fhnd(devtype); } /* hdl_list - list all entry points */ DLL_EXPORT void hdl_list (int flags) { DLLENT *dllent; MODENT *modent; for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { logmsg("dll type = %s",(dllent->flags & HDL_LOAD_MAIN) ? "main" : "load"); logmsg(", name = %s",dllent->name); if (dllent->flags & (HDL_LOAD_NOUNLOAD | HDL_LOAD_WAS_FORCED)) { logmsg(", flags = (%s%s%s)" ,(dllent->flags & HDL_LOAD_NOUNLOAD) ? "nounload" : "" ,(dllent->flags & HDL_LOAD_NOUNLOAD) && (dllent->flags & HDL_LOAD_WAS_FORCED) ? ", " : "" ,(dllent->flags & HDL_LOAD_WAS_FORCED) ? "forced" : "" ); } logmsg("\n"); for(modent = dllent->modent; modent; modent = modent->modnext) if((flags & HDL_LIST_ALL) || !((dllent->flags & HDL_LOAD_MAIN) && !modent->fep)) { logmsg(" symbol = %s",modent->name); // logmsg(", ep = %p",modent->fep); if(modent->fep) logmsg(", loadcount = %d",modent->count); else logmsg(", unresolved"); logmsg(", owner = %s\n",dllent->name); } if(dllent->hndent) { HDLDEV *hndent; logmsg(" devtype ="); for(hndent = dllent->hndent; hndent; hndent = hndent->next) logmsg(" %s",hndent->name); logmsg("\n"); } if(dllent->insent) { HDLINS *insent; for(insent = dllent->insent; insent; insent = insent->next) { logmsg(" instruction = %s, opcode = %4.4X",insent->instname,insent->opcode); if(insent->archflags & HDL_INSTARCH_370) logmsg(", archmode = " _ARCH_370_NAME); if(insent->archflags & HDL_INSTARCH_390) logmsg(", archmode = " _ARCH_390_NAME); if(insent->archflags & HDL_INSTARCH_900) logmsg(", archmode = " _ARCH_900_NAME); logmsg("\n"); } } } } /* hdl_dlst - list all dependencies */ DLL_EXPORT void hdl_dlst (void) { HDLDEP *depent; for(depent = hdl_depend; depent; depent = depent->next) logmsg("dependency(%s) version(%s) size(%d)\n", depent->name,depent->version,depent->size); } /* hdl_dadd - add dependency */ static int hdl_dadd (char *name, char *version, int size) { HDLDEP **newdep; for (newdep = &(hdl_depend); *newdep; newdep = &((*newdep)->next)); (*newdep) = malloc(sizeof(HDLDEP)); (*newdep)->next = NULL; (*newdep)->name = strdup(name); (*newdep)->version = strdup(version); (*newdep)->size = size; return 0; } /* hdl_dchk - dependency check */ static int hdl_dchk (char *name, char *version, int size) { HDLDEP *depent; for(depent = hdl_depend; depent && strcmp(name,depent->name); depent = depent->next); if(depent) { if(strcmp(version,depent->version)) { logmsg(_("HHCHD010I Dependency check failed for %s, version(%s) expected(%s)\n"), name,version,depent->version); return -1; } if(size != depent->size) { logmsg(_("HHCHD011I Dependency check failed for %s, size(%d) expected(%d)\n"), name,size,depent->size); return -1; } } else { hdl_dadd(name,version,size); } return 0; } /* hdl_fent - find entry point */ DLL_EXPORT void * hdl_fent (char *name) { DLLENT *dllent; MODENT *modent; void *fep; /* Find entry point and increase loadcount */ for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { for(modent = dllent->modent; modent; modent = modent->modnext) { if(!strcmp(name,modent->name)) { modent->count++; return modent->fep; } } } /* If not found then lookup as regular symbol */ for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { if((fep = dlsym(dllent->dll,name))) { if(!(modent = malloc(sizeof(MODENT)))) { logmsg(_("HHCHD001E registration malloc failed for %s\n"), name); return NULL; } modent->fep = fep; modent->name = strdup(name); modent->count = 1; /* Insert current entry as first in chain */ modent->modnext = dllent->modent; dllent->modent = modent; return fep; } } /* No entry point found */ return NULL; } /* hdl_nent - find next entry point in chain */ DLL_EXPORT void * hdl_nent (void *fep) { DLLENT *dllent; MODENT *modent = NULL; char *name; for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { for(modent = dllent->modent; modent; modent = modent->modnext) { if(modent->fep == fep) break; } if(modent && modent->fep == fep) break; } if(!modent) return NULL; name = modent->name; if(!(modent = modent->modnext)) { if((dllent = dllent->dllnext)) modent = dllent->modent; else return NULL; } /* Find entry point */ for(; dllent; dllent = dllent->dllnext, modent = dllent->modent) { for(; modent; modent = modent->modnext) { if(!strcmp(name,modent->name)) { return modent->fep; } } } return NULL; } /* hdl_regi - register entry point */ static void hdl_regi (char *name, void *fep) { MODENT *modent; modent = malloc(sizeof(MODENT)); modent->fep = fep; modent->name = strdup(name); modent->count = 0; modent->modnext = hdl_cdll->modent; hdl_cdll->modent = modent; } /* hdl_term - process all "HDL_FINAL_SECTION"s */ static void hdl_term (void *unused _HDL_UNUSED) { DLLENT *dllent; logmsg("HHCHD950I Begin HDL termination sequence\n"); /* Call all final routines, in reverse load order */ for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { if(dllent->hdlfini) { logmsg("HHCHD951I Calling module %s cleanup routine\n",dllent->name); { (dllent->hdlfini)(); } logmsg("HHCHD952I Module %s cleanup complete\n",dllent->name); } } logmsg("HHCHD959I HDL Termination sequence complete\n"); } #if defined(_MSVC_) /* hdl_lexe - load exe */ static int hdl_lexe () { DLLENT *dllent; MODENT *modent; for(dllent = hdl_dll; dllent; dllent = dllent->dllnext); dllent->name = strdup("*Main"); if(!(dllent->dll = (void*)GetModuleHandle( NULL ) )); { logmsg(_("HHCHD007E unable to open DLL %s: %s\n"), dllent->name,dlerror()); free(dllent); return -1; } dllent->flags = HDL_LOAD_MAIN; if(!(dllent->hdldepc = dlsym(dllent->dll,HDL_DEPC_Q))) { logmsg(_("HHCHD013E No dependency section in %s: %s\n"), dllent->name, dlerror()); free(dllent); return -1; } dllent->hdlinit = dlsym(dllent->dll,HDL_INIT_Q); dllent->hdlreso = dlsym(dllent->dll,HDL_RESO_Q); dllent->hdlddev = dlsym(dllent->dll,HDL_DDEV_Q); dllent->hdldins = dlsym(dllent->dll,HDL_DINS_Q); dllent->hdlfini = dlsym(dllent->dll,HDL_FINI_Q); /* No modules or device types registered yet */ dllent->modent = NULL; dllent->hndent = NULL; dllent->insent = NULL; obtain_lock(&hdl_lock); if(dllent->hdldepc) { if((dllent->hdldepc)(&hdl_dchk)) { logmsg(_("HHCHD014E Dependency check failed for module %s\n"), dllent->name); } } hdl_cdll = dllent; /* Call initializer */ if(hdl_cdll->hdlinit) (dllent->hdlinit)(&hdl_regi); /* Insert current entry as first in chain */ dllent->dllnext = hdl_dll; hdl_dll = dllent; /* Reset the loadcounts */ for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) for(modent = dllent->modent; modent; modent = modent->modnext) modent->count = 0; /* Call all resolvers */ for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { if(dllent->hdlreso) (dllent->hdlreso)(&hdl_fent); } /* register any device types */ if(hdl_cdll->hdlddev) (hdl_cdll->hdlddev)(&hdl_dvad); /* register any new instructions */ if(hdl_cdll->hdldins) (hdl_cdll->hdldins)(&hdl_didf); hdl_cdll = NULL; release_lock(&hdl_lock); return 0; } #endif /* hdl_main - initialize hercules dynamic loader */ DLL_EXPORT void hdl_main (void) { HDLPRE *preload; initialize_lock(&hdl_lock); initialize_lock(&hdl_sdlock); hdl_setpath(HDL_DEFAULT_PATH); dlinit(); if(!(hdl_cdll = hdl_dll = malloc(sizeof(DLLENT)))) { fprintf(stderr, _("HHCHD002E cannot allocate memory for DLL descriptor: %s\n"), strerror(errno)); exit(1); } hdl_cdll->name = strdup("*Hercules"); /* This was a nice trick. Unfortunately, on some platforms */ /* it becomes impossible. Some platforms need fully defined */ /* DLLs, some other platforms do not allow dlopen(self) */ #if 1 if(!(hdl_cdll->dll = hdl_dlopen(NULL, RTLD_NOW ))) { fprintf(stderr, _("HHCHD003E unable to open hercules as DLL: %s\n"), dlerror()); exit(1); } hdl_cdll->flags = HDL_LOAD_MAIN | HDL_LOAD_NOUNLOAD; if(!(hdl_cdll->hdldepc = dlsym(hdl_cdll->dll,HDL_DEPC_Q))) { fprintf(stderr, _("HHCHD012E No dependency section in %s: %s\n"), hdl_cdll->name, dlerror()); exit(1); } hdl_cdll->hdlinit = dlsym(hdl_cdll->dll,HDL_INIT_Q); hdl_cdll->hdlreso = dlsym(hdl_cdll->dll,HDL_RESO_Q); hdl_cdll->hdlddev = dlsym(hdl_cdll->dll,HDL_DDEV_Q); hdl_cdll->hdldins = dlsym(hdl_cdll->dll,HDL_DINS_Q); hdl_cdll->hdlfini = dlsym(hdl_cdll->dll,HDL_FINI_Q); #else hdl_cdll->flags = HDL_LOAD_MAIN | HDL_LOAD_NOUNLOAD; hdl_cdll->hdldepc = &HDL_DEPC; hdl_cdll->hdlinit = &HDL_INIT; hdl_cdll->hdlreso = &HDL_RESO; hdl_cdll->hdlddev = &HDL_DDEV; hdl_cdll->hdldins = &HDL_DINS; hdl_cdll->hdlfini = &HDL_FINI; #endif /* No modules or device types registered yet */ hdl_cdll->modent = NULL; hdl_cdll->hndent = NULL; hdl_cdll->insent = NULL; /* No dll's loaded yet */ hdl_cdll->dllnext = NULL; obtain_lock(&hdl_lock); if(hdl_cdll->hdldepc) (hdl_cdll->hdldepc)(&hdl_dadd); if(hdl_cdll->hdlinit) (hdl_cdll->hdlinit)(&hdl_regi); if(hdl_cdll->hdlreso) (hdl_cdll->hdlreso)(&hdl_fent); if(hdl_cdll->hdlddev) (hdl_cdll->hdlddev)(&hdl_dvad); if(hdl_cdll->hdldins) (hdl_cdll->hdldins)(&hdl_didf); release_lock(&hdl_lock); /* Register termination exit */ hdl_adsc( "hdl_term", hdl_term, NULL); for(preload = hdl_preload; preload->name; preload++) hdl_load(preload->name, preload->flag); #if defined(_MSVC_) && 0 hdl_lexe(); #endif } /* hdl_load - load a dll */ DLL_EXPORT int hdl_load (char *name,int flags) { DLLENT *dllent, *tmpdll; MODENT *modent; char *modname; modname = (modname = strrchr(name,'/')) ? modname+1 : name; for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { if(strfilenamecmp(modname,dllent->name) == 0) { logmsg(_("HHCHD005E %s already loaded\n"),dllent->name); return -1; } } if(!(dllent = malloc(sizeof(DLLENT)))) { logmsg(_("HHCHD006S cannot allocate memory for DLL descriptor: %s\n"), strerror(errno)); return -1; } dllent->name = strdup(modname); if(!(dllent->dll = hdl_dlopen(name, RTLD_NOW))) { if(!(flags & HDL_LOAD_NOMSG)) logmsg(_("HHCHD007E unable to open DLL %s: %s\n"), name,dlerror()); free(dllent); return -1; } dllent->flags = (flags & (~HDL_LOAD_WAS_FORCED)); if(!(dllent->hdldepc = dlsym(dllent->dll,HDL_DEPC_Q))) { logmsg(_("HHCHD013E No dependency section in %s: %s\n"), dllent->name, dlerror()); dlclose(dllent->dll); free(dllent); return -1; } for(tmpdll = hdl_dll; tmpdll; tmpdll = tmpdll->dllnext) { if(tmpdll->hdldepc == dllent->hdldepc) { logmsg(_("HHCHD016E DLL %s is duplicate of %s\n"), dllent->name, tmpdll->name); dlclose(dllent->dll); free(dllent); return -1; } } dllent->hdlinit = dlsym(dllent->dll,HDL_INIT_Q); dllent->hdlreso = dlsym(dllent->dll,HDL_RESO_Q); dllent->hdlddev = dlsym(dllent->dll,HDL_DDEV_Q); dllent->hdldins = dlsym(dllent->dll,HDL_DINS_Q); dllent->hdlfini = dlsym(dllent->dll,HDL_FINI_Q); /* No modules or device types registered yet */ dllent->modent = NULL; dllent->hndent = NULL; dllent->insent = NULL; obtain_lock(&hdl_lock); if(dllent->hdldepc) { if((dllent->hdldepc)(&hdl_dchk)) { logmsg(_("HHCHD014E Dependency check failed for module %s\n"), dllent->name); if(!(flags & HDL_LOAD_FORCE)) { dlclose(dllent->dll); free(dllent); release_lock(&hdl_lock); return -1; } dllent->flags |= HDL_LOAD_WAS_FORCED; } } hdl_cdll = dllent; /* Call initializer */ if(hdl_cdll->hdlinit) (dllent->hdlinit)(&hdl_regi); /* Insert current entry as first in chain */ dllent->dllnext = hdl_dll; hdl_dll = dllent; /* Reset the loadcounts */ for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) for(modent = dllent->modent; modent; modent = modent->modnext) modent->count = 0; /* Call all resolvers */ for(dllent = hdl_dll; dllent; dllent = dllent->dllnext) { if(dllent->hdlreso) (dllent->hdlreso)(&hdl_fent); } /* register any device types */ if(hdl_cdll->hdlddev) (hdl_cdll->hdlddev)(&hdl_dvad); /* register any new instructions */ if(hdl_cdll->hdldins) (hdl_cdll->hdldins)(&hdl_didf); hdl_cdll = NULL; release_lock(&hdl_lock); return 0; } /* hdl_dele - unload a dll */ DLL_EXPORT int hdl_dele (char *name) { DLLENT **dllent, *tmpdll; MODENT *modent, *tmpmod; DEVBLK *dev; HDLDEV *hnd; HDLINS *ins; char *modname; modname = (modname = strrchr(name,'/')) ? modname+1 : name; obtain_lock(&hdl_lock); for(dllent = &(hdl_dll); *dllent; dllent = &((*dllent)->dllnext)) { if(strfilenamecmp(modname,(*dllent)->name) == 0) { if((*dllent)->flags & (HDL_LOAD_MAIN | HDL_LOAD_NOUNLOAD)) { logmsg(_("HHCHD015E Unloading of %s not allowed\n"),(*dllent)->name); release_lock(&hdl_lock); return -1; } for(dev = sysblk.firstdev; dev; dev = dev->nextdev) if(dev->pmcw.flag5 & PMCW5_V) for(hnd = (*dllent)->hndent; hnd; hnd = hnd->next) if(hnd->hnd == dev->hnd) { logmsg(_("HHCHD008E Device %4.4X bound to %s\n"),dev->devnum,(*dllent)->name); release_lock(&hdl_lock); return -1; } /* Call dll close routine */ if((*dllent)->hdlfini) { int rc; if((rc = ((*dllent)->hdlfini)())) { logmsg(_("HHCHD017E Unload of %s rejected by final section\n"),(*dllent)->name); release_lock(&hdl_lock); return rc; } } modent = (*dllent)->modent; while(modent) { tmpmod = modent; /* remove current entry from chain */ modent = modent->modnext; /* free module resources */ free(tmpmod->name); free(tmpmod); } tmpdll = *dllent; /* remove current entry from chain */ *dllent = (*dllent)->dllnext; for(hnd = tmpdll->hndent; hnd;) { HDLDEV *nexthnd; free(hnd->name); nexthnd = hnd->next; free(hnd); hnd = nexthnd; } for(ins = tmpdll->insent; ins;) { HDLINS *nextins; #ifdef ZZ_NO_BACKLINK hdl_modify_opcode(FALSE, ins); #endif free(ins->instname); nextins = ins->next; free(ins); ins = nextins; } // dlclose(tmpdll->dll); /* free dll resources */ free(tmpdll->name); free(tmpdll); /* Reset the loadcounts */ for(tmpdll = hdl_dll; tmpdll; tmpdll = tmpdll->dllnext) for(tmpmod = tmpdll->modent; tmpmod; tmpmod = tmpmod->modnext) tmpmod->count = 0; /* Call all resolvers */ for(tmpdll = hdl_dll; tmpdll; tmpdll = tmpdll->dllnext) { if(tmpdll->hdlreso) (tmpdll->hdlreso)(&hdl_fent); } release_lock(&hdl_lock); return 0; } } release_lock(&hdl_lock); logmsg(_("HHCHD009E %s not found\n"),modname); return -1; } #ifdef ZZ_NO_BACKLINK static void hdl_modify_optab(int insert,zz_func *tabent, HDLINS *instr) { if(insert) { #if defined(_370) if(instr->archflags & HDL_INSTARCH_370) { instr->original = tabent[ARCH_370]; tabent[ARCH_370] = instr->instruction; } #endif #if defined(_390) if(instr->archflags & HDL_INSTARCH_390) { instr->original = tabent[ARCH_390]; tabent[ARCH_390] = instr->instruction; } #endif #if defined(_900) if(instr->archflags & HDL_INSTARCH_900) { instr->original = tabent[ARCH_900]; tabent[ARCH_900] = instr->instruction; } #endif } else { #if defined(_370) if(instr->archflags & HDL_INSTARCH_370) tabent[ARCH_370] = instr->original; #endif #if defined(_900) if(instr->archflags & HDL_INSTARCH_390) tabent[ARCH_390] = instr->original; #endif #if defined(_900) if(instr->archflags & HDL_INSTARCH_900) tabent[ARCH_900] = instr->original; #endif } } static void hdl_modify_opcode(int insert, HDLINS *instr) { switch(instr->opcode & 0xff00) { case 0x0100: hdl_modify_optab(insert,opcode_01xx[instr->opcode & 0xff],instr); break; #if defined (FEATURE_VECTOR_FACILITY) case 0xA400: hdl_modify_optab(insert,v_opcode_a4xx[instr->opcode & 0xff],instr); table = v_opcode_a4xx; break; #endif case 0xA500: hdl_modify_optab(insert,opcode_a5xx[instr->opcode & 0x0f],instr); break; case 0xA700: hdl_modify_optab(insert,opcode_a7xx[instr->opcode & 0x0f],instr); break; case 0xB200: hdl_modify_optab(insert,opcode_b2xx[instr->opcode & 0xff],instr); break; case 0xB300: hdl_modify_optab(insert,opcode_b3xx[instr->opcode & 0xff],instr); break; case 0xB900: hdl_modify_optab(insert,opcode_b9xx[instr->opcode & 0xff],instr); break; case 0xC000: hdl_modify_optab(insert,opcode_c0xx[instr->opcode & 0x0f],instr); break; case 0xC200: hdl_modify_optab(insert,opcode_c2xx[instr->opcode & 0x0f],instr); break; case 0xC400: hdl_modify_optab(insert,opcode_c4xx[instr->opcode & 0x0f],instr); break; case 0xC600: hdl_modify_optab(insert,opcode_c6xx[instr->opcode & 0x0f],instr); break; case 0xC800: hdl_modify_optab(insert,opcode_c8xx[instr->opcode & 0x0f],instr); break; case 0xCC00: /*810*/ hdl_modify_optab(insert,opcode_ccxx[instr->opcode & 0x0f],instr); /*810*/ break; /*810*/ case 0xE300: hdl_modify_optab(insert,opcode_e3xx[instr->opcode & 0xff],instr); break; case 0xE500: hdl_modify_optab(insert,opcode_e5xx[instr->opcode & 0xff],instr); break; case 0xE600: hdl_modify_optab(insert,opcode_e6xx[instr->opcode & 0xff],instr); break; case 0xEB00: hdl_modify_optab(insert,opcode_ebxx[instr->opcode & 0xff],instr); break; case 0xEC00: hdl_modify_optab(insert,opcode_ecxx[instr->opcode & 0xff],instr); break; case 0xED00: hdl_modify_optab(insert,opcode_edxx[instr->opcode & 0xff],instr); break; default: hdl_modify_optab(insert,opcode_table[instr->opcode >> 8],instr); } /* Copy opcodes to shadow tables */ copy_opcode_tables(); } #endif /* hdl_didf - Define instruction call */ static void hdl_didf (int archflags, int opcode, char *name, void *routine) { HDLINS *newins; newins = malloc(sizeof(HDLINS)); newins->opcode = opcode > 0xff ? opcode : (opcode << 8) ; newins->archflags = archflags; newins->instname = strdup(name); newins->instruction = routine; newins->next = hdl_cdll->insent; hdl_cdll->insent = newins; #ifdef ZZ_NO_BACKLINK hdl_modify_opcode(TRUE, newins); #endif } #endif /*defined(OPTION_DYNAMIC_LOAD)*/ hercules-3.12/hostinfo.c0000664000175000017500000001104212564723224012176 00000000000000/* HOSTINFO.C (c) Copyright "Fish" (David B. Trout), 2002-2009 */ /* Set and query host information */ /* Released under the Q Public License */ /* (http://www.hercules-390.org/herclic.html) */ /* as modifications to Hercules. */ /*-------------------------------------------------------------------*/ /* functions to set/query host system information */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _HOSTINFO_C_ #define _HUTIL_DLL_ #include "hercules.h" DLL_EXPORT HOST_INFO hostinfo; /* Host system information */ /*-------------------------------------------------------------------*/ /* Initialize host system information */ /*-------------------------------------------------------------------*/ DLL_EXPORT void init_hostinfo ( HOST_INFO* pHostInfo ) { #if defined(_MSVC_) if ( !pHostInfo ) pHostInfo = &hostinfo; w32_init_hostinfo( pHostInfo ); #elif defined( HAVE_SYS_UTSNAME_H ) struct utsname uname_info; if ( !pHostInfo ) pHostInfo = &hostinfo; uname( &uname_info ); strlcpy( pHostInfo->sysname, uname_info.sysname, sizeof(pHostInfo->sysname) ); strlcpy( pHostInfo->nodename, uname_info.nodename, sizeof(pHostInfo->nodename) ); strlcpy( pHostInfo->release, uname_info.release, sizeof(pHostInfo->release) ); strlcpy( pHostInfo->version, uname_info.version, sizeof(pHostInfo->version) ); strlcpy( pHostInfo->machine, uname_info.machine, sizeof(pHostInfo->machine) ); pHostInfo->trycritsec_avail = 0; #if defined(HAVE_SYSCONF) && defined(HAVE_DECL__SC_NPROCESSORS_CONF) && HAVE_DECL__SC_NPROCESSORS_CONF pHostInfo->num_procs = sysconf(_SC_NPROCESSORS_CONF); #else pHostInfo->num_procs = 1; #endif #else if ( !pHostInfo ) pHostInfo = &hostinfo; strlcpy( pHostInfo->sysname, "(unknown)", sizeof(pHostInfo->sysname) ); strlcpy( pHostInfo->nodename, "(unknown)", sizeof(pHostInfo->nodename) ); strlcpy( pHostInfo->release, "(unknown)", sizeof(pHostInfo->release) ); strlcpy( pHostInfo->version, "(unknown)", sizeof(pHostInfo->version) ); strlcpy( pHostInfo->machine, "(unknown)", sizeof(pHostInfo->machine) ); pHostInfo->trycritsec_avail = 0; #if defined(HAVE_SYSCONF) && defined(HAVE_DECL__SC_NPROCESSORS_CONF) && HAVE_DECL__SC_NPROCESSORS_CONF pHostInfo->num_procs = sysconf(_SC_NPROCESSORS_CONF); #else pHostInfo->num_procs = 1; #endif #endif } /*-------------------------------------------------------------------*/ /* Build a host system information string for displaying purposes */ /* (the returned string does NOT end with a newline) */ /*-------------------------------------------------------------------*/ DLL_EXPORT char* get_hostinfo_str ( HOST_INFO* pHostInfo, char* pszHostInfoStrBuff, size_t nHostInfoStrBuffSiz ) { if ( pszHostInfoStrBuff && nHostInfoStrBuffSiz ) { char num_procs[16]; if ( !pHostInfo ) pHostInfo = &hostinfo; if ( pHostInfo->num_procs > 1 ) snprintf( num_procs, sizeof(num_procs), " MP=%d", pHostInfo->num_procs ); else if ( pHostInfo->num_procs == 1 ) strlcpy( num_procs, " UP", sizeof(num_procs) ); else strlcpy( num_procs, "", sizeof(num_procs) ); snprintf( pszHostInfoStrBuff, nHostInfoStrBuffSiz, _("Running on %s %s-%s.%s %s%s"), pHostInfo->nodename, pHostInfo->sysname, pHostInfo->release, pHostInfo->version, pHostInfo->machine, num_procs ); *(pszHostInfoStrBuff + nHostInfoStrBuffSiz - 1) = 0; } return pszHostInfoStrBuff; } /*-------------------------------------------------------------------*/ /* Display host system information on the indicated stream */ /*-------------------------------------------------------------------*/ DLL_EXPORT void display_hostinfo ( HOST_INFO* pHostInfo, FILE *f, int httpfd ) { char host_info_str[256]; init_hostinfo( pHostInfo ); get_hostinfo_str(pHostInfo, host_info_str, sizeof(host_info_str)); if(httpfd<0) { if (!f) f = stdout; if (f != stdout) fprintf(f, "%s\n", host_info_str); else logmsg( "%s\n", host_info_str); } else { hprintf(httpfd,"%s\n",host_info_str); } } hercules-3.12/hsocket.c0000664000175000017500000000705012564723224012011 00000000000000/* HSOCKET.C (c) Copyright Robert Styma, 2006 */ /* Socket read/write routines */ #include "hstdinc.h" #define _HSOCKET_C_ #define _HUTIL_DLL_ #include "hercules.h" /************************************************************************ NAME: read_socket - read a passed number of bytes from a socket. PURPOSE: This routine is used in place of read to read a passed number of bytes from a socket. A read on a socket will return less than the number of bytes requested if there are less currenly available. Thus we read in a loop till we get all we want. PARAMETERS: 1. fd - int (INPUT) This is the file descriptor for the socket to be read. 2. ptr - pointer to void (OUTPUT) This is a pointer to where the data is to be put. 3. nbytes - int (INPUT) This is the number of bytes to read. FUNCTIONS : 1. Read in a loop till an error occurs or the data is read. OUTPUTS: data into the buffer *************************************************************************/ DLL_EXPORT int read_socket(int fd, void *_ptr, int nbytes) { int nleft, nread; char *ptr; nleft = nbytes; ptr=_ptr; while (nleft > 0) { #ifdef _MSVC_ nread = recv(fd, ptr, nleft, 0); if ((nread == SOCKET_ERROR) || (nread < 0)) { nread = -1; break; /* error, return < 0 */ } if (nread == 0) break; #else nread = read(fd, ptr, nleft); if (nread < 0) return(nread); /* error, return < 0 */ else if (nread == 0) /* eof */ break; #endif nleft -= nread; ptr += nread; } /* end of do while */ /* if (nleft != 0) logmsg (_("BOB123 read_socket: Read of %d bytes requested, %d bytes actually read\n"), nbytes, nbytes - nleft);*/ return (nbytes - nleft); } /* end of read_socket */ /************************************************************************ NAME: write_socket - write a passed number of bytes into a socket. PURPOSE: This routine is used in place of write to write a passed number of bytes into a socket. A write on a socket may take less than the number of bytes requested if there is currently insufficient buffer space available. Thus we write in a loop till we get all we want. PARAMETERS: 1. fd - int (OUTPUT) This is the file descriptor for the socket to be written. 2. ptr - pointer to void (INPUT) This is a pointer to where the data is to be gotten from. 3. nbytes - int (INPUT) This is the number of bytes to write. FUNCTIONS : 1. Write in a loop till an error occurs or the data is written. OUTPUTS: Data to the socket. *************************************************************************/ /* * Write "n" bytes to a descriptor. * Use in place of write() when fd is a stream socket. */ DLL_EXPORT int write_socket(int fd, const void *_ptr, int nbytes) { int nleft, nwritten; const char *ptr; nleft = nbytes; ptr=_ptr; while (nleft > 0) { #ifdef _MSVC_ nwritten = send(fd, ptr, nleft, 0); if (nwritten <= 0) { return(nwritten); /* error */ } #else nwritten = write(fd, ptr, nleft); if (nwritten <= 0) return(nwritten); /* error */ #endif nleft -= nwritten; ptr += nwritten; } /* end of do while */ return(nbytes - nleft); } /* end of write_socket */ hercules-3.12/parser.c0000664000175000017500000001022512564723224011643 00000000000000/* PARSER.C (c) Copyright Leland Lucius, 2001 */ /* Simple parameter parser */ #include "hstdinc.h" #define _PARSER_C_ #define _HUTIL_DLL_ #include "hercules.h" #include "parser.h" #if !defined( NULL ) #define NULL 0 #endif /* NAME parser - parse parameter strings SYNOPSIS #include "parser.h" int parser( PARSER *pp, char *str, void *res ) DESCRIPTION The parser() function breaks the str parameter into a keyword and value using the "=" as a delimiter. The pp table is then scanned for the keyword. If found and the table entry specifies a format string, then parser() will use sscanf() to store the value at the location specifed by res. The PARSER table entries consist of a string pointer that designates the keyword and a string pointer that designates the format of the associated value. The format may be set to NULL if the keyword does not take a value. The table must be terminated with an entry that specifies NULL for the keyword string. RETURN VALUE If no errors are detected then the returned value will be the index+1 of the matching table entry. The res argument will be updated only when a format string is specified. If an entry couldn't be found, zero will be returned and res will remain untouched. If an entry is found, but an error is detected while processing the str parameter then a negative value is returned. This value will be the index-1 of the matching table entry. EXAMPLE #include "parser.h" #include PARSER ptab[] = { { "switchkey", NULL }, { "numkey", "%d" }, { "strkey", "%s" }, }; int main( int argc, char *argv[] ) { int rc; union { int num; char str[ 80 ]; } res; while( --argc ) { rc = parser( &ptab[0], argv[ argc ], &res ); printf( "parser() rc = %d\n", rc ); if( rc < 0 ) { printf( "error parsing keyword: %s\n", ptab[ abs( rc 1 ) ].key ); } else if( rc == 0 ) { printf( "unrecognized keyword: %s\n", argv[ argc ] ); } else { switch( rc ) { case 1: printf( "found switchkey\n" ); break; case 2: printf( "numkey value is: %d\n", res.num ); break; case 3: printf( "strkey value is: %s\n", res.str ); break; } } } } SEE ALSO sscanf(3) */ DLL_EXPORT int parser( PARSER *pp, char *str, void *res ) { int ndx; char *key; char *val; ndx = 1; key = strtok( str, "=" ); val = strtok( NULL, "=" ); while( pp->key != NULL ) { if( strcasecmp( key, pp->key ) == 0 ) { if( pp->fmt == NULL ) { if( val != NULL ) { return( -ndx ); } } else { if( val == NULL ) { return( -ndx ); } if( sscanf( val, pp->fmt, res ) != 1 ) { return( -ndx ); } } return( ndx ); } pp++; ndx++; } return( 0 ); } hercules-3.12/pttrace.c0000664000175000017500000004645712564723224012031 00000000000000/* PTTRACE.C (c) Copyright Greg Smith, 2003-2010 */ /* pthreads trace debugger */ /*-------------------------------------------------------------------*/ /* Trace threading calls */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _PTTRACE_C_ #define _HUTIL_DLL_ #include "hercules.h" #ifdef OPTION_PTTRACE PTT_TRACE *pttrace; /* Pthreads trace table */ int pttracex; /* Pthreads trace index */ int pttracen; /* Pthreads trace entries */ LOCK pttlock; /* Pthreads trace lock */ int pttnolock; /* 1=no PTT locking */ int pttnotod; /* 1=don't call gettimeofday */ int pttnowrap; /* 1=don't wrap */ int pttto; /* timeout in seconds */ TID ptttotid; /* timeout thread id */ LOCK ptttolock; /* timeout thread lock */ COND ptttocond; /* timeout thread condition */ DLL_EXPORT void ptt_trace_init (int n, int init) { if (n > 0) pttrace = calloc (n, PTT_TRACE_SIZE); else pttrace = NULL; if (pttrace) pttracen = n; else pttracen = 0; pttracex = 0; if (init) { #if defined(OPTION_FTHREADS) fthread_mutex_init (&pttlock, NULL); #else pthread_mutex_init (&pttlock, NULL); #endif pttnolock = 0; pttnotod = 0; pttnowrap = 0; pttto = 0; ptttotid = 0; #if defined(OPTION_FTHREADS) fthread_mutex_init (&ptttolock, NULL); fthread_cond_init (&ptttocond); #else pthread_mutex_init (&ptttolock, NULL); pthread_cond_init (&ptttocond, NULL); #endif } } DLL_EXPORT int ptt_cmd(int argc, char *argv[], char* cmdline) { int rc = 0; int n, to = -1; char c; UNREFERENCED(cmdline); if (argc > 1) { /* process arguments; last arg can be trace table size */ for (--argc, argv++; argc; --argc, ++argv) { if (strcasecmp("opts", argv[0]) == 0) continue; else if (strcasecmp("error", argv[0]) == 0) { pttclass |= PTT_CL_ERR; continue; } else if (strcasecmp("noerror", argv[0]) == 0) { pttclass &= ~PTT_CL_ERR; continue; } else if (strcasecmp("control", argv[0]) == 0) { pttclass |= PTT_CL_INF; continue; } else if (strcasecmp("nocontrol", argv[0]) == 0) { pttclass &= ~PTT_CL_INF; continue; } else if (strcasecmp("prog", argv[0]) == 0) { pttclass |= PTT_CL_PGM; continue; } else if (strcasecmp("noprog", argv[0]) == 0) { pttclass &= ~PTT_CL_PGM; continue; } else if (strcasecmp("inter", argv[0]) == 0) { pttclass |= PTT_CL_CSF; continue; } else if (strcasecmp("nointer", argv[0]) == 0) { pttclass &= ~PTT_CL_CSF; continue; } else if (strcasecmp("sie", argv[0]) == 0) { pttclass |= PTT_CL_SIE; continue; } else if (strcasecmp("nosie", argv[0]) == 0) { pttclass &= ~PTT_CL_SIE; continue; } else if (strcasecmp("signal", argv[0]) == 0) { pttclass |= PTT_CL_SIG; continue; } else if (strcasecmp("nosignal", argv[0]) == 0) { pttclass &= ~PTT_CL_SIG; continue; } else if (strcasecmp("io", argv[0]) == 0) { pttclass |= PTT_CL_IO; continue; } else if (strcasecmp("noio", argv[0]) == 0) { pttclass &= ~PTT_CL_IO; continue; } else if (strcasecmp("timer", argv[0]) == 0) { pttclass |= PTT_CL_TMR; continue; } else if (strcasecmp("notimer", argv[0]) == 0) { pttclass &= ~PTT_CL_TMR; continue; } else if (strcasecmp("logger", argv[0]) == 0) { pttclass |= PTT_CL_LOG; continue; } else if (strcasecmp("nologger", argv[0]) == 0) { pttclass &= ~PTT_CL_LOG; continue; } else if (strcasecmp("nothreads", argv[0]) == 0) { pttclass &= ~PTT_CL_THR; continue; } else if (strcasecmp("threads", argv[0]) == 0) { pttclass |= PTT_CL_THR; continue; } else if (strcasecmp("nolock", argv[0]) == 0) { pttnolock = 1; continue; } else if (strcasecmp("lock", argv[0]) == 0) { pttnolock = 0; continue; } else if (strcasecmp("notod", argv[0]) == 0) { pttnotod = 1; continue; } else if (strcasecmp("tod", argv[0]) == 0) { pttnotod = 0; continue; } else if (strcasecmp("nowrap", argv[0]) == 0) { pttnowrap = 1; continue; } else if (strcasecmp("wrap", argv[0]) == 0) { pttnowrap = 0; continue; } else if (strncasecmp("to=", argv[0], 3) == 0 && strlen(argv[0]) > 3 && (sscanf(&argv[0][3], "%d%c", &to, &c) == 1 && to >= 0)) { pttto = to; continue; } else if (argc == 1 && sscanf(argv[0], "%d%c", &n, &c) == 1 && n >= 0) { OBTAIN_PTTLOCK; if (pttracen == 0) { if (pttrace != NULL) { RELEASE_PTTLOCK; logmsg( _("HHCPT002E Trace is busy\n")); return -1; } } else if (pttrace) { pttracen = 0; RELEASE_PTTLOCK; usleep(1000); OBTAIN_PTTLOCK; free (pttrace); pttrace = NULL; } ptt_trace_init (n, 0); RELEASE_PTTLOCK; } else { logmsg( _("HHCPT001E Invalid value: %s\n"), argv[0]); rc = -1; break; } } /* for each ptt argument */ /* wakeup timeout thread if to= specified */ if (to >= 0 && ptttotid) { obtain_lock (&ptttolock); ptttotid = 0; signal_condition (&ptttocond); release_lock (&ptttolock); } /* start timeout thread if positive to= specified */ if (to > 0) { obtain_lock (&ptttolock); ptttotid = 0; create_thread (&ptttotid, NULL, ptt_timeout, NULL, "ptt_timeout"); release_lock (&ptttolock); } } else { if (pttracen) rc = ptt_pthread_print(); logmsg( _("HHCPT003I ptt %s%s%s%s%s%s%s%s%s%s%s %s %s to=%d %d\n"), (pttclass & PTT_CL_INF) ? "control " : "", (pttclass & PTT_CL_ERR) ? "error " : "", (pttclass & PTT_CL_PGM) ? "prog " : "", (pttclass & PTT_CL_CSF) ? "inter " : "", (pttclass & PTT_CL_SIE) ? "sie " : "", (pttclass & PTT_CL_SIG) ? "signal " : "", (pttclass & PTT_CL_IO) ? "io " : "", (pttclass & PTT_CL_TMR) ? "timer " : "", (pttclass & PTT_CL_THR) ? "threads " : "", (pttclass & PTT_CL_LOG) ? "logger " : "", pttnolock ? "nolock" : "lock", pttnotod ? "notod" : "tod", pttnowrap ? "nowrap" : "wrap", pttto, pttracen); } return rc; } /* thread to print trace after timeout */ void *ptt_timeout() { struct timeval now; struct timespec tm; obtain_lock (&ptttolock); gettimeofday (&now, NULL); tm.tv_sec = now.tv_sec + pttto; tm.tv_nsec = now.tv_usec * 1000; timed_wait_condition (&ptttocond, &ptttolock, &tm); if (thread_id() == ptttotid) { ptt_pthread_print(); pttto = 0; ptttotid = 0; } release_lock (&ptttolock); return NULL; } #ifndef OPTION_FTHREADS DLL_EXPORT int ptt_pthread_mutex_init(LOCK *mutex, pthread_mutexattr_t *attr, char *loc) { PTTRACE ("lock init", mutex, attr, loc, PTT_MAGIC); return pthread_mutex_init(mutex, attr); } DLL_EXPORT int ptt_pthread_mutex_lock(LOCK *mutex, char *loc) { int result; PTTRACE ("lock before", mutex, NULL, loc, PTT_MAGIC); result = pthread_mutex_lock(mutex); PTTRACE ("lock after", mutex, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_mutex_trylock(LOCK *mutex, char *loc) { int result; PTTRACE ("try before", mutex, NULL, loc, PTT_MAGIC); result = pthread_mutex_trylock(mutex); PTTRACE ("try after", mutex, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_mutex_unlock(LOCK *mutex, char *loc) { int result; result = pthread_mutex_unlock(mutex); PTTRACE ("unlock", mutex, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_init(COND *cond, pthread_condattr_t *attr, char *loc) { PTTRACE ("cond init", NULL, cond, loc, PTT_MAGIC); return pthread_cond_init(cond, attr); } DLL_EXPORT int ptt_pthread_cond_signal(COND *cond, char *loc) { int result; result = pthread_cond_signal(cond); PTTRACE ("signal", NULL, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_broadcast(COND *cond, char *loc) { int result; result = pthread_cond_broadcast(cond); PTTRACE ("broadcast", NULL, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_wait(COND *cond, LOCK *mutex, char *loc) { int result; PTTRACE ("wait before", mutex, cond, loc, PTT_MAGIC); result = pthread_cond_wait(cond, mutex); PTTRACE ("wait after", mutex, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_timedwait(COND *cond, LOCK *mutex, const struct timespec *time, char *loc) { int result; PTTRACE ("tw before", mutex, cond, loc, PTT_MAGIC); result = pthread_cond_timedwait(cond, mutex, time); PTTRACE ("tw after", mutex, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_create(pthread_t *tid, ATTR *attr, void *(*start)(), void *arg, char *nm, char *loc) { int result; UNREFERENCED(nm); result = pthread_create(tid, attr, start, arg); PTTRACE ("create", (void *)*tid, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_join(pthread_t tid, void **value, char *loc) { int result; PTTRACE ("join before", (void *)tid, value ? *value : NULL, loc, PTT_MAGIC); result = pthread_join(tid,value); PTTRACE ("join after", (void *)tid, value ? *value : NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_detach(pthread_t tid, char *loc) { int result; PTTRACE ("dtch before", (void *)tid, NULL, loc, PTT_MAGIC); result = pthread_detach(tid); PTTRACE ("dtch after", (void *)tid, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_kill(pthread_t tid, int sig, char *loc) { PTTRACE ("kill", (void *)tid, (void *)(long)sig, loc, PTT_MAGIC); return pthread_kill(tid, sig); } #else /* OPTION_FTHREADS */ DLL_EXPORT int ptt_pthread_mutex_init(LOCK *mutex, void *attr, char *loc) { PTTRACE ("lock init", mutex, attr, loc, PTT_MAGIC); return fthread_mutex_init(mutex,attr); } DLL_EXPORT int ptt_pthread_mutex_lock(LOCK *mutex, char *loc) { int result; PTTRACE ("lock before", mutex, NULL, loc, PTT_MAGIC); result = fthread_mutex_lock(mutex); PTTRACE ("lock after", mutex, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_mutex_trylock(LOCK *mutex, char *loc) { int result; PTTRACE ("try before", mutex, NULL, loc, PTT_MAGIC); result = fthread_mutex_trylock(mutex); PTTRACE ("try after", mutex, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_mutex_unlock(LOCK *mutex, char *loc) { int result; result = fthread_mutex_unlock(mutex); PTTRACE ("unlock", mutex, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_init(COND *cond, void *attr, char *loc) { UNREFERENCED(attr); PTTRACE ("cond init", NULL, cond, loc, PTT_MAGIC); return fthread_cond_init(cond); } DLL_EXPORT int ptt_pthread_cond_signal(COND *cond, char *loc) { int result; result = fthread_cond_signal(cond); PTTRACE ("signal", NULL, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_broadcast(COND *cond, char *loc) { int result; result = fthread_cond_broadcast(cond); PTTRACE ("broadcast", NULL, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_wait(COND *cond, LOCK *mutex, char *loc) { int result; PTTRACE ("wait before", mutex, cond, loc, PTT_MAGIC); result = fthread_cond_wait(cond, mutex); PTTRACE ("wait after", mutex, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_cond_timedwait(COND *cond, LOCK *mutex, struct timespec *time, char *loc) { int result; PTTRACE ("tw before", mutex, cond, loc, PTT_MAGIC); result = fthread_cond_timedwait(cond, mutex, time); PTTRACE ("tw after", mutex, cond, loc, result); return result; } DLL_EXPORT int ptt_pthread_create(fthread_t *tid, ATTR *attr, PFT_THREAD_FUNC start, void *arg, char *nm, char *loc) { int result; result = fthread_create(tid, attr, start, arg, nm); PTTRACE ("create", (void *)(uintptr_t)(*tid), NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_join(fthread_t tid, void **value, char *loc) { int result; PTTRACE ("join before", (void *)(uintptr_t)tid, value ? *value : NULL, loc, PTT_MAGIC); result = fthread_join(tid,value); PTTRACE ("join after", (void *)(uintptr_t)tid, value ? *value : NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_detach(fthread_t tid, char *loc) { int result; PTTRACE ("dtch before", (void *)(uintptr_t)tid, NULL, loc, PTT_MAGIC); result = fthread_detach(tid); PTTRACE ("dtch after", (void *)(uintptr_t)tid, NULL, loc, result); return result; } DLL_EXPORT int ptt_pthread_kill(fthread_t tid, int sig, char *loc) { PTTRACE ("kill", (void *)(uintptr_t)tid, (void *)(uintptr_t)sig, loc, PTT_MAGIC); return fthread_kill(tid, sig); } #endif DLL_EXPORT void ptt_pthread_trace (int class, char * type, void *data1, void *data2, char *loc, int result) { int i, n; if (pttrace == NULL || pttracen == 0 || !(pttclass & class) ) return; /* ** Fish debug: it appears MSVC sometimes sets the __FILE__ macro ** to a full path filename (rather than just the filename only) ** under certain circumstances. (I think maybe it's only for .h ** files since vstore.h is the one that's messing up). Therefore ** for MSVC we need to convert it to just the filename. ((sigh)) */ #if defined( _MSVC_ ) // fish debug; appears to be vstore.h // maybe all *.h files are this way?? { char* p = strrchr( loc, '\\' ); if (!p) p = strrchr( loc, '/' ); if (p) loc = p+1; } #endif /* * Messages from timer.c, clock.c and/or logger.c are not usually * that interesting and take up table space. Check the flags to * see if we want to trace them. */ if (!strncasecmp(loc, "timer.c:", 8) && !(pttclass & PTT_CL_TMR)) return; if (!strncasecmp(loc, "clock.c:", 8) && !(pttclass & PTT_CL_TMR)) return; if (!strncasecmp(loc, "logger.c:", 9) && !(pttclass & PTT_CL_LOG)) return; /* check for `nowrap' */ if (pttnowrap && pttracex + 1 >= pttracen) return; OBTAIN_PTTLOCK; if (pttrace == NULL || (n = pttracen) == 0) { RELEASE_PTTLOCK; return; } i = pttracex++; if (pttracex >= n) pttracex = 0; RELEASE_PTTLOCK; pttrace[i].tid = thread_id(); pttrace[i].class = class; pttrace[i].type = type; pttrace[i].data1 = data1; pttrace[i].data2 = data2; pttrace[i].loc = loc; if (pttnotod == 0) gettimeofday(&pttrace[i].tv,NULL); pttrace[i].result = result; } DLL_EXPORT int ptt_pthread_print () { int i, n, count = 0; char result[32]; // (result is 'int'; if 64-bits, 19 digits or more!) char tbuf[256]; time_t tt; const char dot = '.'; if (pttrace == NULL || pttracen == 0) return count; OBTAIN_PTTLOCK; n = pttracen; pttracen = 0; RELEASE_PTTLOCK; i = pttracex; do { if (pttrace[i].tid) { tt = pttrace[i].tv.tv_sec; strcpy(tbuf, ctime(&tt)); tbuf[19] = '\0'; if (pttrace[i].result == PTT_MAGIC && (pttrace[i].class & PTT_CL_THR)) result[0] = '\0'; else if((pttrace[i].class & ~PTT_CL_THR)) sprintf(result, "%8.8x", pttrace[i].result); else sprintf(result, "%d", pttrace[i].result); logmsg ( "%8.8"I32_FMT"x " // Thread id (low 32 bits) "%-12.12s " // Trace type (string; 12 chars) PTR_FMTx" " // Data value 1 PTR_FMTx" " // Data value 2 "%-18.18s " // File name "%s%c%6.6ld " // Time of day (HH:MM:SS.usecs) "%s\n" // Numeric result (or empty string) ,(U32)(uintptr_t)(pttrace[i].tid) // Thread id (low 32 bits) ,pttrace[i].type // Trace type (string; 12 chars) ,(uintptr_t)pttrace[i].data1 // Data value 1 ,(uintptr_t)pttrace[i].data2 // Data value 2 ,pttrace[i].loc // File name ,tbuf + 11 // Time of day (HH:MM:SS) ,dot // Time of day (decimal point) ,pttrace[i].tv.tv_usec // Time of day (microseconds) ,result // Numeric result (or empty string) ); count++; } if (++i >= n) i = 0; } while (i != pttracex); memset (pttrace, 0, PTT_TRACE_SIZE * n); pttracex = 0; pttracen = n; return count; } #endif hercules-3.12/cckdcdsk.c0000664000175000017500000001156012564723224012123 00000000000000/* CCKDCDSK.C (c) Copyright Greg Smith, 2000-2009 */ /* Perform chkdsk for Compressed CKD DASD file */ /*-------------------------------------------------------------------*/ /* Perform check function on a compressed ckd file */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" int syntax (); /*-------------------------------------------------------------------*/ /* Main function for stand-alone chkdsk */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int i; /* Index */ int rc; /* Return code */ int level=1; /* Chkdsk level checking */ int ro=0; /* 1=Open readonly */ int force=0; /* 1=Check if OPENED bit on */ CCKDDASD_DEVHDR cdevhdr; /* Compressed CKD device hdr */ DEVBLK devblk; /* DEVBLK */ DEVBLK *dev=&devblk; /* -> DEVBLK */ INITIALIZE_UTILITY("cckdcdsk"); /* parse the arguments */ for (argc--, argv++ ; argc > 0 ; argc--, argv++) { if(**argv != '-') break; switch(argv[0][1]) { case '0': case '1': case '2': case '3': case '4': if (argv[0][2] != '\0') return syntax (); level = (argv[0][1] & 0xf); break; case 'f': if (argv[0][2] != '\0') return syntax (); force = 1; break; case 'r': if (argv[0][2] == 'o' && argv[0][3] == '\0') ro = 1; else return syntax (); break; case 'v': if (argv[0][2] != '\0') return syntax (); display_version (stderr, "Hercules cckd chkdsk program ", FALSE); return 0; default: return syntax (); } } if (argc < 1) return syntax (); for (i = 0; i < argc; i++) { memset (dev, 0, sizeof(DEVBLK)); dev->batch = 1; /* open the file */ hostpath(dev->filename, argv[i], sizeof(dev->filename)); dev->fd = hopen(dev->filename, ro ? O_RDONLY|O_BINARY : O_RDWR|O_BINARY); if (dev->fd < 0) { cckdumsg (dev, 700, "open error: %s\n", strerror(errno)); continue; } /* Check CCKD_OPENED bit if -f not specified */ if (!force) { if (lseek (dev->fd, CCKD_DEVHDR_POS, SEEK_SET) < 0) { cckdumsg (dev, 702, "lseek error offset 0x%" I64_FMT "x: %s\n", (long long)CCKD_DEVHDR_POS, strerror(errno)); close (dev->fd); continue; } if ((rc = read (dev->fd, &cdevhdr, CCKD_DEVHDR_SIZE)) < CCKD_DEVHDR_SIZE) { cckdumsg (dev, 703, "read error rc=%d offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)CCKD_DEVHDR_POS, CCKD_DEVHDR_SIZE, rc < 0 ? strerror(errno) : "incomplete"); close (dev->fd); continue; } if (cdevhdr.options & CCKD_OPENED) { cckdumsg (dev, 707, "OPENED bit is on, use -f\n"); close (dev->fd); continue; } } /* if (!force) */ rc = cckd_chkdsk (dev, level); close (dev->fd); } /* for each arg */ return 0; } /*-------------------------------------------------------------------*/ /* print syntax */ /*-------------------------------------------------------------------*/ int syntax() { fprintf (stderr, _("\ncckdcdsk [-v] [-f] [-level] [-ro] file1 [file2 ...]\n" "\n" " -v display version and exit\n" "\n" " -f force check even if OPENED bit is on\n" "\n" " level is a digit 0 - 4:\n" " -0 -- minimal checking (hdr, chdr, l1tab, l2tabs)\n" " -1 -- normal checking (hdr, chdr, l1tab, l2tabs, free spaces)\n" " -2 -- extra checking (hdr, chdr, l1tab, l2tabs, free spaces, trkhdrs)\n" " -3 -- maximal checking (hdr, chdr, l1tab, l2tabs, free spaces, trkimgs)\n" " -4 -- recover everything without using meta-data\n" "\n" " -ro open file readonly, no repairs\n" "\n")); return -1; } hercules-3.12/cckdcomp.c0000664000175000017500000001104312564723224012131 00000000000000/* CCKDCOMP.C (c) Copyright Greg Smith, 2000-2009 */ /* Compress a Compressed CKD DASD file */ /*-------------------------------------------------------------------*/ /* Remove all free space on a compressed ckd file */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" int syntax (); /*-------------------------------------------------------------------*/ /* Main function for stand-alone compress */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int i; /* Index */ int rc; /* Return code */ int level=-1; /* Level for chkdsk */ int force=0; /* 1=Compress if OPENED set */ CCKDDASD_DEVHDR cdevhdr; /* Compressed CKD device hdr */ DEVBLK devblk; /* DEVBLK */ DEVBLK *dev=&devblk; /* -> DEVBLK */ INITIALIZE_UTILITY("cckdcomp"); /* parse the arguments */ for (argc--, argv++ ; argc > 0 ; argc--, argv++) { if(**argv != '-') break; switch(argv[0][1]) { case '0': case '1': case '2': case '3': if (argv[0][2] != '\0') return syntax (); level = (argv[0][1] & 0xf); break; case 'f': if (argv[0][2] != '\0') return syntax (); force = 1; break; case 'v': if (argv[0][2] != '\0') return syntax (); display_version (stderr, "Hercules cckd compress program ", FALSE); return 0; default: return syntax (); } } if (argc < 1) return syntax (); for (i = 0; i < argc; i++) { memset (dev, 0, sizeof(DEVBLK)); dev->batch = 1; /* open the file */ hostpath(dev->filename, argv[i], sizeof(dev->filename)); dev->fd = hopen(dev->filename, O_RDWR|O_BINARY); if (dev->fd < 0) { cckdumsg (dev, 700, "open error: %s\n", strerror(errno)); continue; } /* Check CCKD_OPENED bit if -f not specified */ if (!force) { if (lseek (dev->fd, CCKD_DEVHDR_POS, SEEK_SET) < 0) { cckdumsg (dev, 702, "lseek error offset 0x%" I64_FMT "x: %s\n", (long long)CCKD_DEVHDR_POS, strerror(errno)); close (dev->fd); continue; } if ((rc = read (dev->fd, &cdevhdr, CCKD_DEVHDR_SIZE)) < CCKD_DEVHDR_SIZE) { cckdumsg (dev, 703, "read error rc=%d offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)CCKD_DEVHDR_POS, CCKD_DEVHDR_SIZE, rc < 0 ? strerror(errno) : "incomplete"); close (dev->fd); continue; } if (cdevhdr.options & CCKD_OPENED) { cckdumsg (dev, 707, "OPENED bit is on, use -f\n"); close (dev->fd); continue; } } /* if (!force) */ /* call chkdsk */ if (cckd_chkdsk (dev, level) < 0) { cckdumsg (dev, 708, "chkdsk errors\n"); close (dev->fd); continue; } /* call compress */ rc = cckd_comp (dev); close (dev->fd); } /* for each arg */ return 0; } /*-------------------------------------------------------------------*/ /* print syntax */ /*-------------------------------------------------------------------*/ int syntax() { fprintf (stderr, "\ncckdcomp [-v] [-f] [-level] file1 [file2 ... ]\n" "\n" " -v display version and exit\n" "\n" " -f force check even if OPENED bit is on\n" "\n" " chkdsk level is a digit 0 - 3:\n" " -0 -- minimal checking\n" " -1 -- normal checking\n" " -2 -- intermediate checking\n" " -3 -- maximal checking\n" " default 0\n" "\n"); return -1; } hercules-3.12/cckddiag.c0000664000175000017500000006571012564723224012111 00000000000000/* CCKDDIAG.C (c) Copyright Greg Smith, 2000-2009 */ /* (c) Copyright James M. Morrison, 2003 */ /* CCKD diagnostic tool */ /* 2003-02-07 James M. Morrison initial implementation */ /* portions borrowed from cckdcdsk & other CCKD code */ /*-------------------------------------------------------------------*/ /* Diagnostic tool to display various CCKD data */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" /* TODO: add FBA support or write cfbadiag */ #include "hercules.h" #include "dasdblks.h" /* data_dump */ typedef struct _CKD_RECSTAT { /* CKD DASD record stats */ int cc; /* CC cylinder # (relative zero) */ int hh; /* HH head # (relative zero) */ int r; /* Record # (relative zero) */ int kl; /* key length */ int dl; /* data length */ } CKD_RECSTAT; /*-------------------------------------------------------------------*/ /* Global data areas */ /*-------------------------------------------------------------------*/ CCKD_L1ENT *l1 = NULL; /* L1TAB */ CCKD_L2ENT *l2 = NULL; /* L2TAB */ void *tbuf = NULL; /* track header & data */ void *bulk = NULL; /* bulk data buffer */ int fd = 0; /* File descriptor */ static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; #ifdef DEBUG int debug = 1; // enable debug code #else int debug = 0; // disable debug code #endif int pausesnap = 0; // 1 = pause after snap (getc) /*-------------------------------------------------------------------*/ /* print syntax */ /*-------------------------------------------------------------------*/ int syntax() { fprintf (stdout, "\n" "cckddiag [options] file-name\n" "Valid options are one or more of the following:\n" " -v display version and exit\n" " -d display DEVHDR\n" " -c display CDEVHDR\n" " -1 display L1TAB (numeric one)\n" " -g enable debug output\n" "CKD track related options:\n" " -a cc hh display absolute CCHH data\n" " -r tt display relative TT data\n" " -2 display L2TAB related to -a or -r\n" " -t display track data\n" " -x hex display track key/data\n" "Offset option:\n" " -o oo ll hex display data at offset oo of length ll\n" "Further information: man 1 cckddiag\n" ); return -1; } /*-------------------------------------------------------------------*/ /* snap - display msg, dump data */ /*-------------------------------------------------------------------*/ /* Newline appended to message */ void snap(char *msg, void *data, int len) { int x; if (msg != NULL) fprintf(stdout, "%s\n", msg); data_dump(data, len); if (pausesnap) { fprintf(stdout, "Press enter to continue\n"); x = getc(stdin); } } /*-------------------------------------------------------------------*/ /* clean - cleanup before exit */ /*-------------------------------------------------------------------*/ void clean(void) { close(fd); free(l1); /* L1TAB buffer */ free(l2); /* L2TAB buffer */ free(tbuf); /* track and header buffer */ free(bulk); /* offset data buffer */ } /*-------------------------------------------------------------------*/ /* makbuf - allocate buffer, handle errors (exit if any) */ /*-------------------------------------------------------------------*/ void *makbuf(int len, char *label) { void *p; p = malloc(len); if (p == NULL) { fprintf(stdout, "malloc %s of length %d failed\n", label, len); clean(); exit(4); } if (debug) fprintf(stdout, "\n" "MAKBUF malloc %s buffer of %d bytes at %p\n", label, len, p); return p; } /*-------------------------------------------------------------------*/ /* readpos - common lseek and read invocation with error handling */ /*-------------------------------------------------------------------*/ /* This code exits on error rather than return to caller. */ int readpos( int fd, /* opened CCKD image file */ void *buf, /* buffer of size len */ off_t offset, /* offset into CCKD image to read */ size_t len /* length of data to read */ ) { if (debug) fprintf(stdout, "\nREADPOS seeking %d (0x%8.8X)\n", (int)offset, (unsigned int)offset); if (lseek(fd, offset, SEEK_SET) < 0) { fprintf(stdout, _("lseek to pos 0x%8.8x error: %s\n"), (unsigned int) offset, strerror(errno)); clean(); exit (1); } if (debug) fprintf(stdout, "READPOS reading buf addr "PTR_FMTx" length %"SIZE_T_FMT"d (0x"SIZE_T_FMTX")\n", (uintptr_t)buf, len, len); if (read(fd, buf, len) < (ssize_t)len) { fprintf(stdout, _("cckddiag: read error: %s\n"), strerror(errno)); clean(); exit (2); } return 0; } /*-------------------------------------------------------------------*/ /* decomptrk - decompress track data */ /*-------------------------------------------------------------------*/ int decomptrk( BYTE *ibuf, /* input buffer address */ int ibuflen, /* input buffer length */ BYTE *obuf, /* output buffer address */ int obuflen, /* output buffer length */ int heads, /* >=0 means CKD, else FBA */ int trk, /* relative track or block number */ char *msg /* addr of 80 byte msg buf or NULL */ ) /* ibuf points at CKDDASD_TRKHDR header followed by track data */ /* ibuflen specifies length of TRKHDR and data */ /* This code based on decompression logic in cdsk_valid_trk. */ /* Returns length of decompressed data or -1 on error. */ { #if defined( HAVE_LIBZ ) || defined( CCKD_BZIP2 ) int rc; /* Return code */ BYTE *bufp; /* Buffer pointer */ #endif size_t bufl; /* Buffer length */ #ifdef CCKD_BZIP2 unsigned int ubufl; /* when size_t != unsigned int */ #endif #if !defined( HAVE_LIBZ ) && !defined( CCKD_BZIP2 ) UNREFERENCED(heads); UNREFERENCED(trk); UNREFERENCED(msg); #endif memset(obuf, 0x00, obuflen); /* clear output buffer */ /* Uncompress the track/block image */ switch (ibuf[0] & CCKD_COMPRESS_MASK) { case CCKD_COMPRESS_NONE: bufl = (ibuflen < obuflen) ? ibuflen : obuflen; memcpy (obuf, ibuf, bufl); break; #ifdef HAVE_LIBZ case CCKD_COMPRESS_ZLIB: bufp = (BYTE *)obuf; memcpy (obuf, ibuf, CKDDASD_TRKHDR_SIZE); bufl = obuflen - CKDDASD_TRKHDR_SIZE; rc = uncompress(&obuf[CKDDASD_TRKHDR_SIZE], (void *)&bufl, &ibuf[CKDDASD_TRKHDR_SIZE], ibuflen); if (rc != Z_OK) { if (msg) snprintf(msg, 80, "%s %d uncompress error, rc=%d;" "%2.2x%2.2x%2.2x%2.2x%2.2x", heads >= 0 ? "trk" : "blk", trk, rc, ibuf[0], ibuf[1], ibuf[2], ibuf[3], ibuf[4]); return -1; } bufl += CKDDASD_TRKHDR_SIZE; break; #endif #ifdef CCKD_BZIP2 case CCKD_COMPRESS_BZIP2: bufp = obuf; memcpy(obuf, ibuf, CKDDASD_TRKHDR_SIZE); ubufl = obuflen - CKDDASD_TRKHDR_SIZE; rc = BZ2_bzBuffToBuffDecompress ( (char *)&obuf[CKDDASD_TRKHDR_SIZE], &ubufl, (char *)&ibuf[CKDDASD_TRKHDR_SIZE], ibuflen, 0, 0); if (rc != BZ_OK) { if (msg) snprintf(msg, 80, "%s %d decompress error, rc=%d;" "%2.2x%2.2x%2.2x%2.2x%2.2x", heads >= 0 ? "trk" : "blk", trk, rc, ibuf[0], ibuf[1], ibuf[2], ibuf[3], ibuf[4]); return -1; } bufl=ubufl; bufl += CKDDASD_TRKHDR_SIZE; break; #endif default: return -1; } /* switch (buf[0] & CCKD_COMPRESS_MASK) */ return bufl; } /*-------------------------------------------------------------------*/ /* show_ckd_count - display CKD dasd record COUNT field */ /*-------------------------------------------------------------------*/ /* RECHDR is stored in big-endian byte order. */ BYTE *show_ckd_count(CKDDASD_RECHDR *rh, int trk) { int cc, hh, r, kl, dl; BYTE *past; cc = (rh->cyl[0] << 8) | (rh->cyl[1]); hh = (rh->head[0] << 8) | (rh->head[1]); r = rh->rec; kl = rh->klen; dl = (rh->dlen[0] << 8) | (rh->dlen[1]); fprintf(stdout, "\n" "Track %d COUNT " "CC=%d HH=%d R=%d KL=%d DL=%d\n", trk, cc, hh, r, kl, dl); past = (BYTE *)rh + sizeof(CKDDASD_RECHDR); return past; } /*-------------------------------------------------------------------*/ /* show_ckd_key - display CKD dasd record KEY field */ /*-------------------------------------------------------------------*/ BYTE *show_ckd_key(CKDDASD_RECHDR *rh, BYTE *buf, int trk, int xop) { if (rh->klen && xop) { fprintf(stdout, "\nTrack %d R%d KEY (%d bytes)\n", trk, rh->rec, rh->klen); data_dump(buf, rh->klen); } return (BYTE *)buf + rh->klen; /* skip past KEY field */ } /*-------------------------------------------------------------------*/ /* show_ckd_data - display CKD dasd record DATA field */ /*-------------------------------------------------------------------*/ BYTE *show_ckd_data(CKDDASD_RECHDR *rh, BYTE *buf, int trk, int xop) { int dl; dl = (rh->dlen[0] << 8) | (rh->dlen[1]); if (dl && xop) { fprintf(stdout, "\nTrack %d R%d DATA (%d bytes)\n", trk, rh->rec, dl); data_dump(buf, dl); } return buf + dl; /* skip past DATA field */ } /*-------------------------------------------------------------------*/ /* showtrk - display track data */ /*-------------------------------------------------------------------*/ /* This code mimics selected logic in cdsk_valid_trk. */ void showtrk( CKDDASD_TRKHDR *buf, /* track header ptr */ int imglen, /* TRKHDR + track user data length */ int trk, /* relative track number */ int xop /* 1=dump key & data blks; 0=don't */ ) { BYTE buf2[64*1024]; /* max uncompressed buffer */ char msg[81]; /* error message buffer */ CKDDASD_RECHDR *rh; /* CCKD COUNT field */ BYTE *bufp; int len; if (debug) snap("\nSHOWTRK Compressed track header and data", buf, imglen); len = decomptrk( (BYTE *)buf, /* input buffer address */ imglen, /* input buffer length */ buf2, /* output buffer address */ sizeof(buf2), /* output buffer length */ 1, /* >=0 means CKD, else FBA */ trk, /* relative track or block number */ msg /* addr of message buffer */ ); if (debug) snap("\nSHOWTRK Decompressed track header and data", buf2, len); bufp = &buf2[sizeof(CKDDASD_TRKHDR)]; while (bufp < &buf2[sizeof(buf2)]) { rh = (CKDDASD_RECHDR *)bufp; if (memcmp((BYTE *)rh, &eighthexFF, 8) == 0) { fprintf(stdout, "\nEnd of Track\n"); break; } bufp = show_ckd_count(rh, trk); bufp = show_ckd_key(rh, bufp, trk, xop); bufp = show_ckd_data(rh, bufp, trk, xop); } } /*-------------------------------------------------------------------*/ /* offtify - given decimal or hex input string, return off_t */ /* Locale independent, does not check for overflow */ /* References and */ /*-------------------------------------------------------------------*/ /* Based on code in P. J. Plauger's "The Standard C Library" */ /* See page 34, in Chapter 2 (ctype.h) */ off_t offtify(char *s) { static const char xd[] = {"0123456789abcdefABCDEF"}; static const char xv[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15}; off_t v; char *p; p = s; if ( (*s == '0') && (*(s+1) == 'x') ) { s = s + 2; for (v = 0; isxdigit(*s); ++s) v = (v << 4) + xv[strchr(xd, *s) - xd]; if (debug) fprintf(stdout, "OFFTIFY string %s hex %8.8" I64_FMT "X decimal %" I64_FMT "d\n", p, (U64)v, (U64)v); return v; } else { /* decimal input */ v = (off_t) atoll(s); if (debug) fprintf(stdout, "OFFTIFY string %s decimal %" I64_FMT "X %" I64_FMT "d\n", p, (U64)v, (U64)v); return v; } } /*-------------------------------------------------------------------*/ /* Main function for CCKD diagnostics */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int cckd_diag_rc = 0; /* Program return code */ char *fn; /* File name */ CKDDASD_DEVHDR devhdr; /* [C]CKD device hdr */ CCKDDASD_DEVHDR cdevhdr; /* Compressed CKD device hdr */ CKDDEV *ckd=0; /* CKD DASD table entry */ FBADEV *fba=0; /* FBA DASD table entry */ int cmd_devhdr = 0; /* display DEVHDR */ int cmd_cdevhdr = 0; /* display CDEVHDR */ int cmd_l1tab = 0; /* display L1TAB */ int cmd_l2tab = 0; /* display L2TAB */ int cmd_trkdata = 0; /* display track data */ int cmd_hexdump = 0; /* display track data (hex) */ int cmd_offset = 0; /* 1 = display data at */ int op_offset = 0; /* op_offset of length */ int op_length = 0; /* op_length */ int cmd_cchh = 0; /* 1 = display CCHH data */ int op_cc = 0; /* CC = cylinder */ int op_hh = 0; /* HH = head */ int cmd_tt = 0; /* 1 = display TT data */ int op_tt = 0; /* relative track # */ int swapend; /* 1 = New endianess doesn't match machine endianess */ int n, trk=0, l1ndx=0, l2ndx=0; off_t l2taboff=0; /* offset to assoc. L2 table */ int ckddasd; /* 1=CKD dasd 0=FBA dasd */ int heads=0; /* Heads per cylinder */ int blks; /* Number fba blocks */ off_t trkhdroff=0; /* offset to assoc. trk hdr */ int imglen=0; /* track length */ char pathname[MAX_PATH]; /* file path in host format */ INITIALIZE_UTILITY("cckddiag"); /* parse the arguments */ argc--; argv++ ; while (argc > 0) { if(**argv != '-') break; switch(argv[0][1]) { case 'v': if (argv[0][2] != '\0') return syntax (); display_version (stdout, "Hercules CCKD diagnostic program\n", FALSE); return 0; case 'd': if (argv[0][2] != '\0') return syntax (); cmd_devhdr = 1; break; case 'c': if (argv[0][2] != '\0') return syntax (); cmd_cdevhdr = 1; break; case '1': if (argv[0][2] != '\0') return syntax (); cmd_l1tab = 1; break; case '2': if (argv[0][2] != '\0') return syntax (); cmd_l2tab = 1; break; case 'a': if (argv[0][2] != '\0') return syntax (); cmd_cchh = 1; argc--; argv++; op_cc = offtify(*argv); argc--; argv++; op_hh = offtify(*argv); break; case 'r': if (argv[0][2] != '\0') return syntax (); cmd_tt = 1; argc--; argv++; op_tt = offtify(*argv); break; case 'o': if (argv[0][2] != '\0') return syntax (); cmd_offset = 1; argc--; argv++; op_offset = offtify(*argv); argc--; argv++; op_length = offtify(*argv); break; case 't': if (argv[0][2] != '\0') return syntax (); cmd_trkdata = 1; break; case 'x': if (argv[0][2] != '\0') return syntax (); cmd_hexdump = 1; cmd_trkdata = 1; break; case 'g': if (argv[0][2] != '\0') return syntax (); debug = 1; break; default: return syntax (); } argc--; argv++; } if (argc != 1) return syntax (); fn = argv[0]; /* open the file */ hostpath(pathname, fn, sizeof(pathname)); fd = hopen(pathname, O_RDONLY | O_BINARY); if (fd < 0) { fprintf(stdout, _("cckddiag: error opening file %s: %s\n"), fn, strerror(errno)); return -1; } /*---------------------------------------------------------------*/ /* display DEVHDR - first 512 bytes of dasd image */ /*---------------------------------------------------------------*/ readpos(fd, &devhdr, 0, sizeof(devhdr)); if (cmd_devhdr) { fprintf(stdout, "\nDEVHDR - %"SIZE_T_FMT"d (decimal) bytes:\n", sizeof(devhdr)); data_dump(&devhdr, sizeof(devhdr)); } /*---------------------------------------------------------------*/ /* Determine CKD or FBA device type */ /*---------------------------------------------------------------*/ if (memcmp(devhdr.devid, "CKD_C370", 8) == 0 || memcmp(devhdr.devid, "CKD_S370", 8) == 0) { ckddasd = 1; ckd = dasd_lookup(DASD_CKDDEV, NULL, devhdr.devtype, 0); if (ckd == NULL) { fprintf(stdout, "DASD table entry not found for devtype 0x%2.2X\n", devhdr.devtype); clean(); exit(5); } } else if (memcmp(devhdr.devid, "FBA_C370", 8) == 0 || memcmp(devhdr.devid, "FBA_S370", 8) == 0) { ckddasd = 0; fba = dasd_lookup(DASD_FBADEV, NULL, devhdr.devtype, 0); if (fba == NULL) { fprintf(stdout, "DASD table entry not found for " "devtype 0x%2.2X\n", DEFAULT_FBA_TYPE); clean(); exit(6); } } else { fprintf(stdout, "incorrect header id\n"); clean(); return -1; } /*---------------------------------------------------------------*/ /* Set up device characteristics */ /*---------------------------------------------------------------*/ if (ckddasd) { heads = ((U32)(devhdr.heads[3]) << 24) | ((U32)(devhdr.heads[2]) << 16) | ((U32)(devhdr.heads[1]) << 8) | (U32)(devhdr.heads[0]); if (debug) fprintf(stdout, "\n%s device has %d heads/cylinder\n", ckd->name, heads); } else { blks = 0; #if 0 /* cdevhdr is uninitialized and blks is never referenced... */ blks = ((U32)(cdevhdr.cyls[0]) << 24) | ((U32)(cdevhdr.cyls[2]) << 16) | ((U32)(cdevhdr.cyls[1]) << 8) | (U32)(cdevhdr.cyls[0]); #endif } /*---------------------------------------------------------------*/ /* display CDEVHDR - follows DEVHDR */ /*---------------------------------------------------------------*/ readpos(fd, &cdevhdr, CKDDASD_DEVHDR_SIZE, sizeof(cdevhdr)); if (cmd_cdevhdr) { fprintf(stdout, "\nCDEVHDR - %"SIZE_T_FMT"d (decimal) bytes:\n", sizeof(cdevhdr)); data_dump(&cdevhdr, sizeof(cdevhdr)); } /*---------------------------------------------------------------*/ /* Find machine endian-ness */ /*---------------------------------------------------------------*/ /* cckd_endian() returns 1 for big-endian machines */ swapend = (cckd_endian() != ((cdevhdr.options & CCKD_BIGENDIAN) != 0)); /*---------------------------------------------------------------*/ /* display L1TAB - follows CDEVHDR */ /*---------------------------------------------------------------*/ /* swap numl1tab if needed */ n = cdevhdr.numl1tab; if (swapend) cckd_swapend4((char *)&n); l1 = makbuf(n * CCKD_L1ENT_SIZE, "L1TAB"); readpos(fd, l1, CCKD_L1TAB_POS, n * CCKD_L1ENT_SIZE); /* L1TAB itself is not adjusted for endian-ness */ if (cmd_l1tab) { fprintf(stdout, "\nL1TAB - %"SIZE_T_FMT"d (0x"SIZE_T_FMTX") bytes:\n", (n * CCKD_L1ENT_SIZE), (n * CCKD_L1ENT_SIZE)); data_dump(l1, n * CCKD_L1ENT_SIZE); } /*---------------------------------------------------------------*/ /* display OFFSET, LENGTH data */ /*---------------------------------------------------------------*/ if (cmd_offset) { bulk = makbuf(op_length, "BULK"); readpos(fd, bulk, op_offset, op_length); fprintf(stdout, "\nIMAGE OFFSET %d (0x%8.8X) " "of length %d (0x%8.8X) bytes:\n", op_offset, op_offset, op_length, op_length); data_dump(bulk, op_length); free(bulk); bulk = NULL; } /*---------------------------------------------------------------*/ /* FBA isn't supported here because I don't know much about FBA */ /*---------------------------------------------------------------*/ if ( (!ckddasd) && ((cmd_cchh) || (cmd_tt)) ) { fprintf(stdout, "CCHH/reltrk not supported for FBA\n"); clean(); exit(3); } /*---------------------------------------------------------------*/ /* Setup CCHH or relative track request */ /*---------------------------------------------------------------*/ if (ckddasd) { if (cmd_tt) { trk = op_tt; op_cc = trk / heads; op_hh = trk % heads; } else { trk = (op_cc * heads) + op_hh; } l1ndx = trk / cdevhdr.numl2tab; l2ndx = trk % cdevhdr.numl2tab; l2taboff = l1[l1ndx]; if (swapend) cckd_swapend4((char *)&l2taboff); } /*---------------------------------------------------------------*/ /* display CKD CCHH or relative track data */ /*---------------------------------------------------------------*/ if ((cmd_cchh) || (cmd_tt)) { fprintf(stdout, "CC %d HH %d = reltrk %d; " "L1 index = %d, L2 index = %d\n" "L1 index %d = L2TAB offset %d (0x%8.8X)\n", op_cc, op_hh, trk, l1ndx, l2ndx, l1ndx, (int)l2taboff, (int)l2taboff); l2 = makbuf(cdevhdr.numl2tab * sizeof(CCKD_L2ENT), "L2TAB"); readpos(fd, l2, l2taboff, cdevhdr.numl2tab * sizeof(CCKD_L2ENT)); if (cmd_l2tab) { fprintf(stdout, "\nL2TAB - %"SIZE_T_FMT"d (decimal) bytes\n", (cdevhdr.numl2tab * sizeof(CCKD_L2ENT))); data_dump(l2, (cdevhdr.numl2tab * sizeof(CCKD_L2ENT)) ); } fprintf(stdout, "\nL2 index %d = L2TAB entry %"SIZE_T_FMT"d bytes\n", l2ndx, sizeof(CCKD_L2ENT) ); data_dump(&l2[l2ndx], sizeof(CCKD_L2ENT) ); trkhdroff = l2[l2ndx].pos; imglen = l2[l2ndx].len; if (swapend) { cckd_swapend4((char *)&trkhdroff); cckd_swapend4((char *)&imglen); } fprintf(stdout, "\nTRKHDR offset %d (0x%8.8X); " "length %d (0x%4.4X)\n", (int)trkhdroff, (int)trkhdroff, imglen, imglen); tbuf = makbuf(imglen, "TRKHDR+DATA"); readpos(fd, tbuf, trkhdroff, imglen); fprintf(stdout, "\nTRKHDR track %d\n", trk); data_dump(tbuf, sizeof(CKDDASD_TRKHDR) ); if (cmd_trkdata) showtrk(tbuf, imglen, trk, cmd_hexdump); free(l2); free(tbuf); l2 = NULL; tbuf = NULL; } /* Close file, exit */ fprintf(stdout, "\n"); clean(); return cckd_diag_rc; } hercules-3.12/cckdswap.c0000664000175000017500000001373712564723224012161 00000000000000/* CCKDSWAP.C (c) Copyright Greg Smith, 2000-2009 */ /* Swap the endianess of a compressed CKD file */ /*-------------------------------------------------------------------*/ /* This module changes the `endianess' of a compressed CKD file. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /*-------------------------------------------------------------------*/ /* Swap the `endianess' of cckd file */ /*-------------------------------------------------------------------*/ int syntax (); int main ( int argc, char *argv[]) { CKDDASD_DEVHDR devhdr; /* CKD device header */ CCKDDASD_DEVHDR cdevhdr; /* Compressed CKD device hdr */ int level = 0; /* Chkdsk level */ int force = 0; /* 1=swap if OPENED bit on */ int rc; /* Return code */ int i; /* Index */ int bigend; /* 1=big-endian file */ DEVBLK devblk; /* DEVBLK */ DEVBLK *dev=&devblk; /* -> DEVBLK */ INITIALIZE_UTILITY("cckdswap"); /* parse the arguments */ for (argc--, argv++ ; argc > 0 ; argc--, argv++) { if(**argv != '-') break; switch(argv[0][1]) { case '0': case '1': case '2': case '3': if (argv[0][2] != '\0') return syntax (); level = (argv[0][1] & 0xf); break; case 'f': if (argv[0][2] != '\0') return syntax (); force = 1; break; case 'v': if (argv[0][2] != '\0') return syntax (); display_version (stderr, "Hercules cckd swap program ", FALSE); return 0; default: return syntax (); } } if (argc < 1) return syntax (); for (i = 0; i < argc; i++) { memset (dev, 0, sizeof (DEVBLK)); dev->batch = 1; /* open the input file */ hostpath(dev->filename, argv[i], sizeof(dev->filename)); dev->fd = hopen(dev->filename, O_RDWR|O_BINARY); if (dev->fd < 0) { cckdumsg (dev, 700, "open error: %s\n", strerror(errno)); continue; } /* read the CKD device header */ if ((rc = read (dev->fd, &devhdr, CKDDASD_DEVHDR_SIZE)) < CKDDASD_DEVHDR_SIZE) { cckdumsg (dev, 703, "read error rc=%d offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)0, CKDDASD_DEVHDR_SIZE, rc < 0 ? strerror(errno) : "incomplete"); close (dev->fd); continue; } if (memcmp(devhdr.devid, "CKD_C370", 8) != 0 && memcmp(devhdr.devid, "CKD_S370", 8) != 0 && memcmp(devhdr.devid, "FBA_C370", 8) != 0 && memcmp(devhdr.devid, "FBA_S370", 8) != 0) { cckdumsg (dev, 999, "not a compressed dasd file\n"); close (dev->fd); continue; } /* read the compressed CKD device header */ if ((rc = read (dev->fd, &cdevhdr, CCKD_DEVHDR_SIZE)) < CCKD_DEVHDR_SIZE) { cckdumsg (dev, 703, "read error rc=%d offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)CCKD_DEVHDR_POS, CCKD_DEVHDR_SIZE, rc < 0 ? strerror(errno) : "incomplete"); close (dev->fd); continue; } /* Check the OPENED bit */ if (!force && (cdevhdr.options & CCKD_OPENED)) { cckdumsg (dev, 707, "OPENED bit is on, use -f\n"); close (dev->fd); continue; } /* get the byte order of the file */ bigend = (cdevhdr.options & CCKD_BIGENDIAN); /* call chkdsk */ if (cckd_chkdsk (dev, level) < 0) { cckdumsg (dev, 708, "chkdsk errors\n"); close (dev->fd); continue; } /* re-read the compressed CKD device header */ if (lseek (dev->fd, CCKD_DEVHDR_POS, SEEK_SET) < 0) { cckdumsg (dev, 702, "lseek error offset 0x%" I64_FMT "x: %s\n", (long long)CCKD_DEVHDR_POS, strerror(errno)); close (dev->fd); continue; } if ((rc = read (dev->fd, &cdevhdr, CCKD_DEVHDR_SIZE)) < CCKD_DEVHDR_SIZE) { cckdumsg (dev, 703, "read error rc=%d offset 0x%" I64_FMT "x len %d: %s\n", rc, (long long)CCKD_DEVHDR_POS, CCKD_DEVHDR_SIZE, rc < 0 ? strerror(errno) : "incomplete"); close (dev->fd); continue; } /* swap the byte order of the file if chkdsk didn't do it for us */ if (bigend == (cdevhdr.options & CCKD_BIGENDIAN)) { cckdumsg (dev, 101, "converting to %s\n", bigend ? "litle-endian" : "big-endian"); if (cckd_swapend (dev) < 0) cckdumsg (dev, 910, "error during swap\n"); } close (dev->fd); } /* for each arg */ return 0; } /* end main */ int syntax () { fprintf (stderr, "\ncckdswap [-v] [-f] file1 [file2 ... ]\n" "\n" " -v display version and exit\n" "\n" " -f force check even if OPENED bit is on\n" "\n" " chkdsk level is a digit 0 - 3:\n" " -0 -- minimal checking\n" " -1 -- normal checking\n" " -2 -- intermediate checking\n" " -3 -- maximal checking\n" " default 0\n" "\n"); return -1; } /* end function syntax */ hercules-3.12/dasdcat.c0000664000175000017500000001647312564723224011765 00000000000000/* DASDCAT.C (c) Copyright Roger Bowler, 1999-2012 */ /* DASD "cat" functions */ /* * dasdcat * * Vast swathes copied from dasdpdsu.c (c) Copyright Roger Bowler, 1999-2009 * Changes and additions Copyright 2000-2009 by Malcolm Beattie */ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" #ifdef WIN32 #include // (setmode) #endif /* Option flags */ #define OPT_ASCIIFY 0x1 #define OPT_CARDS 0x2 #define OPT_PDS_WILDCARD 0x4 #define OPT_PDS_LISTONLY 0x8 #define OPT_SEQNO 0x10 int end_of_track(BYTE *p) { return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff && p[6] == 0xff && p[7] == 0xff; } int do_cat_cards(BYTE *buf, int len, unsigned long optflags) { if (len % 80 != 0) { fprintf(stderr, _("HHCDT002E Can't make 80 column card images from block length %d\n"), len); return -1; } while (len) { char card[81]; make_asciiz(card, sizeof(card), buf, (optflags & OPT_SEQNO) ? 80 : 72); if (optflags & OPT_PDS_WILDCARD) { putchar('|'); putchar(' '); } puts(card); len -= 80; buf += 80; } return 0; } int process_member(CIFBLK *cif, int noext, DSXTENT extent[], BYTE *ttr, unsigned long optflags) { int rc, trk, len, cyl, head, rec; BYTE *buf; set_codepage(NULL); trk = (ttr[0] << 8) | ttr[1]; rec = ttr[2]; while (1) { rc = convert_tt(trk, noext, extent, cif->heads, &cyl, &head); if (rc < 0) return -1; rc = read_block(cif, cyl, head, rec, 0, 0, &buf, &len); if (rc < 0) return -1; if (rc > 0) { trk++; rec = 1; continue; } if (len == 0) break; if (optflags & OPT_CARDS) do_cat_cards(buf, len, optflags); else if (optflags & OPT_ASCIIFY) { BYTE *p; for (p = buf; len--; p++) putchar(guest_to_host(*p)); } else { #if O_BINARY != 0 setmode(fileno(stdout),O_BINARY); #endif fwrite(buf, len, 1, stdout); } rec++; } return 0; } int process_dirblk(CIFBLK *cif, int noext, DSXTENT extent[], BYTE *dirblk, char *pdsmember, unsigned long optflags) { int rc; int dirrem; char memname[9]; /* Load number of bytes in directory block */ dirrem = (dirblk[0] << 8) | dirblk[1]; if (dirrem < 2 || dirrem > 256) { fprintf(stderr, _("HHCDT003E Directory block byte count is invalid\n")); return -1; } if (!strcmp(pdsmember, "*")) optflags |= OPT_PDS_WILDCARD; else if (!strcmp(pdsmember, "?")) optflags |= OPT_PDS_LISTONLY; /* Point to first directory entry */ dirblk += 2; dirrem -= 2; while (dirrem > 0) { PDSDIR *dirent = (PDSDIR*)dirblk; int k, size; if (end_of_track(dirent->pds2name)) return 1; make_asciiz(memname, sizeof(memname), dirent->pds2name, 8); if (optflags & OPT_PDS_LISTONLY) { char memname_lc[9]; memcpy(memname_lc, memname, sizeof(memname)); string_to_lower(memname_lc); puts(memname_lc); } else if ((optflags & OPT_PDS_WILDCARD) || !strcmp(pdsmember, memname)) { if (optflags & OPT_PDS_WILDCARD) printf("> Member %s\n", memname); rc = process_member(cif, noext, extent, dirent->pds2ttrp, optflags); if (rc < 0) return -1; } /* Load the user data halfword count */ k = dirent->pds2indc & PDS2INDC_LUSR; /* Point to next directory entry */ size = 12 + k*2; dirblk += size; dirrem -= size; } return 0; } int do_cat_pdsmember(CIFBLK *cif, DSXTENT *extent, int noext, char *pdsmember, unsigned long optflags) { int rc, trk, rec; /* Point to the start of the directory */ trk = 0; rec = 1; /* Read the directory */ while (1) { BYTE *blkptr; BYTE dirblk[256]; int cyl, head, len; #ifdef EXTERNALGUI if (extgui) fprintf(stderr,"CTRK=%d\n",trk); #endif /*EXTERNALGUI*/ rc = convert_tt(trk, noext, extent, cif->heads, &cyl, &head); if (rc < 0) return -1; rc = read_block(cif, cyl, head, rec, 0, 0, &blkptr, &len); if (rc < 0) return -1; if (rc > 0) { trk++; rec = 1; continue; } if (len == 0) break; memcpy(dirblk, blkptr, sizeof(dirblk)); rc = process_dirblk(cif, noext, extent, dirblk, pdsmember, optflags); if (rc < 0) return -1; if (rc > 0) break; rec++; } return rc; } int do_cat_nonpds(CIFBLK *cif, DSXTENT *extent, int noext, unsigned long optflags) { UNREFERENCED(cif); UNREFERENCED(extent); UNREFERENCED(noext); UNREFERENCED(optflags); fprintf(stderr, _("HHCDT004E non-PDS-members not yet supported\n")); return -1; } int do_cat(CIFBLK *cif, char *file) { int rc; DSXTENT extent[16]; int noext; char buff[100]; /* must fit max length DSNAME/MEMBER..OPTS */ char dsname[45]; unsigned long optflags = 0; char *p; char *pdsmember = 0; if (!cif) return 1; strncpy(buff, file, sizeof(buff)); buff[sizeof(buff)-1] = 0; p = strchr(buff, ':'); if (p) { *p++ = 0; for (; *p; p++) { if (*p == 'a') optflags |= OPT_ASCIIFY; else if (*p == 'c') optflags |= OPT_CARDS; else if (*p == 's') optflags |= OPT_SEQNO; else fprintf(stderr, _("HHCDT005E unknown dataset name option: '%c'\n"), *p); } } p = strchr(buff, '/'); if (p) { *p = 0; pdsmember = p + 1; string_to_upper(pdsmember); } strncpy(dsname, buff, sizeof(dsname)); dsname[sizeof(dsname)-1] = 0; string_to_upper(dsname); rc = build_extent_array(cif, dsname, extent, &noext); if (rc < 0) return -1; #ifdef EXTERNALGUI /* Calculate ending relative track */ if (extgui) { int bcyl; /* Extent begin cylinder */ int btrk; /* Extent begin head */ int ecyl; /* Extent end cylinder */ int etrk; /* Extent end head */ int trks; /* total tracks in dataset */ int i; /* loop control */ for (i = 0, trks = 0; i < noext; i++) { bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1]; btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1]; ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1]; etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1]; trks += (((ecyl*cif->heads)+etrk)-((bcyl*cif->heads)+btrk))+1; } fprintf(stderr,"ETRK=%d\n",trks-1); } #endif /*EXTERNALGUI*/ if (pdsmember) rc = do_cat_pdsmember(cif, extent, noext, pdsmember, optflags); else rc = do_cat_nonpds(cif, extent, noext, optflags); return rc; } int main(int argc, char **argv) { int rc = 0; CIFBLK *cif = 0; char *fn, *sfn; INITIALIZE_UTILITY("dasdcat"); /* Display program info message */ display_version (stderr, "Hercules DASD cat program ", FALSE); if (argc < 2) { fprintf(stderr, "Usage: dasdcat [-i dasd_image [sf=shadow-file-name] dsname...]...\n"); fprintf(stderr, " dsname can (currently must) be pdsname/spec\n"); fprintf(stderr, " spec is memname[:flags], * (all) or ? (list)\n"); fprintf(stderr, " flags can include (c)ard images, (a)scii\n"); exit(2); } /* * If your version of Hercules doesn't have support in its * dasdutil.c for turning off verbose messages, then remove * the following line but you'll have to live with chatty * progress output on stdout. */ set_verbose_util(0); while (*++argv) { if (!strcmp(*argv, "-i")) { fn = *++argv; if (*(argv+1) && strlen (*(argv+1)) > 3 && !memcmp(*(argv+1), "sf=", 3)) sfn = *++argv; else sfn = NULL; if (cif) { close_ckd_image(cif); cif = 0; } cif = open_ckd_image(fn, sfn, O_RDONLY | O_BINARY, 0); if (!cif) fprintf(stderr, _("HHCDT001E failed to open image %s\n"), *argv); } else { if (do_cat(cif, *argv)) rc = 1; } } if (cif) close_ckd_image(cif); return rc; } hercules-3.12/dasdconv.c0000664000175000017500000010776412564723224012167 00000000000000/* DASDCONV.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules DASD Utilities: DASD image converter */ /*-------------------------------------------------------------------*/ /* This program converts a CKD disk image from HDR-30 format */ /* to the AWSCKD format used by Hercules. */ /* */ /* The program is invoked from the shell prompt using the command: */ /* */ /* dasdconv [options] infile outfile */ /* */ /* options -r means overwrite existing outfile */ /* -q means suppress progress messages */ /* -lfs creates one large output file (if supported) */ /* infile is the name of the HDR-30 format CKD image file */ /* ("-" means that the CKD image is read from stdin) */ /* If this module was compiled with HAVE_LIBZ option */ /* activated, then the input file may be compressed */ /* or uncompressed. Otherwise it must be uncompressed. */ /* outfile is the name of the AWSCKD image file to be created. */ /* If the image exceeds 2GB then multiple files will */ /* be created, with names suffixed _1, _2, etc. */ /* (except if the underlying file system supports files */ /* larger than 2GB and the -lfs option is specified). */ /* This program will not overwrite an existing file. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" #include "opcode.h" /*-------------------------------------------------------------------*/ /* Definition of HDR-30 CKD image headers */ /*-------------------------------------------------------------------*/ typedef struct _H30CKD_TRKHDR { /* Track header */ HWORD devcode; /* Device type code */ BYTE resv02[14]; /* Reserved */ HWORD cyl; /* Cylinder number */ HWORD head; /* Head number */ BYTE resv14[28]; /* Reserved */ } H30CKD_TRKHDR; typedef struct _H30CKD_RECHDR { /* Record header */ FWORD resv00; /* Reserved */ HWORD cyl; /* Cylinder number */ HWORD head; /* Head number */ BYTE rec; /* Record number */ BYTE klen; /* Key length */ HWORD dlen; /* Data length */ } H30CKD_RECHDR; #define H30CKD_TRKHDR_SIZE ((ssize_t)sizeof(H30CKD_TRKHDR)) #define H30CKD_RECHDR_SIZE ((ssize_t)sizeof(H30CKD_RECHDR)) /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ BYTE eighthexFF[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; BYTE twelvehex00[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; BYTE ebcdicvol1[] = {0xE5, 0xD6, 0xD3, 0xF1}; BYTE gz_magic_id[] = {0x1F, 0x8B}; BYTE ckd_ident[] = {0x43, 0x4B, 0x44, 0x5F}; /* CKD_ in ASCII */ /*-------------------------------------------------------------------*/ /* Definition of file descriptor for gzip and non-gzip builds */ /*-------------------------------------------------------------------*/ #if defined(HAVE_LIBZ) #define IFD gzFile #define IFREAD gzread #define IFCLOS gzclose #else /*!defined(HAVE_LIBZ)*/ #define IFD int #define IFREAD read #define IFCLOS close #endif /*!defined(HAVE_LIBZ)*/ /*-------------------------------------------------------------------*/ /* Subroutine to display command syntax and exit */ /*-------------------------------------------------------------------*/ static void argexit ( int code ) { fprintf (stderr, "Syntax:\tdasdconv [options] infile outfile\n" "where:\n\tinfile = name of input HDR-30 CKD image file" " (\"-\" means stdin)\n" #if defined(HAVE_LIBZ) "\t\t (input file may be compressed)\n" #endif /*defined(HAVE_LIBZ)*/ "\toutfile = name of AWSCKD image file to be created\n" "options:\n\t-r = replace existing output file\n" "\t-q = suppress progress messages\n"); if (sizeof(off_t) > 4) fprintf(stderr, "\t-lfs = build one large output file\n"); exit(code); } /* end function argexit */ /*-------------------------------------------------------------------*/ /* Subroutine to read data from input file */ /* Input: */ /* ifd Input file descriptor */ /* ifname Input file name */ /* buf Address of input buffer */ /* reqlen Number of bytes requested */ /* offset Current offset in file (for error message only) */ /*-------------------------------------------------------------------*/ static void read_input_data (IFD ifd, char *ifname, BYTE *buf, int reqlen, U32 offset) { int rc; /* Return code */ int len = 0; /* Number of bytes read */ while (len < reqlen) { rc = IFREAD (ifd, buf + len, reqlen - len); if (rc == 0) break; if (rc < 0) { fprintf (stderr, "%s read error: %s\n", ifname, strerror(errno)); exit(3); } len += rc; } /* end while */ if (len < reqlen) { fprintf (stderr, "Unexpected end-of-file on %s\n" "Expected %d bytes at offset %8.8X," " found %d bytes\n", ifname, reqlen, offset, len); exit(3); } } /* end function read_input_data */ /*-------------------------------------------------------------------*/ /* Subroutine to locate next record in HDR-30 CKD track image */ /* Input: */ /* buf Pointer to start of track image buffer */ /* Input+Output: */ /* ppbuf Pointer to current position in track image buffer */ /* plen Length remaining in track image buffer */ /* Output: */ /* pkl Key length */ /* pkp Address of record key */ /* pdl Data length */ /* pdp Address of record data */ /* pcc Cylinder number */ /* phh Head number */ /* prn Record number */ /* Return value: */ /* 0=OK, 1=End of track, >1=Track format error detected */ /*-------------------------------------------------------------------*/ static int find_input_record (BYTE *buf, BYTE **ppbuf, int *plen, BYTE *pkl, BYTE **pkp, U16 *pdl, BYTE **pdp, U32 *pcc, U32 *phh, BYTE *prn) { H30CKD_RECHDR *hrec; /* Input record header */ U16 dlen; /* Data length */ BYTE klen; /* Key length */ int n; /* Integer work area */ UNREFERENCED(buf); /* End of track if not enough bytes remain in buffer */ if (*plen < H30CKD_RECHDR_SIZE) return 1; /* Point to record header */ hrec = (H30CKD_RECHDR*)(*ppbuf); /* End of track if record header is all zero */ if (memcmp(*ppbuf, twelvehex00, 12) == 0) return 1; /* Extract the key length and data length */ klen = hrec->klen; FETCH_HW (dlen, hrec->dlen); /* Check that the reserved bytes are all zero */ if (memcmp(hrec->resv00, twelvehex00, sizeof(hrec->resv00)) != 0) return 2; /* Check that the key and data do not overflow the buffer */ if (*plen < H30CKD_RECHDR_SIZE + klen + dlen) return 3; /* Return the cylinder, head, and record number */ FETCH_HW (*pcc, hrec->cyl); FETCH_HW (*phh, hrec->head); *prn = hrec->rec; /* Point past the record header to the key */ *plen -= H30CKD_RECHDR_SIZE; *ppbuf += H30CKD_RECHDR_SIZE; /* Return the key length and key pointer */ *pkl = klen; *pkp = *ppbuf; /* Point past the key to the data */ *plen -= klen; *ppbuf += klen; /* Return the data length and data pointer */ *pdl = dlen; *pdp = *ppbuf; /* Point past the data to the next record header */ *plen -= dlen; *ppbuf += dlen; /* Ensure next header starts on a fullword boundary */ if ((klen + dlen) & 3) { n = 4 - ((klen + dlen) % 4); *plen -= n; *ppbuf += n; } /* Issue progress message */ #if 0 fprintf (stderr, "+%4.4X cyl=%4.4X head=%4.4X rec=%2.2X" " kl=%2.2X dl=%4.4X trkbal=%d\n", (BYTE*)hrec-buf, *pcc, *phh, *prn, klen, dlen, *plen); #endif return 0; } /* end function find_input_record */ /*-------------------------------------------------------------------*/ /* Subroutine to open input HDR-30 CKD image file */ /* Input: */ /* ifname Input HDR-30 CKD image file name */ /* Output: */ /* devt Device type */ /* vcyls Number of primary cylinders on volume */ /* itrkl Input HDR-30 CKD image track length */ /* itrkb -> Track image buffer (containing 1st track image) */ /* volser Volume serial number (6 bytes ASCII + X'00') */ /* Return value: */ /* Input file descriptor */ /*-------------------------------------------------------------------*/ static IFD open_input_image (char *ifname, U16 *devt, U32 *vcyls, U32 *itrkl, BYTE **itrkb, BYTE *volser) { int rc; /* Return code */ H30CKD_TRKHDR h30trkhdr; /* Input track header */ IFD ifd; /* Input file descriptor */ int len; /* Length of input */ U16 code; /* Device type code */ U16 dt; /* Device type */ U32 cyls; /* Device size (pri+alt cyls)*/ U32 alts; /* Number of alternate cyls */ BYTE *itrkbuf; /* -> Input track buffer */ U32 itrklen; /* Input track length */ BYTE *pbuf; /* Current byte in input buf */ BYTE klen; /* Key length */ U16 dlen; /* Data length */ BYTE *kptr; /* -> Key in input buffer */ BYTE *dptr; /* -> Data in input buffer */ U32 cyl; /* Cylinder number */ U32 head; /* Head number */ BYTE rec; /* Record number */ char pathname[MAX_PATH]; /* file path in host format */ hostpath(pathname, (char *)ifname, sizeof(pathname)); /* Open the HDR-30 CKD image file */ #if defined(HAVE_LIBZ) if (strcmp(ifname, "-") == 0) ifd = gzdopen (STDIN_FILENO, "rb"); else ifd = gzopen (pathname, "rb"); if (ifd == NULL) { fprintf (stderr, "Cannot open %s: %s\n", ifname, errno == 0 ? "gzopen error" : strerror(errno)); exit(3); } #else /*!defined(HAVE_LIBZ)*/ if (strcmp(ifname, "-") == 0) ifd = STDIN_FILENO; else { ifd = hopen(pathname, O_RDONLY | O_BINARY); if (ifd < 0) { fprintf (stderr, "Cannot open %s: %s\n", ifname, strerror(errno)); exit(3); } } #endif /*!defined(HAVE_LIBZ)*/ /* Read the first track header */ read_input_data (ifd, ifname, (BYTE*)&h30trkhdr, H30CKD_TRKHDR_SIZE, 0); #if !defined(HAVE_LIBZ) /* Reject input if compressed and we lack gzip support */ if (memcmp(h30trkhdr.devcode, gz_magic_id, sizeof(gz_magic_id)) == 0) { fprintf (stderr, "Input file %s appears to be a .gz file\n" "but this program was compiled without compression support\n", ifname); exit(3); } #endif /*!defined(HAVE_LIBZ)*/ /* Reject input if it is already in CKD or CCKD format */ if (memcmp((BYTE*)&h30trkhdr, ckd_ident, sizeof(ckd_ident)) == 0) { fprintf (stderr, "Input file %s is already in CKD format, use dasdcopy\n", ifname); exit(3); } /* Extract the device type code from the track header */ FETCH_HW (code, h30trkhdr.devcode); /* Determine the input device type and size from the device code */ switch (code) { case 0x01: dt=0x3330; cyls=411; alts=7; break; /* 3330 */ case 0x02: dt=0x3330; cyls=815; alts=7; break; /* 3330-11 */ case 0x03: dt=0x3340; cyls=351; alts=1; break; /* 3340-35 */ case 0x04: dt=0x3340; cyls=701; alts=1; break; /* 3340-70 */ case 0x05: dt=0x3350; cyls=562; alts=7; break; /* 3350 */ case 0x06: dt=0x3375; cyls=962; alts=3; break; /* 3375 */ case 0x08: dt=0x3380; cyls=888; alts=3; break; /* 3380-A,D,J*/ case 0x09: dt=0x3380; cyls=1774; alts=4; break; /* 3380-E */ case 0x0A: dt=0x3380; cyls=2660; alts=5; break; /* 3380-K */ case 0x0B: dt=0x3390; cyls=1117; alts=4; break; /* 3390-1 */ case 0x0C: dt=0x3390; cyls=2230; alts=4; break; /* 3390-2 */ case 0x0D: dt=0x3390; cyls=3343; alts=4; break; /* 3390-3 */ case 0x12: dt=0x2314; cyls=203; alts=3; break; /* 2314 */ case 0x13: dt=0x3390; cyls=10038; alts=21; break; /* 3390-9 */ case 0x14: dt=0x9345; cyls=1454; alts=14; break; /* 9345-1 */ case 0x15: dt=0x9345; cyls=2170; alts=14; break; /* 9345-2 */ default: fprintf (stderr, "Unknown device code %4.4X" \ " at offset 00000000 in input file %s\n", code, ifname); exit(3); } /* end switch(code) */ /* Use the device type to determine the input image track size */ switch (dt) { case 0x2314: itrklen = 0x2000; break; case 0x3330: itrklen = 0x3400; break; case 0x3340: itrklen = 0x2400; break; case 0x3350: itrklen = 0x4C00; break; case 0x3375: itrklen = 0x9000; break; case 0x3380: itrklen = 0xBC00; break; case 0x3390: itrklen = 0xE400; break; case 0x9345: itrklen = 0xBC00; break; default: fprintf (stderr, "Unknown device type: %4.4X\n", dt); exit(3); } /* end switch(dt) */ /* Obtain the input track buffer */ itrkbuf = malloc (itrklen); if (itrkbuf == NULL) { fprintf (stderr, "Cannot obtain storage for input track buffer: %s\n", strerror(errno)); exit(3); } /* Copy the first track header to the input track buffer */ memcpy (itrkbuf, &h30trkhdr, H30CKD_TRKHDR_SIZE); /* Read the remainder of the first track into the buffer */ read_input_data (ifd, ifname, itrkbuf + H30CKD_TRKHDR_SIZE, itrklen - H30CKD_TRKHDR_SIZE, H30CKD_TRKHDR_SIZE); /* Initialize the volume serial number */ strcpy ((char *)volser, "(NONE)"); /* Search for volume label in record 3 of first track */ pbuf = itrkbuf + H30CKD_TRKHDR_SIZE; len = itrklen - H30CKD_TRKHDR_SIZE; while (1) { /* Find next input record */ rc = find_input_record (itrkbuf, &pbuf, &len, &klen, &kptr, &dlen, &dptr, &cyl, &head, &rec); /* Give up if error or end of track */ if (rc != 0) break; /* Process when record 3 is found */ if (cyl == 0 && head == 0 && rec == 3) { /* Extract volser if it is a volume label */ if (klen == 4 && memcmp(kptr, ebcdicvol1, 4) == 0 && dlen == 80 && memcmp(dptr, ebcdicvol1, 4) == 0) make_asciiz ((char *)volser, 7, dptr+4, 6); break; } } /* end while */ /* Set output variables and return the input file descriptor */ *devt = dt; *vcyls = cyls - alts; *itrkl = itrklen; *itrkb = itrkbuf; return ifd; } /* end function open_input_image */ /*-------------------------------------------------------------------*/ /* Subroutine to create an AWSCKD DASD image file */ /* Input: */ /* ifd Input HDR-30 image file descriptor */ /* ifname Input file name */ /* itrklen Length of input track buffer */ /* itrkbuf Address of input track buffer */ /* repl 1=replace existing file, 0=do not replace */ /* ofname Output AWSCKD file name */ /* fseqn Sequence number of this file (1=first) */ /* devtype Device type */ /* heads Number of heads per cylinder */ /* trksize AWSCKD image track length */ /* obuf Address of output AWSCKD track image buffer */ /* start Starting cylinder number for this file */ /* end Ending cylinder number for this file */ /* volcyls Total number of cylinders on volume */ /* volser Volume serial number */ /*-------------------------------------------------------------------*/ static void convert_ckd_file (IFD ifd, char *ifname, int itrklen, BYTE *itrkbuf, int repl, int quiet, char *ofname, int fseqn, U16 devtype, U32 heads, U32 trksize, BYTE *obuf, U32 start, U32 end, U32 volcyls, BYTE *volser) { int rc; /* Return code */ int ofd; /* Output file descriptor */ CKDDASD_DEVHDR devhdr; /* Output device header */ CKDDASD_TRKHDR *trkhdr; /* -> Output track header */ CKDDASD_RECHDR *rechdr; /* -> Output record header */ U32 cyl; /* Cylinder number */ U32 head; /* Head number */ int fileseq; /* CKD header sequence number*/ int highcyl; /* CKD header high cyl number*/ BYTE *opos; /* -> Byte in output buffer */ BYTE klen; /* Key length */ U16 dlen; /* Data length */ BYTE rec; /* Record number */ BYTE *iptr; /* -> Byte in input buffer */ BYTE *kptr; /* -> Key in input buffer */ BYTE *dptr; /* -> Data in input buffer */ int ilen; /* Bytes left in input buffer*/ H30CKD_TRKHDR *ith; /* -> Input track header */ U32 ihc, ihh; /* Input trk header cyl,head */ U32 offset; /* Current input file offset */ char pathname[MAX_PATH]; /* file path in host format */ UNREFERENCED(volser); /* Set file sequence number to zero if this is the only file */ if (fseqn == 1 && end + 1 == volcyls) fileseq = 0; else fileseq = fseqn; /* Set high cylinder number to zero if this is the last file */ if (end + 1 == volcyls) highcyl = 0; else highcyl = end; /* Create the AWSCKD image file */ hostpath(pathname, (char *)ofname, sizeof(pathname)); ofd = hopen(pathname, O_WRONLY | O_CREAT | O_BINARY | (repl ? 0 : O_EXCL), S_IRUSR | S_IWUSR | S_IRGRP); if (ofd < 0) { fprintf (stderr, "%s open error: %s\n", ofname, strerror(errno)); exit(8); } /* Create the device header */ memset(&devhdr, 0, CKDDASD_DEVHDR_SIZE); memcpy(devhdr.devid, "CKD_P370", 8); devhdr.heads[3] = (heads >> 24) & 0xFF; devhdr.heads[2] = (heads >> 16) & 0xFF; devhdr.heads[1] = (heads >> 8) & 0xFF; devhdr.heads[0] = heads & 0xFF; devhdr.trksize[3] = (trksize >> 24) & 0xFF; devhdr.trksize[2] = (trksize >> 16) & 0xFF; devhdr.trksize[1] = (trksize >> 8) & 0xFF; devhdr.trksize[0] = trksize & 0xFF; devhdr.devtype = devtype & 0xFF; devhdr.fileseq = fileseq; devhdr.highcyl[1] = (highcyl >> 8) & 0xFF; devhdr.highcyl[0] = highcyl & 0xFF; /* Write the device header */ rc = write (ofd, &devhdr, CKDDASD_DEVHDR_SIZE); if (rc < CKDDASD_DEVHDR_SIZE) { fprintf (stderr, "%s device header write error: %s\n", ofname, errno ? strerror(errno) : "incomplete"); exit(1); } /* Write each cylinder */ for (cyl = start; cyl <= end; cyl++) { /* Display progress message every 10 cylinders */ if ((cyl % 10) == 0) { #ifdef EXTERNALGUI if (extgui) fprintf (stderr, "CYL=%u\n", cyl); else #endif /*EXTERNALGUI*/ if (quiet == 0) fprintf (stderr, "Writing cylinder %u\r", cyl); } for (head = 0; head < heads; head++) { /* Calculate the current offset in the file */ offset = ((cyl*heads)+head)*itrklen; /* Read the input track image (except cyl 0 head 0 already read by the open_input_image procedure) */ if (cyl > 0 || head > 0) { read_input_data (ifd, ifname, itrkbuf, itrklen, offset); } /* end if(cyl>0||head>0) */ /* Validate the track header */ ith = (H30CKD_TRKHDR*)itrkbuf; FETCH_HW (ihc, ith->cyl); FETCH_HW (ihh, ith->head); if (ihc != cyl || ihh != head) { fprintf (stderr, "Invalid track header found at offset %8.8X\n" "in input file %s\n" "Expected cyl=%4.4X head=%4.4X\n" " Found cyl=%4.4X head=%4.4X\n", offset, ifname, cyl, head, ihc, ihh); exit(8); } /* Clear the output track image to zeroes */ memset (obuf, 0, trksize); /* Build the output track header */ trkhdr = (CKDDASD_TRKHDR*)obuf; trkhdr->bin = 0; STORE_HW (trkhdr->cyl, cyl); STORE_HW (trkhdr->head, head); opos = obuf + CKDDASD_TRKHDR_SIZE; /* Copy each record from the input buffer */ iptr = itrkbuf + H30CKD_TRKHDR_SIZE; ilen = itrklen - H30CKD_TRKHDR_SIZE; while (1) { /* Locate the next input record */ rc = find_input_record (itrkbuf, &iptr, &ilen, &klen, &kptr, &dlen, &dptr, &ihc, &ihh, &rec); /* Exit at end of track */ if (rc == 1) break; /* Error if invalid record header detected */ if (rc > 1) { fprintf (stderr, "Invalid record header (reason %d)\n" "at offset %4.4X" " in track at cyl %4.4X head %4.4X\n" "at offset %8.8X in input file %s\n", rc, (unsigned int)(iptr-itrkbuf), cyl, head, offset, ifname); exit(9); } /* Build AWSCKD record header in output buffer */ rechdr = (CKDDASD_RECHDR*)opos; opos += CKDDASD_RECHDR_SIZE; STORE_HW (rechdr->cyl, ihc); STORE_HW (rechdr->head, ihh); rechdr->rec = rec; rechdr->klen = klen; STORE_HW (rechdr->dlen, dlen); /* Copy key and data to output buffer */ if (klen != 0) { memcpy (opos, kptr, klen); opos += klen; } if (dlen != 0) { memcpy (opos, dptr, dlen); opos += dlen; } } /* end while */ /* Build the end of track marker */ memcpy (opos, eighthexFF, 8); /* Write the track to the file */ rc = write (ofd, obuf, trksize); if (rc < 0 || (U32)rc < trksize) { fprintf (stderr, "%s cylinder %u head %u write error: %s\n", ofname, cyl, head, errno ? strerror(errno) : "incomplete"); exit(1); } } /* end for(head) */ } /* end for(cyl) */ /* Close the AWSCKD image file */ rc = close (ofd); if (rc < 0) { fprintf (stderr, "%s close error: %s\n", ofname, strerror(errno)); exit(10); } /* Display completion message */ fprintf (stderr, "%u cylinders successfully written to file %s\n", cyl - start, ofname); } /* end function convert_ckd_file */ /*-------------------------------------------------------------------*/ /* Subroutine to create an AWSCKD DASD image */ /* Input: */ /* lfs Build one large output file */ /* ifd Input HDR-30 image file descriptor */ /* ifname Input file name */ /* itrklen Length of input track buffer */ /* itrkbuf Address of input track buffer */ /* repl 1=replace existing file, 0=do not replace */ /* ofname Output AWSCKD image file name */ /* devtype Device type */ /* heads Number of heads per cylinder */ /* maxdlen Maximum R1 record data length */ /* volcyls Total number of cylinders on volume */ /* volser Volume serial number */ /* */ /* If the total number of cylinders exceeds the capacity of a 2GB */ /* file, then multiple CKD image files will be created, with the */ /* suffix _1, _2, etc suffixed to the specified file name. */ /* Otherwise a single file is created without a suffix. */ /*-------------------------------------------------------------------*/ static void convert_ckd (int lfs, IFD ifd, char *ifname, int itrklen, BYTE *itrkbuf, int repl, int quiet, char *ofname, U16 devtype, U32 heads, U32 maxdlen, U32 volcyls, BYTE *volser) { int i; /* Array subscript */ char *s; /* String pointer */ int fileseq; /* File sequence number */ char sfname[260]; /* Suffixed name of this file*/ char *suffix; /* -> Suffix character */ U32 endcyl; /* Last cylinder of this file*/ U32 cyl; /* Cylinder number */ U32 cylsize; /* Cylinder size in bytes */ BYTE *obuf; /* -> Output track buffer */ U32 mincyls; /* Minimum cylinder count */ U32 maxcyls; /* Maximum cylinder count */ U32 maxcpif; /* Maximum number of cylinders in each CKD image file */ int rec0len = 8; /* Length of R0 data */ U32 trksize; /* AWSCKD image track length */ /* Compute the AWSCKD image track length */ trksize = sizeof(CKDDASD_TRKHDR) + sizeof(CKDDASD_RECHDR) + rec0len + sizeof(CKDDASD_RECHDR) + maxdlen + sizeof(eighthexFF); trksize = ROUND_UP(trksize,512); /* Compute minimum and maximum number of cylinders */ cylsize = trksize * heads; mincyls = 1; if (!lfs) { maxcpif = 0x80000000 / cylsize; maxcyls = maxcpif * CKD_MAXFILES; } else maxcpif = maxcyls = volcyls; if (maxcyls > 65536) maxcyls = 65536; /* Check for valid number of cylinders */ if (volcyls < mincyls || volcyls > maxcyls) { fprintf (stderr, "Cylinder count %u is outside range %u-%u\n", volcyls, mincyls, maxcyls); exit(4); } /* Obtain track data buffer */ obuf = malloc(trksize); if (obuf == NULL) { fprintf (stderr, "Cannot obtain track buffer: %s\n", strerror(errno)); exit(6); } /* Display progress message */ fprintf (stderr, "Converting %4.4X volume %s: %u cyls, " "%u trks/cyl, %u bytes/track\n", devtype, volser, volcyls, heads, trksize); #ifdef EXTERNALGUI if (extgui) fprintf (stderr, "CYLS=%u\n", volcyls); #endif /*EXTERNALGUI*/ /* Copy the unsuffixed AWSCKD image file name */ strcpy (sfname, ofname); suffix = NULL; /* Create the suffixed file name if volume will exceed 2GB */ if (volcyls > maxcpif) { /* Look for last slash marking end of directory name */ s = strrchr (ofname, '/'); if (s == NULL) s = ofname; /* Insert suffix before first dot in file name, or append suffix to file name if there is no dot */ s = strchr (s, '.'); if (s != NULL) { i = s - ofname; strcpy (sfname + i, "_1"); strcat (sfname, ofname + i); suffix = sfname + i + 1; } else { strcat (sfname, "_1"); suffix = sfname + strlen(sfname) - 1; } } /* Create the AWSCKD image files */ for (cyl = 0, fileseq = 1; cyl < volcyls; cyl += maxcpif, fileseq++) { /* Insert the file sequence number in the file name */ if (suffix) *suffix = '0' + fileseq; /* Calculate the ending cylinder for this file */ if (cyl + maxcpif < volcyls) endcyl = cyl + maxcpif - 1; else endcyl = volcyls - 1; /* Create an AWSCKD image file */ convert_ckd_file (ifd, ifname, itrklen, itrkbuf, repl, quiet, sfname, fileseq, devtype, heads, trksize, obuf, cyl, endcyl, volcyls, volser); } /* Release the output track buffer */ free (obuf); } /* end function convert_ckd */ /*-------------------------------------------------------------------*/ /* DASDCONV program main entry point */ /*-------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { IFD ifd; /* Input file descriptor */ int repl = 0; /* 1=replace existing file */ int quiet = 0; /* 1=suppress progress msgs */ BYTE *itrkbuf; /* -> Input track buffer */ U32 itrklen; /* Input track length */ U32 volcyls; /* Total cylinders on volume */ U32 heads = 0; /* Number of tracks/cylinder */ U32 maxdlen = 0; /* Maximum R1 data length */ U16 devtype; /* Device type */ char ifname[256]; /* Input file name */ char ofname[256]; /* Output file name */ BYTE volser[7]; /* Volume serial (ASCIIZ) */ int lfs = 0; /* 1 = Build large file */ INITIALIZE_UTILITY("dasdconv"); /* Display the program identification message */ display_version (stderr, "Hercules DASD CKD image conversion program\n", FALSE); /* Process the options in the argument list */ for (; argc > 1; argc--, argv++) { if (strcmp(argv[1], "-") == 0) break; if (argv[1][0] != '-') break; if (strcmp(argv[1], "-r") == 0) repl = 1; else if (strcmp(argv[1], "-q") == 0) quiet = 1; else if (sizeof(off_t) > 4 && strcmp(argv[1], "-lfs") == 0) lfs = 1; else argexit(5); } if (argc != 3) argexit(5); /* The first argument is the input file name */ if (argv[1] == NULL || strlen(argv[1]) == 0 || strlen(argv[1]) > sizeof(ifname)-1) argexit(1); strcpy (ifname, argv[1]); /* The second argument is the output file name */ if (argv[2] == NULL || strlen(argv[2]) == 0 || strlen(argv[2]) > sizeof(ofname)-1) argexit(2); strcpy (ofname, argv[2]); /* Read the first track of the input file, and determine the device type and size from the track header */ ifd = open_input_image (ifname, &devtype, &volcyls, &itrklen, &itrkbuf, volser); /* Use the device type to determine track characteristics */ switch (devtype) { case 0x2314: heads = 20; maxdlen = 7294; break; case 0x3330: heads = 19; maxdlen = 13030; break; case 0x3340: heads = 12; maxdlen = 8368; break; case 0x3350: heads = 30; maxdlen = 19069; break; case 0x3375: heads = 12; maxdlen = 35616; break; case 0x3380: heads = 15; maxdlen = 47476; break; case 0x3390: heads = 15; maxdlen = 56664; break; case 0x9345: heads = 15; maxdlen = 46456; break; default: fprintf (stderr, "Unknown device type: %4.4X\n", devtype); exit(3); } /* end switch(devtype) */ /* Create the device */ convert_ckd (lfs, ifd, ifname, itrklen, itrkbuf, repl, quiet, ofname, devtype, heads, maxdlen, volcyls, volser); /* Release the input buffer and close the input file */ free (itrkbuf); IFCLOS (ifd); /* Display completion message */ fprintf (stderr, "DASD conversion successfully completed.\n"); return 0; } /* end function main */ hercules-3.12/dasdcopy.c0000664000175000017500000005744512564723224012174 00000000000000/* DASDCOPY.C (c) Copyright Roger Bowler, 1999-2010 */ /* Copy a dasd file to another dasd file */ /*-------------------------------------------------------------------*/ /* This program copies a dasd file to another dasd file. */ /* Input file and output file may be compressed or not. */ /* Files may be either ckd (or cckd) or fba (or cfba) but */ /* file types (ckd/cckd or fba/cfba) may not be mixed. */ /* */ /* Usage: */ /* dasdcopy [-options] ifile [sf=sfile] ofile */ /* */ /* Refer to the usage section below for details of options. */ /* */ /* The program may also be invoked by one of the following */ /* aliases which override the default output file format: */ /* */ /* ckd2cckd [-options] ifile ofile */ /* cckd2ckd [-options] ifile [sf=sfile] ofile */ /* fba2cfba [-options] ifile ofile */ /* cfba2fba [-options] ifile [sf=sfile] ofile */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" #include "devtype.h" #include "opcode.h" #define FBA_BLKGRP_SIZE (120 * 512) /* Size of block group */ #define FBA_BLKS_PER_GRP 120 /* Blocks per group */ int syntax (char *); void status (int, int); int nulltrk(BYTE *, int, int, int); #define CKD 0x01 #define CCKD 0x02 #define FBA 0x04 #define CFBA 0x08 #define CKDMASK 0x03 #define FBAMASK 0x0c #define COMPMASK 0x0a /*-------------------------------------------------------------------*/ /* Copy a dasd file to another dasd file */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { char *pgm; /* -> Program name */ int ckddasd=-1; /* 1=CKD 0=FBA */ int rc; /* Return code */ int quiet=0; /* 1=Don't display status */ int comp=255; /* Compression algorithm */ int cyls=-1, blks=-1; /* Size of output file */ int lfs=0; /* 1=Create 1 large file */ int alt=0; /* 1=Create alt cyls */ int r=0; /* 1=Replace output file */ int in=0, out=0; /* Input/Output file types */ int fd; /* Input file descriptor */ char *ifile, *ofile; /* -> Input/Output file names*/ char *sfile=NULL; /* -> Input shadow file name */ CIFBLK *icif, *ocif; /* -> Input/Output CIFBLK */ DEVBLK *idev, *odev; /* -> Input/Output DEVBLK */ CKDDEV *ckd=NULL; /* -> CKD device table entry */ FBADEV *fba=NULL; /* -> FBA device table entry */ int i, n, max; /* Loop index, limits */ BYTE unitstat; /* Device unit status */ char msgbuf[512]; /* Message buffer */ size_t fba_bytes_remaining=0; /* FBA bytes to be copied */ int nullfmt = CKDDASD_NULLTRK_FMT0; /* Null track format */ char pathname[MAX_PATH]; /* file path in host format */ char pgmpath[MAX_PATH]; /* prog path in host format */ INITIALIZE_UTILITY("dasdcopy"); /* Figure out processing based on the program name */ hostpath(pgmpath, argv[0], sizeof(pgmpath)); pgm = strrchr (pgmpath, '/'); if (pgm) pgm++; else pgm = argv[0]; strtok (pgm, "."); if (strcmp(pgm, "ckd2cckd") == 0) { in = CKD; out = CCKD; } else if (strcmp(pgm, "cckd2ckd") == 0) { in = CCKD; out = CKD; } else if (strcmp(pgm, "fba2cfba") == 0) { in = FBA; out = CFBA; } else if (strcmp(pgm, "cfba2fba") == 0) { in = CFBA; out = FBA; } /* Process the arguments */ for (argc--, argv++ ; argc > 0 ; argc--, argv++) { if (argv[0][0] != '-') break; if (strcmp(argv[0], "-v") == 0) { snprintf (msgbuf, 512, _("Hercules %s copy program "), pgm); display_version (stderr, msgbuf, FALSE); return 0; } else if (strcmp(argv[0], "-h") == 0) { syntax(pgm); return 0; } else if (strcmp(argv[0], "-q") == 0 || strcmp(argv[0], "-quiet") == 0) quiet = 1; else if (strcmp(argv[0], "-r") == 0) r = 1; #ifdef CCKD_COMPRESS_ZLIB else if (strcmp(argv[0], "-z") == 0) comp = CCKD_COMPRESS_ZLIB; #endif #ifdef CCKD_COMPRESS_BZIP2 else if (strcmp(argv[0], "-bz2") == 0) comp = CCKD_COMPRESS_BZIP2; #endif else if (strcmp(argv[0], "-0") == 0) comp = CCKD_COMPRESS_NONE; else if ((strcmp(argv[0], "-cyl") == 0 || strcmp(argv[0], "-cyls") == 0) && cyls < 0) { if (argc < 2 || (cyls = atoi(argv[1])) < 0) return syntax(pgm); argc--; argv++; } else if ((strcmp(argv[0], "-blk") == 0 || strcmp(argv[0], "-blks") == 0) && blks < 0) { if (argc < 2 || (blks = atoi(argv[1])) < 0) return syntax(pgm); argc--; argv++; } else if (strcmp(argv[0], "-a") == 0 || strcmp(argv[0], "-alt") == 0 || strcmp(argv[0], "-alts") == 0) alt = 1; else if (strcmp(argv[0], "-lfs") == 0) lfs = 1; else if (out == 0 && strcmp(argv[0], "-o") == 0) { if (argc < 2 || out != 0) return syntax(pgm); if (strcasecmp(argv[1], "ckd") == 0) out = CKD; else if (strcasecmp(argv[1], "cckd") == 0) out = CCKD; else if (strcasecmp(argv[1], "fba") == 0) out = FBA; else if (strcasecmp(argv[1], "cfba") == 0) out = CFBA; else return syntax(pgm); argc--; argv++; } else return syntax(pgm); } /* Get the file names: input-file [sf=shadow-file] output-file */ if (argc < 2 || argc > 3) return syntax(pgm); ifile = argv[0]; if (argc < 3) ofile = argv[1]; else { if (strlen(argv[1]) < 4 || memcmp(argv[1], "sf=", 3)) return syntax(pgm); sfile = argv[1]; ofile = argv[2]; } /* If we don't know what the input file is then find out */ if (in == 0) { BYTE buf[8]; hostpath(pathname, ifile, sizeof(pathname)); fd = hopen(pathname, O_RDONLY|O_BINARY); if (fd < 0) { fprintf (stderr, _("HHCDC001E %s: %s open error: %s\n"), pgm, ifile, strerror(errno)); return -1; } rc = read (fd, buf, 8); if (rc < 8) { fprintf (stderr, _("HHCDC002E %s: %s read error: %s\n"), pgm, ifile, strerror(errno)); return -1; } if (memcmp(buf, "CKD_P370", 8) == 0) in = CKD; else if (memcmp(buf, "CKD_C370", 8) == 0) in = CCKD; else if (memcmp(buf, "FBA_C370", 8) == 0) in = CFBA; else in = FBA; close (fd); } /* If we don't know what the output file type is then derive it from the input file type */ if (out == 0) { switch (in) { case CKD: if (!lfs) out = CCKD; else out = CKD; break; case CCKD: if (comp == 255) out = CKD; else out = CCKD; break; case FBA: if (!lfs) out = CFBA; else out = FBA; break; case CFBA: if (comp == 255) out = FBA; else out = CFBA; break; } } /* Set default compression if out file is to be compressed */ if (comp == 255 && (out & COMPMASK)) #ifdef CCKD_COMPRESS_ZLIB comp = CCKD_COMPRESS_ZLIB; #else comp = CCKD_COMPRESS_NONE; #endif /* Perform sanity checks on the options */ if ((in & CKDMASK) && !(out & CKDMASK)) return syntax(pgm); if ((in & FBAMASK) && !(out & FBAMASK)) return syntax(pgm); if (sfile && !(in & COMPMASK)) return syntax(pgm); if (comp != 255 && !(out & COMPMASK)) return syntax(pgm); if (lfs && (out & COMPMASK)) return syntax(pgm); if (cyls >= 0 && !(in & CKDMASK)) return syntax(pgm); if (blks >= 0 && !(in & FBAMASK)) return syntax(pgm); if (!(in & CKDMASK) && alt) return syntax(pgm); /* Set the type of processing (ckd or fba) */ ckddasd = (in & CKDMASK); /* Open the input file */ if (ckddasd) icif = open_ckd_image (ifile, sfile, O_RDONLY|O_BINARY, 0); else icif = open_fba_image (ifile, sfile, O_RDONLY|O_BINARY, 0); if (icif == NULL) { fprintf (stderr, _("HHCDC003E %s: %s open failed\n"), pgm, ifile); return -1; } idev = &icif->devblk; if (idev->oslinux) nullfmt = CKDDASD_NULLTRK_FMT2; /* Calculate the number of tracks or blocks to copy */ if (ckddasd) { if (cyls < 0) cyls = idev->ckdcyls; else if (cyls == 0) cyls = (idev->hnd->used)(idev); ckd = dasd_lookup (DASD_CKDDEV, NULL, idev->devtype, cyls); if (ckd == NULL) { fprintf (stderr, _("HHCDC004E %s: ckd lookup failed for %4.4X " "cyls %d\n"), pgm, idev->devtype, cyls); close_image_file (icif); return -1; } // if (out == CCKD) cyls = ckd->cyls; if (cyls <= ckd->cyls && alt) cyls = ckd->cyls + ckd->altcyls; n = cyls * idev->ckdheads; max = idev->ckdtrks; if (max < n && out == CCKD) n = max; } else { fba_bytes_remaining = idev->fbanumblk * idev->fbablksiz; if (blks < 0) blks = idev->fbanumblk; else if (blks == 0) blks = (idev->hnd->used)(idev); fba = dasd_lookup (DASD_FBADEV, NULL, idev->devtype, blks); if (fba == NULL) { fprintf (stderr, _("HHCDC005E %s: fba lookup failed, blks %d\n"), pgm, blks); close_image_file (icif); return -1; } n = blks; max = idev->fbanumblk; if (max < n && out == CFBA) n = max; n = (n + FBA_BLKS_PER_GRP - 1) / FBA_BLKS_PER_GRP; max = (max + FBA_BLKS_PER_GRP - 1) / FBA_BLKS_PER_GRP; } /* Create the output file */ if (ckddasd) rc = create_ckd(ofile, idev->devtype, idev->ckdheads, ckd->r1, cyls, "", comp, lfs, 1+r, nullfmt, 0); else rc = create_fba(ofile, idev->devtype, fba->size, blks, "", comp, lfs, 1+r, 0); if (rc < 0) { fprintf (stderr, _("HHCDC006E %s: %s create failed\n"), pgm, ofile); close_image_file (icif); return -1; } /* Open the output file */ if (ckddasd) ocif = open_ckd_image (ofile, NULL, O_RDWR|O_BINARY, 1); else ocif = open_fba_image (ofile, NULL, O_RDWR|O_BINARY, 1); if (ocif == NULL) { fprintf (stderr, _("HHCDC007E %s: %s open failed\n"), pgm, ofile); close_image_file (icif); return -1; } odev = &ocif->devblk; /* Copy the files */ #ifdef EXTERNALGUI if (extgui) /* Notify GUI of total #of tracks or blocks being copied... */ fprintf (stderr, "TRKS=%d\n", n); else #endif /*EXTERNALGUI*/ if (!quiet) printf (" %3d%% %7d of %d", 0, 0, n); for (i = 0; i < n; i++) { /* Read a track or block */ if (ckddasd) { if (i < max) rc = (idev->hnd->read)(idev, i, &unitstat); else { memset (idev->buf, 0, idev->ckdtrksz); rc = nulltrk(idev->buf, i, idev->ckdheads, nullfmt); } } else { if (i < max) rc = (idev->hnd->read)(idev, i, &unitstat); else memset (idev->buf, 0, FBA_BLKGRP_SIZE); rc = 0; } if (rc < 0) { fprintf (stderr, _("HHCDC008E %s: %s read error %s %d " "stat=%2.2X, null %s substituted\n"), pgm, ifile, ckddasd ? "track" : "block", i, unitstat, ckddasd ? "track" : "block"); if (ckddasd) nulltrk(idev->buf, i, idev->ckdheads, nullfmt); else memset (idev->buf, 0, FBA_BLKGRP_SIZE); if (!quiet) { printf (_(" %3d%% %7d of %d"), 0, 0, n); status (i, n); } } /* Write the track or block just read */ if (ckddasd) { rc = (odev->hnd->write)(odev, i, 0, idev->buf, idev->ckdtrksz, &unitstat); } else { if (fba_bytes_remaining >= (size_t)idev->buflen) { rc = (odev->hnd->write)(odev, i, 0, idev->buf, idev->buflen, &unitstat); fba_bytes_remaining -= (size_t)idev->buflen; } else { ASSERT(fba_bytes_remaining > 0 && (i+1) >= n); rc = (odev->hnd->write)(odev, i, 0, idev->buf, (int)fba_bytes_remaining, &unitstat); fba_bytes_remaining = 0; } } if (rc < 0) { fprintf (stderr, _("HHCDC009E %s: %s write error %s %d " "stat=%2.2X\n"), pgm, ofile, ckddasd ? "track" : "block", i, unitstat); close_image_file(icif); close_image_file(ocif); return -1; } /* Update the status indicator */ if (!quiet) status (i+1, n); } close_image_file(icif); close_image_file(ocif); if (!quiet) printf (_("\r")); printf (_("HHCDC010I %s successfully completed.\n"), pgm); return 0; } /*-------------------------------------------------------------------*/ /* Build a null track image */ /*-------------------------------------------------------------------*/ int nulltrk(BYTE *buf, int trk, int heads, int nullfmt) { int i; /* Loop counter */ CKDDASD_TRKHDR *trkhdr; /* -> Track header */ CKDDASD_RECHDR *rechdr; /* -> Record header */ U32 cyl; /* Cylinder number */ U32 head; /* Head number */ BYTE r; /* Record number */ BYTE *pos; /* -> Next position in buffer*/ static BYTE eighthexFF[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; /* cylinder and head calculations */ cyl = trk / heads; head = trk % heads; /* Build the track header */ trkhdr = (CKDDASD_TRKHDR*)buf; trkhdr->bin = 0; store_hw(&trkhdr->cyl, cyl); store_hw(&trkhdr->head, head); pos = buf + CKDDASD_TRKHDR_SIZE; /* Build record zero */ r = 0; rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 8); pos += 8; r++; /* Specific null track formatting */ if (nullfmt == CKDDASD_NULLTRK_FMT0) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 0); r++; } else if (nullfmt == CKDDASD_NULLTRK_FMT2) { for (i = 0; i < 12; i++) { rechdr = (CKDDASD_RECHDR*)pos; pos += CKDDASD_RECHDR_SIZE; store_hw(&rechdr->cyl, cyl); store_hw(&rechdr->head, head); rechdr->rec = r; rechdr->klen = 0; store_hw(&rechdr->dlen, 4096); r++; pos += 4096; } } /* Build the end of track marker */ memcpy (pos, eighthexFF, 8); pos += 8; return 0; } /*-------------------------------------------------------------------*/ /* Display command syntax */ /*-------------------------------------------------------------------*/ int syntax (char *pgm) { char usage[8192]; if (strcmp(pgm, "ckd2cckd") == 0) snprintf(usage,8192,_( "usage: ckd2cckd [-options] ifile ofile\n" "\n" " copy a ckd dasd file to a compressed ckd dasd file\n" "\n" " ifile -- input ckd dasd file\n" " ofile -- output compressed ckd dasd file\n" "\n" " options:\n" " -v display program version and quit\n" " -h display this help and quit\n" " -q quiet mode, don't display status\n" " -r replace the output file if it exists\n" "%s" "%s" " -0 don't compress track images\n" " -cyls n size of output file\n" " -a output file will have alt cyls\n" ), #ifdef CCKD_COMPRESS_ZLIB _( " -z compress using zlib [default]\n" ), #else "", #endif #ifdef CCKD_COMPRESS_BZIP2 _( " -bz2 compress using bzip2\n" ) #else "" #endif ); else if (strcmp(pgm, "cckd2ckd") == 0) snprintf(usage,8192,_( "usage: cckd2ckd [-options] ifile [sf=sfile] ofile\n" "\n" " copy a compressed ckd file to a ckd file\n" "\n" " ifile -- input compressed ckd dasd file\n" " sfile -- input compressed ckd shadow file\n" " (optional)\n" " ofile -- output ckd dasd file\n" "\n" " options:\n" " -v display program version and quit\n" " -h display this help and quit\n" " -q quiet mode, don't display status\n" " -r replace the output file if it exists\n" "%s" " -cyls n size of output file\n" " -a output file will have alt cyls\n" ), (sizeof(off_t) > 4) ? _( " -lfs create single large output file\n" ) : ( "" ) ); else if (strcmp(pgm, "fba2cfba") == 0) snprintf(usage,8192,_( "usage: fba2cfba [-options] ifile ofile\n" "\n" " copy a fba dasd file to a compressed fba dasd file\n" "\n" " ifile -- input fba dasd file\n" " ofile -- output compressed fba dasd file\n" "\n" " options:\n" " -v display program version and quit\n" " -h display this help and quit\n" " -q quiet mode, don't display status\n" " -r replace the output file if it exists\n" "%s" "%s" " -0 don't compress track images\n" " -blks n size of output file\n" ), #ifdef CCKD_COMPRESS_ZLIB _( " -z compress using zlib [default]\n" ), #else "", #endif #ifdef CCKD_COMPRESS_BZIP2 _( " -bz2 compress using bzip2\n" ) #else "" #endif ); else if (strcmp(pgm, "cfba2fba") == 0) snprintf(usage,8192,_( "usage: cfba2fba [-options] ifile [sf=sfile] ofile\n" "\n" " copy a compressed fba file to a fba file\n" "\n" " ifile -- input compressed fba dasd file\n" " sfile -- input compressed fba shadow file\n" " (optional)\n" " ofile -- output fba dasd file\n" "\n" " options:\n" " -v display program version and quit\n" " -h display this help and quit\n" " -q quiet mode, don't display status\n" " -r replace the output file if it exists\n" "%s" " -blks n size of output file\n" ), (sizeof(off_t) > 4) ? _( " -lfs create single large output file\n" ) : ( "" ) ); else snprintf(usage,8192,_( "usage: %s [-options] ifile [sf=sfile] ofile\n" "\n" " copy a dasd file to another dasd file\n" "\n" " ifile -- input dasd file\n" " sfile -- input shadow file [optional]\n" " ofile -- output dasd file\n" "\n" " options:\n" " -v display program version and quit\n" " -h display this help and quit\n" " -q quiet mode, don't display status\n" " -r replace the output file if it exists\n" "%s" "%s" " -0 don't compress output\n" " -blks n size of output fba file\n" " -cyls n size of output ckd file\n" " -a output ckd file will have alt cyls\n" "%s" " even if it exceeds 2G in size\n" " -o type output file type (CKD, CCKD, FBA, CFBA)\n" ), pgm, #ifdef CCKD_COMPRESS_ZLIB _( " -z compress using zlib [default]\n" ), #else "", #endif #ifdef CCKD_COMPRESS_BZIP2 _( " -bz2 compress output using bzip2\n" ) #else "" #endif ,(sizeof(off_t) > 4) ? _( " -lfs output ckd file will be a single file\n" ) : ( "" ) ); printf ("%s", usage); return -1; } /* end function syntax */ /*-------------------------------------------------------------------*/ /* Display progress status */ /*-------------------------------------------------------------------*/ void status (int i, int n) { static char indic[] = "|/-\\"; #ifdef EXTERNALGUI if (extgui) { if (i % 100) return; fprintf (stderr, "TRK=%d\n", i); return; } #endif /*EXTERNALGUI*/ // if (i % 101 != 1) return; printf ("\r%c %3d%% %7d", indic[i%4], (int)((i*100.0)/n), i); } /* end function status */ hercules-3.12/dasdinit.c0000664000175000017500000002515212564723224012153 00000000000000/* DASDINIT.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules DASD Utilities: DASD image builder */ /*-------------------------------------------------------------------*/ /* This program creates a disk image file and initializes it as */ /* a blank FBA or CKD DASD volume. */ /* */ /* The program is invoked from the shell prompt using the command: */ /* */ /* dasdinit [-options] filename devtype[-model] [volser] [size] */ /* */ /* options options: */ /* -a include alternate cylinders */ /* (ignored if size specified manually) */ /* -z build compressed device using zlib */ /* -bz2 build compressed device using bzip2 */ /* -0 build compressed device with no compression */ /* -r "raw" init (bypass VOL1 & IPL track fmt) */ /* */ /* filename is the name of the disk image file to be created */ /* (this program will not overwrite an existing file) */ /* */ /* devtype is the emulated device type. */ /* CKD: 2305, 2311, 2314, 3330, 3350, 3375, 3380, */ /* 3390, 9345 */ /* FBA: 0671, 3310, 3370, 9313, 9332, 9335, 9336 */ /* */ /* model is the device model number and implies the device */ /* size. If specified, then size shouldn't be specified.*/ /* */ /* volser is the volume serial number (1-6 characters) */ /* (only if '-r' option not used) */ /* */ /* size is the size of the device (in cylinders for CKD */ /* devices, or in 512-byte sectors for FBA devices). */ /* Shouldn't be specified if model is specified. */ /* */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" /*-------------------------------------------------------------------*/ /* Subroutine to display command syntax and exit */ /*-------------------------------------------------------------------*/ static void argexit ( int code, char *m ) { switch (code) { case 0: fprintf (stderr, "Invalid or unsupported option: %s\n", m ? m : "(null)"); break; case 1: fprintf (stderr, "Invalid or missing filename: %s\n", m ? m : "(null)"); break; case 2: fprintf (stderr, "Invalid or missing device type: %s\n", m ? m : "(null)"); break; case 3: fprintf (stderr, "Invalid or missing volser: %s\n", m ? m : "(null)"); break; case 4: fprintf (stderr, "Invalid or missing size: %s\n", m ? m : "(null)"); break; case 5: fprintf (stderr, "Invalid number of arguments\n"); break; case 6: fprintf (stderr, "`-linux' only supported for device type 3390\n"); break; default: display_version (stderr, "Hercules DASD image file creation program\n", FALSE); fprintf (stderr, "Builds an empty dasd image file:\n\n" " dasdinit [-options] filename devtype[-model] [volser] [size]\n\n" "where:\n\n" " -v display version info and help\n" #ifdef HAVE_LIBZ " -z build compressed dasd image file using zlib\n" #endif #ifdef CCKD_BZIP2 " -bz2 build compressed dasd image file using bzip2\n" #endif " -0 build compressed dasd image file with no compression\n" ); if (sizeof(off_t) > 4) fprintf(stderr, " -lfs build a large (uncompressed) dasd file (if supported)\n" ); fprintf(stderr, " -a build dasd image file that includes alternate cylinders\n" " (option ignored if size is manually specified)\n" " -r build 'raw' dasd image file (no VOL1 or IPL track)\n" " -linux null track images will look like linux dasdfmt'ed images\n" " (3390 device type only)\n\n" " filename name of dasd image file to be created\n\n" " devtype CKD: 2305, 2311, 2314, 3330, 3340, 3350, 3375, 3380, 3390, 9345\n" " FBA: 0671, 3310, 3370, 9313, 9332, 9335, 9336\n\n" " model device model (implies size) (opt)\n\n" " volser volume serial number (1-6 characters)\n" " (specified only if '-r' option not used)\n\n" " size number of CKD cylinders or 512-byte FBA sectors\n" " (required if model not specified else optional)\n" ); break; } exit(code); } /* end function argexit */ /*-------------------------------------------------------------------*/ /* DASDINIT program main entry point */ /*-------------------------------------------------------------------*/ int main ( int argc, char *argv[] ) { int altcylflag = 0; /* Alternate cylinders flag */ int rawflag = 0; /* Raw format flag */ int volsize_argnum = 4; /* argc value of size option */ U32 size = 0; /* Volume size */ U32 altsize = 0; /* Alternate cylinders */ U32 heads = 0; /* Number of tracks/cylinder */ U32 maxdlen = 0; /* Maximum R1 data length */ U32 sectsize = 0; /* Sector size */ U16 devtype = 0; /* Device type */ BYTE comp = 0xff; /* Compression algoritm */ BYTE type = 0; /* C=CKD, F=FBA */ char fname[1024]; /* File name */ char volser[7]; /* Volume serial number */ BYTE c; /* Character work area */ CKDDEV *ckd; /* -> CKD device table entry */ FBADEV *fba; /* -> FBA device table entry */ int lfs = 0; /* 1 = Build large file */ int nullfmt = CKDDASD_NULLTRK_FMT1; /* Null track format type */ int rc; /* Return code */ INITIALIZE_UTILITY("dasdinit"); /* Display program identification and help */ if (argc <= 1 || (argc == 2 && !strcmp(argv[1], "-v"))) argexit(-1, NULL); /* Process optional arguments */ for ( ; argc > 1 && argv[1][0] == '-'; argv++, argc--) { if (strcmp("0", &argv[1][1]) == 0) comp = CCKD_COMPRESS_NONE; #ifdef HAVE_LIBZ else if (strcmp("z", &argv[1][1]) == 0) comp = CCKD_COMPRESS_ZLIB; #endif #ifdef CCKD_BZIP2 else if (strcmp("bz2", &argv[1][1]) == 0) comp = CCKD_COMPRESS_BZIP2; #endif else if (strcmp("a", &argv[1][1]) == 0) altcylflag = 1; else if (strcmp("r", &argv[1][1]) == 0) rawflag = 1; else if (strcmp("lfs", &argv[1][1]) == 0 && sizeof(off_t) > 4) lfs = 1; else if (strcmp("linux", &argv[1][1]) == 0) nullfmt = CKDDASD_NULLTRK_FMT2; else argexit(0, argv[1]); } /* Check remaining number of arguments */ if (argc < (rawflag ? 3 : 4) || argc > (rawflag ? 4 : 5)) argexit(5, NULL); /* The first argument is the file name */ if (argv[1] == NULL || strlen(argv[1]) == 0 || strlen(argv[1]) > sizeof(fname)-1) argexit(1, argv[1]); strcpy (fname, argv[1]); /* The second argument is the device type. Model number may also be specified */ if (argv[2] == NULL) argexit(2, argv[2]); ckd = dasd_lookup (DASD_CKDDEV, argv[2], 0, 0); if (ckd != NULL) { type = 'C'; devtype = ckd->devt; size = ckd->cyls; altsize = ckd->altcyls; heads = ckd->heads; maxdlen = ckd->r1; } else { fba = dasd_lookup (DASD_FBADEV, argv[2], 0, 0); if (fba != NULL) { type = 'F'; devtype = fba->devt; size = fba->blks; altsize = 0; sectsize = fba->size; } } if (!type) /* Specified model not found */ argexit(2, argv[2]); /* If -r option specified, then there is not volume serial argument and volume size argument is actually argument number 3 and not argument number 4 as otherwise */ if (rawflag) volsize_argnum = 3; else { volsize_argnum = 4; /* The third argument is the volume serial number */ if (argv[3] == NULL || strlen(argv[3]) == 0 || strlen(argv[3]) > sizeof(volser)-1) argexit(3, argv[3]); strcpy (volser, argv[3]); string_to_upper (volser); } /* The fourth argument (or third for -r) is the volume size */ if (argc > volsize_argnum) { if (argc > (volsize_argnum+1)) argexit(5, NULL); if (!argv[volsize_argnum] || strlen(argv[volsize_argnum]) == 0 || sscanf(argv[volsize_argnum], "%u%c", &size, &c) != 1) argexit(4, argv[volsize_argnum]); altcylflag = 0; } /* `-linux' only supported for 3390 device type */ if (nullfmt == CKDDASD_NULLTRK_FMT2 && devtype != 0x3390) argexit(6, NULL); if (altcylflag) size += altsize; /* Create the device */ if (type == 'C') rc = create_ckd (fname, devtype, heads, maxdlen, size, volser, comp, lfs, 0, nullfmt, rawflag); else rc = create_fba (fname, devtype, sectsize, size, volser, comp, lfs, 0, rawflag); /* Display completion message */ if (rc == 0) { fprintf (stderr, _("HHCDI001I DASD initialization successfully " "completed.\n")); } else { fprintf (stderr, _("HHCDI002I DASD initialization unsuccessful" "\n")); } return rc; } /* end function main */ hercules-3.12/dasdisup.c0000664000175000017500000006540112564723224012171 00000000000000/* DASDISUP.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules DASD Utilities: IEHIOSUP */ /*-------------------------------------------------------------------*/ /* This program performs the IEHIOSUP function of OS/360. */ /* It adjusts the TTRs in the XCTL tables in each of the */ /* Open/Close/EOV modules in SYS1.SVCLIB. */ /* */ /* The command format is: */ /* dasdisup ckdfile */ /* where: ckdfile is the name of the CKD image file */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ #define HEX00 ((BYTE)'\x00') /* EBCDIC low value */ #define HEX40 ((BYTE)'\x40') /* EBCDIC space */ #define HEXFF ((BYTE)'\xFF') /* EBCDIC high value */ #define OVERPUNCH_ZERO ((BYTE)'\xC0') /* EBCDIC 12-0 card punch */ /*-------------------------------------------------------------------*/ /* Definition of member information array entry */ /*-------------------------------------------------------------------*/ typedef struct _MEMINFO { BYTE memname[8]; /* Member name (EBCDIC) */ BYTE ttrtext[3]; /* TTR of first text record */ BYTE dwdsize; /* Text size in doublewords */ BYTE alias; /* 1=This is an alias */ BYTE notable; /* 1=Member has no XCTL table*/ BYTE multitxt; /* 1=Member has >1 text rcd */ } MEMINFO; #define MAX_MEMBERS 1000 /* Size of member info array */ /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ /* List of first loads for Open/Close/EOV routines */ static char *firstload[] = { "IGC0001I", /* Open (SVC19) */ "IGC0002{", /* Close (SVC20) */ "IGC0002A", /* Stow (SVC21) */ "IGC0002B", /* OpenJ (SVC22) */ "IGC0002C", /* TClose (SVC23) */ "IGC0002I", /* Scratch (SVC29) */ "IGC0003A", /* FEOV (SVC31) */ "IGC0003B", /* Allocate (SVC32) */ "IGC0005E", /* EOV (SVC55) */ "IGC0008A", /* Setprt (SVC81) */ "IGC0008F", /* Atlas (SVC86) */ "IGC0009C", /* TSO (SVC93) */ "IGC0009D", /* TSO (SVC94) */ NULL }; /* End of list */ /* List of second loads for Open/Close/EOV routines */ static char *secondload[] = { "IFG019", "IGG019", /* Open (SVC19) */ "IFG020", "IGG020", /* Close (SVC20) */ "IGG021", /* Stow (SVC21) */ "IFG023", "IGG023", /* TClose (SVC23) */ "IGG029", /* Scratch (SVC29) */ "IGG032", /* Allocate (SVC32) */ "IFG055", "IGG055", /* EOV (SVC55) */ "IGG081", /* Setprt (SVC81) */ "IGG086", /* Atlas (SVC86) */ "IGG093", /* TSO (SVC93) */ "IGG094", /* TSO (SVC94) */ NULL }; /* End of list */ static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; #if 0 /*-------------------------------------------------------------------*/ /* Subroutine to process a member */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* noext Number of extents in dataset */ /* extent Dataset extent array */ /* memname Member name (ASCIIZ) */ /* ttr Member TTR */ /* */ /* Return value is 0 if successful, or -1 if error */ /*-------------------------------------------------------------------*/ static int process_member (CIFBLK *cif, int noext, DSXTENT extent[], BYTE *memname, BYTE *ttr) { int rc; /* Return code */ int len; /* Record length */ int trk; /* Relative track number */ int cyl; /* Cylinder number */ int head; /* Head number */ int rec; /* Record number */ BYTE *buf; /* -> Data block */ FILE *ofp; /* Output file pointer */ BYTE ofname[256]; /* Output file name */ int offset; /* Offset of record in buffer*/ BYTE card[81]; /* Logical record (ASCIIZ) */ char pathname[MAX_PATH]; /* ofname in host path format*/ /* Build the output file name */ memset (ofname, 0, sizeof(ofname)); strncpy (ofname, memname, 8); string_to_lower (ofname); strcat (ofname, ".mac"); /* Open the output file */ hostpath(pathname, ofname, sizeof(pathname)); ofp = fopen (pathname, "w"); if (ofp == NULL) { fprintf (stderr, "Cannot open %s: %s\n", ofname, strerror(errno)); return -1; } /* Point to the start of the member */ trk = (ttr[0] << 8) | ttr[1]; rec = ttr[2]; fprintf (stdout, "Member %s TTR=%4.4X%2.2X\n", memname, trk, rec); /* Read the member */ while (1) { /* Convert relative track to cylinder and head */ rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head); if (rc < 0) return -1; // fprintf (stdout, // "CCHHR=%4.4X%4.4X%2.2X\n", // cyl, head, rec); /* Read a data block */ rc = read_block (cif, cyl, head, rec, NULL, NULL, &buf, &len); if (rc < 0) return -1; /* Move to next track if record not found */ if (rc > 0) { trk++; rec = 1; continue; } /* Exit at end of member */ if (len == 0) break; /* Check length of data block */ if (len % 80 != 0) { fprintf (stdout, "Bad block length %d at cyl %d head %d rec %d\n", len, cyl, head, rec); return -1; } /* Process each record in the data block */ for (offset = 0; offset < len; offset += 80) { if (asciiflag) { make_asciiz (card, sizeof(card), buf + offset, 72); fprintf (ofp, "%s\n", card); } else { fwrite (buf+offset, 80, 1, ofp); } if (ferror(ofp)) { fprintf (stdout, "Error writing %s: %s\n", ofname, strerror(errno)); return -1; } } /* end for(offset) */ /* Point to the next data block */ rec++; } /* end while */ /* Close the output file and exit */ fclose (ofp); return 0; } /* end function process_member */ #endif /*-------------------------------------------------------------------*/ /* Subroutine to process a directory block */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* noext Number of extents in dataset */ /* extent Dataset extent array */ /* dirblk Pointer to directory block */ /* Input/output: */ /* memtab Member information array */ /* nmem Number of entries in member information array */ /* */ /* Directory information for each member is extracted from the */ /* directory block and saved in the member information array. */ /* */ /* Return value is 0 if OK, +1 if end of directory, or -1 if error */ /*-------------------------------------------------------------------*/ static int process_dirblk (CIFBLK *cif, int noext, DSXTENT extent[], BYTE *dirblk, MEMINFO memtab[], int *nmem) { int n; /* Member array subscript */ int i; /* Array subscript */ int totlen; /* Total module length */ int txtlen; /* Length of 1st text block */ int size; /* Size of directory entry */ int k; /* Userdata halfword count */ BYTE *dirptr; /* -> Next byte within block */ int dirrem; /* Number of bytes remaining */ PDSDIR *dirent; /* -> Directory entry */ char memnama[9]; /* Member name (ASCIIZ) */ UNREFERENCED(cif); UNREFERENCED(noext); UNREFERENCED(extent); /* Load number of bytes in directory block */ dirptr = dirblk; dirrem = (dirptr[0] << 8) | dirptr[1]; if (dirrem < 2 || dirrem > 256) { fprintf (stdout, _("HHCDS003E Directory block byte count is invalid\n")); return -1; } /* Point to first directory entry */ dirptr += 2; dirrem -= 2; /* Process each directory entry */ for (n = *nmem; dirrem > 0; ) { /* Point to next directory entry */ dirent = (PDSDIR*)dirptr; /* Test for end of directory */ if (memcmp(dirent->pds2name, eighthexFF, 8) == 0) return +1; /* Load the user data halfword count */ k = dirent->pds2indc & PDS2INDC_LUSR; /* Point to next directory entry */ size = 12 + k*2; dirptr += size; dirrem -= size; /* Extract the member name */ make_asciiz (memnama, sizeof(memnama), dirent->pds2name, 8); if (dirent->pds2name[7] == OVERPUNCH_ZERO) memnama[7] = '{'; /* Find member in first load table */ for (i = 0; firstload[i] != NULL; i++) if (strcmp(memnama, firstload[i]) == 0) break; /* If not in first table, find in second table */ if (firstload[i] == NULL) { for (i = 0; secondload[i] != NULL; i++) if (memcmp(memnama, secondload[i], 6) == 0) break; /* If not in second table then skip member */ if (secondload[i] == NULL) { fprintf (stdout, _("HHCDS018I %s %s skipped\n"), memnama, ((dirent->pds2indc & PDS2INDC_ALIAS) ? "Alias" : "Member")); continue; } } /* end if(firstload[i]==NULL) */ /* Check that member information array is not full */ if (n >= MAX_MEMBERS) { fprintf (stdout, _("HHCDS004E Number of members exceeds MAX_MEMBERS\n")); return -1; } /* Check that user data contains at least 1 TTR */ if (((dirent->pds2indc & PDS2INDC_NTTR) >> PDS2INDC_NTTR_SHIFT) < 1) { fprintf (stdout, _("HHCDS005E Member %s TTR count is zero\n"), memnama); return -1; } /* Extract the total module length */ totlen = (dirent->pds2usrd[10] << 16) | (dirent->pds2usrd[11] << 8) | dirent->pds2usrd[12]; /* Extract the length of the first text block */ txtlen = (dirent->pds2usrd[13] << 8) | dirent->pds2usrd[14]; /* Save member information in the array */ memcpy (memtab[n].memname, dirent->pds2name, 8); memcpy (memtab[n].ttrtext, dirent->pds2usrd + 0, 3); memtab[n].dwdsize = totlen / 8; /* Flag the member if it is an alias */ memtab[n].alias = (dirent->pds2indc & PDS2INDC_ALIAS) ? 1 : 0; /* Flag member if 7th character of name is non-numeric */ memtab[n].notable = (memnama[6] < '0' || memnama[6] > '9') ? 1 : 0; /* Check that the member has a single text record */ if ((dirent->pds2usrd[8] & 0x01) == 0 || totlen != txtlen) { fprintf (stdout, _("HHCDS006W Member %s is not single text record\n"), memnama); memtab[n].multitxt = 1; } /* Check that the total module length does not exceed X'7F8' */ if (totlen > 255*8) { fprintf (stdout, _("HHCDS007W Member %s size %4.4X " "exceeds X\'7F8\' bytes\n"), memnama, totlen); } /* Check that the total module length is a multiple of 8 */ if (totlen & 0x7) { fprintf (stdout, _("HHCDS008W Member %s size %4.4X " "is not a multiple of 8\n"), memnama, totlen); } /* Increment number of entries in table */ *nmem = ++n; } /* end for */ return 0; } /* end function process_dirblk */ /*-------------------------------------------------------------------*/ /* Subroutine to resolve TTRs embedded within a member */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* noext Number of extents in dataset */ /* extent Dataset extent array */ /* memp Array entry for member whose TTRs are to be resolved */ /* memtab Member information array */ /* nmem Number of entries in member information array */ /* */ /* Return value is 0 if OK, -1 if error */ /*-------------------------------------------------------------------*/ static int resolve_xctltab (CIFBLK *cif, int noext, DSXTENT extent[], MEMINFO *memp, MEMINFO memtab[], int nmem) { int rc; /* Return code */ int i; /* Array subscript */ int len; /* Record length */ int cyl; /* Cylinder number */ int head; /* Head number */ int rec; /* Record number */ int trk; /* Relative track number */ int xctloff; /* Offset to XCTL table */ int warn; /* 1=Flag TTRL difference */ BYTE *blkptr; /* -> Text record data */ char memnama[9]; /* Member name (ASCIIZ) */ BYTE svcnum[3]; /* SVC number (EBCDIC) */ BYTE prefix[3]; /* IGG/IFG prefix (EBCDIC) */ BYTE refname[8]; /* Referred name (EBCDIC) */ char refnama[9]; /* Referred name (ASCIIZ) */ /* Extract the member name */ make_asciiz (memnama, sizeof(memnama), memp->memname, 8); if (memp->memname[7] == OVERPUNCH_ZERO) memnama[7] = '{'; /* Skip the member if it is an alias */ if (memp->alias) { fprintf (stdout, _("HHCDS009I Alias %s skipped\n"), memnama); return 0; } /* Skip the member if it has no XCTL table */ if (memp->notable) { fprintf (stdout, _("HHCDS010I Member %s skipped\n"), memnama); return 0; } /* Error if member is not a single text record */ if (memp->multitxt) { fprintf (stdout, _("HHCDS011E Member %s has multiple text records\n"), memnama); return -1; } /* Convert relative track to cylinder and head */ trk = (memp->ttrtext[0] << 8) | memp->ttrtext[1]; rec = memp->ttrtext[2]; rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head); if (rc < 0) { fprintf (stdout, _("HHCDS012E Member %s has invalid TTR %4.4X%2.2X\n"), memnama, trk, rec); return -1; } fprintf (stdout, _("HHCDS013I Processing member %s text record TTR=%4.4X%2.2X " "CCHHR=%4.4X%4.4X%2.2X\n"), memnama, trk, rec, cyl, head, rec); /* Read the text record */ rc = read_block (cif, cyl, head, rec, NULL, NULL, &blkptr, &len); if (rc != 0) { fprintf (stdout, _("HHCDS014E Member %s error reading TTR %4.4X%2.2X\n"), memnama, trk, rec); return -1; } /* Check for incorrect length record */ if (len < 8 || len > 1024 || (len & 0x7)) { fprintf (stdout, _("HHCDS015E Member %s TTR %4.4X%2.2X " "text record length %4.4X is not valid\n"), memnama, trk, rec, len); return -1; } /* Check that text record length matches directory entry */ if (len != memp->dwdsize * 8) { fprintf (stdout, _("HHCDS016E Member %s TTR %4.4X%2.2X " "text record length %4.4X does not match " "length %4.4X in directory\n"), memnama, trk, rec, len, memp->dwdsize * 8); return -1; } /* Extract the SVC number and the XCTL table offset from the last 4 bytes of the text record */ memcpy (svcnum, blkptr + len - 4, sizeof(svcnum)); xctloff = blkptr[len-1] * 8; /* For the first load of SVC 19, 20, 23, and 55, and for IFG modules, the table is in two parts. The parts are separated by a X'FFFF' delimiter. The first part refers to IFG modules, the second part refers to IGG modules */ if ((memcmp(memnama, "IGC", 3) == 0 && (memcmp(svcnum, "\xF0\xF1\xF9", 3) == 0 || memcmp(svcnum, "\xF0\xF2\xF0", 3) == 0 || memcmp(svcnum, "\xF0\xF2\xF3", 3) == 0 || memcmp(svcnum, "\xF0\xF5\xF5", 3) == 0)) || memcmp(memnama, "IFG", 3) == 0) convert_to_ebcdic (prefix, sizeof(prefix), "IFG"); else convert_to_ebcdic (prefix, sizeof(prefix), "IGG"); /* Process each entry in the XCTL table */ while (1) { /* Exit at end of XCTL table */ if (blkptr[xctloff] == HEX00 && blkptr[xctloff+1] == HEX00) break; /* Switch prefix at end of first part of table */ if (blkptr[xctloff] == HEXFF && blkptr[xctloff+1] == HEXFF) { xctloff += 2; convert_to_ebcdic (prefix, sizeof(prefix), "IGG"); continue; } /* Error if XCTL table overflows text record */ if (xctloff >= len - 10) { fprintf (stdout, _("HHCDS017E Member %s TTR %4.4X%2.2X " "XCTL table improperly terminated\n"), memnama, trk, rec); return -1; } /* Skip this entry if the suffix is blank */ if (blkptr[xctloff] == HEX40 && blkptr[xctloff+1] == HEX40) { xctloff += 6; continue; } /* Build the name of the member referred to */ memcpy (refname, prefix, 3); memcpy (refname + 3, svcnum, 3); memcpy (refname + 6, blkptr+xctloff, 2); make_asciiz (refnama, sizeof(refnama), refname, 8); /* Display XCTL table entry */ fprintf (stdout, _("HHCDS019I In member %s: %s TTRL=%2.2X%2.2X%2.2X%2.2X"), memnama, refnama, blkptr[xctloff+2], blkptr[xctloff+3], blkptr[xctloff+4], blkptr[xctloff+5]); /* Find the referred member in the member array */ for (i = 0; i < nmem; i++) { if (memcmp(memtab[i].memname, refname, 8) == 0) break; } /* end for(i) */ /* Loop if member not found */ if (i == nmem) { fprintf (stdout, " ** Member %s not found **\n", refnama); xctloff += 6; continue; } /* Loop if TTRL in the XCTL table matches actual TTRL */ if (memcmp(blkptr+xctloff+2, memtab[i].ttrtext, 3) == 0 && blkptr[xctloff+5] == memtab[i].dwdsize) { fprintf (stdout, "\n"); xctloff += 6; continue; } /* Flag entries whose L differs */ if (blkptr[xctloff+5] != memtab[i].dwdsize) warn = 1; else warn = 0; /* Replace TTRL in the XCTL table by the actual TTRL */ memcpy (blkptr+xctloff+2, memtab[i].ttrtext, 3); blkptr[xctloff+5] = memtab[i].dwdsize; fprintf (stdout, " replaced by TTRL=%2.2X%2.2X%2.2X%2.2X %s\n", blkptr[xctloff+2], blkptr[xctloff+3], blkptr[xctloff+4], blkptr[xctloff+5], (warn ? "****" : "")); /* Flag the track as modified to force rewrite */ cif->trkmodif = 1; /* Point to next entry in XCTL table */ xctloff += 6; } /* end while */ return 0; } /* end function resolve_xctltab */ /*-------------------------------------------------------------------*/ /* DASDISUP main entry point */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int rc; /* Return code */ int i; /* Array subscript */ int len; /* Record length */ int cyl; /* Cylinder number */ int head; /* Head number */ int rec; /* Record number */ int trk; /* Relative track number */ char *fname; /* -> CKD image file name */ char *sfname; /* -> CKD shadow file name */ int noext; /* Number of extents */ DSXTENT extent[16]; /* Extent descriptor array */ BYTE *blkptr; /* -> PDS directory block */ CIFBLK *cif; /* CKD image file descriptor */ MEMINFO *memtab; /* -> Member info array */ int nmem = 0; /* Number of array entries */ INITIALIZE_UTILITY("dasdisup"); /* Display the program identification message */ display_version (stderr, "Hercules IEHIOSUP program ", FALSE); /* Check the number of arguments */ if (argc < 2 || argc > 3) { fprintf (stdout, "Usage: %s ckdfile [sf=shadow-file-name]\n", argv[0]); return -1; } /* The first argument is the name of the CKD image file */ fname = argv[1]; /* The next argument, if there, is the name of the shadow file */ if (argc > 2) sfname = argv[2]; else sfname = NULL; /* Obtain storage for the member information array */ memtab = (MEMINFO*) malloc (sizeof(MEMINFO) * MAX_MEMBERS); if (memtab == NULL) { fprintf (stdout, _("HHCDS001E Cannot obtain storage for member array: %s\n"), strerror(errno)); return -1; } /* Open the CKD image file */ cif = open_ckd_image (fname, sfname, O_RDWR|O_BINARY, 0); if (cif == NULL) return -1; /* Build the extent array for the SVCLIB dataset */ rc = build_extent_array (cif, "SYS1.SVCLIB", extent, &noext); if (rc < 0) return -1; /* Point to the start of the directory */ trk = 0; rec = 1; /* Read the directory */ while (1) { /* Convert relative track to cylinder and head */ rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head); if (rc < 0) return -1; /* Read a directory block */ rc = read_block (cif, cyl, head, rec, NULL, NULL, &blkptr, &len); if (rc < 0) return -1; /* Move to next track if block not found */ if (rc > 0) { trk++; rec = 1; continue; } /* Exit at end of directory */ if (len == 0) break; /* Extract information for each member in directory block */ rc = process_dirblk (cif, noext, extent, blkptr, memtab, &nmem); if (rc < 0) return -1; if (rc > 0) break; /* Point to the next directory block */ rec++; } /* end while */ fprintf (stdout, _("HHCDS002I End of directory: %d members selected\n"), nmem); #ifdef EXTERNALGUI if (extgui) fprintf (stderr,"NMEM=%d\n",nmem); #endif /*EXTERNALGUI*/ /* Read each member and resolve the embedded TTRs */ for (i = 0; i < nmem; i++) { #ifdef EXTERNALGUI if (extgui) fprintf (stderr,"MEM=%d\n",i); #endif /*EXTERNALGUI*/ rc = resolve_xctltab (cif, noext, extent, memtab+i, memtab, nmem); } /* end for(i) */ /* Close the CKD image file and exit */ rc = close_ckd_image (cif); free (memtab); return rc; } /* end function main */ hercules-3.12/dasdload.c0000664000175000017500000062763312564723224012143 00000000000000/* DASDLOAD.C (c) Copyright Roger Bowler, 1999-2014 */ /* Hercules DASD Utilities: DASD image loader */ /*-------------------------------------------------------------------*/ /* This program creates a virtual DASD volume from a list of */ /* datasets previously unloaded using the TSO XMIT command. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* Corrections to CVOL initialization logic by Jay Maynard */ /* IEBCOPY native dataset support by Ronen Tzur */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" /*-------------------------------------------------------------------*/ /* Internal table sizes */ /*-------------------------------------------------------------------*/ #define MAXDBLK 10000 /* Maximum number of directory blocks per dataset */ #define MAXTTR 50000 /* Maximum number of TTRs per dataset */ #define MAXDSCB 1000 /* Maximum number of DSCBs */ /*-------------------------------------------------------------------*/ /* Internal macro definitions */ /*-------------------------------------------------------------------*/ #define CASERET(s) case s: return (#s) #define XMINF info_msg #define XMINFF info_msg #define XMERR printf #define XMERRF printf #define R0_DATALEN 8 #define IPL1_KEYLEN 4 #define IPL1_DATALEN 24 #define IPL2_KEYLEN 4 #define IPL2_DATALEN 144 #define VOL1_KEYLEN 4 #define VOL1_DATALEN 80 #define EBCDIC_END "\xC5\xD5\xC4" #define EBCDIC_TXT "\xE3\xE7\xE3" /*-------------------------------------------------------------------*/ /* Definition of LOGREC header record */ /*-------------------------------------------------------------------*/ typedef struct _DIPHDR { HWORD recid; /* Record identifier (0xFFFF)*/ HWORD bcyl; /* Extent begin cylinder */ HWORD btrk; /* Extent begin track */ HWORD ecyl; /* Extent end cylinder */ HWORD etrk; /* Extent end track */ BYTE resv; /* Unused */ BYTE restart[7]; /* Restart area BBCCHHR */ HWORD trkbal; /* Bytes remaining on track */ HWORD trklen; /* Total bytes on track */ BYTE reused[7]; /* Last reused BBCCHHR */ HWORD lasthead; /* Last track on cylinder */ HWORD trklen90; /* 90% of track length */ BYTE devcode; /* Device type code */ BYTE cchh90[4]; /* 90% full track CCHH */ BYTE switches; /* Switches */ BYTE endid; /* Check byte (0xFF) */ } DIPHDR; /*-------------------------------------------------------------------*/ /* Definition of internal extent descriptor array entry */ /*-------------------------------------------------------------------*/ typedef struct _EXTDESC { U16 bcyl; /* Begin cylinder */ U16 btrk; /* Begin track */ U16 ecyl; /* End cylinder */ U16 etrk; /* End track */ U16 ntrk; /* Number of tracks */ } EXTDESC; /*-------------------------------------------------------------------*/ /* Definition of internal TTR conversion table array entry */ /*-------------------------------------------------------------------*/ typedef struct _TTRCONV { BYTE origttr[3]; /* TTR in original dataset */ BYTE outpttr[3]; /* TTR in output dataset */ } TTRCONV; /*-------------------------------------------------------------------*/ /* Definitions for dataset initialization methods */ /*-------------------------------------------------------------------*/ #define METHOD_EMPTY 0 #define METHOD_XMIT 1 #define METHOD_DIP 2 #define METHOD_CVOL 3 #define METHOD_VTOC 4 #define METHOD_VS 5 #define METHOD_SEQ 6 #define METHOD_XMSEQ 7 #define METHOD_TEXT 8 /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; BYTE twelvehex00[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; BYTE cvol_low_key[] = {0, 0, 0, 0, 0, 0, 0, 1}; BYTE iplpsw[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; BYTE iplccw1[8] = {0x06, 0x00, 0x3A, 0x98, 0x60, 0x00, 0x00, 0x60}; BYTE iplccw2[8] = {0x08, 0x00, 0x3A, 0x98, 0x00, 0x00, 0x00, 0x00}; BYTE ipl2data[] = {0x07, 0x00, 0x3A, 0xB8, 0x40, 0x00, 0x00, 0x06, 0x31, 0x00, 0x3A, 0xBE, 0x40, 0x00, 0x00, 0x05, 0x08, 0x00, 0x3A, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*BBCCHH*/ 0x00, 0x00, 0x00, 0x00, 0x04}; /*CCHHR*/ BYTE noiplpsw[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F}; BYTE noiplccw1[8] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; BYTE noiplccw2[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /* Information message level: 0=None, 1=File name, 2=File information, 3=Member information, 4=Text units, record headers, 5=Dump data */ int infolvl = 1; /*-------------------------------------------------------------------*/ /* Subroutine to display command syntax and exit */ /*-------------------------------------------------------------------*/ static void argexit ( int code ) { fprintf (stderr, "dasdload creates a DASD image file from a list " "of TSO XMIT files\n" "Syntax:\tdasdload [options] ctlfile outfile [msglevel]\n" "where:\tctlfile = name of input control file\n" "\toutfile = name of DASD image file to be created\n" "\tmsglevel = Value 0-5 controls output verbosity\n" "\noptions:\n" "\t-0: no compression (default)\n" "\t-a: output disk will include alternate cylinders\n" #ifdef CCKD_COMPRESS_ZLIB "\t-z: compress using zlib\n" #endif #ifdef CCKD_COMPRESS_BZIP2 "\t-bz2: compress using bzip2\n" #endif ); if (sizeof(off_t) > 4) fprintf (stderr, "\t-lfs: create single large output file\n" ); exit(code); } /* end function argexit */ /*-------------------------------------------------------------------*/ /* Subroutine to display an informational message */ /*-------------------------------------------------------------------*/ static void info_msg (int lvl, char *msg, ...) { va_list vl; if (infolvl >= lvl) { va_start(vl, msg); vprintf (msg, vl); } } /* end function info_msg */ /*-------------------------------------------------------------------*/ /* Subroutine to load a S/390 integer value from a buffer */ /*-------------------------------------------------------------------*/ static int make_int (BYTE *src, int srclen) { int result = 0; /* Result accumulator */ int i; /* Array subscript */ for (i=0; i < srclen; i++) { result <<= 8; result |= src[i]; } return result; } /* end function make_int */ /*-------------------------------------------------------------------*/ /* Subroutine to return the name of a dataset organization */ /*-------------------------------------------------------------------*/ static char * dsorg_name (BYTE *dsorg) { static char name[8]; /* Name of dsorg */ if (dsorg[0] & DSORG_IS) strcpy (name, "IS"); else if (dsorg[0] & DSORG_PS) strcpy (name, "PS"); else if (dsorg[0] & DSORG_DA) strcpy (name, "DA"); else if (dsorg[0] & DSORG_PO) strcpy (name, "PO"); if (dsorg[0] & DSORG_U) strcat (name, "U"); return name; } /* end function dsorg_name */ /*-------------------------------------------------------------------*/ /* Subroutine to return the name of a record format */ /*-------------------------------------------------------------------*/ static char * recfm_name (BYTE *recfm) { static char name[8]; /* Name of record format */ switch (recfm[0] & RECFM_FORMAT) { case RECFM_FORMAT_V: strcpy (name, "V"); break; case RECFM_FORMAT_F: strcpy (name, "F"); break; case RECFM_FORMAT_U: strcpy (name, "U"); break; default: strcpy (name,"??"); } /* end switch */ if (recfm[0] & RECFM_TRKOFLOW) strcat (name, "T"); if (recfm[0] & RECFM_BLOCKED) strcat (name, "B"); if (recfm[0] & RECFM_SPANNED) strcat (name, "S"); switch (recfm[0] & RECFM_CTLCHAR) { case RECFM_CTLCHAR_A: strcpy (name, "A"); break; case RECFM_CTLCHAR_M: strcpy (name, "M"); break; } /* end switch */ return name; } /* end function recfm_name */ /*-------------------------------------------------------------------*/ /* Subroutine to return the name of a DASD device from the UCB type */ /*-------------------------------------------------------------------*/ static char * dasd_name (FWORD ucbtype) { if (ucbtype[2] != 0x20) return "????"; switch (ucbtype[3]) { case 0x01: return "2311"; case 0x02: return "2301"; case 0x03: return "2303"; case 0x04: if (ucbtype[1] == 0x00) return "2302"; else return "9345"; case 0x05: return "2321"; case 0x06: return "2305-1"; case 0x07: return "2305-2"; case 0x08: return "2314"; case 0x09: return "3330"; case 0x0A: return "3340"; case 0x0B: return "3350"; case 0x0C: return "3375"; case 0x0D: return "3330-11"; case 0x0E: return "3380"; case 0x0F: return "3390"; } /* end switch(key) */ return "????"; } /* end function dasd_name */ /*-------------------------------------------------------------------*/ /* Subroutine to return the UCBTYPE of a DASD device */ /*-------------------------------------------------------------------*/ static U32 ucbtype_code (U16 devtype) { switch (devtype) { case 0x2311: return 0x30002001; case 0x2301: return 0x30402002; case 0x2303: return 0x30002003; case 0x2302: return 0x30002004; case 0x2321: return 0x30002005; case 0x2305: return 0x30002006; case 0x2314: return 0x30C02008; case 0x3330: return 0x30502009; case 0x3340: return 0x3050200A; case 0x3350: return 0x3050200B; case 0x3375: return 0x3050200C; case 0x3380: return 0x3050200E; case 0x3390: return 0x3050200F; case 0x9345: return 0x30502004; } /* end switch(key) */ return 0; } /* end function ucbtype_code */ /*-------------------------------------------------------------------*/ /* Subroutine to calculate relative track address */ /* Input: */ /* cyl Cylinder number */ /* head Head number */ /* heads Number of heads per cylinder */ /* numext Number of extents */ /* xarray Array containing 1-16 extent descriptions */ /* Output: */ /* The return value is the relative track number, */ /* or -1 if an error occurred. */ /*-------------------------------------------------------------------*/ static int calculate_ttr (int cyl, int head, int heads, int numext, EXTDESC xarray[]) { int i; /* Array subscript */ int track; /* Relative track number */ /* Search the extent descriptor array */ for (i = 0, track = 0; i < numext; track += xarray[i++].ntrk) { if (cyl < xarray[i].bcyl || cyl > xarray[i].ecyl) continue; if (cyl == xarray[i].bcyl && head < xarray[i].btrk) continue; if (cyl == xarray[i].ecyl && head > xarray[i].etrk) continue; track += (cyl - xarray[i].bcyl) * heads - xarray[i].btrk + head; break; } /* end for(i) */ /* Error if track was not found in extent table */ if (i == numext) { XMERRF ("HHCDL033E CCHH=%4.4X%4.4X not found in extent table\n", cyl, head); return -1; } /* Return relative track number */ return track; } /* end function calculate_ttr */ /*-------------------------------------------------------------------*/ /* Subroutine to read IPL text from an EBCDIC object file */ /* Input: */ /* iplfnm Name of EBCDIC card image object file */ /* iplbuf Address of buffer in which to build IPL text record */ /* buflen Length of buffer */ /* Output: */ /* The return value is the length of the IPL text built */ /* in the buffer if successful, or -1 if error */ /* Note: */ /* Only TXT records are processed; ESD and RLD records are */ /* ignored because the IPL text is non-relocatable and is */ /* assumed to have zero origin. An END card must be present. */ /*-------------------------------------------------------------------*/ static int read_ipl_text (char *iplfnm, BYTE *iplbuf, int buflen) { int rc; /* Return code */ int ipllen = 0; /* Length of IPL text */ int txtlen; /* Byte count from TXT card */ int txtadr; /* Address from TXT card */ int tfd; /* Object file descriptor */ BYTE objrec[80]; /* Object card image */ char pathname[MAX_PATH]; /* iplfnm in host path format*/ /* Open the object file */ hostpath(pathname, iplfnm, sizeof(pathname)); tfd = hopen(pathname, O_RDONLY|O_BINARY); if (tfd < 0) { XMERRF ("HHCDL034E Cannot open %s: %s\n", iplfnm, strerror(errno)); return -1; } /* Read the object file */ while (1) { /* Read a card image from the object file */ rc = read (tfd, objrec, 80); if (rc < 80) { XMERRF ("HHCDL035E Cannot read %s: %s\n", iplfnm, strerror(errno)); close (tfd); return -1; } /* Column 1 of each object card must contain X'02' */ if (objrec[0] != 0x02) { XMERRF ("HHCDL036E %s is not a valid object file\n", iplfnm); close (tfd); return -1; } /* Exit if END card has been read */ if (memcmp(objrec+1, EBCDIC_END, 3) == 0) break; /* Ignore any cards which are not TXT cards */ if (memcmp(objrec+1, EBCDIC_TXT, 3) != 0) continue; /* Load the address from TXT card columns 6-8 */ txtadr = (objrec[5] << 16) | (objrec[6] << 8) | objrec[7]; /* Load the byte count from TXT card columns 11-12 */ txtlen = (objrec[10] << 8) | objrec[11]; XMINFF (5, "HHCDL037I IPL text address=%6.6X length=%4.4X\n", txtadr, txtlen); /* Check that the byte count is valid */ if (txtlen > 56) { XMERRF ("HHCDL038E TXT record in %s has invalid count %d\n", iplfnm, txtlen); close (tfd); return -1; } /* Check that the text falls within the buffer */ if (txtadr + txtlen > buflen) { XMERRF ("HHCDL039E IPL text in %s exceeds %d bytes\n", iplfnm, buflen); close (tfd); return -1; } /* Copy the IPL text to the buffer */ memcpy (iplbuf + txtadr, objrec+16, txtlen); /* Update the total size of the IPL text */ if (txtadr + txtlen > ipllen) ipllen = txtadr + txtlen; } /* end while */ return ipllen; } /* end function read_ipl_text */ /*-------------------------------------------------------------------*/ /* Subroutine to initialize the output track buffer */ /* Input: */ /* trklen Track length of virtual output device */ /* trkbuf Pointer to track buffer */ /* cyl Cylinder number on output device */ /* head Head number on output device */ /* Output: */ /* usedv Number of bytes written to track of virtual device */ /*-------------------------------------------------------------------*/ static void init_track (int trklen, BYTE *trkbuf, int cyl, int head, int *usedv) { CKDDASD_TRKHDR *trkhdr; /* -> Track header */ CKDDASD_RECHDR *rechdr; /* -> Record header */ /* Clear the track buffer to zeroes */ memset (trkbuf, 0, trklen); /* Build the home address in the track buffer */ trkhdr = (CKDDASD_TRKHDR*)trkbuf; trkhdr->bin = 0; trkhdr->cyl[0] = (cyl >> 8) & 0xFF; trkhdr->cyl[1] = cyl & 0xFF; trkhdr->head[0] = (head >> 8) & 0xFF; trkhdr->head[1] = head & 0xFF; /* Build a standard record zero in the track buffer */ rechdr = (CKDDASD_RECHDR*)(trkbuf + CKDDASD_TRKHDR_SIZE); rechdr->cyl[0] = (cyl >> 8) & 0xFF; rechdr->cyl[1] = cyl & 0xFF; rechdr->head[0] = (head >> 8) & 0xFF; rechdr->head[1] = head & 0xFF; rechdr->rec = 0; rechdr->klen = 0; rechdr->dlen[0] = (R0_DATALEN >> 8) & 0xFF; rechdr->dlen[1] = R0_DATALEN & 0xFF; /* Set number of bytes used in track buffer */ *usedv = CKDDASD_TRKHDR_SIZE + CKDDASD_RECHDR_SIZE + R0_DATALEN; /* Build end of track marker at end of buffer */ memcpy (trkbuf + *usedv, eighthexFF, 8); } /* end function init_track */ /*-------------------------------------------------------------------*/ /* Subroutine to write track buffer to output file */ /* Input: */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* Input/output: */ /* usedv Number of bytes written to track of virtual device */ /* reltrk Relative track number on output device */ /* cyl Cylinder number on output device */ /* head Head number on output device */ /* Output: */ /* The return value is 0 if successful, -1 if error occurred. */ /*-------------------------------------------------------------------*/ static int write_track (CIFBLK *cif, char *ofname, int heads, int trklen, int *usedv, int *reltrk, int *cyl, int *head) { int rc; /* Return code */ UNREFERENCED(ofname); UNREFERENCED(trklen); /* Don't overwrite HA */ if (*usedv == 0) *usedv = CKDDASD_TRKHDR_SIZE; /* Build end of track marker at end of buffer */ memcpy (cif->trkbuf + *usedv, eighthexFF, 8); cif->trkmodif = 1; /* Reset values for next track */ (*reltrk)++; (*head)++; if (*head >= heads) { (*cyl)++; *head = 0; } *usedv = 0; /* Read the next track */ if (*cyl < (int)cif->devblk.ckdcyls) { rc = read_track (cif, *cyl, *head); if (rc < 0) return -1; } return 0; } /* end function write_track */ /*-------------------------------------------------------------------*/ /* Subroutine to add a data block to the output track buffer */ /* Input: */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* blk Pointer to data block */ /* keylen Key length */ /* datalen Data length */ /* devtype Output device type */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* maxtrk Maximum number of tracks to be written */ /* Input/output: */ /* usedv Number of bytes written to track of virtual device */ /* usedr Number of bytes written to track, calculated */ /* according to the formula for a real device */ /* trkbal Number of bytes remaining on track, calculated */ /* according to the formula for a real device */ /* reltrk Relative track number on output device */ /* cyl Cylinder number on output device */ /* head Head number on output device */ /* rec Record number on output device */ /* Output: */ /* The return value is 0 if successful, -1 if error occurred. */ /*-------------------------------------------------------------------*/ static int write_block (CIFBLK *cif, char *ofname, DATABLK *blk, int keylen, int datalen, U16 devtype, int heads, int trklen, int maxtrk, int *usedv, int *usedr, int *trkbal, int *reltrk, int *cyl, int *head, int *rec) { int rc; /* Return code */ int cc; /* Capacity calculation code */ CKDDASD_RECHDR *rechdr; /* -> Record header */ UNREFERENCED(devtype); /* Determine whether record will fit on current track */ cc = capacity_calc (cif, *usedr, keylen, datalen, usedr, trkbal, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (cc < 0) return -1; /* Move to next track if record will not fit */ if (cc > 0 && *usedr > 0) { /* Write current track to output file */ rc = write_track (cif, ofname, heads, trklen, usedv, reltrk, cyl, head); if (rc < 0) return -1; /* Clear bytes used and record number for new track */ *usedr = 0; *rec = 0; /* Determine whether record will fit on new track */ cc = capacity_calc (cif, *usedr, keylen, datalen, usedr, trkbal, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (cc < 0) return -1; } /* end if */ /* Error if record will not even fit on an empty track */ if (cc > 0) { XMERRF ("HHCDL040E Input record CCHHR=%2.2X%2.2X%2.2X%2.2X%2.2X " "exceeds output device track size\n", blk->cyl[0], blk->cyl[1], blk->head[0], blk->head[1], blk->rec); return -1; } /* Determine whether end of extent has been reached */ if (*reltrk >= maxtrk) { XMERRF ("HHCDL041E Dataset exceeds extent size: reltrk=%d, " "maxtrk=%d\n", *reltrk, maxtrk); return -1; } /* Build home address and record 0 if new track */ if (*usedv == 0) { init_track (trklen, cif->trkbuf, *cyl, *head, usedv); } /* Double check that record will not exceed virtual track size */ if (*usedv + CKDDASD_RECHDR_SIZE + keylen + datalen + 8 > trklen) { XMERRF ("HHCDL042E Input record CCHHR=%2.2X%2.2X%2.2X%2.2X%2.2X " "exceeds virtual device track size\n", blk->cyl[0], blk->cyl[1], blk->head[0], blk->head[1], blk->rec); return -1; } /* Add data block to virtual track buffer */ (*rec)++; rechdr = (CKDDASD_RECHDR*)(cif->trkbuf + *usedv); rechdr->cyl[0] = (*cyl >> 8) & 0xFF; rechdr->cyl[1] = *cyl & 0xFF; rechdr->head[0] = (*head >> 8) & 0xFF; rechdr->head[1] = *head & 0xFF; rechdr->rec = *rec; rechdr->klen = keylen; rechdr->dlen[0] = (datalen >> 8) & 0xFF; rechdr->dlen[1] = datalen & 0xFF; *usedv += CKDDASD_RECHDR_SIZE; memcpy (cif->trkbuf + *usedv, blk->kdarea, keylen + datalen); *usedv += keylen + datalen; cif->trkmodif = 1; return 0; } /* end function write_block */ /*-------------------------------------------------------------------*/ /* Subroutine to write track zero */ /* Input: */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* volser Volume serial number (ASCIIZ) */ /* devtype Output device type */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* iplfnm Name of file containing IPL text object deck */ /* Output: */ /* reltrk Next relative track number on output device */ /* outcyl Cylinder number of next track on output device */ /* outhead Head number of next track on output device */ /* The return value is 0 if successful, -1 if error occurred. */ /*-------------------------------------------------------------------*/ static int write_track_zero (CIFBLK *cif, char *ofname, char *volser, U16 devtype, int heads, int trklen, char *iplfnm, int *reltrk, int *outcyl, int *outhead) { int rc; /* Return code */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ int keylen; /* Key length */ int datalen; /* Data length */ int maxtrks = 1; /* Maximum track count */ DATABLK *datablk; /* -> data block */ BYTE buf[32768]; /* Buffer for data block */ /* For 2311 the IPL text will not fit on track 0 record 4, so adjust the IPL2 so that it loads from track 1 record 1 */ if (devtype == 0x2311) { memcpy (ipl2data + 32, "\x00\x00\x00\x00\x00\x01", 6); memcpy (ipl2data + 38, "\x00\x00\x00\x01\x01", 5); maxtrks = 2; } /* Read track 0 */ rc = read_track (cif, 0, 0); if (rc < 0) return -1; /* Initialize the track buffer */ *outcyl = 0; *outhead = 0; init_track (trklen, cif->trkbuf, *outcyl, *outhead, &outusedv); cif->trkmodif = 1; /* Build the IPL1 record */ memset (buf, 0, sizeof(buf)); datablk = (DATABLK*)buf; convert_to_ebcdic (datablk->kdarea, 4, "IPL1"); if (iplfnm != NULL) { memcpy (datablk->kdarea+4, iplpsw, 8); memcpy (datablk->kdarea+12, iplccw1, 8); memcpy (datablk->kdarea+20, iplccw2, 8); } else { memcpy (datablk->kdarea+4, noiplpsw, 8); memcpy (datablk->kdarea+12, noiplccw1, 8); memcpy (datablk->kdarea+20, noiplccw2, 8); } keylen = IPL1_KEYLEN; datalen = IPL1_DATALEN; rc = write_block (cif, ofname, datablk, keylen, datalen, devtype, heads, trklen, maxtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, outcyl, outhead, &outrec); if (rc < 0) return -1; /* Build the IPL2 record */ memset (buf, 0, sizeof(buf)); datablk = (DATABLK*)buf; convert_to_ebcdic (datablk->kdarea, 4, "IPL2"); if (iplfnm != NULL) { memcpy (datablk->kdarea+4, ipl2data, sizeof(ipl2data)); } keylen = IPL2_KEYLEN; datalen = IPL2_DATALEN; rc = write_block (cif, ofname, datablk, keylen, datalen, devtype, heads, trklen, maxtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, outcyl, outhead, &outrec); if (rc < 0) return -1; /* Build the VOL1 record */ memset (buf, 0x40, sizeof(buf)); datablk = (DATABLK*)buf; convert_to_ebcdic (datablk->kdarea, 4, "VOL1"); convert_to_ebcdic (datablk->kdarea+4, 4, "VOL1"); convert_to_ebcdic (datablk->kdarea+8, 6, volser); memset(datablk->kdarea+15, 0, 5); convert_to_ebcdic (datablk->kdarea+45, 8, "HERCULES"); keylen = VOL1_KEYLEN; datalen = VOL1_DATALEN; rc = write_block (cif, ofname, datablk, keylen, datalen, devtype, heads, trklen, maxtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, outcyl, outhead, &outrec); if (rc < 0) return -1; /* Build the IPL text from the object file */ if (iplfnm != NULL) { memset (buf, 0, sizeof(buf)); datalen = read_ipl_text (iplfnm, buf+12, sizeof(buf)-12); if (datalen < 0) return -1; datablk = (DATABLK*)buf; keylen = 0; rc = write_block (cif, ofname, datablk, keylen, datalen, devtype, heads, trklen, maxtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, outcyl, outhead, &outrec); if (rc < 0) return -1; } /* Write track zero to the output file */ rc = write_track (cif, ofname, heads, trklen, &outusedv, reltrk, outcyl, outhead); if (rc < 0) return -1; return 0; } /* end function write_track_zero */ /*-------------------------------------------------------------------*/ /* Subroutine to update a data block in the output file */ /* Input: */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* blk Pointer to data block structure */ /* cyl Cylinder number */ /* head Head number */ /* rec Record number */ /* keylen Key length */ /* datalen Data length */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* Output: */ /* The return value is 0 if successful, -1 if error occurred. */ /*-------------------------------------------------------------------*/ static int update_block (CIFBLK *cif, char *ofname, DATABLK *blk, int cyl, int head, int rec, int keylen, int datalen, int heads, int trklen) { int rc; /* Return code */ int curcyl; /* Original cylinder */ int curhead; /* Original head */ int klen; /* Record key length */ int dlen; /* Record data length */ int skiplen; /* Number of bytes to skip */ int offset; /* Offset into trkbuf */ CKDDASD_TRKHDR trkhdr; /* Track header */ CKDDASD_RECHDR rechdr; /* Record header */ UNREFERENCED(heads); UNREFERENCED(trklen); /* Save the current position in the output file */ curcyl = cif->curcyl; curhead = cif->curhead; /* Read the requested track */ rc = read_track (cif, cyl, head); if (rc < 0) { XMERRF ("HHCDL043E %s cyl %d head %d read error\n", ofname, cyl, head); return -1; } /* Copy the track header */ memcpy (&trkhdr, cif->trkbuf, CKDDASD_TRKHDR_SIZE); offset = CKDDASD_TRKHDR_SIZE; /* Validate the track header */ if (trkhdr.bin != 0 || trkhdr.cyl[0] != (cyl >> 8) || trkhdr.cyl[1] != (cyl & 0xFF) || trkhdr.head[0] != (head >> 8) || trkhdr.head[1] != (head & 0xFF)) { XMERRF ("HHCDL044E %s cyl %d head %d invalid track header " "%2.2X%2.2X%2.2X%2.2X%2.2X\n", ofname, cyl, head, trkhdr.bin, trkhdr.cyl[0], trkhdr.cyl[1], trkhdr.head[0], trkhdr.head[1]); return -1; } /* Search for the record to be updated */ while (1) { /* Copy the next record header */ memcpy (&rechdr, cif->trkbuf + offset, CKDDASD_RECHDR_SIZE); offset += CKDDASD_RECHDR_SIZE; /* Check for end of track */ if (memcmp(&rechdr, eighthexFF, 8) == 0) { XMERRF ("HHCDL045E %s cyl %d head %d rec %d record not found\n", ofname, cyl, head, rec); return -1; } /* Extract record key length and data length */ klen = rechdr.klen; dlen = (rechdr.dlen[0] << 8) | rechdr.dlen[1]; /* Exit loop if matching record number */ if (rechdr.rec == rec) break; /* Skip the key and data areas */ skiplen = klen + dlen; offset += skiplen; } /* end while */ /* Check for attempt to change key length or data length */ if (keylen != klen || datalen != dlen) { XMERRF ("HHCDL046E Cannot update cyl %d head %d rec %d: " "Unmatched KL/DL\n", cyl, head, rec); return -1; } /* Copy the updated block to the trkbuf */ memcpy (cif->trkbuf + offset, blk->kdarea, keylen + datalen); cif->trkmodif = 1; /* Restore original track */ rc = read_track (cif, curcyl, curhead); if (rc < 0) { XMERRF ("HHCDL047E %s cyl %d head %d read error\n", ofname, curcyl, curhead); return -1; } XMINFF (4, "HHCDL048I Updating cyl %u head %u rec %d kl %d dl %d\n", cyl, head, rec, keylen, datalen); return 0; } /* end function update_block */ /*-------------------------------------------------------------------*/ /* Subroutine to build a format 1 DSCB */ /* Input: */ /* dscbtab Array of pointers to DSCB data blocks */ /* dscbnum Number of entries in dscbtab array */ /* dsname Dataset name (ASCIIZ) */ /* volser Volume serial number (ASCIIZ) */ /* dsorg 1st byte of dataset organization bits */ /* recfm 1st byte of record format bits */ /* lrecl Logical record length */ /* blksz Block size */ /* keyln Key length */ /* dirblu Bytes used in last directory block */ /* lasttrk Relative track number of last-used track of dataset */ /* lastrec Record number of last-used block of dataset */ /* trkbal Bytes remaining on last-used track */ /* units Allocation units (C=CYL, T=TRK) */ /* spsec Secondary allocation quantity */ /* bcyl Extent begin cylinder number */ /* bhead Extent begin head number */ /* ecyl Extent end cylinder number */ /* ehead Extent end head number */ /* Output: */ /* The return value is 0 if successful, or -1 if error */ /* */ /* This subroutine allocates a DATABLK structure, builds a DSCB */ /* within the structure, and adds the structure to the DSCB array. */ /*-------------------------------------------------------------------*/ static int build_format1_dscb (DATABLK *dscbtab[], int dscbnum, char *dsname, char *volser, BYTE dsorg, BYTE recfm, int lrecl, int blksz, int keyln, int dirblu, int lasttrk, int lastrec, int trkbal, BYTE units, int spsec, int bcyl, int bhead, int ecyl, int ehead) { DATABLK *datablk; /* -> Data block structure */ FORMAT1_DSCB *f1dscb; /* -> DSCB within data block */ int blklen; /* Size of data block */ struct tm *tmptr; /* -> Date and time structure*/ time_t timeval; /* Current time value */ /* Obtain the current time */ time(&timeval); tmptr = localtime(&timeval); /* Allocate storage for a DATABLK structure */ blklen = 12 + sizeof(FORMAT1_DSCB); datablk = (DATABLK*)malloc(blklen); if (datablk == NULL) { XMERRF ("HHCDL049E Cannot obtain storage for DSCB: %s\n", strerror(errno)); return -1; } /* Check that there is room in the DSCB pointer array */ if (dscbnum >= MAXDSCB) { XMERRF ("HHCDL050E DSCB count exceeds %d, increase MAXDSCB\n", MAXDSCB); return -1; } /* Clear the data block and save its address in the DSCB array */ memset (datablk, 0, blklen); dscbtab[dscbnum] = datablk; /* Point to the DSCB within the data block */ f1dscb = (FORMAT1_DSCB*)(datablk->kdarea); /* Build the format 1 DSCB */ convert_to_ebcdic (f1dscb->ds1dsnam, 44, dsname); f1dscb->ds1fmtid = 0xF1; convert_to_ebcdic (f1dscb->ds1dssn, 6, volser); f1dscb->ds1volsq[0] = 0; f1dscb->ds1volsq[1] = 1; f1dscb->ds1credt[0] = tmptr->tm_year; f1dscb->ds1credt[1] = (tmptr->tm_yday >> 8) & 0xFF; f1dscb->ds1credt[2] = tmptr->tm_yday & 0xFF; f1dscb->ds1expdt[0] = 0; f1dscb->ds1expdt[1] = 0; f1dscb->ds1expdt[2] = 0; f1dscb->ds1noepv = 1; f1dscb->ds1bodbd = dirblu; convert_to_ebcdic (f1dscb->ds1syscd, 13, "HERCULES"); f1dscb->ds1dsorg[0] = dsorg; f1dscb->ds1dsorg[1] = 0; f1dscb->ds1recfm = recfm; f1dscb->ds1optcd = 0; f1dscb->ds1blkl[0] = (blksz >> 8) & 0xFF; f1dscb->ds1blkl[1] = blksz & 0xFF; f1dscb->ds1lrecl[0] = (lrecl >> 8) & 0xFF; f1dscb->ds1lrecl[1] = lrecl & 0xFF; f1dscb->ds1keyl = keyln; f1dscb->ds1rkp[0] = 0; f1dscb->ds1rkp[1] = 0; f1dscb->ds1dsind = DS1DSIND_LASTVOL; if ((blksz & 0x07) == 0) f1dscb->ds1dsind |= DS1DSIND_BLKSIZ8; f1dscb->ds1scalo[0] = (units == 'C' ? DS1SCALO_UNITS_CYL : DS1SCALO_UNITS_TRK); f1dscb->ds1scalo[1] = (spsec >> 16) & 0xFF; f1dscb->ds1scalo[2] = (spsec >> 8) & 0xFF; f1dscb->ds1scalo[3] = spsec & 0xFF; f1dscb->ds1lstar[0] = (lasttrk >> 8) & 0xFF; f1dscb->ds1lstar[1] = lasttrk & 0xFF; f1dscb->ds1lstar[2] = lastrec; f1dscb->ds1trbal[0] = (trkbal >> 8) & 0xFF; f1dscb->ds1trbal[1] = trkbal & 0xFF; f1dscb->ds1ext1.xttype = (units == 'C' ? XTTYPE_CYLBOUND : XTTYPE_DATA); f1dscb->ds1ext1.xtseqn = 0; f1dscb->ds1ext1.xtbcyl[0] = (bcyl >> 8) & 0xFF; f1dscb->ds1ext1.xtbcyl[1] = bcyl & 0xFF; f1dscb->ds1ext1.xtbtrk[0] = (bhead >> 8) & 0xFF; f1dscb->ds1ext1.xtbtrk[1] = bhead & 0xFF; f1dscb->ds1ext1.xtecyl[0] = (ecyl >> 8) & 0xFF; f1dscb->ds1ext1.xtecyl[1] = ecyl & 0xFF; f1dscb->ds1ext1.xtetrk[0] = (ehead >> 8) & 0xFF; f1dscb->ds1ext1.xtetrk[1] = ehead & 0xFF; return 0; } /* end function build_format1_dscb */ /*-------------------------------------------------------------------*/ /* Subroutine to build a format 4 DSCB */ /* Input: */ /* dscbtab Array of pointers to DSCB data blocks */ /* dscbnum Number of entries in dscbtab array */ /* devtype Output device type */ /* Output: */ /* The return value is 0 if successful, or -1 if error */ /* */ /* This subroutine allocates a DATABLK structure, builds a DSCB */ /* within the structure, and adds the structure to the DSCB array. */ /* */ /* Note: The VTOC extent descriptor, the highest F1 DSCB address, */ /* and the number of unused DSCBs, are set to zeroes here and must */ /* be updated later when the VTOC size and location are known. */ /* The device size in cylinders is set to the normal size for the */ /* device type and must be updated when the actual total number of */ /* cylinders written to the volume is known. */ /*-------------------------------------------------------------------*/ static int build_format4_dscb (DATABLK *dscbtab[], int dscbnum, CIFBLK *cif) { DATABLK *datablk; /* -> Data block structure */ FORMAT4_DSCB *f4dscb; /* -> DSCB within data block */ int blklen; /* Size of data block */ int numdscb; /* Number of DSCBs per track */ int numdblk; /* Number of dir blks/track */ int physlen; /* Physical track length */ int numcyls; /* Device size in cylinders */ int numheads; /* Number of heads/cylinder */ int kbconst; /* Keyed block constant */ int lbconst; /* Last keyed block constant */ int nkconst; /* Non-keyed block constant */ BYTE devflag; /* Device flags for VTOC */ int tolfact; /* Device tolerance */ /* Calculate the physical track length, block overheads, device size, and the number of DSCBs and directory blocks per track */ capacity_calc (cif, 0, 44, 96, NULL, NULL, &physlen, &kbconst, &lbconst, &nkconst, &devflag, &tolfact, NULL, &numdscb, &numheads, &numcyls); capacity_calc (cif, 0, 8, 256, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &numdblk, NULL, NULL); /* Allocate storage for a DATABLK structure */ blklen = 12 + sizeof(FORMAT4_DSCB); datablk = (DATABLK*)malloc(blklen); if (datablk == NULL) { XMERRF ("HHCDL051E Cannot obtain storage for DSCB: %s\n", strerror(errno)); return -1; } /* Check that there is room in the DSCB pointer array */ if (dscbnum >= MAXDSCB) { XMERRF ("HHCDL052E DSCB count exceeds %d, increase MAXDSCB\n", MAXDSCB); return -1; } /* Clear the data block and save its address in the DSCB array */ memset (datablk, 0, blklen); dscbtab[dscbnum] = datablk; /* Point to the DSCB within the data block */ f4dscb = (FORMAT4_DSCB*)(datablk->kdarea); /* Build the format 4 DSCB */ memset (f4dscb->ds4keyid, 0x04, 44); f4dscb->ds4fmtid = 0xF4; f4dscb->ds4hcchh[0] = (numcyls >> 8) & 0xFF; f4dscb->ds4hcchh[1] = numcyls & 0xFF; f4dscb->ds4hcchh[2] = 0; f4dscb->ds4hcchh[3] = 0; f4dscb->ds4noatk[0] = 0; f4dscb->ds4noatk[1] = 0; f4dscb->ds4vtoci = DS4VTOCI_DIRF; f4dscb->ds4noext = 1; f4dscb->ds4devsz[0] = (numcyls >> 8) & 0xFF; f4dscb->ds4devsz[1] = numcyls & 0xFF; f4dscb->ds4devsz[2] = (numheads >> 8) & 0xFF; f4dscb->ds4devsz[3] = numheads & 0xFF; f4dscb->ds4devtk[0] = (physlen >> 8) & 0xFF; f4dscb->ds4devtk[1] = physlen & 0xFF; f4dscb->ds4devi = kbconst; f4dscb->ds4devl = lbconst; f4dscb->ds4devk = nkconst; f4dscb->ds4devfg = devflag; f4dscb->ds4devtl[0] = (tolfact >> 8) & 0xFF; f4dscb->ds4devtl[1] = tolfact & 0xFF; f4dscb->ds4devdt = numdscb; f4dscb->ds4devdb = numdblk; return 0; } /* end function build_format4_dscb */ /*-------------------------------------------------------------------*/ /* Subroutine to build a format 5 DSCB */ /* Input: */ /* dscbtab Array of pointers to DSCB data blocks */ /* dscbnum Number of entries in dscbtab array */ /* Output: */ /* The return value is 0 if successful, or -1 if error */ /* */ /* This subroutine allocates a DATABLK structure, builds a DSCB */ /* within the structure, and adds the structure to the DSCB array. */ /* */ /* Note: The format 5 DSCB is built with no free space extents. */ /* The DIRF bit is set in ds4vtoci to force the operating system */ /* VTOC conversion routine to calculate the free space and update */ /* the format 5 DSCB the first time the volume is accessed. */ /*-------------------------------------------------------------------*/ static int build_format5_dscb (DATABLK *dscbtab[], int dscbnum) { DATABLK *datablk; /* -> Data block structure */ FORMAT5_DSCB *f5dscb; /* -> DSCB within data block */ int blklen; /* Size of data block */ /* Allocate storage for a DATABLK structure */ blklen = 12 + sizeof(FORMAT5_DSCB); datablk = (DATABLK*)malloc(blklen); if (datablk == NULL) { XMERRF ("HHCDL053E Cannot obtain storage for DSCB: %s\n", strerror(errno)); return -1; } /* Check that there is room in the DSCB pointer array */ if (dscbnum >= MAXDSCB) { XMERRF ("HHCDL054E DSCB count exceeds %d, increase MAXDSCB\n", MAXDSCB); return -1; } /* Clear the data block and save its address in the DSCB array */ memset (datablk, 0, blklen); dscbtab[dscbnum] = datablk; /* Point to the DSCB within the data block */ f5dscb = (FORMAT5_DSCB*)(datablk->kdarea); /* Build the format 5 DSCB */ memset (f5dscb->ds5keyid, 0x05, 4); f5dscb->ds5fmtid = 0xF5; return 0; } /* end function build_format5_dscb */ /*-------------------------------------------------------------------*/ /* Subroutine to write the VTOC */ /* Input: */ /* dscbtab Array of pointers to DSCB data blocks */ /* numdscb Number of DSCBs including format 4 and format 5 */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* devtype Output device type */ /* reqcyls Requested device size in cylinders, or zero */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* vtoctrk Starting relative track number for VTOC, or zero */ /* vtocext Number of tracks in VTOC, or zero */ /* Input/output: */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /* Output: */ /* volvtoc VTOC starting CCHHR (5 bytes) */ /* The return value is 0 if successful, or -1 if error */ /* */ /* If vtoctrk and vtocext are non-zero, then the VTOC is written */ /* into the space previously reserved at the indicated location. */ /* Otherwise, the VTOC is written at the next available dataset */ /* location, using as many tracks as are necessary, and nextcyl */ /* and nexthead are updated to point past the end of the VTOC. */ /*-------------------------------------------------------------------*/ static int write_vtoc (DATABLK *dscbtab[], int numdscb, CIFBLK *cif, char *ofname, U16 devtype, int reqcyls, int heads, int trklen, int vtoctrk, int vtocext, int *nxtcyl, int *nxthead, BYTE volvtoc[]) { int rc; /* Return code */ int i; /* Array subscript */ DATABLK *datablk; /* -> Data block structure */ FORMAT1_DSCB *f1dscb; /* -> Format 1 DSCB */ FORMAT4_DSCB *f4dscb; /* -> Format 4 DSCB */ int dscbpertrk; /* Number of DSCBs per track */ int mintrks; /* Minimum VTOC size (tracks)*/ int numtrks; /* Actual VTOC size (tracks) */ int highcyl; /* Last used cylinder number */ int highhead; /* Last used head number */ int highrec; /* Last used record number */ int numf0dscb; /* Number of unused DSCBs */ int abstrk; /* Absolute track number */ int endcyl; /* VTOC end cylinder number */ int endhead; /* VTOC end head number */ int numcyls; /* Volume size in cylinders */ int outusedv = 0; /* Bytes used in track buffer*/ int outusedr = 0; /* Bytes used on real track */ int outtrkbr; /* Bytes left on real track */ int outcyl; /* Output cylinder number */ int outhead; /* Output head number */ int outtrk = 0; /* Relative track number */ int outrec = 0; /* Output record number */ int prealloc = 0; /* 1=VTOC is preallocated */ BYTE blankblk[152]; /* Data block for blank DSCB */ int curcyl; /* Current cylinder in file */ int curhead; /* Current head in file */ char dsnama[45]; /* Dataset name (ASCIIZ) */ /* Determine if the VTOC is preallocated */ prealloc = (vtoctrk != 0 && vtocext != 0); /* Point to the format 4 DSCB within the first data block */ f4dscb = (FORMAT4_DSCB*)(dscbtab[0]->kdarea); /* Calculate the minimum number of tracks required for the VTOC */ dscbpertrk = f4dscb->ds4devdt; mintrks = (numdscb + dscbpertrk - 1) / dscbpertrk; /* Save the current position in the output file */ curcyl = cif->curcyl; curhead = cif->curhead; /* Obtain the VTOC starting location and size */ if (prealloc) { /* Use preallocated VTOC location */ outcyl = vtoctrk / heads; outhead = vtoctrk % heads; numtrks = vtocext; } else { /* Use next available dataset location for VTOC */ outcyl = *nxtcyl; outhead = *nxthead; numtrks = mintrks; } /* Check that VTOC extent size is sufficient */ if (numtrks < mintrks) { XMERRF ("HHCDL055E VTOC too small, %d track%s required\n", mintrks, (mintrks == 1 ? "" : "s")); return -1; } /* Read the first track of the VTOC */ rc = read_track (cif, outcyl, outhead); if (rc < 0) { XMERRF ("HHCDL056E Error reading VTOC cyl %d head %d\n", outcyl, outhead); return -1; } /* Calculate the CCHHR of the last format 1 DSCB */ abstrk = (outcyl * heads) + outhead; abstrk += mintrks - 1; highcyl = abstrk / heads; highhead = abstrk % heads; highrec = ((numdscb - 1) % dscbpertrk) + 1; /* Update the last format 1 CCHHR in the format 4 DSCB */ f4dscb->ds4hpchr[0] = (highcyl >> 8) & 0xFF; f4dscb->ds4hpchr[1] = highcyl & 0xFF; f4dscb->ds4hpchr[2] = (highhead >> 8) & 0xFF; f4dscb->ds4hpchr[3] = highhead & 0xFF; f4dscb->ds4hpchr[4] = highrec; /* Build the VTOC start CCHHR */ volvtoc[0] = (outcyl >> 8) & 0xFF; volvtoc[1] = outcyl & 0xFF; volvtoc[2] = (outhead >> 8) & 0xFF; volvtoc[3] = outhead & 0xFF; volvtoc[4] = 1; XMINFF (1, "HHCDL057I VTOC starts at cyl %d head %d and is %d track%s\n", outcyl, outhead, numtrks, (numtrks == 1 ? "" : "s")); /* Calculate the number of format 0 DSCBs required to fill out the unused space at the end of the VTOC */ numf0dscb = (numtrks * dscbpertrk) - numdscb; /* Update the format 0 DSCB count in the format 4 DSCB */ f4dscb->ds4dsrec[0] = (numf0dscb >> 8) & 0xFF; f4dscb->ds4dsrec[1] = numf0dscb & 0xFF; /* Calculate the CCHH of the last track of the VTOC */ abstrk = (outcyl * heads) + outhead; abstrk += numtrks - 1; endcyl = abstrk / heads; endhead = abstrk % heads; /* Update the VTOC extent descriptor in the format 4 DSCB */ f4dscb->ds4vtoce.xttype = (endhead == heads - 1 ? XTTYPE_CYLBOUND : XTTYPE_DATA); f4dscb->ds4vtoce.xtseqn = 0; f4dscb->ds4vtoce.xtbcyl[0] = (outcyl >> 8) & 0xFF; f4dscb->ds4vtoce.xtbcyl[1] = outcyl & 0xFF; f4dscb->ds4vtoce.xtbtrk[0] = (outhead >> 8) & 0xFF; f4dscb->ds4vtoce.xtbtrk[1] = outhead & 0xFF; f4dscb->ds4vtoce.xtecyl[0] = (endcyl >> 8) & 0xFF; f4dscb->ds4vtoce.xtecyl[1] = endcyl & 0xFF; f4dscb->ds4vtoce.xtetrk[0] = (endhead >> 8) & 0xFF; f4dscb->ds4vtoce.xtetrk[1] = endhead & 0xFF; /* Calculate the mimimum volume size */ if (prealloc) { /* The VTOC was preallocated, so the minimum volume size equals the next available cylinder number */ numcyls = *nxtcyl; if (*nxthead != 0) numcyls++; } else { /* The VTOC will be written into the available space, so the minimum volume size is one more than the ending cylinder number of the VTOC */ numcyls = endcyl + 1; } /* If the minimum volume size is less than the requested size then use the requested size as the actual size */ if (numcyls < reqcyls) numcyls = reqcyls; /* Update the volume size in cylinders in the format 4 DSCB */ f4dscb->ds4devsz[0] = (numcyls >> 8) & 0xFF; f4dscb->ds4devsz[1] = numcyls & 0xFF; /* Format the track buffer */ init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv); cif->trkmodif = 1; /* Write the format 4, format 5, and format 1 DSCBs to the VTOC */ for (i = 0; i < numdscb; i++) { /* Load the data block pointer from the DSCB table */ datablk = dscbtab[i]; /* Extract the dataset name from the format 1 DSCB */ memset (dsnama, 0, sizeof(dsnama)); f1dscb = (FORMAT1_DSCB*)(datablk->kdarea); if (f1dscb->ds1fmtid == 0xF1) { make_asciiz (dsnama, sizeof(dsnama), f1dscb->ds1dsnam, sizeof(f1dscb->ds1dsnam)); } /* Add next DSCB to the track buffer */ rc = write_block (cif, ofname, datablk, 44, 96, devtype, heads, trklen, numtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; XMINFF (4, "HHCDL058I Format %d DSCB CCHHR=%4.4X%4.4X%2.2X " "(TTR=%4.4X%2.2X) %s\n", datablk->kdarea[0] == 0x04 ? 4 : datablk->kdarea[0] == 0x05 ? 5 : 1, outcyl, outhead, outrec, outtrk, outrec, dsnama); if (infolvl >= 5) data_dump (datablk, 152); } /* end for(i) */ /* Fill the remainder of the VTOC with format 0 DSCBs */ for (i = 0; i < numf0dscb; i++) { /* Add a format 0 DSCB to the track buffer */ memset (blankblk, 0, sizeof(blankblk)); datablk = (DATABLK*)blankblk; rc = write_block (cif, ofname, datablk, 44, 96, devtype, heads, trklen, numtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; XMINFF (4, "HHCDL059I Format 0 DSCB CCHHR=%4.4X%4.4X%2.2X " "(TTR=%4.4X%2.2X)\n", outcyl, outhead, outrec, outtrk, outrec); } /* end for(i) */ /* Write data remaining in last track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Restore original file position if VTOC was preallocated */ if (prealloc) { /* Read the original track again */ rc = read_track (cif, curcyl, curhead); if (rc < 0) { XMERRF ("HHCDL060E Error reading track cyl %d head %d\n", curcyl, curhead); return -1; } } else { /* Update next cyl and head if VTOC not preallocated */ *nxtcyl = outcyl; *nxthead = outhead; } return 0; } /* end function write_vtoc */ /*-------------------------------------------------------------------*/ /* Subroutine to return the name of a text unit */ /*-------------------------------------------------------------------*/ static char * tu_name (U16 key) { switch (key) { CASERET(INMDDNAM); CASERET(INMDSNAM); CASERET(INMMEMBR); CASERET(INMDIR ); CASERET(INMEXPDT); CASERET(INMTERM ); CASERET(INMBLKSZ); CASERET(INMDSORG); CASERET(INMLRECL); CASERET(INMRECFM); CASERET(INMTNODE); CASERET(INMTUID ); CASERET(INMFNODE); CASERET(INMFUID ); CASERET(INMLREF ); CASERET(INMLCHG ); CASERET(INMCREAT); CASERET(INMFVERS); CASERET(INMFTIME); CASERET(INMTTIME); CASERET(INMFACK ); CASERET(INMERRCD); CASERET(INMUTILN); CASERET(INMUSERP); CASERET(INMRECCT); CASERET(INMSIZE ); CASERET(INMFFM ); CASERET(INMNUMF ); CASERET(INMTYPE ); } /* end switch(key) */ return "????????"; } /* end function tu_name */ /*-------------------------------------------------------------------*/ /* Subroutine to extract next text unit from buffer */ /* Input: */ /* xbuf Pointer to start of buffer */ /* bufpos Position of next text unit within buffer */ /* bufrem Number of bytes remaining in buffer */ /* pkey Pointer to field to receive text unit key */ /* pnum Pointer to field to receive number of data items */ /* maxnum Maximum number of data items expected */ /* plen Pointer to array to receive data item lengths */ /* pdata Pointer to array to receive data item pointers */ /* Output: */ /* The function return value is the total length of the */ /* text unit, or -1 if error. */ /* */ /* Text units are listed if infolvl is 4 or greater. */ /*-------------------------------------------------------------------*/ static int next_tu (BYTE *xbuf, int bufpos, int bufrem, U16 *pkey, U16 *pnum, U16 maxnum, U16 plen[], BYTE *pdata[]) { int i, j; /* Array subscripts */ U16 key, num; /* Text unit header */ int field; /* Field number */ int offset; /* Offset into text unit */ U16 len; /* Field length */ char *name; /* Text unit name */ BYTE c, chars[9]; /* Character work areas */ char hex[17]; /* Character work areas */ set_codepage(NULL); /* Error if remaining length is insufficient for header */ if (bufrem < 4) { XMERR ("HHCDL061E Incomplete text unit\n"); return -1; } /* Load the key and field count from the first 4 bytes */ key = (xbuf[bufpos] << 8) | xbuf[bufpos+1]; num = (xbuf[bufpos+2] << 8) | xbuf[bufpos+3]; /* Obtain the text unit name */ name = tu_name(key); /* Print the text unit name and field count */ XMINFF (4, "HHCDL062I \t+%4.4X %-8.8s %4.4X %4.4X ", bufpos, name, key, num); /* Error if number of fields exceeds maximum */ if (num > maxnum) { XMINF (4, "\n"); XMERR ("HHCDL063E Too many fields in text unit\n"); return -1; } /* Point to first field */ offset = 4; bufrem -= 4; /* Process each field in text unit */ for (field = 0; field < num; field++) { /* Error if remaining length is insufficient for length */ if (bufrem < 2) { XMINF (4, "\n"); XMERR ("HHCDL064E Incomplete text unit\n"); return -1; } /* Load field length from next 2 bytes */ len = (xbuf[bufpos+offset] << 8) | xbuf[bufpos+offset+1]; offset += 2; bufrem -= 2; /* Error if remaining length is insufficient for data */ if (bufrem < len) { XMINF (4, "\n"); XMERR ("HHCDL065E Incomplete text unit\n"); return -1; } /* Print field length and data */ if (field > 0) XMINF (4, "\n\t\t\t\t "); XMINFF (4, "%4.4X ", len); memset (hex, '\0', sizeof(hex)); memset (chars, '\0', sizeof(chars)); for (i = 0, j = 0; i < len; i++, j++) { if (i > 0 && (i & 0x07) == 0) { XMINFF (4, "%-16.16s %-8.8s\n\t\t\t\t ", hex, chars); memset (hex, '\0', sizeof(hex)); memset (chars, '\0', sizeof(chars)); j = 0; } sprintf(hex+2*j, "%2.2X", xbuf[bufpos+offset+i]); c = guest_to_host(xbuf[bufpos+offset+i]); if (!isprint(c)) c = '.'; chars[j] = c; } /* end for(i) */ XMINFF (4, "%-16.16s %-8.8s", hex, chars); /* Save field length and pointer in array */ plen[field] = len; pdata[field] = xbuf + bufpos + offset; /* Get offset of next field in text unit */ offset += len; bufrem -= len; } /* end for */ /* Print newline at end of text unit */ XMINF (4, "\n"); /* Return key, number of fields, and total length */ *pkey = key; *pnum = num; return offset; } /* end function next_tu */ /*-------------------------------------------------------------------*/ /* Subroutine to assemble a logical record from segments */ /* Input: */ /* xfd Input file descriptor */ /* xfname Input file name */ /* xbuf Pointer to buffer to receive logical record */ /* Output: */ /* ctl Zero=data record, non-zero=control record */ /* The return value is the logical record length, */ /* or -1 if an error occurred. */ /*-------------------------------------------------------------------*/ static int read_xmit_rec (int xfd, char *xfname, BYTE *xbuf, BYTE *ctl) { int rc; /* Return code */ int xreclen = 0; /* Cumulative record length */ int segnum; /* Segment counter */ int seglen; /* Segment data length */ BYTE ctlind = 0x00; /* 0x20=Control record */ BYTE seghdr[2]; /* Segment length and flags */ for (segnum = 0; ; segnum++) { /* Read the segment length and flags */ rc = read (xfd, seghdr, 2); if (rc < 2) { XMERRF ("HHCDL066E %s read error: %s\n", xfname, (rc < 0 ? strerror(errno) : "Unexpected end of file")); return -1; } /* Check for valid segment header */ if (seghdr[0] < 2 || (seghdr[1] & 0x1F) != 0) { XMERRF ("HHCDL067E %s invalid segment header: %2.2X%2.2X\n", xfname, seghdr[0], seghdr[1]); return -1; } /* Check flags for first segment */ if (segnum == 0) { /* Check that first segment indicator is set */ if ((seghdr[1] & 0x80) == 0) { XMERRF ("HHCDL068E %s first segment indicator expected\n", xfname); return -1; } /* Save the control record indicator */ ctlind = (seghdr[1] & 0x20); } /* Check flags for subsequent segments */ if (segnum > 0) { /* Check that first segment indicator is not set */ if (seghdr[1] & 0x80) { XMERRF ("HHCDL069E %s first segment indicator not expected\n", xfname); return -1; } /* Check if ctlrec indicator matches first segment */ if ((seghdr[1] & 0x20) != ctlind) { XMERRF ("HHCDL070E %s control record indicator mismatch\n", xfname); return -1; } } /* Read segment data into buffer */ seglen = seghdr[0] - 2; rc = read (xfd, xbuf + xreclen, seglen); if (rc < seglen) { XMERRF ("HHCDL071E %s read error: %s\n", xfname, (rc < 0 ? strerror(errno) : "Unexpected end of file")); return -1; } /* Accumulate total record length */ xreclen += seglen; /* Exit if last segment of record */ if (seghdr[1] & 0x40) break; } /* end for(segnum) */ /* Return record length and control indicator */ *ctl = ctlind; return xreclen; } /* end function read_xmit_rec */ /*-------------------------------------------------------------------*/ /* Subroutine to assemble a logical record from DSORG=VS file */ /* Input: */ /* xfd Input file descriptor */ /* xfname Input file name */ /* xbuf Pointer to buffer to receive logical record */ /* recnum Relative number for the record to be read */ /* Output: */ /* The return value is the logical record length, */ /* or -1 if an error occurred. */ /*-------------------------------------------------------------------*/ static int read_vs_rec (int xfd, char *xfname, BYTE *xbuf, int recnum) { int rc; /* Return code */ int xreclen; /* Cumulative record length */ DATABLK *datablk; /* Data block */ if (recnum == 0) { xreclen = read(xfd, xbuf, 56); /* read COPYR1 plus some extras */ if (xreclen < 56) { XMERRF ("HHCDL072E %s read error: %s\n", xfname, (xreclen < 0 ? strerror(errno) : "Unexpected end of file")); return -1; } } else if (recnum == 1) { xreclen = read(xfd, xbuf, sizeof(COPYR2)); /* read COPYR2 */ if (xreclen < (int)sizeof(COPYR2)) { XMERRF ("HHCDL073E %s read error: %s\n", xfname, (xreclen < 0 ? strerror(errno) : "Unexpected end of file")); return -1; } } else { rc = read(xfd, xbuf, 12); /* read header of DATABLK */ if (rc == 0) /* read nothing? */ return 0; if (rc < 12) { XMERRF ("HHCDL074E %s read error: %s\n", xfname, (rc < 0 ? strerror(errno) : "Unexpected end of file")); return -1; } datablk = (DATABLK *)xbuf; xreclen = ((datablk->dlen[0] << 8) | datablk->dlen[1]) + datablk->klen; rc = read(xfd, xbuf + 12, xreclen); /* read kdarea of DATABLK */ if (rc < xreclen) { XMERRF ("HHCDL075E %s read error: %s\n", xfname, (rc < 0 ? strerror(errno) : "Unexpected end of file")); return -1; } xreclen += 12; /* also count the header */ } /* Return record length */ return xreclen; } /* end function read_vs_rec */ /*-------------------------------------------------------------------*/ /* Subroutine to process an INMR02 control record */ /* Input: */ /* xbuf Pointer to buffer containing control record */ /* xreclen Length of control record */ /* utiln Name of utility being processed (ASCIIZ) */ /* filen Pointer to field to receive file sequence number */ /* dsorg Pointer to byte to receive dataset organization */ /* recfm Pointer to byte to receive record format */ /* lrecl Pointer to integer to receive logical record length */ /* blksz Pointer to integer to receive block size */ /* keyln Pointer to integer to receive key length */ /* dirnm Pointer to integer to number of directory blocks */ /* Output: */ /* If the record contains the text unit INMUTILN whose */ /* value matches the name of the utility passed in utiln */ /* then the dataset attributes are returned and the function */ /* return value is 1. Otherwise the return value is 0 */ /* and the dataset attributes remain unchanged. */ /* If an error occurs then the return value is -1. */ /* */ /* File information is listed if infolvl is 2 or greater. */ /*-------------------------------------------------------------------*/ static int process_inmr02 (BYTE *xbuf, int xreclen, char *utiln, int *filen, BYTE *dsorg, BYTE *recfm, U16 *lrecl, U16 *blksz, U16 *keyln, U16 *dirnm) { int rc; /* Return code */ int i; /* Array subscript */ int len; /* String length */ U32 filenum; /* File number */ int bufpos; /* Position of TU in buffer */ int bufrem; /* Bytes remaining in buffer */ char tuutiln[9]; /* Utility name */ BYTE tukeyln; /* Key length */ HWORD tudsorg; /* Data set organization */ HWORD turecfm; /* Record format */ U16 tulrecl; /* Logical record length */ U16 tublksz; /* Block size */ int tudirct; /* Number of directory blocks*/ U16 tukey; /* Text unit key */ U16 tunum; /* Number of text unit fields*/ char tudsnam[45]; /* Data set name */ #define MAXNUM 20 /* Maximum number of fields */ U16 fieldlen[MAXNUM]; /* Array of field lengths */ BYTE *fieldptr[MAXNUM]; /* Array of field pointers */ /* Extract the file number which follows the record name */ filenum = (xbuf[6] << 24) | (xbuf[7] << 16) | (xbuf[8] << 8) | xbuf[9]; XMINFF (4, "HHCDL076I File number: %d\n", filenum); /* Point to the first text unit */ bufpos = 10; bufrem = xreclen-10; /* Clear values to be loaded from text units */ memset (tudsnam, 0, sizeof(tudsnam)); memset (tuutiln, 0, sizeof(tuutiln)); memset (tudsorg, 0, sizeof(tudsorg)); memset (turecfm, 0, sizeof(turecfm)); tulrecl = 0; tublksz = 0; tukeyln = 0; tudirct = 0; /* Process each text unit */ while (bufrem > 0) { /* Extract the next text unit */ rc = next_tu (xbuf, bufpos, bufrem, &tukey, &tunum, MAXNUM, fieldlen, fieldptr); if (rc < 0) { XMERRF ("HHCDL077E Invalid text unit at offset %4.4X\n", bufpos + 2); return -1; } bufpos += rc; bufrem -= rc; /* Save the values from selected text units */ switch (tukey) { case INMUTILN: make_asciiz (tuutiln, sizeof(tuutiln), fieldptr[0], fieldlen[0]); break; case INMDSORG: if (fieldlen[0] > sizeof(tudsorg)) fieldlen[0] = sizeof(tudsorg); memcpy (tudsorg, fieldptr[0], fieldlen[0]); break; case INMRECFM: if (fieldlen[0] > sizeof(turecfm)) fieldlen[0] = sizeof(turecfm); memcpy (turecfm, fieldptr[0], fieldlen[0]); break; case INMLRECL: tulrecl = make_int (fieldptr[0], fieldlen[0]); break; case INMBLKSZ: tublksz = make_int (fieldptr[0], fieldlen[0]); break; case INMTYPE: tukeyln = make_int (fieldptr[0], fieldlen[0]); break; case INMDIR: tudirct = make_int (fieldptr[0], fieldlen[0]); break; case INMDSNAM: memset (tudsnam, 0, sizeof(tudsnam)); for (i = 0; i < tunum; i++) { len = strlen(tudsnam); if (i > 0 && len < (int)(sizeof(tudsnam) - 1)) tudsnam[len++] = '.'; make_asciiz (tudsnam + len, sizeof(tudsnam) - len, fieldptr[i], fieldlen[i]); } /* end for(i) */ } /* end switch(tukey) */ } /* end while(bufrem) */ /* Return the dataset values if this INMR02 record is for utiln */ if (strcmp(tuutiln, utiln) == 0) { XMINFF (2, "HHCDL078I File %u: DSNAME=%s\n", filenum, tudsnam); XMINFF (2, "HHCDL079I DSORG=%s RECFM=%s " "LRECL=%d BLKSIZE=%d KEYLEN=%d DIRBLKS=%d\n", dsorg_name(tudsorg), recfm_name(turecfm), tulrecl, tublksz, tukeyln, tudirct); *filen = filenum; *dsorg = tudsorg[0]; *recfm = turecfm[0]; *lrecl = tulrecl; *blksz = tublksz; *keyln = tukeyln; *dirnm = tudirct; } return 0; } /* end function process_inmr02 */ /*-------------------------------------------------------------------*/ /* Subroutine to process a control record other than INMR02 */ /* Input: */ /* xbuf Pointer to buffer containing control record */ /* xreclen Length of control record */ /* Output: */ /* The return value is 0 if successful, or -1 if error. */ /*-------------------------------------------------------------------*/ static int process_inmrxx (BYTE *xbuf, int xreclen) { int rc; /* Return code */ int bufpos; /* Position of TU in buffer */ int bufrem; /* Bytes remaining in buffer */ U16 tukey; /* Text unit key */ U16 tunum; /* Number of text unit fields*/ #define MAXNUM 20 /* Maximum number of fields */ U16 fieldlen[MAXNUM]; /* Array of field lengths */ BYTE *fieldptr[MAXNUM]; /* Array of field pointers */ /* Point to the first text unit */ bufpos = 6; bufrem = xreclen-6; /* Process each text unit */ while (bufrem > 0) { /* Extract the next text unit */ rc = next_tu (xbuf, bufpos, bufrem, &tukey, &tunum, MAXNUM, fieldlen, fieldptr); if (rc < 0) { XMERRF ("HHCDL080E Invalid text unit at offset %4.4X\n", bufpos + 2); return -1; } bufpos += rc; bufrem -= rc; } /* end while(bufrem) */ return 0; } /* end function process_inmrxx */ /*-------------------------------------------------------------------*/ /* Subroutine to process a COPYR1 header record */ /* Input: */ /* xbuf Pointer to buffer containing header record */ /* xreclen Length of header record */ /* Output: */ /* The return value is the number of tracks per cylinder, */ /* or -1 if an error occurred. */ /*-------------------------------------------------------------------*/ static int process_copyr1 (BYTE *xbuf, int xreclen) { COPYR1 *copyr1 = (COPYR1*)xbuf; /* -> COPYR1 header record */ U16 blksize; /* Block size */ U16 lrecl; /* Logical record length */ BYTE keylen; /* Key length */ U16 cyls; /* Number of cylinders */ U16 heads; /* Number of tracks/cylinder */ /* Check COPYR1 record for correct length */ if (xreclen != sizeof(COPYR1) && xreclen != sizeof(COPYR1) - 4) { XMERR ("HHCDL081E COPYR1 record length is invalid\n"); return -1; } /* Check that COPYR1 header identifier is correct */ if (memcmp(copyr1->hdrid, COPYR1_HDRID, 3) != 0) { XMERR ("HHCDL082E COPYR1 header identifier not correct\n"); return -1; } /* Check that the dataset is an old format unload */ if ((copyr1->uldfmt & COPYR1_ULD_FORMAT) != COPYR1_ULD_FORMAT_OLD) { XMERR ("HHCDL083E COPYR1 unload format is unsupported\n"); return -1; } blksize = (copyr1->ds1blkl[0] << 8) | copyr1->ds1blkl[1]; lrecl = (copyr1->ds1lrecl[0] << 8) | copyr1->ds1lrecl[1]; keylen = copyr1->ds1keyl; /* Display original dataset information */ XMINFF (2, "HHCDL084I Original dataset: " "DSORG=%s RECFM=%s LRECL=%d BLKSIZE=%d KEYLEN=%d\n", dsorg_name(copyr1->ds1dsorg), recfm_name(©r1->ds1recfm), lrecl, blksize, keylen); XMINFF (2, "HHCDL085I Dataset was unloaded from device type " "%2.2X%2.2X%2.2X%2.2X (%s)\n", copyr1->ucbtype[0], copyr1->ucbtype[1], copyr1->ucbtype[2], copyr1->ucbtype[3], dasd_name(copyr1->ucbtype)); cyls = (copyr1->cyls[0] << 8) | copyr1->cyls[1]; heads = (copyr1->heads[0] << 8) | copyr1->heads[1]; XMINFF (2, "HHCDL086I Original device has %d cyls and %d heads\n", cyls, heads); return heads; } /* end function process_copyr1 */ /*-------------------------------------------------------------------*/ /* Subroutine to process a COPYR2 header record */ /* Input: */ /* xbuf Pointer to buffer containing header record */ /* xreclen Length of header record */ /* xarray Pointer to array to receive 1-16 extent descriptions */ /* Output: */ /* The return value is the number of extents, */ /* or -1 if an error occurred. */ /* */ /* Extent information is listed if infolvl is 4 or greater. */ /*-------------------------------------------------------------------*/ static int process_copyr2 (BYTE *xbuf, int xreclen, EXTDESC xarray[]) { COPYR2 *copyr2 = (COPYR2*)xbuf; /* -> COPYR2 header record */ int numext; /* Number of extents */ int i; /* Array subscript */ /* Check COPYR2 record for correct length */ if (xreclen != sizeof(COPYR2)) { XMERR ("HHCDL087I COPYR2 record length is invalid\n"); return -1; } /* Get number of extents from DEB basic section */ numext = copyr2->debbasic[0]; if (numext < 1 || numext > 16) { XMERRF ("HHCDL088I Invalid number of extents %d\n", numext); return -1; } /* Copy each extent descriptor into the array */ for (i = 0; i < numext; i++) { xarray[i].bcyl = (copyr2->debxtent[i][6] << 8) | copyr2->debxtent[i][7]; xarray[i].btrk = (copyr2->debxtent[i][8] << 8) | copyr2->debxtent[i][9]; xarray[i].ecyl = (copyr2->debxtent[i][10] << 8) | copyr2->debxtent[i][11]; xarray[i].etrk = (copyr2->debxtent[i][12] << 8) | copyr2->debxtent[i][13]; xarray[i].ntrk = (copyr2->debxtent[i][14] << 8) | copyr2->debxtent[i][15]; XMINFF (4, "HHCDL089I Extent %d: Begin CCHH=%4.4X%4.4X " "End CCHH=%4.4X%4.4X Tracks=%4.4X\n", i, xarray[i].bcyl, xarray[i].btrk, xarray[i].ecyl, xarray[i].etrk, xarray[i].ntrk); } /* end for(i) */ /* Return number of extents */ return numext; } /* end function process_copyr2 */ /*-------------------------------------------------------------------*/ /* Subroutine to process a directory block record */ /* Input: */ /* xbuf Pointer to directory block */ /* blklen Length of directory block */ /* cyl Cylinder number of directory block in output file */ /* head Head number of directory block in output file */ /* rec Record number of directory block in output file */ /* dirblka Array of pointers to directory blocks */ /* dirblkn Number of directory blocks in dirblka array */ /* Output: */ /* dirblu Number of bytes used in directory block */ /* The return value is 0 if successful, 1 if end of directory, */ /* or -1 if an error occurred. */ /* */ /* A pointer to the directory block is saved in the dirblka array. */ /* The copy of the data block is updated with the cylinder, head, */ /* and record number of the directory block in the output file. */ /* Directory information is listed if infolvl is 3 or greater. */ /*-------------------------------------------------------------------*/ static int process_dirblk (DATABLK *xbuf, int blklen, int cyl, int head, int rec, DATABLK *dirblka[], int dirblkn, int *dirblu) { int size; /* Size of directory entry */ int i, j; /* Array subscripts */ int k; /* Userdata halfword count */ DATABLK *blkp; /* -> Copy of directory block*/ BYTE *dirptr; /* -> Next byte within block */ int dirrem; /* Number of bytes remaining */ PDSDIR *dirent; /* -> Directory entry */ char memname[9]; /* Member name (ASCIIZ) */ BYTE c, chars[25]; /* Character work areas */ char hex[49]; /* Character work areas */ set_codepage(NULL); /* Check for end of directory */ if (blklen == 12 && memcmp(xbuf, twelvehex00, 12) == 0) { XMINF (3, "HHCDL090I End of directory\n"); return 1; } /* Check directory block record for correct length */ if (blklen != 276) { XMERR ("HHCDL091E Directory block record length is invalid\n"); return -1; } /* Obtain storage for a copy of the directory block */ blkp = (DATABLK*)malloc(blklen); if (blkp == NULL) { XMERRF ("HHCDL092E Cannot obtain storage for directory block: %s\n", strerror(errno)); return -1; } /* Copy the directory block */ memcpy (blkp, xbuf, blklen); /* Check that there is room in the directory block pointer array */ if (dirblkn >= MAXDBLK) { XMERRF ("HHCDL093E Number of directory blocks exceeds %d, " "increase MAXDBLK\n", MAXDBLK); return -1; } /* Add the directory block to the pointer array */ dirblka[dirblkn] = blkp; /* Update the CCHHR in the copy of the directory block */ blkp->cyl[0] = (cyl >> 8) & 0xFF; blkp->cyl[1] = cyl & 0xFF; blkp->head[0] = (head >> 8) & 0xFF; blkp->head[1] = head & 0xFF; blkp->rec = rec; /* Load number of bytes in directory block */ dirptr = xbuf->kdarea + 8; dirrem = (dirptr[0] << 8) | dirptr[1]; if (dirrem < 2 || dirrem > 256) { XMERR ("HHCDL094E Directory block byte count is invalid\n"); return -1; } /* Return number of bytes used in directory block */ *dirblu = dirrem; /* Point to first directory entry */ dirptr += 2; dirrem -= 2; /* Process each directory entry */ while (dirrem > 0) { /* Point to next directory entry */ dirent = (PDSDIR*)dirptr; /* Test for end of directory */ if (memcmp(dirent->pds2name, eighthexFF, 8) == 0) break; /* Extract the member name */ make_asciiz (memname, sizeof(memname), dirent->pds2name, 8); /* Display the directory entry */ XMINFF (3, "HHCDL095I %s %-8.8s TTR=%2.2X%2.2X%2.2X ", (dirent->pds2indc & PDS2INDC_ALIAS) ? " Alias" : "Member", memname, dirent->pds2ttrp[0], dirent->pds2ttrp[1], dirent->pds2ttrp[2]); /* Load the user data halfword count */ k = dirent->pds2indc & PDS2INDC_LUSR; /* Print the user data */ if (k > 0) XMINF (3, "Userdata="); memset (hex, '\0', sizeof(hex)); memset (chars, '\0', sizeof(chars)); for (i = 0, j = 0; i < k*2; i++, j++) { if (i == 8 || i == 32 || i == 56) { if (i == 8) XMINFF (3, "%-16.16s %-8.8s\n ", hex, chars); else XMINFF (3, "%-16.16s %-16.16s %16.16s %-24.24s\n ", hex, hex+16, hex+32, chars); memset (hex, '\0', sizeof(hex)); memset (chars, '\0', sizeof(chars)); j = 0; } sprintf(hex+2*j, "%2.2X", dirent->pds2usrd[i]); c = guest_to_host(dirent->pds2usrd[i]); if (!isprint(c)) c = '.'; chars[j] = c; } /* end for(i) */ if (i <= 8) XMINFF (3, "%-16.16s %-8.8s\n", hex, chars); else XMINFF (3, "%-16.16s %-16.16s %-16.16s %-24.24s\n", hex, hex+16, hex+32, chars); /* Point to next directory entry */ size = 12 + k*2; dirptr += size; dirrem -= size; } return 0; } /* end function process_dirblk */ /*-------------------------------------------------------------------*/ /* Subroutine to replace a TTR in a PDS directory */ /* Input: */ /* memname Member name (ASCIIZ) */ /* ttrptr Pointer to TTR to be replaced */ /* ttrtab Pointer to TTR conversion table */ /* numttr Number of entries in TTR conversion table */ /* Output: */ /* The TTR is replaced using the TTR conversion table. */ /* */ /* Return value is 0 if successful, or -1 if TTR not in table. */ /* Directory information is listed if infolvl is 3 or greater. */ /*-------------------------------------------------------------------*/ static int replace_ttr (char *memname, BYTE *ttrptr, TTRCONV *ttrtab, int numttr) { int i; /* Array subscript */ /* Search for the TTR in the conversion table */ for (i = 0; i < numttr; i++) { if (memcmp(ttrptr, ttrtab[i].origttr, 3) == 0) { XMINFF (4, "HHCDL096I Member %s TTR=%2.2X%2.2X%2.2X " "replaced by TTR=%2.2X%2.2X%2.2X\n", memname, ttrptr[0], ttrptr[1], ttrptr[2], ttrtab[i].outpttr[0], ttrtab[i].outpttr[1], ttrtab[i].outpttr[2]); memcpy (ttrptr, ttrtab[i].outpttr, 3); return 0; } } /* Return error if TTR not found in conversion table */ XMERRF ("HHCDL097E Member %s TTR=%2.2X%2.2X%2.2X not found in dataset\n", memname, ttrptr[0], ttrptr[1], ttrptr[2]); return -1; } /* end function replace_ttr */ /*-------------------------------------------------------------------*/ /* Subroutine to update a note list record */ /* Input: */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* dsstart Relative track number of start of dataset */ /* memname Member name (ASCIIZ) */ /* ttrn Pointer to TTRN of note list record */ /* ttrtab Pointer to TTR conversion table */ /* numttr Number of entries in TTR conversion table */ /* Output: */ /* Each original TTR in the note list record is replaced by the */ /* corresponding output TTR from the TTR conversion table. */ /* */ /* Return value is 0 if successful, or -1 if error. */ /*-------------------------------------------------------------------*/ static int update_note_list (CIFBLK *cif, char *ofname, int heads, int trklen, int dsstart, char *memname, BYTE *ttrn, TTRCONV *ttrtab, int numttr) { int rc; /* Return code */ int i; /* Loop counter */ int trk; /* Relative track number */ int cyl; /* Cylinder number */ int head; /* Head number */ int rec; /* Record number */ int klen; /* Record key length */ int dlen; /* Record data length */ int numnl; /* Number of note list TTRs */ int nllen; /* Note list length */ BYTE *ttrptr; /* -> Note list TTR */ int curcyl; /* Current cylinder */ int curhead; /* Current head */ int offset; /* Offset into track buffer */ int skiplen; /* Number of bytes to skip */ CKDDASD_TRKHDR trkhdr; /* Track header */ CKDDASD_RECHDR rechdr; /* Record header */ BYTE notelist[1024]; /* Note list */ UNREFERENCED(trklen); /* Load the TTR of the note list record */ trk = (ttrn[0] << 8) | ttrn[1]; rec = ttrn[2]; /* Load number of note list TTRs and calculate note list length */ numnl = ttrn[3]; nllen = numnl * 4; /* Calculate the CCHHR of the note list record */ cyl = (dsstart + trk) / heads; head = (dsstart + trk) % heads; XMINFF (4, "HHCDL098I Updating note list for member %s " "at TTR=%4.4X%2.2X CCHHR=%4.4X%4.4X%2.2X\n", memname, trk, rec, cyl, head, rec); /* Save the current position in the output file */ curcyl = cif->curcyl; curhead = cif->curhead; /* Seek to start of track header */ rc = read_track (cif, cyl, head); if (rc < 0) { XMERRF ("HHCDL099E %s cyl %d head %d read error\n", ofname, cyl, head); return -1; } /* Copy the track header */ memcpy (&trkhdr, cif->trkbuf, CKDDASD_TRKHDR_SIZE); offset = CKDDASD_TRKHDR_SIZE; /* Validate the track header */ if (trkhdr.bin != 0 || trkhdr.cyl[0] != (cyl >> 8) || trkhdr.cyl[1] != (cyl & 0xFF) || trkhdr.head[0] != (head >> 8) || trkhdr.head[1] != (head & 0xFF)) { XMERRF ("HHCDL100E %s cyl %d head %d invalid track header " "%2.2X%2.2X%2.2X%2.2X%2.2X\n", ofname, cyl, head, trkhdr.bin, trkhdr.cyl[0], trkhdr.cyl[1], trkhdr.head[0], trkhdr.head[1]); return -1; } /* Search for the note list record */ while (1) { /* Copy the next record header */ memcpy (&rechdr, cif->trkbuf + offset, CKDDASD_RECHDR_SIZE); offset += CKDDASD_RECHDR_SIZE; /* Check for end of track */ if (memcmp(&rechdr, eighthexFF, 8) == 0) { XMERRF ("HHCDL101E %s cyl %d head %d rec %d " "note list record not found\n", ofname, cyl, head, rec); return -1; } /* Extract record key length and data length */ klen = rechdr.klen; dlen = (rechdr.dlen[0] << 8) | rechdr.dlen[1]; /* Exit loop if matching record number */ if (rechdr.rec == rec) break; /* Skip the key and data areas */ skiplen = klen + dlen; offset += skiplen; } /* end while */ /* Check that the data length is sufficient */ if (dlen < nllen) { XMERRF ("HHCDL102E Member %s note list at cyl %d head %d rec %d " "dlen %d is too short for %d TTRs", memname, cyl, head, rec, dlen, numnl); return -1; } /* Skip the key area if present */ offset += klen; /* Copy the note list from the data area */ memcpy (¬elist, cif->trkbuf + offset, nllen); /* Replace the TTRs in the note list record */ ttrptr = notelist; for (i = 0; i < numnl; i++) { rc = replace_ttr (memname, ttrptr, ttrtab, numttr); if (rc < 0) return -1; ttrptr += 4; } /* end for(i) */ /* Copy the updated note list to the buffer */ memcpy (cif->trkbuf + offset, ¬elist, nllen); cif->trkmodif = 1; /* Restore original file position */ rc = read_track (cif, curcyl, curhead); if (rc < 0) { XMERRF ("HHCDL103E %s track read error cyl %d head %d\n", ofname, curcyl, curhead); return -1; } XMINFF (4, "HHCDL104I Updating cyl %u head %u rec %d kl %d dl %d\n", cyl, head, rec, klen, dlen); return 0; } /* end function update_note_list */ /*-------------------------------------------------------------------*/ /* Subroutine to update a directory block record */ /* Input: */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* dsstart Relative track number of start of dataset */ /* xbuf Pointer to directory block */ /* ttrtab Pointer to TTR conversion table */ /* numttr Number of entries in TTR conversion table */ /* Output: */ /* Each original TTR in the directory block is replaced by the */ /* corresponding output TTR from the TTR conversion table. */ /* For any module which has note list entries, the note list */ /* TTRs in the note list record are also updated. */ /* */ /* Return value is 0 if successful, or -1 if any directory entry */ /* contains a TTR which is not found in the TTR conversion table. */ /*-------------------------------------------------------------------*/ static int update_dirblk (CIFBLK *cif, char *ofname, int heads, int trklen, int dsstart, DATABLK *xbuf, TTRCONV *ttrtab, int numttr) { int rc; /* Return code */ int size; /* Size of directory entry */ int k; /* Userdata halfword count */ BYTE *dirptr; /* -> Next byte within block */ int dirrem; /* Number of bytes remaining */ PDSDIR *dirent; /* -> Directory entry */ BYTE *ttrptr; /* -> User TTR */ int n; /* Number of user TTRs */ int i; /* Loop counter */ char memname[9]; /* Member name (ASCIIZ) */ /* Load number of bytes in directory block */ dirptr = xbuf->kdarea + 8; dirrem = (dirptr[0] << 8) | dirptr[1]; if (dirrem < 2 || dirrem > 256) { XMERR ("HHCDL105E Directory block byte count is invalid\n"); return -1; } /* Point to first directory entry */ dirptr += 2; dirrem -= 2; /* Process each directory entry */ while (dirrem > 0) { /* Point to next directory entry */ dirent = (PDSDIR*)dirptr; /* Test for end of directory */ if (memcmp(dirent->pds2name, eighthexFF, 8) == 0) break; /* Extract the member name */ make_asciiz (memname, sizeof(memname), dirent->pds2name, 8); /* Replace the member TTR */ rc = replace_ttr (memname, dirent->pds2ttrp, ttrtab, numttr); if (rc < 0) return -1; /* Load the number of user TTRs */ n = (dirent->pds2indc & PDS2INDC_NTTR) >> PDS2INDC_NTTR_SHIFT; /* Replace the user TTRs */ ttrptr = dirent->pds2usrd; for (i = 0; i < n; i++) { rc = replace_ttr (memname, ttrptr, ttrtab, numttr); if (rc < 0) return -1; ttrptr += 4; } /* end for(i) */ /* Update the note list record if note list TTRs exist */ if ((dirent->pds2indc & PDS2INDC_ALIAS) == 0 && n >= 2 && dirent->pds2usrd[7] != 0) { rc = update_note_list (cif, ofname, heads, trklen, dsstart, memname, dirent->pds2usrd+4, ttrtab, numttr); if (rc < 0) return -1; } /* Load the user data halfword count */ k = dirent->pds2indc & PDS2INDC_LUSR; /* Point to next directory entry */ size = 12 + k*2; dirptr += size; dirrem -= size; } return 0; } /* end function update_dirblk */ /*-------------------------------------------------------------------*/ /* Subroutine to read an IEBCOPY file and write to DASD image file */ /* Input: */ /* xfname XMIT input file name */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* devtype Output device type */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* maxtrks Maximum extent size in tracks */ /* method METHOD_XMIT or METHOD_VS */ /* Output: */ /* odsorg Dataset organization */ /* orecfm Record format */ /* olrecl Logical record length */ /* oblksz Block size */ /* okeyln Key length */ /* dirblu Bytes used in last directory block */ /* lastrec Record number of last block written */ /* trkbal Number of bytes remaining on last track */ /* numtrks Number of tracks written */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /*-------------------------------------------------------------------*/ static int process_iebcopy_file (char *xfname, char *ofname, CIFBLK *cif, U16 devtype, int heads, int trklen, int outcyl, int outhead, int maxtrks, BYTE method, BYTE *odsorg, BYTE *orecfm, int *olrecl, int *oblksz, int *okeyln, int *dirblu, int *lastrec, int *trkbal, int *numtrks, int *nxtcyl, int *nxthead) { int rc = 0; /* Return code */ int i; /* Array subscript */ int xfd; /* XMIT file descriptor */ int dsstart; /* Relative track number of start of output dataset */ BYTE *xbuf; /* -> Logical record buffer */ int xreclen; /* Logical record length */ BYTE xctl; /* 0x20=Control record */ char xrecname[8]; /* XMIT control record name */ int datarecn = 0; /* Data record counter */ int datafiln = 0; /* Data file counter */ int copyfiln = 0; /* Seq num of file to copy */ BYTE dsorg=0; /* Dataset organization */ BYTE recfm=0; /* Dataset record format */ U16 lrecl=0; /* Dataset record length */ U16 blksz=0; /* Dataset block size */ U16 keyln=0; /* Dataset key length */ U16 dirnm; /* Number of directory blocks*/ int enddir = 0; /* 1=End of directory found */ BYTE *blkptr; /* -> Data block in record */ DATABLK *datablk; /* -> Data block */ int blktrk; /* Data block relative track */ int blkcyl; /* Data block cylinder number*/ int blkhead; /* Data block head number */ int blkrec; /* Data block record number */ int keylen; /* Key length of data block */ int datalen; /* Data length of data block */ int blklen; /* Total length of data block*/ int origheads = 0; /* Number of tracks/cylinder on original dataset */ int numext = 0; /* Number of extents */ EXTDESC xarray[16]; /* Extent descriptor array */ DATABLK **dirblka; /* -> Directory block array */ int dirblkn = 0; /* #of directory blocks read */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ TTRCONV *ttrtab; /* -> TTR conversion table */ int numttr = 0; /* TTR table array index */ COPYR1 *copyr1; /* -> header record 1 */ char pathname[MAX_PATH]; /* xfname in host path format*/ /* Open the input file */ hostpath(pathname, xfname, sizeof(pathname)); xfd = hopen(pathname, O_RDONLY|O_BINARY); if (xfd < 0) { XMERRF ("HHCDL106E Cannot open %s: %s\n", xfname, strerror(errno)); return -1; } /* Obtain the input logical record buffer */ xbuf = malloc (65536); if (xbuf == NULL) { XMERRF ("HHCDL107E Cannot obtain input buffer: %s\n", strerror(errno)); close (xfd); return -1; } /* Obtain storage for the directory block array */ dirblka = (DATABLK**)malloc (sizeof(DATABLK*) * MAXDBLK); if (dirblka == NULL) { XMERRF ("HHCDL108E Cannot obtain storage for directory block array: %s\n", strerror(errno)); free (xbuf); close (xfd); return -1; } /* Obtain storage for the TTR conversion table */ ttrtab = (TTRCONV*)malloc (sizeof(TTRCONV) * MAXTTR); if (ttrtab == NULL) { XMERRF ("HHCDL109E Cannot obtain storage for TTR table: %s\n", strerror(errno)); free (xbuf); free (dirblka); close (xfd); return -1; } /* Calculate the relative track number of the dataset */ dsstart = (outcyl * heads) + outhead; /* Display the file information message */ XMINFF (1, "HHCDL110I Processing file %s\n", xfname); /* Read each logical record */ while (1) { xctl=0; if (method == METHOD_XMIT) rc = read_xmit_rec (xfd, xfname, xbuf, &xctl); else if (method == METHOD_VS) { rc = read_vs_rec (xfd, xfname, xbuf, datarecn); if (rc == 0) /* end-of-file */ break; } else rc = -1; if (rc < 0) return -1; xreclen = rc; /* Process control records */ if (method == METHOD_XMIT && xctl) { /* Extract the control record name */ make_asciiz (xrecname, sizeof(xrecname), xbuf, 6); XMINFF (4, "HHCDL111I Control record: %s length %d\n", xrecname, xreclen); /* Exit if control record is a trailer record */ if (strcmp(xrecname, "INMR06") == 0) break; /* Process control record according to type */ if (strcmp(xrecname, "INMR02") == 0) { rc = process_inmr02 (xbuf, xreclen, "IEBCOPY", ©filn, &dsorg, &recfm, &lrecl, &blksz, &keyln, &dirnm); if (rc < 0) return -1; } else { rc = process_inmrxx (xbuf, xreclen); if (rc < 0) return -1; } /* Reset the data counter if data control record */ if (strcmp(xrecname, "INMR03") == 0) { datafiln++; datarecn = 0; XMINFF (4, "HHCDL112I File number: %d %s\n", datafiln, (datafiln == copyfiln) ? "(selected)" : "(not selected)"); } /* Loop to get next record */ continue; } /* end if(xctl) */ /* Process data records */ datarecn++; XMINFF (4, "HHCDL113I Data record: length %d\n", xreclen); if (infolvl >= 5) data_dump (xbuf, xreclen); /* If this is not the IEBCOPY file then ignore data record */ if (method == METHOD_XMIT && datafiln != copyfiln) { continue; } /* Process IEBCOPY header record 1 */ if (datarecn == 1) { origheads = process_copyr1 (xbuf, xreclen); if (origheads < 0) exit(1); if (method == METHOD_VS) { copyr1 = (COPYR1 *)xbuf; dsorg = copyr1->ds1dsorg[0]; recfm = copyr1->ds1recfm; lrecl = (copyr1->ds1lrecl[0] << 8) | copyr1->ds1lrecl[1]; blksz = (copyr1->ds1blkl[0] << 8) | copyr1->ds1blkl[1]; keyln = copyr1->ds1keyl; } continue; } /* Process IEBCOPY header record 2 */ if (datarecn == 2) { numext = process_copyr2 (xbuf, xreclen, xarray); if (numext < 0) exit(1); continue; } /* Process each data block in data record */ blkptr = xbuf; while (xreclen > 0) { /* Compute the length of the block */ datablk = (DATABLK*)blkptr; blkcyl = (datablk->cyl[0] << 8) | datablk->cyl[1]; blkhead = (datablk->head[0] << 8) | datablk->head[1]; blkrec = datablk->rec; keylen = datablk->klen; datalen = (datablk->dlen[0] << 8) | datablk->dlen[1]; blklen = 12 + keylen + datalen; /* Calculate the TTR in the original dataset */ blktrk = (enddir == 0) ? 0 : calculate_ttr (blkcyl, blkhead, origheads, numext, xarray); /* Write the data block to the output file */ rc = write_block (cif, ofname, datablk, keylen, datalen, devtype, heads, trklen, maxtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) { XMERRF ("HHCDL114E write error: input record " "CCHHR=%4.4X%4.4X%2.2X " "(TTR=%4.4X%2.2X) KL=%d DL=%d\n", blkcyl, blkhead, blkrec, blktrk, blkrec, keylen, datalen); return -1; } XMINFF (4, "HHCDL115I CCHHR=%4.4X%4.4X%2.2X " "(TTR=%4.4X%2.2X) KL=%d DL=%d " "-> CCHHR=%4.4X%4.4X%2.2X " "(TTR=%4.4X%2.2X)\n", blkcyl, blkhead, blkrec, blktrk, blkrec, keylen, datalen, outcyl, outhead, outrec, outtrk, outrec); /* Process directory block or member block */ if (enddir == 0) { rc = process_dirblk (datablk, blklen, outcyl, outhead, outrec, dirblka, dirblkn, dirblu); if (rc < 0) return -1; enddir = rc; /* Count the number of directory blocks read */ if (enddir == 0) dirblkn++; } else /* Not a directory block */ { /* Check that TTR conversion table is not full */ if (numttr >= MAXTTR) { XMERRF ("HHCDL116E TTR count exceeds %d, " "increase MAXTTR\n", MAXTTR); return -1; } /* Add an entry to the TTR conversion table */ ttrtab[numttr].origttr[0] = (blktrk >> 8) & 0xFF; ttrtab[numttr].origttr[1] = blktrk & 0xFF; ttrtab[numttr].origttr[2] = blkrec; ttrtab[numttr].outpttr[0] = (outtrk >> 8) & 0xFF; ttrtab[numttr].outpttr[1] = outtrk & 0xFF; ttrtab[numttr].outpttr[2] = outrec; numttr++; } /* Point to next data block in data record */ xreclen -= blklen; blkptr += blklen; } /* end while(xreclen) */ } /* end while(1) */ /* Check for unsupported xmit utility */ if (method == METHOD_XMIT && copyfiln == 0) { XMERRF ("HHCDL130W WARNING -- XMIT file utility is not IEBCOPY;" " file %s not loaded\n", xfname); } /* Return the last record number and track balance */ *lastrec = outrec; *trkbal = outtrkbr; /* Write any data remaining in track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Update the directory and rewrite to output file */ for (i = 0; i < dirblkn; i++) { /* Obtain the directory block pointer from the array */ datablk = dirblka[i]; /* Update TTR pointers in this directory block */ rc = update_dirblk (cif, ofname, heads, trklen, dsstart, datablk, ttrtab, numttr); if (rc < 0) return -1; /* Rewrite the updated directory block */ blkcyl = (datablk->cyl[0] << 8) | datablk->cyl[1]; blkhead = (datablk->head[0] << 8) | datablk->head[1]; blkrec = datablk->rec; keylen = datablk->klen; datalen = (datablk->dlen[0] << 8) | datablk->dlen[1]; rc = update_block (cif, ofname, datablk, blkcyl, blkhead, blkrec, keylen, datalen, heads, trklen); if (rc < 0) return -1; } /* end for(i) */ /* Close input file and release buffers */ close (xfd); for (i = 0; i < dirblkn; i++) free (dirblka[i]); free (dirblka); free (xbuf); free (ttrtab); /* Return the dataset attributes */ *odsorg = dsorg; *orecfm = recfm; *olrecl = lrecl; *oblksz = blksz; *okeyln = keyln; /* Return number of tracks and starting address of next dataset */ *numtrks = outtrk; *nxtcyl = outcyl; *nxthead = outhead; return 0; } /* end function process_iebcopy_file */ /*-------------------------------------------------------------------*/ /* Subroutine to initialize a SYSCTLG dataset as an OS CVOL */ /* Input: */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* volser Volume serial number */ /* devtype Output device type */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* extsize Extent size in tracks */ /* Output: */ /* lastrec Record number of last block written */ /* trkbal Number of bytes remaining on last track */ /* numtrks Number of tracks written */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /* Note: */ /* This subroutine builds a minimal SYSCTLG containing only */ /* the entries required on an OS/360 IPL volume. */ /*-------------------------------------------------------------------*/ static int cvol_initialize (char *ofname, CIFBLK *cif, char *volser, U16 devtype, int heads, int trklen, int outcyl, int outhead, int extsize, int *lastrec, int *trkbal, int *numtrks, int *nxtcyl, int *nxthead) { int rc; /* Return code */ int i; /* Array subscript */ int keylen; /* Key length of data block */ int datalen; /* Data length of data block */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ int blkptrk; /* Number of blocks per track*/ int totblks; /* Number of blocks in CVOL */ int bytes; /* Bytes used in this block */ U32 ucbtype; /* UCB device type */ PDSDIR *catent; /* -> Catalog entry */ DATABLK datablk; /* Data block */ #define NUM_SYS1_DATASETS 8 /* Number of SYS1 datasets */ static char *sys1name[NUM_SYS1_DATASETS] = {"DUMP", "IMAGELIB", "LINKLIB", "NUCLEUS", "PARMLIB", "PROCLIB", "SAMPLIB", "SYSJOBQE"}; /* Set the key length and data length for SYSCTLG dataset */ keylen = 8; datalen = 256; /* Obtain the number of blocks which will fit on a track */ capacity_calc (cif, 0, keylen, datalen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &blkptrk, NULL, NULL); /* Calculate the total number of blocks in the catalog */ totblks = extsize * blkptrk; /* Get the UCB device type */ ucbtype = ucbtype_code (devtype); /*-----------------------------------*/ /* Initialize the volume index block */ /*-----------------------------------*/ memset (datablk.kdarea, 0, keylen + datalen); /* The key field contains all X'FF' */ memcpy (datablk.kdarea, eighthexFF, 8); /* The first entry begins after the 2 byte count field */ bytes = 2; catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Build the volume index control entry (VICE) */ /* The VICE name is X'0000000000000001' */ memcpy (catent->pds2name, cvol_low_key, 8); /* Set TTR to highest block in volume index, i.e. X'000001' */ catent->pds2ttrp[0] = 0; catent->pds2ttrp[1] = 0; catent->pds2ttrp[2] = 1; /* Indicator byte X'05' means 5 user halfwords follow, and uniquely identifies this catalog entry as a VICE */ catent->pds2indc = 5; /* Set the TTR of the last block of the catalog */ catent->pds2usrd[0] = ((extsize - 1) >> 8) & 0xFF; catent->pds2usrd[1] = (extsize - 1) & 0xFF; catent->pds2usrd[2] = blkptrk; catent->pds2usrd[3] = 0; /* Set the TTR of the first unused block (X'000003') */ catent->pds2usrd[4] = 0; catent->pds2usrd[5] = 0; catent->pds2usrd[6] = 3; /* Remainder of user data is 0 */ catent->pds2usrd[7] = 0; catent->pds2usrd[8] = 0; catent->pds2usrd[9] = 0; /* Increment bytes used by the length of the VICE */ bytes += 22; catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Build the index pointer for SYS1 */ convert_to_ebcdic (catent->pds2name, 8, "SYS1"); /* Set TTR of the SYS1 index block, i.e. X'000002' */ catent->pds2ttrp[0] = 0; catent->pds2ttrp[1] = 0; catent->pds2ttrp[2] = 2; /* Indicator byte X'00' means no user halfwords follow, and uniquely identifies this catalog entry as an index pointer */ catent->pds2indc = 0; /* Increment bytes used by the length of the index pointer */ bytes += 12; catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Set the last entry in block marker */ memcpy (catent->pds2name, eighthexFF, 8); /* Increment bytes used by the last entry marker */ bytes += 12; catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Set the number of bytes used in this block */ datablk.kdarea[keylen+0] = (bytes >> 8) & 0xFF; datablk.kdarea[keylen+1] = bytes & 0xFF; /* Write the volume index block to the output file */ rc = write_block (cif, ofname, &datablk, keylen, datalen, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; XMINFF (4, "HHCDL117I Catalog block at cyl %d head %d rec %d\n", outcyl, outhead, outrec); if (infolvl >= 5) data_dump (datablk.kdarea, keylen + datalen); /* Count number of blocks written */ totblks--; /*---------------------------------*/ /* Initialize the SYS1 index block */ /*---------------------------------*/ memset (datablk.kdarea, 0, keylen + datalen); /* The key field contains all X'FF' */ memcpy (datablk.kdarea, eighthexFF, 8); /* The first entry begins after the 2 byte count field */ bytes = 2; catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Build the index control entry (ICE) */ /* The ICE name is X'0000000000000001' */ memcpy (catent->pds2name, cvol_low_key, 8); /* Set TTR to highest block in this index, i.e. X'000002' */ catent->pds2ttrp[0] = 0; catent->pds2ttrp[1] = 0; catent->pds2ttrp[2] = 2; /* Indicator byte X'03' means 3 user halfwords follow, and uniquely identifies this catalog entry as an ICE */ catent->pds2indc = 3; /* Set the TTR of this block */ catent->pds2usrd[0] = 0; catent->pds2usrd[1] = 0; catent->pds2usrd[2] = 2; /* The next byte contains the alias count */ catent->pds2usrd[3] = 0; /* The remaining 2 bytes of userdata are zeroes */ catent->pds2usrd[4] = 0; catent->pds2usrd[5] = 0; /* Increment bytes used by the length of the ICE */ bytes += 18; /* Build the dataset pointers for SYS1.xxxxxxxx datasets */ for (i = 0; i < NUM_SYS1_DATASETS; i++) { /* Point to next dataset pointer entry */ catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Set the name of the dataset pointer entry */ convert_to_ebcdic (catent->pds2name, 8, sys1name[i]); /* Set the TTR to zero */ catent->pds2ttrp[0] = 0; catent->pds2ttrp[1] = 0; catent->pds2ttrp[2] = 0; /* Indicator byte X'07' means 7 user halfwords follow, and uniquely identifies the entry as a dataset pointer */ catent->pds2indc = 7; /* The next two bytes contain the volume count (X'0001') */ catent->pds2usrd[0] = 0; catent->pds2usrd[1] = 1; /* The next four bytes contain the UCB type */ catent->pds2usrd[2] = (ucbtype >> 24) & 0xFF; catent->pds2usrd[3] = (ucbtype >> 16) & 0xFF; catent->pds2usrd[4] = (ucbtype >> 8) & 0xFF; catent->pds2usrd[5] = ucbtype & 0xFF; /* The next six bytes contain the volume serial number */ convert_to_ebcdic (catent->pds2usrd+6, 6, volser); /* The next two bytes contain the volume seq.no. (X'0000') */ catent->pds2usrd[12] = 0; catent->pds2usrd[13] = 0; /* Increment bytes used by the length of the dataset pointer */ bytes += 26; } /* end for(i) */ /* Point to last entry in block */ catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Set the last entry in block marker */ memcpy (catent->pds2name, eighthexFF, 8); /* Increment bytes used by the last entry marker */ bytes += 12; catent = (PDSDIR*)(datablk.kdarea + keylen + bytes); /* Set the number of bytes used in this block */ datablk.kdarea[keylen+0] = (bytes >> 8) & 0xFF; datablk.kdarea[keylen+1] = bytes & 0xFF; /* Write the index block to the output file */ rc = write_block (cif, ofname, &datablk, keylen, datalen, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; XMINFF (4, "HHCDL118I Catalog block at cyl %d head %d rec %d\n", outcyl, outhead, outrec); if (infolvl >= 5) data_dump (datablk.kdarea, keylen + datalen); /* Count number of blocks written */ totblks--; /*--------------------------------------------*/ /* Initialize remaining unused catalog blocks */ /*--------------------------------------------*/ while (totblks > 0) { memset (datablk.kdarea, 0, keylen + datalen); /* Write the volume index block to the output file */ rc = write_block (cif, ofname, &datablk, keylen, datalen, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; XMINFF (4, "HHCDL119I Catalog block at cyl %d head %d rec %d\n", outcyl, outhead, outrec); if (infolvl >= 5) data_dump (datablk.kdarea, keylen + datalen); /* Count number of blocks written */ totblks--; } /* end while(totblks) */ /* Set the last record number to X'FF' so that OS/360 catalog management routines can recognize that the CVOL has been initialized by detecting X'FF' at ds1lstar+2 in the VTOC */ *lastrec = 0xFF; /* Return the track balance */ *trkbal = outtrkbr; /* Write data remaining in track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Return number of tracks and starting address of next dataset */ *numtrks = outtrk; *nxtcyl = outcyl; *nxthead = outhead; return 0; } /* end function cvol_initialize */ /*-------------------------------------------------------------------*/ /* Subroutine to initialize a LOGREC dataset with IFCDIP00 header */ /* Input: */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* devtype Output device type */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* extsize Extent size in tracks */ /* Output: */ /* lastrec Record number of last block written */ /* trkbal Number of bytes remaining on last track */ /* numtrks Number of tracks written */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /*-------------------------------------------------------------------*/ static int dip_initialize (char *ofname, CIFBLK *cif, U16 devtype, int heads, int trklen, int outcyl, int outhead, int extsize, int *lastrec, int *trkbal, int *numtrks, int *nxtcyl, int *nxthead) { int rc; /* Return code */ int keylen; /* Key length of data block */ int datalen; /* Data length of data block */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ int remlen; /* Bytes remaining on 1st trk*/ int physlen; /* Physical track length */ int lasthead; /* Highest head on cylinder */ int endcyl; /* Extent end cylinder */ int endhead; /* Extent end head */ int trklen90; /* 90% of track length */ int cyl90; /* 90% full cylinder number */ int head90; /* 90% full head number */ int reltrk90; /* 90% full relative track */ DIPHDR *diphdr; /* -> Record in data block */ DATABLK datablk; /* Data block */ /* Set the key length and data length for the header record */ keylen = 0; datalen = sizeof(DIPHDR); /* Obtain the physical track size and the track balance remaining on the first track after the header record */ capacity_calc (cif, 0, keylen, datalen, NULL, &remlen, &physlen, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); /* Calculate the end of extent cylinder and head */ lasthead = heads - 1; endcyl = outcyl; endhead = outhead + extsize - 1; while (endhead >= heads) { endhead -= heads; endcyl++; } /* Calculate the 90% full cylinder and head */ trklen90 = physlen * 9 / 10; reltrk90 = extsize * trklen90 / physlen; if (reltrk90 == 0) reltrk90 = 1; cyl90 = outcyl; head90 = outhead + reltrk90 - 1; while (head90 >= heads) { head90 -= heads; cyl90++; } /* Initialize the DIP header record */ diphdr = (DIPHDR*)(datablk.kdarea); memset (diphdr, 0, sizeof(DIPHDR)); diphdr->recid[0] = 0xFF; diphdr->recid[1] = 0xFF; diphdr->bcyl[0] = (outcyl >> 8) & 0xFF; diphdr->bcyl[1] = outcyl & 0xFF; diphdr->btrk[0] = (outhead >> 8) & 0xFF; diphdr->btrk[1] = outhead & 0xFF; diphdr->ecyl[0] = (endcyl >> 8) & 0xFF; diphdr->ecyl[1] = endcyl & 0xFF; diphdr->etrk[0] = (endhead >> 8) & 0xFF; diphdr->etrk[1] = endhead & 0xFF; diphdr->restart[2] = (outcyl >> 8) & 0xFF; diphdr->restart[3] = outcyl & 0xFF; diphdr->restart[4] = (outhead >> 8) & 0xFF; diphdr->restart[5] = outhead & 0xFF; diphdr->restart[6] = 1; diphdr->trkbal[0] = (remlen >> 8) & 0xFF; diphdr->trkbal[1] = remlen & 0xFF; diphdr->trklen[0] = (physlen >> 8) & 0xFF; diphdr->trklen[1] = physlen & 0xFF; diphdr->reused[2] = (outcyl >> 8) & 0xFF; diphdr->reused[3] = outcyl & 0xFF; diphdr->reused[4] = (outhead >> 8) & 0xFF; diphdr->reused[5] = outhead & 0xFF; diphdr->reused[6] = 1; diphdr->lasthead[0] = (lasthead >> 8) & 0xFF; diphdr->lasthead[1] = lasthead & 0xFF; diphdr->trklen90[0] = (trklen90 >> 8) & 0xFF; diphdr->trklen90[1] = trklen90 & 0xFF; diphdr->devcode = (ucbtype_code(devtype) & 0x0F) | 0xF0; diphdr->cchh90[0] = (cyl90 >> 8) & 0xFF; diphdr->cchh90[1] = cyl90 & 0xFF; diphdr->cchh90[2] = (head90 >> 8) & 0xFF; diphdr->cchh90[3] = head90 & 0xFF; diphdr->endid = 0xFF; /* Write the data block to the output file */ rc = write_block (cif, ofname, &datablk, keylen, datalen, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; XMINFF (3, "HHCDL120I DIP complete at cyl %d head %d rec %d\n", outcyl, outhead, outrec); if (infolvl >= 5) data_dump (diphdr, sizeof(DIPHDR)); /* Return the last record number and track balance */ *lastrec = outrec; *trkbal = outtrkbr; /* Write data remaining in track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Return number of tracks and starting address of next dataset */ *numtrks = outtrk; *nxtcyl = outcyl; *nxthead = outhead; return 0; } /* end function dip_initialize */ /*-------------------------------------------------------------------*/ /* Subroutine to initialize a sequential dataset */ /* Input: */ /* sfname SEQ input file name */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* devtype Output device type */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* extsize Extent size in tracks */ /* dsorg Dataset organization (DA or PS) */ /* recfm Record Format (F or FB) */ /* lrecl Record length */ /* blksz Block size */ /* keyln Key length */ /* Output: */ /* lastrec Record number of last block written */ /* trkbal Number of bytes remaining on last track */ /* numtrks Number of tracks written */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /*-------------------------------------------------------------------*/ static int seq_initialize (char *sfname, char *ofname, CIFBLK *cif, U16 devtype, int heads, int trklen, int outcyl, int outhead, int extsize, BYTE dsorg, BYTE recfm, int lrecl, int blksz, int keyln, int *lastrec, int *trkbal, int *numtrks, int *nxtcyl, int *nxthead) { int rc; /* Return code */ int sfd; /* Input seq file descriptor */ int size; /* Size left in input file */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ struct stat st; /* Data area for fstat() */ DATABLK datablk; /* Data block */ char pathname[MAX_PATH]; /* sfname in host path format*/ /* Perform some checks */ if (!(dsorg & DSORG_PS) && !(dsorg & DSORG_DA)) { XMERRF ("HHCDL121E SEQ dsorg must be PS or DA: dsorg=0x%2.2x\n",dsorg); return -1; } if (recfm != RECFM_FORMAT_F && recfm != (RECFM_FORMAT_F|RECFM_BLOCKED)) { XMERRF ("HHCDL122E SEQ recfm must be F or FB: recfm=0x%2.2x\n",recfm); return -1; } if (blksz == 0) blksz = lrecl; if (lrecl == 0) lrecl = blksz; if (lrecl == 0 || blksz % lrecl != 0 || (blksz != lrecl && recfm == RECFM_FORMAT_F)) { XMERRF ("HHCDL123E SEQ invalid lrecl or blksz: lrecl=%d blksz=%d\n", lrecl,blksz); return -1; } if (keyln > 0 && blksz > lrecl) { XMERR ("HHCDL124E SEQ keyln must be 0 for blocked files\n"); return -1; } /* Open the input file */ hostpath(pathname, sfname, sizeof(pathname)); sfd = hopen(pathname, O_RDONLY|O_BINARY); if (sfd < 0) { XMERRF ("HHCDL125E Cannot open %s: %s\n", sfname, strerror(errno)); return -1; } /* Get input file status */ rc = fstat(sfd, &st); if (rc < 0) { XMERRF ("HHCDL126E Cannot stat %s: %s\n", sfname, strerror(errno)); close (sfd); return -1; } size = st.st_size; /* Read the first track */ rc = read_track (cif, *nxtcyl, *nxthead); if (rc < 0) { XMERRF ("HHCDL127E %s cyl %d head %d read error\n", ofname, *nxtcyl, *nxthead); close (sfd); return -1; } while (size > 0) { /* Read a block of data from the input file */ rc = read (sfd, &datablk.kdarea, blksz < size ? blksz : size); if (rc < (blksz < size ? blksz : size)) { XMERRF ("HHCDL128E %s read error: %s\n", sfname, strerror(errno)); close (sfd); return -1; } size -= rc; /* Pad the block if necessary */ if (rc < blksz) { /* Adjust blksize down to next highest multiple of lrecl */ blksz = (((rc-1) / lrecl) + 1) * lrecl; memset (&datablk.kdarea[rc], 0, blksz - rc); } rc = write_block (cif, ofname, &datablk, keyln, blksz - keyln, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) { close (sfd); return -1; } } /* Close the input file */ close (sfd); /* Create the end of file record */ rc = write_block (cif, ofname, &datablk, 0, 0, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; /* Return the last record number and track balance */ *lastrec = outrec; *trkbal = outtrkbr; /* Write data remaining in track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Return number of tracks and starting address of next dataset */ *numtrks = outtrk; *nxtcyl = outcyl; *nxthead = outhead; return 0; } /* end function seq_initialize */ /*-------------------------------------------------------------------*/ /* Subroutine to add a logical record to an output buffer */ /* */ /* If there is no room in the buffer for the logical record */ /* then the block in the buffer is written to the output device */ /* and the logical record is added to the now empty buffer. */ /* A call with reclen=0 is a request to flush a partial block */ /* without adding a new record. */ /* */ /* Input: */ /* cif -> CKD image file descriptor */ /* ofname Output file name */ /* datablk Pointer to buffer containing data block */ /* keylen Length of key in data block */ /* devtype Output device type */ /* heads Number of tracks per cylinder on output device */ /* trklen Track length of virtual output device */ /* maxtrks Maximum number of tracks to be written */ /* recptr Pointer to record to be added (excluding RDW) */ /* reclen Length of record to be added */ /* recfm Output dataset record format */ /* blksz Maximum blocksize of output dataset */ /* Input/output: */ /* blklen Number of data bytes currently in block */ /* usedv Number of bytes written to track of virtual device */ /* usedr Number of bytes written to track, calculated */ /* according to the formula for a real device */ /* trkbal Number of bytes remaining on track, calculated */ /* according to the formula for a real device */ /* reltrk Relative track number on output device */ /* cyl Cylinder number on output device */ /* head Head number on output device */ /* rec Record number on output device */ /* Output: */ /* The return value is 0 if successful, -1 if error occurred. */ /*-------------------------------------------------------------------*/ static int add_logical_record (CIFBLK *cif, char *ofname, DATABLK *datablk, int keylen, U16 devtype, int heads, int trklen, int maxtrks, BYTE *recptr, int reclen, BYTE recfm, int blksz, int *blklen, int *usedv, int *usedr, int *trkbal, int *reltrk, int *cyl, int *head, int *rec) { int rc; /* Return code */ int recsize; /* Record length with RDW */ BYTE *dataptr; /* -> byte in data block */ /* Calculate the logical record length including RDW */ recsize = reclen; if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V) recsize += 4; /* Flush the buffer if the record format is unblocked or there is no room for the record in the buffer or the requested record length is zero */ if (*blklen > 0 && (!(recfm & RECFM_BLOCKED) || *blklen + recsize > blksz || reclen == 0)) { if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V) { /* Build BDW for variable length block */ dataptr = datablk->kdarea + keylen; dataptr[0] = *blklen >> 8; dataptr[1] = *blklen & 0xFF; dataptr[2] = 0x00; dataptr[3] = 0x00; } /* Write the data block to the output file */ rc = write_block (cif, ofname, datablk, keylen, *blklen, devtype, heads, trklen, maxtrks, usedv, usedr, trkbal, reltrk, cyl, head, rec); if (rc < 0) { return -1; } XMINFF (4, "HHCDL135I CCHHR=%4.4X%4.4X%2.2X " "(TTR=%4.4X%2.2X) KL=%d DL=%d\n", *cyl, *head, *rec, *reltrk, *rec, keylen, *blklen); /* Indicate that the buffer is now empty */ *blklen = 0; } /* Nothing more to do if record length is zero */ if (reclen == 0) { return 0; } /* Account for the BDW and RDW for variable length records */ if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V) { /* Allow space for the BDW if at start of block */ if (*blklen == 0) *blklen = 4; /* Build RDW for variable length record */ dataptr = datablk->kdarea + keylen + *blklen; dataptr[0] = recsize >> 8; dataptr[1] = recsize & 0xFF; dataptr[2] = 0x00; dataptr[3] = 0x00; *blklen += 4; } /* Copy the logical record to the data block */ dataptr = datablk->kdarea + keylen + *blklen; memcpy(dataptr, recptr, reclen); *blklen += reclen; return 0; } /* end function add_logical_record */ /*-------------------------------------------------------------------*/ /* Subroutine to read an INMCOPY file and write to DASD image file */ /* Input: */ /* xfname XMIT input file name */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* devtype Output device type */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* maxtrks Maximum extent size in tracks */ /* Output: */ /* odsorg Dataset organization */ /* orecfm Record format */ /* olrecl Logical record length */ /* oblksz Block size */ /* okeyln Key length */ /* lastrec Record number of last block written */ /* trkbal Number of bytes remaining on last track */ /* numtrks Number of tracks written */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /*-------------------------------------------------------------------*/ static int process_inmcopy_file (char *xfname, char *ofname, CIFBLK *cif, U16 devtype, int heads, int trklen, int outcyl, int outhead, int maxtrks, BYTE *odsorg, BYTE *orecfm, int *olrecl, int *oblksz, int *okeyln, int *lastrec, int *trkbal, int *numtrks, int *nxtcyl, int *nxthead) { int rc = 0; /* Return code */ int xfd; /* XMIT file descriptor */ BYTE *xbuf; /* -> Logical record buffer */ int xreclen; /* Logical record length */ BYTE xctl; /* 0x20=Control record */ char xrecname[8]; /* XMIT control record name */ int datarecn = 0; /* Data record counter */ int datafiln = 0; /* Data file counter */ int copyfiln = 0; /* Seq num of file to copy */ BYTE dsorg=0; /* Dataset organization */ BYTE recfm=0; /* Dataset record format */ U16 lrecl=0; /* Dataset record length */ U16 blksz=0; /* Dataset block size */ U16 keyln=0; /* Dataset key length */ U16 dirnm; /* Number of directory blocks*/ DATABLK datablk; /* Data block */ int keylen; /* Key length of data block */ int blklen; /* Data length of data block */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ char pathname[MAX_PATH]; /* xfname in host path format*/ /* Open the input file */ hostpath(pathname, xfname, sizeof(pathname)); xfd = hopen(pathname, O_RDONLY|O_BINARY); if (xfd < 0) { XMERRF ("HHCDL136E Cannot open %s: %s\n", xfname, strerror(errno)); return -1; } /* Obtain the input logical record buffer */ xbuf = malloc (65536); if (xbuf == NULL) { XMERRF ("HHCDL137E Cannot obtain input buffer: %s\n", strerror(errno)); close (xfd); return -1; } keylen = 0; blklen = 0; /* Display the file information message */ XMINFF (1, "HHCDL139I Processing file %s\n", xfname); /* Read each logical record */ while (1) { xctl=0; rc = read_xmit_rec (xfd, xfname, xbuf, &xctl); if (rc < 0) return -1; xreclen = rc; /* Process control records */ if (xctl) { /* Extract the control record name */ make_asciiz (xrecname, sizeof(xrecname), xbuf, 6); XMINFF (4, "HHCDL131I Control record: %s length %d\n", xrecname, xreclen); /* Exit if control record is a trailer record */ if (strcmp(xrecname, "INMR06") == 0) break; /* Process control record according to type */ if (strcmp(xrecname, "INMR02") == 0) { rc = process_inmr02 (xbuf, xreclen, "INMCOPY", ©filn, &dsorg, &recfm, &lrecl, &blksz, &keyln, &dirnm); if (rc < 0) return -1; } else { rc = process_inmrxx (xbuf, xreclen); if (rc < 0) return -1; } /* Reset the data counter if data control record */ if (strcmp(xrecname, "INMR03") == 0) { datafiln++; datarecn = 0; XMINFF (4, "HHCDL132I File number: %d %s\n", datafiln, (datafiln == copyfiln) ? "(selected)" : "(not selected)"); } /* Loop to get next record */ continue; } /* end if(xctl) */ /* Process data records */ datarecn++; XMINFF (4, "HHCDL133I Data record: length %d\n", xreclen); if (infolvl >= 5) data_dump (xbuf, xreclen); /* If this is not the INMCOPY file then ignore data record */ if (datafiln != copyfiln) { continue; } /* Copy the logical record to the data block, and write the block to the output file if necessary */ rc = add_logical_record (cif, ofname, &datablk, keylen, devtype, heads, trklen, maxtrks, xbuf, xreclen, recfm, blksz, &blklen, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) { close(xfd); return -1; } } /* end while(1) */ /* Flush the last partial data block to the output file */ if (blklen > 0) { rc = add_logical_record (cif, ofname, &datablk, keylen, devtype, heads, trklen, maxtrks, NULL, 0, recfm, blksz, &blklen, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) { close(xfd); return -1; } } /* Check for unsupported xmit utility */ if (copyfiln == 0) { XMERRF ("HHCDL138W WARNING -- XMIT file utility is not INMCOPY;" " file %s not loaded\n", xfname); } /* Close input file and release buffer */ close (xfd); free (xbuf); /* Create the end of file record */ rc = write_block (cif, ofname, &datablk, 0, 0, devtype, heads, trklen, maxtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; /* Return the last record number and track balance */ *lastrec = outrec; *trkbal = outtrkbr; /* Write any data remaining in track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Return the dataset attributes */ *odsorg = dsorg; *orecfm = recfm; *olrecl = lrecl; *oblksz = blksz; *okeyln = keyln; /* Return number of tracks and starting address of next dataset */ *numtrks = outtrk; *nxtcyl = outcyl; *nxthead = outhead; return 0; } /* end function process_inmcopy_file */ /*-------------------------------------------------------------------*/ /* Subroutine to read ASCII text file and write to DASD image file */ /* Input: */ /* tfname ASCII text input file name */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* devtype Output device type */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* maxtrks Maximum extent size in tracks */ /* dsorg Dataset organization (DA or PS) */ /* recfm Record Format (F or FB) */ /* lrecl Record length */ /* blksz Block size */ /* keyln Key length */ /* Output: */ /* lastrec Record number of last block written */ /* trkbal Number of bytes remaining on last track */ /* numtrks Number of tracks written */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /*-------------------------------------------------------------------*/ static int process_text_file (char *tfname, char *ofname, CIFBLK *cif, U16 devtype, int heads, int trklen, int outcyl, int outhead, int maxtrks, BYTE dsorg, BYTE recfm, int lrecl, int blksz, int keyln, int *lastrec, int *trkbal, int *numtrks, int *nxtcyl, int *nxthead) { int rc = 0; /* Return code */ FILE *tfp; /* Text file pointer */ char *tbuf; /* -> Text buffer */ int tbuflen = 65536; /* Text buffer length */ int txtlen; /* Input text line length */ int lineno = 0; /* Line number in input file */ BYTE *rbuf; /* -> Logical record buffer */ int reclen; /* Output record length */ int maxlen; /* Maximum record length */ DATABLK datablk; /* Data block */ int keylen; /* Key length of data block */ int blklen; /* Data length of data block */ int reccount = 0; /* Number of records copied */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ char format; /* Record format: F,V,U */ char pathname[MAX_PATH]; /* tfname in host path format*/ /* Validate the DCB attributes */ if (dsorg != DSORG_PS) { XMERRF ("HHCDL141E TEXT dsorg must be PS: dsorg=0x%2.2x\n", dsorg); return -1; } if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_F) format = 'F'; else if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V) format = 'V'; else if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_U) format = 'U'; else { XMERRF ("HHCDL142E TEXT recfm must be F, V, or U: recfm=0x%2.2x\n", recfm); return -1; } if (blksz == 0) blksz = (format == 'V') ? lrecl + 4 : lrecl; if ((lrecl == 0 && format != 'U') || (format == 'F' && blksz % lrecl != 0) || (format == 'V' && lrecl < 5) || (format == 'V' && blksz < lrecl + 4) || (recfm == RECFM_FORMAT_F && blksz != lrecl)) { XMERRF ("HHCDL143E TEXT invalid lrecl or blksz: lrecl=%d blksz=%d\n", lrecl, blksz); return -1; } if (keyln > 0) { XMERR ("HHCDL144E TEXT key length must be 0\n"); return -1; } /* Open the input file */ hostpath(pathname, tfname, sizeof(pathname)); tfp = fopen(pathname, "r"); if (tfp == NULL) { XMERRF ("HHCDL145E Cannot open %s: %s\n", tfname, strerror(errno)); return -1; } /* Obtain the input and output buffers */ maxlen = (format == 'F') ? lrecl : (format == 'V') ? lrecl - 4 : blksz; rbuf = malloc(maxlen + tbuflen); if (rbuf == NULL) { XMERRF ("HHCDL146E Cannot obtain input/output buffers: %s\n", strerror(errno)); fclose(tfp); return -1; } tbuf = (char*)(rbuf + maxlen); /* Copy each logical record to the output file */ keylen = 0; blklen = 0; while (1) { /* Read next record from input file */ lineno++; if (fgets (tbuf, tbuflen, tfp) == NULL) { /* Exit at end of input file */ if (feof(tfp)) break; /* Terminate if error reading input file */ XMERRF ("HHCDL147E Cannot read %s line %d: %s\n", tfname, lineno, strerror(errno)); fclose(tfp); return -1; } /* Check for DOS end of file character */ if (tbuf[0] == '\x1A') break; /* Check that end of statement has been read */ txtlen = strlen(tbuf); if (txtlen == tbuflen - 1 && tbuf[txtlen-1] != '\n') { XMERRF ("HHCDL148E No line feed found in line %d of %s\n", lineno, tfname); fclose(tfp); return -1; } /* Remove trailing carriage return and line feed */ txtlen--; if (txtlen > 0 && tbuf[txtlen-1] == '\r') txtlen--; /* Remove trailing spaces and tab characters */ while (txtlen > 0 && (tbuf[txtlen-1] == SPACE || tbuf[txtlen-1] == '\t')) txtlen--; tbuf[txtlen] = '\0'; /* Validate the record length */ if (txtlen > maxlen) { XMERRF ("HHCDL149E Record length %d exceeds %d at line %d of %s\n", txtlen, maxlen, lineno, tfname); fclose(tfp); return -1; } /* Translate from ASCII to EBCDIC and pad with blanks if fixed */ reclen = (format == 'F') ? lrecl : txtlen; convert_to_ebcdic (rbuf, reclen, tbuf); /* Copy the logical record to the data block, and write the block to the output file if necessary */ rc = add_logical_record (cif, ofname, &datablk, keylen, devtype, heads, trklen, maxtrks, rbuf, reclen, recfm, blksz, &blklen, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) { fclose(tfp); return -1; } reccount++; } /* end while(1) */ /* Flush the last partial data block to the output file */ if (blklen > 0) { rc = add_logical_record (cif, ofname, &datablk, keylen, devtype, heads, trklen, maxtrks, NULL, 0, recfm, blksz, &blklen, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) { fclose(tfp); return -1; } } /* Close input file and release buffers */ fclose(tfp); free(rbuf); /* Create the end of file record */ rc = write_block (cif, ofname, &datablk, 0, 0, devtype, heads, trklen, maxtrks, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; /* Return the last record number and track balance */ *lastrec = outrec; *trkbal = outtrkbr; /* Write any data remaining in track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Display number of records written */ XMINFF (1, "HHCDL140I %d records copied from %s\n", reccount, tfname); /* Return number of tracks and starting address of next dataset */ *numtrks = outtrk; *nxtcyl = outcyl; *nxthead = outhead; return 0; } /* end function process_text_file */ /*-------------------------------------------------------------------*/ /* Subroutine to initialize an empty dataset */ /* Input: */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* devtype Output device type */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* extsize Extent size in tracks */ /* dsorg Dataset organization */ /* dirblks Number of directory blocks */ /* Output: */ /* dirblu Bytes used in last directory block */ /* lastrec Record number of last block written */ /* trkbal Number of bytes remaining on last track */ /* numtrks Number of tracks written */ /* nxtcyl Starting cylinder number for next dataset */ /* nxthead Starting head number for next dataset */ /*-------------------------------------------------------------------*/ static int empty_initialize (char *ofname, CIFBLK *cif, U16 devtype, int heads, int trklen, int outcyl, int outhead, int extsize, BYTE dsorg, int dirblks, int *dirblu, int *lastrec, int *trkbal, int *numtrks, int *nxtcyl, int *nxthead) { int rc; /* Return code */ int i; /* Loop counter */ int keylen; /* Key length of data block */ int datalen; /* Data length of data block */ int outusedv = 0; /* Output bytes used on track of virtual device */ int outusedr = 0; /* Output bytes used on track of real device */ int outtrkbr = 0; /* Output bytes remaining on track of real device */ int outdblu = 0; /* Output bytes used in last directory block */ int outtrk = 0; /* Output relative track */ int outrec = 0; /* Output record number */ DATABLK datablk; /* Data block */ /* Initialize the directory if dataset is a PDS */ if (dsorg & DSORG_PO) { /* Build the first directory block */ keylen = 8; datalen = 256; outdblu = 14; memset (datablk.kdarea, 0, keylen + datalen); memcpy (datablk.kdarea, eighthexFF, 8); datablk.kdarea[keylen] = (outdblu >> 8); datablk.kdarea[keylen+1] = outdblu & 0xFF; memcpy (datablk.kdarea + keylen + 2, eighthexFF, 8); /* Write directory blocks to output dataset */ for (i = 0; i < dirblks; i++) { /* Write a directory block */ rc = write_block (cif, ofname, &datablk, keylen, datalen, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; /* Clear subsequent directory blocks to zero */ memset (datablk.kdarea, 0, keylen + datalen); } /* end for(i) */ } /* end if(DSORG_PO) */ /* Create the end of file record */ keylen = 0; datalen = 0; rc = write_block (cif, ofname, &datablk, keylen, datalen, devtype, heads, trklen, extsize, &outusedv, &outusedr, &outtrkbr, &outtrk, &outcyl, &outhead, &outrec); if (rc < 0) return -1; /* Return number of bytes used in last directory block */ *dirblu = outdblu; /* Return the last record number and track balance */ *lastrec = outrec; *trkbal = outtrkbr; /* Write data remaining in track buffer */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &outtrk, &outcyl, &outhead); if (rc < 0) return -1; /* Return number of tracks and starting address of next dataset */ *numtrks = outtrk; *nxtcyl = outcyl; *nxthead = outhead; return 0; } /* end function empty_initialize */ /*-------------------------------------------------------------------*/ /* Subroutine to read a statement from the control file */ /* Input: */ /* cfp Control file pointer */ /* cfname Control file name */ /* stmt Buffer to receive control statement */ /* sbuflen Length of statement buffer */ /* Output: */ /* pstmtno Statement number */ /* The return value is 0 if a statement was successfully read, */ /* +1 if end of file, or -1 if error */ /*-------------------------------------------------------------------*/ static int read_ctrl_stmt (FILE *cfp, char *cfname, char *stmt, int sbuflen, int *pstmtno) { int stmtlen; /* Length of input statement */ static int stmtno = 0; /* Statement number */ while (1) { /* Read next record from control file */ stmtno++; *pstmtno = stmtno; if (fgets (stmt, sbuflen, cfp) == NULL) { /* Return code +1 if end of control file */ if (feof(cfp)) return +1; /* Return code -1 if control file input error */ XMERRF ("HHCDL019E Cannot read %s line %d: %s\n", cfname, stmtno, strerror(errno)); return -1; } #ifdef EXTERNALGUI /* Indicate input file progess */ if (extgui) fprintf (stderr, "IPOS=%" I64_FMT "d\n", (U64)ftell(cfp)); #endif /*EXTERNALGUI*/ /* Check for DOS end of file character */ if (stmt[0] == '\x1A') return +1; /* Check that end of statement has been read */ stmtlen = strlen(stmt); if (stmtlen == 0 || stmt[stmtlen-1] != '\n') { XMERRF ("HHCDL020E Line too long in %s line %d\n", cfname, stmtno); return -1; } /* Remove trailing carriage return and line feed */ stmtlen--; if (stmtlen > 0 && stmt[stmtlen-1] == '\r') stmtlen--; /* Remove trailing spaces and tab characters */ while (stmtlen > 0 && (stmt[stmtlen-1] == SPACE || stmt[stmtlen-1] == '\t')) stmtlen--; stmt[stmtlen] = '\0'; /* Print the input statement */ XMINFF (0, "--------- %s\n", stmt); /* Ignore comment statements */ if (stmtlen == 0 || stmt[0] == '#' || stmt[0] == '*') continue; break; } /* end while */ return 0; } /* end function read_ctrl_stmt */ /*-------------------------------------------------------------------*/ /* Subroutine to parse a dataset statement from the control file */ /* Input: */ /* stmt Control statement */ /* Output: */ /* dsname ASCIIZ dataset name (1-44 bytes + terminator) */ /* method Processing method (see METHOD_xxx defines) */ /* */ /* The following field is returned only for the XMIT method: */ /* ifptr Pointer to XMIT initialization file name */ /* */ /* The following fields are returned for non-XMIT methods: */ /* units Allocation units (C=CYL, T=TRK) */ /* sppri Primary allocation quantity */ /* spsec Secondary allocation quantity */ /* spdir Directory allocation quantity */ /* dsorg 1st byte of dataset organization bits */ /* recfm 1st byte of record format bits */ /* lrecl Logical record length */ /* blksz Block size */ /* keyln Key length */ /* The return value is 0 if successful, or -1 if error. */ /* Control statement format: */ /* dsname method [initfile] [space [dcbattrib]] */ /* The method can be: */ /* XMIT = load PDS from initfile containing an IEBCOPY unload */ /* dataset created using the TSO TRANSMIT command */ /* EMPTY = create empty dataset (do not specify initfile) */ /* DIP = initialize LOGREC dataset with IFCDIP00 header record */ /* CVOL = initialize SYSCTLG dataset as an OS CVOL */ /* VTOC = reserve space for the VTOC (dsname is ignored) */ /* The space allocation can be: */ /* CYL [pri [sec [dir]]] */ /* TRK [pri [sec [dir]]] */ /* If primary quantity is omitted then the dataset will be */ /* allocated the minimum number of tracks or cylinders needed */ /* to contain the data loaded from the initfile. */ /* Default allocation is in tracks. */ /* The dcb attributes can be: */ /* dsorg recfm lrecl blksize keylen */ /* For the XMIT method the dcb attributes are taken from the */ /* initialization file and need not be specified. */ /* Examples: */ /* SYS1.PARMLIB XMIT /cdrom/os360/reslibs/parmlib.xmi */ /* SYS1.NUCLEUS XMIT /cdrom/os360/reslibs/nucleus.xmi CYL */ /* SYS1.SYSJOBQE EMPTY CYL 10 0 0 DA F 176 176 0 */ /* SYS1.DUMP EMPTY CYL 10 2 0 PS FB 4104 4104 0 */ /* SYS1.OBJPDS EMPTY CYL 10 2 50 PO FB 80 3120 0 */ /* SYSVTOC VTOC CYL 1 */ /* SYSCTLG CVOL TRK 10 */ /* SYS1.LOGREC DIP CYL 1 */ /*-------------------------------------------------------------------*/ static int parse_ctrl_stmt (char *stmt, char *dsname, BYTE *method, char **ifptr, BYTE *units, int *sppri, int *spsec, int *spdir, BYTE *dsorg, BYTE *recfm, int *lrecl, int *blksz, int *keyln) { char *pdsnam; /* -> dsname in input stmt */ char *punits; /* -> allocation units */ char *psppri; /* -> primary space quantity */ char *pspsec; /* -> secondary space qty. */ char *pspdir; /* -> directory space qty. */ char *pdsorg; /* -> dataset organization */ char *precfm; /* -> record format */ char *plrecl; /* -> logical record length */ char *pblksz; /* -> block size */ char *pkeyln; /* -> key length */ char *pimeth; /* -> initialization method */ char *pifile; /* -> initialization filename*/ BYTE c; /* Character work area */ /* Parse the input statement */ pdsnam = strtok (stmt, " \t"); pimeth = strtok (NULL, " \t"); /* Check that all mandatory fields are present */ if (pdsnam == NULL || pimeth == NULL) { XMERR ("HHCDL021E DSNAME or initialization method missing\n"); return -1; } /* Return the dataset name in EBCDIC and ASCII */ string_to_upper (pdsnam); memset (dsname, 0, 45); strncpy (dsname, pdsnam, 44); /* Set default dataset attribute values */ *units = 'T'; *sppri = 1; *spsec = 0; *spdir = 0; *dsorg = 0x00; *recfm = 0x00; *lrecl = 0; *blksz = 0; *keyln = 0; *ifptr = NULL; /* Test for valid initialization method */ if (strcasecmp(pimeth, "XMIT") == 0) *method = METHOD_XMIT; else if (strcasecmp(pimeth, "VS") == 0) *method = METHOD_VS; else if (strcasecmp(pimeth, "EMPTY") == 0) *method = METHOD_EMPTY; else if (strcasecmp(pimeth, "DIP") == 0) *method = METHOD_DIP; else if (strcasecmp(pimeth, "CVOL") == 0) *method = METHOD_CVOL; else if (strcasecmp(pimeth, "VTOC") == 0) *method = METHOD_VTOC; else if (strcasecmp(pimeth, "SEQ") == 0) *method = METHOD_SEQ; else if (strcasecmp(pimeth, "XMSEQ") == 0) *method = METHOD_XMSEQ; else if (strcasecmp(pimeth, "TEXT") == 0) *method = METHOD_TEXT; else { XMERRF ("HHCDL022E Invalid initialization method: %s\n", pimeth); return -1; } /* Locate the initialization file name */ if (*method == METHOD_XMIT || *method == METHOD_VS || *method == METHOD_SEQ || *method == METHOD_XMSEQ || *method == METHOD_TEXT) { pifile = strtok (NULL, " \t"); if (pifile == NULL) { XMERR ("HHCDL023E Initialization file name missing\n"); return -1; } *ifptr = pifile; } /* Determine the space allocation units */ punits = strtok (NULL, " \t"); if (punits == NULL) return 0; string_to_upper (punits); if (strcmp(punits, "CYL") == 0) *units = 'C'; else if (strcmp(punits, "TRK") == 0) *units = 'T'; else { XMERRF ("HHCDL024E Invalid allocation units: %s\n", punits); return -1; } /* Determine the primary space allocation quantity */ psppri = strtok (NULL, " \t"); if (psppri == NULL) return 0; if (sscanf(psppri, "%u%c", sppri, &c) != 1) { XMERRF ("HHCDL025E Invalid primary space: %s\n", psppri); return -1; } /* Determine the secondary space allocation quantity */ pspsec = strtok (NULL, " \t"); if (pspsec == NULL) return 0; if (sscanf(pspsec, "%u%c", spsec, &c) != 1) { XMERRF ("HHCDL026E Invalid secondary space: %s\n", pspsec); return -1; } /* Determine the directory space allocation quantity */ pspdir = strtok (NULL, " \t"); if (pspdir == NULL) return 0; if (sscanf(pspdir, "%u%c", spdir, &c) != 1) { XMERRF ("HHCDL027E Invalid directory space: %s\n", pspsec); return -1; } /* Determine the dataset organization */ pdsorg = strtok (NULL, " \t"); if (pdsorg == NULL) return 0; string_to_upper (pdsorg); if (strcmp(pdsorg, "IS") == 0) *dsorg = DSORG_IS; else if (strcmp(pdsorg, "PS") == 0) *dsorg = DSORG_PS; else if (strcmp(pdsorg, "DA") == 0) *dsorg = DSORG_DA; else if (strcmp(pdsorg, "PO") == 0) *dsorg = DSORG_PO; else { XMERRF ("HHCDL028E Invalid dataset organization: %s\n", pdsorg); return -1; } /* Determine the record format */ precfm = strtok (NULL, " \t"); if (precfm == NULL) return 0; string_to_upper (precfm); if (strcmp(precfm, "F") == 0) *recfm = RECFM_FORMAT_F; else if (strcmp(precfm, "FA") == 0) *recfm = RECFM_FORMAT_F | RECFM_CTLCHAR_A; else if (strcmp(precfm, "FM") == 0) *recfm = RECFM_FORMAT_F | RECFM_CTLCHAR_M; else if (strcmp(precfm, "FB") == 0) *recfm = RECFM_FORMAT_F | RECFM_BLOCKED; else if (strcmp(precfm, "FBA") == 0) *recfm = RECFM_FORMAT_F | RECFM_BLOCKED | RECFM_CTLCHAR_A; else if (strcmp(precfm, "FBM") == 0) *recfm = RECFM_FORMAT_F | RECFM_BLOCKED | RECFM_CTLCHAR_M; else if (strcmp(precfm, "FBS") == 0) *recfm = RECFM_FORMAT_F | RECFM_BLOCKED | RECFM_SPANNED; else if (strcmp(precfm, "V") == 0) *recfm = RECFM_FORMAT_V; else if (strcmp(precfm, "VA") == 0) *recfm = RECFM_FORMAT_V | RECFM_CTLCHAR_A; else if (strcmp(precfm, "VM") == 0) *recfm = RECFM_FORMAT_V | RECFM_CTLCHAR_M; else if (strcmp(precfm, "VB") == 0) *recfm = RECFM_FORMAT_V | RECFM_BLOCKED; else if (strcmp(precfm, "VBA") == 0) *recfm = RECFM_FORMAT_V | RECFM_BLOCKED | RECFM_CTLCHAR_A; else if (strcmp(precfm, "VBM") == 0) *recfm = RECFM_FORMAT_V | RECFM_BLOCKED | RECFM_CTLCHAR_M; else if (strcmp(precfm, "VBS") == 0) *recfm = RECFM_FORMAT_V | RECFM_BLOCKED | RECFM_SPANNED; else if (strcmp(precfm, "U") == 0) *recfm = RECFM_FORMAT_U; else { XMERRF ("HHCDL029E Invalid record format: %s\n", precfm); return -1; } /* Determine the logical record length */ plrecl = strtok (NULL, " \t"); if (plrecl == NULL) return 0; if (sscanf(plrecl, "%u%c", lrecl, &c) != 1 || *lrecl > MAX_DATALEN) { XMERRF ("HHCDL030E Invalid logical record length: %s\n", plrecl); return -1; } /* Determine the block size */ pblksz = strtok (NULL, " \t"); if (pblksz == NULL) return 0; if (sscanf(pblksz, "%u%c", blksz, &c) != 1 || *blksz > MAX_DATALEN) { XMERRF ("HHCDL031E Invalid block size: %s\n", pblksz); return -1; } /* Determine the key length */ pkeyln = strtok (NULL, " \t"); if (pkeyln == NULL) return 0; if (sscanf(pkeyln, "%u%c", keyln, &c) != 1 || *keyln > 255) { XMERRF ("HHCDL032E Invalid key length: %s\n", pkeyln); return -1; } return 0; } /* end function parse_ctrl_stmt */ /*-------------------------------------------------------------------*/ /* Subroutine to process the control file */ /* Input: */ /* cfp Control file pointer */ /* cfname Control file name */ /* ofname DASD image file name */ /* cif -> CKD image file descriptor */ /* volser Output volume serial number (ASCIIZ) */ /* devtype Output device type */ /* reqcyls Requested device size in cylinders, or zero */ /* heads Output device number of tracks per cylinder */ /* trklen Output device virtual track length */ /* outcyl Output starting cylinder number */ /* outhead Output starting head number */ /* Output: */ /* Datasets are written to the DASD image file as indicated */ /* by the control statements. */ /*-------------------------------------------------------------------*/ static int process_control_file (FILE *cfp, char *cfname, char *ofname, CIFBLK *cif, char *volser, U16 devtype, int reqcyls, int heads, int trklen, int outcyl, int outhead) { int rc; /* Return code */ int i; /* Array subscript */ int n; /* Integer work area */ char dsname[45]; /* Dataset name (ASCIIZ) */ BYTE method; /* Initialization method */ char *ifname; /* ->Initialization file name*/ BYTE units; /* C=CYL, T=TRK */ int sppri; /* Primary space quantity */ int spsec; /* Secondary space quantity */ int spdir; /* Directory space quantity */ BYTE dsorg; /* Dataset organization */ BYTE recfm; /* Record format */ int lrecl; /* Logical record length */ int blksz; /* Block size */ int keyln; /* Key length */ char stmt[256]; /* Control file statement */ int stmtno; /* Statement number */ int mintrks; /* Minimum size of dataset */ int maxtrks; /* Maximum size of dataset */ int outusedv; /* Bytes used in track buffer*/ int tracks = 0; /* Tracks used in dataset */ int numdscb = 0; /* Number of DSCBs */ DATABLK **dscbtab; /* -> Array of DSCB pointers */ int dirblu; /* Bytes used in last dirblk */ int lasttrk; /* Relative track number of last used track of dataset*/ int lastrec; /* Record number of last used block of dataset */ int trkbal; /* Bytes unused on last track*/ int bcyl; /* Dataset begin cylinder */ int bhead; /* Dataset begin head */ int ecyl; /* Dataset end cylinder */ int ehead; /* Dataset end head */ int vtoctrk = 0; /* VTOC start relative track */ int vtocext = 0; /* VTOC extent size (tracks) */ BYTE volvtoc[5]; /* VTOC begin CCHHR */ int offset = 0; /* Offset into trkbuf */ int fsflag = 0; /* 1=Free space message sent */ /* Obtain storage for the array of DSCB pointers */ dscbtab = (DATABLK**)malloc (sizeof(DATABLK*) * MAXDSCB); if (dscbtab == NULL) { XMERRF ("HHCDL010E Cannot obtain storage for DSCB pointer array: %s\n", strerror(errno)); return -1; } /* Initialize the DSCB array with format 4 and format 5 DSCBs */ rc = build_format4_dscb (dscbtab, numdscb, cif); if (rc < 0) return -1; numdscb++; rc = build_format5_dscb (dscbtab, numdscb); if (rc < 0) return -1; numdscb++; /* Read dataset statements from control file */ while (1) { /* Read next statement from control file */ rc = read_ctrl_stmt (cfp, cfname, stmt, sizeof(stmt), &stmtno); if (rc < 0) return -1; /* Exit if end of file */ if (rc > 0) break; /* Parse dataset statement from control file */ rc = parse_ctrl_stmt (stmt, dsname, &method, &ifname, &units, &sppri, &spsec, &spdir, &dsorg, &recfm, &lrecl, &blksz, &keyln); /* Exit if error in control file */ if (rc < 0) { XMERRF ("HHCDL011E Invalid statement in %s line %d\n", cfname, stmtno); return -1; } /* Write empty tracks if allocation is in cylinders */ while (units == 'C' && outhead != 0) { /* Initialize track buffer with empty track */ init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv); /* Write track to output file */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &tracks, &outcyl, &outhead); if (rc < 0) break; } /* end while */ XMINFF (1, "HHCDL012I Creating dataset %s at cyl %d head %d\n", dsname, outcyl, outhead); bcyl = outcyl; bhead = outhead; /* Calculate minimum size of dataset in tracks */ mintrks = (units == 'C' ? sppri * heads : sppri); /* Create dataset according to method specified */ switch (method) { case METHOD_XMIT: /* IEBCOPY wrapped in XMIT */ case METHOD_VS: /* "straight" IEBCOPY */ /* Create dataset using IEBCOPY file as input */ maxtrks = MAX_TRACKS; rc = process_iebcopy_file (ifname, ofname, cif, devtype, heads, trklen, outcyl, outhead, maxtrks, method, &dsorg, &recfm, &lrecl, &blksz, &keyln, &dirblu, &lastrec, &trkbal, &tracks, &outcyl, &outhead); if (rc < 0) return -1; break; case METHOD_DIP: /* Initialize LOGREC dataset */ rc = dip_initialize (ofname, cif, devtype, heads, trklen, outcyl, outhead, mintrks, &lastrec, &trkbal, &tracks, &outcyl, &outhead); if (rc < 0) return -1; break; case METHOD_CVOL: /* Initialize SYSCTLG dataset */ rc = cvol_initialize (ofname, cif, volser, devtype, heads, trklen, outcyl, outhead, mintrks, &lastrec, &trkbal, &tracks, &outcyl, &outhead); if (rc < 0) return -1; break; case METHOD_VTOC: /* Reserve space for VTOC */ vtoctrk = (outcyl * heads) + outhead; vtocext = mintrks; tracks = 0; lastrec = 0; trkbal = 0; break; case METHOD_SEQ: /* Create sequential dataset */ rc = seq_initialize (ifname, ofname, cif, devtype, heads, trklen, outcyl, outhead, mintrks, dsorg, recfm, lrecl, blksz, keyln, &lastrec, &trkbal, &tracks, &outcyl, &outhead); if (rc < 0) return -1; break; case METHOD_XMSEQ: /* Create sequential dataset using XMIT file as input */ maxtrks = MAX_TRACKS; rc = process_inmcopy_file (ifname, ofname, cif, devtype, heads, trklen, outcyl, outhead, maxtrks, &dsorg, &recfm, &lrecl, &blksz, &keyln, &lastrec, &trkbal, &tracks, &outcyl, &outhead); if (rc < 0) return -1; break; case METHOD_TEXT: /* Create sequential dataset using an ASCII text file as input */ maxtrks = MAX_TRACKS; rc = process_text_file (ifname, ofname, cif, devtype, heads, trklen, outcyl, outhead, maxtrks, dsorg, recfm, lrecl, blksz, keyln, &lastrec, &trkbal, &tracks, &outcyl, &outhead); if (rc < 0) return -1; break; default: case METHOD_EMPTY: /* Create empty dataset */ rc = empty_initialize (ofname, cif, devtype, heads, trklen, outcyl, outhead, mintrks, dsorg, spdir, &dirblu, &lastrec, &trkbal, &tracks, &outcyl, &outhead); if (rc < 0) return -1; break; } /* end switch(method) */ /* Calculate the relative track number of last used track */ lasttrk = tracks - 1; /* Round up space allocation if allocated in cylinders */ if (units == 'C') { n = (tracks + heads - 1) / heads * heads; if (mintrks < n) mintrks = n; } /* Fill unused space in dataset with empty tracks */ while (tracks < mintrks) { /* Initialize track buffer with empty track */ init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv); /* Write track to output file */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &tracks, &outcyl, &outhead); if (rc < 0) return -1; } /* end while(tracks) */ /* Print number of tracks written to dataset */ XMINFF (2, "HHCDL013I Dataset %s contains %d track%s\n", dsname, tracks, (tracks == 1 ? "" : "s")); /* Calculate end of extent cylinder and head */ ecyl = (outhead > 0 ? outcyl : outcyl - 1); ehead = (outhead > 0 ? outhead - 1 : heads - 1); /* Create format 1 DSCB for the dataset */ if (method != METHOD_VTOC) { rc = build_format1_dscb (dscbtab, numdscb, dsname, volser, dsorg, recfm, lrecl, blksz, keyln, dirblu, lasttrk, lastrec, trkbal, units, spsec, bcyl, bhead, ecyl, ehead); if (rc < 0) return -1; numdscb++; } } /* end while */ /* Write the VTOC */ rc = write_vtoc (dscbtab, numdscb, cif, ofname, devtype, reqcyls, heads, trklen, vtoctrk, vtocext, &outcyl, &outhead, volvtoc); if (rc < 0) return -1; /* Write empty tracks up to end of volume */ while (outhead != 0 || outcyl < reqcyls) { /* Issue free space information message */ if (fsflag == 0) { XMINFF (1, "HHCDL014I Free space starts at cyl %d head %d\n", outcyl, outhead); fsflag = 1; } #ifdef EXTERNALGUI /* Indicate output file progess */ if (extgui) if ((outcyl % 10) == 0) fprintf (stderr, "OUTCYL=%d\n", outcyl); #endif /*EXTERNALGUI*/ /* Initialize track buffer with empty track */ init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv); /* Write track to output file */ rc = write_track (cif, ofname, heads, trklen, &outusedv, &tracks, &outcyl, &outhead); if (rc < 0) return -1; } /* end while */ if (outcyl > reqcyls && reqcyls != 0) { XMINFF (0, "HHCDL015W Volume exceeds %d cylinders\n", reqcyls); } XMINFF (0, "HHCDL016I Total of %d cylinders written to %s\n", outcyl, ofname); /* Update the VTOC pointer in the volume label */ offset = CKDDASD_TRKHDR_SIZE + CKDDASD_RECHDR_SIZE + 8 + CKDDASD_RECHDR_SIZE + IPL1_KEYLEN + IPL1_DATALEN + CKDDASD_RECHDR_SIZE + IPL2_KEYLEN + IPL2_DATALEN + CKDDASD_RECHDR_SIZE + VOL1_KEYLEN + 11; XMINFF (5, "HHCDL017I Updating VTOC pointer %2.2X%2.2X%2.2X%2.2X%2.2X\n", volvtoc[0], volvtoc[1], volvtoc[2], volvtoc[3], volvtoc[4]); rc = read_track (cif, 0, 0); if (rc < 0) { XMERR ("HHCDL018E Cannot read VOL1 record\n"); return -1; } memcpy (cif->trkbuf + offset, volvtoc, sizeof(volvtoc)); cif->trkmodif = 1; /* Release the DSCB buffers */ for (i = 0; i < numdscb; i++) free (dscbtab[i]); /* Release the array of DSCB pointers */ free (dscbtab); return 0; } /* end function process_control_file */ /*-------------------------------------------------------------------*/ /* DASDLOAD main entry point */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int rc = 0; /* Return code */ char *cfname; /* -> Control file name */ char *ofname; /* -> Output file name */ FILE *cfp; /* Control file pointer */ CIFBLK *cif; /* -> CKD image block */ CKDDEV *ckd; /* -> CKD table entry */ char *volser; /* -> Volume serial (ASCIIZ) */ char *sdevtp; /* -> Device type (ASCIIZ) */ char *sdevsz; /* -> Device size (ASCIIZ) */ char *iplfnm; /* -> IPL text file or NULL */ BYTE c; /* Character work area */ U16 devtype; /* Output device type */ int devcyls; /* Default device size (cyls)*/ int reqcyls; /* Requested device size (cyls) or 0 = use minimum size */ int outheads; /* Output device trks/cyl */ int outmaxdl; /* Output device maximum size record data length value */ int outtrklv; /* Output device track length of virtual device */ int reltrk; /* Output track number */ int outcyl; /* Output cylinder number */ int outhead; /* Output head number */ char stmt[256]; /* Control file statement */ int stmtno; /* Statement number */ BYTE comp = 0xff; /* Compression algoritm */ int altcylflag = 0; /* Alternate cylinders flag */ int lfs = 0; /* 1 = Large file */ char pathname[MAX_PATH]; /* cfname in host path format*/ INITIALIZE_UTILITY("dasdload"); /* Display the program identification message */ display_version (stderr, "Hercules DASD loader program ", FALSE); /* Process optional arguments */ for ( ; argc > 1 && argv[1][0] == '-'; argv++, argc--) { if (strcmp("0", &argv[1][1]) == 0) comp = CCKD_COMPRESS_NONE; #ifdef CCKD_COMPRESS_ZLIB else if (strcmp("z", &argv[1][1]) == 0) comp = CCKD_COMPRESS_ZLIB; #endif #ifdef CCKD_COMPRESS_BZIP2 else if (strcmp("bz2", &argv[1][1]) == 0) comp = CCKD_COMPRESS_BZIP2; #endif else if (strcmp("a", &argv[1][1]) == 0) altcylflag = 1; else if (strcmp("lfs", &argv[1][1]) == 0 && sizeof(off_t) > 4) lfs = 1; else argexit(0); } /* Check the number of arguments */ if (argc < 3 || argc > 4) argexit(4); /* The first argument is the control file name */ cfname = argv[1]; if (argv[1] == NULL || strlen(argv[1]) == 0) argexit(1); /* The second argument is the DASD image file name */ ofname = argv[2]; if (argv[2] == NULL || strlen(argv[2]) == 0) argexit(2); /* The optional third argument is the message level */ if (argc > 3 && argv[3] != NULL) { if (sscanf(argv[3], "%u%c", &infolvl, &c) != 1 || infolvl > 5) argexit(3); } /* Open the control file */ hostpath(pathname, cfname, sizeof(pathname)); cfp = fopen (pathname, "r"); if (cfp == NULL) { XMERRF ("HHCDL001E Cannot open %s: %s\n", cfname, strerror(errno)); return -1; } /* Read first statement from control file */ rc = read_ctrl_stmt (cfp, cfname, stmt, sizeof(stmt), &stmtno); if (rc < 0) return -1; /* Error if end of file */ if (rc > 0) { XMERRF ("HHCDL002E Volume serial statement missing from %s\n", cfname); return -1; } /* Parse the volume serial statement */ volser = strtok (stmt, " \t"); sdevtp = strtok (NULL, " \t"); sdevsz = strtok (NULL, " \t"); iplfnm = strtok (NULL, " \t"); /* Validate the volume serial number */ if (volser == NULL || strlen(volser) == 0 || strlen(volser) > 6) { XMERRF ("HHCDL003E Volume serial %s in %s line %d is not valid\n", volser, cfname, stmtno); return -1; } string_to_upper (volser); /* Validate the device type */ ckd = dasd_lookup (DASD_CKDDEV, sdevtp, 0, 0); if (ckd == NULL) { XMERRF ("HHCDL004E Device type %s in %s line %d is not recognized\n", sdevtp, cfname, stmtno); return -1; } devtype = ckd->devt; /* Obtain number of heads per cylinder, maximum data length per track, and default number of cylinders per device */ outheads = ckd->heads; devcyls = ckd->cyls; if (altcylflag) devcyls += ckd->altcyls; outmaxdl = ckd->r1; /* Use default device size if requested size is omitted or is zero or is "*" or compression is specified */ reqcyls = 0; if (sdevsz != NULL && strcmp(sdevsz, "*") != 0 && comp == 0xff) { /* Validate the requested device size in cylinders */ if (sscanf(sdevsz, "%u%c", &reqcyls, &c) != 1) { XMERRF ("HHCDL005E %s in %s line %d is not a valid cylinder " "count\n", sdevsz, cfname, stmtno); return -1; } } if (reqcyls == 0) reqcyls = devcyls; /* Calculate the track size of the virtual device */ outtrklv = sizeof(CKDDASD_TRKHDR) + sizeof(CKDDASD_RECHDR) + R0_DATALEN + sizeof(CKDDASD_RECHDR) + outmaxdl + sizeof(eighthexFF); outtrklv = ROUND_UP(outtrklv,512); /* Display progress message */ XMINFF (0, "HHCDL006I Creating %4.4X volume %s: " "%u trks/cyl, %u bytes/track\n", devtype, volser, outheads, outtrklv); /* Create the output file */ #ifdef EXTERNALGUI if (extgui) fprintf (stderr, "REQCYLS=%d\n", reqcyls); #endif /*EXTERNALGUI*/ rc = create_ckd (ofname, devtype, outheads, outmaxdl, reqcyls, volser, comp, lfs, 0, 0, 0); if (rc < 0) { XMERRF ("HHCDL007E Cannot create %s\n", ofname); return -1; } /* Open the output file */ cif = open_ckd_image (ofname, NULL, O_RDWR | O_BINARY, 0); if (!cif) { XMERRF ("HHCDL008E Cannot open %s\n", ofname); return -1; } /* Display progress message */ XMINFF (0, "HHCDL009I Loading %4.4X volume %s\n", devtype, volser); /* Write track zero to the DASD image file */ rc = write_track_zero (cif, ofname, volser, devtype, outheads, outtrklv, iplfnm, &reltrk, &outcyl, &outhead); if (rc < 0) return -1; /* Process the control file to create the datasets */ rc = process_control_file (cfp, cfname, ofname, cif, volser, devtype, reqcyls, outheads, outtrklv, outcyl, outhead); /* Close files and release buffers */ fclose (cfp); close_ckd_image (cif); return rc; } /* end function main */ hercules-3.12/dasdls.c0000664000175000017500000004100012564723224011614 00000000000000/* DASDLS.C (c) Copyright Roger Bowler, 1999-2012 */ /* Hercules DASD Utilities: DASD image loader */ /* * dasdls * * Copyright 2000-2009 by Malcolm Beattie * Based on code copyright by Roger Bowler, 1999-2009 * Decode of F1 DSCB by Chris Cheney, 2013, based on * P.E. Havercan's VTOCLIST mainframe utility * */ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" static int needsep = 0; /* Write newline separator next time */ /* other globals */ int yroffs = 0; /* year offset */ int dsnlen = 44; /* dsname length (default value) */ int runflgs = 0; /* flags set from command line */ /* distinct CIF instance for F3 DSCB processing else screw up the F1 processing */ CIFBLK *cifx = NULL; /* -------------------------- */ /* runflgs - flag settings */ /* -------------------------- */ /* dates in yyyymmmdd format */ #define rf_caldate (0x1) /* show expiry dates */ #define rf_expdate (0x2) /* show last-referenced dates */ #define rf_refdate (0x4) /* show header */ #define rf_header (0x8) /* show F1 info */ #define rf_info (0x10) int end_of_track(BYTE *p) { return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff && p[6] == 0xff && p[7] == 0xff; } /* ordinalday is 1..365 (366 in leap year) - often wrongly called Julian day */ int ordday_to_calday(int year, int ordinalday, int *month, int *day) { int d, m, offset; int leap = (((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0)) ? 1 : 0); #define janfebdays (31 + 28) /* offset the months so that March is month 0 to deal with the anomalies of February (short month, leap day) */ if ((ordinalday <= 0) || (ordinalday > (365 + leap))) return -1; offset = janfebdays + leap; /* 31 (Jan) + {28, 29} (Feb) */ if (ordinalday <= offset) offset = - (365 - janfebdays); d = ordinalday - 1 - offset; /* ordinal day to index day and offset to 1 March */ /* the months from March follow 5-month cycles of 31, 30, 31, 30, 31 days each month */ m = d / 153; /* which 5-month cycle? */ d -= (153 * m); /* day within 5-month cycle */ m *= 5; /* month that starts the 5-month cycle */ /* day of month = ((d mod (31 + 30)) mod 31 */ while (d >= 61) { d -= 61; m += 2; } /* body is executed 0, 1, or 2 times */ if (d >= 31) { d -= 31; m += 1; } *day = d + 1; /* ordinal day of month */ /* convert back to January start of year and ordinal month */ if (m >= 10) m -= 12; *month = m + 2; /* NB _index_ month, not ordinal month */ return 0; } void pdate(BYTE* value, int runflgs) { int y = value[0] + yroffs; int m = 12; /* 0..11 = Jan..Dec, 12 indexes empty string */ int d = (value[1] << 8) | value[2]; char *fmt; static char *mths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" }; if (runflgs & rf_caldate) { /* calendar date (yyyymmmdd) */ if (ordday_to_calday(y += 1900, d, &m, &d)) fmt = " *********"; /* ordday_to_calday failed */ else fmt = " %4.4d%s%2.2d"; } else /* ordinal day (yyddd) */ { y %= 100; fmt = " %2.2d%s%3.3d"; } printf(fmt, y, mths[m], d); } void pdatex(BYTE* value, int runflgs) { (value[0] | value[1] ? pdate(value, runflgs) : printf(runflgs & rf_caldate ? " ---------" : " -----")); } void pbyte(BYTE* value) { printf(" %3d", value[0]); } void phword(BYTE* value) { printf(" %5d", (value[0] << 8) | value[1]); } /* dataset extent processing */ int hword(HWORD value) { return (value[0] << 8) + value[1]; } int extent_size(DSXTENT *ext, int heads) { return heads * (hword(ext->xtecyl) - hword(ext->xtbcyl)) + (hword(ext->xtetrk) - hword(ext->xtbtrk)) + 1; } int extents_array(DSXTENT extents[], int max, int *count, int heads) { int i; int size = 0; for (i = 0; (*count > 0) && (i < max); i++) if ((&(extents[i]))->xttype) { size += extent_size(&(extents[i]), heads); *count -= 1; } else fprintf(stderr, "*** extents_array type failure\n"); return size; } int chainf3(int *size, BYTE *ptr, int *count, char *fname, char *sfname) { FORMAT3_DSCB *f3dscb = NULL; int rc = 0; /* prime for success */ while ((*count > 0) && (ptr[0] || ptr[1] || ptr[2] || ptr[3] || ptr[4])) { //*debug*/fprintf(stderr, "*** %d %.2x%.2x %.2x%.2x %.2x\n", //*debug*/ *count, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]); if (cifx == NULL) if (NULL == (cifx = open_ckd_image(fname, sfname, O_RDONLY|O_BINARY, 0))) { //*debug*/ fprintf(stderr, "*** Open cifx failed\n"); return -1; /* open failed */ } if ((read_block(cifx, hword(&(ptr[0])), hword(&(ptr[2])), ptr[4], (BYTE **)&f3dscb, NULL, NULL, NULL) == 0)) switch (f3dscb->ds3fmtid) { case 0xf3: if ((f3dscb->ds3keyid[0] != 0x03) || (f3dscb->ds3keyid[1] != 0x03) || (f3dscb->ds3keyid[2] != 0x03) || (f3dscb->ds3keyid[3] != 0x03)) break; /* break out of switch */ else { *size += extents_array(&(f3dscb->ds3extnt[0]), 4, count, cifx->heads); *size += extents_array(&(f3dscb->ds3adext[0]), 9, count, cifx->heads); } case 0xf2: ptr = &(f3dscb->ds3ptrds[0]); /* same offset for both F2 and F3 DSCBs */ continue; /* continue while loop */ } /* end of switch */ rc = -1; //*debug*/fprintf(stderr, "*** DSCB id=0x%.2x\n", f3dscb->ds3fmtid); break; } /* end of while loop */ return rc; } /* list_contents partly based on dasdutil.c:search_key_equal */ int list_contents(CIFBLK *cif, char *volser, DSXTENT *extent, char *fname, char *sfname) { int cext = 0; int ccyl = (extent[cext].xtbcyl[0] << 8) | extent[cext].xtbcyl[1]; int chead = (extent[cext].xtbtrk[0] << 8) | extent[cext].xtbtrk[1]; int ecyl = (extent[cext].xtecyl[0] << 8) | extent[cext].xtecyl[1]; int ehead = (extent[cext].xtetrk[0] << 8) | extent[cext].xtetrk[1]; #ifdef EXTERNALGUI if (extgui) fprintf(stderr,"ETRK=%d\n",((ecyl*(cif->heads))+ehead)); #endif /*EXTERNALGUI*/ printf("%s%s: VOLSER=%s\n", needsep ? "\n" : "", cif->fname, volser); needsep = 1; if (runflgs & rf_header) { /* display column headers allowing for optional columns */ printf("%*s%s", -dsnlen, "Dsname", runflgs & rf_caldate ? " Created " :" CREDT"); printf(runflgs & rf_refdate ? (runflgs & rf_caldate ? " Last Ref." : " REFDT") : ""); printf(runflgs & rf_expdate ? (runflgs & rf_caldate ? " Exp. Date" : " EXPDT") : ""); printf(" ORG RECFM LRECL BLKSZ Key Trks%%Use#Ext 2ndry_alloc\n"); } do { BYTE *ptr; int rc = read_track(cif, ccyl, chead); #ifdef EXTERNALGUI if (extgui) fprintf(stderr,"CTRK=%d\n",((ccyl*(cif->heads))+chead)); #endif /*EXTERNALGUI*/ if (rc < 0) return -1; ptr = cif->trkbuf + CKDDASD_TRKHDR_SIZE; while (!end_of_track(ptr)) { CKDDASD_RECHDR *rechdr = (CKDDASD_RECHDR*)ptr; int kl = rechdr->klen; int dl = (rechdr->dlen[0] << 8) | rechdr->dlen[1]; FORMAT1_DSCB *f1dscb = (FORMAT1_DSCB*)(ptr + CKDDASD_RECHDR_SIZE); char dsname[sizeof(f1dscb->ds1dsnam) + 1]; char txtrecfm[5] = ""; /* recfm text */ char *tmpstr; int lrecl; int numext; int space; double value; make_asciiz(dsname, sizeof(dsname), f1dscb->ds1dsnam, kl); if ( valid_dsname( dsname ) ) { printf("%*s", -dsnlen, dsname); if (runflgs & rf_info) { /* CREDT */ pdate(f1dscb->ds1credt, runflgs); /* REFDT */ #define ds1refdt resv2 if (runflgs & rf_refdate) pdatex(f1dscb->ds1refdt, runflgs); /* EXPDT */ if (runflgs & rf_expdate) pdatex(f1dscb->ds1expdt, runflgs); /* DSORG */ tmpstr = "??"; if (f1dscb->ds1dsorg[0] == 0 || f1dscb->ds1dsorg[0] == DSORG_U) { if (f1dscb->ds1dsorg[1] == DSORG_AM) tmpstr = "VS"; } if (f1dscb->ds1dsorg[1] == 0) switch (f1dscb->ds1dsorg[0] & (DSORG_PS | DSORG_DA | DSORG_PO)) { case DSORG_PS: tmpstr = "PS"; break; case DSORG_DA: tmpstr = "DA"; break; case DSORG_PO: tmpstr = "PO"; break; case 0: tmpstr = " "; } printf(" %s%s", tmpstr, f1dscb->ds1dsorg[0] & DSORG_U ? "U" : " "); /* RECFM */ tmpstr = "U\0V\0F"; switch (f1dscb->ds1recfm & RECFM_FORMAT_U) { case RECFM_FORMAT_F: tmpstr = (char*)(tmpstr + 2); case RECFM_FORMAT_V: tmpstr = (char*)(tmpstr + 2); case RECFM_FORMAT_U: ; } strcpy(txtrecfm, tmpstr); if (f1dscb->ds1recfm & RECFM_BLOCKED) strcat(txtrecfm, "B"); if (f1dscb->ds1recfm & RECFM_SPANNED) strcat(txtrecfm, "S"); tmpstr = ""; switch (f1dscb->ds1recfm & (RECFM_CTLCHAR_A | RECFM_CTLCHAR_M)) { case RECFM_CTLCHAR_A: tmpstr = "A"; break; case RECFM_CTLCHAR_M: tmpstr = "M"; break; case RECFM_CTLCHAR_A | RECFM_CTLCHAR_M: tmpstr = "?"; } strcat(txtrecfm, tmpstr); if (f1dscb->ds1recfm & RECFM_TRKOFLOW) strcat(txtrecfm, "T"); printf(" %-5s", txtrecfm); /* LRECL */ lrecl = (f1dscb->ds1lrecl[0] << 8) | f1dscb->ds1lrecl[1]; if (lrecl) { printf(" %5d", lrecl); } else { printf(" "); } /* BLKSZ, KEYLN */ phword(f1dscb->ds1blkl); /* BLKSZ */ pbyte(&(f1dscb->ds1keyl)); /* KEYLN */ /* space allocated */ numext = f1dscb->ds1noepv; space = extents_array(&(f1dscb->ds1ext1), 3, &numext, cif->heads); chainf3(&space, &(f1dscb->ds1ptrds[0]), &numext, fname, sfname); printf(" %5d", space); /* % of allocated spaced used */ /* fraction of last track used = 1 - ds1trbal / trkzize */ value = 1.0 - (double)hword(&(f1dscb->ds1trbal[0])) / (cif->trksz); /* add in the number of full tracks used */ value += hword(&(f1dscb->ds1lstar[0])); if (space) { value = value * 100 / space; /* % space used */ printf(" %3.0f", value); } else printf(" "); /* avoiding divide by zero */ /* Number of extents */ pbyte(&(f1dscb->ds1noepv)); /* #EXT */ /* SCALO */ tmpstr = "CYL\0TRK\0BLK"; switch (f1dscb->ds1scalo[0] & DS1SCALO_UNITS) { case DS1SCALO_UNITS_ABSTR: printf(" %-11s", "ABSTR"); break; case DS1SCALO_UNITS_BLK: tmpstr = (char*)(tmpstr + 4); case DS1SCALO_UNITS_TRK: tmpstr = (char*)(tmpstr + 4); case DS1SCALO_UNITS_CYL: printf(" %3s%8d", tmpstr, (((f1dscb->ds1scalo[1] << 8) + f1dscb->ds1scalo[2]) << 8) + f1dscb->ds1scalo[3]);; } } /* end of if (runflgs & rf_info) */ /* done */ printf("\n"); } ptr += CKDDASD_RECHDR_SIZE + kl + dl; } chead++; if (chead >= cif->heads) { ccyl++; chead = 0; } } while (ccyl < ecyl || (ccyl == ecyl && chead <= ehead)); return 0; } /* do_ls_cif based on dasdutil.c:build_extent_array */ int do_ls_cif(CIFBLK *cif, char *fname, char *sfname) { int rc, cyl, head, rec, len; unsigned char *vol1data; FORMAT4_DSCB *f4dscb; char volser[7]; rc = read_block(cif, 0, 0, 3, 0, 0, &vol1data, &len); if (rc < 0) return -1; if (rc > 0) { fprintf(stderr, "VOL1 record not found\n"); return -1; } make_asciiz(volser, sizeof(volser), vol1data+4, 6); cyl = (vol1data[11] << 8) | vol1data[12]; head = (vol1data[13] << 8) | vol1data[14]; rec = vol1data[15]; rc = read_block(cif, cyl, head, rec, (void *)&f4dscb, &len, 0, 0); if (rc < 0) return -1; if (rc > 0) { fprintf(stderr, "F4DSCB record not found\n"); return -1; } return list_contents(cif, volser, &f4dscb->ds4vtoce, fname, sfname); } int do_ls(char *file, char *sfile) { int rc = 0; CIFBLK *cif = open_ckd_image(file, sfile, O_RDONLY|O_BINARY, 0); if (!cif || do_ls_cif(cif, file, sfile) || close_ckd_image(cif)) rc = -1; if (cifx && close_ckd_image(cifx)) /* if necc., close the CIFBLK used for F3 DSCBs */ rc = -1; return 0; } int main(int argc, char **argv) { int rc = 0; char *fn, *sfn; INITIALIZE_UTILITY("dasdls"); /* Display program info message */ display_version (stderr, "Hercules DASD list program ", FALSE); if (argc < 2) { fprintf(stderr, "Usage: dasdls [options] dasd_image [sf=shadow-file-name]...\n" "Options:[-hdr] [-dsnl[=n]] [-info] [-caldt]\n" "\t[-refdt] [-expdt] [-yroffs[=n]]\n"); exit(2); } /* * If your version of Hercules doesn't have support in its * dasdutil.c for turning off verbose messages, then remove * the following line but you'll have to live with chatty * progress output on stdout. */ set_verbose_util(0); while (*++argv) { fn = *argv; if (strcmp(fn, "-info") == 0) /* show F1 info */ { runflgs |= rf_info; continue; } if (strcmp(fn, "-caldt") == 0) /* calendar date format */ { runflgs |= (rf_caldate | rf_info); continue; } if (strcmp(fn, "-expdt") == 0) /* show expiry date */ { runflgs |= (rf_expdate | rf_info); continue; } if (strcmp(fn, "-refdt") == 0) /* show last-reference date */ { runflgs |= (rf_refdate | rf_info) ; continue; } if (strcmp(fn, "-hdr") == 0) /* show column headers */ { runflgs |= (rf_header | rf_info); continue; } if (strlen(*argv) > 6 && !memcmp(fn, "-dsnl=", 6)) /* restrict dsname width */ { dsnlen = atoi(fn+6); runflgs |= rf_info; continue; } if (strcmp(fn, "-dsnl") == 0) /* restrict dsname width (default) */ { dsnlen = 26; runflgs |= rf_info; continue; } if (strlen(*argv) > 8 && !memcmp(fn, "-yroffs=", 8)) /* year offset */ { yroffs = atoi(fn+8); runflgs |= rf_info; continue; } if (strcmp(fn, "-yroffs") == 0) /* year offset (default) */ { yroffs = 28; runflgs |= rf_info; continue; } if (*(argv+1) && strlen (*(argv+1)) > 3 && !memcmp(*(argv+1), "sf=", 3)) sfn = *++argv; else sfn = NULL; if (do_ls(fn, sfn)) rc = 1; } return rc; } hercules-3.12/dasdpdsu.c0000664000175000017500000003173712564723224012171 00000000000000/* DASDPDSU.C (c) Copyright Roger Bowler, 1999-2009 */ /* Hercules DASD Utilities: PDS unloader */ /*-------------------------------------------------------------------*/ /* This program unloads members of a partitioned dataset from */ /* a virtual DASD volume and copies each member to a flat file. */ /* */ /* The command format is: */ /* dasdpdsu ckdfile dsname [ascii] */ /* where: ckdfile is the name of the CKD image file */ /* dsname is the name of the PDS to be unloaded */ /* ascii is an optional keyword which will cause the members */ /* to be unloaded as ASCII variable length text files. */ /* Each member is copied to a file memname.mac in the current */ /* working directory. If the ascii keyword is not specified then */ /* the members are unloaded as fixed length binary files. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "dasdblks.h" /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static BYTE asciiflag = 0; /* 1=Translate to ASCII */ static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; /*-------------------------------------------------------------------*/ /* Subroutine to process a member */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* noext Number of extents in dataset */ /* extent Dataset extent array */ /* memname Member name (ASCIIZ) */ /* ttr Member TTR */ /* */ /* Return value is 0 if successful, or -1 if error */ /*-------------------------------------------------------------------*/ static int process_member (CIFBLK *cif, int noext, DSXTENT extent[], char *memname, BYTE *ttr) { int rc; /* Return code */ int len; /* Record length */ int trk; /* Relative track number */ int cyl; /* Cylinder number */ int head; /* Head number */ int rec; /* Record number */ BYTE *buf; /* -> Data block */ FILE *ofp; /* Output file pointer */ char ofname[256]; /* Output file name */ int offset; /* Offset of record in buffer*/ char card[81]; /* Logical record (ASCIIZ) */ char pathname[MAX_PATH]; /* ofname in host format */ /* Build the output file name */ memset (ofname, 0, sizeof(ofname)); strncpy (ofname, memname, 8); string_to_lower (ofname); strcat (ofname, ".mac"); /* Open the output file */ hostpath(pathname, ofname, sizeof(pathname)); ofp = fopen (pathname, (asciiflag? "w" : "wb")); if (ofp == NULL) { fprintf (stderr, "Cannot open %s: %s\n", ofname, strerror(errno)); return -1; } /* Point to the start of the member */ trk = (ttr[0] << 8) | ttr[1]; rec = ttr[2]; fprintf (stderr, "Member %s TTR=%4.4X%2.2X\n", memname, trk, rec); /* Read the member */ while (1) { /* Convert relative track to cylinder and head */ rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head); if (rc < 0) return -1; // fprintf (stderr, // "CCHHR=%4.4X%4.4X%2.2X\n", // cyl, head, rec); /* Read a data block */ rc = read_block (cif, cyl, head, rec, NULL, NULL, &buf, &len); if (rc < 0) return -1; /* Move to next track if record not found */ if (rc > 0) { trk++; rec = 1; continue; } /* Exit at end of member */ if (len == 0) break; /* Check length of data block */ if (len % 80 != 0) { fprintf (stderr, "Bad block length %d at cyl %d head %d rec %d\n", len, cyl, head, rec); return -1; } /* Process each record in the data block */ for (offset = 0; offset < len; offset += 80) { if (asciiflag) { make_asciiz (card, sizeof(card), buf + offset, 72); fprintf (ofp, "%s\n", card); } else { fwrite (buf+offset, 80, 1, ofp); } if (ferror(ofp)) { fprintf (stderr, "Error writing %s: %s\n", ofname, strerror(errno)); return -1; } } /* end for(offset) */ /* Point to the next data block */ rec++; } /* end while */ /* Close the output file and exit */ fclose (ofp); return 0; } /* end function process_member */ /*-------------------------------------------------------------------*/ /* Subroutine to process a directory block */ /* Input: */ /* cif -> CKD image file descriptor structure */ /* noext Number of extents in dataset */ /* extent Dataset extent array */ /* dirblk Pointer to directory block */ /* */ /* Return value is 0 if OK, +1 if end of directory, or -1 if error */ /*-------------------------------------------------------------------*/ static int process_dirblk (CIFBLK *cif, int noext, DSXTENT extent[], BYTE *dirblk) { int rc; /* Return code */ int size; /* Size of directory entry */ int k; /* Userdata halfword count */ BYTE *dirptr; /* -> Next byte within block */ int dirrem; /* Number of bytes remaining */ PDSDIR *dirent; /* -> Directory entry */ char memname[9]; /* Member name (ASCIIZ) */ /* Load number of bytes in directory block */ dirptr = dirblk; dirrem = (dirptr[0] << 8) | dirptr[1]; if (dirrem < 2 || dirrem > 256) { fprintf (stderr, "Directory block byte count is invalid\n"); return -1; } /* Point to first directory entry */ dirptr += 2; dirrem -= 2; /* Process each directory entry */ while (dirrem > 0) { /* Point to next directory entry */ dirent = (PDSDIR*)dirptr; /* Test for end of directory */ if (memcmp(dirent->pds2name, eighthexFF, 8) == 0) return +1; /* Extract the member name */ make_asciiz (memname, sizeof(memname), dirent->pds2name, 8); /* Process the member */ rc = process_member (cif, noext, extent, memname, dirent->pds2ttrp); if (rc < 0) return -1; /* Load the user data halfword count */ k = dirent->pds2indc & PDS2INDC_LUSR; /* Point to next directory entry */ size = 12 + k*2; dirptr += size; dirrem -= size; } return 0; } /* end function process_dirblk */ /*-------------------------------------------------------------------*/ /* DASDPDSU main entry point */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int rc; /* Return code */ int i=0; /* Arument index */ int len; /* Record length */ int cyl; /* Cylinder number */ int head; /* Head number */ int rec; /* Record number */ int trk; /* Relative track number */ char *fname; /* -> CKD image file name */ char *sfname=NULL; /* -> CKD shadow file name */ char dsnama[45]; /* Dataset name (ASCIIZ) */ int noext; /* Number of extents */ DSXTENT extent[16]; /* Extent descriptor array */ BYTE *blkptr; /* -> PDS directory block */ BYTE dirblk[256]; /* Copy of directory block */ CIFBLK *cif; /* CKD image file descriptor */ INITIALIZE_UTILITY("dasdpdsu"); /* Display the program identification message */ display_version (stderr, "Hercules PDS unload program ", FALSE); /* Check the number of arguments */ if (argc < 3 || argc > 5) { fprintf (stderr, "Usage: %s ckdfile [sf=shadow-file-name] pdsname [ascii]\n", argv[0]); return -1; } /* The first argument is the name of the CKD image file */ fname = argv[1]; /* The next argument may be the shadow file name */ if (!memcmp (argv[2], "sf=", 3)) { sfname = argv[2]; i = 1; } /* The second argument is the dataset name */ memset (dsnama, 0, sizeof(dsnama)); strncpy (dsnama, argv[2|+i], sizeof(dsnama)-1); string_to_upper (dsnama); /* The third argument is an optional keyword */ if (argc > 3+i && argv[3+i] != NULL) { if (strcasecmp(argv[3+i], "ascii") == 0) asciiflag = 1; else { fprintf (stderr, "Keyword %s is not recognized\n", argv[3+i]); return -1; } } /* Open the CKD image file */ cif = open_ckd_image (fname, sfname, O_RDONLY|O_BINARY, 0); if (cif == NULL) return -1; /* Build the extent array for the requested dataset */ rc = build_extent_array (cif, dsnama, extent, &noext); if (rc < 0) return -1; #ifdef EXTERNALGUI /* Calculate ending relative track */ if (extgui) { int bcyl; /* Extent begin cylinder */ int btrk; /* Extent begin head */ int ecyl; /* Extent end cylinder */ int etrk; /* Extent end head */ int trks; /* total tracks in dataset */ int i; /* loop control */ for (i = 0, trks = 0; i < noext; i++) { bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1]; btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1]; ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1]; etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1]; trks += (((ecyl * cif->heads) + etrk) - ((bcyl * cif->heads) + btrk)) + 1; } fprintf(stderr,"ETRK=%d\n",trks-1); } #endif /*EXTERNALGUI*/ /* Point to the start of the directory */ trk = 0; rec = 1; /* Read the directory */ while (1) { #ifdef EXTERNALGUI if (extgui) fprintf(stderr,"CTRK=%d\n",trk); #endif /*EXTERNALGUI*/ /* Convert relative track to cylinder and head */ rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head); if (rc < 0) return -1; /* Read a directory block */ fprintf (stderr, "Reading directory block at cyl %d head %d rec %d\n", cyl, head, rec); rc = read_block (cif, cyl, head, rec, NULL, NULL, &blkptr, &len); if (rc < 0) return -1; /* Move to next track if block not found */ if (rc > 0) { trk++; rec = 1; continue; } /* Exit at end of directory */ if (len == 0) break; /* Copy the directory block */ memcpy (dirblk, blkptr, sizeof(dirblk)); /* Process each member in the directory block */ rc = process_dirblk (cif, noext, extent, dirblk); if (rc < 0) return -1; if (rc > 0) break; /* Point to the next directory block */ rec++; } /* end while */ fprintf (stderr, "End of directory\n"); /* Close the CKD image file and exit */ rc = close_ckd_image (cif); return rc; } /* end function main */ hercules-3.12/dasdseq.c0000664000175000017500000014162412564723224012003 00000000000000/* DASDSEQ.C (c) Copyright Roger Bowler, 1999-2012 */ /* (c) Copyright James M. Morrison, 2001-2010 */ /* Hercules DASD Utilities: Sequential dataset unloader */ /* Code borrowed from dasdpdsu Copyright 1999-2009 Roger Bowler */ /* Changes and additions Copyright 2001-2009, James M. Morrison */ /*-------------------------------------------------------------------*/ /* */ /* dasdseq */ /* */ /* This program retrieves a sequential (DSORG=PS) dataset from */ /* a Hercules CKD/CCKD volume. The input file is assumed to be */ /* encoded in the EBCDIC character set. */ /* */ /*-------------------------------------------------------------------*/ // We don't use some of the regular Hercules dasd routines because // we want the DSCB as read from dasd so we can check some of the // file attributes (such as DSORG, RECFM, LRECL). // Dasdseq now uses the same case for the output dataset as the // user specifies on the command line. Prior versions always // used upper case, which seems unnecessarily loud. #include "hstdinc.h" #include "hercules.h" typedef struct _DASD_VOL_LABEL { /* dasd cyl 0 trk 0 record 3 */ /* identifies volser, owner, and VTOC location */ /* recorded in EBCDIC; 80 bytes in length */ BYTE vollabi[3]; // c'VOL' BYTE volno; // volume label sequence # BYTE volserno[6]; // volume serial BYTE security; // security field, set to 0xc0 BYTE volvtoc[5]; // CCHHR of VTOC's F4DSCB BYTE resv1[21]; // reserved; should be left blank BYTE volowner[14]; // volume owner BYTE resv2[29]; // reserved; should be left blank } DASD_VOL_LABEL; #include "dasdblks.h" #ifndef MAX_EXTENTS // see getF3dscb for notes #define MAX_EXTENTS 123 // maximum supported dataset extents #endif typedef struct _DADSM { DASD_VOL_LABEL volrec; // volume label record FORMAT4_DSCB f4buf; // F4 DSCB DSXTENT f4ext; // VTOC extent info FORMAT3_DSCB f3buf; // F3 DSCB FORMAT1_DSCB f1buf; // F1 DSCB int f1numx; // # valid dataset extents DSXTENT f1ext[MAX_EXTENTS]; // dsn extent info } DADSM; //---------------------------------------------------------------------------------- // Globals //---------------------------------------------------------------------------------- int local_verbose = 0; // verbose setting int copy_verbose = 0; // verbose setting for copyfile char *din; // dasd image filename char *sfn; // shadow file parm int absvalid = 0; // 1 = -abs specified, use CCHH not dsn char *argdsn; // MVS dataset name int expert = 0; // enable -abs help int tran_ascii = 0; // 1 = ascii output #ifdef DEBUG int debug = 1; // enable debug code #else int debug = 0; // disable debug code #endif void sayext(int max, DSXTENT *extent) { int i; fprintf(stderr, " EXTENT --begin-- ---end---\n"); fprintf(stderr, "TYPE NUMBER CCCC HHHH CCCC HHHH\n"); for (i = 0; i < max; i++) { int bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1]; int btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1]; int ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1]; int etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1]; fprintf(stderr, " %2.2X %2.2X %4.4X %4.4X %4.4X %4.4X\n", extent[i].xttype, extent[i].xtseqn, bcyl, btrk, ecyl, etrk); } } /* sayext */ //---------------------------------------------------------------------------------- // Display selected F1 DSCB information //---------------------------------------------------------------------------------- void showf1( FILE *fmsg, FORMAT1_DSCB *f1dscb, DSXTENT extent[], int verbose) { int i, dsorg, lrecl, blksize, volseq, x, y, num_extents; char volser[sizeof(f1dscb->ds1dssn) + 1]; char dsn[sizeof(f1dscb->ds1dsnam) + 1]; char txtcredt[9]; // creation date char txtexpdt[9] = "(n/a)"; // expiration date char txtscr[20]; char txtsyscd[14]; char txtdsorg[5] = ""; // dsorg text char txtrecfm[5] = ""; // recfm text if (verbose > 2) { fprintf(fmsg, "showf1 F1 DSCB\n"); data_dump(f1dscb, sizeof(FORMAT1_DSCB)); } make_asciiz(dsn, sizeof(dsn), f1dscb->ds1dsnam, sizeof(f1dscb->ds1dsnam)); make_asciiz(volser, sizeof(volser), f1dscb->ds1dssn, sizeof(f1dscb->ds1dssn)); volseq = (f1dscb->ds1volsq[0] << 8) | (f1dscb->ds1volsq[1]); x = f1dscb->ds1credt[0] + 1900; y = (f1dscb->ds1credt[1] << 8) | f1dscb->ds1credt[2]; sprintf(txtcredt, "%4.4d", x); strcat(txtcredt, "."); sprintf(txtscr, "%3.3d", y); strcat(txtcredt, txtscr); if (f1dscb->ds1expdt[0] || f1dscb->ds1expdt[1] || f1dscb->ds1expdt[2]) { x = f1dscb->ds1expdt[0] + 1900; y = (f1dscb->ds1expdt[1] << 8) | f1dscb->ds1expdt[2]; sprintf(txtexpdt, "%4.4d", x); strcat(txtexpdt, "."); sprintf(txtscr, ".%3.3d", y); strcat(txtexpdt, txtscr); } num_extents = f1dscb->ds1noepv; // Field ignored: ds1nobdb (# bytes used in last PDS dir blk) make_asciiz(txtsyscd, sizeof(txtsyscd), f1dscb->ds1syscd, sizeof(f1dscb->ds1syscd)); dsorg = (f1dscb->ds1dsorg[0] << 8) | (f1dscb->ds1dsorg[1]); if (dsorg & (DSORG_IS * 256)) strcpy(txtdsorg, "IS"); if (dsorg & (DSORG_PS * 256)) strcpy(txtdsorg, "PS"); if (dsorg & (DSORG_DA * 256)) strcpy(txtdsorg, "DA"); if (dsorg & (DSORG_PO * 256)) strcpy(txtdsorg, "PO"); if (dsorg & DSORG_AM) strcpy(txtdsorg, "VS"); if (txtdsorg[0] == '\0') strcpy(txtdsorg, "??"); if (dsorg & (DSORG_U * 256)) strcat(txtdsorg, "U"); if (f1dscb->ds1recfm & RECFM_FORMAT_F) strcpy(txtrecfm, "F"); if (f1dscb->ds1recfm & RECFM_FORMAT_V) strcpy(txtrecfm, "V"); if ((f1dscb->ds1recfm & RECFM_FORMAT_U) == RECFM_FORMAT_U) strcpy(txtrecfm, "U"); if (f1dscb->ds1recfm & RECFM_BLOCKED) strcat(txtrecfm, "B"); if (f1dscb->ds1recfm & RECFM_SPANNED) strcat(txtrecfm, "S"); if (f1dscb->ds1recfm & RECFM_CTLCHAR_A) strcat(txtrecfm, "A"); if (f1dscb->ds1recfm & RECFM_CTLCHAR_M) strcat(txtrecfm, "M"); if (f1dscb->ds1recfm & RECFM_TRKOFLOW) strcat(txtrecfm, "T"); // Field ignored: ds1optcd (option codes, same as in DCB) blksize = (f1dscb->ds1blkl[0] << 8) | f1dscb->ds1blkl[1]; lrecl = (f1dscb->ds1lrecl[0] << 8) | f1dscb->ds1lrecl[1]; // Field ignored: ds1keyl (key length) // Field ignored: ds1rkp (relative key position) // Field ignored: ds1dsind (data set indicators) // Field ignored: ds1scalo (secondary allocation) // Field ignored: ds1lstar (pointer to last written block; ttr) // Field ignored: ds1trbal (bytes remaining on last track used) // Extent information was passed to us, so we ignore what's in F1DSCB fprintf(fmsg, "Dataset %s on volume %s sequence %d\n", dsn, volser, volseq); fprintf(fmsg, "Created %s expires %s\n", txtcredt, txtexpdt); fprintf(fmsg, "Dsorg=%s recfm=%s lrecl=%d blksize=%d\n", txtdsorg, txtrecfm, lrecl, blksize); fprintf(fmsg, "System code %s\n", txtsyscd); if (verbose > 1) { fprintf(stderr, "Dataset has %d extent(s)\n", num_extents); if (verbose > 2) data_dump((void *)extent, sizeof(DSXTENT) * MAX_EXTENTS); fprintf(stderr, "Extent Information:\n"); fprintf(stderr, " EXTENT --begin-- ---end---\n"); fprintf(stderr, "TYPE NUMBER CCCC HHHH CCCC HHHH\n"); for (i = 0; i < num_extents; i++) { int bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1]; int btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1]; int ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1]; int etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1]; fprintf(stderr, " %2.2X %2.2X %4.4X %4.4X %4.4X %4.4X\n", extent[i].xttype, extent[i].xtseqn, bcyl, btrk, ecyl, etrk); } } return; } /* showf1 */ //---------------------------------------------------------------------------------- // Copy DSORG=PS RECFM=F[B] dataset to output file // // Input: // fout FILE * (opened "w" for ascii, "wb" for ebcdic) // cif dasdutil control block // f1dscb F1 DSCB // extent dataset extent array // tran 0 = ebcdic output, 1 = ascii output // ascii output will have trailing blanks removed // verbose 0 = no status messages // 1 = status messages // > 1 debugging messages // > 2 dump read record // > 3 dump written record // > 4 dump read record from input buffer // Output: // File written, messages displayed on stderr // Returns -1 on error, else returns # records written // Notes: // Caller is responsible for opening and closing fout. // // The F1 DSCB's DS1LSTAR field is used to determine EOF (absent a prior // EOF being encountered), since some datasets don't have an EOF marker // present. On my MVSRES, for instance, SYS1.BRODCAST has no EOF marker. // // 2003-01-14 jmm DS1LSTAR may be zero; if so, ignore DS1LSTAR and // hope for valid EOF. //---------------------------------------------------------------------------------- int fbcopy( FILE *fout, CIFBLK *cif, DADSM *dadsm, int tran, int verbose) { FORMAT1_DSCB *f1dscb = &dadsm->f1buf; DSXTENT extent[MAX_EXTENTS]; int rc, trk = 0, trkconv = 999, rec = 1; int cyl = 0, head = 0, rc_rb, len, offset; int rc_copy = 0; int recs_written = 0, lrecl, num_extents; int lstartrack = 0, lstarrec = 0, lstarvalid = 0; BYTE *buffer; char *pascii = NULL; char zdsn[sizeof(f1dscb->ds1dsnam) + 1]; // ascii dsn // Kludge to avoid rewriting this code (for now): memcpy(&extent, (void *)&(dadsm->f1ext), sizeof(extent)); num_extents = f1dscb->ds1noepv; lrecl = (f1dscb->ds1lrecl[0] << 8) | (f1dscb->ds1lrecl[1]); if (absvalid) { strcpy(zdsn, argdsn); if (debug) fprintf(stderr, "fbcopy absvalid\n"); } else { make_asciiz(zdsn, sizeof(zdsn), f1dscb->ds1dsnam, sizeof(f1dscb->ds1dsnam)); if ((f1dscb->ds1lstar[0] !=0) || (f1dscb->ds1lstar[1] != 0) || (f1dscb->ds1lstar[2] != 0)) { lstartrack = (f1dscb->ds1lstar[0] << 8) | (f1dscb->ds1lstar[1]); lstarrec = f1dscb->ds1lstar[2]; lstarvalid = 1; // DS1LSTAR valid } } if (debug) { fprintf(stderr, "fbcopy zdsn %s\n", zdsn); fprintf(stderr, "fbcopy num_extents %d\n", num_extents); fprintf(stderr, "fbcopy lrecl %d\n", lrecl); fprintf(stderr, "fbcopy F1 DSCB\n"); data_dump(f1dscb, sizeof(FORMAT1_DSCB)); sayext(num_extents, (void *)&extent); } if (verbose) // DS1LSTAR = last block written TTR fprintf(stderr, "fbcopy DS1LSTAR %2.2X%2.2X%2.2X lstartrack %d " "lstarrec %d lstarvalid %d\n", f1dscb->ds1lstar[0], f1dscb->ds1lstar[1], f1dscb->ds1lstar[2], lstartrack, lstarrec, lstarvalid); if (tran) { // need ASCII translation buffer? pascii = malloc(lrecl + 1); if (pascii == NULL) { fprintf(stderr, "fbcopy unable to allocate ascii buffer\n"); return -1; } } while (1) { // output records until something stops us // Honor DS1LSTAR when valid if ((lstarvalid) && (trk == lstartrack) && (rec > lstarrec)) { if (verbose) fprintf(stderr, "fbcopy DS1LSTAR indicates EOF\n" "fbcopy DS1LSTAR %2.2X%2.2X%2.2X " "track %d record %d\n", f1dscb->ds1lstar[0], f1dscb->ds1lstar[1], f1dscb->ds1lstar[2], trk, rec); rc_copy = recs_written; break; } // Convert TT to CCHH for upcoming read_block call if (trkconv != trk) { // avoid converting for each block trkconv = trk; // current track converted rc = convert_tt(trk, num_extents, extent, cif->heads, &cyl, &head); if (rc < 0) { fprintf(stderr, "fbcopy convert_tt track %5.5d, rc %d\n", trk, rc); if (absvalid) rc_copy = recs_written; else rc_copy = -1; break; } if (verbose > 1) fprintf(stderr, "fbcopy convert TT %5.5d CCHH %4.4X %4.4X\n", trk, cyl, head); } // Read block from dasd if (verbose > 2) fprintf(stderr, "fbcopy reading track %d " "record %d CCHHR = %4.4X %4.4X %2.2X\n", trk, rec, cyl, head, rec); rc_rb = read_block(cif, cyl, head, rec, NULL, NULL, &buffer, &len); if (rc_rb < 0) { // error fprintf(stderr, "fbcopy error reading %s, rc %d\n", zdsn, rc_rb); rc_copy = -1; break; } // Handle end of track return from read_block if (rc_rb > 0) { // end of track if (verbose > 2) fprintf(stderr, "fbcopy End Of Track %d rec %d\n", trk, rec); trk++; // next track rec = 1; // record 1 on new track continue; } // Check for dataset EOF if (len == 0) { // EOF if (verbose) fprintf(stderr, "fbcopy EOF track %5.5d rec %d\n", trk, rec); if (absvalid) { // capture as much -abs data as possible if (verbose) fprintf(stderr, "fbcopy ignoring -abs EOF\n"); } else { rc_copy = recs_written; break; } } if (verbose > 3) fprintf(stderr, "fbcopy read %d bytes\n", len); if (verbose > 2) { data_dump(buffer, len); fprintf(stderr, "\n"); } // Deblock input dasd block, write records to output dataset for (offset = 0; offset < len; offset += lrecl) { if (verbose > 3) { fprintf(stderr, "fbcopy offset %d length %d rec %d\n", offset, lrecl, recs_written); } if (tran) { // ASCII output memset(pascii, 0, lrecl + 1); make_asciiz(pascii, lrecl + 1, buffer + offset, lrecl); if (verbose > 4) { fprintf(stderr, "fbcopy buffer offset %d rec %d\n", offset, rec); data_dump(buffer + offset, lrecl); } if (verbose > 3) { fprintf(stderr, "->%s<-\n", pascii); data_dump(pascii, lrecl); } fprintf(fout, "%s\n", pascii); } else { // EBCDIC output if (verbose > 3) { fprintf(stderr, "fbcopy EBCDIC buffer\n"); data_dump(buffer + offset, lrecl); } fwrite(buffer + offset, lrecl, 1, fout); } if (ferror(fout)) { fprintf(stderr, "fbcopy error writing %s\n", zdsn); fprintf(stderr, "%s\n", strerror(errno)); rc_copy = -1; } recs_written++; } if (rc_copy != 0) break; else rec++; // next record on track } /* while (1) */ if (pascii) free(pascii); // release ASCII conversion buffer return rc_copy; } /* fbcopy */ //---------------------------------------------------------------------------------- // Given extent information, place it into appropriate extent table entry //---------------------------------------------------------------------------------- void makext( int i, // extent # int heads, // # heads per cylinder on device DSXTENT *extent, // extent table entry int startcyl, // start cylinder int starttrk, // start track int size) { // extent size in tracks int endcyl = ((startcyl * heads) + starttrk + size - 1) / heads; int endtrk = ((startcyl * heads) + starttrk + size - 1) % heads; if (i > (MAX_EXTENTS - 1)) { fprintf(stderr, "makext extent # parm invalid %d, abort\n", i); exit(4); } extent[i].xttype = 1; // extent type extent[i].xtseqn = i; // extent # (relative zero) extent[i].xtbcyl[0] = startcyl >> 8; // begin cyl extent[i].xtbcyl[1] = startcyl - ((startcyl / 256) * 256); extent[i].xtbtrk[0] = starttrk >> 8; extent[i].xtbtrk[1] = starttrk - ((starttrk / 256) * 256); extent[i].xtecyl[0] = endcyl >> 8; // end cyl extent[i].xtecyl[1] = endcyl - ((endcyl / 256) * 256); extent[i].xtetrk[0] = endtrk >> 8; extent[i].xtetrk[1] = endtrk - ((endtrk / 256) * 256); // end track return; } /* makext */ //---------------------------------------------------------------------------------- // showhelp - display syntax help //---------------------------------------------------------------------------------- void showhelp() { fprintf(stderr, (expert) ? "Usage: dasdseq [-debug] [-expert] [-ascii] image [sf=shadow] [attr] filespec\n" " -debug optional - Enables debug mode, additional debug help appears\n" : "Usage: dasdseq [-expert] [-ascii] image [sf=shadow] filespec\n"); fprintf(stderr, " -expert optional - Additional help describes expert operands\n" " -ascii optional - translate output file to ascii, trim trailing blanks\n" " image required - [path/]filename of dasd image file (dasd volume)\n" " shadow optional - [path/]filename of shadow file (note sf=)\n"); if (expert) fprintf(stderr, " ALL EXPERT FACILITIES ARE EXPERIMENTAL\n" " attr optional - dataset attributes (only useful with -abs)\n" " attr syntax: [-recfm fb] [-lrecl aa]\n" " -recfm designates RECFM, reserved for future support\n" " fb - fixed, blocked (only RECFM currently supported)\n" " -lrecl designates dataset LRECL\n" " aa - decimal logical record length (default 80)\n" " Blocksize need not be specified; dasdseq handles whatever\n" " block size comes off the volume.\n" " filespec required (optional sub-operands in the following order):\n" " [-heads xx]\n" " [-abs cc hh tt] [...] [-abs cc hh tt ]\n" " filename\n" " When -abs is -not- specified,\n" " Filename specifies the MVS DSORG=PS dataset on the volume.\n" " The dasd image volume containing the dataset must have a valid VTOC\n" " structure, and a F1 DSCB describing the dataset.\n" " Specifying -debug will (eventually) display extent information.\n" " When -abs is specified, each -abs group specifies one dataset extent.\n" " For multi-extent datasets, -abs groups may be repeated as needed,\n" " in the order in which the dataset's extents occur.\n" " A maximum of %d extents are supported.\n" " No VTOC structure is implied, a F1 DSCB will not be sought.\n" " Dasdseq will frequently report 'track not found in extent table'\n" " (along with a message from fbcopy about rc -1 from convert_tt)\n" " due to potentially missing EOF markers in the extent, and the\n" " fact that the F1 DSCB DS1LSTAR field is not valid.\n" " Check your output file before you panic.\n" " Fbcopy ignores EOF, in case you are attempting to recovery PDS\n" " member(s) from a damaged dasd volume, preferring to wait until\n" " all tracks in the extent have been processed.\n" " Tracks containing PDS members may have more than one EOF per track.\n" " Expect a lot of associated manual effort with -abs.\n" " -heads defines # tracks per cylinder on device;\n" " xx - decimal number of heads per cylinder on device\n" " default xx = 15 (valid for 3380s, 3390s)\n" " -abs indicates the beginning of each extent's location in terms of\n" " absolute dasd image location.\n" " cc - decimal cylinder number (relative zero)\n" " hh - decimal head number (relative zero)\n" " tt - decimal number of tracks in extent\n" " filename will be the filename of the output file in the current directory;\n" " output filename in the same case as the command line filename.\n", MAX_EXTENTS); else fprintf(stderr, " filespec required - MVS dataset name of DSORG=PS dataset, output filename\n"); if (debug) fprintf(stderr, "\n" "Debugging options (at end of dasdseq command)\n" " [verbose [x [y [z]]]]\n\n" " verbose debug output level (default = 0 when not specified)\n" " x main program (default = 1 when verbose specified)\n" " y copyfile + showf1\n" " z dasdutil\n" " Higher numbers produces more output\n"); return; } /* showhelp */ //---------------------------------------------------------------------------------- // parsecmd - parse command line; results stored in program globals //---------------------------------------------------------------------------------- int parsecmd(int argc, char **argv, DADSM *dadsm) { int util_verbose = 0; // Hercules dasdutil.c diagnostic level int heads = 15; // # heads per cylinder on device int extnum = 0; // extent number for makext() int abscyl = 0; // absolute CC (default 0) int abshead = 0; // absolute HH (default 0) int abstrk = 1; // absolute tracks (default 1) int lrecl = 80; // default F1 DSCB lrecl // Usage: dasdseq [-debug] [-expert] [-ascii] image [sf=shadow] [attr] filespec argv++; // skip dasdseq command argv[0] if ((*argv) && (strcasecmp(*argv, "-debug") == 0)) { argv++; debug = 1; fprintf(stderr, "Command line DEBUG specified\n"); } if ((*argv) && (strcasecmp(*argv, "-expert") == 0)) { argv++; expert = 1; if (debug) fprintf(stderr, "EXPERT mode\n"); } if ((*argv) && (strcasecmp(*argv, "-ascii") == 0)) { argv++; tran_ascii = 1; if (debug) fprintf(stderr, "ASCII translation enabled\n"); } if (*argv) din = *argv++; // dasd image filename if (debug) fprintf(stderr, "IMAGE %s\n", din); if (*argv && strlen(*argv) > 3 && !memcmp(*argv, "sf=", 3)) { sfn = *argv++; // shadow file parm } else sfn = NULL; if (debug) fprintf(stderr, "SHADOW %s\n", sfn); dadsm->f1buf.ds1recfm = RECFM_FORMAT_F | RECFM_BLOCKED; // recfm FB for fbcopy if ((*argv) && (strcasecmp(*argv, "-recfm") == 0)) { argv++; // skip -recfm if ((*argv) && (strcasecmp(*argv, "fb") == 0)) { argv++; // skip fb if (debug) fprintf(stderr, "RECFM fb\n"); } else { argv++; // skip bad recfm fprintf(stderr, "Unsupported -recfm value %s\n", *argv); } } if ((*argv) && (strcasecmp(*argv, "-lrecl") == 0)) { argv++; // skip -lrecl if (*argv) lrecl = atoi(*argv++); // lrecl value if (debug) fprintf(stderr, "LRECL %d\n", lrecl); } dadsm->f1buf.ds1lrecl[0] = lrecl >> 8; // for fbcopy dadsm->f1buf.ds1lrecl[1] = lrecl - ((lrecl >> 8) << 8); if ((*argv) && (strcasecmp(*argv, "-heads") == 0)) { argv++; // skip -heads if (*argv) heads = atoi(*argv++); // heads value } if (debug) fprintf(stderr, "HEADS %d\n", heads); if ((*argv) && (strcasecmp(*argv, "-abs") == 0)) { absvalid = 1; // CCHH valid while ((*argv) && (strcasecmp(*argv, "-abs") == 0)) { argv++; // skip -abs abscyl = 0; abshead = 0; abstrk = 1; // defaults if (*argv) abscyl = atoi(*argv++); // abs cc if (*argv) abshead = atoi(*argv++); // abs hh if (*argv) abstrk = atoi(*argv++); // abs tracks // Build extent entry for -abs group makext(extnum, heads, (DSXTENT *) &dadsm->f1ext, abscyl, abshead, abstrk); extnum++; dadsm->f1buf.ds1noepv = extnum; // for fbcopy if (debug) fprintf(stderr, "Absolute CC %d HH %d tracks %d\n", abscyl, abshead, abstrk); if (extnum > MAX_EXTENTS) { fprintf(stderr, "Too many extents, abort\n"); exit(3); } } // if (debug) sayext(MAX_EXTENTS, dadsm->f1ext);// show extent table } if (debug) { fprintf(stderr, "parsecmd completed F1 DSCB\n"); data_dump(&dadsm->f1buf, sizeof(FORMAT1_DSCB)); } if (*argv) argdsn = *argv++; // [MVS dataset name/]output filename if (debug) fprintf(stderr, "DSN %s\n", argdsn); if ((*argv) && ( // support deprecated 'ascii' operand (strcasecmp(*argv, "ascii") == 0) || (strcasecmp(*argv, "-ascii") == 0) ) ) { argv++; tran_ascii = 1; if (debug) fprintf(stderr, "ASCII translation enabled\n"); } set_verbose_util(0); // default util verbosity if ((*argv) && (strcasecmp(*argv, "verbose") == 0)) { local_verbose = 1; argv++; if (*argv) local_verbose = atoi(*argv++); if (*argv) copy_verbose = atoi(*argv++); if (*argv) { util_verbose = atoi(*argv++); set_verbose_util(util_verbose); if (debug) fprintf(stderr, "Utility verbose %d\n", util_verbose); } } // If the user specified expert mode without -abs, give help & exit // Additionally, if the user has "extra" parms, show help & exit // No "extraneous parms" message is issued, since some of the code // above forces *argv to be true when it wants help displayed if ((argc < 3) || (*argv) || ((expert) && (!absvalid))) { showhelp(); // show syntax before bailing exit(2); } return 0; } /* parsecmd */ //---------------------------------------------------------------------------------- // getlabel - retrieve label record from dasd volume image //---------------------------------------------------------------------------------- // // Input: // cif ptr to opened CIFBLK of dasd image // glbuf ptr to 80 byte buffer provided by caller // verbose 0 = no status messages // 1 = status messages // > 1 debugging messages // // Output: // glbuf dasd volume label record // // Returns: 0 OK, else error // // Notes: // The volume label record always resides at CCHHR 0000 0000 03. // The dasd volume label record contains the CCHHR of the VTOC. // The volume label record is copied to the caller's buffer. //---------------------------------------------------------------------------------- int getlabel( CIFBLK *cif, DASD_VOL_LABEL *glbuf, int verbose) { int len, rc; void *plabel; if (verbose) fprintf(stderr, "getlabel reading volume label\n"); rc = read_block(cif, 0, 0, 3, NULL, NULL, (void *) &plabel, &len); if (rc) { fprintf(stderr, "getlabel error reading volume label, rc %d\n", rc); return 1; } if (len != sizeof(DASD_VOL_LABEL)) { fprintf(stderr, "getlabel error: volume label %d, not 80 bytes long\n", len); return 2; } memcpy((void *)glbuf, plabel, sizeof(DASD_VOL_LABEL)); if (verbose > 1) { fprintf(stderr, "getlabel volume label\n"); data_dump(glbuf, len); } return 0; } /* getlabel */ //---------------------------------------------------------------------------------- // getF4dscb - retrieve Format 4 DSCB - VTOC self-descriptor record //---------------------------------------------------------------------------------- // // Input: // cif ptr to opened CIFBLK of dasd image containing dataset // f4dscb ptr to F4 DSCB buffer (key & data) // volrec ptr to buffer containing volume label rec // vtocx ptr to VTOC extent array (one extent only) // verbose 0 = no status messages // 1 = status messages // > 1 debugging messages // // Output: // f4buf F4 DSCB in buffer (44 byte key, 96 bytes of data) // vtocx VTOC extent array updated // // Returns: 0 OK, else error // // Notes: // There should only be one F4 DSCB in the VTOC, and it should always be // the first record in the VTOC. The F4 provides VTOC extent information, // anchors free space DSCBs, and provides information about the device on // which the VTOC resides. //---------------------------------------------------------------------------------- int getF4dscb( CIFBLK *cif, FORMAT4_DSCB *f4dscb, DASD_VOL_LABEL *volrec, DSXTENT *vtocx, int verbose) { char vtockey[sizeof(f4dscb->ds4keyid)]; void *f4key, *f4data; int f4kl, f4dl; int cyl, head, rec, rc; // Extract VTOC's CCHHR from volume label cyl = (volrec->volvtoc[0] << 8) | volrec->volvtoc[1]; head = (volrec->volvtoc[2] << 8) | volrec->volvtoc[3]; rec = volrec->volvtoc[4]; if (verbose > 1) fprintf(stderr, "getF4dscb VTOC F4 at cyl %d head %d rec %d\n", cyl, head, rec); // Read VTOC's Format 4 DSCB (VTOC self-descriptor) if (verbose) fprintf(stderr, "getF4dscb reading VTOC F4 DSCB\n"); rc = read_block(cif, cyl, head, rec, (void *) &f4key, &f4kl, (void *) &f4data, &f4dl); if (rc) { fprintf(stderr, "getF4dscb error reading F4 DSCB, rc %d\n", rc); return 1; } // Verify correct key and data length if ((f4kl != sizeof(f4dscb->ds4keyid)) || (f4dl != (sizeof(FORMAT4_DSCB) - sizeof(f4dscb->ds4keyid)))) { fprintf(stderr, "getF4dscb erroneous key length %d or data length %d\n", f4kl, f4dl); return 2; } // Return data to caller memcpy((void *) &f4dscb->ds4keyid, f4key, f4kl); // copy F4 key into buffer memcpy((void *) &f4dscb->ds4fmtid, f4data, f4dl); // copy F4 data into buffer memcpy((void *) vtocx, (void *)&f4dscb->ds4vtoce, sizeof(f4dscb->ds4vtoce)); // copy VTOC extent entry if (verbose > 1) { fprintf(stderr, "getF4dscb F4 DSCB\n"); data_dump((void *) f4dscb, sizeof(FORMAT4_DSCB)); } // Verify DS4FMTID byte = x'F4', DS4KEYID key = x'04', and DS4NOEXT = x'01' // Do this after copying data to caller's buffer so we can use struct fields // rather than having to calculate offset to verified data; little harm done // if it doesn't verify since we're toast if they're bad. memset(vtockey, 0x04, sizeof(vtockey)); if ((f4dscb->ds4fmtid != 0xf4) || (f4dscb->ds4noext != 0x01) || (memcmp(&f4dscb->ds4keyid, vtockey, sizeof(vtockey)))) { fprintf(stderr, "getF4dscb " "VTOC format id byte invalid (DS4IDFMT) %2.2X, \n" "VTOC key invalid, or multi-extent VTOC\n", f4dscb->ds4fmtid); return 3; } // Display VTOC extent info (always one extent, never more) if (verbose > 1) { fprintf (stderr, "getF4dscb " "VTOC start CCHH=%2.2X%2.2X %2.2X%2.2X " "end CCHH=%2.2X%2.2X %2.2X%2.2X\n", vtocx->xtbcyl[0], vtocx->xtbcyl[1], vtocx->xtbtrk[0], vtocx->xtbtrk[1], vtocx->xtecyl[0], vtocx->xtecyl[1], vtocx->xtetrk[0], vtocx->xtetrk[1]); } return 0; } /* getF4dscb */ //---------------------------------------------------------------------------------- // getF1dscb - retrieve Format 1 DSCB //---------------------------------------------------------------------------------- // // Input: // cif ptr to opened CIFBLK of dasd image containing dataset // zdsn ASCII null-terminated dataset name // f1dscb ptr to F1 DSCB buffer (key & data) // vtocext ptr to VTOC's extent info // verbose 0 = no status messages // 1 = status messages // > 1 debugging messages // // Output: // f1buf F1 DSCB (44 byte key, 96 byte data) // // Returns: 0 OK, else error // // Notes: The F1 DSCB describes the MVS dataset's physical and logical attributes // such as RECFM, LRECL, BLKSIZE, and where on the volume the dataset // resides (the extent information). The first 3 possible extents are // described in the F1 DSCB. If additional extents are allocated, they // are described by F3 DSCBs referred to by the F1 DSCB. //---------------------------------------------------------------------------------- int getF1dscb( CIFBLK *cif, char *pdsn[], FORMAT1_DSCB *f1dscb, DSXTENT *vtocext[], int verbose) { char zdsn[sizeof(f1dscb->ds1dsnam) + 1]; // zASCII dsn BYTE edsn[sizeof(f1dscb->ds1dsnam)]; // EBCDIC dsn void *f1key, *f1data; int f1kl, f1dl; int cyl, head, rec, rc; int vtocextents = 1; // VTOC has only one extent // Locate dataset's F1 DSCB memset(zdsn, 0, sizeof(zdsn)); strncpy(zdsn, *pdsn, sizeof(zdsn) - 1); string_to_upper(zdsn); convert_to_ebcdic(edsn, sizeof(edsn), zdsn); if (verbose) fprintf(stderr, "getF1dscb searching VTOC for %s\n", zdsn); rc = search_key_equal(cif, edsn, sizeof(edsn), vtocextents, (DSXTENT *)vtocext, &cyl, &head, &rec); if (rc) { fprintf(stderr, "getF1dscb search_key_equal rc %d\n", rc); if (verbose) { fprintf(stderr, "getF1dscb key\n"); data_dump(edsn, sizeof(edsn)); } if (rc == 1) fprintf(stderr, "getF1dscb no DSCB found for %s\n", zdsn); return 1; } // Read F1 DSCB describing dataset if (verbose) fprintf(stderr, "getF1dscb reading F1 DSCB\n"); rc = read_block(cif, cyl, head, rec, (void *)&f1key, &f1kl, (void *) &f1data, &f1dl); if (rc) { fprintf(stderr, "getF1dscb error reading F1 DSCB, rc %d\n", rc); return 2; } // Return data to caller if ((f1kl == sizeof(f1dscb->ds1dsnam)) && (f1dl == (sizeof(FORMAT1_DSCB) - sizeof(f1dscb->ds1dsnam)))) { memcpy((void *) &f1dscb->ds1dsnam, f1key, f1kl); // copy F1 key to buffer memcpy((void *) &f1dscb->ds1fmtid, f1data, f1dl); // copy F1 data to buffer } else { fprintf(stderr, "getF1dscb bad key %d or data length %d\n", f1kl, f1dl); return 3; } if (verbose > 1) { fprintf(stderr, "getF1dscb F1 DSCB\n"); data_dump((void *) f1dscb, sizeof(FORMAT1_DSCB)); } // Verify DS1FMTID byte = x'F1' // Do this after copying data to caller's buffer so we can use struct fields // rather than having to calculate offset to verified data; little harm done // if it doesn't verify since we're toast if it's bad. if (f1dscb->ds1fmtid != 0xf1) { fprintf(stderr, "getF1dscb " "F1 DSCB format id byte invalid (DS1IDFMT) %2.2X\n", f1dscb->ds1fmtid); return 4; } return 0; } /* getF1dscb */ //---------------------------------------------------------------------------------- // getF3dscb - Retrieve Format 3 DSCB //---------------------------------------------------------------------------------- // // Input: // cif ptr to opened CIFBLK of dasd image containing dataset // f3cchhr CCHHR of F3 DSCB to be read (key & data) // f3dscb ptr to F3 DSCB buffer // verbose 0 = no status messages // 1 = status messages // > 1 debugging messages // // Output: // f3buf F3 DSCB (44 byte key, 96 byte data) // // Returns: 0 OK, else error // // Notes: The F3 DSCB describes additional dataset extents beyond those // described by the F1 DSCB. Each F3 DSCB describes 13 extents. // Physical sequential datasets are limited to 16 extents on each // volume, extended format datasets are limited to 123 extents on // each volume. Dasdseq doesn't provide explicit support for // multi-volume datasets. // // Note there is extent information embedded in the key. // // If you want support for > 16 extents, you will have to recompile // dasdseq after changing MAX_EXTENTS. // // Warning: I haven't tested the "chase the F3 chain" code, as I have no // reasonable way to do so. The highest level of MVS I can run under // Hercules is MVS38j. //---------------------------------------------------------------------------------- int getF3dscb( CIFBLK *cif, BYTE *f3cchhr, FORMAT3_DSCB *f3dscb, int verbose) { int cyl, head, rec, rc; void *f3key, *f3data; int f3kl, f3dl; cyl = (f3cchhr[0] << 8) | f3cchhr[1]; head = (f3cchhr[2] << 8) | f3cchhr[3]; rec = f3cchhr[4]; if (verbose) fprintf(stderr, "getF3dscb reading F3 DSCB " "cyl %d head %d rec %d\n", cyl, head, rec); rc = read_block (cif, cyl, head, rec, (void *)&f3key, &f3kl, (void *)&f3data, &f3dl); if (rc) { fprintf(stderr, "getF3dscb error reading F3 DSCB, rc %d\n", rc); return 1; } if ((f3kl != 44) || (f3dl != 96)) { fprintf(stderr, "getF3dscb bad key %d or data %d length\n", f3kl, f3dl); return 2; } memcpy((void *) &f3dscb->ds3keyid, f3key, f3kl); // copy F3 key to buffer memcpy((void *) ((BYTE*)f3dscb + f3kl), f3data, f3dl); // copy F3 data to buffer if (verbose > 1) { fprintf(stderr, "getF3dscb F3 DSCB\n"); data_dump((void *) f3dscb, sizeof(FORMAT3_DSCB)); } // Verify DS3FMTID byte = x'F3' // Do this after copying data to caller's buffer so we can use struct fields // rather than having to calculate offset to verified data; little harm done // if it doesn't verify since we're toast if it's bad. if (f3dscb->ds3fmtid != 0xf3) { fprintf(stderr, "getF3dscb " "F3 DSCB format id byte invalid (DS3IDFMT) %2.2X\n", f3dscb->ds3fmtid); return 2; } return 0; } /* getF3dscb */ //---------------------------------------------------------------------------------- // dadsm_setup - retrieve volume label & DSCBs sufficient to describe dataset //---------------------------------------------------------------------------------- // // This routine reads the volume label rec, the VTOC F4 DSCB, the F1 DSCB // for the dataset, and any F3 DSCB(s) associated with the dataset. // Constructs extent array describing space allocated to the dataset. // // Input: // cif ptr to opened CIFBLK of dasd image containing dataset // pdsn ptr to ASCII null-terminated dataset name // dadsm ptr to DADSM workarea // verbose 0 = no status messages // 1 = status messages // > 1 debugging messages // // Output: // dadsm DADSM workarea // // Returns: 0 OK, else error // // Notes: //---------------------------------------------------------------------------------- int dadsm_setup( CIFBLK *cif, char *pdsn[], DADSM *dadsm, int verbose) { DSXTENT *f1x; BYTE *pcchhr; int numx = MAX_EXTENTS; // # extent slots available int rc; // Read dasd volume label record rc = getlabel(cif, &dadsm->volrec, verbose); if (rc) return rc; // Read F4 DSCB, save VTOC extent info rc = getF4dscb(cif, &dadsm->f4buf, &dadsm->volrec, &dadsm->f4ext, verbose); if (rc) return rc; // Read F1 DSCB, save first three extents from F1 DSCB rc = getF1dscb(cif, pdsn, &dadsm->f1buf, (void *)&dadsm->f4ext, verbose); if (rc) return rc; f1x = &dadsm->f1ext[0]; // @ extent # 0 numx -= 3; // will use 3 slots (if available) if (numx < 0) { fprintf(stderr, "dadsm_setup exhausted extent slots\n"); return 1; } memcpy(f1x, &dadsm->f1buf.ds1ext1, sizeof(DSXTENT) * 3); f1x += 3; // @ extent # 3 dadsm->f1numx = dadsm->f1buf.ds1noepv; // # extents alloc'd to dataset if (dadsm->f1numx < 4) { if (verbose > 1) fprintf(stderr, "dadsm_setup " "no F3 DSCB required, only %d extent(s); all in F1\n", dadsm->f1numx); return 0; } // When more than 3 extents, get additional extent info from F3 DSCB(s). // Chase the F3 chain starting with the CCHHR in the F1, accumulating // extent information for the dataset as we progress. pcchhr = (BYTE *)&dadsm->f1buf.ds1ptrds; // @ F1 ptr to F3 while (pcchhr[0] || pcchhr[1] || pcchhr[2] || pcchhr[3] || pcchhr[4]) { rc = getF3dscb(cif, pcchhr, &dadsm->f3buf, verbose); if (rc) return rc; numx -= 4; // use extent slots if (numx < 0) { fprintf(stderr, "dadsm_setup exhausted extent slots\n"); return 2; } memcpy(f1x, &dadsm->f3buf.ds3extnt[0], sizeof(DSXTENT) * 4); f1x += 4; numx -= 9; // use extent slots if (numx < 0) { fprintf(stderr, "dadsm_setup exhausted extent slots\n"); fprintf(stderr, "Maximum supported extents %d\n", MAX_EXTENTS); return 3; } memcpy(f1x, &dadsm->f3buf.ds3adext[0], sizeof(DSXTENT) * 9); f1x += 9; pcchhr = (BYTE *)&dadsm->f3buf.ds3ptrds; // @ next F3 CCHHR } return 0; } /* dadsm_setup */ //---------------------------------------------------------------------------------- // Main //---------------------------------------------------------------------------------- int main(int argc, char **argv) { DADSM dadsm; // DADSM workarea FILE *fout = NULL; // output file CIFBLK *cif; int dsn_recs_written = 0, bail, dsorg, rc; char pathname[MAX_PATH]; fprintf(stderr, "dasdseq %s (C) Copyright 1999-2010 Roger Bowler\n" "Portions (C) Copyright 2001-2010 James M. Morrison\n", VERSION); if (debug) fprintf(stderr, "DEBUG enabled\n"); // Parse command line memset(&dadsm, 0, sizeof(dadsm)); // init DADSM workarea rc = parsecmd(argc, argv, &dadsm); if (rc) exit(rc); // Open CKD image cif = open_ckd_image(din, sfn, O_RDONLY | O_BINARY, 0); if (!cif) { fprintf(stderr, "dasdseq unable to open image file %s\n", din); exit(20); } // Unless -abs specified (in which case trust the expert user): // Retrieve extent information for the dataset // Display dataset attributes // Verify dataset has acceptable attributes if (!absvalid) { rc = dadsm_setup(cif, &argdsn, &dadsm, local_verbose); if (rc) { close_ckd_image(cif); exit(rc); } if (local_verbose) { fprintf(stderr, "\n"); showf1(stderr, &dadsm.f1buf, dadsm.f1ext, copy_verbose); fprintf(stderr, "\n"); } bail = 1; dsorg = (dadsm.f1buf.ds1dsorg[0] << 8) | (dadsm.f1buf.ds1dsorg[1]); if (dsorg & (DSORG_PS * 256)) { if ((dadsm.f1buf.ds1recfm & RECFM_FORMAT) == RECFM_FORMAT_F) bail = 0; if ((dadsm.f1buf.ds1recfm & RECFM_FORMAT) == RECFM_FORMAT_V) { bail = 1; // not yet fprintf(stderr, "dasdseq only supports RECFM=F[B]\n"); } } else fprintf(stderr, "dasdseq only supports DSORG=PS datasets\n"); if (bail) { close_ckd_image(cif); exit(21); } } // Open output dataset (EBCDIC requires binary open) hostpath(pathname, argdsn, sizeof(pathname)); fout = fopen(pathname, (tran_ascii) ? "wb" : "w"); if (fout == NULL) { fprintf(stderr, "dasdseq unable to open output file %s, %s\n", argdsn, strerror(errno)); close_ckd_image(cif); exit(22); } if (local_verbose) fprintf(stderr, "dasdseq writing %s\n", argdsn); // Write dasd data to output dataset dsn_recs_written = fbcopy(fout, cif, &dadsm, tran_ascii, copy_verbose); if (dsn_recs_written == -1) fprintf(stderr, "dasdseq error processing %s\n", argdsn); else fprintf(stderr, "dasdseq wrote %d records to %s\n", dsn_recs_written, argdsn); // Close output dataset, dasd image and return to caller fclose(fout); if (local_verbose > 2) fprintf(stderr, "CLOSED %s\n", argdsn); if (local_verbose > 3) { fprintf(stderr, "CIFBLK\n"); data_dump((void *) cif, sizeof(CIFBLK)); } close_ckd_image(cif); if (local_verbose > 2) fprintf(stderr, "CLOSED image\n"); return rc; } /* main */ hercules-3.12/dmap2hrc.c0000664000175000017500000001713512564723224012056 00000000000000/* DMAP2HRC.C (c) Copyright Jay Maynard, 2001-2009 */ /* Convert P/390 DEVMAP to Hercules config file */ /*-------------------------------------------------------------------*/ /* This program reads a P/390 DEVMAP file and extracts the device */ /* definitions from it, then writes them to the standard output in */ /* the format Hercules uses for its .cnf file. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /*-------------------------------------------------------------------*/ /* Structure definition for DEVMAP controller record */ /*-------------------------------------------------------------------*/ typedef struct _DEVMAP_CTLR { BYTE channel; /* High order dev addr byte */ BYTE name[8]; /* Name of controller program*/ BYTE lowdev; /* Low addr byte first dev */ BYTE highdev; /* Low addr byte last dev */ BYTE filler1; /* Fill byte */ BYTE type[4]; /* Type of controller */ BYTE flags; /* Flag byte */ BYTE filler2[47]; /* More filler bytes */ } DEVMAP_CTLR; /*-------------------------------------------------------------------*/ /* Structure definition for DEVMAP device record */ /*-------------------------------------------------------------------*/ typedef struct _DEVMAP_DEV { BYTE highaddr; /* High order dev addr byte */ BYTE lowaddr; /* Low order dev addr byte */ char type[4]; /* Type of device */ union { struct { /* Disk devices: */ BYTE filler1[4]; /* filler */ BYTE volser[6]; /* Volume serial */ BYTE filler2[2]; /* more filler */ char filename[45]; /* name of file on disk */ BYTE flags; /* flag byte */ } disk; struct { /* Other devices: */ BYTE filler1[7]; /* fill bytes */ char filename[50]; /* device filename */ BYTE flags; /* flag byte */ } other; } parms; } DEVMAP_DEV; /*-------------------------------------------------------------------*/ /* DEVMAP2CNF main entry point */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int i; /* Array subscript */ int len; /* Length of actual read */ char *filename; /* -> Input file name */ int infd = -1; /* Input file descriptor */ DEVMAP_CTLR controller; /* Controller record */ DEVMAP_DEV device; /* Device record */ char output_type[5]; /* Device type to print */ char *output_filename; /* -> filename to print */ int more_devices; /* More devices this ctlr? */ char pathname[MAX_PATH]; /* file path in host format */ INITIALIZE_UTILITY("dmap2hrc"); /* Display the program identification message */ display_version (stderr, "P/390 DEVMAP to Hercules conversion program\n", FALSE); /* The only argument is the DEVMAP file name */ if (argc == 2 && argv[1] != NULL) { filename = argv[1]; } else { fprintf (stderr,"Usage: dmap2hrc filename\n"); exit (1); } /* Open the devmap file */ hostpath(pathname, filename, sizeof(pathname)); infd = hopen(pathname, O_RDONLY | O_BINARY); if (infd < 0) { fprintf (stderr,"dmap2hrc: Error opening %s: %s\n", filename, strerror(errno)); exit (2); } /* Skip the file header */ for (i = 0; i < 9; i++) { len = read (infd, (void *)&controller, sizeof(DEVMAP_CTLR)); if (len < 0) { fprintf (stderr, "dmap2hrc: error reading header records from %s: %s\n", filename, strerror(errno)); exit (3); } } /* Read records from the input file and convert them */ while (1) { /* Read a controller record. */ len = read (infd, (void *)&controller, sizeof(DEVMAP_CTLR)); if (len < 0) { fprintf (stderr, "dmap2hrc: error reading controller record from %s:" " %s\n", filename, strerror(errno)); exit (4); } /* Did we finish too soon? */ if ((len > 0) && (len < (int)sizeof(DEVMAP_CTLR))) { fprintf (stderr, "dmap2hrc: incomplete controller record on %s\n", filename); exit(5); } /* Check for end of file. */ if (len == 0) { fprintf(stderr, "End of input file.\n"); break; } /* Read devices on this controller. */ more_devices = 1; while (more_devices) { /* Read a device record. */ len = read (infd, (void *)&device, sizeof(DEVMAP_DEV)); if (len < 0) { fprintf (stderr, "dmap2hrc: error reading device record from %s:" " %s\n", filename, strerror(errno)); exit (6); } /* Did we finish too soon? */ if ((len > 0) && (len < (int)sizeof(DEVMAP_DEV))) { fprintf (stderr, "dmap2hrc: incomplete device record on %s\n", filename); exit(7); } /* Check for end of file. */ if (len == 0) { fprintf (stderr,"dmap2hrc: premature end of input file\n"); exit(8); } /* Is this the dummy device record at the end of the controller's set of devices? */ if (strncmp(device.type," ",4) == 0) { more_devices = 0; break; } /* It's a real device. Fix the type so Hercules can use it and locate the output filename. */ strncpy(output_type, device.type, 4); output_type[4] = '\0'; if (isprint(device.parms.disk.volser[0])) output_filename = device.parms.disk.filename; else output_filename = device.parms.other.filename; if (strncmp(device.type, "3278", 4) == 0) { strcpy(output_type, "3270"); output_filename = ""; } if (strncmp(device.type, "2540", 4) == 0) strcpy(output_type, "3505"); /* Emit the Hercules config file entry. */ printf("%02X%02X %s", device.highaddr, device.lowaddr, output_type); if (strlen(output_filename) > 0) printf(" %s", output_filename); puts(""); /* newline */ } /* end while more_devices) */ } /* end while (1) */ /* Close files and exit */ close (infd); return 0; } /* end function main */ hercules-3.12/hercifc.c0000664000175000017500000001653412564723224011763 00000000000000/* HERCIFC.C (c) Copyright Roger Bowler, 2000-2012 */ /* (c) Copyright James A. Pierson, 2002-2009 */ /* Hercules Interface Configuration Program */ // Based on code originally written by Roger Bowler // Modified to communicate via unix sockets. // // This module configures the TUN/TAP interface for Hercules. // It is invoked as a setuid root program by tuntap.c // // The are no command line arguments anymore. // // Error messages are written to stderr, which is redirected to // the Hercules message log by ctcadpt.c // // The exit status is zero if successful, non-zero if error. // #include "hstdinc.h" #if defined(BUILD_HERCIFC) #include "hercules.h" #include "hercifc.h" // -------------------------------------------------------------------- // HERCIFC program entry point // -------------------------------------------------------------------- int main( int argc, char **argv ) { char* pszProgName = NULL; // Name of this program char* pOp = NULL; // Operation text char* pIF = NULL; // -> interface name void* pArg = NULL; // -> ifreq or rtentry CTLREQ ctlreq; // Request Buffer int sockfd; // Socket descriptor int fd; // FD for ioctl int rc; // Return code pid_t ppid; // Parent's PID int answer; // 1 = write answer to stdout char szMsgBuffer[255]; UNREFERENCED( argc ); DROP_PRIVILEGES(CAP_NET_ADMIN); pszProgName = strdup( argv[0] ); // Must not be run from the commandline if( isatty( STDIN_FILENO ) ) { fprintf( stderr, _("HHCIF001E %s: Must be called from within Hercules.\n"), pszProgName ); exit( 1 ); } // Obtain a socket for ioctl operations sockfd = socket( AF_INET, SOCK_DGRAM, 0 ); if( sockfd < 0 ) { fprintf( stderr, _("HHCIF002E %s: Cannot obtain socket: %s\n"), pszProgName, strerror( errno ) ); exit( 2 ); } ppid = getppid(); // Process ioctl messages from Hercules while( 1 ) { rc = read( STDIN_FILENO, &ctlreq, CTLREQ_SIZE ); if( rc == -1 ) { fprintf( stderr, _("HHCIF003E %s: I/O error on read: %s.\n"), pszProgName, strerror( errno ) ); exit( 3 ); } if( ppid != getppid() ) { sleep( 1 ); // Let other messages go first fprintf( stderr, _("HHCIF007E %s: Hercules disappeared!! .. exiting\n"), pszProgName); exit( 4 ); } fd = sockfd; answer = 0; switch( ctlreq.iCtlOp ) { case TUNSETIFF: pOp = "TUNSETIFF"; pArg = &ctlreq.iru.ifreq; pIF = "?"; fd = ctlreq.iProcID; answer = 1; break; case SIOCSIFADDR: pOp = "SIOCSIFADDR"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; case SIOCSIFDSTADDR: pOp = "SIOCSIFDSTADDR"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; case SIOCSIFFLAGS: pOp = "SIOCSIFFLAGS"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; #if 0 /* (hercifc can't "get" information, only "set" it) */ case SIOCGIFFLAGS: pOp = "SIOCGIFFLAGS"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; answer = 1; break; #endif /* (caller should do 'ioctl' directly themselves instead) */ case SIOCSIFMTU: pOp = "SIOCSIFMTU"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; case SIOCADDMULTI: pOp = "SIOCADDMULTI"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; case SIOCDELMULTI: pOp = "SIOCDELMULTI"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; #ifdef OPTION_TUNTAP_SETNETMASK case SIOCSIFNETMASK: pOp = "SIOCSIFNETMASK"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; #endif #ifdef OPTION_TUNTAP_SETMACADDR case SIOCSIFHWADDR: pOp = "SIOCSIFHWADDR"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; #endif #ifdef OPTION_TUNTAP_DELADD_ROUTES case SIOCADDRT: pOp = "SIOCADDRT"; pArg = &ctlreq.iru.rtentry; pIF = ctlreq.szIFName; ctlreq.iru.rtentry.rt_dev = ctlreq.szIFName; break; case SIOCDELRT: pOp = "SIOCDELRT"; pArg = &ctlreq.iru.rtentry; pIF = ctlreq.szIFName; ctlreq.iru.rtentry.rt_dev = ctlreq.szIFName; break; #endif #ifdef OPTION_TUNTAP_CLRIPADDR case SIOCDIFADDR: pOp = "SIOCDIFADDR"; pArg = &ctlreq.iru.ifreq; pIF = ctlreq.iru.ifreq.ifr_name; break; #endif case CTLREQ_OP_DONE: close( STDIN_FILENO ); close( STDOUT_FILENO ); close( STDERR_FILENO ); exit( 0 ); default: snprintf( szMsgBuffer,sizeof(szMsgBuffer), _("HHCIF004W %s: Unknown request: %lX\n"), pszProgName, ctlreq.iCtlOp ); write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) ); continue; } #if defined(DEBUG) || defined(_DEBUG) snprintf( szMsgBuffer,sizeof(szMsgBuffer), _("HHCIF006I %s: Doing %s on %s\n"), pszProgName, pOp, pIF); write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) ); #endif /*defined(DEBUG) || defined(_DEBUG)*/ rc = ioctl( fd, ctlreq.iCtlOp, pArg ); if( rc < 0 ) { if (1 #if defined(SIOCSIFHWADDR) && defined(ENOTSUP) /* Suppress spurious error message */ && !(ctlreq.iCtlOp == SIOCSIFHWADDR && errno == ENOTSUP) #endif #if defined(SIOCDIFADDR) && defined(EINVAL) /* Suppress spurious error message */ && !(ctlreq.iCtlOp == SIOCDIFADDR && errno == EINVAL) #endif #if defined(TUNSETIFF) && defined(EINVAL) /* Suppress spurious error message */ && !(ctlreq.iCtlOp == TUNSETIFF && errno == EINVAL) #endif ) { snprintf( szMsgBuffer,sizeof(szMsgBuffer), _("HHCIF005E %s: ioctl error doing %s on %s: %d %s\n"), pszProgName, pOp, pIF, errno, strerror( errno ) ); write( STDERR_FILENO, szMsgBuffer, strlen( szMsgBuffer ) ); } } else if (answer) { write( STDOUT_FILENO, &ctlreq, CTLREQ_SIZE ); } } // Never reached. return 0; } #endif // defined(BUILD_HERCIFC) hercules-3.12/herclin.c0000664000175000017500000000670312564723224012001 00000000000000/* HERCLIN.C (c) Copyright Ivan Warren, 2005-2009 */ /* Hercules Line Mode Console */ /************************************************/ /* (C) Copyright 2005-2009 Roger Bowler & Others*/ /* Initial author : Ivan Warren */ /* */ /* HERCLIN.C */ /* */ /* THIS IS SAMPLE CODE DEMONSTRATING */ /* THE USE OF THE INITIAL HARDWARE PANEL */ /* INTERFACE FEATURE. */ /************************************************/ #ifdef _MSVC_ #include #include #endif #include #include #include #include "hextapi.h" #if defined(HDL_USE_LIBTOOL) /* This must be included if HDL uses the */ /* libtool ltdl convenience library */ #include "ltdl.h" #endif /**********************************************/ /* The following function is the LOG callback */ /* function. It gets called by the engine */ /* whenever a log message needs to be */ /* displayed. This function may therefore be */ /* invoked from a separate thread */ /* */ /* This simple version simply writes to STDOUT*/ /**********************************************/ #ifdef _MSVC_ static HANDLE hLogCallbackThread = NULL; #endif void mywrite(const char *a,size_t b) { #ifdef _MSVC_ if (!hLogCallbackThread) hLogCallbackThread = OpenThread( SYNCHRONIZE, FALSE, GetCurrentThreadId()); #endif fflush(stdout); fwrite(a,b,1,stdout); fflush(stdout); } int main(int ac,char **av) { /*****************************************/ /* COMMANDHANDLER is the function type */ /* of the engine's panel command handler */ /* this MUST be resolved at run time */ /* since some HDL module might have */ /* redirected the initial engine function*/ /*****************************************/ COMMANDHANDLER ch; char *str,*bfr; #if defined( OPTION_DYNAMIC_LOAD ) && defined( HDL_USE_LIBTOOL ) /* LTDL Preloaded symbols for HDL using libtool */ LTDL_SET_PRELOADED_SYMBOLS(); #endif /******************************************/ /* Register the 'mywrite' function as the */ /* log callback routine */ /******************************************/ registerLogCallback(mywrite); /******************************************/ /* Initialize the HERCULE Engine */ /******************************************/ impl(ac,av); /******************************************/ /* Get the command handler function */ /* This MUST be done after IML */ /******************************************/ ch=getCommandHandler(); /******************************************/ /* Read STDIN and pass to Command Handler */ /******************************************/ bfr=(char *)malloc(1024); while ( #ifdef _MSVC_ !hLogCallbackThread || WaitForSingleObject(hLogCallbackThread,0) != WAIT_OBJECT_0 #else 1 #endif ) { #ifdef _MSVC_ if (!kbhit()) Sleep(50); else #endif if ((str=fgets(bfr,1024,stdin))) { str[strlen(str)-1]=0; ch(str); } } #ifdef _MSVC_ CloseHandle(hLogCallbackThread); #endif return 0; } hercules-3.12/hdlmain.c0000664000175000017500000002350112564723224011764 00000000000000/* HDLMAIN.C (c) Copyright Jan Jaeger, 2003-2010 */ /* Hercules Dynamic Loader */ #include "hstdinc.h" #define _HDLMAIN_C_ #define _HERCULES_EXE_ #include "hercules.h" #include "httpmisc.h" #define CRYPTO_EXTERN extern #include "crypto.h" #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "hdlmain.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "hdlmain.c" #endif #if defined(OPTION_DYNAMIC_LOAD) /* Following block moved to 'hdl.c' */ /* this is so that */ /* hdlmain.c can be moved to the executable portion */ /* hdl_main can find hdl_preload */ /* HDLPRE hdl_preload[] = { { "hdteq", HDL_LOAD_NOMSG }, { "dyncrypt", HDL_LOAD_NOMSG }, #if 0 { "dyn_test1", HDL_LOAD_DEFAULT }, { "dyn_test2", HDL_LOAD_NOMSG }, { "dyn_test3", HDL_LOAD_NOMSG | HDL_LOAD_NOUNLOAD }, #endif { NULL, 0 } }; */ HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(REGS); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); HDL_DEPENDENCY(WEBBLK); } END_DEPENDENCY_SECTION HDL_REGISTER_SECTION; { HDL_REGISTER( parse_args, parse_args ); HDL_REGISTER( panel_command, panel_command_r ); HDL_REGISTER( panel_display, panel_display_r ); HDL_REGISTER( config_command, UNRESOLVED ); HDL_REGISTER( system_command, UNRESOLVED ); HDL_REGISTER( daemon_task, UNRESOLVED ); HDL_REGISTER( debug_cpu_state, UNRESOLVED ); HDL_REGISTER( debug_cd_cmd, UNRESOLVED ); HDL_REGISTER( debug_device_state, UNRESOLVED ); HDL_REGISTER( debug_program_interrupt, UNRESOLVED ); HDL_REGISTER( debug_diagnose, UNRESOLVED ); HDL_REGISTER( debug_iucv, UNRESOLVED ); HDL_REGISTER( debug_sclp_unknown_command, UNRESOLVED ); HDL_REGISTER( debug_sclp_unknown_event, UNRESOLVED ); HDL_REGISTER( debug_sclp_unknown_event_mask, UNRESOLVED ); HDL_REGISTER( debug_sclp_event_data, UNRESOLVED ); HDL_REGISTER( debug_chsc_unknown_request, UNRESOLVED ); HDL_REGISTER( debug_watchdog_signal, UNRESOLVED ); #if defined(OPTION_W32_CTCI) HDL_REGISTER( debug_tt32_stats, UNRESOLVED ); HDL_REGISTER( debug_tt32_tracing, UNRESOLVED ); #endif HDL_REGISTER( hdl_device_type_equates, UNRESOLVED ); #if defined(_390_FEATURE_MESSAGE_SECURITY_ASSIST) HDL_REGISTER( s390_cipher_message, UNRESOLVED ); HDL_REGISTER( s390_cipher_message_with_chaining, UNRESOLVED ); HDL_REGISTER( s390_compute_message_digest, UNRESOLVED ); HDL_REGISTER( s390_compute_message_authentication_code, UNRESOLVED ); #endif /*defined(_390_FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(_900_FEATURE_MESSAGE_SECURITY_ASSIST) HDL_REGISTER( z900_cipher_message, UNRESOLVED ); HDL_REGISTER( z900_cipher_message_with_chaining, UNRESOLVED ); HDL_REGISTER( z900_compute_message_digest, UNRESOLVED ); HDL_REGISTER( z900_compute_message_authentication_code, UNRESOLVED ); #endif /*defined(_900_FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(_390) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) HDL_REGISTER( s390_perform_cryptographic_key_management_operation, UNRESOLVED ); #endif #if defined(_900) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) HDL_REGISTER( z900_perform_cryptographic_key_management_operation, UNRESOLVED ); #endif #if defined(_390) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) HDL_REGISTER( s390_cipher_message_with_cipher_feedback, UNRESOLVED ); HDL_REGISTER( s390_cipher_message_with_counter, UNRESOLVED ); HDL_REGISTER( s390_cipher_message_with_output_feedback, UNRESOLVED ); HDL_REGISTER( s390_perform_cryptographic_computation, UNRESOLVED ); #endif #if defined(_390) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) HDL_REGISTER( z900_cipher_message_with_cipher_feedback, UNRESOLVED ); HDL_REGISTER( z900_cipher_message_with_counter, UNRESOLVED ); HDL_REGISTER( z900_cipher_message_with_output_feedback, UNRESOLVED ); HDL_REGISTER( z900_perform_cryptographic_computation, UNRESOLVED ); #endif } END_REGISTER_SECTION HDL_RESOLVER_SECTION; { HDL_RESOLVE( panel_command ); HDL_RESOLVE( panel_display ); HDL_RESOLVE( config_command ); HDL_RESOLVE( system_command ); HDL_RESOLVE( daemon_task ); HDL_RESOLVE( debug_cpu_state ); HDL_RESOLVE( debug_cd_cmd ); HDL_RESOLVE( debug_device_state ); HDL_RESOLVE( debug_program_interrupt ); HDL_RESOLVE( debug_diagnose ); HDL_RESOLVE( debug_sclp_unknown_command ); HDL_RESOLVE( debug_sclp_unknown_event ); HDL_RESOLVE( debug_sclp_unknown_event_mask ); HDL_RESOLVE( debug_sclp_event_data ); HDL_RESOLVE( debug_chsc_unknown_request ); #if defined(OPTION_W32_CTCI) HDL_RESOLVE( debug_tt32_stats ); HDL_RESOLVE( debug_tt32_tracing ); #endif HDL_RESOLVE( hdl_device_type_equates ); #if defined(_390_FEATURE_MESSAGE_SECURITY_ASSIST) HDL_RESOLVE( s390_cipher_message ); HDL_RESOLVE( s390_cipher_message_with_chaining ); HDL_RESOLVE( s390_compute_intermediate_message_digest ); HDL_RESOLVE( s390_compute_last_message_digest ); HDL_RESOLVE( s390_compute_message_authentication_code ); #endif /*defined(_390_FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(_900_FEATURE_MESSAGE_SECURITY_ASSIST) HDL_RESOLVE( z900_cipher_message ); HDL_RESOLVE( z900_cipher_message_with_chaining ); HDL_RESOLVE( z900_compute_intermediate_message_digest ); HDL_RESOLVE( z900_compute_last_message_digest ); HDL_RESOLVE( z900_compute_message_authentication_code ); #endif /*defined(_900_FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(_390) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) HDL_RESOLVE( s390_perform_cryptographic_key_management_operation ); #endif #if defined(_900) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) HDL_RESOLVE( z900_perform_cryptographic_key_management_operation ); #endif #if defined(_390) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) HDL_RESOLVE( s390_cipher_message_with_cipher_feedback ); HDL_RESOLVE( s390_cipher_message_with_counter ); HDL_RESOLVE( s390_cipher_message_with_output_feedback ); HDL_RESOLVE( s390_perform_cryptographic_computation ); #endif #if defined(_390) && defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) HDL_RESOLVE( z900_cipher_message_with_cipher_feedback ); HDL_RESOLVE( z900_cipher_message_with_counter ); HDL_RESOLVE( z900_cipher_message_with_output_feedback ); HDL_RESOLVE( z900_perform_cryptographic_computation ); #endif } END_RESOLVER_SECTION HDL_FINAL_SECTION; { system_cleanup(); } END_FINAL_SECTION #endif /*defined(OPTION_DYNAMIC_LOAD)*/ HDL_DEVICE_SECTION; { #if !defined(OPTION_DYNAMIC_LOAD) /* TTY consoles */ HDL_DEVICE(1052, constty_device_hndinfo ); HDL_DEVICE(3215, constty_device_hndinfo ); /* 3270 consoles */ HDL_DEVICE(3270, loc3270_device_hndinfo ); HDL_DEVICE(3287, loc3270_device_hndinfo ); /* Communication line devices */ HDL_DEVICE(2703, comadpt_device_hndinfo ); /* Card readers */ HDL_DEVICE(1442, cardrdr_device_hndinfo ); HDL_DEVICE(2501, cardrdr_device_hndinfo ); HDL_DEVICE(3505, cardrdr_device_hndinfo ); /* Card punches */ HDL_DEVICE(3525, cardpch_device_hndinfo ); /* Printers */ HDL_DEVICE(1403, printer_device_hndinfo ); HDL_DEVICE(3211, printer_device_hndinfo ); /* Tape drives */ HDL_DEVICE(3410, tapedev_device_hndinfo ); HDL_DEVICE(3411, tapedev_device_hndinfo ); HDL_DEVICE(3420, tapedev_device_hndinfo ); HDL_DEVICE(3480, tapedev_device_hndinfo ); HDL_DEVICE(3490, tapedev_device_hndinfo ); HDL_DEVICE(9347, tapedev_device_hndinfo ); HDL_DEVICE(9348, tapedev_device_hndinfo ); HDL_DEVICE(8809, tapedev_device_hndinfo ); HDL_DEVICE(3422, tapedev_device_hndinfo ); HDL_DEVICE(3430, tapedev_device_hndinfo ); /* Communications devices */ HDL_DEVICE(3088, ctcadpt_device_hndinfo ); HDL_DEVICE(CTCI, ctci_device_hndinfo ); HDL_DEVICE(CTCT, ctct_device_hndinfo ); HDL_DEVICE(CTCE, ctce_device_hndinfo ); HDL_DEVICE(LCS, lcs_device_hndinfo ); HDL_DEVICE(VMNET,vmnet_device_hndinfo ); #if defined(WIN32) HDL_DEVICE(CTCI-W32, ctci_device_hndinfo); #endif /*defined(WIN32)*/ #endif /*!defined(OPTION_DYNAMIC_LOAD)*/ /* Count Key Data Direct Access Storage Devices */ HDL_DEVICE(2305, ckddasd_device_hndinfo ); HDL_DEVICE(2311, ckddasd_device_hndinfo ); HDL_DEVICE(2314, ckddasd_device_hndinfo ); HDL_DEVICE(3330, ckddasd_device_hndinfo ); HDL_DEVICE(3340, ckddasd_device_hndinfo ); HDL_DEVICE(3350, ckddasd_device_hndinfo ); HDL_DEVICE(3375, ckddasd_device_hndinfo ); HDL_DEVICE(3380, ckddasd_device_hndinfo ); HDL_DEVICE(3390, ckddasd_device_hndinfo ); HDL_DEVICE(9345, ckddasd_device_hndinfo ); /* Fixed Block Architecture Direct Access Storage Devices */ HDL_DEVICE(0671, fbadasd_device_hndinfo ); HDL_DEVICE(3310, fbadasd_device_hndinfo ); HDL_DEVICE(3370, fbadasd_device_hndinfo ); HDL_DEVICE(9313, fbadasd_device_hndinfo ); HDL_DEVICE(9332, fbadasd_device_hndinfo ); HDL_DEVICE(9335, fbadasd_device_hndinfo ); HDL_DEVICE(9336, fbadasd_device_hndinfo ); } END_DEVICE_SECTION #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/bootstrap.c0000664000175000017500000003730512564723224012374 00000000000000/* BOOTSTRAP.C (c) Copyright Ivan Warren, 2003-2009 */ /* (c) Copyright "Fish" (David B. Trout), 2005-2009 */ /* Hercules executable main module */ /*-------------------------------------------------------------------*/ /* This module is the initial entry point of the Hercules emulator. */ /* The main() function performs platform-specific functions before */ /* calling the impl function which launches the emulator. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #if defined(HDL_USE_LIBTOOL) #include "ltdl.h" #endif #if !defined( _MSVC_ ) /*-------------------------------------------------------------------*/ /* For Unix-like platforms, the main() function: */ /* - sets the privilege level */ /* - initializes the LIBTOOL environment */ /* - passes control to the impl() function in impl.c */ /*-------------------------------------------------------------------*/ int main(int ac,char *av[]) { DROP_PRIVILEGES(CAP_SYS_NICE); SET_THREAD_NAME("bootstrap"); #if defined( OPTION_DYNAMIC_LOAD ) && defined( HDL_USE_LIBTOOL ) LTDL_SET_PRELOADED_SYMBOLS(); #endif exit(impl(ac,av)); } #else // defined( _MSVC_ ) /*-------------------------------------------------------------------*/ /* For Windows platforms, the main() function: */ /* - disables the standard CRT invalid parameter handler */ /* - requests a minimum resolution for periodic timers */ /* - sets up an exception trap */ /* - passes control to the impl() function in impl.c */ /* */ /* The purpose of the exception trap is to call a function which */ /* will write a minidump file in the event of a Hercules crash. */ /*-------------------------------------------------------------------*/ #pragma optimize( "", off ) typedef BOOL (MINIDUMPWRITEDUMPFUNC) ( HANDLE hProcess, DWORD ProcessId, HANDLE hDumpFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam ); static MINIDUMPWRITEDUMPFUNC* g_pfnMiniDumpWriteDumpFunc = NULL; static HMODULE g_hDbgHelpDll = NULL; // Global string buffers to prevent C4748 warning: "/GS can not protect // parameters and local variables from local buffer overrun because // optimizations are disabled in function" static WCHAR g_wszHercDrive [ 4 * _MAX_DRIVE ] = {0}; static WCHAR g_wszHercDir [ 4 * _MAX_DIR ] = {0}; static WCHAR g_wszFileDir [ 4 * _MAX_DIR ] = {0}; static WCHAR g_wszHercPath [ 4 * _MAX_PATH ] = {0}; static WCHAR g_wszDumpPath [ 4 * _MAX_PATH ] = {0}; static WCHAR g_wszFileName [ 4 * _MAX_FNAME ] = {0}; static TCHAR g_szSaveTitle[ 512 ] = {0}; static LPCTSTR g_pszTempTitle = _T("{98C1C303-2A9E-11d4-9FF5-0060677l8D04}"); // (forward reference) static void ProcessException( EXCEPTION_POINTERS* pExceptionPtrs ); static HWND FindConsoleHandle(); // (helper macro) #ifndef ARRAYSIZE #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) #endif /////////////////////////////////////////////////////////////////////////////// #include #pragma comment( lib, "Winmm" ) int main(int ac,char *av[]) { int rc = 0; SET_THREAD_NAME("bootstrap"); // Disable default invalid crt parameter handling DISABLE_CRT_INVALID_PARAMETER_HANDLER(); // Request the highest possible time-interval accuracy... timeBeginPeriod( 1 ); // (one millisecond time interval accuracy) EnableMenuItem( GetSystemMenu( FindConsoleHandle(), FALSE ), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED ); // If we're being debugged, then let the debugger // catch the exception. Otherwise, let our exception // handler catch it... if ( IsDebuggerPresent() ) // (are we being debugged?) { rc = impl(ac,av); // (yes, let debugger catch the exception) } else // (not being debugged; use our exception handler) { if (1 && (g_hDbgHelpDll = LoadLibrary(_T("DbgHelp.dll"))) && (g_pfnMiniDumpWriteDumpFunc = (MINIDUMPWRITEDUMPFUNC*) GetProcAddress( g_hDbgHelpDll, _T("MiniDumpWriteDump"))) ) { GetModuleFileNameW( NULL, g_wszHercPath, ARRAYSIZE(g_wszHercPath) ); _wsplitpath( g_wszHercPath, g_wszHercDrive, g_wszHercDir, NULL, NULL ); } SetErrorMode( SEM_NOGPFAULTERRORBOX ); __try { rc = impl(ac,av); // (Hercules, do your thing!) } __except ( fflush(stdout), fflush(stderr), _ftprintf( stderr, _T("]!OOPS!\n") ), fflush(stdout), fflush(stderr), Sleep(10), _tprintf( _T("\n\n") ), _tprintf( _T(" ***************\n") ), _tprintf( _T(" * OOPS! *\n") ), _tprintf( _T(" ***************\n") ), _tprintf( _T("\n") ), _tprintf( _T(" Hercules has crashed!\n") ), _tprintf( _T("\n") ), _tprintf( _T("(you may need to press ENTER if no 'oops!' dialog-box appears)\n") ), _tprintf( _T("\n") ), ProcessException( GetExceptionInformation() ), EXCEPTION_EXECUTE_HANDLER ) { rc = -1; // (indicate error) } } // Each call to "timeBeginPeriod" must be matched with a call to "timeEndPeriod" timeEndPeriod( 1 ); // (no longer care about accurate time intervals) EnableMenuItem( GetSystemMenu( FindConsoleHandle(), FALSE ), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED ); return rc; } /////////////////////////////////////////////////////////////////////////////// static HWND FindConsoleHandle() { HWND hWnd; if (!GetConsoleTitle(g_szSaveTitle,ARRAYSIZE(g_szSaveTitle))) return NULL; if (!SetConsoleTitle(g_pszTempTitle)) return NULL; Sleep(20); hWnd = FindWindow(NULL,g_pszTempTitle); SetConsoleTitle(g_szSaveTitle); return hWnd; } /////////////////////////////////////////////////////////////////////////////// static BOOL CreateMiniDump( EXCEPTION_POINTERS* pExceptionPtrs ); static void ProcessException( EXCEPTION_POINTERS* pExceptionPtrs ) { UINT uiMBFlags = 0 | MB_SYSTEMMODAL | MB_TOPMOST | MB_SETFOREGROUND ; HWND hwndMBOwner = FindConsoleHandle(); if (!hwndMBOwner || !IsWindowVisible(hwndMBOwner)) hwndMBOwner = GetDesktopWindow(); if ( !g_pfnMiniDumpWriteDumpFunc ) { MessageBox ( hwndMBOwner, _T("The creation of a crash dump for analysis by the Hercules ") _T("development team is NOT possible\nbecause the required 'DbgHelp.dll' ") _T("is missing or is not installed or was otherwise not located.") ,_T("OOPS! Hercules has crashed!"), uiMBFlags | MB_ICONERROR | MB_OK ); return; } if ( IDYES == MessageBox ( hwndMBOwner, _T("The creation of a crash dump for further analysis by ") _T("the Hercules development team is strongly suggested.\n\n") _T("Would you like to create a crash dump for ") _T("the Hercules development team to analyze?") ,_T("OOPS! Hercules has crashed!"), uiMBFlags | MB_ICONERROR | MB_YESNO )) { if ( CreateMiniDump( pExceptionPtrs ) ) { MessageBox ( hwndMBOwner, _T("Please send the dump to the Hercules development team for analysis.") ,_T("Dump Complete"), uiMBFlags | MB_ICONEXCLAMATION | MB_OK ); } } } /////////////////////////////////////////////////////////////////////////////// // The following CreateMiniDump functions are based on // Oleg Starodumov's sample at http://www.debuginfo.com static void BuildUserStreams( MINIDUMP_USER_STREAM_INFORMATION* pMDUSI ); static BOOL CALLBACK MyMiniDumpCallback // (fwd ref) ( PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput ); static BOOL CreateMiniDump( EXCEPTION_POINTERS* pExceptionPtrs ) { BOOL bSuccess = FALSE; HANDLE hDumpFile; _wmakepath( g_wszDumpPath, g_wszHercDrive, g_wszHercDir, L"Hercules", L".dmp" ); _tprintf( _T("Creating crash dump \"%ls\"...\n"), g_wszDumpPath ); _tprintf( _T("Please wait; this may take a few minutes...\n") ); _tprintf( _T("(another message will appear when the dump is complete)\n") ); hDumpFile = CreateFileW ( g_wszDumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hDumpFile && INVALID_HANDLE_VALUE != hDumpFile ) { // Create the minidump MINIDUMP_EXCEPTION_INFORMATION mdei; MINIDUMP_USER_STREAM_INFORMATION mdusi; MINIDUMP_CALLBACK_INFORMATION mci; MINIDUMP_TYPE mdt; BuildUserStreams( &mdusi ); mdei.ThreadId = GetCurrentThreadId(); mdei.ExceptionPointers = pExceptionPtrs; mdei.ClientPointers = FALSE; mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE) MyMiniDumpCallback; mci.CallbackParam = 0; mdt = (MINIDUMP_TYPE) (0 | MiniDumpWithPrivateReadWriteMemory | MiniDumpWithDataSegs | MiniDumpWithHandleData // | MiniDumpWithFullMemoryInfo // | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules ); bSuccess = g_pfnMiniDumpWriteDumpFunc( GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, mdt, (pExceptionPtrs != 0) ? &mdei : 0, &mdusi, &mci ); CloseHandle( hDumpFile ); if ( bSuccess ) { _tprintf( _T("Dump \"%ls\" created.\n"), g_wszDumpPath ); } else _tprintf( _T("MiniDumpWriteDump failed! Error: %u\n"), GetLastError() ); } else { _tprintf( _T("CreateFile failed! Error: %u\n"), GetLastError() ); } return bSuccess; } /////////////////////////////////////////////////////////////////////////////// // Build User Stream Arrays... #define MAX_MINIDUMP_USER_STREAMS (64) static char g_host_info_str [ 1024 ]; static MINIDUMP_USER_STREAM UserStreamArray [ MAX_MINIDUMP_USER_STREAMS ]; static void BuildUserStreams( MINIDUMP_USER_STREAM_INFORMATION* pMDUSI ) { const char** ppszBldInfoStr; int nNumBldInfoStrs; ULONG UserStreamCount; _ASSERTE( pMDUSI ); get_hostinfo_str( NULL, g_host_info_str, sizeof(g_host_info_str) ); nNumBldInfoStrs = get_buildinfo_strings( &ppszBldInfoStr ); UserStreamCount = min( (3+nNumBldInfoStrs), MAX_MINIDUMP_USER_STREAMS ); pMDUSI->UserStreamCount = UserStreamCount; pMDUSI->UserStreamArray = UserStreamArray; UserStreamCount = 0; if ( UserStreamCount < pMDUSI->UserStreamCount ) { UserStreamArray[UserStreamCount].Type = CommentStreamA; UserStreamArray[UserStreamCount].Buffer = VERSION; UserStreamArray[UserStreamCount].BufferSize = sizeof(VERSION); UserStreamCount++; } if ( UserStreamCount < pMDUSI->UserStreamCount ) { UserStreamArray[UserStreamCount].Type = CommentStreamA; UserStreamArray[UserStreamCount].Buffer = HERCULES_COPYRIGHT; UserStreamArray[UserStreamCount].BufferSize = sizeof(HERCULES_COPYRIGHT); UserStreamCount++; } if ( UserStreamCount < pMDUSI->UserStreamCount ) { UserStreamArray[UserStreamCount].Type = CommentStreamA; UserStreamArray[UserStreamCount].Buffer = g_host_info_str; UserStreamArray[UserStreamCount].BufferSize = strlen(g_host_info_str)+1; UserStreamCount++; } for (; nNumBldInfoStrs && UserStreamCount < pMDUSI->UserStreamCount; nNumBldInfoStrs--, UserStreamCount++, ppszBldInfoStr++ ) { UserStreamArray[UserStreamCount].Type = CommentStreamA; UserStreamArray[UserStreamCount].Buffer = (PVOID)*ppszBldInfoStr; UserStreamArray[UserStreamCount].BufferSize = strlen(*ppszBldInfoStr)+1; } } /////////////////////////////////////////////////////////////////////////////// // Custom minidump callback static BOOL IsDataSectionNeeded( const WCHAR* pwszModuleName ); // (fwd ref) static BOOL CALLBACK MyMiniDumpCallback ( PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput ) { BOOL bRet = FALSE; if ( !pInput || !pOutput ) return FALSE; switch ( pInput->CallbackType ) { case IncludeModuleCallback: { // Include the module into the dump bRet = TRUE; } break; case IncludeThreadCallback: { // Include the thread into the dump bRet = TRUE; } break; case ModuleCallback: { // Are data sections available for this module ? if ( pOutput->ModuleWriteFlags & ModuleWriteDataSeg ) { // Yes, but do we really need them? if ( !IsDataSectionNeeded( pInput->Module.FullPath ) ) pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg); } bRet = TRUE; } break; case ThreadCallback: { // Include all thread information into the minidump bRet = TRUE; } break; case ThreadExCallback: { // Include this information bRet = TRUE; } break; /* NOTE About MemoryCallback : * This is defined for DbgHelp > 6.1.. * Since "false" is returned, it has been commented out. * * Additionally, false is now returned by default. This * ensures that the callback function will operate correctly * even with future versions of the DbhHelp DLL. * -- Ivan */ // case MemoryCallback: // { // // We do not include any information here -> return FALSE // bRet = FALSE; // } // break; // Following default block added by ISW 2005/05/06 default: { // Do not return any information for unrecognized // callback types. bRet=FALSE; } break; // case CancelCallback: // break; } return bRet; } /////////////////////////////////////////////////////////////////////////////// // This function determines whether we need data sections of the given module static BOOL IsDataSectionNeeded( const WCHAR* pwszModuleName ) { BOOL bNeeded = FALSE; _ASSERTE( pwszModuleName ); _wsplitpath( pwszModuleName, NULL, g_wszFileDir, g_wszFileName, NULL ); if ( _wcsicmp( g_wszFileName, L"ntdll" ) == 0 ) { bNeeded = TRUE; } else if ( _wcsicmp( g_wszFileDir, g_wszHercDir ) == 0 ) { bNeeded = TRUE; } return bNeeded; } /////////////////////////////////////////////////////////////////////////////// #pragma optimize( "", on ) #endif // !defined( _MSVC_ ) hercules-3.12/hetget.c0000664000175000017500000004225212564723224011634 00000000000000/* HETGET.C (c) Copyright Leland Lucius, 2000-2009 */ /* Extract files from an HET file */ /* || ---------------------------------------------------------------------------- || || HETGET.C (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Extract files from an HET file || || ---------------------------------------------------------------------------- */ #include "hstdinc.h" #include "hercules.h" #include "hetlib.h" #include "sllib.h" #include "herc_getopt.h" /* || Local volatile data */ #define O_NL 0x80 #define O_ASCII 0x40 #define O_STRIP 0x20 #define O_UNBLOCK 0x10 struct { char *ifile; char *ofile; int fileno; int lrecl; int blksize; unsigned char flags; unsigned char recfm; } opts = { NULL, NULL, 0, 0, 0, 0, 0, }; /* || Local constant data */ static const char help[] = "%s - Extract files from an HET file\n\n" "Usage: %s [options] hetfile outfile fileno [recfm lrecl blksize]\n\n" "Options:\n" " -a convert to ASCII (implies -u)\n" " -h display usage summary\n" " -n file is an NL (or BLP like) tape\n" " -u unblock (removes BDWs and RDWs if RECFM=V)\n" " -s strip trailing blanks (requires -a)\n"; /* || Valid record formats */ #define O_UNDEFINED 0x80 #define O_FIXED 0x40 #define O_VARIABLE 0x20 #define O_BLOCKED 0x08 #define O_SPANNED 0x04 static const struct { char *recfm; int fmt; } valfm[] = { { "U", O_UNDEFINED | 0 | 0 }, { "UA", O_UNDEFINED | 0 | 0 }, { "UM", O_UNDEFINED | 0 | 0 }, { "F", O_FIXED | 0 | 0 }, { "FA", O_FIXED | 0 | 0 }, { "FM", O_FIXED | 0 | 0 }, { "FB", O_FIXED | O_BLOCKED | 0 }, { "FBA", O_FIXED | O_BLOCKED | 0 }, { "FBM", O_FIXED | O_BLOCKED | 0 }, { "FS", O_FIXED | O_BLOCKED | 0 }, { "FSA", O_FIXED | O_BLOCKED | 0 }, { "FSM", O_FIXED | O_BLOCKED | 0 }, { "FBS", O_FIXED | O_BLOCKED | 0 }, { "FBSA", O_FIXED | O_BLOCKED | 0 }, { "FBSM", O_FIXED | O_BLOCKED | 0 }, { "V", O_VARIABLE | 0 | 0 }, { "VA", O_VARIABLE | 0 | 0 }, { "VM", O_VARIABLE | 0 | 0 }, { "VB", O_VARIABLE | O_BLOCKED | 0 }, { "VBA", O_VARIABLE | O_BLOCKED | 0 }, { "VBM", O_VARIABLE | O_BLOCKED | 0 }, { "VS", O_VARIABLE | 0 | O_SPANNED }, { "VSA", O_VARIABLE | 0 | O_SPANNED }, { "VSM", O_VARIABLE | 0 | O_SPANNED }, { "VBS", O_VARIABLE | O_BLOCKED | O_SPANNED }, { "VBSA", O_VARIABLE | O_BLOCKED | O_SPANNED }, { "VBSM", O_VARIABLE | O_BLOCKED | O_SPANNED }, }; #define VALFMCNT ( sizeof( valfm ) / sizeof( valfm[ 0 ] ) ) /* || Block and record management */ unsigned char *blkptr = NULL; int blkidx = 0; int blklen = 0; unsigned char *recptr = NULL; int recidx = 0; int reclen = 0; #ifdef EXTERNALGUI /* || Previously reported file position */ static off_t prevpos = 0; /* || Report progress every this many bytes */ #define PROGRESS_MASK (~0x3FFFF /* 256K */) #endif /*EXTERNALGUI*/ /* || Merge DCB information from HDR2 label */ void merge( SLLABEL *lab ) { SLFMT fmt; int i; /* || Make the label more managable */ sl_fmtlab( &fmt, lab ); /* || Merge the record format; */ if( opts.recfm == 0 ) { opts.recfm = O_UNDEFINED; for( i = 0 ; i < (int)VALFMCNT ; i++ ) { if( strcasecmp( fmt.slds2.recfm, valfm[ i ].recfm ) == 0 ) { opts.recfm = valfm[ i ].fmt; break; } } } /* || Merge in the record length */ if( opts.lrecl == 0 ) { opts.lrecl = atoi( fmt.slds2.lrecl ); } /* || Merge in the block size */ if( opts.blksize == 0 ) { /* || Try the blksize field first */ opts.blksize = atoi( fmt.slds2.blksize ); if( opts.blksize == 0 ) { /* || Still zero, so try the lblkln field */ opts.blksize = atoi( fmt.slds2.lblkln ); } } /* || Locate final RECFM string */ for( i = 0 ; i < (int)VALFMCNT ; i++ ) { if( strcasecmp( fmt.slds2.recfm, valfm[ i ].recfm ) == 0 ) { break; } } /* || Print DCB attributes */ printf( "DCB Attributes used:\n" ); printf( " RECFM=%-4.4s LRECL=%-5.5d BLKSIZE=%d\n", valfm[ i ].recfm, opts.lrecl, opts.blksize ); return; } /* || Return block length from BDW */ int bdw_length( const unsigned char *ptr ) { unsigned int len; /* || Extended format BDW? */ if( ptr[ 0 ] & 0x80 ) { /* || Length is 31 bits */ len = ptr[ 0 ] << 24; len += ptr[ 1 ] << 16; len += ptr[ 2 ] << 8; len += ptr[ 3 ]; len &= 0x7fffffff; } else { /* || Length is 15 bits */ len = ptr[ 0 ] << 8; len += ptr[ 1 ]; } return( len ); } /* || Return record length from RDW */ int rdw_length( const unsigned char *ptr ) { unsigned int len; /* || Get the record length */ len = ptr[ 0 ] << 8; len += ptr[ 1 ]; return( len ); } /* || Retrieves a block from the tape file and resets variables */ int getblock( HETB *hetb ) { int rc; /* || Read a block from the tape */ rc = het_read( hetb, blkptr ); if( rc < 0 ) { return( rc ); } /* || Save the block length (should we use BDW for RECFM=V files???) */ blklen = rc; return( rc ); } /* || Retrieve logical records from the tape - doesn't handle SPANNED records */ int getrecord( HETB *hetb ) { int rc; /* || Won't be null if we've been here before */ if( recptr != NULL ) { recidx += reclen; } /* || Need a new block first time through or we've exhausted current block */ if( ( recptr == NULL ) || ( recidx >= blklen ) ) { /* || Go get another block */ rc = getblock( hetb ); if( rc < 0 ) { return( rc ); } /* || For RECFM=V, bump index past BDW */ recidx = 0; if( opts.recfm & O_VARIABLE ) { /* protect against a corrupt (short) block */ if ( rc < 8 ) { return ( -1 ); } recidx = 4; } } /* || Set the new record pointer */ recptr = &blkptr[ recidx ]; /* || Set the record length depending on record type */ if( opts.recfm & O_FIXED ) { reclen = opts.lrecl; } else if( opts.recfm & O_VARIABLE ) { reclen = rdw_length( recptr ); /* protect against corrupt (short) block */ if ( reclen + recidx > blklen ) { return (-1); } /* protect against a corrupt (less than 4) RDW */ if ( reclen < 4 ) { return (-1); } } else { reclen = blklen; } return( reclen ); } /* || Retrieve and validate a standard label */ int get_sl( HETB *hetb, SLLABEL *lab ) { int rc; /* || Read a block */ rc = het_read( hetb, blkptr ); if( rc >= 0 ) { /* || Does is look like a standard label? */ if( sl_islabel( lab, blkptr, rc ) == TRUE ) { return( 0 ); } } else { printf( "%s while reading block\n", het_error( rc ) ); } return( -1 ); } /* || Extract the file from the tape */ int getfile( HETB *hetb, FILE *outf ) { SLFMT fmt; SLLABEL lab; unsigned char *ptr; int fileno; int rc; /* || Skip to the desired file */ if( opts.flags & O_NL ) { /* || For NL tapes, just use the specified file number */ fileno = opts.fileno; /* || Start skipping */ while( --fileno ) { /* || Forward space to beginning of next file */ rc = het_fsf( hetb ); if( rc < 0 ) { printf( "%s while positioning to file #%d\n", het_error( rc ), opts.fileno ); return( rc ); } } } else { /* || First block should be a VOL1 record */ rc = get_sl( hetb, &lab ); if( rc < 0 || !sl_isvol( &lab, 1 ) ) { printf( "Expected VOL1 label\n" ); return( -1 ); } /* || For SL, adjust the file # so we end up on the label before the data */ fileno = ( opts.fileno * 3 ) - 2; /* || Start skipping */ while( --fileno ) { /* || Forward space to beginning of next file */ rc = het_fsf( hetb ); if( rc < 0 ) { printf( "%s while positioning to file #%d\n", het_error( rc ), opts.fileno ); return( rc ); } } /* || Get the HDR1 label. */ rc = get_sl( hetb, &lab ); if( rc < 0 || !sl_ishdr( &lab, 1 ) ) { printf( "Expected HDR1 label\n" ); return( -1 ); } /* || Make the label more managable */ sl_fmtlab( &fmt, &lab ); printf("File Info:\n DSN=%-17.17s\n", fmt.slds1.dsid ); /* || Get the HDR2 label. */ rc = get_sl( hetb, &lab ); if( rc < 0 || !sl_ishdr( &lab, 2 ) ) { printf( "Expected HDR2 label\n" ); return( -1 ); } /* || Merge the DCB information */ merge( &lab ); /* || Hop over the tapemark */ rc = het_fsf( hetb ); if( rc < 0 ) { printf( "%s while spacing to start of data\n", het_error( rc ) ); return( rc ); } } /* || Different processing when converting to ASCII */ if( opts.flags & ( O_ASCII | O_UNBLOCK ) ) { /* || Get a record */ while( ( rc = getrecord( hetb ) ) >= 0 ) { #ifdef EXTERNALGUI if( extgui ) { /* Report progress every nnnK */ off_t curpos = ftell( hetb->fd ); if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) ) { prevpos = curpos; fprintf( stderr, "IPOS=%" I64_FMT "d\n", (U64)curpos ); } } #endif /*EXTERNALGUI*/ /* || Get working copy of record ptr */ ptr = recptr; /* || Only want data portion for RECFM=V records */ if( opts.recfm & O_VARIABLE ) { ptr += 4; rc -= 4; } /* || Convert record to ASCII */ if( opts.flags & O_ASCII ) { sl_etoa( NULL, ptr, rc ); } /* || Strip trailing blanks */ if( opts.flags & O_STRIP ) { while( rc > 0 && ptr[ rc - 1 ] == ' ' ) { rc--; } } /* || Write the record out */ fwrite( ptr, rc, 1, outf ); /* || Put out a linefeed when converting */ if( opts.flags & O_ASCII ) { fwrite( "\n", 1, 1, outf ); } } } else { /* || Get a record */ while( ( rc = getblock( hetb ) ) >= 0 ) { #ifdef EXTERNALGUI if( extgui ) { /* Report progress every nnnK */ off_t curpos = ftell( hetb->fd ); if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) ) { prevpos = curpos; fprintf( stderr, "IPOS=%" I64_FMT "d\n", (U64)curpos ); } } #endif /*EXTERNALGUI*/ /* || Write the record out */ fwrite( blkptr, blklen, 1, outf ); } } return( rc ); } /* || Prints usage information */ void usage( char *name ) { printf( help, name, name ); } /* || Standard main */ int main( int argc, char *argv[] ) { HETB *hetb; FILE *outf; int rc; int i; INITIALIZE_UTILITY("hetget"); /* Display the program identification message */ display_version (stderr, "Hercules HET extract files program ", FALSE); /* || Process option switches */ while( TRUE ) { rc = getopt( argc, argv, "abhnsu" ); if( rc == -1 ) { break; } switch( rc ) { case 'a': opts.flags |= O_ASCII; break; case 'h': usage( argv[ 0 ] ); exit( 1 ); break; case 'n': opts.flags |= O_NL; break; case 's': opts.flags |= O_STRIP; break; case 'u': opts.flags |= O_UNBLOCK; break; default: usage( argv[ 0 ] ); exit( 1 ); break; } } /* || Calc number of non-switch arguments */ argc -= optind; /* || We must have at least the first 3 parms */ if( argc < 3 ) { printf( "Must specify input tape, output file, and file #\n" ); printf( "Use -h option for more help\n" ); exit( 1 ); } opts.ifile = argv[ optind ]; opts.ofile = argv[ optind + 1 ]; opts.fileno = atoi( argv[ optind + 2 ] ); if( opts.fileno == 0 || opts.fileno > 9999 ) { printf( "File number must be within 1-9999\n" ); exit( 1 ); } /* || If NL tape, then we require the DCB attributes */ if( opts.flags & O_NL ) { if( argc != 6 ) { printf( "DCB attributes required for NL tapes\n" ); exit( 1 ); } } /* || If specified, get the DCB attributes */ if( argc > 3 ) { /* || Must have only three */ if( argc != 6 ) { usage( argv[ 0 ] ); exit( 1 ); } /* || Lookup the specified RECFM in our table */ opts.recfm = 0; for( i = 0 ; i < (int)VALFMCNT ; i++ ) { if( strcasecmp( argv[ optind + 3 ], valfm[ i ].recfm ) == 0 ) { opts.recfm = valfm[ i ].fmt; break; } } /* || If we didn't find a match, show the user what the valid ones are */ if( opts.recfm == 0) { /* || Dump out the valid RECFMs */ printf( "Valid record formats are:\n" ); for( i = 0 ; i < (int)VALFMCNT ; i++ ) { printf( " %-4.4s", valfm[ i ].recfm ); if( ( ( i + 1 ) % 3 ) == 0 ) { printf( "\n" ); } } exit( 1 ); } /* || Get the record length */ opts.lrecl = atoi( argv[ optind + 4 ] ); /* || Get and validate the blksize */ opts.blksize = atoi( argv[ optind + 5 ] ); if( opts.blksize == 0 ) { printf( "Block size can't be zero\n" ); exit( 1 ); } } /* || Open the tape file */ rc = het_open( &hetb, opts.ifile, 0 ); if( rc >= 0 ) { /* || Get memory for the tape buffer */ blkptr = malloc( HETMAX_BLOCKSIZE ); if( blkptr != NULL ) { /* || Open the output file */ char pathname[MAX_PATH]; hostpath(pathname, opts.ofile, sizeof(pathname)); outf = fopen( pathname, "wb" ); if( outf != NULL ) { /* || Go extract the file from the tape */ rc = getfile( hetb, outf ); /* || Close the output file */ fclose( outf ); } /* || Free the buffer memory */ free( blkptr ); } } else { printf( "het_open() returned %s\n", het_error( rc ) ); } /* || Close the tape file */ het_close( &hetb ); return 0; } hercules-3.12/hetinit.c0000664000175000017500000001100312564723224012006 00000000000000/* HETINIT.C (c) Copyright Leland Lucius, 2000-2009 */ /* Creates IEHINITT or NL format Hercules Emulated Tapes*/ /* || ---------------------------------------------------------------------------- || || HETINIT.C (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Creates IEHINITT or NL format Hercules Emulated Tapes. || || ---------------------------------------------------------------------------- */ #include "hstdinc.h" #include "hercules.h" #include "hetlib.h" #include "sllib.h" #include "herc_getopt.h" /* || Local constant data */ static const char help[] = "%s - Initialize a tape\n\n" "Usage: %s [options] filename [volser] [owner]\n\n" "Options:\n" " -d disable compression\n" " -h display usage summary\n" " -i create an IEHINITT formatted tape (default: on)\n" " -n create an NL tape\n"; /* || Prints usage information */ static void usage( char *name ) { printf( help, name, name ); } /* || Subroutine to convert a null-terminated string to upper case */ void het_string_to_upper (char *source) { int i; for (i = 0; source[i] != '\0'; i++) source[i] = toupper(source[i]); } /* || Standard main() function */ int main( int argc, char *argv[] ) { int rc; SLLABEL lab; HETB *hetb; int o_iehinitt; int o_nl; int o_compress; char *o_filename; char *o_owner; char *o_volser; INITIALIZE_UTILITY("hetinit"); hetb = NULL; o_filename = NULL; o_iehinitt = TRUE; o_nl = FALSE; o_compress = TRUE; o_owner = NULL; o_volser = NULL; /* Display the program identification message */ display_version (stderr, "Hercules HET IEHINITT program ", FALSE); while( TRUE ) { rc = getopt( argc, argv, "dhin" ); if( rc == -1 ) { break; } switch( rc ) { case 'd': o_compress = FALSE; break; case 'h': usage( argv[ 0 ] ); goto exit; break; case 'i': o_iehinitt = TRUE; o_nl = FALSE; break; case 'n': o_iehinitt = FALSE; o_nl = TRUE; break; default: usage( argv[ 0 ] ); goto exit; break; } } argc -= optind; if( argc < 1 ) { usage( argv[ 0 ] ); goto exit; } o_filename = argv[ optind ]; if( o_iehinitt ) { if( argc == 2 ) { o_volser = argv[ optind + 1 ]; } else if( argc == 3 ) { o_volser = argv[ optind + 1 ]; o_owner = argv[ optind + 2 ]; } else { usage( argv[ 0 ] ); goto exit; } } if( o_nl ) { if( argc != 1 ) { usage( argv[ 0 ] ); goto exit; } } if( o_volser ) het_string_to_upper( o_volser ); if( o_owner ) het_string_to_upper( o_owner ); rc = het_open( &hetb, o_filename, HETOPEN_CREATE ); if( rc < 0 ) { printf( "het_open() returned %d\n", rc ); goto exit; } rc = het_cntl( hetb, HETCNTL_SET | HETCNTL_COMPRESS, o_compress ); if( rc < 0 ) { printf( "het_cntl() returned %d\n", rc ); goto exit; } if( o_iehinitt ) { rc = sl_vol1( &lab, o_volser, o_owner ); if( rc < 0 ) { printf( "%s\n", sl_error(rc) ); goto exit; } rc = het_write( hetb, &lab, sizeof( lab ) ); if( rc < 0 ) { printf( "het_write() for VOL1 returned %d\n", rc ); goto exit; } rc = sl_hdr1( &lab, SL_INITDSN, NULL, 0, 0, NULL, 0 ); if( rc < 0 ) { printf( "%s\n", sl_error(rc) ); goto exit; } rc = het_write( hetb, &lab, sizeof( lab ) ); if( rc < 0 ) { printf( "het_write() for HDR1 returned %d\n", rc ); goto exit; } } else if( o_nl ) { rc = het_tapemark( hetb ); if( rc < 0 ) { printf( "het_tapemark() returned %d\n", rc ); goto exit; } } rc = het_tapemark( hetb ); if( rc < 0 ) { printf( "het_tapemark() returned %d\n", rc ); goto exit; } exit: het_close( &hetb ); return( rc < 0 ); } hercules-3.12/hetmap.c0000664000175000017500000002277312564723224011640 00000000000000/* HETMAP.C (c) Copyright Leland Lucius, 2000-2009 */ /* Displays information about a Hercules Emulated Tape */ /* || ---------------------------------------------------------------------------- || || HETMAP.C (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Displays information about the structure of a Hercules Emulated Tape. || || ---------------------------------------------------------------------------- */ #include "hstdinc.h" #include "hercules.h" #include "hetlib.h" #include "sllib.h" #include "herc_getopt.h" /* || Local constant data */ static const char sep[] = "---------------------\n"; static const char help_hetmap[] = "%s - Print a map of an HET or AWS tape file\n\n" "Usage: %s [options] filename\n\n" "Options:\n" " -a print all label and file information (default: on)\n" " -d print only dataset information (default: off)\n" " -f print only file information (default: off)\n" " -h display usage summary\n" " -l print only label information (default: off)\n" " -t print TAPEMAP-compatible format output (default: off)\n"; static const char help_tapemap[] = "%s - Print a map of an HET or AWS tape file\n\n" "Usage: %s filename\n\n"; #ifdef EXTERNALGUI /* Previous reported file position */ static off_t prevpos = 0; /* Report progress every this many bytes */ #define PROGRESS_MASK (~0x3FFFF /* 256K */) #endif /*EXTERNALGUI*/ /* || Print terse dataset information (from VOL1/EOF1/EOF2) */ void printdataset( char *buf, int len, int fileno ) { SLLABEL lab; SLFMT fmt; char crtdt[ 9 ]; char expdt[ 9 ]; char recfm[ 4 ]; if( sl_islabel( &lab, buf, len ) == FALSE ) { return; } sl_fmtlab( &fmt, &lab ); if( sl_isvol( buf, 1 ) ) { printf( "vol=%-17.17s owner=%s\n\n", fmt.slvol.volser, fmt.slvol.owner); } else if( sl_iseof( buf, 1 ) ) { printf( "seq=%-17d file#=%d\n", atoi( fmt.slds1.dsseq ), fileno ); printf( "dsn=%-17.17s crtdt=%-8.8s expdt=%-8.8s blocks=%d\n", fmt.slds1.dsid, sl_fmtdate( crtdt, fmt.slds1.crtdt, TRUE ), sl_fmtdate( expdt, fmt.slds1.expdt, TRUE ), atoi( fmt.slds1.blkhi ) * 1000000 + atoi( fmt.slds1.blklo ) ); } else if( sl_iseof( buf, 2 ) ) { recfm[ 0 ] = '\0'; strcat( strcat( strcat( recfm, fmt.slds2.recfm ), fmt.slds2.blkattr ), fmt.slds2.ctrl ); printf( "job=%17.17s recfm=%-3.3s lrecl=%-5d blksize=%-5d\n\n", fmt.slds2.jobid, recfm, atoi( fmt.slds2.lrecl ), atoi( fmt.slds2.blksize ) ); } return; } /* || Print all label fields */ void printlabel( char *buf, int len ) { SLLABEL lab; SLFMT fmt; int i; if( sl_islabel( &lab, buf, len ) == FALSE ) { return; } sl_fmtlab( &fmt, &lab ); printf( sep ); for( i = 0; fmt.key[ i ] != NULL; i++ ) { printf("%-20.20s: '%s'\n", fmt.key[ i ] , fmt.val[ i ] ); } return; } /* || Print label fields in TAPEMAP format */ void printlabeltapemap( char *buf, int len ) { SLLABEL lab; BYTE labelrec[81]; int i; if( sl_islabel( &lab, buf, len ) == FALSE ) { return; } for (i=0; i < 80; i++) { labelrec[i] = guest_to_host(buf[i]); } labelrec[i] = '\0'; printf("%s\n", labelrec); } /* || Prints usage information */ void usage( char *name ) { if ((strcmp(name, "tapemap") == 0) || (strcmp(name, "TAPEMAP") == 0)) { printf( help_tapemap, name, name ); } else { printf( help_hetmap, name, name ); } } /* || Standard main */ int main( int argc, char *argv[] ) { char buf[ HETMAX_BLOCKSIZE ]; HETB *hetb; int rc; int fileno; U32 blocks; U32 uminsz; U32 umaxsz; U32 ubytes; U32 cminsz; U32 cmaxsz; U32 cbytes; U32 totblocks; U32 totubytes; U32 totcbytes; U32 opts = 0; char pgmpath[MAX_PATH]; char *pgm; #define O_ALL 0xC0 #define O_FILES 0X80 #define O_LABELS 0X40 #define O_DATASETS 0X20 #define O_TAPEMAP_OUTPUT 0x10 #define O_TAPEMAP_INVOKED 0x08 /* Figure out processing based on the program name */ hostpath(pgmpath, argv[0], sizeof(pgmpath)); pgm = strrchr(pgmpath, '/'); if (pgm) { pgm++; } else { pgm = argv[0]; } strtok (pgm, "."); if ((strcmp(pgm, "tapemap") == 0) || (strcmp(pgm, "TAPEMAP") == 0)) { opts = O_TAPEMAP_OUTPUT+O_TAPEMAP_INVOKED; } INITIALIZE_UTILITY(pgm); /* Display the program identification message */ display_version (stderr, "Hercules HET and AWS tape map program ", FALSE); if (! (opts & O_TAPEMAP_INVOKED) ) { opts = O_ALL; while( TRUE ) { rc = getopt( argc, argv, "adfhlt" ); if( rc == -1 ) { break; } switch( rc ) { case 'a': opts = O_ALL; break; case 'd': opts = O_DATASETS; break; case 'f': opts = O_FILES; break; case 'h': usage( pgm ); exit( 1 ); break; case 'l': opts = O_LABELS; break; case 't': opts = O_TAPEMAP_OUTPUT; break; default: usage( pgm ); exit( 1 ); break; } } } // end if (! (opts & O_TAPEMAP_INVOKED) ) argc -= optind; if( argc != 1 ) { usage( pgm ); exit( 1 ); } if( opts & O_ALL ) { printf( sep ); printf( "%-20.20s: %s\n", "Filename", argv[ optind ] ); } rc = het_open( &hetb, argv[ optind ], 0 ); if( rc < 0 ) { printf( "het_open() returned %d\n", rc ); het_close( &hetb ); exit( 1 ); } fileno = 0; blocks = 0; uminsz = 0; umaxsz = 0; ubytes = 0; cminsz = 0; cmaxsz = 0; cbytes = 0; totblocks = 0; totubytes = 0; totcbytes = 0; while( TRUE ) { #ifdef EXTERNALGUI if( extgui ) { /* Report progress every nnnK */ off_t curpos = ftell( hetb->fd ); if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) ) { prevpos = curpos; fprintf( stderr, "IPOS=%" I64_FMT "d\n", (U64)curpos ); } } #endif /*EXTERNALGUI*/ rc = het_read( hetb, buf ); if( rc == HETE_EOT ) { if( opts & O_TAPEMAP_OUTPUT ) { printf ("End of tape.\n"); } break; } if( rc == HETE_TAPEMARK ) { fileno += 1; if( opts & O_TAPEMAP_OUTPUT ) { printf ("File %u: Blocks=%u, block size min=%u, max=%u\n", fileno, blocks, uminsz, umaxsz ); } if( opts & O_FILES ) { printf( sep ); printf( "%-20.20s: %d\n", "File #", fileno ); printf( "%-20.20s: %d\n", "Blocks", blocks ); printf( "%-20.20s: %d\n", "Min Blocksize", uminsz ); printf( "%-20.20s: %d\n", "Max Blocksize", umaxsz ); printf( "%-20.20s: %d\n", "Uncompressed bytes", ubytes ); printf( "%-20.20s: %d\n", "Min Blocksize-Comp", cminsz ); printf( "%-20.20s: %d\n", "Max Blocksize-Comp", cmaxsz ); printf( "%-20.20s: %d\n", "Compressed bytes", cbytes ); } totblocks += blocks; totubytes += ubytes; totcbytes += cbytes; blocks = 0; uminsz = 0; umaxsz = 0; ubytes = 0; cminsz = 0; cmaxsz = 0; cbytes = 0; continue; } if( rc < 0 ) { printf( "het_read() returned %d\n", rc ); break; } blocks += 1; ubytes += hetb->ublksize; cbytes += hetb->cblksize; if( uminsz == 0 || hetb->ublksize < uminsz ) uminsz = hetb->ublksize; if( hetb->ublksize > umaxsz ) umaxsz = hetb->ublksize; if( cminsz == 0 || hetb->cblksize < cminsz ) cminsz = hetb->cblksize; if( hetb->cblksize > cmaxsz ) cmaxsz = hetb->cblksize; if( opts & O_LABELS ) { printlabel( buf, rc ); } if( opts & O_TAPEMAP_OUTPUT ) { printlabeltapemap( buf, rc ); } if( opts & O_DATASETS ) { printdataset( buf, rc, fileno ); } } if( opts & O_FILES ) { printf( sep ); printf( "%-20.20s:\n", "Summary" ); printf( "%-20.20s: %d\n", "Files", fileno ); printf( "%-20.20s: %d\n", "Blocks", totblocks ); printf( "%-20.20s: %d\n", "Uncompressed bytes", totubytes ); printf( "%-20.20s: %d\n", "Compressed bytes", totcbytes ); printf( "%-20.20s: %d\n", "Reduction", totubytes - totcbytes ); } het_close( &hetb ); return 0; } hercules-3.12/hetupd.c0000664000175000017500000002107712564723224011647 00000000000000/* HETUPD.C (c) Copyright Leland Lucius, 2000-2009 */ /* Update/Copy Hercules Emulated Tape */ /* || ---------------------------------------------------------------------------- || || HETUPD.C (c) Copyright Leland Lucius, 2000-2009 || Released under terms of the Q Public License. || || Copy/update Hercules Emulated Tapes while allowing various modifications || like enabling/disabling compression, changing compression method/level, and || internal chunk size. || || ---------------------------------------------------------------------------- */ #include "hstdinc.h" #include "hercules.h" #include "hetlib.h" #include "sllib.h" #include "herc_getopt.h" /* || Local volatile data */ static int o_chunksize = HETDFLT_CHKSIZE; static int o_decompress = HETDFLT_DECOMPRESS; static int o_compress = HETDFLT_COMPRESS; static int o_level = HETDFLT_LEVEL; static int o_method = HETDFLT_METHOD; static int o_verbose = FALSE; static char *o_sname = NULL; static char *o_dname = NULL; static int dorename = FALSE; static HETB *s_hetb = NULL; static HETB *d_hetb = NULL; #ifdef EXTERNALGUI /* Previous reported file position */ static off_t prevpos = 0; /* Report progress every this many bytes */ #define PROGRESS_MASK (~0x3FFFF /* 256K */) #endif /*EXTERNALGUI*/ /* || Local constant data */ static const char help[] = "%s - Updates the compression of a Hercules Emulated Tape file.\n\n" "Usage: %s [options] source [dest]\n\n" "Options:\n" " -1 compress fast\n" " ...\n" " -9 compress best\n" #if defined( HET_BZIP2 ) " -b use BZLIB compression\n" #endif /* defined( HET_BZIP2 ) */ " -c n set chunk size to \"n\"\n" " -d decompress source tape\n" " -h display usage summary\n" " -r rechucnk\n" " -s strict AWSTAPE specification (chunksize=4096,no compression)\n" " -v verbose information\n" " -z use ZLIB compression\n"; /* || Prints usage information */ static void usage( char *name ) { printf( help, name, name ); } /* || Supply "Yes" or "No" */ static const char * yesno( int val ) { return( ( val ? "Yes" : "No" ) ); } /* || Close tapes and cleanup */ static void closetapes( int rc ) { het_close( &d_hetb ); het_close( &s_hetb ); if( dorename ) { if( rc >= 0 ) { rc = rename( o_dname, o_sname ); } else { rc = remove( o_dname ); } if( rc == -1 ) { printf( "Error renaming files - manual checks required\n"); } } return; } /* || Copy source to dest */ static int copytape( void ) { int rc; char buf[ HETMAX_BLOCKSIZE ]; while( TRUE ) { #ifdef EXTERNALGUI if( extgui ) { /* Report progress every nnnK */ off_t curpos = ftell( s_hetb->fd ); if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) ) { prevpos = curpos; fprintf( stderr, "IPOS=%" I64_FMT "d\n", (U64)curpos ); } } #endif /*EXTERNALGUI*/ rc = het_read( s_hetb, buf ); if( rc == HETE_EOT ) { rc = 0; break; } if( rc == HETE_TAPEMARK ) { rc = het_tapemark( d_hetb ); if( rc < 0 ) { printf( "Error writing tapemark - rc: %d\n", rc ); break; } continue; } if( rc < 0 ) { printf( "het_read() returned %d\n", rc ); break; } rc = het_write( d_hetb, buf, rc ); if( rc < 0 ) { printf( "het_write() returned %d\n", rc ); break; } } return( rc ); } /* || Open HET tapes and set options */ static int opentapes( void ) { int rc; rc = het_open( &s_hetb, o_sname, 0 ); if( rc < 0 ) { goto exit; } rc = het_open( &d_hetb, o_dname, HETOPEN_CREATE ); if( rc < 0 ) { goto exit; } rc = het_cntl( s_hetb, HETCNTL_SET | HETCNTL_DECOMPRESS, o_decompress ); if( rc < 0 ) { goto exit; } rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_COMPRESS, o_compress ); if( rc < 0 ) { goto exit; } rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_METHOD, o_method ); if( rc < 0 ) { goto exit; } rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_LEVEL, o_level ); if( rc < 0 ) { goto exit; } rc = het_cntl( d_hetb, HETCNTL_SET | HETCNTL_CHUNKSIZE, o_chunksize ); if( rc < 0 ) { goto exit; } if( o_verbose ) { printf( "Source : %s\n", o_sname ); printf( "Destination : %s\n", o_dname ); printf( "Decompress source : %s\n", yesno( het_cntl( s_hetb, HETCNTL_DECOMPRESS, 0 ) ) ); printf( "Compress dest : %s\n", yesno( het_cntl( d_hetb, HETCNTL_COMPRESS, 0 ) ) ); printf( "Compression method : %d\n", het_cntl( d_hetb, HETCNTL_METHOD, 0 ) ); printf( "Compression level : %d\n", het_cntl( d_hetb, HETCNTL_LEVEL, 0 ) ); } exit: if( rc < 0 ) { het_close( &d_hetb ); het_close( &s_hetb ); } return( rc ); } /* || Standard main */ int main( int argc, char *argv[] ) { char toname[ PATH_MAX ]; HETB *s_hetb; HETB *d_hetb; int rc; INITIALIZE_UTILITY("hetupd"); s_hetb = NULL; d_hetb = NULL; /* Display the program identification message */ display_version (stderr, "Hercules HET copy/update program ", FALSE); while( TRUE ) { #if defined( HET_BZIP2 ) rc = getopt( argc, argv, "bc:dhrsvz0123456789" ); #else rc = getopt( argc, argv, "c:dhrsvz0123456789" ); #endif /* defined( HET_BZIP2 ) */ if( rc == -1 ) { break; } switch( rc ) { case '1': case '2': case '3': case '4': /* Compression level */ case '5': case '6': case '7': case '8': case '9': o_level = ( rc - '0' ); break; #if defined( HET_BZIP2 ) case 'b': /* Use BZLIB compression */ o_method = HETMETH_BZLIB; o_compress = TRUE; o_decompress = TRUE; break; #endif /* defined( HET_BZIP2 ) */ case 'c': /* Chunk size */ o_chunksize = atoi( optarg ); break; case 'd': /* Decompress */ o_compress = FALSE; o_decompress = TRUE; break; case 'h': /* Print usage */ usage( argv[ 0 ] ); exit( 1 ); break; case 'r': /* Rechunk */ o_compress = FALSE; o_decompress = FALSE; break; case 's': /* Strict HET spec */ o_chunksize = 4096; o_compress = FALSE; o_decompress = TRUE; break; case 'v': /* Be chatty */ o_verbose = TRUE; break; case 'z': /* Use ZLIB compression */ o_method = HETMETH_ZLIB; o_compress = TRUE; o_decompress = TRUE; break; default: /* Print usage */ usage( argv[ 0 ] ); exit( 1 ); break; } } argc -= optind; switch( argc ) { case 1: sprintf( toname, "%s.%010d", argv[ optind ], rand() ); o_dname = toname; dorename = TRUE; break; case 2: o_dname = argv[ optind + 1 ]; break; default: usage( argv[ 0 ] ); exit( 1 ); break; } o_sname = argv[ optind ] ; rc = opentapes(); if( rc < 0 ) { printf( "Error opening files - HETLIB rc: %d\n%s\n", rc, het_error( rc ) ); exit( 1 ); } rc = copytape(); if( rc < 0 ) { printf( "Error copying files - HETLIB rc: %d\n%s\n", rc, het_error( rc ) ); exit( 1 ); } closetapes( rc ); return 0; } hercules-3.12/tapecopy.c0000664000175000017500000007542012564723224012203 00000000000000/* TAPECOPY.C (c) Copyright Roger Bowler, 1999-2010 */ /* Convert SCSI tape into AWSTAPE format */ /* Read from AWSTAPE and write to SCSI tape mods */ /* Copyright 2005-2009 James R. Maynard III */ /*-------------------------------------------------------------------*/ /* This program reads a SCSI tape and produces a disk file with */ /* each block of the tape prefixed by an AWSTAPE block header. */ /* If no disk file name is supplied, then the program simply */ /* prints a summary of the tape files and blocksizes. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" #include "tapedev.h" #include "scsitape.h" /*-------------------------------------------------------------------*/ /* (if no SCSI tape support generated, do nothing) */ /*-------------------------------------------------------------------*/ #if !defined(OPTION_SCSI_TAPE) // SYSBLK sysblk; int main (int argc, char *argv[]) { UNREFERENCED(argc); UNREFERENCED(argv); printf( _("HHCTC017E SCSI tape not supported with this build\n") ); return 0; } #else /*-------------------------------------------------------------------*/ /* External GUI flag... */ /*-------------------------------------------------------------------*/ #if defined(EXTERNALGUI) time_t curr_progress_time = 0; time_t prev_progress_time = 0; #define PROGRESS_INTERVAL_SECS ( 3 ) /* (just what it says) */ #endif /*defined(EXTERNALGUI)*/ /*-------------------------------------------------------------------*/ /* Return Codes... */ /*-------------------------------------------------------------------*/ #define RC_SUCCESS ( 0) #define RC_ERROR_BAD_ARGUMENTS ( 1) #define RC_ERROR_OPENING_SCSI_DEVICE ( 3) #define RC_ERROR_OPENING_AWS_FILE ( 4) #define RC_ERROR_SETTING_SCSI_VARBLK_PROCESSING ( 5) #define RC_ERROR_REWINDING_SCSI ( 6) #define RC_ERROR_OBTAINING_SCSI_STATUS ( 7) #define RC_ERROR_READING_AWS_HEADER ( 8) #define RC_ERROR_READING_DATA ( 9) #define RC_ERROR_AWSTAPE_BLOCK_TOO_LARGE (10) #define RC_ERROR_WRITING_TAPEMARK (11) #define RC_ERROR_WRITING_OUTPUT_AWS_HEADER_BLOCK (12) #define RC_ERROR_WRITING_DATA (13) /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static BYTE vollbl[] = "\xE5\xD6\xD3"; /* EBCDIC characters "VOL" */ static BYTE hdrlbl[] = "\xC8\xC4\xD9"; /* EBCDIC characters "HDR" */ static BYTE eoflbl[] = "\xC5\xD6\xC6"; /* EBCDIC characters "EOF" */ static BYTE eovlbl[] = "\xC5\xD6\xE5"; /* EBCDIC characters "EOV" */ static struct mt_tape_info tapeinfo[] = MT_TAPE_INFO; static struct mt_tape_info densinfo[] = { {0x01, "NRZI (800 bpi)" }, {0x02, "PE (1600 bpi)" }, {0x03, "GCR (6250 bpi)" }, {0x05, "QIC-45/60 (GCR, 8000 bpi)" }, {0x06, "PE (3200 bpi)" }, {0x07, "IMFM (6400 bpi)" }, {0x08, "GCR (8000 bpi)" }, {0x09, "GCR (37871 bpi)" }, {0x0A, "MFM (6667 bpi)" }, {0x0B, "PE (1600 bpi)" }, {0x0C, "GCR (12960 bpi)" }, {0x0D, "GCR (25380 bpi)" }, {0x0F, "QIC-120 (GCR 10000 bpi)" }, {0x10, "QIC-150/250 (GCR 10000 bpi)" }, {0x11, "QIC-320/525 (GCR 16000 bpi)" }, {0x12, "QIC-1350 (RLL 51667 bpi)" }, {0x13, "DDS (61000 bpi)" }, {0x14, "EXB-8200 (RLL 43245 bpi)" }, {0x15, "EXB-8500 (RLL 45434 bpi)" }, {0x16, "MFM 10000 bpi" }, {0x17, "MFM 42500 bpi" }, {0x24, "DDS-2" }, {0x8C, "EXB-8505 compressed" }, {0x90, "EXB-8205 compressed" }, {0, NULL }, }; /*-------------------------------------------------------------------*/ /* Maximum blocksized SCSI tape I/O buffer... */ /*-------------------------------------------------------------------*/ static BYTE buf[ 65535 ]; /*-------------------------------------------------------------------*/ /* Global variables used by main and the read/write functions */ /*-------------------------------------------------------------------*/ int len; /* Block length */ int prevlen; /* Previous block length */ int64_t bytes_written; /* Bytes written to o/p file */ char *devnamein; /* -> Input tape device name */ char *devnameout; /* -> Output tape device name*/ char *filenamein; /* -> Input AWS file name */ char *filenameout; /* -> Output AWS file name */ /*-------------------------------------------------------------------*/ /* Custom exit function... */ /*-------------------------------------------------------------------*/ void delayed_exit (int exit_code) { if (RC_SUCCESS != exit_code) printf( _( "HHCTC000I Abnormal termination\n" ) ); /* Delay exiting is to give the system * time to display the error message. */ usleep(100000); exit(exit_code); } #define EXIT(rc) delayed_exit(rc) /* (use this macro to exit) */ /*-------------------------------------------------------------------*/ /* Subroutine to print tape status */ /*-------------------------------------------------------------------*/ static void print_status (char *devname, long stat) { printf (_("HHCTC015I %s status: %8.8lX"), devname, stat); if (GMT_EOF ( stat )) printf (" EOF" ); if (GMT_BOT ( stat )) printf (" BOT" ); if (GMT_EOT ( stat )) printf (" EOT" ); if (GMT_SM ( stat )) printf (" SETMARK"); if (GMT_EOD ( stat )) printf (" EOD" ); if (GMT_WR_PROT( stat )) printf (" WRPROT" ); if (GMT_ONLINE ( stat )) printf (" ONLINE" ); if (GMT_D_6250 ( stat )) printf (" 6250" ); if (GMT_D_1600 ( stat )) printf (" 1600" ); if (GMT_D_800 ( stat )) printf (" 800" ); if (GMT_DR_OPEN( stat )) printf (" NOTAPE" ); printf ("\n"); } /* end function print_status */ /*-------------------------------------------------------------------*/ /* Subroutine to print usage message */ /*-------------------------------------------------------------------*/ static void print_usage (void) { printf ( _( "\n" // 1...5...10...15...20...25...30...35...40...45...50...55...60...65...70...75...80 "Copies a SCSI tape to or from an AWSTAPE disk file.\n\n" "Tapecopy reads a SCSI tape and outputs an AWSTAPE file representation\n" "of the tape, or else reads an AWSTAPE file and creates an identical copy\n" "of its contents on a tape mounted on a SCSI tape drive.\n\n" "Usage:\n\n" " tapecopy [tapedrive] [awsfile] or\n" " tapecopy [awsfile] [tapedrive]\n\n" "Where:\n\n" " tapedrive specifies the device filename of the SCSI tape drive.\n" " Must begin with /dev%s to be recognized.\n" " awsfile specifies the filename of the AWSTAPE disk file.\n\n" "The first filename is the input; the second is the output.\n\n" "If the input file is a SCSI tape, it is read and processed until physical EOD\n" "(end-of-data) is reached (i.e. it does not stop whenever multiple tapemarks or\n" "filemarks are read; it continues processing until the SCSI tape drive says\n" "there is no more data on the tape). The resulting AWSTAPE output disk file,\n" "when specified for the filename on a Hercules tape device configuration\n" "statement, can then be used instead in order for the Hercules guest O/S to\n" "read the exact same data without having to have a SCSI tape drive physically\n" "attached to the host system. This allows you to easily transfer SCSI tape data\n" "to other systems that may not have SCSI tape drives attached to them.\n\n" "The possible return codes and their meaning are:\n\n" " %2d Successful completion.\n" " %2d Invalid arguments or no arguments given.\n" " %2d Unable to open SCSI tape drive device file.\n" " %2d Unable to open AWSTAPE disk file.\n" " %2d Unrecoverable I/O error setting variable length block\n" " processing for SCSI tape device.\n" " %2d Unrecoverable I/O error rewinding SCSI tape device.\n" " %2d Unrecoverable I/O error obtaining status of SCSI device.\n" " %2d Unrecoverable I/O error reading block header\n" " from AWSTAPE disk file.\n" " %2d Unrecoverable I/O error reading data block.\n" " %2d AWSTAPE block size too large.\n" " %2d Unrecoverable I/O error writing tapemark.\n" " %2d Unrecoverable I/O error writing block header\n" " to AWSTAPE disk file.\n" " %2d Unrecoverable I/O error writing data block.\n" "\n" ) #if defined(_MSVC_) ," or \\\\.\\Tape" #else ,"" #endif ,RC_SUCCESS ,RC_ERROR_BAD_ARGUMENTS ,RC_ERROR_OPENING_SCSI_DEVICE ,RC_ERROR_OPENING_AWS_FILE ,RC_ERROR_SETTING_SCSI_VARBLK_PROCESSING ,RC_ERROR_REWINDING_SCSI ,RC_ERROR_OBTAINING_SCSI_STATUS ,RC_ERROR_READING_AWS_HEADER ,RC_ERROR_READING_DATA ,RC_ERROR_AWSTAPE_BLOCK_TOO_LARGE ,RC_ERROR_WRITING_TAPEMARK ,RC_ERROR_WRITING_OUTPUT_AWS_HEADER_BLOCK ,RC_ERROR_WRITING_DATA ); } /* end function print_usage */ /*-------------------------------------------------------------------*/ /* Subroutine to obtain SCSI tape status... */ /* */ /* Return value: 0 == normal */ /* +1 == end-of-tape */ /* -1 == error */ /*-------------------------------------------------------------------*/ static int obtain_status (char *devname, int devfd, struct mtget* mtget) { int rc; /* Return code */ rc = ioctl_tape (devfd, MTIOCGET, (char*)mtget); if (rc < 0) { if (1 && EIO == errno && (0 || GMT_EOD( mtget->mt_gstat ) || GMT_EOT( mtget->mt_gstat ) ) ) return +1; printf (_("HHCTC016E Error reading status of %s: rc=%d, errno=%d: %s\n"), devname, rc, errno, strerror(errno)); return -1; } if (GMT_EOD( mtget->mt_gstat ) || GMT_EOT( mtget->mt_gstat )) return +1; return 0; } /* end function obtain_status */ /*-------------------------------------------------------------------*/ /* Read a block from SCSI tape */ /*-------------------------------------------------------------------*/ int read_scsi_tape (int devfd, void *buf, size_t bufsize, struct mtget* mtget) { int rc; int save_errno; len = read_tape (devfd, buf, bufsize); if (len < 0) { /* Determine whether end-of-tape has been read */ save_errno = errno; ASSERT( devnamein ); rc = obtain_status (devnamein, devfd, mtget); if (rc == +1) { printf (_("HHCTC011I End of tape.\n")); errno = save_errno; return(-1); } printf (_("HHCTC008E Error reading %s: errno=%d: %s\n"), devnamein, errno, strerror(errno)); EXIT( RC_ERROR_READING_DATA ); } return(len); } /* end function read_scsi_tape */ /*-------------------------------------------------------------------*/ /* Read a block from AWSTAPE disk file */ /*-------------------------------------------------------------------*/ int read_aws_disk (int diskfd, void *buf, size_t bufsize) { AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ int rc; unsigned int count_read = 0; unsigned int blksize; int end_block; BYTE *bufptr = buf; while (1) { /* Read block header */ rc = read (diskfd, &awshdr, sizeof(AWSTAPE_BLKHDR)); if (rc == 0) { printf (_("HHCTC018I End of AWSTAPE input file.\n")); return (-1); } if (rc < (int)sizeof(AWSTAPE_BLKHDR)) { printf (_("HHCTC019E Error reading AWSTAPE header from %s: rc=%d, errno=%d: %s\n"), filenamein, rc, errno, strerror(errno)); EXIT( RC_ERROR_READING_AWS_HEADER ); } /* end if(rc) */ /* Interpret the block header */ blksize = ((int)awshdr.curblkl[1] << 8) + awshdr.curblkl[0]; end_block = (awshdr.flags1 & AWSTAPE_FLAG1_ENDREC) != 0; /* If this is a tapemark, return immediately */ if (blksize == 0) return (0); /* Check maximum block length */ if ((count_read + blksize) > bufsize) { printf (_("HHCTC020E AWSTAPE block too large on %s: block size=%d, maximum=%d\n"), filenamein, count_read+blksize, (int)bufsize); EXIT( RC_ERROR_AWSTAPE_BLOCK_TOO_LARGE ); } /* end if(count) */ /* Read data block */ rc = read (diskfd, bufptr, blksize); if (rc < (int)blksize) { printf (_("HHCTC021E Error reading data block from %s: rc=%d, errno=%d: %s\n"), filenamein, rc, errno, strerror(errno)); EXIT( RC_ERROR_READING_DATA ); } /* end if(rc) */ bufptr += blksize; count_read += blksize; if (end_block) break; } return(count_read); } /* end function read_aws_disk */ /*-------------------------------------------------------------------*/ /* Write a block to SCSI tape */ /*-------------------------------------------------------------------*/ int write_scsi_tape (int devfd, void *buf, size_t len) { int rc; rc = write_tape (devfd, buf, len); if (rc < (int)len) { printf (_("HHCTC022E Error writing data block to %s: rc=%d, errno=%d: %s\n"), devnameout, rc, errno, strerror(errno)); EXIT( RC_ERROR_WRITING_DATA ); } /* end if(rc) */ bytes_written += rc; return(rc); } /* end function write_scsi_tape */ /*-------------------------------------------------------------------*/ /* Write a block to AWSTAPE disk file */ /*-------------------------------------------------------------------*/ int write_aws_disk (int diskfd, void *buf, size_t len) { AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ int rc; /* Build the block header */ awshdr.curblkl[0] = len & 0xFF; awshdr.curblkl[1] = ( len >> 8 ) & 0xFF; awshdr.prvblkl[0] = prevlen & 0xFF; awshdr.prvblkl[1] = ( prevlen >> 8 ) & 0xFF; awshdr.flags1 = 0 | AWSTAPE_FLAG1_NEWREC | AWSTAPE_FLAG1_ENDREC ; awshdr.flags2 = 0; /* Write block header to output file */ rc = write (diskfd, &awshdr, sizeof(AWSTAPE_BLKHDR)); if (rc < (int)sizeof(AWSTAPE_BLKHDR)) { printf (_("HHCTC013E Error writing AWSTAPE header on %s: rc=%d, errno=%d: %s\n"), filenameout, rc, errno, strerror(errno)); EXIT( RC_ERROR_WRITING_OUTPUT_AWS_HEADER_BLOCK ); } /* end if(rc) */ bytes_written += rc; /* Write data block to output file */ rc = write (diskfd, buf, len); if (rc < (int)len) { printf (_("HHCTC014E Error writing data block to %s: rc=%d, errno=%d: %s\n"), filenameout, rc, errno, strerror(errno)); EXIT( RC_ERROR_WRITING_DATA ); } /* end if(rc) */ bytes_written += rc; return(rc); } /* end function write_aws_disk */ /*-------------------------------------------------------------------*/ /* Write a tapemark to SCSI tape */ /*-------------------------------------------------------------------*/ int write_tapemark_scsi_tape (int devfd) { struct mtop opblk; /* Area for MTIOCTOP ioctl */ int rc; opblk.mt_op = MTWEOF; opblk.mt_count = 1; rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk); if (rc < 0) { printf (_("HHCTC023E Error writing tapemark on %s: rc=%d, errno=%d: %s\n"), devnameout, rc, errno, strerror(errno)); EXIT( RC_ERROR_WRITING_TAPEMARK ); } return(rc); } /* end function write_tapemark_scsi_tape */ /*-------------------------------------------------------------------*/ /* Write a tapemark to AWSTAPE disk file */ /*-------------------------------------------------------------------*/ int write_tapemark_aws_disk (int diskfd) { AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ int rc; /* Build block header for tape mark */ awshdr.curblkl[0] = 0; awshdr.curblkl[1] = 0; awshdr.prvblkl[0] = prevlen & 0xFF; awshdr.prvblkl[1] = ( prevlen >> 8 ) & 0xFF; awshdr.flags1 = AWSTAPE_FLAG1_TAPEMARK; awshdr.flags2 = 0; /* Write block header to output file */ rc = write (diskfd, &awshdr, sizeof(AWSTAPE_BLKHDR)); if (rc < (int)sizeof(AWSTAPE_BLKHDR)) { printf (_("HHCTC010E Error writing tapemark on %s: rc=%d, errno=%d, %s\n"), filenameout, rc, errno, strerror(errno)); EXIT( RC_ERROR_WRITING_TAPEMARK ); } /* end if(rc) */ bytes_written += rc; return(rc); } /* end function write_tapemark_aws_disk */ /*-------------------------------------------------------------------*/ /* TAPECOPY main entry point */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int rc; /* Return code */ int i; /* Array subscript */ int devfd; /* Tape file descriptor */ int diskfd = -1; /* Disk file descriptor */ int fileno; /* Tape file number */ int blkcount; /* Block count */ int totalblks = 0; /* Block count */ int minblksz; /* Minimum block size */ int maxblksz; /* Maximum block size */ struct mtop opblk; /* Area for MTIOCTOP ioctl */ long density; /* Tape density code */ BYTE labelrec[81]; /* Standard label (ASCIIZ) */ int64_t bytes_read; /* Bytes read from i/p file */ int64_t file_bytes; /* Byte count for curr file */ char pathname[MAX_PATH]; /* file name in host format */ struct mtget mtget; /* Area for MTIOCGET ioctl */ #if defined(EXTERNALGUI) struct mtpos mtpos; /* Area for MTIOCPOS ioctl */ int is3590 = 0; /* 1 == 3590, 0 == 3480/3490 */ #endif /*defined(EXTERNALGUI)*/ INITIALIZE_UTILITY("tapecopy"); /* Display the program identification message */ display_version (stderr, "Hercules tape copy program ", FALSE); /* The first argument is the input file name (either AWS disk file or SCSI tape device) */ if ((argc < 2) || (argv[1] == NULL)) { print_usage(); EXIT( RC_ERROR_BAD_ARGUMENTS ); return(0); /* Make gcc -Wall happy */ } if (0 || ( strlen( argv[1] ) > 5 && strnfilenamecmp( argv[1], "/dev/", 5 ) == 0 ) || ( strlen( argv[1] ) > 4 && strnfilenamecmp( argv[1], "\\\\.\\", 4 ) == 0 ) ) { devnamein = argv[1]; filenamein = NULL; } else { filenamein = argv[1]; devnamein = NULL; } /* The second argument is the output file name (either AWS disk file or SCSI tape device) */ if (argc > 2 && argv[2] ) { if (0 || ( strlen( argv[2] ) > 5 && strnfilenamecmp( argv[2], "/dev/", 5 ) == 0 ) || ( strlen( argv[2] ) > 4 && strnfilenamecmp( argv[2], "\\\\.\\", 4 ) == 0 ) ) { devnameout = argv[2]; filenameout = NULL; } else { filenameout = argv[2]; devnameout = NULL; } } else { print_usage(); EXIT( RC_ERROR_BAD_ARGUMENTS ); } /* Check input arguments and disallow tape-to-tape or disk-to-disk copy */ if ((!devnamein && !devnameout) || (!filenamein && !filenameout)) { print_usage(); EXIT( RC_ERROR_BAD_ARGUMENTS ); } /* Open the SCSI tape device */ if (devnamein) { hostpath( pathname, devnamein, sizeof(pathname) ); devfd = open_tape (pathname, O_RDONLY|O_BINARY); } else // (devnameout) { hostpath( pathname, devnameout, sizeof(pathname) ); devfd = open_tape (pathname, O_RDWR|O_BINARY); } if (devfd < 0) { printf (_("HHCTC001E Error opening %s: errno=%d: %s\n"), (devnamein ? devnamein : devnameout), errno, strerror(errno)); EXIT( RC_ERROR_OPENING_SCSI_DEVICE ); } usleep(50000); /* Set the tape device to process variable length blocks */ opblk.mt_op = MTSETBLK; opblk.mt_count = 0; rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk); if (rc < 0) { printf (_("HHCTC005E Error setting attributes for %s: rc=%d, errno=%d: %s\n"), (devnamein ? devnamein : devnameout), rc, errno, strerror(errno)); EXIT( RC_ERROR_SETTING_SCSI_VARBLK_PROCESSING ); } usleep(50000); /* Rewind the tape to the beginning */ opblk.mt_op = MTREW; opblk.mt_count = 1; rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk); if (rc < 0) { printf (_("HHCTC006E Error rewinding %s: rc=%d, errno=%d: %s\n"), (devnamein ? devnamein : devnameout), rc, errno, strerror(errno)); EXIT( RC_ERROR_REWINDING_SCSI ); } usleep(50000); /* Obtain the tape status */ rc = obtain_status ((devnamein ? devnamein : devnameout), devfd, &mtget); if (rc < 0) EXIT( RC_ERROR_OBTAINING_SCSI_STATUS ); /* Display tape status information */ for (i = 0; tapeinfo[i].t_type != 0 && tapeinfo[i].t_type != mtget.mt_type; i++); if (tapeinfo[i].t_name) printf (_("HHCTC003I %s device type: %s\n"), (devnamein ? devnamein : devnameout), tapeinfo[i].t_name); else printf (_("HHCTC003I %s device type: 0x%lX\n"), (devnamein ? devnamein : devnameout), mtget.mt_type); density = (mtget.mt_dsreg & MT_ST_DENSITY_MASK) >> MT_ST_DENSITY_SHIFT; for (i = 0; densinfo[i].t_type != 0 && densinfo[i].t_type != density; i++); if (densinfo[i].t_name) printf (_("HHCTC004I %s tape density: %s\n"), (devnamein ? devnamein : devnameout), densinfo[i].t_name); else printf (_("HHCTC004I %s tape density code: 0x%lX\n"), (devnamein ? devnamein : devnameout), density); if (mtget.mt_gstat != 0) print_status ((devnamein ? devnamein : devnameout), mtget.mt_gstat); /* Open the disk file */ if (filenamein) { hostpath( pathname, filenamein, sizeof(pathname) ); diskfd = hopen(pathname, O_RDONLY | O_BINARY); } else { hostpath( pathname, filenameout, sizeof(pathname) ); diskfd = hopen(pathname, O_WRONLY | O_CREAT | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP); } if (diskfd < 0) { printf (_("HHCTC007E Error opening %s: errno=%d: %s\n"), (filenamein ? filenamein : filenameout), errno, strerror(errno)); EXIT( RC_ERROR_OPENING_AWS_FILE ); } /* Copy blocks from input to output */ fileno = 1; blkcount = 0; totalblks = 0; minblksz = 0; maxblksz = 0; len = 0; bytes_read = 0; bytes_written = 0; file_bytes = 0; #if defined(EXTERNALGUI) // Notify the GUI of the high-end of the copy-progress range... if ( extgui ) { // Retrieve BOT block-id... VERIFY( 0 == ioctl_tape( devfd, MTIOCPOS, (char*)&mtpos ) ); is3590 = ((mtpos.mt_blkno & 0x7F000000) != 0x01000000) ? 1 : 0; if (!is3590) { // The seg# portion the SCSI tape physical // block-id number values ranges from 1 to 95... fprintf( stderr, "BLKS=%d\n", 95 ); } else { // FIXME: 3590s (e.g. Magstar) use 32-bit block addressing, // and thus its block-id does not contain a seg# value, so // we must use some other technique. For now, we'll simply // presume the last block on the tape is block# 0x003FFFFF // (just to keep things simple). fprintf( stderr, "BLKS=%d\n", 0x003FFFFF ); } // Init time of last issued progress message prev_progress_time = time( NULL ); } #endif /*defined(EXTERNALGUI)*/ /* Perform the copy... */ while (1) { #if defined(EXTERNALGUI) /* Issue a progress message every few seconds... */ if ( extgui ) { if ( ( curr_progress_time = time( NULL ) ) >= ( prev_progress_time + PROGRESS_INTERVAL_SECS ) ) { prev_progress_time = curr_progress_time; if ( ioctl_tape( devfd, MTIOCPOS, (char*)&mtpos ) == 0 ) { if (!is3590) fprintf( stderr, "BLK=%ld\n", (mtpos.mt_blkno >> 24) & 0x0000007F ); else fprintf( stderr, "BLK=%ld\n", mtpos.mt_blkno ); } } } #endif /*defined(EXTERNALGUI)*/ /* Save previous block length */ prevlen = len; /* Read a block */ if (devnamein) len = read_scsi_tape(devfd, buf, sizeof(buf), &mtget); else len = read_aws_disk(diskfd, buf, sizeof(buf)); /* If returned with -1, end of tape; errors are handled by the read functions themselves */ if (len < 0) break; /* Check for tape mark */ if (len == 0) { /* Write tape mark to output file */ if (filenameout) write_tapemark_aws_disk(diskfd); else write_tapemark_scsi_tape(devfd); /* Print summary of current file */ if (blkcount) { ASSERT( file_bytes ); // (sanity check) printf (_("HHCTC009I File %u: Blocks=%u, Bytes=%"I64_FMT"d, Block size min=%u, " "max=%u, avg=%u\n"), fileno, blkcount, file_bytes, minblksz, maxblksz, (int)file_bytes/blkcount); } else { ASSERT( !file_bytes ); // (sanity check) } /* Show the 'tapemark' AFTER the above file summary since that's the actual physical sequence of events; i.e. the file data came first THEN it was followed by a tapemark */ printf(_(" (tapemark)\n")); // (align past HHCmsg#) /* Reset counters for next file */ if (blkcount) fileno++; minblksz = 0; maxblksz = 0; blkcount = 0; file_bytes = 0; continue; } /* Count blocks and block sizes */ blkcount++; totalblks++; bytes_read += len; file_bytes += len; if (len > maxblksz) maxblksz = len; if (minblksz == 0 || len < minblksz) minblksz = len; /* Print standard labels */ if (1 && blkcount < 4 && len == 80 && (0 || memcmp( buf, vollbl, 3 ) == 0 || memcmp( buf, hdrlbl, 3 ) == 0 || memcmp( buf, eoflbl, 3 ) == 0 || memcmp( buf, eovlbl, 3 ) == 0 ) ) { for (i=0; i < 80; i++) labelrec[i] = guest_to_host(buf[i]); labelrec[i] = '\0'; printf (_("HHCTC012I %s\n"), labelrec); } else { ASSERT(blkcount); #if defined(EXTERNALGUI) if ( !extgui ) #endif printf( _("File %u: Block %u\r"), fileno, blkcount ); } /* Write block to output file */ if (filenameout) write_aws_disk(diskfd, buf, len); else write_scsi_tape(devfd, buf, len); } /* end while */ /* Print run totals, close files, and exit... */ #define ONE_MEGABYTE ( 1024 * 1024 ) #define HALF_MEGABYTE ( ONE_MEGABYTE / 2 ) printf ( _( "HHCTC000I Successful completion;\n" " Bytes read: %"I64_FMT"d (%3.1f MB), Blocks=%u, avg=%u\n" ) , bytes_read ,(double) ( bytes_read + HALF_MEGABYTE ) / (double) ONE_MEGABYTE ,totalblks ,totalblks ? (int)bytes_read/totalblks : -1 ); printf ( _( " Bytes written: %"I64_FMT"d (%3.1f MB)\n" ) , bytes_written ,(double) ( bytes_written + HALF_MEGABYTE ) / (double) ONE_MEGABYTE ); close (diskfd); /* Rewind the tape back to the beginning again before exiting */ opblk.mt_op = MTREW; opblk.mt_count = 1; rc = ioctl_tape (devfd, MTIOCTOP, (char*)&opblk); if (rc < 0) { printf (_("HHCTC006E Error rewinding %s: rc=%d, errno=%d: %s\n"), (devnamein ? devnamein : devnameout), rc, errno, strerror(errno)); EXIT( RC_ERROR_REWINDING_SCSI ); } close_tape (devfd); EXIT( RC_SUCCESS ); return(0); /* Make -Wall happy */ } /* end function main */ #endif /* defined(OPTION_SCSI_TAPE) */ hercules-3.12/tapemap.c0000664000175000017500000001666712564723224012016 00000000000000/* TAPEMAP.C (c) Copyright Jay Maynard, 2000-2009 */ /* Map AWSTAPE format tape image */ /*-------------------------------------------------------------------*/ /* This program reads an AWSTAPE format tape image file and produces */ /* a map of the tape, printing any standard label records it finds. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /*-------------------------------------------------------------------*/ /* Structure definition for AWSTAPE block header */ /*-------------------------------------------------------------------*/ typedef struct _AWSTAPE_BLKHDR { HWORD curblkl; /* Length of this block */ HWORD prvblkl; /* Length of previous block */ BYTE flags1; /* Flags byte 1 */ BYTE flags2; /* Flags byte 2 */ } AWSTAPE_BLKHDR; /* Definitions for AWSTAPE_BLKHDR flags byte 1 */ #define AWSTAPE_FLAG1_NEWREC 0x80 /* Start of new record */ #define AWSTAPE_FLAG1_TAPEMARK 0x40 /* Tape mark */ #define AWSTAPE_FLAG1_ENDREC 0x20 /* End of record */ /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static BYTE vollbl[] = "\xE5\xD6\xD3"; /* EBCDIC characters "VOL" */ static BYTE hdrlbl[] = "\xC8\xC4\xD9"; /* EBCDIC characters "HDR" */ static BYTE eoflbl[] = "\xC5\xD6\xC6"; /* EBCDIC characters "EOF" */ static BYTE eovlbl[] = "\xC5\xD6\xE5"; /* EBCDIC characters "EOV" */ static BYTE buf[65536]; #ifdef EXTERNALGUI /* Report progress every this many bytes */ #define PROGRESS_MASK (~0x3FFFF /* 256K */) /* How many bytes we've read so far. */ long curpos = 0; long prevpos = 0; #endif /*EXTERNALGUI*/ /*-------------------------------------------------------------------*/ /* TAPEMAP main entry point */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int i; /* Array subscript */ int len; /* Block length */ int prevlen; /* Previous block length */ char *filename; /* -> Input file name */ int infd = -1; /* Input file descriptor */ int fileno; /* Tape file number */ int blkcount; /* Block count */ int curblkl; /* Current block length */ int minblksz; /* Minimum block size */ int maxblksz; /* Maximum block size */ BYTE labelrec[81]; /* Standard label (ASCIIZ) */ AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ char pathname[MAX_PATH]; /* file path in host format */ INITIALIZE_UTILITY("tapemap"); /* Display the program identification message */ display_version (stderr, "Hercules tape map program ", FALSE); /* The only argument is the tape image file name */ if (argc == 2 && argv[1] != NULL) { filename = argv[1]; } else { printf ("Usage: tapemap filename\n"); exit (1); } /* Open the tape device */ hostpath(pathname, filename, sizeof(pathname)); infd = hopen(pathname, O_RDONLY | O_BINARY); if (infd < 0) { printf ("tapemap: Error opening %s: %s\n", filename, strerror(errno)); exit (2); } /* Read blocks from the input file and report on them */ fileno = 1; blkcount = 0; minblksz = 0; maxblksz = 0; len = 0; while (1) { #ifdef EXTERNALGUI if (extgui) { /* Report progress every nnnK */ if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) ) { prevpos = curpos; fprintf( stderr, "IPOS=%ld\n", curpos ); } } #endif /*EXTERNALGUI*/ /* Save previous block length */ prevlen = len; /* Read a block from the tape */ len = read (infd, buf, sizeof(AWSTAPE_BLKHDR)); #ifdef EXTERNALGUI if (extgui) curpos += len; #endif /*EXTERNALGUI*/ if (len < 0) { printf ("tapemap: error reading header block from %s: %s\n", filename, strerror(errno)); exit (3); } /* Did we finish too soon? */ if ((len > 0) && (len < (int)sizeof(AWSTAPE_BLKHDR))) { printf ("tapemap: incomplete block header on %s\n", filename); exit(4); } /* Check for end of tape. */ if (len == 0) { printf ("End of tape.\n"); break; } /* Parse the block header */ memcpy(&awshdr, buf, sizeof(AWSTAPE_BLKHDR)); /* Tapemark? */ if ((awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) != 0) { /* Print summary of current file */ printf ("File %u: Blocks=%u, block size min=%u, max=%u\n", fileno, blkcount, minblksz, maxblksz); /* Reset counters for next file */ fileno++; minblksz = 0; maxblksz = 0; blkcount = 0; } else /* if(tapemark) */ { /* Count blocks and block sizes */ blkcount++; curblkl = awshdr.curblkl[0] + (awshdr.curblkl[1] << 8); if (curblkl > maxblksz) maxblksz = curblkl; if (minblksz == 0 || curblkl < minblksz) minblksz = curblkl; /* Read the data block. */ len = read (infd, buf, curblkl); #ifdef EXTERNALGUI if (extgui) curpos += len; #endif /*EXTERNALGUI*/ if (len < 0) { printf ("tapemap: error reading data block from %s: %s\n", filename, strerror(errno)); exit (5); } /* Did we finish too soon? */ if ((len > 0) && (len < curblkl)) { printf ("tapemap: incomplete final data block on %s, " "expected %d bytes, got %d\n", filename, curblkl, len); exit(6); } /* Check for end of tape */ if (len == 0) { printf ("tapemap: header block with no data on %s\n", filename); exit(7); } /* Print standard labels */ if (len == 80 && blkcount < 4 && (memcmp(buf, vollbl, 3) == 0 || memcmp(buf, hdrlbl, 3) == 0 || memcmp(buf, eoflbl, 3) == 0 || memcmp(buf, eovlbl, 3) == 0)) { for (i=0; i < 80; i++) labelrec[i] = guest_to_host(buf[i]); labelrec[i] = '\0'; printf ("%s\n", labelrec); } } /* end if(tapemark) */ } /* end while */ /* Close files and exit */ close (infd); return 0; } /* end function main */ hercules-3.12/tapesplt.c0000664000175000017500000002441712564723224012213 00000000000000/* TAPESPLT.C (c) Copyright Jay Maynard, 2000-2009 */ /* Split AWSTAPE format tape image */ /*-------------------------------------------------------------------*/ /* This program reads an AWSTAPE format tape image file and produces */ /* output files containing pieces of it, controlled by command line */ /* options. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #include "hercules.h" /*-------------------------------------------------------------------*/ /* Structure definition for AWSTAPE block header */ /*-------------------------------------------------------------------*/ typedef struct _AWSTAPE_BLKHDR { HWORD curblkl; /* Length of this block */ HWORD prvblkl; /* Length of previous block */ BYTE flags1; /* Flags byte 1 */ BYTE flags2; /* Flags byte 2 */ } AWSTAPE_BLKHDR; /* Definitions for AWSTAPE_BLKHDR flags byte 1 */ #define AWSTAPE_FLAG1_NEWREC 0x80 /* Start of new record */ #define AWSTAPE_FLAG1_TAPEMARK 0x40 /* Tape mark */ #define AWSTAPE_FLAG1_ENDREC 0x20 /* End of record */ /*-------------------------------------------------------------------*/ /* Static data areas */ /*-------------------------------------------------------------------*/ static BYTE vollbl[] = "\xE5\xD6\xD3"; /* EBCDIC characters "VOL" */ static BYTE hdrlbl[] = "\xC8\xC4\xD9"; /* EBCDIC characters "HDR" */ static BYTE eoflbl[] = "\xC5\xD6\xC6"; /* EBCDIC characters "EOF" */ static BYTE eovlbl[] = "\xC5\xD6\xE5"; /* EBCDIC characters "EOV" */ static BYTE buf[65536]; #ifdef EXTERNALGUI /* Report progress every this many bytes */ #define PROGRESS_MASK (~0x3FFFF /* 256K */) /* How many bytes we've read so far. */ long curpos = 0; long prevpos = 0; #endif /*EXTERNALGUI*/ /*-------------------------------------------------------------------*/ /* tapesplt main entry point */ /*-------------------------------------------------------------------*/ int main (int argc, char *argv[]) { int rc; /* Return code */ int i; /* Array subscript */ int len; /* Block length */ int prevlen; /* Previous block length */ char *infilename; /* -> Input file name */ char *outfilename; /* -> Current out file name */ int infd = -1; /* Input file descriptor */ int outfd = -1; /* Current out file desc */ int fileno; /* Tape file number */ int blkcount; /* Block count */ int curblkl; /* Current block length */ int minblksz; /* Minimum block size */ int maxblksz; /* Maximum block size */ int outfilenum; /* Current out file# in argv */ int outfilecount; /* Current # files copied */ int files2copy; /* Current # files to copy */ BYTE labelrec[81]; /* Standard label (ASCIIZ) */ AWSTAPE_BLKHDR awshdr; /* AWSTAPE block header */ char pathname[MAX_PATH]; /* file path in host format */ INITIALIZE_UTILITY("tapesplt"); /* Display the program identification message */ display_version (stderr, "Hercules tape split program ", FALSE); /* The only argument is the tape image file name */ if (argc > 3 && argv[1] != NULL) { infilename = argv[1]; } else { printf ("Usage: tapesplt infilename outfilename count [...]\n"); exit (1); } /* Open the tape device */ hostpath(pathname, infilename, sizeof(pathname)); infd = hopen(pathname, O_RDONLY | O_BINARY); if (infd < 0) { printf ("tapesplt: error opening input file %s: %s\n", infilename, strerror(errno)); exit (2); } /* Copy blocks from input to output files */ fileno = 1; blkcount = 0; minblksz = 0; maxblksz = 0; len = 0; for (outfilenum = 2; outfilenum < argc; outfilenum += 2) { outfilename = argv[outfilenum]; printf ("Writing output file %s.\n", outfilename); hostpath(pathname, outfilename, sizeof(pathname)); outfd = hopen(pathname, O_WRONLY | O_CREAT | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP); if (outfd < 0) { printf ("tapesplt: error opening output file %s: %s\n", outfilename, strerror(errno)); exit (3); } if (outfilenum == argc) { /* count not specified for last file, so use big number */ files2copy = 32767; } else { files2copy = atoi(argv[outfilenum + 1]); } /* Copy just that many files */ for (outfilecount = 0; outfilecount < files2copy; ) { /* Save previous block length */ prevlen = len; /* Read a block from the tape */ len = read (infd, buf, sizeof(AWSTAPE_BLKHDR)); if (len < 0) { printf ("tapesplt: error reading header block from %s: %s\n", infilename, strerror(errno)); exit (4); } /* Did we finish too soon? */ if ((len > 0) && (len < (int)sizeof(AWSTAPE_BLKHDR))) { printf ("tapesplt: incomplete block header on %s\n", infilename); exit(5); } #ifdef EXTERNALGUI if (extgui) { curpos += len; /* Report progress every nnnK */ if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) ) { prevpos = curpos; fprintf( stderr, "IPOS=%ld\n", curpos ); } } #endif /*EXTERNALGUI*/ /* Check for end of tape. */ if (len == 0) { printf ("End of input tape.\n"); break; } /* Copy the header to the output file. */ rc = write(outfd, buf, sizeof(AWSTAPE_BLKHDR)); if (rc < (int)sizeof(AWSTAPE_BLKHDR)) { printf ("tapesplt: error writing block header to %s: %s\n", outfilename, strerror(errno)); exit(6); } /* Parse the block header */ memcpy(&awshdr, buf, sizeof(AWSTAPE_BLKHDR)); /* Tapemark? */ if ((awshdr.flags1 & AWSTAPE_FLAG1_TAPEMARK) != 0) { /* Print summary of current file */ printf ("File %u: Blocks=%u, block size min=%u, max=%u\n", fileno, blkcount, minblksz, maxblksz); /* Reset counters for next file */ fileno++; minblksz = 0; maxblksz = 0; blkcount = 0; /* Count the file we just copied. */ outfilecount++; } else /* if(tapemark) */ { /* Count blocks and block sizes */ blkcount++; curblkl = awshdr.curblkl[0] + (awshdr.curblkl[1] << 8); if (curblkl > maxblksz) maxblksz = curblkl; if (minblksz == 0 || curblkl < minblksz) minblksz = curblkl; /* Read the data block. */ len = read (infd, buf, curblkl); if (len < 0) { printf ("tapesplt: error reading data block from %s: %s\n", infilename, strerror(errno)); exit (7); } /* Did we finish too soon? */ if ((len > 0) && (len < curblkl)) { printf ("tapesplt: incomplete final data block on %s: " "expected %d bytes, got %d\n", infilename, curblkl, len); exit(8); } /* Check for end of tape */ if (len == 0) { printf ("tapesplt: header block with no data on %s\n", infilename); exit(9); } #ifdef EXTERNALGUI if (extgui) { curpos += len; /* Report progress every nnnK */ if( ( curpos & PROGRESS_MASK ) != ( prevpos & PROGRESS_MASK ) ) { prevpos = curpos; fprintf( stderr, "IPOS=%ld\n", curpos ); } } #endif /*EXTERNALGUI*/ /* Copy the header to the output file. */ rc = write(outfd, buf, len); if (rc < len) { printf ("tapesplt: error writing data block to %s: %s\n", outfilename, strerror(errno)); exit(10); } /* Print standard labels */ if (len == 80 && blkcount < 4 && (memcmp(buf, vollbl, 3) == 0 || memcmp(buf, hdrlbl, 3) == 0 || memcmp(buf, eoflbl, 3) == 0 || memcmp(buf, eovlbl, 3) == 0)) { for (i=0; i < 80; i++) labelrec[i] = guest_to_host(buf[i]); labelrec[i] = '\0'; printf ("%s\n", labelrec); } } /* end if(tapemark) */ } /* end for(outfilecount) */ close(outfd); } /* end for(outfilenum) */ /* Close files and exit */ close (infd); return 0; } /* end function main */ hercules-3.12/COPYRIGHT0000664000175000017500000000053712564723224011503 00000000000000All materials in this distribution are copyrighted by Roger Bowler and others. Hercules may be distributed under the terms of the Q Public License Version 1.0 Please refer to: http://www.hercules-390.org/herclic.html for details. In the context of this license, the initial developers of the software are Roger Bowler, Jan Jaeger, and Jay Maynard. hercules-3.12/hercules.cnf0000664000175000017500000001232512564723224012510 00000000000000# # Sample configuration file for Hercules ESA/390 emulator # #------------------------------------------------------------------------------ # CPU Configuration #------------------------------------------------------------------------------ CPUSERIAL 002623 # CPU serial number CPUMODEL 3090 # CPU model number MODEL EMULATOR # STSI returned model PLANT ZZ # STSI returned plant MANUFACTURER HRC # STSI returned manufacturer LPARNAME HERCULES # DIAG 204 returned lparname CPUVERID FD # CPU Version Identification MAINSIZE 64 # Main storage size in megabytes XPNDSIZE 0 # Expanded storage size in megabytes NUMCPU 1 # Number of CPUs # NUMVEC 1 # Number of Vector Processors MAXCPU 8 # Maximum number of CPUs ARCHMODE ESA/390 # Architecture mode S/370, ESA/390 or z/Arch ALRF DISABLE # ASN-and-LX-Reuse facility ECPSVM NO # VM Assist : NO or Level (20 recommended) #------------------------------------------------------------------------------ # OS Tailoring #------------------------------------------------------------------------------ LOADPARM 0120.... # IPL parameter OSTAILOR LINUX # OS tailoring SYSEPOCH 1900 # Base year for initial TOD clock # TZOFFSET 0 # Using UTC (GMT) #------------------------------------------------------------------------------ # Hercules Service Processor and Hercules Application Window #------------------------------------------------------------------------------ # MODPATH /usr/local/lib/hercules # Where to search for modules # LDMOD dyninst tcpip # Modules to be loaded #------------------------------------------------------------------------------ # Hercules Service Processor and Hercules Application Window #------------------------------------------------------------------------------ CODEPAGE default # CodePage conversion table DIAG8CMD disable # OS may not issue commands via DIAG 8 HTTPPORT 8081 noauth userid password # HTTP server port # HTTPROOT /usr/local/share/hercules/ # HTTP root directory PANRATE FAST # Panel refresh rate #------------------------------------------------------------------------------- # Advanced Hercules Performance Tailoring # # +----------------------------------------------------------------+ # | Caution: Modification of these parameters may adversely | # | affect the performance of the host system | # | and/or Hercules. | # +----------------------------------------------------------------+ #------------------------------------------------------------------------------- # HERCPRIO 0 # Hercules process runs at Normal priority # CPUPRIO 15 # CPU thread(s) run at Low priority # DEVPRIO 8 # Device thread(s) run at Below Normal priority # TODPRIO -20 # TOD Clock and timer thread are Time Critical #------------------------------------------------------------------------------- # Integrated Hercules I/O Controller # # DEVTMAX 0 # Device threads, 8 on Windows, else unlimited CNSLPORT 3270 # TCP port number to which consoles connect # SHRDPORT 3990 # TCP port number for sharing DASD images on # this instance of Hercules (inactive) # .-----------------------Device number # | .-----------------Device type # | | .---------File name and parameters # | | | # V V V # ---- ---- -------------------- 0009 3215-C / noprompt 000C 3505 ./util/zzsacard.bin 000D 3525 punch00d.txt ascii 000E 1403 print00e.txt crlf 001F 3270 # The following statements are examples. Some of them require # user tailoring before being used. # 0580 3420 ickdsf.ipl # 0120 3380 mvsv5r.120 # 0121 3380 mvsv5d.121 # 0122 3380 mvswk1.122 # 0140 9336 dosres.140 # 0141 9336 syswk1.141 # # The following statement defines 3 3270 devices starting # at address 0200 # 0200.3 3270 # # The following statement defines 3480 devices # at addresses 0280 to 028F # 280-28F 3480 # # The following statement defines 3420 devices # at addresses 02C0 & 02C2 # 2C0,2C2 3420 # 0300 3370 sysres.300 # # The following statements define 3380 Devices # with the CUU substituted in the device file name # device file names will be # 400.3380, 401.3380, 402.3380 and 403.3380 # 400-403 3380 $(CUU).3380 # # CCUU may also be used to define a 4 digit device address # in the name # device file names will be # 0480.3380, 0481.3380, 0482.3380 and 0483.3380 # 480-483 3380 $(CCUU).3380 # # 0700 3270 hercules-3.12/cckdfix.c0000664000175000017500000000643312564723224011770 00000000000000/* CCKDFIX.C (c) Copyright Greg Smith, 2000-2009 */ /* Correct compressed CKD file. */ #include "hercules.h" int main ( int argc, char *argv[]) { int fd; CKDDASD_DEVHDR devhdr; CCKDDASD_DEVHDR cdevhdr; int heads, cyls, devt; char pathname[MAX_PATH]; hostpath(pathname, argv[1], sizeof(pathname)); fd = hopen(pathname, O_RDWR|O_BINARY); if (fd < 0) return 1; read (fd, &devhdr, CKDDASD_DEVHDR_SIZE); read (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); /* --------------------------------------- */ /* Device header updates */ /* --------------------------------------- */ /* device identifier */ // memcpy (devhdr.devid, "CKD_C370", 8); /* number of heads per cylinder must be in little-endian byte order */ // devhdr.heads[3] = (heads >> 24) & 0xFF; // devhdr.heads[2] = (heads >> 16) & 0xFF; // devhdr.heads[1] = (heads >> 8) & 0xFF; // devhdr.heads[0] = heads & 0xFF; /* device type -- last two digits */ // devhdr.devtype = devt; /* eg 0x90 for 3390 */ /* file sequence number; must be zero for compressed ckd dasd emulation */ // devhdr.fileseq = 0; /* highest cylinder on this file; must be zero for compressed ckd dasd emulation */ // devhdr.highcyl[0] = 0; // devhdr.highcyl[1] = 0; // memset (&devhdr.resv, 0, 492); /* --------------------------------------- */ /* Compressed device header updates */ /* --------------------------------------- */ /* version-release-modification level */ // cdevhdr.vrm[0] = CCKD_VERSION; // cdevhdr.vrm[0] = CCKD_RELEASE; // cdevhdr.vrm[0] = CCKD_MODLVL; /* options byte */ // cdevhdr.options = 0; // cdevhdr.options |= CCKD_NOFUDGE; // cdevhdr.options |= CCKD_BIGENDIAN; // cdevhdr.options |= CCKD_OPENED; /* lookup table sizes*/ // cdevhdr.numl1tab = (cyls * heads) >> 8; // if ((cyls * heads) & 0xff != 0) // cdevhdr.numl1tab++; // cdevhdr.numl2tab = 256; /* free space header -- set to zeroes to force cckdcdsk to rebuild the free space */ // cdevhdr.size = cdevhdr.used = cdevhdr.free = // cdevhdr.free_total = cdevhdr.free_largest = // cdevhdr.free_number = cdevhdr.free_imbed = 0; /* number of cylinders on the emulated device must be in little-endian byte order */ // cdevhdr.cyls[3] = (cyls >> 24) & 0xFF; // cdevhdr.cyls[2] = (cyls >> 16) & 0xFF; // cdevhdr.cyls[1] = (cyls >> 8) & 0xFF; // cdevhdr.cyls[0] = cyls & 0xFF; // cdevhdr.resv1 = 0; /* compression algorithm and parameter */ // cdevhdr.compress = CCKD_COMPRESS_NONE; // cdevhdr.compress_parm = 0; // cdevhdr.compress = CCKD_COMPRESS_ZLIB; // cdevhdr.compress_parm = Z_DEFAULT_COMPRESSION; // cdevhdr.compress = CCKD_COMPRESS_BZIP2; // cdevhdr.compress_parm = 5; // memset (&cdevhdr.resv2, 0, 464); lseek (fd, 0, SEEK_SET); write (fd, &devhdr, CKDDASD_DEVHDR_SIZE); write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE); close (fd); return 0; } hercules-3.12/README.COMMADPT0000664000175000017500000001311312564723224012265 00000000000000Preliminary 2703 BSC Support Only allows Point to Point connection. Hercules device statement : CCUU 2703 lport=port lhost=host rhost=host rport=port dial=IN|OUT|INOUT|NO [pto=nnn|0|-1] [rto=nnn|0|-1] [eto=nnn|0|-1] lport : the local TCP port number or service name on which the line will listen for incoming TCP calls This parameter is irrelevant and is ignored for DIAL=OUT for DIAL=IN|INOUT|NO, this parameter is mandatory cwlhost : The local interface IP address on which to listen. if not specified, all interfaces will be used. ex: lhost=127.0.0.1 : Only accept calls from local host lhost=192.168.0.1 : Only accept calls from hosts that can be routed through the interface that has an IP address of 192.168.0.1 If there is no 192.168.0.1 local IP address, this will fail. This parameter is irrelevant and is ignored for DIAL=OUT for DIAL=IN|INOUT|NO, this parameter is mandatory rhost : the remote host ip address or name This parameter is irrelevant and is ignored for DIAL=IN for DIAL=OUT|INOUT|NO, this parameter is mandatory rport : the remote port number or service name This parameter is irrelevant and is ignored for DIAL=IN for DIAL=OUT|INOUT|NO, this parameter is mandatory rto, pto, eto : Read, Poll and Enable Timeout values in miliseconds. specifying 0 means No Timeout (infinite wait). -1 Means immediate timeout. The read timeout is how long the handler will wait for an ending character after the last character was received or the I/O initiated. The read timeout default is 3000 Miliseconds (3 Seconds) The poll timeout is how long the handler will wait for a polled station to respond to a poll request. The poll timeout default is 3000 Miliseconds (3 Seconds) The enable timeout is how long the handler will wait for the TCP connection to be established. The enable timeout default is 10000 Miliseconds (10 Seconds), except if DIAL=NO is also specified, in which case the enable timeout defaults to 0. Note : the ETO parameter is ignored if DIAL=NO is not specified. for a dialed line, there is no enable timeout. If the eto parameter is specified and DIAL is not "NO", then a warning message is issued and the parameter is ignored. dial=IN|OUT|INOUT|NO Indicate call direction (if any). This parameter also modifies the behaviour of certain CCWS as well as TCP incoming call handling : ENABLE : DIAL=IN|DIAL=INOUT Wait forever for an incoming call DIAL=NO Completes immediatelly if a call is already present Otherwise, attemps connecting to the remote end if the call fails, ENABLE exits with Int Req status DIAL=OUT Enable is not a valid CCW for a DIALOUT only line DIAL : DIAL=IN|DIAL=NO DIAL is not a valid CCW for a DIAL IN or non-switched line DIAL=OUT|DIAL=INOUT The outgoing call is attempted Incomming TCP call : In any case, if a call is already present, the call is rejected. DIAL=NO : The call is accepted, even if no CCW is currently executing DIAL=OUT : The call is rejected DIAL=IN|DIAL=INOUT The call is accepted if the line is currently executing an ENABLE ccw. The communication protocol : The communication protocol is basic. Every character written by the guest program with a WRITE CCW is transfered to the remote end, untranslated and untouched (except for Transparent BSC rules which deem that DLE characters are doubled when the program has previously written a DLE/STX sequence). Dial data format Dial data is originally as follows : x x x x 0 0 0 0 : Dial # 0 ......... x x x x 1 0 0 1 : Dial # 9 x x x x 1 1 0 0 : EON x x x x 1 1 0 1 : SEP In order to perform an outgoing call, the data must follow these specifications : N[N[N]]SEPN[N[N]]SEPN[N[N]]SEPN[N[N]]]SEPN[..[N]][EON] Where N is any dialing number from 0 to 9 and SEP is the separator. The 4 first group of digits represet the IP address. The last group represent a TCP port number. For example (* is the SEP character representation) : 192*168*0*1*8888 : will issue a TCP connection to 192.168.0.1 port 8888 The EON is optional. If it is present, it must be the last character of the dial data. Bugs, Caveats The Address Prepare is not implemented The POLL CCW Has not been tested Group DIAL IN is not implemented DIAL CCW Not tested There is 1 thread per line, when there should be 1 thread for ALL lines. MAXDEVT may have to be adjusted under WINDOWS to accomodate for a large number of lines (because some I/O may take an undefinite amount of time). There is no 'REAL' Bsc line support yet. hercules-3.12/README.DYNMOD0000664000175000017500000001053412564723224012057 00000000000000------------------------------------------------------------------------------- Hercules Dynamic Modules (on Windows) ------------------------------------------------------------------------------- Required Files Required files: makefile: "{modname}.msvc" defines module name and source file(s) resource file: "{modname}.rc" the module's version resource file ------------------------------------------------------------------------------- makefile stub format Required makefile format: # Module name: DYNMOD = {modname} # Source files: DYNOBJ = \ $(O){srcfile1}.obj \ $(O){srcfile2}.obj \ $(O){srcfile3}.obj ... etc... Your makefile is !INCLUDEd as part of Hercules's main makefile and thus your dynamic module gets built along with the rest of Hercules. ------------------------------------------------------------------------------- The MAKE/BUILD command Building (making): dynmake.bat {projdir} {modname} {build_type} {num_cpus} [-a|clean] e.g.: "X:\Hercules\dynmake.bat" "$(SolutionDir)" {modname} RETAIL 32 -a The {projdir} value you pass MUST be a fully qualified path to your dynamic module's project directory where all of your files are. The dynamke.bat command you invoke should also be a fully qualifed path to the desired Hercules dynmake.bat file. The other arguments (i.e. {build_type}, {num_cpus}, etc) are identical to the values normally specified for the main Hercules "makefile.bat" command used to build Hercules with. Refer to makefile.bat for details. ------------------------------------------------------------------------------- Pre-Build event and Post-Build event callbacks Optional files: prebuild.bat Called before the main Hercules makefile.bat is called. postbld.bat Called after the main Hercules makefile.bat is called. During the build process, dynmake.bat checks if the file exists in your specified project directory and if it does, calls it with the following parameters: {hercdir} {modname} {build_type} {num_cpus} [-a|clean] The {hercdir} value is the fully qualified path the main Hercules source code directory. The other parameters are the same values that you passed to the dynmake.bat command. ------------------------------------------------------------------------------- Resource Compiler For your convenience the following #defines are also passed to the resource compiler on the command-line during the actual build process: VERSION The Hercules version string (e.g. "3.06-svn-5602") TARGETFILENAME Your module name string (e.g. "{modname}.dll") MAX_CPU_ENGINES_STR Number of CPUs as a string (e.g. "32") Use them in your .rc resource file's VERSIONINFO structure as needed. ------------------------------------------------------------------------------- The Build Process Dynmake.bat first creates a work subdirectory beneath Hercules's main source code directory using the same name as the {modname} you passed to it. It then calls your prebuild.bat file if it exists. Use this callback to perform any pre-build adjustments to your source files that may be necessary before the actual build process begins. When your prebuild.bat returns, it then copys all *.c, *.h, *.rc, *.rc2 and *.msvc files from your project directory into its {modname} subdirectory and invokes Hercules's primary "makefile.bat" script to perform the actual build. When the build is done it then calls your postbld.bat callback if it exists. You can use this callback to copy the resulting binary from Hercules's output directory to your project directory or whatever other post-build processing your product may require. ------------------------------------------------------------------------------- More Information For additional information regarding dynamic modules please see the "Hercules Dynamic Loader" readme document called "README.HDL". ------------------------------------------------------------------------------- hercules-3.12/README.ECPSVM0000664000175000017500000001463312564723224012066 00000000000000ECPS:VM : Extended Control Program Support : VM/370 - AND - Extended VM Assists - Partial Privop Simulation And Virtual Interval Timer ************ CHANGE LOG **************** 07/07/03 : Changed description for configuration and commands ECPS:VM changed to ECPSVM (config) ecpsvm changed to ecpsvm (command) - PARTIAL IMPLEMENTATION DOCUMENTATION - ************************* Affected operating systems : VM/370 Release 6 (PTFs required - PLC 029 works fine) up to VM/SP 6 (with or without HPO option) --- VM/XA SF, VM/XA SP, VM/ESA and z/VM do NOT use these Assists, but rely on the SIE instruction to perform some of these functions. A VM/SP Guest (or VM/370 Guest with 4K Storage key updates) running under [z/]VM[/[XA|ESA]] will NOT have access to either the CP assists or VM Assists. The ECPS:VM Feature is disabled when running under SIE. ************************ How to enable VM Assists : In the HERCULES.CNF file, in the configuration section : ECPSVM YES|NO|LEVEL n (where n is the requested level.) If "YES" is specified, the most appropriate level is returned (Level 20) n Doesn't affect the operations of the assist but what level is reported to the program. - CAUTION - Use the 'n' form is not recommended, and is only provided for engineering use. ********** New panel command : 'ecpsvm' Subcommands : ecpsvm stats : Shows ECPS:VM Call/Hit statistics ecpsvm enable/disable feature : Enable/Disable named feature ecpsvm help : (guess) ecpsvm debug [feature|ALL|CPASSIST|VMASSIST] : Turn on debugging messages for a specific feature ecpsvm nodebug [feature|ALL|CPASSIST|VMASSIST] : Turn off... ecpsvm level [nn] : Force ECPS:VM to report a certain support level (or display the current support level) NOTE : ecpsvm disable does NOT entirelly disables CP ASSISTS. If it did (i.e. generate a program interrupt whenever a E6xx instruction is invoked) VM would abend immediatelly. Rather, ommit the ECPSVM statement in the configuration file. To determine the feature names, type "ecpsvm enable ALL". All the enabled features will be listed. the ecpsvm command is NOT case sensitive ********** Determining if the assist is used by VM : Use the 2 following CLASS A commands : CP QUERY CPASSIST CP QUERY SASSIST Both queries should return 'ON'. Also use the following CLASS G Command : CP QUERY SET 2nd line should indicate : ASSIST ON SVC TMR *********** Technical information the CP Assists provides The VM SCP with various microcoded instructions to shorten the supervisor pathlength. All microcoded instructions are priviledged instructions and have an opcode of E6xx. They are native representation of what the SCP would do in a similar case. For all cases where the assist is not able to resolve a situation, the E6XX instructions resolve to a no-op, thus leaving the responsability of the task to the original CP Code. The VM Assists alters the behaviour of certain priviledged instructions when executed in problem state (controled by the Problem State bit in the PSW) either by completely simulating the instruction (when feasable), Branching directly to the CP support module for that instruction (therefore bypassing Program interruption processing and instruction decoding), or generating a Program interruption otherwise. The VM Virtual Interval Timer assist allows updating of a Virtual Machine virtual interval timer directly by the microcode. Both CP And VM Assists are controled by real Control Register 6 which control availability, and behaviour of the assists. ************ Troubleshooting In the event that a certain CP or VM Assist disrupts normal operations, it is possible to selectivelly disable each discrete component. The best method is to disable ALL VM and CP Assists (Except STEVL and SSM if done prior to IPL) and to enable each feature until the problem occurs. If it is unknown whether the problem lies in the VM or CP Assist, it is also possible to enable/disable the entire group of assists. See the EVM ENA|DISA Commands. EVM STA allows to see how often each assist is invoked. The hit and hit ration makes it possible to determine how effective the assists are. A Low hit ratio may be normal in some situations (for example, the LPSW Hit ration will be very low when running VM under VM, because most PSW switches cannot be resolved by the assist) A Low invocation count simply shows that in THAT particular situation, the related assist is not used often (For example, there are very few LCTLs when running CMS). Some assists are just invoked once at IPL (STEVL). This is normal behaviour. ************ Implemented Assists : CP ASSISTS : FREEX, FRETX (CP Free Storage management) DISP0, DISP1, DISP2 (CP Dispatching) PGLOCK, PGULOCK (Real frame locking/unlocking) TRANBRNG, TRANLOCK (Virtual frame addressing/locking) SCNRU, SCNVU (Real/Virtual Device control block scan) STEVL (Store ECPS:VM support level) VM ASSISTS : Virtual Interval Timer LPSW Simulation SSM Simulation SVC Simulation LCTL Simulation Non-Implemented assists : CP ASSISTS : FREE/FRET : (Original (up to level 19) CP Storage Management - replaced by FREEX/FRETX) CCWGN, DFCCW, DNCCW, UXCCW : CCW/CSW Translation assists (Soon) LCSPG : Locate Changed Shared Page (Soon) VIPT, VIST : Virtual Translation Page/Segment Invalidation (Soon) LINK/RETURN (SVC 8/SVC 12) (Soon) Prefered Machine Assists (Insufficient information) .. Maybe others ... VM ASSISTS : V=R Shadow Table Bypass assists (Including LRA instruction) (note : The V=R Shadow Table Bypass assist is a feature which requires the guest program to be aware of the feature (Page 0 Relocation)) SIO (In progress - Partial sim) DIAG (In progress - Partial sim) IUCV (In Progress - Partial sim - VM/SP4 or later only) STxSM (Almost never invoked - ECMODE Only) ISK/SSK/ISKE/SSKE/IVSK (Extended Key Ops assist) VM Assists for MVS .. Maybe others ... ***************** BUGS & Caveats : ECPS:VM will NOT work in an AP or MP system. An AP or MP generated system locks the control blocks being manipulated by the assisted functions (VMBLOK, RDEVBLOK, VDEVBLOK, etc..). However, the current ECPS:VM implementation doesn't lock any of those structures. Therefore, CP will fairly quickly abend because it will find some of the control blocks to not have been locked when they should (various LOKXXX abends). Consequently, ECPS:VM must be disabled when a AP or MP system is used. ***************** Have Fun, --Ivan hercules-3.12/README.HDL0000664000175000017500000005312412564723224011476 00000000000000/* Hercules Dynamic Loader The dynamic loader is intended to supply a loading and linking mechanism, whereby routines, commands, instructions and functions can be dynamically added to hercules, without the need to rebuild or even restart hercules. The loader can be controlled by the following hercules commands: ldmod - Load modules named in module list rmmod - Unload modules named in list lsmod - List all modules and entry points lsdep - List all dependencies The ldmod statement may also appear in the hercules configuration file. configuration statement: modpath - Specifies where modules are loaded from The loader has 2 basic functions module load and module unload. Module load: int hdl_load(char *name, int flags); Where name is the module name, this name may include the path. If no path is given then the module is loaded from the default library search order. Note that this is different from the standard search order. flags may be one of the following: HDL_LOAD_DEFAULT or 0 - Default load HDL_LOAD_MAIN - Reserved for hercules use HDL_LOAD_NOUNLOAD - Module cannot be unloaded HDL_LOAD_FORCE - Override dependency check HDL_LOAD_NOMSG - Do not issue any error messages This function returns a zero value when the load is successful. Module unload: int hdl_dele(char *name); Where name is the name of the module that is to be unloaded. This function returns a zero value when the unload is successful. Resolving Symbols: void * HDL_FINDSYM(char *symbolname); This function will return the entry point of symbolname or zero when the symbol cannot be resolved. void * HDL_FINDNXT(current_entry point); This function will return the previous entry point. That is, the entry point which was current before the entry point as identified by current_entry point was registered. This function is intended to allow a module to call the original routine. An example of this is given in the panel_command entry as listed below. There are some special considerations for systems that do not support the concept of back-linking. Back-linking is the operating system support of dynamically resolving unresolved external references in a dynamic module, with the main module, or other loaded modules. Cygwin does not support back-linking and Cygwin specials are listed in this example with #if defined(WIN32). Some additional notes: Unload will remove all references to a specific module, but currently it will not actually remove the loaded module from memory. This is because there is no safe way (yet) to synchronize unloading of code and, besides, it may still be in use. This should however pose no practical limitations. When a module lists a new dependency, that dependency will be regis- tered. Unloading the module does not remove the dependency, this is to be consistent with the previous note about unloading. Diagnose F14 - dll interface Purpose: Allow external routines to be called from OS running under hercules external routines must reside in hercules dll's Instruction: Format: 83 r1 r3 d2(b2) r1: register containing real address of external routine name to be called this routine name is defined as CL32, and is subject to EBCDIC to ASCII translation under control of hercules codepages. This parameter must be 32 byte aligned. r3: register containing user parameter. d2(b2): 0xF14 External routine: void xxxx_diagf14_routine_name(int r1, int r3, REGS *regs); xxxx_diagf14_ prefix to routine_name xxxx being either s370, s390 or z900 depending on architecture mode. The instruction is subject to machine malfunction checking. The external routine may be interrupted when an extended wait or loop occurs. */ #include "hercules.h" #include "devtype.h" #include "opcode.h" /* Local definitions */ static void *gui_cpu_state(REGS *regs) { void *(*prev_cpu_state)(REGS *); /* CPU status update processing */ /* Call higher level routine if one exists */ if((prev_cpu_state = HDL_FINDNXT(gui_cpu_state))) return prev_cpu_state(regs); return NULL; } void *ProcessCommand (char *command) { void * (*prev_panel_command)(char *); if (strncasecmp(command,"ourcmd",6) == 0) { logmsg ("This is our command\n"); } else /* Call higher level command handler */ if((prev_panel_command = HDL_FINDNXT(ProcessCommand))) return prev_panel_command(command); return NULL; } /* The dependency section is - for all intents and purposes - called before the module is loaded. Its function is to check that there are no incompatibilities between this module and the version of hercules that we are running. Dependencies are identified by name, this name is given on the HDL_DEPENDENCY statement. Each dependency then has a version code, and a size code, where the version code is a character string, and the size code an integer value. If the version or size codes do not match with those in the hercules main module, the module cannot be loaded. The version is usually a character string that identifies the version of the component, and the size is to be the size of the component in the case of structures or unions. Version and size should be coded as following: #define HDL_VERS_SOMETHING "1.0" #define HDL_SIZE_SOMETHING sizeof(SOMETHING) where SOMETHING can be a structure or other component. the associated dependency statement: HDL_DEPENDENCY(SOMETHING); When a dependency is given that has not yet been registered, it will be registered, such that it can be checked in subsequent module loads. The dependency section is mandatory. */ HDL_DEPENDENCY_SECTION; { /* Define version dependencies that this module requires */ HDL_DEPENDENCY ( HERCULES ); HDL_DEPENDENCY ( SYSBLK ); HDL_DEPENDENCY ( REGS ); HDL_DEPENDENCY ( DEVBLK ); } END_DEPENDENCY_SECTION; /* The registration exports labels and their associated entry points to hercules, such that the symbols and associated entry points may be known to hercules and any other module that may have been loaded. The registration section is called once during module load. If we have registered a function that is also called from this DLL, then it must also be listed in the resolver section. This to ensure that the symbol is properly resolved when other modules are loaded. The registration section is optional. */ HDL_REGISTER_SECTION; { /* These are the entry points we export to Hercules All functions and labels used this dll must be static and non exportable, this to ensure that no foreign names are included by the system loader on systems that provide back-link support (mostly *nix systems) */ HDL_REGISTER ( daemon_task, external_gui_interface ); HDL_REGISTER ( debug_cpu_state, gui_cpu_state ); HDL_REGISTER ( panel_command, ProcessCommand ); } END_REGISTER_SECTION; /* The resolver section imports the entry points of symbols that have been previously registered. When a symbol is requested that has not been previously registered then the resolve function will search the loaded modules for that symbol, and register it implicitly. This latter function is mainly provided to support systems that do not have back-link support (most notably Cygwin). Entry points that are resolved should be indirect pointers, for example the panel_command routine is defined as: void *(*panel_command)(char *) The resolver may be called multiple times, the first time it is called is during module load, immediately after the registration section is called. It is subsequently called when other modules are loaded or unloaded. When a symbol cannot be resolved it will be set to NULL. The resolver section is optional. */ HDL_RESOLVER_SECTION; { /* These are Hercules's entry points that we need access to these may be updated by other loadable modules, so we need to resolve them here. */ HDL_RESOLVE ( panel_command ); HDL_RESOLVE ( debug_cpu_state ); HDL_RESOLVE_PTRVAR ( my_sysblk_ptr, sysblk ); } END_RESOLVER_SECTION; /* The device section is to register device drivers with hercules. It associates device types with device handlers If a device handler is not registered for a specific device type then and a loadable mode with the name of "hdtxxxx" (where xxxx is the device type) exists then that module is loaded Search order: 1) The most recently registered (ie loaded) device of the requested device type. 2) Device driver in external loadable module, where the module name is hdtxxxx (where xxxx is the device type ie module name hdtlcs for device type LCS or hdt2703 for device type 2703) 3) If the device is listed in the alias table (hdteq.c) then external module hdtyyyy will be loaded, where yyyy is the base name as listed in hdteq.c. The device name is always mapped to lower case when searching for loadable modules. The device section is optional */ HDL_DEVICE_SECTION; { HDL_DEVICE(1052,constty_device_hndinfo); HDL_DEVICE(3215,constty_device_hndinfo); } END_DEVICE_SECTION; /* The instruction section registers inserts optional instructions, or modifies existing instructions. Instructions are generally defined with DEF_INST(instname) which results in an external reference of s370_instname, s390_instname and z900_instname. If an instruction is not defined for a certain architecture mode then UNDEF_INST(instname) must be used for that given architecture mode. The instruction section is optional */ HDL_INSTRUCTION_SECTION; { HDL_DEFINST(HDL_INSTARCH_370,0xB2FE,new_B2FE_inst_doing_something); HDL_DEFINST(HDL_INSTARCH_390|HDL_INSTARCH_900,0xB2FD,new_B2FD_inst_doing_something_else); } END_INSTRUCTION_SECTION; /* The final section is called once, when the module is unloaded or when hercules terminates. A dll can reject being unloaded by returning a non-zero value in the final section. The final section is intended to be used to perform cleanup or indicate cleanup action to be taken. It may set a shutdown flag that is used within this dll that all local functions must now terminate. The final section is optional */ HDL_FINAL_SECTION; { } END_FINAL_SECTION; Below is Fish's sample code... /* Define version dependencies that this module requires... ** ** The following are the various Hercules structures whose layout your ** module depends on. The layout of the following structures (size and ** version) MUST match the layout that was used to build Hercules with. ** If the size/version of any of the following structures changes (and ** a new version of Hercules is built using the new layout), then YOUR ** module must also be built with the new layout as well. The layout of ** the structures as they were when your module is built MUST MATCH the ** layout as it was when the version of Hercules you're using was built. ** Further note that the below HDL_DEPENDENCY_SECTION is actually just ** a function that the hdl logic calls, and thus allows you to insert ** directly into the below section any specialized 'C' code you need. */ HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(REGS); HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); HDL_DEPENDENCY(WEBBLK); } END_DEPENDENCY_SECTION; /* Register re-bindable entry point with resident version, or UNRESOLVED ** ** The following section defines the entry points within Hercules that ** your module is overriding (replacing). Your module's functions will ** be called by Hercules instead of the normal Hercules function (if any). ** The functions defined below thus provide additional/new functionality ** above/beyond the functionality normally provided by Hercules. Be aware ** however that it is entirely possible for other dlls to subsequently ** override the same functions that you've overridden such that they end ** up being called before your override does and your override may thus ** not get called at all (depending on how their override is written). ** Note that the "entry-point name" does not need to correspond to any ** existing variable or function (i.e. the entry-point name is just that: ** a name, and nothing more. There does not need to be a variable defined ** anywhere in your module with that name). Further note that the below ** HDL_REGISTER_SECTION is actually just a function that the hdl logic ** calls, thus allowing you to insert directly into the below section ** any specialized 'C' code that you may need. */ HDL_REGISTER_SECTION; { /* register this as the address of entry-point name, this var or func */ HDL_REGISTER( panel_command, my_panel_command ); HDL_REGISTER( panel_display, my_panel_display ); HDL_REGISTER( some_exitpoint, UNRESOLVED ); } END_REGISTER_SECTION; /* Resolve re-bindable entry point on module load or unload... ** ** The following entries "resolve" entry points that your module ** needs. These entries define the names of registered entry points ** that you need "imported" into your dll so that you may call them ** directly yourself. The HDL_RESOLVE_PTRVAR macro is used to auto- ** matically set one of your own pointer variables to the registered ** entry point's currently registered value (usually an address of ** a function or variable). Note that the HDL_RESOLVER_SECTION is ** actually just a function that the hdl logic calls, thus allowing ** you to insert directly into the below section any specialized 'C' ** code that you may need. */ HDL_RESOLVER_SECTION; { /* Herc's registered entry points that you need to call directly yourself */ HDL_RESOLVE( config_command ); HDL_RESOLVE( some_exitpoint ); HDL_RESOLVE( debug_cpu_state ); HDL_RESOLVE( debug_program_interrupt ); HDL_RESOLVE( debug_diagnose ); /* The following illustrates how to use HDL_RESOLVE_PTRVAR macro to retrieve the address of one of Herc's registered entry points. Your pointer- Herc's registered variable name entry-point name */ HDL_RESOLVE_PTRVAR( my_sysblk_ptr, sysblk ); } END_RESOLVER_SECTION; /* The following section defines what should be done just before ** your module is unloaded. It is nothing more than a function that ** is called by hdl logic just before your module is unloaded, and ** nothing more. Thus you can place any 'C' code here that you want. */ HDL_FINAL_SECTION; { my_cleanup(); } END_FINAL_SECTION; /* DYNDIAG.C (c) Copyright Jan Jaeger, 2003 */ /* Hercules Dynamic Loader */ /* Sample diagf14 dll routine */ /* */ /* Assembler to call routine: */ /* */ /* LRA R1,=CL32'test' */ /* LRA R2,=X'01020304' USERPARM */ /* DC X'83120F14' DIAG R1,R2,X'F14' */ /* */ #include "hercules.h" #include "opcode.h" #include "inline.h" void ARCH_DEP(diagf14_test) (int r1, int r3, REGS *regs) { U32 r3loc; logmsg("diagf14: r3 = %8.8X\n",regs->GR_L(r3)); r3loc = ARCH_DEP(vfetch4) (regs->GR_L(r3), USE_REAL_ADDR, regs); logmsg("diagf14: *r3 = %8.8X\n",r3loc); } #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "dyndiag.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "dyndiag.c" #endif HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY (HERCULES); HDL_DEPENDENCY (REGS); HDL_DEPENDENCY (DEVBLK); HDL_DEPENDENCY (SYSBLK); } END_DEPENDENCY_SECTION; HDL_REGISTER_SECTION; { HDL_REGISTER(s370_diagf14_test,s370_diagf14_test); HDL_REGISTER(s390_diagf14_test,s390_diagf14_test); HDL_REGISTER(z900_diagf14_test,z900_diagf14_test); } END_REGISTER_SECTION; HDL_RESOLVER_SECTION; { } END_RESOLVER_SECTION; HDL_FINAL_SECTION; { } END_FINAL_SECTION; #endif /*!defined(_GEN_ARCH)*/ /* END DYNDIAG.C */ /* DYNCGI.C (c)Copyright Jan Jaeger, 2002-2003 */ /* HTTP cgi-bin routines */ /* This file contains cgi routines that may be executed on the */ /* server (ie under control of a hercules thread) */ /* */ /* */ /* Dynamically loaded cgi routines must be registered under the */ /* pathname that they are accessed with (ie /cgi-bin/test) */ /* All cgi pathnames must start with /cgi-bin/ */ /* */ /* */ /* The cgi-bin routines may call the following HTTP service routines */ /* */ /* char *cgi_variable(WEBBLK *webblk, char *name); */ /* This call returns a pointer to the cgi variable requested */ /* or a NULL pointer if the variable is not found */ /* */ /* char *cgi_cookie(WEBBLK *webblk, char *name); */ /* This call returns a pointer to the cookie requested */ /* or a NULL pointer if the cookie is not found */ /* */ /* char *cgi_username(WEBBLK *webblk); */ /* Returns the username for which the user has been authenticated */ /* or NULL if not authenticated (refer to auth/noauth parameter */ /* on the HTTPPORT configuration statement) */ /* */ /* char *cgi_baseurl(WEBBLK *webblk); */ /* Returns the url as requested by the user */ /* */ /* void html_header(WEBBLK *webblk); */ /* Sets up the standard html header, and includes the */ /* html/header.htmlpart file. */ /* */ /* void html_footer(WEBBLK *webblk); */ /* Sets up the standard html footer, and includes the */ /* html/footer.htmlpart file. */ /* */ /* int html_include(WEBBLK *webblk, char *filename); */ /* Includes an html file */ /* */ /* */ /* Jan Jaeger - 28/03/2002 */ #include "hstdinc.h" #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "httpmisc.h" #if defined(OPTION_HTTP_SERVER) void cgibin_test(WEBBLK *webblk) { html_header(webblk); hprintf(webblk->hsock, "

Sample cgi routine

\n"); html_footer(webblk); } HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); // HDL_DEPENDENCY(REGS); // HDL_DEPENDENCY(DEVBLK); // HDL_DEPENDENCY(SYSBLK); HDL_DEPENDENCY(WEBBLK); } END_DEPENDENCY_SECTION; HDL_REGISTER_SECTION; { HDL_REGISTER( /cgi-bin/test, cgibin_test ); } END_REGISTER_SECTION; HDL_RESOLVER_SECTION; { } END_RESOLVER_SECTION; HDL_FINAL_SECTION; { } END_FINAL_SECTION; #endif /*defined(OPTION_HTTP_SERVER)*/ /* TESTINS.C Test instruction */ #include "hercules.h" #include "opcode.h" /*-------------------------------------------------------------------*/ /* 0000 BARF - Barf [RR] */ /*-------------------------------------------------------------------*/ DEF_INST(barf) { int r1, r2; /* register values */ RR(inst, regs, r1, r2) logmsg("Barf\n"); ARCH_DEP(program_interrupt)(regs, PGM_OPERATION_EXCEPTION); } #if !defined(_GEN_ARCH) #if defined(_ARCHMODE2) #define _GEN_ARCH _ARCHMODE2 #include "testins.c" #endif #if defined(_ARCHMODE3) #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "testins.c" #endif HDL_DEPENDENCY_SECTION; { } END_DEPENDENCY_SECTION; HDL_INSTRUCTION_SECTION; { HDL_DEFINST(HDL_INSTARCH_ALL,0x00,barf); } END_INSTRUCTION_SECTION; #endif /*!defined(_GEN_ARCH)*/ hercules-3.12/README.NETWORKING0000664000175000017500000003754412564723224012566 00000000000000----------------------------------------------------------------- Hercules Networking ----------------------------------------------------------------- *** Please read herctcp.html as Roger explains how *** *** to set up TCP/IP networking with Hercules. *** All of the communications emulation implemented within Hercules use a CTCA (Channel to Channel Adapter) type device. Depending on the "flavor", the CTCA device will provide either a point-to-point or a virtual network adapter interface to the driving system's TCP/IP stack or in the case of CTCT, a "true" CTCA connection to another instance of Hercules via a TCP/IP connection. All current emulations, with the exception of VMNET, CTCT and CTCE use the Universal TUN/TAP driver on *nix and TunTap32 (WinPCap) on the Windows platforms which creates a network interface on the driving system which allow Hercules to present frames to, and receive frames from the TCP/IP stack. This network interface is configured on *nix platforms by the hercifc program which is invoked by Hercules after the TUN/TAP device is opened. The hercifc program runs as root. Please read herctcp.html for more information on the security implications of the hercifc program. Now for the gory details: --------------------------------------------------------------- *** Important information about changes to the *** *** Hercules configuration files - PLEASE READ *** The format of the Hercules configuration file statements for all of the networking emulations have changed from the previous releases of Hercules. The older format will still be accepted to maintain compatibility, however it is the recommendation of the maintainer that the new format be used. Also note that there is no distinction between the CTCI and CTCI-W32 modes any more, in fact CTCI-W32 does not exist in this release (other than to maintain compatibility with previous configuration files). --------------------------------------------------------------- *** Important information about changes to the *** *** Hercules configuration files - PLEASE READ *** In releases prior to Hercules version 3.00, all of the TCP/IP emulations required two addresses to be defined in the Hercules configuration file: one address for the read subchannel and the other for write. --------------------------------------------------------------- *** Important information about changes to the *** *** Hercules configuration files - PLEASE READ *** Hercules release version 3.00, however, [temporarily] changed the rules: With [ONLY!] version 3.00 of Hercules, only the FIRST address address need be specified in the configuration file. Hercules version 3.00 automatically creates the second address. Care must be taken to NOT define the second address [with Hercules version 3.00 ONLY!] or a configuration error will occur. --------------------------------------------------------------- *** Important information about changes to the *** *** Hercules configuration files - PLEASE READ *** Starting with Hercules version 3.01 however, we've gone back to doing things the way we ORIGINALLY were (and the way most users are used to (i.e. the way most users EXPECT things to work)): With Hercules version 3.01 you need to define BOTH addresses! Both the even numbered read device AS WELL AS the odd numbered write device must BOTH be defined in your Hercules configuration file starting with Hercules version 3.01. We apologize for the mess, but we thought having Herc automatically define the write device for you (as it does in version 3.00) would be easier for everyone. Turns out it caused a lot of problems with a lot of people, so we decided to go back to the original way. Again, we apologize for whatever headaches this may have caused anyone. --------------------------------------------------------------- *** Important information about changes to the *** *** Hercules configuration files - PLEASE READ *** Note that the VMNET and CTCT protocols have ALWAYS required BOTH addresses to be defined (i.e. ALL versions of Hercules, including version 3.00 as well, require BOTH even/odd read/write devices to be defined separately [in your Hercules configuration file]). --------------------------------------------------------------- The currently supported emulation modes are: CTCT - CTCA Emulation via TCP connection CTCE - Enhanced CTCA Emulation via CTP connection CTCI - Point-to-point connection to the host IP stack. LCS - LAN Channel Station (3172/OSA) VMNET - Point-to-point link via SLIP/VMNET ----------------------------------------------------------------- CTCT - Channel to Channel Emulation via TCP connection ----------------------------------------------------------------- This emulation mode provides protocol-independent communication with another instance of this driver via a TCP connection. This mode appears to the operating system running in the Hercules machine as an IBM 3088 Channel to Channel Adapter and can operate in either Basic or Extended mode. The configuration statement for CTCT is as follows: 3088 CTCT where: is the address of the CTCT device. is the TCP/IP port on the local system. is the IP address on the remote. is the TCP/IP port on the remote system. ----------------------------------------------------------------- CTCI - Channel to Channel link to Linux TCP/IP stack ----------------------------------------------------------------- This is a point-to-point link to the driving system's TCP/IP stack. From the point of view of the operating system running in the Hercules machine it appears to be a CTC link to a machine running TCP/IP for MVS or VM. CTCI uses the Universal TUN/TAP driver on *nix and Politecnico di Torino's WinPCap packet driver as well as Fish's TunTap32 and FishPack DLLs on Windows[1]. The configuration statement for CTCI is as follows: CTCI [options] where: is the address pair of the CTCI device. is the IP address of the Hercules (guest OS) side. is the IP address on the driving system. [options] can be any of the following: -n or --dev where is: [*nix] the name of the TUN/TAP special character device, normally /dev/net/tun. [Windows] is either the IP or MAC address of the driving systems network card. TunTap32 will automatically select the first network card it finds if this option is omitted, this may not be desirable for some users. -t or --mtu [*nix only] where is the maximum transmission unit size, normally 1500 -s or --netmask [*nix only] where is the netmask to be configured on the link. Note: Since this is a point-to-point link netmask is meaningless from the perspective of the actual network device. -m or --mac [Windows only] where is the optional hardware address of the interface in the format of either xx:xx:xx:xx:xx:xx or xx-xx-xx-xx-xx-xx. -k or --kbuff [Windows only] where is the size of the WinPCap kernel buffer size, normally 1024. -i or --ibuff [Windows only] where is the size of the WinPCap I/O buffer size, normally 64. -d or --debug this will turn on the internal debugging routines. Warning: This will produce a tremendous amount of output to the Hercules console. It is suggested that you only enable this at the request of the maintainers. ----------------------------------------------------------------- LCS - LAN Channel Station ----------------------------------------------------------------- This emulation mode appears to the operating system running in the Hercules machine as an IBM 8232 LCS device, an IBM 2216 router, a 3172 running ICP (Interconnect Communications Program), the LCS3172 driver of a P/390, or an IBM Open Systems Adapter. Rather than a point-to-point link, this emulation creates a virtual ethernet adapter through which the guest operating system running in the Hercules machine can communicate. As such, this mode is not limited to TCP/IP traffic, but in fact will handle any ethernet frame. The configuration statement for LCS is as follows: LCS [options] [] where: is the address pair of the LCS device. This pair must be an even-odd address. [] is an optional IP address of the Hercules (guest OS) side. Note: This is only used to establish a point-to-point routing table entry on driving system. If you use the --oat option, do not specify an address here. There are no required parameters for the LCS emulation, however there are several options that can be specified on the config statement: -n or --dev where is: [*nix] the name of the TUN/TAP special character device, normally /dev/net/tun. [Windows] is either the IP or MAC address of the driving systems network card. TunTap32 will automatically select the first network card it finds if this option is omitted, this may not be desirable for some users. -o or --oat where specifies the filename of the Address Translation file. If this option is specified, the optional and --mac entries are ignored in preference to statements in the OAT. (See below for the format of the OAT) -m or --mac where is the optional hardware address of the interface in the format: xx:xx:xx:xx:xx:xx -d or --debug this will turn on the internal debugging routines. Warning: This will produce a tremendous amount of output to the Hercules console. It is suggested that you only enable this at the request of the maintainers. If no Address Translation file is specified, the emulation module will create the following: An ethernet adapter (port 0) for TCP/IP traffic only. Two device addresses will be defined (devnum and devnum + 1). The syntax for the Address Translation file is as follows: ********************************************************* * Dev Mode Port Entry specific information * ********************************************************* 0400 IP 00 PRI 172.021.003.032 0402 IP 00 SEC 172.021.003.033 0404 IP 00 NO 172.021.003.038 0406 IP 01 NO 172.021.002.016 040E SNA 00 HWADD 00 02:00:FE:DF:00:42 HWADD 01 02:00:FE:DF:00:43 ROUTE 00 172.021.003.032 255.255.255.224 where: Dev is the base device address Mode is the operation mode - IP or SNA Port is the virtual (relative) adapter number. When the device is specifies the odd address of the pair, then the read/write functions of the pair will be swapped. For IP modes, the entry specific information is as follows: PRI|SEC|NO specifies where a packet with an unknown IP address is forwarded to. PRI is the primary default entry, SEC specifies the entry to use when the primary is not available, and NO specifies that this is not a default entry. nnn.nnn.nnn.nnn specifies the home IP address When the operation mode is IP, specify only the even (read) address. The odd (write) address will be create automatically. Note: SNA mode does not currently work. Additionally, two other statements can be included in the address translation file. The HWADD and ROUTE statements. Use the HWADD to specify a hardware (MAC) address for a virtual adapter. The first parameter after HWADD specifies with relative adapter for which the address is applied. The ROUTE statement is included for convenience. This allows the hercifc program to create a network route for this specified virtual adapter. Please note that it is not necessary to include point-to-point routes for each IP address in the table. This is done automatically by the emulation module. Up to 4 virtual (relative) adapters 00-03 are currently supported. ----------------------------------------------------------------- SLIP/VMNET - Channel to Channel link to TCP/IP via SLIP/VMNET ----------------------------------------------------------------- If the emulation mode is not specified on the configuration statement, it is assumed to be a point-to-point link to the driving system's TCP/IP stack using Willem Konynenberg's VMNET package. This provides the same function as the CTCI mode of operation, except that it uses a virtual SLIP interface instead of the TUN/TAP driver. Refer to http://www.kiyoinc.com/herc3088.html for more details. ----------------------------------------------------------------- CTCE - Enhanced Channel to Channel Emulation via TCP connection ----------------------------------------------------------------- The CTCE device type will emulate a real 3088 Channel to Channnel Adapter also for non-IP traffic, enhancing the CTCT capabilities. CTCE connections are also based on TCP/IP between two (or more) Hercules instances, and requires an even-odd pair of port numbers per device side. Only the even port numbers are to be configured; the odd numbers are just derived by adding 1 to the (configured) even port numbers. The socket connection pairs cross-connect, the arrows showing the send->receive direction : x-lport-even -> y-rport-odd x-lport-odd <- y-rport-even The configuration statement for CTCE is as follows : CTCE [[] ] where: is the address of the CTCT device. is the even TCP/IP port on the local system. is the IP address on the remote. is the even TCP/IP port on the remote system. optional mtu buffersize, defaults to 32778 optional small minimum for mtu, defaults to 8 A sample CTCE device configuration is shown below: Hercules PC Host A with IP address 192.168.1.100 : 0E40 CTCE 30880 192.168.1.200 30880 0E41 CTCE 30882 192.168.1.200 30882 Hercules PC Host B with IP address 192.168.1.200 : 0E40 CTCE 30880 192.168.1.100 30880 0E41 CTCE 30882 192.168.1.100 30882 CTCE connected Hercules instances can be hosted on either Unix or Windows platforms, both sides do not need to be the same. ================================================================= [1] The TunTap32.dll and FishPack.dll are part of Fish's CTCI-W32 http://www.softdevlabs.com/Hercules/ctci-w32-index.html package, but the required WinPCap packet driver must be installed separately from http://www.winpcap.org See Fish's web page for details. ALSO NOTE that it is HIGHLY RECOMMENDED that you stick with using only the current RELEASE version of WinPCap and NOT any type of 'alpha' OR 'beta' version! Alpha and Beta versions of WinPCap are NOT SUPPORTED! Only official *release* version are supported! When you visit the WinPCap download web page, you need need to scroll down the page a bit to reach the OFFICIAL RELEASE VERSION of WinPcap. They usually put their Beta versions at the top of the page, and BETA versions ARE NOT SUPPORTED. *Please* scroll down the page and use and official RELEASE version. Thanks. You may, if you want, use a beta version of WinPCap, but if you do, then you're on your own if you have any problems with it. -- Fish, May 2004. hercules-3.12/README.OSX0000664000175000017500000000520212564723224011532 00000000000000(The previous contents of this file were removed, as they haven't applied in years.) To compile on OS X for another architecture than the one running, or another OS version, you have to supply several arguments to the configure command. To force a particular architecture, you need to specify the machine architecture to the gcc command with the "-arch " operand. You also need to tell configure what environment you're building for, with --host. ARCHITECTURE -arch --host 32-bit Intel i386 i686 64-bit Intel x86_64 x86_64 32-bit PowerPC ppc powerpc 64-bit PowerPC ppc64 powerpc64 The argument for --host is the first part of a build triplet, specified as --. The vendor is apple for all OS X builds. OS is "darwin8.8.0" for OS X 10.4 (Tiger), and "darwin9.6.0" for OS X 10.5 (Leopard). This makes, for example, building for 64-bit Intel on Leopard use "--host x86_64-apple-darwin9.6.0". The -arch argument is specified by overriding the CC (C compiler) value and adding it to the end, as in CC="gcc -arch x86_64". If you're building for an OS that's not the one you're running on, you also need to tell the build environment that you're doing so. For building for Tiger on Leopard, you need to add two arguments to the configure invocation: "CFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk' LDFLAGS='-isysroot/Developer/SDKs/MacOSX10.4u.sdk -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk'". (All on one line, of course.) You also need to add an environment variable that's passed to gcc upon invocation, and this takes adding it to the beginning of the CC value, as in CC="/usr/bin/env MACOSX_DEPLOYMENT_TARGET=10.4 gcc -arch ix86_64". This makes a complete invocation for building for 32-bit Intel for Tiger on Leopard (again, all on one line): CC="/usr/bin/env MACOSX_DEPLOYMENT_TARGET=10.4 gcc -arch i386" CFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk' LDFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk' ./configure --enable-setuid-hercifc --host=i686-apple-darwin8.8.0 Building 32-bit Intel for Leopard on Leopard is easier: CC="gcc -arch i386" ./configure --enable-setuid-hercifc --host=i686-apple-darwin9.6.0 (Note that building a 64-bit Intel version on a Mac with a 64-bit Intel processor still requires explicitly setting the architecture. If you don't, you'll get a 32-bit Intel version.) Once you have the various architectures built, you can combine them into one binary with lipo. This is done by saying "lipo -output -create". The best approach is to automate this with a shell script; I've done this for my own use. hercules-3.12/README.TAPE0000664000175000017500000002310212564723224011611 00000000000000------------------------------------------------------------------------------- * Hercules Tape Support Enhancements SPE/Fixes * * V1.0 - By Ivan S. Warren * ------------------------------------------------------------------------------- 0 - Version History * 08 Mar 2003 : ISW : Initial Release I - Supported Device Type emulations : Device Types supported as of yet : 3410/3411, 3420, 3480, 3490, 9347 Upcoming Device type support : 3422, 3424, 3490E, 3590, 3430, 8809 II - Basic ACF support The ACF (Automatic Cartridge Feeder) is a feature on Cartridge type tape drives (3480, 3490, etc..) that automatically loads a new tape when a tape is removed from the drive. There is no real control over this device by the host, as it just keeps on feeding tapes one after the other. Although the ACF feature is unique to cartridge type systems, the emulation accepts to use the same technique for emulated 1/2 inch tapes reel drives as well. ACF is supported as follows : hercules.cnf syntax : CUU DEVT @filename devinit syntax : devinit CUU @filename the 'filename' (without the prefixing @) contains a list of files that will be loaded one after the other. The filenames contained in the file list cannot describe another ACF file nor an SCSI tape handle (/dev/stX). However, the files may be standard AWS, HET or OMA files. To manually reset the ACF to the top of the stack, the devinit can be used to 'reload' the ACF feature. If the filename in the ACF description file contains a '*', any option(s) that follow(s) the '*' (is)are applied to each file, followed by the option(s) specified on the devinit or hercules.cnf entry, followed by the option(s) specified on each individual entry. Example : hercules.cnf: 180 3420 @newstack compress=1 newstack: # Sample file * maxsizeM=16 eotmargin=131072 tape01.aws compress=0 tape02.het maxsizeM=32 eotmargin=65536 tape03.het maxsize=0 This is equivalent to issuing (one at the start and one after each tape unload event) 180 3420 tape01.aws maxsizeM=16 eotmargin=131072 compress=1 compress=0 devinit 180 tape02.het maxsizeM=16 eotmargin=131072 compress=1 maxsizeM=32 eotmargin=65536 devinit 180 tape03.het maxsizeM=16 eotmargin=131072 compress=1 maxsize=0 Options are processed in the order in which they appear. Any conflicting parameter overrides the previous one. For example, on the 1st entry, the resuling "compress" will be 0. Care must be taken that '*' line entries are all proecessed at once. For example : * compress=0 tape01.aws * compress=1 tape02.aws is EQUIVALENT to * compress=0 compress=1 tape01.aws tape02.aws NOTE : This may change in the future though, so ACF description files should not rely on this feature. III - Multivolume support - End of tape indication, Tape file size limitation Numerous requests have been made in order to support multi-volume tape handling, as well as limiting the file size generated by any individual tape file. Because multivolume support is not necesserally VOL1-HDR1/EOV/EOF based, a certain number of new features have to be implemented in order to let the guest program manage the multivolume on it's own. (ex: VM/DDR, DOS Tape Spooled output, etc..) Multivolume support resides in the capacity of a drive to indicate to the controling program that it is about to reach the end of the physical tape and that measures have to be taken to close the current volume and request a new media. 3 new options are introduced : maxsize[K|M]=nnnn : The resulting file size is limited to the amount specified. maxsize specifies bytes, maxsizeK specifies a multiple of 10$24 bytes and maxsizeM specifies a multiple of 1024*1024 bytes. specifying a size of 0 indicates that there is no limit on the size of the file. the default is 0 (unlimited file size) strictsize=0|1 : Upon reaching the tape file size limit, depending on strictsize, the tape file will or will not be truncated to enforce the maxsize limit. The limit is only enforced during a write type operation (that is : if the file already exists and the program only reads the file, then the file will NOT be truncated, regardless of the strictsize setting). This affects any write that starts BELOW the limit, but that would extend BEYOND the limit. This parameter only affects compress HET files. On AWS tapes, the limit is always enforced, but the file is not truncated (i.e. the write does not occur, because 1) AWS tapes are never truncated, 2) the effects of the write are known in advance (no compression)). Regardless of strictsize, any write operation (Write, Write TM) will return a Unit Check with Equip Check to the program if the file size exceeds the predefined limit. If strictsize is 0, the write will actually have been performed on the tape file. If strictsize is 1, the file will be truncated on the preceeding tape block boundary. If an attempt is made to write beyond the maxsize li Care must be taken that regardless of the 'strictsize' setting, the tape may become unusable for the guest program should such an event occur (absence of a Tape Mark for example). This option has no effect if maxsize is 0 This option only affects HET file tapes The default is 0 (do not truncate) eotmargin=nnnn : This option specifies, in bytes, the threshold before reaching maxsize during which an indication will be returned to the program to indicate that an EOT marker has been reached for a write type operation. The indication of reaching near-capacity is indicated to the program by presenting Unit Exception in the CSW on a Write type operation, along with Channel End and Device End. For certain device types, sense information may also indicate this information independently of a write operation. The purpose of this option is to allow the program to determine that it is time to change to ask for a new tape. For example : maxsizeM=2 eotmargin=131072 all writes up to 2Mb - 128Kb will occur normally All writes between 2Mb-128Kb and 2Mb will receive Unit Exception All writes beyond 2Mb will receive Unit Check This option has no effect if maxsize is 0 The default is 131072 (128Kb) Caveats : If the emulated tape file resides on a disk media that reaches full capacity before the tape image exceeds it's size limit, the tape emulation will not detect that situation and will simulate reaching physical end of tape BEFORE reaching the EOT marker. This behaviour may be changed at a later time. IV - Various other changes / Corrections IV.1 : Device End Suppression for Tape motion CCWs on a non-ready tape drive IV.2 : Control Unit End is presented on Rewind Unload status IV.3 : Sense Pending status support When certain conditions arise during an I/O operation, A sense is built and Unit Check is presented to the program. The program is then responsible for retrieving the sense information. However, if the sense is not the result of a previously occuring Unit Check, a new sense is built to reflect the current device status. Also, this management is a necessary step in order to eventually implement multipath operations (Contengency Allegiance status). IV.4 : readonly=0|1 : force an emulated tape device read only. (1/2 Inch tape ring or 38k Cartridge Protect tab) (support for this feature is incomplete) --Ivan 8 Mar 2003 ------------------------------------------------------------------------------- * AUTOMOUNT support * ------------------------------------------------------------------------------- Starting with Hercules version 3.06 a new AUTOMOUNT option is available that allows guest operating systems to directly mount, unmount and query tape device filenames for themselves, without any intervention on the part of the Hercules operator. Automount support is enabled via the AUTOMOUNT configuration file statement. An example guest automount program for VSE called "TMOUNT" is provided in the util subdirectory of the Hercules source code distribution. Briefly, the 0x4B (Set Diagnose) CCW is used to mount (or unmount) a file onto a tape drive, and the 0xE4 (Sense Id) CCW opcode is used to query the name of the currently mounted file. For mounts, the 0x4B CCW specifies the filename of the file to be mounted onto the drive. The file MUST reside in the specified AUTOMOUNT directory or the automount request will be rejected. To unmount the currently mounted file, simply do a mount of the special filename "OFFLINE". To query the name of the currently mounted file, the 0xE4 CCW is used. Note however that the 0xE4 (Sense Id) CCW opcode cannot be used by itself since the drive may also already natively support the Sense Id CCW opcode. Instead, it must be preceded by (command-chained from) a 0x4B CCW with a data transfer length of one byte. The following 0xE4 command is the one that then specifies the i/o buffer and buffer length of where the query function is to place the device's currently mounted host filename. In summary: MOUNT: X'4B', , X'20', UNMOUNT: (same thing but use filename "OFFLINE" instead) QUERY: X'4B', , X'60', 1 X'E4', , X'20', Again, please refer to the provided TMOUNT sample for a simple example. -- Fish 28 May 2008 hercules-3.12/README.HERCLOGO0000664000175000017500000000461412564723224012271 00000000000000Customizable hercules 3270 Logo The initial welcome screen presented when a TN 3270 terminal connects to a hercules 3270 device can now be customized. The customized logo is stored in a plain text file which contains positioning orders, attributes and variable substitutions. hercules also contains a built-in logo should no suitable file be found. Upon startup, hercules will first look for a file named "herclogo.txt" in the current directory. The name of the logo file can also be specified as a startup option by using the '-b' flag. Additionally, the file may also be specified by using the 'HERCLOGO' configuration statement. (NOTE : The statement was previously LOGOFILE, but LOGOFILE has been deprecated). The file may also be specified by using the 'HERCLOGO' environment variable. The file to be used can also be specified at run time using the 'HERCLOGO' panel command. Each line in the file represent either an order or a plain text line. The orders are as follows : @SBA X,Y Position the current buffer position to Row X col Y (X and Y start at 0) @SF [H][P] Set the Highlight and/or Protected attribute @NL Forces going to the next line @ALIGN NONE|LEFT|RIGHT|CENTER Specified the text alignement (relative to the left and right borders of the terminal). When ALIGN is other than "NONE", a new line is automatically inserted after each line of text. If ALIGN is "NONE", then the text will be written without skipping to the next line. It is also possible to embbed substitution variables in outgoing text. Substition is indicated by enclosing the variable name between $( and ) The following variables are defined in that environment : VERSION : The hercules version HOSTNAME : The host name on which hercules is running HOSTOS : The host operating system HOSTOSREL : The Host operating system release HOSTOSVER : The host operating system version HOSTARCH : The host architecture HOSTNUMCPUS : UP (for 1) or MP=X (for more than 1) LPARNAME : The LPAR name specified in the configuration file CCUU,ccuu,CUU,cuu : Various forms of the device number of the terminal CSS : The Logical Channel Subsystem Set or Channel Set for the terminal SUBCHAN : The Subchannel number for the terminal Additionally, it is also possible to specify environment variable names. The file 'herclogo.txt' is provided in the distribution as a sample template. It reflects the contents of the built-in logo. Ivan Warren 3/1/2006 hercules-3.12/RELEASE.NOTES0000664000175000017500000004107612564723224012105 00000000000000------------------------------------------------------------------------------- Version 3.08 RELEASE NOTES * The new minimum supported Microsoft Windows platform is now Windows XP or greater. Windows 98, Windows NT and Windows 2000 are no longer supported. ------------------------------------------------------------------------------- Version 3.06 RELEASE NOTES * Tape "AUTOMOUNT" support Starting with Hercules version 3.06 a new AUTOMOUNT option is available that allows guest operating systems to directly mount, unmount and query tape device filenames for themselves, without any intervention on the part of the Hercules operator. Automount support is enabled via the AUTOMOUNT configuration file statement. An example guest automount program for VSE called "TMOUNT" is provided in the util subdirectory of the Hercules source code distribution. Briefly, the 0x4B (Set Diagnose) CCW is used to mount (or unmount) a file onto a tape drive, and the 0xE4 (Sense Id) CCW opcode is used to query the name of the currently mounted file. For mounts, the 0x4B CCW specifies the filename of the file to be mounted onto the drive. The file MUST reside in the specified AUTOMOUNT directory or the automount request will be rejected. To unmount the currently mounted file, simply do a mount of the special filename "OFFLINE". To query the name of the currently mounted file, the 0xE4 CCW is used. Note however that the 0xE4 (Sense Id) CCW opcode cannot be used by itself since the drive may also already natively support the Sense Id CCW opcode. Instead, it must be preceded by (command-chained from) a 0x4B CCW with a data transfer length of one byte. The following 0xE4 command is the one that then specifies the i/o buffer and buffer length of where the query function is to place the device's currently mounted host filename. In summary: MOUNT: X'4B', , X'20', UNMOUNT: (same thing but use filename "OFFLINE" instead) QUERY: X'4B', , X'60', 1 X'E4', , X'20', Again please refer to the provided TMOUNT program for a simple example of how automount support might be implmented on a guest operating system. ------------------------------------------------------------------------------- Version 3.05 RELEASE NOTES * The 'conspawn' utility used to process 'sh' commands now recognizes a specially designed keyword "startgui" to accomodate automatic starting of Windows GUI applications via the .RC file or panel command-line. If the first word following 'sh' is "startgui", then the "ShellExecute" API is used to start the requested program rather than the 'system()' API as otherwise. This is to address an issue related to running Hercules via the HercGUI graphical front end wherein programs started via the .RC file would cause HercGUI to hang at PowerOff until all programs started by Hercules (via the .RC file or panel command-line) were first closed. If the program you wish to invoke via the 'sh' command is a command-line program (that thus uses stdio to read from stdin and write to stdout) then "startgui" should NOT be used. Instead, simply start the program as before (e.g. "sh cmd /c myprog myargs..."). If the application you wish to start is a normal Windows GUI application however, then the "startgui" keyword should be used instead. For example, to automatically start the Vista 3270 terminal emulator from your .RC file, use: "sh startgui D:\Vista32\Vista32.exe Hercules.ses". Again, this is only for starting Windows GUI programs and thus does not impact non-GUI (command-line) programs nor, obviously, non-MSVC builds of Hercules nor when Hercules is run via the command-line (in non-GUI mode). This is only for the Window MSVC build of Hercules and only when Hercules is started via HercGUI and only when starting a Windows GUI program via the 'sh' command either via the panel command-line or the .RC file. (Note: the panel command-line also includes commands entered via the http server interface as well) * Real SCSI tape drives used with Hercules must provide a certain minimum set is "IBM compatible" support in their SCSI command set/behavior in order to work properly with Hercules. Furthermore, the Hercules device-type used on your device statement in your Hercules configuration file should match the the level of support/behavior that they provide. For example, all SCSI tape drives used with Hercules must provide the ability to set variable-length blocks as well as long erase-gaps (long erase-gaps allows new data to be appended to the end of existing data without having to write a tape-mark to separate the new data from the old existing data first). Another example would be using a model of SCSI tape drive that happens to report physical block-id values in a format different from the way real IBM mainframe tape drives report them. 3480/3490 tape drives for example report their block-ids (used in Read Block Id and Locate CCWs) in a very specific format wherein bits 1-7 of the high-order byte of the reported 4-byte block- id indicates the tape's physical "segment" location of where the lower 22- bit block number is physically located on the tape. (The block-id segment is used to allow the tape drive to quickly position itself to the approximate location where the desired block acually resides on the tape and thus allows high-speed positioning for the Locate CCW). If the model of SCSI tape drive you are actually using with Hercules does not use this same block-id format however, then it cannot be used with Hercules as a 3480 or 3490 model tape drive with specially defined options. If the SCSI tape drive you are using reports its block-ids using a 32-bit block-id value (the same way a 3590 model tape drive does), then similarly, it should be defined to Hercules as a model 3590 device-type as well (since that is how it is behaving with respect the format of the returned blockid values). It you wish to define it in Hercules as a model 3480 or 3490, then you will need to use specially defined options before it will work properly as the model drive you wish it to emulate. With all that being said, it should be noted that PARTIAL support for 3590 device emulation is possible with judicious use the aforementioned special options, but full/complete 3590 support is unlikely due to lack of publicly available documentation. Details regarding 3590 CCW handling is restricted (confidential) IBM proprietary information, and is not normally available outside of IBM. Not long ago IBM was required by US law to publish such information, but unfortunately for Hercules, such is no longer the case. For further information regarding use of SCSI attached tape drives with Hercules and their associated specially defined options, please refer to the section on SCSI tape drives in the Hercules's Device Configuration documentation. * In order to ensure proper functioning of the TOD clock with older versions of guest operating systems, the default values of Hercules's internal thread priorities for the Windows version of Hercules were changed to be identical to those used by all other supported platforms. Originally, the default thread priority values for the Windows version of Hercules were: *** 3.04 (and prior) Default Priorities *** Thread Priority Meaning ------- -------- ------------------------ HERCPRIO 0 Normal Process priority DEVPRIO -8 Above Normal Thread priority TODPRIO 0 Normal Thread priority CPUPRIO 0 Normal Thread priority which caused acceptable performance/functioning on most, but not all, guest operating systems. Beginning with version 3.05 however, the prioriries now default to: *** 3.05 (and later) Default Priorities *** Thread Priority Meaning ------- -------- ------------------------ HERCPRIO 0 Normal Process priority TODPRIO -20 Time Critical Thread priority DEVPRIO 8 Below Normal Thread priority CPUPRIO 15 Lowest Thread priority which may on more modern guest operating systems (which handle the TOD clock differently than do older less sophticated versions) cause a slight decrease in overall performance. If such is the case, the original default priorities (and thus the original behavior) can be obtained via addition of appropriate HERCPRIO, TODPRIO, DEVPRIO and CPUPRIO control file statements with values identical to the original version 3.04 default values. * Additional configuration file usability enhancements have been implemented in the form of a new 'INCLUDE' (and associated 'IGNORE') statement, allowing configuration files to "include" statements from a different named file. Additonally, a new "enhanced" symbolic substitution syntax is now also supported. Refer to the Hercules "Configuration File" documentation for further information and details. A rather nifty "Automatic Operator" facility has also been implemented in the current release as well. While not exactly a "configuration file usability enhancement", it is nevertheless something we hope might prove to be more useful/helpful to our many users. See the "README.HAO" document for more information. ------------------------------------------------------------------------------- Version 3.01 RELEASE NOTES - Support for z990 crypto instructions is conditional on the presence of the glibcrypt library. If Hercules is BUILT, the development files for glibcrypt should be available. When hercules is RUN, the runtime files for glibcrypt should be installed. Depending on the level of glibcrypt used to *build* hercules, the associated level of glibcrypt should also be present on the target machine. On systems supporting shared library versioning, multiple levels of the glibcrypt runtime libraries can be installed simultaneously, ensuring availability of the z990 crypto instructions, regardless of the level of glibcrypt with which hercules was initially built. - CTC and LCS devices now ++MUST++ specify ALL addresses on the configuration statement. Example: 0A00.2 LCS ..... 0B00.2 CTCI .... or 0A00.4 LCS -oat hercules.oat or 0A00-0A03 LCS -oat hercules.oat or 0A00 LCS -oat hercules.oat 0A01 LCS 0A02 LCS 0A03 LCS Previously (i.e. with version 3.00), only the first (even numbered) device needed to be defined and Herc would automatically define the odd numbered device for you. Starting with Hercules version 3.01 however, you now need to define BOTH devices, just like you did with versions prior to 3.00. Once again, starting with version 3.01, you **MUST** define BOTH DEVICES. ------------------------------------------------------------------------------- Version 3.00 RELEASE NOTES - Reminder that CTCI device handling was changed as follows: - The CTCI-W32 protocol is deprecated. You should use the CTCI protocol instead. - You MUST NOT define both even/odd CTCI device pairs in your configuration file. You should ONLY define the first even numbered device. Hercules will automatically define the odd numbered device for you. If you define the odd numbered device by mistake, an open error will occur on that device. This is by design. See the README.NETWORKING document for further details. - Hercules Dynamic Loader support: starting with version 3.00, Hercules now contains support for the dynamic loading of certain modules upon startup on some platforms (e.g. Linux and Windows for example). As a result of this new feature, "Hercules" itself now no longer consists of just the 'hercules.exe' module by itself, but rather consists of BOTH the 'hercules.exe' program AS WELL AS whatever dynamic modules (DLLs) that accompany it. As a result if this change, whenever you install a new version of Hercules, you must ensure that you ALSO install the accompanying new versions of the new dynamic modules as well. Attempting to use a version of Hercules with a dynamic module that was not specifically built for that version will cause loading of that dynamic module to fail. You CANNOT mix versions of Hercules with differing versions of dynamically loaded modules. Ensure that your library path LD_LIBRARY_PATH is set correctly such that it includes the directory of your Hercules executables. Especially, message HHCCF042E will indicate that system is unable to locate necessary loadable modules. - ECPS:VM: Do not use ECPS:VM (See README.ECPSVM) in an AP or MP environment in VM/370. If AP=YES or MP=YES is coded in DMKSYS and the AP/MP control file is used to build the CP nucleus and NUMCPU is set to more than 1 in the hercules.cnf file, any of LOK001, LOK003 or other abends will occur. This occurs because the Hercules ECPS:VM CP Assist implementation is not MP safe, and particularily, attemps VM dispatching without holding necessary AP or MP locks. - Due to the change in Hercules' "mainstor" memory allocation technique to address a "double memory consumption" bug in Cygwin's malloc implementation, some Windows Hercules users may experience an "out of memory" error whenever Hercules is started with a large MAINSIZE configuration file value: "HHCCF031S Cannot obtain nnnMB main storage" This error will most likely occur (if it does at all) for those users who have manually adjusted their Cygwin "heap_chunk_in_mb" Windows registry setting value (in order to allow them to specify a large MAINSIZE value when running Hercules). If this problem does occur (i.e. if you DO happen to experience the above mentioned "HHCCF031S Cannot obtain main storage" error with this new release of Hercules), then either REDUCE your "heap_ chunk_in_mb" value (yes, that's correct: REDUCE it; i.e. change it to a SMALLER value) or else remove it altogether (so as to let it default). Detailed explanation: History/background: Cygwin has a built-in limit to the amount of memory that may be allocated in one chunk. If you try 'malloc'ing more than this limit, you will receive an "out of memory" error. Since many Hercules users specify large MAINSIZE values in their configuration file, they sometimes experience this problem. The suggested workaround to this "problem" was to add a "heap_chunk_in_mb" registry value to Cygwin's registry settings with a large enough value such that Cygwin would then be able to satisfy Hercules' 'malloc' request for such a large MAINSIZE value. This worked fine until sometime around version 1.3.15 of Cygwin, at which time they began using a different 'malloc' technique that unfortunately causes TWICE as much Windows virtual memory to be allocated for any large memory allocation (the technical reasons of which are explained in comments in source member config.c where mainsize is being allocated). In order to address this double memory allocation issue in Cygwin's malloc implementation, Hercules was changed to use mmap to allocate its mainstor rather than malloc (which, unlike malloc, does NOT inadvertently allocate twice as Windows virtual storage than was requested), which did indeed re- solve the "double memory allocation" problem. Unfortunately however, because Cygwin's malloc and mmap logic each consume completely different portions of Windows' virtual memory, the more memory that is reserved for malloc usage (via using a larger "heap_chunk_in_mb" value), the LESS becomes available for mmap usage! Thus, while increasing your "heap_chunk_in_mb" registry value USED to HELP [to allow you to allocate larger amounts of mainstor (MAINSIZE)], it NOW causes the complete OPPOSITE effect: it ends up PREVENTING you from being able to 'mmap' as much storage as you'd like to have! Conclusion: Therefore, if you are currently using the "heap_chunk_in_mb" registry value setting to allow you to allocate large MAINSIZE values, then starting with version 3.00 of Hercules you need to DESCREASE your "heap_chunk_in_mb" value (or remove it altogether and let it default) in order to leave enough memory remaining for Hercules (Cygwin actually) to be able to satisfy its 'mmap' request for your desired MAINSIZE amount. ------------------------------------------------------------------------------- hercules-3.12/README.WIN320000664000175000017500000000274312564723224011672 00000000000000HERCULES FOR WIN32 README FILE HOW TO COMPILE HERCULES FOR WINDOWS 32 BIT MSVC x86 1. Install Visual C++ 2010 Express from the Visual Studio 2010 Express page: http://www.microsoft.com/visualstudio/en-us/products/2010-editions/express 2. Install Visual Studio 2010 Service Pack 1 (VS10sp1-KB983509) from: http://www.microsoft.com/en-us/download/details.aspx?id=23691 3. Go to the start menu and choose "All Programs" - "Microsoft Visual Studio 2010 Express" - "Visual Studio Command Prompt (2010)" 4. Change to the directory where you unpacked the Hercules source 5. If you require gzip or bzip2 for disk or tape compression, or if you require PCRE for the Hercules Automatic Operator facility, you should install the WIN32 versions of these programs in winbuild\zlib\ winbuild\bzip2\ and winbuild\pcre\ under the Hercules directory. You may override these default directory locations by setting environment variables, for example: SET ZLIB_DIR=c:\packages\zlib SET BZIP2_DIR=c:\packages\bzip2 SET PCRE_DIR=c:\packages\pcre 6. copy makefile.msvc makefile 7. nmake clean nmake 8. The binaries will be installed into subfolder "msvc.dllmod.bin" 9. If you copy the binaries to a machine which does not have Visual Studio 2010 (VS10) installed, then you must also install the Microsoft Visual C++ 2010 Redistributable Package (x86) on the target machine. This package can be downloaded from http://www.microsoft.com/en-us/download/details.aspx?id=5555 hercules-3.12/README.WIN640000664000175000017500000000420112564723224011666 00000000000000HERCULES FOR WIN64 README FILE There are two 64-bit architectures supported by 64-bit Windows: - x64 also known as x86_64 (for AMD64 and Intel EM64T processors) - ia64 (for Intel Itanium processors) This document covers only the x64 architecture. HOW TO COMPILE HERCULES FOR AMD64 1. Install Visual C++ 2010 Express from the Visual Studio 2010 Express page: http://www.microsoft.com/visualstudio/en-us/products/2010-editions/express 2. Install Microsoft Windows SDK 7.1 from: http://www.microsoft.com/en-us/download/details.aspx?id=8279 IMPORTANT: select all components *except* the Visual C++ Compilers 3. Install Visual Studio 2010 Service Pack 1 (VS10sp1-KB983509) from: http://www.microsoft.com/en-us/download/details.aspx?id=23691 4. Install Visual C++ 2010 Service Pack 1 Compiler Update for the Windows SDK 7.1 (VC-Compiler-KB2519277) from: http://www.microsoft.com/en-us/download/details.aspx?id=4422 5. Go to the start menu and choose "All Programs" - "Microsoft Windows SDK v7.1" - "Microsoft Windows SDK 7.1 Command Prompt" 6. Change to the directory where you unpacked the Hercules source 7. If you require gzip or bzip2 for disk or tape compression, or if you require PCRE for the Hercules Automatic Operator facility, you should install the AMD64 versions of these programs in winbuild\zlib\x64 winbuild\bzip2\x64 and winbuild\pcre\x64 under the Hercules directory. You may override these default directory locations by setting environment variables, for example: SET ZLIB_DIR=c:\packages\zlib SET BZIP2_DIR=c:\packages\bzip2 SET PCRE_DIR=c:\packages\pcre 8. copy makefile.msvc makefile 9. nmake clean nmake 10. The binaries will be installed into subfolder "msvc.AMD64.bin" If you compiled on a 32-bit Windows system, copy this folder to your target 64-bit Windows machine. 11. If you copy the binaries to a machine which does not have Visual Studio 2010 (VS10) installed, then you must also install the Microsoft Visual C++ 2010 Redistributable Package (x64) on the target machine. This package can be downloaded from http://www.microsoft.com/en-us/download/details.aspx?id=14632 hercules-3.12/README.SUN0000664000175000017500000001054012564723224011527 00000000000000HOW TO BUILD HERCULES FROM SVN UNDER SOLARIS 1. DOWNLOAD AND INSTALL THE GNU COMPILER AND TOOLS (a) You can obtain all the required tools from http://www.sunfreeware.com To download the tools you will need wget which is installed in /usr/sfw/bin on Solaris 9 and 10. First add this directory to your path using the command: PATH=${PATH}:/usr/sfw/bin (b) Follow instructions on http://www.blastwave.org/pkg-get.php to install the pkg-get package. Choose /opt/csw as the package base directory. Choose a local mirror site from the list at http://www.blastwave.org/mirrors.html and update /opt/csw/etc/pkg-get.conf to point to the /stable directory at the mirror site, for example: url=http://blastwave.informatik.uni-erlangen.de/csw/stable Add /opt/csw/bin to your path using the command: PATH=/opt/csw/bin:${PATH} (c) Then install the GNU compiler and tools using these commands: pkg-get install textutils pkg-get install automake pkg-get install autoconf pkg-get install subversion pkg-get install flex pkg-get install gmake pkg-get install ggrep pkg-get install gcc3 (d) Check that all the required tools are installed: pkg-get compare subversion autoconf automake flex gawk gcc3 pkg-get compare ggrep libiconv gm4 gmake perl gsed which should produce output something like this: software localrev remoterev subversion 1.4.5,REV=2007.11.18 SAME autoconf 2.61,REV=2007.07.13 SAME automake 1.9.6 SAME flex 2.5.4,REV=2005.10.03 SAME gawk 3.1.5 SAME gcc3 3.4.5 SAME ggrep 2.5,REV=2004.12.01 SAME libiconv 1.9.2 SAME gm4 1.4.5,REV=2006.07.27 SAME gmake 3.81 SAME perl 5.8.8,REV=2007.10.05 SAME gsed 4.1.4 SAME (e) Finally, add symbolic links to allow certain GNU tools to be invoked using standard Unix names: cd /opt/csw/bin ln -s /opt/csw/gcc3/bin/gcc gcc ln -s /opt/csw/bin/ggrep grep ln -s /opt/csw/bin/gm4 m4 ln -s /opt/csw/bin/gmake make ln -s /opt/csw/bin/gsed sed 2. DOWNLOAD THE HERCULES SOURCE FROM SVN Add the following line to your .profile file: PATH=/opt/csw/bin:${PATH} From your home directory issue this command: svn checkout svn://svn.hercules-390.org/hercules/trunk hercules Note: svn will fail if you do not have libuuid installed on your system ld.so.1: svn: fatal: libuuid.so.1: open failed: No such file or directory If you get this message, you will need to install a patch from Sun: 1. Go to sunsolve.sun.com and select "Patch Finder" 2. Scroll down to "Download Product Specific Patches" and select your version of Solaris (for example, Solaris 2.9 SPARC) 3. Look for a patch which contains libuuid (for example, 114129-02) 4. Download the patch and unzip it into /var/spool/patch 5. patchadd /var/spool/patch/114129-02 3. CHECK THAT THE REQUIRED LEVELS OF TOOLS ARE INSTALLED From your home directory issue these commands: cd hercules util/bldlvlck which should produce output something like this: OK SVN (informational), found x.yy.zz OK autoconf requires 2.5, found 2.61 OK automake requires 1.9, found 1.9.6 OK flex requires 2.5, found 2.5.4 OK gawk requires 3.0, found 3.1.5 OK gcc requires 2.95, found 3.4.5 OK grep requires 0, found 2.5 OK libiconv requires 1.8, found 1.9 OK m4 requires 0.0, found 1.4 OK make requires 3.79, found 3.81 OK perl requires 5.6, found 5.8.8 OK sed requires 3.02, found 4.1.4 4. BUILD HERCULES In the hercules directory issue these commands: sh ./autogen.sh ./configure make hercules-3.12/makefile.msvc0000664000175000017500000000050612564723224012653 00000000000000# *************************************************************************** # MAKEFILE.MSVC (c) Copyright Roger Bowler, 2005 # Build Hercules for Win32 using MSVC and nmake (static link version) # # $Id$ # # $Log$ # # *************************************************************************** !include makefile-dllmod.msvc hercules-3.12/makefile-dllmod.msvc0000664000175000017500000000511012564723224014120 00000000000000# *************************************************************************** # MAKEFILE-DLLMOD.MSVC (c) Copyright Roger Bowler, 2005-2007 # Build Hercules for Win32 using MSVC and nmake (DLL version with loadable modules) # *************************************************************************** INCDIR = msvc.makefile.includes # --------------------------------------------------------------------- !INCLUDE $(INCDIR)\CONFIG.msvc !INCLUDE $(INCDIR)\VERSION.msvc !INCLUDE $(INCDIR)\OUTPUT_DIRS.msvc !INCLUDE $(INCDIR)\MODULES.msvc !INCLUDE $(INCDIR)\OBJ_CODE.msvc !INCLUDE $(INCDIR)\ZLIB_DIR.msvc !INCLUDE $(INCDIR)\BZIP2_DIR.msvc !INCLUDE $(INCDIR)\PCRE_DIR.msvc # --------------------------------------------------------------------- ################################################### # NOTE! must set the 'NODEBUG' variable properly # BEFORE calling win32.mak since it uses it. ################################################### # --------------------------------------------------------------------- !INCLUDE # --------------------------------------------------------------------- ################################################### # NOTE! must set our prefered 'cdebug' value(s) # AFTER calling win32.mak since it sets it. ################################################### # --------------------------------------------------------------------- !INCLUDE $(INCDIR)\DEBUG_RETAIL.msvc !INCLUDE $(INCDIR)\ZLIB_FLAGS.msvc !INCLUDE $(INCDIR)\BZIP2_FLAGS.msvc !INCLUDE $(INCDIR)\PCRE_FLAGS.msvc !INCLUDE $(INCDIR)\HERC_FLAGS.msvc # --------------------------------------------------------------------- !IFDEF DYNDIR !INCLUDE $(DYNDIR)$(DYNMOD).msvc MODULES = $(MODULES) $(X)$(DYNMOD).dll rcflags = $(rcflags) -D TARGETFILENAME=\"$(DYNMOD).dll\" -D MAX_CPU_ENGINES_STR=\"$(MAX_CPU_ENGINES)\" !ENDIF # --------------------------------------------------------------------- !INCLUDE $(INCDIR)\PRIM_RULES.msvc !INCLUDE $(INCDIR)\OUTDIR_RULES.msvc !INCLUDE $(INCDIR)\MOD_RULES1.msvc !INCLUDE $(INCDIR)\MOD_RULES2.msvc !INCLUDE $(INCDIR)\ZLIB_RULES.msvc !INCLUDE $(INCDIR)\BZIP2_RULES.msvc !INCLUDE $(INCDIR)\PCRE_RULES.msvc # --------------------------------------------------------------------- !IFDEF DYNDIR $(O)$(DYNMOD).res: $(DYNDIR)$(DYNMOD).rc $(rc) $(rcflags) $(rcvars) -fo $(O)$(DYNMOD).res $(DYNDIR)$(DYNMOD).rc $(X)$(DYNMOD).dll: $(O)$(DYNMOD).res $(DYNOBJ) $(O)hengine.lib $(O)hutil.lib $(O)hsys.lib $(linkdll) {$(DYNDIR)}.c{$(OBJDIR)}.obj:: $(cc) $(cdebug) $(cflags) /Fp"$(OBJDIR)\\build_pch.pch" /Yu"hstdinc.h" $(cvarsdll) /Fo"$(OBJDIR)\\" /Fd"$(OBJDIR)\\" $< !ENDIF hercules-3.12/hercver.rc0000664000175000017500000000653612622170250012167 00000000000000/* HERCVER.RC (c) Copyright "Fish" (David B. Trout), 2009-2011 */ /* Define Windows resources to be linked into product */ ///////////////////////////////////////////////////////////////////////////////////////// // HercVer.rc -- defines the Windows resources to be linked into the product // (c) Copyright "Fish" (David B. Trout), 2009 // Released under the Q Public License as modifications to Hercules. // (http://www.hercules-390.org/herclic.html) ///////////////////////////////////////////////////////////////////////////////////////// #ifdef APSTUDIO_INVOKED #error This file is not editable by Microsoft Visual C++ #endif ///////////////////////////////////////////////////////////////////////////////////////// // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. 001 ICON DISCARDABLE "hercules.ico" ///////////////////////////////////////////////////////////////////////////////////////// #include #ifndef NONE #define NONE 0x0L #endif #define HERCULES_PRODUCT "The Hercules System/370, ESA/390, and z/Architecture Emulator" #define HERCULES_COPYRIGHT "(c)Copyright 1999-2015" #define HERCULES_COMPANY "by Roger Bowler, Jan Jaeger, and others" #define HERCULES_PRODUCT_URL "http://www.hercules-390.eu" #define HERCULES_PRODUCT_EMAIL "hercules-390@yahoogroups.com" #if defined(PRERELEASE) #define ISPRERELEASE VS_FF_PRERELEASE #else #define ISPRERELEASE NONE #endif #if !defined(VERSION) || !defined(V1) || !defined(V2) || !defined(V3) || !defined(V4) #error VERSION not defined properly #endif ///////////////////////////////////////////////////////////////////////////////////////// 1 VERSIONINFO FILEVERSION V1, V2, V3, V4 PRODUCTVERSION V1, V2, V3, V4 FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_UNKNOWN #if defined(DEBUG) || defined(_DEBUG) FILEFLAGS ISPRERELEASE | VS_FF_SPECIALBUILD | VS_FF_DEBUG #else FILEFLAGS ISPRERELEASE | VS_FF_SPECIALBUILD #endif FILEFLAGSMASK VS_FFI_FILEFLAGSMASK { BLOCK "StringFileInfo" { BLOCK "040904B0" // 0x0409 (1033) == U.S. English, 0x04B0 (1200) == UNICODE { // Standard/Required Attributes... VALUE "ProductName", HERCULES_PRODUCT "\0" VALUE "ProductVersion", VERSION "\0" VALUE "FileDescription", HERCULES_PRODUCT "\0" VALUE "FileVersion", VERSION "\0" VALUE "CompanyName", HERCULES_COMPANY "\0" VALUE "LegalCopyright", HERCULES_COPYRIGHT " " HERCULES_COMPANY "\0" // Custom Attributes... VALUE "Hercules URL", HERCULES_PRODUCT_URL "\0" VALUE "Hercules Email", HERCULES_PRODUCT_EMAIL "\0" VALUE "Hercules Version", VERSION "\0" #if defined(PRERELEASE) #define PRE "PRERELEASE " #else #define PRE #endif #if defined(_WIN64) #define ARCH "64-bit " #else #define ARCH "32-bit " #endif #if defined(_DEBUG) || defined(DEBUG) #define CFG "DEBUG " #else #define CFG "RETAIL " #endif VALUE "SpecialBuild", PRE ARCH CFG "version" "\0" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x409, 1200 // 0x409 (1033) == U.S. English, 1200 (0x4B0) == UNICODE } } ///////////////////////////////////////////////////////////////////////////////////////// hercules-3.12/build_pch.c0000664000175000017500000000024612564723224012302 00000000000000/* BUILD_PCH (c)Copyright Ivan Warren, 2005-2009 */ /* Dummy module for building pre-compiled header files */ #include "hstdinc.h" hercules-3.12/conspawn.c0000664000175000017500000001737012564723224012207 00000000000000/* CONSPAWN.C (c) "Fish" (David B. Trout), 2005-2012 */ /* Spawn console command */ /*-------------------------------------------------------------------*/ /* This program is spawned by Hercules as a result of */ /* the 'sh' (shell) command. Its purpose is to simply */ /* call the host's shell (command interpreter) program */ /* with the arguments supplied (usually to invoke yet */ /* another program), redirecting the results back to */ /* Hercules for display. NOTE that this program does */ /* not perform the actual stdio redirection itself, but */ /* rather relies on Hercules to have set that up before */ /* invoking this program. */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define PGMNAME "conspawn" int main(int argc, char* argv[]) { int i, k, rc; char* p; #ifdef _MSVC_ #pragma comment(lib,"shell32.lib") // (need ShellExecute) // -------------------------------------------------------- // PROGRAMMING NOTE: We MUST use "ShellExecute" for Windows // GUI programs since: 1) GUI programs don't use stdio, // 2) they never exit until the user manually closes them. // // Erroneously using the 'system()' function to start a GUI // program causes HercGUI to hang at PowerOff as it waits // for its child process to close its stdio handles which // GUI programs never do until they exit (which they never // do until the user manually closes them). // // The reason this phenomenon occurs even though Hercules // does indeed close ITS OWN stdio handles when it ends is // because its child processes that it creates ALSO inherit // the same stdio handles! (I.e. the GUI programs that Herc // starts end up never closing "Herc's" [inherited] stdio // handles, which are the same handles that HercGUI waits // on! Thus GUI programs started by Herc using the 'system' // API end up hanging HercGUI! (during Herc PowerOff)) // // Thus, for GUI apps, we MUST use "ShellExecute" here // to prevent HercGUI from hanging at PowerOff. Also note // that this hang obviously does not occur when Hercules // is run in command-line (non-HercGUI) mode even when // the 'system()' API is erroneously used, since Herc is // obviously (duh!) not being run under the control of an // external GUI in such a situation. -- Fish, Aug. 2006 // -------------------------------------------------------- if (argc >= 2 && strcasecmp(argv[1],"startgui") == 0) { //////////////////////////////////////////////////////// // Windows GUI program; no stdio; use 'ShellExecute'... //////////////////////////////////////////////////////// // REFERENCE: upon entry: // argv[0] "conspawn" // argv[1] "startgui" // argv[2] (program to start) // argv[3..n] (arguments for program) HWND hwnd = NULL; LPCTSTR lpOperation = NULL; LPCTSTR lpFile = argv[2]; LPCTSTR lpParameters = NULL; LPCTSTR lpDirectory = NULL; INT nShowCmd = SW_SHOWNORMAL; char* pszErrMsg = NULL; // Build arguments string from passed args... for (i=3, k=0; i < argc; i++) k += strlen(argv[i]) + 1; if (k) { // (allocate room for arguments string) if (!(p = malloc(sizeof(char)*k))) { errno = ENOMEM; perror( PGMNAME ); return -1; } *p = 0; // (build arguments string from args) for (i=3; i < argc; ++i) { strcat(p,argv[i]); if (i != (argc-1)) strcat(p," "); } lpParameters = p; } else p = NULL; rc = (intptr_t) ShellExecute( hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd ); if (p) free(p); if ( rc > 32) return 0; // rc > greater than 32 == success... // rc <= less than or equal 32 == error... switch (rc) { case 0: pszErrMsg = "The operating system is out of memory or resources"; break; case SE_ERR_FNF: pszErrMsg = "The specified file was not found"; break; case SE_ERR_PNF: pszErrMsg = "The specified path was not found"; break; case SE_ERR_ACCESSDENIED: pszErrMsg = "The operating system denied access to the specified file"; break; case ERROR_BAD_FORMAT: pszErrMsg = "The .exe file is invalid (non-Microsoft Win32 .exe or error in .exe image)"; break; case SE_ERR_OOM: pszErrMsg = "There was not enough memory to complete the operation"; break; case SE_ERR_DLLNOTFOUND: pszErrMsg = "The specified dynamic-link library (DLL) was not found"; break; case SE_ERR_SHARE: pszErrMsg = "A sharing violation occurred"; break; case SE_ERR_ASSOCINCOMPLETE: pszErrMsg = "The file name association is incomplete or invalid"; break; case SE_ERR_DDETIMEOUT: pszErrMsg = "The DDE transaction could not be completed because the request timed out"; break; case SE_ERR_DDEFAIL: pszErrMsg = "The DDE transaction failed"; break; case SE_ERR_DDEBUSY: pszErrMsg = "The Dynamic Data Exchange (DDE) transaction could not be completed because other DDE transactions were being processed"; break; case SE_ERR_NOASSOC: pszErrMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable"; break; default: printf(PGMNAME": ShellExecute(\"%s\", \"%s\",...) failed: Unknown error; rc=%d (0x%08.8X).\n", lpFile, lpParameters, rc, rc ); return -1; } printf( PGMNAME": ShellExecute(\"%s\", \"%s\",...) failed: %s.\n", lpFile, lpParameters, pszErrMsg ); return -1; } #endif // _MSVC_ //////////////////////////////////////////////////////// // Command line program using stdio; use 'system()'... //////////////////////////////////////////////////////// // Re-build a complete command line from passed args... for (i=1, k=0; i < argc; i++) k += strlen(argv[i]) + 1; if (!k) { errno = EINVAL; perror( PGMNAME ); printf( PGMNAME": Usage: command [args]\n"); return -1; } // (allocate room for command line) if (!(p = malloc(sizeof(char)*k))) { errno = ENOMEM; perror( PGMNAME ); return -1; } *p = 0; // (rebuild command-line from args) for (i=1; i < argc; ++i) { strcat(p,argv[i]); if (i != (argc-1)) strcat(p," "); } // Ask system() to process command line... // NOTE: the below call WILL NOT RETURN // until the program being called exits! rc = system(p); free(p); // -------------------------------------------------------- // PROGRAMMING NOTE: only rc == -1 need be reported since, // if the command interpreter called a batch/cmd file for // example, it could have set its own custom return code. // // Only -1 means the system() call itself failed, which // is the only thing that actually needs to be reported. // -------------------------------------------------------- if ( -1 == rc ) perror( PGMNAME ); return rc; } hercules-3.12/getopt.c0000664000175000017500000004621212564723224011656 00000000000000/* GETOPT.C (c) Copyright see notice below */ /* NetBSD getopt parsing function */ /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #define _GETOPT_C_ #define _HUTIL_DLL_ #include "hstdinc.h" #include "hercules.h" /* #include #include #include */ #include "getopt.h" /* #include #include */ #define REPLACE_GETOPT #define _DIAGASSERT(x) do {} while (0) #ifdef REPLACE_GETOPT #ifdef __weak_alias __weak_alias(getopt,_getopt) #endif DLL_EXPORT int opterr = 1; /* if error message should be printed */ DLL_EXPORT int optind = 1; /* index into parent argv vector */ DLL_EXPORT int optopt = '?'; /* character checked for validity */ DLL_EXPORT int optreset; /* reset getopt */ DLL_EXPORT char *optarg; /* argument associated with option */ #endif #ifdef __weak_alias __weak_alias(getopt_long,_getopt_long) #endif #ifndef __CYGWIN__ #define __progname __argv[0] #else extern char __declspec(dllimport) *__progname; #endif #define IGNORE_FIRST (*options == '-' || *options == '+') #define PRINT_ERROR ((opterr) && ((*options != ':') \ || (IGNORE_FIRST && options[1] != ':'))) /* This differs from the cygwin implementation, which effectively defaults to PC, but is consistent with the NetBSD implementation and doc's. */ #ifndef IS_POSIXLY_CORRECT #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) #endif #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) /* XXX: GNU ignores PC if *options == '-' */ #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') /* return values */ #define BADCH (int)'?' #define BADARG ((IGNORE_FIRST && options[1] == ':') \ || (*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 static char EMSG[1]; static int getopt_internal (int, char * const *, const char *); static int gcd (int, int); static void permute_args (int, int, int, char * const *); static char *place = EMSG; /* option letter processing */ /* XXX: set optreset to 1 rather than these two */ static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; static void _vwarnx(const char *fmt, va_list ap) { (void)fprintf(stderr, "%s: ", __progname); if (fmt != NULL) (void)vfprintf(stderr, fmt, ap); (void)fprintf(stderr, "\n"); } static void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _vwarnx(fmt, ap); va_end(ap); } /* * Compute the greatest common divisor of a and b. */ static int gcd(a, b) int a; int b; { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return b; } /* * Exchange the block from nonopt_start to nonopt_end with the block * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ static void permute_args(panonopt_start, panonopt_end, opt_end, nargv) int panonopt_start; int panonopt_end; int opt_end; char * const *nargv; { int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; char *swap; _DIAGASSERT(nargv != NULL); /* * compute lengths of blocks and number and size of cycles */ nnonopts = panonopt_end - panonopt_start; nopts = opt_end - panonopt_end; ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; swap = nargv[pos]; /* LINTED const cast */ ((char **) nargv)[pos] = nargv[cstart]; /* LINTED const cast */ ((char **)nargv)[cstart] = swap; } } } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. * Returns -2 if -- is found (can be long option or end of options marker). */ static int getopt_internal(nargc, nargv, options) int nargc; char * const *nargv; const char *options; { char *oli; /* option letter list index */ int optchar; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); optarg = NULL; /* * XXX Some programs (like rsyncd) expect to be able to * XXX re-initialize optind to 0 and have getopt_long(3) * XXX properly function again. Work around this braindamage. */ if (optind == 0) optind = 1; if (optreset) nonopt_start = nonopt_end = -1; start: if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if ((*(place = nargv[optind]) != '-') || (place[1] == '\0')) { /* found non-option */ place = EMSG; if (IN_ORDER) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return INORDER; } if (!PERMUTE) { /* * if no permutation wanted, stop parsing * at first non-option */ return -1; } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; if (place[1] && *++place == '-') { /* found "--" */ place++; return -2; } } if ((optchar = (int)*place++) == (int)':' || (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { /* option letter unknown or ':' */ if (!*place) ++optind; if (PRINT_ERROR) warnx(illoptchar, optchar); optopt = optchar; return BADCH; } if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ /* XXX: what if no long options provided (called by getopt)? */ if (*place) return -2; if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return BADARG; } else /* white space */ place = nargv[optind]; /* * Handle -W arg the same as --arg (which causes getopt to * stop parsing). */ return -2; } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; /* XXX: disable test for :: if PC? (GNU doesn't) */ else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) warnx(recargchar, optchar); optopt = optchar; return BADARG; } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return optchar; } #ifdef REPLACE_GETOPT /* * getopt -- * Parse argc/argv argument vector. * * [eventually this will replace the real getopt] */ DLL_EXPORT int getopt(nargc, nargv, options) int nargc; char * const *nargv; const char *options; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); if ((retval = getopt_internal(nargc, nargv, options)) == -2) { ++optind; /* * We found an option (--), so if we skipped non-options, * we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; retval = -1; } return retval; } #endif /* * getopt_long -- * Parse argc/argv argument vector. */ DLL_EXPORT int getopt_long(nargc, nargv, options, long_options, idx) int nargc; char * const *nargv; const char *options; const struct option *long_options; int *idx; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); _DIAGASSERT(long_options != NULL); /* idx may be NULL */ if ((retval = getopt_internal(nargc, nargv, options)) == -2) { char *current_argv, *has_equal; size_t current_argv_len; int i, match; current_argv = place; match = -1; optind++; place = EMSG; if (*current_argv == '\0') { /* found "--" */ /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == (unsigned)current_argv_len) { /* exact match */ match = i; break; } if (match == -1) /* partial match */ match = i; else { /* ambiguous abbreviation */ if (PRINT_ERROR) warnx(ambig, (int)current_argv_len, current_argv); optopt = 0; return BADCH; } } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) warnx(noarg, (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of * flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; return BADARG; } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use * next nargv */ optarg = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' * indicates no error should be generated */ if (PRINT_ERROR) warnx(recargstring, current_argv); /* * XXX: GNU sets optopt to val regardless * of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; --optind; return BADARG; } } else { /* unknown option */ if (PRINT_ERROR) warnx(illoptstring, current_argv); optopt = 0; return BADCH; } if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; retval = 0; } else retval = long_options[match].val; if (idx) *idx = match; } return retval; } hercules-3.12/herclogo.txt0000664000175000017500000000211412564723224012544 00000000000000@ALIGN NONE @SBA 0,0 @SF P Hercules Version : @SF HP $(VERSION) @NL @SF P Host name : @SF HP $(HOSTNAME) @NL @SF P Host OS : @SF HP $(HOSTOS)-$(HOSTOSREL) $(HOSTOSVER) @NL @SF P Host Architecture : @SF HP $(HOSTARCH) @NL @SF P Processors : @SF HP $(HOSTNUMCPUS) @NL @SF P Chanl Subsys : @SF HP $(CSS) @NL @SF P Device number : @SF HP $(CCUU) @NL @SF P Subchannel : @SF HP $(SUBCHAN) @SF P @ALIGN LEFT HHH HHH The S/370, ESA/390 and z/Architecture HHH HHH Emulator HHH HHH HHH HHH EEEE RRR CCC U U L EEEE SSS HHHHHHHHHHHHHHHH E R R C U U L E S HHHHHHHHHHHHHHHH EEE RRR C U U L EEE SS HHHHHHHHHHHHHHHH E R R C U U L E S HHH HHH EEEE R R CCC UU LLLL EEEE SSS HHH HHH HHH HHH HHH HHH My PC thinks it's a MAINFRAME Copyright (c) 1999-2009 Roger Bowler, Jan Jaeger, and others hercules-3.12/hercules.ico0000664000175000017500000000525612564723224012521 00000000000000(6 è^00hF( €€€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿ"" (‚€"" (‚€"" (ˆˆˆ‚€""""" (ˆˆˆ‚€"" (‚€"" (‚€"" ÿÿÇÇÇÇÇ€€€ÇÇÇÇÇÿÿÿÿ( @€€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿ"" """""""" "" """" "" """""""" "" """" "" """""""" "" """" """""""""""""""""""""""" """""""""""""" "" """""""" "" """" "" """""""" "" """" "" """""""" "" ""ÿÿÿÿÿÿÿÿÿÿÿÿðþà?üðþøÿÿðþà?üðþøÿÿðþà?üðþøÿÿðàðøÿÿðþà?üðþøÿÿðþà?üðþøÿÿðþà?üðþÿÿÿÿÿÿÿÿ(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"""" """ """"""""""" """""""" """""""" """ """" """" """"""""""" """""""" """""""" """ """" """" """"""""""" """""""" """""""" """ """"""" """""""""""""""""""""""""""""""""" """"""""""""""""" """"""""""""""""" """""""""""""""""""""""""""""""" """ """"""""""" """""""" """""""" """ """" """" """"""""""" """""""" """""""" """ """" """" """"""""""" """""""" """""""" """ """"""" ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø?ÿÿÿðÿþÿàÿüÿàÿüÿàÿüÿðÿþÿüÿÿÿðÿþÿàÿüÿàÿüÿàÿüÿðÿþÿüÿÿÿðÿþÿàÿüÿàÿüÿàÿüÿðÿþÿø?ÿÿÿðÿàÿàÿàÿðÿøÿðÿþÿàÿüÿàÿüÿàÿüÿðÿþÿüÿÿÿðÿþÿàÿüÿàÿüÿàÿüÿðÿþÿüÿÿÿðÿþÿàÿüÿàÿüÿàÿüÿðÿþÿø?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿhercules-3.12/decNumber/0000775000175000017500000000000012625667404012174 500000000000000hercules-3.12/decNumber/Makefile.in0000664000175000017500000005411712625667166014176 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Makefile for building the decNumber package # for use with Hercules S/370, ESA/390 and z/Architecture emulator # # This file was added by the Hercules project. # It is not part of the original decNumber distribution. # # $Id$ # # $Log$ # Revision 1.3 2006/12/13 11:49:02 rbowler # Correct make tar error: No rule to make target `decNumber.pdf' # # Revision 1.2 2006/12/12 14:07:50 rbowler # Make decNumber a shared library not a loadable module # # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = decNumber DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/mkinstalldirs \ $(top_srcdir)/autoconf/depcomp $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = libdecNumber_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am__objects_1 = decContext.lo decimal128.lo decimal32.lo decimal64.lo \ decNumber.lo decPacked.lo am_libdecNumber_la_OBJECTS = $(am__objects_1) libdecNumber_la_OBJECTS = $(am_libdecNumber_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libdecNumber_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libdecNumber_la_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/autoconf/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libdecNumber_la_SOURCES) DIST_SOURCES = $(libdecNumber_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lns = @LN_S@ LDADD = @LIBS@ AM_CPPFLAGS = -I$(top_srcdir) decNumber_SRC = decContext.c \ decimal128.c \ decimal32.c \ decimal64.c \ decNumber.c \ decPacked.c @BUILD_SHARED_FALSE@XSTATIC = -static @BUILD_SHARED_TRUE@XSTATIC = @OPTION_DYNAMIC_LOAD_FALSE@LTDL = @OPTION_DYNAMIC_LOAD_TRUE@LTDL = ../ltdl.c @OPTION_DYNAMIC_LOAD_FALSE@LIB_LD_FLAGS = $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_FALSE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_FALSE@ -avoid-version @OPTION_DYNAMIC_LOAD_TRUE@LIB_LD_FLAGS = -export-dynamic \ @OPTION_DYNAMIC_LOAD_TRUE@ $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_TRUE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_TRUE@ -avoid-version HERCLIBS = HERCLIBS2 = libdecNumber.la noinst_LTLIBRARIES = $(HERCLIBS) lib_LTLIBRARIES = $(HERCLIBS2) libdecNumber_la_SOURCES = $(decNumber_SRC) libdecNumber_la_LDFLAGS = $(LIB_LD_FLAGS) libdecNumber_la_LIBADD = $(LDADD) noinst_HEADERS = decContext.h \ decDPD.h \ decimal128.h \ decimal32.h \ decimal64.h \ decNumber.h \ decNumberLocal.h \ decPacked.h EXTRA_DIST = decNumber.def \ decnumber.pdf \ decNumber.rc \ ICU-license.html \ readme.txt all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu decNumber/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu decNumber/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libdecNumber.la: $(libdecNumber_la_OBJECTS) $(libdecNumber_la_DEPENDENCIES) $(EXTRA_libdecNumber_la_DEPENDENCIES) $(AM_V_CCLD)$(libdecNumber_la_LINK) -rpath $(libdir) $(libdecNumber_la_OBJECTS) $(libdecNumber_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decContext.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decNumber.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decPacked.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decimal128.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decimal32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decimal64.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libLTLIBRARIES %.s: %.c $(COMPILE) -S $< # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/decNumber/Makefile.am0000664000175000017500000000307312564723224014146 00000000000000## Process this file with automake to produce Makefile.in # # Makefile for building the decNumber package # for use with Hercules S/370, ESA/390 and z/Architecture emulator # # This file was added by the Hercules project. # It is not part of the original decNumber distribution. # # $Id$ # # $Log$ # Revision 1.3 2006/12/13 11:49:02 rbowler # Correct make tar error: No rule to make target `decNumber.pdf' # # Revision 1.2 2006/12/12 14:07:50 rbowler # Make decNumber a shared library not a loadable module # # lns=@LN_S@ LDADD = @LIBS@ AM_CPPFLAGS = -I$(top_srcdir) decNumber_SRC = decContext.c \ decimal128.c \ decimal32.c \ decimal64.c \ decNumber.c \ decPacked.c if BUILD_SHARED XSTATIC = else XSTATIC = -static endif if OPTION_DYNAMIC_LOAD LTDL = ../ltdl.c LIB_LD_FLAGS = -export-dynamic \ $(XSTATIC) \ -no-undefined \ -avoid-version else LTDL = LIB_LD_FLAGS = $(XSTATIC) \ -no-undefined \ -avoid-version endif HERCLIBS = HERCLIBS2 = libdecNumber.la noinst_LTLIBRARIES = $(HERCLIBS) lib_LTLIBRARIES = $(HERCLIBS2) libdecNumber_la_SOURCES = $(decNumber_SRC) libdecNumber_la_LDFLAGS = $(LIB_LD_FLAGS) libdecNumber_la_LIBADD = $(LDADD) noinst_HEADERS = decContext.h \ decDPD.h \ decimal128.h \ decimal32.h \ decimal64.h \ decNumber.h \ decNumberLocal.h \ decPacked.h EXTRA_DIST = decNumber.def \ decnumber.pdf \ decNumber.rc \ ICU-license.html \ readme.txt %.s: %.c $(COMPILE) -S $< hercules-3.12/decNumber/decContext.h0000664000175000017500000001750212564723224014365 00000000000000/* ------------------------------------------------------------------ */ /* Decimal Context module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* */ /* Context must always be set correctly: */ /* */ /* digits -- must be in the range 1 through 999999999 */ /* emax -- must be in the range 0 through 999999999 */ /* emin -- must be in the range 0 through -999999999 */ /* round -- must be one of the enumerated rounding modes */ /* traps -- only defined bits may be set */ /* status -- [any bits may be cleared, but not set, by user] */ /* clamp -- must be either 0 or 1 */ /* extended -- must be either 0 or 1 [present only if DECSUBSET] */ /* */ /* ------------------------------------------------------------------ */ #if !defined(DECCONTEXT) #define DECCONTEXT #define DECCNAME "decContext" /* Short name */ #define DECCFULLNAME "Decimal Context Descriptor" /* Verbose name */ #define DECCAUTHOR "Mike Cowlishaw" /* Who to blame */ #if !defined(int32_t) #include // C99 standard integers #endif #include // for traps /* Conditional code flag -- set this to 0 for best performance */ #define DECSUBSET 0 // 1=enable subset arithmetic /* Context for operations, with associated constants */ enum rounding { DEC_ROUND_CEILING, // round towards +infinity DEC_ROUND_UP, // round away from 0 DEC_ROUND_HALF_UP, // 0.5 rounds up DEC_ROUND_HALF_EVEN, // 0.5 rounds to nearest even DEC_ROUND_HALF_DOWN, // 0.5 rounds down DEC_ROUND_DOWN, // round towards 0 (truncate) DEC_ROUND_FLOOR, // round towards -infinity DEC_ROUND_MAX // enum must be less than this }; typedef struct { int32_t digits; // working precision int32_t emax; // maximum positive exponent int32_t emin; // minimum negative exponent enum rounding round; // rounding mode uint32_t traps; // trap-enabler flags uint32_t status; // status flags uint8_t clamp; // flag: apply IEEE exponent clamp #if DECSUBSET uint8_t extended; // flag: special-values allowed #endif } decContext; /* Maxima and Minima */ #define DEC_MAX_DIGITS 999999999 #define DEC_MIN_DIGITS 1 #define DEC_MAX_EMAX 999999999 #define DEC_MIN_EMAX 0 #define DEC_MAX_EMIN 0 #define DEC_MIN_EMIN -999999999 #define DEC_MAX_MATH 999999 // max emax, etc., for math functions /* Trap-enabler and Status flags (exceptional conditions), and their names */ // Top byte is reserved for internal use #define DEC_Conversion_syntax 0x00000001 #define DEC_Division_by_zero 0x00000002 #define DEC_Division_impossible 0x00000004 #define DEC_Division_undefined 0x00000008 #define DEC_Insufficient_storage 0x00000010 // [used if malloc fails] #define DEC_Inexact 0x00000020 #define DEC_Invalid_context 0x00000040 #define DEC_Invalid_operation 0x00000080 #if DECSUBSET #define DEC_Lost_digits 0x00000100 #endif #define DEC_Overflow 0x00000200 #define DEC_Clamped 0x00000400 #define DEC_Rounded 0x00000800 #define DEC_Subnormal 0x00001000 #define DEC_Underflow 0x00002000 /* IEEE 854 groupings for the flags */ // [DEC_Clamped, DEC_Lost_digits, DEC_Rounded, and DEC_Subnormal are // not in IEEE 854] #define DEC_IEEE_854_Division_by_zero (DEC_Division_by_zero) #if DECSUBSET #define DEC_IEEE_854_Inexact (DEC_Inexact | DEC_Lost_digits) #else #define DEC_IEEE_854_Inexact (DEC_Inexact) #endif #define DEC_IEEE_854_Invalid_operation (DEC_Conversion_syntax | \ DEC_Division_impossible | \ DEC_Division_undefined | \ DEC_Insufficient_storage | \ DEC_Invalid_context | \ DEC_Invalid_operation) #define DEC_IEEE_854_Overflow (DEC_Overflow) #define DEC_IEEE_854_Underflow (DEC_Underflow) // flags which are normally errors (results are qNaN, infinite, or 0) #define DEC_Errors (DEC_IEEE_854_Division_by_zero | \ DEC_IEEE_854_Invalid_operation | \ DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow) // flags which cause a result to become qNaN #define DEC_NaNs DEC_IEEE_854_Invalid_operation // flags which are normally for information only (have finite results) #if DECSUBSET #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact \ | DEC_Lost_digits) #else #define DEC_Information (DEC_Clamped | DEC_Rounded | DEC_Inexact) #endif // name strings for the exceptional conditions #define DEC_Condition_CS "Conversion syntax" #define DEC_Condition_DZ "Division by zero" #define DEC_Condition_DI "Division impossible" #define DEC_Condition_DU "Division undefined" #define DEC_Condition_IE "Inexact" #define DEC_Condition_IS "Insufficient storage" #define DEC_Condition_IC "Invalid context" #define DEC_Condition_IO "Invalid operation" #if DECSUBSET #define DEC_Condition_LD "Lost digits" #endif #define DEC_Condition_OV "Overflow" #define DEC_Condition_PA "Clamped" #define DEC_Condition_RO "Rounded" #define DEC_Condition_SU "Subnormal" #define DEC_Condition_UN "Underflow" #define DEC_Condition_ZE "No status" #define DEC_Condition_MU "Multiple status" #define DEC_Condition_Length 21 // length of the longest string, // including terminator /* Initialization descriptors, used by decContextDefault */ #define DEC_INIT_BASE 0 #define DEC_INIT_DECIMAL32 32 #define DEC_INIT_DECIMAL64 64 #define DEC_INIT_DECIMAL128 128 /* decContext routines */ decContext * decContextDefault(decContext *, int32_t); decContext * decContextSetStatus(decContext *, uint32_t); const char * decContextStatusToString(const decContext *); decContext * decContextSetStatusFromString(decContext *, const char *); #endif hercules-3.12/decNumber/decDPD.h0000664000175000017500000017577012564723224013364 00000000000000/* ------------------------------------------------------------------------ */ /* Binary Coded Decimal <--> Densely Packed Decimal lookup tables */ /* [Automatically generated -- do not edit. 2006.11.09] */ /* ------------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ /* ------------------------------------------------------------------------ */ /* For details, see: http://www2.hursley.ibm.com/decimal/DPDecimal.html */ /* */ /* This include file defines conversion tables for DPD, as follows. */ /* */ /* uint16_t BCD2DPD[2458]; // BCD -> DPD (0x999 => 2457) */ /* uint16_t BIN2DPD[1000]; // BIN -> DPD (999 => 2457) */ /* uint8_t BIN2CHAR[4001]; // Bin -> CHAR (999 => '\3' '9' '9' '9') */ /* uint16_t DPD2BCD[1024]; // DPD -> BCD (0x3FF => 0x999) */ /* uint16_t DPD2BIN[1024]; // DPD -> BIN (0x3FF => 999) */ /* uint8_t DPD2BCD8[4096]; // DPD -> bytes (x3FF => 9 9 9 3) */ /* */ /* In all cases the result (10 bits or 12 bits, or binary) is right-aligned */ /* in the table entry. BIN2CHAR entries are a single byte length (0 for */ /* value 0) followed by three digit characters; a trailing terminator is */ /* included to allow 4-char moves always. DPD2BCD8 entries are similar */ /* with the three BCD8 digits followed by a one-byte length. */ /* */ /* To use a table, its name, prefixed with DEC_, must be defined with a */ /* value of 1 before this header file is included. For example: */ /* #define DEC_BCD2DPD 1 */ /* ------------------------------------------------------------------------ */ #if DEC_BCD2DPD==1 && !defined(DECBCD2DPD) #define DECBCD2DPD const uint16_t BCD2DPD[2458]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 0, 0, 0, 0, 0, 0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 0, 0, 0, 0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, 0, 0, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 0, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 0, 0, 0, 0, 0, 0, 10, 11, 42, 43, 74, 75, 106, 107, 78, 79, 0, 0, 0, 0, 0, 0, 26, 27, 58, 59, 90, 91, 122, 123, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 42, 43, 74, 75, 106, 107, 78, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 0, 0, 0, 0, 0, 0, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 0, 0, 0, 0, 0, 0, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 0, 0, 0, 0, 0, 0, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 0, 0, 0, 0, 0, 0, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 0, 0, 0, 0, 0, 0, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 0, 0, 0, 0, 0, 0, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 0, 0, 0, 0, 0, 0, 138, 139, 170, 171, 202, 203, 234, 235, 206, 207, 0, 0, 0, 0, 0, 0, 154, 155, 186, 187, 218, 219, 250, 251, 222, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 139, 170, 171, 202, 203, 234, 235, 206, 207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 0, 0, 0, 0, 0, 0, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 0, 0, 0, 0, 0, 0, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 0, 0, 0, 0, 0, 0, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 0, 0, 0, 0, 0, 0, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 0, 0, 0, 0, 0, 0, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, 0, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 0, 0, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 0, 0, 0, 0, 0, 0, 266, 267, 298, 299, 330, 331, 362, 363, 334, 335, 0, 0, 0, 0, 0, 0, 282, 283, 314, 315, 346, 347, 378, 379, 350, 351, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 266, 267, 298, 299, 330, 331, 362, 363, 334, 335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 0, 0, 0, 0, 0, 0, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 0, 0, 0, 0, 0, 0, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 0, 0, 0, 0, 0, 0, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 0, 0, 0, 0, 0, 0, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 0, 0, 0, 0, 0, 0, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 0, 0, 0, 0, 0, 0, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 0, 0, 0, 0, 0, 0, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 0, 0, 0, 0, 0, 0, 394, 395, 426, 427, 458, 459, 490, 491, 462, 463, 0, 0, 0, 0, 0, 0, 410, 411, 442, 443, 474, 475, 506, 507, 478, 479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 394, 395, 426, 427, 458, 459, 490, 491, 462, 463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 0, 0, 0, 0, 0, 0, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 0, 0, 0, 0, 0, 0, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 0, 0, 0, 0, 0, 0, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 0, 0, 0, 0, 0, 0, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 0, 0, 0, 0, 0, 0, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 0, 0, 0, 0, 0, 0, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 0, 0, 0, 0, 0, 0, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 0, 0, 0, 0, 0, 0, 522, 523, 554, 555, 586, 587, 618, 619, 590, 591, 0, 0, 0, 0, 0, 0, 538, 539, 570, 571, 602, 603, 634, 635, 606, 607, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 522, 523, 554, 555, 586, 587, 618, 619, 590, 591, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 0, 0, 0, 0, 0, 0, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 0, 0, 0, 0, 0, 0, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 0, 0, 0, 0, 0, 0, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 0, 0, 0, 0, 0, 0, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 0, 0, 0, 0, 0, 0, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 0, 0, 0, 0, 0, 0, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 0, 0, 0, 0, 0, 0, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 0, 0, 0, 0, 0, 0, 650, 651, 682, 683, 714, 715, 746, 747, 718, 719, 0, 0, 0, 0, 0, 0, 666, 667, 698, 699, 730, 731, 762, 763, 734, 735, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 650, 651, 682, 683, 714, 715, 746, 747, 718, 719, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 0, 0, 0, 0, 0, 0, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 0, 0, 0, 0, 0, 0, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 0, 0, 0, 0, 0, 0, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 0, 0, 0, 0, 0, 0, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 0, 0, 0, 0, 0, 0, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 0, 0, 0, 0, 0, 0, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 0, 0, 0, 0, 0, 0, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 0, 0, 0, 0, 0, 0, 778, 779, 810, 811, 842, 843, 874, 875, 846, 847, 0, 0, 0, 0, 0, 0, 794, 795, 826, 827, 858, 859, 890, 891, 862, 863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 778, 779, 810, 811, 842, 843, 874, 875, 846, 847, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 0, 0, 0, 0, 0, 0, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 0, 0, 0, 0, 0, 0, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 0, 0, 0, 0, 0, 0, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 0, 0, 0, 0, 0, 0, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 0, 0, 0, 0, 0, 0, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 0, 0, 0, 0, 0, 0, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 0, 0, 0, 0, 0, 0, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 0, 0, 0, 0, 0, 0, 906, 907, 938, 939, 970, 971, 1002, 1003, 974, 975, 0, 0, 0, 0, 0, 0, 922, 923, 954, 955, 986, 987, 1018, 1019, 990, 991, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 906, 907, 938, 939, 970, 971, 1002, 1003, 974, 975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 268, 269, 524, 525, 780, 781, 46, 47, 0, 0, 0, 0, 0, 0, 28, 29, 284, 285, 540, 541, 796, 797, 62, 63, 0, 0, 0, 0, 0, 0, 44, 45, 300, 301, 556, 557, 812, 813, 302, 303, 0, 0, 0, 0, 0, 0, 60, 61, 316, 317, 572, 573, 828, 829, 318, 319, 0, 0, 0, 0, 0, 0, 76, 77, 332, 333, 588, 589, 844, 845, 558, 559, 0, 0, 0, 0, 0, 0, 92, 93, 348, 349, 604, 605, 860, 861, 574, 575, 0, 0, 0, 0, 0, 0, 108, 109, 364, 365, 620, 621, 876, 877, 814, 815, 0, 0, 0, 0, 0, 0, 124, 125, 380, 381, 636, 637, 892, 893, 830, 831, 0, 0, 0, 0, 0, 0, 14, 15, 270, 271, 526, 527, 782, 783, 110, 111, 0, 0, 0, 0, 0, 0, 30, 31, 286, 287, 542, 543, 798, 799, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 270, 271, 526, 527, 782, 783, 110, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 141, 396, 397, 652, 653, 908, 909, 174, 175, 0, 0, 0, 0, 0, 0, 156, 157, 412, 413, 668, 669, 924, 925, 190, 191, 0, 0, 0, 0, 0, 0, 172, 173, 428, 429, 684, 685, 940, 941, 430, 431, 0, 0, 0, 0, 0, 0, 188, 189, 444, 445, 700, 701, 956, 957, 446, 447, 0, 0, 0, 0, 0, 0, 204, 205, 460, 461, 716, 717, 972, 973, 686, 687, 0, 0, 0, 0, 0, 0, 220, 221, 476, 477, 732, 733, 988, 989, 702, 703, 0, 0, 0, 0, 0, 0, 236, 237, 492, 493, 748, 749, 1004, 1005, 942, 943, 0, 0, 0, 0, 0, 0, 252, 253, 508, 509, 764, 765, 1020, 1021, 958, 959, 0, 0, 0, 0, 0, 0, 142, 143, 398, 399, 654, 655, 910, 911, 238, 239, 0, 0, 0, 0, 0, 0, 158, 159, 414, 415, 670, 671, 926, 927, 254, 255}; #endif #if DEC_DPD2BCD==1 && !defined(DECDPD2BCD) #define DECDPD2BCD const uint16_t DPD2BCD[1024]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 128, 129, 2048, 2049, 2176, 2177, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 144, 145, 2064, 2065, 2192, 2193, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 130, 131, 2080, 2081, 2056, 2057, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 146, 147, 2096, 2097, 2072, 2073, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 132, 133, 2112, 2113, 136, 137, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 148, 149, 2128, 2129, 152, 153, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 134, 135, 2144, 2145, 2184, 2185, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 150, 151, 2160, 2161, 2200, 2201, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 384, 385, 2304, 2305, 2432, 2433, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 400, 401, 2320, 2321, 2448, 2449, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 386, 387, 2336, 2337, 2312, 2313, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 402, 403, 2352, 2353, 2328, 2329, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 388, 389, 2368, 2369, 392, 393, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 404, 405, 2384, 2385, 408, 409, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 390, 391, 2400, 2401, 2440, 2441, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 406, 407, 2416, 2417, 2456, 2457, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 640, 641, 2050, 2051, 2178, 2179, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 656, 657, 2066, 2067, 2194, 2195, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 642, 643, 2082, 2083, 2088, 2089, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 658, 659, 2098, 2099, 2104, 2105, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 644, 645, 2114, 2115, 648, 649, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 660, 661, 2130, 2131, 664, 665, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 646, 647, 2146, 2147, 2184, 2185, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 662, 663, 2162, 2163, 2200, 2201, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 896, 897, 2306, 2307, 2434, 2435, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 912, 913, 2322, 2323, 2450, 2451, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 898, 899, 2338, 2339, 2344, 2345, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 914, 915, 2354, 2355, 2360, 2361, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 900, 901, 2370, 2371, 904, 905, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 916, 917, 2386, 2387, 920, 921, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 902, 903, 2402, 2403, 2440, 2441, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 918, 919, 2418, 2419, 2456, 2457, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1152, 1153, 2052, 2053, 2180, 2181, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1168, 1169, 2068, 2069, 2196, 2197, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1154, 1155, 2084, 2085, 2120, 2121, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1170, 1171, 2100, 2101, 2136, 2137, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1156, 1157, 2116, 2117, 1160, 1161, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1172, 1173, 2132, 2133, 1176, 1177, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1158, 1159, 2148, 2149, 2184, 2185, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1174, 1175, 2164, 2165, 2200, 2201, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1408, 1409, 2308, 2309, 2436, 2437, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1424, 1425, 2324, 2325, 2452, 2453, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1410, 1411, 2340, 2341, 2376, 2377, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1426, 1427, 2356, 2357, 2392, 2393, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1412, 1413, 2372, 2373, 1416, 1417, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1428, 1429, 2388, 2389, 1432, 1433, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1414, 1415, 2404, 2405, 2440, 2441, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1430, 1431, 2420, 2421, 2456, 2457, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1664, 1665, 2054, 2055, 2182, 2183, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1680, 1681, 2070, 2071, 2198, 2199, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1666, 1667, 2086, 2087, 2152, 2153, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1682, 1683, 2102, 2103, 2168, 2169, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1668, 1669, 2118, 2119, 1672, 1673, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1684, 1685, 2134, 2135, 1688, 1689, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1670, 1671, 2150, 2151, 2184, 2185, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1686, 1687, 2166, 2167, 2200, 2201, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1920, 1921, 2310, 2311, 2438, 2439, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1936, 1937, 2326, 2327, 2454, 2455, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1922, 1923, 2342, 2343, 2408, 2409, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1938, 1939, 2358, 2359, 2424, 2425, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1924, 1925, 2374, 2375, 1928, 1929, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1940, 1941, 2390, 2391, 1944, 1945, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1926, 1927, 2406, 2407, 2440, 2441, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1942, 1943, 2422, 2423, 2456, 2457}; #endif #if DEC_BIN2DPD==1 && !defined(DECBIN2DPD) #define DECBIN2DPD const uint16_t BIN2DPD[1000]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 10, 11, 42, 43, 74, 75, 106, 107, 78, 79, 26, 27, 58, 59, 90, 91, 122, 123, 94, 95, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 138, 139, 170, 171, 202, 203, 234, 235, 206, 207, 154, 155, 186, 187, 218, 219, 250, 251, 222, 223, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 266, 267, 298, 299, 330, 331, 362, 363, 334, 335, 282, 283, 314, 315, 346, 347, 378, 379, 350, 351, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 394, 395, 426, 427, 458, 459, 490, 491, 462, 463, 410, 411, 442, 443, 474, 475, 506, 507, 478, 479, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 522, 523, 554, 555, 586, 587, 618, 619, 590, 591, 538, 539, 570, 571, 602, 603, 634, 635, 606, 607, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 650, 651, 682, 683, 714, 715, 746, 747, 718, 719, 666, 667, 698, 699, 730, 731, 762, 763, 734, 735, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 778, 779, 810, 811, 842, 843, 874, 875, 846, 847, 794, 795, 826, 827, 858, 859, 890, 891, 862, 863, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 906, 907, 938, 939, 970, 971, 1002, 1003, 974, 975, 922, 923, 954, 955, 986, 987, 1018, 1019, 990, 991, 12, 13, 268, 269, 524, 525, 780, 781, 46, 47, 28, 29, 284, 285, 540, 541, 796, 797, 62, 63, 44, 45, 300, 301, 556, 557, 812, 813, 302, 303, 60, 61, 316, 317, 572, 573, 828, 829, 318, 319, 76, 77, 332, 333, 588, 589, 844, 845, 558, 559, 92, 93, 348, 349, 604, 605, 860, 861, 574, 575, 108, 109, 364, 365, 620, 621, 876, 877, 814, 815, 124, 125, 380, 381, 636, 637, 892, 893, 830, 831, 14, 15, 270, 271, 526, 527, 782, 783, 110, 111, 30, 31, 286, 287, 542, 543, 798, 799, 126, 127, 140, 141, 396, 397, 652, 653, 908, 909, 174, 175, 156, 157, 412, 413, 668, 669, 924, 925, 190, 191, 172, 173, 428, 429, 684, 685, 940, 941, 430, 431, 188, 189, 444, 445, 700, 701, 956, 957, 446, 447, 204, 205, 460, 461, 716, 717, 972, 973, 686, 687, 220, 221, 476, 477, 732, 733, 988, 989, 702, 703, 236, 237, 492, 493, 748, 749, 1004, 1005, 942, 943, 252, 253, 508, 509, 764, 765, 1020, 1021, 958, 959, 142, 143, 398, 399, 654, 655, 910, 911, 238, 239, 158, 159, 414, 415, 670, 671, 926, 927, 254, 255}; #endif #if DEC_DPD2BIN==1 && !defined(DECDPD2BIN) #define DECDPD2BIN const uint16_t DPD2BIN[1024]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 80, 81, 800, 801, 880, 881, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 90, 91, 810, 811, 890, 891, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 82, 83, 820, 821, 808, 809, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 92, 93, 830, 831, 818, 819, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 84, 85, 840, 841, 88, 89, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 94, 95, 850, 851, 98, 99, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 86, 87, 860, 861, 888, 889, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 96, 97, 870, 871, 898, 899, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 180, 181, 900, 901, 980, 981, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 190, 191, 910, 911, 990, 991, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 182, 183, 920, 921, 908, 909, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 192, 193, 930, 931, 918, 919, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 184, 185, 940, 941, 188, 189, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 194, 195, 950, 951, 198, 199, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 186, 187, 960, 961, 988, 989, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 196, 197, 970, 971, 998, 999, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 280, 281, 802, 803, 882, 883, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 290, 291, 812, 813, 892, 893, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 282, 283, 822, 823, 828, 829, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 292, 293, 832, 833, 838, 839, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 284, 285, 842, 843, 288, 289, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 294, 295, 852, 853, 298, 299, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 286, 287, 862, 863, 888, 889, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 296, 297, 872, 873, 898, 899, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 380, 381, 902, 903, 982, 983, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 390, 391, 912, 913, 992, 993, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 382, 383, 922, 923, 928, 929, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 392, 393, 932, 933, 938, 939, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 384, 385, 942, 943, 388, 389, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 394, 395, 952, 953, 398, 399, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 386, 387, 962, 963, 988, 989, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 396, 397, 972, 973, 998, 999, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 480, 481, 804, 805, 884, 885, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 490, 491, 814, 815, 894, 895, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 482, 483, 824, 825, 848, 849, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 492, 493, 834, 835, 858, 859, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 484, 485, 844, 845, 488, 489, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 494, 495, 854, 855, 498, 499, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 486, 487, 864, 865, 888, 889, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 496, 497, 874, 875, 898, 899, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 580, 581, 904, 905, 984, 985, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 590, 591, 914, 915, 994, 995, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 582, 583, 924, 925, 948, 949, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 592, 593, 934, 935, 958, 959, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 584, 585, 944, 945, 588, 589, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 594, 595, 954, 955, 598, 599, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 586, 587, 964, 965, 988, 989, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 596, 597, 974, 975, 998, 999, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 680, 681, 806, 807, 886, 887, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 690, 691, 816, 817, 896, 897, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 682, 683, 826, 827, 868, 869, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 692, 693, 836, 837, 878, 879, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 684, 685, 846, 847, 688, 689, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 694, 695, 856, 857, 698, 699, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 686, 687, 866, 867, 888, 889, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 696, 697, 876, 877, 898, 899, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 780, 781, 906, 907, 986, 987, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 790, 791, 916, 917, 996, 997, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 782, 783, 926, 927, 968, 969, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 792, 793, 936, 937, 978, 979, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 784, 785, 946, 947, 788, 789, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 794, 795, 956, 957, 798, 799, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 786, 787, 966, 967, 988, 989, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 796, 797, 976, 977, 998, 999}; #endif #if DEC_BIN2CHAR==1 && !defined(DECBIN2CHAR) #define DECBIN2CHAR const uint8_t BIN2CHAR[4001]={ '\0','0','0','0', '\1','0','0','1', '\1','0','0','2', '\1','0','0','3', '\1','0','0','4', '\1','0','0','5', '\1','0','0','6', '\1','0','0','7', '\1','0','0','8', '\1','0','0','9', '\2','0','1','0', '\2','0','1','1', '\2','0','1','2', '\2','0','1','3', '\2','0','1','4', '\2','0','1','5', '\2','0','1','6', '\2','0','1','7', '\2','0','1','8', '\2','0','1','9', '\2','0','2','0', '\2','0','2','1', '\2','0','2','2', '\2','0','2','3', '\2','0','2','4', '\2','0','2','5', '\2','0','2','6', '\2','0','2','7', '\2','0','2','8', '\2','0','2','9', '\2','0','3','0', '\2','0','3','1', '\2','0','3','2', '\2','0','3','3', '\2','0','3','4', '\2','0','3','5', '\2','0','3','6', '\2','0','3','7', '\2','0','3','8', '\2','0','3','9', '\2','0','4','0', '\2','0','4','1', '\2','0','4','2', '\2','0','4','3', '\2','0','4','4', '\2','0','4','5', '\2','0','4','6', '\2','0','4','7', '\2','0','4','8', '\2','0','4','9', '\2','0','5','0', '\2','0','5','1', '\2','0','5','2', '\2','0','5','3', '\2','0','5','4', '\2','0','5','5', '\2','0','5','6', '\2','0','5','7', '\2','0','5','8', '\2','0','5','9', '\2','0','6','0', '\2','0','6','1', '\2','0','6','2', '\2','0','6','3', '\2','0','6','4', '\2','0','6','5', '\2','0','6','6', '\2','0','6','7', '\2','0','6','8', '\2','0','6','9', '\2','0','7','0', '\2','0','7','1', '\2','0','7','2', '\2','0','7','3', '\2','0','7','4', '\2','0','7','5', '\2','0','7','6', '\2','0','7','7', '\2','0','7','8', '\2','0','7','9', '\2','0','8','0', '\2','0','8','1', '\2','0','8','2', '\2','0','8','3', '\2','0','8','4', '\2','0','8','5', '\2','0','8','6', '\2','0','8','7', '\2','0','8','8', '\2','0','8','9', '\2','0','9','0', '\2','0','9','1', '\2','0','9','2', '\2','0','9','3', '\2','0','9','4', '\2','0','9','5', '\2','0','9','6', '\2','0','9','7', '\2','0','9','8', '\2','0','9','9', '\3','1','0','0', '\3','1','0','1', '\3','1','0','2', '\3','1','0','3', '\3','1','0','4', '\3','1','0','5', '\3','1','0','6', '\3','1','0','7', '\3','1','0','8', '\3','1','0','9', '\3','1','1','0', '\3','1','1','1', '\3','1','1','2', '\3','1','1','3', '\3','1','1','4', '\3','1','1','5', '\3','1','1','6', '\3','1','1','7', '\3','1','1','8', '\3','1','1','9', '\3','1','2','0', '\3','1','2','1', '\3','1','2','2', '\3','1','2','3', '\3','1','2','4', '\3','1','2','5', '\3','1','2','6', '\3','1','2','7', '\3','1','2','8', '\3','1','2','9', '\3','1','3','0', '\3','1','3','1', '\3','1','3','2', '\3','1','3','3', '\3','1','3','4', '\3','1','3','5', '\3','1','3','6', '\3','1','3','7', '\3','1','3','8', '\3','1','3','9', '\3','1','4','0', '\3','1','4','1', '\3','1','4','2', '\3','1','4','3', '\3','1','4','4', '\3','1','4','5', '\3','1','4','6', '\3','1','4','7', '\3','1','4','8', '\3','1','4','9', '\3','1','5','0', '\3','1','5','1', '\3','1','5','2', '\3','1','5','3', '\3','1','5','4', '\3','1','5','5', '\3','1','5','6', '\3','1','5','7', '\3','1','5','8', '\3','1','5','9', '\3','1','6','0', '\3','1','6','1', '\3','1','6','2', '\3','1','6','3', '\3','1','6','4', '\3','1','6','5', '\3','1','6','6', '\3','1','6','7', '\3','1','6','8', '\3','1','6','9', '\3','1','7','0', '\3','1','7','1', '\3','1','7','2', '\3','1','7','3', '\3','1','7','4', '\3','1','7','5', '\3','1','7','6', '\3','1','7','7', '\3','1','7','8', '\3','1','7','9', '\3','1','8','0', '\3','1','8','1', '\3','1','8','2', '\3','1','8','3', '\3','1','8','4', '\3','1','8','5', '\3','1','8','6', '\3','1','8','7', '\3','1','8','8', '\3','1','8','9', '\3','1','9','0', '\3','1','9','1', '\3','1','9','2', '\3','1','9','3', '\3','1','9','4', '\3','1','9','5', '\3','1','9','6', '\3','1','9','7', '\3','1','9','8', '\3','1','9','9', '\3','2','0','0', '\3','2','0','1', '\3','2','0','2', '\3','2','0','3', '\3','2','0','4', '\3','2','0','5', '\3','2','0','6', '\3','2','0','7', '\3','2','0','8', '\3','2','0','9', '\3','2','1','0', '\3','2','1','1', '\3','2','1','2', '\3','2','1','3', '\3','2','1','4', '\3','2','1','5', '\3','2','1','6', '\3','2','1','7', '\3','2','1','8', '\3','2','1','9', '\3','2','2','0', '\3','2','2','1', '\3','2','2','2', '\3','2','2','3', '\3','2','2','4', '\3','2','2','5', '\3','2','2','6', '\3','2','2','7', '\3','2','2','8', '\3','2','2','9', '\3','2','3','0', '\3','2','3','1', '\3','2','3','2', '\3','2','3','3', '\3','2','3','4', '\3','2','3','5', '\3','2','3','6', '\3','2','3','7', '\3','2','3','8', '\3','2','3','9', '\3','2','4','0', '\3','2','4','1', '\3','2','4','2', '\3','2','4','3', '\3','2','4','4', '\3','2','4','5', '\3','2','4','6', '\3','2','4','7', '\3','2','4','8', '\3','2','4','9', '\3','2','5','0', '\3','2','5','1', '\3','2','5','2', '\3','2','5','3', '\3','2','5','4', '\3','2','5','5', '\3','2','5','6', '\3','2','5','7', '\3','2','5','8', '\3','2','5','9', '\3','2','6','0', '\3','2','6','1', '\3','2','6','2', '\3','2','6','3', '\3','2','6','4', '\3','2','6','5', '\3','2','6','6', '\3','2','6','7', '\3','2','6','8', '\3','2','6','9', '\3','2','7','0', '\3','2','7','1', '\3','2','7','2', '\3','2','7','3', '\3','2','7','4', '\3','2','7','5', '\3','2','7','6', '\3','2','7','7', '\3','2','7','8', '\3','2','7','9', '\3','2','8','0', '\3','2','8','1', '\3','2','8','2', '\3','2','8','3', '\3','2','8','4', '\3','2','8','5', '\3','2','8','6', '\3','2','8','7', '\3','2','8','8', '\3','2','8','9', '\3','2','9','0', '\3','2','9','1', '\3','2','9','2', '\3','2','9','3', '\3','2','9','4', '\3','2','9','5', '\3','2','9','6', '\3','2','9','7', '\3','2','9','8', '\3','2','9','9', '\3','3','0','0', '\3','3','0','1', '\3','3','0','2', '\3','3','0','3', '\3','3','0','4', '\3','3','0','5', '\3','3','0','6', '\3','3','0','7', '\3','3','0','8', '\3','3','0','9', '\3','3','1','0', '\3','3','1','1', '\3','3','1','2', '\3','3','1','3', '\3','3','1','4', '\3','3','1','5', '\3','3','1','6', '\3','3','1','7', '\3','3','1','8', '\3','3','1','9', '\3','3','2','0', '\3','3','2','1', '\3','3','2','2', '\3','3','2','3', '\3','3','2','4', '\3','3','2','5', '\3','3','2','6', '\3','3','2','7', '\3','3','2','8', '\3','3','2','9', '\3','3','3','0', '\3','3','3','1', '\3','3','3','2', '\3','3','3','3', '\3','3','3','4', '\3','3','3','5', '\3','3','3','6', '\3','3','3','7', '\3','3','3','8', '\3','3','3','9', '\3','3','4','0', '\3','3','4','1', '\3','3','4','2', '\3','3','4','3', '\3','3','4','4', '\3','3','4','5', '\3','3','4','6', '\3','3','4','7', '\3','3','4','8', '\3','3','4','9', '\3','3','5','0', '\3','3','5','1', '\3','3','5','2', '\3','3','5','3', '\3','3','5','4', '\3','3','5','5', '\3','3','5','6', '\3','3','5','7', '\3','3','5','8', '\3','3','5','9', '\3','3','6','0', '\3','3','6','1', '\3','3','6','2', '\3','3','6','3', '\3','3','6','4', '\3','3','6','5', '\3','3','6','6', '\3','3','6','7', '\3','3','6','8', '\3','3','6','9', '\3','3','7','0', '\3','3','7','1', '\3','3','7','2', '\3','3','7','3', '\3','3','7','4', '\3','3','7','5', '\3','3','7','6', '\3','3','7','7', '\3','3','7','8', '\3','3','7','9', '\3','3','8','0', '\3','3','8','1', '\3','3','8','2', '\3','3','8','3', '\3','3','8','4', '\3','3','8','5', '\3','3','8','6', '\3','3','8','7', '\3','3','8','8', '\3','3','8','9', '\3','3','9','0', '\3','3','9','1', '\3','3','9','2', '\3','3','9','3', '\3','3','9','4', '\3','3','9','5', '\3','3','9','6', '\3','3','9','7', '\3','3','9','8', '\3','3','9','9', '\3','4','0','0', '\3','4','0','1', '\3','4','0','2', '\3','4','0','3', '\3','4','0','4', '\3','4','0','5', '\3','4','0','6', '\3','4','0','7', '\3','4','0','8', '\3','4','0','9', '\3','4','1','0', '\3','4','1','1', '\3','4','1','2', '\3','4','1','3', '\3','4','1','4', '\3','4','1','5', '\3','4','1','6', '\3','4','1','7', '\3','4','1','8', '\3','4','1','9', '\3','4','2','0', '\3','4','2','1', '\3','4','2','2', '\3','4','2','3', '\3','4','2','4', '\3','4','2','5', '\3','4','2','6', '\3','4','2','7', '\3','4','2','8', '\3','4','2','9', '\3','4','3','0', '\3','4','3','1', '\3','4','3','2', '\3','4','3','3', '\3','4','3','4', '\3','4','3','5', '\3','4','3','6', '\3','4','3','7', '\3','4','3','8', '\3','4','3','9', '\3','4','4','0', '\3','4','4','1', '\3','4','4','2', '\3','4','4','3', '\3','4','4','4', '\3','4','4','5', '\3','4','4','6', '\3','4','4','7', '\3','4','4','8', '\3','4','4','9', '\3','4','5','0', '\3','4','5','1', '\3','4','5','2', '\3','4','5','3', '\3','4','5','4', '\3','4','5','5', '\3','4','5','6', '\3','4','5','7', '\3','4','5','8', '\3','4','5','9', '\3','4','6','0', '\3','4','6','1', '\3','4','6','2', '\3','4','6','3', '\3','4','6','4', '\3','4','6','5', '\3','4','6','6', '\3','4','6','7', '\3','4','6','8', '\3','4','6','9', '\3','4','7','0', '\3','4','7','1', '\3','4','7','2', '\3','4','7','3', '\3','4','7','4', '\3','4','7','5', '\3','4','7','6', '\3','4','7','7', '\3','4','7','8', '\3','4','7','9', '\3','4','8','0', '\3','4','8','1', '\3','4','8','2', '\3','4','8','3', '\3','4','8','4', '\3','4','8','5', '\3','4','8','6', '\3','4','8','7', '\3','4','8','8', '\3','4','8','9', '\3','4','9','0', '\3','4','9','1', '\3','4','9','2', '\3','4','9','3', '\3','4','9','4', '\3','4','9','5', '\3','4','9','6', '\3','4','9','7', '\3','4','9','8', '\3','4','9','9', '\3','5','0','0', '\3','5','0','1', '\3','5','0','2', '\3','5','0','3', '\3','5','0','4', '\3','5','0','5', '\3','5','0','6', '\3','5','0','7', '\3','5','0','8', '\3','5','0','9', '\3','5','1','0', '\3','5','1','1', '\3','5','1','2', '\3','5','1','3', '\3','5','1','4', '\3','5','1','5', '\3','5','1','6', '\3','5','1','7', '\3','5','1','8', '\3','5','1','9', '\3','5','2','0', '\3','5','2','1', '\3','5','2','2', '\3','5','2','3', '\3','5','2','4', '\3','5','2','5', '\3','5','2','6', '\3','5','2','7', '\3','5','2','8', '\3','5','2','9', '\3','5','3','0', '\3','5','3','1', '\3','5','3','2', '\3','5','3','3', '\3','5','3','4', '\3','5','3','5', '\3','5','3','6', '\3','5','3','7', '\3','5','3','8', '\3','5','3','9', '\3','5','4','0', '\3','5','4','1', '\3','5','4','2', '\3','5','4','3', '\3','5','4','4', '\3','5','4','5', '\3','5','4','6', '\3','5','4','7', '\3','5','4','8', '\3','5','4','9', '\3','5','5','0', '\3','5','5','1', '\3','5','5','2', '\3','5','5','3', '\3','5','5','4', '\3','5','5','5', '\3','5','5','6', '\3','5','5','7', '\3','5','5','8', '\3','5','5','9', '\3','5','6','0', '\3','5','6','1', '\3','5','6','2', '\3','5','6','3', '\3','5','6','4', '\3','5','6','5', '\3','5','6','6', '\3','5','6','7', '\3','5','6','8', '\3','5','6','9', '\3','5','7','0', '\3','5','7','1', '\3','5','7','2', '\3','5','7','3', '\3','5','7','4', '\3','5','7','5', '\3','5','7','6', '\3','5','7','7', '\3','5','7','8', '\3','5','7','9', '\3','5','8','0', '\3','5','8','1', '\3','5','8','2', '\3','5','8','3', '\3','5','8','4', '\3','5','8','5', '\3','5','8','6', '\3','5','8','7', '\3','5','8','8', '\3','5','8','9', '\3','5','9','0', '\3','5','9','1', '\3','5','9','2', '\3','5','9','3', '\3','5','9','4', '\3','5','9','5', '\3','5','9','6', '\3','5','9','7', '\3','5','9','8', '\3','5','9','9', '\3','6','0','0', '\3','6','0','1', '\3','6','0','2', '\3','6','0','3', '\3','6','0','4', '\3','6','0','5', '\3','6','0','6', '\3','6','0','7', '\3','6','0','8', '\3','6','0','9', '\3','6','1','0', '\3','6','1','1', '\3','6','1','2', '\3','6','1','3', '\3','6','1','4', '\3','6','1','5', '\3','6','1','6', '\3','6','1','7', '\3','6','1','8', '\3','6','1','9', '\3','6','2','0', '\3','6','2','1', '\3','6','2','2', '\3','6','2','3', '\3','6','2','4', '\3','6','2','5', '\3','6','2','6', '\3','6','2','7', '\3','6','2','8', '\3','6','2','9', '\3','6','3','0', '\3','6','3','1', '\3','6','3','2', '\3','6','3','3', '\3','6','3','4', '\3','6','3','5', '\3','6','3','6', '\3','6','3','7', '\3','6','3','8', '\3','6','3','9', '\3','6','4','0', '\3','6','4','1', '\3','6','4','2', '\3','6','4','3', '\3','6','4','4', '\3','6','4','5', '\3','6','4','6', '\3','6','4','7', '\3','6','4','8', '\3','6','4','9', '\3','6','5','0', '\3','6','5','1', '\3','6','5','2', '\3','6','5','3', '\3','6','5','4', '\3','6','5','5', '\3','6','5','6', '\3','6','5','7', '\3','6','5','8', '\3','6','5','9', '\3','6','6','0', '\3','6','6','1', '\3','6','6','2', '\3','6','6','3', '\3','6','6','4', '\3','6','6','5', '\3','6','6','6', '\3','6','6','7', '\3','6','6','8', '\3','6','6','9', '\3','6','7','0', '\3','6','7','1', '\3','6','7','2', '\3','6','7','3', '\3','6','7','4', '\3','6','7','5', '\3','6','7','6', '\3','6','7','7', '\3','6','7','8', '\3','6','7','9', '\3','6','8','0', '\3','6','8','1', '\3','6','8','2', '\3','6','8','3', '\3','6','8','4', '\3','6','8','5', '\3','6','8','6', '\3','6','8','7', '\3','6','8','8', '\3','6','8','9', '\3','6','9','0', '\3','6','9','1', '\3','6','9','2', '\3','6','9','3', '\3','6','9','4', '\3','6','9','5', '\3','6','9','6', '\3','6','9','7', '\3','6','9','8', '\3','6','9','9', '\3','7','0','0', '\3','7','0','1', '\3','7','0','2', '\3','7','0','3', '\3','7','0','4', '\3','7','0','5', '\3','7','0','6', '\3','7','0','7', '\3','7','0','8', '\3','7','0','9', '\3','7','1','0', '\3','7','1','1', '\3','7','1','2', '\3','7','1','3', '\3','7','1','4', '\3','7','1','5', '\3','7','1','6', '\3','7','1','7', '\3','7','1','8', '\3','7','1','9', '\3','7','2','0', '\3','7','2','1', '\3','7','2','2', '\3','7','2','3', '\3','7','2','4', '\3','7','2','5', '\3','7','2','6', '\3','7','2','7', '\3','7','2','8', '\3','7','2','9', '\3','7','3','0', '\3','7','3','1', '\3','7','3','2', '\3','7','3','3', '\3','7','3','4', '\3','7','3','5', '\3','7','3','6', '\3','7','3','7', '\3','7','3','8', '\3','7','3','9', '\3','7','4','0', '\3','7','4','1', '\3','7','4','2', '\3','7','4','3', '\3','7','4','4', '\3','7','4','5', '\3','7','4','6', '\3','7','4','7', '\3','7','4','8', '\3','7','4','9', '\3','7','5','0', '\3','7','5','1', '\3','7','5','2', '\3','7','5','3', '\3','7','5','4', '\3','7','5','5', '\3','7','5','6', '\3','7','5','7', '\3','7','5','8', '\3','7','5','9', '\3','7','6','0', '\3','7','6','1', '\3','7','6','2', '\3','7','6','3', '\3','7','6','4', '\3','7','6','5', '\3','7','6','6', '\3','7','6','7', '\3','7','6','8', '\3','7','6','9', '\3','7','7','0', '\3','7','7','1', '\3','7','7','2', '\3','7','7','3', '\3','7','7','4', '\3','7','7','5', '\3','7','7','6', '\3','7','7','7', '\3','7','7','8', '\3','7','7','9', '\3','7','8','0', '\3','7','8','1', '\3','7','8','2', '\3','7','8','3', '\3','7','8','4', '\3','7','8','5', '\3','7','8','6', '\3','7','8','7', '\3','7','8','8', '\3','7','8','9', '\3','7','9','0', '\3','7','9','1', '\3','7','9','2', '\3','7','9','3', '\3','7','9','4', '\3','7','9','5', '\3','7','9','6', '\3','7','9','7', '\3','7','9','8', '\3','7','9','9', '\3','8','0','0', '\3','8','0','1', '\3','8','0','2', '\3','8','0','3', '\3','8','0','4', '\3','8','0','5', '\3','8','0','6', '\3','8','0','7', '\3','8','0','8', '\3','8','0','9', '\3','8','1','0', '\3','8','1','1', '\3','8','1','2', '\3','8','1','3', '\3','8','1','4', '\3','8','1','5', '\3','8','1','6', '\3','8','1','7', '\3','8','1','8', '\3','8','1','9', '\3','8','2','0', '\3','8','2','1', '\3','8','2','2', '\3','8','2','3', '\3','8','2','4', '\3','8','2','5', '\3','8','2','6', '\3','8','2','7', '\3','8','2','8', '\3','8','2','9', '\3','8','3','0', '\3','8','3','1', '\3','8','3','2', '\3','8','3','3', '\3','8','3','4', '\3','8','3','5', '\3','8','3','6', '\3','8','3','7', '\3','8','3','8', '\3','8','3','9', '\3','8','4','0', '\3','8','4','1', '\3','8','4','2', '\3','8','4','3', '\3','8','4','4', '\3','8','4','5', '\3','8','4','6', '\3','8','4','7', '\3','8','4','8', '\3','8','4','9', '\3','8','5','0', '\3','8','5','1', '\3','8','5','2', '\3','8','5','3', '\3','8','5','4', '\3','8','5','5', '\3','8','5','6', '\3','8','5','7', '\3','8','5','8', '\3','8','5','9', '\3','8','6','0', '\3','8','6','1', '\3','8','6','2', '\3','8','6','3', '\3','8','6','4', '\3','8','6','5', '\3','8','6','6', '\3','8','6','7', '\3','8','6','8', '\3','8','6','9', '\3','8','7','0', '\3','8','7','1', '\3','8','7','2', '\3','8','7','3', '\3','8','7','4', '\3','8','7','5', '\3','8','7','6', '\3','8','7','7', '\3','8','7','8', '\3','8','7','9', '\3','8','8','0', '\3','8','8','1', '\3','8','8','2', '\3','8','8','3', '\3','8','8','4', '\3','8','8','5', '\3','8','8','6', '\3','8','8','7', '\3','8','8','8', '\3','8','8','9', '\3','8','9','0', '\3','8','9','1', '\3','8','9','2', '\3','8','9','3', '\3','8','9','4', '\3','8','9','5', '\3','8','9','6', '\3','8','9','7', '\3','8','9','8', '\3','8','9','9', '\3','9','0','0', '\3','9','0','1', '\3','9','0','2', '\3','9','0','3', '\3','9','0','4', '\3','9','0','5', '\3','9','0','6', '\3','9','0','7', '\3','9','0','8', '\3','9','0','9', '\3','9','1','0', '\3','9','1','1', '\3','9','1','2', '\3','9','1','3', '\3','9','1','4', '\3','9','1','5', '\3','9','1','6', '\3','9','1','7', '\3','9','1','8', '\3','9','1','9', '\3','9','2','0', '\3','9','2','1', '\3','9','2','2', '\3','9','2','3', '\3','9','2','4', '\3','9','2','5', '\3','9','2','6', '\3','9','2','7', '\3','9','2','8', '\3','9','2','9', '\3','9','3','0', '\3','9','3','1', '\3','9','3','2', '\3','9','3','3', '\3','9','3','4', '\3','9','3','5', '\3','9','3','6', '\3','9','3','7', '\3','9','3','8', '\3','9','3','9', '\3','9','4','0', '\3','9','4','1', '\3','9','4','2', '\3','9','4','3', '\3','9','4','4', '\3','9','4','5', '\3','9','4','6', '\3','9','4','7', '\3','9','4','8', '\3','9','4','9', '\3','9','5','0', '\3','9','5','1', '\3','9','5','2', '\3','9','5','3', '\3','9','5','4', '\3','9','5','5', '\3','9','5','6', '\3','9','5','7', '\3','9','5','8', '\3','9','5','9', '\3','9','6','0', '\3','9','6','1', '\3','9','6','2', '\3','9','6','3', '\3','9','6','4', '\3','9','6','5', '\3','9','6','6', '\3','9','6','7', '\3','9','6','8', '\3','9','6','9', '\3','9','7','0', '\3','9','7','1', '\3','9','7','2', '\3','9','7','3', '\3','9','7','4', '\3','9','7','5', '\3','9','7','6', '\3','9','7','7', '\3','9','7','8', '\3','9','7','9', '\3','9','8','0', '\3','9','8','1', '\3','9','8','2', '\3','9','8','3', '\3','9','8','4', '\3','9','8','5', '\3','9','8','6', '\3','9','8','7', '\3','9','8','8', '\3','9','8','9', '\3','9','9','0', '\3','9','9','1', '\3','9','9','2', '\3','9','9','3', '\3','9','9','4', '\3','9','9','5', '\3','9','9','6', '\3','9','9','7', '\3','9','9','8', '\3','9','9','9', '\0'}; #endif #if DEC_DPD2BCD8==1 && !defined(DECDPD2BCD8) #define DECDPD2BCD8 const uint8_t DPD2BCD8[4096]={ 0,0,0,0, 0,0,1,1, 0,0,2,1, 0,0,3,1, 0,0,4,1, 0,0,5,1, 0,0,6,1, 0,0,7,1, 0,0,8,1, 0,0,9,1, 0,8,0,2, 0,8,1,2, 8,0,0,3, 8,0,1,3, 8,8,0,3, 8,8,1,3, 0,1,0,2, 0,1,1,2, 0,1,2,2, 0,1,3,2, 0,1,4,2, 0,1,5,2, 0,1,6,2, 0,1,7,2, 0,1,8,2, 0,1,9,2, 0,9,0,2, 0,9,1,2, 8,1,0,3, 8,1,1,3, 8,9,0,3, 8,9,1,3, 0,2,0,2, 0,2,1,2, 0,2,2,2, 0,2,3,2, 0,2,4,2, 0,2,5,2, 0,2,6,2, 0,2,7,2, 0,2,8,2, 0,2,9,2, 0,8,2,2, 0,8,3,2, 8,2,0,3, 8,2,1,3, 8,0,8,3, 8,0,9,3, 0,3,0,2, 0,3,1,2, 0,3,2,2, 0,3,3,2, 0,3,4,2, 0,3,5,2, 0,3,6,2, 0,3,7,2, 0,3,8,2, 0,3,9,2, 0,9,2,2, 0,9,3,2, 8,3,0,3, 8,3,1,3, 8,1,8,3, 8,1,9,3, 0,4,0,2, 0,4,1,2, 0,4,2,2, 0,4,3,2, 0,4,4,2, 0,4,5,2, 0,4,6,2, 0,4,7,2, 0,4,8,2, 0,4,9,2, 0,8,4,2, 0,8,5,2, 8,4,0,3, 8,4,1,3, 0,8,8,2, 0,8,9,2, 0,5,0,2, 0,5,1,2, 0,5,2,2, 0,5,3,2, 0,5,4,2, 0,5,5,2, 0,5,6,2, 0,5,7,2, 0,5,8,2, 0,5,9,2, 0,9,4,2, 0,9,5,2, 8,5,0,3, 8,5,1,3, 0,9,8,2, 0,9,9,2, 0,6,0,2, 0,6,1,2, 0,6,2,2, 0,6,3,2, 0,6,4,2, 0,6,5,2, 0,6,6,2, 0,6,7,2, 0,6,8,2, 0,6,9,2, 0,8,6,2, 0,8,7,2, 8,6,0,3, 8,6,1,3, 8,8,8,3, 8,8,9,3, 0,7,0,2, 0,7,1,2, 0,7,2,2, 0,7,3,2, 0,7,4,2, 0,7,5,2, 0,7,6,2, 0,7,7,2, 0,7,8,2, 0,7,9,2, 0,9,6,2, 0,9,7,2, 8,7,0,3, 8,7,1,3, 8,9,8,3, 8,9,9,3, 1,0,0,3, 1,0,1,3, 1,0,2,3, 1,0,3,3, 1,0,4,3, 1,0,5,3, 1,0,6,3, 1,0,7,3, 1,0,8,3, 1,0,9,3, 1,8,0,3, 1,8,1,3, 9,0,0,3, 9,0,1,3, 9,8,0,3, 9,8,1,3, 1,1,0,3, 1,1,1,3, 1,1,2,3, 1,1,3,3, 1,1,4,3, 1,1,5,3, 1,1,6,3, 1,1,7,3, 1,1,8,3, 1,1,9,3, 1,9,0,3, 1,9,1,3, 9,1,0,3, 9,1,1,3, 9,9,0,3, 9,9,1,3, 1,2,0,3, 1,2,1,3, 1,2,2,3, 1,2,3,3, 1,2,4,3, 1,2,5,3, 1,2,6,3, 1,2,7,3, 1,2,8,3, 1,2,9,3, 1,8,2,3, 1,8,3,3, 9,2,0,3, 9,2,1,3, 9,0,8,3, 9,0,9,3, 1,3,0,3, 1,3,1,3, 1,3,2,3, 1,3,3,3, 1,3,4,3, 1,3,5,3, 1,3,6,3, 1,3,7,3, 1,3,8,3, 1,3,9,3, 1,9,2,3, 1,9,3,3, 9,3,0,3, 9,3,1,3, 9,1,8,3, 9,1,9,3, 1,4,0,3, 1,4,1,3, 1,4,2,3, 1,4,3,3, 1,4,4,3, 1,4,5,3, 1,4,6,3, 1,4,7,3, 1,4,8,3, 1,4,9,3, 1,8,4,3, 1,8,5,3, 9,4,0,3, 9,4,1,3, 1,8,8,3, 1,8,9,3, 1,5,0,3, 1,5,1,3, 1,5,2,3, 1,5,3,3, 1,5,4,3, 1,5,5,3, 1,5,6,3, 1,5,7,3, 1,5,8,3, 1,5,9,3, 1,9,4,3, 1,9,5,3, 9,5,0,3, 9,5,1,3, 1,9,8,3, 1,9,9,3, 1,6,0,3, 1,6,1,3, 1,6,2,3, 1,6,3,3, 1,6,4,3, 1,6,5,3, 1,6,6,3, 1,6,7,3, 1,6,8,3, 1,6,9,3, 1,8,6,3, 1,8,7,3, 9,6,0,3, 9,6,1,3, 9,8,8,3, 9,8,9,3, 1,7,0,3, 1,7,1,3, 1,7,2,3, 1,7,3,3, 1,7,4,3, 1,7,5,3, 1,7,6,3, 1,7,7,3, 1,7,8,3, 1,7,9,3, 1,9,6,3, 1,9,7,3, 9,7,0,3, 9,7,1,3, 9,9,8,3, 9,9,9,3, 2,0,0,3, 2,0,1,3, 2,0,2,3, 2,0,3,3, 2,0,4,3, 2,0,5,3, 2,0,6,3, 2,0,7,3, 2,0,8,3, 2,0,9,3, 2,8,0,3, 2,8,1,3, 8,0,2,3, 8,0,3,3, 8,8,2,3, 8,8,3,3, 2,1,0,3, 2,1,1,3, 2,1,2,3, 2,1,3,3, 2,1,4,3, 2,1,5,3, 2,1,6,3, 2,1,7,3, 2,1,8,3, 2,1,9,3, 2,9,0,3, 2,9,1,3, 8,1,2,3, 8,1,3,3, 8,9,2,3, 8,9,3,3, 2,2,0,3, 2,2,1,3, 2,2,2,3, 2,2,3,3, 2,2,4,3, 2,2,5,3, 2,2,6,3, 2,2,7,3, 2,2,8,3, 2,2,9,3, 2,8,2,3, 2,8,3,3, 8,2,2,3, 8,2,3,3, 8,2,8,3, 8,2,9,3, 2,3,0,3, 2,3,1,3, 2,3,2,3, 2,3,3,3, 2,3,4,3, 2,3,5,3, 2,3,6,3, 2,3,7,3, 2,3,8,3, 2,3,9,3, 2,9,2,3, 2,9,3,3, 8,3,2,3, 8,3,3,3, 8,3,8,3, 8,3,9,3, 2,4,0,3, 2,4,1,3, 2,4,2,3, 2,4,3,3, 2,4,4,3, 2,4,5,3, 2,4,6,3, 2,4,7,3, 2,4,8,3, 2,4,9,3, 2,8,4,3, 2,8,5,3, 8,4,2,3, 8,4,3,3, 2,8,8,3, 2,8,9,3, 2,5,0,3, 2,5,1,3, 2,5,2,3, 2,5,3,3, 2,5,4,3, 2,5,5,3, 2,5,6,3, 2,5,7,3, 2,5,8,3, 2,5,9,3, 2,9,4,3, 2,9,5,3, 8,5,2,3, 8,5,3,3, 2,9,8,3, 2,9,9,3, 2,6,0,3, 2,6,1,3, 2,6,2,3, 2,6,3,3, 2,6,4,3, 2,6,5,3, 2,6,6,3, 2,6,7,3, 2,6,8,3, 2,6,9,3, 2,8,6,3, 2,8,7,3, 8,6,2,3, 8,6,3,3, 8,8,8,3, 8,8,9,3, 2,7,0,3, 2,7,1,3, 2,7,2,3, 2,7,3,3, 2,7,4,3, 2,7,5,3, 2,7,6,3, 2,7,7,3, 2,7,8,3, 2,7,9,3, 2,9,6,3, 2,9,7,3, 8,7,2,3, 8,7,3,3, 8,9,8,3, 8,9,9,3, 3,0,0,3, 3,0,1,3, 3,0,2,3, 3,0,3,3, 3,0,4,3, 3,0,5,3, 3,0,6,3, 3,0,7,3, 3,0,8,3, 3,0,9,3, 3,8,0,3, 3,8,1,3, 9,0,2,3, 9,0,3,3, 9,8,2,3, 9,8,3,3, 3,1,0,3, 3,1,1,3, 3,1,2,3, 3,1,3,3, 3,1,4,3, 3,1,5,3, 3,1,6,3, 3,1,7,3, 3,1,8,3, 3,1,9,3, 3,9,0,3, 3,9,1,3, 9,1,2,3, 9,1,3,3, 9,9,2,3, 9,9,3,3, 3,2,0,3, 3,2,1,3, 3,2,2,3, 3,2,3,3, 3,2,4,3, 3,2,5,3, 3,2,6,3, 3,2,7,3, 3,2,8,3, 3,2,9,3, 3,8,2,3, 3,8,3,3, 9,2,2,3, 9,2,3,3, 9,2,8,3, 9,2,9,3, 3,3,0,3, 3,3,1,3, 3,3,2,3, 3,3,3,3, 3,3,4,3, 3,3,5,3, 3,3,6,3, 3,3,7,3, 3,3,8,3, 3,3,9,3, 3,9,2,3, 3,9,3,3, 9,3,2,3, 9,3,3,3, 9,3,8,3, 9,3,9,3, 3,4,0,3, 3,4,1,3, 3,4,2,3, 3,4,3,3, 3,4,4,3, 3,4,5,3, 3,4,6,3, 3,4,7,3, 3,4,8,3, 3,4,9,3, 3,8,4,3, 3,8,5,3, 9,4,2,3, 9,4,3,3, 3,8,8,3, 3,8,9,3, 3,5,0,3, 3,5,1,3, 3,5,2,3, 3,5,3,3, 3,5,4,3, 3,5,5,3, 3,5,6,3, 3,5,7,3, 3,5,8,3, 3,5,9,3, 3,9,4,3, 3,9,5,3, 9,5,2,3, 9,5,3,3, 3,9,8,3, 3,9,9,3, 3,6,0,3, 3,6,1,3, 3,6,2,3, 3,6,3,3, 3,6,4,3, 3,6,5,3, 3,6,6,3, 3,6,7,3, 3,6,8,3, 3,6,9,3, 3,8,6,3, 3,8,7,3, 9,6,2,3, 9,6,3,3, 9,8,8,3, 9,8,9,3, 3,7,0,3, 3,7,1,3, 3,7,2,3, 3,7,3,3, 3,7,4,3, 3,7,5,3, 3,7,6,3, 3,7,7,3, 3,7,8,3, 3,7,9,3, 3,9,6,3, 3,9,7,3, 9,7,2,3, 9,7,3,3, 9,9,8,3, 9,9,9,3, 4,0,0,3, 4,0,1,3, 4,0,2,3, 4,0,3,3, 4,0,4,3, 4,0,5,3, 4,0,6,3, 4,0,7,3, 4,0,8,3, 4,0,9,3, 4,8,0,3, 4,8,1,3, 8,0,4,3, 8,0,5,3, 8,8,4,3, 8,8,5,3, 4,1,0,3, 4,1,1,3, 4,1,2,3, 4,1,3,3, 4,1,4,3, 4,1,5,3, 4,1,6,3, 4,1,7,3, 4,1,8,3, 4,1,9,3, 4,9,0,3, 4,9,1,3, 8,1,4,3, 8,1,5,3, 8,9,4,3, 8,9,5,3, 4,2,0,3, 4,2,1,3, 4,2,2,3, 4,2,3,3, 4,2,4,3, 4,2,5,3, 4,2,6,3, 4,2,7,3, 4,2,8,3, 4,2,9,3, 4,8,2,3, 4,8,3,3, 8,2,4,3, 8,2,5,3, 8,4,8,3, 8,4,9,3, 4,3,0,3, 4,3,1,3, 4,3,2,3, 4,3,3,3, 4,3,4,3, 4,3,5,3, 4,3,6,3, 4,3,7,3, 4,3,8,3, 4,3,9,3, 4,9,2,3, 4,9,3,3, 8,3,4,3, 8,3,5,3, 8,5,8,3, 8,5,9,3, 4,4,0,3, 4,4,1,3, 4,4,2,3, 4,4,3,3, 4,4,4,3, 4,4,5,3, 4,4,6,3, 4,4,7,3, 4,4,8,3, 4,4,9,3, 4,8,4,3, 4,8,5,3, 8,4,4,3, 8,4,5,3, 4,8,8,3, 4,8,9,3, 4,5,0,3, 4,5,1,3, 4,5,2,3, 4,5,3,3, 4,5,4,3, 4,5,5,3, 4,5,6,3, 4,5,7,3, 4,5,8,3, 4,5,9,3, 4,9,4,3, 4,9,5,3, 8,5,4,3, 8,5,5,3, 4,9,8,3, 4,9,9,3, 4,6,0,3, 4,6,1,3, 4,6,2,3, 4,6,3,3, 4,6,4,3, 4,6,5,3, 4,6,6,3, 4,6,7,3, 4,6,8,3, 4,6,9,3, 4,8,6,3, 4,8,7,3, 8,6,4,3, 8,6,5,3, 8,8,8,3, 8,8,9,3, 4,7,0,3, 4,7,1,3, 4,7,2,3, 4,7,3,3, 4,7,4,3, 4,7,5,3, 4,7,6,3, 4,7,7,3, 4,7,8,3, 4,7,9,3, 4,9,6,3, 4,9,7,3, 8,7,4,3, 8,7,5,3, 8,9,8,3, 8,9,9,3, 5,0,0,3, 5,0,1,3, 5,0,2,3, 5,0,3,3, 5,0,4,3, 5,0,5,3, 5,0,6,3, 5,0,7,3, 5,0,8,3, 5,0,9,3, 5,8,0,3, 5,8,1,3, 9,0,4,3, 9,0,5,3, 9,8,4,3, 9,8,5,3, 5,1,0,3, 5,1,1,3, 5,1,2,3, 5,1,3,3, 5,1,4,3, 5,1,5,3, 5,1,6,3, 5,1,7,3, 5,1,8,3, 5,1,9,3, 5,9,0,3, 5,9,1,3, 9,1,4,3, 9,1,5,3, 9,9,4,3, 9,9,5,3, 5,2,0,3, 5,2,1,3, 5,2,2,3, 5,2,3,3, 5,2,4,3, 5,2,5,3, 5,2,6,3, 5,2,7,3, 5,2,8,3, 5,2,9,3, 5,8,2,3, 5,8,3,3, 9,2,4,3, 9,2,5,3, 9,4,8,3, 9,4,9,3, 5,3,0,3, 5,3,1,3, 5,3,2,3, 5,3,3,3, 5,3,4,3, 5,3,5,3, 5,3,6,3, 5,3,7,3, 5,3,8,3, 5,3,9,3, 5,9,2,3, 5,9,3,3, 9,3,4,3, 9,3,5,3, 9,5,8,3, 9,5,9,3, 5,4,0,3, 5,4,1,3, 5,4,2,3, 5,4,3,3, 5,4,4,3, 5,4,5,3, 5,4,6,3, 5,4,7,3, 5,4,8,3, 5,4,9,3, 5,8,4,3, 5,8,5,3, 9,4,4,3, 9,4,5,3, 5,8,8,3, 5,8,9,3, 5,5,0,3, 5,5,1,3, 5,5,2,3, 5,5,3,3, 5,5,4,3, 5,5,5,3, 5,5,6,3, 5,5,7,3, 5,5,8,3, 5,5,9,3, 5,9,4,3, 5,9,5,3, 9,5,4,3, 9,5,5,3, 5,9,8,3, 5,9,9,3, 5,6,0,3, 5,6,1,3, 5,6,2,3, 5,6,3,3, 5,6,4,3, 5,6,5,3, 5,6,6,3, 5,6,7,3, 5,6,8,3, 5,6,9,3, 5,8,6,3, 5,8,7,3, 9,6,4,3, 9,6,5,3, 9,8,8,3, 9,8,9,3, 5,7,0,3, 5,7,1,3, 5,7,2,3, 5,7,3,3, 5,7,4,3, 5,7,5,3, 5,7,6,3, 5,7,7,3, 5,7,8,3, 5,7,9,3, 5,9,6,3, 5,9,7,3, 9,7,4,3, 9,7,5,3, 9,9,8,3, 9,9,9,3, 6,0,0,3, 6,0,1,3, 6,0,2,3, 6,0,3,3, 6,0,4,3, 6,0,5,3, 6,0,6,3, 6,0,7,3, 6,0,8,3, 6,0,9,3, 6,8,0,3, 6,8,1,3, 8,0,6,3, 8,0,7,3, 8,8,6,3, 8,8,7,3, 6,1,0,3, 6,1,1,3, 6,1,2,3, 6,1,3,3, 6,1,4,3, 6,1,5,3, 6,1,6,3, 6,1,7,3, 6,1,8,3, 6,1,9,3, 6,9,0,3, 6,9,1,3, 8,1,6,3, 8,1,7,3, 8,9,6,3, 8,9,7,3, 6,2,0,3, 6,2,1,3, 6,2,2,3, 6,2,3,3, 6,2,4,3, 6,2,5,3, 6,2,6,3, 6,2,7,3, 6,2,8,3, 6,2,9,3, 6,8,2,3, 6,8,3,3, 8,2,6,3, 8,2,7,3, 8,6,8,3, 8,6,9,3, 6,3,0,3, 6,3,1,3, 6,3,2,3, 6,3,3,3, 6,3,4,3, 6,3,5,3, 6,3,6,3, 6,3,7,3, 6,3,8,3, 6,3,9,3, 6,9,2,3, 6,9,3,3, 8,3,6,3, 8,3,7,3, 8,7,8,3, 8,7,9,3, 6,4,0,3, 6,4,1,3, 6,4,2,3, 6,4,3,3, 6,4,4,3, 6,4,5,3, 6,4,6,3, 6,4,7,3, 6,4,8,3, 6,4,9,3, 6,8,4,3, 6,8,5,3, 8,4,6,3, 8,4,7,3, 6,8,8,3, 6,8,9,3, 6,5,0,3, 6,5,1,3, 6,5,2,3, 6,5,3,3, 6,5,4,3, 6,5,5,3, 6,5,6,3, 6,5,7,3, 6,5,8,3, 6,5,9,3, 6,9,4,3, 6,9,5,3, 8,5,6,3, 8,5,7,3, 6,9,8,3, 6,9,9,3, 6,6,0,3, 6,6,1,3, 6,6,2,3, 6,6,3,3, 6,6,4,3, 6,6,5,3, 6,6,6,3, 6,6,7,3, 6,6,8,3, 6,6,9,3, 6,8,6,3, 6,8,7,3, 8,6,6,3, 8,6,7,3, 8,8,8,3, 8,8,9,3, 6,7,0,3, 6,7,1,3, 6,7,2,3, 6,7,3,3, 6,7,4,3, 6,7,5,3, 6,7,6,3, 6,7,7,3, 6,7,8,3, 6,7,9,3, 6,9,6,3, 6,9,7,3, 8,7,6,3, 8,7,7,3, 8,9,8,3, 8,9,9,3, 7,0,0,3, 7,0,1,3, 7,0,2,3, 7,0,3,3, 7,0,4,3, 7,0,5,3, 7,0,6,3, 7,0,7,3, 7,0,8,3, 7,0,9,3, 7,8,0,3, 7,8,1,3, 9,0,6,3, 9,0,7,3, 9,8,6,3, 9,8,7,3, 7,1,0,3, 7,1,1,3, 7,1,2,3, 7,1,3,3, 7,1,4,3, 7,1,5,3, 7,1,6,3, 7,1,7,3, 7,1,8,3, 7,1,9,3, 7,9,0,3, 7,9,1,3, 9,1,6,3, 9,1,7,3, 9,9,6,3, 9,9,7,3, 7,2,0,3, 7,2,1,3, 7,2,2,3, 7,2,3,3, 7,2,4,3, 7,2,5,3, 7,2,6,3, 7,2,7,3, 7,2,8,3, 7,2,9,3, 7,8,2,3, 7,8,3,3, 9,2,6,3, 9,2,7,3, 9,6,8,3, 9,6,9,3, 7,3,0,3, 7,3,1,3, 7,3,2,3, 7,3,3,3, 7,3,4,3, 7,3,5,3, 7,3,6,3, 7,3,7,3, 7,3,8,3, 7,3,9,3, 7,9,2,3, 7,9,3,3, 9,3,6,3, 9,3,7,3, 9,7,8,3, 9,7,9,3, 7,4,0,3, 7,4,1,3, 7,4,2,3, 7,4,3,3, 7,4,4,3, 7,4,5,3, 7,4,6,3, 7,4,7,3, 7,4,8,3, 7,4,9,3, 7,8,4,3, 7,8,5,3, 9,4,6,3, 9,4,7,3, 7,8,8,3, 7,8,9,3, 7,5,0,3, 7,5,1,3, 7,5,2,3, 7,5,3,3, 7,5,4,3, 7,5,5,3, 7,5,6,3, 7,5,7,3, 7,5,8,3, 7,5,9,3, 7,9,4,3, 7,9,5,3, 9,5,6,3, 9,5,7,3, 7,9,8,3, 7,9,9,3, 7,6,0,3, 7,6,1,3, 7,6,2,3, 7,6,3,3, 7,6,4,3, 7,6,5,3, 7,6,6,3, 7,6,7,3, 7,6,8,3, 7,6,9,3, 7,8,6,3, 7,8,7,3, 9,6,6,3, 9,6,7,3, 9,8,8,3, 9,8,9,3, 7,7,0,3, 7,7,1,3, 7,7,2,3, 7,7,3,3, 7,7,4,3, 7,7,5,3, 7,7,6,3, 7,7,7,3, 7,7,8,3, 7,7,9,3, 7,9,6,3, 7,9,7,3, 9,7,6,3, 9,7,7,3, 9,9,8,3, 9,9,9,3}; #endif hercules-3.12/decNumber/decimal128.h0000664000175000017500000001161312564723224014113 00000000000000/* ------------------------------------------------------------------ */ /* Decimal 128-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECIMAL128) #define DECIMAL128 #define DEC128NAME "decimal128" /* Short name */ #define DEC128FULLNAME "Decimal 128-bit Number" /* Verbose name */ #define DEC128AUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decimal128s */ #define DECIMAL128_Bytes 16 // length #define DECIMAL128_Pmax 34 // maximum precision (digits) #define DECIMAL128_Emax 6144 // maximum adjusted exponent #define DECIMAL128_Emin -6143 // minimum adjusted exponent #define DECIMAL128_Bias 6176 // bias for the exponent #define DECIMAL128_String 43 // maximum string length, +1 #define DECIMAL128_EconL 12 // exponent continuation length // highest biased exponent (Elimit-1) #define DECIMAL128_Ehigh (DECIMAL128_Emax+DECIMAL128_Bias-DECIMAL128_Pmax+1) // check enough digits, if pre-defined #if defined(DECNUMDIGITS) #if (DECNUMDIGITS=34 for safe use #endif #endif #ifndef DECNUMDIGITS #define DECNUMDIGITS DECIMAL128_Pmax // size if not already defined #endif #ifndef DECNUMBER #include "decNumber.h" // context and number library #endif /* Decimal 128-bit type, accessible by bytes */ typedef struct { uint8_t bytes[DECIMAL128_Bytes]; // decimal128: 1, 5, 12, 110 bits } decimal128; /* special values [top byte excluding sign bit; last two bits are don't-care for Infinity on input, last bit don't-care for NaN] */ #if !defined(DECIMAL_NaN) #define DECIMAL_NaN 0x7c // 0 11111 00 NaN #define DECIMAL_sNaN 0x7e // 0 11111 10 sNaN #define DECIMAL_Inf 0x78 // 0 11110 00 Infinity #endif /* Macros for accessing decimal128 fields. These assume the argument is a reference (pointer) to the decimal128 structure, and the decimal128 is in network byte order (big-endian) */ // Get sign #define decimal128Sign(d) ((unsigned)(d)->bytes[0]>>7) // Get combination field #define decimal128Comb(d) (((d)->bytes[0] & 0x7c)>>2) // Get exponent continuation [does not remove bias] #define decimal128ExpCon(d) ((((d)->bytes[0] & 0x03)<<10) \ | ((unsigned)(d)->bytes[1]<<2) \ | ((unsigned)(d)->bytes[2]>>6)) // Set sign [this assumes sign previously 0] #define decimal128SetSign(d, b) { \ (d)->bytes[0]|=((unsigned)(b)<<7);} // Set exponent continuation [does not apply bias] // This assumes range has been checked and exponent previously 0; // type of exponent must be unsigned #define decimal128SetExpCon(d, e) { \ (d)->bytes[0]|=(uint8_t)((e)>>10); \ (d)->bytes[1] =(uint8_t)(((e)&0x3fc)>>2); \ (d)->bytes[2]|=(uint8_t)(((e)&0x03)<<6);} /* ------------------------------------------------------------------ */ /* Routines */ /* ------------------------------------------------------------------ */ // String conversions decimal128 * decimal128FromString(decimal128 *, const char *, decContext *); char * decimal128ToString(const decimal128 *, char *); char * decimal128ToEngString(const decimal128 *, char *); // decNumber conversions decimal128 * decimal128FromNumber(decimal128 *, const decNumber *, decContext *); decNumber * decimal128ToNumber(const decimal128 *, decNumber *); #endif hercules-3.12/decNumber/decimal32.h0000664000175000017500000001132712564723224014027 00000000000000/* ------------------------------------------------------------------ */ /* Decimal 32-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECIMAL32) #define DECIMAL32 #define DEC32NAME "decimal32" /* Short name */ #define DEC32FULLNAME "Decimal 32-bit Number" /* Verbose name */ #define DEC32AUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decimal32s */ #define DECIMAL32_Bytes 4 // length #define DECIMAL32_Pmax 7 // maximum precision (digits) #define DECIMAL32_Emax 96 // maximum adjusted exponent #define DECIMAL32_Emin -95 // minimum adjusted exponent #define DECIMAL32_Bias 101 // bias for the exponent #define DECIMAL32_String 15 // maximum string length, +1 #define DECIMAL32_EconL 6 // exponent continuation length // highest biased exponent (Elimit-1) #define DECIMAL32_Ehigh (DECIMAL32_Emax+DECIMAL32_Bias-DECIMAL32_Pmax+1) // check enough digits, if pre-defined #if defined(DECNUMDIGITS) #if (DECNUMDIGITS=7 for safe use #endif #endif #ifndef DECNUMDIGITS #define DECNUMDIGITS DECIMAL32_Pmax // size if not already defined #endif #ifndef DECNUMBER #include "decNumber.h" // context and number library #endif /* Decimal 32-bit type, accessible by bytes */ typedef struct { uint8_t bytes[DECIMAL32_Bytes]; // decimal32: 1, 5, 6, 20 bits } decimal32; /* special values [top byte excluding sign bit; last two bits are don't-care for Infinity on input, last bit don't-care for NaN] */ #if !defined(DECIMAL_NaN) #define DECIMAL_NaN 0x7c // 0 11111 00 NaN #define DECIMAL_sNaN 0x7e // 0 11111 10 sNaN #define DECIMAL_Inf 0x78 // 0 11110 00 Infinity #endif /* Macros for accessing decimal32 fields. These assume the argument is a reference (pointer) to the decimal32 structure, and the decimal32 is in network byte order (big-endian) */ // Get sign #define decimal32Sign(d) ((unsigned)(d)->bytes[0]>>7) // Get combination field #define decimal32Comb(d) (((d)->bytes[0] & 0x7c)>>2) // Get exponent continuation [does not remove bias] #define decimal32ExpCon(d) ((((d)->bytes[0] & 0x03)<<4) \ | ((unsigned)(d)->bytes[1]>>4)) // Set sign [this assumes sign previously 0] #define decimal32SetSign(d, b) { \ (d)->bytes[0]|=((unsigned)(b)<<7);} // Set exponent continuation [does not apply bias] // This assumes range has been checked and exponent previously 0; // type of exponent must be unsigned #define decimal32SetExpCon(d, e) { \ (d)->bytes[0]|=(uint8_t)((e)>>4); \ (d)->bytes[1]|=(uint8_t)(((e)&0x0F)<<4);} /* ------------------------------------------------------------------ */ /* Routines */ /* ------------------------------------------------------------------ */ // String conversions decimal32 * decimal32FromString(decimal32 *, const char *, decContext *); char * decimal32ToString(const decimal32 *, char *); char * decimal32ToEngString(const decimal32 *, char *); // decNumber conversions decimal32 * decimal32FromNumber(decimal32 *, const decNumber *, decContext *); decNumber * decimal32ToNumber(const decimal32 *, decNumber *); #endif hercules-3.12/decNumber/decimal64.h0000664000175000017500000001133212564723224014030 00000000000000/* ------------------------------------------------------------------ */ /* Decimal 64-bit format module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECIMAL64) #define DECIMAL64 #define DEC64NAME "decimal64" /* Short name */ #define DEC64FULLNAME "Decimal 64-bit Number" /* Verbose name */ #define DEC64AUTHOR "Mike Cowlishaw" /* Who to blame */ /* parameters for decimal64s */ #define DECIMAL64_Bytes 8 // length #define DECIMAL64_Pmax 16 // maximum precision (digits) #define DECIMAL64_Emax 384 // maximum adjusted exponent #define DECIMAL64_Emin -383 // minimum adjusted exponent #define DECIMAL64_Bias 398 // bias for the exponent #define DECIMAL64_String 24 // maximum string length, +1 #define DECIMAL64_EconL 8 // exponent continuation length // highest biased exponent (Elimit-1) #define DECIMAL64_Ehigh (DECIMAL64_Emax+DECIMAL64_Bias-DECIMAL64_Pmax+1) // check enough digits, if pre-defined #if defined(DECNUMDIGITS) #if (DECNUMDIGITS=16 for safe use #endif #endif #ifndef DECNUMDIGITS #define DECNUMDIGITS DECIMAL64_Pmax // size if not already defined #endif #ifndef DECNUMBER #include "decNumber.h" // context and number library #endif /* Decimal 64-bit type, accessible by bytes */ typedef struct { uint8_t bytes[DECIMAL64_Bytes]; // decimal64: 1, 5, 8, 50 bits } decimal64; /* special values [top byte excluding sign bit; last two bits are don't-care for Infinity on input, last bit don't-care for NaN] */ #if !defined(DECIMAL_NaN) #define DECIMAL_NaN 0x7c // 0 11111 00 NaN #define DECIMAL_sNaN 0x7e // 0 11111 10 sNaN #define DECIMAL_Inf 0x78 // 0 11110 00 Infinity #endif /* Macros for accessing decimal64 fields. These assume the argument is a reference (pointer) to the decimal64 structure, and the decimal64 is in network byte order (big-endian) */ // Get sign #define decimal64Sign(d) ((unsigned)(d)->bytes[0]>>7) // Get combination field #define decimal64Comb(d) (((d)->bytes[0] & 0x7c)>>2) // Get exponent continuation [does not remove bias] #define decimal64ExpCon(d) ((((d)->bytes[0] & 0x03)<<6) \ | ((unsigned)(d)->bytes[1]>>2)) // Set sign [this assumes sign previously 0] #define decimal64SetSign(d, b) { \ (d)->bytes[0]|=((unsigned)(b)<<7);} // Set exponent continuation [does not apply bias] // This assumes range has been checked and exponent previously 0; type // of exponent must be unsigned #define decimal64SetExpCon(d, e) { \ (d)->bytes[0]|=(uint8_t)((e)>>6); \ (d)->bytes[1]|=(uint8_t)(((e)&0x3F)<<2);} /* ------------------------------------------------------------------ */ /* Routines */ /* ------------------------------------------------------------------ */ // String conversions decimal64 * decimal64FromString(decimal64 *, const char *, decContext *); char * decimal64ToString(const decimal64 *, char *); char * decimal64ToEngString(const decimal64 *, char *); // decNumber conversions decimal64 * decimal64FromNumber(decimal64 *, const decNumber *, decContext *); decNumber * decimal64ToNumber(const decimal64 *, decNumber *); #endif hercules-3.12/decNumber/decNumber.h0000664000175000017500000001732212564723224014171 00000000000000/* ------------------------------------------------------------------ */ /* Decimal Number arithmetic module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECNUMBER) #define DECNUMBER #define DECNAME "decNumber" /* Short name */ #define DECVERSION "decNumber 3.37" /* Version [16 max.] */ #define DECFULLNAME "Decimal Number Module" /* Verbose name */ #define DECAUTHOR "Mike Cowlishaw" /* Who to blame */ #if !defined(DECCONTEXT) #include "decContext.h" #endif // Bit settings for decNumber.bits #define DECNEG 0x80 // Sign; 1=negative, 0=positive or zero #define DECINF 0x40 // 1=Infinity #define DECNAN 0x20 // 1=NaN #define DECSNAN 0x10 // 1=sNaN // The remaining bits are reserved; they must be 0 #define DECSPECIAL (DECINF|DECNAN|DECSNAN) // any special value // Define the decNumber data structure. The size and shape of the // units array in the structure is determined by the following // constant. This must not be changed without recompiling the // decNumber library modules. #define DECDPUN 3 // DECimal Digits Per UNit [must be in // range 1-9; 3 or powers of 2 are best]. // DECNUMDIGITS is the default number of digits that can be held in // the structure. If undefined, 1 is assumed and it is assumed that // the structure will be immediately followed by extra space, as // required. DECNUMDIGITS is always >0. #if !defined(DECNUMDIGITS) #define DECNUMDIGITS 1 #endif // The size (integer data type) of each unit is determined by the // number of digits it will hold. #if DECDPUN<=2 #define decNumberUnit uint8_t #elif DECDPUN<=4 #define decNumberUnit uint16_t #else #define decNumberUnit uint32_t #endif // The number of decNumberUnits needed is ceil(DECNUMDIGITS/DECDPUN) #define DECNUMUNITS ((DECNUMDIGITS+DECDPUN-1)/DECDPUN) // The data structure... typedef struct { int32_t digits; // Count of digits in the coefficient; >0 int32_t exponent; // Unadjusted exponent, unbiased, in // range: -1999999997 through 999999999 uint8_t bits; // Indicator bits (see above) decNumberUnit lsu[DECNUMUNITS];// Coefficient, from least significant unit } decNumber; // Notes: // 1. If digits is > DECDPUN then there will one or more // decNumberUnits immediately following the first element of lsu. // These contain the remaining (more significant) digits of the // number, and may be in the lsu array, or may be guaranteed by // some other mechanism (such as being contained in another // structure, or being overlaid on dynamically allocated storage). // // Each integer of the coefficient (except potentially the last) // contains DECDPUN digits (e.g., a value in the range 0 through // 99999999 if DECDPUN is 8, or 0 through 999 if DECDPUN is 3). // // 2. A decNumber converted to a string may need up to digits+14 // characters. The worst cases (non-exponential and exponential // formats) are: -0.00000{9...}# // and: -9.{9...}E+999999999# (where # is '\0') /* ------------------------------------------------------------------ */ /* decNumber public functions and macros */ /* ------------------------------------------------------------------ */ // Conversions decNumber * decNumberFromString(decNumber *, const char *, decContext *); char * decNumberToString(const decNumber *, char *); char * decNumberToEngString(const decNumber *, char *); // Operators and elementary functions decNumber * decNumberAbs(decNumber *, const decNumber *, decContext *); decNumber * decNumberAdd(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberCompareTotal(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberDivide(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberDivideInteger(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberExp(decNumber *, const decNumber *, decContext *); decNumber * decNumberLn(decNumber *, const decNumber *, decContext *); decNumber * decNumberLog10(decNumber *, const decNumber *, decContext *); decNumber * decNumberMax(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberMin(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberMinus(decNumber *, const decNumber *, decContext *); decNumber * decNumberMultiply(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberNormalize(decNumber *, const decNumber *, decContext *); decNumber * decNumberPlus(decNumber *, const decNumber *, decContext *); decNumber * decNumberPower(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberQuantize(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberRescale(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberSameQuantum(decNumber *, const decNumber *, const decNumber *); decNumber * decNumberSquareRoot(decNumber *, const decNumber *, decContext *); decNumber * decNumberSubtract(decNumber *, const decNumber *, const decNumber *, decContext *); decNumber * decNumberToIntegralValue(decNumber *, const decNumber *, decContext *); // Utilities decNumber * decNumberCopy(decNumber *, const decNumber *); decNumber * decNumberTrim(decNumber *); const char * decNumberVersion(void); decNumber * decNumberZero(decNumber *); // Macros for testing decNumbers #define decNumberIsZero(dn) (*(dn)->lsu==0 \ && (dn)->digits==1 \ && (((dn)->bits&DECSPECIAL)==0)) #define decNumberIsNegative(dn) (((dn)->bits&DECNEG)!=0) #define decNumberIsNaN(dn) (((dn)->bits&(DECNAN|DECSNAN))!=0) #define decNumberIsQNaN(dn) (((dn)->bits&(DECNAN))!=0) #define decNumberIsSNaN(dn) (((dn)->bits&(DECSNAN))!=0) #define decNumberIsInfinite(dn) (((dn)->bits&DECINF)!=0) #define decNumberIsSpecial(dn) (((dn)->bits&DECSPECIAL)!=0) #endif hercules-3.12/decNumber/decNumberLocal.h0000664000175000017500000002132212564723224015137 00000000000000/* ------------------------------------------------------------------ */ /* decNumber package local type, tuning, and macro definitions */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This header file is included by all modules in the decNumber */ /* library, and contains local type definitions, tuning parameters, */ /* etc. It must only be included once, and should not need to be */ /* used by application programs. decNumber.h must be included first. */ /* ------------------------------------------------------------------ */ #if !defined(DECNUMBERLOC) #define DECNUMBERLOC #define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */ /* Tuning parameter */ #define DECBUFFER 36 // Maximum size basis for local buffers. // Should be a common maximum precision // rounded up to a multiple of 4; must // be zero or positive. /* Conditional code flags -- set these to 1 for best performance */ #define DECENDIAN 1 // 1=concrete formats are endian #define DECUSE64 1 // 1 to allow use of 64-bit integers /* Conditional check flags -- set these to 0 for best performance */ #define DECCHECK 0 // 1 to enable robust checking #define DECALLOC 0 // 1 to enable memory allocation accounting #define DECTRACE 0 // 1 to trace critical intermediates, etc. /* Local names for common types -- for safety, decNumber modules do not use int or long directly */ #define Flag uint8_t #define Byte int8_t #define uByte uint8_t #define Short int16_t #define uShort uint16_t #define Int int32_t #define uInt uint32_t #define Unit decNumberUnit #if DECUSE64 #define Long int64_t #define uLong uint64_t #endif /* Development-use defines */ #if DECALLOC // if these interfere with your C includes, just comment them out #define int ? // enable to ensure that plain C 'int' or #define long ?? // .. 'long' types are not used #endif /* Limits and constants */ #define DECNUMMAXP 999999999 // maximum precision code can handle #define DECNUMMAXE 999999999 // maximum adjusted exponent ditto #define DECNUMMINE -999999999 // minimum adjusted exponent ditto #if (DECNUMMAXP != DEC_MAX_DIGITS) #error Maximum digits mismatch #endif #if (DECNUMMAXE != DEC_MAX_EMAX) #error Maximum exponent mismatch #endif #if (DECNUMMINE != DEC_MIN_EMIN) #error Minimum exponent mismatch #endif /* Set DECDPUNMAX -- the maximum integer that fits in DECDPUN */ /* digits, and D2UTABLE -- the initializer for the D2U table */ #if DECDPUN==1 #define DECDPUNMAX 9 #define D2UTABLE {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17, \ 18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, \ 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, \ 48,49} #elif DECDPUN==2 #define DECDPUNMAX 99 #define D2UTABLE {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10, \ 11,11,12,12,13,13,14,14,15,15,16,16,17,17,18, \ 18,19,19,20,20,21,21,22,22,23,23,24,24,25} #elif DECDPUN==3 #define DECDPUNMAX 999 #define D2UTABLE {0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7, \ 8,8,8,9,9,9,10,10,10,11,11,11,12,12,12,13,13, \ 13,14,14,14,15,15,15,16,16,16,17} #elif DECDPUN==4 #define DECDPUNMAX 9999 #define D2UTABLE {0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6, \ 6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11, \ 11,11,11,12,12,12,12,13} #elif DECDPUN==5 #define DECDPUNMAX 99999 #define D2UTABLE {0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5, \ 5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9, \ 9,9,10,10,10,10} #elif DECDPUN==6 #define DECDPUNMAX 999999 #define D2UTABLE {0,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4, \ 4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8, \ 8,8,8,8,8,9} #elif DECDPUN==7 #define DECDPUNMAX 9999999 #define D2UTABLE {0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3, \ 4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7, \ 7,7,7,7,7,7} #elif DECDPUN==8 #define DECDPUNMAX 99999999 #define D2UTABLE {0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3, \ 3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6, \ 6,6,6,6,6,7} #elif DECDPUN==9 #define DECDPUNMAX 999999999 #define D2UTABLE {0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3, \ 3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5, \ 5,5,6,6,6,6} #elif defined(DECDPUN) #error DECDPUN must be in the range 1-9 #endif /* ----- Shared data (in decNumber.c) ----- */ // Public powers of of ten array (powers[n]==10**n, 0<=n<=10) extern const uInt powers[]; // Public lookup table used by the D2U macro (see below) #define DECMAXD2U 49 extern const uByte d2utable[DECMAXD2U+1]; /* ----- Macros ----- */ // ISZERO -- return true if decNumber dn is a zero // [performance-critical in some situations] #define ISZERO(dn) decNumberIsZero(dn) // now just a local name // X10 and X100 -- multiply integer i by 10 or 100 // [shifts are usually faster than multiply; could be conditional] #define X10(i) (((i)<<1)+((i)<<3)) #define X100(i) (((i)<<2)+((i)<<5)+((i)<<6)) // D2U -- return the number of Units needed to hold d digits // (runtime version, with table lookaside for small d) #if DECDPUN==8 #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+7)>>3)) #elif DECDPUN==4 #define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+3)>>2)) #else #define D2U(d) ((d)<=DECMAXD2U?d2utable[d]:((d)+DECDPUN-1)/DECDPUN) #endif // SD2U -- static D2U macro (for compile-time calculation) #define SD2U(d) (((d)+DECDPUN-1)/DECDPUN) // MSUDIGITS -- returns digits in msu, calculated using D2U #define MSUDIGITS(d) ((d)-(D2U(d)-1)*DECDPUN) // D2N -- return the number of decNumber structs that would be // needed to contain that number of digits (and the initial // decNumber struct) safely. Note that one Unit is included in the // initial structure. Used for allocating space that is aligned on // a decNumber struct boundary. #define D2N(d) \ ((((SD2U(d)-1)*sizeof(Unit))+sizeof(decNumber)*2-1)/sizeof(decNumber)) // TODIGIT -- macro to remove the leading digit from the unsigned // integer u at column cut (counting from the right, LSD=0) and // place it as an ASCII character into the character pointed to by // c. Note that cut must be <= 9, and the maximum value for u is // 2,000,000,000 (as is needed for negative exponents of // subnormals). The unsigned integer pow is used as a temporary // variable. #define TODIGIT(u, cut, c, pow) { \ *(c)='0'; \ pow=powers[cut]*2; \ if ((u)>pow) { \ pow*=4; \ if ((u)>=pow) {(u)-=pow; *(c)+=8;} \ pow/=2; \ if ((u)>=pow) {(u)-=pow; *(c)+=4;} \ pow/=2; \ } \ if ((u)>=pow) {(u)-=pow; *(c)+=2;} \ pow/=2; \ if ((u)>=pow) {(u)-=pow; *(c)+=1;} \ } // MAX and MIN -- general max & min (not in ANSI) #define MAX(x,y) ((x)<(y)?(y):(x)) #define MIN(x,y) ((x)>(y)?(y):(x)) #else #error decNumberLocal included more than once #endif hercules-3.12/decNumber/decPacked.h0000664000175000017500000000515612564723224014132 00000000000000/* ------------------------------------------------------------------ */ /* Packed Decimal conversion module header */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ #if !defined(DECPACKED) #define DECPACKED #define DECPNAME "decPacked" /* Short name */ #define DECPFULLNAME "Packed Decimal conversions" /* Verbose name */ #define DECPAUTHOR "Mike Cowlishaw" /* Who to blame */ #define DECPACKED_DefP 32 // default precision #ifndef DECNUMDIGITS #define DECNUMDIGITS DECPACKED_DefP // size if not already defined #endif #include "decNumber.h" // context and number library /* Sign nibble constants */ #define DECPPLUSALT 0x0A // alternate plus nibble #define DECPMINUSALT 0x0B // alternate minus nibble #define DECPPLUS 0x0C // preferred plus nibble #define DECPMINUS 0x0D // preferred minus nibble #define DECPPLUSALT2 0x0E // alternate plus nibble #define DECPUNSIGNED 0x0F // alternate plus nibble (unsigned) /* ---------------------------------------------------------------- */ /* decPacked public routines */ /* ---------------------------------------------------------------- */ // Conversions uint8_t * decPackedFromNumber(uint8_t *, int32_t, int32_t *, const decNumber *); decNumber * decPackedToNumber(const uint8_t *, int32_t, const int32_t *, decNumber *); #endif hercules-3.12/decNumber/decContext.c0000664000175000017500000002426512564723224014364 00000000000000/* ------------------------------------------------------------------ */ /* Decimal Context module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for handling arithmetic */ /* context structures. */ /* ------------------------------------------------------------------ */ #include // for strcmp #include "decContext.h" // context and base types #include "decNumberLocal.h" // decNumber local types, etc. /* ------------------------------------------------------------------ */ /* decContextDefault -- initialize a context structure */ /* */ /* context is the structure to be initialized */ /* kind selects the required set of default values, one of: */ /* DEC_INIT_BASE -- select ANSI X3-274 defaults */ /* DEC_INIT_DECIMAL32 -- select IEEE 754r defaults, 32-bit */ /* DEC_INIT_DECIMAL64 -- select IEEE 754r defaults, 64-bit */ /* DEC_INIT_DECIMAL128 -- select IEEE 754r defaults, 128-bit */ /* For any other value a valid context is returned, but with */ /* Invalid_operation set in the status field. */ /* returns a context structure with the appropriate initial values. */ /* ------------------------------------------------------------------ */ decContext * decContextDefault(decContext *context, Int kind) { // set defaults... context->digits=9; // 9 digits context->emax=DEC_MAX_EMAX; // 9-digit exponents context->emin=DEC_MIN_EMIN; // .. balanced context->round=DEC_ROUND_HALF_UP; // 0.5 rises context->traps=DEC_Errors; // all but informational context->status=0; // cleared context->clamp=0; // no clamping #if DECSUBSET context->extended=0; // cleared #endif switch (kind) { case DEC_INIT_BASE: // [use defaults] break; case DEC_INIT_DECIMAL32: context->digits=7; // digits context->emax=96; // Emax context->emin=-95; // Emin context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even context->traps=0; // no traps set context->clamp=1; // clamp exponents #if DECSUBSET context->extended=1; // set #endif break; case DEC_INIT_DECIMAL64: context->digits=16; // digits context->emax=384; // Emax context->emin=-383; // Emin context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even context->traps=0; // no traps set context->clamp=1; // clamp exponents #if DECSUBSET context->extended=1; // set #endif break; case DEC_INIT_DECIMAL128: context->digits=34; // digits context->emax=6144; // Emax context->emin=-6143; // Emin context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even context->traps=0; // no traps set context->clamp=1; // clamp exponents #if DECSUBSET context->extended=1; // set #endif break; default: // invalid Kind // use defaults, and .. decContextSetStatus(context, DEC_Invalid_operation); // trap } return context;} // decContextDefault /* ------------------------------------------------------------------ */ /* decContextStatusToString -- convert status flags to a string */ /* */ /* context is a context with valid status field */ /* */ /* returns a constant string describing the condition. If multiple */ /* (or no) flags are set, a generic constant message is returned. */ /* ------------------------------------------------------------------ */ const char *decContextStatusToString(const decContext *context) { Int status=context->status; if (status==DEC_Conversion_syntax ) return DEC_Condition_CS; if (status==DEC_Division_by_zero ) return DEC_Condition_DZ; if (status==DEC_Division_impossible ) return DEC_Condition_DI; if (status==DEC_Division_undefined ) return DEC_Condition_DU; if (status==DEC_Inexact ) return DEC_Condition_IE; if (status==DEC_Insufficient_storage ) return DEC_Condition_IS; if (status==DEC_Invalid_context ) return DEC_Condition_IC; if (status==DEC_Invalid_operation ) return DEC_Condition_IO; #if DECSUBSET if (status==DEC_Lost_digits ) return DEC_Condition_LD; #endif if (status==DEC_Overflow ) return DEC_Condition_OV; if (status==DEC_Clamped ) return DEC_Condition_PA; if (status==DEC_Rounded ) return DEC_Condition_RO; if (status==DEC_Subnormal ) return DEC_Condition_SU; if (status==DEC_Underflow ) return DEC_Condition_UN; if (status==0 ) return DEC_Condition_ZE; return DEC_Condition_MU; // Multiple errors } // decContextStatusToString /* ------------------------------------------------------------------ */ /* decContextSetStatusFromString -- set status from a string */ /* */ /* context is the controlling context */ /* string is a string exactly equal to one that might be returned */ /* by decContextStatusToString */ /* */ /* The status bit corresponding to the string is set, and a trap */ /* is raised if appropriate. */ /* */ /* returns the context structure, unless the string is equal to */ /* DEC_Condition_MU or is not recognized. In these cases NULL is */ /* returned. */ /* ------------------------------------------------------------------ */ decContext * decContextSetStatusFromString(decContext *context, const char *string) { if (strcmp(string, DEC_Condition_CS)==0) return decContextSetStatus(context, DEC_Conversion_syntax); if (strcmp(string, DEC_Condition_DZ)==0) return decContextSetStatus(context, DEC_Division_by_zero); if (strcmp(string, DEC_Condition_DI)==0) return decContextSetStatus(context, DEC_Division_impossible); if (strcmp(string, DEC_Condition_DU)==0) return decContextSetStatus(context, DEC_Division_undefined); if (strcmp(string, DEC_Condition_IE)==0) return decContextSetStatus(context, DEC_Inexact); if (strcmp(string, DEC_Condition_IS)==0) return decContextSetStatus(context, DEC_Insufficient_storage); if (strcmp(string, DEC_Condition_IC)==0) return decContextSetStatus(context, DEC_Invalid_context); if (strcmp(string, DEC_Condition_IO)==0) return decContextSetStatus(context, DEC_Invalid_operation); #if DECSUBSET if (strcmp(string, DEC_Condition_LD)==0) return decContextSetStatus(context, DEC_Lost_digits); #endif if (strcmp(string, DEC_Condition_OV)==0) return decContextSetStatus(context, DEC_Overflow); if (strcmp(string, DEC_Condition_PA)==0) return decContextSetStatus(context, DEC_Clamped); if (strcmp(string, DEC_Condition_RO)==0) return decContextSetStatus(context, DEC_Rounded); if (strcmp(string, DEC_Condition_SU)==0) return decContextSetStatus(context, DEC_Subnormal); if (strcmp(string, DEC_Condition_UN)==0) return decContextSetStatus(context, DEC_Underflow); if (strcmp(string, DEC_Condition_ZE)==0) return context; return NULL; // Multiple status, or unknown } // decContextSetStatusFromString /* ------------------------------------------------------------------ */ /* decContextSetStatus -- set status and raise trap if appropriate */ /* */ /* context is the controlling context */ /* status is the DEC_ exception code */ /* returns the context structure */ /* */ /* Control may never return from this routine, if there is a signal */ /* handler and it takes a long jump. */ /* ------------------------------------------------------------------ */ decContext * decContextSetStatus(decContext *context, uInt status) { context->status|=status; if (status & context->traps) raise(SIGFPE); return context;} // decContextSetStatus hercules-3.12/decNumber/decimal128.c0000664000175000017500000006110512564723224014107 00000000000000/* ------------------------------------------------------------------ */ /* Decimal 128-bit format module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for decimal128 format numbers. */ /* Conversions are supplied to and from decNumber and String. */ /* */ /* No arithmetic routines are included; decNumber provides these. */ /* */ /* Error handling is the same as decNumber (qv.). */ /* ------------------------------------------------------------------ */ #include // [for memset/memcpy] #include // [for printf] #if defined(_MSVC_) #pragma warning(disable:4244) // [for win64] #endif /*defined(_MSVC_)*/ #define DECNUMDIGITS 34 // make decNumbers with space for 34 #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. #include "decimal128.h" // our primary include /* Utility routines and tables [in decimal64.c] */ extern const uInt COMBEXP[32], COMBMSD[32]; extern const uShort DPD2BIN[1024]; extern const uShort BIN2DPD[1000]; // [not used] extern const uByte BIN2CHAR[4001]; extern void decDigitsFromDPD(decNumber *, const uInt *, Int); extern void decDigitsToDPD(const decNumber *, uInt *, Int); #if DECTRACE || DECCHECK void decimal128Show(const decimal128 *); // for debug extern void decNumberShow(const decNumber *); // .. #endif /* compile-time endian tester [assumes sizeof(int)>1] */ static const Int mfcone=1; // constant 1 static const Flag *mfctop=(Flag *)&mfcone; // -> top byte #define LITEND mfctop[0] // named flag; 1=little-endian /* Useful macro */ // Clear a structure (e.g., a decNumber) #define DEC_clear(d) memset(d, 0, sizeof(*d)) /* ------------------------------------------------------------------ */ /* decimal128FromNumber -- convert decNumber to decimal128 */ /* */ /* ds is the target decimal128 */ /* dn is the source number (assumed valid) */ /* set is the context, used only for reporting errors */ /* */ /* The set argument is used only for status reporting and for the */ /* rounding mode (used if the coefficient is more than DECIMAL128_Pmax*/ /* digits or an overflow is detected). If the exponent is out of the */ /* valid range then Overflow or Underflow will be raised. */ /* After Underflow a subnormal result is possible. */ /* */ /* DEC_Clamped is set if the number has to be 'folded down' to fit, */ /* by reducing its exponent and multiplying the coefficient by a */ /* power of ten, or if the exponent on a zero had to be clamped. */ /* ------------------------------------------------------------------ */ decimal128 * decimal128FromNumber(decimal128 *d128, const decNumber *dn, decContext *set) { uInt status=0; // status accumulator Int ae; // adjusted exponent decNumber dw; // work decContext dc; // .. uInt *pu; // .. uInt comb, exp; // .. uInt targar[4]={0,0,0,0}; // target 128-bit #define targhi targar[3] // name the word with the sign #define targmh targar[2] // name the words #define targml targar[1] // .. #define targlo targar[0] // .. // If the number has too many digits, or the exponent could be // out of range then reduce the number under the appropriate // constraints. This could push the number to Infinity or zero, // so this check and rounding must be done before generating the // decimal128] ae=dn->exponent+dn->digits-1; // [0 if special] if (dn->digits>DECIMAL128_Pmax // too many digits || ae>DECIMAL128_Emax // likely overflow || aeround; // use supplied rounding decNumberPlus(&dw, dn, &dc); // (round and check) // [this changes -0 to 0, so enforce the sign...] dw.bits|=dn->bits&DECNEG; status=dc.status; // save status dn=&dw; // use the work number } // maybe out of range if (dn->bits&DECSPECIAL) { // a special value if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24; else { // sNaN or qNaN if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient && (dn->digitsbits&DECNAN) targhi|=DECIMAL_NaN<<24; else targhi|=DECIMAL_sNaN<<24; } // a NaN } // special else { // is finite if (decNumberIsZero(dn)) { // is a zero // set and clamp exponent if (dn->exponent<-DECIMAL128_Bias) { exp=0; // low clamp status|=DEC_Clamped; } else { exp=dn->exponent+DECIMAL128_Bias; // bias exponent if (exp>DECIMAL128_Ehigh) { // top clamp exp=DECIMAL128_Ehigh; status|=DEC_Clamped; } } comb=(exp>>9) & 0x18; // msd=0, exp top 2 bits .. } else { // non-zero finite number uInt msd; // work Int pad=0; // coefficient pad digits // the dn is known to fit, but it may need to be padded exp=(uInt)(dn->exponent+DECIMAL128_Bias); // bias exponent if (exp>DECIMAL128_Ehigh) { // fold-down case pad=exp-DECIMAL128_Ehigh; exp=DECIMAL128_Ehigh; // [to maximum] status|=DEC_Clamped; } // [fastpath for common case is not a win, here] decDigitsToDPD(dn, targar, pad); // save and clear the top digit msd=targhi>>14; targhi&=0x00003fff; // create the combination field if (msd>=8) comb=0x18 | ((exp>>11) & 0x06) | (msd & 0x01); else comb=((exp>>9) & 0x18) | msd; } targhi|=comb<<26; // add combination field .. targhi|=(exp&0xfff)<<14; // .. and exponent continuation } // finite if (dn->bits&DECNEG) targhi|=0x80000000; // add sign bit // now write to storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct store, in the right order pu=(uInt *)d128->bytes; // overlay if (LITEND) { pu[0]=targlo; // directly store the low int pu[1]=targml; // then the mid-low pu[2]=targmh; // then the mid-high pu[3]=targhi; // then the high int } else { pu[0]=targhi; // directly store the high int pu[1]=targmh; // then the mid-high pu[2]=targml; // then the mid-low pu[3]=targlo; // then the low int } #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal uByte *pb; // work Int off; // .. for (pb=&d128->bytes[15]; pb>=d128->bytes; pb--) { off=3-((pb-d128->bytes)>>2); // 0, then 1, 2, 3 *pb=(uByte)(targar[off]&0xff); targar[off]>>=8; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d128->bytes; // overlay pu[0]=targhi; // directly store the high int pu[1]=targmh; // then the mid-high pu[2]=targml; // then the mid-low pu[3]=targlo; // then the low int } #endif if (status!=0) decContextSetStatus(set, status); // pass on status // decimal128Show(d128); return d128; } // decimal128FromNumber /* ------------------------------------------------------------------ */ /* decimal128ToNumber -- convert decimal128 to decNumber */ /* d128 is the source decimal128 */ /* dn is the target number, with appropriate space */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decimal128ToNumber(const decimal128 *d128, decNumber *dn) { uInt msd; // coefficient MSD uInt exp; // exponent top two bits uInt comb; // combination field uInt *pu; // work Int need; // .. uInt sourar[4]; // source 128-bit #define sourhi sourar[3] // name the word with the sign #define sourmh sourar[2] // and the mid-high word #define sourml sourar[1] // and the mod-low word #define sourlo sourar[0] // and the lowest word // load source from storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct load, in the right order pu=(uInt *)d128->bytes; // overlay if (LITEND) { sourlo=pu[0]; // directly load the low int sourml=pu[1]; // then the mid-low sourmh=pu[2]; // then the mid-high sourhi=pu[3]; // then the high int } else { sourhi=pu[0]; // directly load the high int sourmh=pu[1]; // then the mid-high sourml=pu[2]; // then the mid-low sourlo=pu[3]; // then the low int } #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal const uByte *pb; // work Int off; // .. for (pb=d128->bytes; pb<=&d128->bytes[15]; pb++) { off=3-((pb-d128->bytes)>>2); // 3, then 2, 1, 0 sourar[off]<<=8; sourar[off]|=*pb; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d128->bytes; // overlay sourhi=pu[0]; // directly load the high int sourmh=pu[1]; // then the mid-high sourml=pu[2]; // then the mid-low sourlo=pu[3]; // then the low int } #endif comb=(sourhi>>26)&0x1f; // combination field decNumberZero(dn); // clean number if (sourhi&0x80000000) dn->bits=DECNEG; // set sign if negative msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { // is a special if (msd==0) { dn->bits|=DECINF; return dn; // no coefficient needed } else if (sourhi&0x02000000) dn->bits|=DECSNAN; else dn->bits|=DECNAN; msd=0; // no top digit } else { // is a finite number dn->exponent=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; // unbiased } // get the coefficient sourhi&=0x00003fff; // clean coefficient continuation if (msd) { // non-zero msd sourhi|=msd<<14; // prefix to coefficient need=12; // process 12 declets } else { // msd=0 if (sourhi) need=11; // declets to process else if (sourmh) need=10; else if (sourml) need=7; else if (sourlo) need=4; else return dn; // easy: coefficient is 0 } //msd=0 decDigitsFromDPD(dn, sourar, need); // process declets // decNumberShow(dn); return dn; } // decimal128ToNumber /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decimal128ToString(d128, string); */ /* decimal128ToEngString(d128, string); */ /* */ /* d128 is the decimal128 format number to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least 24 characters */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decimal128ToEngString(const decimal128 *d128, char *string){ decNumber dn; // work decimal128ToNumber(d128, &dn); decNumberToEngString(&dn, string); return string; } // decimal128ToEngString char * decimal128ToString(const decimal128 *d128, char *string){ uInt msd; // coefficient MSD Int exp; // exponent top two bits or full uInt comb; // combination field char *cstart; // coefficient start char *c; // output pointer in string uInt *pu; // work char *s, *t; // .. (source, target) Int dpd; // .. Int pre, e; // .. const uByte *u; // .. uInt sourar[4]; // source 128-bit #define sourhi sourar[3] // name the word with the sign #define sourmh sourar[2] // and the mid-high word #define sourml sourar[1] // and the mod-low word #define sourlo sourar[0] // and the lowest word // load source from storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct load, in the right order pu=(uInt *)d128->bytes; // overlay if (LITEND) { sourlo=pu[0]; // directly load the low int sourml=pu[1]; // then the mid-low sourmh=pu[2]; // then the mid-high sourhi=pu[3]; // then the high int } else { sourhi=pu[0]; // directly load the high int sourmh=pu[1]; // then the mid-high sourml=pu[2]; // then the mid-low sourlo=pu[3]; // then the low int } #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal const uByte *pb; // work Int off; // .. for (pb=d128->bytes; pb<=&d128->bytes[15]; pb++) { off=3-((pb-d128->bytes)>>2); // 3, then 2, 1, 0 sourar[off]<<=8; sourar[off]|=*pb; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d128->bytes; // overlay sourhi=pu[0]; // directly load the high int sourmh=pu[1]; // then the mid-high sourml=pu[2]; // then the mid-low sourlo=pu[3]; // then the low int } #endif c=string; // where result will go if (((Int)sourhi)<0) *c++='-'; // handle sign comb=(sourhi>>26)&0x1f; // combination field msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { if (msd==0) { // infinity strcpy(c, "Infinity"); return string; // easy } if (sourhi&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past if (sourlo==0 && sourml==0 && sourmh==0 && (sourhi&0x0003ffff)==0) return string; // zero payload // otherwise drop through to add integer; set correct exp exp=0; msd=0; // setup for following code } else exp=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; // unbiased // convert 34 digits of significand to characters cstart=c; // save start of coefficient if (msd) *c++='0'+(char)msd; // non-zero most significant digit // Now decode the declets. After extracting each one, it is // decoded to binary and then to a 4-char sequence by table lookup; // the 4-chars are a 1-char length (significant digits, except 000 // has length 0). This allows us to left-align the first declet // with non-zero content, then remaining ones are full 3-char // length. We use fixed-length memcpys because variable-length // causes a subroutine call in GCC. (These are length 4 for speed // and are safe because the array has an extra terminator byte.) #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} dpd=(sourhi>>4)&0x3ff; // declet 1 dpd2char; dpd=((sourhi&0xf)<<6) | (sourmh>>26); // declet 2 dpd2char; dpd=(sourmh>>16)&0x3ff; // declet 3 dpd2char; dpd=(sourmh>>6)&0x3ff; // declet 4 dpd2char; dpd=((sourmh&0x3f)<<4) | (sourml>>28); // declet 5 dpd2char; dpd=(sourml>>18)&0x3ff; // declet 6 dpd2char; dpd=(sourml>>8)&0x3ff; // declet 7 dpd2char; dpd=((sourml&0xff)<<2) | (sourlo>>30); // declet 8 dpd2char; dpd=(sourlo>>20)&0x3ff; // declet 9 dpd2char; dpd=(sourlo>>10)&0x3ff; // declet 10 dpd2char; dpd=(sourlo)&0x3ff; // declet 11 dpd2char; if (c==cstart) *c++='0'; // all zeros -- make 0 if (exp==0) { // integer or NaN case -- easy *c='\0'; // terminate return string; } /* non-0 exponent */ e=0; // assume no E pre=c-cstart+exp; // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' } // exponential form /* modify the coefficient, adding 0s, '.', and E+nn as needed */ s=c-1; // source (LSD) if (pre>0) { // ddd.ddd (plain), perhaps with E char *dotat=cstart+pre; if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap *t='.'; // insert the dot c++; // length increased by one } // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 4 digits if (e!=0) { *c++='E'; // starts with E *c++='+'; // assume positive if (e<0) { *(c-1)='-'; // oops, need '-' e=-e; // uInt, please } if (e<1000) { // 3 (or fewer) digits case u=&BIN2CHAR[e*4]; // -> length byte memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] c+=*u; // bump pointer appropriately } else { // 4-digits Int thou=((e>>3)*1049)>>17; // e/1000 Int rem=e-(1000*thou); // e%1000 *c++='0'+(char)thou; u=&BIN2CHAR[rem*4]; // -> length byte memcpy(c, u+1, 4); // copy fixed 3+1 characters [is safe] c+=3; // bump pointer, always 3 digits } } *c='\0'; // add terminator //printf("res %s\n", string); return string; } // pre>0 /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ t=c+1-pre; *(t+1)='\0'; // can add terminator now for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right c=cstart; *c++='0'; // always starts with 0. *c++='.'; for (; pre<0; pre++) *c++='0'; // add any 0's after '.' //printf("res %s\n", string); return string; } // decimal128ToString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decimal128FromString(result, string, set); */ /* */ /* result is the decimal128 format number which gets the result of */ /* the conversion */ /* *string is the character string which should contain a valid */ /* number (which may be a special value) */ /* set is the context */ /* */ /* The context is supplied to this routine is used for error handling */ /* (setting of status and traps) and for the rounding mode, only. */ /* If an error occurs, the result will be a valid decimal128 NaN. */ /* ------------------------------------------------------------------ */ decimal128 * decimal128FromString(decimal128 *result, const char *string, decContext *set) { decContext dc; // work decNumber dn; // .. decContextDefault(&dc, DEC_INIT_DECIMAL128); // no traps, please dc.round=set->round; // use supplied rounding decNumberFromString(&dn, string, &dc); // will round if needed decimal128FromNumber(result, &dn, &dc); if (dc.status!=0) { // something happened decContextSetStatus(set, dc.status); // .. pass it on } return result; } // decimal128FromString #if DECTRACE || DECCHECK /* ------------------------------------------------------------------ */ /* decimal128Show -- display a decimal128 in hexadecimal [debug aid] */ /* d128 -- the number to show */ /* ------------------------------------------------------------------ */ // Also shows sign/cob/expconfields extracted void decimal128Show(const decimal128 *d128) { char buf[DECIMAL128_Bytes*2+1]; Int i, j=0; #if DECENDIAN if (LITEND) { for (i=0; ibytes[15-i]); } printf(" D128> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, d128->bytes[15]>>7, (d128->bytes[15]>>2)&0x1f, ((d128->bytes[15]&0x3)<<10)|(d128->bytes[14]<<2)| (d128->bytes[13]>>6)); } else { #endif for (i=0; ibytes[i]); } printf(" D128> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, decimal128Sign(d128), decimal128Comb(d128), decimal128ExpCon(d128)); #if DECENDIAN } #endif } // decimal128Show #endif hercules-3.12/decNumber/decimal32.c0000664000175000017500000005137712564723224014033 00000000000000/* ------------------------------------------------------------------ */ /* Decimal 32-bit format module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for decimal32 format numbers. */ /* Conversions are supplied to and from decNumber and String. */ /* */ /* No arithmetic routines are included; decNumber provides these. */ /* */ /* Error handling is the same as decNumber (qv.). */ /* ------------------------------------------------------------------ */ #include // [for memset/memcpy] #include // [for printf] #if defined(_MSVC_) #pragma warning(disable:4244) // [for win64] #endif /*defined(_MSVC_)*/ #define DECNUMDIGITS 7 // make decNumbers with space for 7 #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. #include "decimal32.h" // our primary include /* Utility tables and routines [in decimal64.c] */ extern const uInt COMBEXP[32], COMBMSD[32]; extern const uShort DPD2BIN[1024]; extern const uShort BIN2DPD[1000]; extern const uByte BIN2CHAR[4001]; extern void decDigitsToDPD(const decNumber *, uInt *, Int); extern void decDigitsFromDPD(decNumber *, const uInt *, Int); #if DECTRACE || DECCHECK void decimal32Show(const decimal32 *); // for debug extern void decNumberShow(const decNumber *); // .. #endif /* Useful macro */ // Clear a structure (e.g., a decNumber) #define DEC_clear(d) memset(d, 0, sizeof(*d)) #if !DECENDIAN || DECTRACE || DECCHECK /* compile-time endian tester [assumes sizeof(int)>1] */ static const Int mfcone=1; // constant 1 static const Flag *mfctop=(Flag *)&mfcone; // -> top byte #define LITEND mfctop[0] // named flag; 1=little-endian #endif /* ------------------------------------------------------------------ */ /* decimal32FromNumber -- convert decNumber to decimal32 */ /* */ /* ds is the target decimal32 */ /* dn is the source number (assumed valid) */ /* set is the context, used only for reporting errors */ /* */ /* The set argument is used only for status reporting and for the */ /* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */ /* digits or an overflow is detected). If the exponent is out of the */ /* valid range then Overflow or Underflow will be raised. */ /* After Underflow a subnormal result is possible. */ /* */ /* DEC_Clamped is set if the number has to be 'folded down' to fit, */ /* by reducing its exponent and multiplying the coefficient by a */ /* power of ten, or if the exponent on a zero had to be clamped. */ /* ------------------------------------------------------------------ */ decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn, decContext *set) { uInt status=0; // status accumulator Int ae; // adjusted exponent decNumber dw; // work decContext dc; // .. uInt *pu; // .. uInt comb, exp; // .. uInt targ=0; // target 32-bit // If the number has too many digits, or the exponent could be // out of range then reduce the number under the appropriate // constraints. This could push the number to Infinity or zero, // so this check and rounding must be done before generating the // decimal32] ae=dn->exponent+dn->digits-1; // [0 if special] if (dn->digits>DECIMAL32_Pmax // too many digits || ae>DECIMAL32_Emax // likely overflow || aeround; // use supplied rounding decNumberPlus(&dw, dn, &dc); // (round and check) // [this changes -0 to 0, so enforce the sign...] dw.bits|=dn->bits&DECNEG; status=dc.status; // save status dn=&dw; // use the work number } // maybe out of range if (dn->bits&DECSPECIAL) { // a special value if (dn->bits&DECINF) targ=DECIMAL_Inf<<24; else { // sNaN or qNaN if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient && (dn->digitsbits&DECNAN) targ|=DECIMAL_NaN<<24; else targ|=DECIMAL_sNaN<<24; } // a NaN } // special else { // is finite if (decNumberIsZero(dn)) { // is a zero // set and clamp exponent if (dn->exponent<-DECIMAL32_Bias) { exp=0; // low clamp status|=DEC_Clamped; } else { exp=dn->exponent+DECIMAL32_Bias; // bias exponent if (exp>DECIMAL32_Ehigh) { // top clamp exp=DECIMAL32_Ehigh; status|=DEC_Clamped; } } comb=(exp>>3) & 0x18; // msd=0, exp top 2 bits .. } else { // non-zero finite number uInt msd; // work Int pad=0; // coefficient pad digits // the dn is known to fit, but it may need to be padded exp=(uInt)(dn->exponent+DECIMAL32_Bias); // bias exponent if (exp>DECIMAL32_Ehigh) { // fold-down case pad=exp-DECIMAL32_Ehigh; exp=DECIMAL32_Ehigh; // [to maximum] status|=DEC_Clamped; } // fastpath common case if (DECDPUN==3 && pad==0) { targ=BIN2DPD[dn->lsu[0]]; if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10; msd=(dn->digits==7 ? dn->lsu[2] : 0); } else { // general case decDigitsToDPD(dn, &targ, pad); // save and clear the top digit msd=targ>>20; targ&=0x000fffff; } // create the combination field if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01); else comb=((exp>>3) & 0x18) | msd; } targ|=comb<<26; // add combination field .. targ|=(exp&0x3f)<<20; // .. and exponent continuation } // finite if (dn->bits&DECNEG) targ|=0x80000000; // add sign bit // now write to storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct store pu=(uInt *)d32->bytes; // overlay *pu=targ; // directly store the int #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal uByte *pb; // work for (pb=&d32->bytes[3]; pb>=d32->bytes; pb--) { *pb=(uByte)(targ&0xff); targ>>=8; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d32->bytes; // overlay *pu=targ; // directly store the int } #endif if (status!=0) decContextSetStatus(set, status); // pass on status // decimal32Show(d32); return d32; } // decimal32FromNumber /* ------------------------------------------------------------------ */ /* decimal32ToNumber -- convert decimal32 to decNumber */ /* d32 is the source decimal32 */ /* dn is the target number, with appropriate space */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) { uInt msd; // coefficient MSD uInt exp; // exponent top two bits uInt comb; // combination field uInt *pu; // work uInt sour; // source 32-bit // load source from storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct load pu=(uInt *)d32->bytes; // overlay sour=*pu; // directly load the int #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal const uByte *pb; // work sour=0; // [keep compiler quiet] for (pb=d32->bytes; pb<=&d32->bytes[3]; pb++) { sour<<=8; sour|=*pb; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d32->bytes; // overlay sour=*pu; // directly load the int } #endif comb=(sour>>26)&0x1f; // combination field decNumberZero(dn); // clean number if (sour&0x80000000) dn->bits=DECNEG; // set sign if negative msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { // is a special if (msd==0) { dn->bits|=DECINF; return dn; // no coefficient needed } else if (sour&0x02000000) dn->bits|=DECSNAN; else dn->bits|=DECNAN; msd=0; // no top digit } else { // is a finite number dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; // unbiased } // get the coefficient sour&=0x000fffff; // clean coefficient continuation if (msd) { // non-zero msd sour|=msd<<20; // prefix to coefficient decDigitsFromDPD(dn, &sour, 3); // process 3 declets return dn; } // msd=0 if (!sour) return dn; // easy: coefficient is 0 if (sour&0x000ffc00) // need 2 declets? decDigitsFromDPD(dn, &sour, 2); // process 2 declets else decDigitsFromDPD(dn, &sour, 1); // process 1 declet return dn; } // decimal32ToNumber /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decimal32ToString(d32, string); */ /* decimal32ToEngString(d32, string); */ /* */ /* d32 is the decimal32 format number to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least 24 characters */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decimal32ToEngString(const decimal32 *d32, char *string){ decNumber dn; // work decimal32ToNumber(d32, &dn); decNumberToEngString(&dn, string); return string; } // decimal32ToEngString char * decimal32ToString(const decimal32 *d32, char *string){ uInt msd; // coefficient MSD Int exp; // exponent top two bits or full uInt comb; // combination field char *cstart; // coefficient start char *c; // output pointer in string uInt *pu; // work char *s, *t; // .. (source, target) Int dpd; // .. Int pre, e; // .. const uByte *u; // .. uInt sour; // source 32-bit // load source from storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct load pu=(uInt *)d32->bytes; // overlay sour=*pu; // directly load the int #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal const uByte *pb; // work sour=0; // [keep compiler quiet] for (pb=d32->bytes; pb<=&d32->bytes[3]; pb++) { sour<<=8; sour|=*pb; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d32->bytes; // overlay sour=*pu; // directly load the int } #endif c=string; // where result will go if (((Int)sour)<0) *c++='-'; // handle sign comb=(sour>>26)&0x1f; // combination field msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { if (msd==0) { // infinity strcpy(c, "Infinity"); return string; // easy } if (sour&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past if ((sour&0x000fffff)==0) return string; // zero payload // otherwise drop through to add integer; set correct exp exp=0; msd=0; // setup for following code } else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; // unbiased // convert 7 digits of significand to characters cstart=c; // save start of coefficient if (msd) *c++='0'+(char)msd; // non-zero most significant digit // Now decode the declets. After extracting each one, it is // decoded to binary and then to a 4-char sequence by table lookup; // the 4-chars are a 1-char length (significant digits, except 000 // has length 0). This allows us to left-align the first declet // with non-zero content, then remaining ones are full 3-char // length. We use fixed-length memcpys because variable-length // causes a subroutine call in GCC. (These are length 4 for speed // and are safe because the array has an extra terminator byte.) #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} dpd=(sour>>10)&0x3ff; // declet 1 dpd2char; dpd=(sour)&0x3ff; // declet 2 dpd2char; if (c==cstart) *c++='0'; // all zeros -- make 0 if (exp==0) { // integer or NaN case -- easy *c='\0'; // terminate return string; } /* non-0 exponent */ e=0; // assume no E pre=c-cstart+exp; // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' } // exponential form /* modify the coefficient, adding 0s, '.', and E+nn as needed */ s=c-1; // source (LSD) if (pre>0) { // ddd.ddd (plain), perhaps with E char *dotat=cstart+pre; if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap *t='.'; // insert the dot c++; // length increased by one } // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 3 digits (E-101 case) if (e!=0) { *c++='E'; // starts with E *c++='+'; // assume positive if (e<0) { *(c-1)='-'; // oops, need '-' e=-e; // uInt, please } u=&BIN2CHAR[e*4]; // -> length byte memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] c+=*u; // bump pointer appropriately } *c='\0'; // add terminator //printf("res %s\n", string); return string; } // pre>0 /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ t=c+1-pre; *(t+1)='\0'; // can add terminator now for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right c=cstart; *c++='0'; // always starts with 0. *c++='.'; for (; pre<0; pre++) *c++='0'; // add any 0's after '.' //printf("res %s\n", string); return string; } // decimal32ToString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decimal32FromString(result, string, set); */ /* */ /* result is the decimal32 format number which gets the result of */ /* the conversion */ /* *string is the character string which should contain a valid */ /* number (which may be a special value) */ /* set is the context */ /* */ /* The context is supplied to this routine is used for error handling */ /* (setting of status and traps) and for the rounding mode, only. */ /* If an error occurs, the result will be a valid decimal32 NaN. */ /* ------------------------------------------------------------------ */ decimal32 * decimal32FromString(decimal32 *result, const char *string, decContext *set) { decContext dc; // work decNumber dn; // .. decContextDefault(&dc, DEC_INIT_DECIMAL32); // no traps, please dc.round=set->round; // use supplied rounding decNumberFromString(&dn, string, &dc); // will round if needed decimal32FromNumber(result, &dn, &dc); if (dc.status!=0) { // something happened decContextSetStatus(set, dc.status); // .. pass it on } return result; } // decimal32FromString #if DECTRACE || DECCHECK /* ------------------------------------------------------------------ */ /* decimal32Show -- display a decimal32 in hexadecimal [debug aid] */ /* d32 -- the number to show */ /* ------------------------------------------------------------------ */ // Also shows sign/cob/expconfields extracted - valid bigendian only void decimal32Show(const decimal32 *d32) { char buf[DECIMAL32_Bytes*2+1]; Int i, j=0; #if DECENDIAN if (LITEND) { for (i=0; ibytes[3-i]); } printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f, ((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4)); } else { #endif for (i=0; ibytes[i]); } printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32)); #if DECENDIAN } #endif } // decimal32Show #endif hercules-3.12/decNumber/decimal64.c0000664000175000017500000011007212564723224014024 00000000000000/* ------------------------------------------------------------------ */ /* Decimal 64-bit format module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for decimal64 format numbers. */ /* Conversions are supplied to and from decNumber and String. */ /* */ /* No arithmetic routines are included; decNumber provides these. */ /* */ /* Error handling is the same as decNumber (qv.). */ /* ------------------------------------------------------------------ */ #include // [for memset/memcpy] #include // [for printf] #if defined(_MSVC_) #pragma warning(disable:4244) // [for win64] #endif /*defined(_MSVC_)*/ #define DECNUMDIGITS 16 // make decNumbers with space for 16 #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. #include "decimal64.h" // our primary include /* Utility routines and tables [in decimal64.c] */ extern const uInt COMBEXP[32], COMBMSD[32]; extern void decDigitsFromDPD(decNumber *, const uInt *, Int); extern void decDigitsToDPD(const decNumber *, uInt *, Int); #if DECTRACE || DECCHECK void decimal64Show(const decimal64 *); // for debug extern void decNumberShow(const decNumber *); // .. #endif /* compile-time endian tester [assumes sizeof(Int)>1] */ static const Int mfcone=1; // constant 1 static const Flag *mfctop=(Flag *)&mfcone; // -> top byte #define LITEND *mfctop // named flag; 1=little-endian /* Useful macro */ // Clear a structure (e.g., a decNumber) #define DEC_clear(d) memset(d, 0, sizeof(*d)) /* define and include the tables to use for conversions */ #define DEC_BIN2CHAR 1 #define DEC_DPD2BIN 1 #define DEC_BIN2DPD 1 // used for all sizes #include "decDPD.h" // lookup tables /* ------------------------------------------------------------------ */ /* decimal64FromNumber -- convert decNumber to decimal64 */ /* */ /* ds is the target decimal64 */ /* dn is the source number (assumed valid) */ /* set is the context, used only for reporting errors */ /* */ /* The set argument is used only for status reporting and for the */ /* rounding mode (used if the coefficient is more than DECIMAL64_Pmax */ /* digits or an overflow is detected). If the exponent is out of the */ /* valid range then Overflow or Underflow will be raised. */ /* After Underflow a subnormal result is possible. */ /* */ /* DEC_Clamped is set if the number has to be 'folded down' to fit, */ /* by reducing its exponent and multiplying the coefficient by a */ /* power of ten, or if the exponent on a zero had to be clamped. */ /* ------------------------------------------------------------------ */ decimal64 * decimal64FromNumber(decimal64 *d64, const decNumber *dn, decContext *set) { uInt status=0; // status accumulator Int ae; // adjusted exponent decNumber dw; // work decContext dc; // .. uInt *pu; // .. uInt comb, exp; // .. uInt targar[2]={0, 0}; // target 64-bit #define targhi targar[1] // name the word with the sign #define targlo targar[0] // and the other // If the number has too many digits, or the exponent could be // out of range then reduce the number under the appropriate // constraints. This could push the number to Infinity or zero, // so this check and rounding must be done before generating the // decimal64] ae=dn->exponent+dn->digits-1; // [0 if special] if (dn->digits>DECIMAL64_Pmax // too many digits || ae>DECIMAL64_Emax // likely overflow || aeround; // use supplied rounding decNumberPlus(&dw, dn, &dc); // (round and check) // [this changes -0 to 0, so enforce the sign...] dw.bits|=dn->bits&DECNEG; status=dc.status; // save status dn=&dw; // use the work number } // maybe out of range if (dn->bits&DECSPECIAL) { // a special value if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24; else { // sNaN or qNaN if ((*dn->lsu!=0 || dn->digits>1) // non-zero coefficient && (dn->digitsbits&DECNAN) targhi|=DECIMAL_NaN<<24; else targhi|=DECIMAL_sNaN<<24; } // a NaN } // special else { // is finite if (decNumberIsZero(dn)) { // is a zero // set and clamp exponent if (dn->exponent<-DECIMAL64_Bias) { exp=0; // low clamp status|=DEC_Clamped; } else { exp=dn->exponent+DECIMAL64_Bias; // bias exponent if (exp>DECIMAL64_Ehigh) { // top clamp exp=DECIMAL64_Ehigh; status|=DEC_Clamped; } } comb=(exp>>5) & 0x18; // msd=0, exp top 2 bits .. } else { // non-zero finite number uInt msd; // work Int pad=0; // coefficient pad digits // the dn is known to fit, but it may need to be padded exp=(uInt)(dn->exponent+DECIMAL64_Bias); // bias exponent if (exp>DECIMAL64_Ehigh) { // fold-down case pad=exp-DECIMAL64_Ehigh; exp=DECIMAL64_Ehigh; // [to maximum] status|=DEC_Clamped; } // fastpath common case if (DECDPUN==3 && pad==0) { uInt dpd[6]={0,0,0,0,0,0}; uInt i; Int d=dn->digits; for (i=0; d>0; i++, d-=3) dpd[i]=BIN2DPD[dn->lsu[i]]; targlo =dpd[0]; targlo|=dpd[1]<<10; targlo|=dpd[2]<<20; if (dn->digits>6) { targlo|=dpd[3]<<30; targhi =dpd[3]>>2; targhi|=dpd[4]<<8; } msd=dpd[5]; // [did not really need conversion] } else { // general case decDigitsToDPD(dn, targar, pad); // save and clear the top digit msd=targhi>>18; targhi&=0x0003ffff; } // create the combination field if (msd>=8) comb=0x18 | ((exp>>7) & 0x06) | (msd & 0x01); else comb=((exp>>5) & 0x18) | msd; } targhi|=comb<<26; // add combination field .. targhi|=(exp&0xff)<<18; // .. and exponent continuation } // finite if (dn->bits&DECNEG) targhi|=0x80000000; // add sign bit // now write to storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct store, in the right order pu=(uInt *)d64->bytes; // overlay if (LITEND) { pu[0]=targar[0]; // directly store the low int pu[1]=targar[1]; // then the high int } else { pu[0]=targar[1]; // directly store the high int pu[1]=targar[0]; // then the low int } #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal uByte *pb; // work Int off; // .. for (pb=&d64->bytes[7]; pb>=d64->bytes; pb--) { off=1-((pb-d64->bytes)>>2); // 0 then 1 *pb=(uByte)(targar[off]&0xff); targar[off]>>=8; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d64->bytes; // overlay pu[0]=targar[1]; // directly store the high int pu[1]=targar[0]; // then the low int } #endif if (status!=0) decContextSetStatus(set, status); // pass on status // decimal64Show(d64); return d64; } // decimal64FromNumber /* ------------------------------------------------------------------ */ /* decimal64ToNumber -- convert decimal64 to decNumber */ /* d64 is the source decimal64 */ /* dn is the target number, with appropriate space */ /* No error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decimal64ToNumber(const decimal64 *d64, decNumber *dn) { uInt msd; // coefficient MSD uInt exp; // exponent top two bits uInt comb; // combination field uInt *pu; // work Int need; // .. uInt sourar[2]; // source 64-bit #define sourhi sourar[1] // name the word with the sign #define sourlo sourar[0] // and the lower word // load source from storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct load, in the right order pu=(uInt *)d64->bytes; // overlay if (LITEND) { sourlo=pu[0]; // directly load the low int sourhi=pu[1]; // then the high int } else { sourhi=pu[0]; // directly load the high int sourlo=pu[1]; // then the low int } #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal const uByte *pb; // work Int off; // .. for (pb=d64->bytes; pb<=&d64->bytes[7]; pb++) { off=1-((pb-d64->bytes)>>2); // 1 then 0 sourar[off]<<=8; sourar[off]|=*pb; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d64->bytes; // overlay sourhi=pu[0]; // directly load the high int sourlo=pu[1]; // then the low int } #endif comb=(sourhi>>26)&0x1f; // combination field decNumberZero(dn); // clean number if (sourhi&0x80000000) dn->bits=DECNEG; // set sign if negative msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { // is a special if (msd==0) { dn->bits|=DECINF; return dn; // no coefficient needed } else if (sourhi&0x02000000) dn->bits|=DECSNAN; else dn->bits|=DECNAN; msd=0; // no top digit } else { // is a finite number dn->exponent=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; // unbiased } // get the coefficient sourhi&=0x0003ffff; // clean coefficient continuation if (msd) { // non-zero msd sourhi|=msd<<18; // prefix to coefficient need=6; // process 6 declets } else { // msd=0 if (!sourhi) { // top word 0 if (!sourlo) return dn; // easy: coefficient is 0 need=3; // process at least 3 declets if (sourlo&0xc0000000) need++; // process 4 declets // [could reduce some more, here] } else { // some bits in top word, msd=0 need=4; // process at least 4 declets if (sourhi&0x0003ff00) need++; // top declet!=0, process 5 } } //msd=0 decDigitsFromDPD(dn, sourar, need); // process declets return dn; } // decimal64ToNumber /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decimal64ToString(d64, string); */ /* decimal64ToEngString(d64, string); */ /* */ /* d64 is the decimal64 format number to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least 24 characters */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decimal64ToEngString(const decimal64 *d64, char *string){ decNumber dn; // work decimal64ToNumber(d64, &dn); decNumberToEngString(&dn, string); return string; } // decimal64ToEngString char * decimal64ToString(const decimal64 *d64, char *string){ uInt msd; // coefficient MSD Int exp; // exponent top two bits or full uInt comb; // combination field char *cstart; // coefficient start char *c; // output pointer in string uInt *pu; // work char *s, *t; // .. (source, target) Int dpd; // .. Int pre, e; // .. const uByte *u; // .. uInt sourar[2]; // source 64-bit #define sourhi sourar[1] // name the word with the sign #define sourlo sourar[0] // and the lower word // load source from storage; this may be endian, or not #if DECENDIAN // DECENDIAN -- direct load, in the right order pu=(uInt *)d64->bytes; // overlay if (LITEND) { sourlo=pu[0]; // directly load the low int sourhi=pu[1]; // then the high int } else { sourhi=pu[0]; // directly load the high int sourlo=pu[1]; // then the low int } #else // not DECENDIAN -- use network byte order if (LITEND) { // little-endian needs reversal const uByte *pb; // work Int off; // .. for (pb=d64->bytes; pb<=&d64->bytes[7]; pb++) { off=1-((pb-d64->bytes)>>2); // 1 then 0 sourar[off]<<=8; sourar[off]|=*pb; } // i } else { // big-endian; it's the right way round already pu=(uInt *)d64->bytes; // overlay sourhi=pu[0]; // directly load the high int sourlo=pu[1]; // then the low int } #endif c=string; // where result will go if (((Int)sourhi)<0) *c++='-'; // handle sign comb=(sourhi>>26)&0x1f; // combination field msd=COMBMSD[comb]; // decode the combination field exp=COMBEXP[comb]; // .. if (exp==3) { if (msd==0) { // infinity strcpy(c, "Infinity"); return string; // easy } if (sourhi&0x02000000) *c++='s'; // sNaN strcpy(c, "NaN"); // complete word c+=3; // step past if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; // zero payload // otherwise drop through to add integer; set correct exp exp=0; msd=0; // setup for following code } else exp=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; // convert 16 digits of significand to characters cstart=c; // save start of coefficient if (msd) *c++='0'+(char)msd; // non-zero most significant digit // Now decode the declets. After extracting each one, it is // decoded to binary and then to a 4-char sequence by table lookup; // the 4-chars are a 1-char length (significant digits, except 000 // has length 0). This allows us to left-align the first declet // with non-zero content, then remaining ones are full 3-char // length. We use fixed-length memcpys because variable-length // causes a subroutine call in GCC. (These are length 4 for speed // and are safe because the array has an extra terminator byte.) #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \ if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \ else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;} dpd=(sourhi>>8)&0x3ff; // declet 1 dpd2char; dpd=((sourhi&0xff)<<2) | (sourlo>>30); // declet 2 dpd2char; dpd=(sourlo>>20)&0x3ff; // declet 3 dpd2char; dpd=(sourlo>>10)&0x3ff; // declet 4 dpd2char; dpd=(sourlo)&0x3ff; // declet 5 dpd2char; if (c==cstart) *c++='0'; // all zeros -- make 0 if (exp==0) { // integer or NaN case -- easy *c='\0'; // terminate return string; } /* non-0 exponent */ e=0; // assume no E pre=c-cstart+exp; // [here, pre-exp is the digits count (==1 for zero)] if (exp>0 || pre<-5) { // need exponential form e=pre-1; // calculate E value pre=1; // assume one digit before '.' } // exponential form /* modify the coefficient, adding 0s, '.', and E+nn as needed */ s=c-1; // source (LSD) if (pre>0) { // ddd.ddd (plain), perhaps with E char *dotat=cstart+pre; if (dotat=dotat; s--, t--) *t=*s; // open the gap; leave t at gap *t='.'; // insert the dot c++; // length increased by one } // finally add the E-part, if needed; it will never be 0, and has // a maximum length of 3 digits if (e!=0) { *c++='E'; // starts with E *c++='+'; // assume positive if (e<0) { *(c-1)='-'; // oops, need '-' e=-e; // uInt, please } u=&BIN2CHAR[e*4]; // -> length byte memcpy(c, u+4-*u, 4); // copy fixed 4 characters [is safe] c+=*u; // bump pointer appropriately } *c='\0'; // add terminator //printf("res %s\n", string); return string; } // pre>0 /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */ t=c+1-pre; *(t+1)='\0'; // can add terminator now for (; s>=cstart; s--, t--) *t=*s; // shift whole coefficient right c=cstart; *c++='0'; // always starts with 0. *c++='.'; for (; pre<0; pre++) *c++='0'; // add any 0's after '.' //printf("res %s\n", string); return string; } // decimal64ToString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decimal64FromString(result, string, set); */ /* */ /* result is the decimal64 format number which gets the result of */ /* the conversion */ /* *string is the character string which should contain a valid */ /* number (which may be a special value) */ /* set is the context */ /* */ /* The context is supplied to this routine is used for error handling */ /* (setting of status and traps) and for the rounding mode, only. */ /* If an error occurs, the result will be a valid decimal64 NaN. */ /* ------------------------------------------------------------------ */ decimal64 * decimal64FromString(decimal64 *result, const char *string, decContext *set) { decContext dc; // work decNumber dn; // .. decContextDefault(&dc, DEC_INIT_DECIMAL64); // no traps, please dc.round=set->round; // use supplied rounding decNumberFromString(&dn, string, &dc); // will round if needed decimal64FromNumber(result, &dn, &dc); if (dc.status!=0) { // something happened decContextSetStatus(set, dc.status); // .. pass it on } return result; } // decimal64FromString #if DECTRACE || DECCHECK /* ------------------------------------------------------------------ */ /* decimal64Show -- display a decimal64 in hexadecimal [debug aid] */ /* d64 -- the number to show */ /* ------------------------------------------------------------------ */ // Also shows sign/cob/expconfields extracted void decimal64Show(const decimal64 *d64) { char buf[DECIMAL64_Bytes*2+1]; Int i, j=0; #if DECENDIAN if (LITEND) { for (i=0; ibytes[7-i]); } printf(" D64> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf, d64->bytes[7]>>7, (d64->bytes[7]>>2)&0x1f, ((d64->bytes[7]&0x3)<<6)| (d64->bytes[6]>>2)); } else { #endif for (i=0; ibytes[i]); } printf(" D64> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf, decimal64Sign(d64), decimal64Comb(d64), decimal64ExpCon(d64)); #if DECENDIAN } #endif } // decimal64Show #endif /* ================================================================== */ /* Shared utility routines and tables */ /* ================================================================== */ // define and include the conversion tables to use for shared code #if DECDPUN==3 #define DEC_DPD2BIN 1 #else #define DEC_DPD2BCD 1 #endif #include "decDPD.h" // lookup tables // The maximum number of decNumberUnits needed for a working copy of // the units array is the ceiling of digits/DECDPUN, where digits is // the maximum number of digits in any of the formats for which this // is used. decimal128.h must not be included in this module, so, as // a very special case, that number is defined as a literal here. #define DECMAX754 34 #define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN) /* ------------------------------------------------------------------ */ /* Combination field lookup tables (uInts to save measurable work) */ /* */ /* COMBEXP - 2-bit most-significant-bits of exponent */ /* [11 if an Infinity or NaN] */ /* COMBMSD - 4-bit most-significant-digit */ /* [0=Infinity, 1=NaN if COMBEXP=11] */ /* */ /* Both are indexed by the 5-bit combination field (0-31) */ /* ------------------------------------------------------------------ */ const uInt COMBEXP[32]={0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 2, 2, 3, 3}; const uInt COMBMSD[32]={0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, 0, 1}; /* ------------------------------------------------------------------ */ /* decDigitsToDPD -- pack coefficient into DPD form */ /* */ /* dn is the source number (assumed valid, max DECMAX754 digits) */ /* targ is 1, 2, or 4-element uInt array, which the caller must */ /* have cleared to zeros */ /* shift is the number of 0 digits to add on the right (normally 0) */ /* */ /* The coefficient must be known small enough to fit. The full */ /* coefficient is copied, including the leading 'odd' digit. This */ /* digit is retrieved and packed into the combination field by the */ /* caller. */ /* */ /* The target uInts are altered only as necessary to receive the */ /* digits of the decNumber. When more than one uInt is needed, they */ /* are filled from left to right (that is, the uInt at offset 0 will */ /* end up with the least-significant digits). */ /* */ /* shift is used for 'fold-down' padding. */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */ #if DECDPUN<=4 // Constant multipliers for divide-by-power-of five using reciprocal // multiply, after removing powers of 2 by shifting, and final shift // of 17 [we only need up to **4] static const uInt multies[]={131073, 26215, 5243, 1049, 210}; // QUOT10 -- macro to return the quotient of unit u divided by 10**n #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17) #endif void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) { Int cut; // work Int n; // output bunch counter Int digits=dn->digits; // digit countdown uInt dpd; // densely packed decimal value uInt bin; // binary value 0-999 uInt *uout=targ; // -> current output uInt uInt uoff=0; // -> current output offset [from right] const Unit *inu=dn->lsu; // -> current input unit Unit uar[DECMAXUNITS]; // working copy of units, iff shifted #if DECDPUN!=3 // not fast path Unit in; // current unit #endif if (shift!=0) { // shift towards most significant required // shift the units array to the left by pad digits and copy // [this code is a special case of decShiftToMost, which could // be used instead if exposed and the array were copied first] const Unit *source; // .. Unit *target, *first; // .. uInt next=0; // work source=dn->lsu+D2U(digits)-1; // where msu comes from target=uar+D2U(digits)-1+D2U(shift);// where upper part of first cut goes cut=DECDPUN-MSUDIGITS(shift); // where to slice if (cut==0) { // unit-boundary case for (; source>=dn->lsu; source--, target--) *target=*source; } else { first=uar+D2U(digits+shift)-1; // where msu will end up for (; source>=dn->lsu; source--, target--) { // split the source Unit and accumulate remainder for next #if DECDPUN<=4 uInt quot=QUOT10(*source, cut); uInt rem=*source-quot*powers[cut]; next+=quot; #else uInt rem=*source%powers[cut]; next+=*source/powers[cut]; #endif if (target<=first) *target=(Unit)next; // write to target iff valid next=rem*powers[DECDPUN-cut]; // save remainder for next Unit } } // shift-move // propagate remainder to one below and clear the rest for (; target>=uar; target--) { *target=(Unit)next; next=0; } digits+=shift; // add count (shift) of zeros added inu=uar; // use units in working array } /* now densely pack the coefficient into DPD declets */ #if DECDPUN!=3 // not fast path in=*inu; // current unit cut=0; // at lowest digit bin=0; // [keep compiler quiet] #endif for(n=0; digits>0; n++) { // each output bunch #if DECDPUN==3 // fast path, 3-at-a-time bin=*inu; // 3 digits ready for convert digits-=3; // [may go negative] inu++; // may need another #else // must collect digit-by-digit Unit dig; // current digit Int j; // digit-in-declet count for (j=0; j<3; j++) { #if DECDPUN<=4 Unit temp=(Unit)((uInt)(in*6554)>>16); dig=(Unit)(in-X10(temp)); in=temp; #else dig=in%10; in=in/10; #endif if (j==0) bin=dig; else if (j==1) bin+=X10(dig); else /* j==2 */ bin+=X100(dig); digits--; if (digits==0) break; // [also protects *inu below] cut++; if (cut==DECDPUN) {inu++; in=*inu; cut=0;} } #endif // here there are 3 digits in bin, or have used all input digits dpd=BIN2DPD[bin]; // write declet to uInt array *uout|=dpd<>(10-uoff); // collect top bits } // n declets return; } // decDigitsToDPD /* ------------------------------------------------------------------ */ /* decDigitsFromDPD -- unpack a format's coefficient */ /* */ /* dn is the target number, with 7, 16, or 34-digit space. */ /* sour is a 1, 2, or 4-element uInt array containing only declets */ /* declets is the number of (right-aligned) declets in sour to */ /* be processed. This may be 1 more than the obvious number in */ /* a format, as any top digit is prefixed to the coefficient */ /* continuation field. It also may be as small as 1, as the */ /* caller may pre-process leading zero declets. */ /* */ /* When doing the 'extra declet' case care is taken to avoid writing */ /* extra digits when there are leading zeros, as these could overflow */ /* the units array when DECDPUN is not 3. */ /* */ /* The target uInts are used only as necessary to process declets */ /* declets into the decNumber. When more than one uInt is needed, */ /* they are used from left to right (that is, the uInt at offset 0 */ /* provides the least-significant digits). */ /* */ /* dn->digits is set, but not the sign or exponent. */ /* No error is possible [the redundant 888 codes are allowed]. */ /* ------------------------------------------------------------------ */ void decDigitsFromDPD(decNumber *dn, const uInt *sour, Int declets) { uInt dpd; // collector for 10 bits Int n; // counter Unit *uout=dn->lsu; // -> current output unit Unit *last=uout; // will be unit containing msd const uInt *uin=sour; // -> current input uInt uInt uoff=0; // -> current input offset [from right] #if DECDPUN!=3 uInt bcd; // BCD result uInt nibble; // work Unit out=0; // accumulator Int cut=0; // power of ten in current unit #endif #if DECDPUN>4 uInt const *pow; // work #endif // Expand the densely-packed integer, right to left for (n=declets-1; n>=0; n--) { // count down declets of 10 bits dpd=*uin>>uoff; uoff+=10; if (uoff>32) { // crossed uInt boundary uin++; uoff-=32; dpd|=*uin<<(10-uoff); // get waiting bits } dpd&=0x3ff; // clear uninteresting bits #if DECDPUN==3 if (dpd==0) *uout=0; else { *uout=DPD2BIN[dpd]; // convert 10 bits to binary 0-999 last=uout; // record most significant unit } uout++; } // n #else // DECDPUN!=3 if (dpd==0) { // fastpath [e.g., leading zeros] // write out three 0 digits (nibbles); out may have digit(s) cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} if (n==0) break; // [as below, works even if MSD=0] cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} continue; } bcd=DPD2BCD[dpd]; // convert 10 bits to 12 bits BCD // now accumulate the 3 BCD nibbles into units nibble=bcd & 0x00f; if (nibble) out=(Unit)(out+nibble*powers[cut]); cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} bcd>>=4; // if this is the last declet and the remaining nibbles in bcd // are 00 then process no more nibbles, because this could be // the 'odd' MSD declet and writing any more Units would then // overflow the unit array if (n==0 && !bcd) break; nibble=bcd & 0x00f; if (nibble) out=(Unit)(out+nibble*powers[cut]); cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} bcd>>=4; nibble=bcd & 0x00f; if (nibble) out=(Unit)(out+nibble*powers[cut]); cut++; if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;} } // n if (cut!=0) { // some more left over *uout=out; // write out final unit if (out) last=uout; // and note if non-zero } #endif // here, last points to the most significant unit with digits; // inspect it to get the final digits count -- this is essentially // the same code as decGetDigits in decNumber.c dn->digits=(last-dn->lsu)*DECDPUN+1; // floor of digits, plus // must be at least 1 digit #if DECDPUN>1 if (*last<10) return; // common odd digit or 0 dn->digits++; // must be 2 at least #if DECDPUN>2 if (*last<100) return; // 10-99 dn->digits++; // must be 3 at least #if DECDPUN>3 if (*last<1000) return; // 100-999 dn->digits++; // must be 4 at least #if DECDPUN>4 for (pow=&powers[4]; *last>=*pow; pow++) dn->digits++; #endif #endif #endif #endif return; } //decDigitsFromDPD hercules-3.12/decNumber/decNumber.c0000664000175000017500000114456712564723224014201 00000000000000/* ------------------------------------------------------------------ */ /* Decimal Number arithmetic module */ /* ------------------------------------------------------------------ */ /* Copyright (c) IBM Corporation, 2000, 2006. All rights reserved. */ /* */ /* This software is made available under the terms of the */ /* ICU License -- ICU 1.8.1 and later. */ /* */ /* The description and User's Guide ("The decNumber C Library") for */ /* this software is called decNumber.pdf. This document is */ /* available, together with arithmetic and format specifications, */ /* testcases, and Web links, at: http://www2.hursley.ibm.com/decimal */ /* */ /* Please send comments, suggestions, and corrections to the author: */ /* mfc@uk.ibm.com */ /* Mike Cowlishaw, IBM Fellow */ /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ /* ------------------------------------------------------------------ */ /* This module comprises the routines for General Decimal Arithmetic */ /* as defined in the specification which may be found on the */ /* http://www2.hursley.ibm.com/decimal web pages. It implements both */ /* the full ('extended') arithmetic and the simpler ('subset') */ /* arithmetic. */ /* */ /* Usage notes: */ /* */ /* 1. This code is ANSI C89 except: */ /* */ /* a) C99 line comments (double forward slash) are used. (Most C */ /* compilers accept these. If yours does not, a simple script */ /* can be used to convert them to ANSI C comments.) */ /* */ /* b) Types from C99 stdint.h are used. If you do not have this */ /* header file, see the User's Guide section of the decNumber */ /* documentation; this lists the necessary definitions. */ /* */ /* c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */ /* uint64_t types may be used. To avoid these, set DECUSE64=0 */ /* and DECDPUN<=4 (see documentation). */ /* */ /* 2. The decNumber format which this library uses is optimized for */ /* efficient processing of relatively short numbers; in particular */ /* it allows the use of fixed sized structures and minimizes copy */ /* and move operations. It does, however, support arbitrary */ /* precision (up to 999,999,999 digits) and arbitrary exponent */ /* range (Emax in the range 0 through 999,999,999 and Emin in the */ /* range -999,999,999 through 0). Mathematical functions (for */ /* example decNumberExp) as identified below are restricted more */ /* tightly: digits, emax, and -emin in the context must be <= */ /* DEC_MAX_MATH (999999), and their operand(s) must be within */ /* these bounds. */ /* */ /* 3. Operands to operator functions are never modified unless they */ /* are also specified to be the result number (which is always */ /* permitted). Other than that case, operands must not overlap. */ /* */ /* 4. Error handling: the type of the error is ORed into the status */ /* flags in the current context (decContext structure). The */ /* SIGFPE signal is then raised if the corresponding trap-enabler */ /* flag in the decContext is set (is 1). */ /* */ /* It is the responsibility of the caller to clear the status */ /* flags as required. */ /* */ /* The result of any routine which returns a number will always */ /* be a valid number (which may be a special value, such as an */ /* Infinity or NaN). */ /* */ /* 5. The decNumber format is not an exchangeable concrete */ /* representation as it comprises fields which may be machine- */ /* dependent (packed or unpacked, or special length, for example). */ /* Canonical conversions to and from strings are provided; other */ /* conversions are available in separate modules. */ /* */ /* 6. Normally, input operands are assumed to be valid. Set DECCHECK */ /* to 1 for extended operand checking (including NULL operands). */ /* Results are undefined if a badly-formed structure (or a NULL */ /* pointer to a structure) is provided, though with DECCHECK */ /* enabled the operator routines are protected against exceptions. */ /* (Except if the result pointer is NULL, which is unrecoverable.) */ /* */ /* However, the routines will never cause exceptions if they are */ /* given well-formed operands, even if the value of the operands */ /* is inappropriate for the operation and DECCHECK is not set. */ /* (Except for SIGFPE, as and where documented.) */ /* */ /* 7. Subset arithmetic is available only if DECSUBSET is set to 1. */ /* ------------------------------------------------------------------ */ /* Implementation notes for maintenance of this module: */ /* */ /* 1. Storage leak protection: Routines which use malloc are not */ /* permitted to use return for fastpath or error exits (i.e., */ /* they follow strict structured programming conventions). */ /* Instead they have a do{}while(0); construct surrounding the */ /* code which is protected -- break may be used to exit this. */ /* Other routines can safely use the return statement inline. */ /* */ /* Storage leak accounting can be enabled using DECALLOC. */ /* */ /* 2. All loops use the for(;;) construct. Any do construct does */ /* not loop; it is for allocation protection as just described. */ /* */ /* 3. Setting status in the context must always be the very last */ /* action in a routine, as non-0 status may raise a trap and hence */ /* the call to set status may not return (if the handler uses long */ /* jump). Therefore all cleanup must be done first. In general, */ /* to achieve this status is accumulated and is only applied just */ /* before return by calling decContextSetStatus (via decStatus). */ /* */ /* Routines which allocate storage cannot, in general, use the */ /* 'top level' routines which could cause a non-returning */ /* transfer of control. The decXxxxOp routines are safe (do not */ /* call decStatus even if traps are set in the context) and should */ /* be used instead (they are also a little faster). */ /* */ /* 4. Exponent checking is minimized by allowing the exponent to */ /* grow outside its limits during calculations, provided that */ /* the decFinalize function is called later. Multiplication and */ /* division, and intermediate calculations in exponentiation, */ /* require more careful checks because of the risk of 31-bit */ /* overflow (the most negative valid exponent is -1999999997, for */ /* a 999999999-digit number with adjusted exponent of -999999999). */ /* */ /* 5. Rounding is deferred until finalization of results, with any */ /* 'off to the right' data being represented as a single digit */ /* residue (in the range -1 through 9). This avoids any double- */ /* rounding when more than one shortening takes place (for */ /* example, when a result is subnormal). */ /* */ /* 6. The digits count is allowed to rise to a multiple of DECDPUN */ /* during many operations, so whole Units are handled and exact */ /* accounting of digits is not needed. The correct digits value */ /* is found by decGetDigits, which accounts for leading zeros. */ /* This must be called before any rounding if the number of digits */ /* is not known exactly. */ /* */ /* 7. The multiply-by-reciprocal 'trick' is used for partitioning */ /* numbers up to four digits, using appropriate constants. This */ /* is not useful for longer numbers because overflow of 32 bits */ /* would lead to 4 multiplies, which is almost as expensive as */ /* a divide (unless a floating-point or 64-bit multiply is */ /* assumed to be available). */ /* */ /* 8. Unusual abbreviations that may be used in the commentary: */ /* lhs -- left hand side (operand, of an operation) */ /* lsd -- least significant digit (of coefficient) */ /* lsu -- least significant Unit (of coefficient) */ /* msd -- most significant digit (of coefficient) */ /* msi -- most significant item (in an array) */ /* msu -- most significant Unit (of coefficient) */ /* rhs -- right hand side (operand, of an operation) */ /* +ve -- positive */ /* -ve -- negative */ /* ** -- raise to the power */ /* ------------------------------------------------------------------ */ #include // for malloc, free, etc. #include // for printf [if needed] #include // for strcpy #include // for lower #if defined(_MSVC_) #pragma warning(disable:4244) // [for win64] #endif /*defined(_MSVC_)*/ #include "decNumber.h" // base number library #include "decNumberLocal.h" // decNumber local types, etc. /* Constants */ // Public constant array: powers of ten (powers[n]==10**n, 0<=n<=9) const uInt powers[10]={1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; // Public lookup table used by the D2U macro const uByte d2utable[DECMAXD2U+1]=D2UTABLE; // Local constants #define DIVIDE 0x80 // Divide operators #define REMAINDER 0x40 // .. #define DIVIDEINT 0x20 // .. #define REMNEAR 0x10 // .. #define COMPARE 0x01 // Compare operators #define COMPMAX 0x02 // .. #define COMPMIN 0x03 // .. #define COMPTOTAL 0x04 // .. #define COMPNAN 0x05 // .. [NaN processing] #define DEC_sNaN 0x40000000 // local status: sNaN signal #define BADINT (Int)0x80000000 // most-negative Int; error indicator // Next two indicate an integer >= 10**6, and its parity (bottom bit) #define BIGEVEN (Int)0x80000002 #define BIGODD (Int)0x80000003 static Unit uarrone[1]={1}; // Unit array of 1, used for incrementing /* Granularity-dependent code */ #if DECDPUN<=4 #define eInt Int // extended integer #define ueInt uInt // unsigned extended integer // Constant multipliers for divide-by-power-of five using reciprocal // multiply, after removing powers of 2 by shifting, and final shift // of 17 [we only need up to **4] static const uInt multies[]={131073, 26215, 5243, 1049, 210}; // QUOT10 -- macro to return the quotient of unit u divided by 10**n #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17) #else // For DECDPUN>4 non-ANSI-89 64-bit types are needed. #if !DECUSE64 #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4 #endif #define eInt Long // extended integer #define ueInt uLong // unsigned extended integer #endif /* Local routines */ static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *, decContext *, uByte, uInt *); static Flag decBiStr(const char *, const char *, const char *); static uInt decCheckMath(const decNumber *, decContext *, uInt *); static void decApplyRound(decNumber *, decContext *, Int, uInt *); static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag); static decNumber * decCompareOp(decNumber *, const decNumber *, const decNumber *, decContext *, Flag, uInt *); static void decCopyFit(decNumber *, const decNumber *, decContext *, Int *, uInt *); static decNumber * decDivideOp(decNumber *, const decNumber *, const decNumber *, decContext *, Flag, uInt *); static decNumber * decExpOp(decNumber *, const decNumber *, decContext *, uInt *); static void decFinalize(decNumber *, decContext *, Int *, uInt *); static Int decGetDigits(Unit *, Int); static Int decGetInt(const decNumber *); static decNumber * decLnOp(decNumber *, const decNumber *, decContext *, uInt *); static decNumber * decMultiplyOp(decNumber *, const decNumber *, const decNumber *, decContext *, uInt *); static decNumber * decNaNs(decNumber *, const decNumber *, const decNumber *, uInt *); static decNumber * decPutInt(decNumber *, Int); static decNumber * decQuantizeOp(decNumber *, const decNumber *, const decNumber *, decContext *, Flag, uInt *); static void decSetCoeff(decNumber *, decContext *, const Unit *, Int, Int *, uInt *); static void decSetOverflow(decNumber *, decContext *, uInt *); static void decSetSubnormal(decNumber *, decContext *, Int *, uInt *); static Int decShiftToLeast(Unit *, Int, Int); static Int decShiftToMost(Unit *, Int, Int); static void decStatus(decNumber *, uInt, decContext *); static void decToString(const decNumber *, char[], Flag); static decNumber * decTrim(decNumber *, Flag, Int *); static Int decUnitAddSub(const Unit *, Int, const Unit *, Int, Int, Unit *, Int); static Int decUnitCompare(const Unit *, Int, const Unit *, Int, Int); #if !DECSUBSET /* decFinish == decFinalize when no subset arithmetic needed */ #define decFinish(a,b,c,d) decFinalize(a,b,c,d) #else static void decFinish(decNumber *, decContext *, Int *, uInt *); static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *); #endif /* Local macros */ // masked special-values bits #define SPECIALARG (rhs->bits & DECSPECIAL) #define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL) /* Diagnostic macros, etc. */ #if DECALLOC // Handle malloc/free accounting. If enabled, our accountable routines // are used; otherwise the code just goes straight to the system malloc // and free routines. #define malloc(a) decMalloc(a) #define free(a) decFree(a) #define DECFENCE 0x5a // corruption detector // 'Our' malloc and free: static void *decMalloc(size_t); static void decFree(void *); uInt decAllocBytes=0; // count of bytes allocated // Note that DECALLOC code only checks for storage buffer overflow. // To check for memory leaks, the decAllocBytes variable must be // checked to be 0 at appropriate times (e.g., after the test // harness completes a set of tests). This checking may be unreliable // if the testing is done in a multi-thread environment. #endif #if DECCHECK // Optional checking routines. Enabling these means that decNumber // and decContext operands to operator routines are checked for // correctness. This roughly doubles the execution time of the // fastest routines (and adds 600+ bytes), so should not normally be // used in 'production'. // decCheckInexact is used to check that inexact results have a full // complement of digits (where appropriate -- this is not the case // for Quantize, for example) #define DECUNUSED (void *)(0xffffffff) static Flag decCheckOperands(decNumber *, const decNumber *, const decNumber *, decContext *); static Flag decCheckNumber(const decNumber *, decContext *); static void decCheckInexact(const decNumber *, decContext *); #endif #if DECTRACE || DECCHECK // Optional trace/debugging routines (may or may not be used) void decNumberShow(const decNumber *); // displays the components of a number static void decDumpAr(char, const Unit *, Int); #endif /* ================================================================== */ /* Conversions */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decNumberToString(dn, string); */ /* decNumberToEngString(dn, string); */ /* */ /* dn is the decNumber to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least dn->digits+14 characters long */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */ char * decNumberToString(const decNumber *dn, char *string){ decToString(dn, string, 0); return string; } // DecNumberToString char * decNumberToEngString(const decNumber *dn, char *string){ decToString(dn, string, 1); return string; } // DecNumberToEngString /* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decNumberFromString -- convert string to decNumber */ /* dn -- the number structure to fill */ /* chars[] -- the string to convert ('\0' terminated) */ /* set -- the context used for processing any error, */ /* determining the maximum precision available */ /* (set.digits), determining the maximum and minimum */ /* exponent (set.emax and set.emin), determining if */ /* extended values are allowed, and checking the */ /* rounding mode if overflow occurs or rounding is */ /* needed. */ /* */ /* The length of the coefficient and the size of the exponent are */ /* checked by this routine, so the correct error (Underflow or */ /* Overflow) can be reported or rounding applied, as necessary. */ /* */ /* If bad syntax is detected, the result will be a quiet NaN. */ /* ------------------------------------------------------------------ */ decNumber * decNumberFromString(decNumber *dn, const char chars[], decContext *set) { Int exponent=0; // working exponent [assume 0] uByte bits=0; // working flags [assume +ve] Unit *res; // where result will be built Unit resbuff[SD2U(DECBUFFER+1)];// local buffer in case need temporary Unit *allocres=NULL; // -> allocated result, iff allocated Int d=0; // count of digits found in decimal part const char *dotchar=NULL; // where dot was found const char *cfirst=chars; // -> first character of decimal part const char *last=NULL; // -> last digit of decimal part const char *c; // work Unit *up; // .. #if DECDPUN>1 Int cut, out; // .. #endif Int residue; // rounding residue uInt status=0; // error code #if DECCHECK if (decCheckOperands(DECUNUSED, DECUNUSED, DECUNUSED, set)) return decNumberZero(dn); #endif do { // status & malloc protection for (c=chars;; c++) { // -> input character if (*c>='0' && *c<='9') { // test for Arabic digit last=c; d++; // count of real digits continue; // still in decimal part } if (*c=='.' && dotchar==NULL) { // first '.' dotchar=c; // record offset into decimal part if (c==cfirst) cfirst++; // first digit must follow continue;} if (c==chars) { // first in string... if (*c=='-') { // valid - sign cfirst++; bits=DECNEG; continue;} if (*c=='+') { // valid + sign cfirst++; continue;} } // *c is not a digit, or a valid +, -, or '.' break; } // c if (last==NULL) { // no digits yet status=DEC_Conversion_syntax;// assume the worst if (*c=='\0') break; // and no more to come... #if DECSUBSET // if subset then infinities and NaNs are not allowed if (!set->extended) break; // hopeless #endif // Infinities and NaNs are possible, here if (dotchar!=NULL) break; // .. unless had a dot decNumberZero(dn); // be optimistic if (decBiStr(c, "infinity", "INFINITY") || decBiStr(c, "inf", "INF")) { dn->bits=bits | DECINF; status=0; // is OK break; // all done } // a NaN expected // 2003.09.10 NaNs are now permitted to have a sign dn->bits=bits | DECNAN; // assume simple NaN if (*c=='s' || *c=='S') { // looks like an sNaN c++; dn->bits=bits | DECSNAN; } if (*c!='n' && *c!='N') break; // check caseless "NaN" c++; if (*c!='a' && *c!='A') break; // .. c++; if (*c!='n' && *c!='N') break; // .. c++; // now either nothing, or nnnn payload, expected // -> start of integer and skip leading 0s [including plain 0] for (cfirst=c; *cfirst=='0';) cfirst++; if (*cfirst=='\0') { // "NaN" or "sNaN", maybe with all 0s status=0; // it's good break; // .. } // something other than 0s; setup last and d as usual [no dots] for (c=cfirst;; c++, d++) { if (*c<'0' || *c>'9') break; // test for Arabic digit last=c; } if (*c!='\0') break; // not all digits if (d>set->digits-1) { // [NB: payload in a decNumber can be full length unless // clamped, in which case can only be digits-1] if (set->clamp) break; if (d>set->digits) break; } // too many digits? // good; drop through to convert the integer to coefficient status=0; // syntax is OK bits=dn->bits; // for copy-back } // last==NULL else if (*c!='\0') { // more to process... // had some digits; exponent is only valid sequence now Flag nege; // 1=negative exponent const char *firstexp; // -> first significant exponent digit status=DEC_Conversion_syntax;// assume the worst if (*c!='e' && *c!='E') break; /* Found 'e' or 'E' -- now process explicit exponent */ // 1998.07.11: sign no longer required nege=0; c++; // to (possible) sign if (*c=='-') {nege=1; c++;} else if (*c=='+') c++; if (*c=='\0') break; for (; *c=='0' && *(c+1)!='\0';) c++; // strip insignificant zeros firstexp=c; // save exponent digit place for (; ;c++) { if (*c<'0' || *c>'9') break; // not a digit exponent=X10(exponent)+(Int)*c-(Int)'0'; } // c // if not now on a '\0', *c must not be a digit if (*c!='\0') break; // (this next test must be after the syntax checks) // if it was too long the exponent may have wrapped, so check // carefully and set it to a certain overflow if wrap possible if (c>=firstexp+9+1) { if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2; // [up to 1999999999 is OK, for example 1E-1000000998] } if (nege) exponent=-exponent; // was negative status=0; // is OK } // stuff after digits // Here when whole string has been inspected; syntax is good // cfirst->first digit (never dot), last->last digit (ditto) // strip leading zeros/dot [leave final 0 if all 0's] if (*cfirst=='0') { // [cfirst has stepped over .] for (c=cfirst; cextended) { decNumberZero(dn); // clean result break; // [could be return] } #endif } // at least one leading 0 // Handle decimal point... if (dotchar!=NULL && dotchardigits) res=dn->lsu; // fits into supplied decNumber else { // rounding needed Int needbytes=D2U(d)*sizeof(Unit);// bytes needed res=resbuff; // assume use local buffer if (needbytes>(Int)sizeof(resbuff)) { // too big for local allocres=(Unit *)malloc(needbytes); if (allocres==NULL) {status|=DEC_Insufficient_storage; break;} res=allocres; } } // res now -> number lsu, buffer, or allocated storage for Unit array // Place the coefficient into the selected Unit array // [this is often 70% of the cost of this function when DECDPUN>1] #if DECDPUN>1 out=0; // accumulator up=res+D2U(d)-1; // -> msu cut=d-(up-res)*DECDPUN; // digits in top unit for (c=cfirst;; c++) { // along the digits if (*c=='.') continue; // ignore '.' [don't decrement cut] out=X10(out)+(Int)*c-(Int)'0'; if (c==last) break; // done [never get to trailing '.'] cut--; if (cut>0) continue; // more for this unit *up=(Unit)out; // write unit up--; // prepare for unit below.. cut=DECDPUN; // .. out=0; // .. } // c *up=(Unit)out; // write lsu #else // DECDPUN==1 up=res; // -> lsu for (c=last; c>=cfirst; c--) { // over each character, from least if (*c=='.') continue; // ignore . [don't step up] *up=(Unit)((Int)*c-(Int)'0'); up++; } // c #endif dn->bits=bits; dn->exponent=exponent; dn->digits=d; // if not in number (too long) shorten into the number if (d>set->digits) { residue=0; decSetCoeff(dn, set, res, d, &residue, &status); // always check for overflow or subnormal and round as needed decFinalize(dn, set, &residue, &status); } else { // no rounding, but may still have overflow or subnormal // [these tests are just for performance; finalize repeats them] if ((dn->exponent-1emin-dn->digits) || (dn->exponent-1>set->emax-set->digits)) { residue=0; decFinalize(dn, set, &residue, &status); } } // decNumberShow(dn); } while(0); // [for break] if (allocres!=NULL) free(allocres); // drop any storage used if (status!=0) decStatus(dn, status, set); return dn; } /* decNumberFromString */ /* ================================================================== */ /* Operators */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* decNumberAbs -- absolute value operator */ /* */ /* This computes C = abs(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This has the same effect as decNumberPlus unless A is negative, */ /* in which case it has the same effect as decNumberMinus. */ /* ------------------------------------------------------------------ */ decNumber * decNumberAbs(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dzero; // for 0 uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif decNumberZero(&dzero); // set 0 dzero.exponent=rhs->exponent; // [no coefficient expansion] decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberAbs /* ------------------------------------------------------------------ */ /* decNumberAdd -- add two Numbers */ /* */ /* This computes C = A + B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X+X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This just calls the routine shared with Subtract */ decNumber * decNumberAdd(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decAddOp(res, lhs, rhs, set, 0, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberAdd /* ------------------------------------------------------------------ */ /* decNumberCompare -- compare two Numbers */ /* */ /* This computes C = A ? B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit (or NaN). */ /* ------------------------------------------------------------------ */ decNumber * decNumberCompare(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPARE, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberCompare /* ------------------------------------------------------------------ */ /* decNumberCompareTotal -- compare two Numbers, using total ordering */ /* */ /* This computes C = A ? B, under total ordering */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit; the result will always be one of */ /* -1, 0, or 1. */ /* ------------------------------------------------------------------ */ decNumber * decNumberCompareTotal(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberCompareTotal /* ------------------------------------------------------------------ */ /* decNumberDivide -- divide one number by another */ /* */ /* This computes C = A / B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X/X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberDivide(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, DIVIDE, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberDivide /* ------------------------------------------------------------------ */ /* decNumberDivideInteger -- divide and return integer quotient */ /* */ /* This computes C = A # B, where # is the integer divide operator */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X#X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberDivideInteger(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberDivideInteger /* ------------------------------------------------------------------ */ /* decNumberExp -- exponentiation */ /* */ /* This computes C = exp(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* Finite results will always be full precision and Inexact, except */ /* when A is a zero or -Infinity (giving 1 or 0 respectively). */ /* */ /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* This is a wrapper for decExpOp which can handle the slightly wider */ /* (double) range needed by Ln (which has to be able to calculate */ /* exp(-a) where a can be the tiniest number (Ntiny). */ /* ------------------------------------------------------------------ */ decNumber * decNumberExp(decNumber *res, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // Check restrictions; these restrictions ensure that if h=8 (see // decExpOp) then the result will either overflow or underflow to 0. // Other math functions restrict the input range, too, for inverses. // If not violated then carry out the operation. if (!decCheckMath(rhs, set, &status)) do { // protect allocation #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif decExpOp(res, rhs, set, &status); } while(0); // end protected #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // drop any storage used #endif // apply significant status if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberExp /* ------------------------------------------------------------------ */ /* decNumberLn -- natural logarithm */ /* */ /* This computes C = ln(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Notable cases: */ /* A<0 -> Invalid */ /* A=0 -> -Infinity (Exact) */ /* A=+Infinity -> +Infinity (Exact) */ /* A=1 exactly -> 0 (Exact) */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* This is a wrapper for decLnOp which can handle the slightly wider */ /* (+11) range needed by Ln, Log10, etc. (which may have to be able */ /* to calculate at p+e+2). */ /* ------------------------------------------------------------------ */ decNumber * decNumberLn(decNumber *res, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // Check restrictions; this is a math function; if not violated // then carry out the operation. if (!decCheckMath(rhs, set, &status)) do { // protect allocation #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } // special check in subset for rhs=0 if (ISZERO(rhs)) { // +/- zeros -> error status|=DEC_Invalid_operation; break;} } // extended=0 #endif decLnOp(res, rhs, set, &status); } while(0); // end protected #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // drop any storage used #endif // apply significant status if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberLn /* ------------------------------------------------------------------ */ /* decNumberLog10 -- logarithm in base 10 */ /* */ /* This computes C = log10(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Notable cases: */ /* A<0 -> Invalid */ /* A=0 -> -Infinity (Exact) */ /* A=+Infinity -> +Infinity (Exact) */ /* A=10**n (if n is an integer) -> n (Exact) */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* This calculates ln(A)/ln(10) using appropriate precision. For */ /* ln(A) this is the max(p, rhs->digits + t) + 3, where p is the */ /* requested digits and t is the number of digits in the exponent */ /* (maximum 6). For ln(10) it is p + 3; this is often handled by the */ /* fastpath in decLnOp. The final division is done to the requested */ /* precision. */ /* ------------------------------------------------------------------ */ decNumber * decNumberLog10(decNumber *res, const decNumber *rhs, decContext *set) { uInt status=0, ignore=0; // status accumulators uInt needbytes; // for space calculations Int p; // working precision Int t; // digits in exponent of A // buffers for a and b working decimals // (adjustment calculator, same size) decNumber bufa[D2N(DECBUFFER+2)]; decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *a=bufa; // temporary a decNumber bufb[D2N(DECBUFFER+2)]; decNumber *allocbufb=NULL; // -> allocated bufa, iff allocated decNumber *b=bufb; // temporary b decNumber bufw[D2N(10)]; // working 2-10 digit number decNumber *w=bufw; // .. #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif decContext aset; // working context #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // Check restrictions; this is a math function; if not violated // then carry out the operation. if (!decCheckMath(rhs, set, &status)) do { // protect malloc #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } // special check in subset for rhs=0 if (ISZERO(rhs)) { // +/- zeros -> error status|=DEC_Invalid_operation; break;} } // extended=0 #endif decContextDefault(&aset, DEC_INIT_DECIMAL64); // clean context // handle exact powers of 10; only check if +ve finite if (!(rhs->bits&(DECNEG|DECSPECIAL)) && !ISZERO(rhs)) { Int residue=0; // (no residue) uInt copystat=0; // clean status // round to a single digit... aset.digits=1; decCopyFit(w, rhs, &aset, &residue, ©stat); // copy & shorten // if exact and the digit is 1, rhs is a power of 10 if (!(copystat&DEC_Inexact) && w->lsu[0]==1) { // the exponent, conveniently, is the power of 10; making // this the result needs a little care as it might not fit, // so first convert it into the working number, and then move // to res decPutInt(w, w->exponent); residue=0; decCopyFit(res, w, set, &residue, &status); // copy & round decFinish(res, set, &residue, &status); // cleanup/set flags break; } // not a power of 10 } // not a candidate for exact // simplify the information-content calculation to use 'total // number of digits in a, including exponent' as compared to the // requested digits, as increasing this will only rarely cost an // iteration in ln(a) anyway t=6; // it can never be >6 // allocate space when needed... p=(rhs->digits+t>set->digits?rhs->digits+t:set->digits)+3; needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space } aset.digits=p; // as calculated aset.emax=DEC_MAX_MATH; // usual bounds aset.emin=-DEC_MAX_MATH; // .. aset.clamp=0; // and no concrete format decLnOp(a, rhs, &aset, &status); // a=ln(rhs) // skip the division if the result so far is infinite, NaN, or // zero, or there was an error; note NaN from sNaN needs copy if (status&DEC_NaNs && !(status&DEC_sNaN)) break; if (a->bits&DECSPECIAL || ISZERO(a)) { decNumberCopy(res, a); // [will fit] break;} // for ln(10) an extra 3 digits of precision are needed p=set->digits+3; needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit); if (needbytes>sizeof(bufb)) { // need malloc space allocbufb=(decNumber *)malloc(needbytes); if (allocbufb==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} b=allocbufb; // use the allocated space } decNumberZero(w); // set up 10... #if DECDPUN==1 w->lsu[1]=1; w->lsu[0]=0; // .. #else w->lsu[0]=10; // .. #endif w->digits=2; // .. aset.digits=p; decLnOp(b, w, &aset, &ignore); // b=ln(10) aset.digits=set->digits; // for final divide decDivideOp(res, a, b, &aset, DIVIDE, &status); // into result } while(0); // [for break] if (allocbufa!=NULL) free(allocbufa); // drop any storage used if (allocbufb!=NULL) free(allocbufb); // .. #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // .. #endif // apply significant status if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberLog10 /* ------------------------------------------------------------------ */ /* decNumberMax -- compare two Numbers and return the maximum */ /* */ /* This computes C = A ? B, returning the maximum or A if equal */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMax(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPMAX, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMax /* ------------------------------------------------------------------ */ /* decNumberMin -- compare two Numbers and return the minimum */ /* */ /* This computes C = A ? B, returning the minimum or A if equal */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMin(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decCompareOp(res, lhs, rhs, set, COMPMIN, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMin /* ------------------------------------------------------------------ */ /* decNumberMinus -- prefix minus operator */ /* */ /* This computes C = 0 - A */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* Simply use AddOp for the subtract, which will do the necessary. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMinus(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dzero; uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif decNumberZero(&dzero); // make 0 dzero.exponent=rhs->exponent; // [no coefficient expansion] decAddOp(res, &dzero, rhs, set, DECNEG, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMinus /* ------------------------------------------------------------------ */ /* decNumberPlus -- prefix plus operator */ /* */ /* This computes C = 0 + A */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This simply uses AddOp; Add will take fast path after preparing A. */ /* Performance is a concern here, as this routine is often used to */ /* check operands and apply rounding and overflow/underflow testing. */ /* ------------------------------------------------------------------ */ decNumber * decNumberPlus(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dzero; uInt status=0; // accumulator #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif decNumberZero(&dzero); // make 0 dzero.exponent=rhs->exponent; // [no coefficient expansion] decAddOp(res, &dzero, rhs, set, 0, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberPlus /* ------------------------------------------------------------------ */ /* decNumberMultiply -- multiply two Numbers */ /* */ /* This computes C = A x B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X+X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberMultiply(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decMultiplyOp(res, lhs, rhs, set, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberMultiply /* ------------------------------------------------------------------ */ /* decNumberNormalize -- remove trailing zeros */ /* */ /* This computes C = 0 + A, and normalizes the result */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberNormalize(decNumber *res, const decNumber *rhs, decContext *set) { #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif uInt status=0; // as usual Int residue=0; // as usual Int dropped; // work #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // specials copy through, except NaNs need care if (decNumberIsNaN(rhs)) { decNaNs(res, rhs, NULL, &status); break; } // reduce result to the requested length and copy to result decCopyFit(res, rhs, set, &residue, &status); // copy & round decFinish(res, set, &residue, &status); // cleanup/set flags decTrim(res, 1, &dropped); // normalize in place } while(0); // end protected #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // .. #endif if (status!=0) decStatus(res, status, set);// then report status return res; } // decNumberNormalize /* ------------------------------------------------------------------ */ /* decNumberPower -- raise a number to a power */ /* */ /* This computes C = A ** B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X**X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* However, if 1999999997<=B<=999999999 and B is an integer then the */ /* restrictions on A and the context are relaxed to the usual bounds, */ /* for compatibility with the earlier (integer power only) version */ /* of this function. */ /* */ /* When B is an integer, the result may be exact, even if rounded. */ /* */ /* The final result is rounded according to the context; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ decNumber * decNumberPower(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif decNumber *allocdac=NULL; // -> allocated acc buffer, iff used decNumber *allocinv=NULL; // -> allocated 1/x buffer, iff used Int reqdigits=set->digits; // requested DIGITS Int n; // rhs in binary Flag rhsint=0; // 1 if rhs is an integer Flag useint=0; // 1 if can use integer calculation Flag isoddint=0; // 1 if rhs is an integer and odd Int i; // work #if DECSUBSET Int dropped; // .. #endif uInt needbytes; // buffer size needed Flag seenbit; // seen a bit while powering Int residue=0; // rounding residue uInt status=0; // accumulators uByte bits=0; // result sign if errors decContext aset; // working context decNumber dnOne; // work value 1... // local accumulator buffer [a decNumber, with digits+elength+1 digits] decNumber dacbuff[D2N(DECBUFFER+9)]; decNumber *dac=dacbuff; // -> result accumulator // same again for possible 1/lhs calculation decNumber invbuff[D2N(DECBUFFER+9)]; #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, &status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // handle NaNs and rhs Infinity (lhs infinity is harder) if (SPECIALARGS) { if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { // NaNs decNaNs(res, lhs, rhs, &status); break;} if (decNumberIsInfinite(rhs)) { // rhs Infinity Flag rhsneg=rhs->bits&DECNEG; // save rhs sign if (decNumberIsNegative(lhs) // lhs<0 && !decNumberIsZero(lhs)) // .. status|=DEC_Invalid_operation; else { // lhs >=0 decNumberZero(&dnOne); // set up 1 dnOne.lsu[0]=1; decNumberCompare(dac, lhs, &dnOne, set); // lhs ? 1 decNumberZero(res); // prepare for 0/1/Infinity if (decNumberIsNegative(dac)) { // lhs<1 if (rhsneg) res->bits|=DECINF; // +Infinity [else is +0] } else if (dac->lsu[0]==0) { // lhs=1 // 1**Infinity is inexact, so return fully-padded 1.0000 Int shift=set->digits-1; *res->lsu=1; // was 0, make int 1 res->digits=decShiftToMost(res->lsu, 1, shift); res->exponent=-shift; // make 1.0000... status|=DEC_Inexact|DEC_Rounded; // deemed inexact } else { // lhs>1 if (!rhsneg) res->bits|=DECINF; // +Infinity [else is +0] } } // lhs>=0 break;} // [lhs infinity drops through] } // specials // Original rhs may be an integer that fits and is in range n=decGetInt(rhs); if (n!=BADINT) { // it is an integer rhsint=1; // record the fact for 1**n isoddint=(Flag)n&1; // [works even if big] if (n!=BIGEVEN && n!=BIGODD) // can use integer path? useint=1; // looks good } if (decNumberIsNegative(lhs) // -x .. && isoddint) bits=DECNEG; // .. to an odd power // handle LHS infinity if (decNumberIsInfinite(lhs)) { // [NaNs already handled] uByte rbits=rhs->bits; // save decNumberZero(res); // prepare if (n==0) *res->lsu=1; // [-]Inf**0 => 1 else { // -Inf**nonint -> error if (!rhsint && decNumberIsNegative(lhs)) { status|=DEC_Invalid_operation; // -Inf**nonint is error break;} if (!(rbits & DECNEG)) bits|=DECINF; // was not a **-n // [otherwise will be 0 or -0] res->bits=bits; } break;} // similarly handle LHS zero if (decNumberIsZero(lhs)) { if (n==0) { // 0**0 => Error #if DECSUBSET if (!set->extended) { // [unless subset] decNumberZero(res); *res->lsu=1; // return 1 break;} #endif status|=DEC_Invalid_operation; } else { // 0**x uByte rbits=rhs->bits; // save if (rbits & DECNEG) { // was a 0**(-n) #if DECSUBSET if (!set->extended) { // [bad if subset] status|=DEC_Invalid_operation; break;} #endif bits|=DECINF; } decNumberZero(res); // prepare // [otherwise will be 0 or -0] res->bits=bits; } break;} // here both lhs and rhs are finite; rhs==0 is handled in the // integer path. Next handle the non-integer cases if (!useint) { // non-integral rhs // any -ve lhs is bad, as is either operand or context out of // bounds if (decNumberIsNegative(lhs)) { status|=DEC_Invalid_operation; break;} if (decCheckMath(lhs, set, &status) || decCheckMath(rhs, set, &status)) break; // variable status decContextDefault(&aset, DEC_INIT_DECIMAL64); // clean context aset.emax=DEC_MAX_MATH; // usual bounds aset.emin=-DEC_MAX_MATH; // .. aset.clamp=0; // and no concrete format // calculate the result using exp(ln(lhs)*rhs), which can // all be done into the accumulator, dac. The precision needed // is enough to contain the full information in the lhs (which // is the total digits, including exponent), or the requested // precision, if larger, + 4; 6 is used for the exponent // maximum length, and this is also used when it is shorter // than the requested digits as it greatly reduces the >0.5 ulp // cases at little cost (because Ln doubles digits each // iteration so a few extra digits rarely causes an extra // iteration) aset.digits=MAX(lhs->digits, set->digits)+6+4; } // non-integer rhs else { // rhs is in-range integer if (n==0) { // x**0 = 1 // (0**0 was handled above) decNumberZero(res); // result=1 *res->lsu=1; // .. break;} // rhs is a non-zero integer if (n<0) n=-n; // use abs(n) aset=*set; // clone the context aset.round=DEC_ROUND_HALF_EVEN; // internally use balanced // calculate the working DIGITS aset.digits=reqdigits+(rhs->digits+rhs->exponent)+2; #if DECSUBSET if (!set->extended) aset.digits--; // use classic precision #endif // it's an error if this is more than can be handled if (aset.digits>DECNUMMAXP) {status|=DEC_Invalid_operation; break;} } // integer path // aset.digits is the count of digits for the accumulator needed // if accumulator is too long for local storage, then allocate needbytes=sizeof(decNumber)+(D2U(aset.digits)-1)*sizeof(Unit); // [needbytes also used below if 1/lhs needed] if (needbytes>sizeof(dacbuff)) { allocdac=(decNumber *)malloc(needbytes); if (allocdac==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} dac=allocdac; // use the allocated space } // here, aset is set up and accumulator is ready for use if (!useint) { // non-integral rhs // x ** y; special-case x=1 here as it will otherwise always // reduce to integer 1; decLnOp has a fastpath which detects // the case of x=1 decLnOp(dac, lhs, &aset, &status); // dac=ln(lhs) // [no error possible, as lhs 0 already handled] if (ISZERO(dac)) { // x==1, 1.0, etc. // need to return fully-padded 1.0000 etc., but rhsint->1 *dac->lsu=1; // was 0, make int 1 if (!rhsint) { // add padding Int shift=set->digits-1; dac->digits=decShiftToMost(dac->lsu, 1, shift); dac->exponent=-shift; // make 1.0000... status|=DEC_Inexact|DEC_Rounded; // deemed inexact } } else { decMultiplyOp(dac, dac, rhs, &aset, &status); // dac=dac*rhs decExpOp(dac, dac, &aset, &status); // dac=exp(dac) } // and drop through for final rounding } // non-integer rhs else { // carry on with integer decNumberZero(dac); // acc=1 *dac->lsu=1; // .. // if a negative power the constant 1 is needed, and if not subset // invert the lhs now rather than inverting the result later if (decNumberIsNegative(rhs)) { // was a **-n [hence digits>0] decNumber *inv=invbuff; // asssume use fixed buffer decNumberCopy(&dnOne, dac); // dnOne=1; [needed now or later] #if DECSUBSET if (set->extended) { // need to calculate 1/lhs #endif // divide lhs into 1, putting result in dac [dac=1/dac] decDivideOp(dac, &dnOne, lhs, &aset, DIVIDE, &status); // now locate or allocate space for the inverted lhs if (needbytes>sizeof(invbuff)) { allocinv=(decNumber *)malloc(needbytes); if (allocinv==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} inv=allocinv; // use the allocated space } // [inv now points to big-enough buffer or allocated storage] decNumberCopy(inv, dac); // copy the 1/lhs decNumberCopy(dac, &dnOne); // restore acc=1 lhs=inv; // .. and go forward with new lhs #if DECSUBSET } #endif } // Raise-to-the-power loop... seenbit=0; // set once a 1-bit is encountered for (i=1;;i++){ // for each bit [top bit ignored] // abandon if had overflow or terminal underflow if (status & (DEC_Overflow|DEC_Underflow)) { // interesting? if (status&DEC_Overflow || ISZERO(dac)) break; } // [the following two lines revealed an optimizer bug in a C++ // compiler, with symptom: 5**3 -> 25, when n=n+n was used] n=n<<1; // move next bit to testable position if (n<0) { // top bit is set seenbit=1; // OK, significant bit seen decMultiplyOp(dac, dac, lhs, &aset, &status); // dac=dac*x } if (i==31) break; // that was the last bit if (!seenbit) continue; // no need to square 1 decMultiplyOp(dac, dac, dac, &aset, &status); // dac=dac*dac [square] } /*i*/ // 32 bits // complete internal overflow or underflow processing if (status & (DEC_Overflow|DEC_Subnormal)) { #if DECSUBSET // If subset, and power was negative, reverse the kind of -erflow // [1/x not yet done] if (!set->extended && decNumberIsNegative(rhs)) { if (status & DEC_Overflow) status^=DEC_Overflow | DEC_Underflow | DEC_Subnormal; else { // trickier -- Underflow may or may not be set status&=~(DEC_Underflow | DEC_Subnormal); // [one or both] status|=DEC_Overflow; } } #endif dac->bits=(dac->bits & ~DECNEG) | bits; // force correct sign // round subnormals [to set.digits rather than aset.digits] // or set overflow result similarly as required decFinalize(dac, set, &residue, &status); decNumberCopy(res, dac); // copy to result (is now OK length) break; } #if DECSUBSET if (!set->extended && // subset math decNumberIsNegative(rhs)) { // was a **-n [hence digits>0] // so divide result into 1 [dac=1/dac] decDivideOp(dac, &dnOne, dac, &aset, DIVIDE, &status); } #endif } // rhs integer path // reduce result to the requested length and copy to result decCopyFit(res, dac, set, &residue, &status); decFinish(res, set, &residue, &status); // final cleanup #if DECSUBSET if (!set->extended) decTrim(res, 0, &dropped); // trailing zeros #endif } while(0); // end protected if (allocdac!=NULL) free(allocdac); // drop any storage used if (allocinv!=NULL) free(allocinv); // .. #if DECSUBSET if (alloclhs!=NULL) free(alloclhs); // .. if (allocrhs!=NULL) free(allocrhs); // .. #endif if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberPower /* ------------------------------------------------------------------ */ /* decNumberQuantize -- force exponent to requested value */ /* */ /* This computes C = op(A, B), where op adjusts the coefficient */ /* of C (by rounding or shifting) such that the exponent (-scale) */ /* of C has exponent of B. The numerical value of C will equal A, */ /* except for the effects of any rounding that occurred. */ /* */ /* res is C, the result. C may be A or B */ /* lhs is A, the number to adjust */ /* rhs is B, the number with exponent to match */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* */ /* Unless there is an error or the result is infinite, the exponent */ /* after the operation is guaranteed to be equal to that of B. */ /* ------------------------------------------------------------------ */ decNumber * decNumberQuantize(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decQuantizeOp(res, lhs, rhs, set, 1, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberQuantize /* ------------------------------------------------------------------ */ /* decNumberRescale -- force exponent to requested value */ /* */ /* This computes C = op(A, B), where op adjusts the coefficient */ /* of C (by rounding or shifting) such that the exponent (-scale) */ /* of C has the value B. The numerical value of C will equal A, */ /* except for the effects of any rounding that occurred. */ /* */ /* res is C, the result. C may be A or B */ /* lhs is A, the number to adjust */ /* rhs is B, the requested exponent */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* */ /* Unless there is an error or the result is infinite, the exponent */ /* after the operation is guaranteed to be equal to B. */ /* ------------------------------------------------------------------ */ decNumber * decNumberRescale(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decQuantizeOp(res, lhs, rhs, set, 0, &status); if (status!=0) decStatus(res, status, set); return res; } // decNumberRescale /* ------------------------------------------------------------------ */ /* decNumberRemainder -- divide and return remainder */ /* */ /* This computes C = A % B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X%X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberRemainder(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, REMAINDER, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberRemainder /* ------------------------------------------------------------------ */ /* decNumberRemainderNear -- divide and return remainder from nearest */ /* */ /* This computes C = A % B, where % is the IEEE remainder operator */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X%X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberRemainderNear(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decDivideOp(res, lhs, rhs, set, REMNEAR, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberRemainderNear /* ------------------------------------------------------------------ */ /* decNumberSameQuantum -- test for equal exponents */ /* */ /* res is the result number, which will contain either 0 or 1 */ /* lhs is a number to test */ /* rhs is the second (usually a pattern) */ /* */ /* No errors are possible and no context is needed. */ /* ------------------------------------------------------------------ */ decNumber * decNumberSameQuantum(decNumber *res, const decNumber *lhs, const decNumber *rhs) { Unit ret=0; // return value #if DECCHECK if (decCheckOperands(res, lhs, rhs, DECUNUSED)) return res; #endif if (SPECIALARGS) { if (decNumberIsNaN(lhs) && decNumberIsNaN(rhs)) ret=1; else if (decNumberIsInfinite(lhs) && decNumberIsInfinite(rhs)) ret=1; // [anything else with a special gives 0] } else if (lhs->exponent==rhs->exponent) ret=1; decNumberZero(res); // OK to overwrite an operand now *res->lsu=ret; return res; } // decNumberSameQuantum /* ------------------------------------------------------------------ */ /* decNumberSquareRoot -- square root operator */ /* */ /* This computes C = squareroot(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This uses the following varying-precision algorithm in: */ /* */ /* Properly Rounded Variable Precision Square Root, T. E. Hull and */ /* A. Abrham, ACM Transactions on Mathematical Software, Vol 11 #3, */ /* pp229-237, ACM, September 1985. */ /* */ /* The square-root is calculated using Newton's method, after which */ /* a check is made to ensure the result is correctly rounded. */ /* */ /* % [Reformatted original Numerical Turing source code follows.] */ /* function sqrt(x : real) : real */ /* % sqrt(x) returns the properly rounded approximation to the square */ /* % root of x, in the precision of the calling environment, or it */ /* % fails if x < 0. */ /* % t e hull and a abrham, august, 1984 */ /* if x <= 0 then */ /* if x < 0 then */ /* assert false */ /* else */ /* result 0 */ /* end if */ /* end if */ /* var f := setexp(x, 0) % fraction part of x [0.1 <= x < 1] */ /* var e := getexp(x) % exponent part of x */ /* var approx : real */ /* if e mod 2 = 0 then */ /* approx := .259 + .819 * f % approx to root of f */ /* else */ /* f := f/l0 % adjustments */ /* e := e + 1 % for odd */ /* approx := .0819 + 2.59 * f % exponent */ /* end if */ /* */ /* var p:= 3 */ /* const maxp := currentprecision + 2 */ /* loop */ /* p := min(2*p - 2, maxp) % p = 4,6,10, . . . , maxp */ /* precision p */ /* approx := .5 * (approx + f/approx) */ /* exit when p = maxp */ /* end loop */ /* */ /* % approx is now within 1 ulp of the properly rounded square root */ /* % of f; to ensure proper rounding, compare squares of (approx - */ /* % l/2 ulp) and (approx + l/2 ulp) with f. */ /* p := currentprecision */ /* begin */ /* precision p + 2 */ /* const approxsubhalf := approx - setexp(.5, -p) */ /* if mulru(approxsubhalf, approxsubhalf) > f then */ /* approx := approx - setexp(.l, -p + 1) */ /* else */ /* const approxaddhalf := approx + setexp(.5, -p) */ /* if mulrd(approxaddhalf, approxaddhalf) < f then */ /* approx := approx + setexp(.l, -p + 1) */ /* end if */ /* end if */ /* end */ /* result setexp(approx, e div 2) % fix exponent */ /* end sqrt */ /* ------------------------------------------------------------------ */ decNumber * decNumberSquareRoot(decNumber *res, const decNumber *rhs, decContext *set) { decContext workset, approxset; // work contexts decNumber dzero; // used for constant zero Int maxp=set->digits+2; // largest working precision Int residue=0; // rounding residue uInt status=0, ignore=0; // status accumulators Int exp; // working exponent Int ideal; // ideal (preferred) exponent Int needbytes; // work Int dropped; // .. #if DECSUBSET decNumber *allocrhs=NULL; // non-NULL if rounded rhs allocated #endif // buffer for f [needs +1 in case DECBUFFER 0] decNumber buff[D2N(DECBUFFER+1)]; // buffer for a [needs +2 to match maxp] decNumber bufa[D2N(DECBUFFER+2)]; // buffer for temporary, b [must be same size as a] decNumber bufb[D2N(DECBUFFER+2)]; decNumber *allocbuff=NULL; // -> allocated buff, iff allocated decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *allocbufb=NULL; // -> allocated bufb, iff allocated decNumber *f=buff; // reduced fraction decNumber *a=bufa; // approximation to result decNumber *b=bufb; // intermediate result // buffer for temporary variable, up to 3 digits decNumber buft[D2N(3)]; decNumber *t=buft; // up-to-3-digit constant or work #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operand and set lostDigits status, as needed if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==NULL) break; // [Note: 'f' allocation below could reuse this buffer if // used, but as this is rare they are kept separate for clarity.] rhs=allocrhs; } } #endif // [following code does not require input rounding] // handle infinities and NaNs if (SPECIALARG) { if (decNumberIsInfinite(rhs)) { // an infinity if (decNumberIsNegative(rhs)) status|=DEC_Invalid_operation; else decNumberCopy(res, rhs); // +Infinity } else decNaNs(res, rhs, NULL, &status); // a NaN break; } // calculate the ideal (preferred) exponent [floor(exp/2)] // [We would like to write: ideal=rhs->exponent>>1, but this // generates a compiler warning. Generated code is the same.] ideal=(rhs->exponent&~1)/2; // target // handle zeros if (ISZERO(rhs)) { decNumberCopy(res, rhs); // could be 0 or -0 res->exponent=ideal; // use the ideal [safe] break; } // any other -x is an oops if (decNumberIsNegative(rhs)) { status|=DEC_Invalid_operation; break; } // space is needed for three working variables // f -- the same precision as the RHS, reduced to 0.01->0.99... // a -- Hull's approximation -- precision, when assigned, is // currentprecision (we allow +2 for use as temporary) // b -- intermediate temporary result // if any is too long for local storage, then allocate needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); if (needbytes>(Int)sizeof(buff)) { allocbuff=(decNumber *)malloc(needbytes); if (allocbuff==NULL) { // hopeless -- abandon status|=DEC_Insufficient_storage; break;} f=allocbuff; // use the allocated space } // a and b both need to be able to hold a maxp-length number needbytes=sizeof(decNumber)+(D2U(maxp)-1)*sizeof(Unit); if (needbytes>(Int)sizeof(bufa)) { // [same applies to b] allocbufa=(decNumber *)malloc(needbytes); allocbufb=(decNumber *)malloc(needbytes); if (allocbufa==NULL || allocbufb==NULL) { // hopeless status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space b=allocbufb; // .. } // copy rhs -> f, save exponent, and reduce so 0.1 <= f < 1 decNumberCopy(f, rhs); exp=f->exponent+f->digits; // adjusted to Hull rules f->exponent=-(f->digits); // to range // set up working contexts (the second is used for Numerical // Turing assignment) decContextDefault(&workset, DEC_INIT_DECIMAL64); decContextDefault(&approxset, DEC_INIT_DECIMAL64); approxset.digits=set->digits; // approx's length // [Until further notice, no error is possible and status bits // (Rounded, etc.) should be ignored, not accumulated.] // Calculate initial approximation, and allow for odd exponent workset.digits=set->digits; // p for initial calculation t->bits=0; t->digits=3; a->bits=0; a->digits=3; if ((exp & 1)==0) { // even exponent // Set t=0.259, a=0.819 t->exponent=-3; a->exponent=-3; #if DECDPUN>=3 t->lsu[0]=259; a->lsu[0]=819; #elif DECDPUN==2 t->lsu[0]=59; t->lsu[1]=2; a->lsu[0]=19; a->lsu[1]=8; #else t->lsu[0]=9; t->lsu[1]=5; t->lsu[2]=2; a->lsu[0]=9; a->lsu[1]=1; a->lsu[2]=8; #endif } else { // odd exponent // Set t=0.0819, a=2.59 f->exponent--; // f=f/10 exp++; // e=e+1 t->exponent=-4; a->exponent=-2; #if DECDPUN>=3 t->lsu[0]=819; a->lsu[0]=259; #elif DECDPUN==2 t->lsu[0]=19; t->lsu[1]=8; a->lsu[0]=59; a->lsu[1]=2; #else t->lsu[0]=9; t->lsu[1]=1; t->lsu[2]=8; a->lsu[0]=9; a->lsu[1]=5; a->lsu[2]=2; #endif } decMultiplyOp(a, a, f, &workset, &ignore); // a=a*f decAddOp(a, a, t, &workset, 0, &ignore); // ..+t // [a is now the initial approximation for sqrt(f), calculated with // currentprecision, which is also a's precision.] // the main calculation loop decNumberZero(&dzero); // make 0 decNumberZero(t); // set t = 0.5 t->lsu[0]=5; // .. t->exponent=-1; // .. workset.digits=3; // initial p for (;;) { // set p to min(2*p - 2, maxp) [hence 3; or: 4, 6, 10, ... , maxp] workset.digits=workset.digits*2-2; if (workset.digits>maxp) workset.digits=maxp; // a = 0.5 * (a + f/a) // [calculated at p then rounded to currentprecision] decDivideOp(b, f, a, &workset, DIVIDE, &ignore); // b=f/a decAddOp(b, b, a, &workset, 0, &ignore); // b=b+a decMultiplyOp(a, b, t, &workset, &ignore); // a=b*0.5 // assign to approx [round to length] decAddOp(a, &dzero, a, &approxset, 0, &ignore); if (workset.digits==maxp) break; // just did final } // loop // a is now at currentprecision and within 1 ulp of the properly // rounded square root of f; to ensure proper rounding, compare // squares of (a - l/2 ulp) and (a + l/2 ulp) with f. // Here workset.digits=maxp and t=0.5 workset.digits--; // maxp-1 is OK now t->exponent=-set->digits-1; // make 0.5 ulp decNumberCopy(b, a); decAddOp(b, b, t, &workset, DECNEG, &ignore); // b = a - 0.5 ulp workset.round=DEC_ROUND_UP; decMultiplyOp(b, b, b, &workset, &ignore); // b = mulru(b, b) decCompareOp(b, f, b, &workset, COMPARE, &ignore); // b ? f, reversed if (decNumberIsNegative(b)) { // f < b [i.e., b > f] // this is the more common adjustment, though both are rare t->exponent++; // make 1.0 ulp t->lsu[0]=1; // .. decAddOp(a, a, t, &workset, DECNEG, &ignore); // a = a - 1 ulp // assign to approx [round to length] decAddOp(a, &dzero, a, &approxset, 0, &ignore); } else { decNumberCopy(b, a); decAddOp(b, b, t, &workset, 0, &ignore); // b = a + 0.5 ulp workset.round=DEC_ROUND_DOWN; decMultiplyOp(b, b, b, &workset, &ignore); // b = mulrd(b, b) decCompareOp(b, b, f, &workset, COMPARE, &ignore); // b ? f if (decNumberIsNegative(b)) { // b < f t->exponent++; // make 1.0 ulp t->lsu[0]=1; // .. decAddOp(a, a, t, &workset, 0, &ignore); // a = a + 1 ulp // assign to approx [round to length] decAddOp(a, &dzero, a, &approxset, 0, &ignore); } } // [no errors are possible in the above, and rounding/inexact during // estimation are irrelevant, so status was not accumulated] // Here, 0.1 <= a < 1 [Hull] a->exponent+=exp/2; // set correct exponent // Process Subnormals decFinalize(a, set, &residue, &status); // count droppable zeros [after any subnormal rounding] by // trimming a copy decNumberCopy(b, a); decTrim(b, 1, &dropped); // [drops trailing zeros] // Finally set Inexact and Rounded. The answer can only be exact if // it is short enough so that squaring it could fit in set->digits, // so this is the only (relatively rare) time a careful check is // needed if (b->digits*2-1 > set->digits) { // cannot fit status|=DEC_Inexact|DEC_Rounded; } else { // could be exact/unrounded uInt mstatus=0; // local status decMultiplyOp(b, b, b, &workset, &mstatus); // try the multiply if (mstatus!=0) { // result won't fit status|=DEC_Inexact|DEC_Rounded; } else { // plausible decCompareOp(t, b, rhs, &workset, COMPARE, &mstatus); // b ? rhs if (!ISZERO(t)) { status|=DEC_Inexact|DEC_Rounded; } else { // is Exact Int todrop; // work // here, dropped is the count of trailing zeros in 'a' // use closest exponent to ideal... todrop=ideal-a->exponent; // most that can be dropped if (todrop<0) { // ideally would add 0s status|=DEC_Rounded; } else { // unrounded if (dropped0) { // OK, some to drop decShiftToLeast(a->lsu, D2U(a->digits), todrop); a->exponent+=todrop; // maintain numerical value a->digits-=todrop; // new length } } } } } // make sure there is a full complement of digits for normal // inexact results if ((status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact) { Int shift=set->digits-a->digits; if (shift>0) { a->digits=decShiftToMost(a->lsu, a->digits, shift); a->exponent-=shift; // adjust the exponent. } } decNumberCopy(res, a); // a is now the result } while(0); // end protected if (allocbuff!=NULL) free(allocbuff); // drop any storage used if (allocbufa!=NULL) free(allocbufa); // .. if (allocbufb!=NULL) free(allocbufb); // .. #if DECSUBSET if (allocrhs !=NULL) free(allocrhs); // .. #endif if (status!=0) decStatus(res, status, set);// then report status #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberSquareRoot /* ------------------------------------------------------------------ */ /* decNumberSubtract -- subtract two Numbers */ /* */ /* This computes C = A - B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X-X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ decNumber * decNumberSubtract(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { uInt status=0; // accumulator decAddOp(res, lhs, rhs, set, DECNEG, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK decCheckInexact(res, set); #endif return res; } // decNumberSubtract /* ------------------------------------------------------------------ */ /* decNumberToIntegralValue -- round-to-integral-value */ /* */ /* res is the result */ /* rhs is input number */ /* set is the context */ /* */ /* res must have space for any value of rhs. */ /* */ /* This implements the IEEE special operator and therefore treats */ /* special values as valid, and also never sets Inexact. For finite */ /* numbers it returns rescale(rhs, 0) if rhs->exponent is <0. */ /* Otherwise the result is rhs (so no error is possible). */ /* */ /* The context is used for rounding mode and status after sNaN, but */ /* the digits setting is ignored. */ /* ------------------------------------------------------------------ */ decNumber * decNumberToIntegralValue(decNumber *res, const decNumber *rhs, decContext *set) { decNumber dn; decContext workset; // working context #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif // handle infinities and NaNs if (SPECIALARG) { uInt status=0; if (decNumberIsInfinite(rhs)) decNumberCopy(res, rhs); // an Infinity else decNaNs(res, rhs, NULL, &status); // a NaN if (status!=0) decStatus(res, status, set); return res; } // have a finite number; no error possible (res must be big enough) if (rhs->exponent>=0) return decNumberCopy(res, rhs); // that was easy, but if negative exponent there is work to do... workset=*set; // clone rounding, etc. workset.digits=rhs->digits; // no length rounding workset.traps=0; // no traps decNumberZero(&dn); // make a number with exponent 0 return decNumberQuantize(res, rhs, &dn, &workset); } // decNumberToIntegralValue /* ================================================================== */ /* Utility routines */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* decNumberCopy -- copy a number */ /* */ /* dest is the target decNumber */ /* src is the source decNumber */ /* returns dest */ /* */ /* (dest==src is allowed and is a no-op) */ /* All fields are updated as required. This is a utility operation, */ /* so special values are unchanged and no error is possible. */ /* ------------------------------------------------------------------ */ decNumber * decNumberCopy(decNumber *dest, const decNumber *src) { #if DECCHECK if (src==NULL) return decNumberZero(dest); #endif if (dest==src) return dest; // no copy required // Use explicit assignments here as structure assignment could copy // more than just the lsu (for small DECDPUN). This would not affect // the value of the results, but could disturb test harness spill // checking. dest->bits=src->bits; dest->exponent=src->exponent; dest->digits=src->digits; dest->lsu[0]=src->lsu[0]; if (src->digits>DECDPUN) { // more Units to come const Unit *smsup, *s; // work Unit *d; // .. // memcpy for the remaining Units would be safe as they cannot // overlap. However, this explicit loop is faster in short cases. d=dest->lsu+1; // -> first destination smsup=src->lsu+D2U(src->digits); // -> source msu+1 for (s=src->lsu+1; sbits=0; dn->exponent=0; dn->digits=1; dn->lsu[0]=0; return dn; } // decNumberZero /* ================================================================== */ /* Local routines */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* decToString -- lay out a number into a string */ /* */ /* dn is the number to lay out */ /* string is where to lay out the number */ /* eng is 1 if Engineering, 0 if Scientific */ /* */ /* string must be at least dn->digits+14 characters long */ /* No error is possible. */ /* */ /* Note that this routine can generate a -0 or 0.000. These are */ /* never generated in subset to-number or arithmetic, but can occur */ /* in non-subset arithmetic (e.g., -1*0 or 1.234-1.234). */ /* ------------------------------------------------------------------ */ // If DECCHECK is enabled the string "?" is returned if a number is // invalid. static void decToString(const decNumber *dn, char *string, Flag eng) { Int exp=dn->exponent; // local copy Int e; // E-part value Int pre; // digits before the '.' Int cut; // for counting digits in a Unit char *c=string; // work [output pointer] const Unit *up=dn->lsu+D2U(dn->digits)-1; // -> msu [input pointer] uInt u, pow; // work #if DECCHECK if (decCheckOperands(DECUNUSED, dn, DECUNUSED, DECUNUSED)) { strcpy(string, "?"); return;} #endif if (decNumberIsNegative(dn)) { // Negatives get a minus *c='-'; c++; } if (dn->bits&DECSPECIAL) { // Is a special value if (decNumberIsInfinite(dn)) { strcpy(c, "Infinity"); return;} // a NaN if (dn->bits&DECSNAN) { // signalling NaN *c='s'; c++; } strcpy(c, "NaN"); c+=3; // step past // if not a clean non-zero coefficient, that's all there is in a // NaN string if (exp!=0 || (*dn->lsu==0 && dn->digits==1)) return; // [drop through to add integer] } // calculate how many digits in msu, and hence first cut cut=MSUDIGITS(dn->digits); // [faster than remainder] cut--; // power of ten for digit if (exp==0) { // simple integer [common fastpath] for (;up>=dn->lsu; up--) { // each Unit from msu u=*up; // contains DECDPUN digits to lay out for (; cut>=0; c++, cut--) TODIGIT(u, cut, c, pow); cut=DECDPUN-1; // next Unit has all digits } *c='\0'; // terminate the string return;} /* non-0 exponent -- assume plain form */ pre=dn->digits+exp; // digits before '.' e=0; // no E if ((exp>0) || (pre<-5)) { // need exponential form e=exp+dn->digits-1; // calculate E value pre=1; // assume one digit before '.' if (eng && (e!=0)) { // engineering: may need to adjust Int adj; // adjustment // The C remainder operator is undefined for negative numbers, so // a positive remainder calculation must be used here if (e<0) { adj=(-e)%3; if (adj!=0) adj=3-adj; } else { // e>0 adj=e%3; } e=e-adj; // if dealing with zero still produce an exponent which is a // multiple of three, as expected, but there will only be the // one zero before the E, still. Otherwise note the padding. if (!ISZERO(dn)) pre+=adj; else { // is zero if (adj!=0) { // 0.00Esnn needed e=e+3; pre=-(2-adj); } } // zero } // eng } // need exponent /* lay out the digits of the coefficient, adding 0s and . as needed */ u=*up; if (pre>0) { // xxx.xxx or xx00 (engineering) form Int n=pre; for (; pre>0; pre--, c++, cut--) { if (cut<0) { // need new Unit if (up==dn->lsu) break; // out of input digits (pre>digits) up--; cut=DECDPUN-1; u=*up; } TODIGIT(u, cut, c, pow); } if (ndigits) { // more to come, after '.' *c='.'; c++; for (;; c++, cut--) { if (cut<0) { // need new Unit if (up==dn->lsu) break; // out of input digits up--; cut=DECDPUN-1; u=*up; } TODIGIT(u, cut, c, pow); } } else for (; pre>0; pre--, c++) *c='0'; // 0 padding (for engineering) needed } else { // 0.xxx or 0.000xxx form *c='0'; c++; *c='.'; c++; for (; pre<0; pre++, c++) *c='0'; // add any 0's after '.' for (; ; c++, cut--) { if (cut<0) { // need new Unit if (up==dn->lsu) break; // out of input digits up--; cut=DECDPUN-1; u=*up; } TODIGIT(u, cut, c, pow); } } /* Finally add the E-part, if needed. It will never be 0, has a base maximum and minimum of +999999999 through -999999999, but could range down to -1999999998 for anormal numbers */ if (e!=0) { Flag had=0; // 1=had non-zero *c='E'; c++; *c='+'; c++; // assume positive u=e; // .. if (e<0) { *(c-1)='-'; // oops, need - u=-e; // uInt, please } // layout the exponent [_itoa or equivalent is not ANSI C] for (cut=9; cut>=0; cut--) { TODIGIT(u, cut, c, pow); if (*c=='0' && !had) continue; // skip leading zeros had=1; // had non-0 c++; // step for next } // cut } *c='\0'; // terminate the string (all paths) return; } // decToString /* ------------------------------------------------------------------ */ /* decAddOp -- add/subtract operation */ /* */ /* This computes C = A + B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X+X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* negate is DECNEG if rhs should be negated, or 0 otherwise */ /* status accumulates status for the caller */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* If possible, the coefficient is calculated directly into C. */ /* However, if: */ /* -- a digits+1 calculation is needed because the numbers are */ /* unaligned and span more than set->digits digits */ /* -- a carry to digits+1 digits looks possible */ /* -- C is the same as A or B, and the result would destructively */ /* overlap the A or B coefficient */ /* then the result must be calculated into a temporary buffer. In */ /* this case a local (stack) buffer is used if possible, and only if */ /* too long for that does malloc become the last resort. */ /* */ /* Misalignment is handled as follows: */ /* Apad: (AExp>BExp) Swap operands and proceed as for BExp>AExp. */ /* BPad: Apply the padding by a combination of shifting (whole */ /* units) and multiplication (part units). */ /* */ /* Addition, especially x=x+1, is speed-critical. */ /* ------------------------------------------------------------------ */ static decNumber * decAddOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, uByte negate, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif Int rhsshift; // working shift (in Units) Int maxdigits; // longest logical length Int mult; // multiplier Int residue; // rounding accumulator uByte bits; // result bits Flag diffsign; // non-0 if arguments have different sign Unit *acc; // accumulator for result Unit accbuff[SD2U(DECBUFFER+20)]; // local buffer [+20 reduces many // allocations when called from // other operations] Unit *allocacc=NULL; // -> allocated acc buffer, iff allocated Int reqdigits=set->digits; // local copy; requested DIGITS Int padding; // work #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // note whether signs differ [used all paths] diffsign=(Flag)((lhs->bits^rhs->bits^negate)&DECNEG); // handle infinities and NaNs if (SPECIALARGS) { // a special bit set if (SPECIALARGS & (DECSNAN | DECNAN)) // a NaN decNaNs(res, lhs, rhs, status); else { // one or two infinities if (decNumberIsInfinite(lhs)) { // LHS is infinity // two infinities with different signs is invalid if (decNumberIsInfinite(rhs) && diffsign) { *status|=DEC_Invalid_operation; break; } bits=lhs->bits & DECNEG; // get sign from LHS } else bits=(rhs->bits^negate) & DECNEG;// RHS must be Infinity bits|=DECINF; decNumberZero(res); res->bits=bits; // set +/- infinity } // an infinity break; } // Quick exit for add 0s; return the non-0, modified as need be if (ISZERO(lhs)) { Int adjust; // work Int lexp=lhs->exponent; // save in case LHS==RES bits=lhs->bits; // .. residue=0; // clear accumulator decCopyFit(res, rhs, set, &residue, status); // copy (as needed) res->bits^=negate; // flip if rhs was negated #if DECSUBSET if (set->extended) { // exponents on zeros count #endif // exponent will be the lower of the two adjust=lexp-res->exponent; // adjustment needed [if -ve] if (ISZERO(res)) { // both 0: special IEEE 854 rules if (adjust<0) res->exponent=lexp; // set exponent // 0-0 gives +0 unless rounding to -infinity, and -0-0 gives -0 if (diffsign) { if (set->round!=DEC_ROUND_FLOOR) res->bits=0; else res->bits=DECNEG; // preserve 0 sign } } else { // non-0 res if (adjust<0) { // 0-padding needed if ((res->digits-adjust)>set->digits) { adjust=res->digits-set->digits; // to fit exactly *status|=DEC_Rounded; // [but exact] } res->digits=decShiftToMost(res->lsu, res->digits, -adjust); res->exponent+=adjust; // set the exponent. } } // non-0 res #if DECSUBSET } // extended #endif decFinish(res, set, &residue, status); // clean and finalize break;} if (ISZERO(rhs)) { // [lhs is non-zero] Int adjust; // work Int rexp=rhs->exponent; // save in case RHS==RES bits=rhs->bits; // be clean residue=0; // clear accumulator decCopyFit(res, lhs, set, &residue, status); // copy (as needed) #if DECSUBSET if (set->extended) { // exponents on zeros count #endif // exponent will be the lower of the two // [0-0 case handled above] adjust=rexp-res->exponent; // adjustment needed [if -ve] if (adjust<0) { // 0-padding needed if ((res->digits-adjust)>set->digits) { adjust=res->digits-set->digits; // to fit exactly *status|=DEC_Rounded; // [but exact] } res->digits=decShiftToMost(res->lsu, res->digits, -adjust); res->exponent+=adjust; // set the exponent. } #if DECSUBSET } // extended #endif decFinish(res, set, &residue, status); // clean and finalize break;} // [NB: both fastpath and mainpath code below assume these cases // (notably 0-0) have already been handled] // calculate the padding needed to align the operands padding=rhs->exponent-lhs->exponent; // Fastpath cases where the numbers are aligned and normal, the RHS // is all in one unit, no operand rounding is needed, and no carry, // lengthening, or borrow is needed if (padding==0 && rhs->digits<=DECDPUN && rhs->exponent>=set->emin // [some normals drop through] && rhs->digits<=reqdigits && lhs->digits<=reqdigits) { Int partial=*lhs->lsu; if (!diffsign) { // adding partial+=*rhs->lsu; if ((partial<=DECDPUNMAX) // result fits in unit && (lhs->digits>=DECDPUN || // .. and no digits-count change partial<(Int)powers[lhs->digits])) { // .. if (res!=lhs) decNumberCopy(res, lhs); // not in place *res->lsu=(Unit)partial; // [copy could have overwritten RHS] break; } // else drop out for careful add } else { // signs differ partial-=*rhs->lsu; if (partial>0) { // no borrow needed, and non-0 result if (res!=lhs) decNumberCopy(res, lhs); // not in place *res->lsu=(Unit)partial; // this could have reduced digits [but result>0] res->digits=decGetDigits(res->lsu, D2U(res->digits)); break; } // else drop out for careful subtract } } // Now align (pad) the lhs or rhs so they can be added or // subtracted, as necessary. If one number is much larger than // the other (that is, if in plain form there is a least one // digit between the lowest digit of one and the highest of the // other) padding with up to DIGITS-1 trailing zeros may be // needed; then apply rounding (as exotic rounding modes may be // affected by the residue). rhsshift=0; // rhs shift to left (padding) in Units bits=lhs->bits; // assume sign is that of LHS mult=1; // likely multiplier // if padding==0 the operands are aligned; no padding needed if (padding!=0) { // some padding needed; always pad the RHS, as any required // padding can then be effected by a simple combination of // shifts and a multiply Flag swapped=0; if (padding<0) { // LHS needs the padding const decNumber *t; padding=-padding; // will be +ve bits=(uByte)(rhs->bits^negate); // assumed sign is now that of RHS t=lhs; lhs=rhs; rhs=t; swapped=1; } // If, after pad, rhs would be longer than lhs by digits+1 or // more then lhs cannot affect the answer, except as a residue, // so only need to pad up to a length of DIGITS+1. if (rhs->digits+padding > lhs->digits+reqdigits+1) { // The RHS is sufficient // for residue use the relative sign indication... Int shift=reqdigits-rhs->digits; // left shift needed residue=1; // residue for rounding if (diffsign) residue=-residue; // signs differ // copy, shortening if necessary decCopyFit(res, rhs, set, &residue, status); // if it was already shorter, then need to pad with zeros if (shift>0) { res->digits=decShiftToMost(res->lsu, res->digits, shift); res->exponent-=shift; // adjust the exponent. } // flip the result sign if unswapped and rhs was negated if (!swapped) res->bits^=negate; decFinish(res, set, &residue, status); // done break;} // LHS digits may affect result rhsshift=D2U(padding+1)-1; // this much by Unit shift .. mult=powers[padding-(rhsshift*DECDPUN)]; // .. this by multiplication } // padding needed if (diffsign) mult=-mult; // signs differ // determine the longer operand maxdigits=rhs->digits+padding; // virtual length of RHS if (lhs->digits>maxdigits) maxdigits=lhs->digits; // Decide on the result buffer to use; if possible place directly // into result. acc=res->lsu; // assume add direct to result // If destructive overlap, or the number is too long, or a carry or // borrow to DIGITS+1 might be possible, a buffer must be used. // [Might be worth more sophisticated tests when maxdigits==reqdigits] if ((maxdigits>=reqdigits) // is, or could be, too large || (res==rhs && rhsshift>0)) { // destructive overlap // buffer needed, choose it; units for maxdigits digits will be // needed, +1 Unit for carry or borrow Int need=D2U(maxdigits)+1; acc=accbuff; // assume use local buffer if (need*sizeof(Unit)>sizeof(accbuff)) { allocacc=(Unit *)malloc(need*sizeof(Unit)); if (allocacc==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} acc=allocacc; } } res->bits=(uByte)(bits&DECNEG); // it's now safe to overwrite.. res->exponent=lhs->exponent; // .. operands (even if aliased) #if DECTRACE decDumpAr('A', lhs->lsu, D2U(lhs->digits)); decDumpAr('B', rhs->lsu, D2U(rhs->digits)); printf(" :h: %d %d\n", rhsshift, mult); #endif // add [A+B*m] or subtract [A+B*(-m)] res->digits=decUnitAddSub(lhs->lsu, D2U(lhs->digits), rhs->lsu, D2U(rhs->digits), rhsshift, acc, mult) *DECDPUN; // [units -> digits] if (res->digits<0) { // borrowed... res->digits=-res->digits; res->bits^=DECNEG; // flip the sign } #if DECTRACE decDumpAr('+', acc, D2U(res->digits)); #endif // If a buffer was used the result must be copied back, possibly // shortening. (If no buffer was used then the result must have // fit, so can't need rounding and residue must be 0.) residue=0; // clear accumulator if (acc!=res->lsu) { #if DECSUBSET if (set->extended) { // round from first significant digit #endif // remove leading zeros that were added due to rounding up to // integral Units -- before the test for rounding. if (res->digits>reqdigits) res->digits=decGetDigits(acc, D2U(res->digits)); decSetCoeff(res, set, acc, res->digits, &residue, status); #if DECSUBSET } else { // subset arithmetic rounds from original significant digit // May have an underestimate. This only occurs when both // numbers fit in DECDPUN digits and are padding with a // negative multiple (-10, -100...) and the top digit(s) become // 0. (This only matters when using X3.274 rules where the // leading zero could be included in the rounding.) if (res->digitsdigits))=0; // ensure leading 0 is there res->digits=maxdigits; } else { // remove leading zeros that added due to rounding up to // integral Units (but only those in excess of the original // maxdigits length, unless extended) before test for rounding. if (res->digits>reqdigits) { res->digits=decGetDigits(acc, D2U(res->digits)); if (res->digitsdigits=maxdigits; } } decSetCoeff(res, set, acc, res->digits, &residue, status); // Now apply rounding if needed before removing leading zeros. // This is safe because subnormals are not a possibility if (residue!=0) { decApplyRound(res, set, residue, status); residue=0; // did what needed to be done } } // subset #endif } // used buffer // strip leading zeros [these were left on in case of subset subtract] res->digits=decGetDigits(res->lsu, D2U(res->digits)); // apply checks and rounding decFinish(res, set, &residue, status); // "When the sum of two operands with opposite signs is exactly // zero, the sign of that sum shall be '+' in all rounding modes // except round toward -Infinity, in which mode that sign shall be // '-'." [Subset zeros also never have '-', set by decFinish.] if (ISZERO(res) && diffsign #if DECSUBSET && set->extended #endif && (*status&DEC_Inexact)==0) { if (set->round==DEC_ROUND_FLOOR) res->bits|=DECNEG; // sign - else res->bits&=~DECNEG; // sign + } } while(0); // end protected if (allocacc!=NULL) free(allocacc); // drop any storage used #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // .. if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decAddOp /* ------------------------------------------------------------------ */ /* decDivideOp -- division operation */ /* */ /* This routine performs the calculations for all four division */ /* operators (divide, divideInteger, remainder, remainderNear). */ /* */ /* C=A op B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X/X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* op is DIVIDE, DIVIDEINT, REMAINDER, or REMNEAR respectively. */ /* status is the usual accumulator */ /* */ /* C must have space for set->digits digits. */ /* */ /* ------------------------------------------------------------------ */ /* The underlying algorithm of this routine is the same as in the */ /* 1981 S/370 implementation, that is, non-restoring long division */ /* with bi-unit (rather than bi-digit) estimation for each unit */ /* multiplier. In this pseudocode overview, complications for the */ /* Remainder operators and division residues for exact rounding are */ /* omitted for clarity. */ /* */ /* Prepare operands and handle special values */ /* Test for x/0 and then 0/x */ /* Exp =Exp1 - Exp2 */ /* Exp =Exp +len(var1) -len(var2) */ /* Sign=Sign1 * Sign2 */ /* Pad accumulator (Var1) to double-length with 0's (pad1) */ /* Pad Var2 to same length as Var1 */ /* msu2pair/plus=1st 2 or 1 units of var2, +1 to allow for round */ /* have=0 */ /* Do until (have=digits+1 OR residue=0) */ /* if exp<0 then if integer divide/residue then leave */ /* this_unit=0 */ /* Do forever */ /* compare numbers */ /* if <0 then leave inner_loop */ /* if =0 then (* quick exit without subtract *) do */ /* this_unit=this_unit+1; output this_unit */ /* leave outer_loop; end */ /* Compare lengths of numbers (mantissae): */ /* If same then tops2=msu2pair -- {units 1&2 of var2} */ /* else tops2=msu2plus -- {0, unit 1 of var2} */ /* tops1=first_unit_of_Var1*10**DECDPUN +second_unit_of_var1 */ /* mult=tops1/tops2 -- Good and safe guess at divisor */ /* if mult=0 then mult=1 */ /* this_unit=this_unit+mult */ /* subtract */ /* end inner_loop */ /* if have\=0 | this_unit\=0 then do */ /* output this_unit */ /* have=have+1; end */ /* var2=var2/10 */ /* exp=exp-1 */ /* end outer_loop */ /* exp=exp+1 -- set the proper exponent */ /* if have=0 then generate answer=0 */ /* Return (Result is defined by Var1) */ /* */ /* ------------------------------------------------------------------ */ /* Two working buffers are needed during the division; one (digits+ */ /* 1) to accumulate the result, and the other (up to 2*digits+1) for */ /* long subtractions. These are acc and var1 respectively. */ /* var1 is a copy of the lhs coefficient, var2 is the rhs coefficient.*/ /* ------------------------------------------------------------------ */ static decNumber * decDivideOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, Flag op, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif Unit accbuff[SD2U(DECBUFFER+DECDPUN)]; // local buffer Unit *acc=accbuff; // -> accumulator array for result Unit *allocacc=NULL; // -> allocated buffer, iff allocated Unit *accnext; // -> where next digit will go Int acclength; // length of acc needed [Units] Int accunits; // count of units accumulated Int accdigits; // count of digits accumulated Unit varbuff[SD2U(DECBUFFER*2+DECDPUN)*sizeof(Unit)]; // buffer for var1 Unit *var1=varbuff; // -> var1 array for long subtraction Unit *varalloc=NULL; // -> allocated buffer, iff used Unit *msu1; // -> msu of var1 const Unit *var2; // -> var2 array const Unit *msu2; // -> msu of var2 Int msu2plus; // msu2 plus one [does not vary] eInt msu2pair; // msu2 pair plus one [does not vary] Int var1units, var2units; // actual lengths Int var2ulen; // logical length (units) Int var1initpad=0; // var1 initial padding (digits) Int maxdigits; // longest LHS or required acc length Int mult; // multiplier for subtraction Unit thisunit; // current unit being accumulated Int residue; // for rounding Int reqdigits=set->digits; // requested DIGITS Int exponent; // working exponent Int maxexponent=0; // DIVIDE maximum exponent if unrounded uByte bits; // working sign Unit *target; // work const Unit *source; // .. uInt const *pow; // .. Int shift, cut; // .. #if DECSUBSET Int dropped; // work #endif #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] bits=(lhs->bits^rhs->bits)&DECNEG; // assumed sign for divisions // handle infinities and NaNs if (SPECIALARGS) { // a special bit set if (SPECIALARGS & (DECSNAN | DECNAN)) { // one or two NaNs decNaNs(res, lhs, rhs, status); break; } // one or two infinities if (decNumberIsInfinite(lhs)) { // LHS (dividend) is infinite if (decNumberIsInfinite(rhs) || // two infinities are invalid .. op & (REMAINDER | REMNEAR)) { // as is remainder of infinity *status|=DEC_Invalid_operation; break; } // [Note that infinity/0 raises no exceptions] decNumberZero(res); res->bits=bits|DECINF; // set +/- infinity break; } else { // RHS (divisor) is infinite residue=0; if (op&(REMAINDER|REMNEAR)) { // result is [finished clone of] lhs decCopyFit(res, lhs, set, &residue, status); } else { // a division decNumberZero(res); res->bits=bits; // set +/- zero // for DIVIDEINT the exponent is always 0. For DIVIDE, result // is a 0 with infinitely negative exponent, clamped to minimum if (op&DIVIDE) { res->exponent=set->emin-set->digits+1; *status|=DEC_Clamped; } } decFinish(res, set, &residue, status); break; } } // handle 0 rhs (x/0) if (ISZERO(rhs)) { // x/0 is always exceptional if (ISZERO(lhs)) { decNumberZero(res); // [after lhs test] *status|=DEC_Division_undefined;// 0/0 will become NaN } else { decNumberZero(res); if (op&(REMAINDER|REMNEAR)) *status|=DEC_Invalid_operation; else { *status|=DEC_Division_by_zero; // x/0 res->bits=bits|DECINF; // .. is +/- Infinity } } break;} // handle 0 lhs (0/x) if (ISZERO(lhs)) { // 0/x [x!=0] #if DECSUBSET if (!set->extended) decNumberZero(res); else { #endif if (op&DIVIDE) { residue=0; exponent=lhs->exponent-rhs->exponent; // ideal exponent decNumberCopy(res, lhs); // [zeros always fit] res->bits=bits; // sign as computed res->exponent=exponent; // exponent, too decFinalize(res, set, &residue, status); // check exponent } else if (op&DIVIDEINT) { decNumberZero(res); // integer 0 res->bits=bits; // sign as computed } else { // a remainder exponent=rhs->exponent; // [save in case overwrite] decNumberCopy(res, lhs); // [zeros always fit] if (exponentexponent) res->exponent=exponent; // use lower } #if DECSUBSET } #endif break;} // Precalculate exponent. This starts off adjusted (and hence fits // in 31 bits) and becomes the usual unadjusted exponent as the // division proceeds. The order of evaluation is important, here, // to avoid wrap. exponent=(lhs->exponent+lhs->digits)-(rhs->exponent+rhs->digits); // If the working exponent is -ve, then some quick exits are // possible because the quotient is known to be <1 // [for REMNEAR, it needs to be < -1, as -0.5 could need work] if (exponent<0 && !(op==DIVIDE)) { if (op&DIVIDEINT) { decNumberZero(res); // integer part is 0 #if DECSUBSET if (set->extended) #endif res->bits=bits; // set +/- zero break;} // fastpath remainders so long as the lhs has the smaller // (or equal) exponent if (lhs->exponent<=rhs->exponent) { if (op&REMAINDER || exponent<-1) { // It is REMAINDER or safe REMNEAR; result is [finished // clone of] lhs (r = x - 0*y) residue=0; decCopyFit(res, lhs, set, &residue, status); decFinish(res, set, &residue, status); break; } // [unsafe REMNEAR drops through] } } // fastpaths /* Long (slow) division is needed; roll up the sleeves... */ // The accumulator will hold the quotient of the division. // If it needs to be too long for stack storage, then allocate. acclength=D2U(reqdigits+DECDPUN); // in Units if (acclength*sizeof(Unit)>sizeof(accbuff)) { allocacc=(Unit *)malloc(acclength*sizeof(Unit)); if (allocacc==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} acc=allocacc; // use the allocated space } // var1 is the padded LHS ready for subtractions. // If it needs to be too long for stack storage, then allocate. // The maximum units needed for var1 (long subtraction) is: // Enough for // (rhs->digits+reqdigits-1) -- to allow full slide to right // or (lhs->digits) -- to allow for long lhs // whichever is larger // +1 -- for rounding of slide to right // +1 -- for leading 0s // +1 -- for pre-adjust if a remainder or DIVIDEINT // [Note: unused units do not participate in decUnitAddSub data] maxdigits=rhs->digits+reqdigits-1; if (lhs->digits>maxdigits) maxdigits=lhs->digits; var1units=D2U(maxdigits)+2; // allocate a guard unit above msu1 for REMAINDERNEAR if (!(op&DIVIDE)) var1units++; if ((var1units+1)*sizeof(Unit)>sizeof(varbuff)) { varalloc=(Unit *)malloc((var1units+1)*sizeof(Unit)); if (varalloc==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} var1=varalloc; // use the allocated space } // Extend the lhs and rhs to full long subtraction length. The lhs // is truly extended into the var1 buffer, with 0 padding, so a // subtract in place is always possible. The rhs (var2) has // virtual padding (implemented by decUnitAddSub). // One guard unit was allocated above msu1 for rem=rem+rem in // REMAINDERNEAR. msu1=var1+var1units-1; // msu of var1 source=lhs->lsu+D2U(lhs->digits)-1; // msu of input array for (target=msu1; source>=lhs->lsu; source--, target--) *target=*source; for (; target>=var1; target--) *target=0; // rhs (var2) is left-aligned with var1 at the start var2ulen=var1units; // rhs logical length (units) var2units=D2U(rhs->digits); // rhs actual length (units) var2=rhs->lsu; // -> rhs array msu2=var2+var2units-1; // -> msu of var2 [never changes] // now set up the variables which will be used for estimating the // multiplication factor. If these variables are not exact, add // 1 to make sure that the multiplier is never overestimated. msu2plus=*msu2; // it's value .. if (var2units>1) msu2plus++; // .. +1 if any more msu2pair=(eInt)*msu2*(DECDPUNMAX+1);// top two pair .. if (var2units>1) { // .. [else treat 2nd as 0] msu2pair+=*(msu2-1); // .. if (var2units>2) msu2pair++; // .. +1 if any more } // The calculation is working in units, which may have leading zeros, // but the exponent was calculated on the assumption that they are // both left-aligned. Adjust the exponent to compensate: add the // number of leading zeros in var1 msu and subtract those in var2 msu. // [This is actually done by counting the digits and negating, as // lead1=DECDPUN-digits1, and similarly for lead2.] for (pow=&powers[1]; *msu1>=*pow; pow++) exponent--; for (pow=&powers[1]; *msu2>=*pow; pow++) exponent++; // Now, if doing an integer divide or remainder, ensure that // the result will be Unit-aligned. To do this, shift the var1 // accumulator towards least if need be. (It's much easier to // do this now than to reassemble the residue afterwards, if // doing a remainder.) Also ensure the exponent is not negative. if (!(op&DIVIDE)) { Unit *u; // work // save the initial 'false' padding of var1, in digits var1initpad=(var1units-D2U(lhs->digits))*DECDPUN; // Determine the shift to do. if (exponent<0) cut=-exponent; else cut=DECDPUN-exponent%DECDPUN; decShiftToLeast(var1, var1units, cut); exponent+=cut; // maintain numerical value var1initpad-=cut; // .. and reduce padding // clean any most-significant units which were just emptied for (u=msu1; cut>=DECDPUN; cut-=DECDPUN, u--) *u=0; } // align else { // is DIVIDE maxexponent=lhs->exponent-rhs->exponent; // save // optimization: if the first iteration will just produce 0, // preadjust to skip it [valid for DIVIDE only] if (*msu1<*msu2) { var2ulen--; // shift down exponent-=DECDPUN; // update the exponent } } // ---- start the long-division loops ------------------------------ accunits=0; // no units accumulated yet accdigits=0; // .. or digits accnext=acc+acclength-1; // -> msu of acc [NB: allows digits+1] for (;;) { // outer forever loop thisunit=0; // current unit assumed 0 // find the next unit for (;;) { // inner forever loop // strip leading zero units [from either pre-adjust or from // subtract last time around]. Leave at least one unit. for (; *msu1==0 && msu1>var1; msu1--) var1units--; if (var1units msu for (pv1=msu1; ; pv1--, pv2--) { // v1=*pv1 -- always OK v2=0; // assume in padding if (pv2>=var2) v2=*pv2; // in range if (*pv1!=v2) break; // no longer the same if (pv1==var1) break; // done; leave pv1 as is } // here when all inspected or a difference seen if (*pv1v2. Prepare for real subtraction; the lengths are equal // Estimate the multiplier (there's always a msu1-1)... // Bring in two units of var2 to provide a good estimate. mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2pair); } // lengths the same else { // var1units > var2ulen, so subtraction is safe // The var2 msu is one unit towards the lsu of the var1 msu, // so only one unit for var2 can be used. mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2plus); } if (mult==0) mult=1; // must always be at least 1 // subtraction needed; var1 is > var2 thisunit=(Unit)(thisunit+mult); // accumulate // subtract var1-var2, into var1; only the overlap needs // processing, as this is an in-place calculation shift=var2ulen-var2units; #if DECTRACE decDumpAr('1', &var1[shift], var1units-shift); decDumpAr('2', var2, var2units); printf("m=%d\n", -mult); #endif decUnitAddSub(&var1[shift], var1units-shift, var2, var2units, 0, &var1[shift], -mult); #if DECTRACE decDumpAr('#', &var1[shift], var1units-shift); #endif // var1 now probably has leading zeros; these are removed at the // top of the inner loop. } // inner loop // The next unit has been calculated in full; unless it's a // leading zero, add to acc if (accunits!=0 || thisunit!=0) { // is first or non-zero *accnext=thisunit; // store in accumulator // account exactly for the new digits if (accunits==0) { accdigits++; // at least one for (pow=&powers[1]; thisunit>=*pow; pow++) accdigits++; } else accdigits+=DECDPUN; accunits++; // update count accnext--; // ready for next if (accdigits>reqdigits) break; // have enough digits } // if the residue is zero, the operation is done (unless divide // or divideInteger and still not enough digits yet) if (*var1==0 && var1units==1) { // residue is 0 if (op&(REMAINDER|REMNEAR)) break; if ((op&DIVIDE) && (exponent<=maxexponent)) break; // [drop through if divideInteger] } // also done enough if calculating remainder or integer // divide and just did the last ('units') unit if (exponent==0 && !(op&DIVIDE)) break; // to get here, var1 is less than var2, so divide var2 by the per- // Unit power of ten and go for the next digit var2ulen--; // shift down exponent-=DECDPUN; // update the exponent } // outer loop // ---- division is complete --------------------------------------- // here: acc has at least reqdigits+1 of good results (or fewer // if early stop), starting at accnext+1 (its lsu) // var1 has any residue at the stopping point // accunits is the number of digits collected in acc if (accunits==0) { // acc is 0 accunits=1; // show have a unit .. accdigits=1; // .. *accnext=0; // .. whose value is 0 } else accnext++; // back to last placed // accnext now -> lowest unit of result residue=0; // assume no residue if (op&DIVIDE) { // record the presence of any residue, for rounding if (*var1!=0 || var1units>1) residue=1; else { // no residue // Had an exact division; clean up spurious trailing 0s. // There will be at most DECDPUN-1, from the final multiply, // and then only if the result is non-0 (and even) and the // exponent is 'loose'. #if DECDPUN>1 Unit lsu=*accnext; if (!(lsu&0x01) && (lsu!=0)) { // count the trailing zeros Int drop=0; for (;; drop++) { // [will terminate because lsu!=0] if (exponent>=maxexponent) break; // don't chop real 0s #if DECDPUN<=4 if ((lsu-QUOT10(lsu, drop+1) *powers[drop+1])!=0) break; // found non-0 digit #else if (lsu%powers[drop+1]!=0) break; // found non-0 digit #endif exponent++; } if (drop>0) { accunits=decShiftToLeast(accnext, accunits, drop); accdigits=decGetDigits(accnext, accunits); accunits=D2U(accdigits); // [exponent was adjusted in the loop] } } // neither odd nor 0 #endif } // exact divide } // divide else /* op!=DIVIDE */ { // check for coefficient overflow if (accdigits+exponent>reqdigits) { *status|=DEC_Division_impossible; break; } if (op & (REMAINDER|REMNEAR)) { // [Here, the exponent will be 0, because var1 was adjusted // appropriately.] Int postshift; // work Flag wasodd=0; // integer was odd Unit *quotlsu; // for save Int quotdigits; // .. // Fastpath when residue is truly 0 is worthwhile [and // simplifies the code below] if (*var1==0 && var1units==1) { // residue is 0 Int exp=lhs->exponent; // save min(exponents) if (rhs->exponentexponent; decNumberZero(res); // 0 coefficient #if DECSUBSET if (set->extended) #endif res->exponent=exp; // .. with proper exponent break; } // note if the quotient was odd if (*accnext & 0x01) wasodd=1; // acc is odd quotlsu=accnext; // save in case need to reinspect quotdigits=accdigits; // .. // treat the residue, in var1, as the value to return, via acc // calculate the unused zero digits. This is the smaller of: // var1 initial padding (saved above) // var2 residual padding, which happens to be given by: postshift=var1initpad+exponent-lhs->exponent+rhs->exponent; // [the 'exponent' term accounts for the shifts during divide] if (var1initpadexponent; // exponent is smaller of lhs & rhs if (rhs->exponentexponent; bits=lhs->bits; // remainder sign is always as lhs // Now correct the result if doing remainderNear; if it // (looking just at coefficients) is > rhs/2, or == rhs/2 and // the integer was odd then the result should be rem-rhs. if (op&REMNEAR) { Int compare, tarunits; // work Unit *up; // .. // calculate remainder*2 into the var1 buffer (which has // 'headroom' of an extra unit and hence enough space) // [a dedicated 'double' loop would be faster, here] tarunits=decUnitAddSub(accnext, accunits, accnext, accunits, 0, accnext, 1); // decDumpAr('r', accnext, tarunits); // Here, accnext (var1) holds tarunits Units with twice the // remainder's coefficient, which must now be compared to the // RHS. The remainder's exponent may be smaller than the RHS's. compare=decUnitCompare(accnext, tarunits, rhs->lsu, D2U(rhs->digits), rhs->exponent-exponent); if (compare==BADINT) { // deep trouble *status|=DEC_Insufficient_storage; break;} // now restore the remainder by dividing by two; the lsu // is known to be even. for (up=accnext; up0 || (compare==0 && wasodd)) { // adjustment needed Int exp, expunits, exprem; // work // This is effectively causing round-up of the quotient, // so if it was the rare case where it was full and all // nines, it would overflow and hence division-impossible // should be raised Flag allnines=0; // 1 if quotient all nines if (quotdigits==reqdigits) { // could be borderline for (up=quotlsu; ; up++) { if (quotdigits>DECDPUN) { if (*up!=DECDPUNMAX) break;// non-nines } else { // this is the last Unit if (*up==powers[quotdigits]-1) allnines=1; break; } quotdigits-=DECDPUN; // checked those digits } // up } // borderline check if (allnines) { *status|=DEC_Division_impossible; break;} // rem-rhs is needed; the sign will invert. Again, var1 // can safely be used for the working Units array. exp=rhs->exponent-exponent; // RHS padding needed // Calculate units and remainder from exponent. expunits=exp/DECDPUN; exprem=exp%DECDPUN; // subtract [A+B*(-m)]; the result will always be negative accunits=-decUnitAddSub(accnext, accunits, rhs->lsu, D2U(rhs->digits), expunits, accnext, -(Int)powers[exprem]); accdigits=decGetDigits(accnext, accunits); // count digits exactly accunits=D2U(accdigits); // and recalculate the units for copy // [exponent is as for original remainder] bits^=DECNEG; // flip the sign } } // REMNEAR } // REMAINDER or REMNEAR } // not DIVIDE // Set exponent and bits res->exponent=exponent; res->bits=(uByte)(bits&DECNEG); // [cleaned] // Now the coefficient. decSetCoeff(res, set, accnext, accdigits, &residue, status); decFinish(res, set, &residue, status); // final cleanup #if DECSUBSET // If a divide then strip trailing zeros if subset [after round] if (!set->extended && (op==DIVIDE)) decTrim(res, 0, &dropped); #endif } while(0); // end protected if (varalloc!=NULL) free(varalloc); // drop any storage used if (allocacc!=NULL) free(allocacc); // .. #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // .. if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decDivideOp /* ------------------------------------------------------------------ */ /* decMultiplyOp -- multiplication operation */ /* */ /* This routine performs the multiplication C=A x B. */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X*X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* status is the usual accumulator */ /* */ /* C must have space for set->digits digits. */ /* */ /* ------------------------------------------------------------------ */ /* 'Classic' multiplication is used rather than Karatsuba, as the */ /* latter would give only a minor improvement for the short numbers */ /* expected to be handled most (and uses much more memory). */ /* */ /* There are two major paths here: the general-purpose ('old code') */ /* path which handles all DECDPUN values, and a fastpath version */ /* which is used if 64-bit ints are available, DECDPUN<=4, and more */ /* than two calls to decUnitAddSub would be made. */ /* */ /* The fastpath version lumps units together into 8-digit or 9-digit */ /* chunks, and also uses a lazy carry strategy to minimise expensive */ /* 64-bit divisions. The chunks are then broken apart again into */ /* units for continuing processing. Despite this overhead, the */ /* fastpath can speed up some 16-digit operations by 10x (and much */ /* more for higher-precision calculations). */ /* */ /* A buffer always has to be used for the accumulator; in the */ /* fastpath, buffers are also always needed for the chunked copies of */ /* of the operand coefficients. */ /* ------------------------------------------------------------------ */ #define FASTMUL (DECUSE64 && DECDPUN<5) static decNumber * decMultiplyOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, uInt *status) { Int accunits; // Units of accumulator in use Int exponent; // work Int residue=0; // rounding residue uByte bits; // result sign Unit *acc; // -> accumulator Unit array Int needbytes; // size calculator void *allocacc=NULL; // -> allocated accumulator, iff allocated Unit accbuff[SD2U(DECBUFFER*2+5)]; // buffer (+1 for DECBUFFER==0, // + 4 for calls from other operations) const Unit *mer, *mermsup; // work Int madlength; // Units in multiplicand Int shift; // Units to shift multiplicand by #if FASTMUL // if DECDPUN is 1 or 3 work in base 10**9, otherwise // (DECDPUN is 2 or 4) then work in base 10**8 #if DECDPUN & 1 // odd #define FASTBASE 1000000000 // base #define FASTDIGS 9 // digits in base #define FASTLAZY 18 // carry resolution point [1->18] #else #define FASTBASE 100000000 #define FASTDIGS 8 #define FASTLAZY 1844 // carry resolution point [1->1844] #endif // three buffers are used, two for chunked copies of the operands // (base 10**8 or base 10**9) and one base 2**64 accumulator with // lazy carry evaluation uInt zlhibuff[(DECBUFFER+7)/8+1]; // buffer (+1 for DECBUFFER==0) uInt *zlhi=zlhibuff; // -> lhs array uInt *alloclhi=NULL; // -> allocated buffer, iff allocated uInt zrhibuff[(DECBUFFER+7)/8+1]; // buffer (+1 for DECBUFFER==0) uInt *zrhi=zrhibuff; // -> rhs array uInt *allocrhi=NULL; // -> allocated buffer, iff allocated uLong zaccbuff[(DECBUFFER+3)/4+2]; // buffer (+1 for DECBUFFER==0) // + 1 for calls from other operations) // [allocacc is shared for both paths, as only one will run] uLong *zacc=zaccbuff; // -> accumulator array for exact result #if DECDPUN==1 Int zoff; // accumulator offset #endif uInt *lip, *rip; // item pointers uInt *lmsi, *rmsi; // most significant items Int ilhs, irhs, iacc; // item counts in the arrays Int lazy; // lazy carry counter uLong lcarry; // uLong carry uInt carry; // carry (NB not uLong) Int count; // work const Unit *cup; // .. Unit *up; // .. uLong *lp; // .. Int p; // .. #endif #if DECSUBSET decNumber *alloclhs=NULL; // -> allocated buffer, iff allocated decNumber *allocrhs=NULL; // -> allocated buffer, iff allocated #endif #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif // precalculate result sign bits=(uByte)((lhs->bits^rhs->bits)&DECNEG); // handle infinities and NaNs if (SPECIALARGS) { // a special bit set if (SPECIALARGS & (DECSNAN | DECNAN)) { // one or two NaNs decNaNs(res, lhs, rhs, status); return res;} // one or two infinities; Infinity * 0 is invalid if (((lhs->bits & DECINF)==0 && ISZERO(lhs)) ||((rhs->bits & DECINF)==0 && ISZERO(rhs))) { *status|=DEC_Invalid_operation; return res;} decNumberZero(res); res->bits=bits|DECINF; // infinity return res;} // For best speed, as in DMSRCN [the original Rexx numerics // module], use the shorter number as the multiplier (rhs) and // the longer as the multiplicand (lhs) to minimise the number of // adds (partial products) if (lhs->digitsdigits) { // swap... const decNumber *hold=lhs; lhs=rhs; rhs=hold; } do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>set->digits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] #if FASTMUL // fastpath can be used // use the fast path if there are enough digits in the shorter // operand to make the setup and takedown worthwhile #define NEEDTWO (DECDPUN*2) // within two decUnitAddSub calls if (rhs->digits>NEEDTWO) { // use fastpath... // calculate the number of elements in each array ilhs=(lhs->digits+FASTDIGS-1)/FASTDIGS; // [ceiling] irhs=(rhs->digits+FASTDIGS-1)/FASTDIGS; // .. iacc=ilhs+irhs; // allocate buffers if required, as usual needbytes=ilhs*sizeof(uInt); if (needbytes>(Int)sizeof(zlhibuff)) { alloclhi=(uInt *)malloc(needbytes); zlhi=alloclhi;} needbytes=irhs*sizeof(uInt); if (needbytes>(Int)sizeof(zrhibuff)) { allocrhi=(uInt *)malloc(needbytes); zrhi=allocrhi;} // Allocating the accumulator space needs a special case when // DECDPUN=1 because when converting the accumulator to Units // after the multiplication each 8-byte item becomes 9 1-byte // units. Therefore iacc extra bytes are needed at the front // (rounded up to a multiple of 8 bytes), and the uLong // accumulator starts offset the appropriate number of units // to the right to avoid overwrite during the unchunking. needbytes=iacc*sizeof(uLong); #if DECDPUN==1 zoff=(iacc+7)/8; // items to offset by needbytes+=zoff*8; #endif if (needbytes>(Int)sizeof(zaccbuff)) { allocacc=(uLong *)malloc(needbytes); zacc=(uLong *)allocacc;} if (zlhi==NULL||zrhi==NULL||zacc==NULL) { *status|=DEC_Insufficient_storage; break;} acc=(Unit *)zacc; // -> target Unit array #if DECDPUN==1 zacc+=zoff; // start uLong accumulator to right #endif // assemble the chunked copies of the left and right sides for (count=lhs->digits, cup=lhs->lsu, lip=zlhi; count>0; lip++) for (p=0, *lip=0; p0; p+=DECDPUN, cup++, count-=DECDPUN) *lip+=*cup*powers[p]; lmsi=lip-1; // save -> msi for (count=rhs->digits, cup=rhs->lsu, rip=zrhi; count>0; rip++) for (p=0, *rip=0; p0; p+=DECDPUN, cup++, count-=DECDPUN) *rip+=*cup*powers[p]; rmsi=rip-1; // save -> msi // zero the accumulator for (lp=zacc; lp0 && rip!=rmsi) continue; lazy=FASTLAZY; // reset delay count // spin up the accumulator resolving overflows for (lp=zacc; lp assume buffer for accumulator needbytes=(D2U(lhs->digits)+D2U(rhs->digits))*sizeof(Unit); if (needbytes>(Int)sizeof(accbuff)) { allocacc=(Unit *)malloc(needbytes); if (allocacc==NULL) {*status|=DEC_Insufficient_storage; break;} acc=(Unit *)allocacc; // use the allocated space } /* Now the main long multiplication loop */ // Unlike the equivalent in the IBM Java implementation, there // is no advantage in calculating from msu to lsu. So, do it // by the book, as it were. // Each iteration calculates ACC=ACC+MULTAND*MULT accunits=1; // accumulator starts at '0' *acc=0; // .. (lsu=0) shift=0; // no multiplicand shift at first madlength=D2U(lhs->digits); // this won't change mermsup=rhs->lsu+D2U(rhs->digits); // -> msu+1 of multiplier for (mer=rhs->lsu; merlsu, madlength, 0, &acc[shift], *mer) + shift; else { // extend acc with a 0; it will be used shortly *(acc+accunits)=0; // [this avoids length of <=0 later] accunits++; } // multiply multiplicand by 10**DECDPUN for next Unit to left shift++; // add this for 'logical length' } // n #if FASTMUL } // unchunked units #endif // common end-path #if DECTRACE decDumpAr('*', acc, accunits); // Show exact result #endif // acc now contains the exact result of the multiplication, // possibly with a leading zero unit; build the decNumber from // it, noting if any residue res->bits=bits; // set sign res->digits=decGetDigits(acc, accunits); // count digits exactly // There can be a 31-bit wrap in calculating the exponent. // This can only happen if both input exponents are negative and // both their magnitudes are large. If there was a wrap, set a // safe very negative exponent, from which decFinalize() will // raise a hard underflow shortly. exponent=lhs->exponent+rhs->exponent; // calculate exponent if (lhs->exponent<0 && rhs->exponent<0 && exponent>0) exponent=-2*DECNUMMAXE; // force underflow res->exponent=exponent; // OK to overwrite now // Set the coefficient. If any rounding, residue records decSetCoeff(res, set, acc, res->digits, &residue, status); decFinish(res, set, &residue, status); // final cleanup } while(0); // end protected if (allocacc!=NULL) free(allocacc); // drop any storage used #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // .. if (alloclhs!=NULL) free(alloclhs); // .. #endif #if FASTMUL if (allocrhi!=NULL) free(allocrhi); // .. if (alloclhi!=NULL) free(alloclhi); // .. #endif return res; } // decMultiplyOp /* ------------------------------------------------------------------ */ /* decExpOp -- effect exponentiation */ /* */ /* This computes C = exp(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. status is updated but */ /* not set. */ /* */ /* Restrictions: */ /* */ /* digits, emax, and -emin in the context must be less than */ /* 2*DEC_MAX_MATH (1999998), and the rhs must be within these */ /* bounds or a zero. This is an internal routine, so these */ /* restrictions are contractual and not enforced. */ /* */ /* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* */ /* Finite results will always be full precision and Inexact, except */ /* when A is a zero or -Infinity (giving 1 or 0 respectively). */ /* ------------------------------------------------------------------ */ /* This approach used here is similar to the algorithm described in */ /* */ /* Variable Precision Exponential Function, T. E. Hull and */ /* A. Abrham, ACM Transactions on Mathematical Software, Vol 12 #2, */ /* pp79-91, ACM, June 1986. */ /* */ /* with the main difference being that the iterations in the series */ /* evaluation are terminated dynamically (which does not require the */ /* extra variable-precision variables which are expensive in this */ /* context). */ /* */ /* The error analysis in Hull & Abrham's paper applies except for the */ /* round-off error accumulation during the series evaluation. This */ /* code does not precalculate the number of iterations and so cannot */ /* use Horner's scheme. Instead, the accumulation is done at double- */ /* precision, which ensures that the additions of the terms are exact */ /* and do not accumulate round-off (and any round-off errors in the */ /* terms themselves move 'to the right' faster than they can */ /* accumulate). This code also extends the calculation by allowing, */ /* in the spirit of other decNumber operators, the input to be more */ /* precise than the result (the precision used is based on the more */ /* precise of the input or requested result). */ /* */ /* Implementation notes: */ /* */ /* 1. This is separated out as decExpOp so it can be called from */ /* other Mathematical functions (notably Ln) with a wider range */ /* than normal. In particular, it can handle the slightly wider */ /* (double) range needed by Ln (which has to be able to calculate */ /* exp(-x) where x can be the tiniest number (Ntiny). */ /* */ /* 2. Normalizing x to be <=0.1 (instead of <=1) reduces loop */ /* iterations by appoximately a third with additional (although */ /* diminishing) returns as the range is reduced to even smaller */ /* fractions. However, h (the power of 10 used to correct the */ /* result at the end, see below) must be kept <=8 as otherwise */ /* the final result cannot be computed. Hence the leverage is a */ /* sliding value (8-h), where potentially the range is reduced */ /* more for smaller values. */ /* */ /* The leverage that can be applied in this way is severely */ /* limited by the cost of the raise-to-the power at the end, */ /* which dominates when the number of iterations is small (less */ /* than ten) or when rhs is short. As an example, the adjustment */ /* x**10,000,000 needs 31 multiplications, all but one full-width. */ /* */ /* 3. The restrictions (especially precision) could be raised with */ /* care, but the full decNumber range seems very hard within the */ /* 32-bit limits. */ /* ------------------------------------------------------------------ */ decNumber * decExpOp(decNumber *res, const decNumber *rhs, decContext *set, uInt *status) { uInt ignore=0; // working status Int h; // adjusted exponent for 0.xxxx Int p; // working precision Int residue; // rounding residue uInt needbytes; // for space calculations const decNumber *x=rhs; // (may point to safe copy later) decContext aset, tset, dset; // working contexts // the argument is often copied to normalize it, so (unusually) it // is treated like other buffers, using DECBUFFER, +1 in case // DECBUFFER is 0 decNumber bufr[D2N(DECBUFFER+1)]; decNumber *allocrhs=NULL; // non-NULL if rhs buffer allocated // the working precision will be no more than set->digits+8+1 // so for on-stack buffers DECBUFFER+9 is used, +1 in case DECBUFFER // is 0 (and twice that for the accumulator) // buffer for t, term (working precision plus) decNumber buft[D2N(DECBUFFER+9+1)]; decNumber *allocbuft=NULL; // -> allocated buft, iff allocated decNumber *t=buft; // term // buffer for a, accumulator (working precision * 2), at least 9 decNumber bufa[D2N(DECBUFFER*2+18+1)]; decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *a=bufa; // accumulator // decNumber for the divisor term; this needs at most 9 digits // and so can be fixed size [16 so can use standard context] decNumber bufd[D2N(16)]; decNumber *d=bufd; // divisor decNumber numone; // constant 1 #if DECCHECK Int iterations=0; // for later sanity check if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage if (SPECIALARG) { // handle infinities and NaNs if (decNumberIsInfinite(rhs)) { // an infinity if (decNumberIsNegative(rhs)) // -Infinity -> +0 decNumberZero(res); else decNumberCopy(res, rhs); // +Infinity -> self } else decNaNs(res, rhs, NULL, status); // a NaN break;} if (ISZERO(rhs)) { // zeros -> exact 1 decNumberZero(res); // make clean 1 *res->lsu=1; // .. break;} // [no status to set] // e**x when 0 < x < 0.66 is < 1+3x/2, hence can fast-path // positive and negative tiny cases which will result in inexact // 1. This also allows the later add-accumulate to always be // exact (because its length will never be more than twice the // working precision). // The comparator (tiny) needs just one digit, so use the // decNumber d for it (reused as the divisor, etc., below); its // exponent is such that if x is positive it will have // set->digits-1 zeros between the decimal point and the digit, // which is 4, and if x is negative one more zero there as the // more precise result will be of the form 0.9999999 rather than // 1.0000001. Hence, tiny will be 0.0000004 if digits=7 and x>0 // or 0.00000004 if digits=7 and x<0. If RHS not larger than // this then the result will be 1.000000 decNumberZero(d); // clean *d->lsu=4; // set 4 .. d->exponent=-set->digits; // * 10**(-d) if (decNumberIsNegative(rhs)) d->exponent--; // negative case if (decCompare(d, rhs, 1)>=0) { // signless compare Int shift=set->digits-1; decNumberZero(res); // set 1 *res->lsu=1; // .. res->digits=decShiftToMost(res->lsu, 1, shift); res->exponent=-shift; // make 1.0000... *status|=DEC_Inexact | DEC_Rounded; // .. inexactly break;} // tiny // set up the context to be used for calculating a, as this is // used on both paths below decContextDefault(&aset, DEC_INIT_DECIMAL64); // accumulator bounds are as requested (could underflow) aset.emax=set->emax; // usual bounds aset.emin=set->emin; // .. aset.clamp=0; // and no concrete format // calculate the adjusted (Hull & Abrham) exponent (where the // decimal point is just to the left of the coefficient msd) h=rhs->exponent+rhs->digits; // if h>8 then 10**h cannot be calculated safely; however, when // h=8 then exp(|rhs|) will be at least exp(1E+7) which is at // least 6.59E+4342944, so (due to the restriction on Emax/Emin) // overflow (or underflow to 0) is guaranteed -- so this case can // be handled by simply forcing the appropriate excess if (h>8) { // overflow/underflow // set up here so Power call below will over or underflow to // zero; set accumulator to either 2 or 0.02 // [stack buffer for a is always big enough for this] decNumberZero(a); *a->lsu=2; // not 1 but < exp(1) if (decNumberIsNegative(rhs)) a->exponent=-2; // make 0.02 h=8; // clamp so 10**h computable p=9; // set a working precision } else { // h<=8 Int maxlever=(rhs->digits>8?1:0); // [could/should increase this for precisions >40 or so, too] // if h is 8, cannot normalize to a lower upper limit because // the final result will not be computable (see notes above), // but leverage can be applied whenever h is less than 8. // Apply as much as possible, up to a MAXLEVER digits, which // sets the tradeoff against the cost of the later a**(10**h). // As h is increased, the working precision below also // increases to compensate for the "constant digits at the // front" effect. Int lever=MIN(8-h, maxlever); // leverage attainable Int use=-rhs->digits-lever; // exponent to use for RHS h+=lever; // apply leverage selected if (h<0) { // clamp use+=h; // [may end up subnormal] h=0; } // Take a copy of RHS if it needs normalization (true whenever x>=1) if (rhs->exponent!=use) { decNumber *newrhs=bufr; // assume will fit on stack needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufr)) { // need malloc space allocrhs=(decNumber *)malloc(needbytes); if (allocrhs==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} newrhs=allocrhs; // use the allocated space } decNumberCopy(newrhs, rhs); // copy to safe space newrhs->exponent=use; // normalize; now <1 x=newrhs; // ready for use // decNumberShow(x); } // Now use the usual power series to evaluate exp(x). The // series starts as 1 + x + x^2/2 ... so prime ready for the // third term by setting the term variable t=x, the accumulator // a=1, and the divisor d=2. // First determine the working precision. From Hull & Abrham // this is set->digits+h+2. However, if x is 'over-precise' we // need to allow for all its digits to potentially participate // (consider an x where all the excess digits are 9s) so in // this case use x->digits+h+2 p=MAX(x->digits, set->digits)+h+2; // a and t are variable precision, and depend on p, so space // must be allocated for them if necessary // the accumulator needs to be able to hold 2p digits so that // the additions on the second and subsequent iterations are // sufficiently exact. needbytes=sizeof(decNumber)+(D2U(p*2)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space } // the term needs to be able to hold p digits (which is // guaranteed to be larger than x->digits, so the initial copy // is safe); it may also be used for the raise-to-power // calculation below, which needs an extra two digits needbytes=sizeof(decNumber)+(D2U(p+2)-1)*sizeof(Unit); if (needbytes>sizeof(buft)) { // need malloc space allocbuft=(decNumber *)malloc(needbytes); if (allocbuft==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} t=allocbuft; // use the allocated space } decNumberCopy(t, x); // term=x decNumberZero(a); *a->lsu=1; // accumulator=1 decNumberZero(d); *d->lsu=2; // divisor=2 decNumberZero(&numone); *numone.lsu=1; // constant 1 for increment // set up the contexts for calculating a, t, and d decContextDefault(&tset, DEC_INIT_DECIMAL64); dset=tset; // accumulator bounds are set above, set precision now aset.digits=p*2; // double // term bounds avoid any underflow or overflow tset.digits=p; tset.emin=DEC_MIN_EMIN; // [emax is plenty] // [dset.digits=16, etc., are sufficient] // finally ready to roll for (;;) { #if DECCHECK iterations++; #endif // only the status from the accumulation is interesting // [but it should remain unchanged after first add] decAddOp(a, a, t, &aset, 0, status); // a=a+t decMultiplyOp(t, t, x, &tset, &ignore); // t=t*x decDivideOp(t, t, d, &tset, DIVIDE, &ignore); // t=t/d // the iteration ends when the term cannot affect the result, // if rounded to p digits, which is when its value is smaller // than the accumulator by p+1 digits. There must also be // full precision in a. if (((a->digits+a->exponent)>=(t->digits+t->exponent+p+1)) && (a->digits>=p)) break; decAddOp(d, d, &numone, &dset, 0, &ignore); // d=d+1 } // iterate #if DECCHECK // just a sanity check; comment out test to show always if (iterations>p+3) printf("Exp iterations=%d, status=%08x, p=%d, d=%d\n", iterations, *status, p, x->digits); #endif } // h<=8 // apply postconditioning: a=a**(10**h) -- this is calculated // at a slightly higher precision than Hull & Abrham suggest if (h>0) { Int seenbit=0; // set once a 1-bit is seen Int i; // counter Int n=powers[h]; // always positive aset.digits=p+2; // sufficient precision // avoid the overhead and many extra digits of decNumberPower // as all that is needed is the short 'multipliers' loop; here // accumulate the answer into t decNumberZero(t); *t->lsu=1; // acc=1 for (i=1;;i++){ // for each bit [top bit ignored] // abandon if have had overflow or terminal underflow if (*status & (DEC_Overflow|DEC_Underflow)) { // interesting? if (*status&DEC_Overflow || ISZERO(t)) break;} n=n<<1; // move next bit to testable position if (n<0) { // top bit is set seenbit=1; // OK, have a significant bit decMultiplyOp(t, t, a, &aset, status); // acc=acc*x } if (i==31) break; // that was the last bit if (!seenbit) continue; // no need to square 1 decMultiplyOp(t, t, t, &aset, status); // acc=acc*acc [square] } /*i*/ // 32 bits // decNumberShow(t); a=t; // and carry on using t instead of a } // Copy and round the result to res residue=1; // indicate dirt to right .. if (ISZERO(a)) residue=0; // .. unless underflowed to 0 aset.digits=set->digits; // [use default rounding] decCopyFit(res, a, &aset, &residue, status); // copy & shorten decFinish(res, set, &residue, status); // cleanup/set flags } while(0); // end protected if (allocrhs !=NULL) free(allocrhs); // drop any storage used if (allocbufa!=NULL) free(allocbufa); // .. if (allocbuft!=NULL) free(allocbuft); // .. // [status is handled by caller] return res; } // decExpOp /* ------------------------------------------------------------------ */ /* Initial-estimate natural logarithm table */ /* */ /* LNnn -- 90-entry 16-bit table for values from .10 through .99. */ /* The result is a 4-digit encode of the coefficient (c=the */ /* top 14 bits encoding 0-9999) and a 2-digit encode of the */ /* exponent (e=the bottom 2 bits encoding 0-3) */ /* */ /* The resulting value is given by: */ /* */ /* v = -c * 10**(-e-3) */ /* */ /* where e and c are extracted from entry k = LNnn[x-10] */ /* where x is truncated (NB) into the range 10 through 99, */ /* and then c = k>>2 and e = k&3. */ /* ------------------------------------------------------------------ */ const uShort LNnn[90]={9016, 8652, 8316, 8008, 7724, 7456, 7208, 6972, 6748, 6540, 6340, 6148, 5968, 5792, 5628, 5464, 5312, 5164, 5020, 4884, 4748, 4620, 4496, 4376, 4256, 4144, 4032, 39233, 38181, 37157, 36157, 35181, 34229, 33297, 32389, 31501, 30629, 29777, 28945, 28129, 27329, 26545, 25777, 25021, 24281, 23553, 22837, 22137, 21445, 20769, 20101, 19445, 18801, 18165, 17541, 16925, 16321, 15721, 15133, 14553, 13985, 13421, 12865, 12317, 11777, 11241, 10717, 10197, 9685, 9177, 8677, 8185, 7697, 7213, 6737, 6269, 5801, 5341, 4889, 4437, 39930, 35534, 31186, 26886, 22630, 18418, 14254, 10130, 6046, 20055}; /* ------------------------------------------------------------------ */ /* decLnOp -- effect natural logarithm */ /* */ /* This computes C = ln(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Notable cases: */ /* A<0 -> Invalid */ /* A=0 -> -Infinity (Exact) */ /* A=+Infinity -> +Infinity (Exact) */ /* A=1 exactly -> 0 (Exact) */ /* */ /* Restrictions (as for Exp): */ /* */ /* digits, emax, and -emin in the context must be less than */ /* DEC_MAX_MATH+11 (1000010), and the rhs must be within these */ /* bounds or a zero. This is an internal routine, so these */ /* restrictions are contractual and not enforced. */ /* */ /* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* The result is calculated using Newton's method, with each */ /* iteration calculating a' = a + x * exp(-a) - 1. See, for example, */ /* Epperson 1989. */ /* */ /* The iteration ends when the adjustment x*exp(-a)-1 is tiny enough. */ /* This has to be calculated at the sum of the precision of x and the */ /* working precision. */ /* */ /* Implementation notes: */ /* */ /* 1. This is separated out as decLnOp so it can be called from */ /* other Mathematical functions (e.g., Log 10) with a wider range */ /* than normal. In particular, it can handle the slightly wider */ /* (+9+2) range needed by a power function. */ /* */ /* 2. The speed of this function is about 10x slower than exp, as */ /* it typically needs 4-6 iterations for short numbers, and the */ /* extra precision needed adds a squaring effect, twice. */ /* */ /* 3. Fastpaths are included for ln(10) and ln(2), up to length 40, */ /* as these are common requests. ln(10) is used by log10(x). */ /* */ /* 4. An iteration might be saved by widening the LNnn table, and */ /* would certainly save at least one if it were made ten times */ /* bigger, too (for truncated fractions 0.100 through 0.999). */ /* However, for most practical evaluations, at least four or five */ /* iterations will be neede -- so this would only speed up by */ /* 20-25% and that probably does not justify increasing the table */ /* size. */ /* ------------------------------------------------------------------ */ decNumber * decLnOp(decNumber *res, const decNumber *rhs, decContext *set, uInt *status) { uInt ignore=0; // working status accumulator uInt needbytes; // for space calculations Int residue; // rounding residue Int r; // rhs=f*10**r [see below] Int p; // working precision Int pp; // precision for iteration Int t; // work // buffers for a (accumulator, typically precision+2) and b // (adjustment calculator, same size) decNumber bufa[D2N(DECBUFFER+2)]; decNumber *allocbufa=NULL; // -> allocated bufa, iff allocated decNumber *a=bufa; // accumulator/work decNumber bufb[D2N(DECBUFFER+2)]; decNumber *allocbufb=NULL; // -> allocated bufa, iff allocated decNumber *b=bufb; // adjustment/work decNumber numone; // constant 1 decNumber cmp; // work decContext aset, bset; // working contexts #if DECCHECK Int iterations=0; // for later sanity check if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif do { // protect allocated storage if (SPECIALARG) { // handle infinities and NaNs if (decNumberIsInfinite(rhs)) { // an infinity if (decNumberIsNegative(rhs)) // -Infinity -> error *status|=DEC_Invalid_operation; else decNumberCopy(res, rhs); // +Infinity -> self } else decNaNs(res, rhs, NULL, status); // a NaN break;} if (ISZERO(rhs)) { // +/- zeros -> -Infinity decNumberZero(res); // make clean res->bits=DECINF|DECNEG; // set - infinity break;} // [no status to set] // Non-zero negatives are bad... if (decNumberIsNegative(rhs)) { // -x -> error *status|=DEC_Invalid_operation; break;} // Here, rhs is positive, finite, and in range // lookaside fastpath code for ln(2) and ln(10) at common lengths if (rhs->exponent==0 && set->digits<=40) { #if DECDPUN==1 if (rhs->lsu[0]==0 && rhs->lsu[1]==1 && rhs->digits==2) { // ln(10) #else if (rhs->lsu[0]==10 && rhs->digits==2) { // ln(10) #endif aset=*set; aset.round=DEC_ROUND_HALF_EVEN; #define LN10 "2.302585092994045684017991454684364207601" decNumberFromString(res, LN10, &aset); *status|=(DEC_Inexact | DEC_Rounded); // is inexact break;} if (rhs->lsu[0]==2 && rhs->digits==1) { // ln(2) aset=*set; aset.round=DEC_ROUND_HALF_EVEN; #define LN2 "0.6931471805599453094172321214581765680755" decNumberFromString(res, LN2, &aset); *status|=(DEC_Inexact | DEC_Rounded); break;} } // integer and short // Determine the working precision. This is normally the // requested precision + 2, with a minimum of 9. However, if // the rhs is 'over-precise' then allow for all its digits to // potentially participate (consider an rhs where all the excess // digits are 9s) so in this case use rhs->digits+2. p=MAX(rhs->digits, MAX(set->digits, 7))+2; // Allocate space for the accumulator and the high-precision // adjustment calculator, if necessary. The accumulator must // be able to hold p digits, and the adjustment up to // rhs->digits+p digits. They are also made big enough for 16 // digits so that they can be used for calculating the initial // estimate. needbytes=sizeof(decNumber)+(D2U(MAX(p,16))-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { // need malloc space allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} a=allocbufa; // use the allocated space } pp=p+rhs->digits; needbytes=sizeof(decNumber)+(D2U(MAX(pp,16))-1)*sizeof(Unit); if (needbytes>sizeof(bufb)) { // need malloc space allocbufb=(decNumber *)malloc(needbytes); if (allocbufb==NULL) { // hopeless -- abandon *status|=DEC_Insufficient_storage; break;} b=allocbufb; // use the allocated space } // Prepare an initial estimate in acc. Calculate this by // considering the coefficient of x to be a normalized fraction, // f, with the decimal point at far left and multiplied by // 10**r. Then, rhs=f*10**r and 0.1<=f<1, and // ln(x) = ln(f) + ln(10)*r // Get the initial estimate for ln(f) from a small lookup // table (see above) indexed by the first two digits of f, // truncated. decContextDefault(&aset, DEC_INIT_DECIMAL64); // 16-digit extended r=rhs->exponent+rhs->digits; // 'normalised' exponent decPutInt(a, r); // a=r decPutInt(b, 2302585); // b=ln(10) (2.302585) b->exponent=-6; // .. decMultiplyOp(a, a, b, &aset, &ignore); // a=a*b // now get top two digits of rhs into b by simple truncate and // force to integer residue=0; // (no residue) aset.digits=2; aset.round=DEC_ROUND_DOWN; decCopyFit(b, rhs, &aset, &residue, &ignore); // copy & shorten b->exponent=0; // make integer t=decGetInt(b); // [cannot fail] if (t<10) t=X10(t); // adjust single-digit b t=LNnn[t-10]; // look up ln(b) decPutInt(b, t>>2); // b=ln(b) coefficient b->exponent=-(t&3)-3; // set exponent b->bits=DECNEG; // ln(0.10)->ln(0.99) always -ve aset.digits=16; aset.round=DEC_ROUND_HALF_EVEN; // restore decAddOp(a, a, b, &aset, 0, &ignore); // acc=a+b // the initial estimate is now in a, with up to 4 digits correct. // When rhs is at or near Nmax the estimate will be low, so we // will approach it from below, avoiding overflow when calling exp. decNumberZero(&numone); *numone.lsu=1; // constant 1 for adjustment // accumulator bounds are as requested (could underflow, but // cannot overflow) aset.emax=set->emax; aset.emin=set->emin; aset.clamp=0; // no concrete format // set up a context to be used for the multiply and subtract bset=aset; bset.emax=DEC_MAX_MATH*2; // use double bounds for the bset.emin=-DEC_MAX_MATH*2; // adjustment calculation // [see decExpOp call below] // for each iteration double the number of digits to calculate, // up to a maximum of p pp=9; // initial precision // [initially 9 as then the sequence starts 7+2, 16+2, and // 34+2, which is ideal for standard-sized numbers] aset.digits=pp; // working context bset.digits=pp+rhs->digits; // wider context for (;;) { // iterate #if DECCHECK iterations++; if (iterations>24) break; // consider 9 * 2**24 #endif // calculate the adjustment (exp(-a)*x-1) into b. This is a // catastrophic subtraction but it really is the difference // from 1 that is of interest. // Use the internal entry point to Exp as it allows the double // range for calculating exp(-a) when a is the tiniest subnormal. a->bits^=DECNEG; // make -a decExpOp(b, a, &bset, &ignore); // b=exp(-a) a->bits^=DECNEG; // restore sign of a // now multiply by rhs and subtract 1, at the wider precision decMultiplyOp(b, b, rhs, &bset, &ignore); // b=b*rhs decAddOp(b, b, &numone, &bset, DECNEG, &ignore); // b=b-1 // the iteration ends when the adjustment cannot affect the // result by >=0.5 ulp (at the requested digits), which // is when its value is smaller than the accumulator by // set->digits+1 digits (or it is zero) -- this is a looser // requirement than for Exp because all that happens to the // accumulator after this is the final rounding (but note that // there must also be full precision in a, or a=0). if (decNumberIsZero(b) || (a->digits+a->exponent)>=(b->digits+b->exponent+set->digits+1)) { if (a->digits==p) break; if (decNumberIsZero(a)) { decCompareOp(&cmp, rhs, &numone, &aset, COMPARE, &ignore); // rhs=1 ? if (cmp.lsu[0]==0) a->exponent=0; // yes, exact 0 else *status|=(DEC_Inexact | DEC_Rounded); // no, inexact break; } // force padding if adjustment has gone to 0 before full length if (decNumberIsZero(b)) b->exponent=a->exponent-p; } // not done yet ... decAddOp(a, a, b, &aset, 0, &ignore); // a=a+b for next estimate if (pp==p) continue; // precision is at maximum // lengthen the next calculation pp=pp*2; // double precision if (pp>p) pp=p; // clamp to maximum aset.digits=pp; // working context bset.digits=pp+rhs->digits; // wider context } // Newton's iteration #if DECCHECK // just a sanity check; remove the test to show always if (iterations>24) printf("Ln iterations=%d, status=%08x, p=%d, d=%d\n", iterations, *status, p, rhs->digits); #endif // Copy and round the result to res residue=1; // indicate dirt to right if (ISZERO(a)) residue=0; // .. unless underflowed to 0 aset.digits=set->digits; // [use default rounding] decCopyFit(res, a, &aset, &residue, status); // copy & shorten decFinish(res, set, &residue, status); // cleanup/set flags } while(0); // end protected if (allocbufa!=NULL) free(allocbufa); // drop any storage used if (allocbufb!=NULL) free(allocbufb); // .. // [status is handled by caller] return res; } // decLnOp /* ------------------------------------------------------------------ */ /* decQuantizeOp -- force exponent to requested value */ /* */ /* This computes C = op(A, B), where op adjusts the coefficient */ /* of C (by rounding or shifting) such that the exponent (-scale) */ /* of C has the value B or matches the exponent of B. */ /* The numerical value of C will equal A, except for the effects of */ /* any rounding that occurred. */ /* */ /* res is C, the result. C may be A or B */ /* lhs is A, the number to adjust */ /* rhs is B, the requested exponent */ /* set is the context */ /* quant is 1 for quantize or 0 for rescale */ /* status is the status accumulator (this can be called without */ /* risk of control loss) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Unless there is an error or the result is infinite, the exponent */ /* after the operation is guaranteed to be that requested. */ /* ------------------------------------------------------------------ */ static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, Flag quant, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif const decNumber *inrhs=rhs; // save original rhs Int reqdigits=set->digits; // requested DIGITS Int reqexp; // requested exponent [-scale] Int residue=0; // rounding residue Int etiny=set->emin-(reqdigits-1); #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>reqdigits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) break; lhs=alloclhs; } if (rhs->digits>reqdigits) { // [this only checks lostDigits] allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) break; rhs=allocrhs; } } #endif // [following code does not require input rounding] // Handle special values if (SPECIALARGS) { // NaNs get usual processing if (SPECIALARGS & (DECSNAN | DECNAN)) decNaNs(res, lhs, rhs, status); // one infinity but not both is bad else if ((lhs->bits ^ rhs->bits) & DECINF) *status|=DEC_Invalid_operation; // both infinity: return lhs else decNumberCopy(res, lhs); // [nop if in place] break; } // set requested exponent if (quant) reqexp=inrhs->exponent; // quantize -- match exponents else { // rescale -- use value of rhs // Original rhs must be an integer that fits and is in range, // which could be from -1999999997 to +999999999, thanks to // subnormals reqexp=decGetInt(inrhs); // [cannot fail] } #if DECSUBSET if (!set->extended) etiny=set->emin; // no subnormals #endif if (reqexp==BADINT // bad (rescale only) or .. || reqexp==BIGODD || reqexp==BIGEVEN // very big (ditto) or .. || (reqexpset->emax)) { // > emax *status|=DEC_Invalid_operation; break;} // the RHS has been processed, so it can be overwritten now if necessary if (ISZERO(lhs)) { // zero coefficient unchanged decNumberCopy(res, lhs); // [nop if in place] res->exponent=reqexp; // .. just set exponent #if DECSUBSET if (!set->extended) res->bits=0; // subset specification; no -0 #endif } else { // non-zero lhs Int adjust=reqexp-lhs->exponent; // digit adjustment needed // if adjusted coefficient will definitely not fit, give up now if ((lhs->digits-adjust)>reqdigits) { *status|=DEC_Invalid_operation; break; } if (adjust>0) { // increasing exponent // this will decrease the length of the coefficient by adjust // digits, and must round as it does so decContext workset; // work workset=*set; // clone rounding, etc. workset.digits=lhs->digits-adjust; // set requested length // [note that the latter can be <1, here] decCopyFit(res, lhs, &workset, &residue, status); // fit to result decApplyRound(res, &workset, residue, status); // .. and round residue=0; // [used] // If just rounded a 999s case, exponent will be off by one; // adjust back (after checking space), if so. if (res->exponent>reqexp) { // re-check needed, e.g., for quantize(0.9999, 0.001) under // set->digits==3 if (res->digits==reqdigits) { // cannot shift by 1 *status&=~(DEC_Inexact | DEC_Rounded); // [clean these] *status|=DEC_Invalid_operation; break; } res->digits=decShiftToMost(res->lsu, res->digits, 1); // shift res->exponent--; // (re)adjust the exponent. } #if DECSUBSET if (ISZERO(res) && !set->extended) res->bits=0; // subset; no -0 #endif } // increase else /* adjust<=0 */ { // decreasing or = exponent // this will increase the length of the coefficient by -adjust // digits, by adding zero or more trailing zeros; this is // already checked for fit, above decNumberCopy(res, lhs); // [it will fit] // if padding needed (adjust<0), add it now... if (adjust<0) { res->digits=decShiftToMost(res->lsu, res->digits, -adjust); res->exponent+=adjust; // adjust the exponent } } // decrease } // non-zero // Check for overflow [do not use Finalize in this case, as an // overflow here is a "don't fit" situation] if (res->exponent>set->emax-res->digits+1) { // too big *status|=DEC_Invalid_operation; break; } else { decFinalize(res, set, &residue, status); // set subnormal flags *status&=~DEC_Underflow; // suppress Underflow [754r] } } while(0); // end protected #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // drop any storage used if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decQuantizeOp /* ------------------------------------------------------------------ */ /* decCompareOp -- compare, min, or max two Numbers */ /* */ /* This computes C = A ? B and carries out one of four operations: */ /* COMPARE -- returns the signum (as a number) giving the */ /* result of a comparison unless one or both */ /* operands is a NaN (in which case a NaN results) */ /* COMPMAX -- returns the larger of the operands, using the */ /* 754r maxnum operation */ /* COMPMIN -- the 754r minnum operation */ /* COMTOTAL -- returns the signum (as a number) giving the */ /* result of a comparison using 754r total ordering */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* op is the operation flag */ /* status is the usual accumulator */ /* */ /* C must have space for one digit for COMPARE or set->digits for */ /* COMPMAX and COMPMIN. */ /* ------------------------------------------------------------------ */ /* The emphasis here is on speed for common cases, and avoiding */ /* coefficient comparison if possible. */ /* ------------------------------------------------------------------ */ decNumber * decCompareOp(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set, Flag op, uInt *status) { #if DECSUBSET decNumber *alloclhs=NULL; // non-NULL if rounded lhs allocated decNumber *allocrhs=NULL; // .., rhs #endif Int result=0; // default result value uByte merged; // work #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif do { // protect allocated storage #if DECSUBSET if (!set->extended) { // reduce operands and set lostDigits status, as needed if (lhs->digits>set->digits) { alloclhs=decRoundOperand(lhs, set, status); if (alloclhs==NULL) {result=BADINT; break;} lhs=alloclhs; } if (rhs->digits>set->digits) { allocrhs=decRoundOperand(rhs, set, status); if (allocrhs==NULL) {result=BADINT; break;} rhs=allocrhs; } } #endif // [following code does not require input rounding] // If total ordering then handle differing signs 'up front' if (op == COMPTOTAL) { // total ordering if (decNumberIsNegative(lhs) & !decNumberIsNegative(rhs)) { result=-1; break; } if (!decNumberIsNegative(lhs) & decNumberIsNegative(rhs)) { result=+1; break; } } // handle NaNs specially; let infinities drop through // This assumes sNaN (even just one) leads to NaN. merged=(lhs->bits | rhs->bits) & (DECSNAN | DECNAN); if (merged) { // a NaN bit set if (op == COMPARE); // result will be NaN else if (op == COMPTOTAL) { // total ordering, always finite // signs are known to be the same; compute the ordering here // as if the signs are both positive, then invert for negatives if (!decNumberIsNaN(lhs)) result=-1; else if (!decNumberIsNaN(rhs)) result=+1; // here if both NaNs else if (decNumberIsSNaN(lhs) && decNumberIsQNaN(rhs)) result=-1; else if (decNumberIsQNaN(lhs) && decNumberIsSNaN(rhs)) result=+1; else { // both NaN or both sNaN // now it just depends on the payload result=decUnitCompare(lhs->lsu, D2U(lhs->digits), rhs->lsu, D2U(rhs->digits), 0); // [Error not possible, as these are 'aligned'] } // both same NaNs if (decNumberIsNegative(lhs)) result=-result; break; } // total order else if (merged & DECSNAN); // sNaN -> qNaN else { // here if MIN or MAX and one or two quiet NaNs // min or max -- 754r rules ignore single NaN if (!decNumberIsNaN(lhs) || !decNumberIsNaN(rhs)) { // just one NaN; force choice to be the non-NaN operand op=COMPMAX; if (lhs->bits & DECNAN) result=-1; // pick rhs else result=+1; // pick lhs break; } } // max or min op = COMPNAN; // use special path decNaNs(res, lhs, rhs, status); break; } result=decCompare(lhs, rhs, 0); // have numbers } while(0); // end protected if (result==BADINT) *status|=DEC_Insufficient_storage; // rare else { if (op == COMPARE || op == COMPTOTAL) { // returning signum if (op == COMPTOTAL && result==0) { // operands are numerically equal or same NaN (and same sign, // tested first); if identical, leave result 0 if (lhs->exponent!=rhs->exponent) { if (lhs->exponentexponent) result=-1; else result=+1; if (decNumberIsNegative(lhs)) result=-result; } // lexp!=rexp } // total-order by exponent decNumberZero(res); // [always a valid result] if (result!=0) { // must be -1 or +1 *res->lsu=1; if (result<0) res->bits=DECNEG; } } else if (op == COMPNAN); // special, drop through else { // MAX or MIN, non-NaN result Int residue=0; // rounding accumulator // choose the operand for the result const decNumber *choice; if (result==0) { // operands are numerically equal // choose according to sign then exponent (see 754r) uByte slhs=(lhs->bits & DECNEG); uByte srhs=(rhs->bits & DECNEG); #if DECSUBSET if (!set->extended) { // subset: force left-hand op=COMPMAX; result=+1; } else #endif if (slhs!=srhs) { // signs differ if (slhs) result=-1; // rhs is max else result=+1; // lhs is max } else if (slhs && srhs) { // both negative if (lhs->exponentexponent) result=+1; else result=-1; // [if equal, use lhs, technically identical] } else { // both positive if (lhs->exponent>rhs->exponent) result=+1; else result=-1; // [ditto] } } // numerically equal // here result will be non-0 if (op == COMPMIN) result=-result;// reverse if looking for MIN choice=(result>0 ? lhs : rhs); // choose // copy chosen to result, rounding if need be decCopyFit(res, choice, set, &residue, status); decFinish(res, set, &residue, status); } } #if DECSUBSET if (allocrhs!=NULL) free(allocrhs); // free any storage used if (alloclhs!=NULL) free(alloclhs); // .. #endif return res; } // decCompareOp /* ------------------------------------------------------------------ */ /* decCompare -- compare two decNumbers by numerical value */ /* */ /* This routine compares A ? B without altering them. */ /* */ /* Arg1 is A, a decNumber which is not a NaN */ /* Arg2 is B, a decNumber which is not a NaN */ /* Arg3 is 1 for a sign-independent compare, 0 otherwise */ /* */ /* returns -1, 0, or 1 for AB, or BADINT if failure */ /* (the only possible failure is an allocation error) */ /* ------------------------------------------------------------------ */ static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag abs) { Int result; // result value Int sigr; // rhs signum Int compare; // work result=1; // assume signum(lhs) if (ISZERO(lhs)) result=0; if (abs) { if (!ISZERO(rhs)) result=1; // not both 0 } else { // signs matter if (result && decNumberIsNegative(lhs)) result=-1; sigr=1; // compute signum(rhs) if (ISZERO(rhs)) sigr=0; else if (decNumberIsNegative(rhs)) sigr=-1; if (result > sigr) return +1; // L > R, return 1 if (result < sigr) return -1; // R < L, return -1 } // signums are the same if (result==0) return 0; // both 0 // Both non-zero if ((lhs->bits | rhs->bits) & DECINF) { // one or more infinities if (decNumberIsInfinite(rhs)) { if (decNumberIsInfinite(lhs)) result=0;// both infinite else result=-result; // only rhs infinite } return result; } // must compare the coefficients, allowing for exponents if (lhs->exponent>rhs->exponent) { // LHS exponent larger // swap sides, and sign const decNumber *temp=lhs; lhs=rhs; rhs=temp; result=-result; } compare=decUnitCompare(lhs->lsu, D2U(lhs->digits), rhs->lsu, D2U(rhs->digits), rhs->exponent-lhs->exponent); if (compare!=BADINT) compare*=result; // comparison succeeded return compare; } // decCompare /* ------------------------------------------------------------------ */ /* decUnitCompare -- compare two >=0 integers in Unit arrays */ /* */ /* This routine compares A ? B*10**E where A and B are unit arrays */ /* A is a plain integer */ /* B has an exponent of E (which must be non-negative) */ /* */ /* Arg1 is A first Unit (lsu) */ /* Arg2 is A length in Units */ /* Arg3 is B first Unit (lsu) */ /* Arg4 is B length in Units */ /* Arg5 is E (0 if the units are aligned) */ /* */ /* returns -1, 0, or 1 for AB, or BADINT if failure */ /* (the only possible failure is an allocation error, which can */ /* only occur if E!=0) */ /* ------------------------------------------------------------------ */ static Int decUnitCompare(const Unit *a, Int alength, const Unit *b, Int blength, Int exp) { Unit *acc; // accumulator for result Unit accbuff[SD2U(DECBUFFER+1)];// local buffer Unit *allocacc=NULL; // -> allocated acc buffer, iff allocated Int accunits, need; // units in use or needed for acc const Unit *l, *r, *u; // work Int expunits, exprem, result; // .. if (exp==0) { // aligned; fastpath if (alength>blength) return 1; if (alength=a; l--, r--) { if (*l>*r) return 1; if (*l<*r) return -1; } return 0; // all units match } // aligned // Unaligned. If one is >1 unit longer than the other, padded // approximately, then can return easily if (alength>blength+(Int)D2U(exp)) return 1; if (alength+1sizeof(accbuff)) { allocacc=(Unit *)malloc(need*sizeof(Unit)); if (allocacc==NULL) return BADINT; // hopeless -- abandon acc=allocacc; } // Calculate units and remainder from exponent. expunits=exp/DECDPUN; exprem=exp%DECDPUN; // subtract [A+B*(-m)] accunits=decUnitAddSub(a, alength, b, blength, expunits, acc, -(Int)powers[exprem]); // [UnitAddSub result may have leading zeros, even on zero] if (accunits<0) result=-1; // negative result else { // non-negative result // check units of the result before freeing any storage for (u=acc; u=0 integers in Unit arrays */ /* */ /* This routine performs the calculation: */ /* */ /* C=A+(B*M) */ /* */ /* Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */ /* */ /* A may be shorter or longer than B. */ /* */ /* Leading zeros are not removed after a calculation. The result is */ /* either the same length as the longer of A and B (adding any */ /* shift), or one Unit longer than that (if a Unit carry occurred). */ /* */ /* A and B content are not altered unless C is also A or B. */ /* C may be the same array as A or B, but only if no zero padding is */ /* requested (that is, C may be B only if bshift==0). */ /* C is filled from the lsu; only those units necessary to complete */ /* the calculation are referenced. */ /* */ /* Arg1 is A first Unit (lsu) */ /* Arg2 is A length in Units */ /* Arg3 is B first Unit (lsu) */ /* Arg4 is B length in Units */ /* Arg5 is B shift in Units (>=0; pads with 0 units if positive) */ /* Arg6 is C first Unit (lsu) */ /* Arg7 is M, the multiplier */ /* */ /* returns the count of Units written to C, which will be non-zero */ /* and negated if the result is negative. That is, the sign of the */ /* returned Int is the sign of the result (positive for zero) and */ /* the absolute value of the Int is the count of Units. */ /* */ /* It is the caller's responsibility to make sure that C size is */ /* safe, allowing space if necessary for a one-Unit carry. */ /* */ /* This routine is severely performance-critical; *any* change here */ /* must be measured (timed) to assure no performance degradation. */ /* In particular, trickery here tends to be counter-productive, as */ /* increased complexity of code hurts register optimizations on */ /* register-poor architectures. Avoiding divisions is nearly */ /* always a Good Idea, however. */ /* */ /* Special thanks to Rick McGuire (IBM Cambridge, MA) and Dave Clark */ /* (IBM Warwick, UK) for some of the ideas used in this routine. */ /* ------------------------------------------------------------------ */ static Int decUnitAddSub(const Unit *a, Int alength, const Unit *b, Int blength, Int bshift, Unit *c, Int m) { const Unit *alsu=a; // A lsu [need to remember it] Unit *clsu=c; // C ditto Unit *minC; // low water mark for C Unit *maxC; // high water mark for C eInt carry=0; // carry integer (could be Long) Int add; // work #if DECDPUN<=4 // myriadal, millenary, etc. Int est; // estimated quotient #endif #if DECTRACE if (alength<1 || blength<1) printf("decUnitAddSub: alen blen m %d %d [%d]\n", alength, blength, m); #endif maxC=c+alength; // A is usually the longer minC=c+blength; // .. and B the shorter if (bshift!=0) { // B is shifted; low As copy across minC+=bshift; // if in place [common], skip copy unless there's a gap [rare] if (a==c && bshift<=alength) { c+=bshift; a+=bshift; } else for (; cmaxC) { // swap Unit *hold=minC; minC=maxC; maxC=hold; } // For speed, do the addition as two loops; the first where both A // and B contribute, and the second (if necessary) where only one or // other of the numbers contribute. // Carry handling is the same (i.e., duplicated) in each case. for (; c=0) { est=(((ueInt)carry>>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [89%] if (*c>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=(((ueInt)carry>>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [99%] if (*c>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // quotient continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative #else // remainder operator is undefined if negative, so must test if ((ueInt)carry<(DECDPUNMAX+1)*2) { // fastpath carry +1 *c=(Unit)(carry-(DECDPUNMAX+1)); // [helps additions] carry=1; continue; } if (carry>=0) { *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1); continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1); #endif } // c // now may have one or other to complete // [pretest to avoid loop setup/shutdown] if (cDECDPUNMAX #if DECDPUN==4 // use divide-by-multiply if (carry>=0) { est=(((ueInt)carry>>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [79.7%] if (*c>11)*53687)>>18; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=(((ueInt)carry>>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // likely quotient [99%] if (*c>3)*16777)>>21; *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative if (*c=0) { est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder carry=est; // quotient continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive est=QUOT10(carry, DECDPUN); *c=(Unit)(carry-est*(DECDPUNMAX+1)); carry=est-(DECDPUNMAX+1); // correctly negative #else if ((ueInt)carry<(DECDPUNMAX+1)*2){ // fastpath carry 1 *c=(Unit)(carry-(DECDPUNMAX+1)); carry=1; continue; } // remainder operator is undefined if negative, so must test if (carry>=0) { *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1); continue; } // negative case carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); // make positive *c=(Unit)(carry%(DECDPUNMAX+1)); carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1); #endif } // c // OK, all A and B processed; might still have carry or borrow // return number of Units in the result, negated if a borrow if (carry==0) return c-clsu; // no carry, so no more to do if (carry>0) { // positive carry *c=(Unit)carry; // place as new unit c++; // .. return c-clsu; } // -ve carry: it's a borrow; complement needed add=1; // temporary carry... for (c=clsu; c current Unit #if DECCHECK if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNUSED)) return dn; #endif *dropped=0; // assume no zeros dropped if ((dn->bits & DECSPECIAL) // fast exit if special .. || (*dn->lsu & 0x01)) return dn; // .. or odd if (ISZERO(dn)) { // .. or 0 dn->exponent=0; // (sign is preserved) return dn; } // have a finite number which is even exp=dn->exponent; cut=1; // digit (1-DECDPUN) in Unit up=dn->lsu; // -> current Unit for (d=0; ddigits-1; d++) { // [don't strip the final digit] // slice by powers #if DECDPUN<=4 uInt quot=QUOT10(*up, cut); if ((*up-quot*powers[cut])!=0) break; // found non-0 digit #else if (*up%powers[cut]!=0) break; // found non-0 digit #endif // have a trailing 0 if (!all) { // trimming // [if exp>0 then all trailing 0s are significant for trim] if (exp<=0) { // if digit might be significant if (exp==0) break; // then quit exp++; // next digit might be significant } } cut++; // next power if (cut>DECDPUN) { // need new Unit up++; cut=1; } } // d if (d==0) return dn; // none dropped // effect the drop decShiftToLeast(dn->lsu, D2U(dn->digits), d); dn->exponent+=d; // maintain numerical value dn->digits-=d; // new length *dropped=d; // report the count return dn; } // decTrim /* ------------------------------------------------------------------ */ /* decShiftToMost -- shift digits in array towards most significant */ /* */ /* uar is the array */ /* digits is the count of digits in use in the array */ /* shift is the number of zeros to pad with (least significant); */ /* it must be zero or positive */ /* */ /* returns the new length of the integer in the array, in digits */ /* */ /* No overflow is permitted (that is, the uar array must be known to */ /* be large enough to hold the result, after shifting). */ /* ------------------------------------------------------------------ */ static Int decShiftToMost(Unit *uar, Int digits, Int shift) { Unit *target, *source, *first; // work Int cut; // odd 0's to add uInt next; // work if (shift==0) return digits; // [fastpath] nothing to do if ((digits+shift)<=DECDPUN) { // [fastpath] single-unit case *uar=(Unit)(*uar*powers[shift]); return digits+shift; } next=0; // all paths source=uar+D2U(digits)-1; // where msu comes from target=source+D2U(shift); // where upper part of first cut goes cut=DECDPUN-MSUDIGITS(shift); // where to slice if (cut==0) { // unit-boundary case for (; source>=uar; source--, target--) *target=*source; } else { first=uar+D2U(digits+shift)-1; // where msu of source will end up for (; source>=uar; source--, target--) { // split the source Unit and accumulate remainder for next #if DECDPUN<=4 uInt quot=QUOT10(*source, cut); uInt rem=*source-quot*powers[cut]; next+=quot; #else uInt rem=*source%powers[cut]; next+=*source/powers[cut]; #endif if (target<=first) *target=(Unit)next; // write to target iff valid next=rem*powers[DECDPUN-cut]; // save remainder for next Unit } } // shift-move // propagate any partial unit to one below and clear the rest for (; target>=uar; target--) { *target=(Unit)next; next=0; } return digits+shift; } // decShiftToMost /* ------------------------------------------------------------------ */ /* decShiftToLeast -- shift digits in array towards least significant */ /* */ /* uar is the array */ /* units is length of the array, in units */ /* shift is the number of digits to remove from the lsu end; it */ /* must be zero or positive and less than units*DECDPUN. */ /* */ /* returns the new length of the integer in the array, in units */ /* */ /* Removed digits are discarded (lost). Units not required to hold */ /* the final result are unchanged. */ /* ------------------------------------------------------------------ */ static Int decShiftToLeast(Unit *uar, Int units, Int shift) { Unit *target, *up; // work Int cut, count; // work Int quot, rem; // for division if (shift==0) return units; // [fastpath] nothing to do target=uar; // both paths cut=MSUDIGITS(shift); if (cut==DECDPUN) { // unit-boundary case; easy up=uar+D2U(shift); for (; updigits is > set->digits) */ /* set is the relevant context */ /* status is the status accumulator */ /* */ /* returns an allocated decNumber with the rounded result. */ /* */ /* lostDigits and other status may be set by this. */ /* */ /* Since the input is an operand, it must not be modified. */ /* Instead, return an allocated decNumber, rounded as required. */ /* It is the caller's responsibility to free the allocated storage. */ /* */ /* If no storage is available then the result cannot be used, so NULL */ /* is returned. */ /* ------------------------------------------------------------------ */ static decNumber *decRoundOperand(const decNumber *dn, decContext *set, uInt *status) { decNumber *res; // result structure uInt newstatus=0; // status from round Int residue=0; // rounding accumulator // Allocate storage for the returned decNumber, big enough for the // length specified by the context res=(decNumber *)malloc(sizeof(decNumber) +(D2U(set->digits)-1)*sizeof(Unit)); if (res==NULL) { *status|=DEC_Insufficient_storage; return NULL; } decCopyFit(res, dn, set, &residue, &newstatus); decApplyRound(res, set, residue, &newstatus); // If that set Inexact then "lost digits" is raised... if (newstatus & DEC_Inexact) newstatus|=DEC_Lost_digits; *status|=newstatus; return res; } // decRoundOperand #endif /* ------------------------------------------------------------------ */ /* decCopyFit -- copy a number, truncating the coefficient if needed */ /* */ /* dest is the target decNumber */ /* src is the source decNumber */ /* set is the context [used for length (digits) and rounding mode] */ /* residue is the residue accumulator */ /* status contains the current status to be updated */ /* */ /* (dest==src is allowed and will be a no-op if fits) */ /* All fields are updated as required. */ /* ------------------------------------------------------------------ */ static void decCopyFit(decNumber *dest, const decNumber *src, decContext *set, Int *residue, uInt *status) { dest->bits=src->bits; dest->exponent=src->exponent; decSetCoeff(dest, set, src->lsu, src->digits, residue, status); } // decCopyFit /* ------------------------------------------------------------------ */ /* decSetCoeff -- set the coefficient of a number */ /* */ /* dn is the number whose coefficient array is to be set. */ /* It must have space for set->digits digits */ /* set is the context [for size] */ /* lsu -> lsu of the source coefficient [may be dn->lsu] */ /* len is digits in the source coefficient [may be dn->digits] */ /* residue is the residue accumulator. This has values as in */ /* decApplyRound, and will be unchanged unless the */ /* target size is less than len. In this case, the */ /* coefficient is truncated and the residue is updated to */ /* reflect the previous residue and the dropped digits. */ /* status is the status accumulator, as usual */ /* */ /* The coefficient may already be in the number, or it can be an */ /* external intermediate array. If it is in the number, lsu must == */ /* dn->lsu and len must == dn->digits. */ /* */ /* Note that the coefficient length (len) may be < set->digits, and */ /* in this case this merely copies the coefficient (or is a no-op */ /* if dn->lsu==lsu). */ /* */ /* Note also that (only internally, from decQuantizeOp and */ /* decSetSubnormal) the value of set->digits may be less than one, */ /* indicating a round to left. This routine handles that case */ /* correctly; caller ensures space. */ /* */ /* dn->digits, dn->lsu (and as required), and dn->exponent are */ /* updated as necessary. dn->bits (sign) is unchanged. */ /* */ /* DEC_Rounded status is set if any digits are discarded. */ /* DEC_Inexact status is set if any non-zero digits are discarded, or */ /* incoming residue was non-0 (implies rounded) */ /* ------------------------------------------------------------------ */ // mapping array: maps 0-9 to canonical residues, so that a residue // can be adjusted in the range [-1, +1] and achieve correct rounding // 0 1 2 3 4 5 6 7 8 9 static const uByte resmap[10]={0, 3, 3, 3, 3, 5, 7, 7, 7, 7}; static void decSetCoeff(decNumber *dn, decContext *set, const Unit *lsu, Int len, Int *residue, uInt *status) { Int discard; // number of digits to discard uInt cut; // cut point in Unit const Unit *up; // work Unit *target; // .. Int count; // .. #if DECDPUN<=4 uInt temp; // .. #endif discard=len-set->digits; // digits to discard if (discard<=0) { // no digits are being discarded if (dn->lsu!=lsu) { // copy needed // copy the coefficient array to the result number; no shift needed count=len; // avoids D2U up=lsu; for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN) *target=*up; dn->digits=len; // set the new length } // dn->exponent and residue are unchanged, record any inexactitude if (*residue!=0) *status|=(DEC_Inexact | DEC_Rounded); return; } // some digits must be discarded ... dn->exponent+=discard; // maintain numerical value *status|=DEC_Rounded; // accumulate Rounded status if (*residue>1) *residue=1; // previous residue now to right, so reduce if (discard>len) { // everything, +1, is being discarded // guard digit is 0 // residue is all the number [NB could be all 0s] if (*residue<=0) { // not already positive count=len; // avoids D2U for (up=lsu; count>0; up++, count-=DECDPUN) if (*up!=0) { // found non-0 *residue=1; break; // no need to check any others } } if (*residue!=0) *status|=DEC_Inexact; // record inexactitude *dn->lsu=0; // coefficient will now be 0 dn->digits=1; // .. return; } // total discard // partial discard [most common case] // here, at least the first (most significant) discarded digit exists // spin up the number, noting residue during the spin, until get to // the Unit with the first discarded digit. When reach it, extract // it and remember its position count=0; for (up=lsu;; up++) { count+=DECDPUN; if (count>=discard) break; // full ones all checked if (*up!=0) *residue=1; } // up // here up -> Unit with first discarded digit cut=discard-(count-DECDPUN)-1; if (cut==DECDPUN-1) { // unit-boundary case (fast) Unit half=(Unit)powers[DECDPUN]>>1; // set residue directly if (*up>=half) { if (*up>half) *residue=7; else *residue+=5; // add sticky bit } else { // digits<=0) { // special for Quantize/Subnormal :-( *dn->lsu=0; // .. result is 0 dn->digits=1; // .. } else { // shift to least count=set->digits; // now digits to end up with dn->digits=count; // set the new length up++; // move to next // on unit boundary, so shift-down copy loop is simple for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN) *target=*up; } } // unit-boundary case else { // discard digit is in low digit(s), and not top digit uInt discard1; // first discarded digit uInt quot, rem; // for divisions if (cut==0) quot=*up; // is at bottom of unit else /* cut>0 */ { // it's not at bottom of unit #if DECDPUN<=4 quot=QUOT10(*up, cut); rem=*up-quot*powers[cut]; #else rem=*up%powers[cut]; quot=*up/powers[cut]; #endif if (rem!=0) *residue=1; } // discard digit is now at bottom of quot #if DECDPUN<=4 temp=(quot*6554)>>16; // fast /10 // Vowels algorithm here not a win (9 instructions) discard1=quot-X10(temp); quot=temp; #else discard1=quot%10; quot=quot/10; #endif // here, discard1 is the guard digit, and residue is everything // else [use mapping array to accumulate residue safely] *residue+=resmap[discard1]; cut++; // update cut // here: up -> Unit of the array with bottom digit // cut is the division point for each Unit // quot holds the uncut high-order digits for the current unit if (set->digits<=0) { // special for Quantize/Subnormal :-( *dn->lsu=0; // .. result is 0 dn->digits=1; // .. } else { // shift to least needed count=set->digits; // now digits to end up with dn->digits=count; // set the new length // shift-copy the coefficient array to the result number for (target=dn->lsu; ; target++) { *target=(Unit)quot; count-=(DECDPUN-cut); if (count<=0) break; up++; quot=*up; #if DECDPUN<=4 quot=QUOT10(quot, cut); rem=*up-quot*powers[cut]; #else rem=quot%powers[cut]; quot=quot/powers[cut]; #endif *target=(Unit)(*target+rem*powers[DECDPUN-cut]); count-=cut; if (count<=0) break; } // shift-copy loop } // shift to least } // not unit boundary if (*residue!=0) *status|=DEC_Inexact; // record inexactitude return; } // decSetCoeff /* ------------------------------------------------------------------ */ /* decApplyRound -- apply pending rounding to a number */ /* */ /* dn is the number, with space for set->digits digits */ /* set is the context [for size and rounding mode] */ /* residue indicates pending rounding, being any accumulated */ /* guard and sticky information. It may be: */ /* 6-9: rounding digit is >5 */ /* 5: rounding digit is exactly half-way */ /* 1-4: rounding digit is <5 and >0 */ /* 0: the coefficient is exact */ /* -1: as 1, but the hidden digits are subtractive, that */ /* is, of the opposite sign to dn. In this case the */ /* coefficient must be non-0. */ /* status is the status accumulator, as usual */ /* */ /* This routine applies rounding while keeping the length of the */ /* coefficient constant. The exponent and status are unchanged */ /* except if: */ /* */ /* -- the coefficient was increased and is all nines (in which */ /* case Overflow could occur, and is handled directly here so */ /* the caller does not need to re-test for overflow) */ /* */ /* -- the coefficient was decreased and becomes all nines (in which */ /* case Underflow could occur, and is also handled directly). */ /* */ /* All fields in dn are updated as required. */ /* */ /* ------------------------------------------------------------------ */ static void decApplyRound(decNumber *dn, decContext *set, Int residue, uInt *status) { Int bump; // 1 if coefficient needs to be incremented // -1 if coefficient needs to be decremented if (residue==0) return; // nothing to apply bump=0; // assume a smooth ride // now decide whether, and how, to round, depending on mode switch (set->round) { case DEC_ROUND_DOWN: { // no change, except if negative residue if (residue<0) bump=-1; break;} // r-d case DEC_ROUND_HALF_DOWN: { if (residue>5) bump=1; break;} // r-h-d case DEC_ROUND_HALF_EVEN: { if (residue>5) bump=1; // >0.5 goes up else if (residue==5) { // exactly 0.5000... // 0.5 goes up iff [new] lsd is odd if (*dn->lsu & 0x01) bump=1; } break;} // r-h-e case DEC_ROUND_HALF_UP: { if (residue>=5) bump=1; break;} // r-h-u case DEC_ROUND_UP: { if (residue>0) bump=1; break;} // r-u case DEC_ROUND_CEILING: { // same as _UP for positive numbers, and as _DOWN for negatives // [negative residue cannot occur on 0] if (decNumberIsNegative(dn)) { if (residue<0) bump=-1; } else { if (residue>0) bump=1; } break;} // r-c case DEC_ROUND_FLOOR: { // same as _UP for negative numbers, and as _DOWN for positive // [negative residue cannot occur on 0] if (!decNumberIsNegative(dn)) { if (residue<0) bump=-1; } else { if (residue>0) bump=1; } break;} // r-f default: { // e.g., DEC_ROUND_MAX *status|=DEC_Invalid_context; #if DECTRACE printf("Unknown rounding mode: %d\n", set->round); #endif break;} } // switch // now bump the number, up or down, if need be if (bump==0) return; // no action required // Simply use decUnitAddSub unless bumping up and the number is // all nines. In this special case set to 100... explicitly // and adjust the exponent by one (as otherwise could overflow // the array) // Similarly handle all-nines result if bumping down. if (bump>0) { Unit *up; // work uInt count=dn->digits; // digits to be checked for (up=dn->lsu; ; up++) { if (count<=DECDPUN) { // this is the last Unit (the msu) if (*up!=powers[count]-1) break; // not still 9s // here if it, too, is all nines *up=(Unit)powers[count-1]; // here 999 -> 100 etc. for (up=up-1; up>=dn->lsu; up--) *up=0; // others all to 0 dn->exponent++; // and bump exponent // [which, very rarely, could cause Overflow...] if ((dn->exponent+dn->digits)>set->emax+1) { decSetOverflow(dn, set, status); } return; // done } // a full unit to check, with more to come if (*up!=DECDPUNMAX) break; // not still 9s count-=DECDPUN; } // up } // bump>0 else { // -1 // here checking for a pre-bump of 1000... (leading 1, all // other digits zero) Unit *up, *sup; // work uInt count=dn->digits; // digits to be checked for (up=dn->lsu; ; up++) { if (count<=DECDPUN) { // this is the last Unit (the msu) if (*up!=powers[count-1]) break; // not 100.. // here if have the 1000... case sup=up; // save msu pointer *up=(Unit)powers[count]-1; // here 100 in msu -> 999 // others all to all-nines, too for (up=up-1; up>=dn->lsu; up--) *up=(Unit)powers[DECDPUN]-1; dn->exponent--; // and bump exponent // iff the number was at the subnormal boundary (exponent=etiny) // then the exponent is now out of range, so it will in fact get // clamped to etiny and the final 9 dropped. // printf(">> emin=%d exp=%d sdig=%d\n", set->emin, // dn->exponent, set->digits); if (dn->exponent+1==set->emin-set->digits+1) { if (count==1 && dn->digits==1) *sup=0; // here 9 -> 0[.9] else { *sup=(Unit)powers[count-1]-1; // here 999.. in msu -> 99.. dn->digits--; } dn->exponent++; *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded; } return; // done } // a full unit to check, with more to come if (*up!=0) break; // not still 0s count-=DECDPUN; } // up } // bump<0 // Actual bump needed. Do it. decUnitAddSub(dn->lsu, D2U(dn->digits), uarrone, 1, 0, dn->lsu, bump); } // decApplyRound #if DECSUBSET /* ------------------------------------------------------------------ */ /* decFinish -- finish processing a number */ /* */ /* dn is the number */ /* set is the context */ /* residue is the rounding accumulator (as in decApplyRound) */ /* status is the accumulator */ /* */ /* This finishes off the current number by: */ /* 1. If not extended: */ /* a. Converting a zero result to clean '0' */ /* b. Reducing positive exponents to 0, if would fit in digits */ /* 2. Checking for overflow and subnormals (always) */ /* Note this is just Finalize when no subset arithmetic. */ /* All fields are updated as required. */ /* ------------------------------------------------------------------ */ static void decFinish(decNumber *dn, decContext *set, Int *residue, uInt *status) { if (!set->extended) { if ISZERO(dn) { // value is zero dn->exponent=0; // clean exponent .. dn->bits=0; // .. and sign return; // no error possible } if (dn->exponent>=0) { // non-negative exponent // >0; reduce to integer if possible if (set->digits >= (dn->exponent+dn->digits)) { dn->digits=decShiftToMost(dn->lsu, dn->digits, dn->exponent); dn->exponent=0; } } } // !extended decFinalize(dn, set, residue, status); } // decFinish #endif /* ------------------------------------------------------------------ */ /* decFinalize -- final check, clamp, and round of a number */ /* */ /* dn is the number */ /* set is the context */ /* residue is the rounding accumulator (as in decApplyRound) */ /* status is the status accumulator */ /* */ /* This finishes off the current number by checking for subnormal */ /* results, applying any pending rounding, checking for overflow, */ /* and applying any clamping. */ /* Underflow and overflow conditions are raised as appropriate. */ /* All fields are updated as required. */ /* ------------------------------------------------------------------ */ static void decFinalize(decNumber *dn, decContext *set, Int *residue, uInt *status) { Int shift; // shift needed if clamping Int tinyexp=set->emin-dn->digits+1; // precalculate subnormal boundary // Must be careful, here, when checking the exponent as the // adjusted exponent could overflow 31 bits [because it may already // be up to twice the expected]. // First test for subnormal. This must be done before any final // round as the result could be rounded to Nmin or 0. if (dn->exponent<=tinyexp) { // prefilter decNumber nmin; // A very nasty case here is dn == Nmin and residue<0 if (dn->exponentemin; if (*residue<0 && decCompare(dn, &nmin, 1)==0) { // (signless compare) decApplyRound(dn, set, *residue, status); // might force down decSetSubnormal(dn, set, residue, status); return; } } // now apply any pending round (this could raise overflow). if (*residue!=0) decApplyRound(dn, set, *residue, status); // Check for overflow [redundant in the 'rare' case] or clamp if (dn->exponent<=set->emax-set->digits+1) return; // neither needed // here when might have an overflow or clamp to do if (dn->exponent>set->emax-dn->digits+1) { // too big decSetOverflow(dn, set, status); return; } // here when the result is normal but in clamp range if (!set->clamp) return; // here when need to apply the IEEE exponent clamp (fold-down) shift=dn->exponent-(set->emax-set->digits+1); // shift coefficient (if non-zero) if (!ISZERO(dn)) { dn->digits=decShiftToMost(dn->lsu, dn->digits, shift); } dn->exponent-=shift; // adjust the exponent to match *status|=DEC_Clamped; // and record the dirty deed return; } // decFinalize /* ------------------------------------------------------------------ */ /* decSetOverflow -- set number to proper overflow value */ /* */ /* dn is the number (used for sign [only] and result) */ /* set is the context [used for the rounding mode] */ /* status contains the current status to be updated */ /* */ /* This sets the sign of a number and sets its value to either */ /* Infinity or the maximum finite value, depending on the sign of */ /* dn and therounding mode, following IEEE 854 rules. */ /* ------------------------------------------------------------------ */ static void decSetOverflow(decNumber *dn, decContext *set, uInt *status) { Flag needmax=0; // result is maximum finite value uByte sign=dn->bits&DECNEG; // clean and save sign bit if (ISZERO(dn)) { // zero does not overflow magnitude Int emax=set->emax; // limit value if (set->clamp) emax-=set->digits-1; // lower if clamping if (dn->exponent>emax) { // clamp required dn->exponent=emax; *status|=DEC_Clamped; } return; } decNumberZero(dn); switch (set->round) { case DEC_ROUND_DOWN: { needmax=1; // never Infinity break;} // r-d case DEC_ROUND_CEILING: { if (sign) needmax=1; // Infinity if non-negative break;} // r-c case DEC_ROUND_FLOOR: { if (!sign) needmax=1; // Infinity if negative break;} // r-f default: break; // Infinity in all other cases } if (needmax) { Unit *up; // work Int count=set->digits; // nines to add dn->digits=count; // fill in all nines to set maximum value for (up=dn->lsu; ; up++) { if (count>DECDPUN) *up=DECDPUNMAX; // unit full o'nines else { // this is the msu *up=(Unit)(powers[count]-1); break; } count-=DECDPUN; // filled those digits } // up dn->bits=sign; // sign dn->exponent=set->emax-set->digits+1; } else dn->bits=sign|DECINF; // Value is +/-Infinity *status|=DEC_Overflow | DEC_Inexact | DEC_Rounded; } // decSetOverflow /* ------------------------------------------------------------------ */ /* decSetSubnormal -- process value whose exponent is extended) { decNumberZero(dn); // always full overflow *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded; return; } #endif // Full arithmetic -- allow subnormals, rounded to minimum exponent // (Etiny) if needed etiny=set->emin-(set->digits-1); // smallest allowed exponent if ISZERO(dn) { // value is zero // residue can never be non-zero here #if DECCHECK if (*residue!=0) { printf("++ Subnormal 0 residue %d\n", *residue); *status|=DEC_Invalid_operation; } #endif if (dn->exponentexponent=etiny; *status|=DEC_Clamped; } return; } *status|=DEC_Subnormal; // have a non-zero subnormal adjust=etiny-dn->exponent; // calculate digits to remove if (adjust<=0) { // not out of range; unrounded // residue can never be non-zero here, except in the Nmin-residue // case (which is a subnormal result), so can take fast-path here // it may already be inexact (from setting the coefficient) if (*status&DEC_Inexact) *status|=DEC_Underflow; return; } // adjust>0, so need to rescale the result so exponent becomes Etiny // [this code is similar to that in rescale] dnexp=dn->exponent; // save exponent workset=*set; // clone rounding, etc. workset.digits=dn->digits-adjust; // set requested length workset.emin-=adjust; // and adjust emin to match // [note that the latter can be <1, here, similar to Rescale case] decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status); decApplyRound(dn, &workset, *residue, status); // Use 754R/854 default rule: Underflow is set iff Inexact // [independent of whether trapped] if (*status&DEC_Inexact) *status|=DEC_Underflow; // if rounded up a 999s case, exponent will be off by one; adjust // back if so [it will fit, because it was shortened earlier] if (dn->exponent>etiny) { dn->digits=decShiftToMost(dn->lsu, dn->digits, 1); dn->exponent--; // (re)adjust the exponent. } // if rounded to zero, it is by definition clamped... if (ISZERO(dn)) *status|=DEC_Clamped; } // decSetSubnormal /* ------------------------------------------------------------------ */ /* decCheckMath - check entry conditions for a math function */ /* */ /* This checks the context and the operand */ /* */ /* rhs is the operand to check */ /* set is the context to check */ /* status is unchanged if both are good */ /* */ /* returns non-zero if status is changed, 0 otherwise */ /* */ /* Restrictions enforced: */ /* */ /* digits, emax, and -emin in the context must be less than */ /* DEC_MAX_MATH (999999), and A must be within these bounds if */ /* non-zero. Invalid_operation is set in the status if a */ /* restriction is violated. */ /* ------------------------------------------------------------------ */ static uInt decCheckMath(const decNumber *rhs, decContext *set, uInt *status) { uInt save=*status; // record if (set->digits>DEC_MAX_MATH || set->emax>DEC_MAX_MATH || -set->emin>DEC_MAX_MATH) *status|=DEC_Invalid_context; else if ((rhs->digits>DEC_MAX_MATH || rhs->exponent+rhs->digits>DEC_MAX_MATH+1 || rhs->exponent+rhs->digits<2*(1-DEC_MAX_MATH)) && !ISZERO(rhs)) *status|=DEC_Invalid_operation; return (*status!=save); } // decCheckMath /* ------------------------------------------------------------------ */ /* decGetInt -- get integer from a number */ /* */ /* dn is the number [which will not be altered] */ /* */ /* returns one of: */ /* BADINT if there is a non-zero fraction */ /* the converted integer */ /* BIGEVEN if the integer is even and > 2*10**9 */ /* BIGODD if the integer is odd and > 2*10**9 */ /* */ /* This checks and gets a whole number from the input decNumber. */ /* The sign can be determined from dn by the caller when BIGEVEN or */ /* BIGODD is returned. */ /* ------------------------------------------------------------------ */ static Int decGetInt(const decNumber *dn) { Int theInt; // result accumulator const Unit *up; // work Int got; // digits (real or not) processed Int ilength=dn->digits+dn->exponent; // integral length Flag neg=decNumberIsNegative(dn); // 1 if -ve // The number must be an integer that fits in 10 digits // Assert, here, that 10 is enough for any rescale Etiny #if DEC_MAX_EMAX > 999999999 #error GetInt may need updating [for Emax] #endif #if DEC_MIN_EMIN < -999999999 #error GetInt may need updating [for Emin] #endif if (ISZERO(dn)) return 0; // zeros are OK, with any exponent up=dn->lsu; // ready for lsu theInt=0; // ready to accumulate if (dn->exponent>=0) { // relatively easy // no fractional part [usual]; allow for positive exponent got=dn->exponent; } else { // -ve exponent; some fractional part to check and discard Int count=-dn->exponent; // digits to discard // spin up whole units until reach the Unit with the unit digit for (; count>=DECDPUN; up++) { if (*up!=0) return BADINT; // non-zero Unit to discard count-=DECDPUN; } if (count==0) got=0; // [a multiple of DECDPUN] else { // [not multiple of DECDPUN] Int rem; // work // slice off fraction digits and check for non-zero #if DECDPUN<=4 theInt=QUOT10(*up, count); rem=*up-theInt*powers[count]; #else rem=*up%powers[count]; // slice off discards theInt=*up/powers[count]; #endif if (rem!=0) return BADINT; // non-zero fraction // it looks good got=DECDPUN-count; // number of digits so far up++; // ready for next } } // now it's known there's no fractional part // tricky code now, to accumulate up to 9.3 digits if (got==0) {theInt=*up; got+=DECDPUN; up++;} // ensure lsu is there if (ilength<11) { Int save=theInt; // collect any remaining unit(s) for (; got1999999997) ilength=11; else if (!neg && theInt>999999999) ilength=11; if (ilength==11) theInt=save; // restore correct low bit } } if (ilength>10) { // too big if (theInt&1) return BIGODD; // bottom bit 1 return BIGEVEN; // bottom bit 0 } if (neg) theInt=-theInt; // apply sign return theInt; } // decGetInt /* ------------------------------------------------------------------ */ /* decPutInt -- put integer into a number */ /* */ /* res is the target number, with enough space for the biggest */ /* integer that the second argument will be */ /* in is the input integer */ /* */ /* Returns res, an integral value; no error is possible. */ /* ------------------------------------------------------------------ */ static decNumber *decPutInt(decNumber *res, Int in) { Unit *up; // work pointer decNumberZero(res); // clean if (in<=0) { // handle sign, 0, and BADINT if (in==0) return res; // easy else if (in!=BADINT) { res->bits=DECNEG; // set sign in=-in; // invert and drop through } else { // BADINT: invert would fail decContext set; decContextDefault(&set, DEC_INIT_DECIMAL64); // 16 digits decNumberFromString(res, "-2147483648", &set); // ugh return res; } } // in is now positive for (up=res->lsu; in>0; up++) { *up=(Unit)(in%(DECDPUNMAX+1)); in=in/(DECDPUNMAX+1); } res->digits=decGetDigits(res->lsu, up-res->lsu); return res; } // decPutInt /* ------------------------------------------------------------------ */ /* decBiStr -- compare string with pairwise options */ /* */ /* targ is the string to compare */ /* str1 is one of the strings to compare against (length may be 0) */ /* str2 is the other; it must be the same length as str1 */ /* */ /* returns 1 if strings compare equal, (that is, it is the same */ /* length as str1 and str2, and each character of targ is in either */ /* str1 or str2 in the corresponding position), or 0 otherwise */ /* */ /* This is used for generic caseless compare, including the awkward */ /* case of the Turkish dotted and dotless Is. Use as (for example): */ /* if (decBiStr(test, "mike", "MIKE")) ... */ /* ------------------------------------------------------------------ */ static Flag decBiStr(const char *targ, const char *str1, const char *str2) { for (;;targ++, str1++, str2++) { if (*targ!=*str1 && *targ!=*str2) return 0; // *targ has a match in one (or both, if terminator) if (*targ=='\0') break; } // forever return 1; } // decBiStr /* ------------------------------------------------------------------ */ /* decNaNs -- handle NaN operand or operands */ /* */ /* res is the result number */ /* lhs is the first operand */ /* rhs is the second operand, or NULL if none */ /* status contains the current status */ /* returns res in case convenient */ /* */ /* Called when one or both operands is a NaN, and propagates the */ /* appropriate result to res. When an sNaN is found, it is changed */ /* to a qNaN and Invalid operation is set. */ /* ------------------------------------------------------------------ */ static decNumber * decNaNs(decNumber *res, const decNumber *lhs, const decNumber *rhs, uInt *status) { // This decision tree ends up with LHS being the source pointer, // and status updated if need be if (lhs->bits & DECSNAN) *status|=DEC_Invalid_operation | DEC_sNaN; else if (rhs==NULL); else if (rhs->bits & DECSNAN) { lhs=rhs; *status|=DEC_Invalid_operation | DEC_sNaN; } else if (lhs->bits & DECNAN); else lhs=rhs; decNumberCopy(res, lhs); res->bits&=~DECSNAN; // convert any sNaN to NaN, while res->bits|=DECNAN; // .. preserving sign res->exponent=0; // clean exponent // [coefficient was copied] return res; } // decNaNs /* ------------------------------------------------------------------ */ /* decStatus -- apply non-zero status */ /* */ /* dn is the number to set if error */ /* status contains the current status (not yet in context) */ /* set is the context */ /* */ /* If the status is an error status, the number is set to a NaN, */ /* unless the error was an overflow, divide-by-zero, or underflow, */ /* in which case the number will have already been set. */ /* */ /* The context status is then updated with the new status. Note that */ /* this may raise a signal, so control may never return from this */ /* routine (hence resources must be recovered before it is called). */ /* ------------------------------------------------------------------ */ static void decStatus(decNumber *dn, uInt status, decContext *set) { if (status & DEC_NaNs) { // error status -> NaN // if cause was an sNaN, clear and propagate [NaN is already set up] if (status & DEC_sNaN) status&=~DEC_sNaN; else { decNumberZero(dn); // other error: clean throughout dn->bits=DECNAN; // and make a quiet NaN } } decContextSetStatus(set, status); // [may not return] return; } // decStatus /* ------------------------------------------------------------------ */ /* decGetDigits -- count digits in a Units array */ /* */ /* uar is the Unit array holding the number (this is often an */ /* accumulator of some sort) */ /* len is the length of the array in units */ /* */ /* returns the number of (significant) digits in the array */ /* */ /* All leading zeros are excluded, except the last if the array has */ /* only zero Units. */ /* ------------------------------------------------------------------ */ // This may be called twice during some operations. static Int decGetDigits(Unit *uar, Int len) { Unit *up=uar+(len-1); // -> msu Int digits=(len-1)*DECDPUN+1; // possible digits excluding msu // (at least 1 in final msu) #if DECDPUN>4 uInt const *pow; // work #endif for (; up>=uar; up--) { if (*up==0) { // unit is all 0s if (digits==1) break; // a zero has one digit digits-=DECDPUN; // adjust for 0 unit continue;} // found the first (most significant) non-zero Unit #if DECDPUN>1 // not done yet if (*up<10) break; // is 1-9 digits++; #if DECDPUN>2 // not done yet if (*up<100) break; // is 10-99 digits++; #if DECDPUN>3 // not done yet if (*up<1000) break; // is 100-999 digits++; #if DECDPUN>4 // count the rest ... for (pow=&powers[4]; *up>=*pow; pow++) digits++; #endif #endif #endif #endif break; } // up return digits; } // decGetDigits #if DECTRACE | DECCHECK /* ------------------------------------------------------------------ */ /* decNumberShow -- display a number [debug aid] */ /* dn is the number to show */ /* */ /* Shows: sign, exponent, coefficient (msu first), digits */ /* or: sign, special-value */ /* ------------------------------------------------------------------ */ // this is public so other modules can use it void decNumberShow(const decNumber *dn) { const Unit *up; // work uInt u, d; // .. Int cut; // .. char isign='+'; // main sign if (dn==NULL) { printf("NULL\n"); return;} if (decNumberIsNegative(dn)) isign='-'; printf(" >> %c ", isign); if (dn->bits&DECSPECIAL) { // Is a special value if (decNumberIsInfinite(dn)) printf("Infinity"); else { // a NaN if (dn->bits&DECSNAN) printf("sNaN"); // signalling NaN else printf("NaN"); } // if coefficient and exponent are 0, no more to do if (dn->exponent==0 && dn->digits==1 && *dn->lsu==0) { printf("\n"); return;} // drop through to report other information printf(" "); } // now carefully display the coefficient up=dn->lsu+D2U(dn->digits)-1; // msu printf("%d", *up); for (up=up-1; up>=dn->lsu; up--) { u=*up; printf(":"); for (cut=DECDPUN-1; cut>=0; cut--) { d=u/powers[cut]; u-=d*powers[cut]; printf("%d", d); } // cut } // up if (dn->exponent!=0) { char esign='+'; if (dn->exponent<0) esign='-'; printf(" E%c%d", esign, abs(dn->exponent)); } printf(" [%d]\n", dn->digits); } // decNumberShow #endif #if DECTRACE || DECCHECK /* ------------------------------------------------------------------ */ /* decDumpAr -- display a unit array [debug aid] */ /* name is a single-character tag name */ /* ar is the array to display */ /* len is the length of the array in Units */ /* ------------------------------------------------------------------ */ static void decDumpAr(char name, const Unit *ar, Int len) { Int i; #if DECDPUN==9 char *spec="%09d "; #elif DECDPUN==8 char *spec="%08d "; #elif DECDPUN==7 char *spec="%07d "; #elif DECDPUN==6 char *spec="%06d "; #elif DECDPUN==5 char *spec="%05d "; #elif DECDPUN==4 char *spec="%04d "; #elif DECDPUN==3 char *spec="%03d "; #elif DECDPUN==2 char *spec="%02d "; #else char *spec="%d "; #endif printf(" :%c: ", name); for (i=len-1; i>=0; i--) { if (i==len-1) printf("%d ", ar[i]); else printf(spec, ar[i]); } printf("\n"); return;} #endif #if DECCHECK /* ------------------------------------------------------------------ */ /* decCheckOperands -- check operand(s) to a routine */ /* res is the result structure (not checked; it will be set to */ /* quiet NaN if error found (and it is not NULL)) */ /* lhs is the first operand (may be DECUNUSED) */ /* rhs is the second (may be DECUNUSED) */ /* set is the context (may be DECUNUSED) */ /* returns 0 if both operands, and the context are clean, or 1 */ /* otherwise (in which case the context will show an error, */ /* unless NULL). Note that res is not cleaned; caller should */ /* handle this so res=NULL case is safe. */ /* The caller is expected to abandon immediately if 1 is returned. */ /* ------------------------------------------------------------------ */ static Flag decCheckOperands(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { Flag bad=0; if (set==NULL) { // oops; hopeless #if DECTRACE printf("Context is NULL.\n"); #endif bad=1; return 1;} else if (set!=DECUNUSED && (set->digits<1 || set->round<0 || set->round>=DEC_ROUND_MAX)) { bad=1; #if DECTRACE printf("Bad context [digits=%d round=%d].\n", set->digits, set->round); #endif } else { if (res==NULL) { bad=1; #if DECTRACE printf("Bad result [is NULL].\n"); #endif } if (!bad && lhs!=DECUNUSED) bad=(decCheckNumber(lhs, set)); if (!bad && rhs!=DECUNUSED) bad=(decCheckNumber(rhs, set)); } if (bad) { if (set!=DECUNUSED) decContextSetStatus(set, DEC_Invalid_operation); if (res!=DECUNUSED && res!=NULL) { decNumberZero(res); res->bits=DECNAN; // qNaN } } return bad; } // decCheckOperands /* ------------------------------------------------------------------ */ /* decCheckNumber -- check a number */ /* dn is the number to check */ /* set is the context (may be DECUNUSED) */ /* returns 0 if the number is clean, or 1 otherwise */ /* */ /* The number is considered valid if it could be a result from some */ /* operation in some valid context (not necessarily the current one). */ /* ------------------------------------------------------------------ */ static Flag decCheckNumber(const decNumber *dn, decContext *set) { const Unit *up; // work uInt maxuint; // .. Int ae, d, digits; // .. Int emin, emax; // .. if (dn==NULL) { // hopeless #if DECTRACE printf("Reference to decNumber is NULL.\n"); #endif return 1;} // check special values if (dn->bits & DECSPECIAL) { if (dn->exponent!=0) { #if DECTRACE printf("Exponent %d (not 0) for a special value.\n", dn->exponent); #endif return 1;} // 2003.09.08: NaNs may now have coefficients, so next tests Inf only if (decNumberIsInfinite(dn)) { if (dn->digits!=1) { #if DECTRACE printf("Digits %d (not 1) for an infinity.\n", dn->digits); #endif return 1;} if (*dn->lsu!=0) { #if DECTRACE printf("LSU %d (not 0) for an infinity.\n", *dn->lsu); #endif return 1;} } // Inf // 2002.12.26: negative NaNs can now appear through proposed IEEE // concrete formats (decimal64, etc.), though they are // never visible in strings. return 0; // if ((dn->bits & DECINF) || (dn->bits & DECNEG)==0) return 0; // #if DECTRACE // printf("Negative NaN in number.\n"); // #endif // return 1; } // check the coefficient if (dn->digits<1 || dn->digits>DECNUMMAXP) { #if DECTRACE printf("Digits %d in number.\n", dn->digits); #endif return 1;} d=dn->digits; for (up=dn->lsu; d>0; up++) { if (d>DECDPUN) maxuint=DECDPUNMAX; else { // reached the msu maxuint=powers[d]-1; if (dn->digits>1 && *upmaxuint) { #if DECTRACE printf("Bad Unit [%08x] in %d-digit number at offset %d [maxuint %d].\n", *up, dn->digits, up-dn->lsu, maxuint); #endif return 1;} d-=DECDPUN; } // check the exponent. Note that input operands can have exponents // which are out of the set->emin/set->emax and set->digits range // (just as they can have more digits than set->digits). ae=dn->exponent+dn->digits-1; // adjusted exponent emax=DECNUMMAXE; emin=DECNUMMINE; digits=DECNUMMAXP; if (ae+emax) { #if DECTRACE printf("Adjusted exponent overflow [%d].\n", ae); decNumberShow(dn); #endif return 1;} return 0; // it's OK } // decCheckNumber /* ------------------------------------------------------------------ */ /* decCheckInexact -- check a normal finite inexact result has digits */ /* dn is the number to check */ /* set is the context (for status and precision) */ /* sets Invalid operation, etc., if some digits are missing */ /* [this check is not made for DECSUBSET compilation] */ /* ------------------------------------------------------------------ */ static void decCheckInexact(const decNumber *dn, decContext *set) { #if !DECSUBSET if ((set->status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact && (set->digits!=dn->digits) && !(dn->bits & DECSPECIAL)) { decContextSetStatus(set, DEC_Invalid_operation); #if DECTRACE printf("Insufficient digits [%d] on normal Inexact result.\n", dn->digits); decNumberShow(dn); #endif } #endif return; } // decCheckInexact #endif #if DECALLOC #undef malloc #undef free /* ------------------------------------------------------------------ */ /* decMalloc -- accountable allocation routine */ /* n is the number of bytes to allocate */ /* */ /* Semantics is the same as the stdlib malloc routine, but bytes */ /* allocated are accounted for globally, and corruption fences are */ /* added before and after the 'actual' storage. */ /* ------------------------------------------------------------------ */ /* This routine allocates storage with an extra twelve bytes; 8 are */ /* at the start and hold: */ /* 0-3 the original length requested */ /* 4-7 buffer corruption detection fence (DECFENCE, x4) */ /* The 4 bytes at the end also hold a corruption fence (DECFENCE, x4) */ /* ------------------------------------------------------------------ */ static void *decMalloc(size_t n) { uInt size=n+12; // true size void *alloc; // -> allocated storage uInt *j; // work uByte *b, *b0; // .. alloc=malloc(size); // -> allocated storage if (alloc==NULL) return NULL; // out of strorage b0=(uByte *)alloc; // as bytes decAllocBytes+=n; // account for storage j=(uInt *)alloc; // -> first four bytes *j=n; // save n // printf(" allo ++ dAB: %d (%d)\n", decAllocBytes, n); for (b=b0+4; b play area } // decMalloc /* ------------------------------------------------------------------ */ /* decFree -- accountable free routine */ /* alloc is the storage to free */ /* */ /* Semantics is the same as the stdlib malloc routine, except that */ /* the global storage accounting is updated and the fences are */ /* checked to ensure that no routine has written 'out of bounds'. */ /* ------------------------------------------------------------------ */ /* This routine first checks that the fences have not been corrupted. */ /* It then frees the storage using the 'truw' storage address (that */ /* is, offset by 8). */ /* ------------------------------------------------------------------ */ static void decFree(void *alloc) { uInt *j, n; // pointer, original length uByte *b, *b0; // work if (alloc==NULL) return; // allowed; it's a nop b0=(uByte *)alloc; // as bytes b0-=8; // -> true start of storage j=(uInt *)b0; // -> first four bytes n=*j; // lift for (b=b0+4; b // for NULL #if defined(_MSVC_) #pragma warning(disable:4244) // [for win64] #endif /*defined(_MSVC_)*/ #include "decNumber.h" // base number library #include "decPacked.h" // packed decimal #include "decNumberLocal.h" // decNumber local types, etc. /* ------------------------------------------------------------------ */ /* decPackedFromNumber -- convert decNumber to BCD Packed Decimal */ /* */ /* bcd is the BCD bytes */ /* length is the length of the BCD array */ /* scale is the scale result */ /* dn is the decNumber */ /* returns bcd, or NULL if error */ /* */ /* The number is converted to a BCD packed decimal byte array, */ /* right aligned in the bcd array, whose length is indicated by the */ /* second parameter. The final 4-bit nibble in the array will be a */ /* sign nibble, C (1100) for + and D (1101) for -. Unused bytes and */ /* nibbles to the left of the number are set to 0. */ /* */ /* scale is set to the scale of the number (this is the exponent, */ /* negated). To force the number to a specified scale, first use the */ /* decNumberRescale routine, which will round and change the exponent */ /* as necessary. */ /* */ /* If there is an error (that is, the decNumber has too many digits */ /* to fit in length bytes, or it is a NaN or Infinity), NULL is */ /* returned and the bcd and scale results are unchanged. Otherwise */ /* bcd is returned. */ /* ------------------------------------------------------------------ */ uByte * decPackedFromNumber(uByte *bcd, Int length, Int *scale, const decNumber *dn) { const Unit *up=dn->lsu; // Unit array pointer uByte obyte, *out; // current output byte, and where it goes Int indigs=dn->digits; // digits processed uInt cut=DECDPUN; // downcounter per Unit uInt u=*up; // work uInt nib; // .. #if DECDPUN<=4 uInt temp; // .. #endif if (dn->digits>length*2-1 // too long .. ||(dn->bits & DECSPECIAL)) return NULL; // .. or special -- hopeless if (dn->bits&DECNEG) obyte=DECPMINUS; // set the sign .. else obyte=DECPPLUS; *scale=-dn->exponent; // .. and scale // loop from lowest (rightmost) byte out=bcd+length-1; // -> final byte for (; out>=bcd; out--) { if (indigs>0) { if (cut==0) { up++; u=*up; cut=DECDPUN; } #if DECDPUN<=4 temp=(u*6554)>>16; // fast /10 nib=u-X10(temp); u=temp; #else nib=u%10; // cannot use *6554 trick :-( u=u/10; #endif obyte|=(nib<<4); indigs--; cut--; } *out=obyte; obyte=0; // assume 0 if (indigs>0) { if (cut==0) { up++; u=*up; cut=DECDPUN; } #if DECDPUN<=4 temp=(u*6554)>>16; // as above obyte=(uByte)(u-X10(temp)); u=temp; #else obyte=(uByte)(u%10); u=u/10; #endif indigs--; cut--; } } // loop return bcd; } // decPackedFromNumber /* ------------------------------------------------------------------ */ /* decPackedToNumber -- convert BCD Packed Decimal to a decNumber */ /* */ /* bcd is the BCD bytes */ /* length is the length of the BCD array */ /* scale is the scale associated with the BCD integer */ /* dn is the decNumber [with space for length*2 digits] */ /* returns dn, or NULL if error */ /* */ /* The BCD packed decimal byte array, together with an associated */ /* scale, is converted to a decNumber. The BCD array is assumed full */ /* of digits, and must be ended by a 4-bit sign nibble in the least */ /* significant four bits of the final byte. */ /* */ /* The scale is used (negated) as the exponent of the decNumber. */ /* Note that zeros may have a sign and/or a scale. */ /* */ /* The decNumber structure is assumed to have sufficient space to */ /* hold the converted number (that is, up to length*2-1 digits), so */ /* no error is possible unless the adjusted exponent is out of range, */ /* no sign nibble was found, or a sign nibble was found before the */ /* final nibble. In these error cases, NULL is returned and the */ /* decNumber will be 0. */ /* ------------------------------------------------------------------ */ decNumber * decPackedToNumber(const uByte *bcd, Int length, const Int *scale, decNumber *dn) { const uByte *last=bcd+length-1; // -> last byte const uByte *first; // -> first non-zero byte uInt nib; // work nibble Unit *up=dn->lsu; // output pointer Int digits; // digits count Int cut=0; // phase of output decNumberZero(dn); // default result last=&bcd[length-1]; nib=*last & 0x0f; // get the sign if (nib==DECPMINUS || nib==DECPMINUSALT) dn->bits=DECNEG; else if (nib<=9) return NULL; // not a sign nibble // skip leading zero bytes [final byte is always non-zero, due to sign] for (first=bcd; *first==0;) first++; digits=(last-first)*2+1; // calculate digits .. if ((*first & 0xf0)==0) digits--; // adjust for leading zero nibble if (digits!=0) dn->digits=digits; // count of actual digits [if 0, // leave as 1] // check the adjusted exponent; note that scale could be unbounded dn->exponent=-*scale; // set the exponent if (*scale>=0) { // usual case if ((dn->digits-*scale-1)<-DECNUMMAXE) { // underflow decNumberZero(dn); return NULL;} } else { // -ve scale; +ve exponent // need to be careful to avoid wrap, here, also BADINT case if ((*scale<-DECNUMMAXE) // overflow even without digits || ((dn->digits-*scale-1)>DECNUMMAXE)) { // overflow decNumberZero(dn); return NULL;} } if (digits==0) return dn; // result was zero // copy the digits to the number's units, starting at the lsu // [unrolled] for (;;) { // forever // left nibble first nib=(unsigned)(*last & 0xf0)>>4; // got a digit, in nib if (nib>9) {decNumberZero(dn); return NULL;} if (cut==0) *up=(Unit)nib; else *up=(Unit)(*up+nib*powers[cut]); digits--; if (digits==0) break; // got them all cut++; if (cut==DECDPUN) { up++; cut=0; } last--; // ready for next nib=*last & 0x0f; // get right nibble if (nib>9) {decNumberZero(dn); return NULL;} // got a digit, in nib if (cut==0) *up=(Unit)nib; else *up=(Unit)(*up+nib*powers[cut]); digits--; if (digits==0) break; // got them all cut++; if (cut==DECDPUN) { up++; cut=0; } } // forever return dn; } // decPackedToNumber hercules-3.12/decNumber/decNumber.def0000664000175000017500000000530512564723224014476 00000000000000; $Id$ ; Module-definition file for decNumber DLL (MSVC) ; ; This file was added by the Hercules project. ; It is not part of the original decNumber distribution. ; ; $Log$ ; LIBRARY decNumber EXPORTS decContextDefault decContextSetStatus decContextStatusToString decContextSetStatusFromString decimal32FromString decimal32ToString decimal32ToEngString decimal32FromNumber decimal32ToNumber decimal64FromString decimal64ToString decimal64ToEngString decimal64FromNumber decimal64ToNumber decimal128FromString decimal128ToString decimal128ToEngString decimal128FromNumber decimal128ToNumber decNumberFromString decNumberToString decNumberToEngString decNumberAbs decNumberAdd decNumberCompare decNumberCompareTotal decNumberDivide decNumberDivideInteger decNumberExp decNumberLn decNumberLog10 decNumberMax decNumberMin decNumberMinus decNumberMultiply decNumberNormalize decNumberPlus decNumberPower decNumberQuantize decNumberRemainder decNumberRemainderNear decNumberRescale decNumberSameQuantum decNumberSquareRoot decNumberSubtract decNumberToIntegralValue decNumberCopy decNumberTrim decNumberVersion decNumberZero decPackedFromNumber decPackedToNumber hercules-3.12/decNumber/decnumber.pdf0000664000175000017500000042142612564723224014557 00000000000000%PDF-1.4 %âãÏÓ 197 0 obj <> endobj xref 197 13 0000000016 00000 n 0000001470 00000 n 0000001554 00000 n 0000001687 00000 n 0000001795 00000 n 0000002423 00000 n 0000002614 00000 n 0000002691 00000 n 0000003016 00000 n 0000003652 00000 n 0000003847 00000 n 0000004483 00000 n 0000000556 00000 n trailer <<4FE959721A464F49891A8DDEC4170F9E>]>> startxref 0 %%EOF 209 0 obj<>stream xÚb```f``j“Çx€‡Y8 Äà¬i6F™û.8‘nú¦9œ+aÛiÉÐ%aÓÊf‹½î1ÛÆÀåßuhc]D`]XSᛦ”'¶†JÓ¶ 9`šÐ¡ÏÝ [þ¢ÅDùNFØ£˜0&¥Ek ÍÖžxÕò¡™æ¹æG ýRdŽú^nIxîÙ—¬Ènx9ñÎ3ÞäIS–j‚¬f p]‘ä%²ÉuMᙞ)†Ž_ææÏ<;áÈgÅ ?Uù2Ù4ìIq*KL p7Ij~2ÅrC]c—³P€»ÿ¤€ÏYŠÝ@æ)=›’5ÒË4nždªòtÏž#R²s‰Ä‚ŸªPuÊsÏÎÍ­â ¨™ÔæzViš¡ã'/Iq³Ò­/|€ßy/Íj”zt\³ˆ¼Ê‰ÅÅMŽÏ*v}Tl¹¡¦ (¦xæÙA ^!ËÅ"¯³/ƒÌséË8Ê~"É˸ÉH/G¤8æ’ã'‰I`®Ê³ç8Š”AæU+0”9ÓU"s¦÷¤Æ9Ž;‹@$î<˜¼v½Èo`Ÿª²4_êyÐÓ= äf™KFê Å'zÀRž ²(aä.èéq-'5!;WbRσ U ¯^jJg‘›"l!±àËb …£ìKYαiØ00 @’“’²YRqqq &/AÁ4 šNi. ÊLÓ‚Æ` "R­g‘ÆPQ0W‘g@èp 3ÅÒ€¶3°†) €š%(5^PØ ,Ã(¤¢…4€‹kh#lâââ–b˜A$ÅÀjÙ@BBªmi`Ä› ›@\Q°v¨åÀm v¶ØÎP¸ “*ØYPÇ1›ÁI¨}L'A8l _ƒC l@Ð7´È§@ëV00ž¤¹€Xì _^ÆìGüؘ¸>(¬eø ôÀ¢=ÃNq³E×ëG2ŠW™"d8#d®@‹‘ Œ1€ !†D >ÂÀį òï0"1h‰ endstream endobj 198 0 obj<> endobj 199 0 obj<> endobj 200 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 201 0 obj<> endobj 202 0 obj<> endobj 203 0 obj<> endobj 204 0 obj<>stream H‰<ÁNÃ0 @ïù Ça^b'i¹¡ †l÷¶Ë¶°v‘ZÆÄ𽤠B–僟Ÿ-/_±tb±V ÀíY)R!¥Qßj0Ö -eêvBÂ!¥k„Di ƒ»Š™;zØùf{éjßà ÚP÷Uÿ}ã>’•²U©Éš kFK¸4Èå蜽û~ñ Œ\Àw°_~ò‘”6«øOEYE 9)(ªQeÓ&œ<¬âµ ñºŽcJfZ‚.8a§Û3þ´ÜÀÚ·mœÐ¹ÆB+†¹Â´è>·ßžá¥ªc_}Æ>øaäµµö“Óº}sw9a¨;lb7bNü 0èyV¨ endstream endobj 205 0 obj<> endobj 206 0 obj<> endobj 207 0 obj<> endobj 208 0 obj<> endobj 1 0 obj<> endobj 2 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 3 0 obj<>stream H‰”TÉnÛ0½ë+æh±ÂE‹utâ$h.@•^‚‰vØZ” JŽû=ä{;¤)/Q ;0 Ñò{3œ7oæòî;…¥ö®Rïò–…tá1?øˆD4ð¤¥G`‰ß4÷ˆOÂCúìÒìq% ZÀu¥Z¡Z=Naœ`‡RIaùÔÆñcŒlØ_×¢YKñ ÔÐL˜É4?Hð0º×¢ù«á®“…O(!dÄÇ?ÓO˜…»,>IHjÂÏ‘r³ÉʯEᴴǬ(d++å"„6BúáÌœWe]uª‰Å4B· ááu¦µ\ MS5ð”©b%ÕÒqâ!'@N–·ÿ¥L‡”ÐÝ /£E‹ª)3y‹§dHˆð-Ë#x.rYf+P]ù(š‰9õ\&½|Nû‡Ñçªè0R!tÞÈÚ¨¶ãžR¾¹5¦…ÒFé‰%¾Âï0 ©lƒ4ÐȘ‹Ýv*wïbón2àïm‚™¿Ø:3r~bƆ‰wïsa‰h\XôÈ>ß·dÖÈö©­Ì‡°Þ·r%Û? ß^ýuѶTÓWÎ.À£àÐJýOʦN…],~¾ œeàÁú;ÛéÏãw$ŽßH<=Z(hR:¥Ó7ÅÌ8:¾:rm@N¸6í¡U°Å¡7ç:k2lÝ~lzjlfu-T!78€×8ØËøAÐ7{_÷GUˆ ɶ:·v»-³tq_ÚM¹[´?œá¸¿•)$>¥$F¼‘ÁB¤4ܤÞ?T   endstream endobj 4 0 obj<> endobj 5 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 6 0 obj<>stream H‰tWMsã6½ëWà(§D˜à7s›™$S“Úq¶Êª½Œs HH„_K‚–½¿~_$EZv¹dI€î~ýúuãþë£`§~óy¿¹ÿC0ÁöÇç1x‹=‰€{l_m\vÂkŸÓ¿Ëfû׳잕¼Üíb§ow avâ ;Ã(âÂìänšFf×þ,Y!ó‡¡:ÈŽ•êÐeÝ+SU[ÊJÖºg ì‘ÁxdÊ…NÝÿ¶Ù~•µì²’ý&sUáýS§ô¹’Zåì±Å³£Ê3­šzåUdœŠXè<à\¥<¶®¯-_ûzÏš¤#Žeƒë“]=cT>ô¬¹._w8Ýq«£¾ «oÂ蛟zÜM¨Ò·ÿë¡jŠ¡”ýÇÊæÇ>÷b«ž›ø7e‚P=ï峬ñL8˜7âCî LHy^f=-U”_Ö~¢æzžƒ÷Ý8Uh*T“ Î"vy¼ý=#y1–Ø9#2\¸ÿ#ƒpmÐö$äž1?L9Ió¤„g™²û r_DÜW›È-ߺ€Ù§-K¾dään²½µx‚‡áù¹5ðó>IÌÃà}¶ ’‘XÚëø1ã(]Õ +’ÑŽUi*°"Óëu7äzè¤%N6ö [Ü‚€S!ûAÄ£ðêxß ].?ðÙ‹±)Zm"WÒ%n ´Qݬ’¬¦OÛ;o:Žû±Ú>hJ~âk“<ôã±SîÆÞÞç‰›Š…; ÜóqO±+|7†ÜÓÄó—¸{(µ5umiÚQ¡.5ždúM6@í4!*®ž´a*ª:AÕ½F3” Í›Dâ—ä»7E>7…Q±Û"ƒšôêTß6 Ôv¸hÝœ§yrYN,·lñB ßÞ;4ÿ01ÜÕ¾ÙÆV8°ÁÙx1ô«¡Ã*ô¬áŽÁÇ âuf¢±"ô4¾V{™<¢ÿBFφq dªoŽú’ BöMN¯ãε;Dî(]ׄïÁr'©âÈJ®ú=hU*­¤iqq„÷M Ùâ>ËåŠåï0`†yÇê­¯3æVFC-s´J&iqÖáƒéÎsïÌ‘giñ½éõ¢§ªÚ@ppG-ÖÙ?Ò8 …ïN‡ßçLàyè->”ÆãA²âÌ—d}ÑUhìñ$\m$GGä g¹àG<P—Ky‰©Ó­Sç¡AòÛ†‹²}ÚÎÃÉŽuÍ`›–“þŒòå{< E¼’/ßÈØèÎÎÌ¢n$“ yáX‘ x¥ñj\ÜØR¹kJëôKrU+_rÙ’Ó¨ŽœšïÀM?¦Ç2;Yê.k™4ƒ`÷Î(BMvºÂÔÛiä¶Sß0I,¦‡+oÖ³ñ¼BkGËr ÙʺfÔYuZ¥MŽ2UÏ“y3„º¾ˆ®²WšWêäàPEÂH—2­K9>ìõlLvq=À'ЀJ Ê QÐM—ä‘Mñ¨ ù« ý÷=žÅëOdù'sÑcv!Ög?þvY±L± &,4ÕF„×oåæ‘.ªÓ}ŽÖAÝÈÌö—šßR†ùÆp…ô\n®qÛG)?hˆÂ¸+–kÏZ·¿Þß_.Ÿ‡®/å+W‡ŠCïG…]w2J’ë ïzÔ•)Ôè[!‘¢‚f›û8‘:^L·\T#®@™ŠäÇö?V«îß÷¹¿Å+÷ÆvobŒ'L¤Pw„> endobj 8 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 9 0 obj<>stream H‰¬WÛnÛH}×Wô£¼Úl6¯yK2ÎÀƒÄÂ"‹xÚd[â Ejš¤ïÛþÄüÇþážê&)R±`g‘(¥¾Ô9Uuêðúç{Á¶ÍâÝfqýA2Á6O !˜‡?ø/öY,Rž²Í~á±->›láq‘Š˜mŽ‹å‡º3l¯²]QéuQåú ñOÕ²‡åcײúÐu¥Êò…áûBUëqÅÃËêýAe-kÚÚ¨­fOµÙ«¶¹Úü†{Ö‚#–Ÿp™†’.ûºTF³ƒ©Ÿ‹\ç´šU«M¶SÕVó«uE<\nvºÑ Kß\ýºù Â”ç@y*J"ù¡ƒE@r{UJŸn…á'¢@¬Ä=kó°úèbi¾¯‡‡ew`mÈ‹²¤*p•ñpµr0ʦv§º<40ÿDqÓZ”ºPL¹'#ñ\.›L•úB}‘Ïe<Û´´õ·–!’$&m‚0$y_†ç•ÓsCÀm*ûÒ»!«+B…ÞXÀ÷d꽫®ÚØÒ»s)›þlšH/œªSýuÎQvêþ>¦Æ±ØGr)ïsƒéd0äPÓš>© 9kè‘"ꪬµG¡{ÛÝ…»üáªo`Ñ“í;²}jà€”½çù¾E$Êä•€7»”&Ú‰¡ƒ—·¶ch Ú:owˆqÊØŸ®lÜàåX´»7#ÍCbm^ûÞú7z#ŒCž,-Ú¹þ *€6hw{ÝBrý„¦Î‰·w÷·ì‹ä~¬EšF¶³†Ù  d³ ÀàŸÎ6IáL*R&<–ë|žŽ3Êó„s3C"'E••]NyÑÆ¨V¹²Eñ üSõÛ†·;SwÛóqâÕÝâs‘ˆäŒ8ç| )1þè c™µZ~{ssÃ’ð&ñjØáÅÐ@ˆ¸œæ€ýDBÚXø<÷“ ¢° NÑl÷tÆq³·Ça`׳)6‚µˆQ*˜mpï±6¿¯¦vCøéf/ྋp΃~Ì“0Åïd¥N&éo$Œ¶…›IÉ9›~‡nƒ é•›Äöô³*;T¥Ñmg¨ˆÔ5_nEám§v(q÷”׬ª[æ,$ÍLOø”Á^8„ç&Ü×¥ Ð[4¿Q‡ƒÎCÆVýÝÜÔ™ê`D‰Û!£®° »5¯$ݽՕ6ëÓÄÀ¼ë©²ø—&u¡3õ0(zýíc­mÆ.öS.–÷žÀœ(_V.Ÿh'Ébµt xrSF6‹†3æ¬vÔè–Z”Ê‘Oû îZW4° úÅ®í+Ò´’D1;ZÀ{õRX«ðªgn…6ÇW*ïEîÕÞ‘a,)þ<Û–Z4¢—ÓóRSh£p}~½ÓÊ`°T$ÆÒÖ¯§6ì»»nƪr.ƒPÛW½ÆKM붸>Sa-Ó°I{Ü ÿ{üèÜV³’±ó¥roOçÊk“#ØcÝ•hdý=óÎ=Ô[ÓUÕà)èc+Gõ®i<jC!v ŽÄ ˜>¨BŒ›ÿ?³Éâñ0HÝÏKṟb÷Sl[²BHü$ti)VPâásÉR¤)ôÎs8lêEâ,Š‚3±RÇï]Ýj7ÍHkk@7È›®C5“¢ø¡ÖsáEç6)„Ìú>é.êÌ'ýyP(쀠Lv,½~x`ZÉDÆÓbò‰×ÚS¢.µËòS©êHåpWNªCkõª¸Ã&C ó›ai3Ø{ôÍ(~ÆçýC‚áÄø#ûú«Çò…`[ÀHø$å‰dû…OOåâ~ñn3ެIŠC¢³—ÐÔ.H‘.ƒ‹b87£õÆœvŠƒNkwm{xs}}<}¾ëLSê^<î9lÊuo1è÷†ïÚ}9KÌÄ+M$“0hDÚÛÛ;¹nUQ6ƒ2žÞ´Ü¨’ÒéÇgcÒy>Çꔎ(æ±£ÃY–ëþ< ’(äÑ0Å1:éÌ·{È; Îêeb06ÎÛÊ]J‚±ÑÙ®ªËzûÂþdŸL½5j¿'1ø;D SÐÏ7_¾¬f>kJO²½hÚúvæ¯ûï_©ÓËÁ5ˆ¬i‹¶kõŠÝé#û'YFw~GOÚ$Ï]Î95äIŸ©D¸Ûg çÔâÀï±Ðÿ´eFàg•ßÖ·•Œd> Æõ“5®oGÃ:# n1Ä)áŠÙ)5@FÙ8æH-¥|º›Rg4œÈCrÜc]YÃnª-|1Äh…3>ç{Ο/¡ƒþÂ)ðŸR’aóxêøKdÐ:5•ó«qO“}öè¾ý¶p˜J¼ÐZóÚlÝÍ5FÇõì fŒÂg©ðëòî}êj-%Ü럸¢#‰Ý“Vh]Ðo´Ôõú¾>¼˜b»£×« £þöÝGö¾6K×P&TÙãNí-yoZlý€6Ϥ¨î³ Cï ¸-=W.(äMö· endstream endobj 10 0 obj<> endobj 11 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 12 0 obj<>stream H‰ŒWÛnÛF}×Wì[(ÇZq—Ë[‚>$JR¸hÒV VQPâJb‹°KÚÑc¡-ò½™¥$ÊŽ‚°%‹3³3gæœYM¼lcG¯ç£é;Á›¯GR2~à%–,ŠK6¯F>ÛÀï|5ò¹†›?Œ¼_­6[öcWäz<ÿ!B /"Œ".(~¨ÈsÞ°ÎjÖn5ËõêCW-µae±4™Ù3½^«B×m¹gEË Ë–Ú¶¬mغ0ðfÕÔ÷Ú´ä]“«eû¦c™¡,|6\"aó7xfªB:ó¡1Ÿ‹zÊvËÖ¦©0@a \®sfôÎh ‡fmÑÔ¬¨á¸SjëÆTY{5[e²lºO›_ Yeåª+)„eì«k–Õ9¤^g%4H¾bËlõÙå°…T\BîH~¬(:UÉ”N›Q,K‡A :¦¯ëIîˆ[g¶}‰÷ôog;Ê ?Ãv›ÕCÓþ¸0¡Óô½¦‚˜-ª]‰9«vá¹ý„àˆ“„1ÈÿËÙˆøØ÷×x"Â8ä‰g[пºÝܰå¾ÕjÔ¦‚ik!èrϨÌ黨o‹ï˜ üN÷EÄT$x "Çq,úÙbá?»@çÀOÀI{ð‚Q·nª¨œÙbŒq&Rp†é¥2Ú­Ñú ¢ -¢R6€j½™ìà NuM°TPoæ# <Þ8“£2Ý›¶>µÐ)Íî0IJÄN‘w£«¬¨s $Ñn±ãzåä ,;@0µÔ!/²ÉxÔZè!ŒÍ§®&ÏoðéˆeæÒaÏ­þÒ‘Oü­š¼ºa/+Õ„P?ï–»>õÊ-œr Rî ’0Ù)vÈûÐ`âP‡éê5O=ĸ¬Ü xì'‡&'©#’‰@Å€ù+àÃ0Éʃ)ÚV  ×°WnoØìLWz×:æ!–ÿ”E8Tj 8H)dât¼âüËê¦Wê°´ÂÏ [mfڣĻºžÌ} |®¢˜à2ŒOs?^z)Á# Î\Nù,ÆNu_Ï>þL­›=Nã_a[„UaµãHX?®+ÊáÚ×ÌG {ïQªfDˆ¢Äi¶Ýn×Ðú(ìKV¬`³[üÔ®L±C]®ae"°(R§a¤km/6y!jšÉò¢§Ë²l`CŸ4þ)¨iÈ$ Âðê7½O"ß÷8çîÍÕ´W¤'8«Ð‡ à=ˆâ¡¤#vâAiXã® cäi&‘É[!×Í$ôä­Pï0,už™÷¯ÞàúÛïÀ˜ZyI3U‚ºóÀW§¹±m!øöÂô¤“±â BO!í|¹äd‰_mÜ´¡Ss…„nñÞJk´nX¤†f d÷YQfKÐ1Úp˜KrH©œ—w Tø7w‹O¬Îƒß¸wŒcBŽ i$Vo¤¯t!fÍnoŠÍ¶Å ðß¼~Ïfmäö0Ìl„Їt/ cËð[•¹×9ÿv¦!,×N¤ëØ£·óÑ ž‚%1 endstream endobj 13 0 obj<> endobj 14 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 15 0 obj<>stream H‰tS[OÛ0}ϯøÓ‰_'Ñ´‡uÒ´Id{=˜ÖM3¥qd»tü{>;¥t¨©r=Ÿïøüæ–Aë’‹&9¿À Y'ŒÅžj %«I Í6¡Ðâ¿Y&”.¡Ù'éÒlÇ®×ö œöà7fÍoä‘:ñàQç„â”,à¯æ—?nç2ŸPÿ©óœ#вJuÀÞ¥àwC7´0*«¶Úk ÷©Óï[ 9¿Ÿ7@?Î2I)St÷rÙ+ç÷fö«ùò–é°xZ’êÕ¯õJ¯ß±ËDIêºÌOP„¸êu Ì£euj€Áx4Ò­HàË ÄÖdŒÈ¼È¡¹B4—5Ÿ+È,c"GÞôÛ€,nÔKfC×Ôv쵃pµÕƒW¾3C†n»!HdŒâ ŠtáÃWʹÝV¯­âÜbvÅ¢6ÉÓj2—"Úõ6jXõ!ôƒòíâæúû\תĹVñÝhM‹“Aé’KLz±†'³³'³(Û|@)VŠjŠ]Ò‹ëñ¤œÈÏ"'jãã}ç7ï5MМÔeR¤xö“x«F÷ ñöøD)Iå 4Ø*mÛ›]¿ŠS{ЇÁA7ÃË8‚rþW|ÇÙÇ%ÛãœÈä€Mêh †’‡Æ½8¾Kjë0ŒY&„  ÊCSË XE`…›«ÂÎä/è {hÍ¥Ÿl×n> endobj 17 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 18 0 obj<>stream H‰ŒWkoÛFýî_1H±…ÜH4‡äð4Ç)¼Ø Dí+((r$M+‘ iÇ»èŸØ-ò{÷̃íŠÒ"̈wî=÷uæÞ«?Q²VïçW3BÉ|uASâãþ$Ihྻ Ÿ¬ñ™¾çû~Hæ“›/ùn¿å8ù•(a󲨫ËùoP:¥Ô*¥Ziû3=ŸÆQ4ßE¸Ó†Ç¼S×pÕ½¬×2ß‘Ç(6¤È+Âs%¶OdÉq¨áUÉKÒԤ仺RÌNvµäƒOfÔˆÚcwQC¹( W’zÏqˆ©¥Ö¿à±ãUCE³!͆“U[V&ÈÅ6_n¹g=L¬‡‰qÿñCú)‰ƒÌ‹lØ´Aê¤c߯C‡„yYä'WW] ¨W¯_IQW\6‡ˆGóX“\®[‹±–¥²ÞwínÉåô42š:KÁYP½(@!±Â¦ÖrJòª$¥PûmþdÐI®ÚmsÔzm~âBâ%aé¸ÜOHè]~žÿý‚¢X¤sÅ™t™ÀEç0²,¶Zï'ß”|%*~9£¨Ùɇ›ë»Ÿúpûãíü £ËêÎ׎ `¿Û̶{·0‚kÑ(d4n,e.ì,¦N˜DUlÛ’“W}z¼Í«ËY’Z0Ë\qR™ßÉV,e.ŸÎÀH"#> £Àø^5¥¨½Íˆ’X +Ôý^ŠªY7ܱ8<’»ätîÒ³Yà|q²ËEµ0O¨íbJŠM.Éwx~¸ÿ¼¸$ÿ>YÕ,¢NU6j5H¬ÕNô~Òç„äS²|£c’ŠDTk—š‘ÒÈ2/ PúÎ6õÏïdñëºj@`Dñæ˜ñ¾>mœvÄAÇI¦3ÞÉÞOLpA•0s?ì”×4ú (Ad‘XîQ`>²lW+.Ç+ÄO» ¡)í*÷‡9§Yv¤Dhxs”%f±"‹‰®ïCS¦Ï ̪n¯êv½±tx2bQwg—0³Ö{YÛ ‹É«n¹îYÕî÷¸4»Ñ\’ô‹êÕâòÍ F ;(æ9ÐãXúƒöŒäM++ðb@ߌ&&Š£cöâóöúƒ&UwÈÅ”…]L“³íeð¯r\‹É·h…)AEþz{w;ÿõý»O7ˆ%AŽE…¹"ߊñ“@¢ŽRè8ýt@:Ùû ¬z˜öê­¯1ˆ»º"æ×)®·¼ú<ÕíéÒ ;¢gi¨—µÖíôvØ‹@Â\BÍ ¡[q<Õ$Õøñdgy#ò³CÆ,a~”õî“¡ä äihš~žÀÑê·Q ³~AœéƒìqÓKg:ø?M§Igú,óô²ƒ{â]YZÍgy°9KÜeš¿Í_/G3&ñ± EãÍØéÚ3=¢y=Hƒ%KëÕ©Z ãnž ÆšÎz/ÛÓàßyMðõö|kÊÔ@Ÿ‘’2 Ù1r NS‡ˆE£dèŸq<êø'8ËUÙ?4ée|± QS¡s†ÒÐûëfc–Þð)‘mUéU¢[p<”Q’zÉä¶"[,'²;¨È#ÿÏvKpõ©—“ÙhèµåÐ^kßwµRB“.PýBi8Ï{q5»¨—ups>KŽ&·¯X +!UcôE÷Cû-Švp ®ôÏËQ÷šzÍ!&ûnÂigT÷®s ƒîæ;ˆE®–„?A´ÃާÙÞÕ ·ÕÑXšPz(µééø¼#ÂÎMÕ“‰»>Lïk ɦlS¸/\4Æ–£-†5 FÃØÜ…wùÝHcQ?òâ Í:Q“«ŽÚÄÆ¦+:}oÀ•eÝlºì(³Îå.Cž‚A)“›ç> “GY—m|™ž @*@y´*É»‚CÀPý“¯9IÍ^}¤Ö“Ì8’éÛ<‹ãÅ/(=yÏÂwüŸäùŒ‘šƒ)¡˜Wã(êNkUq]Xo(àüíûŸÈu›Læšk0¦û±a’Øc“w`#¬tθ|Ð` ¾@Ê@~¬ àN˜öéf~ñ?A‰¼ endstream endobj 19 0 obj<> endobj 20 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 21 0 obj<>stream H‰”WÛnÛF}÷W ¸ ‰Þ]ryI‘Iì.£hÔ¾XF@‹+iŠHÊŽû!þÞÎ^x±M‰¨cG µ;sfæÌÙÙó/ß(¬«“ó“óÏ1P˜¯NhÿáGÈ ¤Ìe„àÛkü›/OˆKñ`þpâ\þL¶»Lƒ'XÛ]±ÏSy-JQÕ“ù?hÖ³f©1K•Ù .×6]BY MÍ7²aíÕÉQA½)…€]R&[&+X82—µL2H¶èªž¶¾ Lj1…Ýçûí(¡XÁ£HÊj1Q8̨‹@.”KÎ5úG-_&ÙrŸánåOÀJæÊür¹ßê·*œ{t°yíNfA¸Üù\” Ôw“Ûùïf`Ã$&Lq‹]ߤNEH‰ú¤´q+4ˆ ï3/ð]NäÄ®gófƒÀ¼ Ø ZE¬"Ø•Å3²zg,…ÆR¨ áñ\J"à1±Æ :׬~¥Üý [ã¤bym³œcÖ·õC1… Ö¾鯓¥>!Îù9R"¯ê$¯+›¤CHB–ÃFA4Kû ÐG‰\0Ðùìƒèø3Œ ѨÉkè…¾!xî¡Ú¶hÚ}fK ‰‚Îë¢N2%fŠy‹tÝgõHFxh3âf¤YªÝ*°!~ÖP‰Z;ŽLŠò‡Ìת êëç~`óQçÍÒg¹IT%Jtssqùéú¯¯W_®æßÞRÿö'î±²Èán¿Za®VÅãU LUtCóúª§ñu8^,æ¿,–ÍÖ…X%X’…ó ¦mjª„!|¿º¾šÿøáÛåb‚p¿WD«Cò_1’KêÙ\F£¹l–Þ8íËdW½'è˜ÑÀ¤./@¿qI˜uºl–—©\˺zϸrJšö)ÅRêr1~ T±‹Á©õKɘãvm¯g>—Åö›æBéÊd櫾9¥§SP•ÑUðˆ…Ïcò‚ò£Fã\цB”Ž’¥Ûø¢³Ÿ¡ÔÂg1>±SËìÑlæÑQÑëÖðÊ;…S^Övã±²êƒ%K±Oƒe·ÿ§²Œ7• FSÖ®F¢3›1ïv¼²ÔÊK8RÙQiò‰÷ª²ò^¦¢É4-ÛâRsøéãù½úïYz4ƒ^Ü(•°vmÚ‡4}…K*-&«å¦·ô8¢¨Ñ66ªmíÚ¢?ŠQ¾Âd«ûª ZToÞè%Ç¡…¤6:Âuk[d_ñà“»ìÁéq¥Cg»Õ¢Ä¥`úËaZX¼éFõ­]ÛËØŸ¢ÂÉ\ô`5ŸfÚ|E/| æË“êÀÁŒ]âùCúǬþÍßè'TKû,…Rì²d)ô…JÍy{¿:µ7òâž}mz›ÈüÀ…Îó"ÜC0 «}¾¬ÕÜ%s¸4—M´°p’4U£> endobj 23 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 24 0 obj<>stream H‰¤WÛŽÛÈ}×W4ˆ¡qfh6ïL°¶×»ëì l!yA‹lJÜ¥H-/#+A¾"A¾7§º›—™¥Ábv¬QWWÕ©S§«^ýð™³m³x³Z¼ú>fœ­²˜ÿð+tXÈ˱m|±_Øl‹ŸU²°-Û¶]¶:.–ハý¡ÌeÿfÑ4ùƒd²®«šíD™y¹½Yý‚»]s7×wsº;lËW[ÜöbußG™·;Y³*cøÍµ|È«®aRûið—ê!O%å‰þÝʤͫ’‰­È˦eyù Šy»_RÈ2eme¼UÛZì›[†øûQ$]!”•YÚ.Ù1ѰêAÖYQ­›»0 -¾|ŸõGª$éêÛ›/«Ÿ«—Ê%×€Qv2«jy«\fy) V˦+ZvÌ‹‚‚؈MqBèLcìlÍœ8°\ºø­+£°gÀv¹;žXPD޲ÍKD’·’­—©L>*ôú°š¶î’¶Ã'•ÏãX¶;@mß×Ù‰•)ŽâÔ0]‘µ¸H”¬:ÈZxË6]K¹ç5é$Û‹+«–î™uÅúÆJæûžoœ¸‘æÈÏ¥dpAUKv2ù•Î÷cÕ)Ý4|I(kXü§8º.·BßcZ|ıiEÛ5sPú‘幟Qd‘2Ë%üöÉ·UÙʯ „ŒbÊÉ02åÐIpëÄÆZd]©™> \ŒÆô—?VG:xKllw¢5þØ·'Ò¢a 0]ÙæÅÈGô¯r·L ‰¢¥ðTä*‘õr48Œ@J¶WYR•²ÌeÙ¢–©þ›Ì²ªyЋkPV;œìF¹@_“µMŽˆEšê>îÉF-?ÉC!àR0¸‡ëªÛîú'/h ûê 1Û:ƒÒ«ê|«zV_X˃f)£¶fDÔ Ò·•éúæšC¡æP¨(„¶ ½‹˜> FÖqk¦Û9÷­€ çïÇý¾®öŸÛX¬—/ÀÛºêíÃ=ÿrË^4²]ßüñæÎ…\/_½~P7I8Vuª»ùYx1×›mk'K÷*bÃÑó‘œ@ýÆæN»T5/ŠÍÞ5÷ãÑ<{p¹¥¥e}Ãþ~ÙIKÖ‰j'ÃѲj³õò›×%˜}€È"±nO Jå†d6Ãóxÿ»æËz]~s{6 PÀ Â3æ)Ä:œÁN‘zTÀÏ*óU5²•°žC›"ðƒ3„óô€ vÚ¤–ÝRŒÏp‹ÜyþwÑuwƒJø—ëêz¦XñUòôG'mô]N£OßB¬ÿµëÊ>ixÕ[hx:ð-ýï·í™ÔcËápç¸&2n_ ­?; íuš>‹«*å$&ß{Óïù券ÓGtU‡³“ˆþ„§±~“iùgÒ8Dõò¥:r94›÷¡9WCΑ}ÀP•Š‚k«VctFÁMt q©:0õåùnÑa¹q/wüª4g'ˆ}’ † 9 «ÿ½oÕzá¯,ÅsØâiÆÑÈ‹¨¹a/‡üªtŽgŸH'{Á¾{÷ö¯ïÔP3«£½Ç ×F~UG‡³÷¼};q§2tê¿Jy`U‰ÉCÏW—3÷Ã>ŽàjÃÙAÏ?é1”Ëå\__ VCËëwL3H?Z‹f‘q-Û‹&öÚlg±á0âs6f墬˪¼û›¬+laVc¡PMTÐÎ0G "ŸxñÓæa&NbæûÁSdzVæ¦`^ Ýû‡œ[G4ùÚŸ”?vÜåÉ»W“ÔXÞÔRQ´kƒ-n ©6búç ì$µ<ö˜Ù–;é´·´òÕ VNÝmÍ©lÅWÕó#„a…®Yþk}£ÄŽ2âq›ÍÎ7IáO*©÷&}n‹UmŸ¢Û±ÁÓ͉–NÊ÷{\H¼ƒNw×r±ÇºHX7$;{j8Ćâ`\îÌþ7Ç, Cû™ëñá˜ãE à GÃû%øéãÏZx !"Ëw<ç!l#²l@ðF­±ú9jdW¨~R²Õ×XY·Xú=#pࡉ ýžÐ I—BþP5M¾ÁÚK·ªV/MN £º.@pcU}Êþ})¿Šd¾}CXôwHˈ«Dÿ“kvPåg#r¬ºSß`“íý§ c±Lgœ;dØ•OÇÑ>'ØsHÞ[ê«5 #¢dú"+ª#«’¤«1yci*‚¯¼@äÏ´°€%˜•jÒßžùz8±Ÿ4HàhþBäS—³d'Ê­Äüjʈ.Á}£¢X—z㶨‘[ÑHÔ½ÈËÙîàH01Cwd]™NLÔô H ª ¶©¦/V…þ _¿zjK=ˆZìe «aMͨvÀ;ÃÓ í1]Bê΂š¡½Äv[牲C pX?i” Q–^J¥²Ë~\¢XÏQ]N*³^j ƒA`EQ(du‡´¶Öc˜@ßМ]é@…QÊ@©Ú.Gn¢ÞvêµÖ­ޥVS&²°VeL ¢´ lô4PÅAq]ná¹ä!æc5:ón…O?àç'ý…ÙxÆBv$|`÷_l–.8ËÙ¯5÷+Ž\¶_püT,>/Þ¬WtÎÅ7žL•‹X}³È·\¤Î]{$ˆyÚ~ÎìºÑC‘`Äé.«s°J%‡"OTM@芈,[‘†ÇÍA&y†ê>š`4ãaZW˜1ü’EÞòM7*Õˆ¨ñ–ºKä Ýb•"éKÑN)Zp{«è@á)¬ëL$²1ÅæºØw¶ƒžv´f÷´¸_þ¹%] 0î?áã¹4RH¡R1V @›Éa:ý[{8A¤w¤1 ˜üþÍö¶ªU­)‹}+ DƒÀò—¯¡Hêpà ý²~i?ÖšXûÒøjoñd¢ =þ#ÀÆÛP endstream endobj 25 0 obj<> endobj 26 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 27 0 obj<>stream H‰ŒWÛŽã6|ï¯ °/öÂfë~ÙÉ.tz’’ @ŒÝ‡éE K´Í‰$¤Ôc±¿1ß›âE¶|Q&4¦Û&yêœS¬S|üîWŸlÕÃ7«‡Ç÷9ñÉjóàgÄÃ?ü—$õx¾h<²ÅϪ|ð¨çy!YfÏŸŠf_3‘Ϥ(;þÆ“RH²+Úªæív¾úˆ£Cw´oöõÑIÓ0tGS/ösâjÇH]¨Ž0w´9‰Uö\Eö…RSd}$S¢»JÑvìSg#Æ.¢g#z$ò}wׄT]Ñõjift ì‡ÙpVW¤â’•]}¤óe'4œ½´óÿ®~xX†! r/'KŸØü-6ûXaÂv;®†,&ƒ'¢ø¶-jÒ°isÕ,é²ï„+éd±Wä°ã厒Yp½à°c­Naõw0¶ýqEeÙKª¿ö4”ÔAñÂÜ.û6Ñ2"6HÅÊŸûfÍ$Ùô-Ú*ZEë)Èšw„·¡àažP/Hâå4ÿ«Åš¦ã=£%†-‘ ¯ºÙ#ùJŸ³ }šeY|.òR34ŽÌ¶ïv­”LíE[iœӘ€D>ÒÄH#ÎÇt1 ˜H HBšz—»,šxLð$ŽbêÏ^t½‹nH 5&¯3üâ¿Î5¶"ïkQh–/¼í,±ü”FA‰å¥Qî.eÉöºi^gnr¤ŸD€›8O³sŠ¿¾|÷þ—ç©=Oç˜w!¸KÀß’iâôÙ×Mr¯á/’ƒe }æpî%{ã¢WõÑ¥ ²j­§9p›W¬í8êin‡½?²ÇG ³ Ê¢®5ˆÚ£¬› 0èPœ¢CeÑá+ÅqU¤[…“l/dgâjFì·-“¬ë¥NŸ˜,¼Kø™o¯æ'Vö&í¯ks™xÛ3R(#úíî|ô®¨H+:{Áz¤ŸõRÃ᳎àCÞÝÊ€NBWÃUiŠ QBÓ8%qQ}{6Ô¢Ý~lötð³ »¢h¼íY~è.šô±oöúÿ‚œ­UL¾¡† ZƒNµ¡ŽMühÜCˆ±MígÑ1K/¾Á¹&‚Í…)ªµ­°® ëãK)*æ”ÔreЃˎe˜…:Ô­*ÚÀN‡v- ”À™ç¦Ç,[ã›âwf³VõÒA.Úãm³PÑË’™æ"0IõZì!¿u-Ê¢C°†5BA£¬YÑâÃ,Üï¥ØKŽEz]Sß÷}+‹+À“¬0µ¡FT|s4¹ ³Ý·u2ëôå2ƒwÃ¥ÒålÄ›–SŒz,Ì®kgBMªOÓ$ IÚåFígÐ?jäõŸÞ»)ºE)Mâ,mCíðÉ ?zgXƒË À¦ó(Ï3½Õlº'ö gÑÅ¡_ÖzÈ_ìG7HÒ k`æÇè¬Ø¦èëNk¼ó…#Þζu„î¶N\HH“‘@ûüôÛ³™íSeÂPÌs]ÝóN-Ò¾·ÖeA Y%\[[¬k㤌½Ø@_@Në„2³¾âÆXQ§‘ÏÅÝ‘7“ö®Æ4Š£à®b–$àóš!€éȤa(eà®§çÄ›‚·“B”b íhÏ=!zÿÃU:µG¤æüá…Ô÷2aÀÅ£˜>éÇ4×8mø0ûo˺Ç}ùʺû×|™'ž7{|¼˜5Úß…‘'$ÌòMÃ4rtŠ"’ÑF»g€ƒK_¡ãPò1&û…ýüqPúI\ivWhqùÔóc£Òqªef€èKõ “ôT?„ÿmÝoNSáÝꟹòuEù;Q-ºÝ4JXð;(ã?G™|%›=vö&xåšù½õ pm]ø’ü?{Ð`atX:ÝÖ µ¡ÏíûÕµ…kâ ¹®\6ê±dŸÍ-gÎþ0‡4³É’ ¸Nk? .Áx8Ó¹…-Ç;Ýôo-‹’‡!x5ó§[‰÷çŠå_®Øy£éîÿ§¢x Qì01ü0wòý=“È@+ܸ™è®6¤œ·V RZWUsä'£'ÓÙùƒ!ÕÌBðgö£ÖÀèÖB½“Qc¦ë§Ö¶k¨nÞ~²„)P|­‚¬…{ØhI<;gC¯líëüì3‚ܽŒÌü=0‡¦˜ý·^L/±{†¼ŒÙ2Ò’´ÁAéPö½gUðƉxÚJÿhjœ`§4¶77žæ6ª•à\Ãîci ­î¬† SwªœºoÅT)ù‰¯Y-úÕuå¤Íܘ°MQv¤o[¦ë¯[\œ{»Ö³³ºÊ_ß=1`Ƕ²hoVY[f> endobj 29 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 30 0 obj<>stream H‰”WÛŽÛF}Ÿ¯hØ€ZH6Én’1ò°™Œ/°É#ìË(XPTKC["^f<ö+v‘ïÝSÝÍ‹dqäÀ0lI]]§ªNª¾ýé³]}óÃòæö}À8[no8gþàŸÈgOÜ„-7Ûáï2»ñ\ÎC|õrã,Ÿ+Ôç†ÕjwPEÃÊ-ËÊbyÍò¢VU£6,Ý6ªbû¼Pt%NÜNÇ=>±•ó±­{¢Áeês^7y±›-?ÂÙ‚»ô#¹…³Êöi•6yYÔ«Ùwtäö}d G1>x˽˜É8vcBíp×”66ÏÄFá 7 åpôÑÉÁsºoÕ»Ù‚±ç9··ì¥¬>áÛ*O×{5ûmù÷/½&¸%ŠÌ-žQH€æ»Ú€»!…#"W±IÙa«ó]‘îWÎÇŸÞÿó~ÎÌçŸÓb³WÕjFˆ-àZ5¬=ÚìÉœ¸ ¼O—6]áUHÝÑGG§ê{¸ûx8®œc¥Pðg¥±HÏ`é¾d@Á…Z«â9¯Ê‚ØrSZLâ*¦î(J¸©4°ÕŒýޤøÒ Y9EYüául,‹¡ž]ÁƒœÄàGCw¥R[7iÓÖìÛïÙ÷wÿ¾¯ª²ª‘—À¢ù¤Ô‘•Åþ•)ýÓ¾oaDWaôGè¼]9ß<"4Uz<¢ÿRÿæ®VÅ7s†Žº+‹ ü á.ˇV»•ó-bXͨ”—ºŒøÎù¾Ç® d_ogL*Õ´U¡ ãøï¦ÛËó.¸K®»ëítÃýÇ„sIçDŒ«/}ügU©9KO%€´ÍH’™VØ Á¡`§mǶm‘‘b‘U¥vP7ܹ9“7— nBZ9ù‘os\Þ”úÆ;VµkòQºséXÄ"Ö œ¥û}wx*!AÄÝÄ—LÈØ•CB Ú‰¬„’èñÈH½Äf­ƒ\`x®b1ŠÑ~0òI€×Êæiƒöœ"v¸= „tÅÜÈàp3KxblDî}m‰$vµê#˜ôðØM¤üÂý‰úN  [ŸO¡hžÒ†½ä¨ÝÚÔixyR]·ðA蟤O˜ôHFœJóZmæ:$U?u:þ¹=Ó„…½Éè¦_ÐøóžQáÜh¢ Õ^0Æ FyÐâ?UOÂÆGFä\|ÁŸÚ†N É]ßù_65Ûæ&ýFØp¬NŸm|Y[U´pËÜH½Ësß„;‡ú¬²Öx+ºV™Š©§Šc¸øžÇ‡`»a6.¢|b Q×1½„XÌÈ_Í<„®¥Q7ô¶Üï˱®L zŠ?bâme»‹‡.ÑN—éQ°¢llÄ´5úð‘‹7‚÷#@^A“gˆüæÅTÔI‹HŽLz0ã"g4yÑ"š´á·e¥Œz/|Ï•’KKRÙ)b¨%Ñù°…Óìbû”&w™¡ô”Ü€°ô& o1MU\ZíZZ0j¢å"eE{XÓždÒN2u&Á}‡ä7é'À=îÓL}×—¡ý÷Hë%VÅËŸó–ürŽV’…ý¢õ¦€¡kpÊÛŸ?Iêyû³õ«Žcé'x³®ÒêÕ$8rý8’|8ïÿIðAdFäWÉO@RÉýÁì21úîï¢æÔ±yê«9‰/” ã(yº>#0òCŒ y,8ÍI³R‹±¾š ̇N¦êéñ‹‚zräQ´[è=ÞMßÒ ÇõC‹‘ˆA[[tC»cÍ>ÙYûß¶x)Ûbó¿nYÐ≙“gOì%5K(ˆóøRctò§·2Ï‹¼ÉÁÃnÿ˜Ò¸¾ X'nø•£±ÓƘ…Z|=O±–oû &‹‚0ÎCv¼È?'èX¨ç†’„B?($E?7Ø1­k³´åM—!›™)ÀXlùüŒB>¨ll9+Oó£ßYÝXÝf™RP—æɲ½J!¥iñŠÓÓCJñ¢ öñ²¦l"±ˆKøÉ¨¨Úr*áx›`°v ŸŒX÷=¯2ó&ŒªÍv5P”íògÒïòLïªt§Q‰~´SÅ }!.ñXG±M^CÚ_aª®ÓÆH[kݧþN!?=³’õÑÍ€Gzu™ßæHÝþuX¨âù›9MM4?QÞµX y’ˆ‘É”¢ªb3ê¤(I,éJxÁ¾É¦·Zá v@‘ZwÃ6ñèdö É<3ÛÝ¢Ö˜æÈü&ßn•ÞèÖê)}ÎK"fEU×9­Lë}g rúÆšÓF‘î+•n^iÚc>î·ÛÉuº¥=‚îùØŽïôÿ(ëìX•»*=&ŸdžњQ¨Óäµþh´ïØ6äfù×LqÂýõh2ØÍgX|æl´¼¸&ÑÜ$:ÑyN¨Õ“aR<:ÿ•¨íl`J‘-kd cmcìâ­†5A³ŠvW_«|÷Ô@º2ÈÖ‡þÁîÊêXVºïAH„DJØù„K¦g«‘}×:> endobj 32 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 33 0 obj<>stream H‰”WÛrÛF}×WLiË)Ò¡`Ìà^N\•Èv¢-Û/æî ©r€!91°p‘ÅÝÊOäAß»g.¸Ø&ÄMY’I`fúôéÓ=Ý/~ûHɶ¾øuyñâmB(Yn.hL\üÃ#es]¼Ø_¸d‹ßezá:®ëzdùåböæï¹ y$i¹?T¢®EF6eµçM=_þs={.5çRun$N¢uhÈ}Ör'¸—e[a® ÏsÒª33‘~h÷w¢"uSµiÓÂÉd%Ò&?.È]ÛfÇk›Èše£¸äŠ:€ðZO¨6¶š"V^Éü¨‘ó´!¼ÈÔ¾=Ow²W™8ˆ"Eã̯"/q˜‚X ›¦’°§ÐU‚lE!*À<’mYjßç·Ë^,Ÿ+{A`ˆ:ˆJ+Ra°ªð¯&u+~ñ¸WV|+4ñîx/å†ÚûÚé} OÌÁ’ÜóÜc‹îcè/ôQö+e±¦È`?Tå½ÌÀ.å›L%Ü]ô |G_jK²è¹ébm‚¤|Pøe±íð*èí4%‰„†+<¿Cƒn%6#–‘j{àíJ), M y/T€eAàI¼Pà˜»#øG`/t˜Šò¬–{™s0Z÷Õ3 çh–ù^Àϱ;.^/ôªkb4Z »FÃøaԉ܈1ub“jß&/y3!{¨-íé ®f¤FrÊZ;4ŽÙ·æ²²…r&ì1êcS8a.ã 'Íñ HTV¯é Gºr׆àwQ‰¿@kÑ¥¥ÒͶâ{ðø'? Òª¸Cá§j‹B‹ú’ ¤/A-Ï›]ÙnwxöW­Í­2äv¹ß+e&·ñ“ ^7:6¼Ú¶{¥À´lÕßH?“;<ϰÞ1¤D†”Hs‚/®çP7&Ço ‘:SQ¦“øá°~öâEÇAà¤äñqÈ2À(î¡wYõÓÆ!s;k·[ºšýCiÞf‚\öÝ% Sìº Õ€Ã&»-–¹¼«xu´Êš‚D] É; ©[:‚ôSÝd²tv¯æWÔeªëY½žP šÍiûÈq?Il(œÈ‹|«N߈’:. |% ¢¾V‡Xp¥ÇÖ!GšËb­?A3éRAaxŽÏ÷«Ûõœü÷ÉpùQd '­²ÈXí–®f£p¼+,4¬|)«Ïª6¯M•|:<~ZÑYÝR Áj ;áÿ2Öp|Öp·T¾.‹F< áE£l»ñ×¶SóúŒqß·Æ“³Æ»¥«™Ž-:˜Y½~s}óþ—w¡ÿé£~p«°X(ÆýÇWf)®äÍfŠ (”áÆñ=ÏâA œÔ­µ€vâAÔ+ÜŽÙèEðø €#YW³PÕi—(”:“—F‡…‹ÝJåÊ6 H&4ùjžèJúJOa`ƒëøAr"[étQé º]ý´óZlx›7ëÙÑ‚ –Ÿn>Ü,?õA]Ï_°( ÙHžËÿˆ“i Ô^œœBíŸA=]d,j/ŠÔ&’o«ro´Ü|At¡· ¢œàÓ¾¼°+4ôl¥Ö‚œIÙšKqTwÐÑÉí®QÚã]»uà²:};u ‚®ÔгµfXkнüÙ}IäO1þüøãd]í ù]i¡ÓµM·6Ô¯­ÍmrMFÉçȽ|æ²r ºÝ®äí$×8ÍóOÉ!™N¤F¿Q äÏIÌ;a€¹g3uØhöôÁ\–¦’kQ™Tý!S.N%ªGO v¾X {Æô²ìuY¦tNðvûvgºßé¬÷k»8_>«ÉϯȳZÿY¯‹ËQRi ,È€c" ,qO±áecØhöTcga¼wŸv›EIç¶Îíaퟪ¢©ve¢§aAìø¶O3ù©Ý ,“–|'Q3A¿Yïë:¸©‰%ÂLàÆô”MXè. A)Êßò#ÊÏOêoJ‘3ìÔ›×%±Fõ*3{$¼`4P;ÓŽ»Û×v­ÅN ªUd#s=Æ7û§cPÜL…Õób'd ÐljŒåÿ޿¾ùífùq‚ W~H£p´u„Q5ºCß‚ ŠÊ·Cñ'Æ9mìùãÇC{£Ç̼‚GL-¢°ÜeOÆ‘¹¾…ð¥ˆæÀa$˜# âÑF…"²ø‰ªWÓCZSèq2#Wq¦‰Z}Ìy%2;3ÆŽÆÉ©Ùí‹Ìs5áòI(C9Uéû¨ÆU­Œ43£=Þ å‹TsaC*ô!rZ'Ž;žI}×(~i,¼QD¥ÅX“ðî¦àµ•]…¸t]'êD›"E­µTR¥_’{^I5¦Ö/{ƒßúcÝ7¶ÝYjÊZ¬ÃKªØé¼œˆ¥º>8M6ÎI„Ái*~¨Ÿb"tþ%B 8îzî Ò‹b6"!Ñ´™wd`§ÖƤ¬,­’Ú½À´n2)> Ñz¦‚„G›¶Hõ$åˆ4Î8~Ïo¤–{‰P©³z-Z%À½ ÃÀa³¥Ž7ÍÌ=Ï[¾6Ï””´*Åýv4À,ŸCU¡–íËJŸU(9gr+ád¹!‡ ¾Ôþ¸º»AsSc×#Mþvs¥Àí•´è³¶'•%Š´ÌôT¨p3“õVEf¯ jh$ê À•6ÜIÿFZ›ù•§fŽ~£¯/¦XoŒ¡T?ßïv+Ìq]Ž&7׳åëæ×÷京¥I.T7Ô!‚`Qds“È5A&‰ê^5¿A …L’¯àbtRN½Y^üO€ä5âG endstream endobj 34 0 obj<> endobj 35 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 36 0 obj<>stream H‰tTÛr›0}ç+öwl‚Ó™v¦¹¸“N’—оÄ}A5 ìú;Úé÷v%|mêq˜$fuÎÙ=guõù™@¡ëÔ¹š@ ]:„€üSˆIâ%® |ÒÌñ=?Œ°p㼸²¨ÿ‡RÐe³óä"“+^±ê~µJWz-ro4a!ó¨;“JwЕâ¤XjÈšz-T'rèšÑ÷ô Nˆ‡\·ÈJÂilX]n=Yè±Á¨_våJt2Cˆ¾Êa! ãJIDjún ¼Îa)k^UÛ=ë°cŒÒNúΰPb{swB<{E5 ›•Ý!WˆÕ¨Ì]Y#šAàZÇ×JÖÅkAvøemtäR·ß"VW8¯•EÁ0FJç#3ƼÈ5 ÄO¾j+1¹´zeÝö¶Yô+Qw°8Ð_vBW3¶sÍ\ó! ±ç³Ø4ðØ`i(N ó\h‚õôôÀA›ûÛŽ®ªfƒÝÁf?àCcïÜ7:Œ…çàÃGÀ¬Sðý³ŸáÕE˜D†^´SG±Ü¦ÇÔº¼ûЩ5é˜=3~kÖí" 9ºáÛ±©Ã®Ô«íƒt4(H¢Á ¾5ˆ+‡?ƒû/d§¡YB«T˦%t+²N®Eµ5†‘GŒH-vjJ¾GzLž‰T§­•g¡pmdûÁ°¸>Ù”¹kdZ˜f±–M¯¡¶p%¯ ¡M–°»;Q2»>óA¾ ¸äVb²ÌžÁõ!ÔŽÌŸn÷[oJÁsܾ¥¬„é wsËqay‰ÉÓÉ’ÜÞÝ<}}¼½ÿ|Ÿ>_N”Ø;ä,ÖûÉã,µÐòB%ó‘ñVàpQ›u}ÆÄm.ѺÁ¬Jßâà½3Ͻ› ܉¥N srÌþ‹û oBôr4 ‚À \|âÝÇÃÁ©=8’L= ûþ´Mˆ›¦Ý*Y”Fv†bï¯á¦Qm£¸‰ ^Ä>;Ü#Ÿª l±6±jm„„ÿ(ðÂH’3¹.!¦©»Ôù+À¡n³å endstream endobj 37 0 obj<> endobj 38 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 39 0 obj<>stream H‰”WÛnÛF}÷W,\8 ‰Þ]Þº@ÇmŠ&R¡/–PäÊÚ†"’ò¥A~#ßÛÙ«h™Ó\dKš9sv.‡g¿ýEÐmsôëôèì*AMG$Fþˆ¢ˆP—b _¬Ž0º…ÿÓì»cMéj]0¢ïècš}a9ºd_¥*7«9«›ÑôðíißDù&Âwb7Ž]ˆàoºä bÚiÍî«úKƒL:FM›Ö-/oQZ戕¹øõž·Ë=Á]£ qÁý¥ ø¯›vŒ ^²ùÒ]€ª…EÐ̹_òl¹ŽVUΜ5³Jko]¤?¢vɤ¯s•n¤Òd¶JBÒÄõU²‘ùõƒˆ;º™þBÍVüŠ7ñ»çÔ‘Ÿx™›œ&!ÆÎqÎ2•¹»<Ö®z©Æ‰ë©è–é’•÷¢*Šê^0 ÞŠ´N[^•L1Ísȯ­¤JíR†.¦A'†t¿Jy¹çî½`P/샤,6e& œë„vÈ$Øs ŽQàn<âîÁg˜´ö×Ά—mü¹UÕ´þ®o.¾âLÆ^qçõÍ·W£ ‰ê³3ÄË;Ö´+V¶‹?ýᶃÈ&Ö¹m:xÛÛsêàôèçV]¶DÛdiÁ.ð«nÂXùq¼AZŒé–¨Öa%L’‰$TL‹‹Ð Nö3D= øÃ Øs= ˆ°Š2D€j‚AŒé–€G–ÖM‡º­…+¤É=P^ÐC@8L€=×C€Œúƒ%@}Í@4È€1í”Sù“ðF4@¨;>Þ06×ræìÏx=¹ÇùÛs}—ÏTæ²!Uª/\w€ L5É ÆôÚÉ–i=šP,Ùk®ýäFÏIÅ¢ª5 ߃½\ø 1\˜ØÁÉØ´dŒ&žˆÎ¥q‡‚¬Ú”-«l?".Õ£6´ -Ä„é^3ÙÀ½˜Üˆ¼ä-O þ/“ À˜ÕéŠA´f¬Voº³|ÇÓS( ˆÂ>lÁc]§ÒoÚ4UÆ¡™s$¯T’ÉÒléŽ&´£ï¼+ѺNa d2tÃЊß.[4k7ÍÑ¢®VxÁáp¥òV!Ã8P!ó´MçiÃÀe˜x*ÙjS^‘'™±iÔn«YÆøJQ¸:ãyªHC÷ÕÓí8s¤tèD6{5‘)¬U‚0è.­y:/˜*ÒÍyòáQ¬Ýn`£W‚À„dq>°h8^vU rr¨ÙªºcùXÆTbj .ªÚÜ. w…J¿>1â%±ÿ•jí«C¦Õ)½fŽ]® Ú ‚ªEç£ÙhŒ^l÷™y3½:Œ/Žt<:͘b7”Éô 4{n Ð|"ñÙm£D…]ö7¯µïÃfWМýH¢Û®óf>B^6žocâbø²è"1 .uƒ›Ó |åõZd _ò;ž³™#ÓÄÁå¦ÌkQ§/&¯yBhGJˆ—3²OPY‚}OB3¦h¯óü®ªdL¿ƒé%@äQhpÉZÓ¢Õ½¸ëLò2;¨<¼ƒêôTš @£DC‹¡YS‹ì= #¾.\[µi±E'Õ¢C€K(`òËÃM›/þ±elM;Œ}RÙe~®`D÷”—Üü–· ‚á û`Ibz¤gQc×’ž&!ƒC’ÆÏ†äl/;„ØN›ëÔb¶ÅežZœFQ|:pJÑÐL)`ª6­R¬rþÐ2x–”æJ(-Ñ5q)·žHñ!X[±8gñ‹øÏ$„×—/aÏ~=É÷M¤ýF*’µmÖ5.¸ŽJýñSïfŒŽO0}@Çc«ùÍ¡+ñ¼¾+9ð ``؃ò’¾LšDgÐÖÖdwüIêŽst"$z²8Ég£Ù¬„,eê2YÕu&Õ>IA:G:YB" üwV³±‘%V•x(«Ê;V«2zª;ê4O+E—êÔ´õ&›XDdƒà µÆl7€S(7è7ÏùS & äÙ¦H[%ik5@¶<%> endobj 41 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 42 0 obj<>stream H‰”WË’Û¸Ý÷W`7êT‹CðÍÉÊÓvRIÍL¥j”dae&!‰.¾€-+»|Ãäƒs.@R”ºéTÊå’-÷uÎ=÷âû?þÊÙQ?ü¸{øþœq¶;<óñiÀyÛ5>;âï®xð=?ŽC¶;?l~îÊ¡–¬”ºPUoª®Õ»/°:Kœ[Kø€¥8I‡N5dDwdGÙJ%j¦èÄ׸²©ÿ œcT9#S&è)‘¨"î7†¾´‘·°h„© öŠ. µ-U#.L‹ƒ¬/TD^R*ÍP›jkkú^¥H“ÀOˆJß×U!lªûÇu~úyÞ‡ýYßꎶYôè˜~¹ ŸƒT²-äCm¥6¬—Šê$ð-Ijxéæã­•÷ƒ #×r§NË«í§Ô»m?÷eK t N–lhQ9+!®Ú¢Öðò i>o‘¡ ˜ˆ2IHøÿéT1ÕAv…¡¬æfT¡·öÒ1a²GHIk¼±)Þ+q'÷%þk?ó©_«fhÀŒ‚òo©¾‚™¡¥®ÀtDš“(ŒZÜkAäì ^r•ƒR¿ Í‹T?u…¨WÅ;ö¹—æI°¸¾ˆÛ6ÖþñÉå&^–ûÉÁÄwÂE1ÔŽu¬ìl+ùÏ¡¢ú–¥@h´¢1€®‘M§.OL~-do,™T7´¥¥<à¾"¤#€cÁ5ÁÇi”>ÇgÌêÖäàiRüú,.f-…å°„«[E¸­Ñ˜¹C_3ŠKTÚ6è…¡•{mGY’“` gÉŽD£W Ð6èZÝË/CÓëEsOíûBt(“ê@WG*†ZYúý$VÌ1¸ö“_œ­¡;Eb-¥iêºMJ!R†+sr‚j9úmnaCý#¤ÓŠ6±mmú$!.ùõÆæ?cÀ‰%i|×3sÃ~#ö~xÆÍóýÿO"K Û)^ì7?=¯¤ù©ü|~J Ddù}Óó·ãà/.Þ«¶ì7Nî Õi§ó§ùg 劄g\ÝȰùŸOÆ«ÍvER3?·˜±tñn÷Üoäyb.ë·EBz$Ap³κò¡,Wë…U"çË«s`´r r슑Û6 ¥‹“lä(¦¸EérÎ…~愦Sà¾kKMBê¶Ç¦Á®qcÇ®/_ð\Øvª‚j Äµhƒ8J4ÏÙ ?uèÛõb^^öð©+GSOv-ÎÑN´R² ½€£9üð])öÄj͘{Ÿ‡×»›±Kb/Ì‚ôn¹Lüü½.1—,Y£=Çhý”ñìfq„h­ÅSâ|qcáÚ®,«¾òo· ¿wF‚¸â [>®ðxÍÿήíåï¯6XxÆŒí3ÇmKĈç<_Ÿ—iîåyߦM‰B¬ÎI4ºÑ8!'²Ü< Ô¸³—²ÕØ{ì¢{Ä+Ãþ66¡epÑ Û£9}cAK‚øã_­°ÍSíÐaÜÙ3)á+HîÖÛm’¡oÀÚ«õÓr=²·0¯Ð)v Û£êúl—Å ëHaܳñ}îs8ÎA®=p-ëwû½ÿÝ*½€@Ž|ç;›qcß<¹=›3¼sÛŸ7C=ijoÃ0ôB¼®ÂtÄ:uw2{'ñ.Ũʓ´ÀôÏ:e[»ÚûO?þÌž;ÕwÊn0èA?™—DZŠíaÚ"ðd|•¥wû0›‚Œ!jy>Eêòç!åói÷ð_6ÐáI endstream endobj 43 0 obj<> endobj 44 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 45 0 obj<>stream H‰¬WÛrÛ8}×WàÑÞ‰`ÜIfŸ&×ÍT&©J´»ñTŠ’ ‰)ŠÔ’”eχä{÷ $R -Ov+år,5º§»OܼýÌɲ½˜ŒnÞ$„“ÉbÄcÂð¿"A".¨` _¬GŒ,ñ3™eŒI2Ù®ævö²,{ßu9ßæözò ®dëŠWܹ2ÚP%Œ÷D…ðÇ'+KÎ\à“EVØš4îÛ´IIÝTÛY³­,ÙÖvNeE6Uy—ͳbé­f­|ã`dÌ)çL‘É+—­Ö!Ûrc«´ÉÊ¢&iü¬Ó"]:7ö~f7î»4wîæ™·£w¦uwšó1·Y¹ÞTYÝ&¾(ó¼Ü9Ï‹Ìæóúy@F·È°€ óȰˆšXŒ=ªÙ2kê(¹ˆ©Id÷”ÏiÀ?ׂFºoþ¸ÿÈPÖ÷Ï(—ÜCøå*\‡du¨ES’Ú6þÆ›Êβ¨¹§Z¥9 O¯Ç1iäR¾þcòÛh¬¨d ïWŒs­=•­·yCÊEÏ ÙeyîBT嶘‡,šRÊm±lV$[ÂÎl]§ÕÃ3_ê•-f¾7'ë6„K»Þ¤3 {;oÓu¶qQçÛõÔV2»0Ù:k`=}a=$t¨m½´ÑT+ñÔ*£lLöOQ™¨­¢”æaƒÂ;oÞ˜ÓÀ‚Ê8œ_›ÈBÇ”ëDý8ôUÀs½­²Jï,IÉ]šoK€K‹¥…Ëf…Ú,W.Ƙs™$ê•ØûJ’äYû3„ÆCKE5k×éý…¹èš?:œª'ûŽ4u×Úq`|q$Öé²ÈšíÜúbáƒ<­–¶nÚ’%¥ˆF›^ #äv~=±¡âÊÞoÊÂ{Ogkf¨a½”Ñí©/úŸI0}–R„X¸& -Žx˜WÃÕÊ}dÝÝy–æ³mžºSG}®ìþ®E˜œ­Â¤‡Ñ3a°á3æàBãÔ³ βE6#EÙ„¿õé"À³–šýl2÷×þä.ì#*ÆçÃý§­J⇠TÃ6,Ô¿)1·×çïr‰÷ð.íüÚžÕö$ÿcaÜÙÊs߮ܢ¦m©›€¹zP3IAt*ãéø8 Oère"š¨}+vø¬ðL‰lX?mŠõ%nR.Ÿ–€–”«Þ*L¢ÿ/%:: z™–ÿ(ðÓX‰²R¬xò³¬„£PF¢eެ¸T¯ŽùVB'<Õy$©Ð]k7ÆJ_¢¥ƒ†ÈISÅ’žçS’ s‘‡”`TFÃ9¶C~$¯á¼0̺賔‰T8Z”•›ãÀ2µã©„Ñø§yªCQy»FpÌEþŸDuÎQ޹~š§OÔÿÎS¡Q…>;›Ø}Kˆ#;Jâ{¯5°wù±žÅ3@¼ºÎ u"yè[t5JWo§¡Ú®Ê’aµ7>š¤y]¢Bö>5Ž ˆ†žÛfB/iu¢2U»ð,9Ž>ö=tÀ°Ý܇™Ù”uMóÃ~»½šåeí¾Á„¹ZÞ^{}zh(ÔÔM<"B Œ;!tÀá¡ì1)®âž_ìÈXCex\a& Zƒ›nä«_¸o4ã ¨šQ•8 ¶leDta™Hè"wÆ¥éZyÁÛŠ…¿­·ýØÿà÷ð>A# ¨³Ž§ Í9¸ÜDŒÇ’Tæ4+Þ.™é¶!;¿cÃk/Œ÷Âõfs Ẕ¯¿_2 :QÆçKfº_çæ$MÀ˜"‰êö8~Q%°E¾]ãÛ«Áå"1qQßúˆÆ¡½Ø9@57ƽblÁ®'Þ²Ô#­! t´¹¼×ÚÞ蘣 qòW4ê-UÏÓD†ã$®Î"ó§«Œ²*ƒíä6áYJC +cÜ ÞC­#N‚”g4Rì„Ø:zÐëÂ2=„WÂ1)æäLçÐ%9ó^ŒÇÝG•q?'Êž*ƒŠ&·³ j¼ß¬Xb,Ë wí 0ga(ƒ°U-ÖÁmìÞt,:¼ ;Ã|§Õ™o+ïÂ:ů}ì ­•ÛDMhrO‘v[ø¾¨÷1Ô¥þDH\Yœ ï²¼P¡)gícµi=¿°Áž…" ­ôêõ˯Ÿ>þóë¯/_¿{ÿîÃÛÁ¡ÀUÚ9Üé±O.a@½K«yM~H@*…9:qÄK±ÈЬyˆ.ƒxuS§®É㈪(:¹æ«ÿþðèMÒ=9xGæ4_µ-fòë gcð»;ñǔ޼ÿøñÓã9éÞù¡œ†`GwiÁôyß/⎗?tN^Æs«SÜÿñëû7—Á×ÝÓ?¸'æ1ÅÂmþîfŠ ›gu“P{~dȼÜ>¿×\ñ-~~ƒûoÄqgDv.ÍßÉ—?™8ÉÈÈ]Mº¦”d=âúøW>ú> endobj 47 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 48 0 obj<>stream H‰œWmsÛÆþî_qé–Bî `òɉåÔŒâI”¶3RF’G )0(Yù!ý½}ö„JGªµÇ¢†¾ÛÝÛ}öÙg¿ùáÁ6í»ï®ß}óÉ0Á®×ïgôB¦‘ÉKDeìzû޳ þ]/éÇã»ÙÇËïï~þé׫wûðã§»Ë\^½¿þ–ToIxK‚ÉØDRÇ#K‘Huæ¬ü\ï«ëjVÙ¼±m÷-+ÖÌþ±/VEÛåU7g;ÑÖ¬»Ï;ü°ä…GœsÃ.D$d¢ÙõGú&Ž•³¹.ª¼d«bSt¬h™}°UäC >Ò¤i¤3ãŸùÊë~ýrúméÄÂs(o}Þ~w6B“Á¾~-Â3Á%frù8¸ü1bë¦Þ2ÞÇÇHfb R<ûGüݾ x¢]›]ß[ð â8&žž?í!Qª§7x¤bSt73¶.l¹bËz»kŠÖ¶¬®,[ëºa6_Þ³zMhböëÒ&Ì,ëjUÐïíûß®ÿþîBG©’=Êb2¡”pï_ÙvÙ »bEå µ;»,ÖÅ2wØíÌyúšow¥³ÅCÑâ?Øâ‰ýi›šYÀŽÃÄ≞yý*O&µs@6)à• q&oY#Rꈫ„GÀá#Çw‹§;rȧҰ!³©‘!˜›ÙíûèýE¢y”Ì~ª–x­xs`c·yã+¶¯º¢ôÉC·Ç‰&]–Ôôr—¼}k›9uù¶n,µzå 6„-ñÍÂÂײnVv‚êxqG*Õo…+à§’é-TšËK¨¡åiÓÛ^«Pô¸—Ž÷EÕ)y×…zÔÜ~}«Þ÷íl_µÅ¦r@ëìÆ6®©0Q<û®èÚþ<à·û¶CêÊ'd«¯ƒ8¤9‚±ˆV¸Vxb¨È·ÞêÊ.¿¯á÷kÇîm¾² ü”–°&‘™}®¨tsÂA뮓9 ™<;8‹4‹8ÃØÕ~»€‘²X4yó„r¯ö%ºóñÞVVdõr¹8ûŽ< "ejü*P|hÀ7¥PŽm^]¬½¯÷Ä<Ö7Wï8ßíš<^ô}û?Æ%j6tr¾î` ]•Eµ sÈí{sï×IéÁí ª¥‰’d„ ®Éwçˆvté4ÏÊÈ39~Ò| Ì&çQR©ô„dÑȰ›sJC^‹sÛgæ@µ’óÇ\Û“Eû`›Ð«‰-$4ÚXN3œ‰|zgpx3£“vMª£hçÔ#y¢Ž O€}Ûô4ñ"TÄQ’B UAg)pŒÕWaîó¨XWëi"ÖíÚ9sº¨óÍÕ·zE#íèi·{Xÿ¢×s¯•ñ¼ÇE„éñ6¾ÕFF‰š\b£Ê5´f»Ásð,3< $éŸõ™B¤JºÅ³Ü ž^z4jY“c"ö­KÔŠZ&+”Ó)&£MÕ_>ÿðéË噆ԉp6•\·³½†ˆUÅbbÁ§Ô…݇&‰ÂÑ©¹у?•5²Sm.¾Ô˜'ìòè>Ž˜.2¼!ΦÙBxaòa·+™³…zÄE7µ ÂsÕC_RÇÓ+ÐÔ&ös2sc€¬X½³Í…ÓòGXÍÎ{ Q£’HÎ>”àÝ _>ØòiNœý©ƒ]ã—¥…JíØþPëPSB4‚ݘÖ {cOuÆç³ì?, Ô  *3ÉÂîTIˆ*#Ó±¥ó$ @ÂÓ#÷2›tЪ@â;H”`e‘½- ç6¦©Ñô÷ùƒõТ dgx© ¥’¾1=噜^"ªÿEÅuË—nÏ *Œ¸˜¦Á±ëgf7`sF;±€.ê5•ˆ°\%–=#˜µ–þæUÝÙaÑ%E³/;JÉaô‹C;å./±µáƒ=äemáDU/‘œ<É«WZKdÂôZæµ)v ca1+KâJÊ<ì­ëh$…4y?ÓCó 3Qšb°*“‚ÆFÝäö£¼tü‚¡‘‚ç(<À_Rx3ç(Œ§$ŠB¥N‚’j*9Àévv•_óªTtÖidÁÓ4JI‹¼yÇn ’âË7¹ËwSï7+øÞ+¿ IÅQò•ÀØ,:h,•û†.ÅÍÂíШ o+˜å »[¬ãç4-KèÌ3¤3ºtVí©éñ“擌fê$&$€OÕ^¾ZµÐAľPø í:ÃxòœU‚(ñ30ävåƒÖ3œg}vÍ¡â^Íã®­–õÊÉâ–õß’Ò„Dßæ͆T'‘žý“œðùàç9¬¢iy“z-_Û¢ó‚5”ºT’à`2Ë T²çò`×ýbN¨žÞ|:"l6ì^÷aR³?mSðX`Œ¡ã\Z]¨>wI$¸”G}Í!œ§‚Ò]$Æ`pºäˆ×“ÃÆ©iVŒG® “$L”y-=yËH6ܵóBÚ2EgØ>Gæ ‹‚ò2‹DœNO¯Š ˜éȳÂRrÆ3 RZMBÉó¹£”}@kÛ²´gš‰cI­”Ëù h?@ß°{-JŒé÷]»^£a†Z÷¥@ÚQäzŠZl2¬·Ý8£è?ŠÍ½“äuC…®7Ï[h_V²ƒ#M^m^7<‚Èô§11ìB ãNA§K­ÉÊÛšeFoNî Ž½ø+„ i¤î$ÖžDË—nÇõáXamã©<å8™Ç+Fº¤Xiõ¢(ïÇ<†N •5®¼‹à&D @‘I|J©ZIWŸPI&›Ÿ‡Ù<¡Õnrx« )Aeúm.$Ï"¡4>|@UPná br…H/óØýÀØs$Öž¤“›¾F7|‘&c4¢ªÿ]Ì2ý[•—E×´öN“㪾ÂLÅ*Z霜•*) öøh!¹×dYl.Aµ#õYf^‰‚²á4S šÎ^3)ã å‡ãåˆóYƃ’uJ3ôr¥RL—ÃÓ ’Ù×Ó«gó#±L¥"ìÏ¥Gœ]:$Q&Ò7Ê#ˆCe¦—&o|ËÒÙ­Ó—~iëHO,×bt};ƒîÜWÄ úÅ“W¨Ç£Idb$ ±EØ CâŒ2Ý;§ 9@6>~ÎC¦"a&WïñDBÿvM]¶Ž_Kû`K7í ¤­íŠ%k÷»]Ýt$‰/L:V'‡õÀ/f‡G7Ó^¼õBžv²]ݶł†W[oib%eË{»ü·ÓÞö}ÑxµÈ>_^^²BˆN=VKÛÏÚ ÷"ÀkÏWs7šÚý¢¢Ãe¿bùý¡ë¦Þ²Ñ2p;s›[àO´ÏÜK¯ïk(‚|õ;VMD6Vbeýˆ@Íu:J9JøD†Õ‘®§Å‚nŽIXÌ…e˜¾¥Äö8>ýÊ0•ò(6XxÇ¡ 2lR[§ÊbÃPánx÷kš„2KŽ€"¥Ì\^þ¥"‰‘€¶Öexß·¤ vyDî˼™‡FFùé®za(¸û+ë ‘B[:*qpp3N.~m†4&þ{ï^A‹ ××{ïÝ-œ.±Ös Fß’žÍjiRÄÑ’,êðL„+ú©¯¢gó•vÆdO$UöhTçÀô‰Ûã÷ϧ;Å݇Î,rôBÑs¶x›ìÚD õÎæ9+<®K.K¢pc¶(z4)u7V…æ}éQ]p{ÛõnZ…¥–Æàê±lw8k£Vˆ5òòƒMrk_$øÇÔÀ}y? «2ÃCmö“y4 endstream endobj 49 0 obj<> endobj 50 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 51 0 obj<>stream H‰¬W]oäÆ|ׯ˜T ¥93~8Ow²b\àF´Î‹¸äì.}\’à'Éoùù½®ž!w¹+Qr‚àNºƒ´=Ó]]]]óí÷œíÌÕÇõÕ·‘Œ³õöŠsàþá"ñ£T²˜§~ÊÖ‡«€íðµÎéÛã•÷iˮ׿"R‘‹Äß0ð¥JO‘ž~êu]è¼¼*á~˜Î?…¢k~ñØcYU,«³gÃ6šñÖïuMߨõ¿ÖÅÑeR~rv Mùû»ÛûŸ?Þß­òqˆ0/$ÒuYïX›uÙA÷ºc‡ì™22º·‰¬„ðe"8[qŸó(dëïé€(âöö¾Á-e=¢ö"gE>È9ˆýHœ’.t~ÛÔ= ô÷ y ™ 4Œæ±t¯ËÛ¿^EIâ o½/C³Ó‡æ«&G_ôP*t?‘Ñ‹tÞi¥LS?r!¶-uU°m×lÿLß y?túf0ô£0#€Ê(¢ØEgu˜fJ?C%ySPYnugP.{”̃4˜jÞ•_µaêúæ?"ø†™V£ºqý'JO)ik+m‡ƒºîÙ¶¡þÖϬiu—õeS‰ïã¤D‘òEÿa¬x¬äyÜ1€…Ì›-ëŸÛe¢ &xòòꡬûäs¿DpMp¥¯~Øl¨M¹«uÁ6Ͻ~¸ö]8úª"jQ|lQÇvH¼Ÿ*šK.–ue¿Ç¬”9až—Û2·PZt·C‡Ït¬Ð}VV¨ÕÍôAgvÌPúC¶¢R‚sf×#À i:V?e‡¶ÒV%X× uA§À*Á⑎x„Å‚©”ÎÄBo˺´_@‘¢ÐÂ0’VäÖ$H¯Ï6†"àçŸþcÍcîAÍã ¬i:MÓ^gÜ–•ŠH,§ªsw0ŒmŠ7 ôPç¶Ò iòWH WœÃʃ0¤çïÃaCJ×C¥ÿŒÑ"VRÛ4°Fƒ‡¾9 ¥9fñçÕP¸;©ðSp^©Øçɹ̹»á!I)rzÌÕÊ\ 6§Þ§šeEa;çj”Êç± —¸Ó8ìˆ%Þ©1¬Èúì¤QøÉ»rƒú² dâ†Ð°z4Öm¾;rt6i2¶ëß%+?±LÑõp…ÅNù%Y 3CÛ6]ïàìIÇJ"6©“ s|CÄAÅ¥ËÙ´—,NpÛo3'Þc²'˜ŽÊú*ˆÂyù/Š~ÊuK¹g¤ÜµkÛVÙÎÜ8¶–g‹ýåZÒ—Ø.aŠM­’SY˜ Kƒ*êàçQó°X/Œ±•£W.컬]¼Z"Óåû,fDM¤~‹ ¶É4„\]²p£Êº7'ÆvY½ÓÔ—¶ƒ^‚Ô®Êâ×Á}ôSÛÔ´Ó.åx#0LØ ¯ÇIÚ,ÿ’í´UÐÕ)fFt…»Hù°­µÚ<2õu˜‰%~@…í›G xƧºNTPÐn+ë0 œÓªáÏŠùñN-»>ÝÝݱD…7ìq_æ{¬( æ V¿aJ(*aÖuMgûKÁžúà-«{ua:…rê§ùùîxÄk£¦¤Òó¨‡ë›Q7…û|à§a(ú<ÝçþÙi+è!‡–žµA&AzÙ†×Çò=|kN¶5‰Ä€A­3à0ŽõB<ø ëe¨“ïóf?À;­:ì§lƒådÑ„C#öáÆqŸÓ(¼Œß­2ƒŒ®tnéaWsV•¿9)4ùÂ8Ž:6?g¶È§*ÛaSÁV\®Ä¹ö»w<л×_!×Õ›89ÃÁÀö8ó‚ßf=€£ß~7gÓ¥2.<’d Hh²"=’ë¶‚ËyãAû >‹ËdO„Ðê¼úåO€#ŽýµïöãC–A-€véÁs‹0ÇéM ¾6y>t¬Ü²éùJׯjöÿh†L±§'šýƒ²yCΔÂõÍ¢èÍ99ÿwx†ž¿@­s÷¡x|¨n4“Z@Ì‚óG'þýß°ƒÆ3É¡ûaS7Ý!«–0J!ùàÌÏMç{ȧÎt‡SëÑ rÉèÂf¨Äº=ïçº*¿h;U ½ ™sâ“£sÜ}ÝdNÆâ$Óù`—'½ZËzÐæøŠš5!–¡³v6?4Â.48-D;o©Á§wuÕÎÂ>xC]ichŽ.™V3=×^öag4ÔÙU¬„÷Á8«xƒž‰WÈd23³D“´¡yg\ìkÁæfFi&_q&cfı†´yzôYÏ®q’ûÇúì ^‰m•åzô…Ü‘"µœHY,h±L å£ÇÁõJJ¬/_ñÈÂØ&60—¬ÄpЦGkÛ´Ï]¹Û“dçPÜOÿÆn›¾Î%,‚ XQùÊûtì‡ uCwØûþxáE¦ŠÇ~šž¥ëñˆŠº[_ý.À¯& endstream endobj 52 0 obj<> endobj 53 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 54 0 obj<>stream H‰¬WksÛ¸ýî_ôŽÅD¿åá´îd“Ø»íLÜñÐe³•IIÙñþþÞ€”DJ‚¤¤›LlÇÂÅ}{îÁϽâä¾9y{}òóG8¹žpEþâ›ÄrC ¹~æåÔ»zÈZ|F‘Í_²×†ÜåÇsFòç¼ôÙwž¬ì<3òX5-©jÜ:'Õ,tkVäóiC². øiò–äßžÐ⢿’›mdMNÊüex:›N»€22ÏÚ¼^;\¶è9¯ŸCïiàÍih7óh0=³ú~R´ÁÁ_ºþéM¼£p/"‚§¾ó1¨  ÏÉ¡Yr“DƉKA¥6ÃÃ_`;=7Œ%?…Fîp%˜‚õ8ÂUA¾&å¹1†êäתÀ}µ¯ß¨6}ÖMžÒÞ×ÎBHIVëBxäªÂÚæˆ* #`)n£E¶>s©F1!u“.S'¾Å>@ˆU‚Y€y—õS^ϪúÑçŒ29š&ŸK@Ш›ª%Õtœ¢(×Ì8sez´wd4/ÃÛcѶñM’•¯¤ÂùºsD^ LÈ`ÒðÑßÄä]Œš–yËbê©rZøœÎÈÝ¢ÅEíC$Rh©uÖÍRê̺‘ï/ÞÝ^–áÊÛ ‘†2EJ¯¬†­oíú’U”žÉÛ¬]€Cж«›äT[f¶É£¿s6ÿñ—$2ŽXžbDJ• Î÷¢0TñÑqF…ÔË­îëñ¾U*ÁFL×µúty}ûöÍÕEįHáÆ°mÇZÎz° ý‚#ý/Þ|ºº$ÿ”TXÈ •y[„zÎ%µ6MÇèŒõpowžH=Îðxv;,—ù}й‹ ¶H±ÒceB_׉N‹û¢I‰æ[6¶ÔQwØEˆ €uûƒPÂÐÔˆí òÇì[ ˆšCSˆ­Üî:4 ý²1ŜˈÄ-ÿœ †h»`œSÇ€ °®-®b­«E‰BZyÇ2R¯,%WÔ@ím9ÿòù·Oïoÿöæã‡Ûß~5Í jFwgÉÞ¬•`€ –Ûž»5I!o­#.‡‰Oæ9ðÛ“-¶‡³©ÚèSÚi',/)À0 ù#¯«›Ó³%eîj—ßDÒ"†;õ:î¶Îžba ̀DZÑÊÿ*ꇬ âf€ì”k(wÛÞ=\ÔuUG+Ç`˜B Çbù{¸`¯Fœ+:ÊTívÿÅã5!V [%‡¶ÉYlƒ÷ë^á;8/œí–Jþ-›D·¸˜S7²:‹í.Á0v9›.>BeÞîå*á` MQI¦Dû *!¶1… Úð±íª‚W‹»"›G{ȨÖGžyßCÏØ øò¢” f·ÝOæÙãSÌ­9;w»ævÖoiô˜§ÛK:[2Úö*ýrh ÅA¿i§s!|ò=âàÉG&C½êÕÿŒ<ÕyU7ˆ²“¥çšö¤`FAR Özî³ð©+ vÇRqizŒbðšÔLÇŠ?\þòæ£1~æ^ µÛ;€:’ Y”ª!]Ðlµ ôi´Fðlm¬Š€ôËÅãdë¢)Êû5S»Tnèb){‰uyqqAR®z1Ï›B1,{œB‘<¥)†„RQ©=V¡øÑ±c«A`[×P(~‘Ét;ˆ} Årš¦ú11¬Ô2wn¬–_Ö“>dÌ9Z‹š'ÎÐu€cŠ÷´Æ[Ĥ½€ Órd2ð}¼F‘xLyoxþo´Sç±¢wùMœÞ¯K@±&åfËÛ>5æå¦Ðc£=™Æ]n=iUø>Þ®kAvñûŧXÉR“šÑž€ôaE&,4 ¤à–÷½‚L`²•S»îÐc$"¶bcbhŒoGµOniìvÉ6¬|TfU?!’¦VnHCfm'áG— ^íäev7ϧ~Ùî®§mj‰V`Ò3Ç­Z<&ðæùhäÖ¦åAgDë†^à¸MçVªÒPiVòh[;uõ2fcá¯Vq² ™z¯ì.·T3qôÂ]ÿî…;0ݹp:¸pwyÿ…»I¿p£¬n$ýc®SîÀµže\¸^úûª0MÓG/Ü” 3¶¶µ>ø¦$™zho†±o妽VØ"Ý¢çhÍG¦MÍpðzÚÏÂÔ…—„€¶Õ,=nÏ‚Ã۬ϢiX¼Ð¶|G7-w0f·çÕîC>ß _ê.”ŒH&áÀ#P¤(9ç? €…4~ªáI ¡sH nÍŠ° ŠK‹ŽýPjbtuI?†…ðÆccÓY£<Ѷ(ªwû>šƒ¤sàQÍ·ãè9(î^iPŽÚ0õÄ9KOŠ- Jÿl òúÈQÍ×üž‚ÆVû(Hªc(hGˆbMAÒm,bÎåh®±„†AEÓáþÙKB^LV~¿“ƒ$ÖÕ¦ç}$Sk7ý°%HôÏ¡ ÀG ùQÐúŠž‚¸—ZÊh•]rЗ¼]Ôe¥!nh y(°Ž<ïúË&UÙBÕبajlA»³¼?+º³‚XAÀ‰Tº¾Œ+ý†‘×y¹ÊÛ«ð¸Yú=#Ýûàæ4¿U§¸µ'fT§­¯‡Ù¢œ´EUzh,Èl`÷¥*ѯšdÏyøý¤ª!«Ÿªrê?©ðq—oœ¥¨ÀwL8”ùû^G ’bl´Št™/¦&oY6¯ólú:H.–›tTAS€C¨g´#›i eéØÊÇ'†ÉÝœúí5¥’Ïåü5€mW²Â`2µÜìi?ù3ô^C£íCV†{ú4W › q:?ƒv}M~ÏëSpŠç(âNðÏö i;Ã4"/F4×}Ó}j盛׺¸hñF›àivùöò®ªŸª: aa> endobj 56 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 57 0 obj<>stream H‰ìWMsÛȽóW̑ڒfç  9ÙNvk·ÖN*br±¶R8ဃÓÊßXÿà¼$@¢”C*‡”‹e‘…éé~ýúõÃ÷?ÞJöP/Þ®ßÿ ™d«ÍBJ&ðÿYŬŒyÌV»…`ø¬Ò…à"4[ËÕÖ±¤zhw®hjüå~wµú„@AHt„$$Fu¡èpZûÒt'ž\-UÄÃX-ï–ÝÃáyx©×A8~øãríÒwý7¡Ëï®~]ýü­«”08=ÍðXãÇåÝ·!–.3Ä«XS²•×MÕ¦M[9vØ–5}Oš¶fYMÜã»kxç· #Åedä ‘.À@ÆÇ.#2yºEúZý}òHàŒ–Ó̸”‘Ïî)qèn‰Êðí>kXVЬ>²€²” ¥›4,auöP$9Û&Å:GÛ,Ýöß0-¬©’=«’¬™î§5úrÜ—¶—/µ»ý5CpаH»™©ÊÜ¢ò*ßn¶©Ê§ÚÍH®–?5#‰r%;Ýê;?™a˜o(›ŸË ñníuçïǰ—m•v­[“T´¨;AÉy^¢]ømçveõýÀ¾ð]+xG*Ù“Ju¤RDÚ@c¼ Þ±&¤ýÖ5·¾å? ¶Û¦¢& T½&…ö]›!-ŧõfã>¾Rq¿×ÆíÈúb MÄ“dD²AfæH‹ˆcŒÆ—\Ö&­ ·æIfÑXšH%’‘ü\#CR Ê¥Hv]ón”æQœë‘=yƒž§2РŽ#ÇÚÖ¼*;x'£ˆiyNqî=A(m“zÄ  ì€ýæJ«ýœÊ ·‰nÂÑʤ9šùšé!¤bÇ@^³ˆ&÷ãx·¬ÜCRÑ Ö„3Xîu¸¯±—xÈÚSh~ÒBÌ+l„ÇÔ&m„~GÌDXB½tƒ ¥¦§F¦¥«ŽôªK ]ÅÑX·^eÞŒÿ‰ÌkÍÛèØe«2zø?0oã ÿ æÍ(²»AÃq Ó©àqzøã2Ý&Í›œGB†¸$4Óܸ s4Ø·^ûm´kkšX¬š$m ìîŸ-6Ê/‹~í²‡­d¿Ñ5µ¶g+Iˆ^  sÒŰåá }6Àü·¾¨'`hr¡†¤>ùrÀ#’<æd£%'!Žù.¿^÷© íǾôUDÕ:«2îµý( ´óŠòLB¨NLýš:Q‰±gAãlGu¾oó&ÛçÕÆáåj­âÆÈxè˜7U 73ªRÃ6š8žqH•Kˇ"û—[{”zCŽUN! j®ªÊª³y—öqì—ñB§©‘·ˆâW8Íщ‰ðµ…n/¸3ó«D e'!.±Ò cg/ArMuC–&õ1‘§]ÇÈFxáz’ȇ¿þòËœ=ˆT<@vÚå½ú+”ÂÃM=¸úYNÔ&ßû¼—¤­Ïšñg=ø`ÔÙÿÍøÿ¾WVò±A™Óù£Îy«ure}צλêÅ#aû~{ÏnM¥c®A¯qØ£Tcu±… ÏÛp-ƒ§iÙayb/&lÛî’↜]rŸ“G®Ó*Ûû\½#?½tª(#ƒ¦flâê´ºúü;Æ!ƒ¾¢± 1‹æ)Ï'æ ÿŒuóéõÖmtì²U=|fÝB‹•õŒy  Cr’#ñÈ»Y£^ëÜŽ/2DôN±7uç~G]ˆ‰ÊtO}4':äÆCëeilÝç6‰/jLÆd°ƒ—zwpQÆÓS”œ¼ây{––»}aê¤Ù§µv›ŒÊëRëý=±7²3<Û‚¯Ào“ånvYã\ܽ£Á´ÀÑø«H^ðr&H–È€BFÞå*Ѧ§ŽIŒ_ÏöOÚOóŒ“BÁ¥ól:Çhý¾ºà¡ ^§©õlù:]°7®L´®ð¡0s­õ;©ðS,ü\™ßž<­ÈŒ¢—Ç¿ˆ÷¦ •JD±A< sJ÷¬TdòÇ®ùŸŸàùCË”Ð{öñWÁÖ É2¶€ìH !"Ív RÕá[¾¸]¼]-BŸ@Hò$QˆûeD÷Äþ˜Eu©?3:DÓß0Ÿ±Æ¾vl=`YúÕv ¿ºi½F@†\Q÷MÀöæ5[VÒ†%]gy9ø½Kku·/ë:»ïGæ¸ÑX)Lšâêv4º—sÝsh¬|l»íŽF¾¨c‰EUqx,©çÖ»rÿXùw.¬P윟޾gïÊj_VÞ[Ѥ…|x¡}ƒ5á¦Õ®ú<ø½c®Š„ Çj¸ÐÃ'£¾Ÿÿ`VŠï~ endstream endobj 58 0 obj<> endobj 59 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 60 0 obj<>stream H‰d‘MÔ0 †ïý>¶‡f’vú‘#;0$¸LÅe—ChÓnQ'®R°ÿ'´%QâØïó:‡÷Ó–> endobj 62 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 63 0 obj<>stream H‰œWKrë¸{Êi™M v’ô§^ž´«2xN¥( ’ØE‘ ?v»ÒûÈj²œ €) ¶“z岟Üï¹ç|ûó/œíº»¿<Ý}ûSÎ8{ÚÞqÍbüï,aO¢$ŽñÅá.f;ü<­ïâ(ŽcÁž^ï³~+Ó²C³*sÿô+, o‰;Kœ,¥i)k&â‚çööÓÞ°K ø`[Ö¦c=}YôëúvX÷CkØÐ™ Û6-kͱ5©û²Þ±Ú^ïXY³‚üÇìGà T)(nX7”}±‚²±nÇ¡/ú²©—¬¨7ìØ6/åÆ{Þõš¾êìÙæhÚÂ:kj|Ýt†½Õ`ºèäPi-½Ï8Ën¤wN£ì`°/åï>³Ý–ëéP kÓuÖÓiVðúbª7Öí›¶S½Ê2—Òz|^ô!Ãä~¨7­ÙtdfSîʾ{¾ÿžJt,Ú¾\UѲ²gEU5¯.c—oËßUgc;…ÜQÈëÓŸ¨™æäîëâPÖ6Õ<¾Ù*š3Ö å‹îr`HØbœ‹ZÖÖ§kù’í›WóbÚ%:t<"Ñû<ýÍùе²™íªìÛ¢}C‰Ìºì`…mÙïé°çÅpd}Ãò<_ú*}y(*Ÿþ’½â43¿›•0fåàì+u«­<êÔVôˆÐëTO[åbÒë]¦üÜ8(?±‡˜ Σœ§L¥ Mýt‘íusÂB`”„J£\\Ü=‡4÷åzO£ºrW—0HAŒøˆÌ>$*Êc!¦Js7(bË÷ÂçB#üœ)•D¹JÏÑÅ „Î5 äüÞÉñךèc¯7ˆ¸÷“x6Z¼©ÙêÍçgÃ#”܈O&9ÒF¯ü¸¼2“Qžè«¥s8T¶2ÖùƒH£4Éõ¤‰ç¶ÃPõå±*ÍæùÞñË{Õ"R’)Gz/µ/hóHëÙøÖ¹‹sÎJÛxOôQmv–W–Ä1kðmûZv††5QNwù¨:Î&@1bZ´¨ æ“dXh@¢£ÌE·°„B†‚ýùù3w£êÍeø_ÍvH ñÝýCš¦‘ýyH¤W‡€TœÌØTþ™@GbšÑI üù~–pjO§LH%:Æa!O‡ßéPçe63îk©Ýá8BÇQôÅfv°Geî¿ 2LšE)0<óð ôƒªÓìâÚÿج{<žOêX6 I2,ËIÙ>E$2Åp¦|^?ËÙB!ˆÄ3·¹-M¬ÙG¯vUÕ5cÐvÃ9J˜Ãf ÑâÜ×EwÄf)ªû!%6›¶ËðzLAׄ¢‰ŠÇ——j äÒNñf½² "8¡U”€6/C[<¡’Å×W&€{ÈæJD”e ij¨%N×EªÍ¡”«0¯q9$™ÌóˆOý×PšàšR=¿trhC…J:;»!¬!è£~ß6Ãn?QÏ÷ÄnÁBŽf"áסÑÜX°’´n“«ð²Sxm.uËëKn–Öƒ+&–“Æ¿%RmàRØö¯Wb9S¯›¡îM{Þ$³äöéçÎÚùw  pÃs©˜Ô”•}QÖÐÛeÿâ*´ó9¿ãf-ŠQßù°ÉÒP”N‘¢<6•^úm›¡…Ø4•Ó¨ým­ü] <($vFLƒ}˜‰·¨À¤4&·ìÐ…€«H¡e³ãïÛÏ0_jvaÆ6Sjm_”µÃFeê©O>TZðyWé~B*¢ÝZóÛ1A" s×¹/-E’Ÿ+9$‰Ìé-ðýiPJ×ø·ã)ù«µpbÏäÚqY÷"ùg(ñDéˆ+ÖM× 7D‡¡ëÙ¾x¡`)wDf[Ô;“žR,ÔÁš-ƒ¹š¼6B¥# ÆØVÒ õòXèÉ•wQŠ—•Îþ'Ðw*™]¡÷c–Ïpºoh,©£¹¹ÃÞ‚JX|Áh»j¡—^‚=æ{õæxØ›¯ -ÝÅÖØ€¸[s Ëý¾è'…ç! l@Ÿ\dLä É'[¹ØüŠŽš Ö2ä:"°™%õ’pjéä•æÄŽ[ÕHá*Ê Ö˜Ü.Æ©çðz"À¶eoßœ€U*oª“1˜ž–†ÊXŽ•­‹]ËÙóô´h¯…KÚ™yèàÔ#!$m¹Šqjur+oœ ªOkõ›É‡Ï÷Ôþ\ºwë~†Jy†Ž/È4ÇNÀÀµC}BÀ«}Xµ¦ÃÃéâÉ‚ 5‡/;8¢¢¢¤v4jj+ˆþl›ÖŒÕ:³œß+¶ÖÇ´á†ß…ØÚK§wDs ›OJPqÉ æ>š5‘ƒ†ôìÞ⛀K¼ãfG§äêŽq~ÓÛ+!ŸðÌf¶¸ßØY”e‰¼ØØ’;^ü;Éw_©è#`“ õ¤ÆÎeèMÕbãD íÓ[ä2 §*v#óÒz„1ûj]²][l´m€ív[5¯˜’šÜ•Šä:ÀnXÕM |@»Ï=ÆÈµœNCN",S«Êl0¹H"¾øâ§v]tfé¶z´:2„ÆiígW#bˆ/¶Éʬ›tchÄ¡04PŸ™ 1<à(C–&‡'p/¹º¸ò‘HM‡Åìðó"$<±¨Rà`vã¼.;Ü, *å@<Á`¥‚çSsh˜J,ƒ-¸{¾Ç7šGxOÌïÛ«1ÝiÜÌ®‹³¦±ŒãX½3}OxݶÍÁoåq¦o‰ÿÉ|5öÝÚÓZÙ‚D>'Û’ ÞrõiÞâ)=Qæ÷¦Zö3 #˜p}íúᆔp¥¦÷ïH+‹+™Ùc«Åÿôø²J%êÓÖS Ý0;Në4VÒÿplí»¥g+Òûr½õmʵ}Ê¢³ÁGfœÍ]œ«¡=À³Hòë°Ò›úæyÁ‰®õaeçhrW–ÒnŽ 9i,÷lvÕÞšÊÅ’ ±Ï¦K‡™OnçŒ a‡Ûq×y¦bª‰P˜¼ùì”4:ÅãÒñIY­.äÍ{Âb"%”d@¨‡òG;JcGų+”P&."8å´nÌv[®KÚ¥î‰[ÔoX¢Å®nº¾\c¼·¤éå5>b•Rò"“çÅ¡×ɤ9~a‰ø\>h ôº˜žEqq¦c’Ä8•ù/áUÏÛ0D÷þŠŒ^ÙP;0¦Q‡Ùª.,׉­¤&gÈ¿ï;S\Õí€ÄÀÁ}ñÞ»á4vQçÕå±úq*ƒó=«•ܨlÇ‘'Oùªÿ¢?¾‰h0 9ùOh ±ÿbLL«¢Œç×ð"ϱmx+f:c—tjª’‡›ðú BC-ë Ê®0JÍ<(¢øÐœ}@Ò"T ~¹­Ïqù¨ ‡Ú]ùCý(ˆ)ÎAÌsÎ5QJ›¨Iz;Þ.w5dkibEaq[˜‹º¶þðŸñÒ†‘öi’B̦Կgohêáµ”r#3¬m@°-*oÈx^a´ Öä”à+öæz·ý©#XnÔ/O‡ÕÞØ«±¾V"Ï«ÈÃ;€¸?ìŽæxZQµž¹›‰œ‚z~}ø`œlÌ8 endstream endobj 64 0 obj<> endobj 65 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 66 0 obj<>stream H‰¬W]sܶ}ׯÀãª#!@€d:}¨?âq&ötÆr_¬¸_çÜs¿{óA°u{öâêì»4ìêöLDŒþá["Y"2ž±«ÍYÄÖøºZÒ÷g‹²Ý_ý#Œ„7LÈ”›L,Ww–ùÃ'/-¸Rztø‘‹MÌ…xEÂù„Ÿ¤rޱÛ–+V´¬®,«¶©›Ùç¥I¸Ò“(‡wUѵ3®È4åñ$;ºRT¬´Õº»c׋ú–uûmï‰9öD¥‚ÇYò '+»|¿ÛÜØæ#\šñ(Öìå‘KÁ‘ –WlWµÅº²+ºàRáÓD&ìRpapè׎Ug×¶¹>'»[ÖU—UË:ÔqU¬‘FÑÌWUÉŒë8cI”p%"ă«—µ½½-–…­æQI̵9²…odþiÁÏ/6\,^çË;F%bÝ6¶Å…}ÅϾúñìRJªl<‰P ÔŒÜp=b¡VDD’ ÉLs%âçE$$ÏÔ‘íà˧…Kò]Þ²œÝUÞìÙç¼ÜÙÞ£&¯Ö–E>*ax‚ÄNÊ–&ÆyÒÝ5õn}w'Aç.Õܤ̤ ×r@5Ó‘"Íx$ Do°øcš™ÆY=9<òL\°û;û cÅU–LÍÇÎ0Ny¦“Ó“Ó·kåpC¥>”9÷}CY§|¾[Û…$G¨—ã,;gnösè1J+‘\“òß)W¯^¿|õïç2–Xèxlâ ¨B׋ÖZ¶ÍQûX\Ÿ‡Æ×ŽLÛâW×¾!’E»ÉËÒ¶}‚ŒË b¿˜Ýì;ÛúÀ4— Ì<½öqWQ÷EYö€w—nò/Åf· )ºsÔê?¡§9EÑ…¦¿˜MÝ…WáL‹û6Û¦h‹jý8Äbôr¨nbù<ˆEèUudK®ôíÐvyÓ!:P1¹PÚy">,pq^u>‘×4}(×=ÖT¦§Ùiì\:Ðý²´ÛÎçª~øÒ ]z Ñ™Š%0” fdÌÓ8;„ÿx#Å`&¤\OìGºo|ôÎ$O¨,><Œ€ÄȾD¨žŸðøàïmSoðjO/3îË”Ügd‡žzª÷J’÷‰žØ/ßýÚìÝªîØ Ø©E«#—Êͤ£˜}t¯¦îʯhe\šUbãýÐêy \hãWÛÔŸ /~²ùŠ:þ$ö”­ûÄjÍU2EÚûï^½}óöêÃÜà‰"LÑÔLŒy«,(-Ï£HE¾+‘–®v-Ó=1ǵ7³Š0ÆY¦Í7¹9„K®S=í4ÐçbåR4;Ѐf`sbÿ8KÀYÉ8žy÷‚B*zy·¥ÌäÈV]ú1A"eйnŒž6ž¾ï~ 9ŸW{–o·%(¶+ê ìÐ9mѧ3gÿªêûj˜\ASSú ´ÃÐxÏÝN$3—€Š&œ^¥‡ùþÕf‘ÄBÔ,;Dc¢žß0%Èe(JGw—wÁ]Pž#×_òͶ´ ï(Zˆ±(ÐÜ"ý‹#O”OùÛŠÕ”Ÿ¦>›œD&”fM|„2 ‚Ðt²ÈÍ3r £Û:uA^ý…ŠI8¤›·M½nòÍÆ6ÿn!ÂÛ-jQÜeÑí)[µ;TÅÅä DØîúI@΋2¿)ÈTh¿†àîU‘w¶Ü£zeYß÷ bXˆf)F/҄ʼnr+ãS(›hd¦&ƒ/=Å€å…À‚%@`›P>hÄ>PÎ¥$y¯Óã’_ ú¯ÛÓXŠP*ˆ•f·ì½6° ÚÝ¢,¨XQïÚPÄöP’(¬5Zé&ß·Nÿõˆžµ­l“Cßå­%ìC.Ö"xÒvuC]åÒ¡H‡'z·Û|i†÷þBpIj]uƒü {–Ÿ©XOX1T—#Ó¯W «Gµ&&\ê´Ÿt9âsá|Øo-› Rƒ¸TrúüÛGÄ2×: d©¤<ñ¤—`×à$ƒ¤¡›ú]#YྶGdPœ€rªã£¾QÒW¨ hËl6'È42 #MütEFNâüØnpâÓâúüÂw‰ã*’Ñue™-íý|¤Rp¹x{;+Íâ@JŸ:ö¨®‰3¬XZúÕ´²vö¥81›æ1R±ç•[{ìûÞ=ùlö+ýìZ³Ên  ªHÀAîZÑô½:$—¤º{åZÙÂAì°¼#^]Á´Á•·`ÂjiWN1j8šº©Öní²4]Q ¹H|¹-š6, ‹oŠH’Ã~tj.´rQ'#ÖI=7¼u{¢ý‚‡:»ò¼<4w#»vNØ;¯Á掆¼LÀ¯˜-Í[¿8äŸRPh²\7›œ´{»#k‰ÕË–H ïXVM<¢:¬qø<‘µF0& -öVSåå‘gÈQ|Ð9‰ðW2Þb,–»2o.h¾áÆ ñve/=®\÷ârãÎ@~)€:£EÊFëhæ;4>îP°ŠÏR¯Âèn¿Ÿ4t4V6&£7Å£‘ÁV¥-Áñn¶=>6™ÿ{šÁñň;fÉΈ½ÆW¹ÐÿRÅ\GszÇd0Ķ5ëC½ƒNG{5é@b’ïç˜"Cü&æ2Ëžºû`4SFFã×ÿ6±PTìôô93W—Š't %”I»Q Àjn6•p— .t¤Ÿã,¹4²ô5SŸ4×âȧ›ÇR„ëW¤DˆçøƒþÒÐ4cKçOô%¦Ij‚©GLñˆ†zÛŽ8]WsHòäÈÒý¦.Î/ ifù{¸àäeàUF†kyÔ§‹BfÖP‚ŽÅÄÜçbœ Ï=8ÆcX)ZI> c£çaáä9ñ'aA$˜äê[°0¶çûÿ‚‚0ÂóùP[(DDŒoñ·@aléú-úÞz}…ßßàëGœÿrAcѹ'ËwìÓÏ[ V°3‚ŠAAoΰò¿•gÎ^\\îg$ ‘1n@¹Á˜¹Ï2–BÇ(6v¡£îÃîÙ›ïë]GŠ “»WÄ›b}×Ñx¸)Ö—˜É>ƒ\ÀJÙ•6üáÂ-Ö×°Mˆmì)/²žDH‚ÄçîŸ^»œC¢¹øJB.oš:¯‘Á ¢ngfðYú+^ÖÛ}ãü»^,¯ÏÙÛïØËºÙbo"dÚà€/þ1å·ŒtHƒå‡ƒ¯}š´Hx–ÉþA—)BÑþ'Àþ"u/ endstream endobj 67 0 obj<> endobj 68 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 69 0 obj<>stream H‰”VMoã6zô¯˜£\Ä\‘)rºNv‘ Tí%éA–h›…> QJ6XôÐ?ÑßÛ¡¨ÄR-NlgçÍ›y#~øò;…ƒ]}JW>G@!ݯ(…ðO ¡Š(H«U|¥¹ûõ° ²º€uú7¢Äˆ =*I“32øÏÊ—ÇÓ0ÄH!&¡?øÐ‘IHʧ—ø>äQB(ò‘‚ù>œêøœŸp·Nç|vßÓ†Žz&Xjò. Óp9z._·/è0¢\à„Niû%6¡$ *…黸0’¼„Œ¾…ÿøljÄÄ;S†ôÙ0°—z˜@ÓÔKZaèâbà¶à!&‘ŠBìÌ41ôÙGùR"F¤L¦HÇgìmú%LTõ¶ÃG ´:oª~Sj:k8{Ó ¾è8f÷ô~Úø©d«—oÛe‹ ¦ËjœÀ:«œ¤N·¡‡)pr,<öX.%Ä‚‘hò8úÎvgø¤ ñ 2]§{ƒ¸ÛãfvѳîT…Sø21zöæêËR”@{;wàoÍ¡v¥¢)Ôïoª6ÙÎO#}êw¥Éaß×¹ÿÞ™ Êò¶y–ò¼«¦èKܾDêÙª¬r‹ïOuÝ¢ ñÄõ&r7€À=áF`ârâ5HI"âø íêcþˆmszlÍáØ¡Sr¼Ô\ú¶M{jÚlðÚZ Î8~.K‚-¢Õí½.˜ršàUdF7`ÌÉw•®þ`&wC endstream endobj 70 0 obj<> endobj 71 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 72 0 obj<>stream H‰¤WËrä¶Ýë+°lÅ-AðW¶<OâŒî$‹Q*E‘èn$l²‚Òh™oH*ß›sðÑj15U±k^".îûœƒw¿ý…³CóýîæÝ‡‚q¶Ûßð˜…ødËx¤lwº Ù¿výö|³ù0´•Q]ÛßîþSáM¹3ådšæEÀÉt³;JæÎ¥þ\èÎ…¬È‚0-gkY}NRÕÊÕ<°If›0ˆ¢¨ °>oXß º’l¯ɪ®5¥j{fÀyxlTÅöcଖ{ÕÊš©Ö~?ʲ–Ú·Ùýîæ.¢,OÙ'7?›0å6{$ÔÓõ§³Vö/í“Ô½½Õt¬lk¶×݉õF«öÐoíý¥Væx’1tg©KÄÖ¤dw¿‚“0I„u2Õ(ó2GЙâI ‘-ìœPÙ4lß5M÷lodÙÂOÃôÐÈþד1ê»|Â,Œ]Ùþy{Ç“, òÍÏ[[ÛDÌÅõÏGU‘†dS(á2ƒ–={Øh¹—Z¶júø‚Äpö0ÜÙZFÏy¾(%OÒÈfy’­y¸µ×¶Ud§®V{…;†aÛÞ½ØÏeÓw¬?ËÊ}F|Ò†ïCcæX®Kù°qÁ+*ÒsùÒ3dyRÆÈúáö¢¬>¼0‰µüyod»]tÌ—¡C±‰v®h¶™>šÒM]_¢Sd¬*ÛÉÛ芇Ü5ᑾkMÉuƒ¡¹<7e%·ì ž0GLaܺ'|…·}§O%JÜÞ%YD›fòKy:70°5÷!r«#ÐsŽ|BëЦõåb·ÂÀÜüÆý<ž†©ÿ²b1Ç¿ù†oÙÐS HœNß D¼H–ÉŽ™F軺žflKõ¡®ö4 ˜\£N˜¬}Ù †9âãE|Qˆ„Gÿ_b/+ßðÀ%àEñjqøˆ7óâ¼/1c&ŒúÓ3e0iZJý2Î6£—Æø2YˆÂ°nϺVÒvj¦µz{{Â8²‹ûjåÌÚ©þ[V²s§Z[:Úe ÿ<ˆø‡–ø[;[ޱ»´gŸsÚ<Œ’«´¿TòLfh’©•Ç"l‚ÔºÓ½Ý]-Ï6Îט~É•ñèë6yMqÊ‘³„‹ sÇC”woJ3¬qOœç LåÒl<0^6ر½ƒy‘àÐeyóØ··d‹ cfï©]_XØë%È¥ ‰· Ñ£œz–.ŠkŠ€$xæˆ<%_ÉMQœEri5Å0Rͬ —'AQ$é+MÒ+ÕNêïQöf) ·@ºQÑ[Ý÷ÜQ=» |Ø´™ÇØÂήH‘;$°6GYý}–ê+† òN’ ö~íæG±€]Ê/ )1¡õÔâ8Bàh!4¨è ‡¦™ô¹\ì«+À™|!Oý[ Ø –²×J¢ ÁËP @áâú_ðäÇq@ßâ<=&ÃÈç1vÈbúÄ›?{6^£¡5幸ˆáëàçy¦WÁðNC¢!îàl‚Ÿr„Õ{‚¶\¥b$‰Z0ê’Ýg´ ÖXüœÓj ÇÓ_–(`gÿ2RD£æ[ïØ½Vå¡íz£*lB‡i›—oASf<Í—(qžÙ0,¬;5kË〔fë¬A.-íQ -UC„ ¹+Û~ÐNî—Æ×Ðí¢Ý¾‰¢ÐSlkžÌ¯Õ‚U&ö¶ÒhX9‡¶@ à J6ú:…B¸^Í!·=Ò“Ôàá‹¥¢Ý/‘§³UlVçVÆé>d½—K5½J|ß @숀Ô*:ð‰ë\:X ƒ³{û¦òÂd [騳tº#-Óz-~}rRÈå‚V÷º;á b´Ìʱ Û‘[œ"1|­„«c©ËÊ8&‡¹Ï•û8#gDqò"¢êZ䘮ýß¿XË?Û)Ê‘xl5wžÅ‡sî~¡wôð[*ê¡wøï*B‰½œ¾.JB|bHEå1é#Æàtn¤mç$6Ü#eb{þz( Z)ŒjŠþ¸7¦ûËr 6 þÅ…ÍU.;J]#ï¥Væx’´×ýYVj¯ªÒ½iíb‡Eh? %´ˆÞš’•_P,v÷¤jª-°—˜eM.\µŽ%m;uØé^ZëHP«„e.U&þóÕ²Ð(ÇH .ÛUÊÉQ ´t\ÿÔ±CÌŽÞbÑ4CA¿Ón|ÞX¡™‚^aD7ÒÆcqwŽrhÉ<ƒâêPˆ 3PBbèŽØÀÜ^™-¦Ïaáª.Œâ4IŽEV»ÎÕÞ·†bQ S´s¶¢g™’÷ ©ç)¸Æ¶}ecŒ`Arm%˜eáýÈÖ¶ …,ì~ÞüÉMÔíÔ2j_™w˜9›ÜÚ eèÙ4޽¡v/î»ó‹V‡£+TP:¿ÿ»ï4hȽNÀß)mhŠ ß|GE‡{¢ ©Ÿdx‡¯‚LÐÀ¢#u¹E‚òy¿»ù¯¾_¥¿ endstream endobj 73 0 obj<> endobj 74 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 75 0 obj<>stream H‰´WÛŽÛÈ}Ÿ¯èG3¢ÙW’û ëõÇØÕæe&Xp¤–† ‰THÊöì‡ø?ò‡9ÕݤHIÔL†aKêîª:UuêÔÛ?ÿÌÙ¦¹ù~qóöGÉ8[¬o8g1þàŸD°„gQÆ»›˜mðw±¼‰#a2Í_nfëÂnW¬}²µ]WµeUûÄV¶µõ®(mC¿°]þµØvl_ÛeÑUÉp”ʺ:”+»båa÷hë†ååêvñLÌy7~€Xkéì¬ìúø^Qº÷šâw˪µûne—Ý3¬iëò=À—ÚþóPÔvõ¯ê4ôðl+y½9ìlÙÂpm¿£3oÔ!þØÇSü&áQ’jùâýõÎã"L&‡·f3Øœ¾Î¥ˆ¤6ÃÃ÷³>”Û¹‰ãÙ›Û,þrÑR–â²™:"v?{¸ÅÆDzö©*Jd„µ•ÃꈾxÄgÛ²u]íÜ˧¼Î—­²(7Q0-#¡ŽÀø/Ó_z.ýÙû9v;× Šñ &&¸–#×¢X©"JEâ‘¢ÜÚ ¡‡Ó‹§¢a»CÓZ9ûœo Wµ¶.–Γ¹Di%rP¸B†,ø§îXÞ0_Ã+XsFóý¾®öu‘·HÁ­±.–y‹ö€] qW¦þö¥ØnYY‘ ÎäâM=ßÂãPäiâq¤2_ŠË qm_ÊÑàÆËI:vÅû.˜˜›D"†É\‰XGq:2†\e:;&+QI”ž&+„0(ã/OUc§êT‰8ÊD:2ã)¥Øm3„¢Ä›Ñ­Ù›ÀXi)™[°ÔÔÛ„KœnœWwDƒS†tŒBSæ< Ž}!§šè¢³Æ³dÀß JrEÅgG|/—vßæ[; nòÎ~ÝW%˜“Õy¹±wq÷%éóq9n$Ò!˜NM$VM›·‡©Lð,ŽL<ºÿãÄø2a~¡A z 5RÛ}U·pê™Ùº®êý”€"õìÚ!ãl²Rb%*ehÉ£ûµµ4©&k%‰ŒIϙ։BÊ=ØÊõDBj7jt¼+ú`<ŽR®¸7>mWã˜8µŠ©Ý>O™Fq¦<ùŸ-K.q,6£‡>æ'ÌJÉ£”3<>ÈÃN9!àΉëØKÔ9±ÛБæŠ'i‚ãüÜ“àÔî©Ñu<˼±·$\è½¹‘J³l(œ²,õåç»Ø®<±¸ù_lNú/þnëÊ)!êõÆÖŸi¤Ì­#CbþåÏ,ß6U?}`Céc½®ŸÙªÈ7eÕ´ÅþBãíÜ8£Ñ—wc –<ï²b·³+~ÛgèÁí¶úB¿Ã¿•”ùκÑ6×4Ø]ˆ&5®~²`ÿ²™"KÎ ’‹R€~•Ê)ؤÊ69¹àm'°­yPÊ#ÌÓ ?UMSIz¶qNÌ ¡P1êŽø¡c˜Þ¿ûsó3d0ûµy.ÛIB—1ªPêñ+½;à›‡Y{Ô « Bºá)ÿìéÝ?N™Èa@ÊX™(Nõ@êÞaÂKÒõT‚ «¼€nlCN'R ²$R&c(Î(Æû£J‰™ï‘SAÇu *(‡Û»ŽÓÏW“2MÎ= Äÿ¼×(¼ /4€VàÏI7ÐAf—*`È¥ñæ«ß í¸ÝÈ}. †-v8Oy9U:R€ 4´fÍ0Ž€AtEÈ,ƒ†R^>úGðõ$±DM H˜Ù¦¹Š˜€>Í0(•Ñ‘¾ Ù¤D“±BO@c /wþÀíŽJ—}Ï’KÔfö+Vˆ‡[âÎX‘â R­C§!´d"çAˆáµÆ½·*ˆ4= Ãœd˜ì/‚ PaÛQïòœÐÈÅÉ-r¤ËÉ@XÓÒáˆ#ï·'Jü:Ó,ëâÑ-4><"ÜdÔÝ6ê)¯‹öigi<ŒöW…Ÿ0nÁj%M-Õeᕃõ† YQ • EGaús™:âÆ"òѰ¨~vLøÐ“™gFì—áÁCÐÉPt&dÝ?…ݸ>”Ë6ä»Sœ¾ ZR°Ú57~ÍÏË;Ü$âl–…-çݼ‹¸1™‹ ¡jòðTD£Ú/­y:ÜrúÂI—/@Hí–¶~Öâ cK•ØÛêã6¶‚ ÞÓ–å ‘“XÆÃ»ýÖî`³ñEè9–ŸU!Ö“0 ­h>Œê›‹Ð…ó͇>ÕoJFÒŒž¸8h³(4’B~²ÑDFz¨Ä6ï0Ú绉®¡Cê*•¾²aºjpkÖ‰òóÚ‘ ÛÁáûc5Ý8ž½ P^Xv°¤i125DEÒó‰Òå ,Lûгøâ±#¦Ö×g§¾¢©Í‡AófX³zD®æ«GäxëˆßϨ'À‘MÙ8’7åØ;êq„#MÓs8N;Ž=Ök|ò:Ƶ 6Z[I´æaEIšÈ!ƒÑGg,àé+…øÒÂP›ì¨Ûˆ¸Z ¥ÿçêèUUöÃ}0öÃLuã¬ÓÆ£““À Å#¨>‘ èVqZÌßþè_›j9 öLAæ®Ï½ÒB øß¨mAû‹6~ß¹ZBp^èño93c±­zÅð±ò:›hpß)ïu]íX;¤gä‡+ -%É)‘e@ck@εØM†\ÄǼ;ÿ0{’ºé ”‚‹ê5û-W$ݹ›\$ ‘'§¿½d}À¶¾×™À„ÓÙÉééõT`²ê :zp(à£ßO§$V•(5j|Õ3Ì{:Ã%4þ©=$«ßTCþýjÛo©A°L Z<-ñö¹?ß&œ! (©.:C‚©Ø”äÂÛª,¢£ÄuIaåÝ”UC"ʆTŽ/×IQ# EaøTÔ¼/7ÿ¹®á©Á"h4N3ñÿÑ5¶ÜY#b_%P-Ž‹{aó0ûâd q]/o: “ƒW·mâ÷¥Ú†<{©Äâa?Oqêâ†Î³@§GýÃNÔΤ¶¤XYÒs4¥‚^ ¦JÄH!ðëˆÃ\<~ãªÊ"­ü¤:Ò$îR:ÒB@­¶ àtmãôB¾s"À¸Ïgr¹/:ù_*ç¦ØØ^·ÏÈê+‰yX陋>#ð²£r¼Ÿý݇z;—Âp†¿IÀ=ñSw1u‚É ;²£h ]ù®Ú?×Åæ©E™-‘éßÿ•½«ê}Uûâqlz±û't¸! lý™*`”èÎSÍ“(ËFî΄¢ Þ/nþ-Àꌡþ endstream endobj 76 0 obj<> endobj 77 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 78 0 obj<>stream H‰œW]oÛÈ}÷¯˜GzcÍÎ÷p‚EÝ4-R`ƒÖèKÜZ¢,¶”è’Tïéïí™!)‘¢GR­@ž;ç~œ9÷Þÿþ;'OÍÍ/÷7?þÍNî×7\†ø°‚Xn¨!÷ÛFžðs¿¼a”1&ÉýËMòs]´›mÞK²Þï–mQíšÛûã*Ù_Å»«¸¿Ê¤–2íx¸ eU¸ä~““ì‹HV–d]•eõBZœi²-~½îÚìÉv+Rï˼¹ ÿÍjüe¿Ýâš?ò•÷€‘§\i¸þWï±ÖÁã/ÉcŽûèíÂCµÇ~ 8möŸ< t€Åî —>í·ù®mÞßþëþˆI÷1±.&bÒš Ý'ÈG³Ûoó:’.Rjœ[%IwØœÞÎ¥ ‡F‡¿$«|ù¹CXÆ’z׿H.…±˜@Óðp;¤à·ªØµyMÚªËr[ï—í }Ùäu—“:oöeK^ $ê1'Ïe¶ÌWô\V¤–:f¥ÜÄxqHÉÑ䊔Ÿ¦„º I1|’’Ž“b©9—”b¹!E¾.óuK6ž€M±ÊɃóá–TÏy½>, •Rê½åºªÃ]Þ(ó¼q0 =dµ-Ú6ïL¶Õ.[áµÌš³õ` $8–£¾\ŽƒÅÕ8œ#•Èv¼µ²R¡å©ÕÇZ8ÉqÃuµ¨‹§Í´µ/ÆP­Ô›eHB ß®Dˆû­„j+¨R£g¿¬àã·öBVGf—Ó::òú¡‡X‹8Î%VSf&`ˆÖ){L¬Uzþòû& ®$ËúYÌÏètC3Ì›ªÜ·9ùš•ûÜ'α$ ®”äs÷ã“–Ôʇ1@#޹}˜7Ys\‚òõ:_¶¾m¦M11š)SÔ°^êñ[¹oÈ~‡¥)Ú)ƒôù0˜¡6½& q°bbá¡õ1©»ü Dúšßyzu#Û2-‹ölPh² »Ë$¨i<¿»ý9RJƒ9HNŸ;W«#;KÏÎk)*Æ‘^GQ,_BM.-ˆ¢;1/ '$í'*3[­†1+ÊQH´0nî~|7“(.S.êMïFQãÁ¡óÎÏ< 4|Á'&ɹs{`ݼĪí3fÖ?YfáœoìýåÊô;bx‡ÉsÙA€Æ/é`ÿ™×~2+_ý2§pOòé‚€˜”zÿÇ —Š“ò ?=UÂSo±ÅVØxõ ;^&l.Õ {h¼€ ˜gVR‘ZÊì¨ážØiÜÄÆ¼‡{)ÊÒw±ÑÓèd;69 ,–pvæClnèoÆ83ó s€û2§˜$ú2¿†U)ÿïËÌZuÖ¢w?d¥Ù?¶u¶l1öŸp/y~ocî¤ãcÀ ¾½Tûrå£d·w!ñuÇ`?I5VÑЮË0Æ}buŸ(óÑúžs‰Ô °ÄÌ9Cj¦¨ãæœOuž…­õ"¯YJYjøÿ ±ÇŠÇ¿Dle±¤2ûæÙäkÐÛœšy\;bx¿›9ª°ÐžŽ…CÇ}ëzÂ1>ì0zšîª¶—±ì±ÌÇ|­v8ZcÈl7>ñùœ}†bz7î8F‡^4Tϯuñ´i13-á×§_~%ªú¹ª³0gÆŒoXi5U’p¸ñ“R^Íáhxâ)úÈ8q7Úõñþæÿ ÄuÓ endstream endobj 79 0 obj<> endobj 80 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 81 0 obj<>stream H‰ÌWÛrã¸}÷WàQNYXâNÔ>egfSNeç%J^Æ[[´ËLɤ–¤|Ù™ïÍ@Z¤DÊòT2IÙ–%›î>Ý}Nㇿü‘u}ñÓâ⇟adqwÁ8Ið…_ß,¥)Y<\$dŸÅò"¡‰R‚,ž.f+·ü¼{¸uÕÇü1_¹›Y>]‘Í}}E*ÿ²,‹Æ=77——‹Á…h]°è‚ £J½øs÷ŽÄçUû|ŸOˆU”s9°i½N8`ÜRv`±OáËŒä5©]Cš’4p[¹z·iHyGV>§¼X‡?_þºøëX8"I©µ#)‰€gÔ˜éxn_N{ÔŒrËF\VÓ.¢,ÚÌh|x¬èÚšj9 í°Ú×(ìÚUßXt­4UV¿«è}›óŠ>ð2]ô<¦B¶YJÿ C™Ö#yMw‚d–Z©§£|£¤²Tj3âsº$J+”aC0C/Ì…¦25dŽ&ÑCÿÑG“Z£ù\6ád Éò°«rëȶ¬ëüvã<’îy Ðê>zYM²¢ƒ—^Î@%Qiú¤;è>{t!ÉÄ;gÞó®aB6EIÊÊ¡ë¼ñçã̘ž>„„IšXsƒ–I÷ˆ´-Iãàp•R‘hÛ7ïò8Í•L©š]ßùàW¥ é]‰Žâ2¡ÖH{ÐÇO~óƒTçeñ[þÐ9Y6ðŒÖê(²DxNŽA†B…Þ®²¼v«®¬¥Juጓú§çí~¸Ïk•rÐÓyS­)S¶gñÆL dÿù„2™Ot[ T[îñíBbœP)eûïþyÂŽ!¶åød0IË ¬.Žó?AÊ\QÍùh>3^îŠÈïHá–˜«¬z!»ºã¡}Ϲ.hntzµ"·È‹H$ã…`RR‹žRØ£™™ª‡ñŒ7°êsWV¬záNÁÆ•¢ÂyɽÏ6w_Ý£+&´4 œáýg›uYåÍý Qx¼¤zÈsœùwpýs^äMG`5yÊ7œð”½Ôžïîvøš[†¹ Iæ…{ΖÍøoé¶ y |0Ž´” t ˆRˆó³$Ÿê¡Ék´±ï3ò‡«JRVS,äçD”ö=~½.î|ª/“ŠP-Ô¥oI™À¶ßÌÖ /àËà6@lë–Mþè6/7—`ÊdogמC@Jðþ×eYÔfóK„~LPÙ‘ŽnÇâŠÜî Ù‹7Þmý˜²ôvî™ Z¦¶?ø»Ív˜,U,íF¿×97³€ñC³Éåv“-ÝÍ¥ÿìª ¹âM•A–Yíê¶©˜òòo‡MÅR«[D™B¥2Œ^òe¶A7¬,~ 3Â’‰Ñ™P Cx*©LPAf¨Tr_A=¥bi B‘0`¯¯¡øÁpuSåÁqMÐÄÃv®²bíH¶Ýn^ ßmr–jµq¤+W/«üD•Ý–î„äHèNC8{ù[ñ~‰ANT2}îæ(A=“·G14@²^ÇöÆ"kvê¸)×Y`´Îþ=Úär G`k±S'HpqFÿyõ™ IKÕ12'hEpÜBŽ’ŸyÜadé5T¹•š1}"ç × 4ô§”Û›>W¸å¸Î Í|@|L‚&…Ûx¢ñ}žI¬ƒìD šÇqz%ùÅè/JÔ„D³HVRxò<]\ÏÝ2<= ¸Þöž{ÂöE„vü›ú§‡d¦%û ),ö[ô%ƒÜÉô<…”1Å6>ÜÞкßw˜S¯W¯5@ÕÃE«©O÷ùòž@Ý\¸¾ôõËamÓ ºæ½ÚÖ U añ§>¾%g´Ù÷R³„Ï ÿ=5Øûå}KÌÔãµ´ÿs-Û>;²rÍ’÷«™`DòóÔ s)dßä-5Kq) ]fͨš+Wƒ9-羚<€ÒŠã NÜy„ *Géo¹ô˜4ý2jmF.=§î<ð'àí~ðo_zx24óžÓ1É9yë±bÄù™÷кäÓAŒÜ|&C‘’!¡t$”|«hbÓI÷}uÙ+^ÊÍèÐê|&¼#™ý£©’Œc "Fž‡ !l^ã=Pž¬xÅhǰÈÑzk¿PnË'Wy­Á^ùFŽ’´ CyßAà÷Ÿ¢cW!ˆ½.^n¿U°Þ¼m¼DXs¾>cõ©…ÇP¥+æ+Ô66ì¬K¡Í«›ïÌÂ9Vm!9в3à l|éžV–÷e —O`w´„{åÓªóuì÷¼- W4>;Űªþ£Øµ\Ì S²——¢½Ãí|E®¼üš”[Wõ#óû.Ǫð9ûÎ÷ø•xñ¼Ý5NÀÀÿ#þf>9¿æFuÍ®*ÜjØœ6dl}/ÙpQù2û'àEç\Îý¶ fø1­zµ3™›”0›b‰—­a‡våÿPn_ª|}߀]– ‹ëŸ~!Êj[VYhJž$Úoñœ?û380<\û¡tÕ£1:<R;k»HcZ<À§ÅÅ¿W„ endstream endobj 82 0 obj<> endobj 83 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 84 0 obj<>stream H‰œWË–Û¸Ýë+°T'-  yfO’9žsì“d”lܳ`SD‡"ilµæCò½¹xˆ»EI·õFêqëVÕ?ÿÊȦ}XÎ~ø;#Œ,×3ÆI€?¼ÄøÏšån Ë|Ð ŠYîgó•Ê?÷»g¥?ÕÓ¼²oI¹m‰6Oy]uêµ{zxX~…~áõ3§ŸYý£"í 4ˆyl/·EKÖ}•wE]AͮɴjI·¯‰»¥5¯JyV–’U+Òª®%îžÈ߸{"â„Ê8]fïqÊ&¬ §Ñ)c¢4¢_椫I·U¤ÝÁ¥éàç׿ë‡ß–¿Ì" ©d’,…ò¿ùOW·GçˆúÖg¥‘¬¦¼à<¦¡”D&)åw{Á%¬#5X/è|[·¸v_t[¢Õ&Ó+ã[[l*YõÚÔ•ª:ãaÄh2ÿwÕ/œ,¦œEìÌ? ‡¶7©y$Åš@šÔÒF®ËÈ·¾Pùœ}¶úMkEVî³Ck¶îñ¬˜ƒêÊEÔÙÕ˜ŒN'Ñwp¬+Cø‡kß:ðÜwÃÒ˜*g>ÎÜÍÌ­++æø»lÆaEà|$~š÷Ua\f°ÎöħóYimè¾›¡cØtS%4µÉq|X’ÊÓÌis³Ër[{•'&Ó»G^) žZFÀÜEh†œ.ŽaÐs™6<Ã:cJùŽÂVž¤#½Våÿ¦òÄ!'r–ú1îê7[òçãW©­:i5I s3$V¦sÂ8BçÒtÁCð|j¿úgŸan9_¯¾kÔ` Æ¥pX+/lXxo'Tè®^ëƒYyܦÓÖ'£Àff`"—Àêæ¹Ó HWX×P_Å Co˜}Ylªô®%–E¢6®ý‚¹ˆdJ…¬†X¢'¢¬qÜÚdOÀC, _ÙVbHë8Mv—«³˜F˜>.‘]ÓëÛÜ#1¬§ŒU<^¹:«Õ à6„0«0¥ç‚m‘ô·%ÿ_àåW¬‘ŒÉÞ„èùò[@V3F 23yÅT“–݌E§Oåì×Ù‡åHs˜L¥| ÅÔžHIQ†8ÐÄÅP¤Ñ'jUf¯®ÛøŽØ ›(–UxÚ7ûL¯Z r×àøsQÝ=¤Ûš*V™. àéEéö¤êýÂ:®OiÙo tì¼îËÄ·=•fŠ#*±^%è¾fNMP`˜=§Ñt ‚ÀÈÌÏOŸ7›£c&¢~Bõ½sD rµÀ:'ñzìi_æÿq>?`¤À#±—ÇF³³-r‘»“!£â§º9èb³íÜpýøáù©àÜæbDÚÍIbsú Ú¶=l’×*ý¢VoŒ=º±˜¦)?^hCÄcÃÿ 0w~°… endstream endobj 85 0 obj<> endobj 86 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 87 0 obj<>stream H‰¤WËnãÈÝ÷WÔRNlëÉ*Ù$Ýt$1Å(hÐbÉ®D*$e·ç7ä×ò;9Å*J"¥’=ôÆÄËû>çÜþô7J»¸ÿðÃgN(¹_ ”äøƒ#5™!÷Û9yÄ¿û•ÿïåÃâïO¶&7÷?ÃLF³<˜ù¿23BmíSž=sAñŒæ'ÏæÌ™÷ñÓ‚¸Ž”díj×[Rï·¶½%®ïÈÍ?îÿ|É3,“>ðcÔ>Xûm×Ô¶î10Í3%i:†}g+Rv¤²¤µÿÜÛ®Çã[Éráz²k›gWÙníob‚’;Š7QAî?â¹”<¼³$ÿÚ•}oÛúßdÝ´ñ½Ý~Ó/o²›;¥T&_窱ëµ[9塞+ҹǚ”­%øÙ´¶Êo¹÷£F?CÆ÷xc¢;FfBS¢ ²,†î„ʦÄLÆ'Ï#“BËcu:Û“¾A£žËÍÞ’—'·zòŸãµ¶u«r³y%(Z¹A¡ì·•ÝõCÒeýJÚf_W®~\Þø7  ©ÆbU¡} ]Ý$‡J‹¬ÐƒŒJzK¶MåÖ.´´¶+ÛueûJ:@Ùc¾ÈS²×èŽV:‹{$¼zröÙâI×ݾ¼ò+‘Ócô'­M®F‘å3SŒS1–¾YA¦¼R‰Fçü‚ëëýÖè÷ÜÌ»';Yý¼ʲ\<›HÐÔîÉ­ûÐÐc=Óû*ÏŒ¼Tž7VVh™åæBqÆ(c Ã6ò"Ãîéé:RÉc%m&xè1_|F:ö[¹Ým,@çz­YÁ2­ ¢$Ï4{׌2d ÔÔä$&$P .ÃREÇjî˜cs*ÏSÆ3!U‘ªU°cô²{ìˆG›> "~šÙ¦i¨E’)ŸÇ”=ããÚ³ÁA,Èàã¬4çY!±û‚f s±€–D·Ï+91ÀÿÛPˆ#6“—f¿©ÈCÒ9ã&S…œ½ìØ•…£Ppž•Y.Â*g’“ÀD&Œ—'}séÍXªðýâú'ŒCz‡s†7˜KY¿µÄØ~Åç–§¾q©|…Ê3“ç—Üþ'å¼ væo°b †²¦×ÞþŽY.øÂÏÄýGNh!ô–)ChTšwí‰G`*'& ¯ |P4‡RÉõ„ð3Êõ{‹›ÞÐý2Ž•a˜J3£ß E¦èÄâš¶-_ý’ìšÎõîàÁ‹ÛlÈÆúo®‚©P4Ó¾;óˆ®ò–€®)fV>ª\¬ol€ ‘hêlq ·A0èÐ-0À Æzv;» :b×¼ØvøØÖCŸ¦Š,Ë• ú²ŽÜéérÒ£€-[‹Eœn!ïüou lüâ* ¿ªžâ睊{û­Ï*÷æM %P¹1§Ö>J>îüˆtµµ•­bÙxÆ™f3ÍCf®¾ºyá×L¾%òW‰ É2ü8µ<øÀùÔï9"Ã/ãÜñÇOüú¥•¸êk³³mÙ»¦NA$ºàƒ@±PñÊy{?&mé:¯Ëï %2ŽÏ÷e[¢+ãq.( ª’àâg.¤U>t¶^ gÛ6^ '{Zi㑃)µWï[ !Í©ÑÉÉ2¬Àæ¥|í¢–ïãv¼¡B…¡8p?ÌcIËÄùÈŠ‰É" ÷§ˆ6q¹d,\Îé¸\\å7ÑwfXÛÔHjÀ”¹9d²8öÓbØërssÇð z#¦w…IC-Ÿ¾yjY ¿±@.ÇIÝw¾zí~cÜn·y½%ñ( Ÿ'`‘b°2Š!ï‚óÃvšµ«(`oÍð"|?s] ®ˆd:cZß¶è\2>yË!ÌËër†¡`³,{éGq¯F€‡dIE•æÂí¶vm×EÌB°4ËB°Ì_fØle+»úqX‘¿Úméêʶ˸3·Jþ–´þ¿ˆ°Ë›DüK•É 7Ç Þ§±¼Å@¿'&ohtj0_ÔÎö#ɶc&`a›qþ¡ÐÍg_9`LGõµ8*÷ì@Gâ5ŒàªËvîýÊ1‘ øÄû9ê9‰B:6"êèxÑuå6­Œp$i(Lâ˜è÷Åk6=1M¥Þ/DÆqž>|Eu ™œ<}’W¸ØŽ8®"¢9K$Žr’†Bœy4±Ãeû¸ß‚ˆ:ùcÉ#Ä^ç. n'ûŒ£.@âaÙ>Sò‘ ½0¥g8ï嘳ž˜,ÈïqeN«‰®#%˜ qcÙâ»°°ñóØ=ÿü¿³ç¥0S‹Y4ÈvC'Aµé”Wvùôñå ù-¹’ÕVpÐ/ <5›ª›èø‘‹(çÓC kv5]žæ[PjNMÞ–ùÔ‰ Ëÿ%Àd`ã³À¯Ë‡Üèkq¼W>¸N×3ç×Ô³ñ3ç*ré¾óô2`ê•…Ø´Õ¨/è¹J…Œ ƒ“¾|úô‰hàÙÍ’¦ D½Í¹”¥s¥&“5¬»Þ–™BßçeÄ ëz'2Å‹x4¤ñØoåv·±ƒ Lˆ2¨„àïT©¬0‹ƒWäòT†«l8(½‡Aqq£$TìÜû}ˆãMæ}ÞÕÙÙôÒì7•§©;Å[>p­—‹“ÎÌ˃]•˜Éìm½LC•ý3Êφv¹Àõè¯ÒƒÔòæÊiƼÆ7jŽ¯ÝªÜØïDV Ü7zÜ÷¢ˆèê×3 Lç0è@À6ø"% ÎHׄeô$ ojH2TLL¼fsk· ¾ jø°C ÓG,KÌ…â„अȴz”ą́™šxwŽ€Aø¨ 9ñ/{¬»ûÅ¢…2)-aÚx¨Â¶|%åùb"{ߣPã~BŠÄpìö-è׆“ålÖ=fÍ–ó}oüû.¨«7‰Œ l¡oÊÙÇÍqšÉÓ¨ —2nèÉJðZƒÇþ.ví…RY¿’¶Ù×x`yó»Øõîvø"ª(ögÝ–«»Pž¡(|ZF5 N}]ËÍ óF<ûåUσ wcM”DJ…ŽJÜŒ‹.†4BR©)F£¿Þ{غõò®ïë®.¬góPÖ `RF¡`ù7×NM -r$&±¿Œµ;†XþéàfB up븿‘}Ü=»•UQB_ZiN­•%娮öý¹ŽÊ@Wv’±c[eÉ˧œó3œÄ“0møx`ñÍãØ£‰¬ËxfÎw[Ë Ø –/×AfМØAÔä´‡D{[°…ÖA{¹¡¹Wö:ð~ž©€Ì¡F}º,J)«Íè)ÀƒèÏ endstream endobj 88 0 obj<>stream H‰bd`ab`dd÷öñpñuÕvÎ/-ÊL-ÒõOÊÉ,,MIYþfü!ÎÒÀÃôC†G¬õwïOáŸÛYå0þï–[À éÜfvó°Ë20¬ãý^Êÿ½FpÕN!&FÆü:çü‚Ê¢ÌôŒdMCK K ii& Á¤˜4“f`ÒLZ(8¦ä'¥*W—¤æ+xæ%çä%–¤¦è)(8æä(L.VJ-N-*Š¢»¼‚X™˜-Ûøøº}¿qèÍw~¡ï³.…~!üáûÃËE¿ó»üægÿÞñg¹è!vá¿ðÿNù®óûÆo—6ˆ®¤ƒBߣ _ÞðãÌ÷_¢óÛç6ÌáXR]8%GZÇÇ1ÄK^øÂwŽß!ßÚC~púö=–]xÃçï ;Öì—^²¨5s’<_íÌfüÖžùýт߮Ýlß&}èþ³¾—ý×!îoD ÿ¿ž£ endstream endobj 89 0 obj<> endobj 90 0 obj<> endobj 91 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 92 0 obj<>stream H‰”W]Û6}Ÿ_ÁGÏÂȤHŠÛ´YÌ`[£/ñ¢ÐØ´­B–\IgþH~o)Ù–,Óö"HÌèò~žsÏýô¯ßY×O?Íž>}„‘Ùê‰1áþÓœhf¨!³íSDÖø;[¸O“ÙÆ’çÙŸ°’UÔZEÄH'gÃI±ß¾Ùªýxä‚qCEïëˆF:‘ÎÅ· ÉjRÛ†4%IÉ{šï-9l²ÅÆýÚ*[¤yþAì_û4'ó‰ý¾°»†¬ÊФÅ©Ê}±ÌŠõüÙ½Ðlìóÿfÿ¾°K3RTvyºôòM8‰©NúßÓ(Q¼ xJ*[#&»$µó˜6$kÈ&­wü­üÒ~ß•…-úü¢yBåd† ›Ì¾[|™ÕSÿ}(Ü8FÉ"ÉFA/J»Ze‹ /‚MLšöâ'åêN””'g—·{I4µgW2>÷6]þ¹÷õ˜OÞÎí"h_½ÉVMÛºs!ë`E„L(ãjÝ±Îø„1”+ÅB!׎^[›` ’1IÎFATÁQ’<¦&îuBݧ/1£L+I^ѳŸ]X]sÏ}Ayì÷t»Ëí”d]L×È4ÅDi€K?2Ü,A!“Åɳ/ȲW®êÒ-Wš5òʸ ±T:Ô †a‘š]úö¶SzI–vñÕÏÛ¯-ÊÈ Ú× àDákÇ9j§Í vR ÿŒ›¡ãL8›6”QLrØ ¥¨Rç ~„ª†ñƒÁÙ)Ÿvè¯÷yCå>_’7òÍuŒø¥9÷åSÁâE°òjhÜ|ÒbÌêšš&±”ׇý&ÎH\Ï~Y³AëÂT&À¦g{¹1&;‰‡v}¿Àj(ÏØp*„» u76‰3=ƒ Ÿ?·H E³7mú@às94ºK„v’CBHt¼„_b¯×Ù[niÔ5ÐÆ DêLªhMe-ËæŒÔÊ!µÛ]·ÐÇŠò©Ïn¬wqÈžÅÆpÊö=`X™Ã/mŸîIJ¹wŒq\TI"G‘߀ FJëë‘`ÿùãÔ-åÖóÂÖuZ}€žŽz¢]ü.Ø—I ´ Àö–Ç•×.ng”7E¡ÐN@‘l¤3BÅT(¦X¼¶üÒ‹8X9©¨ÁùuéÚàÇ&ÍW?ì» ®p wœèËŽÜ?âµ`¾.+Ü[Ì8‹€í‡jWÙ&Ý.»Õ-(¶”¾ºº{ë¹^abB‡UQƒ )f›ç¼VyYVóÓsŸxªÄð$9¿pkq Ð=K‚‹sÿÖTé¢o͇)plýÉ¡­Ï÷Éߨ©Wst îò¹7]‚ãnCG/¸Ka¨Nt( UUno{„fÌ=tá2¼©ãäa&7;-Ày2ÔéYùŠv®«4ÿ=Í÷öÿ'_ÁpuÆõZA•ˆžÅ^ ¨ŠÁ÷¸Gö¯õ:ÈŒ…î(ç`­.Ý™öZW} µ©‚PÁ»´j0mÛò=HÁžv#ÒÉUÂ8q϶\Ú{ü› 41 b|ç…c H¯oÕŽ KH5¸Lã¶Ú§¤(É*O×­¨rM˜OöEŽ”û’Ëß ^¹âºB^PLóç©§ù®ÑõB´¨Ý¦d“¾ãúqŽ¡ÌÞÏên8íÆ'hÜ0š3s~›üÁí®¹!àu7%º5L¼aB˜IÐéøhíBéŽÞÏåî£ÊÖ—á’ôõ§ÿÏeµ+ÛCÑ‘¶:É B–ùkÇ<¶zwºu ‚Ž‘J¦±ÄáN¸qIý2{ú[€_6ð endstream endobj 93 0 obj<> endobj 94 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 95 0 obj<>stream H‰ÄWÛnã6}÷WðQ^Ä\’’(± tÓ R`ƒ¢uû’ôA‘i›­,¹¤” û!ýÞζ%%¶“l-Ãv̹s83zÿ㯜¬ÜäÃ|òþE8™/'C嬦¡õBÿ›ÝD4¤GßVUÐEÓ<És€ .ƒ8Œ®np'/ ëv}òÒŸRRœåTedŸ³ú‚œ)Àš«‘9&™ŽäXB»’sul´íÐvma[Ìzi›Í‰&"â”*–’Dq¸9ƒ¬+×R>Œ<™L<âRJ˜-ؾNq,rA…RCËóš9Ș Fw¬—Ǻ\õ ›ªÇGp \ÆTØvöíà &°\œ€„Ö“CKH2AÓ$dy¾¯¦Œfcƒa–h®¢­müÚ60÷î*í¹Y ý¾e[7’$¦Jñž¦Ã¾rWõDÚêýâqnáH¶½lœêé}£ÕÐja¾âƒ¾§fó…9GÏL±XÒ“øSl`õrõAÉØ¹.˜ƒ±…‹]00{¦ 6°ÜUç% ¿C3D4*åœ&¹”#•B#Ìv1öZåä6¯°Eö”ç$\ЃƒKØ–ð¤ßúŒÓ~ó‘>a8¬u>£+²Ùl+ü `*À ´Íפ>"ä3;rŒÛíqÍ^ׯ‘kÌaÖùŸåZýÝÝ"Z¸{ôÈÛéHÂò™¤JŠ7Jx`õ²„‡?CÂÿŒ„cÁ_/aOÌYýæÆÝÿ£_Á3*E~\ÀzåŸ$^£bÁð h?˜Ÿ©âzÒÆÿ ϲ#Ÿ´mÂJ;à fáþùÄÇÁ_Ÿ¨<}‚×ëõÎSà:£Ü{£—ÕÞŸý ±²û"Z‡‡šôõZßÓw¾]Ãöòåä®<„ ™UòÀêMô»¶"Oa}Æm^Ùü,æÞ0÷ÐK¶ê{ôî9ïžÚ¬Y­[(´„"¯>|$—Ý6¶ðEÁ¥‡ Öuâ;xòsÚÞïq–i wR©QºQ̰¨ïç“Lç endstream endobj 96 0 obj<> endobj 97 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 98 0 obj<>stream H‰¼—]sÚ8†ïùº4 ZþíîÕ¶»ÝéÎlf»ñô¢a/„ [Ɇ²¿~$ƒ!B¦“/>¤s^½ç9GäíwÍõà}>xû‘ ‚òÙ€ȇ/ø“À7IqŠòrà£9üä…ùµxS^ܶ儫Oúó-»{•}6óo*ìBŠ˜P4Ëp–ÙXØãÐÆÉB£Y[‚Ç­æSÔHÔpÝ õ‚7 ®C.¼YÀÐçVðAVl’ùhDpé~3Ñ8bjÞ–¼j`í;'&îÄøNŒoÅP‚ƒÄÌèpñOˆ'AŠiîmòÆž[KÆ&a€Ã˜î­½ïÍލï{o†ÿæÍ“¥°7ØOÔ[uï¹#J)޽¿¥¨°ÃøGÖj‹¦U “š£[¶ÜxïO¸µ’O±Í:"G)¥Æ´Ôš"’¸ ÿpˆRiÐ5ö &‘˜ÙGý¿ARò±7cKmKS­µÐƒÒ0¥‡õ-ÙÆª°5 ¶é·,€TQÖKnª0“«d…’¿ J"®”´j©µ˜,9v8Fm F’°¯î­wÒ'ƒ+Ðz'æ[ŠjþJbãÈÇô™Àîö<Íëné pí¥ý Z?{­þŸ'6KpvXã3´ËèzÄFI‚#z”د\ÉKˆb(z|bÿƒ„`ö=/±âƹŠÏ™y<¾äˆÀ=>“ä~ÓÓ(÷k_ÀòžºŸsà§éå0›Âœ%8KBœ>ž¹ ä ÈW"œÇIv„à\‰ò~ÃÚ/íœ'QçüI€/%P)* .f¢`^£˜°½n¬‚}J–;¸ÁŸ8ìÄ ¢7ÁÖšü-î"ìÄ¢…±£Ú@fÓ³åð}ØóNÍM6h*Vbj–˜â’Ï@›0]1٘ûL[óÍV×JÖJ°†ƒÑkH,A¯ 7Tdú­ÕÍ6ÿQËÊÄbE!•ɲܼ¢ƒ$À4zf+ö›žnÅ~í ZqOÝ5Z0,Ïô¢5`Û…',#„âÔ‡cÅNÜ4:oYìãä`ýþIðö ·G:ͱÛìÓ;ÇŽu_ö ºï Wö޽s­ø[›ÓøÈµ¡:W¨s–Ÿ,|ìÓpÑ´X0Sõ8ÄôtݸãìbåÀ˜ƒ"2´hKVgSf,šr](Q[Ò Ë•;®Q7"†W?9z™;`·|gªYñÍ9bzMµF¹ƒÊ¥xà–¶l÷‡ fB¥˜V7ýë…,a´Í2@gks ˜áÏJîæ€Ñ*JA=q£äÞShx1Ûl‡E瘧y ú7Ÿš,Yõ}GßGÿ`æx×ÕæQY3x%Šþcê­ ±œf‹™äÁ§Ãˉ߿n253A3ºGW‡øp†!=øIºs$ncj7¦v²Ð(Úî6r⃬7JÌ Ø^€aŸÞÿ…>HUKpÍÐø>Ýö+Ì.ÖК«Õvª> endobj 100 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 101 0 obj<>stream H‰|’ÁŽ›0†ï<ÅM%¼6Äzëî¶ÕVêªjQMz Ä!TG¶IÕ>}džM²«Mƒ%fþùçß|üÆ¡µÑmÝ|àÀ¡ÚF<†7~r|xA ¨úˆA‹«jüëwD6ªyûµ2?”Ñ+2„ý*Ž«_(”ÍB|âAˆqš3ƃeBdA§Úu¶ãиN€ûѪ 8 V9p;Çz?*Ð[¨áT¬3cãF£|ä_t@}a §B,$T÷^YAmÚ±WƒCá·“51[c“5æ­I)©˜zô–¦^®tÂÓ‚Ê2;ç™BåKež¥4òºãe(Rúé—ò4ú%ù®ŒÅè8AH W>'æSb‹0¹X³K²Ô£{_EÿaôöË endstream endobj 102 0 obj<> endobj 103 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 104 0 obj<>stream H‰”WÛrÛ¶}×WàQîH0Á;Ó§$vRw&žÎXíKœŠ‚$¤¼hHЊúÖoèùà³6@R¤båôŒG²$Ø·µÖÞ¸ýø$Ø®™½[Ín?$L°Õv&bæàÿ"—EÂå®ãàA1sدU6s¸ã8[góÌT‘æž»`ÝÇÐ_°´Üô_…߬¾bßRpœrG'`_QmÚ\6ôèöƒ×Ö° ásá»Æ.÷D˜˜m«½dÿÆ$ëÎÇO[UJ¦i_ªSÖèºÍt[ãvùÕO0 Ü$6¶m™iU• ÛV5˪‥ÜÐ×"Õ ;îU¶gi-9@–±Ž,®ž>ÏñCl Ùú¤eó|ÃòªÜ-[Ž@„°õyŽ£æ^d~â7Ë Š¹O!6’êêEm$kLW,Zà8sªç³Ú‘©jÛÇ‹ÅøÐÀk¦J–¯ÓL›¿¬~í¬g­i¶GN–ªÜȃÄ[©Mtð CÌï¤NUn,PÞúÈ)æôOÒuŽOú9üöCØUϱÕsX² v¹ÓUÏäu¯õáÍííñxtù¾­›\ž¸Z¾ÞvaÐJ"ßë"¿Œ  ‹Hîúq` ¼=¤5⨫Â[m·²¦ÐrYîôÞ”›Õi¹“C`e[¬eÝ,̽¯¥`ƒXÏõJPJ“9E¹RYš/XSa‡jX# \Ø×¶Ñ¨G“ÕjýúŒÓÐï2ˆüF^b+lq©,ÒÈ3ÂÝò\-Wø‘ ëŒE:²Â>«IQFnÉo™<èóúõ‹ªÚ†•i!™—4o‡ÈŒlorÂmÂ]›pÃÖа,5+MiJ5ÝLqQVG`/ËÛ ¨šøët«û\χŠxôp¿|zË¢À¿Ð…D gÓz>ýƒ…õžotþR勬MÕNÆx£Už³¦]E1ˆ.6¦ŸYÛNÙ©jkVKV«æOÞ¡Öû>RÇO|kÿ¡´ÕUÅ!—²›š"K0§ ›ái-Iða¥TFxS§' ¹-µ+ñ»‘ò=ðyD•°È×âž+œZ„´ˆª ][%ósRP JöÆ–.¸¤!¸âû!Æ44î\áDŒ‡‰7Þd zåxˆâ ™,ÿáñP·hºÂº0‡œZIµÛk›DJk:Šß²w"«rgrºôyˆàµÌÞɲȲßÒìOTå®NYfÕÛÂd•ÜnU¦à€aDh¼™ïnÌGWrƒQB… eòEÀ“>@W¸bè\®êt'm$Öÿ¾®6D‹Ÿ¯5|Ùƒ0%áY*Ãûm•çàY¿üܼ¼ÈFYÕYS8  „]¥e‰æòô,¤ÎÐjZqÈSMH¦ž Ä”­ú†ÔŒÎX«ÝÒ³˜HÆît¨ø^û‘Çg^"¦ øì|¹† àÁEOï7I8 þA,áÅ@Ä¢f;mOF ¨ºÈ4x„ä©LK‹tcT€bWh\Z–‚KÂa¾—õ ®uoòJ¬äyÌ‹ŽYvwÿþþñîáíã•1Pa£ˆ&;GòÇtkÂEKƒpk”þyÞ ;<¾K±šæØz sœðrPWl[뺫—j~9í.t“”ý2%Î5Åž÷„¢ëç¾? ‡‘ÞãôpÔȾ¯úþÛu£~ õmâ|b—'ü©¤Ý;éõ¡Á2j©M{er!(NVIäûk].’h¼ œô»VÂöy {v½¦ƒé0E ©¬« \ǾÏÅüAÛªc.N`nT…Ptý£¯ï@Ksµ o#œÙyÛOòF’® bc«7Ù:ŸFº Qi¨}ªí‰ÔÅèÏsµÅ¬€Ñ4¯±øÔ%d…¡A¹¦¶Kà^Ü~UârøpC;má@ÂÇß?Ý=||X=]­œÏ}ãêh"Š¢è,=4Š˜¡‚p3õ¥4Y“ëYn =$ŽiYÛÛFm:W£þ’}ÕÐC’׸C‹•¸þÜI‡ãé:Ž /°—¡‡-øR›™¬4“B§ˆv”í/³Fű„l;ª¥4›í 4v¢º¤¸p»«WAóÈZNÆ<Ø@©Û¾APÈC¢Èd ¦¶³'­¸RCÒb×uõRú¿ªHôvâ"ûÄöå H/³8ˆä5@Üu}&‡ÿ‡ìoš¨úX Ò¼ÊÞ¼ˆ-,D¢^Í=×îýûf)‚(àñü}ÉîjkÛÜ"Ç7Â<¸ÜØzõ­¬H¿©¢-ÎWÆ…± ‹E@€M˜0SËý øˆ×¯ÈÛW†l…;RÚ?±Ï_¶™ ¦Ø ……Œr'öX1Áù[>{š½[ íó\ž„áå\–˜ ‹îA…çðØÔòIÊkú(%˜ôÎkÿÍÕõî·®~yí}ðqpœ ÐádšàÑ€ÑÚ¢Hks…è:¯…†‡‘2p¼×äãÊHÛµPaÀ>?†ê/] a4Pàóü€0¸YzžÇ½9^QwCŠìÖØøÕ¸ ‰I8»çûêp²r÷<Ï€†‡wŸØûªìµ ãN8\ßÞ‚“f1ÝŸY¿7­A1MX "ž$noÐëy~þ+ÀëWIy endstream endobj 105 0 obj<> endobj 106 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 107 0 obj<>stream H‰”WÛn#¹}×WðQZXœ&Ù×¼eíu0v2È*Ƀ,ènJêÝV·Ð_óùÞ^ú&¹g²0 ëŠuêTÕá§¿üÂȱYý¸[}z„‘ÝaÅñðƒ?IH"–ЄìÎ+ñ»KW[z^‚“¯«µz»T¥*Û;Òž)TylO¤:˜ÿÊîü¬j’—äù½UÍ‘ef¾8Ë·üÜû8žžd-ÓVÕÍf÷¢låð°B¨ &üh㦭óòHU}¾ ´Ç‘´è2ý5\óR¶U½ßPísË)‹Y¬=ÇÎ3ã,ОŸÖÿÙlY4^ÿ,Óºj´w"ÓT5qfR“Æñ!WEÖÜDN«ó¥Î‡ÓM~,ï>|η›ïþº£ßä…[æUi[ŒzPá ló²3–ò˜ÞþAò2×§‡^ºç"OÉ¡+Sû¹ƒ1Si~–Eè“s•u…¢æš»ôÍÂ(17Û}pŽÈ¢©ÌÅdo&YOe¤®:\VYð >—þà¿›ú2ßóM´U6ªx'_eú;Ü=ØÀ$“­´°t²µO¡#«gÉêáETøœ„ܣܷ”ÕŽ‘ÂÃ×z²f7A@…Ÿ'vížÖä„ʣƇ\ƒ´EH#ƒL![°l€Âà·åfš Kl¡‹ªú}Û]H+Ÿ dòzÊÓt:±Ì ¦Ê´ÊzÈpmûÏ7€Ñ)™š±s{ßýº*q¸}­ú@Ž ‡ª«û†¨`ƒ$ÇüE•¦dy1pmÇ t¦š˜MhÒXvmu†]* >ªRÕ²…oDsªº"#eÕ’RéÏ `†¤¨-FâŠáÛbø$â$ð "|ìÉ»PAmÄ\›˜Ú,0$‰@îxzx 7Mœ³PÀÈŸ%œ'Ž PM•aǼ+n/ÓÍi!×ßÏhe¸SÅÁ‡3ÂVÁ è³Ò¸m+ô¡®În6ö“vòÒübG•ž›th¨ú± ô¯“ÒŒÀù{$£ÞZí³KÛ„ÉË8®Õ¥ª[¢êºª;ûyV¤îzvª¢¨^uÅÍ@XëOë Öµ›. x†¡ál©¶–ìŒwòŒùcLÄ>=r[-ŽañÓ¾íbjSÇ1æ*ÊmE¹¦‹/"šD¶˜ÈÙ/ÊýøáC÷ΔÈì7Ëtô±4YèF‰;²ìN€°'ÄN[Ϲ‹°ßsøvÁºx²FQä¯?Ÿó¥Pgl ;}¦›ŒÆaÉnZAPßÄ÷°7Ó mõ_»Î–Á0˦&È-b®ŠNö —uޞΠƒ4äpÀ„0™ïq1Wݼ5{öÒ6¤éžK_a»!¤¡†³Aê¡ fï ó/ò‹c{^ÚÕ×ë 8Ö HÕ/niè•<ß®˜‹ž™tŒˆ²þ|ÀŒÂÎß~0ãY¿[ž¿È¢Sä5/ ÃǪ+3[ÄCÞ^7–™E²>v¦Fº/þdÁ ®ËÎó–ÍÖ–-ûR=xLC¬–ѳað1Á©zãÙ§‰ÿmèyë\KÝÆIbØòi iû¢ \Ë~­òR3X8¡æ>Tjí0Ò_^óœºèƒ½ޏXƒïÒÛü˜ôGŸÖúV›mAñ~0¦,Ó{QÏ÷'hø>Øt…F^^ºöƒ´Ýi3Î]Ój¤¤&Yžiu‰e™Ú~ÀRŒ#ññí'“¼Ù2³Æ› ×AG"ëõ¬ãê嬲oÕ‚ÇÐXñX 7 ¿SÑêûåÏŠº5¤o/ׄc&ybv=ê%†FþMEÒ›÷zªµ”¼¯« yx@Óʶ[R&¾Ãžu¯A<Í?YNCÆ4Á웕ÚlÀ»®Š>~âê¹æv²,ßí^¾s«·—ûVŒ»mÐŽDÖù°šöëFAÁÈ£"\ì7™zD3µ¶©Áª!ð0PkY•Ýþù›ÊÆý5WBõö‹L?hÝMÉäafŽþ]¡$7 󒱯ØÂ#øs)·(ä@°hfb/ÝÅ©bqb ƒ ”¯:&µ%úF!ðîÅm:Ðãá§û_ï‡BýÚ¼C"¾-½DLsmBã@¥;;¯­@=¢ÙÓ–C‰ØýÙË~ìG^èvÈÍÝ¢û¯ˆñ…ie|3á‹îg(­}¾Ì×Nå—¾a×·ßüu˜˜-q’Qk>­ÿiù¸Ù !¨Xã7rõЬal c£’!åzkœ[÷Õå½Î§ ¤Hòó?“ûªÆ²¶¯!îyá Ìþ ~˜Ã q¯—AŽ]Ý4`xÂ&³ë®…!èO»Õÿ¤ÿ endstream endobj 108 0 obj<> endobj 109 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 110 0 obj<>stream H‰´WÛrÛ6}÷Wà‘ÊXî$û–8I'&Ói4}±;š‚$f(RåÅŽ$ßÛÀ (›’SO'ñØ¢ìâìÙ=‡¯ýBѶ¾x»ºxý"ŠV› Êð+„ÿ4ÂZí/ÚÂÏ*½ ˜HÉÑêþ"Xë4Û'¹«òKSeÅöf|t‰j÷h±X}ƒÃyw8u‡S{8¡˜(nÇ„pfO]í²mÚ"m²²@ðw[ë5jJ”–Å®” ! *Úý­®Ì· JwI•¤ |t¡/a'üBušé¢É6YjR!hI1¥L¢Õ;{¡lØ¢lqƒ’é€m&Bë5¤p4»Ä<¸DÍNWÝgyŽn5úÖÖ ‚Õhm³žlJø6)úDMÜÕ+ºëàPfEs³À‹¥R Ëà#¼?äz1ks>Zü½úÍ« qÀÄH„ED‘ a_»â˜4åñª?3àsB0 §gxÉuP׎Âf“TY³Ûë&KQ}€[A ¶i.Á¡`‘ÁVQ& ¶PH³mÛº+%•þÅe#oTPâS9^f(ñÌ (‹°Š¹¿1¸ Übu€r†¹Tþâk/ÂR¼êð~)Ž`3›„òÁ†w5üÃÔÔ±Ñ@hÓ¦*À IÇ_Gæ¤#)îÂ> ¦†ÑÊÉšˆŒ»žÈ¸ø:0 ´X†qŒãp„vòiv˜*ÅF8¢(z Çq{¢Ûv³O÷»,ݹ^ªtª³;í–—ÅÒq‹ã0 ùqÛöðwºAà·ÓÞt%À-›ëþînô Nf!` BG¼ß½¿úøéÍïJ|ýr yA ''øýt0q³!¨Q^öµ_rèImï„ýmø?5°§¨ÑLÛPªpD’1àO˜z†"‚b&v`³x©0‹U×¾GŸK¤«ª¬Ì,<”uÝæmªr…òf5vQŸ’)8,l?2/u\QêlÿT퇦Èò¤Ê ô/í ý/¸œöÆ8á³¥è¤5k/ vþÞœêAÈAh}^g|Zbl@kŸ4x¢Gþ§ÄƒË Œþ¼¸{ÏK™·x*î øwJÞcLŸƒ2Ç\zÂøâçä½ÖM_x=‰Ýnikàx¬0¥<¢¶Õ3zLL½¡ÑRt—ä­†é’iÞ®­©mo S›Ü}ç(?ƒK®OqE|¬Ã9A“ ¡Š„“cŽÆ 0>q]êìí’ÅFŒèäZvµÍŸ`Ô/"ލŽßçXám8ÏŠq±e…«Êb)cŽÙiÓÇ"1 fšßhØ`ú$¨ý1+²âÐ6#7p¿lå“Â㎇LÓ¢Ÿ6 0VBrefù<šðNr¯×ºQqÓqÛ30[L¯º` ÓgAe\Ìk?G# ÊwŽtê“~Öù˜íÊZÏùfAC,§Iöæ9iÚzŽñ< Ws©¡M¦óµ79»·/’áQÍbájVéCif+ˆ´“Ó¢6wTÉw‡Úáéä¦*Á —m±¶VÄ%Ì\œC ˜Udl/ݤxz)lÌ$’±Œ @ÔìÝ—\`Å)ܧ•þ§Ízr-%¦’Ǿ'}®eÀw(ÂTÏæè§€Qát‹íGü(UR Z?h­…Öø”º!=Òw˜£5X©C²Õˆƒ-¿·”êCóXíåÙÁÄLGÄàp`æ1 ‚®{àáëÕ`m¾ÖE“|Ÿ¹>cZêé0ñHƽAç÷—ÅGVÍ·FÇT|ì°g=Ä)ë@¡ cÙ;¶ˆ³—Øëqè/a¬Þ ·9f°ºÃ 3ô| |r½R´ÛR¿ÐŒPÓC<úy3âm> endobj 112 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 113 0 obj<>stream H‰|R]oÓ0}ϯ¸R\ß8vâG6b/+]ê¶AmÙÎÿ´„"'RtŽÏǽ«{WÜôÅêNB¿+A|§­¡EEô§‚Á>œ~ˆ¯™–Ó³¶eÿ=ðø™‡™‡€uG¥â¯d²&*¯%×” ù }"[=<äÛ«¦ãT7å·þã?uTK±kªeL‰hñ‰¬Ë²<@Èg3N^[ðüAƒÕn9zpÞ.ƒ_¬¦ܽ‡Óâ<6/ܼ4쌔°÷£wÉH%i]Ë*¤ÁÏ»"H ÁS+f³ÕÃèF3ј¸W+Ñ$xB~ÑAxrkù«yDI;&AvжŒa*ñÿ WŒì!$£!yeùÁ€¶6„ÌÆ¹ñùB[s M…_»eü%Í곬Jª*.ˆ’y;Rã_µÑËŠsN9 §=Ï®ÍÄ.»0¹°!MsaG;u¾âÖÌ?í¸?xX“a]ÂýÍ'¸5v6v}@͘ ó’R†Íx{> endobj 115 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 116 0 obj<>stream H‰”WËrÛFÝó+zIM‰î٥ĥT9•*3³‘²Pì”Ììæf*ß;çvãEY­rÉ/ô}û:÷‡Ÿ%{lÖ‹~Š™dëíBFLàþ ¥âJ|Ø/{ÄÏ:].„ðØúy±Ìòô×$ý’gl_eÇ"¿ZÿM^§I:M’4ZsÏë4qODÒ*XïröR ;ÔÕ“Éò†¥Uù”שʆµKÊŒmëjϺç·yjöIÁÊã~ƒgœ¬ ¶’\Aù­õ3ެ™ßÊÂ|ÉY k~«;KÍ5++Ö gkÒ‰#YÒ&¬iëcÚ뜙ß¶¦Ä—Mž&Ç>Ú‡dqýX’Âó{D¦>±âÇæ˜ʼníò"cIó? ÌÍ©Íñ½NNðãÙ´;›i‚/¹±NnrS>Z©ÁŽÐÚ!ß䇤NÚj«š‘B“g#a‡€TÒùõ:dÖ½Þ-XÏÿ<æe ¶ìƒ)“úÄnªl"–™GÓÂÛ}մߢ­•v¾™Ç’MÊ–mMÝ´ìa™´ý¢zÎñïj»mò–™Y¥ÿ¡x¸²i®J@ |¶AÈ·;h00'én„ÝWuò‹µÉ,aOIq´Aˆ¿ãk«¯}®:ç­Z²÷pÕ¡^ZT¢+ò$#åuÿšÈGžJµ€÷S¸G‘Àˆ%ì¿®t× Â5ƒ`*< C¦uÀƒÀué-Íf3ÛA*¹ÖgB£GÿhϦ(Ø.yʇðëõQߤd%Š—=ïŒÃn¥×H×YöÂÐby¿Dµ£Â3ê¸:?Ôy“—.y”WŠ•þî ˆ_­B ]ûÙEÁöÉ å èO½@c¾²CÕ¬®~_ÿü²– ‰X¯›:‚—¨Á9 KÒ“BЏbÍã8ÒSxTžéb‰$Í‘"æAêsS_E2cJzd9‘¹_>\]­<|ð–‡âØØ_ÉWŠ„(y!œñõû™Èõál.…3ÊLÃÙ›òíxPÜžtñH1—).¤¯§Ï¿#Šñ1H/0<Ÿ”:…2ÌPØÛ¼®ó ÁÍ–œ¯÷'‡] ©ùžˆ†·(»ÐàÌY<6%ßñ4¢‹=4y_ÑMM¹¢››ncˆƒÌ{zˆ&PÔÕÜå^¿3œQ®g{1œAæÕp+“â:Žè½Ïeì"Q¤üŒByèÈ ìg»i=³Ø‰@äÛ ë}œá=7ÁÚÍ-aZ…`¡éMsºÍËn…4M•šé¨e`ë%s[ö–2€¤e½Êk6¬¿¹íÅ€D2/ ¹7Ù~–øÌàé…ÆêLfðè~‰(‚8®vYþ„•“tHw÷¾Ø VJòXêéDvF2AR`Ûªe±zô‚u¬bGÛÿj–MˆÔ]3C¶_MÊ·$n—8çÜž«@_c¯„ÌCû‡“aô·Tž¯ƒ¹ŒBHùþTl0|¿<ç›ÀK]“'åÄno§Õ~¶C‰°œëC?”\+’WÝä³~j‰zP"˜È-¹{Û$¾{ëÛîÉ-ÑqCN5ó7‡Š<ŽÎ¥÷T3øÆ>¢xúx¸ønÝÃd¸Ê;pw ’(¶­¶Y…C¦¬Úî‚ Ì‡{ãüÊ 2:/W«º]èI©:ºøòè(¿×‘â;"Øiq¤Kª_j¾ƒbj‰8&(üâHÞ ¹2œJ’uù- ×D&íÙc¶'b—®–èÂ&)@V³Sea«™Ö/11ƒLUûÝ Ô¾˜Ô< Y/âž»ýñæ—ß>ÝÞ}¼[~£{ÂÀ¦²°ëu3—Ó¦¥óayÊF—ØAA9¤ãˆÚfŽA¨ uÒky¥å €Ö W] é]…µ¼Û²SuDÛ6;²ö\Õ_\ïÌ#ÝŠKX¦ëª&ŠSÃNCÍqÝ—Ýlßú £W”F.ß’ƶò4.™‰,Eu µ•‹Ó‘”¾wžÂnâFp³µ1`.£ã8ìòrLGÙ‰ö„ZDœï…ö‚„ ˜NÇã¤vy·1B.b׆ᤠß,Úg2V<Š¿{°Hbݣ̜W¨·¦¢:lSâjê&èœ]j‘uñ~ùŸ«•Ô¡æÑò¦+Ù†ÀNk³éAí³éF;¹æÐ¬ƒíöMõÔ¡‚u6µ1™Êýú87FÝöX¦îÿMÙoÓ®'öUvìQþq X?âçgÀñCƒ€ð<˜ŸØýï‚e É [`¶Ç‘Çö ©Ç‹Ï‹ëXÑ;…/Á„h8bÛ1‹4§%)•à/à&ÀžÀšà4ZûDëëÏ¢’VöbRº „Ñåu¥)3“‚"9î0PgÀWÕ`V;–¤Eàj@º@ÒüÝ¿R˜> endobj 118 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 119 0 obj<>stream H‰œWÛrãÆ}×WÌ#äˆã¹`€ç)^gSNÙ[.‡Î •Ú‚@„C jW?’_Ëïäô H”@)©-­.œžé>Ý}úô·ù›dÛöæûåÍ·“l¹¹‘1ø‡o©b©Lx–‡Á¶øZæôß—›èã±Ê»²®ÚÛåï0Õ½© ¦’L›òX8IÖÑrW°p4éŠpT0—r‘¸éñu‘ÿ’åÿ,Ö<Ÿy@&ffb&¸RÊ‘«ˆµõ±É ¶)÷ËëªËʪeÜx<>ìËœmN°u±)«bÍÊʾ+²uÑxC~ûå_o–«Ô&l!¹”Ú²åxI£=ˆ¬Å¥MýT®ýKOEÓú{»šeÕšmšú€7òOÇÃÝ[7‚’}P*¥Ýßz ’gmÑÎi–˜z+†Û©ã6•C´Ÿ~ûé§¹XA„B»dbD^÷³…¼l|þ‹u¦áVI;SW¤-h˜Ì•JÌQ’q’b<»wNYm¹™ÚŒÈÜ‹™¹ôK°•Ðúå{WÉÓV§zöAŸ)¯#P©ù.«¶Ô?)¸I]Ú~~ÙÕíyBÂù-ø™†b¨è±¬ÙcÖd‡¢#‚^$ {íF)#Žxñ€F­Ê‡‡}qrß_íq-“j_|‘Ÿ ©º:€Ç¦Ø Ë÷Q#„çLG(²MA5Ê€rFý/¥s£ tfÓ$™‘SŽˆÍN°-f£H.^ƒø*æ6mP3´)¼òüSqü¸`®ë…çmùjr®í•ƒ‘ü߃¤:I­y=Èõ,É`¤ØX]rîEëx¬õ2¾Ï=ç bµ™¤}¡,@9PYöLfyìàÕ¨ú(~ái>:d_ËÃñpjYàiìì².(•~úœ«™Z¿ FëfŽ5„€´1F“æRÊ×G’}™/„¤&VÑ&ᣌb‡Ã´ñ¨+É3´4ޝ™E1ÖtX¯" MŒ‰~«h?»]¨”@ ôršƒiê® ˆ¾mOg_lº©ÆóìÚ/W:qæÓQ‰uL[x.‚°»JùÒó&çá±KÍ0{gf4)ú¥£í5äŸ_ÁYˆ»*¶8þþ°¥huè¶šŠ=­\1W©‰/eƒ1#ëU91lWæÇ}ÖîP€MÛ1äa4^!Á2—éTpkF«íY\ýZ\GC%²b|ÁÙA ³ÁìʺmŠÎ¶S–4Nô\‚šF(¼Ñ€b•§)þu,=Õ{ÀÑhu³î±Xÿ~DàèÆ+]–&`W(|1¢ŒSfæj^;î&Vg?ߤŒö„~ñd^›M™—󯩠päü»}cÅÔFbŠc(lLm›5Ï<¼ ûTxAÑ€§±f¬™Êª 9–u¨…ûÐÉwý°¿;UZȶ”Y¡‡Ö§”ì›=q®üL¤A)ìõÊúUÍÆÂ–úu@>,¿‡Y@òÿA£$kÊn1Ræ48kâdV?áDû’P<—dÍöx@–¼¶ûn¦°(PêãôÒê´cŽŒÞÞ1G‡WÑë ýÜvI˜^Ù0m•NäÄ?ì6o˜àôñ†‰u#L.ÐÙ±jƒ¾ j´_8êªËúRjÑà-yî‚ãIуÂåW°”«ÊÕÅì æ`õ0G‡·VŸçúP¦1,t<ñj$ý=‚Ø—Lô! ÒöãËËâ~ x¬—Íe°äs¬AÉÖ©÷í&'£w0^X`QáÉõj’1téØ?TSl=Púû^!ð£Å]/㽞- *œñcZ¦íì€îê~EKxœ7-\)T®›–í"MO‡hà> endobj 121 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 122 0 obj<>stream H‰|’ÍrÚ0…÷<Å]šP$ےѲI&4‹Öí&t!@€:Fb$¥’çÍ•L€’Òa îñùîѹùôÁ"ônëÞÍÇÔóc@ñ…U“DB½êQXàUOãÛ®—}ÕíÆÛýú*ùAI;e RÉ3yf7«‰öÝø#Æ)çã”P^&£ll£C€v©AÏçzÚš-~û½vVÛv*€Û´àæà•]hp>Î_©ôs¼»‚ÉiIØùŽÑq²ou¸¡uŒ¬Dæ(QÞ«}B1v«3ƒq– ŒU X3™4:ým] ‚YØAU´òÑþrÈØÈ)( BÖïS(¼ˆ†OY·+}–ã>é…„g÷I0ïñáSt@ÿgýW—»ç%'¼ $'¥ìÀã÷‡‡+ûçB¢èRuÆ&€OÝÐ3\oöjÿ&ú‚cCrú/ÿÿV¥X•œòë;Ó4°TX’xx Š$Ža>"Rp#åqyL5{tmŲt–o’byIdÅ@T#"N˜Ï×Ê\P›çxM¡üÑÞm—xØvo ¼†µ ÁÄBx6MkìºXélYg+“«ŒÅ”'¶§ìNgûâ(H‘áUN¢ê„£$“Y–¯êHšw¸së½7‹e‹ežŽûpûîœ_;¯Z|4䔊c÷Þaæi8Ð~«gä`xAÊYE¤ü 7+d\êCÝ{`®‘+T endstream endobj 123 0 obj<> endobj 124 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 125 0 obj<>stream H‰\’O›0Åï|Š9B•8þw·Ù*•ÚKQ/ÝÀ[ÀÈ6ÝæÛwlH«VÈ22~¿y3Ç/:Õ;W±( ßßJó<ÈZø)í6U» \Îç3á¤íG´²Þy¼éÕ240) ú¶`Tlo¾u¸º1 -HÚ@­&«Õ0l® þ[ÃÙR.}6¥‹¦ÌÖ€ý¾„> endobj 127 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 128 0 obj<>stream H‰¬WËŽãÆÝë+j@ $‹ÅâÃYyºgŒ6âáÖx3íE•(Ú"Ká£-óùÞœ[ER¤Ôr:H0èé‡XÅû8çÜs?üðÌYVÏ>®g>ÇŒ³õnÆ#æâ¾… ¹çx®‹Š™Ë2|­Ó™ë¸®+Øú4›¯Û2/3–”[Ö¨º¡ŸI•ªQU½XÿŽkEw-·×rº6ã†ÒÜêpKºìÛ|½Wl«Ò/m±Q.JÿH2Åò2ÕÕQW ÞÀVÚOõŽ¥º8æµjòB^ë,V‘Ÿ?íØO.~[ÿˆÐWÜᾇÀ)…Hx&…f¯êñq–×,Ý'e¦¶K–¬™DUë¶JÛáÅ5Û(ʸ­Õ–mÝàwV)„µ¢Ô×¥×Hi+E‘¢Hš©²n+…à+<Ú0}TÈ,×¥CgLÁ%HJoJsÒãÜ`^‹ ›¶T&ȦJ¶j¥w; ¬9)U²ºAÝ2ó¬iR}Tj‹É8p„©÷.¯êæ­y·‘£Ò¶F[zw‘—Hœ^—UIÙ’*oΦÉ!ů”JÍ^¨¬£Vmó,oj†\ÓPO.â±Í± öeaBEJ]èÀ™Õª1™î+¥˜®èç„õÉ^Þœ4R dìD&¥-xã‚Z›4íKý ï~‚OöºjºhMìèÑ%jÄS©´9J^ê¡¢ERâ[¡Ê†ý‹tõ!aÓîvtÅNW·:]³S\,uŒ³MRÖJݰí¹LŠ<51ã?ôÛ[dPšÔÑJ}gIt$s-É\"™ô¤#bË\zÿ㧇ǟ¿~¹ÃJ4Þ‰á9Ü ;žïQÍTZªh^ Ü Á‹¥r)oÈäìï#Ž£ü&ßŰoiPÒÓ.)M£2 ®4}^qàÊ2õŠ”«»ƒ¯ˆåx7p¥ÛlÏbb†ÍŸJÏ¢üÃ{uØRæ¬3/úðY^§t9^À™„|Fž¼¤Nà¿“³FŽˆ&gL¼pj¡¹­IV¦è®•pé¢XcúZæÜ³0÷øËbÉNû<Ý›®µU |)¡$ÌQ¥L­Lhü±"¬’åPöÔ0€-¢¨ÓíC¾©’êì°§r±B@Z€œ!yøî".á%::öÏÅŠËP‚µPê®”7(âa ù(i䑊ÿdÏã¤)ã¨]'1„\¾„ø–¯ÈÝp‘¤t—ÔÍìmÉÙ ÏS6â+=“X•\ùNìÉøVÞ€«Sâqªƒ§Ð‘ó§’eªÄ}ÀÖÖü59´Šjz/sŽ{Ì—Ò‰ù^"ûþÄtuÔ־£ºAW\9ÿY™‡IëkU½Ò@²/äo4€ŒG%õyÇ’ 0¹ä+± endstream endobj 129 0 obj<> endobj 130 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 131 0 obj<>stream H‰œWÛrÛÈ}×WÌ#•"g1ƒÁ-NRåkV‰í¤b:/«ÔIdA€ÁE÷7’Ê÷æôÌ)A¶R.É%}™îÓ§ÏüðÇ/‚m›«7Ë«>øL°åæJæáþJò8 Y$ž°åþÊc[ü,³+ûIŒG÷W³¿”šU5ÛWµf×ËÂOèüxÖǤ”ÜóÇnÈðÝû·o¾~øðþoÖêQt…Ü“a4²;E]4ù¯zÍVÝf£ë†ÝçEÁVš¥EQei‹7UÉÚfM›f¿Ì)ÂBH.¼ ` Á…RŠ-ßÁa e`®õA—ë¼Üö–›®ÌÚ¼*_±¬ÚÒ:oªrÎÒõ:§§Íœ5ݪ­ÓÌý•–kвü œŠ0òSýp¨J]¶yJ_QvC†£çlßm~(òløÀ¼lX{_Ÿlßå ÞœËHóŸf£¯wµÖ¯l(ÛB?°ê kãµaûôxŠKñëE,<.g7-ËVk-®ÿ±ü“ áE±-Ê%A-Û]ÚNöe•¾`a˜ð@Å/hor)£èÌ’B+{:Óξ@(׆™ŸHÁ /z2‡wýúy"?‰xäÅr2ªZ4ÕEjn2YHŸ:}( ÌöžŒ‹´Þj¦ËªÛîX[±]U¬©A{ôºìö+‚n^²cÕÕ,= 8à¯!WJ*ò Þ… lg^£)ymœòB/Ú|¯Pšîu«k<.Ûº*ƒä"E€–2§¿È¢ÖMƒ¾®u–ïÓ‚mªzŸ¶ Eõ.N%‘-Æí¬ÑçñýÛk (gK3dUM/!uç¢c!Z£{ç„hi¶«]R1tŽj¼2ïGà âØ†¤lWG•z­kÍÛÙ¿iHÓ²Äþs{=>S×Ò‡"m)"Qbt”@þ@|à| qL'gªúTz¡;çJ7-Ã蘴ËL³ûÒír~v 9u Õ¼ÙUÚ‹36º¥à±‚i|@‡“)ü­ÙÔ¤‰i‹˜qÄ•<]üljþ^ðÝԼŠ̥Û¹ìÀÈRNÞüvjÔ"˜‡1^г){ÿùÝÍë©9³kDFç¦\ØØK*ä¾CáQ< AôfQÂýÙ͆‰9z‘g»±,;Í-[;”Ñ"0ÉãlvΚ8Çd¼²˜,,ú\sÙ \=²:„¨‹#}ðd| e„v.*¦R¢à9%Å^zgŠzS¶º`qÈÒ:Ûå­ÎÚl½OñögKkm«TÏJ"\›Æ†`é8ùE|V]"ãiUä:&S½ö¥±´Ü±¯°ÕQ€\·§éÓ•·ÿb4Gý³aœìFœªa¯n|\K} Ñ÷O¬¨ŽêÌÊÒÝ_÷{e»×ŸhLÏͲa–Ã@½4%0ÌĆOæóÓìŠ-ú'¨îžàõ s×JÅÃHªË±ñíï·uÓUm$8ÎöíÙ‰‹åE—Þ úÞù¶K‚ôÇv§l†[2}È÷ݞݥEg–ÞQº^Kì^1V²ßÙë±ÝxXs³YJ†›B¢ +ÿ|WyRX±²$ÁίÍp=½°£‡ëª0çËˬèhkÒ¶ÑmâõZ»t›·yj]Ežì×"B°e;ýBûžò× ÷¶ÃøÒ½²îJ›Ç p*³W“-9é¬e³T'­¤|§úU×­óÖ]|QxŸˆ–vïÁN-®éàäÈÖyƒeIB‰®H°b\ú •bò4$SŒ¤C1ÔŸ¯…™˜¥dN9¯;s€Rß” «+ºP‘æ·=—¶çPK@ëÞIÆé6ãç¸oõ_P¡=ݨƒ”pêèo!¡Ü„?±’fã3] g)-EÀCùò…#%ø6 19xzá ïç6ÝèH5Œ‡çíïßþù[glÈ…æ7NznÝŒðn Ü8ô6mÝÙ m­7¤Ù¦–¾ßKY’ÇýõÅÌéVWÿ=Sh;žä¡MÏE®BgA#8&ž“lµ B ’œhª”!7BLpŒ¨þó×§úPí@‹c# º«¤åD›èÑ…¨Ô˜¯!KûÉÆÐašW¤’°g$vºJ.ê&%ÐnêF'Ϻº&â®MC-èR™$ j†Ž¥4}6¦IÊA4¹Æhd- :¼}k% bÀÎiúçëöçaŸN*ŒyÄþ™àBXý޼Ӷ£«hÛK¾Û™Å×>EmRº&¤Äˆr;åÑTI®‚G£NA¡P-¾RWúÒ^i@»¤Òä³¶ûŠ`îA°Z¨Yv¤”,×™möøªË7G"6°ÿ”ÓôÃ¦šŽŒ®Q§ayšÊÛâèHMغ%¦l ÍwrâO³¿[¾¼^ø¾ÇOäºYÃØÆJõÖ”©ð·ÕáXçÛ8`nÞ|bo«® éy!ïµøkÍ|Lº²Ñõ^sð"SˆGž$géΔ¤C½_^ýO€¤Ï_ú endstream endobj 132 0 obj<> endobj 133 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 134 0 obj<>stream H‰ŒV]oã6|÷¯àËNá0¤¾Õ·Ä—kÓ^¯@íîú@K”­ž$ª•œÿHo‡¢+i”;ØNA»;;;³äÕNöÝâf»¸zçN¶Å‚sÂðÁ?x4‰"ó”¦d[/Ùã·ÍŒ²8ˆÈöa±Ü¨ZÕJ-L©šŽñY’ZiIÌA4Ä<”™$¢#•jöä¡4 Ãd¢ÈAÚZ¢ë¾3d'‰õR#ÒÀeÌR.ï ÂWŽÃc#ê2#QZì%é;û DŸ—F| ¢cþtR~컂ò‹Ñ‚t­È\dU©LØX4íæLv}Q†º—º¨ÔÉ”Ö}k¥ã$ÑZâ3½êm¿³%îÔ)´£ Ì^vr ±µ QjH£³ Y¡Š±on¬Èºƒê«ü¬ ðQÉÂXV]úÓ„ TFú¦’•¨höÒIj'mšZäÒöbSόКkpêŸçø¨PšÍŒ2@Ó)÷'¨ ®Nõ¤e%éÀÊŒz<ŸzOÔ³ýíz}ûUõ<†a˜<øõ$<¡É¨žLj#JÌO—¦ÌDeý×¼AæÿiÙw pùiÑD|Õ ~«ËÆsàãÄ‚O&A”§hfÿéÂîœçk©­€èSÔó]ƒöÛÙä@Y ¹\ÞËJµµl , GKS/ö—­šê¸ÂtˆØ[ ftf±8Ó_F4¼À¦Š‚0³1?²]cÀ ÌTÝbÒ—¦Änm…µ4`ßY¨äW6YNa˜Áù.SPçá̤¬ÛJÚºÁ¶ÏV+‹½qiÉ=gcÊ®ßÙ%0Æ bäx@ÌîH®?lîÈŸ–ˆ`XãTμcçh8/»q£ŸÝ›£¨,Å; Ma2…e©Éäêd¸—A †–ÿô¥–¹­Cå)/xÃÆ”ÍcÅÍW\šz”Co!’ [Óús­ ƒ/†ægóˆO¢ž8ÔZs5:e÷ý+ ½ˆ†O,ºùýfs»}Õ£^<‰£,àé7x4òql}‘Öñè_ç9®Ì™U°A9ËA~ù(=|ެDZÆçf@ƒsÇàx°ÛLÃ^i%ӨǪ–åJì1è¡ìyf8´tŸ™ ÇÀgg38 ƒ ΢© ¢SÒ\¶%7îFakXNp¤ÆËÍx‚ÌMÔKÁ\ ¸Ì›îû¯ÕqKHÒx7A4\¬‰5ÎIÇñÄ/p¼ë ×2ž/­%¼wœn?˜³7ÿzìÍxõàP:àI­.Óó­ããò\¥xËŒM‰_<»ÀdLO,²àmx.ÅZµG]îË?Ã:¾»ù…¬•n•ÃD<Æ"ËrY/¯1±áeëõNê{«JWðÒÇ4MŸÀ]¾mêv»øO€Åñh endstream endobj 135 0 obj<> endobj 136 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 137 0 obj<>stream H‰¼WÛnÜ6}߯à㺰‘"uyLì$p:…³íK\\iv—­D.(ÉŽû -ú½RÚµv½J ( ä™3sæÌE/Þ~ddÝÌ^-f/Þ0ÂÈb5ãœDøƒRN&('‹z‘5þ.ŠYD#)c²x˜Í_n·`Jý…üM.7ʬ¡9[ü†ŽâÞcÁþAG2I( Ž(—2˜/6º!j磴EWƒiRô¾H£M¤ÝYi×´än®M ΨêîŒ8¨@5@ì ß@?;sAD.åˆv5Žön~åÔª%ŒÊèœàã7°$<ŠØÝíã`=, 9§Y…ÐçC–D²ó•DWNÞuÕãàlš‘§T$= ŒÅ܇õiþÇÙ“©¤˜ôÚè•.”)}nŠ˜®^‚#Õ%€ÁĪ¡$+gkröëâ‚É,êÁ"£?ecÄÀ'p n"D%4J³ã8ã>NÒÚI<ÁZÈgx……&£‡ÂœÂLr*2ys~î1Ôö¼ùEÓ\"o§Ê»µM£—U/õºÓ­†&Ôõ‚S–±Ìe½Ñ)Þ‡ÌØqfŒå4‰Ɖ ‚ J(nBQn¡)T™qÆ©cKŒ6çr`sÕ™¢ÕÖŒ+[ÂJ¬-f]«¶Øñ/½Ì›-AÞ„†`/XDe&³1<ëýϯ Ù*×ꢫ”#»ªòYåX†ù%XÑ<~ªœÛL53b*å…ÇM†¼Œ}ØE‹â0ð@àËÖT)µƒ¢­ωSøÐáʤ@õIå4MSq²ÂÖªEvv¾NWw\Xda œªÎ‰ªª=çMˆÒAÛ9ÄÆV€må‡õkG¶N×Ê=⣦«ZÒ´®+ðmè©_üðý"Š2Nby¶ÓÐOªøÊ…íµ4E6g4ŽG–ȇðj:ÔOy,+¤ÜE•Â~(þ"= ¹ÂŠÔ )°¥5}çñ€X,òaZúê©;œ¼Kìª0™ˆÑKì±sò°Ñ(ÏÝÃ~Fã`ž÷SP‚{ùØB3LYOÝSIà ÐõÖa‡—¤°æ\ãBCÄ]©¢µ.¸|°ß®ùÚàÛ˜¾Û÷ Š §)”ýh r·`6êúÖ«U9”öôˆ}ä丰ñ>¶…0­¿µ x.if±„œípš5©m‰(CLɱ¢x$hžÊ‘£¾m¯^_~¾ýðóÍÕçË××ï¯oÞNÄã¨Ï“,;Ø—•å ›ÂŽq ɲ¯€¿yÿáÃíÔÄçh.’x ú©*ª,¡†]ÌðÝ<ýkÎ^,Ïöþ/ƒ@9üæ¾±þeÍyJøTߌN›m·¬t1yÔì;ç»7—Ì1.ÄÍwSçÊ",ìGÔØWVWŒéMýêÙñØyÐ8TÃ(õª ùÜ«ªÛ÷ÿo¸bö{+‰ÓÓ[\¯pY…•X[ýr`·ÆwØ´ÎZ³TP–®ó…½þêyÄÑ6ÏlÏÉáåøÔŸû+JNâÜB­´)ÁÝ€šÂŠ%fÂÇöHRÊóá,BmOÇ™¤"llŒöðƒ‚§º3M}©Ù1òq훡-M®ŒSµ|ÖÈ'«ç?âãÞB…]|¸Éê¾·O¶/ê•·ÞØ®í/ÅU…ÇiºíÖºÖï:/Ãéî³8áK‹Ÿ ¸nŽŽ¬1Áyà'÷}œ?Ý·Ÿæ;2/üPŒçø›ÒK{Ã,¢hòÌ3µ³öèÃýi·N¯7þ§À/›ëW?’Kë0ƒ‡Ÿ+ =»HðJÎ_bÃ…—š€»ß Èg‘J–Ò> endobj 139 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 140 0 obj<>stream H‰¼W]sÛÆ}ׯØG²#!ذÚ'G–;ÎÔI&búRu:KpI¢±ì”¬¼õ74?¸çî$@VÝN;±ãÈÁý>÷œ»ßüþ‘³Msóíâæ›œq¶XßpÁBüƒ?RüâY±Åî&dü^7a&IÄ/7³û­ª7ºaeÍþ¨mSšš‰€sö4 û¤l±e" ÅÓ|¾ø+üGîýsò/ó$àyì"À4LÈñŸfÿ˜ßñ$M‚l¶Øj¶Õj¥-[—‚mÕ³fK­kfµ±U—¿è¥`,}Ô¶3øboËgÕjÖ¾î5«Õ–O³æPlç^|wƒ43ž±; ¥÷TÊQ ó‰Ê.ÑÐ'J¹†Aœ¦LfQúlgëv¢,.2|äÃÏÑ5žs_Sõй4®…Jâ€K16vé}¨Ôf*bšÁˆÇ}À§93‡–™5kÑMý¹Õ¶Vz†ÿX«bÜà`~—ä1Ê›øøÖe~—±ÌÅ©ƒ'TЗš:ß°Ú¼°C£³‰îŠH‚°†A>¬¸iWpl'ªY‰® y Ï~ìkkvì>ÏŸ8G‘¤Ìa'}ò"òs佫*¶¤¶Õºo]av{ôè®-w@˜²ð® 1IØ[é󺦡{¿NM;—LÆaðìTõJßvKmÿ` UMV8QÑ|ä`Xý`¨·raÊj¶ÒMaË¥_ÅjýÂ]´´½ØM…m4‹Ã§yß1t7ÌúŽ%Ç…9_Ó®H~¹=y À)°v±pÛs,òݲ™,0 ø™Ùm‡¡Ë˜og×c|RŸ§ ”ÆAŽÌHvm›…º.G–ãñ}*뉨Z–ÆòzTLn}¨Ý<†ÀR«•^ui y 2œËŠJÙr]Ê{"èUÙ[b›‹Ž¹ÀX‚³ …€\çÂ7ö:ï âýˆ½óVoò~’ˆ Bûú¶}-–ö§Ž/l¹›ÒGvW[ŽŽ4— çDÿW ƒj’( ò8äã¬Â>ªJO!”‹ åc[RÊt:óÃ~ås,´S-DØO°×Å ¿;n·$ݽÆä­£ïF·M'{aÝ2D²úïÝPýŒ˜k îm {VÕDÕÜTöÿSèn ¿„Ò(MØw‡êõMŒÆIaè ’Wô„æ¼WÅ߈#¯uÜêu6õrqÌ ¨+O¸Œ,Ë?£ôv ) Ê"Ì€ó¨;…FCƒ8§xNi4täàß½Ù"örSbRG­Òk˜•4¯Öl4þβÄsš^S:40×ËÅo†c÷#dåº#Ûäê¢qãÚ8Q_ïxj%®¨pd6\Ács šŸ[V6Œ£\)e̾7­ZV¯¿õÍ‚0’ɾއòÆ4Ìãñ6¾/ŸËÕä2†‰[Æ%F•åâò°»ˆ*"\ºq2² ÆæEÛ)É@Î\&“‘O’±2XÚ8tgpkUY•õÆÍºéä# ¢Ôëy‡6!eê©uK§ºgöÚö˜ãa–c O_l«ˆ9nBQ ¯Ö÷zŽp•ÁfhKIÉsŽ+T£ƒÒ-îw­ln×cyxQ$gÇ=ñUiÁè~ã¯pÌÂ8¾¸ç!ISß9v;2 ¡ÓéDx„V¢Ê½išrYi‡ü]¿ Ý­µSu_{œÖ Д`VDqëjÜæÖ®…ôˆi·Š¶ãÖ‡wYej:¹•§xbNÕh:à&JýÚu‰°íQ,)§Õ A½Z?Û©…Á…#ùÈmN²tR¼t Ò,üxUU¡§¹¾ýŽªœððꤟSCn–ŽTžµ%Š&?ôª0)¢Ê²†tí: N½¡¬D¡Wái]I1Îõ¾ÕÔ7ÅE¤9ð–}ýDä%³¡ýiÃ>à©óØZìûä<°ÇgÖ“7µˆÒ ÅKé,Ô#ÜWúÍPQ”™YcÉäíÓϹ,â-¢àïÍaùoñ4Ì“±Ù‘#ÝV@„ò—SÀFu IøZ—-±^R…ne_I¶øœù 7Æ9SExœ—§tÎ9?,kBaÕOŽ>Žâ>:½\ì²\Ñì#~¬˜Þ®iWpP!aÿÃe7Eq°`òè;wñ"åId Ɔ²aóß?Üÿå‡.Î$º$lùØx(ñH¯ÃõE\Ç@f:øçcQSò(`-²ÉÈ \•þÄÄ©U„„ÜB%‰0ÛòYW¯ýã ›žfý±/;h„äórK/.ÁÂX ‡<ÕÍÁÒü@Ø—#Æÿs»Ë £.ÐÂ?5ƒ*ïÊ–,_ÙLJ‡–ab—<ß'.Ez-ñ#JNé5Ì÷†ÐjìŠNTB€éƒÁWÅ~oœ—»ëi‹œwbêÃàÔÕ8êA“e uS+åÉ }ˆÞŽÄ ŒO¤‚¼^Aø©®®SãÒïJzÙÒ»Ž†~¨Ü¹„¶&ãD»ÖŸUÑNvô \}¹K‘Ø)Ž‹+u$Dh~ì#N>Vó æéÈ M~Žæ³ç*kÌ9Ú|±Mw9yˆÃ{Èå5ˆ­tëÑëuÄi†ý|*¾§S}ú_<ôrןœÔ3—áìTx~E(¿ÓÎ0õ†™3ÌÐ×,8ñ:k*»»ŸïÍþÕ–›m xOsöñÛOìÞØ½ñ'0©¹<>FÞAÜÇ ëÏ»‰LžBdFéÎâ„Zö°¸ù—þMŠ endstream endobj 141 0 obj<> endobj 142 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 143 0 obj<>stream H‰¬WÑrÛ¸}÷WàegäŽÍ%$»O‰ãm³ÓMÛXm’N"! EjAÒŽ÷­ßÐN¿·ç‚¤$ZbZÏt'Žâ‹{qî¹ç|ÿ»;Î×Ë‹ï䌳åú‚ âþJð›§AÊ–Û‹Ýãk™_„AÇ’-/7]Ý›†ÙŠýÕ¸ÆÖHÙÇgïê³]ÇDŠ——ËÏÈ ‡ ¼ÏÀ)ƒÊ¢@FCœúañËk'q.–Ã.ÿ¾ü騸°¥è,H¤<Ž_&×QÖwµÛêÒþjfò !‚x<äq_[wUÞÒ}6ºa+c*¦‹ÂW ÿÔ«wÆé¶vÁåug(Ó6l«¿Švc|Áלq(Ù5¸[¾9.¯Ízmskª–Õk¦Y嫦ӛMíZúfW7]•†=n,þÜj[µø²Õ=³mCÆÙ\—ìA— è¢×"à)O)i2&})¤*ΘR2£ˆO1½û¥Óμ¯ëvTÉ)§á¸tFø~ UB1ŠÕãèLÛ¹Ê#ÉÌW·¬ñ‰XE CÏàêPÜ1 WÌÕ]…¬­ýÍÎävmñÁÎá;OY]¬ùR̉|2zŽæß6¸D{€4>4æA¨@4`“D{’/Ì×ÖPa3Pò ƒNÂŽò³Æ´­'BÃø+k|ë)Y §3¬kpÃGÛnê®Åtîð§1W€¢‡2ÅÉqò ÉPñ>ǽ}0À1¯€j˧=’Î4]ÙbÆÇó‹º#šŽ >^¢Ÿ±Jé¹öæöæÓê¦ýTØ{âíºÔ÷>ÿò7“‰ÐGgÖ5ê¯+$\º'èˆ{˜NÐq‚qa„RýÏðŠ ª¦¦qûZ€/p ƒ%JDqOI(÷ÿg æ0SXˆÅ,æƒ"n4Ðó ßêÂÏîX`ã8C§?jgô”& X Á~4+‡9x"A•ßÔ8ÂÆi„Š|C}/¶ú3ªík¤$ûÑfc:º:ñÙ™]©s³Š>ÂOß¡¿h5xFéÞ;r Nšxõ$ÁxÓSbMS…ž¯žüíÆÃ*ó8þÇLW%ºÂ!±È@H~è*N¶S)f./c`a.®æ¸#|’%“¨h&AÆT“˜£‹_y)™II(Ÿ¿é\ÒTaR'‘¤™ÐA}mm”èî´+Ã"§oooo¯ï^±ÌjZ\T»^+§süûúÑ<ð"øÉ'kZ[–¬éVŸ¡#¤Ã=ÿ~ ‘bºeOuçXýX1g›/ÁžWª¿Áâ½)u‹ümM ÁL…zj6ã5~»KÆ› fç–Ÿùº«+¢õËtÛmÖA‰Í>§à<áB±H%A”fGƒæô% Á­i ”<™î¿q9 7uÕB»šërìÁa¯s0 Ãy“ÎŽû­©Ë²~ìG·«Vº$„Šý]›~#Ø~WMàé¶ó§_Ó&×ö |y©·;ZB¤è߀/Aš‚þ Iä=>ŸÊ‚8>Ž™ô2ü®ãHù9±Í`!â IyLš[@ƒqÏ­=saýR8q¾ŠÕs4_]† œ×XœÞM T'P†ØZYŠ‚4IXÒŽ½¡êæ^‚,ž„u&ÓÕE—{W¦ÒÄoqïÊvð¥d~ŸXcÛNS½ž€WI1Å3TþèÅ#íôÁË 8z¶Æðµf4ûô¥ÝÚ¶ïèÚ¶#ÂúAÛRÓF…§w}¤'³ÐsžðsDÞlf‡4¥™Eœ'Ø"bRAjùá²Xå…(vE°™µÂXëÇ‘G¥nìL¥·¸ñ\ ª®Ò89­öìŸÞÌ– S,œ¯±ç% âl$ Ýsga·¼?ƒG¿¬‚ÒãÆúÄÔú¸g^§ÀâY™Ê;-ƒ¢å ßýåõÝírÎ'1„Ä!L“ûçEÛù×ÑN; J;yf(±f`èÀô²—L¿E¼ê×^E%NEW„Q<¼à ïƒüÈÒxüÒY‡6BhבqÕ…Øü‡ÞÄÒ‡@=¼ê7«q^5 ÔÈzºI·4jýC…5dÌìvXÑ0T<üîß"ün^q’ìD¿ßL:½,ó {œ<6Q3Ë£§&]¤ sÚ5˜Ôž&‡Ü’ØŠÖö|y{³ýÿ4Ó” þ 3‘™–ì§®üïFšôö08¡ˆëvôËèH98‘¦Þò{‡Ý ø¶Nç_öŸé{˜àb´ÄäªÎXé‘d¶œyèß©y½…8¶Æ'f眾=ƒé0z&9M0Nj?zû‡ÀŸ;]µöW3'kx …b2ÉFU#ñð‹ìdò¸äQ-Þ ãˆ];›£ÙëôLÁA®"‚l¢}}Áï¡]ºœ«—§Ø˜|N­Áb›äf‡™ÜèÖw£1´Š1¸÷ø4;xsØÃ^$Z|n~ ×ˆ4ˆäœ—ø'šl¾j¢È¿ƘÌ+rUÔü]v³;ëEí”PE¼ 86ŽˆåËÚ)Áëh‹U‘¥£+ðÏ™™¼"•A'qû¢ÖHPÈÓðYîø•ÿZéíÇÜ6!†€™ÙÔ½­²->í5t–ÔBègÉÓ¤q³Î,Í \ž+ãЊ5Ìù´C•Íd·ý3lðI¹®ªº%kôL3\Fª0Æüƒò]^KÀ,øJ†À¤L}`Êx– oÇ!šJý7õîÉÙûM åÌ?^²·¯f7µC?<¨¤¢ŠV«RA¼x…§žÿaZ‰q4üg+yB¨—»ˆt»¼øY¼ endstream endobj 144 0 obj<> endobj 145 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 146 0 obj<>stream H‰¤WIsãD¾çWôÑ¡pO/Z¹ÁL BÃ2.ŠÜ¶ÅÈjÓjÅ 7þ9ßÓbË‹R¤¨©L§ßö½ïmï¾û$Ùº¾ùfqóî[Í$[¬n¤dÿð-V,–)OÙb{#Ø_‹œþÛßü>ûçv.Ã8äÉl±1ìöÅ÷Ð { ¢Ó@Jž$ÑQÍliòÍöѸ…½¯¼Yw»øóšq‘ ‰ .TvÖÙª©r_ØŠm²š=S1gve–›%{|aþ—tó4n¹¬ü5+3á\ ¿DÄÃÁ1‘¦cƒ_üv> SÔ¬ØîJ³5•¯[×*³g®)MÍVÖ ŽªÎ†ZŸ=–/_‘ Aï’þáÛ($ó¼³dˆÖVå «gÞ²¿³¬XµaÛqYµDÊ–,ëÌOGÑַŪï+óœåž­ÊlMê+ëI;ïbQ\&2¹ø6z¦<šEZó0<åç§¿šÌ™_¬õSŒ2 žD\0´²¬´ˆŽŸÜ6+‹¿M zÄ2æjvJìœY祊]tRq•¤Á(Sm’V¥µîaÖʱwêá–wÞ¡ªÎ[Eµ¦È³êíó8{¿Éà(Z±_«ÉaÍñþa&Ù'³ó†°`Jýp;©Ž%e `Kø§^U¶\Öm®÷G<ˆuY¬74qƺuV&-GŒªŠmí’J„ŸSðMùU’ÇqÀÂŒ?Ko¶5?7Yå›íT~ƒ˜ëp$,‹XN6 Äj–H¬”Zð ÃÁ› Þo bsÌïmŸVÍã0 ÇxHHÕºWC/jƒ ©áéob}t‰ŠàRD,DsÖÉ Á.UÂ7pÈF…<û’u/M¤)E|ÍFLšPQ)=–‚§:ì:Ó—-s& *tu!’Ñ¡±“U­&­êHC“åÌjÐgzc²%’·*¨aWvÏòÉ?#5™G•«¾\ÅZž¤4F(­Ž­u”ˬBo4ÔÊ*/Ðåá–RüÂÐiŸQ)ZG&í õ±lò¢Z³%B]Cè[Û쳩‡¦9"PáÁVý·© êïÀzV{×ä¾¹ý¦È7ä‹·–Õ€¨œ 6ñ‘_Qœ’ ð%B„-Ój„ã~úÀvYþù]SÑ7†Áå‹Êô\¦"iÝ=Z’IÜåxkŸ gåìv’Y”­(aA˜pJÑežó)v©’ÁXò`iXS£H&Á”M0zʦ–!$¯šŸMžQ‚¨ÊËÌ{ä‡òJd)‹ÏíN=¶ƒ~N늌‚«-:0Q1dÌ+Ý?€+ºkÑ×{~6+öcîíéø: y‘ˆTxÞ>fY»¥O_Ú²"Í­Y­Š¼ 9‡ør[=¡–E¶®lí‹n­hPRwíjÊ&ˆs€ .ÖÕX€Ü9»Ë°dôà¬Ù¾ð›®nG/ßÞP¯ÔºŽHÍéœig jwrËM°ŽEiÊè+KÄA”vacEæÖM¿PE( ¢*¼ië‡ Ö“‹ê5¸¼3dl˂ØÙ#W˜g¶WƒñúViò?|…U)±Jb¡|úo›„ÂäÇ{ˡ؎ÒÇ Ü×÷=8“9xe‡¹vaFatFé„¢éD½[˜0 EÊ“)ýýƾ°û»»;‡£E h(ä–†IêB`>+»Å ûZß‚.CÜ—ãUGª[ÓZÝO!þC2‡ŽÜnw™+j˜ïʶXµ{cîÑhËØ_Ma<5pöØøRÄuZ]o_wÅEϺfßÿŽ¿9ƒm°¢ÃåÿApKöÄ,‹ÃÓÿ[¬tŸ|‹ÌÔv†+KŒ…i±ˆÒóAø0#ëð9AHŸÚáÒbÝ„¯QµÃ8 d2qsuëIw‚bk­–´rã5Çõc<öæÙéÓ“¶ñ¤ÔÒhÔúÆr;×Zs=ÃWÜÃw‚I+˜ ¶“½4ù¨:ïíîÅë ]9‡ûo~`ï­ÛY×m> endobj 148 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 149 0 obj<>stream H‰¬WÛrã6}÷WàQJ,†^*™‡‰ílM*q%;ʾ¬÷’`‰Ô”ïÛ~CòÁ{/²Eo’JÍÅ”L »OŸÓ—/þö‘³­»øzyñÅ7œq¶¼¿à‚Åøƒþò<ÊÙr³-þ-×q+•°åÓÅìêA—[ã˜-Ù?LílU²$ŠÝ͸bßKÃD«»ù|ù3®OÂõ¼½žûëã8Êüõ‘ˆUF·þsößù‚«LEùì}½=îMÙ8ÖTìþX®ØpìéÁ®˜® ûÕ–‡cêr÷ü›ÿ¢¬žØÆ¬«Z7fÞlóÀšÃæÿZ~ Tp!n]ˆ™ŠeÄG^ø°Ö°ÑLø\¤,Íó(m}î‘ødžŸªzCnîõ'ãmþí¬©™.7Ìé{<áµµÞíØ}]í™fWŸΞj}8àWëv."ë ñœçlÁ£T*Å–×¥¤x‰ÒÆpô¾ª÷º\VÝ D¾7],S²ë›«ë~ºýê]´c+ƒïìþPW@ÉW®Ñåƒ4å­Å>ÆÆÂåç/»»Þá®±Uë<øÎîíNûûåñdÉ«¤—ÌÔuU­G¤óö¸_™úïÆ5ãqì¿üñ¨ËÆþg wáùxxL¶É$XR›5xÍYšFDµiŽu \xÇ1¼pÑBõVß2ÄËþlÞÍâ¨(Šü’¦˜ßÍÙ±ÜP¢½åågcô@ªÆüÒ´”<À®%½¼K¢–hç´§@´‚ˆv^h‰ ¡ vmÖ†ø¿bSYÜiù ƒ‚DøK‰p^D™”ÃéYýÍ/‡ k¼H¢¸"ÜEÀ½OÕÀE½Ù„4 Oã4¸à–PdžÃHÈ%ݹºeæÄXR…WÛÊ5ò¡ÖÖ/XâØ¡z€Õ½·¶y¤Ï³"ÀËhN’ú¡ [YΔŒÛ¢2 û]9nŽ[ãÑ™Ñ/Î(Fÿ(òÊ)½z»‚{êwÄŽƒÕ–ÇNˆBER/ཉ|‘mæ£9Í·’…Ï·q&$œÒÑfÈðD¤CÚŠ$O½›¥ÆûzÇvÕ¶-wÃ𠩬´ ŒèØ“!æžá¦Iöiœž°ïû5ƒÐQˆ 'öè ²ÉDˆrA‘EH¡”8G§@¥Kï¨EöÑìžÿ"b‘*“E%§ÄúÈ>•V4Ä”ŽÁÙyŽ­oÔ ÚŸžì¨My¿=½ÒÇ%sÕÄt-sÙJ¶´´4æêý1DœÂ÷õJ…Šú; ‹˜„†S½}襗ÃÚOϞ Dã—.y7¿l磉üH…Ë”Rg\z³9øR ñ©nì„É·!Nùðfµ ‚÷‡0p‹.vJåªBúB1åˆ?Ö¾Lõ“`h Ãho¼›Ó8Žá.kdz¶fÈ(I1ØÚ7y@Þ†;,€ÛÒÞ[È­‘Æ5Žñ{v¡¾Ã+²ï“Òœðóu 'î»Æv0ÚÖ zÑÓHߦ35]R c|oK´º5öWÁp™ÙX´Oâò:¬bÃ,»×4ŒÓ1l¼Æ •„²u~Ëðå0uk\úÖ'@,ùÇ×8!0æ¤Ãéa¼¢^›%æ´Ý¤Ô$VŽÑiZÕM…D-凂ں múrÊ!gQŠœ†3xõÁýx«§TFãi–c|íÐÌëzbíÆ„HÆUwdïã´=ž§Q,Fg{R¾½àœÄ^øÛ Êa‘ޏ0_$ ®Ÿ%ÂÁ¬=˜ûƒ9ã<Ù&D{ÅUux®íö¡A2 ]öáëïÙUUª–üžSÐsš¢éÏÞcXò/;šÔMý8é©òÓ‰»3™F7Ë‹ÿ 0w„n& endstream endobj 150 0 obj<> endobj 151 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 152 0 obj<>stream H‰ŒV[¢H~÷WÔ#n´¤.ò¨´³ÛsÛdÚl:qæ¡Tf…"Îtÿû9 £N§C›Pß©óó ³¿ŸÚ—£åz4{GAë݈RäÂüø Â1Eëlä¢=<ëØüû9róD¾Œ×ßÁŒ5f„Ôfðfž˜ÔfØõݦRɽÔ] Äé=¯„bÎz·‹Ûn™ïcÆ/ÝFÛ©Bê¨JUÞ:¥žM†‹}Э&Ij0ˆz“ñ”1†™Cƒ8¸2ù~*+™ ùR¨ä±ÙãD]ká,>?=¢²Šò$Ò‰¡M0L åÚ)¾¬žŸ-¯^£ÇÕj…柒`î_w¬g†©o@@Ôø˜^:iÒéý©.¤k<úëb¥õ©¨ewv¦’t—Æu"‘ÚYR¬']De iÙ¾"-wRË<–65 ê&»´:d²Jãûô§YtD¤eg^|>e[©A4û®,Õñ$ד2TódtÏ÷ˆ äR:ÚK*– g·Š”h_Sñ}‘.oi ¥Ïi`ÀÎ2|8ø‚œó$%Z¦y¤_Q¨HíC“‹ ÎÓ´q¶é~*ó$rÄXWÌœ^+æ«×·¢A9O ­:³š4qy—õÆa¡<ÝnVÿþ’ú´ÓÍ‘{YƒêؾVò Ûâ tn}²KŸæœÑ»Ç‚Ÿßœ Ÿö’‡w$gT`q9—⃌ÿ·e×·§mªn,žµ{|Œ²qñ¦l„ FíK7œ¼«)Þ8¡¹´UÞ @k ºICq "‚Õ#+ÐìšsËða.>~ü7DÜŽó*üg~0õ¯Ö_áªE]×=Vr}œšû–xßRQw•A$i9XPæžA‰¬Åi•fƒÀ­:œœ#Õ)O꽦eiÓ-Î!pb&#Ìû,êT†þ"îysfcü±Ãò(ƒÚ1šý€ô DûmΞ%к4èû·÷­„*…òa^™×¶EûñÔ…˜ýˆ®6έ£vöÀã·†~cØ´ÓÁ~ÂskmX´S,TÅ«N÷‡ ¾VbøPy\~‚1¥ ÕìrXµ®Àã©€O'ÏY¨—°{J©È_gêÁ]‡&#«õè—«u£ endstream endobj 153 0 obj<> endobj 154 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 155 0 obj<>stream H‰´W[oâ8~çWøV4í\[:ì2P•töaf…B4»$ŽrévþýÚqBn…•F¡Äß¹|ç;¶÷OŽéèÑÝÏ1€À9Œ 2ýÐC:4%8áHGúu¼‘,ɪŠóïèûxï{Aèž 2@F@š%AtœÜAY–ÇXüåüNMî e¨Ǫ 0bø(w~ÒÆ;¿uQ—¼j-¯šrWŽy¥(YÒbÜzUxOœ¿ùbÍœGažêbö`]ƒÒ”‹¨Øõþñ÷ÄAZüRC¸m¿P /ÜVÌM¹«¹]BÕÜ„¨VV´ô BÅÆÖÚ¢{$þÉl¸AZ9•k§I’<΀›óв´íõ~n– oð†7€Ž€¢™’¡i¼åY#XL}Áæ`X¬J¦fØFoXöl;;¹aLëì‘hd‰ÊØPëµ7°‚÷ ¥¸mÆ$MƒÝÉH›Nî0Æ#£¶kG²“„$)Øg~úSµ)(™Õ`ØEä¸^ÖËJgð.ôÝ=û-‰ýÄeО¢AÙ¶Z’4Ûîƒ#Mæê…ÍËúuemgöb¹X=¨”»­±f­ÿ\ æËõúE¸òåa9¶+Vío6]UV_Ÿ…kÍ×]%^Híš ª»ÉwIèn¸P¥ù°\®g´÷é®OÜÐÏΛCi‹ûø:ŸÛ/ Ë#¶+z`ØϾس?Änž ĉ2ÿ# ¿'ÇkúFÙÊF¨ðC÷£õDÍÇÌ/ X{É>§¡Æ$¬Æç4s³<--” h  *’¢*Å•3Î7®Ö›ç„˜­wn³’¡ôÁÉ?KB+‚[I‰³üƒ›Ÿ2pÈ#¯©¡.oüló„ËJŸMæ 7üH§—š†¤)JeÍÚ¦œœgôO@ß2ðcìý˜€ÅãW0#ILÊ™ɲ&Mî4M“ÔñÃé p ?õ“w/•;™ªP—L³•îX-HÙÎè?Ó¡*§ endstream endobj 156 0 obj<> endobj 157 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 158 0 obj<>stream H‰´WKs£8¾ûWèH¶‚`8&±3å­‰+“9lf –‰vyxA8Éþúm!ƒÁÈ SS[)W ô©»éÇ×Ý—_VÅåä:œ\Þ„Q¸™`Œ,øƒþMq`(L'ŠáFËœÚ6 _'FRVÈÆgá_ppMŒ1Aálb¤ùºJ²-yþ/Z |*yœuå#ßðˆfëÞÛ;,Ór]"•>å–Eœ&hG“Š•gز,†¿+hcÞŽ%Ï3DjÍ` ñˆ×5´+uÍ¢e•>³Â|Až°½\÷9¸ÝA]=—hSe‘ ®·^ÂÝäé–ìg°a.À ã.lßÄÒg|Ç×C#¼“ÐE&XÌŠQ7æoÛQ¸Û"OW¢àY<€ |Q.² ϸØ­ýÄE¹¤Ë±HSÁwcÓIÖ%Ï¢\‡þÁŠ|ôk6ʽ_óˆ&ý$ÇDf9ül->ÆÖ(ÉwômŽ-êqÕ°Ê´È*|› ’\ ^æEJI/cÐ÷ÉHîóWM!èß*š‰±úXJy¶Öˆö?B/{£„|ڢîhÊjã«t€tø*ੇ<ãàÕ³(h4æó,>AΰtîÕœUÐä»ìÈ™jZÌIô8Ë>3« .øÀ—Úê~†Câ}ÛÔ¬}ª^¿ï»Þ¡ZnéÍo–w³Å—E¸BQž•‚߆u#¹ìëoûØG®c:®ãÊö ­š ôüŽ@‡’öo¾4Z•«¹ÁÂZ<±áµQ}眒é˼§Ñßl}€«rëÎûK½´Q·-ÓdmfÒ¤‘Q•2öØ>ž9ZÙ½4klêÒ1éó€‚È®¨‚6˜¯‡ùç`ˆîêñz5‘¨2i4LPá‚Mˆ=È1Ò»>\ÝÌ!`J8F!WsÏ9%™ô“wƲ’}ï}=S¡mÃzŽˆÓÎaC—>`Ô"'Hð@ýÐÏ M ¤³v,É·)Ë¢|ÝŒ’‡yÏR9Àc.J}ø»Ñ„®Êor Œ·¶H:5¯ÎUXúSëG)f¤UW´íŸ]BLÒ¡geãì~ö™ÆŠ1tÂÑúTÕïMy„J‘4îŽ ¶½ȉ jˆVk.dx Š.oƒýšá«5ÇÝF$˜šØõÕ¦!¯Íx°“Ô`˜¶Wc[5°-x •«)}û¥¨}È ,…›Ž÷¿)x2X¶æ¶ÒFýP2],‹yÆXÝr2Ø z-J§³°¢È ôu’J»Ÿ‡0ªÇ`¿á¸--KùB×;_¹xAr§k ØáÍ7šn%~îϽ-ÚOé[KR^!pp|ÁÊÆõ^'%ÂF΄¢l[[QU›AY]¹CŒfÈ8,»ZºGªi4’:D8ßû7ëçðÈ~ȼõž:Rýãò«Ú êÒ ÐÔFר“±Ÿšì‚_sqª.ªõ|Ósœæ¶ü¤}ŽÊͲàñ‹@?ŒèÇZ\ß¡›¼Ø]ˆš²,Ë3Ï.<Ï3]ã*IP .¸;h|zK]<5ƒ g®áÖ.‡“ÿj£ÿ endstream endobj 159 0 obj<> endobj 160 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 161 0 obj<>stream H‰¬VÉn#7½ë+êØ $šK¯Çì8ð"ä2“§›’èéEèf;v¾>Õû¢–&CDÖBÖ{õŠw¿38«ûÕ݃ûÊ1 ø‡_¾ HûdEሟ}¸¢„:Ž€ý_«/ÖîM&çX½Þ2J©å¯ÿÜÿ‚f[F0Ô§‘…ÓZ°5µhmµÿi´í޶ù°}–E¡_¨<Ïr8É4Šuzlm½Á®ÐuEÚè,m œ‘ÁY…ZÆð*ãRí>o2áa…+ÜÑ¡Õ[¨ÎU ô³´ Úy±QXõv†ì¬r9ÊÊÝnŸVEªl²T¥f½YÍ2QâqÞTRF/eaTÌÞ¬·B",ÞÊ O*üŽWTqªà#t ‘ -“o*ïNÑûöI¬D¾é¤L0EÃJt:]ÁJ)cêDÞpÿjš«éúþÀÝÁÅ›Á¨4RÑbæ¹ÏRƒÓzß=-=ý†ž>xl‘€5ü¬òjÎθBÌ¿\síéZÓº€‚„kœŸù›ØŽíÌ{¤7ÎèÁ Ø ?|¦À“ƒÿ&Ãï(1»¨`\×!Ψ£ž®´¶Å^g—-õ´Ûí 0¨Ö2Àwì- |¯¦A=ŸRõ&C3Hl'웪´½™N(SFvi›^½HÛš¾§‹2‰Yd¬ÿ®š ­k8Û€àãœ"i$˜÷³ºè’z_±<+ñìýHBu¾ÂÕª\ó 7ËóÚÚ¾C‚®[ú1-ibµE-Õ2Eõ‚kó¡ÃãôÆxÂíìÈèZ5*ôñþ& <º§ÞQ=¨å^B—V2\ —»(™ãKeß-p*ƒ—ä ÂN'µÅsV ¾ú¨MqÁ¾1õâ¢ÜÀÒt½ªIt‚sâŽEéó œy@‰˜wÐDʇAÑ&=@p¤ßD¸ùý#¤½£=2Ñ $ñ&ûÿ"DYÜ’Eú€·©ß Ùd~, v«™Ñ§ÄG ¼›È°ýË0­M4ó¿ÍÓ»Ö Ô€Õ Üž_¬?š!Þõ0~¼ÖÑkZù€ú‰Œ²;ïê­ Ügç÷\O¾Zá×5<}ü ÷Y~ÎòöMF©KÖ[×u‰c}ˆc¨‹JKUþª"²|R‡y$&ǵœz:íö«b'#U endstream endobj 162 0 obj<> endobj 163 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 164 0 obj<>stream H‰ŒVÛ’›8}÷Wô#Þ²$.†Çdn•­ZïlƵ/“<`=J@ò‚˜$ûõÛ 0¾Ì–Ëe·Ô§ûœÓÒÍã3}=û¸™Ý<ø@`³›¾ð#^ÁŠ$n›ræÁß›læ¹+JaócæTŒ U¥"ûÄŸo¾Í–Äõ#?ü¤¸ÕÆzaèëà§”"ÍyòÀªTɪž/‰çy ç_7¿Ï6¿é˜ºY³lÝ”[VÙbc†ìeS(~(x–*.ЕFpó˜"⮈V"ßwS…^ºîBOêÅÐ0‰M½=tG¤%{ȤxÂ1™^~Zª†qµJ…ªMWµ³kD¦WŽŸ•2o V_ê³N×@½s¹œœ§{!k…íì"ô~ÿ4œ©ÑïŠÕØ¢hŸ±æ{‘º–.ê4§`ûq;õ"Á·Û‚oŒ9²*ÓÞÒ¢a–O |vÿóuJÑÚ³¾Z@µ‘ç9óߥe^¦Ìc¿qöâÈCÛï°Ÿ¨Q“5ð®e$Ô%þòérJºZ¹^0Mù”fßYw,ãXµmÇèBwÏ ¸ÝûViÉ”îÇ;Z*¼`KÅK¥öÅQhi¤‹ùÒGuûNÐYäªÑy;͈Èt;ؾ³CÑÔÆ¤Zê–®Q€üÁªÞÆ'¦ÀŠíøÏëÅ¥[gØÛ L<è®ÅÑý¼^TÅ…Úu˜Á^"YÆ¡F]êydàú¯ \ëè(ö\GÛû º -Þ)µlY I›×ÓPOvE[Ûž]Tc›–F. ãÈÏW@†Ià’ÀŸJÒŽhfÚXUúŸÈ«jÍ¢$¤Õ¾)qÕièxò—)9Ê€ÆgÆNž¬3#³ÓßɱHÌ„:VÉIÛ*Ùˆ\÷Yî,¤èÆ âúNç陥Z@VÌBœBÓI¯sžƒ´¨%X€½;»ìV …Ãçx,Na™ò–J.QÆlß;kä½dàê³ÆñŒÉù(> endobj 166 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 167 0 obj<>stream H‰œVÛŽÛ6}÷WÌ£x¹"©‹õ˜Ýµƒè"¨åà7}@l!¿‰9ä»K+¢7”—*°“©h¢´ žìæ€1CaŠ›Ýç™_5Ð`}6Û˜IyˆSÊÀÝ“IÎÎç|w8WÓÆ­¹qòEl/ÌÜivvMŠ#n§ð§¥(Ú,¼90Kçg éTiW‡ìdk™g†ÑÅÅJê—ƒÐ2úÔ1E¼¢ü(TµuËŸ±9¸Ôº§¿ËX Py®{p‹ ëãZ|ÃYǺ,FÉž*ª¹Ò®x—$¥·2ÓäÅÖ ·Hb8F=;š«x/ NÓ<±ù»üºäâr+µÌöàòït]>g¹B…A’gfUwõ-&j¨·Ñ ~]o/„†þbç ²ø9EJà nWaÓÑ‹º£ úÃñ]^÷´É'2YŒt¿Áú *¤•”ž.·-O[&fJ“UJn³à6JÅÒÐ…oBåÅ”8ä¯=}Øð¾ð¸ìXªá—%Äâz®‡y¿–Vòpa\ïXbÓefpÇXÅXõ®M)ï:ã¢b–÷w›Õjù‡AÖ–òd&>lÑæ³Î9áƒJbxùøðþí#pÞذÞÜ­—P¿tò7ñÍz‰Ö†‹ª >§ |Ç#^¯…Í-¨pSµ¡Êl+v2CÛP¢(SÝ6?Oÿн =ж|?Лºˆ1Ó®ôçÞ°)„ú¯€w¥ÜžYCCI£µã–d=0ÍsÀ+ut½°¾Ž¯ÔÑeá§u¬:ßXoÜ(qäq|E}¢ƒŒ>¢`/°ãxunÏîÏ+ì¸KAXìLŸ^½é"6DX­­œ÷üíŠÖÄŠWhŒ(ô;öOÓuZÍãš…A½°Î}´²:·]mbõ÷ùñ_%÷/>M“O3x÷;Üçê˜×/ú®ã“ÙïûÄ›¾MS¨À…¹P¯bKÆ™z4 a8 ;õªËhò¿_‡ endstream endobj 168 0 obj<> endobj 169 0 obj<> endobj 170 0 obj<> endobj 171 0 obj<> endobj 172 0 obj<> endobj 173 0 obj<> endobj 174 0 obj<> endobj 175 0 obj<> endobj 176 0 obj<>stream H‰lU{XWŸI˜I@ a°Mì$*Ú ~PTÄGÁV bÀD ­òFi@”‡DlÕ–-*y(F)ˆ‚™Á*EKw±ú¹ÛjëvѺV=ÃwãÇNØÝ¿¶ßÌý}sÎüι÷œsϽ8f'Âpw ûH³B37(k‹15ÑhS¹óJœŸfÇOŸêVŠ*Ç©ñNâ kqu¹œžþÖA9&Âñ¬Ü ,C¾159%G='þ]µÿ"Oý½'ÑgߟDßI\8‰~“¸H˜µ)Q½6?;'1#[’Ÿe4d7æ$&ÌS«ÓÓÕ‘6ÏÙêÈÄìDc® ýß1\x01Ž‘8fo‡99c3¥˜'ùØR¶ÃV8akí±õ–‚aY)Љ01æ…qøømÜ*ò¥ˆö‰jEÑââ$q——Ýz»vb1G “¡ä.²¼C>“8Iâ$ãÒiô‰½Ê¾À¾Ã~ØaŽC¸Ã!‡[Sܦ|6ehjþÔ3Sß8.v,s<éØãxßqL–)pšæ´Åé®ó4çýÎw\—8— .CòUò#ò©©Ã® W½k›ë?èùtýÐÍÁÍà6ì6æ6!“A t•çÉa ÔQŸò!ü]Ú‹¤Lu¨‹¸L"Oè¢ç’6¡‡”Ú~¬|;^‚M`¾%Xroò• ÌP‚õ¦L`ï ʉ‡¶?Âu“ºÅŸ5mA˜ä+ð#¨›OYO²ò‰h²åÈ}Rˆ" m©#©ï@Lî@óuc'ƒè(Ìú¯ðµ PCÉN—4Áͯ¬¸¦ÛPþŠëï«ån²Ôj€ßCÄ__°-‰¡Þ@€Õ•H¸ŸÜ{Eàêþ€û *èí«/ò©Žææ>å` ›Yùw8Rüm79KŒí íǺ¾ìxû‹ÉÛ×*Í„õDÙ›/˜ M­WÍç ¶43'º‰†„¸ãÑJÿ˜èÈÄšÔºUù¡’ÏKª[Qº0]Ñ>ÿ5ÇÖžog¨‚ւꥷdgfj•1±­ƒw»ÛÎSÉÞ/ÄÁ̉ùMãÓi¹áQÈÓCfßB×| ©ÿ1pW€ìü+Ë3æ?՜~ž+gtdca™s~’){bô~‚éµ'·Àf+dð§\xœ‡ÃÑoÅü6~]0„Ü£Â<"ˆ<ˆæ!+Û‚aFÒ|äÜŸz†‘CÿÙàLÈ ’Å¡óUI³(4:¤A:ˆ@4¢á!°L /À‘ö$Ñb€”Ê€óÒ‹ô鬿øÄ͆´Œ¦ÌŽ3­'Ï224kü'üWÞ[ÌWŒ/¥õ&+þævw®­2|‡ƒ¤»¡—¾XösÂs=eCã*e^ÞÞ=ùªEÆdïiYúÞõEй'ÐFX«Aú(£+£wJ< Ð äàk>YÊ_ÜÝÓ£IÈAÔiÎI01 ÑÃ+Â¥²rŽ?%$ä¬øÏ…Âð§$h[4¡•@paÝ€‚µ'‹ÅŸ²P/,Æèr]0ª“@¨ˆWº/?P4íj.:É ¤4†+à Q1ª`V2ø}ÓÕ{wb—l/+ÜSȧ- þ,å à·„ts.¼¬œwe·Z¨>æÑÏ—5§f¨çæFsÓ}EËÎú’LG¶®m•r•&'uªfñuí³ÊGæuÑ1ñ«Õª½Ú£$5ÒÔ´ow£ªuç¥ ­"äcý¼ˆ555±L¡¾­Èî*­U޾¶¡ÂxÍÁK8ü,»Õóz=Êy,‘ Jô†øÔH$Ä-âM4ºR'W)tÅb¡N˜„Ø÷B=ºêr‰Óç'1 z†®IÌ;‰s·,åG”ÏØ°Ð pÝŒÕá5&­ªDKäõ»uP ] TÉŠ8ØÉ®O>ÆBíw‘ê%ÅóEüIúj°ä£ðm©ÑªEk5óÑ{ ¤§ðÇ õò÷á¿ü6ö‰èõ‰™ª À»ÿþ°SJñ&souWežJe¹©ÂÄ|UU¾ÿŠziÓºÔÐ9‘1-—s™Òê{뤽 ×Ï(;;ó“ëTUù‡Œ9 ™)—¯æðç,t\óå|}ÍêÞaÿ m­&úIYQú ©Oþ;›ÀÁ~6™¥^ð%àMÿÞš\ÍPc­5ÍS Æ Å¬"f­nÜxÉÈP/¶ï£Xxw ¸0à4toDE‰‹Ú”ê[õ병ÃM÷.é#j ª§ý—4ú¹Gž<ý籎6­ddEW!¤*„¼Û³pVÈûx@ÿyÛãˆ+LsZìÑX%/÷óò¾æŽ×o7XZT¹»"ÌÛ(Ý•™V–¶»´r·2*r­p¡Pë&bµR8oò è »I¼«%OCö‘ÔC!7 ›·S]õa5¥[¼£Ùg7®[³ï®ëlöžx„.Š›J—|¤_5»PGåP*•&WDá1Œ;äkÊ×Ä­H¢ï)IçMÝ"t…)1Fss=kw×™Ç}Ïa̽Ïsþ:Ï»~ïzë·ÖúíðFXN40„ÀY²pýJ58ò] «‹œ’“}öhnžÕ‘SûÏžÖn+ØrR¼;uß4È]F½· mj®¿å«/Hyù_•”h9e"ÕAÒ–¤Ô41).b§NÀßÃòÇêÂs»³ª¥Ú¬²èÅZ®¿óøÄ «ÒÅ 11»– 8ÂÁA]S›¹¦L:•ž»:QKII7¨®7*6T†~M-³"Ô/yŽ€Çg0æÁˆ†»×štÕ’‡âB泉Ǚ‚ea¹¡N…Zœ€S¿ÇÑx¯óô7-¦Ù èM×Oép p™wï{#OŠûã¿X)`ÖûÅ««+÷d—K¯w=@­œÉo NŽçFOÏðp¢©~R¾3ê’tvua€‹ÖDb$(Jâp¸;$ŒpFî?Ê[øTÆáx"ÁeÙ] ŠåŒP‰Ã |j\#wõ^²ú„ &ÐuMîÒë ÁƹӨŸ&C.A;Š3å=Έ‚jÌÌÀ ¢*! Gþ…å<ÁC2ŒG;65påfY@W`éZ˜–í/o¶Ä†WKÓ ÄÉþlEøœ¿S>ÇÚÓ,ÝÐþ>:CÔíÛ'ò¯Jàc–Zhš”Ê`ÞŒ×m‰·¢ï"#wa4@ô=‚±ò=Ó¨Ö¼€X ó~·NL\çÓ„6Ó•ã¦èÁ52¸õèþÛ{]¨:KE¡‡X6¶#äaèu«ÝÉç6©´ƒ™Ûur³·a&™ô¶8ù¾QïI‹D<Á™íé)‰hš^ïV9iدˆ“‰ÙaÔÛÂA#°ŒÞ<”`™üÚ¨·ÿpo;Ÿé¡;¶D§èkŽfÑûðÐÇàXù¢QN3%óý58‡0•j¥ aõAæb™0þE ‰bô(9”ï­òã|K•í :›ŠJSÜAÐB TC¹q+s[ÉQ›6þF¢*#Š»åü‹! õ8Û'ÑEîÞ•µësÀ]”?ç‘›…,Ú¡­-÷œax^@¯¿ˆ¦ÚŒ#pˆ>x ŠwI±ã/ùÇ‹øõ{!—ÚVãÀNÝv#§±\Ê+:\Q¡•m?Û–²y¸(a^V°€ ¢ õagèÚØûÙ_Ír^H`5…¶~g:m‰O‚zWÔYµzR k{u·ðw"ÖüOí£. ïEM©¯ÕNeƒð£¬âX #ÕÕu;¢ò¤ö­OÕR"Áï­…ùò­…kß›·‹ä0öOI2@!Žpç,¸¢-Ôÿ™'ñUúã¢o‘S†ï«eÇRò/j¯µ]z*Ò#—ÒbÏK\¥ÅdÌ a¹³‰láŠÐœEŽš;Îm|תc™W¼¥;, ¯ËV9›ö¦¦jæ/57ðXy˜È%ZtÉèGXŠUÎFµvfÖôZøè¥>þu^Ô˜iúýÁ]iVX–ãRB­æLªd m¨Æf¢ƒ©•$¢¢Ñ7(k/ÌÂÈ”_ã-m¦Ç{ÄDïÿ:I\ZœÙdÐB¨î”»±Šñ¥O“N\U~e“A¸ÔšSR&Uœ?ÚrM T®uJ,Ñ„dLVz1â¸vꤞ›¡ãäXô6Æ¢Ë<#˜,ÿSMgJs_ è*°ÞýÒÛä4'èlu·^é2êäŸX½ÑÃkf¹šû­"WæG‚árº‰B\SC×`ì§.¡ÑæHl¨$Z©Ô69RÍ€ húÿ’AñȇÔâ:Q—Ö¼Q5pmé:…ÚÜQ[©…¯qä2Ð_Í/6¨¡­ˆ{êU»•”)ÜÃ×_,fß}­LnëFMS#—®ÔÙ’©°-ø¼0½@,K]rÆU˜ã»nM”ÂäuÜÎïL;-åoÌŽ×&°Ù‘aÙÔ=¸‡º,”¸º€+³_}Û^Õ@D.ÝÝE7W·`‰ŸÎC˜UQZp$ïDŽ”Á°§V¨®Ü¾­Rz—ÁSBg†æú—ÎÕ) ȃ#2÷GÛÏKÙ Â !÷°\º1Ç]†,W×Înüª2† `÷†€J’mG{Ìtõr2€MïG ¾<ÁC´Þl€WªÏ(§oðk ³6Å;ÈC@ç(`Ú¾ëxê+ +«$_ª99œ-Z~4H@_æŒcÁÒ4}·Škšÿ/ÑzÏMTÝ·%žJ;Ë0#ÙÖ°9GBœÆ O™@«N¤ÃìVÛ™¦2JÆ46 R(ö¾3Æà …O?kðý„s¾’)Q/šFÕÕ+ð3uÅõü†&ÒÛ;M'è"öŠ–VžL44h÷+éfñKœ‚ÃìPÄÁíh 3»{ η‰Ïã+uóþæÀ 9¤˜Ú : Œ ªˆj´TŽ(üÞøû— 18h—{š´#}÷ÚõÚEö´o:íeÅš`tÒ/ L¸ÌÖ|QêR²};õdj05f%YF4%Ð@mP«bC•iÅrÝAliœ_±'õžÈŒw¼ó L¾~÷T]…„CÙ‰‹qÈÿc‡CÅ-!ÌæËÒzÚÕH«F1ÆÓè`ù)ÞcFO»ÙýýÃÖçðÉù?Éæ™k&Ü<OÒ¿gÒf6{5õ.ZÍö‰X,B.Jò#³,’‰;ü­ªm©nä.‘%LŸúοu’`£Ü[2áú¸C¯RȃÍ,´aá¿LWmPTe–ðÞ»c$×Û«w›ÌœQ'g($K!@’”ä"Ÿ¦" øˆP2 ".®ºÂ~‚ˆÈ h⪫۾™Š³ÆŠÀŒÊ¥ŽÍ¤;ýÑ{sú{ï{Îûqžó<Ï©p¤¶‘£=í©Šˆ;éxÆza¬]6‡ýԗᓽ^…ñc£®‹j9{$0º|¸âªMºqQኊLá;vm²Á©-[Å”^¶è¬B“¹Æx\{½ùÄå!ÍËbˆÔºLµƒ/dcdP x“NN\Ú¥”KkÏ…Þ™ÆË0¼˜Ç´”0 g0²úÕ=gÀ ®û<Ã??—5´Èú¹JWH:y@#Ey%UöPŠÊ­¹êpÉO°¶Ëç6QÔÚŸLÎÊO|I˜h+u~cMkÛ·ïÙ&ħe¬ß¨m/É4Ç kr6ælÔòƒ–·$›Ëû‰§ká×|¤Álzö«Åÿvç8 ?s‹Fceù~më–ªô4 v¸wíï¢`•R<Þ);”êíçxKûÎ 9b}Avm’¾4gu¼–wÞÀ1ÃØ?^GºöqÏßi».tv}®Å}J)©õ¢VÞFäéŠá ñh%¼•ò‰àL|óé\ªØó??QÚ¥žýq(²(Dý68æ†7 ÀŒ^± Ž ðF?³Ãï„bðä«ÛËÚ‹[D~p85¤#HX±>y=…ç/ ñ¸LôXЏ§q©-$eT¯'OA C÷AÏ‘ ß[Ü÷|ôÖŠüÌÈ~!Ž¿yŠÝ’•vùü£®8¢;TZ¯jÜ‘¿?[˜"}¦å{A…K%˜Bq7E’'\«9¾ý/˜`iµ ÇË3 Úñ‹ûŒ‘d;´Ù³4:äZðSG ¯ÃkæW¬nV(=tHóó£ÚN‘wR”w^mÿØT®éËØÚj¤—¬ ØdÈ;\¤ý!É©¿[®âG.èl†¦uªšÕ;Ê5!øZYz”t¸=I¼&a±p[¬Ö­÷ÞžÝÜÇ¡(›I;ñàu¹Ù÷IF„—¯¯ËÓæšÊÚZ4PJ=A‹ê0©k9êx&l·Ýýµ¹é†ÂÇ_)ïâ£\ЉBÅá.¤çfw 긄Ը5Ë„¼Ü½¦mαmm8¥üÅj.å`Ê™&È…™Ns»Y)]r()gá=:’ÜcîÌ•°ìòVÄ6Xö¦zÝ/¹C!tàOC¸Cý¥>ˆ]ÐÄ$³ØvÅJf&Ð 7ØÐ žŠõsw&÷­ŽA FCLƒå¸ Ry'-S¿/ æ0BÞ ³`.ã$¸\úžEOj5'Ç\!˜ °0ç0üa("A ¡Fv:ˆ A‘–¬[JH>G!ßÃ(DP[òÐ}Ú©‹ÃÐFáicnŒ‘n³…/æàBº'zH` X°È¦—çôP:ÒL[h/Ì–æc0È\uiðûà(ï3qÔ09²€"8N—ˆE”+Wê×™z4ÄYw= ¾"öwí¾gÕ@(×ÓaêÖ‹„K¬Œ.Ýœ¨*ÉÕmÈÒàdê§ sÂ2Å8ΑYŸƒ~ʧ,ý†º\±!ñZ©µRõÿ]N*»@¹ÚÆ…™ OŸ&s­ºÓ%Íâfk´1±Z%qݺŽâH †r‰»÷LjÁ »ÞOÔ`¹®x¥N”8kõ5cƒUU׬?ݪ„ƒ_ý)‡Yô’{·y@ÍžðLîUÏc¡…¹ÊzA>ñ’#<å:ÊÄAI¦¤Nî­Å¹uðð(~ZÅB©áÏ*W[5G&‘×å'Sÿ`ÏÞ` endstream endobj 177 0 obj<>stream H‰bd`ab`ddäóöqðñÕ®ÌMÊω¨ÿaü!ÎòC–Gì·Çï¿®ýjc•e`Xþ…÷»;ÿ÷ïa‚ó~Ø 1032r¦deæ¥eæe–T:çTe¦g”(h$k*ZZ˜ê€Hs0i "- À¤¹‚cJ~RªBpeqIjn±‚g^r~QA~QbIjŠž‚cNŽؘb…¢ÔâÔ¢2  Ôi@ÀÈØÎ0‡a‹ÂÒ[X™˜ë×<àã;ò]p×wýŒK÷þ8¶—ùûÏï{Eý•ÍY µMۣɸÙñ”Ñó)Ÿ¦¹¶xÁâ²#ŸŸ7zÒ|µé±ö9­„˜²²J¿ެ,Ñ€ ªŠàºº€Çº¶o¿ü0wmýò²#ÑgÅŽì^¾`íô‡+·;wÅw¤†ÌžQ5/àŸB÷¡ïû1~ï>Ä<õ‡ŽhÈ÷Æß‡¾7~o<ôH„ündÿ¾ãŽè¡?KCØù~T—3Îù1ƒùÇÊÕ¢i~þ.ú]ø½(-í{ ÄÒ¾ùßâ6ü.ø^ÈÊW1ï§é¬ß±3Øžs=àþÞ'òSE Àç¬Äh endstream endobj 178 0 obj<> endobj 179 0 obj<> endobj 180 0 obj<>stream H‰T=oà †w~Å©:ð‘!C“Vò¶ªÓîÎR ãÁÿ¾àX©:€Þûx‡£ÇæÔx—~¤`ZÌÐ;oNaN¡ÃÁyà¬3y‹ÖÛŒ:-æv™2ŽïHIèg)N9-°{}zd@ß“Åäü» ÿú.‰vŽñGô({Bgßôˆ@«í/wY"‚Xc¾=,NQLÚ’ Ò ·ÿkdst½¹êDnBðEdÇ‹fì™]ÍEŸŠ”[wV¿x3sJ…yÝÊV¡œÇûªbˆ•¡ò+À¹ãm½ endstream endobj 181 0 obj<> endobj 182 0 obj<> endobj 183 0 obj<> endobj 184 0 obj<> endobj 185 0 obj<> endobj 186 0 obj<> endobj 187 0 obj<> endobj 188 0 obj<> endobj 189 0 obj<> endobj 190 0 obj<> endobj 191 0 obj<> endobj 192 0 obj<> endobj 193 0 obj<> endobj 194 0 obj<> endobj 195 0 obj<>stream Acrobat Distiller 7.0.5 (Windows) 2006-11-22T12:57:21Z SCRIPT/VS 4.0.0: DEVICE PSA4 CHARS PSFTR 2006-11-22T12:57:21Z application/pdf DECNUMB uuid:d462cbbf-034c-4ec7-a2c8-503cf6bfa1ff uuid:7672f74c-1c5f-47a4-8e5d-3b40dbfbf384 endstream endobj 196 0 obj<> endobj xref 0 197 0000000000 65535 f 0000004676 00000 n 0000004803 00000 n 0000004909 00000 n 0000005564 00000 n 0000005691 00000 n 0000005841 00000 n 0000007718 00000 n 0000007845 00000 n 0000007995 00000 n 0000010304 00000 n 0000010434 00000 n 0000010563 00000 n 0000012257 00000 n 0000012387 00000 n 0000012505 00000 n 0000013168 00000 n 0000013298 00000 n 0000013438 00000 n 0000015530 00000 n 0000015660 00000 n 0000015800 00000 n 0000017757 00000 n 0000017887 00000 n 0000018038 00000 n 0000020569 00000 n 0000020699 00000 n 0000020839 00000 n 0000023082 00000 n 0000023212 00000 n 0000023341 00000 n 0000025340 00000 n 0000025470 00000 n 0000025599 00000 n 0000027790 00000 n 0000027920 00000 n 0000028038 00000 n 0000028906 00000 n 0000029036 00000 n 0000029165 00000 n 0000031061 00000 n 0000031191 00000 n 0000031309 00000 n 0000033157 00000 n 0000033287 00000 n 0000033427 00000 n 0000035522 00000 n 0000035652 00000 n 0000035781 00000 n 0000038714 00000 n 0000038844 00000 n 0000038995 00000 n 0000041196 00000 n 0000041326 00000 n 0000041466 00000 n 0000044150 00000 n 0000044280 00000 n 0000044409 00000 n 0000046579 00000 n 0000046709 00000 n 0000046827 00000 n 0000047290 00000 n 0000047420 00000 n 0000047571 00000 n 0000050640 00000 n 0000050770 00000 n 0000050910 00000 n 0000053571 00000 n 0000053701 00000 n 0000053852 00000 n 0000054971 00000 n 0000055101 00000 n 0000055252 00000 n 0000057703 00000 n 0000057833 00000 n 0000057973 00000 n 0000060543 00000 n 0000060673 00000 n 0000060824 00000 n 0000063275 00000 n 0000063405 00000 n 0000063545 00000 n 0000065652 00000 n 0000065782 00000 n 0000065922 00000 n 0000068185 00000 n 0000068315 00000 n 0000068467 00000 n 0000071408 00000 n 0000071869 00000 n 0000072098 00000 n 0000072228 00000 n 0000072357 00000 n 0000074423 00000 n 0000074553 00000 n 0000074693 00000 n 0000076219 00000 n 0000076349 00000 n 0000076478 00000 n 0000077725 00000 n 0000077857 00000 n 0000077987 00000 n 0000078553 00000 n 0000078686 00000 n 0000078838 00000 n 0000080907 00000 n 0000081040 00000 n 0000081192 00000 n 0000083359 00000 n 0000083492 00000 n 0000083633 00000 n 0000085426 00000 n 0000085559 00000 n 0000085689 00000 n 0000086190 00000 n 0000086323 00000 n 0000086464 00000 n 0000088445 00000 n 0000088578 00000 n 0000088730 00000 n 0000091251 00000 n 0000091384 00000 n 0000091514 00000 n 0000092146 00000 n 0000092279 00000 n 0000092387 00000 n 0000092902 00000 n 0000093035 00000 n 0000093176 00000 n 0000095531 00000 n 0000095664 00000 n 0000095805 00000 n 0000098422 00000 n 0000098555 00000 n 0000098685 00000 n 0000099967 00000 n 0000100100 00000 n 0000100230 00000 n 0000101666 00000 n 0000101799 00000 n 0000101929 00000 n 0000104046 00000 n 0000104179 00000 n 0000104309 00000 n 0000106519 00000 n 0000106652 00000 n 0000106782 00000 n 0000108707 00000 n 0000108840 00000 n 0000108981 00000 n 0000110956 00000 n 0000111089 00000 n 0000111208 00000 n 0000112221 00000 n 0000112354 00000 n 0000112473 00000 n 0000113617 00000 n 0000113750 00000 n 0000113869 00000 n 0000115122 00000 n 0000115255 00000 n 0000115374 00000 n 0000116500 00000 n 0000116633 00000 n 0000116752 00000 n 0000117908 00000 n 0000118041 00000 n 0000118160 00000 n 0000119088 00000 n 0000119285 00000 n 0000119920 00000 n 0000120110 00000 n 0000120661 00000 n 0000121235 00000 n 0000121742 00000 n 0000121922 00000 n 0000122554 00000 n 0000128248 00000 n 0000128775 00000 n 0000129790 00000 n 0000130017 00000 n 0000130322 00000 n 0000130408 00000 n 0000131040 00000 n 0000131233 00000 n 0000131416 00000 n 0000131463 00000 n 0000131488 00000 n 0000131513 00000 n 0000131608 00000 n 0000131738 00000 n 0000131870 00000 n 0000132002 00000 n 0000132140 00000 n 0000132282 00000 n 0000132391 00000 n 0000135863 00000 n trailer <> startxref 116 %%EOF hercules-3.12/decNumber/decNumber.rc0000664000175000017500000000333712564723224014347 00000000000000/* $Id$ * Resource-definition script file for decNumber DLL (MSVC) * * This file was added by the Hercules project. * It is not part of the original decNumber distribution. * * $Log$ * */ #include #define DECNAME "decNumber" /* Short name */ #define DECVERSION "decNumber 3.37" /* Version [16 max.] */ #define DECFULLNAME "Decimal Number Module" /* Verbose name */ #define DECAUTHOR "Mike Cowlishaw" /* Who to blame */ #define DECCOPYRIGHT "Copyright (c) IBM Corporation, 2000, 2006" #define DECLICENSE "ICU License -- ICU 1.8.1 and later" #define DECVERMAJOR 3 /* Major version number */ #define DECVERMINOR 37 /* Minor version number */ #define SPECIALINFO "Built for Hercules" 1 VERSIONINFO FILEVERSION DECVERMAJOR,DECVERMINOR,0,0 PRODUCTVERSION DECVERMAJOR,DECVERMINOR,0,0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS VS_FF_SPECIALBUILD FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" /* US English, Unicode */ BEGIN VALUE "Comments", DECLICENSE "\0" VALUE "CompanyName", DECAUTHOR "\0" VALUE "FileDescription", DECFULLNAME "\0" VALUE "FileVersion", DECVERSION "\0" VALUE "LegalCopyright", DECCOPYRIGHT "\0" VALUE "ProductName", DECFULLNAME "\0" VALUE "ProductVersion", DECVERSION "\0" VALUE "SpecialBuild", SPECIALINFO "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation",0x409,0x4B0 /* US English, Unicode */ END END hercules-3.12/decNumber/ICU-license.html0000664000175000017500000000367112564723224015044 00000000000000 ICU License - ICU 1.8.1 and later

ICU License - ICU 1.8.1 and later

COPYRIGHT AND PERMISSION NOTICE

Copyright (c) 1995-2005 International Business Machines Corporation and others
All rights reserved.

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, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, provided that the above
copyright notice(s) and this permission notice appear in all copies of
the Software and that both the above copyright notice(s) and this
permission notice appear in supporting documentation.

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
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
of the copyright holder.

--------------------------------------------------------------------------------
All trademarks and registered trademarks mentioned herein are the property of their respective owners.
hercules-3.12/decNumber/readme.txt0000664000175000017500000000562512564723224014115 00000000000000This is the readme.txt for the decNumber package. It includes instructions for compiling and testing the package; please read them. --------------------------------------------------------------------- decNumber is distributed in three forms; as a complete package from the IBM alphaWorks site (available under either a trial or a commercial license), as a complete package from the International Components for Unicode (ICU) site (under an as-is license), or as a collection of Open Source files from the GCC source repository (under the GPL license). If you are using the GCC files, you can obtain the documentation, the example files mentioned below, and this readme from: http://www2.hursley.ibm.com/decimal/#decNumber (the URL for the open source files is also linked from there). The alphaWorks and ICU packages ------------------------------- The alphaWorks and ICU packages include the files: * readme.txt (this file) * alphaWorks-license-files.zip (contains the 90-day trial license, in multiple languages), or ICU-license.html Note: a commercial license for this code is also available by following the 'License this technology' link from the alphaWorks page: http://www.alphaWorks.ibm.com/tech/decnumber * decNumber.pdf (documentation) * The .c and .h file for each module in the package (see documentation), decDPD.h (used by decimal32), and decNumberLocal.h (local definitions) * The .c files for each of the examples (example1.c through example6.c) The alphaWorks package is made available under the terms of the IBM alphaWorks License Agreement (included in various languages in the file alphaWorks-license-files.zip), unless you have agreed different licensing terms with IBM. Your use of that package indicates your acceptance of the terms and conditions of that Agreement. The ICU package is made available under the terms of the ICU License (ICU 1.8.1 and later) included in the package as ICU-license.html. Your use of that package indicates your acceptance of the terms and conditions of that Agreement. To use and check decNumber -------------------------- Please read the appropriate license and documentation before using this package. 1. Compile and link example1.c, decNumber.c, and decContext.c For example: gcc -o example1 example1.c decNumber.c decContext.c Note: If your compiler does not provide stdint.h or if your C compiler does not handle line comments (// ...), then see the User's Guide section in the documentation for further information (including a suitable minimal stdint.h). 2. Run example1 with two numeric arguments, for example: example1 1.23 1.27 this should display: 1.23 + 1.27 => 2.50 3. Similarly, try the other examples, at will. Example 5 requires decimal64.c in addition to the core modules. Example 6 requires decPacked.c in addition to the core modules. hercules-3.12/softfloat/0000775000175000017500000000000012625667404012271 500000000000000hercules-3.12/softfloat/Makefile.in0000664000175000017500000005242112625667166014267 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Makefile for building the SoftFloat package # for use with Hercules S/370, ESA/390 and z/Architecture emulator # # This file was added by the Hercules project. # It is not part of the original SoftFloat distribution. # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = softfloat DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/mkinstalldirs \ $(top_srcdir)/autoconf/depcomp $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = libsoftfloat_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am__objects_1 = softfloat.lo am_libsoftfloat_la_OBJECTS = $(am__objects_1) libsoftfloat_la_OBJECTS = $(am_libsoftfloat_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsoftfloat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsoftfloat_la_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/autoconf/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsoftfloat_la_SOURCES) DIST_SOURCES = $(libsoftfloat_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lns = @LN_S@ LDADD = @LIBS@ AM_CPPFLAGS = -I$(top_srcdir) softfloat_SRC = softfloat.c @BUILD_SHARED_FALSE@XSTATIC = -static @BUILD_SHARED_TRUE@XSTATIC = @OPTION_DYNAMIC_LOAD_FALSE@LTDL = @OPTION_DYNAMIC_LOAD_TRUE@LTDL = ../ltdl.c @OPTION_DYNAMIC_LOAD_FALSE@LIB_LD_FLAGS = $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_FALSE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_FALSE@ -avoid-version @OPTION_DYNAMIC_LOAD_TRUE@LIB_LD_FLAGS = -export-dynamic \ @OPTION_DYNAMIC_LOAD_TRUE@ $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_TRUE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_TRUE@ -avoid-version HERCLIBS = HERCLIBS2 = libsoftfloat.la noinst_LTLIBRARIES = $(HERCLIBS) lib_LTLIBRARIES = $(HERCLIBS2) libsoftfloat_la_SOURCES = $(softfloat_SRC) libsoftfloat_la_LDFLAGS = $(LIB_LD_FLAGS) libsoftfloat_la_LIBADD = $(LDADD) noinst_HEADERS = milieu.h \ processor.h \ softfloat.h \ softfloat-macros \ softfloat-specialize EXTRA_DIST = README.txt \ SoftFloat.txt \ SoftFloat-history.txt \ SoftFloat-source.txt all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu softfloat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu softfloat/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsoftfloat.la: $(libsoftfloat_la_OBJECTS) $(libsoftfloat_la_DEPENDENCIES) $(EXTRA_libsoftfloat_la_DEPENDENCIES) $(AM_V_CCLD)$(libsoftfloat_la_LINK) -rpath $(libdir) $(libsoftfloat_la_OBJECTS) $(libsoftfloat_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/softfloat.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libLTLIBRARIES %.s: %.c $(COMPILE) -S $< # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/softfloat/Makefile.am0000664000175000017500000000227012564723224014241 00000000000000## Process this file with automake to produce Makefile.in # # Makefile for building the SoftFloat package # for use with Hercules S/370, ESA/390 and z/Architecture emulator # # This file was added by the Hercules project. # It is not part of the original SoftFloat distribution. # lns=@LN_S@ LDADD = @LIBS@ AM_CPPFLAGS = -I$(top_srcdir) softfloat_SRC = softfloat.c if BUILD_SHARED XSTATIC = else XSTATIC = -static endif if OPTION_DYNAMIC_LOAD LTDL = ../ltdl.c LIB_LD_FLAGS = -export-dynamic \ $(XSTATIC) \ -no-undefined \ -avoid-version else LTDL = LIB_LD_FLAGS = $(XSTATIC) \ -no-undefined \ -avoid-version endif HERCLIBS = HERCLIBS2 = libsoftfloat.la noinst_LTLIBRARIES = $(HERCLIBS) lib_LTLIBRARIES = $(HERCLIBS2) libsoftfloat_la_SOURCES = $(softfloat_SRC) libsoftfloat_la_LDFLAGS = $(LIB_LD_FLAGS) libsoftfloat_la_LIBADD = $(LDADD) noinst_HEADERS = milieu.h \ processor.h \ softfloat.h \ softfloat-macros \ softfloat-specialize EXTRA_DIST = README.txt \ SoftFloat.txt \ SoftFloat-history.txt \ SoftFloat-source.txt %.s: %.c $(COMPILE) -S $< hercules-3.12/softfloat/milieu.h0000664000175000017500000000374012564723224013645 00000000000000 /*============================================================================ This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic Package, Release 2b. Written by John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ arithmetic/SoftFloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. Derivative works are acceptable, even for commercial purposes, so long as (1) the source code for the derivative work includes prominent notice that the work is derivative, and (2) the source code includes prominent notice with these four paragraphs for those parts of this code that are retained. =============================================================================*/ /*---------------------------------------------------------------------------- | Include common integer types and flags. *----------------------------------------------------------------------------*/ #include "processor.h" hercules-3.12/softfloat/processor.h0000664000175000017500000000732512564723224014403 00000000000000/*---------------------------------------------------------------------------- | Softfloat processor file for Hercules *----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | The macro `BITS64' can be defined to indicate that 64-bit integer types are | supported by the compiler. *----------------------------------------------------------------------------*/ #define BITS64 /*---------------------------------------------------------------------------- | Each of the following `typedef's defines the most convenient type that holds | integers of at least as many bits as specified. For example, `uint8' should | be the most convenient type that can hold unsigned integers of as many as | 8 bits. The `flag' type must be able to hold either a 0 or 1. For most | implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed | to the same as `int'. *----------------------------------------------------------------------------*/ typedef char flag; typedef unsigned char uint8; typedef signed char int8; typedef int uint16; typedef int int16; typedef unsigned int uint32; typedef signed int int32; #ifdef BITS64 typedef unsigned long long int uint64; typedef signed long long int int64; #endif /*---------------------------------------------------------------------------- | Each of the following `typedef's defines a type that holds integers | of _exactly_ the number of bits specified. For instance, for most | implementation of C, `bits16' and `sbits16' should be `typedef'ed to | `unsigned short int' and `signed short int' (or `short int'), respectively. *----------------------------------------------------------------------------*/ typedef unsigned char bits8; typedef signed char sbits8; typedef unsigned short int bits16; typedef signed short int sbits16; typedef unsigned int bits32; typedef signed int sbits32; #ifdef BITS64 typedef unsigned long long int bits64; typedef signed long long int sbits64; #endif #ifdef BITS64 /*---------------------------------------------------------------------------- | The `LIT64' macro takes as its argument a textual integer literal and | if necessary ``marks'' the literal as having a 64-bit integer type. | For example, the GNU C Compiler (`gcc') requires that 64-bit literals be | appended with the letters `LL' standing for `long long', which is `gcc's | name for the 64-bit integer type. Some compilers may allow `LIT64' to be | defined as the identity macro: `#define LIT64( a ) a'. *----------------------------------------------------------------------------*/ #define LIT64( a ) a##LL #endif /*---------------------------------------------------------------------------- | The macro `INLINE' can be used before functions that should be inlined. If | a compiler does not support explicit inlining, this macro should be defined | to be `static'. *----------------------------------------------------------------------------*/ #define INLINE static /*---------------------------------------------------------------------------- | Disable certain compiler warnings *----------------------------------------------------------------------------*/ #if defined(_MSVC_) #pragma warning(disable:4146) /* unary minus operator applied to unsigned type, result still unsigned */ #pragma warning(disable:4244) /* conversion from 'type' to 'type', possible loss of data */ #endif /*defined(_MVSC_)*/ /*---------------------------------------------------------------------------- | Declaration of static variables that must be instanced on a per-thread basis *----------------------------------------------------------------------------*/ #if defined(_MSVC_) #define __thread __declspec(thread) #endif /*defined(_MVSC_)*/ hercules-3.12/softfloat/softfloat.h0000664000175000017500000003431012564723224014357 00000000000000/* THIS FILE HAS BEEN MODIFIED FOR USE BY THE HERCULES PROJECT */ /*============================================================================ This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic Package, Release 2b. Written by John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ arithmetic/SoftFloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. Derivative works are acceptable, even for commercial purposes, so long as (1) the source code for the derivative work includes prominent notice that the work is derivative, and (2) the source code includes prominent notice with these four paragraphs for those parts of this code that are retained. =============================================================================*/ /*---------------------------------------------------------------------------- | The macro `FLOATX80' must be defined to enable the extended double-precision | floating-point format `floatx80'. If this macro is not defined, the | `floatx80' type will not be defined, and none of the functions that either | input or output the `floatx80' type will be defined. The same applies to | the `FLOAT128' macro and the quadruple-precision format `float128'. *----------------------------------------------------------------------------*/ #define FLOAT128 /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point types. *----------------------------------------------------------------------------*/ typedef bits32 float32; typedef bits64 float64; #ifdef FLOATX80 typedef struct { bits16 high; bits64 low; } floatx80; #endif #ifdef FLOAT128 typedef struct { bits64 high, low; } float128; #endif /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point underflow tininess-detection mode. *----------------------------------------------------------------------------*/ extern int8 float_detect_tininess; enum { float_tininess_after_rounding = 0, float_tininess_before_rounding = 1 }; /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point rounding mode. *----------------------------------------------------------------------------*/ extern __thread int8 float_rounding_mode; enum { float_round_nearest_even = 0, float_round_to_zero = 1, float_round_down = 2, float_round_up = 3 }; /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point exception flags. *----------------------------------------------------------------------------*/ extern __thread int8 float_exception_flags; enum { float_flag_inexact = 1, float_flag_underflow = 2, float_flag_overflow = 4, float_flag_divbyzero = 8, float_flag_invalid = 16 }; /*---------------------------------------------------------------------------- | Routine to set the floating-point rounding mode. *----------------------------------------------------------------------------*/ void float_set_rounding_mode( int8 ); /*---------------------------------------------------------------------------- | Routine to get the floating-point exception flags. *----------------------------------------------------------------------------*/ int8 float_get_exception_flags( void ); /*---------------------------------------------------------------------------- | Routine to clear the floating-point exception flags. *----------------------------------------------------------------------------*/ void float_clear_exception_flags( void ); /*---------------------------------------------------------------------------- | Routine to raise any or all of the software IEC/IEEE floating-point | exception flags. *----------------------------------------------------------------------------*/ void float_raise( int8 ); /*---------------------------------------------------------------------------- | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ #define float32_default_nan 0x7FC00000 /*---------------------------------------------------------------------------- | Unsigned-integer to floating-point conversion routines. *----------------------------------------------------------------------------*/ float32 uint32_to_float32( uint32 ); float32 uint64_to_float32( uint64 ); float64 uint32_to_float64( uint32 ); float64 uint64_to_float64( uint64 ); #ifdef FLOAT128 float128 uint32_to_float128( uint32 ); float128 uint64_to_float128( uint64 ); #endif /*---------------------------------------------------------------------------- | Software IEC/IEEE integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ float32 int32_to_float32( int32 ); float64 int32_to_float64( int32 ); #ifdef FLOATX80 floatx80 int32_to_floatx80( int32 ); #endif #ifdef FLOAT128 float128 int32_to_float128( int32 ); #endif float32 int64_to_float32( int64 ); float64 int64_to_float64( int64 ); #ifdef FLOATX80 floatx80 int64_to_floatx80( int64 ); #endif #ifdef FLOAT128 float128 int64_to_float128( int64 ); #endif /*---------------------------------------------------------------------------- | Floating-point to unsigned-integer conversion routines. *----------------------------------------------------------------------------*/ uint32 float32_to_uint32( float32 ); uint64 float32_to_uint64( float32 ); uint32 float64_to_uint32( float64 ); uint64 float64_to_uint64( float64 ); #ifdef FLOAT128 uint32 float128_to_uint32( float128 ); uint64 float128_to_uint64( float128 ); #endif /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ int32 float32_to_int32( float32 ); int32 float32_to_int32_round_to_zero( float32 ); int64 float32_to_int64( float32 ); int64 float32_to_int64_round_to_zero( float32 ); float64 float32_to_float64( float32 ); #ifdef FLOATX80 floatx80 float32_to_floatx80( float32 ); #endif #ifdef FLOAT128 float128 float32_to_float128( float32 ); #endif /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision operations. *----------------------------------------------------------------------------*/ float32 float32_round_to_int( float32 ); float32 float32_add( float32, float32 ); float32 float32_sub( float32, float32 ); float32 float32_mul( float32, float32 ); float32 float32_div( float32, float32 ); float32 float32_rem( float32, float32 ); float32 float32_sqrt( float32 ); flag float32_eq( float32, float32 ); flag float32_le( float32, float32 ); flag float32_lt( float32, float32 ); flag float32_eq_signaling( float32, float32 ); flag float32_le_quiet( float32, float32 ); flag float32_lt_quiet( float32, float32 ); flag float32_is_inf( float32 ); flag float32_is_nan( float32 ); flag float32_is_neg( float32 ); flag float32_is_signaling_nan( float32 ); flag float32_is_subnormal( float32 ); flag float32_is_zero( float32 ); float32 float32_pos( float32 ); float32 float32_neg( float32 ); float32 float32_snan_to_qnan( float32 ); float32 float32_build( int, int, bits32 ); bits16 float32_exp( float32 ); bits32 float32_fract( float32 ); /*---------------------------------------------------------------------------- | The pattern for a default generated double-precision NaN. *----------------------------------------------------------------------------*/ #define float64_default_nan LIT64( 0x7FF8000000000000 ) /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ int32 float64_to_int32( float64 ); int32 float64_to_int32_round_to_zero( float64 ); int64 float64_to_int64( float64 ); int64 float64_to_int64_round_to_zero( float64 ); float32 float64_to_float32( float64 ); #ifdef FLOATX80 floatx80 float64_to_floatx80( float64 ); #endif #ifdef FLOAT128 float128 float64_to_float128( float64 ); #endif /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ float64 float64_round_to_int( float64 ); float64 float64_add( float64, float64 ); float64 float64_sub( float64, float64 ); float64 float64_mul( float64, float64 ); float64 float64_div( float64, float64 ); float64 float64_rem( float64, float64 ); float64 float64_sqrt( float64 ); flag float64_eq( float64, float64 ); flag float64_le( float64, float64 ); flag float64_lt( float64, float64 ); flag float64_eq_signaling( float64, float64 ); flag float64_le_quiet( float64, float64 ); flag float64_lt_quiet( float64, float64 ); flag float64_is_inf( float64 ); flag float64_is_nan( float64 ); flag float64_is_neg( float64 ); flag float64_is_signaling_nan( float64 ); flag float64_is_subnormal( float64 ); flag float64_is_zero( float64 ); float64 float64_pos( float64 ); float64 float64_neg( float64 ); float64 float64_snan_to_qnan( float64 ); float64 float64_build( int, int, bits64 ); bits16 float64_exp( float64 ); bits64 float64_fract( float64 ); #ifdef FLOATX80 /*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision conversion routines. *----------------------------------------------------------------------------*/ int32 floatx80_to_int32( floatx80 ); int32 floatx80_to_int32_round_to_zero( floatx80 ); int64 floatx80_to_int64( floatx80 ); int64 floatx80_to_int64_round_to_zero( floatx80 ); float32 floatx80_to_float32( floatx80 ); float64 floatx80_to_float64( floatx80 ); #ifdef FLOAT128 float128 floatx80_to_float128( floatx80 ); #endif /*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision rounding precision. Valid | values are 32, 64, and 80. *----------------------------------------------------------------------------*/ extern int8 floatx80_rounding_precision; /*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision operations. *----------------------------------------------------------------------------*/ floatx80 floatx80_round_to_int( floatx80 ); floatx80 floatx80_add( floatx80, floatx80 ); floatx80 floatx80_sub( floatx80, floatx80 ); floatx80 floatx80_mul( floatx80, floatx80 ); floatx80 floatx80_div( floatx80, floatx80 ); floatx80 floatx80_rem( floatx80, floatx80 ); floatx80 floatx80_sqrt( floatx80 ); flag floatx80_eq( floatx80, floatx80 ); flag floatx80_le( floatx80, floatx80 ); flag floatx80_lt( floatx80, floatx80 ); flag floatx80_eq_signaling( floatx80, floatx80 ); flag floatx80_le_quiet( floatx80, floatx80 ); flag floatx80_lt_quiet( floatx80, floatx80 ); flag floatx80_is_signaling_nan( floatx80 ); #endif #ifdef FLOAT128 /*---------------------------------------------------------------------------- | The pattern for a default generated quadruple-precision NaN. The `high' and | `low' values hold the most- and least-significant bits, respectively. *----------------------------------------------------------------------------*/ #define float128_default_nan_high LIT64( 0x7FFF800000000000 ) #define float128_default_nan_low LIT64( 0x0000000000000000 ) /*---------------------------------------------------------------------------- | Software IEC/IEEE quadruple-precision conversion routines. *----------------------------------------------------------------------------*/ int32 float128_to_int32( float128 ); int32 float128_to_int32_round_to_zero( float128 ); int64 float128_to_int64( float128 ); int64 float128_to_int64_round_to_zero( float128 ); float32 float128_to_float32( float128 ); float64 float128_to_float64( float128 ); #ifdef FLOATX80 floatx80 float128_to_floatx80( float128 ); #endif /*---------------------------------------------------------------------------- | Software IEC/IEEE quadruple-precision operations. *----------------------------------------------------------------------------*/ float128 float128_round_to_int( float128 ); float128 float128_add( float128, float128 ); float128 float128_sub( float128, float128 ); float128 float128_mul( float128, float128 ); float128 float128_div( float128, float128 ); float128 float128_rem( float128, float128 ); float128 float128_sqrt( float128 ); flag float128_eq( float128, float128 ); flag float128_le( float128, float128 ); flag float128_lt( float128, float128 ); flag float128_eq_signaling( float128, float128 ); flag float128_le_quiet( float128, float128 ); flag float128_lt_quiet( float128, float128 ); flag float128_is_inf( float128 ); flag float128_is_nan( float128 ); flag float128_is_neg( float128 ); flag float128_is_signaling_nan( float128 ); flag float128_is_subnormal( float128 ); flag float128_is_zero( float128 ); float128 float128_pos( float128 ); float128 float128_neg( float128 ); float128 float128_snan_to_qnan( float128 ); float128 float128_build( int sign, int exp, bits64 fract_high, bits64 fract_low ); bits16 float128_exp( float128 a ); bits64 float128_fract_high( float128 a ); bits64 float128_fract_low( float128 a ); #endif hercules-3.12/softfloat/softfloat-macros0000664000175000017500000005765012564723224015427 00000000000000/* THIS FILE HAS BEEN MODIFIED FOR USE WITH THE HERCULES PROJECT */ /*============================================================================ This C source fragment is part of the SoftFloat IEC/IEEE Floating-point Arithmetic Package, Release 2b. Written by John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ arithmetic/SoftFloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. Derivative works are acceptable, even for commercial purposes, so long as (1) the source code for the derivative work includes prominent notice that the work is derivative, and (2) the source code includes prominent notice with these four paragraphs for those parts of this code that are retained. =============================================================================*/ /*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero | bits are shifted off, they are ``jammed'' into the least significant bit of | the result by setting the least significant bit to 1. The value of `count' | can be arbitrarily large; in particular, if `count' is greater than 32, the | result will be either 0 or 1, depending on whether `a' is zero or nonzero. | The result is stored in the location pointed to by `zPtr'. *----------------------------------------------------------------------------*/ INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) { bits32 z; if ( count == 0 ) { z = a; } else if ( count < 32 ) { z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); } else { z = ( a != 0 ); } *zPtr = z; } /*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero | bits are shifted off, they are ``jammed'' into the least significant bit of | the result by setting the least significant bit to 1. The value of `count' | can be arbitrarily large; in particular, if `count' is greater than 64, the | result will be either 0 or 1, depending on whether `a' is zero or nonzero. | The result is stored in the location pointed to by `zPtr'. *----------------------------------------------------------------------------*/ INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) { bits64 z; if ( count == 0 ) { z = a; } else if ( count < 64 ) { z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); } else { z = ( a != 0 ); } *zPtr = z; } /*---------------------------------------------------------------------------- | Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 | _plus_ the number of bits given in `count'. The shifted result is at most | 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The | bits shifted off form a second 64-bit result as follows: The _last_ bit | shifted off is the most-significant bit of the extra result, and the other | 63 bits of the extra result are all zero if and only if _all_but_the_last_ | bits shifted off were all zero. This extra result is stored in the location | pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. | (This routine makes more sense if `a0' and `a1' are considered to form | a fixed-point value with binary point between `a0' and `a1'. This fixed- | point value is shifted right by the number of bits given in `count', and | the integer part of the result is returned at the location pointed to by | `z0Ptr'. The fractional part of the result may be slightly corrupted as | described above, and is returned at the location pointed to by `z1Ptr'.) *----------------------------------------------------------------------------*/ INLINE void shift64ExtraRightJamming( bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) { bits64 z0, z1; int8 negCount = ( - count ) & 63; if ( count == 0 ) { z1 = a1; z0 = a0; } else if ( count < 64 ) { z1 = ( a0<>count; } else { if ( count == 64 ) { z1 = a0 | ( a1 != 0 ); } else { z1 = ( ( a0 | a1 ) != 0 ); } z0 = 0; } *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the | number of bits given in `count'. Any bits shifted off are lost. The value | of `count' can be arbitrarily large; in particular, if `count' is greater | than 128, the result will be 0. The result is broken into two 64-bit pieces | which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. *----------------------------------------------------------------------------*/ INLINE void shift128Right( bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) { bits64 z0, z1; int8 negCount = ( - count ) & 63; if ( count == 0 ) { z1 = a1; z0 = a0; } else if ( count < 64 ) { z1 = ( a0<>count ); z0 = a0>>count; } else { z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; z0 = 0; } *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the | number of bits given in `count'. If any nonzero bits are shifted off, they | are ``jammed'' into the least significant bit of the result by setting the | least significant bit to 1. The value of `count' can be arbitrarily large; | in particular, if `count' is greater than 128, the result will be either | 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or | nonzero. The result is broken into two 64-bit pieces which are stored at | the locations pointed to by `z0Ptr' and `z1Ptr'. *----------------------------------------------------------------------------*/ INLINE void shift128RightJamming( bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) { bits64 z0, z1; int8 negCount = ( - count ) & 63; if ( count == 0 ) { z1 = a1; z0 = a0; } else if ( count < 64 ) { z1 = ( a0<>count ) | ( ( a1<>count; } else { if ( count == 64 ) { z1 = a0 | ( a1 != 0 ); } else if ( count < 128 ) { z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); z0 = a0>>count; } else { if ( count == 64 ) { z2 = a1; z1 = a0; } else { a2 |= a1; if ( count < 128 ) { z2 = a0<>( count & 63 ); } else { z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); z1 = 0; } } z0 = 0; } z2 |= ( a2 != 0 ); } *z2Ptr = z2; *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the | number of bits given in `count'. Any bits shifted off are lost. The value | of `count' must be less than 64. The result is broken into two 64-bit | pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. *----------------------------------------------------------------------------*/ INLINE void shortShift128Left( bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) { *z1Ptr = a1<>( ( - count ) & 63 ) ); } /*---------------------------------------------------------------------------- | Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left | by the number of bits given in `count'. Any bits shifted off are lost. | The value of `count' must be less than 64. The result is broken into three | 64-bit pieces which are stored at the locations pointed to by `z0Ptr', | `z1Ptr', and `z2Ptr'. *----------------------------------------------------------------------------*/ INLINE void shortShift192Left( bits64 a0, bits64 a1, bits64 a2, int16 count, bits64 *z0Ptr, bits64 *z1Ptr, bits64 *z2Ptr ) { bits64 z0, z1, z2; int8 negCount; z2 = a2<>negCount; z0 |= a1>>negCount; } *z2Ptr = z2; *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit | value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so | any carry out is lost. The result is broken into two 64-bit pieces which | are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. *----------------------------------------------------------------------------*/ INLINE void add128( bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) { bits64 z1; z1 = a1 + b1; *z1Ptr = z1; *z0Ptr = a0 + b0 + ( z1 < a1 ); } /*---------------------------------------------------------------------------- | Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the | 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is | modulo 2^192, so any carry out is lost. The result is broken into three | 64-bit pieces which are stored at the locations pointed to by `z0Ptr', | `z1Ptr', and `z2Ptr'. *----------------------------------------------------------------------------*/ INLINE void add192( bits64 a0, bits64 a1, bits64 a2, bits64 b0, bits64 b1, bits64 b2, bits64 *z0Ptr, bits64 *z1Ptr, bits64 *z2Ptr ) { bits64 z0, z1, z2; uint8 carry0, carry1; z2 = a2 + b2; carry1 = ( z2 < a2 ); z1 = a1 + b1; carry0 = ( z1 < a1 ); z0 = a0 + b0; z1 += carry1; z0 += ( z1 < carry1 ); z0 += carry0; *z2Ptr = z2; *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the | 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo | 2^128, so any borrow out (carry out) is lost. The result is broken into two | 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and | `z1Ptr'. *----------------------------------------------------------------------------*/ INLINE void sub128( bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) { *z1Ptr = a1 - b1; *z0Ptr = a0 - b0 - ( a1 < b1 ); } /*---------------------------------------------------------------------------- | Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' | from the 192-bit value formed by concatenating `a0', `a1', and `a2'. | Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The | result is broken into three 64-bit pieces which are stored at the locations | pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. *----------------------------------------------------------------------------*/ INLINE void sub192( bits64 a0, bits64 a1, bits64 a2, bits64 b0, bits64 b1, bits64 b2, bits64 *z0Ptr, bits64 *z1Ptr, bits64 *z2Ptr ) { bits64 z0, z1, z2; uint8 borrow0, borrow1; z2 = a2 - b2; borrow1 = ( a2 < b2 ); z1 = a1 - b1; borrow0 = ( a1 < b1 ); z0 = a0 - b0; z0 -= ( z1 < borrow1 ); z1 -= borrow1; z0 -= borrow0; *z2Ptr = z2; *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Multiplies `a' by `b' to obtain a 128-bit product. The product is broken | into two 64-bit pieces which are stored at the locations pointed to by | `z0Ptr' and `z1Ptr'. *----------------------------------------------------------------------------*/ INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) { bits32 aHigh, aLow, bHigh, bLow; bits64 z0, zMiddleA, zMiddleB, z1; aLow = a; aHigh = a>>32; bLow = b; bHigh = b>>32; z1 = ( (bits64) aLow ) * bLow; zMiddleA = ( (bits64) aLow ) * bHigh; zMiddleB = ( (bits64) aHigh ) * bLow; z0 = ( (bits64) aHigh ) * bHigh; zMiddleA += zMiddleB; z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); zMiddleA <<= 32; z1 += zMiddleA; z0 += ( z1 < zMiddleA ); *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Multiplies the 128-bit value formed by concatenating `a0' and `a1' by | `b' to obtain a 192-bit product. The product is broken into three 64-bit | pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and | `z2Ptr'. *----------------------------------------------------------------------------*/ INLINE void mul128By64To192( bits64 a0, bits64 a1, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr, bits64 *z2Ptr ) { bits64 z0, z1, z2, more1; mul64To128( a1, b, &z1, &z2 ); mul64To128( a0, b, &z0, &more1 ); add128( z0, more1, 0, z1, &z0, &z1 ); *z2Ptr = z2; *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the | 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit | product. The product is broken into four 64-bit pieces which are stored at | the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. *----------------------------------------------------------------------------*/ INLINE void mul128To256( bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr, bits64 *z2Ptr, bits64 *z3Ptr ) { bits64 z0, z1, z2, z3; bits64 more1, more2; mul64To128( a1, b1, &z2, &z3 ); mul64To128( a1, b0, &z1, &more2 ); add128( z1, more2, 0, z2, &z1, &z2 ); mul64To128( a0, b0, &z0, &more1 ); add128( z0, more1, 0, z1, &z0, &z1 ); mul64To128( a0, b1, &more1, &more2 ); add128( more1, more2, 0, z2, &more1, &z2 ); add128( z0, z1, 0, more1, &z0, &z1 ); *z3Ptr = z3; *z2Ptr = z2; *z1Ptr = z1; *z0Ptr = z0; } /*---------------------------------------------------------------------------- | Returns an approximation to the 64-bit integer quotient obtained by dividing | `b' into the 128-bit value formed by concatenating `a0' and `a1'. The | divisor `b' must be at least 2^63. If q is the exact quotient truncated | toward zero, the approximation returned lies between q and q + 2 inclusive. | If the exact quotient q is larger than 64 bits, the maximum positive 64-bit | unsigned integer is returned. *----------------------------------------------------------------------------*/ static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) { bits64 b0, b1; bits64 rem0, rem1, term0, term1; bits64 z; if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); b0 = b>>32; z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; mul64To128( b, z, &term0, &term1 ); sub128( a0, a1, term0, term1, &rem0, &rem1 ); while ( ( (sbits64) rem0 ) < 0 ) { z -= LIT64( 0x100000000 ); b1 = b<<32; add128( rem0, rem1, b0, b1, &rem0, &rem1 ); } rem0 = ( rem0<<32 ) | ( rem1>>32 ); z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; return z; } /*---------------------------------------------------------------------------- | Returns an approximation to the square root of the 32-bit significand given | by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of | `aExp' (the least significant bit) is 1, the integer returned approximates | 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' | is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either | case, the approximation returned lies strictly within +/-2 of the exact | value. *----------------------------------------------------------------------------*/ static bits32 estimateSqrt32( int16 aExp, bits32 a ) { static const bits16 sqrtOddAdjustments[] = { 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 }; static const bits16 sqrtEvenAdjustments[] = { 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 }; int8 index; bits32 z; index = ( a>>27 ) & 15; if ( aExp & 1 ) { z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; z = ( ( a / z )<<14 ) + ( z<<15 ); a >>= 1; } else { z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; z = a / z + z; z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); } return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); } /*---------------------------------------------------------------------------- | Returns the number of leading 0 bits before the most-significant 1 bit of | `a'. If `a' is zero, 32 is returned. *----------------------------------------------------------------------------*/ static int8 countLeadingZeros32( bits32 a ) { static const int8 countLeadingZerosHigh[] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int8 shiftCount; shiftCount = 0; if ( a < 0x10000 ) { shiftCount += 16; a <<= 16; } if ( a < 0x1000000 ) { shiftCount += 8; a <<= 8; } shiftCount += countLeadingZerosHigh[ a>>24 ]; return shiftCount; } /*---------------------------------------------------------------------------- | Returns the number of leading 0 bits before the most-significant 1 bit of | `a'. If `a' is zero, 64 is returned. *----------------------------------------------------------------------------*/ static int8 countLeadingZeros64( bits64 a ) { int8 shiftCount; shiftCount = 0; if ( a < ( (bits64) 1 )<<32 ) { shiftCount += 32; } else { a >>= 32; } shiftCount += countLeadingZeros32( a ); return shiftCount; } /*---------------------------------------------------------------------------- | Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' | is equal to the 128-bit value formed by concatenating `b0' and `b1'. | Otherwise, returns 0. *----------------------------------------------------------------------------*/ INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) { return ( a0 == b0 ) && ( a1 == b1 ); } /*---------------------------------------------------------------------------- | Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less | than or equal to the 128-bit value formed by concatenating `b0' and `b1'. | Otherwise, returns 0. *----------------------------------------------------------------------------*/ INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) { return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less | than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, | returns 0. *----------------------------------------------------------------------------*/ INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) { return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); } #if 0 /*---------------------------------------------------------------------------- | Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is | not equal to the 128-bit value formed by concatenating `b0' and `b1'. | Otherwise, returns 0. *----------------------------------------------------------------------------*/ INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) { return ( a0 != b0 ) || ( a1 != b1 ); } #endif hercules-3.12/softfloat/softfloat-specialize0000664000175000017500000006416012564723224016265 00000000000000/* THIS FILE HAS BEEN MODIFIED FOR USE WITH THE HERCULES PROJECT */ /*============================================================================ This C source fragment is part of the SoftFloat IEC/IEEE Floating-point Arithmetic Package, Release 2b. Written by John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ arithmetic/SoftFloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. Derivative works are acceptable, even for commercial purposes, so long as (1) the source code for the derivative work includes prominent notice that the work is derivative, and (2) the source code includes prominent notice with these four paragraphs for those parts of this code that are retained. =============================================================================*/ /*---------------------------------------------------------------------------- | Underflow tininess-detection mode, statically initialized to default value. | (The declaration in `softfloat.h' must match the `int8' type here.) *----------------------------------------------------------------------------*/ int8 float_detect_tininess = float_tininess_before_rounding; /*---------------------------------------------------------------------------- | Sets the floating-point rounding mode. *----------------------------------------------------------------------------*/ void float_set_rounding_mode( int8 mode ) { float_rounding_mode = mode; } /*---------------------------------------------------------------------------- | Gets the floating-point exception flags. *----------------------------------------------------------------------------*/ int8 float_get_exception_flags() { return float_exception_flags; } /*---------------------------------------------------------------------------- | Clears the floating-point exception flags. *----------------------------------------------------------------------------*/ void float_clear_exception_flags() { float_exception_flags = 0; } /*---------------------------------------------------------------------------- | Raises the exceptions specified by `flags'. Floating-point traps can be | defined here if desired. It is currently not possible for such a trap to | substitute a result value. If traps are not implemented, this routine | should be simply `float_exception_flags |= flags;'. *----------------------------------------------------------------------------*/ void float_raise( int8 flags ) { float_exception_flags |= flags; } /*---------------------------------------------------------------------------- | Internal canonical NaN format. *----------------------------------------------------------------------------*/ typedef struct { flag sign; bits64 high, low; } commonNaNT; /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is infinity; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float32_is_inf( float32 a ) { return ( 0xFF000000 == (bits32) ( a<<1 ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is a NaN; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float32_is_nan( float32 a ) { return ( 0xFF000000 < (bits32) ( a<<1 ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is negative; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float32_is_neg( float32 a ) { return ( a>>31 ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is a signaling | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ flag float32_is_signaling_nan( float32 a ) { return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is subnormal; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float32_is_subnormal( float32 a ) { return ( ( ( a>>23 ) & 0xFF ) == 0 ) && ( a & 0x007FFFFF ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is zero; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float32_is_zero( float32 a ) { return ( ( a & 0x7FFFFFFF ) == 0); } /*---------------------------------------------------------------------------- | Returns the single-precision floating-point value `a' with positive sign. *----------------------------------------------------------------------------*/ float32 float32_pos( float32 a ) { return ( a & 0x7FFFFFFF ); } /*---------------------------------------------------------------------------- | Returns the single-precision floating-point value `a' with negative sign. *----------------------------------------------------------------------------*/ float32 float32_neg( float32 a ) { return ( a | 0x80000000 ); } /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point | signaling NaN `a' to a quiet NaN. *----------------------------------------------------------------------------*/ float32 float32_snan_to_qnan( float32 a ) { return ( a | 0x00400000 ); } /*---------------------------------------------------------------------------- | Builds a single-precision floating-point value. *----------------------------------------------------------------------------*/ float32 float32_build( int sign, int exp, bits32 fract ) { return ( (bits32) ( sign ? 0x80000000 : 0 ) ) | ( (bits32) ( exp & 0xFF ) << 23 ) | ( fract & 0x007FFFFF ); } /*---------------------------------------------------------------------------- | Returns the exponent of single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ bits16 float32_exp( float32 a ) { return (( a>>23 ) & 0xFF ); } /*---------------------------------------------------------------------------- | Returns the fraction of single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ bits32 float32_fract( float32 a ) { return ( a & 0x007FFFFF ); } /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ static commonNaNT float32ToCommonNaN( float32 a ) { commonNaNT z; if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); z.sign = a>>31; z.low = 0; z.high = ( (bits64) a )<<41; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the canonical NaN `a' to the single- | precision floating-point format. *----------------------------------------------------------------------------*/ static float32 commonNaNToFloat32( commonNaNT a ) { return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); } /*---------------------------------------------------------------------------- | Takes two single-precision floating-point values `a' and `b', one of which | is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a | signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ static float32 propagateFloat32NaN( float32 a, float32 b ) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; aIsNaN = float32_is_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); bIsNaN = float32_is_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); a |= 0x00400000; b |= 0x00400000; if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); if ( aIsNaN ) { return ( aIsSignalingNaN & bIsNaN ) ? b : a; } else { return b; } } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is infinity; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float64_is_inf( float64 a ) { return ( LIT64( 0xFFE0000000000000 ) == (bits64) ( a<<1 ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is a NaN; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float64_is_nan( float64 a ) { return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is negative; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float64_is_neg( float64 a ) { return ( a>>63 ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is a signaling | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ flag float64_is_signaling_nan( float64 a ) { return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is subnormal; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float64_is_subnormal( float64 a ) { return ( ( ( a>>52 ) & 0x7FF ) == 0 ) && ( a & LIT64( 0x000FFFFFFFFFFFFF ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is zero; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float64_is_zero( float64 a ) { return ( ( a & LIT64( 0x7FFFFFFFFFFFFFFF ) ) == 0); } /*---------------------------------------------------------------------------- | Returns the double-precision floating-point value `a' with positive sign. *----------------------------------------------------------------------------*/ float64 float64_pos( float64 a ) { return ( a & LIT64( 0x7FFFFFFFFFFFFFFF ) ); } /*---------------------------------------------------------------------------- | Returns the double-precision floating-point value `a' with negative sign. *----------------------------------------------------------------------------*/ float64 float64_neg( float64 a ) { return ( a | LIT64( 0x8000000000000000 ) ); } /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point | signaling NaN `a' to a quiet NaN. *----------------------------------------------------------------------------*/ float64 float64_snan_to_qnan( float64 a ) { return ( a | LIT64( 0x0008000000000000 ) ); } /*---------------------------------------------------------------------------- | Builds a double-precision floating-point value. *----------------------------------------------------------------------------*/ float64 float64_build( int sign, int exp, bits64 fract ) { return ( (bits64) ( sign ? LIT64( 0x8000000000000000 ) : 0 ) | ( (bits64) ( exp & 0x7FF ) << 52 ) | ( fract & LIT64( 0x000FFFFFFFFFFFFF ) ) ); } /*---------------------------------------------------------------------------- | Returns the exponent of double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ bits16 float64_exp( float64 a ) { return (( a>>52 ) & 0x7FF ); } /*---------------------------------------------------------------------------- | Returns the fraction of double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ bits64 float64_fract( float64 a ) { return ( a & LIT64( 0x000FFFFFFFFFFFFF ) ); } /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ static commonNaNT float64ToCommonNaN( float64 a ) { commonNaNT z; if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); z.sign = a>>63; z.low = 0; z.high = a<<12; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the canonical NaN `a' to the double- | precision floating-point format. *----------------------------------------------------------------------------*/ static float64 commonNaNToFloat64( commonNaNT a ) { return ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FF8000000000000 ) | ( a.high>>12 ); } /*---------------------------------------------------------------------------- | Takes two double-precision floating-point values `a' and `b', one of which | is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a | signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ static float64 propagateFloat64NaN( float64 a, float64 b ) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; aIsNaN = float64_is_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); bIsNaN = float64_is_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); a |= LIT64( 0x0008000000000000 ); b |= LIT64( 0x0008000000000000 ); if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); if ( aIsNaN ) { return ( aIsSignalingNaN & bIsNaN ) ? b : a; } else { return b; } } #ifdef FLOATX80 /*---------------------------------------------------------------------------- | The pattern for a default generated extended double-precision NaN. The | `high' and `low' values hold the most- and least-significant bits, | respectively. *----------------------------------------------------------------------------*/ #define floatx80_default_nan_high 0xFFFF #define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is a | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ flag floatx80_is_nan( floatx80 a ) { return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is a | signaling NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ flag floatx80_is_signaling_nan( floatx80 a ) { bits64 aLow; aLow = a.low & ~ LIT64( 0x4000000000000000 ); return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( aLow<<1 ) && ( a.low == aLow ); } /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the | invalid exception is raised. *----------------------------------------------------------------------------*/ static commonNaNT floatx80ToCommonNaN( floatx80 a ) { commonNaNT z; if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); z.sign = a.high>>15; z.low = 0; z.high = a.low<<1; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the canonical NaN `a' to the extended | double-precision floating-point format. *----------------------------------------------------------------------------*/ static floatx80 commonNaNToFloatx80( commonNaNT a ) { floatx80 z; z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; return z; } /*---------------------------------------------------------------------------- | Takes two extended double-precision floating-point values `a' and `b', one | of which is a NaN, and returns the appropriate NaN result. If either `a' or | `b' is a signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; aIsNaN = floatx80_is_nan( a ); aIsSignalingNaN = floatx80_is_signaling_nan( a ); bIsNaN = floatx80_is_nan( b ); bIsSignalingNaN = floatx80_is_signaling_nan( b ); a.low |= LIT64( 0xC000000000000000 ); b.low |= LIT64( 0xC000000000000000 ); if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); if ( aIsNaN ) { return ( aIsSignalingNaN & bIsNaN ) ? b : a; } else { return b; } } #endif #ifdef FLOAT128 /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is infinity; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float128_is_inf( float128 a ) { return ( a.low == 0 && ( (bits64) ( a.high<<1 ) == LIT64( 0xFFFE000000000000 ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is a NaN; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float128_is_nan( float128 a ) { return ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is negative; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float128_is_neg( float128 a ) { return ( a.high>>63 ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is a | signaling NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ flag float128_is_signaling_nan( float128 a ) { return ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is subnormal; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float128_is_subnormal( float128 a ) { return ( ( ( a.high>>48 ) & 0x7FFF ) == 0 ) && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is zero; | otherwise returns 0. *----------------------------------------------------------------------------*/ flag float128_is_zero( float128 a ) { return ( a.low == 0 && ( a.high & LIT64( 0x7FFFFFFFFFFFFFFF ) ) == 0 ); } /*---------------------------------------------------------------------------- | Returns the quadruple-precision floating-point value `a' with positive sign. *----------------------------------------------------------------------------*/ float128 float128_pos( float128 a ) { float128 result; result.high = ( a.high & LIT64( 0x7FFFFFFFFFFFFFFF ) ); result.low = a.low; return result; } /*---------------------------------------------------------------------------- | Returns the quadruple-precision floating-point value `a' with negative sign. *----------------------------------------------------------------------------*/ float128 float128_neg( float128 a ) { float128 result; result.high = ( a.high | LIT64( 0x8000000000000000 ) ); result.low = a.low; return result; } /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | signaling NaN `a' to a quiet NaN. *----------------------------------------------------------------------------*/ float128 float128_snan_to_qnan( float128 a ) { float128 result; result.high = ( a.high | LIT64( 0x0000800000000000 ) ); result.low = a.low; return result; } /*---------------------------------------------------------------------------- | Builds a quadruple-precision floating-point value. *----------------------------------------------------------------------------*/ float128 float128_build( int sign, int exp, bits64 fract_high, bits64 fract_low ) { float128 result; result.high = ( (bits64) ( sign ? LIT64( 0x8000000000000000 ) : 0 ) | ( (bits64) ( exp & 0x7FFF ) << 48 ) | ( fract_high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); result.low = fract_low; return result; } /*---------------------------------------------------------------------------- | Returns the exponent of quadruple-precision floating-point value `a'. *----------------------------------------------------------------------------*/ bits16 float128_exp( float128 a ) { return (( a.high>>48 ) & 0x7FFF ); } /*---------------------------------------------------------------------------- | Returns the high-order 48 bits of the fraction of quadruple-precision | floating-point value `a'. *----------------------------------------------------------------------------*/ bits64 float128_fract_high( float128 a ) { return ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ); } /*---------------------------------------------------------------------------- | Returns the low-order 64 bits of the fraction of quadruple-precision | floating-point value `a'. *----------------------------------------------------------------------------*/ bits64 float128_fract_low( float128 a ) { return ( a.low ); } /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ static commonNaNT float128ToCommonNaN( float128 a ) { commonNaNT z; if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); z.sign = a.high>>63; shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the canonical NaN `a' to the quadruple- | precision floating-point format. *----------------------------------------------------------------------------*/ static float128 commonNaNToFloat128( commonNaNT a ) { float128 z; shift128Right( a.high, a.low, 16, &z.high, &z.low ); z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); return z; } /*---------------------------------------------------------------------------- | Takes two quadruple-precision floating-point values `a' and `b', one of | which is a NaN, and returns the appropriate NaN result. If either `a' or | `b' is a signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ static float128 propagateFloat128NaN( float128 a, float128 b ) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; aIsNaN = float128_is_nan( a ); aIsSignalingNaN = float128_is_signaling_nan( a ); bIsNaN = float128_is_nan( b ); bIsSignalingNaN = float128_is_signaling_nan( b ); a.high |= LIT64( 0x0000800000000000 ); b.high |= LIT64( 0x0000800000000000 ); if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); if ( aIsNaN ) { return ( aIsSignalingNaN & bIsNaN ) ? b : a; } else { return b; } } #endif hercules-3.12/softfloat/softfloat.c0000664000175000017500000060714412564723224014365 00000000000000/* THIS FILE HAS BEEN MODIFIED BY THE HERCULES PROJECT */ /*============================================================================ This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic Package, Release 2b. Written by John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. More information is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ arithmetic/SoftFloat.html'. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. Derivative works are acceptable, even for commercial purposes, so long as (1) the source code for the derivative work includes prominent notice that the work is derivative, and (2) the source code includes prominent notice with these four paragraphs for those parts of this code that are retained. =============================================================================*/ #include "milieu.h" #include "softfloat.h" /*---------------------------------------------------------------------------- | Floating-point rounding mode, extended double-precision rounding precision, | and exception flags. *----------------------------------------------------------------------------*/ __thread int8 float_rounding_mode = float_round_nearest_even; __thread int8 float_exception_flags = 0; #ifdef FLOATX80 int8 floatx80_rounding_precision = 80; #endif /*---------------------------------------------------------------------------- | Primitive arithmetic functions, including multi-word arithmetic, and | division and square root approximations. (Can be specialized to target if | desired.) *----------------------------------------------------------------------------*/ #include "softfloat-macros" /*---------------------------------------------------------------------------- | Functions and definitions to determine: (1) whether tininess for underflow | is detected before or after rounding by default, (2) what (if anything) | happens when exceptions are raised, (3) how signaling NaNs are distinguished | from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs | are propagated from function inputs to output. These details are target- | specific. *----------------------------------------------------------------------------*/ #include "softfloat-specialize" /*---------------------------------------------------------------------------- | Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 | and 7, and returns the properly rounded 32-bit integer corresponding to the | input. If `zSign' is 1, the input is negated before being converted to an | integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input | is simply rounded to an integer, with the inexact exception raised if the | input cannot be represented exactly as an integer. However, if the fixed- | point input is too large, the invalid exception is raised and the largest | positive or negative integer is returned. *----------------------------------------------------------------------------*/ static int32 roundAndPackInt32( flag zSign, bits64 absZ ) { int8 roundingMode; flag roundNearestEven; int8 roundIncrement, roundBits; int32 z; roundingMode = float_rounding_mode; roundNearestEven = ( roundingMode == float_round_nearest_even ); roundIncrement = 0x40; if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { roundIncrement = 0; } else { roundIncrement = 0x7F; if ( zSign ) { if ( roundingMode == float_round_up ) roundIncrement = 0; } else { if ( roundingMode == float_round_down ) roundIncrement = 0; } } } roundBits = absZ & 0x7F; absZ = ( absZ + roundIncrement )>>7; absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); z = absZ; if ( zSign ) z = - z; if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; } if ( roundBits ) float_exception_flags |= float_flag_inexact; return z; } /*---------------------------------------------------------------------------- | Takes a 64-bit fixed-point value `absZ' with binary point after bit 56, | and returns the corresponding rounded 32-bit unsigned integer. | Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input is | rounded to an integer, with the inexact exception raised if the input | cannot be represented exactly as an integer. However, if the fixed-point | input is too large, the invalid exception is raised and the largest | unsigned integer is returned. *----------------------------------------------------------------------------*/ static uint32 roundAndPackU32( bits64 absZ ) { int8 roundingMode; flag roundNearestEven; int8 roundIncrement, roundBits; uint32 z; roundingMode = float_rounding_mode; roundNearestEven = ( roundingMode == float_round_nearest_even ); if ( roundNearestEven ) { roundIncrement = 0x40; } else if ( roundingMode == float_round_down || roundingMode == float_round_to_zero ) { roundIncrement = 0; } else { roundIncrement = 0x7F; } roundBits = absZ & 0x7F; absZ = ( absZ + roundIncrement )>>7; absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); z = absZ; if ( absZ>>32 ) { float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); return 0xFFFFFFFF; } if ( roundBits ) float_exception_flags |= float_flag_inexact; return z; } /*---------------------------------------------------------------------------- | Takes the 128-bit fixed-point value formed by concatenating `absZ0' and | `absZ1', with binary point between bits 63 and 64 (between the input words), | and returns the properly rounded 64-bit integer corresponding to the input. | If `zSign' is 1, the input is negated before being converted to an integer. | Ordinarily, the fixed-point input is simply rounded to an integer, with | the inexact exception raised if the input cannot be represented exactly as | an integer. However, if the fixed-point input is too large, the invalid | exception is raised and the largest positive or negative integer is | returned. *----------------------------------------------------------------------------*/ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 ) { int8 roundingMode; flag roundNearestEven, increment; int64 z; roundingMode = float_rounding_mode; roundNearestEven = ( roundingMode == float_round_nearest_even ); increment = ( (sbits64) absZ1 < 0 ); if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0; } else { if ( zSign ) { increment = ( roundingMode == float_round_down ) && absZ1; } else { increment = ( roundingMode == float_round_up ) && absZ1; } } } if ( increment ) { ++absZ0; if ( absZ0 == 0 ) goto overflow; absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven ); } z = absZ0; if ( zSign ) z = - z; if ( z && ( ( z < 0 ) ^ zSign ) ) { overflow: float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); return zSign ? (sbits64) LIT64( 0x8000000000000000 ) : LIT64( 0x7FFFFFFFFFFFFFFF ); } if ( absZ1 ) float_exception_flags |= float_flag_inexact; return z; } /*---------------------------------------------------------------------------- | Takes the 128-bit fixed-point value formed by concatenating `absZ0' and | `absZ1', with binary point between bits 63 and 64 (between the input words), | and returns the corresponding rounded 64-bit unsigned integer. | Ordinarily, the fixed-point input is simply rounded to an integer, with | the inexact exception raised if the input cannot be represented exactly as | an integer. However, if the fixed-point input is too large, the invalid | exception is raised and the largest unsigned integer is returned. *----------------------------------------------------------------------------*/ static uint64 roundAndPackU64( bits64 absZ0, bits64 absZ1 ) { int8 roundingMode; flag roundNearestEven, increment; uint64 z; roundingMode = float_rounding_mode; roundNearestEven = ( roundingMode == float_round_nearest_even ); increment = ( (sbits64) absZ1 < 0 ); if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0; } else { increment = ( roundingMode == float_round_up ) && absZ1; } } if ( increment ) { ++absZ0; if ( absZ0 == 0 ) { float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); return LIT64( 0xFFFFFFFFFFFFFFFF ); } absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven ); } z = absZ0; if ( absZ1 ) float_exception_flags |= float_flag_inexact; return z; } /*---------------------------------------------------------------------------- | Returns the fraction bits of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ INLINE bits32 extractFloat32Frac( float32 a ) { return a & 0x007FFFFF; } /*---------------------------------------------------------------------------- | Returns the exponent bits of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ INLINE int16 extractFloat32Exp( float32 a ) { return ( a>>23 ) & 0xFF; } /*---------------------------------------------------------------------------- | Returns the sign bit of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ INLINE flag extractFloat32Sign( float32 a ) { return a>>31; } /*---------------------------------------------------------------------------- | Normalizes the subnormal single-precision floating-point value represented | by the denormalized significand `aSig'. The normalized exponent and | significand are stored at the locations pointed to by `zExpPtr' and | `zSigPtr', respectively. *----------------------------------------------------------------------------*/ static void normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) { int8 shiftCount; shiftCount = countLeadingZeros32( aSig ) - 8; *zSigPtr = aSig<>7; zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); if ( zSig == 0 ) zExp = 0; return packFloat32( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Takes an abstract floating-point value having sign `zSign', exponent `zExp', | and significand `zSig', and returns the proper single-precision floating- | point value corresponding to the abstract input. This routine is just like | `roundAndPackFloat32' except that `zSig' does not have to be normalized. | Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' | floating-point exponent. *----------------------------------------------------------------------------*/ static float32 normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) { int8 shiftCount; shiftCount = countLeadingZeros32( zSig ) - 1; if (shiftCount >= 0) return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>1 ); } /*---------------------------------------------------------------------------- | Returns the fraction bits of the double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ INLINE bits64 extractFloat64Frac( float64 a ) { return a & LIT64( 0x000FFFFFFFFFFFFF ); } /*---------------------------------------------------------------------------- | Returns the exponent bits of the double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ INLINE int16 extractFloat64Exp( float64 a ) { return ( a>>52 ) & 0x7FF; } /*---------------------------------------------------------------------------- | Returns the sign bit of the double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ INLINE flag extractFloat64Sign( float64 a ) { return a>>63; } /*---------------------------------------------------------------------------- | Normalizes the subnormal double-precision floating-point value represented | by the denormalized significand `aSig'. The normalized exponent and | significand are stored at the locations pointed to by `zExpPtr' and | `zSigPtr', respectively. *----------------------------------------------------------------------------*/ static void normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) { int8 shiftCount; shiftCount = countLeadingZeros64( aSig ) - 11; *zSigPtr = aSig<>10; zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); if ( zSig == 0 ) zExp = 0; return packFloat64( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Takes an abstract floating-point value having sign `zSign', exponent `zExp', | and significand `zSig', and returns the proper double-precision floating- | point value corresponding to the abstract input. This routine is just like | `roundAndPackFloat64' except that `zSig' does not have to be normalized. | Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' | floating-point exponent. *----------------------------------------------------------------------------*/ static float64 normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) { int8 shiftCount; shiftCount = countLeadingZeros64( zSig ) - 1; if (shiftCount >= 0) return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>1 ); } #ifdef FLOATX80 /*---------------------------------------------------------------------------- | Returns the fraction bits of the extended double-precision floating-point | value `a'. *----------------------------------------------------------------------------*/ INLINE bits64 extractFloatx80Frac( floatx80 a ) { return a.low; } /*---------------------------------------------------------------------------- | Returns the exponent bits of the extended double-precision floating-point | value `a'. *----------------------------------------------------------------------------*/ INLINE int32 extractFloatx80Exp( floatx80 a ) { return a.high & 0x7FFF; } /*---------------------------------------------------------------------------- | Returns the sign bit of the extended double-precision floating-point value | `a'. *----------------------------------------------------------------------------*/ INLINE flag extractFloatx80Sign( floatx80 a ) { return a.high>>15; } /*---------------------------------------------------------------------------- | Normalizes the subnormal extended double-precision floating-point value | represented by the denormalized significand `aSig'. The normalized exponent | and significand are stored at the locations pointed to by `zExpPtr' and | `zSigPtr', respectively. *----------------------------------------------------------------------------*/ static void normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) { int8 shiftCount; shiftCount = countLeadingZeros64( aSig ); *zSigPtr = aSig<>48 ) & 0x7FFF; } /*---------------------------------------------------------------------------- | Returns the sign bit of the quadruple-precision floating-point value `a'. *----------------------------------------------------------------------------*/ INLINE flag extractFloat128Sign( float128 a ) { return a.high>>63; } /*---------------------------------------------------------------------------- | Normalizes the subnormal quadruple-precision floating-point value | represented by the denormalized significand formed by the concatenation of | `aSig0' and `aSig1'. The normalized exponent is stored at the location | pointed to by `zExpPtr'. The most significant 49 bits of the normalized | significand are stored at the location pointed to by `zSig0Ptr', and the | least significant 64 bits of the normalized significand are stored at the | location pointed to by `zSig1Ptr'. *----------------------------------------------------------------------------*/ static void normalizeFloat128Subnormal( bits64 aSig0, bits64 aSig1, int32 *zExpPtr, bits64 *zSig0Ptr, bits64 *zSig1Ptr ) { int8 shiftCount; if ( aSig0 == 0 ) { shiftCount = countLeadingZeros64( aSig1 ) - 15; if ( shiftCount < 0 ) { *zSig0Ptr = aSig1>>( - shiftCount ); *zSig1Ptr = aSig1<<( shiftCount & 63 ); } else { *zSig0Ptr = aSig1<>( - shiftCount ); if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { float_exception_flags |= float_flag_inexact; } if ( aSign ) z = - z; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the 64-bit unsigned integer format. If `a' is negative or is a NaN, | zero is returned. Otherwise, if the conversion overflows, the largest | unsigned integer is returned. *----------------------------------------------------------------------------*/ uint64 float32_to_uint64( float32 a ) { flag aSign; int16 aExp, shiftCount; bits32 aSig; bits64 aSig64, aSigExtra; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aSign ) return LIT64( 0x0000000000000000 ); shiftCount = 0xBE - aExp; if ( shiftCount < 0 ) { float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); if ( ( aExp == 0xFF ) && aSig ) { /*@Z900*/ return LIT64( 0x0000000000000000 ); /*@Z900*/ } /*@Z900*/ return LIT64( 0xFFFFFFFFFFFFFFFF ); } if ( aExp ) aSig |= 0x00800000; aSig64 = aSig; aSig64 <<= 40; shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra ); return roundAndPackU64( aSig64, aSigExtra ); } /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the 64-bit two's complement integer format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic---which means in particular that the conversion is rounded | according to the current rounding mode. If `a' is a NaN, the largest | positive integer is returned. Otherwise, if the conversion overflows, the | largest integer with the same sign as `a' is returned. *----------------------------------------------------------------------------*/ int64 float32_to_int64( float32 a ) { flag aSign; int16 aExp, shiftCount; bits32 aSig; bits64 aSig64, aSigExtra; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); shiftCount = 0xBE - aExp; if ( shiftCount < 0 ) { float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); if ( ( aExp == 0xFF ) && aSig ) { /*@Z900*/ return LIT64( 0x8000000000000000 ); /*@Z900*/ } /*@Z900*/ if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { return LIT64( 0x7FFFFFFFFFFFFFFF ); } return (sbits64) LIT64( 0x8000000000000000 ); } if ( aExp ) aSig |= 0x00800000; aSig64 = aSig; aSig64 <<= 40; shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra ); return roundAndPackInt64( aSign, aSig64, aSigExtra ); } /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the 64-bit two's complement integer format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic, except that the conversion is always rounded toward zero. If | `a' is a NaN, the largest positive integer is returned. Otherwise, if the | conversion overflows, the largest integer with the same sign as `a' is | returned. *----------------------------------------------------------------------------*/ int64 float32_to_int64_round_to_zero( float32 a ) { flag aSign; int16 aExp, shiftCount; bits32 aSig; bits64 aSig64; int64 z; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); shiftCount = aExp - 0xBE; if ( 0 <= shiftCount ) { if ( a != 0xDF000000 ) { float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); if ( ( aExp == 0xFF ) && aSig ) { /*@Z900*/ return LIT64( 0x8000000000000000 ); /*@Z900*/ } /*@Z900*/ if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { return LIT64( 0x7FFFFFFFFFFFFFFF ); } } return (sbits64) LIT64( 0x8000000000000000 ); } else if ( aExp <= 0x7E ) { if ( aExp | aSig ) float_exception_flags |= float_flag_inexact; return 0; } aSig64 = aSig | 0x00800000; aSig64 <<= 40; z = aSig64>>( - shiftCount ); if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) { float_exception_flags |= float_flag_inexact; } if ( aSign ) z = - z; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the double-precision floating-point format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ float64 float32_to_float64( float32 a ) { flag aSign; int16 aExp; bits32 aSig; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) ); return packFloat64( aSign, 0x7FF, 0 ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); normalizeFloat32Subnormal( aSig, &aExp, &aSig ); --aExp; } return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); } #ifdef FLOATX80 /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the extended double-precision floating-point format. The conversion | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ floatx80 float32_to_floatx80( float32 a ) { flag aSign; int16 aExp; bits32 aSig; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) ); return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } aSig |= 0x00800000; return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); } #endif #ifdef FLOAT128 /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the double-precision floating-point format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ float128 float32_to_float128( float32 a ) { flag aSign; int16 aExp; bits32 aSig; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) ); return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); normalizeFloat32Subnormal( aSig, &aExp, &aSig ); --aExp; } return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 ); } #endif /*---------------------------------------------------------------------------- | Rounds the single-precision floating-point value `a' to an integer, and | returns the result as a single-precision floating-point value. The | operation is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 float32_round_to_int( float32 a ) { flag aSign; int16 aExp; bits32 lastBitMask, roundBitsMask; int8 roundingMode; float32 z; aExp = extractFloat32Exp( a ); if ( 0x96 <= aExp ) { if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { return propagateFloat32NaN( a, a ); } return a; } if ( aExp <= 0x7E ) { if ( (bits32) ( a<<1 ) == 0 ) return a; float_exception_flags |= float_flag_inexact; aSign = extractFloat32Sign( a ); switch ( float_rounding_mode ) { case float_round_nearest_even: if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { return packFloat32( aSign, 0x7F, 0 ); } break; case float_round_down: return aSign ? 0xBF800000 : 0; case float_round_up: return aSign ? 0x80000000 : 0x3F800000; } return packFloat32( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x96 - aExp; roundBitsMask = lastBitMask - 1; z = a; roundingMode = float_rounding_mode; if ( roundingMode == float_round_nearest_even ) { z += lastBitMask>>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; if ( z != a ) float_exception_flags |= float_flag_inexact; return z; } /*---------------------------------------------------------------------------- | Returns the result of adding the absolute values of the single-precision | floating-point values `a' and `b'. If `zSign' is 1, the sum is negated | before being returned. `zSign' is ignored if the result is a NaN. | The addition is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign ) { int16 aExp, bExp, zExp; bits32 aSig, bSig, zSig; int16 expDiff; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); bSig = extractFloat32Frac( b ); bExp = extractFloat32Exp( b ); expDiff = aExp - bExp; aSig <<= 6; bSig <<= 6; if ( 0 < expDiff ) { if ( aExp == 0xFF ) { if ( aSig ) return propagateFloat32NaN( a, b ); return a; } if ( bExp == 0 ) { --expDiff; } else { bSig |= 0x20000000; } shift32RightJamming( bSig, expDiff, &bSig ); zExp = aExp; } else if ( expDiff < 0 ) { if ( bExp == 0xFF ) { if ( bSig ) return propagateFloat32NaN( a, b ); return packFloat32( zSign, 0xFF, 0 ); } if ( aExp == 0 ) { ++expDiff; } else { aSig |= 0x20000000; } shift32RightJamming( aSig, - expDiff, &aSig ); zExp = bExp; } else { if ( aExp == 0xFF ) { if ( aSig | bSig ) return propagateFloat32NaN( a, b ); return a; } if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); zSig = 0x40000000 + aSig + bSig; zExp = aExp; goto roundAndPack; } aSig |= 0x20000000; zSig = ( aSig + bSig )<<1; --zExp; if ( (sbits32) zSig < 0 ) { zSig = aSig + bSig; ++zExp; } roundAndPack: return roundAndPackFloat32( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the result of subtracting the absolute values of the single- | precision floating-point values `a' and `b'. If `zSign' is 1, the | difference is negated before being returned. `zSign' is ignored if the | result is a NaN. The subtraction is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static float32 subFloat32Sigs( float32 a, float32 b, flag zSign ) { int16 aExp, bExp, zExp; bits32 aSig, bSig, zSig; int16 expDiff; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); bSig = extractFloat32Frac( b ); bExp = extractFloat32Exp( b ); expDiff = aExp - bExp; aSig <<= 7; bSig <<= 7; if ( 0 < expDiff ) goto aExpBigger; if ( expDiff < 0 ) goto bExpBigger; if ( aExp == 0xFF ) { if ( aSig | bSig ) return propagateFloat32NaN( a, b ); float_raise( float_flag_invalid ); return float32_default_nan; } if ( aExp == 0 ) { aExp = 1; bExp = 1; } if ( bSig < aSig ) goto aBigger; if ( aSig < bSig ) goto bBigger; return packFloat32( float_rounding_mode == float_round_down, 0, 0 ); bExpBigger: if ( bExp == 0xFF ) { if ( bSig ) return propagateFloat32NaN( a, b ); return packFloat32( zSign ^ 1, 0xFF, 0 ); } if ( aExp == 0 ) { ++expDiff; } else { aSig |= 0x40000000; } shift32RightJamming( aSig, - expDiff, &aSig ); bSig |= 0x40000000; bBigger: zSig = bSig - aSig; zExp = bExp; zSign ^= 1; goto normalizeRoundAndPack; aExpBigger: if ( aExp == 0xFF ) { if ( aSig ) return propagateFloat32NaN( a, b ); return a; } if ( bExp == 0 ) { --expDiff; } else { bSig |= 0x40000000; } shift32RightJamming( bSig, expDiff, &bSig ); aSig |= 0x40000000; aBigger: zSig = aSig - bSig; zExp = aExp; normalizeRoundAndPack: --zExp; return normalizeRoundAndPackFloat32( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the result of adding the single-precision floating-point values `a' | and `b'. The operation is performed according to the IEC/IEEE Standard for | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 float32_add( float32 a, float32 b ) { flag aSign, bSign; aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); if ( aSign == bSign ) { return addFloat32Sigs( a, b, aSign ); } else { return subFloat32Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of subtracting the single-precision floating-point values | `a' and `b'. The operation is performed according to the IEC/IEEE Standard | for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 float32_sub( float32 a, float32 b ) { flag aSign, bSign; aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); if ( aSign == bSign ) { return subFloat32Sigs( a, b, aSign ); } else { return addFloat32Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of multiplying the single-precision floating-point values | `a' and `b'. The operation is performed according to the IEC/IEEE Standard | for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 float32_mul( float32 a, float32 b ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; bits32 aSig, bSig; bits64 zSig64; bits32 zSig; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); bSig = extractFloat32Frac( b ); bExp = extractFloat32Exp( b ); bSign = extractFloat32Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0xFF ) { if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { return propagateFloat32NaN( a, b ); } if ( ( bExp | bSig ) == 0 ) { float_raise( float_flag_invalid ); return float32_default_nan; } return packFloat32( zSign, 0xFF, 0 ); } if ( bExp == 0xFF ) { if ( bSig ) return propagateFloat32NaN( a, b ); if ( ( aExp | aSig ) == 0 ) { float_raise( float_flag_invalid ); return float32_default_nan; } return packFloat32( zSign, 0xFF, 0 ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } if ( bExp == 0 ) { if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); normalizeFloat32Subnormal( bSig, &bExp, &bSig ); } zExp = aExp + bExp - 0x7F; aSig = ( aSig | 0x00800000 )<<7; bSig = ( bSig | 0x00800000 )<<8; shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); zSig = zSig64; if ( 0 <= (sbits32) ( zSig<<1 ) ) { zSig <<= 1; --zExp; } return roundAndPackFloat32( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the result of dividing the single-precision floating-point value `a' | by the corresponding value `b'. The operation is performed according to the | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 float32_div( float32 a, float32 b ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; bits32 aSig, bSig, zSig; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); bSig = extractFloat32Frac( b ); bExp = extractFloat32Exp( b ); bSign = extractFloat32Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0xFF ) { if ( aSig ) return propagateFloat32NaN( a, b ); if ( bExp == 0xFF ) { if ( bSig ) return propagateFloat32NaN( a, b ); float_raise( float_flag_invalid ); return float32_default_nan; } return packFloat32( zSign, 0xFF, 0 ); } if ( bExp == 0xFF ) { if ( bSig ) return propagateFloat32NaN( a, b ); return packFloat32( zSign, 0, 0 ); } if ( bExp == 0 ) { if ( bSig == 0 ) { if ( ( aExp | aSig ) == 0 ) { float_raise( float_flag_invalid ); return float32_default_nan; } float_raise( float_flag_divbyzero ); return packFloat32( zSign, 0xFF, 0 ); } normalizeFloat32Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } zExp = aExp - bExp + 0x7D; aSig = ( aSig | 0x00800000 )<<7; bSig = ( bSig | 0x00800000 )<<8; if ( bSig <= ( aSig + aSig ) ) { aSig >>= 1; ++zExp; } zSig = ( ( (bits64) aSig )<<32 ) / bSig; if ( ( zSig & 0x3F ) == 0 ) { zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 ); } return roundAndPackFloat32( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the remainder of the single-precision floating-point value `a' | with respect to the corresponding value `b'. The operation is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 float32_rem( float32 a, float32 b ) { flag aSign, bSign, zSign; int16 aExp, bExp, expDiff; bits32 aSig, bSig; bits32 q; bits64 aSig64, bSig64, q64; bits32 alternateASig; sbits32 sigMean; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); bSig = extractFloat32Frac( b ); bExp = extractFloat32Exp( b ); bSign = extractFloat32Sign( b ); if ( aExp == 0xFF ) { if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { return propagateFloat32NaN( a, b ); } float_raise( float_flag_invalid ); return float32_default_nan; } if ( bExp == 0xFF ) { if ( bSig ) return propagateFloat32NaN( a, b ); return a; } if ( bExp == 0 ) { if ( bSig == 0 ) { float_raise( float_flag_invalid ); return float32_default_nan; } normalizeFloat32Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { if ( aSig == 0 ) return a; normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } expDiff = aExp - bExp; aSig |= 0x00800000; bSig |= 0x00800000; if ( expDiff < 32 ) { aSig <<= 8; bSig <<= 8; if ( expDiff < 0 ) { if ( expDiff < -1 ) return a; aSig >>= 1; } q = ( bSig <= aSig ); if ( q ) aSig -= bSig; if ( 0 < expDiff ) { q = ( ( (bits64) aSig )<<32 ) / bSig; q >>= 32 - expDiff; bSig >>= 2; aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; } else { aSig >>= 2; bSig >>= 2; } } else { if ( bSig <= aSig ) aSig -= bSig; aSig64 = ( (bits64) aSig )<<40; bSig64 = ( (bits64) bSig )<<40; expDiff -= 64; while ( 0 < expDiff ) { q64 = estimateDiv128To64( aSig64, 0, bSig64 ); q64 = ( 2 < q64 ) ? q64 - 2 : 0; aSig64 = - ( ( bSig * q64 )<<38 ); expDiff -= 62; } expDiff += 64; q64 = estimateDiv128To64( aSig64, 0, bSig64 ); q64 = ( 2 < q64 ) ? q64 - 2 : 0; q = q64>>( 64 - expDiff ); bSig <<= 6; aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; } do { alternateASig = aSig; ++q; aSig -= bSig; } while ( 0 <= (sbits32) aSig ); sigMean = aSig + alternateASig; if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { aSig = alternateASig; } zSign = ( (sbits32) aSig < 0 ); if ( zSign ) aSig = - aSig; return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig ); } /*---------------------------------------------------------------------------- | Returns the square root of the single-precision floating-point value `a'. | The operation is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 float32_sqrt( float32 a ) { flag aSign; int16 aExp, zExp; bits32 aSig, zSig; bits64 rem, term; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if ( aSig ) return propagateFloat32NaN( a, 0 ); if ( ! aSign ) return a; float_raise( float_flag_invalid ); return float32_default_nan; } if ( aSign ) { if ( ( aExp | aSig ) == 0 ) return a; float_raise( float_flag_invalid ); return float32_default_nan; } if ( aExp == 0 ) { if ( aSig == 0 ) return 0; normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; aSig = ( aSig | 0x00800000 )<<8; zSig = estimateSqrt32( aExp, aSig ) + 2; if ( ( zSig & 0x7F ) <= 5 ) { if ( zSig < 2 ) { zSig = 0x7FFFFFFF; goto roundAndPack; } aSig >>= aExp & 1; term = ( (bits64) zSig ) * zSig; rem = ( ( (bits64) aSig )<<32 ) - term; while ( (sbits64) rem < 0 ) { --zSig; rem += ( ( (bits64) zSig )<<1 ) | 1; } zSig |= ( rem != 0 ); } shift32RightJamming( zSig, 1, &zSig ); roundAndPack: return roundAndPackFloat32( 0, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to | the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float32_eq( float32 a, float32 b ) { if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than | or equal to the corresponding value `b', and 0 otherwise. The comparison | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ flag float32_le( float32 a, float32 b ) { flag aSign, bSign; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); return ( a == b ) || ( aSign ^ ( a < b ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than | the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float32_lt( float32 a, float32 b ) { flag aSign, bSign; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); return ( a != b ) && ( aSign ^ ( a < b ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to | the corresponding value `b', and 0 otherwise. The invalid exception is | raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float32_eq_signaling( float32 a, float32 b ) { if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { float_raise( float_flag_invalid ); return 0; } return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than or | equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not | cause an exception. Otherwise, the comparison is performed according to the | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float32_le_quiet( float32 a, float32 b ) { flag aSign, bSign; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); return ( a == b ) || ( aSign ^ ( a < b ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than | the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an | exception. Otherwise, the comparison is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float32_lt_quiet( float32 a, float32 b ) { flag aSign, bSign; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); return ( a != b ) && ( aSign ^ ( a < b ) ); } /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the 32-bit unsigned integer format. If `a' is negative or is a NaN, | zero is returned. Otherwise, if the conversion overflows, the largest | unsigned integer is returned. *----------------------------------------------------------------------------*/ uint32 float64_to_uint32( float64 a ) { flag aSign; int16 aExp, shiftCount; bits64 aSig; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aSign ) return 0; if ( ( aExp == 0x7FF ) && aSig ) return 0; if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); shiftCount = 0x42C - aExp; if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); return roundAndPackU32( aSig ); } /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the 32-bit two's complement integer format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic---which means in particular that the conversion is rounded | according to the current rounding mode. If `a' is a NaN, the largest | positive integer is returned. Otherwise, if the conversion overflows, the | largest integer with the same sign as `a' is returned. *----------------------------------------------------------------------------*/ int32 float64_to_int32( float64 a ) { flag aSign; int16 aExp, shiftCount; bits64 aSig; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); // if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; if ( ( aExp == 0x7FF ) && aSig ) aSign = 1; /*@Z900*/ if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); shiftCount = 0x42C - aExp; if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); return roundAndPackInt32( aSign, aSig ); } /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the 32-bit two's complement integer format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic, except that the conversion is always rounded toward zero. | If `a' is a NaN, the largest positive integer is returned. Otherwise, if | the conversion overflows, the largest integer with the same sign as `a' is | returned. *----------------------------------------------------------------------------*/ int32 float64_to_int32_round_to_zero( float64 a ) { flag aSign; int16 aExp, shiftCount; bits64 aSig, savedASig; int32 z; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( 0x41E < aExp ) { // if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; if ( ( aExp == 0x7FF ) && aSig ) aSign = 1; /*@Z900*/ goto invalid; } else if ( aExp < 0x3FF ) { if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; return 0; } aSig |= LIT64( 0x0010000000000000 ); shiftCount = 0x433 - aExp; savedASig = aSig; aSig >>= shiftCount; z = aSig; if ( aSign ) z = - z; if ( ( z < 0 ) ^ aSign ) { invalid: float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; } if ( ( aSig<>( - shiftCount ); if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { float_exception_flags |= float_flag_inexact; } } if ( aSign ) z = - z; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the single-precision floating-point format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ float32 float64_to_float32( float64 a ) { flag aSign; int16 aExp; bits64 aSig; bits32 zSig; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a ) ); return packFloat32( aSign, 0xFF, 0 ); } shift64RightJamming( aSig, 22, &aSig ); zSig = aSig; if ( aExp || zSig ) { zSig |= 0x40000000; aExp -= 0x381; } return roundAndPackFloat32( aSign, aExp, zSig ); } #ifdef FLOATX80 /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the extended double-precision floating-point format. The conversion | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ floatx80 float64_to_floatx80( float64 a ) { flag aSign; int16 aExp; bits64 aSig; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a ) ); return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } return packFloatx80( aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 ); } #endif #ifdef FLOAT128 /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the quadruple-precision floating-point format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ float128 float64_to_float128( float64 a ) { flag aSign; int16 aExp; bits64 aSig, zSig0, zSig1; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a ) ); return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); normalizeFloat64Subnormal( aSig, &aExp, &aSig ); --aExp; } shift128Right( aSig, 0, 4, &zSig0, &zSig1 ); return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 ); } #endif /*---------------------------------------------------------------------------- | Rounds the double-precision floating-point value `a' to an integer, and | returns the result as a double-precision floating-point value. The | operation is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 float64_round_to_int( float64 a ) { flag aSign; int16 aExp; bits64 lastBitMask, roundBitsMask; int8 roundingMode; float64 z; aExp = extractFloat64Exp( a ); if ( 0x433 <= aExp ) { if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) { return propagateFloat64NaN( a, a ); } return a; } if ( aExp < 0x3FF ) { if ( (bits64) ( a<<1 ) == 0 ) return a; float_exception_flags |= float_flag_inexact; aSign = extractFloat64Sign( a ); switch ( float_rounding_mode ) { case float_round_nearest_even: if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) { return packFloat64( aSign, 0x3FF, 0 ); } break; case float_round_down: return aSign ? LIT64( 0xBFF0000000000000 ) : 0; case float_round_up: return aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ); } return packFloat64( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x433 - aExp; roundBitsMask = lastBitMask - 1; z = a; roundingMode = float_rounding_mode; if ( roundingMode == float_round_nearest_even ) { z += lastBitMask>>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; if ( z != a ) float_exception_flags |= float_flag_inexact; return z; } /*---------------------------------------------------------------------------- | Returns the result of adding the absolute values of the double-precision | floating-point values `a' and `b'. If `zSign' is 1, the sum is negated | before being returned. `zSign' is ignored if the result is a NaN. | The addition is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign ) { int16 aExp, bExp, zExp; bits64 aSig, bSig, zSig; int16 expDiff; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); bSig = extractFloat64Frac( b ); bExp = extractFloat64Exp( b ); expDiff = aExp - bExp; aSig <<= 9; bSig <<= 9; if ( 0 < expDiff ) { if ( aExp == 0x7FF ) { if ( aSig ) return propagateFloat64NaN( a, b ); return a; } if ( bExp == 0 ) { --expDiff; } else { bSig |= LIT64( 0x2000000000000000 ); } shift64RightJamming( bSig, expDiff, &bSig ); zExp = aExp; } else if ( expDiff < 0 ) { if ( bExp == 0x7FF ) { if ( bSig ) return propagateFloat64NaN( a, b ); return packFloat64( zSign, 0x7FF, 0 ); } if ( aExp == 0 ) { ++expDiff; } else { aSig |= LIT64( 0x2000000000000000 ); } shift64RightJamming( aSig, - expDiff, &aSig ); zExp = bExp; } else { if ( aExp == 0x7FF ) { if ( aSig | bSig ) return propagateFloat64NaN( a, b ); return a; } if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; zExp = aExp; goto roundAndPack; } aSig |= LIT64( 0x2000000000000000 ); zSig = ( aSig + bSig )<<1; --zExp; if ( (sbits64) zSig < 0 ) { zSig = aSig + bSig; ++zExp; } roundAndPack: return roundAndPackFloat64( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the result of subtracting the absolute values of the double- | precision floating-point values `a' and `b'. If `zSign' is 1, the | difference is negated before being returned. `zSign' is ignored if the | result is a NaN. The subtraction is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static float64 subFloat64Sigs( float64 a, float64 b, flag zSign ) { int16 aExp, bExp, zExp; bits64 aSig, bSig, zSig; int16 expDiff; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); bSig = extractFloat64Frac( b ); bExp = extractFloat64Exp( b ); expDiff = aExp - bExp; aSig <<= 10; bSig <<= 10; if ( 0 < expDiff ) goto aExpBigger; if ( expDiff < 0 ) goto bExpBigger; if ( aExp == 0x7FF ) { if ( aSig | bSig ) return propagateFloat64NaN( a, b ); float_raise( float_flag_invalid ); return float64_default_nan; } if ( aExp == 0 ) { aExp = 1; bExp = 1; } if ( bSig < aSig ) goto aBigger; if ( aSig < bSig ) goto bBigger; return packFloat64( float_rounding_mode == float_round_down, 0, 0 ); bExpBigger: if ( bExp == 0x7FF ) { if ( bSig ) return propagateFloat64NaN( a, b ); return packFloat64( zSign ^ 1, 0x7FF, 0 ); } if ( aExp == 0 ) { ++expDiff; } else { aSig |= LIT64( 0x4000000000000000 ); } shift64RightJamming( aSig, - expDiff, &aSig ); bSig |= LIT64( 0x4000000000000000 ); bBigger: zSig = bSig - aSig; zExp = bExp; zSign ^= 1; goto normalizeRoundAndPack; aExpBigger: if ( aExp == 0x7FF ) { if ( aSig ) return propagateFloat64NaN( a, b ); return a; } if ( bExp == 0 ) { --expDiff; } else { bSig |= LIT64( 0x4000000000000000 ); } shift64RightJamming( bSig, expDiff, &bSig ); aSig |= LIT64( 0x4000000000000000 ); aBigger: zSig = aSig - bSig; zExp = aExp; normalizeRoundAndPack: --zExp; return normalizeRoundAndPackFloat64( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the result of adding the double-precision floating-point values `a' | and `b'. The operation is performed according to the IEC/IEEE Standard for | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 float64_add( float64 a, float64 b ) { flag aSign, bSign; aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); if ( aSign == bSign ) { return addFloat64Sigs( a, b, aSign ); } else { return subFloat64Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of subtracting the double-precision floating-point values | `a' and `b'. The operation is performed according to the IEC/IEEE Standard | for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 float64_sub( float64 a, float64 b ) { flag aSign, bSign; aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); if ( aSign == bSign ) { return subFloat64Sigs( a, b, aSign ); } else { return addFloat64Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of multiplying the double-precision floating-point values | `a' and `b'. The operation is performed according to the IEC/IEEE Standard | for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 float64_mul( float64 a, float64 b ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; bits64 aSig, bSig, zSig0, zSig1; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); bSig = extractFloat64Frac( b ); bExp = extractFloat64Exp( b ); bSign = extractFloat64Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FF ) { if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { return propagateFloat64NaN( a, b ); } if ( ( bExp | bSig ) == 0 ) { float_raise( float_flag_invalid ); return float64_default_nan; } return packFloat64( zSign, 0x7FF, 0 ); } if ( bExp == 0x7FF ) { if ( bSig ) return propagateFloat64NaN( a, b ); if ( ( aExp | aSig ) == 0 ) { float_raise( float_flag_invalid ); return float64_default_nan; } return packFloat64( zSign, 0x7FF, 0 ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } if ( bExp == 0 ) { if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); normalizeFloat64Subnormal( bSig, &bExp, &bSig ); } zExp = aExp + bExp - 0x3FF; aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; mul64To128( aSig, bSig, &zSig0, &zSig1 ); zSig0 |= ( zSig1 != 0 ); if ( 0 <= (sbits64) ( zSig0<<1 ) ) { zSig0 <<= 1; --zExp; } return roundAndPackFloat64( zSign, zExp, zSig0 ); } /*---------------------------------------------------------------------------- | Returns the result of dividing the double-precision floating-point value `a' | by the corresponding value `b'. The operation is performed according to | the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 float64_div( float64 a, float64 b ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; bits64 aSig, bSig, zSig; bits64 rem0, rem1; bits64 term0, term1; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); bSig = extractFloat64Frac( b ); bExp = extractFloat64Exp( b ); bSign = extractFloat64Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FF ) { if ( aSig ) return propagateFloat64NaN( a, b ); if ( bExp == 0x7FF ) { if ( bSig ) return propagateFloat64NaN( a, b ); float_raise( float_flag_invalid ); return float64_default_nan; } return packFloat64( zSign, 0x7FF, 0 ); } if ( bExp == 0x7FF ) { if ( bSig ) return propagateFloat64NaN( a, b ); return packFloat64( zSign, 0, 0 ); } if ( bExp == 0 ) { if ( bSig == 0 ) { if ( ( aExp | aSig ) == 0 ) { float_raise( float_flag_invalid ); return float64_default_nan; } float_raise( float_flag_divbyzero ); return packFloat64( zSign, 0x7FF, 0 ); } normalizeFloat64Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } zExp = aExp - bExp + 0x3FD; aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; if ( bSig <= ( aSig + aSig ) ) { aSig >>= 1; ++zExp; } zSig = estimateDiv128To64( aSig, 0, bSig ); if ( ( zSig & 0x1FF ) <= 2 ) { mul64To128( bSig, zSig, &term0, &term1 ); sub128( aSig, 0, term0, term1, &rem0, &rem1 ); while ( (sbits64) rem0 < 0 ) { --zSig; add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); } zSig |= ( rem1 != 0 ); } return roundAndPackFloat64( zSign, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the remainder of the double-precision floating-point value `a' | with respect to the corresponding value `b'. The operation is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 float64_rem( float64 a, float64 b ) { flag aSign, bSign, zSign; int16 aExp, bExp, expDiff; bits64 aSig, bSig; bits64 q, alternateASig; sbits64 sigMean; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); bSig = extractFloat64Frac( b ); bExp = extractFloat64Exp( b ); bSign = extractFloat64Sign( b ); if ( aExp == 0x7FF ) { if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { return propagateFloat64NaN( a, b ); } float_raise( float_flag_invalid ); return float64_default_nan; } if ( bExp == 0x7FF ) { if ( bSig ) return propagateFloat64NaN( a, b ); return a; } if ( bExp == 0 ) { if ( bSig == 0 ) { float_raise( float_flag_invalid ); return float64_default_nan; } normalizeFloat64Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { if ( aSig == 0 ) return a; normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } expDiff = aExp - bExp; aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; if ( expDiff < 0 ) { if ( expDiff < -1 ) return a; aSig >>= 1; } q = ( bSig <= aSig ); if ( q ) aSig -= bSig; expDiff -= 64; while ( 0 < expDiff ) { q = estimateDiv128To64( aSig, 0, bSig ); q = ( 2 < q ) ? q - 2 : 0; aSig = - ( ( bSig>>2 ) * q ); expDiff -= 62; } expDiff += 64; if ( 0 < expDiff ) { q = estimateDiv128To64( aSig, 0, bSig ); q = ( 2 < q ) ? q - 2 : 0; q >>= 64 - expDiff; bSig >>= 2; aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; } else { aSig >>= 2; bSig >>= 2; } do { alternateASig = aSig; ++q; aSig -= bSig; } while ( 0 <= (sbits64) aSig ); sigMean = aSig + alternateASig; if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { aSig = alternateASig; } zSign = ( (sbits64) aSig < 0 ); if ( zSign ) aSig = - aSig; return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig ); } /*---------------------------------------------------------------------------- | Returns the square root of the double-precision floating-point value `a'. | The operation is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 float64_sqrt( float64 a ) { flag aSign; int16 aExp, zExp; bits64 aSig, zSig, doubleZSig; bits64 rem0, rem1, term0, term1; aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { if ( aSig ) return propagateFloat64NaN( a, a ); if ( ! aSign ) return a; float_raise( float_flag_invalid ); return float64_default_nan; } if ( aSign ) { if ( ( aExp | aSig ) == 0 ) return a; float_raise( float_flag_invalid ); return float64_default_nan; } if ( aExp == 0 ) { if ( aSig == 0 ) return 0; normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; aSig |= LIT64( 0x0010000000000000 ); zSig = estimateSqrt32( aExp, aSig>>21 ); aSig <<= 9 - ( aExp & 1 ); zSig = estimateDiv128To64( aSig, 0, zSig<<32 ) + ( zSig<<30 ); if ( ( zSig & 0x1FF ) <= 5 ) { doubleZSig = zSig<<1; mul64To128( zSig, zSig, &term0, &term1 ); sub128( aSig, 0, term0, term1, &rem0, &rem1 ); while ( (sbits64) rem0 < 0 ) { --zSig; doubleZSig -= 2; add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 ); } zSig |= ( ( rem0 | rem1 ) != 0 ); } return roundAndPackFloat64( 0, zExp, zSig ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the | corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float64_eq( float64 a, float64 b ) { if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than or | equal to the corresponding value `b', and 0 otherwise. The comparison is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ flag float64_le( float64 a, float64 b ) { flag aSign, bSign; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); return ( a == b ) || ( aSign ^ ( a < b ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than | the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float64_lt( float64 a, float64 b ) { flag aSign, bSign; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); return ( a != b ) && ( aSign ^ ( a < b ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the | corresponding value `b', and 0 otherwise. The invalid exception is raised | if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float64_eq_signaling( float64 a, float64 b ) { if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { float_raise( float_flag_invalid ); return 0; } return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than or | equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not | cause an exception. Otherwise, the comparison is performed according to the | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float64_le_quiet( float64 a, float64 b ) { flag aSign, bSign; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); return ( a == b ) || ( aSign ^ ( a < b ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than | the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an | exception. Otherwise, the comparison is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float64_lt_quiet( float64 a, float64 b ) { flag aSign, bSign; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); return ( a != b ) && ( aSign ^ ( a < b ) ); } #ifdef FLOATX80 /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the 32-bit two's complement integer format. The | conversion is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic---which means in particular that the conversion | is rounded according to the current rounding mode. If `a' is a NaN, the | largest positive integer is returned. Otherwise, if the conversion | overflows, the largest integer with the same sign as `a' is returned. *----------------------------------------------------------------------------*/ int32 floatx80_to_int32( floatx80 a ) { flag aSign; int32 aExp, shiftCount; bits64 aSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; shiftCount = 0x4037 - aExp; if ( shiftCount <= 0 ) shiftCount = 1; shift64RightJamming( aSig, shiftCount, &aSig ); return roundAndPackInt32( aSign, aSig ); } /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the 32-bit two's complement integer format. The | conversion is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic, except that the conversion is always rounded | toward zero. If `a' is a NaN, the largest positive integer is returned. | Otherwise, if the conversion overflows, the largest integer with the same | sign as `a' is returned. *----------------------------------------------------------------------------*/ int32 floatx80_to_int32_round_to_zero( floatx80 a ) { flag aSign; int32 aExp, shiftCount; bits64 aSig, savedASig; int32 z; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( 0x401E < aExp ) { if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; goto invalid; } else if ( aExp < 0x3FFF ) { if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; return 0; } shiftCount = 0x403E - aExp; savedASig = aSig; aSig >>= shiftCount; z = aSig; if ( aSign ) z = - z; if ( ( z < 0 ) ^ aSign ) { invalid: float_raise( float_flag_invalid ); return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; } if ( ( aSig<>( - shiftCount ); if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { float_exception_flags |= float_flag_inexact; } if ( aSign ) z = - z; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the single-precision floating-point format. The | conversion is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float32 floatx80_to_float32( floatx80 a ) { flag aSign; int32 aExp; bits64 aSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) ) { return commonNaNToFloat32( floatx80ToCommonNaN( a ) ); } return packFloat32( aSign, 0xFF, 0 ); } shift64RightJamming( aSig, 33, &aSig ); if ( aExp || aSig ) aExp -= 0x3F81; return roundAndPackFloat32( aSign, aExp, aSig ); } /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the double-precision floating-point format. The | conversion is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float64 floatx80_to_float64( floatx80 a ) { flag aSign; int32 aExp; bits64 aSig, zSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) ) { return commonNaNToFloat64( floatx80ToCommonNaN( a ) ); } return packFloat64( aSign, 0x7FF, 0 ); } shift64RightJamming( aSig, 1, &zSig ); if ( aExp || aSig ) aExp -= 0x3C01; return roundAndPackFloat64( aSign, aExp, zSig ); } #ifdef FLOAT128 /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the quadruple-precision floating-point format. The | conversion is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 floatx80_to_float128( floatx80 a ) { flag aSign; int16 aExp; bits64 aSig, zSig0, zSig1; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) { return commonNaNToFloat128( floatx80ToCommonNaN( a ) ); } shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); return packFloat128( aSign, aExp, zSig0, zSig1 ); } #endif /*---------------------------------------------------------------------------- | Rounds the extended double-precision floating-point value `a' to an integer, | and returns the result as an extended quadruple-precision floating-point | value. The operation is performed according to the IEC/IEEE Standard for | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 floatx80_round_to_int( floatx80 a ) { flag aSign; int32 aExp; bits64 lastBitMask, roundBitsMask; int8 roundingMode; floatx80 z; aExp = extractFloatx80Exp( a ); if ( 0x403E <= aExp ) { if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) { return propagateFloatx80NaN( a, a ); } return a; } if ( aExp < 0x3FFF ) { if ( ( aExp == 0 ) && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { return a; } float_exception_flags |= float_flag_inexact; aSign = extractFloatx80Sign( a ); switch ( float_rounding_mode ) { case float_round_nearest_even: if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) { return packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) ); } break; case float_round_down: return aSign ? packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) ) : packFloatx80( 0, 0, 0 ); case float_round_up: return aSign ? packFloatx80( 1, 0, 0 ) : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) ); } return packFloatx80( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x403E - aExp; roundBitsMask = lastBitMask - 1; z = a; roundingMode = float_rounding_mode; if ( roundingMode == float_round_nearest_even ) { z.low += lastBitMask>>1; if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { z.low += roundBitsMask; } } z.low &= ~ roundBitsMask; if ( z.low == 0 ) { ++z.high; z.low = LIT64( 0x8000000000000000 ); } if ( z.low != a.low ) float_exception_flags |= float_flag_inexact; return z; } /*---------------------------------------------------------------------------- | Returns the result of adding the absolute values of the extended double- | precision floating-point values `a' and `b'. If `zSign' is 1, the sum is | negated before being returned. `zSign' is ignored if the result is a NaN. | The addition is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) { int32 aExp, bExp, zExp; bits64 aSig, bSig, zSig0, zSig1; int32 expDiff; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); bSig = extractFloatx80Frac( b ); bExp = extractFloatx80Exp( b ); expDiff = aExp - bExp; if ( 0 < expDiff ) { if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); return a; } if ( bExp == 0 ) --expDiff; shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); zExp = aExp; } else if ( expDiff < 0 ) { if ( bExp == 0x7FFF ) { if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) ++expDiff; shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); zExp = bExp; } else { if ( aExp == 0x7FFF ) { if ( (bits64) ( ( aSig | bSig )<<1 ) ) { return propagateFloatx80NaN( a, b ); } return a; } zSig1 = 0; zSig0 = aSig + bSig; if ( aExp == 0 ) { normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); goto roundAndPack; } zExp = aExp; goto shiftRight1; } zSig0 = aSig + bSig; if ( (sbits64) zSig0 < 0 ) goto roundAndPack; shiftRight1: shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); zSig0 |= LIT64( 0x8000000000000000 ); ++zExp; roundAndPack: return roundAndPackFloatx80( floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); } /*---------------------------------------------------------------------------- | Returns the result of subtracting the absolute values of the extended | double-precision floating-point values `a' and `b'. If `zSign' is 1, the | difference is negated before being returned. `zSign' is ignored if the | result is a NaN. The subtraction is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) { int32 aExp, bExp, zExp; bits64 aSig, bSig, zSig0, zSig1; int32 expDiff; floatx80 z; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); bSig = extractFloatx80Frac( b ); bExp = extractFloatx80Exp( b ); expDiff = aExp - bExp; if ( 0 < expDiff ) goto aExpBigger; if ( expDiff < 0 ) goto bExpBigger; if ( aExp == 0x7FFF ) { if ( (bits64) ( ( aSig | bSig )<<1 ) ) { return propagateFloatx80NaN( a, b ); } float_raise( float_flag_invalid ); z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; return z; } if ( aExp == 0 ) { aExp = 1; bExp = 1; } zSig1 = 0; if ( bSig < aSig ) goto aBigger; if ( aSig < bSig ) goto bBigger; return packFloatx80( float_rounding_mode == float_round_down, 0, 0 ); bExpBigger: if ( bExp == 0x7FFF ) { if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) ++expDiff; shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); bBigger: sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); zExp = bExp; zSign ^= 1; goto normalizeRoundAndPack; aExpBigger: if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); return a; } if ( bExp == 0 ) --expDiff; shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); aBigger: sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); zExp = aExp; normalizeRoundAndPack: return normalizeRoundAndPackFloatx80( floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); } /*---------------------------------------------------------------------------- | Returns the result of adding the extended double-precision floating-point | values `a' and `b'. The operation is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 floatx80_add( floatx80 a, floatx80 b ) { flag aSign, bSign; aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { return addFloatx80Sigs( a, b, aSign ); } else { return subFloatx80Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of subtracting the extended double-precision floating- | point values `a' and `b'. The operation is performed according to the | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 floatx80_sub( floatx80 a, floatx80 b ) { flag aSign, bSign; aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { return subFloatx80Sigs( a, b, aSign ); } else { return addFloatx80Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of multiplying the extended double-precision floating- | point values `a' and `b'. The operation is performed according to the | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 floatx80_mul( floatx80 a, floatx80 b ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; bits64 aSig, bSig, zSig0, zSig1; floatx80 z; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); bSig = extractFloatx80Frac( b ); bExp = extractFloatx80Exp( b ); bSign = extractFloatx80Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { return propagateFloatx80NaN( a, b ); } if ( ( bExp | bSig ) == 0 ) goto invalid; return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( bExp == 0x7FFF ) { if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); if ( ( aExp | aSig ) == 0 ) { invalid: float_raise( float_flag_invalid ); z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; return z; } return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); } if ( bExp == 0 ) { if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); } zExp = aExp + bExp - 0x3FFE; mul64To128( aSig, bSig, &zSig0, &zSig1 ); if ( 0 < (sbits64) zSig0 ) { shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); --zExp; } return roundAndPackFloatx80( floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); } /*---------------------------------------------------------------------------- | Returns the result of dividing the extended double-precision floating-point | value `a' by the corresponding value `b'. The operation is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 floatx80_div( floatx80 a, floatx80 b ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; bits64 aSig, bSig, zSig0, zSig1; bits64 rem0, rem1, rem2, term0, term1, term2; floatx80 z; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); bSig = extractFloatx80Frac( b ); bExp = extractFloatx80Exp( b ); bSign = extractFloatx80Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); if ( bExp == 0x7FFF ) { if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); goto invalid; } return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( bExp == 0x7FFF ) { if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); return packFloatx80( zSign, 0, 0 ); } if ( bExp == 0 ) { if ( bSig == 0 ) { if ( ( aExp | aSig ) == 0 ) { invalid: float_raise( float_flag_invalid ); z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; return z; } float_raise( float_flag_divbyzero ); return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); } zExp = aExp - bExp + 0x3FFE; rem1 = 0; if ( bSig <= aSig ) { shift128Right( aSig, 0, 1, &aSig, &rem1 ); ++zExp; } zSig0 = estimateDiv128To64( aSig, rem1, bSig ); mul64To128( bSig, zSig0, &term0, &term1 ); sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); while ( (sbits64) rem0 < 0 ) { --zSig0; add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); } zSig1 = estimateDiv128To64( rem1, 0, bSig ); if ( (bits64) ( zSig1<<1 ) <= 8 ) { mul64To128( bSig, zSig1, &term1, &term2 ); sub128( rem1, 0, term1, term2, &rem1, &rem2 ); while ( (sbits64) rem1 < 0 ) { --zSig1; add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); } zSig1 |= ( ( rem1 | rem2 ) != 0 ); } return roundAndPackFloatx80( floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); } /*---------------------------------------------------------------------------- | Returns the remainder of the extended double-precision floating-point value | `a' with respect to the corresponding value `b'. The operation is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 floatx80_rem( floatx80 a, floatx80 b ) { flag aSign, bSign, zSign; int32 aExp, bExp, expDiff; bits64 aSig0, aSig1, bSig; bits64 q, term0, term1, alternateASig0, alternateASig1; floatx80 z; aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); bSig = extractFloatx80Frac( b ); bExp = extractFloatx80Exp( b ); bSign = extractFloatx80Sign( b ); if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig0<<1 ) || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { return propagateFloatx80NaN( a, b ); } goto invalid; } if ( bExp == 0x7FFF ) { if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); return a; } if ( bExp == 0 ) { if ( bSig == 0 ) { invalid: float_raise( float_flag_invalid ); z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; return z; } normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { if ( (bits64) ( aSig0<<1 ) == 0 ) return a; normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); } bSig |= LIT64( 0x8000000000000000 ); zSign = aSign; expDiff = aExp - bExp; aSig1 = 0; if ( expDiff < 0 ) { if ( expDiff < -1 ) return a; shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); expDiff = 0; } q = ( bSig <= aSig0 ); if ( q ) aSig0 -= bSig; expDiff -= 64; while ( 0 < expDiff ) { q = estimateDiv128To64( aSig0, aSig1, bSig ); q = ( 2 < q ) ? q - 2 : 0; mul64To128( bSig, q, &term0, &term1 ); sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); expDiff -= 62; } expDiff += 64; if ( 0 < expDiff ) { q = estimateDiv128To64( aSig0, aSig1, bSig ); q = ( 2 < q ) ? q - 2 : 0; q >>= 64 - expDiff; mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); while ( le128( term0, term1, aSig0, aSig1 ) ) { ++q; sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); } } else { term1 = 0; term0 = bSig; } sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) && ( q & 1 ) ) ) { aSig0 = alternateASig0; aSig1 = alternateASig1; zSign = ! zSign; } return normalizeRoundAndPackFloatx80( 80, zSign, bExp + expDiff, aSig0, aSig1 ); } /*---------------------------------------------------------------------------- | Returns the square root of the extended double-precision floating-point | value `a'. The operation is performed according to the IEC/IEEE Standard | for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 floatx80_sqrt( floatx80 a ) { flag aSign; int32 aExp, zExp; bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0; bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; floatx80 z; aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a ); if ( ! aSign ) return a; goto invalid; } if ( aSign ) { if ( ( aExp | aSig0 ) == 0 ) return a; invalid: float_raise( float_flag_invalid ); z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; return z; } if ( aExp == 0 ) { if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); } zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; zSig0 = estimateSqrt32( aExp, aSig0>>32 ); shift128Right( aSig0, 0, 2 + ( aExp & 1 ), &aSig0, &aSig1 ); zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); doubleZSig0 = zSig0<<1; mul64To128( zSig0, zSig0, &term0, &term1 ); sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); while ( (sbits64) rem0 < 0 ) { --zSig0; doubleZSig0 -= 2; add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); } zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); if ( ( zSig1 & LIT64( 0x3FFFFFFFFFFFFFFF ) ) <= 5 ) { if ( zSig1 == 0 ) zSig1 = 1; mul64To128( doubleZSig0, zSig1, &term1, &term2 ); sub128( rem1, 0, term1, term2, &rem1, &rem2 ); mul64To128( zSig1, zSig1, &term2, &term3 ); sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); while ( (sbits64) rem1 < 0 ) { --zSig1; shortShift128Left( 0, zSig1, 1, &term2, &term3 ); term3 |= 1; term2 |= doubleZSig0; add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); } zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); } shortShift128Left( 0, zSig1, 1, &zSig0, &zSig1 ); zSig0 |= doubleZSig0; return roundAndPackFloatx80( floatx80_rounding_precision, 0, zExp, zSig0, zSig1 ); } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is | equal to the corresponding value `b', and 0 otherwise. The comparison is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ flag floatx80_eq( floatx80 a, floatx80 b ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( b )<<1 ) ) ) { if ( floatx80_is_signaling_nan( a ) || floatx80_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is | less than or equal to the corresponding value `b', and 0 otherwise. The | comparison is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag floatx80_le( floatx80 a, floatx80 b ) { flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( b )<<1 ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign != bSign ) { return aSign || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return aSign ? le128( b.high, b.low, a.high, a.low ) : le128( a.high, a.low, b.high, b.low ); } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is | less than the corresponding value `b', and 0 otherwise. The comparison | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ flag floatx80_lt( floatx80 a, floatx80 b ) { flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( b )<<1 ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign != bSign ) { return aSign && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return aSign ? lt128( b.high, b.low, a.high, a.low ) : lt128( a.high, a.low, b.high, b.low ); } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is equal | to the corresponding value `b', and 0 otherwise. The invalid exception is | raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag floatx80_eq_signaling( floatx80 a, floatx80 b ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( b )<<1 ) ) ) { float_raise( float_flag_invalid ); return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is less | than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs | do not cause an exception. Otherwise, the comparison is performed according | to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag floatx80_le_quiet( floatx80 a, floatx80 b ) { flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( b )<<1 ) ) ) { if ( floatx80_is_signaling_nan( a ) || floatx80_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign != bSign ) { return aSign || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return aSign ? le128( b.high, b.low, a.high, a.low ) : le128( a.high, a.low, b.high, b.low ); } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is less | than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause | an exception. Otherwise, the comparison is performed according to the | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag floatx80_lt_quiet( floatx80 a, floatx80 b ) { flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (bits64) ( extractFloatx80Frac( b )<<1 ) ) ) { if ( floatx80_is_signaling_nan( a ) || floatx80_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign != bSign ) { return aSign && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return aSign ? lt128( b.high, b.low, a.high, a.low ) : lt128( a.high, a.low, b.high, b.low ); } #endif #ifdef FLOAT128 /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the 32-bit unsigned integer format. If `a' is negative or | is a NaN, zero is returned. Otherwise, if the conversion overflows, the | largest unsigned integer is returned. *----------------------------------------------------------------------------*/ uint32 float128_to_uint32( float128 a ) { flag aSign; int32 aExp, shiftCount; bits64 aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aSign ) return 0; if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) return 0; if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 ); aSig0 |= ( aSig1 != 0 ); shiftCount = 0x4028 - aExp; if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); return roundAndPackU32( aSig0 ); } /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the 32-bit two's complement integer format. The conversion | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic---which means in particular that the conversion is rounded | according to the current rounding mode. If `a' is a NaN, the largest | positive integer is returned. Otherwise, if the conversion overflows, the | largest integer with the same sign as `a' is returned. *----------------------------------------------------------------------------*/ int32 float128_to_int32( float128 a ) { flag aSign; int32 aExp, shiftCount; bits64 aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); // if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0; if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 1; /*@Z900*/ if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 ); aSig0 |= ( aSig1 != 0 ); shiftCount = 0x4028 - aExp; if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); return roundAndPackInt32( aSign, aSig0 ); } /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the 32-bit two's complement integer format. The conversion | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic, except that the conversion is always rounded toward zero. If | `a' is a NaN, the largest positive integer is returned. Otherwise, if the | conversion overflows, the largest integer with the same sign as `a' is | returned. *----------------------------------------------------------------------------*/ int32 float128_to_int32_round_to_zero( float128 a ) { flag aSign; int32 aExp, shiftCount; bits64 aSig0, aSig1, savedASig; int32 z; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); aSig0 |= ( aSig1 != 0 ); if ( 0x401E < aExp ) { // if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0; if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 1; /*@Z900*/ goto invalid; } else if ( aExp < 0x3FFF ) { if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact; return 0; } aSig0 |= LIT64( 0x0001000000000000 ); shiftCount = 0x402F - aExp; savedASig = aSig0; aSig0 >>= shiftCount; z = aSig0; if ( aSign ) z = - z; if ( ( z < 0 ) ^ aSign ) { invalid: float_raise( float_flag_inexact ); /*@Z900*/ float_raise( float_flag_invalid ); return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; } if ( ( aSig0<>( ( - shiftCount ) & 63 ) ); if ( (bits64) ( aSig1<>( - shiftCount ); if ( aSig1 || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) { float_exception_flags |= float_flag_inexact; } } if ( aSign ) z = - z; return z; } /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the single-precision floating-point format. The conversion | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ float32 float128_to_float32( float128 a ) { flag aSign; int32 aExp; bits64 aSig0, aSig1; bits32 zSig; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { return commonNaNToFloat32( float128ToCommonNaN( a ) ); } return packFloat32( aSign, 0xFF, 0 ); } aSig0 |= ( aSig1 != 0 ); shift64RightJamming( aSig0, 18, &aSig0 ); zSig = aSig0; if ( aExp || zSig ) { zSig |= 0x40000000; aExp -= 0x3F81; } return roundAndPackFloat32( aSign, aExp, zSig ); } /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the double-precision floating-point format. The conversion | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ float64 float128_to_float64( float128 a ) { flag aSign; int32 aExp; bits64 aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { return commonNaNToFloat64( float128ToCommonNaN( a ) ); } return packFloat64( aSign, 0x7FF, 0 ); } shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); aSig0 |= ( aSig1 != 0 ); if ( aExp || aSig0 ) { aSig0 |= LIT64( 0x4000000000000000 ); aExp -= 0x3C01; } return roundAndPackFloat64( aSign, aExp, aSig0 ); } #ifdef FLOATX80 /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the extended double-precision floating-point format. The | conversion is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ floatx80 float128_to_floatx80( float128 a ) { flag aSign; int32 aExp; bits64 aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { return commonNaNToFloatx80( float128ToCommonNaN( a ) ); } return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 ); normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); } else { aSig0 |= LIT64( 0x0001000000000000 ); } shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 ); return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 ); } #endif /*---------------------------------------------------------------------------- | Rounds the quadruple-precision floating-point value `a' to an integer, and | returns the result as a quadruple-precision floating-point value. The | operation is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 float128_round_to_int( float128 a ) { flag aSign; int32 aExp; bits64 lastBitMask, roundBitsMask; int8 roundingMode; float128 z; aExp = extractFloat128Exp( a ); if ( 0x402F <= aExp ) { if ( 0x406F <= aExp ) { if ( ( aExp == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) { return propagateFloat128NaN( a, a ); } return a; } lastBitMask = 1; lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1; roundBitsMask = lastBitMask - 1; z = a; roundingMode = float_rounding_mode; if ( roundingMode == float_round_nearest_even ) { if ( lastBitMask ) { add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low ); if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; } else { if ( (sbits64) z.low < 0 ) { ++z.high; if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; } } } else if ( roundingMode != float_round_to_zero ) { if ( extractFloat128Sign( z ) ^ ( roundingMode == float_round_up ) ) { add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); } } z.low &= ~ roundBitsMask; } else { if ( aExp < 0x3FFF ) { if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; float_exception_flags |= float_flag_inexact; aSign = extractFloat128Sign( a ); switch ( float_rounding_mode ) { case float_round_nearest_even: if ( ( aExp == 0x3FFE ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) { return packFloat128( aSign, 0x3FFF, 0, 0 ); } break; case float_round_down: return aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) : packFloat128( 0, 0, 0, 0 ); case float_round_up: return aSign ? packFloat128( 1, 0, 0, 0 ) : packFloat128( 0, 0x3FFF, 0, 0 ); } return packFloat128( aSign, 0, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x402F - aExp; roundBitsMask = lastBitMask - 1; z.low = 0; z.high = a.high; roundingMode = float_rounding_mode; if ( roundingMode == float_round_nearest_even ) { z.high += lastBitMask>>1; if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { z.high &= ~ lastBitMask; } } else if ( roundingMode != float_round_to_zero ) { if ( extractFloat128Sign( z ) ^ ( roundingMode == float_round_up ) ) { z.high |= ( a.low != 0 ); z.high += roundBitsMask; } } z.high &= ~ roundBitsMask; } if ( ( z.low != a.low ) || ( z.high != a.high ) ) { float_exception_flags |= float_flag_inexact; } return z; } /*---------------------------------------------------------------------------- | Returns the result of adding the absolute values of the quadruple-precision | floating-point values `a' and `b'. If `zSign' is 1, the sum is negated | before being returned. `zSign' is ignored if the result is a NaN. | The addition is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign ) { int32 aExp, bExp, zExp; bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; int32 expDiff; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); bSig1 = extractFloat128Frac1( b ); bSig0 = extractFloat128Frac0( b ); bExp = extractFloat128Exp( b ); expDiff = aExp - bExp; if ( 0 < expDiff ) { if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); return a; } if ( bExp == 0 ) { --expDiff; } else { bSig0 |= LIT64( 0x0001000000000000 ); } shift128ExtraRightJamming( bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); zExp = aExp; } else if ( expDiff < 0 ) { if ( bExp == 0x7FFF ) { if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); return packFloat128( zSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { ++expDiff; } else { aSig0 |= LIT64( 0x0001000000000000 ); } shift128ExtraRightJamming( aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); zExp = bExp; } else { if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 | bSig0 | bSig1 ) { return propagateFloat128NaN( a, b ); } return a; } add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); zSig2 = 0; zSig0 |= LIT64( 0x0002000000000000 ); zExp = aExp; goto shiftRight1; } aSig0 |= LIT64( 0x0001000000000000 ); add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); --zExp; if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; ++zExp; shiftRight1: shift128ExtraRightJamming( zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); roundAndPack: return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); } /*---------------------------------------------------------------------------- | Returns the result of subtracting the absolute values of the quadruple- | precision floating-point values `a' and `b'. If `zSign' is 1, the | difference is negated before being returned. `zSign' is ignored if the | result is a NaN. The subtraction is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ static float128 subFloat128Sigs( float128 a, float128 b, flag zSign ) { int32 aExp, bExp, zExp; bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; int32 expDiff; float128 z; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); bSig1 = extractFloat128Frac1( b ); bSig0 = extractFloat128Frac0( b ); bExp = extractFloat128Exp( b ); expDiff = aExp - bExp; shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); if ( 0 < expDiff ) goto aExpBigger; if ( expDiff < 0 ) goto bExpBigger; if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 | bSig0 | bSig1 ) { return propagateFloat128NaN( a, b ); } float_raise( float_flag_invalid ); z.low = float128_default_nan_low; z.high = float128_default_nan_high; return z; } if ( aExp == 0 ) { aExp = 1; bExp = 1; } if ( bSig0 < aSig0 ) goto aBigger; if ( aSig0 < bSig0 ) goto bBigger; if ( bSig1 < aSig1 ) goto aBigger; if ( aSig1 < bSig1 ) goto bBigger; return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 ); bExpBigger: if ( bExp == 0x7FFF ) { if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { ++expDiff; } else { aSig0 |= LIT64( 0x4000000000000000 ); } shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); bSig0 |= LIT64( 0x4000000000000000 ); bBigger: sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); zExp = bExp; zSign ^= 1; goto normalizeRoundAndPack; aExpBigger: if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); return a; } if ( bExp == 0 ) { --expDiff; } else { bSig0 |= LIT64( 0x4000000000000000 ); } shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); aSig0 |= LIT64( 0x4000000000000000 ); aBigger: sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); zExp = aExp; normalizeRoundAndPack: --zExp; return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 ); } /*---------------------------------------------------------------------------- | Returns the result of adding the quadruple-precision floating-point values | `a' and `b'. The operation is performed according to the IEC/IEEE Standard | for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 float128_add( float128 a, float128 b ) { flag aSign, bSign; aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); if ( aSign == bSign ) { return addFloat128Sigs( a, b, aSign ); } else { return subFloat128Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of subtracting the quadruple-precision floating-point | values `a' and `b'. The operation is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 float128_sub( float128 a, float128 b ) { flag aSign, bSign; aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); if ( aSign == bSign ) { return subFloat128Sigs( a, b, aSign ); } else { return addFloat128Sigs( a, b, aSign ); } } /*---------------------------------------------------------------------------- | Returns the result of multiplying the quadruple-precision floating-point | values `a' and `b'. The operation is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 float128_mul( float128 a, float128 b ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; float128 z; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); bSig1 = extractFloat128Frac1( b ); bSig0 = extractFloat128Frac0( b ); bExp = extractFloat128Exp( b ); bSign = extractFloat128Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FFF ) { if ( ( aSig0 | aSig1 ) || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { return propagateFloat128NaN( a, b ); } if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; return packFloat128( zSign, 0x7FFF, 0, 0 ); } if ( bExp == 0x7FFF ) { if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); if ( ( aExp | aSig0 | aSig1 ) == 0 ) { invalid: float_raise( float_flag_invalid ); z.low = float128_default_nan_low; z.high = float128_default_nan_high; return z; } return packFloat128( zSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); } if ( bExp == 0 ) { if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); } zExp = aExp + bExp - 0x4000; aSig0 |= LIT64( 0x0001000000000000 ); shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); zSig2 |= ( zSig3 != 0 ); if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { shift128ExtraRightJamming( zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); ++zExp; } return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); } /*---------------------------------------------------------------------------- | Returns the result of dividing the quadruple-precision floating-point value | `a' by the corresponding value `b'. The operation is performed according to | the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 float128_div( float128 a, float128 b ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; float128 z; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); bSig1 = extractFloat128Frac1( b ); bSig0 = extractFloat128Frac0( b ); bExp = extractFloat128Exp( b ); bSign = extractFloat128Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); if ( bExp == 0x7FFF ) { if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); goto invalid; } return packFloat128( zSign, 0x7FFF, 0, 0 ); } if ( bExp == 0x7FFF ) { if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); return packFloat128( zSign, 0, 0, 0 ); } if ( bExp == 0 ) { if ( ( bSig0 | bSig1 ) == 0 ) { if ( ( aExp | aSig0 | aSig1 ) == 0 ) { invalid: float_raise( float_flag_invalid ); z.low = float128_default_nan_low; z.high = float128_default_nan_high; return z; } float_raise( float_flag_divbyzero ); return packFloat128( zSign, 0x7FFF, 0, 0 ); } normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); } if ( aExp == 0 ) { if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); } zExp = aExp - bExp + 0x3FFD; shortShift128Left( aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); shortShift128Left( bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); ++zExp; } zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); while ( (sbits64) rem0 < 0 ) { --zSig0; add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); } zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); if ( ( zSig1 & 0x3FFF ) <= 4 ) { mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); while ( (sbits64) rem1 < 0 ) { --zSig1; add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); } zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); } shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); } /*---------------------------------------------------------------------------- | Returns the remainder of the quadruple-precision floating-point value `a' | with respect to the corresponding value `b'. The operation is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 float128_rem( float128 a, float128 b ) { flag aSign, bSign, zSign; int32 aExp, bExp, expDiff; bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; bits64 allZero, alternateASig0, alternateASig1, sigMean1; sbits64 sigMean0; float128 z; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); bSig1 = extractFloat128Frac1( b ); bSig0 = extractFloat128Frac0( b ); bExp = extractFloat128Exp( b ); bSign = extractFloat128Sign( b ); if ( aExp == 0x7FFF ) { if ( ( aSig0 | aSig1 ) || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { return propagateFloat128NaN( a, b ); } goto invalid; } if ( bExp == 0x7FFF ) { if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); return a; } if ( bExp == 0 ) { if ( ( bSig0 | bSig1 ) == 0 ) { invalid: float_raise( float_flag_invalid ); z.low = float128_default_nan_low; z.high = float128_default_nan_high; return z; } normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); } if ( aExp == 0 ) { if ( ( aSig0 | aSig1 ) == 0 ) return a; normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); } expDiff = aExp - bExp; if ( expDiff < -1 ) return a; shortShift128Left( aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15 - ( expDiff < 0 ), &aSig0, &aSig1 ); shortShift128Left( bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); q = le128( bSig0, bSig1, aSig0, aSig1 ); if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); expDiff -= 64; while ( 0 < expDiff ) { q = estimateDiv128To64( aSig0, aSig1, bSig0 ); q = ( 4 < q ) ? q - 4 : 0; mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); expDiff -= 61; } if ( -64 < expDiff ) { q = estimateDiv128To64( aSig0, aSig1, bSig0 ); q = ( 4 < q ) ? q - 4 : 0; q >>= - expDiff; shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); expDiff += 52; if ( expDiff < 0 ) { shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); } else { shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); } mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); } else { shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); } do { alternateASig0 = aSig0; alternateASig1 = aSig1; ++q; sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); } while ( 0 <= (sbits64) aSig0 ); add128( aSig0, aSig1, alternateASig0, alternateASig1, (bits64*)&sigMean0, &sigMean1 ); if ( ( sigMean0 < 0 ) || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { aSig0 = alternateASig0; aSig1 = alternateASig1; } zSign = ( (sbits64) aSig0 < 0 ); if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); return normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 ); } /*---------------------------------------------------------------------------- | Returns the square root of the quadruple-precision floating-point value `a'. | The operation is performed according to the IEC/IEEE Standard for Binary | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ float128 float128_sqrt( float128 a ) { flag aSign; int32 aExp, zExp; bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; float128 z; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a ); if ( ! aSign ) return a; goto invalid; } if ( aSign ) { if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; invalid: float_raise( float_flag_invalid ); z.low = float128_default_nan_low; z.high = float128_default_nan_high; return z; } if ( aExp == 0 ) { if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); } zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; aSig0 |= LIT64( 0x0001000000000000 ); zSig0 = estimateSqrt32( aExp, aSig0>>17 ); shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); doubleZSig0 = zSig0<<1; mul64To128( zSig0, zSig0, &term0, &term1 ); sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); while ( (sbits64) rem0 < 0 ) { --zSig0; doubleZSig0 -= 2; add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); } zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); if ( ( zSig1 & 0x1FFF ) <= 5 ) { if ( zSig1 == 0 ) zSig1 = 1; mul64To128( doubleZSig0, zSig1, &term1, &term2 ); sub128( rem1, 0, term1, term2, &rem1, &rem2 ); mul64To128( zSig1, zSig1, &term2, &term3 ); sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); while ( (sbits64) rem1 < 0 ) { --zSig1; shortShift128Left( 0, zSig1, 1, &term2, &term3 ); term3 |= 1; term2 |= doubleZSig0; add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); } zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); } shift128ExtraRightJamming( zSig0, zSig1, 0, 14, &zSig0, &zSig1, &zSig2 ); return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to | the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float128_eq( float128 a, float128 b ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { if ( float128_is_signaling_nan( a ) || float128_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than | or equal to the corresponding value `b', and 0 otherwise. The comparison | is performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic. *----------------------------------------------------------------------------*/ flag float128_le( float128 a, float128 b ) { flag aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); if ( aSign != bSign ) { return aSign || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return aSign ? le128( b.high, b.low, a.high, a.low ) : le128( a.high, a.low, b.high, b.low ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than | the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float128_lt( float128 a, float128 b ) { flag aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { float_raise( float_flag_invalid ); return 0; } aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); if ( aSign != bSign ) { return aSign && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return aSign ? lt128( b.high, b.low, a.high, a.low ) : lt128( a.high, a.low, b.high, b.low ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to | the corresponding value `b', and 0 otherwise. The invalid exception is | raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float128_eq_signaling( float128 a, float128 b ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { float_raise( float_flag_invalid ); return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than | or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not | cause an exception. Otherwise, the comparison is performed according to the | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float128_le_quiet( float128 a, float128 b ) { flag aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { if ( float128_is_signaling_nan( a ) || float128_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); if ( aSign != bSign ) { return aSign || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return aSign ? le128( b.high, b.low, a.high, a.low ) : le128( a.high, a.low, b.high, b.low ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than | the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an | exception. Otherwise, the comparison is performed according to the IEC/IEEE | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ flag float128_lt_quiet( float128 a, float128 b ) { flag aSign, bSign; if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { if ( float128_is_signaling_nan( a ) || float128_is_signaling_nan( b ) ) { float_raise( float_flag_invalid ); } return 0; } aSign = extractFloat128Sign( a ); bSign = extractFloat128Sign( b ); if ( aSign != bSign ) { return aSign && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return aSign ? lt128( b.high, b.low, a.high, a.low ) : lt128( a.high, a.low, b.high, b.low ); } #endif hercules-3.12/softfloat/README.txt0000664000175000017500000000611412564723224013704 00000000000000 Package Overview for SoftFloat Release 2b John R. Hauser 2002 May 27 ---------------------------------------------------------------------------- Overview SoftFloat is a software implementation of floating-point that conforms to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. SoftFloat is distributed in the form of C source code. Compiling the SoftFloat sources generates two things: -- A SoftFloat object file (typically `softfloat.o') containing the complete set of IEC/IEEE floating-point routines. -- A `timesoftfloat' program for evaluating the speed of the SoftFloat routines. (The SoftFloat module is linked into this program.) The SoftFloat package is documented in four text files: SoftFloat.txt Documentation for using the SoftFloat functions. SoftFloat-source.txt Documentation for compiling SoftFloat. SoftFloat-history.txt History of major changes to SoftFloat. timesoftfloat.txt Documentation for using `timesoftfloat'. Other files in the package comprise the source code for SoftFloat. Please be aware that some work is involved in porting this software to other targets. It is not just a matter of getting `make' to complete without error messages. I would have written the code that way if I could, but there are fundamental differences between systems that can't be hidden. You should not attempt to compile SoftFloat without first reading both `SoftFloat.txt' and `SoftFloat-source.txt'. ---------------------------------------------------------------------------- Legal Notice SoftFloat was written by me, John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. Derivative works are acceptable, even for commercial purposes, provided that the minimal documentation requirements stated in the source code are satisfied. ---------------------------------------------------------------------------- Contact Information At the time of this writing, the most up-to-date information about SoftFloat and the latest release can be found at the Web page `http:// www.cs.berkeley.edu/~jhauser/arithmetic/SoftFloat.html'. hercules-3.12/softfloat/SoftFloat.txt0000664000175000017500000004054212564723224014653 00000000000000 SoftFloat Release 2b General Documentation John R. Hauser 2002 May 27 ---------------------------------------------------------------------------- Introduction SoftFloat is a software implementation of floating-point that conforms to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. As many as four formats are supported: single precision, double precision, extended double precision, and quadruple precision. All operations required by the standard are implemented, except for conversions to and from decimal. This document gives information about the types defined and the routines implemented by SoftFloat. It does not attempt to define or explain the IEC/IEEE Floating-Point Standard. Details about the standard are available elsewhere. ---------------------------------------------------------------------------- Limitations SoftFloat is written in C and is designed to work with other C code. The SoftFloat header files assume an ISO/ANSI-style C compiler. No attempt has been made to accomodate compilers that are not ISO-conformant. In particular, the distributed header files will not be acceptable to any compiler that does not recognize function prototypes. Support for the extended double-precision and quadruple-precision formats depends on a C compiler that implements 64-bit integer arithmetic. If the largest integer format supported by the C compiler is 32 bits, SoftFloat is limited to only single and double precisions. When that is the case, all references in this document to extended double precision, quadruple precision, and 64-bit integers should be ignored. ---------------------------------------------------------------------------- Contents Introduction Limitations Contents Legal Notice Types and Functions Rounding Modes Extended Double-Precision Rounding Precision Exceptions and Exception Flags Function Details Conversion Functions Standard Arithmetic Functions Remainder Functions Round-to-Integer Functions Comparison Functions Signaling NaN Test Functions Raise-Exception Function Contact Information ---------------------------------------------------------------------------- Legal Notice SoftFloat was written by John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. ---------------------------------------------------------------------------- Types and Functions When 64-bit integers are supported by the compiler, the `softfloat.h' header file defines four types: `float32' (single precision), `float64' (double precision), `floatx80' (extended double precision), and `float128' (quadruple precision). The `float32' and `float64' types are defined in terms of 32-bit and 64-bit integer types, respectively, while the `float128' type is defined as a structure of two 64-bit integers, taking into account the byte order of the particular machine being used. The `floatx80' type is defined as a structure containing one 16-bit and one 64-bit integer, with the machine's byte order again determining the order within the structure. When 64-bit integers are _not_ supported by the compiler, the `softfloat.h' header file defines only two types: `float32' and `float64'. Because ISO/ANSI C guarantees at least one built-in integer type of 32 bits, the `float32' type is identified with an appropriate integer type. The `float64' type is defined as a structure of two 32-bit integers, with the machine's byte order determining the order of the fields. In either case, the types in `softfloat.h' are defined such that if a system implements the usual C `float' and `double' types according to the IEC/IEEE Standard, then the `float32' and `float64' types should be indistinguishable in memory from the native `float' and `double' types. (On the other hand, when `float32' or `float64' values are placed in processor registers by the compiler, the type of registers used may differ from those used for the native `float' and `double' types.) SoftFloat implements the following arithmetic operations: -- Conversions among all the floating-point formats, and also between integers (32-bit and 64-bit) and any of the floating-point formats. -- The usual add, subtract, multiply, divide, and square root operations for all floating-point formats. -- For each format, the floating-point remainder operation defined by the IEC/IEEE Standard. -- For each floating-point format, a ``round to integer'' operation that rounds to the nearest integer value in the same format. (The floating- point formats can hold integer values, of course.) -- Comparisons between two values in the same floating-point format. The only functions required by the IEC/IEEE Standard that are not provided are conversions to and from decimal. ---------------------------------------------------------------------------- Rounding Modes All four rounding modes prescribed by the IEC/IEEE Standard are implemented for all operations that require rounding. The rounding mode is selected by the global variable `float_rounding_mode'. This variable may be set to one of the values `float_round_nearest_even', `float_round_to_zero', `float_round_down', or `float_round_up'. The rounding mode is initialized to nearest/even. ---------------------------------------------------------------------------- Extended Double-Precision Rounding Precision For extended double precision (`floatx80') only, the rounding precision of the standard arithmetic operations is controlled by the global variable `floatx80_rounding_precision'. The operations affected are: floatx80_add floatx80_sub floatx80_mul floatx80_div floatx80_sqrt When `floatx80_rounding_precision' is set to its default value of 80, these operations are rounded (as usual) to the full precision of the extended double-precision format. Setting `floatx80_rounding_precision' to 32 or to 64 causes the operations listed to be rounded to reduced precision equivalent to single precision (`float32') or to double precision (`float64'), respectively. When rounding to reduced precision, additional bits in the result significand beyond the rounding point are set to zero. The consequences of setting `floatx80_rounding_precision' to a value other than 32, 64, or 80 is not specified. Operations other than the ones listed above are not affected by `floatx80_rounding_precision'. ---------------------------------------------------------------------------- Exceptions and Exception Flags All five exception flags required by the IEC/IEEE Standard are implemented. Each flag is stored as a unique bit in the global variable `float_exception_flags'. The positions of the exception flag bits within this variable are determined by the bit masks `float_flag_inexact', `float_flag_underflow', `float_flag_overflow', `float_flag_divbyzero', and `float_flag_invalid'. The exception flags variable is initialized to all 0, meaning no exceptions. An individual exception flag can be cleared with the statement float_exception_flags &= ~ float_flag_; where `' is the appropriate name. To raise a floating-point exception, the SoftFloat function `float_raise' should be used (see below). In the terminology of the IEC/IEEE Standard, SoftFloat can detect tininess for underflow either before or after rounding. The choice is made by the global variable `float_detect_tininess', which can be set to either `float_tininess_before_rounding' or `float_tininess_after_rounding'. Detecting tininess after rounding is better because it results in fewer spurious underflow signals. The other option is provided for compatibility with some systems. Like most systems, SoftFloat always detects loss of accuracy for underflow as an inexact result. ---------------------------------------------------------------------------- Function Details - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Conversion Functions All conversions among the floating-point formats are supported, as are all conversions between a floating-point format and 32-bit and 64-bit signed integers. The complete set of conversion functions is: int32_to_float32 int64_to_float32 int32_to_float64 int64_to_float32 int32_to_floatx80 int64_to_floatx80 int32_to_float128 int64_to_float128 float32_to_int32 float32_to_int64 float32_to_int32 float64_to_int64 floatx80_to_int32 floatx80_to_int64 float128_to_int32 float128_to_int64 float32_to_float64 float32_to_floatx80 float32_to_float128 float64_to_float32 float64_to_floatx80 float64_to_float128 floatx80_to_float32 floatx80_to_float64 floatx80_to_float128 float128_to_float32 float128_to_float64 float128_to_floatx80 Each conversion function takes one operand of the appropriate type and returns one result. Conversions from a smaller to a larger floating-point format are always exact and so require no rounding. Conversions from 32-bit integers to double precision and larger formats are also exact, and likewise for conversions from 64-bit integers to extended double and quadruple precisions. Conversions from floating-point to integer raise the invalid exception if the source value cannot be rounded to a representable integer of the desired size (32 or 64 bits). If the floating-point operand is a NaN, the largest positive integer is returned. Otherwise, if the conversion overflows, the largest integer with the same sign as the operand is returned. On conversions to integer, if the floating-point operand is not already an integer value, the operand is rounded according to the current rounding mode as specified by `float_rounding_mode'. Because C (and perhaps other languages) require that conversions to integers be rounded toward zero, the following functions are provided for improved speed and convenience: float32_to_int32_round_to_zero float32_to_int64_round_to_zero float64_to_int32_round_to_zero float64_to_int64_round_to_zero floatx80_to_int32_round_to_zero floatx80_to_int64_round_to_zero float128_to_int32_round_to_zero float128_to_int64_round_to_zero These variant functions ignore `float_rounding_mode' and always round toward zero. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Standard Arithmetic Functions The following standard arithmetic functions are provided: float32_add float32_sub float32_mul float32_div float32_sqrt float64_add float64_sub float64_mul float64_div float64_sqrt floatx80_add floatx80_sub floatx80_mul floatx80_div floatx80_sqrt float128_add float128_sub float128_mul float128_div float128_sqrt Each function takes two operands, except for `sqrt' which takes only one. The operands and result are all of the same type. Rounding of the extended double-precision (`floatx80') functions is affected by the `floatx80_rounding_precision' variable, as explained above in the section _Extended Double-Precision Rounding Precision_. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Remainder Functions For each format, SoftFloat implements the remainder function according to the IEC/IEEE Standard. The remainder functions are: float32_rem float64_rem floatx80_rem float128_rem Each remainder function takes two operands. The operands and result are all of the same type. Given operands x and y, the remainder functions return the value x - n*y, where n is the integer closest to x/y. If x/y is exactly halfway between two integers, n is the even integer closest to x/y. The remainder functions are always exact and so require no rounding. Depending on the relative magnitudes of the operands, the remainder functions can take considerably longer to execute than the other SoftFloat functions. This is inherent in the remainder operation itself and is not a flaw in the SoftFloat implementation. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Round-to-Integer Functions For each format, SoftFloat implements the round-to-integer function specified by the IEC/IEEE Standard. The functions are: float32_round_to_int float64_round_to_int floatx80_round_to_int float128_round_to_int Each function takes a single floating-point operand and returns a result of the same type. (Note that the result is not an integer type.) The operand is rounded to an exact integer according to the current rounding mode, and the resulting integer value is returned in the same floating-point format. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Comparison Functions The following floating-point comparison functions are provided: float32_eq float32_le float32_lt float64_eq float64_le float64_lt floatx80_eq floatx80_le floatx80_lt float128_eq float128_le float128_lt Each function takes two operands of the same type and returns a 1 or 0 representing either _true_ or _false_. The abbreviation `eq' stands for ``equal'' (=); `le' stands for ``less than or equal'' (<=); and `lt' stands for ``less than'' (<). The standard greater-than (>), greater-than-or-equal (>=), and not-equal (!=) functions are easily obtained using the functions provided. The not-equal function is just the logical complement of the equal function. The greater-than-or-equal function is identical to the less-than-or-equal function with the operands reversed, and the greater-than function is identical to the less-than function with the operands reversed. The IEC/IEEE Standard specifies that the less-than-or-equal and less-than functions raise the invalid exception if either input is any kind of NaN. The equal functions, on the other hand, are defined not to raise the invalid exception on quiet NaNs. For completeness, SoftFloat provides the following additional functions: float32_eq_signaling float32_le_quiet float32_lt_quiet float64_eq_signaling float64_le_quiet float64_lt_quiet floatx80_eq_signaling floatx80_le_quiet floatx80_lt_quiet float128_eq_signaling float128_le_quiet float128_lt_quiet The `signaling' equal functions are identical to the standard functions except that the invalid exception is raised for any NaN input. Likewise, the `quiet' comparison functions are identical to their counterparts except that the invalid exception is not raised for quiet NaNs. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Signaling NaN Test Functions The following functions test whether a floating-point value is a signaling NaN: float32_is_signaling_nan float64_is_signaling_nan floatx80_is_signaling_nan float128_is_signaling_nan The functions take one operand and return 1 if the operand is a signaling NaN and 0 otherwise. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Raise-Exception Function SoftFloat provides a function for raising floating-point exceptions: float_raise The function takes a mask indicating the set of exceptions to raise. No result is returned. In addition to setting the specified exception flags, this function may cause a trap or abort appropriate for the current system. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ---------------------------------------------------------------------------- Contact Information At the time of this writing, the most up-to-date information about SoftFloat and the latest release can be found at the Web page `http:// www.cs.berkeley.edu/~jhauser/arithmetic/SoftFloat.html'. hercules-3.12/softfloat/SoftFloat-history.txt0000664000175000017500000000360512564723224016351 00000000000000 History of Major Changes to SoftFloat, up to Release 2b John R. Hauser 2002 May 27 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Release 2b (2002 May) -- Made minor updates to the documentation, including improved wording of the legal restrictions on using SoftFloat. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Release 2a (1998 December) -- Added functions to convert between 64-bit integers (int64) and all supported floating-point formats. -- Fixed a bug in all 64-bit-version square root functions except `float32_sqrt' that caused the result sometimes to be off by 1 unit in the last place (1 ulp) from what it should be. (Bug discovered by Paul Donahue.) -- Improved the makefiles. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Release 2 (1997 June) -- Created the 64-bit (bits64) version, adding the floatx80 and float128 formats. -- Changed the source directory structure, splitting the sources into a `bits32' and a `bits64' version. Renamed `environment.h' to `milieu.h' to avoid confusion with environment variables. -- Fixed a small error that caused `float64_round_to_int' often to round the wrong way in nearest/even mode when the operand was between 2^20 and 2^21 and halfway between two integers. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Release 1a (1996 July) -- Corrected a mistake that caused borderline underflow cases not to raise the underflow flag when they should have. (Problem reported by Doug Priest.) -- Added the `float_detect_tininess' variable to control whether tininess is detected before or after rounding. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Release 1 (1996 July) -- Original release. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - hercules-3.12/softfloat/SoftFloat-source.txt0000664000175000017500000004170012564723224016146 00000000000000 SoftFloat Release 2b Source Documentation John R. Hauser 2002 May 27 ---------------------------------------------------------------------------- Introduction SoftFloat is a software implementation of floating-point that conforms to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. SoftFloat can support four floating-point formats: single precision, double precision, extended double precision, and quadruple precision. All operations required by the IEEE Standard are implemented, except for conversions to and from decimal. SoftFloat is distributed in the form of C source code, so a C compiler is needed to compile the code. Support for the extended double- precision and quadruple-precision formats is dependent on the C compiler implementing a 64-bit integer type. This document gives information needed for compiling and/or porting SoftFloat. The source code for SoftFloat is intended to be relatively machine- independent and should be compilable using most any ISO/ANSI C compiler. At the time of this writing, SoftFloat has been successfully compiled with the GNU C Compiler (`gcc') for several platforms. ---------------------------------------------------------------------------- Limitations As supplied, SoftFloat requires an ISO/ANSI-style C compiler. No attempt has been made to accomodate compilers that are not ISO-conformant. Older ``K&R-style'' compilers are not adequate for compiling SoftFloat. All testing I have done so far has been with the GNU C Compiler. Compilation with other compilers should be possible but has not been tested by me. The SoftFloat sources assume that source code file names can be longer than 8 characters. In order to compile under an MS-DOS-type system, many of the source files will need to be renamed, and the source and makefiles edited appropriately. Once compiled, the SoftFloat binary does not depend on the existence of long file names. The underlying machine is assumed to be binary with a word size that is a power of 2. Bytes are 8 bits. Arithmetic on signed integers must modularly wrap around on overflows (as is already required for unsigned integers in C). Support for the extended double-precision and quadruple-precision formats depends on the C compiler implementing a 64-bit integer type. If the largest integer type supported by the C compiler is 32 bits, SoftFloat is limited to the single- and double-precision formats. ---------------------------------------------------------------------------- Contents Introduction Limitations Contents Legal Notice SoftFloat Source Directory Structure SoftFloat Source Files processors/*.h softfloat/bits*/*/softfloat.h softfloat/bits*/*/milieu.h softfloat/bits*/*/softfloat-specialize softfloat/bits*/softfloat-macros softfloat/bits*/softfloat.c Steps to Creating a `softfloat.o' Making `softfloat.o' a Library Testing SoftFloat Timing SoftFloat Compiler Options and Efficiency Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros' Contact Information ---------------------------------------------------------------------------- Legal Notice SoftFloat was written by John R. Hauser. This work was made possible in part by the International Computer Science Institute, located at Suite 600, 1947 Center Street, Berkeley, California 94704. Funding was partially provided by the National Science Foundation under grant MIP-9311980. The original version of this code was written as part of a project to build a fixed-point vector processor in collaboration with the University of California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek. THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. Derivative works are acceptable, even for commercial purposes, provided that the minimal documentation requirements stated in the source code are satisfied. ---------------------------------------------------------------------------- SoftFloat Source Directory Structure Because SoftFloat is targeted to multiple platforms, its source code is slightly scattered between target-specific and target-independent directories and files. The directory structure is as follows: processors softfloat bits64 templates 386-Win32-GCC SPARC-Solaris-GCC bits32 templates 386-Win32-GCC SPARC-Solaris-GCC The two topmost directories and their contents are: softfloat - Most of the source code needed for SoftFloat. processors - Target-specific header files that are not specific to SoftFloat. The `softfloat' directory is further split into two parts: bits64 - SoftFloat implementation using 64-bit integers. bits32 - SoftFloat implementation using only 32-bit integers. Within these directories are subdirectories for each of the targeted platforms. The SoftFloat source code is distributed with targets `386-Win32-GCC' and `SPARC-Solaris-GCC' (and perhaps others) already prepared for both the 32-bit and 64-bit implementations. Source files that are not within these target-specific subdirectories are intended to be target-independent. The naming convention used for the target-specific directories is `--'. The names of the supplied target directories should be interpreted as follows: : 386 - Intel 386-compatible processor. SPARC - SPARC processor (as used by Sun computers). : Win32 - Microsoft Win32 executable. Solaris - Sun Solaris executable. : GCC - GNU C Compiler. You do not need to maintain this convention if you do not want to. Alongside the supplied target-specific directories is a `templates' directory containing a set of ``generic'' target-specific source files. A new target directory can be created by copying the `templates' directory and editing the files inside. (Complete instructions for porting SoftFloat to a new target are in the section _Steps to Creating a `softfloat.o'_.) Note that the `templates' directory will not work as a target directory without some editing. To avoid confusion, it would be wise to refrain from editing the files inside `templates' directly. ---------------------------------------------------------------------------- SoftFloat Source Files The purpose of each source file is described below. In the following, the `*' symbol is used in place of the name of a specific target, such as `386-Win32-GCC' or `SPARC-Solaris-GCC', or in place of some other text, as in `bits*' for either `bits32' or `bits64'. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - processors/*.h The target-specific `processors' header file defines integer types of various sizes, and also defines certain C preprocessor macros that characterize the target. The two examples supplied are `386-GCC.h' and `SPARC-GCC.h'. The naming convention used for processor header files is `-.h'. If 64-bit integers are supported by the compiler, the macro name `BITS64' should be defined here along with the corresponding 64-bit integer types. In addition, the function-like macro `LIT64' must be defined for constructing 64-bit integer literals (constants). The `LIT64' macro is used consistently in the SoftFloat code to annotate 64-bit literals. If `BITS64' is not defined, only the 32-bit version of SoftFloat can be compiled. If `BITS64' _is_ defined, either can be compiled. If an inlining attribute (such as an `inline' keyword) is provided by the compiler, the macro `INLINE' should be defined to the appropriate keyword. If not, `INLINE' can be set to the keyword `static'. The `INLINE' macro appears in the SoftFloat source code before every function that should be inlined by the compiler. SoftFloat depends on inlining to obtain good speed. Even if inlining cannot be forced with a language keyword, the compiler may still be able to perform inlining on its own as an optimization. If a command-line option is needed to convince the compiler to perform this optimization, this should be assured in the makefile. (See the section _Compiler Options and Efficiency_ below.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - softfloat/bits*/*/softfloat.h The target-specific `softfloat.h' header file defines the SoftFloat interface as seen by clients. Unlike the actual function definitions in `softfloat.c', the declarations in `softfloat.h' do not use any of the types defined by the `processors' header file. This is done so that clients will not have to include the `processors' header file in order to use SoftFloat. Nevertheless, the target-specific declarations in `softfloat.h' must match what `softfloat.c' expects. For example, if `int32' is defined as `int' in the `processors' header file, then in `softfloat.h' the output of `float32_to_int32' should be stated as `int', although in `softfloat.c' it is given in target- independent form as `int32'. For the `bits64' implementation of SoftFloat, the macro names `FLOATX80' and `FLOAT128' must be defined in order for the extended double-precision and quadruple-precision formats to be enabled in the code. Conversely, either or both of the extended formats can be disabled by simply removing the `#define' of the respective macro. When an extended format is not enabled, none of the functions that either input or output the format are defined, and no space is taken up in `softfloat.o' by such functions. There is no provision for disabling the usual single- and double-precision formats. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - softfloat/bits*/*/milieu.h The target-specific `milieu.h' header file provides declarations that are needed to compile SoftFloat. In addition, deviations from ISO/ANSI C by the compiler (such as names not properly declared in system header files) are corrected in this header if possible. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - softfloat/bits*/*/softfloat-specialize This target-specific C source fragment defines: -- whether tininess for underflow is detected before or after rounding by default; -- what (if anything) special happens when exceptions are raised; -- how signaling NaNs are distinguished from quiet NaNs; -- the default generated quiet NaNs; and -- how NaNs are propagated from function inputs to output. These details are not decided by the IEC/IEEE Standard. This fragment is included verbatim within `softfloat.c' when SoftFloat is compiled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - softfloat/bits*/softfloat-macros This target-independent C source fragment defines a number of arithmetic functions used as primitives within the `softfloat.c' source. Most of the functions defined here are intended to be inlined for efficiency. This fragment is included verbatim within `softfloat.c' when SoftFloat is compiled. Target-specific variations on this file are possible. See the section _Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros'_ below. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - softfloat/bits*/softfloat.c The target-independent `softfloat.c' source file contains the body of the SoftFloat implementation. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The inclusion of the files above within each other (using `#include') can be shown graphically as follows: softfloat/bits*/softfloat.c softfloat/bits*/*/milieu.h processors/*.h softfloat/bits*/*/softfloat.h softfloat/bits*/*/softfloat-specialize softfloat/bits*/softfloat-macros Note in particular that `softfloat.c' does not include the `processors' header file directly. Rather, `softfloat.c' includes the target-specific `milieu.h' header file, which in turn includes the appropriate processor header file. ---------------------------------------------------------------------------- Steps to Creating a `softfloat.o' Porting and/or compiling SoftFloat involves the following steps: 1. If one does not already exist, create an appropriate `.h' file in the `processors' directory. 2. If `BITS64' is defined in the `processors' header file, choose whether to compile the 32-bit or 64-bit implementation of SoftFloat. If `BITS64' is not defined, your only choice is the 32-bit implementation. The remaining steps occur within either the `bits32' or `bits64' subdirectories. 3. If one does not already exist, create an appropriate target-specific subdirectory by copying the given `templates' directory. 4. In the target-specific subdirectory, edit the files `softfloat-specialize' and `softfloat.h' to define the desired exception handling functions and mode control values. In the `softfloat.h' header file, ensure also that all declarations give the proper target-specific type (such as `int' or `long') corresponding to the target-independent type used in `softfloat.c' (such as `int32'). None of the type names declared in the `processors' header file should appear in `softfloat.h'. 5. In the target-specific subdirectory, edit the files `milieu.h' and `Makefile' to reflect the current environment. 6. In the target-specific subdirectory, execute `make'. For the targets that are supplied, if the expected compiler is available (usually `gcc'), it should only be necessary to execute `make' in the target-specific subdirectory. ---------------------------------------------------------------------------- Making `softfloat.o' a Library SoftFloat is not made into a software library by the supplied makefile. If desired, `softfloat.o' can easily be put into its own library (in Unix, `softfloat.a') using the usual system tool (in Unix, `ar'). ---------------------------------------------------------------------------- Testing SoftFloat SoftFloat can be tested using the `testsoftfloat' program by the same author. The `testsoftfloat' program is part of the TestFloat package available at the Web page `http://www.cs.berkeley.edu/~jhauser/arithmetic/ TestFloat.html'. ---------------------------------------------------------------------------- Timing SoftFloat A program called `timesoftfloat' for timing the SoftFloat functions is included with the SoftFloat source code. Compiling `timesoftfloat' should pose no difficulties once `softfloat.o' exists. The supplied makefile will create a `timesoftfloat' executable by default after generating `softfloat.o'. See `timesoftfloat.txt' for documentation about using `timesoftfloat'. ---------------------------------------------------------------------------- Compiler Options and Efficiency In order to get good speed with SoftFloat, it is important that the compiler inline the routines that have been marked `INLINE' in the code. Even if inlining cannot be forced by an appropriate definition of the `INLINE' macro, the compiler may still be able to perform inlining on its own as an optimization. In that case, the makefile should be edited to give the compiler whatever option is required to cause it to inline small functions. ---------------------------------------------------------------------------- Processor-Specific Optimization of `softfloat.c' Using `softfloat-macros' The `softfloat-macros' source fragment defines arithmetic functions used as primitives by `softfloat.c'. This file has been written in a target- independent form. For a given target, it may be possible to improve on these functions using target-specific and/or non-ISO-C features (such as `asm' statements). For example, one of the ``macro'' functions takes two word-size integers and returns their full product in two words. This operation can be done directly in hardware on many processors; but because it is not available through standard C, the function defined in `softfloat-macros' uses four multiplications to achieve the same result. To address these shortcomings, a customized version of `softfloat-macros' can be created in any of the target-specific subdirectories. A simple modification to the target's makefile should be sufficient to ensure that the custom version is used instead of the generic one. ---------------------------------------------------------------------------- Contact Information At the time of this writing, the most up-to-date information about SoftFloat and the latest release can be found at the Web page `http:// www.cs.berkeley.edu/~jhauser/arithmetic/SoftFloat.html'. hercules-3.12/m4/0000775000175000017500000000000012625667404010610 500000000000000hercules-3.12/m4/Makefile.in0000664000175000017500000002756212625667166012616 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = m4 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/mkinstalldirs ChangeLog ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = glibc2.m4 intmax.m4 longdouble.m4 longlong.m4 nls.m4 po.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu m4/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu m4/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/m4/Makefile.am0000664000175000017500000000053312564723224012560 00000000000000EXTRA_DIST = glibc2.m4 intmax.m4 longdouble.m4 longlong.m4 nls.m4 po.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 hercules-3.12/m4/ChangeLog0000664000175000017500000000254512564723224012303 000000000000002005-05-12 gettextize * codeset.m4: Upgrade to gettext-0.14.4. * gettext.m4: Upgrade to gettext-0.14.4. * glibc2.m4: New file, from gettext-0.14.4. * glibc21.m4: Upgrade to gettext-0.14.4. * iconv.m4: Upgrade to gettext-0.14.4. * intdiv0.m4: Upgrade to gettext-0.14.4. * intmax.m4: New file, from gettext-0.14.4. * inttypes.m4: Upgrade to gettext-0.14.4. * inttypes_h.m4: Upgrade to gettext-0.14.4. * inttypes-pri.m4: Upgrade to gettext-0.14.4. * isc-posix.m4: Upgrade to gettext-0.14.4. * lcmessage.m4: Upgrade to gettext-0.14.4. * lib-ld.m4: Upgrade to gettext-0.14.4. * lib-link.m4: Upgrade to gettext-0.14.4. * lib-prefix.m4: Upgrade to gettext-0.14.4. * longdouble.m4: New file, from gettext-0.14.4. * longlong.m4: New file, from gettext-0.14.4. * nls.m4: New file, from gettext-0.14.4. * po.m4: New file, from gettext-0.14.4. * printf-posix.m4: New file, from gettext-0.14.4. * progtest.m4: Upgrade to gettext-0.14.4. * signed.m4: New file, from gettext-0.14.4. * size_max.m4: New file, from gettext-0.14.4. * stdint_h.m4: Upgrade to gettext-0.14.4. * uintmax_t.m4: Upgrade to gettext-0.14.4. * ulonglong.m4: Upgrade to gettext-0.14.4. * wchar_t.m4: New file, from gettext-0.14.4. * wint_t.m4: New file, from gettext-0.14.4. * xsize.m4: New file, from gettext-0.14.4. * Makefile.am (EXTRA_DIST): Add the new files. hercules-3.12/m4/glibc2.m40000664000175000017500000000135412564723224012132 00000000000000# glibc2.m4 serial 1 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Test for the GNU C Library, version 2.0 or newer. # From Bruno Haible. AC_DEFUN([gt_GLIBC2], [ AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, ac_cv_gnu_library_2, [AC_EGREP_CPP([Lucky GNU user], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ >= 2) Lucky GNU user #endif #endif ], ac_cv_gnu_library_2=yes, ac_cv_gnu_library_2=no) ] ) AC_SUBST(GLIBC2) GLIBC2="$ac_cv_gnu_library_2" ] ) hercules-3.12/m4/intmax.m40000664000175000017500000000174612564723224012275 00000000000000# intmax.m4 serial 2 (gettext-0.14.2) dnl Copyright (C) 2002-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the system has the 'intmax_t' type, but don't attempt to dnl find a replacement if it is lacking. AC_DEFUN([gt_TYPE_INTMAX_T], [ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gl_AC_HEADER_STDINT_H]) AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, [AC_TRY_COMPILE([ #include #include #if HAVE_STDINT_H_WITH_UINTMAX #include #endif #if HAVE_INTTYPES_H_WITH_UINTMAX #include #endif ], [intmax_t x = -1;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)]) if test $gt_cv_c_intmax_t = yes; then AC_DEFINE(HAVE_INTMAX_T, 1, [Define if you have the 'intmax_t' type in or .]) fi ]) hercules-3.12/m4/longdouble.m40000664000175000017500000000205312564723224013117 00000000000000# longdouble.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether the compiler supports the 'long double' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_LONGDOUBLE], [ AC_CACHE_CHECK([for long double], gt_cv_c_long_double, [if test "$GCC" = yes; then gt_cv_c_long_double=yes else AC_TRY_COMPILE([ /* The Stardent Vistra knows sizeof(long double), but does not support it. */ long double foo = 0.0; /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ int array [2*(sizeof(long double) >= sizeof(double)) - 1]; ], , gt_cv_c_long_double=yes, gt_cv_c_long_double=no) fi]) if test $gt_cv_c_long_double = yes; then AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) fi ]) hercules-3.12/m4/longlong.m40000664000175000017500000000141612564723224012606 00000000000000# longlong.m4 serial 5 dnl Copyright (C) 1999-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_LONG_LONG if 'long long' works. AC_DEFUN([gl_AC_TYPE_LONG_LONG], [ AC_CACHE_CHECK([for long long], ac_cv_type_long_long, [AC_TRY_LINK([long long ll = 1LL; int i = 63;], [long long llmax = (long long) -1; return ll << i | ll >> i | llmax / ll | llmax % ll;], ac_cv_type_long_long=yes, ac_cv_type_long_long=no)]) if test $ac_cv_type_long_long = yes; then AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have the 'long long' type.]) fi ]) hercules-3.12/m4/nls.m40000664000175000017500000000353012564723224011562 00000000000000# nls.m4 serial 2 (gettext-0.14.3) dnl Copyright (C) 1995-2003, 2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) AC_DEFUN([AM_NLS], [ AC_MSG_CHECKING([whether NLS is requested]) dnl Default is enabled NLS AC_ARG_ENABLE(nls, [ --disable-nls do not use Native Language Support], USE_NLS=$enableval, USE_NLS=yes) AC_MSG_RESULT($USE_NLS) AC_SUBST(USE_NLS) ]) AC_DEFUN([AM_MKINSTALLDIRS], [ dnl Tell automake >= 1.10 to complain if mkinstalldirs is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([mkinstalldirs])]) dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly dnl find the mkinstalldirs script in another subdir but $(top_srcdir). dnl Try to locate it. MKINSTALLDIRS= if test -n "$ac_aux_dir"; then case "$ac_aux_dir" in /*) MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" ;; *) MKINSTALLDIRS="\$(top_builddir)/$ac_aux_dir/mkinstalldirs" ;; esac fi if test -z "$MKINSTALLDIRS"; then MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" fi AC_SUBST(MKINSTALLDIRS) ]) hercules-3.12/m4/po.m40000664000175000017500000004364312564723224011415 00000000000000# po.m4 serial 7 (gettext-0.14.3) dnl Copyright (C) 1995-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) dnl Checks for all prerequisites of the po subdirectory. AC_DEFUN([AM_PO_SUBDIRS], [ AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_MKINSTALLDIRS])dnl AC_REQUIRE([AM_NLS])dnl dnl Perform the following tests also if --disable-nls has been given, dnl because they are needed for "make dist" to work. dnl Search for GNU msgfmt in the PATH. dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. dnl The second test excludes FreeBSD msgfmt. AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) dnl Search for GNU xgettext 0.12 or newer in the PATH. dnl The first test excludes Solaris xgettext and early GNU xgettext versions. dnl The second test excludes FreeBSD xgettext. AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) dnl Remove leftover from FreeBSD xgettext call. rm -f messages.po dnl Search for GNU msgmerge 0.11 or newer in the PATH. AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. dnl Test whether we really found GNU msgfmt. if test "$GMSGFMT" != ":"; then dnl If it is no GNU msgfmt we define it as : so that the dnl Makefiles still can work. if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 && (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then : ; else GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'` AC_MSG_RESULT( [found $GMSGFMT program is not GNU msgfmt; ignore it]) GMSGFMT=":" fi fi dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. dnl Test whether we really found GNU xgettext. if test "$XGETTEXT" != ":"; then dnl If it is no GNU xgettext we define it as : so that the dnl Makefiles still can work. if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 && (if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then : ; else AC_MSG_RESULT( [found xgettext program is not GNU xgettext; ignore it]) XGETTEXT=":" fi dnl Remove leftover from FreeBSD xgettext call. rm -f messages.po fi AC_OUTPUT_COMMANDS([ for ac_file in $CONFIG_FILES; do # Support "outfile[:infile[:infile...]]" case "$ac_file" in *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; esac # PO directories have a Makefile.in generated from Makefile.in.in. case "$ac_file" in */Makefile.in) # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Treat a directory as a PO directory if and only if it has a # POTFILES.in file. This allows packages to have multiple PO # directories under different names or in different locations. if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" POMAKEFILEDEPS="POTFILES.in" # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend # on $ac_dir but don't depend on user-specified configuration # parameters. if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then # The LINGUAS file contains the set of available languages. if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` # Hide the ALL_LINGUAS assigment from automake. eval 'ALL_LINGUAS''=$ALL_LINGUAS_' POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) # Compute UPDATEPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) # Compute DUMMYPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) # Compute GMOFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) case "$ac_given_srcdir" in .) srcdirpre= ;; *) srcdirpre='$(srcdir)/' ;; esac POFILES= UPDATEPOFILES= DUMMYPOFILES= GMOFILES= for lang in $ALL_LINGUAS; do POFILES="$POFILES $srcdirpre$lang.po" UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" DUMMYPOFILES="$DUMMYPOFILES $lang.nop" GMOFILES="$GMOFILES $srcdirpre$lang.gmo" done # CATALOGS depends on both $ac_dir and the user's LINGUAS # environment variable. INST_LINGUAS= if test -n "$ALL_LINGUAS"; then for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "$LINGUAS"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then INST_LINGUAS="$INST_LINGUAS $presentlang" fi done fi CATALOGS= if test -n "$INST_LINGUAS"; then for lang in $INST_LINGUAS; do CATALOGS="$CATALOGS $lang.gmo" done fi test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do if test -f "$f"; then case "$f" in *.orig | *.bak | *~) ;; *) cat "$f" >> "$ac_dir/Makefile" ;; esac fi done fi ;; esac done], [# Capture the value of obsolete ALL_LINGUAS because we need it to compute # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it # from automake. eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" ]) ]) dnl Postprocesses a Makefile in a directory containing PO files. AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], [ # When this code is run, in config.status, two variables have already been # set: # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, # - LINGUAS is the value of the environment variable LINGUAS at configure # time. changequote(,)dnl # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Find a way to echo strings without interpreting backslash. if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then gt_echo='echo' else if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then gt_echo='printf %s\n' else echo_func () { cat < "$ac_file.tmp" if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` cat >> "$ac_file.tmp" < /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` cat >> "$ac_file.tmp" <> "$ac_file.tmp" < #include /* The string "%2$d %1$d", with dollar characters protected from the shell's dollar expansion (possibly an autoconf bug). */ static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; static char buf[100]; int main () { sprintf (buf, format, 33, 55); return (strcmp (buf, "55 33") != 0); }], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, [ AC_EGREP_CPP(notposix, [ #if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ notposix #endif ], gt_cv_func_printf_posix="guessing no", gt_cv_func_printf_posix="guessing yes") ]) ]) case $gt_cv_func_printf_posix in *yes) AC_DEFINE(HAVE_POSIX_PRINTF, 1, [Define if your printf() function supports format strings with positions.]) ;; esac ]) hercules-3.12/m4/signed.m40000664000175000017500000000115412564723224012237 00000000000000# signed.m4 serial 1 (gettext-0.10.40) dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([bh_C_SIGNED], [ AC_CACHE_CHECK([for signed], bh_cv_c_signed, [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)]) if test $bh_cv_c_signed = no; then AC_DEFINE(signed, , [Define to empty if the C compiler doesn't support this keyword.]) fi ]) hercules-3.12/m4/size_max.m40000664000175000017500000000364512564723224012614 00000000000000# size_max.m4 serial 2 dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([gl_SIZE_MAX], [ AC_CHECK_HEADERS(stdint.h) dnl First test whether the system already has SIZE_MAX. AC_MSG_CHECKING([for SIZE_MAX]) result= AC_EGREP_CPP([Found it], [ #include #if HAVE_STDINT_H #include #endif #ifdef SIZE_MAX Found it #endif ], result=yes) if test -z "$result"; then dnl Define it ourselves. Here we assume that the type 'size_t' is not wider dnl than the type 'unsigned long'. dnl The _AC_COMPUTE_INT macro works up to LONG_MAX, since it uses 'expr', dnl which is guaranteed to work from LONG_MIN to LONG_MAX. _AC_COMPUTE_INT([~(size_t)0 / 10], res_hi, [#include ], result=?) _AC_COMPUTE_INT([~(size_t)0 % 10], res_lo, [#include ], result=?) _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, [#include ], result=?) if test "$fits_in_uint" = 1; then dnl Even though SIZE_MAX fits in an unsigned int, it must be of type dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. AC_TRY_COMPILE([#include extern size_t foo; extern unsigned long foo; ], [], fits_in_uint=0) fi if test -z "$result"; then if test "$fits_in_uint" = 1; then result="$res_hi$res_lo"U else result="$res_hi$res_lo"UL fi else dnl Shouldn't happen, but who knows... result='~(size_t)0' fi fi AC_MSG_RESULT([$result]) if test "$result" != yes; then AC_DEFINE_UNQUOTED([SIZE_MAX], [$result], [Define as the maximum value of type 'size_t', if the system doesn't define it.]) fi ]) hercules-3.12/m4/wchar_t.m40000664000175000017500000000132612564723224012416 00000000000000# wchar_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether has the 'wchar_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WCHAR_T], [ AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, [AC_TRY_COMPILE([#include wchar_t foo = (wchar_t)'\0';], , gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) if test $gt_cv_c_wchar_t = yes; then AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) fi ]) hercules-3.12/m4/wint_t.m40000664000175000017500000000130412564723224012267 00000000000000# wint_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl Test whether has the 'wint_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WINT_T], [ AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, [AC_TRY_COMPILE([#include wint_t foo = (wchar_t)'\0';], , gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) if test $gt_cv_c_wint_t = yes; then AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) fi ]) hercules-3.12/m4/xsize.m40000664000175000017500000000064512564723224012134 00000000000000# xsize.m4 serial 3 dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_XSIZE], [ dnl Prerequisites of lib/xsize.h. AC_REQUIRE([gl_SIZE_MAX]) AC_REQUIRE([AC_C_INLINE]) AC_CHECK_HEADERS(stdint.h) ]) hercules-3.12/m4/codeset.m40000664000175000017500000000135112564723224012413 00000000000000# codeset.m4 serial AM1 (gettext-0.10.40) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_LANGINFO_CODESET], [ AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, [AC_TRY_LINK([#include ], [char* cs = nl_langinfo(CODESET);], am_cv_langinfo_codeset=yes, am_cv_langinfo_codeset=no) ]) if test $am_cv_langinfo_codeset = yes; then AC_DEFINE(HAVE_LANGINFO_CODESET, 1, [Define if you have and nl_langinfo(CODESET).]) fi ]) hercules-3.12/m4/gettext.m40000664000175000017500000005166712564723224012470 00000000000000# gettext.m4 serial 37 (gettext-0.14.4) dnl Copyright (C) 1995-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. dnl Macro to add for using GNU gettext. dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The dnl default (if it is not specified or empty) is 'no-libtool'. dnl INTLSYMBOL should be 'external' for packages with no intl directory, dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. dnl If INTLSYMBOL is 'use-libtool', then a libtool library dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, dnl depending on --{enable,disable}-{shared,static} and on the presence of dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library dnl $(top_builddir)/intl/libintl.a will be created. dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext dnl implementations (in libc or libintl) without the ngettext() function dnl will be ignored. If NEEDSYMBOL is specified and is dnl 'need-formatstring-macros', then GNU gettext implementations that don't dnl support the ISO C 99 formatstring macros will be ignored. dnl INTLDIR is used to find the intl libraries. If empty, dnl the value `$(top_builddir)/intl/' is used. dnl dnl The result of the configuration is one of three cases: dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled dnl and used. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 2) GNU gettext has been found in the system's C library. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 3) No internationalization, always use English msgid. dnl Catalog format: none dnl Catalog extension: none dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. dnl The use of .gmo is historical (it was needed to avoid overwriting the dnl GNU format catalogs when building on a platform with an X/Open gettext), dnl but we keep it in order not to force irrelevant filename changes on the dnl maintainers. dnl AC_DEFUN([AM_GNU_GETTEXT], [ dnl Argument checking. ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT ])])])])]) ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT ])])])]) define([gt_included_intl], ifelse([$1], [external], [no], [yes])) define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) AC_REQUIRE([AM_PO_SUBDIRS])dnl ifelse(gt_included_intl, yes, [ AC_REQUIRE([AM_INTL_SUBDIR])dnl ]) dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Sometimes libintl requires libiconv, so first search for libiconv. dnl Ideally we would do this search only after the dnl if test "$USE_NLS" = "yes"; then dnl if test "$gt_cv_func_gnugettext_libc" != "yes"; then dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT dnl the configure script would need to contain the same shell code dnl again, outside any 'if'. There are two solutions: dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not dnl documented, we avoid it. ifelse(gt_included_intl, yes, , [ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) ]) dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. gt_INTL_MACOSX dnl Set USE_NLS. AM_NLS ifelse(gt_included_intl, yes, [ BUILD_INCLUDED_LIBINTL=no USE_INCLUDED_LIBINTL=no ]) LIBINTL= LTLIBINTL= POSUB= dnl If we use NLS figure out what method if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no ifelse(gt_included_intl, yes, [ AC_MSG_CHECKING([whether included gettext is requested]) AC_ARG_WITH(included-gettext, [ --with-included-gettext use the GNU gettext library included here], nls_cv_force_use_gnu_gettext=$withval, nls_cv_force_use_gnu_gettext=no) AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" if test "$nls_cv_force_use_gnu_gettext" != "yes"; then ]) dnl User does not insist on using GNU NLS library. Figure out what dnl to use. If GNU gettext is available we use this. Else we have dnl to fall back to GNU NLS library. dnl Add a version number to the cache macros. define([gt_api_version], ifelse([$2], [need-formatstring-macros], 3, ifelse([$2], [need-ngettext], 2, 1))) define([gt_cv_func_gnugettext_libc], [gt_cv_func_gnugettext]gt_api_version[_libc]) define([gt_cv_func_gnugettext_libintl], [gt_cv_func_gnugettext]gt_api_version[_libintl]) AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc, [AC_TRY_LINK([#include ]ifelse([$2], [need-formatstring-macros], [#ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ], [])[extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings;], [bindtextdomain ("", ""); return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_domain_bindings], gt_cv_func_gnugettext_libc=yes, gt_cv_func_gnugettext_libc=no)]) if test "$gt_cv_func_gnugettext_libc" != "yes"; then dnl Sometimes libintl requires libiconv, so first search for libiconv. ifelse(gt_included_intl, yes, , [ AM_ICONV_LINK ]) dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) dnl because that would add "-liconv" to LIBINTL and LTLIBINTL dnl even if libiconv doesn't exist. AC_LIB_LINKFLAGS_BODY([intl]) AC_CACHE_CHECK([for GNU gettext in libintl], gt_cv_func_gnugettext_libintl, [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" dnl Now see whether libintl exists and does not depend on libiconv. AC_TRY_LINK([#include ]ifelse([$2], [need-formatstring-macros], [#ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ], [])[extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias ("")], gt_cv_func_gnugettext_libintl=yes, gt_cv_func_gnugettext_libintl=no) dnl Now see whether libintl exists and depends on libiconv. if test "$gt_cv_func_gnugettext_libintl" != yes && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include ]ifelse([$2], [need-formatstring-macros], [#ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ], [])[extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")]ifelse([$2], [need-ngettext], [ + * ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias ("")], [LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" gt_cv_func_gnugettext_libintl=yes ]) fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) fi dnl If an already present or preinstalled GNU gettext() is found, dnl use it. But if this macro is used in GNU gettext, and GNU dnl gettext is already preinstalled in libintl, we update this dnl libintl. (Cf. the install rule in intl/Makefile.in.) if test "$gt_cv_func_gnugettext_libc" = "yes" \ || { test "$gt_cv_func_gnugettext_libintl" = "yes" \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else dnl Reset the values set by searching for libintl. LIBINTL= LTLIBINTL= INCINTL= fi ifelse(gt_included_intl, yes, [ if test "$gt_use_preinstalled_gnugettext" != "yes"; then dnl GNU gettext is not found in the C library. dnl Fall back on included GNU gettext library. nls_cv_use_gnu_gettext=yes fi fi if test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions used to generate GNU NLS library. BUILD_INCLUDED_LIBINTL=yes USE_INCLUDED_LIBINTL=yes LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV" LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV" LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi CATOBJEXT= if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions to use GNU gettext tools. CATOBJEXT=.gmo fi ]) if test -n "$INTL_MACOSX_LIBS"; then if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Some extra flags are needed during linking. LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" fi fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if translation of program messages to the user's native language is requested.]) else USE_NLS=no fi fi AC_MSG_CHECKING([whether to use NLS]) AC_MSG_RESULT([$USE_NLS]) if test "$USE_NLS" = "yes"; then AC_MSG_CHECKING([where the gettext function comes from]) if test "$gt_use_preinstalled_gnugettext" = "yes"; then if test "$gt_cv_func_gnugettext_libintl" = "yes"; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi AC_MSG_RESULT([$gt_source]) fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if test "$gt_cv_func_gnugettext_libintl" = "yes"; then AC_MSG_CHECKING([how to link with libintl]) AC_MSG_RESULT([$LIBINTL]) AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) fi dnl For backward compatibility. Some packages may be using this. AC_DEFINE(HAVE_GETTEXT, 1, [Define if the GNU gettext() function is already present or preinstalled.]) AC_DEFINE(HAVE_DCGETTEXT, 1, [Define if the GNU dcgettext() function is already present or preinstalled.]) fi dnl We need to process the po/ directory. POSUB=po fi ifelse(gt_included_intl, yes, [ dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL dnl to 'yes' because some of the testsuite requires it. if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then BUILD_INCLUDED_LIBINTL=yes fi dnl Make all variables we use known to autoconf. AC_SUBST(BUILD_INCLUDED_LIBINTL) AC_SUBST(USE_INCLUDED_LIBINTL) AC_SUBST(CATOBJEXT) dnl For backward compatibility. Some configure.ins may be using this. nls_cv_header_intl= nls_cv_header_libgt= dnl For backward compatibility. Some Makefiles may be using this. DATADIRNAME=share AC_SUBST(DATADIRNAME) dnl For backward compatibility. Some Makefiles may be using this. INSTOBJEXT=.mo AC_SUBST(INSTOBJEXT) dnl For backward compatibility. Some Makefiles may be using this. GENCAT=gencat AC_SUBST(GENCAT) dnl For backward compatibility. Some Makefiles may be using this. INTLOBJS= if test "$USE_INCLUDED_LIBINTL" = yes; then INTLOBJS="\$(GETTOBJS)" fi AC_SUBST(INTLOBJS) dnl Enable libtool support if the surrounding package wishes it. INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) ]) dnl For backward compatibility. Some Makefiles may be using this. INTLLIBS="$LIBINTL" AC_SUBST(INTLLIBS) dnl Make all documented variables known to autoconf. AC_SUBST(LIBINTL) AC_SUBST(LTLIBINTL) AC_SUBST(POSUB) ]) dnl Checks for all prerequisites of the intl subdirectory, dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. AC_DEFUN([AM_INTL_SUBDIR], [ AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_MKINSTALLDIRS])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([gt_GLIBC2])dnl AC_REQUIRE([AC_PROG_RANLIB])dnl AC_REQUIRE([AC_ISC_POSIX])dnl AC_REQUIRE([AC_HEADER_STDC])dnl AC_REQUIRE([AC_C_CONST])dnl AC_REQUIRE([bh_C_SIGNED])dnl AC_REQUIRE([AC_C_INLINE])dnl AC_REQUIRE([AC_TYPE_OFF_T])dnl AC_REQUIRE([AC_TYPE_SIZE_T])dnl AC_REQUIRE([gl_AC_TYPE_LONG_LONG])dnl AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl AC_REQUIRE([gt_TYPE_WCHAR_T])dnl AC_REQUIRE([gt_TYPE_WINT_T])dnl AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gl_AC_HEADER_STDINT_H]) AC_REQUIRE([gt_TYPE_INTMAX_T]) AC_REQUIRE([gt_PRINTF_POSIX]) AC_REQUIRE([AC_FUNC_ALLOCA])dnl AC_REQUIRE([AC_FUNC_MMAP])dnl AC_REQUIRE([gl_GLIBC21])dnl AC_REQUIRE([gt_INTDIV0])dnl AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl AC_REQUIRE([gt_HEADER_INTTYPES_H])dnl AC_REQUIRE([gt_INTTYPES_PRI])dnl AC_REQUIRE([gl_XSIZE])dnl AC_REQUIRE([gt_INTL_MACOSX])dnl AC_CHECK_TYPE([ptrdiff_t], , [AC_DEFINE([ptrdiff_t], [long], [Define as the type of the result of subtracting two pointers, if the system doesn't define it.]) ]) AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ stdlib.h string.h unistd.h sys/param.h]) AC_CHECK_FUNCS([asprintf fwprintf getcwd getegid geteuid getgid getuid \ mempcpy munmap putenv setenv setlocale snprintf stpcpy strcasecmp strdup \ strtoul tsearch wcslen __argz_count __argz_stringify __argz_next \ __fsetlocking]) dnl Use the _snprintf function only if it is declared (because on NetBSD it dnl is defined as a weak alias of snprintf; we prefer to use the latter). gt_CHECK_DECL(_snprintf, [#include ]) gt_CHECK_DECL(_snwprintf, [#include ]) dnl Use the *_unlocked functions only if they are declared. dnl (because some of them were defined without being declared in Solaris dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built dnl on Solaris 2.5.1 to run on Solaris 2.6). dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. gt_CHECK_DECL(feof_unlocked, [#include ]) gt_CHECK_DECL(fgets_unlocked, [#include ]) gt_CHECK_DECL(getc_unlocked, [#include ]) case $gt_cv_func_printf_posix in *yes) HAVE_POSIX_PRINTF=1 ;; *) HAVE_POSIX_PRINTF=0 ;; esac AC_SUBST([HAVE_POSIX_PRINTF]) if test "$ac_cv_func_asprintf" = yes; then HAVE_ASPRINTF=1 else HAVE_ASPRINTF=0 fi AC_SUBST([HAVE_ASPRINTF]) if test "$ac_cv_func_snprintf" = yes; then HAVE_SNPRINTF=1 else HAVE_SNPRINTF=0 fi AC_SUBST([HAVE_SNPRINTF]) if test "$ac_cv_func_wprintf" = yes; then HAVE_WPRINTF=1 else HAVE_WPRINTF=0 fi AC_SUBST([HAVE_WPRINTF]) AM_ICONV AM_LANGINFO_CODESET if test $ac_cv_header_locale_h = yes; then gt_LC_MESSAGES fi if test -n "$INTL_MACOSX_LIBS"; then CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers" fi dnl intl/plural.c is generated from intl/plural.y. It requires bison, dnl because plural.y uses bison specific features. It requires at least dnl bison-1.26 because earlier versions generate a plural.c that doesn't dnl compile. dnl bison is only needed for the maintainer (who touches plural.y). But in dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put dnl the rule in general Makefile. Now, some people carelessly touch the dnl files or have a broken "make" program, hence the plural.c rule will dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not dnl present or too old. AC_CHECK_PROGS([INTLBISON], [bison]) if test -z "$INTLBISON"; then ac_verc_fail=yes else dnl Found it, now check the version. AC_MSG_CHECKING([version of bison]) changequote(<<,>>)dnl ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` case $ac_prog_version in '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) changequote([,])dnl ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; esac AC_MSG_RESULT([$ac_prog_version]) fi if test $ac_verc_fail = yes; then INTLBISON=: fi ]) dnl Checks for special options needed on MacOS X. dnl Defines INTL_MACOSX_LIBS. AC_DEFUN([gt_INTL_MACOSX], [ dnl Check for API introduced in MacOS X 10.2. AC_CACHE_CHECK([for CFPreferencesCopyAppValue], gt_cv_func_CFPreferencesCopyAppValue, [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers" gt_save_LIBS="$LIBS" LIBS="$LIBS -framework CoreFoundation" AC_TRY_LINK([#include ], [CFPreferencesCopyAppValue(NULL, NULL)], [gt_cv_func_CFPreferencesCopyAppValue=yes], [gt_cv_func_CFPreferencesCopyAppValue=no]) CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1, [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) fi dnl Check for API introduced in MacOS X 10.3. AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent, [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I/System/Library/Frameworks/CoreFoundation.framework/Headers" gt_save_LIBS="$LIBS" LIBS="$LIBS -framework CoreFoundation" AC_TRY_LINK([#include ], [CFLocaleCopyCurrent();], [gt_cv_func_CFLocaleCopyCurrent=yes], [gt_cv_func_CFLocaleCopyCurrent=no]) CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFLocaleCopyCurrent = yes; then AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1, [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi AC_SUBST([INTL_MACOSX_LIBS]) ]) dnl gt_CHECK_DECL(FUNC, INCLUDES) dnl Check whether a function is declared. AC_DEFUN([gt_CHECK_DECL], [ AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1, [AC_TRY_COMPILE([$2], [ #ifndef $1 char *p = (char *) $1; #endif ], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)]) if test $ac_cv_have_decl_$1 = yes; then gt_value=1 else gt_value=0 fi AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value], [Define to 1 if you have the declaration of `$1', and to 0 if you don't.]) ]) dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) hercules-3.12/m4/glibc21.m40000664000175000017500000000144512564723224012214 00000000000000# glibc21.m4 serial 3 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Test for the GNU C Library, version 2.1 or newer. # From Bruno Haible. AC_DEFUN([gl_GLIBC21], [ AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, ac_cv_gnu_library_2_1, [AC_EGREP_CPP([Lucky GNU user], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) Lucky GNU user #endif #endif ], ac_cv_gnu_library_2_1=yes, ac_cv_gnu_library_2_1=no) ] ) AC_SUBST(GLIBC21) GLIBC21="$ac_cv_gnu_library_2_1" ] ) hercules-3.12/m4/iconv.m40000664000175000017500000000642612564723224012113 00000000000000# iconv.m4 serial AM4 (gettext-0.11.3) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_lib_iconv=yes am_cv_func_iconv=yes) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST(LIBICONV) AC_SUBST(LTLIBICONV) ]) AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_TRY_COMPILE([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) fi ]) hercules-3.12/m4/intdiv0.m40000664000175000017500000000334012564723224012342 00000000000000# intdiv0.m4 serial 1 (gettext-0.11.3) dnl Copyright (C) 2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([gt_INTDIV0], [ AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], gt_cv_int_divbyzero_sigfpe, [ AC_TRY_RUN([ #include #include static void #ifdef __cplusplus sigfpe_handler (int sig) #else sigfpe_handler (sig) int sig; #endif { /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ exit (sig != SIGFPE); } int x = 1; int y = 0; int z; int nan; int main () { signal (SIGFPE, sigfpe_handler); /* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ #if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) signal (SIGTRAP, sigfpe_handler); #endif /* Linux/SPARC yields signal SIGILL. */ #if defined (__sparc__) && defined (__linux__) signal (SIGILL, sigfpe_handler); #endif z = x / y; nan = y / y; exit (1); } ], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, [ # Guess based on the CPU. case "$host_cpu" in alpha* | i[34567]86 | m68k | s390*) gt_cv_int_divbyzero_sigfpe="guessing yes";; *) gt_cv_int_divbyzero_sigfpe="guessing no";; esac ]) ]) case "$gt_cv_int_divbyzero_sigfpe" in *yes) value=1;; *) value=0;; esac AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, [Define if integer division by zero raises signal SIGFPE.]) ]) hercules-3.12/m4/inttypes.m40000664000175000017500000000147212564723224012650 00000000000000# inttypes.m4 serial 1 (gettext-0.11.4) dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_INTTYPES_H if exists and doesn't clash with # . AC_DEFUN([gt_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, [ AC_TRY_COMPILE( [#include #include ], [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) ]) if test $gt_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, [Define if exists and doesn't clash with .]) fi ]) hercules-3.12/m4/inttypes_h.m40000664000175000017500000000162312564723224013155 00000000000000# inttypes_h.m4 serial 6 dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([gl_AC_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1;], gl_cv_header_inttypes_h=yes, gl_cv_header_inttypes_h=no)]) if test $gl_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) hercules-3.12/m4/inttypes-pri.m40000664000175000017500000000200212564723224013426 00000000000000# inttypes-pri.m4 serial 1 (gettext-0.11.4) dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. # Define PRI_MACROS_BROKEN if exists and defines the PRI* # macros to non-string values. This is the case on AIX 4.3.3. AC_DEFUN([gt_INTTYPES_PRI], [ AC_REQUIRE([gt_HEADER_INTTYPES_H]) if test $gt_cv_header_inttypes_h = yes; then AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], gt_cv_inttypes_pri_broken, [ AC_TRY_COMPILE([#include #ifdef PRId32 char *p = PRId32; #endif ], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) ]) fi if test "$gt_cv_inttypes_pri_broken" = yes; then AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, [Define if exists and defines unusable PRI* macros.]) fi ]) hercules-3.12/m4/isc-posix.m40000664000175000017500000000170612564723224012707 00000000000000# isc-posix.m4 serial 2 (gettext-0.11.2) dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # This file is not needed with autoconf-2.53 and newer. Remove it in 2005. # This test replaces the one in autoconf. # Currently this macro should have the same name as the autoconf macro # because gettext's gettext.m4 (distributed in the automake package) # still uses it. Otherwise, the use in gettext.m4 makes autoheader # give these diagnostics: # configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX # configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX undefine([AC_ISC_POSIX]) AC_DEFUN([AC_ISC_POSIX], [ dnl This test replaces the obsolescent AC_ISC_POSIX kludge. AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) ] ) hercules-3.12/m4/lcmessage.m40000664000175000017500000000240412564723224012730 00000000000000# lcmessage.m4 serial 4 (gettext-0.14.2) dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995. # Check whether LC_MESSAGES is available in . AC_DEFUN([gt_LC_MESSAGES], [ AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES, [AC_TRY_LINK([#include ], [return LC_MESSAGES], gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)]) if test $gt_cv_val_LC_MESSAGES = yes; then AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your file defines LC_MESSAGES.]) fi ]) hercules-3.12/m4/lib-ld.m40000664000175000017500000000653112564723224012135 00000000000000# lib-ld.m4 serial 3 (gettext-0.13) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl Subroutines of libtool.m4, dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision dnl with libtool.m4. dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) hercules-3.12/m4/lib-link.m40000664000175000017500000005542612564723224012502 00000000000000# lib-link.m4 serial 6 (gettext-0.14.3) dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.50) dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, dnl hardcode_direct, hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ dnl Tell automake >= 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib$1-prefix], [ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib$1-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/lib" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then found_dir="$additional_libdir" found_so="$additional_libdir/lib$name.$shlibext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then found_dir="$dir" found_so="$dir/lib$name.$shlibext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */lib | */lib/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/lib"; then haveit= if test "X$additional_libdir" = "X/usr/local/lib"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) hercules-3.12/m4/lib-prefix.m40000664000175000017500000001231012564723224013023 00000000000000# lib-prefix.m4 serial 4 (gettext-0.14.2) dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/lib" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/lib"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/lib"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) hercules-3.12/m4/progtest.m40000664000175000017500000000555012564723224012641 00000000000000# progtest.m4 serial 4 (gettext-0.14.2) dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1996. AC_PREREQ(2.50) # Search path for a program which passes the given test. dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) AC_DEFUN([AM_PATH_PROG_WITH_TEST], [ # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL(ac_cv_path_$1, [case "[$]$1" in [[\\/]]* | ?:[[\\/]]*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in ifelse([$5], , $PATH, [$5]); do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) fi AC_SUBST($1)dnl ]) hercules-3.12/m4/stdint_h.m40000664000175000017500000000157312564723224012607 00000000000000# stdint_h.m4 serial 5 dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_STDINT_H_WITH_UINTMAX if exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([gl_AC_HEADER_STDINT_H], [ AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1;], gl_cv_header_stdint_h=yes, gl_cv_header_stdint_h=no)]) if test $gl_cv_header_stdint_h = yes; then AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) hercules-3.12/m4/uintmax_t.m40000664000175000017500000000207612564723224013002 00000000000000# uintmax_t.m4 serial 9 dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. AC_PREREQ(2.13) # Define uintmax_t to 'unsigned long' or 'unsigned long long' # if it is not already defined in or . AC_DEFUN([gl_AC_TYPE_UINTMAX_T], [ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) AC_REQUIRE([gl_AC_HEADER_STDINT_H]) if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG]) test $ac_cv_type_unsigned_long_long = yes \ && ac_type='unsigned long long' \ || ac_type='unsigned long' AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, [Define to unsigned long or unsigned long long if and don't define.]) else AC_DEFINE(HAVE_UINTMAX_T, 1, [Define if you have the 'uintmax_t' type in or .]) fi ]) hercules-3.12/m4/ulonglong.m40000664000175000017500000000161512564723224012774 00000000000000# ulonglong.m4 serial 4 dnl Copyright (C) 1999-2004 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_UNSIGNED_LONG_LONG if 'unsigned long long' works. AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG], [ AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long, [AC_TRY_LINK([unsigned long long ull = 1ULL; int i = 63;], [unsigned long long ullmax = (unsigned long long) -1; return ull << i | ull >> i | ullmax / ull | ullmax % ull;], ac_cv_type_unsigned_long_long=yes, ac_cv_type_unsigned_long_long=no)]) if test $ac_cv_type_unsigned_long_long = yes; then AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, [Define if you have the 'unsigned long long' type.]) fi ]) hercules-3.12/util/0000775000175000017500000000000012625667404011245 500000000000000hercules-3.12/util/Makefile.in0000664000175000017500000003710412625667166013244 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = util DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/mkinstalldirs $(dist_pkgdata_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)" SCRIPTS = $(bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(dist_pkgdata_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ bin_SCRIPTS = dasdlist bldlvlck dist_pkgdata_DATA = cckddump.hla awswrite.jcl rawstape.jcl tapeconv.jcl\ TMOUNT.txt \ zzsacard.bin awssl-v19g cckdload.hla EXTRA_DIST = dasdlist dasdlist.bat bldlvlck all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu util/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu util/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgdataDATA: $(dist_pkgdata_DATA) @$(NORMAL_INSTALL) @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done uninstall-dist_pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_pkgdataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binSCRIPTS uninstall-dist_pkgdataDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-binSCRIPTS install-data \ install-data-am install-dist_pkgdataDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-binSCRIPTS \ uninstall-dist_pkgdataDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/util/Makefile.am0000664000175000017500000000036212564723224013215 00000000000000bin_SCRIPTS = dasdlist bldlvlck dist_pkgdata_DATA = cckddump.hla awswrite.jcl rawstape.jcl tapeconv.jcl\ TMOUNT.txt \ zzsacard.bin awssl-v19g cckdload.hla EXTRA_DIST = dasdlist dasdlist.bat bldlvlck hercules-3.12/util/cckddump.hla0000664000175000017500000024315312564723224013450 00000000000000*/* ---------------------------------------------------------------- * * build a dasd file from sysut1 to sysut2 * * ---------------------------------------------------------------- */ version EQU 0 release EQU 1 mod EQU 15 CZV70 */* ---------------------------------------------------------------- * * macros * * ---------------------------------------------------------------- */ MACRO &L STLE &R,&A store little-endian &L STC &R,&A STCM &R,2,1+&A STCM &R,4,2+&A STCM &R,8,3+&A MEND MACRO &L STHLE &R,&A store halfword little-endian &L STC &R,&A STCM &R,2,1+&A MEND MACRO &L LLE &R,&A load little-endian &L IC &R,&A ICM &R,2,1+&A ICM &R,4,2+&A ICM &R,8,3+&A MEND MACRO &L LHLE &R,&A load halfword little-endian &L SLR &R,&R IC &R,&A ICM &R,2,1+&A MEND MACRO &L #MSG &LVL,&MSG,&TYPE=CALL LCLA &A,&N,&O LCLC &C GBLA &MSG_IX GBLC &MSGS(256) AIF ('&TYPE' EQ 'CALL').CALL, x ('&TYPE' EQ 'GEN').GEN MNOTE 8,'Invalid type specified' MEXIT .* .CALL ANOP &C SETC '&LVL' AIF ('&LVL' NE '').LVLOK &C SETC '1' .LVLOK ANOP &L CLI msglvl,&C BH #MG&SYSNDX.X &MSG_IX SETA &MSG_IX+1 &MSGS(&MSG_IX) SETC '&MSG' L re,=A(#MSG&MSG_IX) LA rf,L'#MSG&MSG_IX &A SETA 1 &O SETA 0 &N SETA N'&SYSLIST-2 AGO .PL0 .PLLOOP ANOP LA re,&SYSLIST(&A+2) &A SETA &A+1 AIF (&A GT &N).PLX14 LA rf,&SYSLIST(&A+2) &A SETA &A+1 .PL0 AIF (&A GT &N).PLX15 LA r0,&SYSLIST(&A+2) &A SETA &A+1 AIF (&A GT &N).PLX0 LA r1,&SYSLIST(&A+2) &A SETA &A+1 AIF (&A GT &N).PLX1 STM re,r1,msgl+&O &O SETA &O+16 AGO .PLLOOP .PLX14 ST re,msgl+&O AGO .CALL2 .PLX15 STM re,rf,msgl+&O AGO .CALL2 .PLX0 STM re,r0,msgl+&O AGO .CALL2 .PLX1 STM re,r1,msgl+&O .CALL2 LA r1,msgl L rf,=a(msg_rtn) BALR re,rf #MG&SYSNDX.X DS 0H MEXIT .* .GEN ANOP AIF ('&L' EQ '').GENNOL &L DS 0H .GENNOL ANOP &A SETA 1 .GENLOOP AIF (&A GT &MSG_IX).MEND #MSG&A DC C&MSGS(&A) &A SETA &A+1 AGO .GENLOOP .MEND MEND */* ---------------------------------------------------------------- * * * * ---------------------------------------------------------------- */ main CSECT , main RMODE ANY main AMODE 31 SAVE (14,12),,'cckddump main() &SYSDATE &SYSTIME ' pgmid EQU main+5 LR rc,rf USING main,rc LA rb,4095(,rc) USING main+4095,rb LR r2,r1 */* ---------------------------------------------------------------- * * get/clear workareas * * ---------------------------------------------------------------- */ STORAGE OBTAIN,LENGTH=vdw_len,BNDRY=PAGE ST r1,8(,rd) ST rd,4(,r1) LR rd,r1 USING vdw,rd MVC id,=C'vdw ' LA r0,vdw+8 L r1,=A(vdw_len-8) SLR rf,rf MVCL r0,re ST rd,vdw_31 STORAGE OBTAIN,LENGTH=vdw24_len,LOC=BELOW,BNDRY=PAGE ST r1,vdw_24 LR ra,r1 USING vdw24,ra MVC id24,=C'vdw24' LA r0,vdw24+4 L r1,=A(vdw24_len-4) SLR rf,rf MVCL r0,re */* ---------------------------------------------------------------- * * try to open print file * * ---------------------------------------------------------------- */ MVC prdcb,model_prdcb MVC prdcbe,model_prdcbe pr USING IHADCB,prdcb LA r1,prdcbe ST r1,pr.DCBDCBE MVC devtl,model_devtl DEVTYPE pr.DCBDDNAM,(devta,L'devta),MF=(E,devtl) LTR rf,rf BNZ noprint MVC openl,model_openl OPEN (pr.IHADCB,OUTPUT),MODE=31,MF=(E,openl) #MSG 1,'%s %d.%d.%d starting', x pgmid,=A(version),=A(release),=A(mod) #MSG 0,'main workarea is at address 0x%x, 24-bit workarea is x at address 0x%x',vdw_31,vdw_24 noprint DS 0H */* ---------------------------------------------------------------- * * get parameters * * ---------------------------------------------------------------- */ LR r1,r2 BAS r9,getopts */* ---------------------------------------------------------------- * * get device information for sysut1 [the volume to be dumped] * * ---------------------------------------------------------------- */ MVC devtl,model_devtl DEVTYPE =CL8'SYSUT1',(devta,L'devta), x INFOLIST=devt_infol_2,MF=(E,devtl) LTR rf,rf BNZ ut1_devt_err TM devta+2,UCB3DACC check for dasd device BNO ut1_not_dasd TM dev_flags,X'80' check for eckd BNO ut1_not_eckd L r3,cyls M r2,trks_per_cyl total number of trks ST r3,trks */* ---------------------------------------------------------------- * * get device information for sysut2 [the file to be dumped] * * ---------------------------------------------------------------- */ MVC devtl,model_devtl DEVTYPE =CL8'SYSUT2',(dw,L'devta), x INFOLIST=devt_infol_2,MF=(E,devtl) LTR rf,rf BNZ out_devt_err TM dw+2,UCB3DACC check for dasd device BNO out_not_dasd */* ---------------------------------------------------------------- * * part 1 -- determine which tracks to dump * * * * From the vtoc, determine which tracks are to be dumped. * * A vector [trk_vec] is built for each track on the volume. * * If an entry is zero, then the track will not be dumped; * * otherwise, the entry points to an entry in the dataset * * table [dsn_area] which will contain statistics about each * * dataset on the volume. The first 3 entries in the dataset * * table are special, representing free space [**free**], * * track 0 [**track 0] and the vtoc [**vtoc**], respectively. * * * * ---------------------------------------------------------------- */ */* ---------------------------------------------------------------- * * open sysut1 vtoc * * ---------------------------------------------------------------- */ vt USING IHADCB,vtdcb MVC vtdcb,model_vtdcb LA r1,exlst STCM r1,7,vt.DCBEXLSA LA r1,jfcb ST r1,exlst MVI exlst,X'87' MVC openl24,model_openl24 RDJFCB (vt.IHADCB,INPUT),MF=(E,openl24) LTR rf,rf BNZ ut1_rdjfcb_err j USING INFMJFCB,jfcb MVI j.JFCBDSNM,4 vtoc name is all x'04's MVC j.JFCBDSNM+1(L'JFCBDSNM-1),j.JFCBDSNM MVC volser,j.JFCBVOLS DROP j OPEN vt.IHADCB,TYPE=J,MF=(E,openl24) TM vt.DCBOFLGS,DCBOFOPN BNO ut1_vtoc_open_err L r2,vt.DCBDEBAD load deb address for cvaf N r2,=A(X'00FFFFFF') #MSG 1,'%s:6 vtoc opened',volser #MSG 0,'%s:6 has %d cyls, %d trks/cyl and %d total trks', x volser,cyls,trks_per_cyl,trks */* ---------------------------------------------------------------- * * read the format 4 dscb * * ---------------------------------------------------------------- */ h USING BFLHDR,bflh OI h.BFLHFL,BFLHDSCB MVI h.BFLHNOE,1 e USING BFLE,bflent LA r1,dscb4 ST r1,e.BFLEBUF OI e.BFLEFL,BFLECHR MVI e.BFLELTH,L'dscb4 MVC cvpl_area,model_cvpl CVAFSEQ ACCESS=GTEQ,BUFLIST=h.BFLHDR,DEB=(r2), x BRANCH=(YES,PGM),MF=(E,cvpl_area) LTR rf,rf BNZ ut1_dscb4_err DROP h,e f4 USING IECSDSL4-44,dscb4 CLI f4.DS4IDFMT,C'4' BNE ut1_dscb4_err */* ---------------------------------------------------------------- * * calculate size of the vtoc and get an area for all dscbs * * ---------------------------------------------------------------- */ SLR r4,r4 IC r4,f4.DS4DEVDT ST r4,dscbs_per_trk LA r1,f4.DS4VTOCE BAL re,cnv_xtnt r0 - starting track, x r1 - number of tracks ST r1,vtoc_trks MR r0,r4 ST r1,total_dscbs number of dscbs MH r1,=Y(DS1END-IECSDSL1) ST r1,vtoc_size size of vtoc STORAGE OBTAIN,LENGTH=(r1),BNDRY=PAGE area for the vtoc ST r1,vtoc_area #MSG 0,'%s:6 vtoc has %d total dscbs', x volser,total_dscbs #MSG 0,'storage obtained for vtoc area, addr 0x%x size %d', x vtoc_area,vtoc_size */* ---------------------------------------------------------------- * * read the entire vtoc a track at a time * * ---------------------------------------------------------------- */ #MSG 0,'reading %s:6 vtoc',volser L r3,vtoc_area L r4,vtoc_trks LA r5,=XL5'0' BAL re,cvaf_bld MVC cvpl_area,model_cvpl read the first track CVAFSEQ ACCESS=GTEQ,BUFLIST=bflh,DEB=(r2), x BRANCH=(YES,PGM),MF=(E,cvpl_area) LTR rf,rf BNZ ut1_cvaf_err B vtocnext vtocloop BAL re,cvaf_bld read another track CVAFSEQ ACCESS=GT,BUFLIST=bflh,DEB=(r2), x BRANCH=(YES,PGM),MF=(E,cvpl_area) LTR rf,rf BNZ ut1_cvaf_err vtocnext BCT r4,vtocloop CLOSE vtdcb,MF=(E,openl24) #MSG 0,'%s:6 vtoc closed',volser B process_vtoc */* ---------------------------------------------------------------- * * subroutine to build the cvaf control blocks * * * * r3 - pointer to buffer for dscb (updated) * * r5 - cchhr of 1st dscb - points to last bflearg on exit * * ---------------------------------------------------------------- */ cvaf_bld XC bflh,bflh USING IECSDSL1,r3 h USING BFLHDR,bflh OI h.BFLHFL,BFLHDSCB L r0,dscbs_per_trk STC r0,h.BFLHNOE LA rf,bflent USING BFLE,rf cvaf_bld_loop DS 0H XC BFLE(BFLELN),BFLE OI BFLEFL,BFLECHR MVI BFLELTH,DS1END-IECSDSF1 MVC BFLEARG,0(r5) arg only used for 1st entry ST r3,BFLEBUF LA r3,DS1END LA r5,BFLEARG r5 will point to last bflearg LA rf,BFLE+BFLELN on exit BCT r0,cvaf_bld_loop BR re DROP r3,h,rf */* ---------------------------------------------------------------- * * count nbr datasets and get a dataset area * * ---------------------------------------------------------------- */ process_vtoc DS 0H L r0,total_dscbs L r1,vtoc_area USING IECSDSL1,r1 SLR r3,3 init nbr datasets SLR rf,rf cnt_dsn CLI DS1FMTID,C'1' BNE cnt_dsn_next LA r3,1(,r3) LR rf,r1 remember last fmt1 dscb addr cnt_dsn_next DS 0H LA r1,DS1END BCT r0,cnt_dsn DROP r1 ST r3,dsn_nbr ST rf,last_f1_dscb #MSG 1,'%d datasets are on %s:6',dsn_nbr,volser LA r3,3(,r3) for free, track 0 and vtoc ST r3,dsn_nbr M r2,=A(dsn_area_len) ST r3,dsn_area_size STORAGE OBTAIN,LENGTH=(R3),BNDRY=PAGE ST r1,dsn_area_addr LR r2,r1 SLR rf,rf MVCL r2,re USING dsn_area,r1 MVC dsn_name,=CL44'*** free ***' LA r1,dsn_area_len(,r1) MVC dsn_name,=CL44'*** track 0 ***' MVC dsn_extents,=A(1) MVC dsn_trks,=A(1) MVC dsn_trks_dump,=A(1) DROP r1 #MSG 0,'storage obtained for dsn area, addr 0x%x size %d', x dsn_area_addr,dsn_area_size */* ---------------------------------------------------------------- * * get track vector * * * * each word corresponds to a track; if the word is non-zero * * then it points to a dsn_area entry and the track will * * be dumped. * * ---------------------------------------------------------------- */ L r3,trks SLL r3,2 ST r3,trk_vec_size STORAGE OBTAIN,LENGTH=(r3),BNDRY=PAGE ST r1,trk_vec LR r2,r1 SLR rf,rf MVCL r2,re TM opts,ALLTRKS dumping all tracks ? BNO init_trk_vec1 no, continue L r3,trks init_trk_vec DS 0H MVC 0(4,r1),dsn_area_addr set entry to '*** none ***' LA r1,4(,r1) BCT r3,init_trk_vec init_trk_vec1 DS 0H L r1,trk_vec L r2,dsn_area_addr LA r2,dsn_area_len(,r2) track 0 dsn_area [2nd entry] ST r2,0(,r1) set track 0 to dump #MSG 0,'storage obtained for trk vector, addr 0x%x size %d', x trk_vec,trk_vec_size */* ---------------------------------------------------------------- * * figure out which tracks to dump * * ---------------------------------------------------------------- */ L r9,vtoc_area L r4,dsn_area_addr LA r4,dsn_area_len*2(,r4) point to 3rd entry [vtoc] USING dsn_area,r4 fmt4 MVC dsn_name,=CL44'*** vtoc ***' first dscb is format 4 MVC dsn_extents,=A(1) USING IECSDSL4-44,r9 LA r1,DS4VTOCE BAL re,cnv_xtnt get vtoc start trk, size ST r1,dsn_trks ST r1,dsn_trks_dump LA r1,DS4VTOCE LA r2,1 SLR r3,r3 BCTR r3,0 BAL re,upd_trk_vec LA r4,dsn_area_len(,r4) DROP r9 USING IECSDSL1,r9 vtoc_loop LA r9,DS1END CL r9,last_f1_dscb BH vtoc_exit CLI DS1FMTID,C'1' BNE vtoc_loop fmt1 MVC dsn_name,DS1DSNAM format 1 dscb processing SLR r2,r2 IC r2,DS1NOEPV ST r2,dsn_extents LTR r2,r2 BZ f1_part2 */* count number of tracks allocated for the dataset */ LA r6,DS1EXT1 LA r7,3 format 1 has 3 extents f1_xt LR r1,r6 BAL re,cnv_xtnt A r1,dsn_trks ST r1,dsn_trks SH r2,=Y(1) BNP f1_part2 LA r6,10(,r6) BCT r7,f1_xt fmt3 LA r1,DS1PTRDS BAL re,cnv_ptr LR r8,r1 USING IECSDSL3,r8 LA r6,DS3EXTNT fmt 3 starts off with 4 extents LA r7,4 f3_xt1 LR r1,r6 BAL re,cnv_xtnt A r1,dsn_trks ST r1,dsn_trks SH r2,=Y(1) BNP f1_part2 LA r6,10(,r6) BCT r7,f3_xt1 LA r6,DS3ADEXT LA r7,9 and has 9 additional extents f3_xt2 LR r1,r6 BAL re,cnv_xtnt A r1,dsn_trks ST r1,dsn_trks SH r2,=Y(1) BNP f1_part2 LA r6,10(,r6) BCT r7,f3_xt2 LA r1,DS3PTRDS B fmt3 DROP r8 f1_part2 DS 0H */* check if dataset included or excluded */ L r1,dsn_incl_list LTR r1,r1 BZ f1_in_ok LA r0,DS1DSNAM BAL re,chk_dsn_list LTR rf,rf BZ f1_in_ok OI dsn_flag,dsn_not_incl f1_in_ok L r1,dsn_excl_list LTR r1,r1 BZ f1_ex_ok LA r0,DS1DSNAM BAL re,chk_dsn_list LTR rf,rf BNZ f1_ex_ok OI dsn_flag,dsn_excl #MSG 1,'%s:44 Excluded',DS1DSNAM Msg for DS exclude SOMITCW f1_ex_ok TM dsn_flag,dsn_not_incl+dsn_excl BNZ f1_exit */* check if we'll use ds1lstar */ SLR r3,r3 presume we won't use ds1lstar BCTR r3,0 TM opts,ALLDATA+ALLTRKS BNZ f1_no_lstar TM DS1SMSFG,DS1PDSE+DS1STRP+DS1PDSEX+DS1DSAE BNZ f1_no_lstar CLC DS1DSORG,=AL1(DS1DSGPS,0) BE f1_lstar_ok CLC DS1DSORG,=AL1(DS1DSGPO,0) BNE f1_no_lstar f1_lstar_ok DS 0H SLR r3,r3 ICM r3,3,DS1LSTAR LA r3,1(,r3) number tracks in use f1_no_lstar DS 0H */* scan the extents */ LA r0,3 LA r1,DS1EXT1 L r2,dsn_extents f1_xt_2 BAL re,upd_trk_vec LTR rf,rf BNZ f1_exit BCT r0,f1_xt_2 LA r1,DS1PTRDS fmt3_2 BAL re,cnv_ptr LR r8,r1 USING IECSDSL3,r8 LA r1,DS3EXTNT LA r0,4 f3_xt1_2 BAL re,upd_trk_vec LTR rf,rf BNZ f1_exit BCT r0,f3_xt1_2 LA r1,DS3ADEXT LA r0,9 f3_xt2_2 BAL re,upd_trk_vec LTR rf,rf BNZ f1_exit BCT r0,f3_xt2_2 LA r1,DS3PTRDS B fmt3_2 DROP r8 f1_exit LA r4,dsn_area_len(,r4) B vtoc_loop vtoc_exit DS 0H DROP r9,r4 L r1,vtoc_area L r0,vtoc_size STORAGE RELEASE,ADDR=(1),LENGTH=(0) #MSG 0,'storage released for vtoc area, addr 0x%x size %d', x vtoc_area,vtoc_size XC vtoc_area,vtoc_area XC last_f1_dscb,last_f1_dscb XC vtoc_size,vtoc_size * The dsn_excl_list memory is being freed here. SOMITCW L r1,dsn_excl_list Load addr. of first list entry SOMITCW in_free DS 0H SOMITCW LTR r1,r1 See if a list entry to free SOMITCW BZ in_freed All dsn_excl_list freed, go exit SOMITCW L r2,0(,r1) Save the next address to free SOMITCW FREEMAIN RU,LV=49,A=(1) Free the list entry SOMITCW LR r1,r2 Set the next address to free SOMITCW B in_free Go to free the next list entry SOMITCW in_freed DS 0H SOMITCW XC dsn_excl_list(4),dsn_excl_list Clear the anchor SOMITCW */* ---------------------------------------------------------------- * * count number of tracks we're going to dump * * ---------------------------------------------------------------- */ SLR r2,r2 L r1,trk_vec L r0,trks SLR rf,rf cnt_dump CL rf,0(,r1) BE *+8 LA r2,1(,r2) LA r1,4(,r1) BCT r0,cnt_dump ST r2,trks_dump #MSG 0,'%d tracks out of %d will be dumped', x trks_dump,trks */* ---------------------------------------------------------------- * * part 2 -- do the actual work */* ---------------------------------------------------------------- */* ---------------------------------------------------------------- * * open sysut1 in excp mode * * ---------------------------------------------------------------- */ ex USING IHADCB,exdcb MVC exdcb,model_exdcb LA r1,exlst STCM r1,7,ex.DCBEXLSA LA r1,jfcb ST r1,exlst MVI exlst,X'87' MVC openl24,model_openl24 RDJFCB (ex.IHADCB,INPUT),MF=(E,openl24) LTR rf,rf BNZ ut1_rdjfcb_err j USING INFMJFCB,jfcb MVI j.JFCBDSNM,4 vtoc name is all x'04's MVC j.JFCBDSNM+1(L'JFCBDSNM-1),j.JFCBDSNM DROP j OPEN ex.IHADCB,TYPE=J,MF=(E,openl24) TM ex.DCBOFLGS,DCBOFOPN BNO ut1_excp_open_err */* ---------------------------------------------------------------- * * update the deb so we can read the entire volume * * [this requires key 0 - hence supervisor state] * * ---------------------------------------------------------------- */ L r2,ex.DCBDEBAD load deb address N r2,=A(X'00FFFFFF') USING DEBBASIC,r2 LA r3,DEBBASND USING DEBDASD,r3 MODESET MODE=SUP IPK 0(r2) SPKA 0 SLR r1,r1 STH r1,DEBSTRCC STH r1,DEBSTRHH L r1,cyls BCTR r1,0 STCM r1,3,DEBENDCC L r1,trks_per_cyl BCTR r1,0 STCM r1,3,DEBENDHH L r1,trks C r1,=A(65535) BNH *+8 L r1,=A(65535) STCM r1,3,DEBNMTRK SPKA 0(r2) MODESET MODE=PROB DROP r2,r3 */* ---------------------------------------------------------------- * * build the sysut1 iob * * ---------------------------------------------------------------- */ i1 USING IOBSTDRD,excp_iob OI i1.IOBFLAG1,IOBDATCH+IOBCMDCH+IOBUNREL LA r1,excp_ecb ST r1,i1.IOBECBPT LA r1,excp_ccws ST r1,i1.IOBSTART LA r1,exdcb ST r1,i1.IOBDCBPT */* ---------------------------------------------------------------- * * get area for read track (rt) * * ---------------------------------------------------------------- */ MVC trkcalcl,model_trkcalcl TRKCALC FUNCTN=TRKBAL,TYPE=devta+3,R=1,K=0,DD=65535, x MAXSIZE=YES,REGSAVE=YES,MF=(E,trkcalcl) LR r3,r0 copy max r1 data size A r3,=A(ha_len+count_len+8+count_len+8) x add ha size, r0 size, x r1 count and end-track marker LA r3,511(,r3) round_up 512 SRL r3,9 SLL r3,9 ST r3,trk_size M r2,trks_per_cyl STORAGE OBTAIN,LENGTH=(r3),LOC=BELOW,BNDRY=PAGE ST r1,excp_io_area ST r3,excp_io_size #MSG 0,'storage obtained for %s i/o area, addr 0x%x size %d',x volser,excp_io_area,excp_io_size */* ---------------------------------------------------------------- * * get area for compression * * ---------------------------------------------------------------- */ TM opts,COMPRESSION BNO no_compress_1 L r2,trk_size A r2,=A(4096) SRL r2,12 SLL r2,12 STORAGE OBTAIN,LENGTH=(r2),BNDRY=PAGE STM r1,r2,compr_area #MSG 0,'storage obtained for compression, addr 0x%x size %d',x compr_area,compr_size LA r2,handle LA r3,=A(32*1024) LA r4,=A(1) STM r2,r4,dw OI dw+8,X'80' LA r1,dw L rf,=V(EDCXHOTL) create persistent c environ BALR re,rf #MSG 0,'persistent c environment created, handle=0x%x', x handle no_compress_1 DS 0H */* ---------------------------------------------------------------- * * open sysut2 (output file) * * ---------------------------------------------------------------- */ o USING IHADCB,outdcb MVC outdcb,model_outdcb MVC outdcbe,model_outdcbe CZV70 LA r1,outdcbe CZV70 ST r1,o.DCBDCBE CZV70 OPEN (o.IHADCB,OUTPUT),MF=(E,openl24) TM o.DCBOFLGS,DCBOFOPN BNO out_open_err #MSG 1,'file SYSUT2 opened for output' */* ---------------------------------------------------------------- * * get sysut2 i/o areas * * ---------------------------------------------------------------- */ STORAGE OBTAIN,LENGTH=16384,BNDRY=PAGE ST r1,out_buf first output buffer MVC out_bufsz,=A(16384) * build the headers LR r3,r1 USING VDHDR,r3 ST r3,vdhdr_addr LR r0,r3 L r1,=A(16384) SLR rf,rf MVCL r0,re USING CKDDASD_DEVHDR,VDH_devhdr * MVC CKD_devid,=cl8'CKD_C370' Deleted SOMITCW * TR CKD_devid,e2aTab Deleted SOMITCW MVC CKD_devid,=XL8'434B445F43333730' SOMITCW L rf,trks_per_cyl STLE rf,CKD_heads L rf,trk_size STLE rf,CKD_trksize MVI CKD_devtype,x'90' CLI devta+3,x'0f' BE *+8 MVI CKD_devtype,x'80' USING CCKDDASD_DEVHDR,VDH_devhdr2 MVC CCKD_vrm,=AL1(version,release,mod) TM opts,DONTCOMPRESS BO *+8 MVI CCKD_options,1 L rf,cyls STLE rf,CCKD_cyls * calculate number lvl 1 entries L rf,trks LR r2,rf SRL r2,8 number of trks / 256 N rf,=A(X'000000ff') evenly divisible ? BZ *+8 LA r2,1(,r2) no, increment number STLE r2,CCKD_numl1tab LA r1,256 STLE r1,CCKD_numl2tab L r1,cckd_compr STC r1,CCKD_compress L r1,cckd_compr_level STHLE r1,CCKD_compress_parm LR r1,r2 calclate first pos SLL r1,2 (at end ov lvl 1 tab) AL r1,=A(VDH_l1tab-VDHDR) ST r1,out_pos ST r1,bytes_ovh DROP r3 * get area for rewrites LA r2,2(r2,r2) 2 entries for ea lvl 2 tab MH r2,=Y(rw_len) plus the 1st buf + a spare STORAGE OBTAIN,LENGTH=(r2),BNDRY=PAGE STM r1,r2,rw_area LR r0,r1 clear the rewrite area LR r1,r2 SLR rf,rf MVCL r0,re L r2,rw_area set first rewrite entry USING rw_ent,r2 MVC rw_buf,out_buf ST r2,last_rw LA r2,rw_next ST r2,next_rw DROP r2 */* ---------------------------------------------------------------- * * read tracks * * ---------------------------------------------------------------- */ SLR r2,r2 init relative track L r3,trk_vec read_loop CL r2,trks BNL read_exit LR rf,r2 get dsn area addr for trk SLL rf,2 L r4,0(rf,r3) LTR r4,r4 BZ read_next SLR r6,r6 LR r7,r2 D r6,trks_per_cyl get cc [r7] and hh [r6] XC i1.IOBSEEK,i1.IOBSEEK STCM r7,3,i1.IOBCC STCM r6,3,i1.IOBHH * build locate record ccw XC excp_ccws,excp_ccws LA r5,excp_ccws USING ccw0,r5 MVI CCW0CMD,lr LA r1,lr_parms STCM r1,7,CCW0ADDR OI CCW0FLAG,CCW0CC LA r1,L'lr_parms STCM r1,3,CCW0CNT LA r5,CCW0END * build read track ccws, try to read to end-of-cylinder L r0,trk_size L r1,excp_io_area USING ha,r1 read_rt MVI ha_bin,0 build a ha STCM r7,3,ha_cc STCM r6,3,ha_hh LA rf,ha_end DROP r1 MVI CCW0CMD,rt STCM rf,7,CCW0ADDR OI CCW0FLAG,CCW0SLI+CCW0CC STCM r0,3,CCW0CNT AR r1,r0 next i/o area addr LA r6,1(,r6) increment hh C r6,trks_per_cyl BNL read_rt_x exit if next cylinder LA r2,1(,r2) increment track nbr LR rf,r2 SLL rf,2 L r4,0(rf,r3) LTR r4,r4 BZ read_rt_x exit if trk_vec entry is 0 LA r5,CCW0END else point to next ccw B read_rt and loop back read_rt_x NI CCW0FLAG,255-CCW0CC unchain last ccw DROP r5 SLR rf,rf ICM rf,3,i1.IOBHH SR r6,rf number of read rt ccws * build locate record parameters XC lr_parms,lr_parms LA r5,lr_parms USING lr_parm_area,r5 MVI lr_op,lr_orient_home+lr_read_tracks STC r6,lr_count MVC lr_seek_addr,i1.IOBCC MVC lr_search_arg,i1.IOBCC DROP r5 * issue excp XC excp_ecb,excp_ecb EXCP i1.IOBSTDRD WAIT 1,ECB=excp_ecb CLI excp_ecb,X'7f' BNE ut1_io_err * process each track image L r1,excp_io_area read_proc LA r7,ha_len(,r1) find end of the track USING count,r7 read_proc1 CLC =X'ffffffffffffffff',count BE read_proc2 SLR rf,rf IC rf,count_key SLR r0,r0 ICM r0,3,count_data AR rf,r0 LA r7,count_end(rf) B read_proc1 DROP r7 read_proc2 LA r0,8(,r7) get length of track image SR r0,r1 ST r1,trk_addr ST r0,trk_sz ST r1,ctrk_addr CH r0,=Y(37) track just an eof ? BNE *+6 SLR r0,r0 yes, use 0 length ST r0,ctrk_sz * compress the track [but not the ha] * void *__xhotu(void *handle, void *function, ...); * int compress(uchar *dest, ulong *destLen, * const uchar *source, ulong sourceLen); TM opts,COMPRESSION BNO no_compress2 LA re,handle set parms for edcxhotu LA rf,=V(COMPRES2) STM re,rf,zlib_pl LM re,rf,compr_area dest area, length MVC 0(ha_len,re),0(r1) copy the ha MVI 0(re),1 flag indicating compressed trk LA re,ha_len(,re) point past the ha SH rf,=Y(ha_len) adjust dest length ST rf,compr_used set dest length LA rf,compr_used addr dest length STM re,rf,zlib_pl+8 set dest addr, addr len SH r0,=Y(ha_len) adjust source len BNP no_compress2 don't compress if null track ST r0,zlib_pl+20 set source length LA r1,ha_len(,r1) adjust source addr ST r1,zlib_pl+16 set source addr L re,compr_level get compression level ST re,zlib_pl+24 set compression level LA r1,zlib_pl parameter list addr L rf,=V(EDCXHOTU) call zlib compress function BALR re,rf LTR rf,rf test return code BNZ no_compress2 L r1,compr_used get compressed length LA r1,ha_len(,r1) add size of ha C r1,trk_sz check lengths BNL no_compress2 use uncompressed img MVC ctrk_addr,compr_area ST r1,ctrk_sz no_compress2 DS 0H * update byte counts LM r0,r1,bytes_read total bytes read AL r1,trk_sz BC 12,*+8 AL r0,=A(1) STM r0,r1,bytes_read LM r0,r1,bytes_written total bytes written AL r1,ctrk_sz BC 12,*+8 AL r0,=A(1) STM r0,r1,bytes_written L r1,ctrk_addr calculate dsn entry address USING ha_bin,r1 SLR re,re SLR rf,rf ICM rf,3,ha_cc M re,trks_per_cyl SLR re,re ICM re,3,ha_hh ALR rf,re SLL rf,2 L r4,0(rf,r3) DROP r1 USING dsn_area,r4 LM r0,r1,dsn_bytes_read dataset bytes read AL r1,trk_sz BC 12,*+8 AL r0,=A(1) STM r0,r1,dsn_bytes_read LM r0,r1,dsn_bytes_written dataset bytes written AL r1,ctrk_sz BC 12,*+8 AL r0,=A(1) STM r0,r1,dsn_bytes_written DROP r4 * call write track routine LA r1,ctrk_addr point to addr, len BAL re,write_track call write_track() L r1,trk_addr A r1,trk_size BCT r6,read_proc loop back if more tracks * next track read_next LA r2,1(,r2) B read_loop */* ---------------------------------------------------------------- * * finished reading -- cleanup * * ---------------------------------------------------------------- */ read_exit SLR r1,r1 nullify parm pointer BAL re,write_track call write_track() to finish CLOSE exdcb,MF=(E,openl24) #MSG 1,'file SYSUT1 closed' CLC =A(0),handle BE no_c_env LA r1,handle terminate the c environment ST r1,dw OI dw,X'80' LA r1,dw L rf,=V(EDCXHOTT) BALR re,rf no_c_env LM r1,r2,excp_io_area STORAGE RELEASE,ADDR=(1),LENGTH=(r2) LM r1,r2,compr_area LTR r1,r1 BZ read_term STORAGE RELEASE,ADDR=(1),LENGTH=(r2) read_term DS 0H ********* DC H'0' */* ---------------------------------------------------------------- * * print statistics * * ---------------------------------------------------------------- */ L rf,=A(do_stats) statistics routine addr BALR re,rf print the statistics */* ---------------------------------------------------------------- * * close the print file * * ---------------------------------------------------------------- */ TM pr.DCBOFLGS,DCBOFOPN did the print file open BNO noprint2 nope CLOSE pr.IHADCB,MODE=31,MF=(E,openl) noprint2 DS 0H */* ---------------------------------------------------------------- * * free the workareas and return * * ---------------------------------------------------------------- */ L r1,vdw_24 L r0,=A(vdw24_len) STORAGE RELEASE,ADDR=(1),LENGTH=(0) LR r1,rd L rd,4(,rd) L r0,=A(vdw_len) STORAGE RELEASE,ADDR=(1),LENGTH=(0) RETURN (14,12),RC=0 */* ---------------------------------------------------------------- * * write_track() -- output subroutine * * ---------------------------------------------------------------- */ write_track DS 0H STM re,r8,wt_save LTR r8,r1 0 means finish up BZ wt_finish LM re,rf,0(r8) load addr, length LTR rf,rf do nothing for null tracks BZ wt_return USING ha,re SLR r1,r1 calculate track number from ha ICM r1,3,ha_cc M r0,trks_per_cyl SLR r2,r2 ICM r2,3,ha_hh AR r2,r1 DROP re * get pos of level 2 table L r3,vdhdr_addr USING VDHDR,r3 LR r4,r2 SRL r4,8 lvl 1 tab index SLL r4,2 lvl 1 tab entry len is 4 LA r4,VDH_l1tab(r4) addr lvl 2 tab pos in lvl 1 tab DROP r3 LLE r3,0(r4) lvl 2 tab pos LTR r3,r3 does lvl 2 tab exist BNZ wt_l2t_ok yes, continue * level 2 table doesn't exist yet; build one L r0,bytes_ovh update AL r0,=A(256*L'L2TAB_entry) overhead ST r0,bytes_ovh total * get pos range of the new level 2 table L r3,out_pos load current pos STLE r3,0(r4) update lvl 1 pos LR r4,r3 calculate next pos AL r4,=A(256*L'L2TAB_entry) ST r4,out_pos set next available pos * set buffer for rewrite [if it already isn't] L r5,last_rw see if buf set for rewrite USING rw_ent,r5 CLC rw_pos,out_buf_pos BE wt_l2t_1 yes, continue LA r5,rw_next try next entry CLC rw_pos,out_buf_pos BE wt_l2t_1 yes, continue L r5,next_rw no, set this buf for rewrite MVC rw_pos,out_buf_pos MVC rw_buf,out_buf LA r0,rw_next ST r0,next_rw set next available rewrite entry wt_l2t_1 ST r5,last_rw update last rewrite entry addr * if the table fills this buffer then write it out LR r0,r4 copy next pos N r0,=A(x'ffffc000') convert to buf pos CL r0,out_buf_pos need to write this buf ? BE wt_l2t_ok no, continue L r6,out_buf write the current buf WRITE outdecb,SF,outdcb,(r6),MF=E CHECK outdecb NOTE outdcb note its file position ST r1,rw_ttr STORAGE OBTAIN,LENGTH=16384,BNDRY=PAGE L r0,out_bufsz AL r0,=A(16384) ST r0,out_bufsz LR r6,r1 ST r6,out_buf new output buf LR r0,r6 clear the buf L r1,=A(16384) SLR rf,rf MVCL r0,re L r1,out_buf_pos load previous buf pos AL r1,=A(16384) set new buf pos ST r1,out_buf_pos set new buf pos * if the table spans into the new buf then set it for rewrite CLR r4,r1 new pos same as new buf pos ? BE wt_l2t_ok yes, table didn't span L r5,next_rw get a new rewrite entry ST r1,rw_pos set buf pos ST r6,rw_buf set buf addr LA r5,rw_next ST r5,next_rw set next available rewrite entry DROP r5 wt_l2t_ok DS 0H r3 has lvl 2 tab pos * build the lvl 2 entry in a work area * (this is necessary because the entry might span buffers) w USING L2TAB,dw XC w.L2TAB_entry,w.L2TAB_entry L r1,out_pos get next available pos STLE r1,w.L2TAB_pos set pos for trk image L r1,4(,r8) get length of trk image STHLE r1,w.L2TAB_size set size of the area STHLE r1,w.L2TAB_len set length of the trk image DROP w * get address of the lvl 2 entry SLL r2,24 shift out all but low 8 bits SRL r2,21 shift back but multiplied by 8 AR r2,r3 have pos for lvl 2 tab entry LR rf,r2 N rf,=A(x'ffffc000') pos of buf for this entry L r4,last_rw find the rewrite entry USING rw_ent,r4 CL rf,rw_pos BE wt_l2t_2 found the entry LA r4,rw_next else try the next entry CL rf,rw_pos BNE wt_logic_err not good wt_l2t_2 L rf,rw_buf load buf addr for this entry N r2,=A(x'00003fff') get buf offset from pos AR r2,rf now have addr of lvl 2 entry * copy the work entry to the actual entry USING L2TAB,r2 A rf,=A(16384) calculate length SR rf,r2 left in this buf CH rf,=Y(8) check length to copy BNH *+8 LA rf,8 BCTR rf,0 decrement for EX EX rf,wt_l2t_mvc copy the entry LA re,6 calculate length-1 SR re,rf to copy BM wt_l2t_x exit if finished LA rf,dw+1(rf) source address LA r4,rw_next to next rewrite entry L r2,rw_buf target addr (start of next buf) EX re,wt_l2t_mvc2 copy the rest B wt_l2t_x wt_l2t_mvc MVC L2TAB_entry(0),dw wt_l2t_mvc2 MVC L2TAB_entry(0),0(rf) DROP r4,r2 wt_l2t_x DS 0H lvl 2 tab entry built * copy the track image LM r4,r5,0(r8) source addr, length wt_data LTR r5,r5 anything left to copy ? BZ wt_return no, return L r2,out_pos get current pos N r2,=A(x'00003fff') convert to buf offset L r3,out_buf get current buf addr ALR r2,r3 now have target addr AL r3,=A(16384) calculate target length SLR r3,r2 CLR r3,r5 check lengths BNH *+6 and set target length LR r3,r5 to the shortest LR r1,r3 save target length MVCL r2,r4 copy L r2,out_pos get old pos ALR r2,r1 new pos ST r2,out_pos set new pos L r3,out_buf_pos load current buf pos N r2,=A(x'ffffc000') new buf pos CLR r2,r3 is current buf full ? BE wt_data no [but r5 should be 0] ST r2,out_buf_pos set new buf pos L r6,out_buf write the buffer WRITE outdecb,SF,outdcb,(r6),MF=E CHECK outdecb LR r1,r6 copy old buf addr L r6,last_rw check for old buf rewrite USING rw_ent,r6 CL r3,rw_pos BE wt_data_1 yes ... get new buf LA r6,rw_next CL r3,rw_pos BNE wt_data_2 no ... use old buf wt_data_1 NOTE outdcb note disk addr for old buf ST r1,rw_ttr DROP r6 STORAGE OBTAIN,LENGTH=16384,BNDRY=PAGE L r0,out_bufsz AL r0,=A(16384) ST r0,out_bufsz ST r1,out_buf new buf wt_data_2 LR r0,r1 clear the buf L r1,=A(16384) SLR rf,rf MVCL r0,re B wt_data wt_return LM re,r8,wt_save return BR re */* ---------------------------------------------------------------- * * write_track() finish * * - set free space and write last buffer(s) * * - close & reopen in updat mode * * - rewrite buffers in the rewrite queue * * - close & return * * ---------------------------------------------------------------- */ wt_finish DS 0H * unused space at the end is free space L r2,out_pos get next available pos N r2,=A(x'00003fff') convert to buf offset BZ wt_fsp_ok if zero then no free space L r3,=A(16384) calculate length of free space SLR r3,r2 on current block LR r4,r3 copy CH r4,=Y(8) minimum free space is 8 bytes BNL *+8 otherwise we need AL r4,=A(16384) another block ST r4,bytes_free remember free space XC dw,dw build the free entry in a work STLE r4,dw+4 area since we may span buffers AL r2,out_buf get addr of free space CH r3,=Y(8) check length left BNH *+8 jumps if not too long LA r3,8 else reset BCTR r3,0 decrement for ex EX r3,wt_fsp_mvc copy the free space entry LA r4,dw+1(r3) resume copy from here LA r5,6 calculate length-1 left to copy SR r5,r3 negative if all copied * write the last buffer(s) wt_fsp_wr L r6,out_buf write the buffer WRITE outdecb,SF,outdcb,(r6),MF=E CHECK outdecb LR r1,r6 copy old buf addr L r3,out_buf_pos get buffer pos L r6,last_rw check for old buf rewrite USING rw_ent,r6 CL r3,rw_pos BE wt_fsp_1 yes ... get new buf LA r6,rw_next CL r3,rw_pos BNE wt_fsp_2 no ... use old buf wt_fsp_1 NOTE outdcb note disk addr for old buf ST r1,rw_ttr DROP r6 STORAGE OBTAIN,LENGTH=16384,BNDRY=PAGE L r0,out_bufsz AL r0,=A(16384) ST r0,out_bufsz ST r1,out_buf new buf wt_fsp_2 AL r3,=A(16384) new buf pos ST r3,out_buf_pos set new pos LR r0,r1 clear the buf L r1,=A(16384) SLR rf,rf MVCL r0,re LTR r5,r5 more to copy ? BM wt_fsp_ok no, continue L r2,out_buf get target addr EX r5,wt_fsp_mvc2 copy the rest of the entry SLR r5,r5 make r5 negative BCTR r5,0 to terminate the loop B wt_fsp_wr go write wt_fsp_mvc MVC 0(0,r2),dw wt_fsp_mvc2 MVC 0(0,r2),0(r4) wt_fsp_ok DS 0H last block has been written * update the header L r2,vdhdr_addr USING VDHDR,r2 USING CCKDDASD_DEVHDR,VDH_devhdr2 L re,out_buf_pos STLE re,CCKD_size set file size L rf,out_pos STLE rf,CCKD_used set bytes used L r0,bytes_free STLE r0,CCKD_free_total set total free space STLE r0,CCKD_free_largest set largest free space LTR r0,r0 any free space ? BZ wt_hd2_ok no, continue STLE rf,CCKD_free set offset to free entry LA r1,1 STLE r1,CCKD_free_number set number free entries DROP r2 wt_hd2_ok DS 0H * close the file and open in update mode CLOSE outdcb,MF=(E,openl24) #MSG 1,'file SYSUT2 closed for output' o USING IHADCB,outdcb OPEN (o.IHADCB,UPDAT),MF=(E,openl24) TM o.DCBOFLGS,DCBOFOPN BNO out_open_err #MSG 1,'file SYSUT2 opened for update' * update the noted buffers L r2,rw_area USING rw_ent,r2 L r3,out_buf buffer for read/write wt_update C r2,next_rw at end of entries ? BNL wt_upd_ok yes, exit POINT outdcb,rw_ttr position the file READ outdecb,SF,outdcb,(r3),MF=E CHECK outdecb LR r0,r3 copy the rewrite buf L r1,=A(16384) L re,rw_buf LR rf,r1 MVCL r0,re WRITE outdecb,SF,outdcb,(r3),MF=E CHECK outdecb L r1,rw_buf free the buf STORAGE RELEASE,ADDR=(1),LENGTH=16384 LA r2,rw_next point to the next entry B wt_update loop back wt_upd_ok CLOSE outdcb,MF=(E,openl24) STORAGE RELEASE,ADDR=(r3),LENGTH=16384 LM r1,r2,rw_area free stuff STORAGE RELEASE,ADDR=(1),LENGTH=(r2) #MSG 1,'file SYSUT2 closed for update' B wt_return */* ------------------------------------------------------ SOMITCW * * subroutine to check if dsn is in the include or SOMITCW * * exclude list. SOMITCW * * r0 points to the dsname from the vtoc on entry SOMITCW * * rf points to the dsname from the vtoc for compare SOMITCW * * r1 points to the first list entry SOMITCW * * A(next-entry-address) SOMITCW * * XL1'EX-CLC-compare-length' SOMITCW * * CL44'dsn-or-dsn-prefix' SOMITCW * * r2 is the length for the EX of the CLC instruction SOMITCW * * rf will have 0 if dsname found, otherwise 4 SOMITCW * * ---------------------------------------------------- */ SOMITCW * SOMITCW chk_dsn_list DS 0H SOMITCW LR rf,r0 Copy DS1-DSNAME for addressing SOMITCW cdl_loop DS 0H SOMITCW IC r2,4(,r1) Load length for EX of CLC SOMITCW EX r2,cdl_CLC See if the data set name found SOMITCW BE cdl_ret0 Data set in list, go return SOMITCW ICM r1,B'1111',0(r1) Link to the next entry SOMITCW BZ cdl_ret4 End of list, return dsn not found SOMITCW B cdl_loop Go back to try next list entry SOMITCW cdl_ret4 LA rf,4 Indicate that dsname not found SOMITCW BR re Return to caller SOMITCW cdl_ret0 SLR rf,rf Indicate that dsname was found SOMITCW cdl_ret BR re Return to caller SOMITCW cdl_CLC CLC 0(0,rf),5(r1) See if the dsn is in list SOMITCW */* ---------------------------------------------------------------- * * subroutine to convert a 10 byte vtoc extent descriptor [r1] * * to starting track [r0] and number tracks [r1] * * ---------------------------------------------------------------- */ cnv_xtnt STM r2,r5,cnv_xtnt_save SLR r3,r3 calculate ending extent ICM r3,3,6(r1) M r2,trks_per_cyl AH r3,8(,r1) SLR r5,r5 calculate beginning extent ICM r5,3,2(r1) M r4,trks_per_cyl AH r5,4(,r1) LR r0,r5 SR r3,r5 LA r1,1(,r3) LM r2,r5,cnv_xtnt_save BR re */* ---------------------------------------------------------------- * * subroutine to convert a 5 byte vtoc pointer [r1] * * to an address in the vtoc area [r1] * * ---------------------------------------------------------------- */ cnv_ptr STM r2,r5,cnv_ptr_save f4 USING IECSDSL4-44,dscb4 SLR r3,r3 calculate vtoc starting trk ICM r3,3,f4.DS4VTOCE+2 M r2,trks_per_cyl SLR r2,r2 ICM r2,3,f4.DS4VTOCE+4 AR r3,r2 SLR r5,r5 calculate dscb trk ICM r5,3,0(r1) M r4,trks_per_cyl AH r5,2(,r1) SR r5,r3 have relative trk M r4,dscbs_per_trk SLR r3,r3 IC r3,4(,r1) AR r5,r3 now have relative dscb BCTR r5,0 M r4,=A(DS1END-IECSDSF1) L r6,vtoc_area LA r1,0(r5,r6) LM r2,r6,cnv_ptr_save BR re DROP f4 */* ---------------------------------------------------------------- * * subroutine to populate the track vector table * * * * r1 - pointer to extent descriptor (incremented) * * r2 - nbr extents left (decremented) * * r3 - -1 or last relative track (decremented) * * r4 - dsn entry address * * * * ---------------------------------------------------------------- */ upd_trk_vec SAVE (14,12) USING dsn_area,r4 LA rf,4 LTR r2,r2 exit if no extents left BNP utvret BCTR r2,0 LTR r3,r3 exit if lstar is zero BZ utvret LA r5,10(,r1) BAL re,cnv_xtnt LR r6,r0 SLL r6,2 AL r6,trk_vec L r7,dsn_trks_dump utvloop ST r4,0(,r6) LA r7,1(,r7) LTR r3,r3 BM utvnext SH r3,=Y(1) BNP utvexit utvnext LA r6,4(,r6) BCT r1,utvloop SLR rf,rf utvexit ST r7,dsn_trks_dump LR r1,r5 utvret STM r1,r3,24(rd) RETURN (14,12),RC=(15) DROP r4 */* ---------------------------------------------------------------- * * retrieve options * * ---------------------------------------------------------------- */ getopts DS 0H MVI opts,COMPRESSION MVC compr_level,=A(CCKD_DEFAULT_COMPRESSION) For this JOB MVC cckd_compr_level,=A(Z_DEFAULT_COMPRESSION) In CCKD disk MVC cckd_compr,=A(CCKD_COMPRESS_ZLIB) */* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SOMITCW * * See if a SYSIN file SOMITCW * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ SOMITCW * SOMITCW * Locate Task I/O Table SOMITCW MVC extract,model_extract Move MF=L EXTRACT MACRO SOMITCW EXTRACT tiot_addr,'S',FIELDS=TIOT,MF=(E,EXTRACT) SOMITCW L rf,tiot_addr SOMITCW LA r1,24 Bump past JOB, STEP, PROCSTEP names SOMITCW in_tiot DS 0H SOMITCW AR rf,r1 Bump to next TIOT entry SOMITCW ICM r1,b'0001',0(rf) Load length of TIOT entry SOMITCW BZR r9 No SYSIN, take all defaults SOMITCW * CLC in.DCBDDNAM,4(rf) See if the SYSIN entry SOMITCW CLC model_indcb+DCBDDNAM-IHADCB(8),4(rf) See if SYSIN entry SOMITCW BNE in_tiot Not SYSIN, go check next TIOT entry SOMITCW * SOMITCW */* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SOMITCW * * try to open SYSIN file SOMITCW * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ SOMITCW * SOMITCW MVC indcb,model_indcb SOMITCW MVC indcbe,model_indcbe SOMITCW in USING IHADCB,indcb SOMITCW LA r1,indcbe SOMITCW ST r1,in.DCBDCBE SOMITCW * SYSIN exists, OPEN it SOMITCW * * A list entry will be built for each exclude record SOMITCW * * Format of each list entry will be: SOMITCW * * A(next-entry-address) SOMITCW * * XL1'EX-CLC-compare-length' SOMITCW * * CL44'dsn-or-dsn-prefix' SOMITCW * * r2 will contain the address of the previous list entry, SOMITCW * * to link the new list entry to the previous. SOMITCW MVC openl,model_openl Insure unused bits are zero SOMITCW OPEN (in.IHADCB,INPUT),MODE=31,MF=(E,openl) SOMITCW TM in.DCBOFLGS,DCBOFOPN See if SYSIN OPENed SOMITCW BZ X'081B'(rb) Abend S0C6 if OPEN failed SOMITCW LA R2,dsn_excl_list Load address of list anchor SOMITCW in_get DS 0h SOMITCW GET in.IHADCB Read a record SOMITCW MVC in_rec,0(r1) Store record for display SOMITCW #MSG 1,'SYSIN Read: %s:71',in_rec Display the record SOMITCW CLI in_rec,C'*' See if a comment SOMITCW BE in_get Is comment, don't process SOMITCW CLC =Cl8'EXCLUDE ',in_rec See if an exclude SOMITCW BNE ut1_bad_sysin Not an exclude, go abend SOMITCW GETMAIN RU,LV=49 Get memory for a list entry SOMITCW XC 0(4,r1),0(r1) Clear link addr.in GETMAINed area SOMITCW ST r1,0(,r2) Link to the old list entry SOMITCW LR rf,r1 Load the new list entry address SOMITCW CLI in_rec+8,X'40' See if a data set name SOMITCW BE ut1_bad_sysin No data set name, go abend SOMITCW MVC 5(44,rf),in_rec+8 Save entire possible dsname SOMITCW TRT in_rec+8(44),in_trt_table find space or asterisk SOMITCW BZ in_full44 Full data set name, go store SOMITCW LA r2,in_rec+8 Load address of start of dsname SOMITCW CLI 0(r1),X'40' See if a space found SOMITCW BE in_dsn_found Dsn found, go add to list SOMITCW in_prefix_found DS 0H SOMITCW BCTR r1,0 Drop the asterisk byte for prefix SOMITCW in_dsn_found DS 0H SOMITCW *already LA r2,in_rec+8 Load address of start of dsname SOMITCW SR r1,r2 Find the length of the dsname SOMITCW STC r1,4(,rf) Store the length for compare SOMITCW in_next DS 0H SOMITCW LR r2,rf Restore list entry address SOMITCW B in_get Go get the next record SOMITCW in_full44 DS 0H SOMITCW MVI 4(rf),x'43' Store EX length of data set name SOMITCW B in_next Go get next SYSIN record SOMITCW in_exit DS 0H SOMITCW CLOSE in.IHADCB,MODE=31,MF=(E,openl) SOMITCW BR r9 SYSIN processed, return to caller SOMITCW * BR re Deleted SOMITCW */* ---------------------------------------------------------------- * * fatal errors * * ---------------------------------------------------------------- */ ut1_bad_sysin DS 0H SOMITCW LR r2,r1 Save bad sysin record SOMITCW #MSG 3,'Bad record on SYSIN, must start with "EXCLUDE dsn"' SOMITCW B abend SOMITCW ut1_devt_err DS 0H STM rf,r0,retcode #MSG 3,'DEVTYPE failed for SYSUT1; RC=%x reason %x', x retcode,rsncode B abend out_devt_err DS 0H STM rf,r0,retcode #MSG 3,'DEVTYPE failed for SYSUT2; RC=%x reason %x', x retcode,rsncode B abend ut1_not_dasd DS 0H #MSG 3,'SYSUT1 is not a disk device' B abend out_not_dasd DS 0H #MSG 3,'SYSUT2 is not a disk device' B abend ut1_not_eckd DS 0H #MSG 3,'SYSUT1 is not an eckd disk device' B abend ut1_rdjfcb_err DS 0H ST rf,retcode #MSG 3,'RDJFCB failed for SYSUT1; RC=%x',retcode B abend ut1_vtoc_open_err DS 0H #MSG 3,'OPEN failed for SYSUT1 vtoc on %s',volser B abend out_open_err DS 0H #MSG 3,'OPEN failed for SYSUT2' B abend ut1_dscb4_err DS 0H ST rf,retcode c USING CVPL,cvpl_area #MSG 3,'Error processing format 4 dscb on %s; RC=%x CVSTAT=%dx :1',volser,retcode,c.CVSTAT B abend DROP c ut1_cvaf_err ABEND 6 ST rf,retcode c USING CVPL,cvpl_area #MSG 3,'CVAF error reading %s vtoc; RC=%x CVSTAT=%d:1', x volser,retcode,c.CVSTAT B abend DROP c ut1_excp_open_err DS 0H #MSG 3,'EXCP OPEN failed for SYSUT1 on %s',volser B abend ut1_io_err DS 0H #MSG 3,'EXCP I/O error for SYSUT1 on %s',volser B abend wt_logic_err DS 0H #MSG 3,'logic error writing track',volser B abend abend ABEND 99,DUMP */* ---------------------------------------------------------------- * * literals and constants * * ---------------------------------------------------------------- */ LTORG , WXTRN EDCXHOTL,EDCXHOTU,EDCXHOTT,COMPRESS PRINT GEN Was NOGEN SOMITCW model_extract EXTRACT *-*,'S',FIELDS=TIOT,MF=L SOMITCW model_extract_l EQU *-model_extract SOMITCW model_indcb DCB DDNAME=SYSIN,DSORG=PS,MACRF=GL,DCBE=0 SOMITCW model_indcb_l EQU *-model_indcb SOMITCW model_indcbe DCBE RMODE31=BUFF,EODAD=in_exit SOMITCW model_indcbe_l EQU *-model_indcbe SOMITCW model_prdcb DCB DDNAME=SYSPRINT,DSORG=PS,MACRF=PL,DCBE=0 model_prdcb_l EQU *-model_prdcb model_prdcbe DCBE RMODE31=BUFF model_prdcbe_l EQU *-model_prdcbe model_vtdcb DCB DDNAME=SYSUT1,DSORG=PS,MACRF=R model_vtdcb_l EQU *-model_vtdcb model_exdcb DCB DDNAME=SYSUT1,DSORG=DA,MACRF=E model_exdcb_l EQU *-model_exdcb model_outdcb DCB DDNAME=SYSUT2,DSORG=PS,MACRF=(RP,WP), x RECFM=F,BLKSIZE=16384,LRECL=16384,DCBE=0 CZV70 model_outdcb_l EQU *-model_outdcb model_outdcbe DCBE BLOCKTOKENSIZE=LARGE CZV70 model_outdcbe_l EQU *-model_outdcbe CZV70 model_openl OPEN (0),MODE=31,MF=L model_openl_l EQU *-model_openl model_openl24 OPEN (0),MODE=31,MF=L model_openl24_l EQU *-model_openl24 model_devtl DEVTYPE ,,INFOLIST=devt_infol_1,MF=L model_devtl_l EQU *-model_devtl devt_infol_1 DEVTYPE INFO=DEVTYPE devt_infol_2 DEVTYPE INFO=(DEVTYPE,DASD) model_cvpl CVAFSEQ MF=L model_cvpl_l EQU *-model_cvpl model_trkcalcl TRKCALC MF=L model_trkcalcl_l EQU *-model_trkcalcl * e2aTAB DS 0D Deleted SOMITCW * 0 1 2 3 4 5 6 7 8 9 a b c d e f Deleted SOMITCW * DC X'00010203 1A091A7F 1A1A1A0B 0C0D0E0F' 0 Deleted SOMITCW * DC X'10111213 1A0A081A 18191A1A 1C1D1E1F' 1 Deleted SOMITCW * DC X'1A1A1C1A 1A0A171B 1A1A1A1A 1A050607' 2 Deleted SOMITCW * DC X'1A1A161A 1A1E1A04 1A1A1A1A 14151A1A' 3 Deleted SOMITCW * DC X'20A6E180 EB909FE2 AB8B9B2E 3C282B7C' 4 Deleted SOMITCW * DC X'26A9AA9C DBA599E3 A89E2124 2A293B5E' 5 Deleted SOMITCW * DC X'2D2FDFDC 9ADDDE98 9DACBA2C 255F3E3F' 6 Deleted SOMITCW * DC X'D78894B0 B1B2FCD6 FB603A23 40273D22' 7 Deleted SOMITCW * DC X'F8616263 64656667 686996A4 F3AFAEC5' 8 Deleted SOMITCW * DC X'8C6A6B6C 6D6E6F70 71729787 CE93F1FE' 9 Deleted SOMITCW * DC X'C87E7374 75767778 797AEFC0 DA5BF2F9' a Deleted SOMITCW * DC X'B5B6FDB7 B8B9E6BB BCBD8DD9 BF5DD8C4' b Deleted SOMITCW * DC X'7B414243 44454647 4849CBCA BEE8ECED' c Deleted SOMITCW * DC X'7D4A4B4C 4D4E4F50 5152A1AD F5F4A38F' d Deleted SOMITCW * DC X'5CE75354 55565758 595AA085 8EE9E4D1' e Deleted SOMITCW * DC X'30313233 34353637 3839B3F7 F0FAA7FF' f Deleted SOMITCW in_trt_table DC 256Xl1'0' Table to find end of dsname SOMITCW ORG in_trt_table+X'40' Back up the location counter SOMITCW DC XL1'40' Overlay the space position SOMITCW ORG , Set the location counter to normal SOMITCW ORG in_trt_table+X'5C' Back up the location counter SOMITCW DC XL1'5C' Overlay the asterisk position SOMITCW ORG , Set the location counter to normal SOMITCW PRINT GEN DROP , */* ---------------------------------------------------------------- * * subroutine to issue messages * * ---------------------------------------------------------------- */ USING msg_rtn,rc USING vdw,rd USING vdw24,ra msg_rtn STM re,rc,mr_save LR rc,rf LA r8,prdcb USING IHADCB,r8 TM DCBOFLGS,DCBOFOPN BNO mr_ret return if no message file LM r4,r5,0(r1) pattern addr, length BCTR r5,0 LA r3,8(,r1) first parameter LA r6,msg MVI msg,C' ' init msg to blanks MVC msg+1(L'msg-1),msg mr_loop LTR r5,r5 BM mr_exit LA r1,1(r4,r5) SLR r2,r2 EX r5,mr_trt1 SR r1,r4 length scanned BNP mr_skip1 LR rf,r1 BCTR rf,0 EX rf,mr_mvc1 copy literal text AR r6,r1 mr_skip1 AR r4,r1 SR r5,r1 BM mr_exit BP mr_skip2 MVC 0(1,r6),0(r4) string ends in special char LA r6,1(,r6) B mr_exit mr_skip2 B *(r2) br on special char type B mr_pct '%' B mr_bs '\' mr_pct CLI 1(r4),C's' BE mr_pct_s CLI 1(r4),C'x' BE mr_pct_x CLI 1(r4),C'd' BE mr_pct_d MVC 0(1,r6),0(r4) tread '%' as any other char LA r6,1(,r6) LA r4,1(,r4) BCTR r5,0 B mr_loop mr_pct_s L r7,0(,r3) load string ptr LA r3,4(,r3) LA r4,2(,r4) point past '%s' SH r5,=Y(2) BAL re,mr_op r1 - target len, r2 - source len LTR r2,r2 BNZ mr_pct_s3 LR r2,r7 source len = 0, find end of string mr_pct_s1 CLI 0(r2),C' ' BNH mr_pct_s2 LA r2,1(,r2) B mr_pct_s1 mr_pct_s2 SR r2,r7 BNP mr_loop mr_pct_s3 LR rf,r2 copy source string to the msg BCTR rf,0 EX rf,mr_mvc2 LTR r1,r1 BNZ mr_pct_s5 AR r6,r2 truncate trailing spaces if mr_pct_s4 BCTR r6,0 target len is 0 CLI 0(r6),C' ' BNH mr_pct_s4 LA r6,1(,r6) B mr_loop mr_pct_s5 CR r1,r2 BH mr_pct_s6 AR r6,r1 truncate the string B mr_loop mr_pct_s6 AR r6,r2 pad string with trailing blanks SR r1,r2 mr_pct_s7 MVI 0(r6),C' ' LA r6,1(,r6) BCT r1,mr_pct_s7 B mr_loop mr_pct_x L r7,0(,r3) load hex ptr LA r3,4(,r3) LA r4,2(,r4) point past '%x' SH r5,=Y(2) BAL re,mr_op r1 - target len, r2 - source len LTR r2,r2 BNZ *+8 LA r2,4 default source len is 4 EX r2,mr_pct_x_unpk TR dw,mr_hextab LTR r1,r1 BNZ mr_pct_x1 LA r1,8 determine default target len CLC =C'00',dw BNE mr_pct_x1 LA r1,6 CLC =C'0000',dw BNE mr_pct_x1 LA r1,4 CLC =C'000000',dw BNE mr_pct_x1 LA r1,2 mr_pct_x1 LA r7,dw+8 copy the hex string to the msg SR r7,r1 BCTR r1,0 EX r1,mr_mvc2 LA r6,1(r1,r6) B mr_loop mr_pct_d L r7,0(,r3) load decimal ptr LA r3,4(,r3) LA r4,2(,r4) point past '%d' SH r5,=Y(2) BAL re,mr_op r1 - target len, r2 - source len LTR r2,r2 BNZ *+8 LA r2,4 default source len is 4 LA rf,4 SR rf,r2 LA re,15 SRL re,0(rf) EX re,mr_pct_d_icm CVD rf,dw MVC dw2(16),=X'40202020202020202020202020202120' ED dw2(16),dw LTR r1,r1 BNZ mr_pct_d2 LA rf,dw2+16 default length - mr_pct_d1 BCTR rf,0 truncate leading spaces CLI 0(rf),C' ' BH mr_pct_d1 LA r1,dw2+15 SR r1,rf mr_pct_d2 LA r7,dw2+16 SR r7,r1 BCTR r1,0 EX r1,mr_mvc2 LA r6,1(r1,r6) B mr_loop mr_bs MVC 0(1,r6),1(r4) copy char following '\' LA r6,1(,r6) LA r4,2(,r4) SH r5,=Y(2) B mr_loop mr_exit LA r1,msg SR r6,r1 calculate msg length BNP mr_ret TM DCBRECFM,DCBRECCA+DCBRECCM BZ *+8 LA r6,1(,r6) increment for carriage control TM DCBRECFM,DCBRECU BO mr_u TM DCBRECFM,DCBRECF BO mr_f TM DCBRECFM,DCBRECV BO mr_v mr_u CH r6,DCBBLKSI BNH *+8 LH r6,DCBBLKSI STH r6,DCBLRECL PUT IHADCB TM DCBRECFM,DCBRECCA+DCBRECCM BZ mr_u1 MVI 0(r1),C' ' LA r1,1(,r1) BCTR r6,0 TM DCBRECFM,DCBRECCA BO mr_u1 BCTR r1,0 MVI 0(r1),X'09' LA r1,1(,r1) mr_u1 BCTR r6,0 EX r6,mr_mvc3 B mr_ret mr_f CH r6,DCBLRECL BNH *+8 LH r6,DCBLRECL PUT IHADCB TM DCBRECFM,DCBRECCA+DCBRECCM BZ mr_f1 MVI 0(r1),C' ' LA r1,1(,r1) BCTR r6,0 TM DCBRECFM,DCBRECCA BO mr_f1 BCTR r1,0 MVI 0(r1),X'09' LA r1,1(,r1) mr_f1 BCTR r6,0 EX r6,mr_mvc3 B mr_ret mr_v LA r6,4(,r6) LH r1,DCBBLKSI SH r1,=Y(4) CR r6,r1 BNH *+6 LR r6,r1 STH r6,DCBLRECL PUT IHADCB STH r6,0(,r1) XC 2(2,r1),2(r1) LA r1,4(,r1) SH r6,=Y(4) TM DCBRECFM,DCBRECCA+DCBRECCM BZ mr_v1 MVI 0(r1),C' ' LA r1,1(,r1) BCTR r6,0 TM DCBRECFM,DCBRECCA BO mr_v1 BCTR r1,0 MVI 0(r1),X'09' LA r1,1(,r1) mr_v1 BCTR r6,0 EX r6,mr_mvc3 mr_ret LM re,rc,mr_save BR re DROP r8 */* ---------------------------------------------------------------- * * message subroutine to get operand lengths * * ---------------------------------------------------------------- */ mr_op SLR r1,r1 SLR r2,r2 mr_op1 LTR r5,r5 first number is target length BMR re CLI 0(r4),C'0' BL mr_op2 IC rf,0(,r4) N rf,=A(X'0000000f') MH r1,=Y(10) AR r1,rf LA r4,1(,r4) BCTR r5,0 B mr_op1 mr_op2 CLI 0(r4),C':' second number follows a ':' BNER re mr_op3 LA r4,1(,r4) second number is source length SH r5,=Y(1) BMR re CLI 0(r4),C'0' BLR re IC rf,0(,r4) N rf,=A(X'0000000f') MH r2,=Y(10) AR r2,rf B mr_op3 */* ---------------------------------------------------------------- */ mr_mvc1 MVC 0(0,r6),0(r4) mr_trt1 TRT 0(0,r4),mr_tab1 mr_mvc2 MVC 0(0,r6),0(r7) mr_mvc3 MVC 0(0,r1),msg mr_pct_x_unpk UNPK dw(9),0(0,r7) mr_pct_d_icm ICM rf,0,0(r7) mr_tab1 DC XL256'0' ORG mr_tab1+C'%' DC AL1(4) ORG mr_tab1+C'\' DC AL1(8) ORG mr_tab1+256 mr_hextab EQU *-240 DC C'0123456789abcdef' do_stats BR 14 LTORG , */* ---------------------------------------------------------------- * * messages * * ---------------------------------------------------------------- */ #MSG TYPE=GEN */* ---------------------------------------------------------------- * * dynamic storage * * ---------------------------------------------------------------- */ vdw DSECT id DS 0CL4'vdw' save DS 18F cnv_xtnt_save DS 8F savearea for cnv_xtnt cnv_ptr_save DS 8F savearea for cnv_ptr wt_save DS 12F savearea for write_track mr_save DS 16F savearea for msg_rtn vdw_31 DS A addr this area vdw_24 DS A addr 24 bit area opts DS X ALLTRKS EQU X'80' dump all tracks ALLDATA EQU X'40' dump all data in datasets COMPRESSION EQU X'20' compress dumped data DONTCOMPRESS EQU X'10' explicitly don't compress msglvl DS X volser DS CL6 retcode DS F rsncode DS F dw DS D dw2 DS D dw3 DS D dw4 DS D trks DS F total number tracks trks_dump DS F total number tracks to dump trk_size DS F max track size trk_vec DS A vector of trks to dump trk_vec_size DS F dscbs_per_trk DS F number dscbs per track vtoc_trks DS F number tracks in vtoc total_dscbs DS F number dscbs in vtoc vtoc_area DS A addr of area to hold all dscbs vtoc_size DS F size of area to hold all dscbs last_f1_dscb DS A addr last format 1 dscb dsn_nbr DS F nbr datasets on volume tiot_addr DS A Address of the Task I/O Table SOMITCW in_rec DS CL80 Input record for display SOMITCW dsn_area_addr DS A dsn_area_size DS A dsn_incl_list DS A dsn_excl_list DS A excp_io_area DS A excp_io_size DS F compr_area DS A compr_size DS F compr_used DS F compr_level DS F cckd_compr DS F cckd_compr_level DS F Z_NO_COMPRESSION EQU 0 Z_BEST_SPEED EQU 1 Z_BEST_COMPRESSION EQU 9 Z_DEFAULT_COMPRESSION EQU -1 CCKD_DEFAULT_COMPRESSION EQU 3 out_buf DS A current output buf addr out_buf_pos DS F pos for current buf out_bufsz DS F total buf size used for output vdhdr_addr DS A buf addr containing VDHDR out_pos DS F current available pos rw_area DS A rewrite area addr rw_size DS F size of rewrite area last_rw DS A addr last used entries next_rw DS A next available entry trk_addr DS A trk_sz DS F ctrk_addr DS A ctrk_sz DS F bytes_read DS 2F bytes_written DS 2F bytes_ovh DS F bytes_free DS F handle DS F msgl DS 16F extract DS XL(model_extract_l) SOMITCW indcbe DS XL(model_indcbe_l) SOMITCW prdcbe DS XL(model_prdcbe_l) outdcbe DS XL(model_outdcbe_l) CZV70 openl DS XL(model_openl_l) devtl DS XL(model_devtl_l) devta DS XL(32) cyls EQU devta+4,4 trks_per_cyl EQU devta+8,4 dev_flags EQU devta+12,2 trkcalcl DS XL(model_trkcalcl_l) zlib_pl DS 8F dscb4 DS XL(DS1END-IECSDSF1) msg DS CL256 cvpl_area DS XL(model_cvpl_l) bflh DS XL(BFLHLN) bflent DS 256XL(BFLELN) bfle_arg DS XL(L'BFLEARG) vdw_len EQU *-vdw vdw24 DSECT , id24 DS CL4'vdw24' openl24 DS XL(model_openl24_l) exlst DS F indcb DS XL(model_indcb_l) SOMITCW prdcb DS XL(model_prdcb_l) vtdcb DS XL(model_vtdcb_l) exdcb DS XL(model_exdcb_l) READ outdecb,SF,MF=L outdcb DS XL(model_outdcb_l) jfcb DS XL(JFCBLGTH) excp_ecb DS F DS 0D lr_parms DS XL16 excp_iob DS XL40 excp_ccws DS XL256 vdw24_len EQU *-vdw24 dsn_area DSECT dsn_name DS CL44 dsn_flag DS F dsn_not_incl EQU X'80' dsn_excl EQU X'40' dsn_extents DS F dsn_trks DS F dsn_trks_dump DS F dsn_bytes_read DS 2F dsn_bytes_written DS 2F dsn_next DS 0F dsn_area_len EQU *-dsn_area lr_parm_area DSECT , locate record parameter area lr_op DS X operation byte lr_orient_count EQU B'00000000' lr_orient_home EQU B'01000000' lr_orient_data EQU B'10000000' lr_orient_index EQU B'11000000' lr_orient EQU X'00' lr_write_data EQU X'01' lr_format_write EQU X'03' lr_read_data EQU X'06' lr_write_track EQU X'0b' lr_read_tracks EQU X'0c' lr_read EQU X'16' lr_aux DS X auxiliary byte lr_use_tlf EQU B'10000000' lr_read_count_ccw EQU B'00000001' DS X lr_count DS X count parameter lr_seek_addr DS 0XL4 seek addr lr_seek_addr_cc DS XL2 lr_seek_addr_hh DS XL2 lr_search_arg DS 0XL5 search arg lr_search_arg_cc DS XL2 lr_search_arg_hh DS XL2 lr_search_arg_r DS X lr_sector DS X lr_tlf DS XL2 transfer length factor lr_parms_l EQU *-lr_parm_area count DSECT , count area descriptor count_cchhr DS 0XL5 record address count_cchh DS 0XL4 record address count_cc DS XL2 count_hh DS XL2 count_r DS X count_key DS X key length count_data DS XL2 data length count_end DS 0X count_len EQU *-count ha DSECT , home area descriptor ha_bin DS X ha_cc DS XL2 ha_hh DS XL2 ha_end DS 0X ha_len EQU *-ha rw_ent DSECT , rewrite entry rw_pos DS F rw_buf DS A rw_ttr DS F rw_next DS 0F rw_len EQU *-rw_ent L2TAB DSECT , level 2 lookup table entry L2TAB_entry DS 0XL8 L2TAB_pos DS XL4 pos of track image L2TAB_len DS XL2 length of track in area L2TAB_size DS XL2 size of track area L2TAB_next DS 0X VDHDR DSECT , virt disk file header VDH_devhdr DS XL512 VDH_devhdr2 DS XL512 VDH_l1tab DS 0X CKDDASD_DEVHDR DSECT , device header CKD_devid DS XL8 CKD_heads DS F CKD_trksize DS F CKD_devtype DS X CKD_fileseq DS X CKD_highcyl DS H CKD_resv DS XL(512-(*-CKDDASD_DEVHDR)) CKD_len EQU *-CKDDASD_DEVHDR CCKDDASD_DEVHDR DSECT , compressed device header CCKD_vrm DS XL3 CCKD_options DS X CCKD_NOFUDGE EQU 1 CCKD_BIGENDIAN EQU 2 CCKD_OPENED EQU 128 CCKD_numl1tab DS F CCKD_numl2tab DS F CCKD_size DS F CCKD_used DS F CCKD_free DS F CCKD_free_total DS F CCKD_free_largest DS F CCKD_free_number DS F CCKD_free_imbed DS F CCKD_cyls DS F DS X CCKD_compress DS X CCKD_COMPRESS_NONE EQU 0 CCKD_COMPRESS_ZLIB EQU 1 CCKD_compress_parm DS H CCKD_gcol DS 5XL16 CCKD_resv DS XL(512-(*-CCKDDASD_DEVHDR)) CCKD_len EQU *-CCKDDASD_DEVHDR */* ---------------------------------------------------------------- * * dsects * * ---------------------------------------------------------------- */ PRINT GEN Was NOGEN SOMITCW DCBD DSORG=PS IEFUCBOB , IEFJFCBN , ICVAFBFL , ICVAFPL , IECSDSL1 (1,3,4) IEZDEB , IEZIOB , IOSDCCW , */* ---------------------------------------------------------------- * * equates * * ---------------------------------------------------------------- */ lr equ x'47' locate record rt equ x'de' read track r0 equ 0 r1 equ 1 r2 equ 2 r3 equ 3 r4 equ 4 r5 equ 5 r6 equ 6 r7 equ 7 r8 equ 8 r9 equ 9 ra equ 10 rb equ 11 rc equ 12 rd equ 13 re equ 14 rf equ 15 END , hercules-3.12/util/awswrite.jcl0000664000175000017500000003755612564723224013537 00000000000000//IBMUSERA JOB CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1) //ASMCLG PROC //IEUASM EXEC PGM=ASMA90,PARM='NOOBJECT,DECK',REGION=4M //SYSPRINT DD SYSOUT=* //SYSLIB DD DSN=SYS1.MACLIB,DISP=SHR // DD DSN=SYS1.MODGEN,DISP=SHR //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(5,5)) //SYSPUNCH DD DSN=&&OBJSET,DISP=(,PASS),UNIT=SYSDA, // SPACE=(TRK,(5,5)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3120) //IEWL EXEC PGM=IEWL,PARM='LIST,LET,NCAL,MAP', // COND=(0,NE,IEUASM),REGION=4M //SYSPRINT DD SYSOUT=* //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(5,5)) //SYSLIN DD DSN=&&OBJSET,DISP=(OLD,DELETE) //SYSLMOD DD DSN=&&GOSET(GO),DISP=(,PASS),UNIT=SYSDA, // SPACE=(TRK,(5,5,5)),DCB=(RECFM=U,BLKSIZE=6144) //GO EXEC PGM=*.IEWL.SYSLMOD,COND=((0,NE,IEUASM),(0,NE,IEWL)) //SYSPRINT DD SYSOUT=* //AWSIN DD DSN=&SYSUID..XXXXXX.AWSTAPE,DISP=SHR //TAPEOUT DD UNIT=3480,VOL=SER=XXXXXX,LABEL=(1,BLP,EXPDT=98000) // PEND //ASMCLG EXEC ASMCLG AWSWRITE TITLE 'Copy AWSTAPE file to physical tape' AWSWRITE CSECT ***** PROGRAM DESCRIPTION * * This program copies an AWSTAPE file (a tape image on disk) * to a physical tape. The exact structure of the tape image * (all files including data blocks and tape marks) is copied * to the physical tape. * * The JCL for running this program is: * * //AWSWRIT EXEC PGM=AWSWRITE * //SYSPRINT DD SYSOUT=* * //AWSIN DD DSN=file.awstape,DISP=SHR * //TAPEOUT DD UNIT=3480,VOL=SER=XXXXXX,LABEL=(1,BLP) * * Notes: * 1. The input file AWSIN can be any record format (fixed, * variable, or undefined) and can have any record length * 2. The output tape is written with BLP, therefore the * job must be run under a job class which allows BLP * processing. The JES2PARM parameter BLP=YES in the * JOBCLASS statement allows a job to use BLP. * This can be modified dynamically by using the command * $TJOBCLASS(A),BLP=YES * * AWSWRITE was created by Roger Bowler, September 2003 * and placed in the public domain. ***** AWSWRITE CSECT SAVE (14,12),,AWSWRITE-Roger-Bowler-2003 LR R12,R15 Establish base register USING AWSWRITE,R12 LA R15,AWSSAVEA Point to new savearea ST R13,4(,R15) Establish forward/ ST R15,8(,R13) backward pointers LR R13,R15 Activate new savearea L R1,0(,R1) Point to PARM area LH R2,0(,R1) Pick up PARM length LA R3,2(,R1) Point to PARM text CH R2,=H'4' Could it be PARM=TEST? BNE NOTTEST No, skip CLC 0(4,R3),=C'TEST' Is it PARM=TEST? BNE NOTTEST No, skip MVI TESTFLAG,X'FF' Yes, set TEST flag NOTTEST EQU * *** * Open the DCBs *** MVC RETCODE,=F'16' Prime return code for failure OPEN (SYSPRINT,OUTPUT) Open listing dataset TM SYSPRINT+48,X'10' Listing DCB open? BZ EXIT No, exit with return code 16 OPEN (AWSIN,INPUT) Open input dataset TM AWSIN+48,X'10' Input DCB open? BZ TERMINE No, exit with return code 16 CLI TESTFLAG,X'FF' Is it PARM=TEST? BE NOOPENT Yes, do not open tape OPEN (TAPEOUT,OUTPUT) Open output dataset TM TAPEOUT+48,X'10' Output DCB open? BZ TERMINE No, exit with return code 16 NOOPENT EQU * MVC RETCODE,=F'0' Prime return code for success *** * Obtain a 64K output buffer *** GETMAIN R,LV=MAXBLKL Obtain 64K storage area ST R1,OUTBUFP Save address of output buffer XC OUTBLKL,OUTBLKL Clear output block length XC INDATAP,INDATAP Clear input data pointer XC INDATAL,INDATAL Clear input data length *** * Read a 6-byte AWSTAPE block header from the input file *** NEXTHDR EQU * LA R4,AWSHDR Address of buffer for header LA R5,AWSHDRL Length of AWSTAPE header BAL R10,READIN Read 6-byte header from AWSIN CLC AWSHDR(6),=XL6'00' Is it all zero? BE LOGEOF Yes, treat as logical end-of-file TM AWSFLG1,AWSF1TM Is this a tape mark? BO WRITETM Yes, go write a tape mark *** * Obtain length of logical data block which follows *** SR R2,R2 Clear length register ICM R2,B'0001',AWSBLKL Load input block length... ICM R2,B'0010',AWSBLKL+1 ...in reverse byte order *** * Determine where to read logical data block into output buffer *** TM AWSFLG1,AWSF1BB Is it start of a physical block? BZ BEGBLK1 No, append to data in buffer XC OUTBLKL,OUTBLKL Yes, clear output block length BEGBLK1 DS 0H L R1,OUTBLKL Calculate... ALR R1,R2 ...new output block length CL R1,=A(MAXBLKL) Does data exceed buffer length? BNL BADBLKL Yes, error *** * Read a logical data block from the input file *** L R4,OUTBUFP Point to start of buffer AL R4,OUTBLKL Point past data already in buffer LR R5,R2 Load logical data block length BAL R10,READIN Read logical data block L R1,OUTBLKL Calculate... ALR R1,R5 ...new output block length ST R1,OUTBLKL Update new output block length TM AWSFLG1,AWSF1EB End of physical block? BZ NEXTHDR No, read next input header *** * Write a physical data block to the tape *** L R1,OUTBLKL Load output block length CVD R1,DWORK Convert block length to decimal MVC MSGDBL(6),=X'402020202120' ED MSGDBL(6),DWORK+5 Edit block length into message MVC MSGDBV,MSGDBV-1 Clear label area in message CH R1,=H'80' Is it an 80-byte block? BNE NOTLABL No, cannot be a standard label L R1,OUTBUFP Point to output buffer CLC 0(3,R1),=C'VOL' Could it be a standard label? BE PRTLABL Yes, list it CLC 0(3,R1),=C'HDR' Could it be a standard label? BE PRTLABL Yes, list it CLC 0(3,R1),=C'EOF' Could it be a standard label? BE PRTLABL Yes, list it CLC 0(3,R1),=C'UHL' Could it be a standard label? BE PRTLABL Yes, list it CLC 0(3,R1),=C'UTL' Could it be a standard label? BNE NOTLABL No, skip PRTLABL EQU * MVC MSGDBV,0(R1) Copy standard label to message NOTLABL EQU * PUT SYSPRINT,MSGDB Write diagnostic message MVI CCW,X'01' Set CCW command = Write L R1,OUTBUFP Point to output buffer STCM R1,B'0111',CCW+1 Save 24-bit buffer address in CCW MVI CCW+4,X'20' Set CCW flags = SLI L R1,OUTBLKL Load length of data in buffer STH R1,CCW+6 Save 16-bit data length in CCW BAL R10,EXCPIO Perform I/O via EXCP B NEXTHDR Read next input header *** * Write a tape mark to the tape *** WRITETM DS 0H L R2,=A(MSGTM) Point to tape mark message PUT SYSPRINT,(R2) Write diagnostic message MVI CCW,X'1F' Set CCW command = Write Tape Mark XC CCW+1(3),CCW+1 Zeroise CCW data address MVI CCW+4,X'20' Set CCW flags = SLI MVC CCW+6(2),=H'1' Set CCW data length non-zero BAL R10,EXCPIO Perform I/O via EXCP B NEXTHDR Read next input header *** * Fatal error routines *** BADBLKL DS 0H L R2,=A(ERRMSG1) Data block exceeds 64K-1 PUT SYSPRINT,(R2) Write error message MVC RETCODE,=F'12' Set bad return code B TERMINE Exit with bad return code OUTIOER DS 0H UNPK ERRM2CCW(9),CCW(5) TR ERRM2CCW(8),HEXTAB-240 MVI ERRM2CCW+8,C' ' UNPK ERRM2CCW+9(9),CCW+4(5) TR ERRM2CCW+9(8),HEXTAB-240 MVI ERRM2CCW+17,C',' UNPK ERRM2ECB(3),ECB(2) TR ERRM2CCW(2),HEXTAB-240 MVI ERRM2CCW+2,C',' UNPK ERRM2CSW(9),IOBCSW(5) TR ERRM2CSW(8),HEXTAB-240 MVI ERRM2CSW+8,C' ' UNPK ERRM2CSW+9(9),IOBCSW+4(5) TR ERRM2CSW+9(8),HEXTAB-240 MVI ERRM2CSW+17,C',' UNPK ERRM2SNS(5),IOBSENSE(3) TR ERRM2SNS(4),HEXTAB-240 MVI ERRM2SNS+4,C' ' PUT SYSPRINT,ERRMSG2 Print I/O error message MVC RETCODE,=F'8' Set bad return code B TERMINE Exit with bad return code *** * Termination routines *** READEOF DS 0H L R2,=A(MSGPEOF) Physical end-of-file on AWSIN PUT SYSPRINT,(R2) Write diagnostic message B TERMINE LOGEOF DS 0H L R2,=A(MSGLEOF) Logical end-of-file on AWSIN PUT SYSPRINT,(R2) Write diagnostic message TERMINE DS 0H ICM R1,B'1111',OUTBUFP Load output buffer address BZ NOFREEM Skip if no buffer allocated FREEMAIN R,A=(1),LV=MAXBLKL Release storage area NOFREEM EQU * CLOSE (AWSIN,,TAPEOUT) Close input/output DCBs CLOSE (SYSPRINT) Close listing dataset EXIT EQU * L R13,4(,R13) Load HSA pointer L R15,RETCODE Load return code L R14,12(,R13) Restore... LM R0,R12,20(R13) ...registers BR R14 Exit from AWSWRITE *** * Subroutine to read a given number of bytes from the input file * * Input: R4 = Destination buffer address * R5 = Number of bytes to read *** READIN DS 0H STM R4,R5,READSAVE Save work registers READCONT EQU * CL R5,INDATAL Enough data in input buffer? BNH READMOVE Yes, copy it * Copy as much data as is available from the input buffer LR R0,R4 R0 = destination buffer address L R1,INDATAL R1 = length of input data L R14,INDATAP R14 => data in input buffer L R15,INDATAL R15 = length of input data MVCL R0,R14 Copy data from input buffer LR R4,R0 R4 = updated destination addr SL R5,INDATAL R5 = updated length remaining * Read the next input record into the input buffer GET AWSIN Get-locate input record SR R0,R0 Clear for insert ICM R0,B'0011',AWSLRECL R0 = record length from DCB TM AWSRECFM,DCBRECU Is it RECFM=U ? BO READNOTV Yes, skip TM AWSRECFM,DCBRECV Is it RECFM=V or RECFM=VB ? BNO READNOTV No, skip * For RECFM=V or RECFM=VB there is a 4-byte RDW preceding the data ICM R0,B'0011',0(R1) Load record length from RDW SH R0,=H'4' Subtract length of RDW LA R1,4(,R1) Skip over the RDW READNOTV EQU * ST R0,INDATAL Save input data length ST R1,INDATAP Save input data pointer B READCONT Go back and move more data READMOVE EQU * * Copy data from the input buffer to the destination buffer L R14,INDATAP R14 => data in input buffer L R15,INDATAL R15 = length of input data MVCL R4,R14 Copy data from input buffer ST R14,INDATAP Save updated input data pointer ST R15,INDATAL Save updated input data length LM R4,R5,READSAVE Restore work registers BR R10 Return from READIN subroutine *** * Subroutine to write to tape using EXCP *** EXCPIO DS 0H CLI TESTFLAG,X'FF' Is it PARM=TEST? BE EXCPRET Yes, bypass tape I/O MVI ECB,X'00' Clear ECB completion code EXCP IOB Start channel program WAIT ECB=ECB Wait for I/O completion CLI ECB,X'7F' I/O completed successfully? BNE OUTIOER No, take error exit EXCPRET EQU * BR R10 Return from EXCPIO subroutine EJECT * * AWSTAPE 6-byte logical block header * AWSHDR DS 0H AWSBLKL DS XL2 Logical block length (reversed) AWSPRVL DS XL2 Previous block length (reversed) AWSFLG1 DS X Flags... AWSF1BB EQU X'80' ...beginning of physical block AWSF1TM EQU X'40' ...tape mark AWSF1EB EQU X'20' ...end of physical block AWSFLG2 DS X Flags (unused) AWSHDRL EQU *-AWSHDR Length of AWSTAPE block header MAXBLKL EQU 65536 Maximum block size 64K * * Data areas for EXCP I/O to tape * CCW CCW X'01',0,X'20',0 Write Data CCW ECB DC F'0' Event Control Block IOB DS 0F Input Output Block... IOBFLAGS DC XL2'0' ...IOB flags IOBSENSE DC XL2'0' ...IOB sense bytes IOBECBPT DC A(ECB) ...ECB pointer IOBCSW DC 2F'0' ...CSW after I/O IOBSTART DC A(CCW) ...CCW pointer IOBDCBPT DC A(TAPEOUT) ...DCB pointer IOBRESTR DC A(0) IOBINCAM DC H'1' ...Block count increment IOBERRCT DC H'0' ...Error counter * * Static data areas * LTORG DWORK DC D'0' Doubleword work area RETCODE DC F'0' Program final return code INDATAP DC A(0) Pointer to next byte of input data INDATAL DC F'0' No.of input data bytes remaining OUTBUFP DC A(0) Address of output buffer OUTBLKL DC F'0' Length of data in output buffer AWSSAVEA DS 18F New savearea READSAVE DS 2F Savearea for READIN subroutine TESTFLAG DC X'00' X'FF' if PARM=TEST specified PRINT NOGEN SYSPRINT DCB DSORG=PS,MACRF=PM,DDNAME=SYSPRINT, RECFM=FBA,LRECL=133,BLKSIZE=133 AWSIN DCB DSORG=PS,MACRF=GL,DDNAME=AWSIN,EODAD=READEOF AWSLRECL EQU DCBLRECL-IHADCB+AWSIN AWSRECFM EQU DCBRECFM-IHADCB+AWSIN TAPEOUT DCB DSORG=PS,MACRF=E,DDNAME=TAPEOUT,DEVD=TA HEXTAB DC C'0123456789ABCDEF' * * Messages * ERRMSG1 DC CL133' *** Error *** Data block length exceeds 64K-1' ERRMSG2 DC CL133' ' ORG ERRMSG2 DC C' *** Error *** ' DC C'CCW=' ERRM2CCW DC C'xxxxxxxx xxxxxxxx,' DC C'ECBCC=' ERRM2ECB DC C'xx,' DC C'CSW=' ERRM2CSW DC C'xxxxxxxx xxxxxxxx,' DC C'SENSE=' ERRM2SNS DC C'xxxx ' ORG MSGTM DC CL133' ** Tape Mark **' MSGDB DC CL133' Data Block: nnnnn bytes' MSGDBL EQU MSGDB+12,6 MSGDBV EQU MSGDB+30,80 MSGPEOF DC CL133' Terminated at end-of-file on AWSIN' MSGLEOF DC CL133' Terminated by zero header on AWSIN' R0 EQU 0 R1 EQU 1 R2 EQU 2 R3 EQU 3 R4 EQU 4 R5 EQU 5 R6 EQU 6 R7 EQU 7 R8 EQU 8 R9 EQU 9 R10 EQU 10 R11 EQU 11 R12 EQU 12 R13 EQU 13 R14 EQU 14 R15 EQU 15 DCBD DSORG=PS,DEVD=TA END // hercules-3.12/util/rawstape.jcl0000664000175000017500000003206512564723224013506 00000000000000//IBMUSERA JOB ,'JAN JAEGER',NOTIFY=IBMUSER,CLASS=A,MSGCLASS=A 00000103 //ASMA90 EXEC PGM=ASMA90,PARM='DECK,NOOBJ,XREF(SHORT)' 00000200 //SYSPRINT DD SYSOUT=* 00000300 //SYSLIB DD DSN=SYS1.MACLIB,DISP=SHR 00000400 // DD DSN=SYS1.MODGEN,DISP=SHR 00000500 //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,10) 00000600 //SYSPUNCH DD DSN=&&PUNCH,DISP=(NEW,PASS), 00000700 // UNIT=SYSALLDA,SPACE=(CYL,10) 00000800 RAWSTAPE TITLE 'Convert file from AWSTAPE format' 00000900 *---------------------------------------------------------------------* 00001000 * Function: * 00001100 * This program converts an AWSTAPE format file to RECFM=U * 00001200 * SYSUT1 is converted reblocked according to the AWS * 00001300 * header records. The blocksize of SYSUT2 can be reset * 00001400 * using IEBGENER * 00001500 * The parm field indicates the filenumber to be extracted, * 00001600 * this number has the same value as when using BLP in JCL. * 00001700 *---------------------------------------------------------------------* 00001800 RAWSTAPE CSECT 00001900 LR R12,R15 Load base register 00002000 USING RAWSTAPE,R12 Establish addressability 00002100 L R2,0(,R1) PARM= 00002200 LH R3,0(,R2) L'PARM 00002300 LTR R3,R3 00002400 BZ NOPARM No parm field 00002500 BCTR R3,0 Reduce to Machine length 00002600 EX R3,EXPACK 00002700 CVB R3,DWORD 00002800 ST R3,FILENUM Filenumber to be read 00002900 NOPARM DS 0H 00003000 OPEN (SYSUT1,INPUT) Open input DCB 00003100 TM SYSUT1+48,X'10' Is DCB open? 00003200 BZ EXIT020 No, exit with RC=20 00003300 OPEN (SYSUT2,OUTPUT) Open output DCB 00003400 TM SYSUT2+48,X'10' Is DCB open? 00003500 BZ EXIT020 No, exit with RC=20 00003600 LA R2,BUFFER 00003700 SLR R3,R3 Total number of bytes in buffer 00003800 LA R5,1 We start at file 1 00003900 READBLK DS 0H 00004000 LA R2,BUFFER(R3) 00004100 GET SYSUT1,(2) Get input block 00004200 AH R3,SYSUT1+82 R3=total bytes in buffer 00004300 GETNEXT DS 0H 00004400 CH R3,=Y(L'HEADER) Do we at least have the header 00004500 BM READBLK 00004600 TM HDRFLAG1,HDRF1TMK Take mark? 00004700 BZ NOEOF 00004800 LA R5,1(,R5) Increment file number 00004900 C R5,FILENUM Beyond requested file? 00005000 BH EXIT000 00005100 NOEOF DS 0H 00005200 SLR R4,R4 Logical block length 00005300 ICM R4,B'0001',HDRCURLN Load low-order length byte 00005400 ICM R4,B'0010',HDRCURLN+1 Load high-order length byte 00005500 LA R1,L'HEADER(,R4) 00005600 CR R3,R1 Full block yet? 00005700 BM READBLK No: Fetch another 00005800 C R5,FILENUM Is this the file we want? 00005900 BNE NOPUT 00006000 TM HDRFLAG1,HDRF1BOR+HDRF1EOR 00006100 BM EXIT016 00006200 BNO NOPUT 00006300 LA R2,DATA Skip AWS header 00006400 STH R4,SYSUT2+82 Store block size 00006500 PUT SYSUT2,(2) Write block 00006600 NOPUT DS 0H 00006700 AH R4,=Y(L'HEADER) Remove header 00006800 SLR R3,R4 Remove block 00006900 LA R2,BUFFER Back to start 00007000 LR R6,R2 Move remainder to beginning 00007100 LA R8,0(R4,R2) Point past block 00007200 LR R7,R3 Set length 00007300 LR R9,R3 00007400 MVCL R6,R8 Move block 00007500 B GETNEXT 00007600 * 00007700 EXIT000 DS 0H 00007800 CLOSE (SYSUT1,,SYSUT2) Close DCBs 00007900 SR R15,R15 Zeroize return code 00008000 SVC 3 Exit with RC=0 00008100 EXIT012 DS 0H 00008200 LA R15,12 Premature EOF 00008300 SVC 3 Exit with RC=12 00008400 EXIT016 DS 0H 00008500 LA R15,16 Invalid record type 00008600 SVC 3 Exit with RC=16 00008700 EXIT020 DS 0H 00008800 LA R15,20 DD statement missing 00008900 SVC 3 Exit with RC=20 00009000 * 00009100 * EXecuted 00009200 * 00009300 EXPACK PACK DWORD,2(0,2) 00009400 DROP R12 Drop base register 00009500 * 00009600 * Variables 00009700 * 00009800 FILENUM DC F'1' 00009900 DWORD DS D 00010000 * 00010100 * Data Control Blocks 00010200 * 00010300 PRINT NOGEN 00010400 SYSUT1 DCB DSORG=PS,MACRF=GM,DDNAME=SYSUT1,EODAD=EXIT012, X00010500 RECFM=U,LRECL=0,BLKSIZE=32760 00010600 SYSUT2 DCB DSORG=PS,MACRF=PM,DDNAME=SYSUT2, X00010700 RECFM=U,LRECL=0,BLKSIZE=32760 00010800 LTORG 00010900 * 00011000 BUFFER DS 0C 00011100 * 00011200 * AWSTAPE block header 00011300 * 00011400 HEADER DS 0CL6 Block header 00011500 HDRCURLN DS XL2 Current block length 00011600 HDRPRVLN DS XL2 Previous block length 00011700 HDRFLAG1 DS X'00' Flags byte 1... 00011800 HDRF1BOR EQU X'80' ...beginning of record 00011900 HDRF1TMK EQU X'40' ...tape mark 00012000 HDRF1EOR EQU X'20' ...end of record 00012100 HDRFLAG2 DS X'00' Flags byte 2 00012200 * 00012300 * Data 00012400 * 00012500 DATA DS 0C 00012600 DS 65536C 00012700 * 00012800 * Register equates 00012900 * 00013000 R0 EQU 0 00013100 R1 EQU 1 00013200 R2 EQU 2 00013300 R3 EQU 3 00013400 R4 EQU 4 00013500 R5 EQU 5 00013600 R6 EQU 6 00013700 R7 EQU 7 00013800 R8 EQU 8 00013900 R9 EQU 9 00014000 R10 EQU 10 00014100 R11 EQU 11 00014200 R12 EQU 12 00014300 R13 EQU 13 00014400 R14 EQU 14 00014500 R15 EQU 15 00014600 END 00014700 //IEWL EXEC PGM=IEWL 00014800 //SYSPRINT DD SYSOUT=* 00014900 //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,10) 00015000 //SYSLMOD DD DSN=IBMUSER.LOAD(RAWSTAPE),DISP=SHR 00015100 //SYSLIN DD DSN=&&PUNCH,DISP=(OLD,DELETE) 00015200 //* 00015300 //CONVERT EXEC PGM=*.IEWL.SYSLMOD,PARM=3 00016704 //SYSUDUMP DD SYSOUT=* 00016800 //SYSUT1 DD DISP=SHR,DSN=IBMUSER.SADUMP.AWS 00016900 //SYSUT2 DD DSN=IBMUSER.SADUMP,DISP=(NEW,CATLG), 00017000 // UNIT=SYSALLDA,SPACE=(TRK,1200,RLSE) 00018000 //* 00019000 //SETDCB EXEC PGM=IEBGENER 00020000 //SYSPRINT DD SYSOUT=* 00030000 //SYSIN DD DUMMY 00040000 //SYSUT1 DD DUMMY, 00050000 // DCB=(DSORG=PS,RECFM=FBS,LRECL=4160,BLKSIZE=29120) 00060000 //SYSUT2 DD DISP=MOD,DCB=(*.SYSUT1),DSN=IBMUSER.SADUMP 00070000 hercules-3.12/util/tapeconv.jcl0000664000175000017500000002453212564723224013477 00000000000000//IBMUSERA JOB CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1) 00010000 //ASMCLG PROC 00020000 //IEUASM EXEC PGM=ASMA90,PARM='NOOBJECT,DECK',REGION=4M 00030000 //SYSPRINT DD SYSOUT=* 00040000 //SYSLIB DD DSN=SYS1.MACLIB,DISP=SHR 00050000 // DD DSN=SYS1.MODGEN,DISP=SHR 00060000 //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(5,5)) 00070000 //SYSPUNCH DD DSN=&&OBJSET,DISP=(,PASS),UNIT=SYSDA, 00080000 // SPACE=(TRK,(5,5)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3120) 00090000 //IEWL EXEC PGM=IEWL,PARM='LIST,LET,NCAL,MAP', 00100000 // COND=(0,NE,IEUASM),REGION=4M 00110000 //SYSPRINT DD SYSOUT=* 00120000 //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(5,5)) 00130000 //SYSLIN DD DSN=&&OBJSET,DISP=(OLD,DELETE) 00140000 //SYSLMOD DD DSN=&&GOSET(GO),DISP=(,PASS),UNIT=SYSDA, 00150000 // SPACE=(TRK,(5,5,5)),DCB=(RECFM=U,BLKSIZE=6144) 00160000 //GO EXEC PGM=*.IEWL.SYSLMOD,COND=((0,NE,IEUASM),(0,NE,IEWL)) 00170000 //SYSUT1 DD DSN=TAPE.DATASET,UNIT=3480,VOL=SER=AAAAAA,DISP=OLD 00180000 //SYSUT2 DD DSN=IBMUSER.AWSTAPE.DATASET,DISP=(,CATLG), 00181000 // UNIT=SYSDA,VOL=SER=VVVVVV,SPACE=(CYL,(5,5),RLSE) 00181100 // PEND 00182000 //ASMCLG EXEC ASMCLG 00183000 TAPECONV TITLE 'Convert file to AWSTAPE format' 00184000 *---------------------------------------------------------------------* 00185000 * Function: * 00186000 * This program converts a tape file to AWSTAPE format. * 00187000 * It reads undefined length blocks of data from SYSUT1 and * 00188000 * writes each block, prefixed by a 6-byte header, to SYSUT2. * 00189000 * * * Modification by Charlie Brint: * * This program has been modified from its original Hercules * * source format to handle blocks > 32K and < 64k because the * * default blksize for ADRDSSU is 65,520 in most installations * * and the original TAPECONV would just truncate blocks at * * 32,760 bytes without giving any error indication. As a side * * benefit, SYSUT2 can reside on disk even if SYSUT1 is an * * ADRDSSU dump tape with blocks longer than 32760 because the * * program never writes blocks longer than 32760 to SYSUT2. * * NOTE: This version uses the Large Block Interface (LBI) and * * thus requires OS/390 V2R10 or z/OS to assemble and run. * * For earlier versions of MVS, the program still assembles and * * runs (without LBI) if you replace &LBI SETB 1 by &LBI SETB 0 * *---------------------------------------------------------------------* 00226000 GBLB &LBI &LBI SETB 1 1=use LBI, 0=do not use LBI TAPECONV CSECT 03740000 LR R12,R15 Load base register 03750000 USING TAPECONV,R12 Establish addressability 03760000 OPEN (SYSUT1,INPUT) Open input DCB 03770000 TM SYSUT1+48,X'10' Is DCB open? 03780000 BZ EXIT020 No, exit with RC=20 03790000 OPEN (SYSUT2,OUTPUT) Open output DCB 03791000 TM SYSUT2+48,X'10' Is DCB open? 03792000 BZ EXIT020 No, exit with RC=20 03793000 GENLOOP EQU * 03800000 GET SYSUT1 Get input block 03810000 LR R2,R1 R2=>input block 03811000 LH R4,SYSUT1+82 R4=actual block length 03820000 AIF (NOT &LBI).LBIN1 L R15,SYSUT1+68 Get IOB address SH R15,=H'4' Reduce by 4 as per LBI docs L R4,0(R15) R4 should now be the blk leng .LBIN1 ANOP , LR R5,R4 Copy length for later use C R4,=F'65520' Is the block > 65520 ? BH EXIT020 yes, take error exit C R4,=F'32760' Is the block > 32760 ? BNH UNDER32 no, skip L R4,=F'32760' yes, set write length to max UNDER32 DS 0H MVC HDRPRVLN,HDRCURLN Copy previous block length 03830000 STCM R5,B'0001',HDRCURLN Store low-order length byte STCM R5,B'0010',HDRCURLN+1 Store high-order length byte MVI HDRFLAG1,HDRF1BOR+HDRF1EOR Set complete record flags MVC SYSUT2+82(2),=H'6' Set header length in DCB 03851001 PUT SYSUT2,HEADER Write block header to SYSUT2 03860000 STH R4,SYSUT2+82 Set block length in DCB 03870001 PUT SYSUT2,(R2) Write data block to SYSUT2 03880000 CR R4,R5 Did we write all the data ? BE GENLOOP yes, go back for next record ALR R2,R4 no, bump input block pointer SR R5,R4 Compute remaining length STH R5,SYSUT2+82 Set remaining length in DCB PUT SYSUT2,(R2) Write the rest of the block B GENLOOP Go back for next record 03890000 GENEOF DS 0H 03900000 MVC HDRPRVLN,HDRCURLN Copy previous block length 03901000 XC HDRCURLN,HDRCURLN Clear current block length 03901100 MVI HDRFLAG1,HDRF1TMK Set tape mark flag MVC SYSUT2+82(2),=H'6' Set header length in DCB 03902001 PUT SYSUT2,HEADER Write block header to SYSUT2 03903000 CLOSE (SYSUT1,,SYSUT2) Close DCBs 03910000 SR R15,R15 Zeroize return code 03920000 SVC 3 Exit with RC=0 03930000 EXIT020 DS 0H 04050000 LA R15,20 DD statement missing 04060000 SVC 3 Exit with RC=20 04070000 DROP R12 Drop base register 04080000 * 04081000 * AWSTAPE block header 04082000 * 04083000 HEADER DS 0CL6 Block header 04090000 HDRCURLN DC XL2'0000' Current block length 04100100 HDRPRVLN DC XL2'0000' Previous block length 04100202 HDRFLAG1 DC X'00' Flags byte 1... 04100300 HDRF1BOR EQU X'80' ...beginning of record HDRF1TMK EQU X'40' ...tape mark HDRF1EOR EQU X'20' ...end of record HDRFLAG2 DC X'00' Flags byte 2 * 04100400 * Data Control Blocks 04100500 * 04100600 AIF (&LBI).LBID1 SYSUT1 DCB DSORG=PS,MACRF=GL,DDNAME=SYSUT1,EODAD=GENEOF, X04110000 RECFM=U,LRECL=0,BLKSIZE=32760 04120000 AGO .LBID2 .LBID1 ANOP , SYSUT1 DCB DSORG=PS,MACRF=GL,DDNAME=SYSUT1,EODAD=GENEOF, X RECFM=U,LRECL=0,DCBE=MYDCBE MYDCBE DCBE BLKSIZE=65520 DCB extension, new in OS/390 V2R10 .LBID2 ANOP , SYSUT2 DCB DSORG=PS,MACRF=PM,DDNAME=SYSUT2, X04121000 RECFM=U,LRECL=0,BLKSIZE=32760 04122000 LTORG 04130000 * 04431000 * Register equates 04432000 * 04433000 R0 EQU 0 04434000 R1 EQU 1 04435000 R2 EQU 2 04436000 R3 EQU 3 04437000 R4 EQU 4 04438000 R5 EQU 5 04439000 R6 EQU 6 04440000 R7 EQU 7 04450000 R8 EQU 8 04460000 R9 EQU 9 04470000 R10 EQU 10 04480000 R11 EQU 11 04490000 R12 EQU 12 04500000 R13 EQU 13 04510000 R14 EQU 14 04520000 R15 EQU 15 04530000 END 04540000 hercules-3.12/util/TMOUNT.txt0000664000175000017500000001761212564723224012756 00000000000000+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Fish note: The length of the filename is not limted to 17 characters as the below sample states. Rather, the length of the filename is limited solely by the host filesystem code. On Windows, filenames can be up to 260 characters long. (or even longer if "\\?\" format is used!) +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * $$ JOB JNM=TMOUNT,DISP=D,CLASS=0 // JOB TMOUNT COMPILE PROGRAM TMOUNT // LIBDEF *,CATALOG=PRD2.CONFIG // OPTION ERRS,SXREF,SYM,NODECK,CATAL PHASE TMOUNT,* // EXEC ASMA90,SIZE=(ASMA90,64K),PARM='EXIT(LIBEXIT(EDECKXIT)),SIZE(MAXC -200K,ABOVE)' TMOUNT CSECT SPACE 1 *--------------------------------------------------------------------- * * TMOUNT - VSE VERSION II * * THE TMOUNT COMMAND IS USED FROM VSE ON THE P/390 TO TELL THE * AWSTAPE MANAGER WHICH OS/2 FILE TO USE WHEN THE USER WRITES TO * THIS DEVICE. IT CAN ALSO BE USED TO QUERY WHAT OS/2 FILE IS * CURRENTLY ASSOCIATED WITH THE DEVICE. * * TWO SPECIAL CCW OPCODES ARE SUPPORTED BY THE AWSTAPE EMULATOR: * X'4B' - ASSIGN A DOS FILEID TO THE DEVICE. (WAS '4B' 6/30) * X'E4' - SENSE FILEID - RETURN THE NAME OF THE ASSIGNED DOS FILE * * THE EMULATED TAPE HAS TO BE ASSIGNED TO SYS014 * * E.G // JOB TMOUNT * // ASSGN SYS014,580 * // EXEC TMOUNT,REAL,SIZE=AUTO,PARM='580 D:TEST.TAP' * OR * // EXEC TMOUNT,REAL,SIZE=AUTO,PARM='580 (QUERY' * /* * /& * * AWSTAPE HAS A LIMIT OF 17 CHARACTERS IN A DOS FILEID. THAT * LIMIT IS ENFORCED ENTIRELY IN AWSTAPE. * * THIS PROGRAM IS PROVIDED ON AN AS-IS BASIS. * IT HAS NOT BEEN TESTED ON R/390 * NO MAINTENANCE WILL BE DONE AND NO APARS WILL BE ACCEPTED * * COMMENTS AND SUGGESTION ARE WELCOME * * AUTHOR: CHUCK BERGHORN * REVISED FOR VSE: CHRISTIAN TOEPSCH (TOEPSCH@DE.IBM.COM) * *--------------------------------------------------------------------- * SPACE 1 PRINT GEN BALR R8,0 USING *,R8 CR R15,R1 TEST FOR PARM= BE NOPARM NO PARM SPECIFIED, RETURN L R2,0(R1) GET PARAMETER ADDRESS SR R3,R3 CLEAR R3 LH R3,0(R2) GET PARMLENGTH AH R3,=X'0001' ADJUST MOVE LENGTH EX R3,MOVEINST DO THE MOVE CLC PARMLEN,=X'0015' PARMLEN > THAN 21? * BH TOOLONG PARMS TOO LONG, RETURN OPEN CONSOLE PREPARE TO WRITE TO CONSOLE MVC MSGOUT,MSGSTART * PUT CONSOLE PRINT OUT THIS MESSAGE *--------------------------------------------------------------------- * * END OF PROLOGUE * *--------------------------------------------------------------------- * CLI PARMDAT,C'(' ANY OPTIONS? BNE NOOPT NO, DO SETFILE CLC PARMDAT+1(5),=C'QUERY' IS IT A QUERY? BE DOQUERY B BADOPT *--------------------------------------------------------------------- * * QUERY THE CURRENT FILE THAT IS THE VIRTUAL TAPE * *--------------------------------------------------------------------- * DOQUERY DS 0H SET UP TO DO A QUERY MVC MSGOUT,TMPQUERY MVC MSGOUT+42(4),PARMDEV INSERT DEVADDR FROM PARM PUT CONSOLE PRINT OUT THIS MESSAGE * * DO THE QUERY * EXCP QDCCB FIND OUT THE CURRENT FILE WAIT QDCCB WAIT FOR IT TO HAPPEN MVC MSGOUT,DOSFID PREPARE MESSAGE AND DISPLAY PUT CONSOLE RESULT OF QUERY LA R15,0 SET RETURN CODE B RETURN MOVEINST MVC RADDR(01),0(R2) GET PARMS MOVEINS2 MVC DOSFID(01),PARMDAT MOVE FILENAME *--------------------------------------------------------------------- * * CODE TO SET A NEW FILENAME EQUAL TO THE VIRTUAL TAPE... * *--------------------------------------------------------------------- * NOOPT DS 0H ASSUME ATTEMPT TO SET FILENAME CLI PARMDAT+1,C':' WAS A DRIVE LETTER SPECIFIED * BNE BADFILE CLC PARMDAT,MSGBLANK ANY FILENAME SPECIFIED BE BADFILE NO, BAD FILENAME MVC MSGOUT,TMPNOOPT MVC MSGOUT+49(4),PARMDEV PUT DEVADDR IN MESSAGE PUT CONSOLE LH R6,PARMLEN THIS IS THE LENGTH HALFW LA R4,PARMDAT THIS IS THE DATA S R6,PLUS4 SUBTRACT DEVADDR LENGTH AND STH R6,SDCCW+6 STORE LENGTH IN CCW SH R6,=X'0001' ADJUST MOVE LENGTH EX R6,MOVEINS2 DO THE MOVE MVC MSGOUT,MSGBLANK CLEAR MESSAGE AREA MVC MSGOUT,DOSFID FILENAME IN MESSAGE PUT CONSOLE DISPLAY IT EXCP SDCCB SET THE FILENAME INTO MOUNT WAIT SDCCB WAIT FOR THIS TO HAPPEN LA R15,0 SET RETURN CODE B RETURN EXIT *--------------------------------------------------------------------- * * ERROR CONDITIONS * *--------------------------------------------------------------------- * NOPARM DS 0H MVC MSGOUT,MSGOPT25 SUBSTITUTE VSE MSG PUT CONSOLE SHOW THIS MESSAGE LA R15,4 B RETURN BADOPT DS 0H MVC MSGOUT,MSGOPT24 SUBSTITUTE VSE MSG PUT CONSOLE SHOW THIS MESSAGE LA R15,8 B RETURN BADFILE DS 0H MVC MSGOUT,MSGNOF5 SUBSTITUTE VSE MSG PUT CONSOLE SHOW THIS MESSAGE LA R15,12 B RETURN TOOLONG DS 0H MVC MSGOUT,MSGLNG6 SUBSTITUTE VSE MSG PUT CONSOLE SHOW THIS MESSAGE LA R15,16 B RETURN *--------------------------------------------------------------------- * * EXIT CODE * *--------------------------------------------------------------------- * RETURN DS 0H MVC MSGOUT,MSGEND TMP MSG TO SHOW COMPLETION * PUT CONSOLE TMP - PUT OUT THIS MESSAGE CLOSE CONSOLE EOJ * * CONSOLE DTFCN DEVADDR=SYSLOG,IOAREA1=MSGOUT,RECFORM=FIXUNB, X TYPEFLE=CMBND,BLKSIZE=70,INPSIZE=17 MSGOUT DS CL80 MSGSTART DC CL80'*** BEGINNING OF VSE MOUNT ***' MSGEND DC CL80'*** END OF VSE MOUNT ***' MSGNOF5 DC CL80'AWSMNT001E NO OR INCORRECT FILEID SPECIFIED' MSGLNG6 DC CL80'AWSMNT002E DOS FILENAME TOO LONG' MSGOPT24 DC CL80'AWSMNT003E NO OR INVALID OPTION SPECIFIED' MSGOPT25 DC CL80'AWSMNT004E NO PARM= GIVEN' TMPQUERY DC CL80'AWSMNT005E QUERY VIRTUAL TAPE AT ADDRESS ' TMPNOOPT DC CL80'AWSMNT006E ASSIGNING TO VIRTUAL TAPE AT ADDRESS ' MSGBLANK DC CL216' ' * RADDR DS 0CL256 USED TO SAVE PARMS PARMLEN DC CL2' ' PARAMETER LENGTH PARMDEV DC CL4' ' DEVADDR FROM PARMS PARMDAT DC CL216' ' DATA FROM PARMS (QUERY * OR FULL QUALIFIED FILENAME DOSFID DC CL80' ' * * QDCCB CCB SYS014,QDCCW SDCCB CCB SYS014,SDCCW QDCCW CCW X'4B',DOSFID,X'60',1 CCW X'E4',DOSFID,X'20',L'DOSFID SDCCW CCW X'4B',DOSFID,X'20',L'DOSFID * * PLUS4 DC F'4' R0 EQU 0 R1 EQU 1 R2 EQU 2 R3 EQU 3 R4 EQU 4 R5 EQU 5 R6 EQU 6 R7 EQU 7 R8 EQU 8 R9 EQU 9 R10 EQU 10 R11 EQU 11 R12 EQU 12 R13 EQU 13 R14 EQU 14 R15 EQU 15 END /* // IF $MRC GT 4 THEN // GOTO NOLNK // EXEC LNKEDT /. NOLNK /& * $$ EOJ hercules-3.12/util/zzsacard.bin0000664000175000017500000007152012564723224013500 00000000000000z~ˆ@P~ˆ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@~Ø@P(@Px@PÈ@P€@P€h@P€¸@P@PX@P¨@Pø@P‚H@P‚˜@P‚è@Pƒ8@Pƒˆ@PƒØ@P„(@P„x@P„È@P…@P…h@P…¸@P†@P†X@P†¨@P†ø@P‡H@P‡˜@P‡è@Pˆ8@Pˆˆ@PˆØ@P‰(@P‰x@P‰È@P`X`(`(è@P8@Pˆ@PØ@P(@Px@PÈ@P@Ph@P¸@P@PX@P¨@Pø@PH@P˜@Pè@P8@Pˆ@PØ@P (@P x@P È@P @P h@P ¸@P @P X@P ¨@P ø@P H@P ˜@P è@P 8@P ˆ@P Ø@P(@Px@PÈ@P@Ph@P¸@P@PX@P¨@Pø@PH@P˜@Pè@P8@Pˆ@PØ@P(@Px@PÈ@P@Ph@P¸@P@PX@P¨@Pø@PH@P˜@Pè@P8@Pˆ@PØ@P(@Px@PÈ@P@Ph@P¸@P@PX@P¨@Pø@PH@P˜@Pè@P8@Pˆ@PØ@P(@Px@PÈ@P@Ph`8@Pˆ@PØ@P (`'¸@P(@P(X@P(¨@P(ø@P)H@P)˜@P)è@P*8@P*ˆ@P*Ø@P+(@P+x@P+È@P,@P,h@P,¸@P-@P-X@P-¨@P-ø@P.H@P.˜@P.è@P/8@P/ˆ@P/Ø@P0(@P0x@P0È@P1@P1h@P1¸@P2@P2X@P2¨@P2ø@P3H@P3˜@P3è@P48@P4ˆ@P4Ø@P5(`(5ð@P6@@P6@P6à@P70@P7€@P7Ð@P8 @P8p@P8À@P9@P9`@P9°@P:@P:P@P: @P:ð@P;@@P;@P;à@P<0@P<€@P<Ð@P= @P=p@P=À@P>@P>`@P>°@P?@P?P@P? @P?ð@P@@@P@@P@à@PA0@PA€@PAÐ@PB @PBp@PBÀ@PC@PC`@PC°@PD@PDP@PD @PDð@PE@@PE@PEà@PF0@PF€@PFÐ@PG @PGp@PGÀ@PH@PH`@PH°@PI@PIP@PI @PIð@PJ@@PJ@PJà@PK0@PK€@PKÐ@PL @PLp@PLÀ@PM`V@PVf@PV¶@PW@PWV@PW¦@PWö@PXF@PX–@PXæ@PY6@PY†@PYÖ@PZ&@PZv@PZÆ@P[@P[f@P[¶@P\@P\V@P\¦@P\ö@P]F@P]–@P]æ@P^6@P^†@P^Ö@P_&@P_v@P_Æ@P`@P`f@P`¶`,bˆ@PbØ@Pc(@Pcx@PcÈ@Pd@Pdh@Pd¸@Pe@PeX@Pe¨@Peø@PfH@Pf˜@Pfè@Pg8@Pgˆ@PgØ@Ph(@Phx@PhÈ@Pi@Pih@Pi¸@Pj@PjX@Pj¨@Pjø@PkH@Pk˜@Pkè@Pl8@Plˆ@PlØ` n˜@Pnè@Po8@Poˆ@PoØ@Pp(@Ppx@PpÈ@Pq@Pqh@Pq¸@Pr@PrX@Pr¨@Prø@PsH@Ps˜@Psè@Pt8@Ptˆ@PtØ@Pu(@Pux@PuÈ@Pv@Pvh@Pv¸`x€@PxÐ@Py @Pyp@PyÀ@Pz@Pz`@Pz°@P{@P{P@P{ @P{ð@P|@@P|@P|à@P}0@P}€@P}Ð@P~ @P~p € \€:€~ Þ­ Þ­€ÐÑKÑÁÅÇÅÙ`ééâÁÉ×Óð`ðòaò÷aðö`òðKôôééâÅÃÙÅã ~ˆH@€ÿÿÿÿÿÿÿÿ@@@@@@@@@@@@@@@ðñòóôõö÷øùÁÂÃÄÅÆ‚þ(H`Љ`Xf˜ æ˜.4‚ ¸Òj”ðö(JÂØHpþh!X0¼X¸‘0ÜG€6²50è•0ñGpâ‘0ðG€2”ï0Ü‘€1CG€ö•1/Gpö•1AGpöX<_ Õ PGp#Gp˜ñhGð.²50@‘0ÜG2•0IGpâ‘0HGàV– 0Ü‘€0HGà‚Õ G€pY0Gp‚X<_ Õ RG€ö‘0@Gpª‘ 0HGª‘0HG‘0HGª‘0HGà‘€0ÜG€”0ÜX<_ Õ PGp#Gp”Ï:‘0@Gpâ‘0HG€ê– :Gðö‘€0HG€ö–:‘ 0ÜG”ý9‘ 0ÜGà2”ß0Ü–0Ü’0à’ 0áÒ0â TA1(P0äAð0àMà”˜þh‚8þ¨˜5 Õ†0G€P‡4BX`0 æ˜þ¨‚@zŠxþ‘Ž–0”ýþ²@‘ŽX0_0 Õ P0~YŽ–Ü–0”ýþÒh ø˜% €xÒfÐGðf$˜4ð˜‰hÒh Xü²40Pü^ ,Gðä‰hXP 0X 4×ÿ00×G11A²40G@‘0G€ Y¸Gp,P0P0€P00–€0²20‡4¿ V!^ 8½,üGp CP0^0P0_@ôP@øþ˜5ð½0G€€‡4nAð þX0€Að•0Žÿþ1× 0404P004’ÿ0:–À09Pð0<–€0Ü”÷0ÜX0€²304Gpâ²8GpØX (^ 8P 8²8–!þ”Ï"– "þ–!þX0P3Ž!DU$þXP!0ŽDU$þ˜5ðÕ0G€@‡4,Að þX0€ÿþ QŽŒ ˆ0#¾XCBPUŽoArðA…§´AÃpÔ¬GЪ¡³ÆÓ¬¦³AÃ`Ó¬A£`³ÁÓ¬csF€vFj!4DU$þX@dX0$T0 Ò¯} Ò”û¯@׮ޮŽ×¯4¯4’®Gð¦ Ýñ®€Ò®Œ»>Ò¯} Ò”û¯@׮ޮŽ×¯4¯4’®˜ñ®€I®ŽG°¦Mà«^Ò°6»@Ò¯Gº¼‘®G¦:Ò°6»BÒ¯GºÀH ®ŽN Pó2XU–ð[ÜXwÒ¯àXH ®ŒN Pó2XU–ð[ÜXwÒ¯ëXpaK`®ŽLp®ŽwG€¦ŽpA``Jp®ŒpA@AwðA øA0°8ծ޻DGp¦â‘®G€¦Ò_0ºÄ_ ºÄÒT0¸ A UA00U@Gð¦âÒQ0·¸A RA00R@fG€§$’@0ÒN00Xð®„ïIð»FGЧAðPðDð®hÜO0 ÒA00PA P~`F@¦âGð§L‘®G§>ÒQ0¸±A RA00RGð§LÒQ0¸_A RA00R‘®G€§^Ò 0¹A @ ¯:XAð¯8 Ò¯} Ò”û¯@ ‘®G€§Œ Gð§¦XAð Gp§ŒAVKJ@ ˜H ˜Ò°/¹I»ÖO  Ä"Õ ÄG€À¼Að•~  G€ÁìÒÃ{ GðÀ ÿ•ó šG€Áì•à šG€Áì•} šGpÀ²•@ÄGpÀÂÒÃ{ ÒGðÀ ÒÃ{ úGðÀ ÒÄ  ÒXÄÜXÒA CWŒF ÀÔ ÿG€ÀöÒÃ{ "GðÀ 1 yÖ•30ˆG€ÁÒÃ{ JGðÀ zÒ'¯PÃ×PPñ!P0ó2XP–ð[ÜXwÒ¯iXA, ñÒ1ÁîÒ0ŒA2Ò1 Ò0A2Ò1ÂRÒ0A2Ò1„ñTP0—ó•XP–ðaÜ XwÒ XA2Ò1¶ñP0–ó!XP–ðZÜXwÒ YA2Ò1ÂèÒ 0±A2AMà¥âA, ÒÃ{ ÒÿG€À å–“¤”…@Ó‚…“@É„…•£‰†‰…™@@@@@@@ooo@@@@@@@@@@@@@@@@@å–“¤”…@Ó‚…“@Õ¤”‚…™@@@@@@@@@@@o@@@@@@@@@@@@@@@@@@@å–“¤”…@â…™‰“@Õ¤”‚…™@@@@@@@@@@oooooo@@@@@@@@@@@@@@åãÖÃ@×–‰•£…™@MÃÃÈÈÙ]@@@@@@@@@@oooooooooo@@@@@@@@@@å–“¤”…@â…ƒ¤™‰£¨@@@@@@@@@@@@@@@ç}oo}@@@@@@@@@@@@@@@Ö¦•…™@Õ”…@•„@Á„„™…¢¢@Ö„…@@@oooooooooooooo@@@@@@ÄÁâÄ@™…ƒ–™„@ó@†–™@„…¥‰ƒ…@oooo@@@@@@@@@@@Ï.°C`ééâÁÇåÖÓ@Éèĉ¢—“¨@ÄÁâÄ@Ù…ƒ–™„@ó@MåÖÓñ]@{è@@@@@@@@@@@@@@@@@@@@Â``Ö””•„è~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`JJ`Å•£…™@ô@„‰‡‰£@ÄÁâÄ@„…¥‰ƒ…@•¤”‚…™zOJè~~~nÈ@@@@`OP@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ÀÒÆ: ÒÒÆÑÈ<ÒÆýÈtÒÇÛÇß”ûÆ•@ÆMG€À(–ÆXAðÆ  XAð GpÀ4AVKJÒÇÛÇß@ ˜IÈzGÐÀ¨•  GpÀrÒO  KÈ|GðÀPÜO   ÒÖO  ÇìÕ ÇßG€ÀÞÕ ÇâG€Á$Að•~  G€ÄªÒÆ: GðÀÿ•ó šG€Äª•à šG€Äª•} šGpÀÔ•@ÆÑGpÀäÒÆ: ÒGðÀÒÆ: úGðÀÒÆÑ  ÒXÆÑÜXÒA CWŒF Àö ÿG€ÁLÒÆýÈtÒÆ: "ÒÇÛÇßGðÀÒÆý  A   ÿG€ÁLÒÆÑÈ<ÒÆ: 6ÒÇÛÇâGðÀ1 yÖ•30ˆG€ÁrÒÆýÈtÒÆ: JÒÇÛÇßGðÀ zÕÈ@0ŒG€ÁŒÒÆ: ^GðÀÒ'¯PÅDÒ¯]0ܯ] ÒÒÆý0ÜÆý Ò×PPñ!P0ó2XP–ð[ÜXwÒ¯dXÒÆÑX zXG€Ä¬€0_P"DC@0J@0A@@•ñ04GpÄzA® aÒ`ĶÒ+`0XàÈD‘0VGÂ|XàÈH‘0VGÂ|XàÈL‘0VGÂ|XàÈP‘0[GÂ|XàÈT‘€0ZGÂ|XàÈX‘@0ZGÂ|XàÈ\‘ 0ZGÂ|XàÈ`‘0ZGÂ|XàÈd‘0ZG€Âˆ¿âÈ~Pà`3Aà`>‘À0\Gà¦ÒàÈhAààGðÂÊ‘€0\Gà¸ÒàÈlAàà‘@0\GàÂÊÒàÈpAàà‘ 0\GàÂÚ’ãàAàà‘0\GàÂê’ÂàAàà‘0\GàÂú’âàAàà‘0\Gàà ’ÁàAàà‘0\GàÃ’ÔàAààHà0^NàPóBXU–ð\Ò`KXHà0`NàPóBXU–ð\Ò`WXîCà0=NàPó!XV–ðZÒ`dY¿ã0>NàPóBXU–ð\Ò`fZîCà0SNàPó!XV–ðZÒ`rY¿ã0TNàPóBXU–ð\Ò`tZîCà0@NàPó!XV–ðZÒ`~Y¿ã0ANàPóBXU–ð\Ò`€ZîCà0CNàPó!XV–ðZÒ`‹X’@`ŽÒÿ``ŽÒaaŽAà0PàÅlAðÅl {>AAàÅlAð`Ž•àG€Äv×PPñCPàótðP–ððÜðw’`ð ñCPàótð P–ððÜð wAàà AððFÄ,A ‡4ÁìA®AðP A®AðPMà¥â  ÒÆ: ÒÿG€À ÒÆ: šGðÀoooooooooooooooooooooooooooooooooooooooooooo@ÄâÖÙÇ~oooo@ÙÅÃÆÔ~oooo@ÂÓÒâÉéÅ~ooooo@ÓÙÅÃÓ~ooooo@ÃÙÄÁãÅ~ooooo@ÙÅÆÄÁãÅ~ooooo@Åç×Äã~ooooo@ÅçãÅÕã~oooåãÖÃ@“‰¢£‰•‡@ooooooMoooo]@@@@@@@@@@@@@@@Ë5øC`ééâÁÇÄÅå@ÉèåãÖÃ@Ó‰¢£@䣉“‰£¨@{è@@@@@@@@@@@@@@@@@@@@Â``Ö””•„è~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`Çj`Å•£…™@ô@„‰‡‰£@ÄÁâÄ@„…¥‰ƒ…@•¤”‚…™zJJè~~~nÈ@@@@`Lj`–™@ÄÁâÄ@¥–“¤”…@¢…™‰“zOJè~~~nÈ@@@@@@`ÔJèÕ–£…z`㈅@ÄÁâÄ@¥–“¤”…@”¤¢£@ˆ¥…@‚……•@ƒƒ…¢¢…„@—™…¥‰–¤¢“¨Õa‰•@–™„…™@£–@‚…@‚“…@£–@¢—…ƒ‰†¨@£ˆ…@¥–“¤”…@¢…™‰“KÖñɆ@£ˆ…@„…¥‰ƒ…@•¤”‚…™@‰¢@¤•’•–¦•@¤¢…@—™‰”™¨@”…•¤ØÁ–—£‰–•@ð@£–@™…„@““@ÄÁâÄ@¥–“¤”…@“‚…“¢@†‰™¢£KJPJPOP@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@åÖÓñ×Ö`ÅâãÙ×ÈÆâ@åâ@@Éâ@@×â@@ÄÁ@@×Ö@@oo@@ä@@@Æ@@@å@@@@@@@@@ä ÀÒƵ ÒÒÇLÇÐÒ ÇŽÇàÒǚǞ”ûÆ•@ÆÈG€À(–ÆXAðÆˆ  XAð GpÀ4AVKJÒǚǞ@ ˜IÇêGÐÀœ•  GpÀrÒO  KÇìGðÀPÕ ÇžG€ÀòÕ Ç¡G€Á Að•~  G€ÅPÒƵ GðÀÿ•ó šG€ÅP•à šG€ÅP•} šGpÀâÒƵ ÒÒǚǞ•@ÇLG€ÀÒǚǡ•@ÇŽG€ÀÒǚǞGðÁ&ÒǚǞÒƵ úGðÀÒÇL  ÜÇL ÒÒK   ¤KÇîGðÀPÒ ÇŽ  Ü ÇŽ ÒÒE   ªKÇðGðÀPÒXÇLÖXÇÐÜXÒA CWŒF Á> ÿG€Á`ÒƵ "GðÀPÅTׯ€Æ€Ò XÇŽÖ XÇàÜ XÒA CWŒF Á€PÆ‚A C_ŒF Á”ŒBƆXÅT zXÇÔ PÆt1X ÅTAðÆX GpÁòCƆABƆÕÆ‚0GpÁò¿ J GðÂXÇÔ ÒƵ rÒǚǡGðÀAð PÅ\ÒÅ`ÇòqÒïpÅb×PPñ!P ó2XP–ð[ÜXwÒp XÒp ×PPñ!P0ó2XP–ð[ÜXwÒp\X×PPñ!P0ó2XP–ð[ÜXwÒpaX×PPñP0ó!XP–ðZÜXwÒpfYîCàÅXNàPó!XV–ðZÒpzX×PPñPÅXó!XP–ðZÜXwÒpwYîCà0NàPó!XV–ðZÒp¯X×PPñP0ó!XP–ðZÜXwÒp¬YHà0NàPóBXU–ð\ÒpÌX×PPñ!P0ó2XP–ð[ÜXwÒpÇX¿0G€Ä>A]ÇØH Å`!@ Å`LÇô ’@ÒNApPA@0UCP0f’@pÒNpp@`H×PPñ!PHó2XP–ð[ÜXwÒpXfGpÃÜÒpÇöA€pAp:ñP@ó!XP–ðZÜXwÒ€YÒ@A@@A``A€€AB`H‘HGpÄ&A€€‘HGpÄ:AppPFPàGðÄ>FPÃä¿0G€Å"A]ÇØH Å`!@ Å`LÇô ’@ÒNApPA@0UCP0E¿S0f’@pÒNpp@`H×PPñ!PHó2XP–ð[ÜXwÒpXfGpÄÀÒpÇÜA€pAp:ñP@ó!XP–ðZÜXwÒ€YÒ@A@@A``A€€AB`H‘HGpÅ A€€‘HGpÅAppPFPÄ„GðÅ"FPÄÈAPHÅ`XðÅ\Ò'¯PǨMà¥â _Æt ÒƵ ÒÿG€À Ä…¥‰ƒ…@@@@@@ooooMoooooo]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ÃÃÈÈÙ@@@@@@@oooo@oooo@oo@@@â…ƒ£–™@@@@@@ooMooo]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Ò…¨@“…•‡£ˆ@@ooMooo]@@@@@@@@Ä£@“…•‡£ˆ@ooooMooooo]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>è1@>ê>È`ÿÿ"=À>øC`ééâÁÄäÔ×@ÉèĤ”—@ÄÁâÄ@™…ƒ–™„@{è@@@@@@@@@@@@@@@@@@@@Â``Ö””•„è~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`Çj`Å•£…™@ô@„‰‡‰£@ÄÁâÄ@„…¥‰ƒ…@•¤”‚…™zJJè~~~nÈ@@@@`Lj`•„@™…ƒ–™„@„„™…¢¢@‰•@ñð@„‰‡‰£@ÃÃÈÈÙ@†–™”£zOJè~~~nÈ@@@@@@@@@@`JPJPOPÄÁâÄ@™…ƒ–™„@„¤”—@@@@@@@@@@@@@@@@@@@@@@@@@@@@ÿÿÄ£@@@@@@@@@@ PÒ…¨ ÀÒÃOÂBÒ Ã‘ÂJÒ¸ ÒÒÃä”ûÂ’•@ÂËG€À(–Â’XAðŠ  XAð GpÀ4AVKJÒÃä@ ˜IÂTGÐÀœ•  GpÀrÒO  KÂVGðÀPÕ äG€ÀòÕ çG€Á Að•~  G€Â6Ò¸ GðÀÿ•ó šG€Â6•à šG€Â6•} šGpÀâÒ¸ ÒÒÃä•@ÃOG€ÀÒÃç•@ÑG€ÀÒÃäGðÁ&ÒÃäÒ¸ úGðÀÒÃO  ÜÃO ÒÒK   ¤KÂXGðÀPÒ Ã‘  Ü Ñ ÒÒE   ªKÂZGðÀPÒXÃOÖXÂBÜXÒA CWŒF Á> ÿG€Á`Ò¸ "GðÀPÂ:×Â‚Â‚Ò XÃ‘Ö XÂJÜ XÒA CWŒF Á€P„A C_ŒF Á”ŒBˆXÂ: zXÂF PÂ~1X Â:AðÂb GpÁöCˆABˆÕ„0GpÁöÕÂ\0G€Â GðÂ"XÂF Ò¸ rÒÃçGðÀXÂF Ò¸ vÒÃçGðÀ DXÂF ÿG€À @@@@ÿþ@@@@@@@@@@ @Bè1@BêBÐ ÿÿBøC`ééâÁÁÓãÙ@ÉèÁ“£…™@ÄÁâÄ@™…ƒ–™„@{è@@@@@@@@@@@@@@@@@@@@Â``Ö””•„è~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`Çj`Å•£…™@ô@„‰‡‰£@ÄÁâÄ@„…¥‰ƒ…@•¤”‚…™zJJè~~~nÈ@@@@`Lj`•„@™…ƒ–™„@„„™…¢¢@‰•@ñð@„‰‡‰£@ÃÃÈÈÙ@†–™”£zOJè~~~nÈ@@@@@@@@@@`JPÁ^JPOPÒÌ Ò×Ë&Ë&cƒXpËz—ghX Â:ÒHË(×PPñ!PHó2Ì„P–ð̇ÜÌ„w×PPñ!P ó2ËýP–ðÌÜËýwñTP„ó•ÌP–ðÌÜ ÌwA@̯APA`0^`Ë&wCp0[pË&GÐÅVAPPA ¾÷@A@@@Ë"Ò@ËÆA@@Ò@ËÔA@@Ò@ËÆA@@A> ¾÷@A@@Ò@ËÆA@@YË~GÐĘADÊ.DÊ4AA@A ¾÷@A@@A0@H×PPñ!PHó2@P–ð@Ü@wA@@A ¾÷@A@@A€Ò@ËÈ^ËzÕ`G€ÅÒ@ËÊA@@ñP`ó!XP–ðZÜXwÒ@YA@@A``FpÅBGðÅVF€ÄöAPPYPË‚GÐÄfGðÆœ¿0G€ÆœpGÐÆœAPPYPË‚G ÆœÒ@ËÆA@@A ¾÷@A@@@Ë$Ò@ËÆA@@Ò@ˆA@@Ò@ËÆA@@A> ¾÷@A@@Ò@ËÆA@@YË~GÐÅÖADÊ.DÊ4AA@A ¾÷@A@@A0C0@H×PPñ!PHó2@P–ð@Ü@wA@@A ¾÷@A@@A€Ò@ËÈ^ËzÕ`G€ÆXÒ@ËÊA@@ñP`ó!XP–ðZÜXwÒ@YA@@A``FpƈGðÆœF€ÆAVKJÒÉ}É@ ˜IÌÐGÐÀ°•  GpÀ|ÒO  KÌÒGðÀZÕ ÉG€ÁÕ É„G€Á(Õ ɇG€ÁLAð•~  G€Ã¢ÒÇ GðÀÿ•ó šG€Ã¢•à šG€Ã¢•} šGpÀþÒÇ ÒÒÉ}É•@ÈG€ÀÒÉ}É„•@ÈsGpÁp•@ÈŸG€ÀÒÉ}ÉGðÁpÒÇ úGðÀÒ+È  Ü+È ÒÖ+ÈÌvÒ#   ÌKÌÔGðÀZÒÈs  ÜÈs ÒÖÈsÌ¢ÒK   ¤KÌÖ–€ÊÈGðÀZÒÈŸ  ÜÈŸ ÒÖÈŸÌÊÒI   ¦KÌØ–@ÊÈGðÀZ•@ÈsG€Â‘@ÊÈGÂÒXÈsÜXÒA CWŒF Á’ ÿG€ÁÀÒÈŸÌÊÒÇ "ÒÉ}É„GðÀ yÖGpÁè•3ˆGpÁþ zGpÁèÒÈŸGðÂLÒÈŸÌÊÒÇ rÒÉ}É„GðÀÒÈŸÌÊÒÇ JÒÉ}É„GðÀAÈŸ ÿG€Â6ÒÈsÌ¢ÒÇ 6ÒÉ}ɇGðÀñ!Pó2ÈsP–ðÈvÜÈswPÊÊÕ̦ŒGpä zXG€Ã´ Ò_Ì 4AðÊâÒÊâ̪ zöA ×ÊÞÊÞÕÌ®ÊâG€ÃÄ‘ËÔG€ÃÔX̲ ‘A€ApÊâPÊÚ•pG€ÃfPɪX`pP`ɰXÊÊAðÉŽ GpÃä9U¿Sɨ¿JPYPDC@0J@0G€ÃfA@@5ÊÎH 0AR0A00ÕÌn0G€Ãf Z,C@0 T@̶‰@A@@ ‡4Ø5Ê·4ÂðA``½cÌ"G@ÃVˆ`A``‰`Y`pGÐÂÊApp F€ÂºA‚XðÊÚXÊÞG€ÃôÒ ¯PÇTÒ¯ZÈMà¥âXÊÞLÌÚ^̲ ÒÇ ÒÿG€À ÒÇ ^ÒÉ}É„GðÀÒÇ šÒÉ}É„GðÀÒÇ †ÒÉ}ÉGðÀÒÇ ®ÒÉ}ÉGðÀÒÇ ÂÒÉ}ÉGðÀÒÇ ÖÒÉ}ÉXÊÞLÌÚ^̲ GðÀA‚ X ÊÞA P ÊÞ‘ÀËÖGÄ6ÒÉ´GðÄ<ÒÊ6Ò0×PPñ2P0óS P–ðÜ wA@APÊ∿ƒ0f¿cPL`Ì"J`Phw¿sPLpÌ"JpPgGÐÄž†‡€APP F@ÄlŒ` HÌ"`¾sX¾cZÒ\0 ñTPXó•P–ð#Ü w‘ÀËÖGŬ‘0 GÅž‘0 GàÅž"C 0 N Pó)V–ð*C 0 N Pó,V–ð-óBX0–ð\Ò6XÒ9ZóBX0–ð\ÒDXÒGZñR0ñ!P0óSXP–ð]ÒRXÒUZÒX\H 0N Pó2`U–ðcH 0N Pó2jU–ðmH 0N Pó2sU–ðvÒ{0 GðÇR’@%Ò[&%GðÇR×PPñ2P0óS*P–ð/Ü*w×PPñ2P0óS4P–ð9Ü4wÒQʸ‘0G€ÅøÒQÊÄCP0TP̺‰PAUʸÒGPAPU‘0G€Æ„A 0!‘0G€Æ*A ‘€0 G€ÆFÒPÌâÒP APPA ‘0G€ÆZ^ ̾T ÌÂA • GpÆ„×PPñP ó!XP–ðZÜXwÒ>YAPPe‘€0G€ÆœÒPÌçAPP‘@0G€Æ®ÒPÌêAPP‘ 0G€ÆÀÒPÌíAPP‘0G€ÆÒÒPÌðAPP‘0G€ÆäÒPÌóAPP‘0G€ÆöÒPÌöAPP‘0GÇÒPÌùAPP‘€0GÇÒPÌüAPP‘0G€Ç,ÒPÌÿAPP‘0G€Ç>ÒPÍAPPVG€ÇR_`ÌÆÒ`ÌÜ’]P ĉ™…ƒ£–™¨@]€C`ééâÁÓ×Äâ@ÉèÓ‰¢£@×Äâ@ĉ™…ƒ£–™¨@{è@@@@@@@@@@@@@@@@@@@@Â``Ö””•„è~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`ÆZ`Å•£…™@„£¢…£@•”…zÈzè~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`KZ`•„@ô@„‰‡‰£@ÄÁâÄ@„…¥‰ƒ…@•¤”‚…™zMzè~~~nÈ@@@@`PZ`–™@ÄÁâÄ@¥–“¤”…@¢…™‰“zÒzè~~~nÈ@@@@@@`×zèÕ–£…z`㈅@ÄÁâÄ@¥–“¤”…@”¤¢£@ˆ¥…@‚……•@ƒƒ…¢¢…„@—™…¥‰–¤¢“¨Ùщ•@–™„…™@£–@‚…@‚“…@£–@¢—…ƒ‰†¨@£ˆ…@¥–“¤”…@¢…™‰“KZaɆ@£ˆ…@„…¥‰ƒ…@•¤”‚…™@‰¢@¤•’•–¦•@¤¢…@—™‰”™¨@”…•¤[ñ–—£‰–•@ð@£–@™…„@““@ÄÁâÄ@¥–“¤”…@“‚…“¢@†‰™¢£KÉ@É@N@Ó@@_È9@_Ê_°^ ÿÿoooooooo@ããÙ~oooooo@ÃÃÈÈÙ~oooooooooo@åÅÙ~ooKoo@ÃÙÄÁãÅ~ooKooo@ÃÈÄÁãÅ~ooKooo@ÃÈãÉÔÅ~oozoozoo@âÉéÅ~oooo@ÉÕÉã~oooo@ÔÖÄ~oooo@ÉÄ~ooooooooooooooo@ããÙ~oooooo@ÃÃÈÈÙ~oooooooooo@âÉéÅ~oooooo@Å×~oooooo@ÁÃ~oo@ÁÔÖÄÅ~ooo@ÙÔÖÄÅ~ooo@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@òô@@\\\@óñ@@ÁÕè@ÿÿÿÿÿÿÿÿ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@åÖÓñ^0ÿÿÿÿÿþ@@@@@@,‚ÁããÙ~MÔÁÉÕ~kÙÕkÙäkÖåkãâkÖÓkâÃkÕçkÆÖkÕÅkÙÆ À PÂd˜5ðf‘0GàÁÞ yÖA``A` qÒ_pÂX0€ˆBX–ðXÜXwÒpX×PPñ!P0‚ó2XP–ð[ÜXwÒpX×PPñ!P0ó2XP–ð[ÜXwÒpXX0 T0T0¾HApA €A€0D ÂG€ÀÜ×PPñP€ó!XP–ðZÜXwÒYAA€€Š GpÀ®•0…G€ÁÞÒp0šñ!P0…ó2XP–ð[ÜXwÒp3X•0‡G€ÁÞ’`p7×PPñP0‡ó!XP–ðZÜXwÒp8Y•0ˆG€ÁÞÒp;Âñ!P0ˆó2XP–ð[ÜXwÒp>X•0ŠG€ÁÞ’`pB×PPñP0Šó!XP–ðZÜXwÒpCY•30ˆGpÁÞ z•0G€ÁÞÒpF”ÒpJ0ÒpQ ñTP0—ó•XP–ðaÜ XwÒ pVX‡4ÀA`XðÂdÒ'¯PÂlMà¥âL`˜  ‘HâÃÈ~ozoooo@ÄÅå~oooo@ÃÈ×~@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Ä…¥‰ƒ…@Ó‰¢£@@@@@@@@@@@@@@@@@@@@@@@@@@@@@åÖÓ~`Ãã~Äã~åãÖÃ~ ÀÒÄß ÒÒ+ÅhÈÒÒÅÃÈÊÒÅüÈþÒÆ(ÉÒÇÇ ’Ç”ûIJ•@ÄòG€À8–IJXAðĪ  XAð GpÀDAVKJÒÇÇ @ ˜IÉGÐÀÀ•  GpÀ‚ÒO  KÉGðÀ`Õ Ç G€ÁÕ Ç G€Á8Õ ÇG€ÁXÕ ÇG€Á|Að•~  G€ÄÒÄß GðÀ$ÿ•ó šG€Ä•à šG€Ä•} šGpÁÒÄß ÒÒÇÇ •@ÅhG€À$ÒÇÇ•@ÅüGpÁ •@Æ(G€À$ÒÇÇ GðÁ ÒÄß úGðÀ$Ò+Åh  Ü+Åh ÒÖ+ÅhÈÒÒ#   ÌKÉGðÀ`ÒÅà  ÜÅà ÒÖÅÃÈÊÒG   ¨KÉGðÀ`ÒÅü  ÜÅü ÒÖÅüÈþÒK   ¤KÉ–€ÇGðÀ`ÒÆ(  ÜÆ( ÒÖÆ(ÉÒI   ¦KÉ–@ÇGðÀ`•@ÅüG€ÂD‘@ÇGÂDÒXÅüÜXÒA CWŒF Á ÿG€ÁðÒÆ(ÉÒÄß "ÒÇÇGðÀ$ yÖGp•3ˆGpÂ. zGpÂÒÆ(GðÂ|ÒÆ(ÉÒÄß rÒÇÇGðÀ$ÒÆ(ÉÒÄß JÒÇÇGðÀ$AÆ( ÿG€ÂfÒÅüÈþÒÄß 6ÒÇÇGðÀ$ñ!Pó2ÅüP–ðÅÿÜÅüwPÇÕÉŒGpÄ zXG€Ä* Ò_Èb 4AðÇ6ÒÇ6É zöA ×Ç&Ç&ÕÉ Ç6G€Ä:‘bÈ(G€ÄZ‘€È*G€Äj‘ÀÈ*GÄjÕÈ.É G ÄzÒÈÄÇ8’ÈÈ‘È(G€Ã8•@ÅÃG€ÄŠXÇAÇ6ÒÇ*ÈvÒÇ,ÅÃAðÇ* {ŒÿGpÄJPÈÄBÈÈXÇAÇ6ÒÈÂÈvAðÈ |þÿGpÄ ×Ç&Ç&PÇPÇ"G€Ã°0QPH€È.( wDCp0¿C0GAspA“@A@@XÇ&APÇ& D Äš‡xÔ‡4ÃzHÈ.XðÇ"XÇ&Ò¯PÄ Ò ¯WÅh‘È(G€ÃìA ¯n •@ G€ÃÔ’M Ò ÅÃ’] Mà¥â _Ç ÒÄß ÒÿG€À$ ÒÄß rÒÇÇGðÀ$ÒÄß ^ÒÇÇGðÀ$ÒÄß šÒÇÇGðÀ$ÒÄß †ÒÇÇ GðÀ$ÒÄß êÒÇÇ GðÀ$ÒÄß þÒÇÇ GðÀ$ÒÄß ÒÇÇ GðÀ$ÒÄß &ÒÇÇ GðÀ$ÒÄß :ÒÇÇ GðÀ$Òp™–¦¢…@Xj€C`ééâÁÂÙÄâ@Éè™–¦¢…@„£¢…£@–™@”…”‚…™@{è@@@@@@@@@@@@@@@@@@@@Â``Ö””•„è~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`ÆZ`Å•£…™@„£¢…£@•”…zÇjè~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`JJ`Å•£…™@”…”‚…™@•”…@M×Äâ@–•“¨]zKZè~~~nÈ@@@@@@@@`Mz`•„@ô@„‰‡‰£@ÄÁâÄ@„…¥‰ƒ…@•¤”‚…™zOJè~~~nÈ@@@@`Ñj`–™@ÄÁâÄ@¥–“¤”…@¢…™‰“zÒzè~~~nÈ@@@@@@`×zèÕ–£…z`㈅@ÄÁâÄ@¥–“¤”…@”¤¢£@ˆ¥…@‚……•@ƒƒ…¢¢…„@—™…¥‰–¤¢“¨Ùщ•@–™„…™@£–@‚…@‚“…@£–@¢—…ƒ‰†¨@£ˆ…@¥–“¤”…@¢…™‰“KZaɆ@£ˆ…@„…¥‰ƒ…@•¤”‚…™@‰¢@¤•’•–¦•@¤¢…@—™‰”™¨@”…•¤[ñ–—£‰–•@ð@£–@™…„@““@ÄÁâÄ@¥–“¤”…@“‚…“¢@†‰™¢£KÇðÇðK`OPÓ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@åÖÓñk6@@@@@@, ÀÒÅŸ ÒÒ+Æ(É”ÒƃɌÒƼÉÀÒÆèÉÐÒÇÆÇÊ’ÇÖ”ûÅt•@ŲG€À8–ÅtXAðÅl  XAð GpÀDAVKJÒÇÆÇÊ@ ˜IÉÖGÐÀÀ•  GpÀ‚ÒO  KÉØGðÀ`Õ ÇÊG€ÁÕ ÇÍG€Á8Õ ÇÐG€ÁXÕ ÇÓG€Á|Að•~  G€ÄÒÅŸ GðÀ$ÿ•ó šG€Ä•à šG€Ä•} šGpÁÒÅŸ ÒÒÇÆÇÊ•@Æ(G€À$ÒÇÆÇЕ@ƼGpÁ •@ÆèG€À$ÒÇÆÇÊGðÁ ÒÅŸ úGðÀ$Ò+Æ(  Ü+Æ( ÒÖ+Æ(É”Ò#   ÌKÉÚGðÀ`Òƃ  Üƃ ÒÖƃɌÒG   ¨KÉÜGðÀ`ÒƼ  ÜƼ ÒÖƼÉÀÒK   ¤KÉÞ–€ÇÖGðÀ`ÒÆè  ÜÆè ÒÖÆèÉÐÒI   ¦KÉà–@ÇÖGðÀ`•@ƼG€ÂF‘@ÇÖGÂFÒXƼÜXÒA CWŒF Á ÿG€ÁðÒÆèÉÐÒÅŸ "ÒÇÆÇÐGðÀ$ yÖGp•3ˆGpÂ0 zGpÂÒÆèGðÂ~ÒÆèÉÐÒÅŸ rÒÇÆÇÐGðÀ$ÒÆèÉÐÒÅŸ JÒÇÆÇÐGðÀ$AÆè ÿG€ÂhÒƼÉÀÒÅŸ 6ÒÇÆÇÓGðÀ$ñ!Pó2ƼP–ðÆ¿ÜƼwPÇØÕÉÄŒGpÄ  zXG€Ä0 Ò_É 4AðÇôÒÇôÉÈ zöA ×ÇäÇäÕÉÌÇôG€Ä@‘bÈæG€Ä`‘€ÈèG€Äp‘ÀÈèGÄpÕÈìÉâG Ä€ÒÉ‚Çö’Ɇ‘ÈæG€Ã:•@ƃG€ÄXÇØAÇôÒÇèÉ4ÒÇêÆƒAðÇè {ŒÿGpÄPPÉ‚BɆXÇØAÇôÒÉ€É4AðÉ€ |þÿGpÄ×ÇäÇäPÇÜPÇàG€Ã²0QPH€Èì( wDCp0¿C0GAspA“@A@@XÇäAPÇä D Ä ‡xÖ‡4Ã|HÈìXðÇàXÇäÒ¯PÅcÒ"¯UÆ(‘ÈæG€ÃîA ¯n •@ G€ÃÖ’M Ò ƃ’] AÐĦMॸ _ÇÜ ÒÅŸ ÒÿG€À$ ÒÅŸ rÒÇÆÇÐGðÀ$ÒÅŸ ^ÒÇÆÇÐGðÀ$ÒÅŸ šÒÇÆÇÐGðÀ$ÒÅŸ †ÒÇÆÇÊGðÀ$ÒÅŸ êÒÇÆÇÍGðÀ$ÒÅŸ þÒÇÆÇÊGðÀ$ÒÅŸ ÒÇÆÇÊGðÀ$ÒÅŸ &ÒÇÆÇÊGðÀ$ÒÅŸ :ÒÇÆÇÍGðÀ$Òp ÀAªÀÕÇäÉÌG€Å&X0ÇÜXPÇà¥PH€Èì( wDCp0¿C0GAspA“@A@@ºD Å2G€ÅP ÅXÒÅV0ÒÅ^0XÇØAðÅ< GpÅ*GðŸ‡xÄê¿0¡‡4ÄÎÿ AðGðÅ(Õ°p@tP1@tRt8Å„‰£@VthC`ééâÁÅÄÄâ@ÉèÅ„‰£@„£¢…£@–™@”…”‚…™@{è@@@@@@@@@@@@@@@@@@@@Â``Ö””•„è~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`ÆZ`Å•£…™@„£¢…£@•”…zÇjè~~~nÈ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`JJ`Å•£…™@”…”‚…™@•”…@M×Äâ@–•“¨]zKZè~~~nÈ@@@@@@@@`Mz`•„@ô@„‰‡‰£@ÄÁâÄ@„…¥‰ƒ…@•¤”‚…™zOJè~~~nÈ@@@@`Ñj`–™@ÄÁâÄ@¥–“¤”…@¢…™‰“zÒzè~~~nÈ@@@@@@`×zèÕ–£…z`㈅@ÄÁâÄ@¥–“¤”…@”¤¢£@ˆ¥…@‚……•@ƒƒ…¢¢…„@—™…¥‰–¤¢“¨Ùщ•@–™„…™@£–@‚…@‚“…@£–@¢—…ƒ‰†¨@£ˆ…@¥–“¤”…@¢…™‰“KZaɆ@£ˆ…@„…¥‰ƒ…@•¤”‚…™@‰¢@¤•’•–¦•@¤¢…@—™‰”™¨@”…•¤[ñ–—£‰–•@ð@£–@™…„@““@ÄÁâÄ@¥–“¤”…@“‚…“¢@†‰™¢£KÇðÇðK`OPÓ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@åÖÓñu@@@@@@, À X¼‘@ÜGÀ0 yÖGpÀ˜5ÀjÕ0…G€ÀP‡4ÀGðÀÒO  Å†Að GpÀÖO  Å†Õ  G€À^–@ÜAðÀ~ GðÀÒO  Å†P yPyV1t2p2w2tuy`G`ééâÁ×âæÄ@]⣕„@Á“–•…@䣉“‰£‰…¢JØ`Å•£…™@×¢¢¦–™„zOØè~~~nL@@@@@@@@`]\`Ñ•@Ñ…‡…™@`@å…™¢‰–•@ðòaò÷aðö`òðKôô À×((A(PÀ4AðÀ0 ׄ„A„PÀ ÀX ðןððÒð iÕ ‡Ã8G€ÀJ0QDC@0J@0A@@Õ0 ‡G€À>‡4À,GðÀJÒ'ð0 ÒYðF05 À ¿qÑXÂâ ‘A€•pG€Á(PÁfX`pP`ÁlAðÁJ GpÁ09U¿SÁd¿ JPYPDC@0J@0G€Á(A@@5Á:H 0AR0A00ÕÂÚ0G€Á(Õ°0G€ÀÆC@0 T@Âæ‰@A@@ ‡4Àj˜5Á:‡4ÀHA``½c°G@À²ˆ`A``‰`Y`pGÐÀ$App F€ÀGðÁ(A@]ˆ¿ƒ0f¿cPL`°J`Phw¿sPLp°JpPgGÐÁ†‡€APP F@ÀÒŒ` H `‰pg"C 0 ÿXÂâ  AðGðÁAð GðÁ@|ø9@|ú|à^ ÿÿ ÀAq•pG€ÀüÕðpG@À"ÕðpGÐÀ6App •pG€ÁFÀGðÀüïÒÁZð CÁ^BÁ^XÁp PÁ4PÁTAðÁ GpÀü¿ JXPÁpP IPÁ‚G@ÀüX0ÁTASPPÕÁ„0G€ÁC0D¿C0AA@‡4À„•pG€ÁX`ÁZA``½càG@Àƈ`A``‰`Y`pGÐÀæApp •pG€ÁX`pFÀæGðÁP`ÁZXÁp PÁTAðÁ8GðÀ\AðGðÁAP ÿXÁ4 @~X1@~Z~ ^ ÿÿ@~X9@~Z~@^ ÿÿ@@@@@@@@ÿÿÿÿÿÿÿÿÿÿhercules-3.12/util/awssl-v19g0000664000175000017500000060525712564723224013037 00000000000000 TITLE 'AWSSL 1.9G AWS Virtual Tape (standard labels)' *********************************************************************** * AWSSL 1.9G, AWS Virtual Tape (standard labels) * * * * This program moves datasets to/from AWS virtual tape files. HET * * virtual tape formats will likely be support in the "not to distant" * * future. * * * * Copyright (C) 2002, By Reed H. Petty, rhp@draper.net * * * * You are free to make any changes you like to this code for any * * purpose (including commercial for profit use) PROVIDED that you * * carry the credits forward into derived works. * * * * NO WARRANTY OF ANY KIND IS MADE! USE AT YOUR OWN RISK! * * * * JCL quick start example: * * * * //MAKETAPE EXEC PGM=AWSSL * * //STEPLIB DD DSN=my.load.library,DISP=SHR * * //AWSPRINT DD SYSOUT=* * * //myddnam1 DD DSN=my.file1,DISP=SHR (optional) * * //myddnam2 DD DSN=my.file2,DISP=SHR (optional) * * //AWSFILE DD DSN=mytape.aws,DISP=(,CATLG,DELETE), * * // SPACE=(whatever make sense to you in your environment), * * // DCB=(whatever makes sense to you in your environment) * * //AWSCNTL DD * * * AWSVOL VOLSER=mytape * * AWSPUT INDSN=catalogued dataset name 1 * * AWSPUT INDSN=catalogued dataset name 2,UNLOAD=IEBCOPY * * AWSPUT INDD=myddnam1 * * AWSPUT INDD=myddnam1,UNLOAD=IEBCOPY * * ... or ... * * AWSVOL VOLSER=mytape * * AWSGET OUTDD=dd1,INDSN=dataset name on tape,FILENO=1 * * AWSGET OUTDD=dd2,INDSN=dataset name on tape,FILENO=5,SL=NO * * AWSGET OUTDD=dd7,INDSN=dataset name on tape,FILENO=2,LOAD=IEBCOPY * * ... and so forth * * /* * * * * Feedback, good or bad, is always welcome! * * * * Kudo's to Roger Bowler, somitcw@erols.com (whoever you are), * * Sam Golob, and to Linus Torvalds (who encouraged my trivial * * contributions to the Linux kernel). * * * * Special thanks to Michael A. Quinlan who was my boss at the * * University of Utah so many years ago. Mike is by far the best * * assembler programmer that I have ever known. * * * *********************************************************************** EJECT *********************************************************************** * * * AWS Virtual Tape Motivation, The Good, the Bad, and the Ugly. * * ------------------------------------------------------------- * * * * This program creates AWS structures which contain one or more * * OS datasets of any record format (except spanned blocks), with or * * without standard labels, where the output AWS structure can also * * be of any record format (including spanned blocks). * * * * This program will also retrieve datasets from an AWS structure of * * any record format (except spanned blocks). The retrieved datasets * * may be reblocked if necessary. If DCB attributes are omitted on * * the receiving dataset, and if standard labels are present within * * the AWS structure, then the DCB attributes of the receiving dataset * * will be defaulted to those within the HDR1 label. * * * * AWS (acronym is unknown to me, someone please tell me!) was widely * * used by the IBM P/390 product family to implement an entire tape * * volume as a byte stream contained within an OS/2 file. As * * implementations of the System/360/370/zArch architecture families * * in software expanded (such as Hercules, Flex/ES, and others) the * * AWS presence expanded as well. * * * * Recommended reading: Sam Golob's AWS article published by NaSPA. * * See URL: http://www.naspa.com/PDF/2001/1201%20PDF/T0112012.pdf * * * * Hercules provided the means for me to rekindle my MVT and MVS 3.8 * * memories. I found myself constantly moving datasets between * * these older operating systems and OS/390 running on real blue * * hardware. As neither MVT nor MVS 3.8J implement TCP/IP it became * * necessary to move 1) entire disk volumes, 2) AWS tape volumes, or * * 3) card decks. Hercules does an excellent job of reading/writing * * AWS tape volumes, but support in OS/390 was lacking (IMHO). * * * * Utilities available on OS/390 were a bit cumbersome. If standard * * label functionality was needed then the structure first had to be * * copied to a real tape volume (AWSUTIL by Brandon Hill). If a need * * existed to pluck a single file from an AWS structure, without first * * copying the entire structure to a real volume, RAWSTAPE (written * * by Jan Jaeger) was required. Also, RAWSTAPE requires that DCB * * attributes be manually set in a subsequent step. * * * * As Jay Maynard (Hercules Maintainer) is fond of saying: If you have * * an itch, then scratch it! This work represents my scratching. * * * * The itch: find a way to easily and quickly move sequential files * * and PDS' (including PDSE's) between my OS/390 and MVS 3.8J systems. * * The goals: easy syntax, standard label exploitation to set default * * DCB attributes in the receiving system, multiple file insertion * * or extraction in a single step execution, automatic PDS staging * * (this itch actually belongs to Roger Bowler but the idea is handy), * * compatibility with all known AWS utilities, and so forth. * * * *********************************************************************** EJECT *********************************************************************** * * * Assembly * * -------- * * * * To assemble on a MVS 3.8J system: * * * * //my job card * * // EXEC ASMFCL,COND=(0,NE),MAC1='SYS1.AMODGEN',REGION=4096K, * * // PARM.LKED='LIST,LET,MAP,XREF,RENT,REFR' * * //SYSIN DD * * * this code * * //LKED.SYSLMOD DD DSN=my.load.library(AWSSL),DISP=SHR * * //SYSIN DD * * * SETCODE AC(1) (if UNLOAD=IEBCOPY is used) * * // * * * * To assemble on an OS/390 R2.10 system: * * //my job card * * // EXEC HLASMCL,COND=(0,NE), * * // PARM.L='LIST,LET,MAP,XREF,RENT,REFR' * * //SYSIN DD * * * this code * * //L.SYSLMOD DD DSN=my.load.library(AWSSL),DISP=SHR * * //SYSIN DD * * * SETCODE AC(1) (if UNLOAD=IEBCOPY is used) * * // * * * * If the UNLOAD=IEBCOPY option is utilized this code must execute * * authorized. This code runs in 24 bit mode and is reentrant. * * Assembly on older releases of MVS require that SYS1.AMODGEN be * * available to the assembler. * * * * * * Rant * * ---- * * * * Some critical comments have been received regarding my programming * * style (too much uppercase, too much register saving, avoidance of * * new and spiffy instructions, linkage conventions, short 8 byte * * labels, uppercase labels, opcodes, operands, etc). * * * * Normally I strive to generate reentrant 31 bit code sprinkled * * liberally with capabilities found in the "more recent MVS world". * * However, as this code is intended to assemble and run on any * * incarnation of MVS from 3.8J forward, I have tried hard to avoid * * dependency on facilities not present in older releases of MVS. * * * * * *********************************************************************** EJECT *********************************************************************** * * * Random thoughts for the future * * ------------------------------ * * 1) Add HET format support (does anyone know of a gzip * * implementation, preferably in System/370 assembler or others not * * requiring run time library support, and not encumbered by * * overly restrictive licensing? * * *** Found, implementation in progress *** * * * * 2) Add capability to internally call IEBCOPY, IDCAMS, etc to create * * datasets in portable formats before adding to the AWS structure. * * *** Done *** * * * * 3) Add capability to retrieve a dataset from a standard label AWS * * structure and create an equivalent OS dataset. * * *** Done *** * * * * 4) Implement a decent multiple input record keyword parser. * * *** Done *** * * * * 5) Implement capability to generate AWS structures in file formats * * of undefined lengths (PREFERRED!!!), variable lengths (for * * compatibility with output produced by AWSUTIL written by * * Brandon Hill), and fixed lengths (for compatibility with * * the VTT2* utilities written by Sam Golob). * * *** Done *** * * * * 6) Add capability to IDCAMS repro and export VSAM objects. * * * * 7) Rewrite to position for never ending expansion while keeping * * the code base maintainable. * * *** Done *** * * * *********************************************************************** EJECT *********************************************************************** * * * Change History * * -------------- * * August 5, 2002 - Released to the public as v1.0 * * * * August 13, 2002 - V1.1 RELEASE * * - corrected a never ending wait on a never posted ECB in some * * environments (BSAM back to single buffering). * * - added INDD= keyword support. * * - added DSN retrieval via RDJFCB support. * * - added AWSVOL verb support. * * - revised DATASET verb format (removed VOLSER keyword). * * - Ported to MVS 3.8J (TIOT structure changes, SVC99 RB * * assembler F backward reference assembly problems, etc). * * - added support for input datasets having RECFM=U (thanks to * * Roger Bowler who identified the bug). * * - brought label formats forward to that documented in the * * OS/390 R2.10 SMS manuals. * * * * August 16, 2002 - V1.2 Release (Internal Only) * * - added automatic staging (unload) of PDS(E) datasets. * * - corrected RECFM=U ommission from HDR2/EOF2. * * - corrected RDJFCB end of list indicator. * * - converted input I/O from BSAM to QSAM for performance. * * * * September 9, 2002 - V1.9a Release Candidate (Internal Only) * * - Nearly 100% rewrite. * * * * September 18, 2002- 1.9c Release Candidate (public) * * - Added retrieve from aws tape into OS dataset function. * * - Added AWSGET PDS(e) staging. * * - Renamed TAPEVOL, IMPORT, EXPORT to AWSVOL, AWSGET and AWSPUT. * * * * September 19, 2002- V1.9D Release Candidate (public) * * - Bug! subtle, grrr... AWSIGET... when block fragmentation occurs * * between bytes 1 and 2 of AWSLENC then we cannot compute the * * length of the fragmented block and therefore cannot aggregate * * the remainder of the block. The exposure is rare and is more * * likely to be visible when using short record lengths (as is the * * case with AWS text produced by Sam Golob's VTT2DISK utility). * * * * September 23, 2002- V1.9E Release Candidate (public) * * - Incompatibility between AWSSL and VTT2TAPE. VTT2TAPE expects: * * 1) the last text record to be padded with x'20' characters, and * * 2) that an additional record be written completedly filled with * * x'20' bytes. * * Modified AWSSL accordingly when producing fixed length output. * * * * September 25, 2002- V1.9F * * - Added owner= keyword to AWSVOL function. * * * * September 26, 2002- V1.9G * * - Rewrite of AWSIGET csect, new AWSGTXT csect. * * - Force recfm=u when spanned records/blocks are encountered. * * Issue warnings when spanned and other than IEBCOPY load. * * * * * *********************************************************************** EJECT *********************************************************************** * * * Input Parameters * * ---------------- * * All input parameters are taken from control statements supplied by * * the dataset represented by the AWSCNTL dd statement. Statements * * consist of a major function to be performed (i.e. TAPEVOL, EXPORT, * * etc), and a series of keywords which supply values to that function.* * * * Control statement keywords may be continued to as many records as * * necessary. Continued statements are indicated by the last keyword * * argument suffixed with a comma and additional keywords supplied * * on the next record. Additional keywords must not begin in column * * one. * * * * Example: * * * * AWSVOL VOLSER=MYTAPE * * AWSPUT INDSN=SYS1.PROCLIB,OUTDSN=MY.SPECIAL.PROCLIB.D090802, * * UNLOAD=IEBCOPY * * * * * * * * AWSVOL Control Statement * * ------------------------- * * The AWSVOL control statement supplies characteristics of the * * virtual tape volume include volume serial number, compression * * techniques, and so forth. TAPEVOL must also be the first control * * statement specified. * * * * Keywords: VOLSER=(1 to 6 byte argument), * * OWNER=(1 to 10 byte argument placed into VOL1 owner), * * COMPRESS=0:1, (compress and IDRC control whether or not * * compression is to be used. IDRC and COMPRESS * * are durrently synomyms of each other). * * METHOD=1:2, (1 = gzip, 2=bzip2) * * LEVEL=1-9, (specifies the degree of compression required) * * IDRC=0:1, (currently a synonym of COMPRESS) * * CHUNKSIZE=nnnnn (specifies the size of the "chunk" to be * * compressed, should be avoided IMHO). * * * * If COMPRESS=0 then an AWS format is assumed. Note that compression * * related keywords will be implemented at a future date. * * * * Note COMPRESS, METHOD, LEVEL, IDRC, CHUNKSIZE have the same meaning * * as in the Hercules configuration. * * * * * * Example: * * * * AWSVOL VOLSER=MYTAPE,COMPRESS=1,METHOD=1,LEVEL=9,IDRC=1, * * CHUNKSIZE=65536,OWNER='AWSSL 1.9G' * * * * * *********************************************************************** EJECT *********************************************************************** * * * AWSGET Control Statement * * ------------------------ * * The AWSGET control statement will supply values necessary to * * retrieve a dataset FROM an AWS or HET virtual tape volume. * * * * keywords: INDSN=(up to 44 byte dsn of dataset stored inside of * * the AWS virtual tape) * * OUTDD=(ddname representing the dataset to receive data) * * FILENO=nnnnn (file number of the dataset inside of the * * AWS virtual tape, may be a standard label file * * number or absolute file number depending on the * * value of the SL= keyword) * * SL=YES:NO (specifies if standard labels are present, also * * impacts the meaning of the FILENO= keyword) * * * * Example: * * * * AWSGET INDSN=sys1.proclib,OUTDD=dd1,SL=YES * * * * * * * *********************************************************************** EJECT *********************************************************************** * * * AWSPUT Control Statement * * ------------------------ * * The AWSPUT control statement causes a dataset to be copied into the * * AWS or HET virtual tape file. Multiple EXPORT statements may be * * specified. A set of standard labels are produced as each statement * * is processed. * * * * If necessary the dataset is staged into a temporary dynamically * * allocated dataset prior to insertion into the virtual temp. * * * * Keywords: INDD=(statically allocated ddname representing the file * * to be copied and placed into the virtual tape file),* * INDSN=(dsname to be dynamically allocated and placed into * * the virtual tape file), * * OUTDSN=(44 byte dataset name to be placed into the labels * * which preceed and follow the file on virtual tape), * * TAPEDSN=(17 byte dataset name to be placed in label), * * UNLOAD=IEBCOPY:IDCAMS, (the utility called to stage the * * input dataset prior to insertion into the virtual * * tape), * * TYPE=EXPORT:REPRO (if UNLOAD=IDCAMS then TYPE specifies * * the method to be used to stage the dataset prior to * * to insertion into the virtual tape) * * * * The AWS or HET virtual tape OUTPUT file may specify any DCB * * attributes that are meaningful in the users environment. * * * * RECFM=V - Variable length output, lrecl and blksize as specified. * * Records are output in a format consistent with that * * produced by Brandon Hill's AWSUTIL (i.e. no aggregation * * of AWS structures within a single output record). * * * * RECFM=F - Fixed length output, lrecl and blksize as specified. * * Records are output in a format consistent with that * * produced by Sam Golob's VTT2* family of utilities * * (i.e. AWS structures are aggregated and "folded" at the * * specified lrecl). * * * * RECFM=U - Undefined length output, blksize as specified. Records * * are output in an aggregated BLKSIZE length block. * * (THIS IS THE PREFERRED METHOD WHEN THE VIRTUAL TAPE IS TO * * BE TRANSPORTED TO OTHER ENVIRONMENTS SUCH AS HERCULES). * * * * * * * * * *********************************************************************** EJECT *********************************************************************** * * * Implementation Conventions * * -------------------------- * * An effort was made to structure the code such that a nearly endless * * set of new features can be added without becoming unwieldly. For * * that reason functions tend to be implemented as small discrete * * CSECTS. * * * * Each CSECT name should begin with the string AWS to avoid name * * space collision with other code which may be statically linked in * * the future. It is recommended that all labels within an individual * * CSECT follow a name space convention unique to that CSECT. * * * * Each CSECT should contain an LTORG statement. This reduces the * * need for multiple base registers to establish addressability to * * large literal pools. * * * * To avoid subtle addressability related bugs, each CSECT should * * contain a 'DROP ,' statement to release all USINGS in effect. * * * * A register save area stack mechanism is provided to ease linkage * * between internal functions and to minimize contention for scarce * * register resource. All CSECTS should utilize the AWSENTRY and * * AWSEXIT macro instructions where possible. * * * * This code is reentrant and refreshable. All data areas which * * require modification should be placed in CSECT AWSDATA between * * labels DSDYNAM and DSBUFFER. If the data areas contain initialized * * data then they should be placed between labels DSBEGIN and DSBUFFER.* * Data areas located between labels DSDYNAM and DSBEGIN have storage * * allocated for them but are not initialized (to other than nulls). * * * * Dynamic storage ADCON relocation, etc, code should be placed into * * CSECT AWSINIT. * * * *********************************************************************** EJECT *********************************************************************** * * * Register Usage Conventions * * -------------------------- * * * * R14 - Linkage, contains the address at which instruction streaming * * should resume. May be used as an internal work register. * * * * R15 - Linkage, contains the address of the CSECT to be called. * * Upon return contains the return code from the called CSECT. * * May be used as an internal work register. * * * * R0 through R6 - Preserved by AWSENTRY and AWSEXIT. Available for * * whatever usage the programmer desires within the scope of * * the local CSECTs. * * * * R7 through R9 - Reserved for future unforeseen needs. Please avoid * * usage except in the most dire of circumstances. * * * * R10 - Common storage addressability. Set by AWSENTRY. * * * * R11 - Dynamic storage addressability. Set by AWSENTRY. * * * * R12 - Local CSECT base register. Set by AWSENTRY. * * * * R13 - Pointer to current savearea. Set to the next save area stack * * entry by AWSENTRY. * * * * * * * * * * * * * * * * * *********************************************************************** EJECT *********************************************************************** * Customizable Symbols * *********************************************************************** SPACE 1 GBLA &AWSDBUG debug switch &AWSDBUG SETA 0 1 = enable debugging support SPACE 1 STACKCT EQU 10 savearea stack entries BUFSIZE EQU 70000 max blksize + hdrs + aws cb + pad SPACE 1 *********************************************************************** * Register Equates (make registers visible in xref) * *********************************************************************** SPACE 1 R0 EQU 0 R1 EQU 1 R2 EQU 2 R3 EQU 3 R4 EQU 4 R5 EQU 5 R6 EQU 6 R7 EQU 7 R8 EQU 8 R9 EQU 9 R10 EQU 10 R11 EQU 11 R12 EQU 12 R13 EQU 13 R14 EQU 14 R15 EQU 15 TITLE 'AWSSL - macro definitions' *********************************************************************** * MACRO DEFINITIONS * *********************************************************************** EJECT MACRO &LBL AWSENTRY .********************************************************************** .* AWSENTRY - push caller's registers into provided savearea, obtain * .* a new savearea from the savearea stack, addressability. * .********************************************************************** GBLA &AWSDBUG debug switch LCLA &L,&I AIF ('&LBL' EQ '').A010 &LBL DS 0H .A010 ANOP &L SETA (K'&SYSECT+2+4)/2*2 offset to stm &I SETA K'&SYSECT B &L.(,R15) branch around eyecatcher DC AL1(&I) eyecatcher length DC C'&SYSECT' CSECT name STM R14,R12,12(R13) save caller's environment LR R12,R15 base register LA R15,72(,R13) next stack entry ST R15,8(,R13) forward linkage ST R13,4(,R15) backward linkage LR R13,R15 establish new current savearea USING &SYSECT,R12 addressability USING AWSDYNAM,R11 addressability USING AWSCOMST,R10 addressability AIF (&AWSDBUG EQ 0).MEND AIF ('&SYSECT' EQ 'AWSPRNT').MEND AIF ('&SYSECT' EQ 'AWSINIT').MEND AWSMSG 000I,'&SYSECT Entry' .MEND MEND EJECT MACRO &LBL AWSEXIT .********************************************************************** .* AWSEXIT - release savearea stack entry, pop user's environment, * .* return to caller. * .********************************************************************** GBLA &AWSDBUG debug switch AIF ('&LBL' EQ '').A010 &LBL DS 0H .A010 AIF (&AWSDBUG EQ 0).A020 AIF ('&SYSECT' EQ 'AWSPRNT').A020 AIF ('&SYSECT' EQ 'AWSTERM').A020 MVC DSMSG+1(7),=CL7'AWS000I' MVC DSMSG+19(14),=CL14'&SYSECT EXIT' MVC DSMSG+35(3),=CL3'RC:' CVD R15,DSDWORK convert to decimal MVC DSMSG+38(6),=X'402020202120' ED DSMSG+38(6),DSDWORK+5 make printable OI DSMSG+43,C'0' LR R2,R15 save return code AWSMSG , print exit message LR R15,R2 restore retern code .A020 ANOP L R13,4(,R13) restore savearea pointer LM R0,R12,20(R13) restore caller's registers L R14,12(,R13) restore savearea address LTR R15,R15 set condition code into psw BR R14 return to caller SPACE 1 MEND EJECT MACRO &LBL AWSMSG &ID,&TXT .********************************************************************** .* AWSMSG - output a message to the AWSPRINT log * .********************************************************************** GBLA &AWSDBUG debug switch LCLA &L1,&L2 LCLC &C AIF ('&ID' EQ '' AND '&TXT' EQ '').A040 AIF ('&ID' NE '').A010 MNOTE 8,'*** MSG CSECT ID OMITTED' .A010 AIF ('&TXT' NE '').A020 MNOTE 8,'*** MSG TEXT OMITTED' .A020 AIF ('&LBL' EQ '').A030 &LBL DS 0H .A030 ANOP &C SETC 'AWS&ID' &L1 SETA K'&C MVC DSMSG+1(&L1),=C'&C' &L2 SETA K'&TXT-2 MVC DSMSG+19(&L2),=C&TXT .A040 ANOP AWSCALL AWSPRNT print function MEND EJECT MACRO &LBL AWSDMP &ID,&L,&R,&T .********************************************************************** .* AWSDMP - hex dump register (and optionally 16 bytes of storage) * .* i.e. AWSDMP 00I,IGET900,R3 (dumps r3 and 16 bytes strg) * .* i.e. AWSDMP 00I,IGET100,R4,N (dumps r4 only) * .* * .* This macro is intended for debugging purposes only. * .********************************************************************** GBLA &AWSDBUG debug switch LCLA &L1,&L2 LCLC &C STM R14,R12,12(R13) LA R13,72(,R13) AIF ('&ID' NE '').A010 MNOTE 8,'*** MSG CSECT ID OMITTED' .A010 AIF ('&R' NE '').A020 MNOTE 8,'*** REGISTER OMITTED' .A020 AIF ('&LBL' EQ '').A030 &LBL DS 0H .A030 ANOP &C SETC 'AWS&ID' &L1 SETA K'&C MVC DSMSG+1(&L1),=C'&C' AIF ('&L' EQ '').A035 &L1 SETA K'&L+1 MVC DSMSG+10(&L1),=C'&L:' .A035 ANOP &L1 SETA K'&R MVC DSMSG+19(&L1),=C'&R' &L1 SETA 23 ST &R,DSFWORK register UNPK DSHEXWK(9),DSFWORK(5) unpack data TR DSHEXWK(8),CSHEXTR make printable MVC DSMSG+&L1.(8),DSHEXWK return code AIF ('&T' EQ 'N').A040 &L1 SETA &L1+12 UNPK DSHEXWK(9),0(5,&R) TR DSHEXWK(8),CSHEXTR MVC DSMSG+&L1.(8),DSHEXWK &L1 SETA &L1+9 UNPK DSHEXWK(9),4(5,&R) TR DSHEXWK(8),CSHEXTR MVC DSMSG+&L1.(8),DSHEXWK &L1 SETA &L1+9 UNPK DSHEXWK(9),8(5,&R) TR DSHEXWK(8),CSHEXTR MVC DSMSG+&L1.(8),DSHEXWK &L1 SETA &L1+9 UNPK DSHEXWK(9),12(5,&R) TR DSHEXWK(8),CSHEXTR MVC DSMSG+&L1.(8),DSHEXWK MVI DSMSG+72,C'*' MVC DSMSG+73(16),0(&R) MVI DSMSG+89,C'*' .A040 ANOP AWSCALL AWSPRNT print function SH R13,=H'72' LM R14,12,12(R13) MEND EJECT MACRO &LBL AWSCALL &FUN .********************************************************************** .* AWSCALL - Call a function * .********************************************************************** AIF ('&LBL' EQ '').A010 &LBL DS 0H .A010 ANOP AIF ('&FUN' NE 'AWSDYNE').A020 L R15,CSAWSDYE dynamic allocatione error handler AGO .A999 .A020 AIF ('&FUN' NE 'AWSEPUT').A030 L R15,CSAWSEPT put text to virtual tape AGO .A999 .A030 AIF ('&FUN' NE 'AWSMARK').A040 L R15,CSAWSMRK put tapemark to virtual tape AGO .A999 .A040 AIF ('&FUN' NE 'AWSPRNT').A050 L R15,CSAWSPRT write to log AGO .A999 .A050 AIF ('&FUN' NE 'AWSIGET').A900 L R15,CSAWSIGE read a logical aws block AGO .A999 .A900 ANOP L R15,=A(&FUN) function to be called .A999 ANOP BALR R14,R15 issue call MEND EJECT MACRO &LBL AWSSWAP .********************************************************************** .* AWSSWAP - swap byte orders, set sizes * .********************************************************************** AIF ('&LBL' EQ '').A010 &LBL DS 0H .A010 ANOP ICM R0,3,DSLSTSIZ reverse previous size byte order STCM R0,1,AWSLENP STCM R0,2,AWSLENP+1 ICM R0,3,AWSLENC size of current block STCM R0,3,DSLSTSIZ set new last size STCM R0,1,AWSLENC reverse current size byte order STCM R0,2,AWSLENC+1 MEND SPACE 1 MACRO &LBL AWSSWAPR .********************************************************************** .* AWSSWAPR - swap byte orders, no sizes * .********************************************************************** AIF ('&LBL' EQ '').A010 &LBL DS 0H .A010 ANOP ICM R0,3,AWSLENC size of current block STCM R0,1,AWSLENC reverse current size byte order STCM R0,2,AWSLENC+1 MEND SPACE 1 MACRO &LBL AWSDUMMY , Dummy function .********************************************************************** .* AWSDUMMY - dummy function, merely returns * .********************************************************************** &LBL CSECT , dummy function AWSENTRY , SLR R15,R15 zero return code AWSEXIT , DROP , MEND EJECT *********************************************************************** * System control block definitions (Assembler F forward referenced) * *********************************************************************** SPACE 1 PRINT OFF DCBD DSORG=PS IEFZB4D0 , IEFZB4D2 , IHAPSA , PSA IKJTCB , TCB TIOT DSECT , TIOT IEFTIOT1 , PRINT ON EJECT *********************************************************************** * AWSSL - Utility entry point * *********************************************************************** SPACE 1 AWSSL CSECT , module entry point SAVE (14,12),,'AWSSL &SYSDATE &SYSTIME' LR R12,R15 base register USING AWSSL,R12 addressability SPACE 1 GETMAIN R,LV=AWSDATAL+3*BUFSIZE Dynamic storage ST R13,4(,R1) backward linkage ST R1,8(,R13) forward linkage LR R13,R1 current savearea LR R11,R1 set dynamic storage location USING AWSDATA,R11 addressability ST R11,DSDATAP set pointer to awsdata origin LA R0,DSSTACK stack origin ST R0,DSSTACKP set stack origin pointer LA R11,AWSDYNAM-AWSDATA(,R11) position beyond stack USING AWSDYNAM,R11 addressability SPACE 1 L R10,=A(AWSCOMST) constant common data USING AWSCOMST,R10 addressability SPACE 1 AWSCALL AWSINIT initialization BNZ SSLXIT if not successful, branch SPACE 1 SSL010 DS 0H main processing loop AWSCALL AWSMAIN invoke verb handler BZ SSL010 continue until eof or error SPACE 1 SSLXIT DS 0H return to caller CH R15,=H'-4' eof from main? BNE *+6 no, branch SLR R15,R15 else force zero return code LR R2,R15 save rc for now AWSCALL AWSTERM clean up for termination SPACE 1 L R3,4(,R13) Callers savearea L R4,DSDATAP dynamic storage origin FREEMAIN R,LV=AWSDATAL+3*BUFSIZE,A=(R4) release storage SPACE 1 LR R15,R2 restore return code LR R13,R3 restore savearea pointer RETURN (14,12),RC=(15) return to caller SPACE 1 LTORG , DROP TITLE 'AWSSL - Initialization' *********************************************************************** * AWSINIT - initialization, relocation, open files * * msgs AWS01n * *********************************************************************** SPACE 1 AWSINIT CSECT , initialization logic AWSENTRY , csect entry SPACE 1 L R2,=A(AWSRELOC) start of relocatable storage L R3,=A(DSENDL) length of relocateable storage LR R1,R3 origin length = destination LA R0,AWSRELOC-AWSDYNAM(,R11) target of move MVCL R0,R2 copy storage model into dynamic area SPACE 1 LA R0,INFMJFCB jfcb work area STCM R0,7,DSJFCBL+1 LA R0,DSJFCBL rdjfcb exist list location STCM R0,7,AWSUT1+(DCBEXLSA-IHADCB) STCM R0,7,AWSUT2+(DCBEXLSA-IHADCB) STCM R0,7,AWSUT3+(DCBEXLSA-IHADCB) SPACE 1 LA R0,DSBUFFER Buffer location ST R0,DSBUFTP Set location of next text SPACE 1 LA R0,DSARB input dataset request block STCM R0,7,DSARBP+1 LA R0,DSADDNM input ddname ST R0,DSATXTP LA R0,DSADSNM input dsn ST R0,DSATXTP+4 LA R0,DSASTATS input stats ST R0,DSATXTP+8 LA R0,DSADISP input disposition STCM R0,7,DSATXTP+13 LA R1,DSARB input rb location USING S99RB,R1 addressability LA R0,DSATXTP input text pointer ST R0,S99TXTPP MVI S99RBLN,S99RBEND-S99RB length of rb MVI S99VERB,S99VRBAL allocation request MVI S99FLAG1,S99NOCNV+S99NOMNT do not issue mounts DROP R1 SPACE 1 LA R0,DSTARB temp work dataset request block STCM R0,7,DSTARBP+1 LA R0,DSTADDNM temp work ddname ST R0,DSTATXTP LA R0,DSTAUNIT temp work unit ST R0,DSTATXTP+4 LA R0,DSTASPCU temp work space primary units ST R0,DSTATXTP+8 LA R0,DSTASPCP temp work space primary qty ST R0,DSTATXTP+12 LA R0,DSTASPCS temp work space secondary qty STCM R0,7,DSTATXTP+17 LA R1,DSTARB temp work rb location USING S99RB,R1 addressability LA R0,DSTATXTP input text pointer ST R0,S99TXTPP MVI S99RBLN,S99RBEND-S99RB length of rb MVI S99VERB,S99VRBAL allocation request MVI S99FLAG1,S99NOCNV+S99NOMNT do not issue mounts DROP R1 SPACE 1 LA R0,DSSARB sysin dataset request block STCM R0,7,DSSARBP+1 LA R0,DSSADDNM sysin ddname ST R0,DSSATXTP LA R0,DSSAUNIT sysin unit ST R0,DSSATXTP+4 LA R0,DSSASPCU sysin space primary units ST R0,DSSATXTP+8 LA R0,DSSASPCP sysin space primary qty ST R0,DSSATXTP+12 LA R0,DSSASPCS sysin space secondary qty STCM R0,7,DSSATXTP+17 LA R1,DSSARB sysin rb location USING S99RB,R1 addressability LA R0,DSSATXTP input text pointer ST R0,S99TXTPP MVI S99RBLN,S99RBEND-S99RB length of rb MVI S99VERB,S99VRBAL allocation request MVI S99FLAG1,S99NOCNV+S99NOMNT do not issue mounts DROP R1 SPACE 1 LA R0,DSPARB sysprint dataset request block STCM R0,7,DSPARBP+1 LA R0,DSPADDNM sysprint ddname ST R0,DSPATXTP LA R0,DSPADUMY dummy dataset STCM R0,7,DSPATXTP+5 LA R1,DSPARB sysin rb location USING S99RB,R1 addressability LA R0,DSPATXTP input text pointer ST R0,S99TXTPP MVI S99RBLN,S99RBEND-S99RB length of rb MVI S99VERB,S99VRBAL allocation request MVI S99FLAG1,S99NOCNV+S99NOMNT do not issue mounts SPACE 1 LA R0,DSURB unallocation request block STCM R0,7,DSURBP+1 LA R0,DSUDDNM ddname STCM R0,7,DSUTXTP+1 LA R1,DSURB unallocation rb location USING S99RB,R1 addressability LA R0,DSUTXTP input text pointer ST R0,S99TXTPP MVI S99RBLN,S99RBEND-S99RB length of rb MVI S99VERB,S99VRBUN unallocation request MVI S99FLAG1,S99NOCNV+S99NOMNT do not issue mounts DROP R1 SPACE 1 INIT010 DS 0H prepare AWSPRINT OPEN (AWSPRINT,(OUTPUT)),MF=(E,DSOPENL) open awsprint TM AWSPRINT+(DCBOFLGS-IHADCB),DCBOFOPN open successful? BO INIT020 yes, branch WTO 'AWS010E AWSPRINT OPEN FAILED' LA R15,12 sysprint open failed B INITXIT exit with error SPACE 1 INIT020 DS 0H prepare AWSOUT AIF (&AWSDBUG EQ 0).INIT010 AWSMSG 011I,'AWSINIT Entry' .INIT010 ANOP OPEN (AWSCNTL,(INPUT)),MF=(E,DSOPENL) open awscntl TM AWSCNTL+(DCBOFLGS-IHADCB),DCBOFOPN open successful? BO INIT030 yes, branch AWSMSG 012E,'AWSCNTL open failed' LA R15,12 16=awscntl open failed B INITXIT exit with error SPACE 1 INIT030 DS 0H AWSCALL AWSJOBNM Capture job and step name info SPACE 1 INIT040 DS 0H SPACE 1 INITXIT DS 0H function exit AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSMAIN - Process next control statement' *********************************************************************** * AWSMAIN - Verb dispatcher * * msgs AWS02n * *********************************************************************** SPACE 1 AWSMAIN CSECT , Process next control statement AWSENTRY , SPACE 1 LA R0,MAINEOF AWSCNTL eof STCM R0,7,AWSCNTL+(DCBEODA-IHADCB) place into dcb SPACE 1 MAIN010 DS 0H scan for dataset verb GET AWSCNTL retrieve a cntl record LR R3,R1 record location MVC DSMSG+1(17),=C'AWS020I AWSCNTL:' MVC DSMSG+19(80),0(R3) set statement into message buffer AWSMSG , print function CLI 0(R1),C'*' comment? BE MAIN010 yes, branch CLC 0(80,R3),CSBLNKS blank line? BE MAIN010 yes, branch CLC =C'AWSVOL ',0(R3) tapevol verb? BE MAIN020 yes, branch CLC =C'AWSGET ',0(R3) import verb? BE MAIN030 yes, branch CLC =C'AWSPUT ',0(R3) export verb? BE MAIN040 yes, branch AWSMSG 021E,'Statement is not recognized' LA R15,8 rc=4, invalid statement B MAINXIT return to caller SPACE 1 MAIN020 DS 0H tapevol verb AWSCALL AWSTVOL invoke tapevol B MAINXIT SPACE 1 MAIN030 DS 0H import verb TM DSFLAGS2,DSFEXPRT export invoked previously? BO MAIN050 yes, branch OI DSFLAGS2,DSFIMPRT indicate import invoked AWSCALL AWSIMPRT invoke import B MAINXIT SPACE 1 MAIN040 DS 0H export verb TM DSFLAGS2,DSFIMPRT import invoked previously? BO MAIN060 yes, branch OI DSFLAGS2,DSFEXPRT indicate import invoked AWSCALL AWSEXPRT invoke export B MAINXIT SPACE 1 MAIN050 DS 0H import invoked after export AWSMSG 022E,'AWSGET is mutually exclusive with AWSPUT' LA R15,8 B MAINXIT SPACE 1 MAIN060 DS 0H export invoked after import AWSMSG 023E,'AWSPUT is mutually exclusive with AWSGET' LA R15,8 B MAINXIT SPACE 1 MAINEOF DS 0H AWSCNTL reached eof MVC DSMSG+10(8),=C'AWSCNTL:' AWSMSG 024I,'End of AWSCNTL input detected' L R15,=F'-4' indicate eof SPACE 1 MAINXIT DS 0H function exit AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSTERM - Termination processing' *********************************************************************** * AWSTERM - Termination, close files and release resources * * msg AWS03n * *********************************************************************** SPACE 1 AWSTERM CSECT , Termination processing AWSENTRY , SPACE 1 TM DSFLAGS,DSFOPNEX AWSFILE open for export? BZ TERM010 no, branch OI DSFLAGS,DSFFLUSH flush last buffer (just in case) AWSCALL AWSMARK write final tape mark SPACE 1 TERM010 DS 0H check stack integrity L R1,DSSTACKP stack origin LA R0,STACKCT max entries in stack SLR R2,R2 clear counter TERM020 DS 0H calculate max stack depth CLC CSF0,4(R1) entry ever been used? BE TERM030 no, branch LA R2,1(,R2) increment count LA R1,18*4(,R1) position at next stack entry BCT R0,TERM020 continue until exhausted AWSMSG 030W,'WARNING! Stack overflow detected, contact rhp@dra* per.net' B TERM040 SPACE 1 TERM030 DS 0H write max stack depth used AIF (&AWSDBUG EQ 0).TERM030 CVD R2,DSDWORK convert to packed MVC DSXL16(4),=X'40202120' edit mask ED DSXL16(4),DSDWORK+6 OI DSXL16+3,C'0' make printable MVC DSMSG+1(7),=C'AWS031I' MVC DSMSG+19(20),=C'Maximum stack depth:' MVC DSMSG+39(2),DSXL16+2 set count into message AWSMSG , write the message .TERM030 ANOP SPACE 1 TERM040 DS 0H unallocate as needed AWSCALL AWSUNALC dynamic unallocation LR R3,R15 save return code SPACE 1 TM AWSCNTL+(DCBOFLGS-IHADCB),DCBOFOPN open? BZ TERM050 no, branch CLOSE AWSCNTL,MF=(E,DSCLOSEL) close it FREEPOOL AWSCNTL release buffers SPACE 1 TERM050 DS 0H cleanup AWSFILE TM AWSFILE+(DCBOFLGS-IHADCB),DCBOFOPN open? BZ TERM060 no, branch CLOSE AWSFILE,MF=(E,DSCLOSEL) close it FREEPOOL AWSFILE release buffers SPACE 1 TERM060 DS 0H cleanup AWSPRINT TM AWSPRINT+(DCBOFLGS-IHADCB),DCBOFOPN open? BZ TERM070 no, branch CLOSE AWSPRINT,MF=(E,DSCLOSEL) close it FREEPOOL AWSPRINT release buffers SPACE 1 TERM070 DS 0H cleanup SYSIN TM SYSIN+(DCBOFLGS-IHADCB),DCBOFOPN open? BZ TERM080 no, branch CLOSE SYSIN,MF=(E,DSCLOSEL) close it FREEPOOL SYSIN release buffers SPACE 1 TERM080 DS 0H cleanup AWSUT2 TM AWSUT2+(DCBOFLGS-IHADCB),DCBOFOPN open? BZ TERM090 no, branch CLOSE AWSUT2,MF=(E,DSCLOSEL) close it FREEPOOL AWSUT2 release buffers SPACE 1 TERM090 DS 0H cleanup AWSUT2 TM AWSUT3+(DCBOFLGS-IHADCB),DCBOFOPN open? BZ TERM100 no, branch CLOSE AWSUT3,MF=(E,DSCLOSEL) close it FREEPOOL AWSUT3 release buffers SPACE 1 TERM100 DS 0H LR R15,R3 return code from unalloc SPACE 1 TERMXIT DS 0H exit AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSTVOL - AWSVOL verb handler' *********************************************************************** * AWSTVOL - AWSVOL verb handler * * msg AWS04n * *********************************************************************** SPACE 1 AWSTVOL CSECT , TAPEVOL verb handler AWSENTRY , SPACE 1 AWSCALL AWSTVPAR invoke keyword parser SPACE 1 AWSMSG , print blank line AWSMSG , print blank line SPACE 1 AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSIMPRT - Import verb handler' *********************************************************************** * AWSIMPRT - AWSGET verb handler * * msg AWS05n * *********************************************************************** SPACE 1 AWSIMPRT CSECT , Import verb handler AWSENTRY , SPACE 1 LR R3,R1 future reference TM AWSUT2+(DCBOFLGS-IHADCB),DCBOFOPN AWSUT2 open? BZ IMPRT010 no, branch CLOSE AWSUT2,MF=(E,DSCLOSEL) close awsfile FREEPOOL AWSUT2 release buffers SPACE 1 IMPRT010 DS 0H prepare to open NI DSFLAGS,255-DSFOPNEX clear open for export (in case) SPACE 1 XC DSBUFEND,DSBUFEND indicate no blocks read XC DSBUFTP,DSBUFTP LA R2,AWSUT2 dcb location USING IHADCB,R2 addressability MVC DCBDDNAM,=CL8'AWSFILE' set ddname XC DCBBLKSI,DCBBLKSI clear blocksize XC DCBLRECL,DCBLRECL clear lrecl OPEN (AWSUT2,(INPUT)),MF=(E,DSOPENL) open awsfile TM DCBOFLGS,DCBOFOPN open successful? BO IMPRT020 yes, branch AWSMSG 050E,'AWSFILE open for AWSGET failed' LA R15,8 awsout open failed B IMPRTXIT exit with error SPACE 1 IMPRT020 DS 0H import TM AWSFILE+(DCBOFLGS-IHADCB),DCBOFOPN file open? BZ IMPRT030 no, branch CLOSE AWSFILE,MF=(E,DSCLOSEL) else close it FREEPOOL AWSFILE SPACE 1 IMPRT030 DS 0H prepare to import SLR R0,R0 clear register ICM R0,3,DCBLRECL get lrecl BZ IMPRT040 if zero, branch CH R0,=H'16' at least 16 bytes? BNL IMPRT050 yes, branch AWSMSG 051E,'Input lrecl must be at least 16 bytes' LA R15,8 B IMPRTXIT SPACE 1 IMPRT040 DS 0H check blksize ICM R0,3,DCBBLKSI load blksize CH R0,=H'16' at least 16 bytes? BNL IMPRT050 yes, branch AWSMSG 052E,'Input blksize must be at least 16 bytes' LA R15,8 B IMPRTXIT DROP R2 SPACE 1 IMPRT050 DS 0H SLR R0,R0 clear register ST R0,DSGTXTP clear pointer STH R0,DSGTXTL clear length RDJFCB AWSUT2,MF=(E,DSRDJFCB) read the jfcb SPACE 1 AWSMSG , blank line MVC DSMSG+1(7),=C'AWS053I' MVC DSMSG+19(31),=C'Virtual tape dataset name :' MVC DSMSG+51(44),JFCBDSNM AWSMSG , SPACE 1 MVC DSRECFM,CSBLNKS clear default recfm SLR R0,R0 clear register STH R0,DSLRECL clear lrecl STH R0,DSBLKSIZ clear blksize SPACE 1 LR R1,R3 current control statement AWSCALL AWSIMPAR parse import keywords BNZ IMPRTXIT AWSCALL AWSSKPTF position to file BNZ IMPRTXIT AWSCALL AWSIMLBL process header labels BNZ IMPRTXIT AWSCALL AWSICOPY copy data into MVS dataset BNZ IMPRTXIT AWSCALL AWSIMTLR process trailer labels SPACE 1 IMPRTXIT DS 0H EXIT AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSEXPRT - Export verb handler' *********************************************************************** * AWSEXPRT - AWSPUT verb handler * * msg AWS06n * *********************************************************************** SPACE 1 AWSEXPRT CSECT , Export verb handler AWSENTRY , SPACE 1 LR R2,R1 future reference TM AWSFILE+(DCBOFLGS-IHADCB),DCBOFOPN already open? BO EXPRT010 yes, branch CLOSE AWSFILE,MF=(E,DSCLOSEL) close file FREEPOOL AWSFILE SPACE 1 OPEN (AWSFILE,(OUTPUT)),MF=(E,DSOPENL) open awsfile TM AWSFILE+(DCBOFLGS-IHADCB),DCBOFOPN open successful? BO EXPRT010 yes, branch AWSMSG 060E,'AWSFILE open for EXPORT failed' LA R15,8 awsout open failed B EXPRTXIT exit with error SPACE 1 EXPRT010 DS 0H prepare awscntl TM AWSFILE+(DCBRECFM-IHADCB),DCBRECU recfm=u? BO EXPRT020 yes, branch TM AWSFILE+(DCBRECFM-IHADCB),DCBRECV recfm=v? BZ EXPRT020 no, branch OI DSFLAGS,DSFRECV indicate variable length output SPACE 1 EXPRT020 DS 0H export main line OI DSFLAGS,DSFOPNEX indicate open for export LR R1,R2 current control statement AWSCALL AWSEXPAR parse export keywords BNZ EXPRTXIT AWSCALL AWSJFDSN extract JFCB dsname BNZ EXPRTXIT AWSCALL AWSTPDSN set 17 byte tape dsname BNZ EXPRTXIT AWSCALL AWSUNLD unload (stage) file if necessary BNZ EXPRTXIT AWSCALL AWSECOPY copy the file into AWS structure BNZ EXPRTXIT AWSCALL AWSMARK write tape mark BNZ EXPRTXIT AWSCALL AWSTLR write trailer labels BNZ EXPRTXIT AWSCALL AWSUNALC unallocate files SPACE 1 EXPRTXIT DS 0H return to caller AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSTVPAR - Parse AWSVOL verb parameters' *********************************************************************** * AWSTVPAR - Parse AWSVOL verb parameters * * msg AWS07n * * * * On entry, r1 = cntl card image containing extract verb. * * On exit, appropriate data areas updated. * *********************************************************************** SPACE 1 AWSTVPAR CSECT , Parse extract verb parameters AWSENTRY , SPACE 1 MVC DSTVOL,CSBLNKS clear volser MVI DSHETCMP,C' ' clear MVI DSHETMTH,C' ' MVI DSHETLVL,C' ' MVI DSHETIDR,C' ' MVC DSHETCSZ,CSBLNKS MVC DSOWNER,=CL10'AWSSL 1.9G' SPACE 1 LR R3,R1 cntl statement image LR R5,R1 current location in scan LA R1,7 point beyond verb SPACE 1 TVPAR010 DS 0H locate a keyword ALR R5,R1 end of previous keyword if any LA R1,80(,R3) end of statement SLR R1,R3 length remaining BCTR R1,0 machine relative EX R1,TVPAREX1 locate keyword BZ TVPARRC0 if no keyword found, exit LR R4,R1 keyword suffix location LA R5,1(,R1) argument origin TVPAR020 DS 0H locate origin of keyword BCTR R4,0 backup one byte CLI 0(R4),C',' comma delimiter? BE TVPAR030 yes, branch CLI 0(R4),C' ' space delimiter? BE TVPAR030 yes, branch CR R4,R3 origin of statement reached? BH TVPAR020 no, continue search AWSMSG 070E,'TAPEVOL parameter syntax error' LA R15,8 export parameter syntax error B TVPARXIT return to caller SPACE 1 TVPAR030 DS 0H dispatch keyword handler LA R4,1(,R4) keyword origin CLC =C'VOLSER=',0(R4) volser= keyword? BE TVPAR100 yes, branch CLC =C'COMPRESS=',0(r4) COMPRESS= keyword? BE TVPAR110 yes, branch CLC =C'METHOD=',0(r4) METHOD= keyword? BE TVPAR120 yes, branch CLC =C'LEVEL=',0(R4) LEVEL= keyword? BE TVPAR130 yes, branch CLC =C'IDRC=',0(r4) IDRC= keyword? BE TVPAR140 yes, branch CLC =C'CHUNKSIZE=',0(r4) CHUNKSIZE= keyword? BE TVPAR150 yes, branch CLC =C'OWNER=',0(R4) OWNER= keyword? BE TVPAR160 yes, branch MVC DSMSG+1(7),=C'AWS071E' MVC DSMSG+19(29),=C'TAPEVOL KEYWORD UNRECOGNIZED:' LR R1,R5 argument origin SLR R1,R4 length of argument BCTR R1,0 machine relative EX R1,TVPAREX2 set keyword into message AWSMSG , write the message LA R15,8 export keyword unrecognized B TVPARXIT return to caller SPACE 1 TVPAR100 DS 0H tapevol= keyword handler MVC DSTVOL,CSBLNKS clear volser LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,TVPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ TVPAR930 if null, branch CH R1,=Y(L'DSTVOL) greater than maximum length? BL *+8 no, branch LA R1,L'DSTVOL else force to max length BCTR R1,0 machine relative EX R1,TVPAREX4 capture dsn B TVPAR900 SPACE 1 TVPAR110 DS 0H HET= keyword handler MVI DSHETCMP,C' ' clear LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,TVPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ TVPAR930 if null, branch CH R1,=Y(L'DSHETCMP) greater than maximum length? BL *+8 no, branch LA R1,L'DSHETCMP else force to max length BCTR R1,0 machine relative EX R1,TVPAREX5 capture argument AWSMSG 072W,'Warning, COMPRESS keyword is not yet implemented,* ignored' B TVPAR900 SPACE 1 TVPAR120 DS 0H METHOD= keyword handler MVI DSHETMTH,C' ' clear HETLVL LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,TVPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ TVPAR930 if null, branch CH R1,=Y(L'DSHETMTH) greater than maximum length? BL *+8 no, branch LA R1,L'DSHETMTH else force to max length BCTR R1,0 machine relative EX R1,TVPAREX6 capture argument AWSMSG 073W,'Warning, METHOD keyword is not yet implemented, i* gnored' B TVPAR900 SPACE 1 TVPAR130 DS 0H LEVEL= keyword handler MVI DSHETLVL,C' ' clear HETLVL LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,TVPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ TVPAR930 if null, branch CH R1,=Y(L'DSHETLVL) greater than maximum length? BL *+8 no, branch LA R1,L'DSHETLVL else force to max length BCTR R1,0 machine relative EX R1,TVPAREX7 capture argument AWSMSG 074W,'Warning, LEVEL keyword is not yet implemented, ig* nored' B TVPAR900 SPACE 1 TVPAR140 DS 0H IDRC= keyword handler MVI DSHETIDR,C' ' clear LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,TVPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ TVPAR930 if null, branch CH R1,=Y(L'DSHETIDR) greater than maximum length? BL *+8 no, branch LA R1,L'DSHETIDR else force to max length BCTR R1,0 machine relative EX R1,TVPAREX8 capture argument AWSMSG 075W,'Warning, IDRC keyword is not yet implemented, ign* ored' B TVPAR900 SPACE 1 TVPAR150 DS 0H CHUNKSIZE= keyword handler MVC DSHETCSZ,CSBLNKS clear LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,TVPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ TVPAR930 if null, branch CH R1,=Y(L'DSHETCSZ) greater than max length? BL *+8 no, branch LA R1,L'DSHETCSZ else force to max length BCTR R1,0 machine relative EX R1,TVPAREX9 capture argument AWSMSG 076W,'Warning, CHUNKSIZE keyword is not yet implemented* , ignored' B TVPAR900 SPACE 1 TVPAR160 DS 0H OWNER= keyword handler MVC DSOWNER,CSBLNKS LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining TRT 0(1,R5),CSPARST3 quoted string? BZ TVPAR162 no, branch LA R5,1(,R5) position at string origin EX R1,TVPAREXA locate trailing quote B TVPAR164 TVPAR162 DS 0H handle non quoted string EX R1,TVPAREX3 locate delimiter TVPAR164 DS 0H LR R6,R1 delimiter location SR R1,R5 length of argument BZ TVPAR930 if null, branch CH R1,=Y(L'DSOWNER) greater than max length? BL *+8 no, branch LA R1,L'DSOWNER else force to max length BCTR R1,0 machine relative EX R1,TVPAREXB capture argument * B TVPAR900 SPACE 1 TVPAR900 DS 0H handle continuation if present CLC =C', ',0(R6) continuation to next card? BNE TVPAR010 no, continue this statement, branch SPACE 1 TVPAR910 DS 0H retrieve continued statement GET AWSCNTL retrieve a cntl record LR R3,R1 record location MVC DSMSG+1(7),=C'AWS077I' MVC DSMSG+19(80),0(R3) set statement into message buffer AWSMSG , print function CLI 0(R1),C'*' comment? BE TVPAR910 yes, branch CLC 0(80,R3),CSBLNKS blank line? BE TVPAR910 yes, branch CLI 0(R3),C' ' first byte non blank? BE TVPAR920 yes, branch AWSMSG 078E,'Continuation statement error, 1st byte not blank' LA R15,8 continuation error B TVPARXIT return to caller SPACE 1 TVPAR920 DS 0H setup for continue scan LA R5,1(,R1) current location in scan SLR R1,R1 offset to argument B TVPAR010 continue SPACE 1 TVPAR930 DS 0H keyword with null argument found LA R1,1 position beyond delimiter B TVPAR900 continue SPACE 1 TVPARRC0 DS 0H exit with rc = 0 SLR R15,R15 clear register SPACE 1 TVPARXIT DS 0H function exit AWSEXIT , SPACE 1 TVPAREX1 TRT 0(0,R5),CSPARST1 *** execute only *** TVPAREX2 MVC DSMSG+49(0),0(R4) *** execute only *** TVPAREX3 TRT 0(0,R5),CSPARST2 *** execute only *** TVPAREX4 MVC DSTVOL(0),0(R5) *** execute only *** TVPAREX5 MVC DSHETCMP(0),0(R5) *** execute only *** TVPAREX6 MVC DSHETMTH(0),0(R5) *** execute only *** TVPAREX7 MVC DSHETLVL(0),0(R5) *** execute only *** TVPAREX8 MVC DSHETIDR(0),0(R5) *** execute only *** TVPAREX9 MVC DSHETCSZ(0),0(R5) *** execute only *** TVPAREXA TRT 0(0,R5),CSPARST3 *** execute only *** TVPAREXB MVC DSOWNER(0),0(R5) *** execute only *** SPACE 1 LTORG , DROP , TITLE 'AWSIMPAR - Parse IMPORT verb parameters' *********************************************************************** * AWSIMPAR - Parse IMPORT verb parameters * * msg AWS08n * * * * On entry, r1 = cntl card image containing extract verb. * * On exit, appropriate data areas updated. * *********************************************************************** SPACE 1 AWSIMPAR CSECT , Parse IMPORT verb parameters AWSENTRY , SPACE 1 MVC DSOUTDD,CSBLNKS clear MVC DSINDSN,CSBLNKS MVC DSINFLNC,CSBLNKS MVC DSINFLNO,=H'1' MVI DSUSESL,C' ' MVC DSLODPGM,CSBLNKS SPACE 1 LR R3,R1 cntl statement image LR R5,R1 current location in scan LA R6,6(,R5) point beyond verb SPACE 1 IMPAR010 DS 0H locate a keyword LA R5,1(,R6) end of previous keyword if any LA R1,80(,R3) end of statement SLR R1,R3 length remaining BCTR R1,0 machine relative EX R1,IMPAREX1 locate keyword BZ IMPAR940 if no keyword found, exit LR R4,R1 keyword suffix location LA R5,1(,R1) argument origin IMPAR020 DS 0H locate origin of keyword BCTR R4,0 backup one byte CLI 0(R4),C',' comma delimiter? BE IMPAR030 yes, branch CLI 0(R4),C' ' space delimiter? BE IMPAR030 yes, branch CR R4,R3 origin of statement reached? BH IMPAR020 no, continue search AWSMSG 080E,'AWSGET parameter syntax error' LA R15,8 import parameter syntax error B IMPARXIT return to caller SPACE 1 IMPAR030 DS 0H dispatch keyword handler LA R4,1(,R4) keyword origin CLC =C'OUTDD=',0(R4) OUTDD= keyword? BE IMPAR100 yes, branch CLC =C'INDSN=',0(R4) INDSN= keyword? BE IMPAR110 yes, branch CLC =C'FILENO=',0(R4) FILENO= keyword? BE IMPAR120 yes, branch CLC =C'SL=',0(R4) SL= keyword? BE IMPAR140 yes, branch CLC =C'LOAD=',0(R4) LOAD= keyword? BE IMPAR150 yes, branch MVC DSMSG+1(7),=C'AWS081E' MVC DSMSG+19(29),=C'AWSGET keyword unrecognized:' LR R1,R5 argument origin SLR R1,R4 length of argument BCTR R1,0 machine relative EX R1,IMPAREX2 set keyword into message AWSMSG , write the message LA R15,8 import keyword unrecognized B IMPARXIT return to caller SPACE 1 IMPAR100 DS 0H outdd= keyword handler MVC DSOUTDD,CSBLNKS clear volser LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,IMPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ IMPAR930 if null, branch CH R1,=Y(L'DSOUTDD) greater than maximum length? BL *+8 no, branch LA R1,L'DSOUTDD else force to max length BCTR R1,0 machine relative EX R1,IMPAREX4 capture B IMPAR900 SPACE 1 IMPAR110 DS 0H indsn= keyword handler MVC DSINDSN,CSBLNKS clear LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,IMPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ IMPAR930 if null, branch CH R1,=Y(L'DSINDSN) greater than maximum length? BL *+8 no, branch LA R1,L'DSINDSN else force to max length BCTR R1,0 machine relative EX R1,IMPAREX5 capture argument B IMPAR900 SPACE 1 IMPAR120 DS 0H fileno= keyword handler MVC DSINFLNC,CSBLNKS clear MVC DSINFLNO,=H'1' default LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,IMPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ IMPAR930 if null, branch CH R1,=Y(L'DSINFLNC) greater than maximum length? BL *+8 no, branch LA R1,L'DSINFLNC else force to max length BCTR R1,0 machine relative LR R14,R1 save for future reference EX R1,IMPAREX6 numeric? BZ IMPAR130 yes, branch AWSMSG 082E,'FILENO= Argument is not numeric' LA R15,8 return code B IMPARXIT IMPAR130 DS 0H EX R14,IMPAREX7 pack fileno character argument CVB R0,DSDWORK convert to binary STH R0,DSINFLNO ... AND SAVE B IMPAR900 SPACE 1 IMPAR140 DS 0H SL= keyword handler MVI DSUSESL,C' ' clear LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,IMPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ IMPAR930 if null, branch CH R1,=Y(L'DSUSESL) greater than maximum length? BL *+8 no, branch LA R1,L'DSUSESL else force to max length BCTR R1,0 machine relative EX R1,IMPAREX8 capture argument SPACE 1 CLI DSUSESL,C' ' default? BE IMPAR900 yes, branch CLI DSUSESL,C'N' sl=no? BE IMPAR900 yes, branch CLI DSUSESL,C'Y' sl=yes? BE IMPAR900 yes, branch AWSMSG 083E,'SL= Argument is invalid' LA R15,8 B IMPARXIT SPACE 1 IMPAR150 DS 0H MVC DSLODPGM,CSBLNKS clear LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,IMPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ IMPAR930 if null, branch CH R1,=Y(L'DSLODPGM) greater than maximum length? BL *+8 no, branch LA R1,L'DSLODPGM else force to max length BCTR R1,0 machine relative EX R1,IMPAREX9 capture argument * B IMPAR900 SPACE 1 IMPAR900 DS 0H handle continuation if present CLC =C', ',0(R6) continuation to next card? BNE IMPAR010 no, continue this statement, branch SPACE 1 IMPAR910 DS 0H retrieve continued statement GET AWSCNTL retrieve a cntl record LR R3,R1 record location MVC DSMSG+1(7),=C'AWS084I' MVC DSMSG+19(80),0(R3) set statement into message buffer AWSMSG , print function CLI 0(R1),C'*' comment? BE IMPAR910 yes, branch CLC 0(80,R3),CSBLNKS blank line? BE IMPAR910 yes, branch CLI 0(R3),C' ' first byte non blank? BE IMPAR920 yes, branch AWSMSG 085E,'Continuation statement error, 1st byte not blank' LA R15,8 continuation error B IMPARXIT return to caller SPACE 1 IMPAR920 DS 0H setup for continue scan LA R5,1(,R1) current location in scan SLR R1,R1 offset to argument B IMPAR010 continue SPACE 1 IMPAR930 DS 0H keyword with null argument found LA R1,1 position beyond delimiter B IMPAR900 continue SPACE 1 IMPAR940 DS 0H exit with rc = 0 CLI DSOUTDD,C' ' output ddname specified? BH IMPAR950 yes, branch AWSMSG 086E,'AWSGET requires that OUTDD= be specified' LA R15,8 B IMPARXIT SPACE 1 IMPAR950 DS 0H normal return SLR R15,R15 clear register SPACE 1 IMPARXIT DS 0H function exit AWSEXIT , SPACE 1 IMPAREX1 TRT 0(0,R5),CSPARST1 *** execute only *** IMPAREX2 MVC DSMSG+49(0),0(R4) *** execute only *** IMPAREX3 TRT 0(0,R4),CSPARST2 *** execute only *** IMPAREX4 MVC DSOUTDD(0),0(R5) *** execute only *** IMPAREX5 MVC DSINDSN(0),0(R5) *** execute only *** IMPAREX6 TRT 0(0,R5),CSNUMTRT *** execute only *** IMPAREX7 PACK DSDWORK,0(0,R5) *** execute only *** IMPAREX8 MVC DSUSESL(0),0(R5) *** execute only *** IMPAREX9 MVC DSLODPGM(0),0(R5) *** execute only *** SPACE 1 LTORG , DROP , TITLE 'AWSEXPAR - Parse extract verb parameters' *********************************************************************** * AWSEXPAR - Parse extract verb parameters * * msg AWS09n * * * * On entry, r1 = cntl card image containing extract verb. * * On Exit, appropriate data areas updated. * *********************************************************************** SPACE 1 AWSEXPAR CSECT , Parse extract verb parameters AWSENTRY , SPACE 1 MVC DSINDSN,CSBLNKS clear input dsn MVC DSOUTDSN,CSBLNKS clear output dsn MVC DSTDSN,CSBLNKS clear tape dsn MVC DSINDD,CSBLNKS clear input dd name MVC DSUNLPGM,CSBLNKS clear unload program MVC DSUNLTYP,CSBLNKS clear unload type MVI DSUSESL,C' ' clear use standard labels flag SPACE 1 LR R3,R1 cntl statement image LR R5,R1 current location in scan LA R1,7 point beyond verb SPACE 1 EXPAR010 DS 0H locate a keyword ALR R5,R1 end of previous keyword if any LA R1,80(,R3) end of statement SLR R1,R3 length remaining BCTR R1,0 machine relative EX R1,EXPAREX1 locate keyword BZ EXPARRC0 if no keyword found, exit LR R4,R1 keyword suffix location LA R5,1(,R1) argument origin EXPAR020 DS 0H locate origin of keyword BCTR R4,0 backup one byte CLI 0(R4),C',' comma delimiter? BE EXPAR030 yes, branch CLI 0(R4),C' ' space delimiter? BE EXPAR030 yes, branch CR R4,R3 origin of statement reached? BH EXPAR020 no, continue search AWSMSG 090E,'AWSPUT parameter syntax error' LA R15,8 export parameter syntax error B EXPARXIT return to caller SPACE 1 EXPAR030 DS 0H dispatch keyword handler LA R4,1(,R4) keyword origin CLC =C'INDSN=',0(R4) INDSN= keyword? BE EXPAR100 yes, branch CLC =C'OUTDSN=',0(R4) OUTDSN= keyword? BE EXPAR110 yes, branch CLC =C'TAPEDSN=',0(R4) TAPEDSN= keyword? BE EXPAR120 yes, branch CLC =C'INDD=',0(R4) INDD= keyword? BE EXPAR130 yes, branch CLC =C'UNLOAD=',0(R4) UNLOAD= keyword? BE EXPAR140 yes, branch CLC =C'TYPE=',0(R4) TYPE= keyword? BE EXPAR150 yes, branch CLC =C'SL=',0(R4) SL= keyword? BE EXPAR160 yes, branch MVC DSMSG+1(7),=C'AWS091E' MVC DSMSG+19(28),=C'AWSPUT keyword unrecognized:' LR R1,R5 argument origin SLR R1,R4 length of argument BCTR R1,0 machine relative EX R1,EXPAREX2 set keyword into message AWSMSG , write the message LA R15,8 export keyword unrecognized B EXPARXIT return to caller SPACE 1 EXPAR100 DS 0H indsn= keyword handler MVC DSINDSN,CSBLNKS clear dataset name LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,EXPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ EXPAR930 if null, branch CH R1,=Y(L'DSINDSN) greater than maximum length? BL *+8 no, branch LA R1,L'DSINDSN else force to max length BCTR R1,0 machine relative EX R1,EXPAREX4 capture dsn B EXPAR900 SPACE 1 EXPAR110 DS 0H outdsn= keyword handler MVC DSOUTDSN,CSBLNKS clear out dataset name LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,EXPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ EXPAR930 if null, branch CH R1,=Y(L'DSOUTDSN) greater than maximum length? BL *+8 no, branch LA R1,L'DSOUTDSN else force to max length BCTR R1,0 machine relative EX R1,EXPAREX5 capture dsn B EXPAR900 SPACE 1 EXPAR120 DS 0H tapedsn= keyword handler MVC DSTDSN,CSBLNKS clear tape dsn LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,EXPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ EXPAR930 if null, branch CH R1,=Y(L'DSTDSN) greater than maximum length? BL *+8 no, branch LA R1,L'DSTDSN else force to maximum length BCTR R1,0 machine relative EX R1,EXPAREX6 capture dsn B EXPAR900 SPACE 1 EXPAR130 DS 0H INDD= keyword handler MVC DSINDD,CSBLNKS clear input dd name LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,EXPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ EXPAR930 if null, branch CH R1,=Y(L'DSINDD) maximum length BL *+8 no, branch LA R1,L'DSINDD else force to max length BCTR R1,0 machine relative EX R1,EXPAREX7 capture indd B EXPAR900 SPACE 1 EXPAR140 DS 0H UNLOAD= keyword handler MVC DSUNLPGM,CSBLNKS clear unload program name LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,EXPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ EXPAR930 if null, branch CH R1,=Y(L'DSUNLPGM) maximum length BL *+8 no, branch LA R1,L'DSUNLPGM else force to max length BCTR R1,0 machine relative EX R1,EXPAREX8 capture unload program B EXPAR900 SPACE 1 EXPAR150 DS 0H TYPE= keyword handler MVC DSUNLTYP,CSBLNKS clear unload type LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,EXPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ EXPAR930 if null, branch CH R1,=Y(L'DSUNLTYP) maximum length BL *+8 no, branch LA R1,L'DSUNLTYP else force to max length BCTR R1,0 machine relative EX R1,EXPAREX9 capture unload program B EXPAR900 SPACE 1 EXPAR160 DS 0H TYPE= keyword handler MVI DSUNLTYP,C' ' clear use standard labels flag LA R1,80(,R3) end of cntl statement SLR R1,R5 length of statement remaining EX R1,EXPAREX3 locate delimiter LR R6,R1 delimiter location SR R1,R5 length of argument BZ EXPAR170 if null, branch CH R1,=Y(L'DSUSESL) maximum length BL *+8 no, branch LA R1,L'DSUSESL else force to max length BCTR R1,0 machine relative EX R1,EXPAREXA capture SPACE 1 CLI DSUSESL,C' ' default? BE EXPAR170 yes, branch CLI DSUSESL,C'N' sl=no? BE EXPAR170 yes, branch CLI DSUSESL,C'Y' sl=yes? BE EXPAR170 yes, branch AWSMSG 054E,'SL= Argument is invalid' LA R15,8 B EXPARXIT SPACE 1 EXPAR170 DS 0H SPACE 1 EXPAR900 DS 0H handle continuation if present CLC =C', ',0(R6) continuation to next card? BNE EXPAR010 no, continue this statement, branch SPACE 1 EXPAR910 DS 0H retrieve continued statement GET AWSCNTL retrieve a cntl record LR R3,R1 record location MVC DSMSG+1(7),=C'AWS052I' MVC DSMSG+19(80),0(R3) set statement into message buffer AWSMSG , print function CLI 0(R1),C'*' comment? BE EXPAR910 yes, branch CLC 0(80,R3),CSBLNKS blank line? BE EXPAR910 yes, branch CLI 0(R3),C' ' first byte non blank? BE EXPAR920 yes, branch AWSMSG 092E,'Continuation statement error, 1st byte not blank' LA R15,8 continuation error B EXPARXIT return to caller SPACE 1 EXPAR920 DS 0H setup for continue scan LA R5,1(,R1) current location in scan SLR R1,R1 offset to argument B EXPAR010 continue SPACE 1 EXPAR930 DS 0H keyword with null argument found LA R1,1 position beyond delimiter B EXPAR900 continue SPACE 1 EXPARRC0 DS 0H exit with rc = 0 SLR R15,R15 clear register SPACE 1 EXPARXIT DS 0H function exit AWSEXIT , SPACE 1 EXPAREX1 TRT 0(0,R5),CSPARST1 *** execute only *** EXPAREX2 MVC DSMSG+48(0),0(R4) *** execute only *** EXPAREX3 TRT 0(0,R5),CSPARST2 *** execute only *** EXPAREX4 MVC DSINDSN(0),0(R5) *** execute only *** EXPAREX5 MVC DSOUTDSN(0),0(R5) *** execute only *** EXPAREX6 MVC DSTDSN(0),0(R5) *** execute only *** EXPAREX7 MVC DSINDD(0),0(R5) *** execute only *** EXPAREX8 MVC DSUNLPGM(0),0(R5) *** execute only *** EXPAREX9 MVC DSUNLTYP(0),0(R5) *** execute only *** EXPAREXA MVC DSUSESL(0),0(R5) *** execute only *** SPACE 1 LTORG , DROP , TITLE 'AWSJFDSN - Extract input dsn' *********************************************************************** * AWSJFDSN - Extract input dsn * * msg AWS10n * *********************************************************************** SPACE 1 AWSJFDSN CSECT , Extract input dsn AWSENTRY , SPACE 1 CLI DSOUTDSN,C' ' output dsn specified? BH JFDSNXIT yes, exit CLI DSTDSN,C' ' explicit tape dsn specified? BH JFDSNXIT yes, exit SPACE 1 CLI DSINDD,C' ' indd specified? BH JFDSN010 yes, branch MVC DSOUTDSN,DSINDSN else default outdsn to indsn B JFDSNXIT exit SPACE 1 JFDSN010 DS 0H capture outdsn from indd= MVC AWSUT1+(DCBDDNAM-IHADCB)(8),=CL8'AWSUT1' CLI DSINDD,C' ' input dd present? BE *+10 no, use awsut1, branch MVC AWSUT1+(DCBDDNAM-IHADCB)(8),DSINDD SPACE 1 RDJFCB AWSUT1,MF=(E,DSRDJFCB) read the jfcb MVC DSOUTDSN,JFCBDSNM default outdsn to input dsn SPACE 1 JFDSNXIT DS 0H function exit SLR R15,R15 zero return code AWSEXIT , return to caller SPACE 1 LTORG , DROP TITLE 'AWSTPDSN - Set 17 byte tape dsn' *********************************************************************** * AWSTPDSN - Set 17 byte tape dsn * * msg AWS11n * *********************************************************************** SPACE 1 AWSTPDSN CSECT , Set 17 byte tape dsn AWSENTRY , SPACE 1 CLI DSTDSN,C' ' tape dsn explicitly given? BH TPDSNXIT yes, branch SPACE 1 LA R1,DSOUTDSN+L'DSOUTDSN point beyond outdsn TRT DSOUTDSN,CSPARST2 locate end of outdsn LA R2,DSOUTDSN outdsn origin SLR R1,R2 length of outdsn CH R1,=Y(L'DSTDSN) greater than maximum length? BH TPDSN010 yes, branch MVC DSTDSN,DSOUTDSN else default outdsn as is B TPDSNXIT exit SPACE 1 TPDSN010 DS 0H capture right most 17 bytes SH R1,=Y(L'DSTDSN) offset to start of name ALR R2,R1 origin of move MVC DSTDSN,0(R2) capture SPACE 1 TPDSNXIT DS 0H function exit SLR R15,R15 zero return code AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSJOBNM - Capture job and step name info' *********************************************************************** * AWSJOBNM - Capture job and step name info * * msg AWS12n * *********************************************************************** SPACE 1 AWSJOBNM CSECT , Capture job and step name info AWSENTRY , USING PSA,R0 L R3,PSATOLD current TCB location USING TCB,R3 TCB addressasbility L R4,TCBTIO TIOT location USING TIOT,R4 MVC DSJOBNM,TIOCNJOB set job name MVC DSSTEPNM,TIOCSTEP+8 set step name CLI DSSTEPNM,C' ' blank stepname? BNE JOBNMXIT no, branch MVC DSSTEPNM,TIOCSTEP else try w/o procstep SPACE 1 JOBNMXIT DS 0H function exit SLR R15,R15 zero return code AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSUNLD - Unload (stage) dataset' *********************************************************************** * AWSUNLD - Unload (stage) dataset * * msg AWS13n * *********************************************************************** SPACE 1 AWSUNLD CSECT , Unload (stage) dataset AWSENTRY , SPACE 1 SLR R15,R15 zero return code CLI DSUNLPGM,C' ' unload requested? BE UNLODXIT no, branch SPACE 1 AWSCALL AWSALCI allocate input dataset BNZ UNLODXIT SPACE 1 AWSCALL AWSALCT allocate work dataset BNZ UNLODXIT SPACE 1 AWSCALL AWSALCS allocate sysin dataset BNZ UNLODXIT SPACE 1 AWSCALL AWSALCP allocate sysprint dataset BNZ UNLODXIT SPACE 1 OPEN (SYSIN,(OUTPUT)),MF=(E,DSOPENL) open sysin for output SPACE 1 TM SYSIN+(DCBOFLGS-IHADCB),DCBOFOPN open ok? BO UNLOD010 yes, branch AWSMSG 130E,'SYSIN open for output failed' LA R15,8 set return code B UNLODXIT SPACE 1 UNLOD010 DS 0H determine type of unload CLC =C'IEBCOPY',DSUNLPGM iebcopy unload? BE UNLOD100 yes, branch CLC =C'IDCAMS',DSUNLPGM idcams export? BE UNLOD200 yes, branch AWSMSG 131E,'Unrecognized unload program specified' LA R15,8 unrecognized unload pgm B UNLODXIT exit SPACE 1 UNLOD100 DS 0H iebcopy unload request MVI DSCARD,C' ' clear card image MVC DSCARD+1(L'DSCARD-1),DSCARD MVC DSCARD(15),=C' C O=AWSTEMP,I=' MVC DSCARD+15(8),DSINDD assume indd= statement present CLI DSINDD,C' ' indd= keyword present? BH UNLOD110 yes, branch MVC DSCARD+15(8),=CL8'AWSUT1' else use default SPACE 1 UNLOD110 DS 0H write control statement PUT SYSIN,DSCARD SPACE 1 CLOSE SYSIN,MF=(E,DSCLOSEL) close file FREEPOOL SYSIN release buffer pool SPACE 1 SLR R1,R1 clear parameter register LINK EP=IEBCOPY invoke iebcopy LTR R15,R15 success? BZ UNLOD120 yes, branch AWSMSG 132E,'IEBCOPY unload failed' LA R15,8 set return code B UNLODXIT exit space 1 UNLOD120 DS 0H Unload via iebcopy successful msg AWSMSG , blank line AWSMSG 133I,'PDS(E) unload successful' B UNLODXIT exit SPACE 1 UNLOD200 DS 0H idcams export AWSMSG 134F,'IDCAMS export not yet supported' LA R15,12 * B UNLODXIT SPACE 1 UNLODXIT DS 0H return to caller AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSALCI - Dynamically allocate input' *********************************************************************** * AWSALCI - Dynamically allocate input * * msg AWS14n * *********************************************************************** SPACE 1 AWSALCI CSECT , Dynamically allocate input AWSENTRY , SPACE 1 CLI DSINDD,C' ' input dataset already allocated? BNE ALOCI030 yes, branch SPACE 1 MVC DSADSNMT,DSINDSN input dataset name LA R1,DSARBP input rb pointer SVC 99 input allocation LTR R15,R15 successful? BZ ALOCI020 yes, branch LA R3,DSARB rb location USING S99RB,R3 input rb addressability CH R15,CSH4 rc=4? BNE ALOCI010 no, error, branch CLC S99ERROR,=X'0410' ddname already allocated? BE ALOCI030 yes, branch SPACE 1 ALOCI010 DS 0H allocation error occured LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 140E,'Input dataset dynamic allocation failed' LA R15,8 set return code B ALOCIXIT exit SPACE 1 ALOCI020 DS 0H successful dynamic allocation OI DSFLAGS,DSFDYUT1 awsut1 dynamically allocated SPACE 1 ALOCI030 DS 0H normal return SLR R15,R15 zero return code SPACE 1 ALOCIXIT DS 0H return to caller AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSALCT - Dynamically allocate temporary work' *********************************************************************** * AWSALCT - Dynamically allocate temporary work * * msg AWS15n * *********************************************************************** SPACE 1 AWSALCT CSECT , Dynamically allocate temporary work AWSENTRY , SPACE 1 LA R1,DSTARBP temp work rb pointer SVC 99 temp work allocation LTR R15,R15 successful? BZ ALOCT020 yes, branch LA R3,DSTARB rb location USING S99RB,R3 input rb addressability CH R15,CSH4 rc=4? BNE ALOCT010 no, error, branch CLC S99ERROR,=X'0410' ddname already allocated? BE ALOCT030 yes, branch SPACE 1 ALOCT010 DS 0H allocation error occured LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 150E,'Temp work dataset dynamic allocation failed' LA R15,8 set return code B ALOCTXIT exit SPACE 1 ALOCT020 DS 0H successful dynamic allocation OI DSFLAGS,DSFDYTMP awstemp dynamically allocated SPACE 1 ALOCT030 DS 0H normal return SLR R15,R15 zero return code SPACE 1 ALOCTXIT DS 0H return to caller AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSALCS - Dynamically allocate sysin' *********************************************************************** * AWSALCS - Dynamically allocate temporary sysin * * msg AWS16n * *********************************************************************** SPACE 1 AWSALCS CSECT , Dynamically allocate temporary work AWSENTRY , SPACE 1 LA R1,DSSARBP temp work rb pointer SVC 99 temp work allocation LTR R15,R15 successful? BZ ALOCS020 yes, branch LA R3,DSSARB rb location USING S99RB,R3 input rb addressability CH R15,CSH4 rc=4? BNE ALOCS010 no, error, branch CLC S99ERROR,=X'0410' ddname already allocated? BE ALOCS030 yes, branch SPACE 1 ALOCS010 DS 0H allocation error occured LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 160E,'SYSIN dataset dynamic allocation failed' LA R15,8 set return code B ALOCSXIT exit SPACE 1 ALOCS020 DS 0H successful dynamic allocation OI DSFLAGS,DSFDYSYI sysin dynamically allocated SPACE 1 ALOCS030 DS 0H normal return SLR R15,R15 zero return code SPACE 1 ALOCSXIT DS 0H return to caller AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSALCP - Dynamically allocate sysprint' *********************************************************************** * AWSALCP - Dynamically allocate sysprint * * msg AWS17n * *********************************************************************** SPACE 1 AWSALCP CSECT , Dynamically allocate sysprint AWSENTRY , SPACE 1 LA R1,DSPARBP temp work rb pointer SVC 99 temp work allocation LTR R15,R15 successful? BZ ALOCP020 yes, branch LA R3,DSPARB rb location USING S99RB,R3 input rb addressability CH R15,CSH4 rc=4? BNE ALOCP010 no, error, branch CLC S99ERROR,=X'0410' ddname already allocated? BE ALOCP030 yes, branch SPACE 1 ALOCP010 DS 0H allocation error occured LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 170E,'SYSPRINT dataset dynamic allocation failed' LA R15,8 set return code B ALOCPXIT exit SPACE 1 ALOCP020 DS 0H successful dynamic allocation OI DSFLAGS,DSFDYSYP sysprint dynamically allocated SPACE 1 ALOCP030 DS 0H normal return SLR R15,R15 zero return code SPACE 1 ALOCPXIT DS 0H return to caller AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSDYNE - Dyanamic allocation error' *********************************************************************** * AWSDYNE - Dynamic allocation error, on entry r1 = s99rb, r0=rc * * msg AWS18n * *********************************************************************** SPACE 1 AWSDYNE CSECT , Dynamic allocation error AWSENTRY , SPACE 1 LR R3,R1 dynalloc rb location USING S99RB,R3 addressability LR R4,R0 dynalloc return code SPACE 1 MVC DSMSG+1(7),=C'AWS180E' MVC DSMSG+19(54),=C'DYNALLOC FAILURE, RC=XXXX, S99ERROR=XXXX* , S99INFO=XXXX' ST R4,DSFWORK rc UNPK DSHEXWK(9),DSFWORK(5) unpack data TR DSHEXWK,CSHEXTR make printable MVC DSMSG+19+21(4),DSHEXWK+4 return code SPACE 1 UNPK DSHEXWK(5),S99ERROR(3) s99error code TR DSHEXWK,CSHEXTR make printable MVC DSMSG+19+36(4),DSHEXWK SPACE 1 UNPK DSHEXWK(5),S99INFO(3) s99info code TR DSHEXWK,CSHEXTR make printable MVC DSMSG+19+50(4),DSHEXWK SPACE 1 AWSMSG , write the message SPACE 1 CH R4,CSH4 RC = 4? BNE DYNERXIT NO, BRANCH CLC S99ERROR,=X'1708' ERROR = 1708? BNE DYNERXIT NO, BRANCH CLC S99INFO,=X'0002' INFO = 0002? BNE DYNERXIT NO, BRANCH AWSMSG 181E,'Dataset could not be found' SPACE 1 DYNERXIT DS 0H function exit SLR R15,R15 zero return code AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSHDR - Header labels' *********************************************************************** * AWSHDR - header labels * * msg AWS19n * *********************************************************************** SPACE 1 AWSHDR CSECT , header labels AWSENTRY , SPACE 1 SLR R15,R15 zero return code for now CLI DSUSESL,C'N' suppress standard labels? BE HDRLBXIT yes, branch TM DSFLAGS,DSFVOLF vol1 written previously? BO HDRLB100 yes, branch L R3,DSBUFTP Next text location USING AWSREC,R3 Addressability MVC AWSLENC,CSH80 block length AWSSWAP , set sizes MVC AWSFLGS,CSXA000 data follows LA R3,6(,R3) position beyond aws cb ST R3,DSBUFTP set current text pointer TM DSFLAGS,DSFRECV variable length output? BZ HDRLB010 no, branch AWSCALL AWSEPUT write the aws cb L R3,DSBUFTP current buffer pointer USING AWSDBLK,R3 data block origin SPACE 1 HDRLB010 DS 0H build vol1 label MVC DSVOL1SR,DSTVOL set volser into label MVC DSVOL1OW,DSOWNER set owner MVC AWSDBLK(80),DSVOL1 VOL1 LABEL LA R3,80(,R3) Next data record origin ST R3,DSBUFTP Set current text pointer TM DSFLAGS,DSFRECV Variable length output? BZ HDRLB100 No, branch AWSCALL AWSEPUT Write the block SPACE 1 HDRLB100 DS 0H HDR1 LABEL L R3,DSBUFTP Next text location USING AWSREC,R3 MVC AWSLENC,CSH80 block length AWSSWAP , set sizes MVC AWSFLGS,CSXA000 data follows MVC DSHDR1SR,DSTVOL volser LA R3,6(,R3) position beyond aws cb ST R3,DSBUFTP set current text pointer TM DSFLAGS,DSFRECV variable length output? BZ HDBLB110 no, branch AWSCALL AWSEPUT write the aws cb L R3,DSBUFTP current buffer pointer USING AWSDBLK,R3 data block origin SPACE 1 HDBLB110 DS 0H build hdr1 LH R1,DSFILECT file sequence number LA R1,1(,R1) ...increment STH R1,DSFILECT ...and save CVD R1,DSDWORK convert to decimal MVC DSXL16(6),=X'F02020202020' edit mask ED DSXL16(6),DSDWORK+5 MVC DSHDR1SQ,DSXL16+2 set file number into HDR1 OI DSHDR1SQ+L'DSHDR1SQ-1,C'0' MVC DSHDR1NM,DSTDSN Set dataset name into label SPACE 1 TIME DEC get todays date ST R1,DSFWORK set into work area MVC DSXL16(8),=X'F020202020202020' edit mask UNPK DSXL16(8),DSFWORK unpack date OI DSXL16+7,C'0' valid last digit MVC DSHDR1CD,DSXL16+2 set into header MVI DSHDR1CD,C'0' assume 2000-2099 for now CLI DSXL16+2,C'0' 1900-1999? BNE *+8 no, branch MVI DSHDR1CD,C' ' else so indicate SPACE 1 MVC AWSDBLK(80),DSHDR1 HDR1 label LA R3,80(,R3) Next data record origin ST R3,DSBUFTP Set current text pointer TM DSFLAGS,DSFRECV Variable length output? BZ HDRLB200 No, branch AWSCALL AWSEPUT Write the block SPACE 1 HDRLB200 DS 0H HDR2 label L R3,DSBUFTP Next text location USING AWSREC,R3 MVC AWSLENC,CSH80 block length AWSSWAP , set sizes MVC AWSFLGS,CSXA000 data follows LA R3,6(,R3) position beyond aws cb ST R3,DSBUFTP new current text pointer TM DSFLAGS,DSFRECV variable length output? BZ HDRLB210 no, branch AWSCALL AWSEPUT write the aws cb L R3,DSBUFTP current buffer pointer USING AWSDBLK,R3 data block SPACE 1 HDRLB210 DS 0H build hdr2 LA R15,AWSUT1 awsut1 DCB location USING IHADCB,R15 addressability MVI DSHDR2RF,C'U' assume recfm=u for now TM DCBRECFM,DCBRECU recfm=u? BO HDRLB220 yes, branch MVI DSHDR2RF,C'F' assume fixed for now TM DCBRECFM,DCBRECF recfm=f? BO HDRLB220 yes, branch MVI DSHDR2RF,C'V' else assume variable EJECT HDRLB220 DS 0H SLR R0,R0 clear register ICM R0,3,DCBBLKSI blocksize CVD R0,DSDWORK convert to decimal MVC DSXL16(6),=X'F02020202020' ED DSXL16(6),DSDWORK+5 MVC DSHDR2BL,DSXL16+1 OI DSHDR2BL+L'DSHDR2BL-1,C'0' SPACE 1 SLR R0,R0 clear register ICM R0,3,DCBLRECL lrecl CVD R0,DSDWORK convert to decimal MVC DSXL16(6),=X'F02020202020' ED DSXL16(6),DSDWORK+5 MVC DSHDR2RL,DSXL16+1 OI DSHDR2RL+L'DSHDR2RL-1,C'0' SPACE 1 MVI DSHDR2CC,C'A' assume asa for now TM DCBRECFM,DCBRECCA asa carriage control? BO HDRLB230 yes, branch MVI DSHDR2CC,C'M' assume machine for now TM DCBRECFM,DCBRECCM machine carriage control? BO HDRLB230 yes, branch MVI DSHDR2CC,C' ' else no carriage control SPACE 1 HDRLB230 DS 0H handle spanned and blocking MVI DSHDR2BA,C'S' assume spanned or standard TM DCBRECFM,DCBRECSB spanned or standard? BO HDRLB240 yes, branch MVI DSHDR2BA,C'B' assume blocked for now TM DCBRECFM,DCBRECBR blocked? BO HDRLB240 yes, branch MVI DSHDR2BA,C' ' else unblocked EJECT HDRLB240 DS 0H MVC DSHDR2JB,DSJOBNM Set job name MVC DSHDR2ST,DSSTEPNM Set step name SPACE 1 SLR R0,R0 clear register ICM R0,3,AWSUT1+(DCBBLKSI-IHADCB) blocksize CVD R0,DSDWORK convert to decimal MVC DSXL16(12),=X'F02120202020202020202020' ED DSXL16(12),DSDWORK+2 edit OI DSXL16+11,C'0' make printable MVC DSHDR2LB,DSXL16+2 set large blocksize SPACE 1 MVC AWSDBLK(80),DSHDR2 HDR2 label LA R3,80(,R3) Next data record origin ST R3,DSBUFTP Set current text pointer TM DSFLAGS,DSFRECV Variable length output? BZ HDRLB250 No, branch AWSCALL AWSEPUT Write the block SPACE 1 HDRLB250 DS 0H Write labels to log AWSMSG , blank line TM DSFLAGS,DSFVOLF volume header already written? BO HDRLB260 yes, branch OI DSFLAGS,DSFVOLF indicate vol1 has been written MVC DSMSG+1(7),=C'AWS190I' MVC DSMSG+19(80),DSVOL1 vol1 label AWSMSG , SPACE 1 HDRLB260 DS 0H log hdr1 and hdr2 MVC DSMSG+1(7),=C'AWS191I' MVC DSMSG+19(80),DSHDR1 hdr1 label AWSMSG , MVC DSMSG+1(7),=C'AWS192I' MVC DSMSG+19(80),DSHDR2 hdr2 label AWSMSG , AWSMSG , blank line SPACE 1 AWSCALL AWSMARK write tape mark SPACE 1 HDRLBXIT DS 0H exit AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSTLR - Write trailer labels' *********************************************************************** * AWSTLR - Write trailer labels * * msg AWS20n * *********************************************************************** SPACE 1 AWSTLR CSECT , Write trailer labels AWSENTRY , SPACE 1 CLI DSUSESL,C'N' suppress standard labels? BE TLRLBXIT yes, branch L R3,DSBUFTP current text pointer USING AWSREC,R3 addressability MVC AWSLENC,CSH80 BLOCK LENGTH AWSSWAP , swap byte order, set size MVC AWSFLGS,CSXA000 DATA FOLLOWS LA R3,6(,R3) next output text ST R3,DSBUFTP set current pointer TM DSFLAGS,DSFRECV variable length output? BZ TLRLB010 no, branch AWSCALL AWSEPUT write the aws cb L R3,DSBUFTP current text pointer USING AWSDBLK,R3 ... addressability SPACE 1 TLRLB010 DS 0H eof1 MVC DSEOF1,DSHDR1 COPY HDR1 INTO EOF1 MVC DSEOF1(3),=C'EOF' SPACE 1 MVC DSXL16(12),=X'F02020202020202020202020' ED DSXL16(12),DSBLKCNT OI DSXL16+11,C'0' MVC DSEOF1BL,DSXL16+6 low block count MVC DSEOF1BH,DSXL16+2 high block count MVC AWSDBLK(80),DSEOF1 EOF1 label LA R3,80(,R3) next text pointer ST R3,DSBUFTP ...and save TM DSFLAGS,DSFRECV variable length output? BZ TLRLB200 no, branch AWSCALL AWSEPUT write the output text L R3,DSBUFTP current buffer location USING AWSREC,R3 addressability SPACE 1 TLRLB200 DS 0H TLR2 LABEL MVC AWSLENC,CSH80 BLOCK LENGTH AWSSWAP , swap byte order, set size MVC AWSFLGS,CSXA000 DATA FOLLOWS LA R3,6(,R3) next current text pointer ST R3,DSBUFTP ... make current TM DSFLAGS,DSFRECV variable length output? BZ TLRLB210 no, branch AWSCALL AWSEPUT write aws cb L R3,DSBUFTP current text pointer USING AWSDBLK,R3 ... addressability SPACE 1 TLRLB210 DS 0H label text MVC DSEOF2,DSHDR2 copy hdr2 to eof2 MVC DSEOF2(3),=C'EOF' MVC AWSDBLK(80),DSEOF2 EOF2 label LA R3,80(,R3) current text pointer ST R3,DSBUFTP ... make current TM DSFLAGS,DSFRECV variable length output? BZ TLRLB220 no, branch AWSCALL AWSEPUT write text SPACE 1 TLRLB220 DS 0H AWSMSG , blank line MVC DSMSG+1(7),=C'AWS200I' MVC DSMSG+19(80),DSEOF1 EOF1 LABEL AWSMSG , MVC DSMSG+1(7),=C'AWS201I' MVC DSMSG+19(80),DSEOF2 EOF2 LABEL AWSMSG , AWSMSG , blank line SPACE 1 AWSCALL AWSMARK write tape mark AWSMSG , blank line AWSMSG , SPACE 1 TLRLBXIT DS 0H exit SLR R15,R15 zero return code AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSPRNT - Write to AWSPRINT log' *********************************************************************** * AWSPRNT - Write contents of DSBUF to AWSPRINT log * * msg AWS21n * *********************************************************************** SPACE 1 AWSPRNT CSECT , Print Function AWSENTRY , Function Entry SPACE 1 AP DSLINECT,CSP1 increment line count CP DSLINECT,=P'60' page eject needed? BNH PRINT010 no, branch ZAP DSLINECT,CSP1 AP DSPAGECT,CSP1 increment page count MVC DSPAGE,=X'40202120' page mask ED DSPAGE,DSPAGECT insert page count PUT AWSPRINT,DSHEADER write header PUT AWSPRINT,DSMSG1 double space SPACE 1 MVC DSMSG1+1(22),=C'AWS210I Execution Log' PUT AWSPRINT,DSMSG1 MVI DSMSG1+6,C'1' MVI DSMSG1+10,C'-' fill with dashes MVC DSMSG1+11(L'DSMSG1-11),DSMSG1+10 PUT AWSPRINT,DSMSG1 SPACE 1 PRINT010 DS 0H write user specified line PUT AWSPRINT,DSMSG write record MVC DSMSG,CSBLNKS clear print buffer MVC DSMSG1,CSBLNKS SLR R15,R15 zero return code SPACE 1 AWSEXIT , Return to caller SPACE 1 LTORG , DROP , TITLE 'AWSMARK - Output a tape mark' *********************************************************************** * AWSMARK - Output a tape mark * * msg AWS22n * *********************************************************************** SPACE 1 AWSMARK CSECT , Write a tape mark AWSENTRY , SPACE 1 L R3,DSBUFTP Next text location USING AWSREC,R3 XC AWSLENC,AWSLENC zero block length AWSSWAP , set sizes MVC AWSFLGS,CSX4000 tape mark SPACE 1 LA R3,6(,R3) Next data record origin ST R3,DSBUFTP Set current text pointer TM DSFLAGS,DSFRECV+DSFFLUSH write required? BZ MARK010 No, branch AWSCALL AWSEPUT Write the block SPACE 1 MARK010 DS 0H return AWSMSG 220I,'*** tape mark ***' SLR R15,R15 zero return code AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSEPUT - Write text to AWSFILE output' *********************************************************************** * AWSEPUT - Write output text * * msg AWS23n * *********************************************************************** SPACE 1 AWSEPUT CSECT , AWSENTRY , SPACE 1 LA R3,DSBUFFER output buffer origin TM DSFLAGS,DSFRECV variable length output? BZ EPUT100 no, branch SPACE 1 *********************************************************************** * awsfile output is variable (recfm=v) test... good for debugging. * *********************************************************************** SPACE 1 EPUT010 DS 0H handle variable length output L R4,DSBUFTP end of text SR R4,R3 r4 = length of text BNP EPUT900 if zero, done, branch SLR R2,R2 clear register ICM R2,3,AWSFILE+(DCBLRECL-IHADCB) r2 = awsfile lrecl SH R2,CSH4 allow room for rdw CR R4,R2 text at or exceeds lrecl? BL *+6 no, branch LR R4,R2 else length = lrecl - 4 SPACE 1 LA R2,DSBUFFER buffer origin AL R2,=A(BUFSIZE*2) offset to variable length buffer LA R0,4(,R2) target of move LR R1,R4 length of data to write LR R14,R3 origin of data LR R15,R4 length of source MVCL R0,R14 copy data to variable buffer LA R1,4(,R4) length of variable record STCM R1,3,0(R2) set length into rdw XC 2(2,R2),2(R2) clear rdw flags PUT AWSFILE,(R2) write the record SPACE 1 ALR R3,R4 position at next origin B EPUT010 continue until done EJECT *********************************************************************** * awsfile output is undefined (recfm=u) text... preferred. * *********************************************************************** SPACE 1 EPUT100 DS 0H handle undefined length output TM AWSFILE+(DCBRECFM-IHADCB),DCBRECU recfm=u? BNO EPUT200 no, must be recfm=f, branch SPACE 1 EPUT110 DS 0H L R4,DSBUFTP end of current text SR R4,R3 r4=length of text BNP EPUT900 if zero, done, branch SLR R2,R2 clear register ICM R2,3,AWSFILE+(DCBBLKSI-IHADCB) r2 = awsfile blksize CR R4,R2 text at or exceeds blksize? BL EPUT130 no, branch LR R4,R2 else length = blksize SPACE 1 EPUT120 DS 0H write undefined length record STCM R4,3,AWSFILE+(DCBLRECL-IHADCB) set length into dcb PUT AWSFILE,(R3) write the text SPACE 1 ALR R3,R4 position at next origin B EPUT110 continue writing all possible SPACE 1 EPUT130 DS 0H short undefined block found TM DSFLAGS,DSFFLUSH flush requested? BO EPUT120 else write short block LA R1,DSBUFFER output buffer origin CR R1,R3 wrote from origin? BNL EPUT900 yes, branch LA R0,DSBUFFER target of move LR R1,R4 length of move LR R14,R3 source of move LR R15,R4 length of move MVCL R0,R14 copy short block to buffer origin LA R3,DSBUFFER buffer origin ALR R4,R3 offset to end of short block ST R4,DSBUFTP set new next pointer B EPUTXIT EJECT *********************************************************************** * awsfile output is fixed length (recfm=f) (folded) text... grrr. * *********************************************************************** SPACE 1 EPUT200 DS 0H handle fixed length output L R4,DSBUFTP end of current text SR R4,R3 r4=length of text BNP EPUT900 if zero, done, branch SLR R2,R2 clear register ICM R2,3,AWSFILE+(DCBLRECL-IHADCB) r2 = awsfile lrecl CR R4,R2 text at or exceeds lrecl? BL EPUT220 no, branch LR R4,R2 else length = blksize SPACE 1 EPUT210 DS 0H write undefined length record PUT AWSFILE,(R3) write the text SPACE 1 ALR R3,R4 position at next origin B EPUT200 continue writing all possible SPACE 1 EPUT220 DS 0H short undefined block found TM DSFLAGS,DSFFLUSH flush requested? BO EPUT230 else write short block LA R1,DSBUFFER output buffer origin CR R1,R3 wrote from origin? BNL EPUT900 yes, branch LA R0,DSBUFFER target of move LR R1,R4 length of move LR R14,R3 source of move LR R15,R4 length of move MVCL R0,R14 copy short block to buffer origin LA R3,DSBUFFER buffer origin ALR R4,R3 offset to end of short block ST R4,DSBUFTP set new next pointer B EPUTXIT SPACE 1 EPUT230 DS 0H flush short text LA R2,DSBUFFER target of move AL R2,=A(BUFSIZE*2) offset to variable length buffer LR R0,R2 target of move SLR R1,R1 clear high order nibbles ICM R1,3,AWSFILE+(DCBLRECL-IHADCB) length of target LR R14,R3 source of move LR R15,R4 length of source ICM R15,8,=X'20' padding required by VTT2TAPE MVCL R0,R14 copy and pad with nulls short text PUT AWSFILE,(R2) write short text LR R0,R2 buffer location SLR R1,R1 clear high order nibbles ICM R1,3,AWSFILE+(DCBLRECL-IHADCB) length of target SLR R15,R15 zero length source ICM R15,8,=X'20' padding required b y vtt2tape MVCL R0,R14 propogate through entire record PUT AWSFILE,(R2) SPACE 1 EPUT900 DS 0H all data has been written LA R0,DSBUFFER buffer origin ST R0,DSBUFTP set current text pointer SPACE 1 EPUTXIT DS 0H return NI DSFLAGS,255-DSFFLUSH reset forced flush flag SLR R15,R15 zero return code AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSICOPY - copy from aws input' *********************************************************************** * AWSICOPY - copy from aws input dataset (awsfile) * * msg AWS24n * *********************************************************************** SPACE 1 AWSICOPY CSECT , copy from aws input dataset AWSENTRY , SPACE 1 ZAP DSIBLKCT,=P'0' ZERO BLOCK COUNT ZAP DSIRECCT,=P'0' ... AND RECORD COUNT SPACE 1 LA R5,AWSUT3 input dcb location USING IHADCB,R5 addressability MVC DCBDDNAM,DSOUTDD set ddname SLR R0,R0 clear register STCM R0,3,DCBLRECL clear previous lrecl STCM R0,3,DCBBLKSI clear previous blksize SPACE 1 CLI DSRECFM+1,C'S' spanned records? BE ICOPY010 yes, branch CLC =C'IEBCOPY',DSLODPGM iebcopy load? BE ICOPY010 yes, branch RDJFCB AWSUT3,MF=(E,DSRDJFCB) read the jfcb SPACE 1 ICM R0,3,JFCLRECL lrecl specified in jcl? BZ *+8 no, branch STCM R0,3,DCBLRECL else set into dcb SPACE 1 ICM R0,3,JFCBLKSI blksize specified in jcl? BZ *+8 no, branch STCM R0,3,DCBBLKSI else set into dcb SPACE 1 ICOPY010 DS 0H default from label if needed ICM R0,3,DCBLRECL lrecl specified? BNZ *+10 no, branch MVC DCBLRECL,DSLRECL else default from tape label SPACE 1 ICM R0,3,DCBBLKSI blocksize specified? BNZ *+10 no, branch MVC DCBBLKSI,DSBLKSIZ else default from tape label SPACE 1 OI DCBRECFM,DCBRECU assume undefined for now CLI DSRECFM,C' ' recfm specified? BNH ICOPY020 no, branch CLI DSRECFM,C'U' label undefined? BE ICOPY020 yes, branch NI DCBRECFM,255-DCBRECU reset bits OI DCBRECFM,DCBRECF assume fixed for now CLI DSRECFM,C'F' label fixed? BE ICOPY020 yes, branch NI DCBRECFM,255-DCBRECU reset bits OI DCBRECFM,DCBRECV else must be variable SPACE 1 ICOPY020 DS 0H set blocked attribute CLI DSRECFM+1,C' ' blocked specified? BNH ICOPY030 no, branch CLI DSRECFM+1,C'B' blocked records? BNE *+8 no, branch OI DCBRECFM,DCBRECBR else so indicate SPACE 1 CLI DSRECFM+1,C'S' spanned records? BNE *+8 no, branch OI DCBRECFM,DCBRECSB else so indicate SPACE 1 ICOPY030 DS 0H allocate files if needed CLI DSLODPGM,C' ' load program specified? BNH ICOPY070 no, branch MVC DCBDDNAM,=CL8'AWSTEMP' temporary file SPACE 1 AWSCALL AWSALCI allocate input dataset BNZ ICOPYXIT SPACE 1 AWSCALL AWSALCT allocate work dataset BNZ ICOPYXIT SPACE 1 AWSCALL AWSALCS allocate sysin dataset BNZ ICOPYXIT SPACE 1 AWSCALL AWSALCP allocate sysprint dataset BNZ ICOPYXIT SPACE 1 OPEN (SYSIN,(OUTPUT)),MF=(E,DSOPENL) open sysin for output SPACE 1 TM SYSIN+(DCBOFLGS-IHADCB),DCBOFOPN open ok? BO ICOPY040 yes, branch AWSMSG 241E,'SYSIN open for output failed' LA R15,8 set return code B ICOPYXIT SPACE 1 ICOPY040 DS 0H determine type of unload CLC =C'IEBCOPY',DSLODPGM iebcopy unload? BE ICOPY050 yes, branch AWSMSG 242E,'Unrecognized load program specified' LA R15,8 unrecognized unload pgm B ICOPYXIT exit SPACE 1 ICOPY050 DS 0H iebcopy load request MVC DSCARD,CSBLNKS clear MVC DSCARD(15),=C' C I=AWSTEMP,O=' MVC DSCARD+15(8),DSOUTDD set OUTDD statement CLI DSOUTDD,C' ' outdd= keyword present? BH ICOPY060 yes, branch MVC DSCARD+15(8),=CL8'AWSUT1' else use default SPACE 1 ICOPY060 DS 0H write control statement PUT SYSIN,DSCARD SPACE 1 CLOSE SYSIN,MF=(E,DSCLOSEL) close file FREEPOOL SYSIN release buffer pool SPACE 1 ICOPY070 DS 0H open files RDJFCB AWSUT3,MF=(E,DSRDJFCB) read the jfcb SPACE 1 AWSMSG , blank line MVC DSMSG+1(7),=C'AWS240I' MVC DSMSG+19(31),=C'Writing to dataset :' MVC DSMSG+51(44),JFCBDSNM AWSMSG , SPACE 1 TM DCBRECFM,DCBRECSB spanned blocks? panned b BZ ICOPY090 no, branch CLC =C'IEBCOPY',DSLODPGM iebcopy load? BE ICOPY080 yes, bypass warning, branch AWSMSG , AWSMSG 24BW,'*** Warning, spanned formats not supported, force* d to recfm=u' AWSMSG 24CI,'*** Note that IEBCOPY can process unloaded PDS as* recfm=u' AWSMSG , ICOPY080 DS 0H spanned, force to RECFM=U OI DCBRECFM,DCBRECU indciate undefined lrecl NI DCBRECFM,255-DCBRECSB reset spanned indicator SPACE 1 ICOPY090 DS 0H OPEN (AWSUT3,(OUTPUT)),MF=(E,DSOPENL) TM DCBOFLGS,DCBOFOPN open successful? BO ICOPY100 yes, branch AWSMSG 243E,'Open output file for import failed' LA R15,8 return code B ICOPYXIT exit SPACE 1 ICOPY100 DS 0H produce messages SLR R0,R0 clear register ICM R0,3,DCBLRECL load blocksize CVD R0,DSDWORK convert to decimal MVC DSXL16(6),=X'F02020202120' ED DSXL16(6),DSDWORK+5 edit MVI DSXL16+5,C'0' make printable MVC DSMSG+1(7),=C'AWS244I' MVC DSMSG+19(31),=C'Output dataset lrecl :' MVC DSMSG+51(5),DSXL16+1 set blksize into message AWSMSG , write message SPACE 1 SLR R0,R0 clear register ICM R0,3,DCBBLKSI load blocksize CVD R0,DSDWORK convert to decimal MVC DSXL16(6),=X'F02020202120' ED DSXL16(6),DSDWORK+5 edit MVI DSXL16+5,C'0' make printable MVC DSMSG+1(7),=C'AWS245I' MVC DSMSG+19(31),=C'Output dataset blksize :' MVC DSMSG+51(5),DSXL16+1 set blksize into message AWSMSG , write message SPACE 1 MVC DSMSG+1(7),=C'AWS246I' MVC DSMSG+19(31),=C'Output dataset recfm :' NI DSFLAGS,255-DSFRECV reset variable length flag MVI DSMSG+51,C'U' assume recfm=u for now TM DCBRECFM,DCBRECU recfm=u? BO ICOPY110 yes, branch MVI DSMSG+51,C'F' assume fixed for now TM DCBRECFM,DCBRECF recfm=f? BO ICOPY110 yes, branch MVI DSMSG+51,C'V' else assume variable OI DSFLAGS,DSFRECV set variable length flag ICOPY110 DS 0H MVI DSMSG+53,C'A' assume asa for now TM DCBRECFM,DCBRECCA asa carriage control? BO ICOPY120 yes, branch MVI DSMSG+53,C'M' assume machine for now TM DCBRECFM,DCBRECCM machine carriage control? BO ICOPY120 yes, branch MVI DSMSG+53,C' ' else no carriage control SPACE 1 ICOPY120 DS 0H handle spanned and blocking MVI DSMSG+52,C'S' assume spanned or standard TM DCBRECFM,DCBRECSB spanned or standard? BO ICOPY130 yes, branch MVI DSMSG+52,C'B' assume blocked for now TM DCBRECFM,DCBRECBR blocked? BO ICOPY130 yes, branch MVI DSMSG+52,C' ' else unblocked SPACE 1 ICOPY130 DS 0H produce recfm message CLI DSMSG+52,C' ' not blocked or spanned? BNE ICOPY140 no, branch MVC DSMSG+52(1),DSMSG+53 MVI DSMSG+53,C' ' ICOPY140 DS 0H write recfm AWSMSG , write message SPACE 1 ICOPY150 DS 0H copy aws input text to output file AWSCALL AWSIGET retrieve a block BNZ ICOPYEOF if eof, branch L R3,DSBUFTP block location CLC CSX4000,4(R3) tape mark read? BE ICOPYE10 yes, simulate eof, branch AP DSIBLKCT,=P'1' increment block count SLR R4,R4 clear register ICM R4,3,0(R3) size of aws block lr r14,r4 future reference ALR R4,R3 end of aws block LA R3,6(,R3) position beyond aws header TM DSFLAGS,DSFRECV variable length records? BZ ICOPY160 no, branch SLR R4,R4 clear register ICM R4,3,0(R3) block length from rdw ALR R4,R3 end of block LA R3,4(,R3) position beyond block rdw SPACE 1 ICOPY160 DS 0H copy logical records to output CLR R3,R4 reached end of block? BNL ICOPY150 yes, do next one, branch TM DCBRECFM,DCBRECU undefined output? BNO *+8 no, branch STCM R14,3,DCBLRECL else set lrecl PUT AWSUT3,(R3) else write logical record AP DSIRECCT,=P'1' increment record count TM DSFLAGS,DSFRECV variable length records? BO ICOPY170 yes, branch AH R3,DCBLRECL position at next logical block B ICOPY160 continue SPACE 1 ICOPY170 DS 0H position at next variable length rec SLR R0,R0 clear register ICM R0,3,0(R3) record length ALR R3,R0 origin of next record B ICOPY160 continue SPACE 1 ICOPYEOF DS 0H eof reached? CH R15,=H'-4' eof? BNE ICOPYXIT no, error, branch SPACE 1 ICOPYE10 DS 0H logical eof detected CLOSE AWSUT3,MF=(E,DSCLOSEL) close file FREEPOOL AWSUT3 release buffers SPACE 1 AWSMSG , blank line MVC DSXL16,=X'40202020202020202020202020202120' ED DSXL16,DSIBLKCT edit record count OI DSXL16+15,C'0' make last digit printable MVC DSMSG+1(7),=C'AWS247I' message id MVC DSMSG+19(31),=C'Total physical aws blocks read:' MVC DSMSG+51(16),DSXL16 set count into message AWSMSG , SPACE 1 MVC DSXL16,=X'40202020202020202020202020202120' ED DSXL16,DSIRECCT edit record count OI DSXL16+15,C'0' make last digit printable MVC DSMSG+1(7),=C'AWS248I' message id MVC DSMSG+19(31),=C'Total logical records written :' MVC DSMSG+51(16),DSXL16 set count into message AWSMSG , SPACE 1 *********************************************************************** 00010000 * iebcopy * 00020000 *********************************************************************** 00030000 CLI DSLODPGM,C' ' load program specified? BNH ICOPYX00 no, branch SPACE 1 AWSMSG , blank line MVC DCBDDNAM,DSOUTDD output ddname RDJFCB AWSUT3,MF=(E,DSRDJFCB) read the jfcb MVC DSMSG+1(7),=C'AWS240I' MVC DSMSG+19(31),=C'PDS(E) loading to dataset :' MVC DSMSG+51(44),JFCBDSNM AWSMSG , SPACE 1 SLR R1,R1 clear parameter register LINK EP=IEBCOPY invoke iebcopy LTR R15,R15 success? BZ ICOPYE90 yes, branch AWSMSG 24AE,'IEBCOPY unload failed' LA R15,8 set return code B ICOPYXIT exit SPACE 1 ICOPYE90 DS 0H unallocate if needed AWSMSG 249I,'PDS(E) load successful' AWSCALL AWSUNALC dynamic unallocation SPACE 1 ICOPYX00 DS 0H AWSMSG , blank line SLR R15,R15 zero return code SPACE 1 ICOPYXIT DS 0H return AWSEXIT , SPACE 1 LTORG , DROP TITLE 'AWSECOPY - copy to aws output' *********************************************************************** * AWSECOPY - copy to aws output dataset (awsfile) * * msg AWS25n * *********************************************************************** SPACE 1 AWSECOPY CSECT , copy to aws output dataset AWSENTRY , SPACE 1 ZAP DSBLKCNT,=P'0' clear block counter SPACE 1 MVC AWSUT1+(DCBDDNAM-IHADCB)(L'DCBDDNAM),=CL8'AWSTEMP' CLI DSUNLPGM,C' ' unload requested? BH ECOPY010 yes, use awstemp, branch MVC AWSUT1+(DCBDDNAM-IHADCB)(L'DCBDDNAM),DSINDD CLI DSINDD,C' ' dataset already allocated? BH ECOPY010 yes, use indd argument, branch MVC AWSUT1+(DCBDDNAM-IHADCB)(L'DCBDDNAM),=CL8'AWSUT1' AWSCALL AWSALCI else allocate input dataset BNZ ECOPYXIT if error, branch SPACE 1 ECOPY010 DS 0H dataset is allocated, now open it LA R0,ECOPYEOF eof location STCM R0,7,AWSUT1+(DCBEODA-IHADCB) SLR R0,R0 clear register STH R0,AWSUT1+(DCBBLKSI-IHADCB) clear blocksize STH R0,AWSUT1+(DCBLRECL-IHADCB) clear lrecl OPEN (AWSUT1,(INPUT)),MF=(E,DSOPENL) open input dataset TM AWSUT1+(DCBOFLGS-IHADCB),DCBOFOPN opened ok? BO ECOPY020 yes, branch AWSMSG 250E,'Input dataset could not be opened' LA R15,8 return code B ECOPYXIT return ECOPY020 DS 0H write header labels AWSCALL AWSHDR write header labels BNZ ECOPYXIT SPACE 1 CLOSE AWSUT1,MF=(E,DSCLOSEL) close the file OI AWSUT1+(DCBRECFM-IHADCB),DCBRECU force to recfm=u OPEN (AWSUT1,(INPUT)),MF=(E,DSOPENL) reopen TM AWSUT1+(DCBOFLGS-IHADCB),DCBOFOPN opened ok? BO ECOPY030 yes, branch AWSMSG 251E,'Input dataset could not be re-opened' LA R15,8 return code B ECOPYXIT return SPACE 1 ECOPY030 DS 0H copy input dataset L R3,DSBUFTP current text pointer USING AWSREC,R3 addressability SPACE 1 GET AWSUT1 retrieve a block LR R4,R1 save location for future reference AP DSBLKCNT,CSP1 increment block count SLR R2,R2 clear register ICM R2,3,AWSUT1+(DCBLRECL-IHADCB) get block length STH R2,AWSLENC data block length AWSSWAP , set size and swap bytes MVC AWSFLGS,CSXA000 DATA FOLLOWS LA R3,6(,R3) point beyond aws cb ST R3,DSBUFTP ... make it so SPACE 1 TM DSFLAGS,DSFRECV variable length output? BZ ECOPY040 no, branch AWSCALL AWSEPUT else write variable output L R3,DSBUFTP new current text pointer USING AWSDBLK,R3 data block addressability SPACE 1 ECOPY040 DS 0H copy block into output buffer LR R0,R3 target of move LR R1,R2 target length LR R14,R4 source of move LR R15,R2 source length MVCL R0,R14 copy block into text buffer SPACE 1 ALR R3,R2 new current text pointer ST R3,DSBUFTP ... make it so SPACE 1 LA R0,DSBUFFER buffer origin AL R0,=A(BUFSIZE) r0 = origin of 2nd buffer CR R3,R0 text has extended into 2nd buffer? BL ECOPY050 no, branch AWSCALL AWSEPUT else write block immediately B ECOPY030 process next block SPACE 1 ECOPY050 DS 0H handle variable case if appropriate TM DSFLAGS,DSFRECV variable length output? BZ ECOPY030 no, process next block, branch AWSCALL AWSEPUT write the block now B ECOPY030 process next block EJECT ECOPYEOF DS 0H awsut1 reached eof MVC DSMSG+1(7),=C'AWS252I' blocks copied message MVC DSMSG+19(35),=c'Blocks exported into AWS tape file:' MVC DSMSG+54(12),=X'402020202020202020202120' ED DSMSG+54(12),DSBLKCNT set count into message OI DSMSG+65,C'0' AWSMSG , write the message SPACE 1 CLOSE AWSUT1,MF=(E,DSCLOSEL) close input file FREEPOOL AWSUT1 release buffers SPACE 1 NI AWSUT1+(DCBRECFM-IHADCB),255-DCBRECU clear recfm SLR R0,R0 clear register STH R0,AWSUT1+(DCBBLKSI-IHADCB) clear blocksize STH R0,AWSUT1+(DCBLRECL-IHADCB) clear lrecl SPACE 1 SLR R15,R15 zero return code SPACE 1 ECOPYXIT DS 0H exit AWSEXIT , return to caller SPACE 1 LTORG , DROP , TITLE 'AWSUNALC - Unallocate files' *********************************************************************** * AWSUNALC - Unallocate files * * msg AWS26n * *********************************************************************** SPACE 1 AWSUNALC CSECT , Unallocate files AWSENTRY , SPACE 1 TM DSFLAGS,DSFDYUT1 awsut1 dynamically allocated? BZ UNALC010 no, branch MVC DSUDDNM1,=CL8'AWSUT1' LA R1,DSURBP SVC 99 release awsut1 LTR R15,R15 ok? BZ UNALC010 yes, branch LA R3,DSURB rb location USING S99RB,R3 input rb addressability LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 260E,'Unallocation of ddname AWSUT1 failed' LA R15,8 set return code B UNALCXIT exit SPACE 1 UNALC010 DS 0H unallocate awstemp TM DSFLAGS,DSFDYTMP awstemp dynamically allocated? BZ UNALC020 no, branch MVC DSUDDNM1,=CL8'AWSTEMP' LA R1,DSURBP SVC 99 release awstemp LTR R15,R15 ok? BZ UNALC020 yes, branch LA R3,DSURB rb location USING S99RB,R3 input rb addressability LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 261E,'Unallocation of ddname AWSTEMP failed' LA R15,8 set return code B UNALCXIT exit SPACE 1 UNALC020 DS 0H unallocate sysin TM DSFLAGS,DSFDYSYI sysinp dynamically allocated? BZ UNALC030 no, branch MVC DSUDDNM1,=CL8'SYSIN' LA R1,DSURBP SVC 99 release sysin LTR R15,R15 ok? BZ UNALC030 yes, branch LA R3,DSURB rb location USING S99RB,R3 input rb addressability LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 262E,'Unallocation of ddname AWSTEMP failed' LA R15,8 set return code B UNALCXIT exit SPACE 1 UNALC030 DS 0H unallocate sysprint TM DSFLAGS,DSFDYSYP sysinp dynamically allocated? BZ UNALC040 no, branch MVC DSUDDNM1,=CL8'SYSPRINT' LA R1,DSURBP SVC 99 release sysin LTR R15,R15 ok? BZ UNALC040 yes, branch LA R3,DSURB rb location USING S99RB,R3 input rb addressability LR R1,R3 set rb location LR R0,R15 return code AWSCALL AWSDYNE format dynalloc error messages AWSMSG 263E,'UNALLOCATION of ddname SYSPRINT failed' LA R15,8 set return code B UNALCXIT exit SPACE 1 UNALC040 DS 0H successful NI DSFLAGS,255-DSFDYUT1-DSFDYTMP-DSFDYSYI-DSFDYSYP SLR R15,R15 zero return code SPACE 1 UNALCXIT DS 0H exit AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSSKPTF - skip to file' *********************************************************************** * AWSSKPTF - skip to file * * msg AWS27n * *********************************************************************** SPACE 1 AWSSKPTF CSECT , skip to file AWSENTRY , SPACE 1 LH R3,DSINFLNO file number requested CLI DSUSESL,C'N' standard labels in use? BE SKPTF010 no, branch MH R3,=H'3' multiply by 3 (hdr + data + tlr) SH R3,=H'2' header absolute file number SPACE 1 SKPTF010 DS 0H position to absolute file number SLR R2,R2 tape marks encountered BCTR R3,0 tape marks needed relative to zero SPACE 1 SKPTF020 DS 0H check position CLR R2,R3 desired tapemark? BE SKPTF900 yes, exit SPACE 1 SKPTF030 DS 0H find next tape mark AWSCALL AWSIGET get a block BNZ SKPTF040 if error, branch L R4,DSBUFTP block location USING AWSREC,R4 addressability CLC AWSFLGS,CSX4000 tape mark? BNE SKPTF030 no, continue LA R2,1(,R2) increment tape marks found B SKPTF020 continue SPACE 1 SKPTF040 DS 0H error handler CH R15,=H'-4' eof reached? BNE SKPTFXIT no, error, branch AWSMSG 270E,'End of tape reached while positioning' LA R15,8 B SKPTFXIT SPACE 1 SKPTF900 DS 0H good return SLR R15,R15 zero return code SPACE 1 SKPTFXIT DS 0H exit AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSIMLBL - get label values' *********************************************************************** * AWSIMLBL - get label values * * msg AWS28n, AWS29n, AWS30n * *********************************************************************** SPACE 1 AWSIMLBL CSECT , process input labels AWSENTRY , SPACE 1 CLI DSUSESL,C'N' standard labels expected? BE ILBL900 no, branch SPACE 1 TM DSFLAGS,DSFVOLF vol1 encountered previously? BO ILBL100 yes, branch OI DSFLAGS,DSFVOLF else indicate vol1 checked AWSCALL AWSIGET get a block BNZ ILBLXIT L R3,DSBUFTP current text pointer USING AWSREC,R3 addressability SPACE 1 ILBL010 DS 0H check vol1 if present CLC AWSFLGS,CSXA000 correct flags? BE ILBL030 yes, branch CLC AWSFLGS,CSX4000 end of tape? BNE ILBL020 no, branch AWSMSG 280E,'End of tape reached while positioning' LA R15,8 B ILBLXIT ILBL020 DS 0H AWSMSG 281E,'AWSFLGS unexpected value encountered' LA R15,8 B ILBLXIT SPACE 1 ILBL030 DS 0H check vol1 length CLC =C'HDR1',6(R3) hdr1 found? BE ILBL110 yes, branch SLR R0,R0 clear register ICM R0,3,AWSLENC current block length CH R0,=H'80' 80 bytes? BE ILBL040 yes, branch AWSMSG 282E,'VOL1 label record length is other than 80 bytes' LA R15,8 B ILBLXIT SPACE 1 ILBL040 DS 0H validate vol1 LA R3,6(,R3) position at data block CLC =C'VOL1',0(R3) vol1 label? BE ILBL050 yes, branch AWSMSG 283E,'VOL1 label not found' LA R15,8 B ILBLXIT SPACE 1 ILBL050 DS 0H verify volser SPACE 1 CLC DSTVOL,DSVOL1SR-DSVOL1(R3) volser correct? BE ILBL100 yes, branch AWSMSG 285E,'Incorrect volume serial number encountered' LA R15,8 B ILBLXIT SPACE 1 ILBL100 DS 0H validate hdr1 values AWSCALL AWSIGET get a block BNZ ILBLXIT L R3,DSBUFTP current text pointer CLC AWSFLGS,CSXA000 correct flags? BE ILBL110 yes, branch AWSMSG 286E,'HDR1 AWSFLGS invalid' LA R15,8 B ILBLXIT SPACE 1 ILBL110 DS 0H check lengths SLR R0,R0 clear register ICM R0,3,AWSLENC length of current block CH R0,=H'80' 80 byte block? BE ILBL120 yes, branch AWSMSG 287E,'HDR1 length is other than 80 bytes' LA R15,8 B ILBLXIT exit SPACE 1 ILBL120 DS 0H perform hdr1 checks LA R3,6(,R3) position beyond aws control block CLC =C'HDR1',0(R3) HDR1 label? BE ILBL130 yes, branch SH R3,=H'6' backup six bytes CLC =C'VOL1',6(R3) VOL1 label? BE ILBL030 yes, branch AWSMSG 288E,'HDR1 label not found' LA R15,8 B ILBLXIT SPACE 1 ILBL130 DS 0H process HDR1 values MVC DSMSG+1(7),=C'AWS284I' MVC DSMSG+19(31),=C'AWS HDR1 volume serial number :' MVC DSMSG+51(6),DSHDR1SR-DSHDR1(R3) AWSMSG , SPACE 1 PACK DSDWORK,DSHDR1SQ-DSHDR1(4,R3) CVB R0,DSDWORK convert seq to binary CH R0,DSINFLNO agrees with file number requested? BE ILBL140 yes, branch AWSMSG 289E,'HDR1 file number disagrees with that expected' LA R15,8 B ILBLXIT SPACE 1 ILBL140 DS 0H validate dataset name MVC DSTDSN,CSBLNKS clear MVC DSOUTDSN,DSINDSN AWSCALL AWSTPDSN set 17 byte dsn expected MVC DSMSG+1(7),=C'AWS290I' MVC DSMSG+19(31),=C'Requested 44 byte dataset name:' MVC DSMSG+51(44),DSINDSN AWSMSG , SPACE 1 MVC DSMSG+1(7),=C'AWS291I' MVC DSMSG+19(31),=C'AWS HDR1 17 byte dataset name:' MVC DSMSG+51(17),DSHDR1NM-DSHDR1(R3) AWSMSG , SPACE 1 CLC DSTDSN,DSHDR1NM-DSHDR1(R3) tape dsn correct? BE ILBL150 yes, branch CLC DSTDSN,CSBLNKS input dsn omitted? BE ILBL150 yes, branch AWSMSG 292E,'HDR1 dataset name disagrees with that specified' LA R15,8 B ILBLXIT SPACE 1 ILBL150 DS 0H capture number blocks expected MVC DSXL16(4),=4C'0' fill with zeros MVC DSXL16+4(6),DSHDR1BL-DSHDR1(R3) low block count CLI DSHDR1BH-DSHDR1(R3),C'0' high block count specified? BL *+10 no, branch MVC DSXL16(4),DSHDR1BH-DSHDR1(R3) PACK DSDWORK,DSXL16(10) pack block count CVB R0,DSDWORK total block count ST R0,DSBLKCTI save for future reference SPACE 1 ILBL200 DS 0H process hdr2 AWSCALL AWSIGET get a block BNZ ILBLXIT L R3,DSBUFTP block location CLC AWSFLGS,CSXA000 correct flags? BE ILBL210 yes, branch AWSMSG 293E,'AWSFLGS is other than expected value' LA R15,8 B ILBLXIT SPACE 1 ILBL210 DS 0H check hdr2 length SLR R0,R0 clear register ICM R0,3,AWSLENC length of current block CH R0,=H'80' 80 bytes? BE ILBL220 yes, branch AWSMSG 294E,'HDR2 record length other than 80 bytes' LA R15,8 B ILBLXIT SPACE 1 ILBL220 DS 0H validate hdr2 label LA R3,6(,R3) position at data record CLC =C'HDR2',0(R3) hdr2 label? BE ILBL230 yes, branch AWSMSG 295E,'HDR2 label not found' LA R15,8 B ILBLXIT SPACE 1 ILBL230 DS 0H gather hdr2 values MVC DSRECFM(1),DSHDR2RF-DSHDR2(R3) recfm MVC DSRECFM+1(1),DSHDR2BA-DSHDR2(R3) block attribute MVC DSASA,DSHDR2CC-DSHDR2(R3) carriage control PACK DSDWORK,DSHDR2BL-DSHDR2(L'DSHDR2BL,R3) block size CVB R0,DSDWORK ... convert to binary STCM R0,3,DSBLKSIZ ... and save PACK DSDWORK,DSHDR2RL-DSHDR2(L'DSHDR2RL,R3) lrecl CVB R0,DSDWORK ... convert to binary STCM R0,3,DSLRECL ... and save CVD R0,DSDWORK convert to decimal MVC DSXL16(6),=X'F02020202120' ED DSXL16(6),DSDWORK+5 edit MVI DSXL16+5,C'0' make printable MVC DSMSG+1(7),=C'AWS296I' MVC DSMSG+19(31),=C'AWS HDR2 tape dataset lrecl :' MVC DSMSG+51(5),DSXL16+1 set lrecl into message AWSMSG , write message SPACE 1 TRT DSHDR2LB-DSHDR2(L'DSHDR2LB,R3),CSNUMTRT lb numeric? BNZ ILBL240 no, branch PACK DSDWORK,DSHDR2LB-DSHDR2(L'DSHDR2LB,R3) large blocksize CVB R0,DSDWORK convert to binary LTR R0,R0 specified? BZ ILBL240 no, branch STCM R0,3,DSBLKSIZ else save as blocksize SPACE 1 ILBL240 DS 0H write messages SLR R0,R0 clear register ICM R0,3,DSBLKSIZ load blocksize CVD R0,DSDWORK convert to decimal MVC DSXL16(6),=X'F02020202120' ED DSXL16(6),DSDWORK+5 edit MVI DSXL16+5,C'0' make printable MVC DSMSG+1(7),=C'AWS297I' MVC DSMSG+19(31),=C'AWS HDR2 tape dataset blksize :' MVC DSMSG+51(5),DSXL16+1 set blksize into message AWSMSG , write message SPACE 1 MVC DSMSG+1(7),=C'AWS298I' MVC DSMSG+19(31),=C'AWS HDR2 tape dataset recfm :' MVC DSMSG+51(2),DSRECFM AWSMSG , write message SPACE 1 ILBL250 DS 0H prepare for next block AWSCALL AWSIGET get next block (should be tape mark) BNZ ILBLXIT L R3,DSBUFTP text location CLC AWSFLGS,CSX4000 tape mark? BE ILBL900 yes, branch AWSMSG 299E,'Expected tape mark after HDR2 label' LA R15,8 B ILBLXIT SPACE 1 ILBL900 DS 0H good return SLR R15,R15 zero return code SPACE 1 ILBLXIT DS 0H exit AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSIMTLR - import process trailer label' *********************************************************************** * AWSIMTLR - import process trailer label * * msg AWS31n * *********************************************************************** space 1 AWSIMTLR CSECT , import process trailer label AWSENTRY , SPACE 1 CLI DSUSESL,C'N' standard labels expected? BE ITLR900 no, branch AWSCALL AWSIGET get a block BNZ ITLRXIT L R3,DSBUFTP current text pointer USING AWSREC,R3 addressability SPACE 1 CLC AWSFLGS,CSXA000 correct flags? BE ITLR020 yes, branch CLC AWSFLGS,CSX4000 end of tape? BNE ITLR010 no, branch AWSMSG 310E,'End of tape reached while positioning' LA R15,8 B ITLRXIT ITLR010 DS 0H AWSMSG 311E,'AWSFLGS unexpected value encountered' LA R15,8 B ITLRXIT SPACE 1 ITLR020 DS 0H check vol1 length CLC =C'EOF1',6(R3) EOF1 found? BE ITLR030 yes, branch AWSMSG 312E,'EOF1 label expected and not found' LA R15,8 B ITLRXIT space 1 ITLR030 DS 0H LA R3,6(,R3) position beyond aws cb MVC DSXL16(4),=4C'0' fill with zeros MVC DSXL16+4(6),DSHDR1BL-DSHDR1(R3) low block count CLI DSHDR1BH-DSHDR1(R3),C'0' high block count specified? BL *+10 no, branch MVC DSXL16(4),DSHDR1BH-DSHDR1(R3) PACK DSDWORK,DSXL16(10) pack block count CVB R0,DSDWORK total block count ST R0,DSBLKCTI save for future reference MVC DSXL16,=X'40202020202020202020202020202120' ED DSXL16,DSDWORK edit value OI DSXL16+15,C'0' make printable MVC DSMSG+1(7),=C'AWS313I' message id MVC DSMSG+19(31),=C'AWS EOF1 label block count :' MVC DSMSG+51(16),DSXL16 set count into message AWSMSG , AWSMSG , blank line AWSMSG , blank line SPACE 1 ITLR900 DS 0H normal exit SLR R15,r15 zero return code SPACE 1 ITLRXIT DS 0H return AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSIGET - import (get) a block' *********************************************************************** * AWSIGET - import (get) a block * * msg AWS32n * * * * This function returns a pointer (dsbuftp) pointing to the next * * block in the input AWSFILE dataset. * * * *********************************************************************** SPACE 1 AWSIGET CSECT , import (get) a block AWSENTRY , SPACE 1 LA R0,6 r0=amount of text needed LA R1,DSBUFFER r1=position to place text ST R1,DSBUFTP for caller's reference SLR R4,R4 r4=amount of text satisfied LR R5,R0 r5=amount of text needed SPACE 1 IGET010 DS 0H retrieve aws header AWSCALL AWSGTXT get some text BNZ IGETEOF if eof, branch ALR R4,R0 amount of text accumlated ALR R1,R0 r1=put text here LR R0,R5 compute amount still needed SR R0,R4 r0=amount of text still needed BNZ IGET010 if more needed, branch SPACE 1 LA R3,DSBUFFER aws header location USING AWSREC,R3 addressability AWSSWAP , swap bytes, set sizes wap byte SLR R0,R0 clear register ICM R0,3,AWSLENC r0=amount of text needed LA R1,6(,R3) r1=position to place text SLR R4,R4 r4=amount of text satisfied LR R5,R0 r5=amount of text needed SPACE 1 IGET020 DS 0H retrieve data block AWSCALL AWSGTXT get some text BNZ IGETEOF if eof, branch ALR R4,R0 amount of text accumlated ALR R1,R0 r1=put text here LR R0,R5 compute amount still needed SR R0,R4 r0=amount of text still needed BNZ IGET020 if more needed, branch SPACE 1 IGET900 DS 0H exit SLR R15,R15 zero return code B IGETXIT exit SPACE 1 IGETEOF DS 0H eof reached LH R15,=H'-4' indicate eof SPACE 1 IGETXIT DS 0H return to caller AWSEXIT , SPACE 1 LTORG , DROP , TITLE 'AWSGTXT - get AWS text' *********************************************************************** * AWSGTXT - get AWS text * * * * calling parameters: r1 -> location where text is to be placed * * r0 -> length of text requested * * * * exit parameters: r0 -> length of text returned * * r15= -4 when eof * * * *********************************************************************** SPACE 1 AWSGTXT CSECT , get AWS text AWSENTRY , SPACE 1 LR R3,R1 r3=location at which to return text LR R4,R0 r4=length of text requested LA R5,AWSUT2 r5=input dcb location USING IHADCB,R5 ... addressability LA R0,GTXTEOF eof routine location STCM R0,7,DCBEODA ... set into dcb SPACE 1 SLR R2,R2 clear register LR R15,R2 clear registger ICM R15,3,DSGTXTL r15=length of source ICM R14,15,DSGTXTP r14=current location in input buffer ST R2,DSGTXTP assume all text will be used STH R2,DSGTXTL ... and entire length * LTR R14,R14 r14=source text already present? BNZ GTXT010 yes, branch SPACE 1 GET AWSUT2 get some data LR R14,R1 r14=source text location SLR R15,R15 clear register ICM R15,3,DCBLRECL r15=length of source TM DCBRECFM,DCBRECU undefined? BO GTXT010 yes, branch TM DCBRECFM,DCBRECF fixed? BO GTXT010 yes, branch LA R14,4(,R14) r14=source text location (after rdw) SH R15,=H'4' r15=source text length (minus rdw) SPACE 1 GTXT010 DS 0H r3=trg,r4=trglen,r14=src,r15=srclen CLR R15,R4 source length exceeds target length? BNH GTXT020 no, branch LA R0,0(R4,R14) r0= *next* source location ST R0,DSGTXTP ... set next pointer (for next call) SLR R15,R4 r15=*next* source length STCM R15,3,DSGTXTL ... set next length (for next call) LR R15,R4 override current source length SPACE 1 GTXT020 DS 0H r3=trg,r4=trglen,r14=src,r15=trglen LR R2,R15 save length for later use LR R0,R3 target location LR R1,R15 target length MVCL R0,R14 copy into user buffer SLR R15,R15 B GTXTXIT return SPACE 1 GTXTEOF DS 0H end of input reached SLR R2,R2 zero length returned ST R2,DSGTXTP zero pointer STH R2,DSGTXTL clear remaining length LH R15,=H'-4' indicate eof SPACE 1 GTXTXIT DS 0H L R1,4(,R13) caller's savearea ST R2,20(,R1) length returned in caller's r0 SPACE 1 AWSEXIT , SPACE 1 LTORG , DROP TITLE 'Dummy functions pending implementation' *********************************************************************** * Dummy functions pending implementation * *********************************************************************** SPACE 1 *AWSDUMMY AWSDUMMY , dummy csect (expansion?) TITLE 'AWSCOMST - Constant common data' *********************************************************************** * AWSCOMST - Constant common data * *********************************************************************** SPACE 1 AWSCOMST CSECT , constant common data SPACE 1 CSPARST1 DC 256YL1(0) locate keyword ORG CSPARST1+C'=' keyword suffix DC C'=' ORG , SPACE 1 CSPARST2 DC 256YL1(0) locate keyword ORG CSPARST2+C' ' delimiter #1 DC C' ' ORG CSPARST2+C',' delimiter #2 DC C',' ORG , SPACE 1 CSPARST3 DC 256YL1(0) locate keyword ORG CSPARST3+c'"' delimiter #1 DC C'"' ORG CSPARST3+C'''' delimiter #2 DC C'''' ORG , SPACE 1 CSNUMTRT DC 256X'FF' NUMERIC TEXT TRT TABLE ORG CSNUMTRT+C'0' DC 10X'00' ORG , SPACE 1 CSHEXTR EQU *-C'0' hexadecimal translate table DC C'0123456789ABCDEF' ORG , SPACE 1 CSAWSPRT DC A(AWSPRNT) print function CSAWSDYE DC A(AWSDYNE) dynamic allocation error function CSAWSEPT DC A(AWSEPUT) put function CSAWSMRK DC A(AWSMARK) write tape mark function CSAWSIGE DC A(AWSIGET) read a logical aws block CSF0 DC F'0' full word of zero CSH4 DC Y(4) half word 4 CSH80 DC Y(80) half word 80 CSP1 DC P'1' packed value 1 CSXA000 DC X'A000' block flags CSX4000 DC X'4000' tape mark flags CSBLNKS DC CL133' ' some blanks LTORG , TITLE 'AWSDATA - Dynamic common data' *********************************************************************** * AWSDATA - Dynamic common data * *********************************************************************** SPACE 1 AWSDATA CSECT , dynamic storage data areas DSSTACK DS (STACKCT*18)F savearea stack AWSDYNAM EQU * origin addressable dynamic storage DSDWORK DS D double word workarea DSFWORK DS F full word work area DSDATAP DS A origin of relocated awsdata DSSTACKP DS A origin of stack DSBUFTP DS A loc of next text in output buffer DSBUFEND DS A end of current block DSGTXTP DS A get text pointer DSBLKCTI DS F block count expected DSHWORK DS H half word work area DSFILECT DS H logical file number DSLSTSIZ DS H size of last block written DSCURSIZ DS H size of current block written DSINFLNO DS H infile= numeric argument DSBLKSIZ DS H block size DSGTXTL DS H get text length DSLRECL DS H lrecl DSRECFM DS CL2 recfm DSASA DS C carriage control DSFLAGS DS X State flags DSFVOLF EQU X'80' ... VOL1 has been written DSFRECV EQU X'40' ... output variable length records DSFFLUSH EQU X'20' ... flush residual output DSFDYUT1 EQU X'10' ... awsut1 dynamically allocated DSFDYTMP EQU X'08' ... awstemp dynamically allocated DSFDYSYI EQU X'04' ... sysin dynamically allocated DSFDYSYP EQU X'02' ... sysprint dynamically allocated DSFOPNEX EQU X'01' ... awsfile is open for export DSFLAGS2 DS X State flags 2 DSFIMPRT EQU X'80' ... import function invoked DSFEXPRT EQU X'40' ... export function invoked DSFFRAGD EQU X'20' ... AWS CB ITSELF IS FRAGMENTED SPACE 1 DSHETCMP DS CL1 HET COMPRESSION REQUESTED DSHETMTH DS CL1 HET COMPRESSION METHOD DSHETLVL DS CL1 HET COMPRESSION LEVEL DSHETIDR DS CL1 HET IDRC DSHETCSZ DS CL5 HET CHUNK SIZE DSBLKCNT DS PL6 DATASET BLOCK COUNT DSOWNER DS CL10 owner= volume owner DSINDSN DS CL44 indsn= dataset name DSOUTDSN DS CL44 outdsn= dataset name DSTDSN DS CL17 tapedsn= dataset name DSINDD DS CL8 indd= ddname DSOUTDD DS CL8 outdd= ddname DSINFLNC DS CL8 infile= character argument DSUNLPGM DS CL8 unload= program DSLODPGM DS CL8 load= program DSUNLTYP DS CL8 unload type (repro, export, etc) DSUSESL DS CL1 use standard labels flag DSCARD DS CL80 sysin control statements DSTVOL DS CL6 tape volser DSJOBNM DS CL8 job name DSSTEPNM DS CL8 step name SPACE 1 DSXL16 DS XL16 16 byte work area DSHEXWK DS CL9 hex work area DSIBLKCT DS PL8 aws input block count DSIRECCT DS PL8 aws input record count SPACE 1 DS 0D AWSRELOC EQU * beginning of relocated storage SPACE 1 DSOPENL OPEN 0,MF=L open parameter list DSCLOSEL CLOSE 0,MF=L close parameter list DSRDJFCB RDJFCB 0,MF=L rdjfcb parameter list SPACE 1 DSPAGECT DC PL2'0' page count DSLINECT DC PL2'90' line count DSMSG DC CL133' ' message buffer DSMSG1 DC CL133' ' message buffer DSHEADER DC CL133' ' ORG DSHEADER DC C'1AWSSL - AWS Virtual Tape (standard labels) - ' DC C'Version 1.9G - Copyright (C) 2002 - ' DC C'By Reed H. Petty, rhp@draper.net' ORG DSHEADER+123 DC C' Page' DSPAGE DC CL4' 1' ORG , SPACE 1 DSJFCBL DS 0F RDJFCB LIST DC X'87',AL3(INFMJFCB) JFCB EXIT LST SPACE 1 PRINT NOGEN IEFJFCBN LIST=YES JFCB PRINT GEN EJECT *********************************************************************** * Dynamic allocation control blocks * *********************************************************************** SPACE 1 DS 0F DSARBP DC X'80',AL3(DSARB) input dataset request block DSARB DC XL(S99RBEND-S99RB)'00' request block SPACE 1 DSATXTP DC A(DSADDNM) ddname DC A(DSADSNM) dataset name DC A(DSASTATS) dataset status DC X'80',AL3(DSADISP) normal disposition SPACE 1 DSADDNM DC YL2(DALDDNAM),YL2(1),YL2(8) DSADDNM1 DC CL8'AWSUT1' SPACE 1 DSADSNM DC YL2(DALDSNAM),YL2(1),YL2(DSADSNML) DSADSNMT DC CL44' ' DSADSNML EQU *-DSADSNMT SPACE 1 DSASTATS DC YL2(DALSTATS),YL2(1),YL2(1),X'08' SHR SPACE 1 DSADISP DC YL2(DALNDISP),YL2(1),YL2(1),X'08' KEEP SPACE 1 DS 0F DSTARBP DC X'80',AL3(DSTARB) awstemp dataset request block DSTARB DC XL(S99RBEND-S99RB)'00' request block DSTATXTP DC A(DSTADDNM) ddname (AWSTEMP) DC A(DSTAUNIT) unit (SYSDA) DC A(DSTASPCU) space primary units (CYL) DC A(DSTASPCP) space primary qty (100) DC X'80',AL3(DSTASPCS) space secondary qty (100) DSTADDNM DC YL2(DALDDNAM),YL2(1),YL2(7),CL7'AWSTEMP' DSTAUNIT DC YL2(DALUNIT),YL2(1),YL2(5),CL5'SYSDA' DSTASPCU DC YL2(DALCYL),YL2(0) DSTASPCP DC YL2(DALPRIME),YL2(1),YL2(3),AL3(100) DSTASPCS DC YL2(DALSECND),YL2(1),YL2(3),AL3(100) SPACE 1 DS 0F DSSARBP DC X'80',AL3(DSSARB) sysin dataset request block DSSARB DC XL(S99RBEND-S99RB)'00' request block DSSATXTP DC A(DSSADDNM) ddname (SYSIN) DC A(DSSAUNIT) unit (SYSDA) DC A(DSSASPCU) space primary units (CYL) DC A(DSSASPCP) space primary qty (1) DC X'80',AL3(DSSASPCS) space secondary qty (1) DSSADDNM DC YL2(DALDDNAM),YL2(1),YL2(5),CL7'SYSIN' DSSAUNIT DC YL2(DALUNIT),YL2(1),YL2(5),CL5'SYSDA' DSSASPCU DC YL2(DALTRK),YL2(0) DSSASPCP DC YL2(DALPRIME),YL2(1),YL2(3),AL3(1) DSSASPCS DC YL2(DALSECND),YL2(1),YL2(3),AL3(1) SPACE 1 DS 0F DSPARBP DC X'80',AL3(DSPARB) sysprint dataset request block DSPARB DC XL(S99RBEND-S99RB)'00' request block DSPATXTP DC A(DSPADDNM) ddname (SYSPRINT) DC X'80',AL3(DSPADUMY) dummy dd statement DSPADDNM DC YL2(DALDDNAM),YL2(1),YL2(8),CL8'SYSPRINT' DSPADUMY DC YL2(DALDUMMY),YL2(0) SPACE 1 DS 0F DSURBP DC X'80',AL3(DSURB) unallocation request block DSURB DC XL(S99RBEND-S99RB)'00' request block DSUTXTP DC X'80',AL3(DSUDDNM) ddname DSUDDNM DC YL2(DUNDDNAM),YL2(1),YL2(8) DSUDDNM1 DC CL8'AWSUT1' EJECT *********************************************************************** * VOL1 label * *********************************************************************** SPACE 1 DSVOL1 DC CL80' ' vol1 label ORG DSVOL1 DC CL4'VOL1' DSVOL1SR DS CL6 volser DC CL1' ' reserved DC CL5' ' vtoc pointer DC CL25' ' reserved DSVOL1OW DC CL10' ' owner DC CL29' ' reserved SPACE 1 *********************************************************************** * HDR1 label * *********************************************************************** SPACE 1 DSHDR1 DC CL80' ' hdr1 label ORG DSHDR1 DC CL4'HDR1' DSHDR1NM DS CL17 last 17 bytes of dsn DSHDR1SR DS CL6 volser DC CL4'0001' file section number DSHDR1SQ DC CL4'0000' file sequence number DC CL4' ' generation number DC CL2' ' generation version number DSHDR1CD DC CL6'000001' creation date, cyyddd,c=' '=1900 DC CL6'000000' expiration date DC CL1'0' not password protected DSHDR1BL DC CL6'000000' block count low order 6 bytes DC CL13'IBM OS/VS 370' system code DC CL3' ' reserved DSHDR1BH DC CL4' ' block count high order 4 bytes ORG , SPACE 1 *********************************************************************** * HDR2 label * *********************************************************************** SPACE 1 DSHDR2 DC CL80' ' hdr2 label ORG DSHDR2 DC C'HDR2' DSHDR2RF DS CL1 record format DSHDR2BL DS CL5 block length DSHDR2RL DS CL5 record length DC C'0' tape density, 0 = cartridge DC C'0' volume switch is not in progress DSHDR2JB DC CL8' ' jobname DC CL1'/' DSHDR2ST DC CL8' ' step name DC CL2' ' recording technique DSHDR2CC DC CL1' ' a=asa,m=machine,' '=none DC CL1' ' reserved DSHDR2BA DC CL1' ' block attribute * b=blocked records * s=spanned or standard * r=blocked and spanned or standard * unblocked DC CL2' ' reserved DC CL6'AWS19G' serial number of creating device DC CL1' ' checkpoint identifier DC CL22' ' reserved DSHDR2LB DC CL10' ' large block length ORG , EJECT *********************************************************************** * EOF1 label * *********************************************************************** DSEOF1 DC CL80' ' eof1 label ORG DSEOF1 DC CL4'EOF1' DSEOF1NM DS CL17 last 17 bytes of dsn DSEOF1SR DS CL6 volser DC CL4'0001' file section number DSEOF1SQ DC CL4'0000' file sequence number DC CL4' ' generation number DC CL2' ' generation version number DC CL6'000001' creation date, cyyddd,c=' '=1900 DC CL6'000001' expiration date DS CL1'0' not password protected DSEOF1BL DC CL6'000000' block count low order 6 bytes DC CL13'IBM OS/VS 370' system code DC CL3' ' reserved DSEOF1BH DC CL4'0000' block count high order 4 bytes ORG , SPACE 1 *********************************************************************** * EOF2 label * *********************************************************************** SPACE 1 DSEOF2 DC CL80' ' eof2 label ORG DSEOF2 DC C'EOF2' DSEOF2RF DS CL1 record format DSEOF2BL DS CL5 block length DSEOF2RL DS CL5 record length DC C'0' tape density, 0 = cartridge DC C'0' volume switch is not in progress DSEOF2JB DC CL8' ' jobname DC CL1'/' DSEOF2ST DC CL8' ' step name DC CL2' ' recording technique DSEOF2CC DC CL1' ' a=asa,m=machine,' '=none DC CL1' ' reserved DSEOF2BA DC CL1' ' block attribute * b=blocked records * s=spanned or standard * r=blocked and spanned or standard * unblocked DC CL2' ' reserved DC CL6'AWSSL ' serial number of creating device DC CL1' ' checkpoint identifier DC CL22' ' reserved DC CL10' ' large block length ORG , SPACE 1 *********************************************************************** * Data control blocks * *********************************************************************** SPACE 1 PRINT NOGEN AWSPRINT DCB DDNAME=AWSPRINT,DSORG=PS,MACRF=PM,RECFM=FBA,LRECL=133 SPACE 1 AWSUT1 DCB DDNAME=AWSUT1,DSORG=PS,MACRF=GL,EXLST=DSJFCBL AWSUT2 DCB DDNAME=AWSFILE,DSORG=PS,MACRF=GL AWSUT3 DCB DDNAME=AWSUT3,DSORG=PS,MACRF=PM SPACE 1 AWSFILE DCB DDNAME=AWSFILE,DSORG=PS,MACRF=PM SPACE 1 AWSCNTL DCB DDNAME=AWSCNTL,DSORG=PS,MACRF=GL SPACE 1 SYSIN DCB DDNAME=SYSIN,DSORG=PS,MACRF=PM,RECFM=FB,LRECL=80, * BLKSIZE=3120 PRINT GEN DROP SPACE 1 DSBUFFER DS 0D 128k I/O buffer location DSENDL EQU *-AWSRELOC length of relocatable storage AWSDATAL EQU *-AWSDATA data areas length EJECT *********************************************************************** * AWS block header definition * *********************************************************************** SPACE 1 AWSREC DSECT , AWS block header AWSLENC DS H block length AWSLENP DS H file data preceeding this block AWSFLGS DS H block flags AWSDBLK DS 0X data block origin END hercules-3.12/util/cckdload.hla0000664000175000017500000022542312564723224013422 00000000000000*/* ------------------------------------------------------------------- * Restore a cckd file to a real dasd unit. * The dasd unit must be offline. * * Invocation: * //step EXEC PGM=CCKDLOAD,PARM=unit * //STEPLIB DD DISP=SHR,DSN=apf.authorized.loadlib * //SYSPRINT DD SYSOUT=* * //SYSUT1 DD DISP=SHR,DSN=cckd.file * * ------------------------------------------------------------------ */ */* ------------------------------------------------------------------- * local macros * ------------------------------------------------------------------ */ MACRO &L #LLE &R,&A load little-endian &L IC &R,&A ICM &R,2,1+&A ICM &R,4,2+&A ICM &R,8,3+&A MEND MACRO &L #LHLE &R,&A load halfword little-endian &L SLR &R,&R IC &R,&A ICM &R,2,1+&A MEND MACRO &L #LC &R,&A load conditional &L TM cdevhdr_options,CCKD_BIGENDIAN BO #LC&SYSNDX.A #LLE &R,&A B #LC&SYSNDX.B #LC&SYSNDX.A L &R,&A #LC&SYSNDX.B DS 0H MEND MACRO &L #LHC &R,&A load halfword conditional &L TM cdevhdr_options,CCKD_BIGENDIAN BO #LHC&SYSNDX.A #LHLE &R,&A B #LHC&SYSNDX.B #LHC&SYSNDX.A SLR &R,&R ICM &R,3,&A #LHC&SYSNDX.B DS 0H MEND MACRO &L #READ &OFFSET=,&LENGTH=,&ADDR= read a cckd block &L LA r1,pl .* AIF ('&OFFSET'(1,1) EQ '(').r1 LA re,&OFFSET AGO .x1 .r1 LR re,&OFFSET(1) .x1 ANOP .* AIF ('&LENGTH'(1,1) EQ '(').r2 LA rf,&LENGTH AGO .x2 .r2 LR rf,&LENGTH(1) .x2 ANOP .* AIF ('&ADDR'(1,1) EQ '(').r3 LA r0,&ADDR AGO .x3 .r3 LR r0,&ADDR(1) .x3 ANOP .* STM re,r0,0(r1) L rf,=A(readr) BALR re,rf MEND MACRO &L #WRITE &ADDR= write a ckd track image .* AIF ('&ADDR'(1,1) EQ '(').r1 &L LA r1,&ADDR AGO .x1 .r1 ANOP &L LR r1,&ADDR(1) .x1 ANOP L rf,=A(writer) BALR re,rf MEND MACRO &L #MSG &MSG,&TYPE=CALL messages LCLA &A,&N,&O LCLC &C GBLA &MSG_IX GBLC &MSGS(256) AIF ('&TYPE' EQ 'CALL').CALL, x ('&TYPE' EQ 'GEN').GEN MNOTE 8,'Invalid type specified' MEXIT .* .CALL ANOP &MSG_IX SETA &MSG_IX+1 &MSGS(&MSG_IX) SETC '&MSG' &L L re,=A(#MSG&MSG_IX) LA rf,L'#MSG&MSG_IX &A SETA 2 &O SETA 0 &N SETA N'&SYSLIST AGO .PL0 .PLLOOP ANOP LA re,&SYSLIST(&A) &A SETA &A+1 AIF (&A GT &N).PLX14 LA rf,&SYSLIST(&A) &A SETA &A+1 .PL0 ANOP AIF (&A GT &N).PLX15 LA r0,&SYSLIST(&A) &A SETA &A+1 AIF (&A GT &N).PLX0 LA r1,&SYSLIST(&A) &A SETA &A+1 AIF (&A GT &N).PLX1 STM re,r1,pl+&O &O SETA &O+16 AGO .PLLOOP .PLX14 ST re,pl+&O AGO .CALL2 .PLX15 STM re,rf,pl+&O AGO .CALL2 .PLX0 STM re,r0,pl+&O AGO .CALL2 .PLX1 STM re,r1,pl+&O .CALL2 LA r1,pl L rf,=a(msgr) BALR re,rf MEXIT .* .GEN ANOP AIF ('&L' EQ '').GENNOL &L DS 0H .GENNOL ANOP &A SETA 1 .GENLOOP AIF (&A GT &MSG_IX).MEND #MSG&A DC C&MSGS(&A) &A SETA &A+1 AGO .GENLOOP .MEND MEND */* ------------------------------------------------------------------- * mainline routine * ------------------------------------------------------------------ */ main CSECT , main AMODE 31 main RMODE ANY B init-*(,rf) DC AL1(init-*) pgmid DC CL8'cckdload' vrm DC X'000102' version 0 release 1 modlvl 2 CZV70 DC C' &SYSDATE &SYSTIME ' init SAVE (14,12) LR rc,rf set base reg USING main,rc LA ra,4095(,rc) set 2nd base reg USING main+4095,ra LR r2,r1 copy parm reg */* ------------------------------------------------------------------- * obtain and initialize workareas * ------------------------------------------------------------------ */ STORAGE OBTAIN,LENGTH=workl,BNDRY=PAGE get work area ST r1,8(,rd) chain save areas ST rd,4(,r1) LR rd,r1 set area base USING work,rd MVC workid,pgmid set area identifier LA r0,work+8 clear the area L r1,=a(workl-8) SLR rf,rf MVCL r0,re STORAGE OBTAIN,LENGTH=work24l,LOC=BELOW,BNDRY=PAGE 24 bit area LR rb,r1 set 24-bit area base USING work24,rb MVC work24id,pgmid set 24-bit area identifier LA r0,work24+4 clear the 24-bit area L r1,=a(work24l-4) SLR rf,rf MVCL r0,re */* ------------------------------------------------------------------- * process PARM= : * ------------------------------------------------------------------ */ N r2,=A(X'7fffffff') test parameter reg BZ Enoparm invalid parameter list L r3,0(,r2) point to parameters N r3,=A(X'7fffffff') test parameter reg BZ Enoparm invalid parameter list LH r4,0(,r3) get length of parameters LTR r4,r4 test length BNP Enoparm invalid parameter list BCTR r4,0 decrement for EX LA r3,2(,r3) point past length SLR r2,r2 clear TRT register */* 1st and only parm is unit address in hex */ XC dw,dw clear double-word work area CH r4,=Y(4) check 2nd parm length BNL Ebadparm error if too long EX r4,parmmvc copy 2nd parameter */* MVC dw(0),0(r3) *** executed *** */ TR dw,upcase convert to uppercase EX r4,parmhexc test if all hex digits */* TRT drwdw(0),hexchars *** executed *** */ BNZ Ebadparm error if not EX r4,parmhex convert to hex digits */* TR dw(0),hextab *** executed *** */ LA r5,1(,r4) EX r5,parmpack get hex value */* PACK dw2,dw(0) *** executed *** */ SLR r5,r5 clear unit address ICM r5,3,dw2+5 load hex value STH r5,unit save unit address */* ------------------------------------------------------------------- * print initialization message * ------------------------------------------------------------------ */ TIME DEC STM r0,r1,ctime get time and date of load LA r1,ctime LA r0,dtime BAL re,datetime #MSG '%s:8 %d:1.%d:1.%d:1 load starting at %s:20', X pgmid,vrm,vrm+1,vrm+2,dtime */* ------------------------------------------------------------------- * open the cckd file * ------------------------------------------------------------------ */ MVC sysut1,m_sysut1 copy the model dcb MVC sysut1e,m_sysut1e copy the model dcbe ut1 USING IHADCB,sysut1 LA r1,sysut1e set dcbe address ST r1,ut1.DCBDCBE in the dcb DEVTYPE ut1.DCBDDNAM,devta get device info LTR rf,rf test return code BNZ Edevterr error if non-zero TM devta+2,UCB3DACC check for dasd device BNO Enotdasd1 error if not on dasd MVC openl,m_openl copy model open list OPEN (sysut1,INPUT),MODE=31,MF=(E,openl) open the cckd file TM ut1.DCBOFLGS,DCBOFOPN did cckd file open ? BNO Eopenerr no, open error CLC ut1.DCBBLKSI,=Y(16384) check block size CZV70 BNE Ebadblksz error if not 16384 CZV70 MVC pl(l_tcpl),m_tcpl copy model parm list TRKCALC FUNCTN=TRKCAP,TYPE=devta+3,RKDD==x'01004000', CZV70 x REGSAVE=YES,MF=(E,pl) calculate blks/trk LTR rf,rf test return code BNZ Etrkcalc error if non-zero ST r0,bpt save blks/trk */* ------------------------------------------------------------------- * read the CKDDASD_DEVHDR * ------------------------------------------------------------------ */ #READ OFFSET=0,LENGTH=CKDDASD_DEVHDR_SIZE,ADDR=devhdr USING CKDDASD_DEVHDR,devhdr TR devhdr_devid,A2E CLC devhdr_devid,=C'CKD_C370' check devid BNE Edevid #LLE r1,devhdr_heads get number of heads ST r1,heads #LLE r1,devhdr_trksize get trk size ST r1,trklen IC r1,devhdr_devtype get device type STC r1,devtype+1 STC r1,devtype TR devtype(1),devtype_table get 1st byte CLI devtype,0 known type ? BE Ebaddevt no, error */* ------------------------------------------------------------------- * read the CCKDDASD_DEVHDR * ------------------------------------------------------------------ */ #READ OFFSET=CKDDASD_DEVHDR_SIZE,LENGTH=CCKDDASD_DEVHDR_SIZE, x ADDR=cdevhdr USING CCKDDASD_DEVHDR,cdevhdr TM cdevhdr_options,CCKD_OPENED was file closed ? BNO openok yes, continue #MSG 'Warning... cckd file was not closed' MVC result,=A(4) openok DS 0H #LC r1,cdevhdr_cyls number of cylinders ST r1,cyls #LC r2,cdevhdr_numl1tab l1 table entries ST r2,numl1tab */* ------------------------------------------------------------------- * read the CCKD_L1TAB * ------------------------------------------------------------------ */ SLL r2,2 size of l1tab STORAGE OBTAIN,LENGTH=(r2) get l1tab storage LR r3,r1 ST r3,l1tab #READ OFFSET=CCKD_L1TAB_POS,LENGTH=(r2),ADDR=(r3) */* ------------------------------------------------------------------- * find the last used track and cylinder * ------------------------------------------------------------------ */ ALR r2,r3 end of l1tab lastl1 SH r2,=Y(CCKD_L1ENT_SIZE) backup an entry CLR r2,r3 before the beginning ? BL Eempty yes, empty file #LC r4,0(r2) get l2tab offset LTR r4,r4 empty ? BZ lastl1 yes, keep looking #READ OFFSET=(r4),LENGTH=CCKD_L2TAB_SIZE,ADDR=l2tab LA r4,l2tab beginning of l2tab LA r5,CCKD_L2TAB_SIZE(,r4) end of l2tab lastl2 SH r5,=Y(CCKD_L2ENT_SIZE) backup an entry CLR r5,r4 before the beginning ? BL lastl1 yes, keep looking USING CCKD_L2ENT,r5 #LC r0,l2ent_pos load trk offset LTR r0,r0 empty ? BZ lastl2 yes, keep looking SR r2,r3 each 4-byte l1tab SRL r2,2 entry represents SLL r2,8 256 tracks SR r5,r4 each 8-byte l2tab SRL r5,3 entry is a track AR r5,r2 have last used trk ST r5,lasttrk SLR r4,r4 D r4,heads have last used cyl ST r5,lastcyl DROP r5 #MSG 'cckd file is a %x4:2 cyls %d heads %d trklen %d; cyl %dx is the last used cylinder', x devtype,cyls,heads,trklen,lastcyl */* ------------------------------------------------------------------- * `fake-open' the offline device * ------------------------------------------------------------------ */ */* ------------------------------------------------------------------- * look for the ucb for the unit & make sure it's an offline dasd * ------------------------------------------------------------------ */ MVC pl(l_ulpl),m_ulpl copy parm list MODESET MODE=SUP UCBLOOK DEVN=unit,UCBPTR=ucbaddr,PIN,PTOKEN=ptoken, x DYNAMIC=YES,RANGE=ALL,LOC=ANY,MF=(E,pl), x TEXT==C'cckddump offline dasd lookup' STM rf,r0,retcd save ret/rsn codes MODESET MODE=PROB LM rf,r0,retcd LTR rf,rf check return code BNZ Ebaducbl ucblook error OI flags,ucbpin L r2,ucbaddr USING UCBOB,r2 CLI UCBTBYT3,UCB3DACC check for dasd ucb BNE Ebaducbt not a dasd unit TM UCBSTAT,UCBONLI is device online ? BO Ebaducbs unit is not offline */* ------------------------------------------------------------------- * if we got a 31-bit address then we need to `capture' a 24-bit addr * ------------------------------------------------------------------ */ MVC cucbaddr,ucbaddr copy ucb addr TM ucbaddr,X'ff' 31 bit address ? BZ cucbok no, continue MVC pl(l_cupl),m_cupl copy parm list MODESET MODE=SUP IOSCAPU CAPTUCB,UCBPTR=ucbaddr,CAPTPTR=cucbaddr, x MF=(E,pl) capture 24 bit addr STM rf,r0,retcd save ret/rsn codes MODESET MODE=PROB LM rf,r0,retcd LTR rf,rf check return code BNZ Ebaducbc ioscapu error OI flags,captucb cucbok DS 0H */* ------------------------------------------------------------------- * build a dcb for the offline dasd * ------------------------------------------------------------------ */ MVC unitdcb,m_unitdcb copy model dcb udcb USING IHADCB,unitdcb MVC udcb.DCBMACRF,udcb.DCBMACR copy macr */* ------------------------------------------------------------------- * build a deb for the offline dasd * ------------------------------------------------------------------ */ MODESET MODE=SUP,KEY=ZERO GETMAIN RU,LV=DEBLENGTH,SP=230,LOC=BELOW ST r1,debaddr save deb address XC 0(DEBLENGTH,r1),0(r1) clear the deb LR r3,r1 app vector table USING DEBAVT,r3 LA r4,DEBBASND-DEBAVT(,r3) debdasd section USING DEBDASD,r4 LA r5,DEBDASDE-DEBDASD(,r4) deb ext section USING DEBXTN,r5 L r6,CVTPTR get cvt address USING CVT,r6 L rf,CVTXAPG ios app vector table MVC DEBAVT(DEBPREFX-DEBAVT),0(rf) copy vector table ST r5,DEBXTNP set ext address USING PSA,r0 L r7,PSATOLD get tcb address USING TCB,r7 ST r7,DEBTCBAD set tcb address OI DEBFLGS1,DEBXTNIN indicate ext exists LA r0,unitdcb get dcb address ST r0,DEBDCBAD set dcb address MVI DEBDEBID,15 set deb identifier OC DEBPROTG,TCBPKF set protection key ST r3,DEBAPPAD set app table address MVC DEBUCBA,cucbaddr+1 set ucb address MVC DEBXLNGH,=Y(DEBXLEN) set ext length LA r1,DEBBASIC get basic address STCM r1,7,udcb.DCBDEBA set deb addr in dcb SETLOCK OBTAIN,TYPE=LOCAL,REGS=STDSAVE,MODE=UNCOND MVC DEBDEBB,TCBDEB+1 set addr next deb LA r1,DEBBASIC get basic addr ST r1,TCBDEB chain deb to the tcb SETLOCK RELEASE,TYPE=LOCAL,REGS=STDSAVE */* ------------------------------------------------------------------- * add the deb to the deb list * ------------------------------------------------------------------ */ DEBCHK unitdcb,TYPE=ADD,AM=EXCP STM rf,r0,retcd MODESET MODE=PROB,KEY=NZERO LM rf,r0,retcd LTR rf,rf test return code BNZ Ebaddeba debchk add failed OI flags,debadded */* ------------------------------------------------------------------- * build the dasd extent * ------------------------------------------------------------------ */ MODESET MODE=SUP,KEY=ZERO MVC DEBUCBAD,cucbaddr set 24-bit ucb addr MVI DEBDVMOD,0 set device modifier MVC DEBENDCC,=X'7fff' set end cylinder MVC DEBENDHH,=X'00ff' set end head MVC DEBNMTRK,=X'7fff' set nbr trks in extent MODESET MODE=PROB,KEY=NZERO DROP r0,r2,r3,r4,r6,r7 */* ------------------------------------------------------------------- * build a couple of iobs * ------------------------------------------------------------------ */ i1 USING IOBSTDRD,iob1 OI i1.IOBFLAG1,IOBDATCH+IOBCMDCH+IOBUNREL LA r1,ecb1 ST r1,i1.IOBECBPT LA r1,ccws ST r1,i1.IOBSTART LA r1,unitdcb ST r1,i1.IOBDCBPT i2 USING IOBSTDRD,iob2 OI i2.IOBFLAG1,IOBDATCH+IOBCMDCH+IOBUNREL LA r1,ecb2 ST r1,i2.IOBECBPT LA r1,ccws LA r1,ccwl(,r1) ST r1,i2.IOBSTART LA r1,unitdcb ST r1,i2.IOBDCBPT */* ------------------------------------------------------------------- * turn off the `not ready' bit * ------------------------------------------------------------------ */ L r2,ucbaddr load ucb addr USING UCBOB,r2 TM UCBFLA,UCBNRY `not ready' bit on ? BNO nryok no, continue MODESET MODE=SUP,KEY=ZERO NI UCBFLA,255-UCBNRY turn off `not ready' MODESET MODE=PROB,KEY=NZERO DROP r2 OI flags,notready nryok DS 0H */* ------------------------------------------------------------------- * sense the offline device * ------------------------------------------------------------------ */ LA r2,ccws USING CCW0,r2 MODESET MODE=SUP,KEY=ZERO OI DEBXFLG2,DEBCHCMP+DEBBYP MODESET MODE=PROB,KEY=NZERO */* seek */ XC CCW0(8),CCW0 MVI CCW0CMD,SK LA r1,zeros STCM r1,7,CCW0ADDR MVI CCW0FLAG,CCW0SLI MVC CCW0CNT,=Y(6) EXCP iob1 WAIT 1,ECB=ecb1 CLI ecb1,ECBNORM BNE Esnserr */* Sense ID */ XC ecb1,ecb1 XC CCW0(8),CCW0 MVI CCW0CMD,SNSID LA r1,snsidarea STCM r1,7,CCW0ADDR MVI CCW0FLAG,CCW0SLI MVC CCW0CNT,=Y(L'snsidarea) EXCP iob1 WAIT 1,ECB=ecb1 CLI ecb1,ECBNORM BNE Esnserr */* Sense */ XC ecb1,ecb1 XC CCW0(8),CCW0 MVI CCW0CMD,SNS LA r1,snsarea STCM r1,7,CCW0ADDR MVI CCW0FLAG,CCW0SLI MVC CCW0CNT,=Y(L'snsarea) EXCP iob1 WAIT 1,ECB=ecb1 CLI ecb1,ECBNORM BNE Esnserr */* Read Device Characteristics */ XC ecb1,ecb1 XC CCW0(8),CCW0 MVI CCW0CMD,RDC LA r1,rdcarea STCM r1,7,CCW0ADDR MVI CCW0FLAG,0 MVC CCW0CNT,=Y(L'rdcarea) EXCP iob1 WAIT 1,ECB=ecb1 CLI ecb1,ECBNORM BNE Esnserr */* Sense Subsystem Status XC ecb1,ecb1 XC CCW0(8),CCW0 MVI CCW0CMD,SNSS LA r1,snssarea STCM r1,7,CCW0ADDR MVI CCW0FLAG,CCW0SLI MVC CCW0CNT,=Y(L'snssarea) EXCP iob1 WAIT 1,ECB=ecb1 CLI ecb1,ECBNORM BNE Esnserr MODESET MODE=SUP,KEY=ZERO NI DEBXFLG2,255-DEBBYP MODESET MODE=PROB,KEY=NZERO DROP r2,r5 */* ------------------------------------------------------------------- * perform some sanity checks * ------------------------------------------------------------------ */ USING RDCinfo,rdcarea MVC pl(l_tcpl),m_tcpl copy model parm list L r2,cucbaddr TRKCALC FUNCTN=TRKBAL,UCB=(r2),RKDD==A(x'0100ffff'), x MAXSIZE=YES,REGSAVE=YES,MF=(E,pl) CH rf,=Y(8) BNE Ebadcap unexpected return code LR r1,r0 round up 512 LA r1,511(,r1) N r1,=A(x'fffffe00') ST r1,utrklen #MSG 'unit %x4:2 is a %x4:2 cyls %d:2 heads %d:2 trklen %d', x unit,RDCdevt,RDCprime,RDCheads,utrklen CLC RDCdevt,devtype BNE Emisdevt CLC RDCheads,heads+2 BNE Emisheads CLC trklen,utrklen BNE Emislen CLC RDCprime,lastcyl+2 BH cylok #MSG 'Warning... cckd file uses more cylinders than availablex on %x4:2; extras will be omitted',unit MVC result,=A(4) cylok DS 0H */* Dump tracks thru last used cylinder, or thru last cylinder on */ */* on the output device, whichever is lower */ L r3,lastcyl LA r3,1(,r3) M r2,heads ST r3,tracks SLR r3,r3 ICM r3,3,RDCprime M r2,heads C r3,tracks BH *+8 ST r3,tracks tracks to write #MSG '%d tracks will be written',tracks L r3,tracks tracks to write D r2,=A(10) LA r3,99(,r3) SLR r2,r2 D r2,=A(100) LTR r3,r3 BNZ *+8 LA r3,1 10% of tracks to be MH r3,=Y(100) written rounded up ST r3,trk10pct to next 100 SLR r2,r2 for status msg L r3,tracks D r2,heads ST r3,cyls */* ------------------------------------------------------------------- * get area for the buffers * ------------------------------------------------------------------ */ L r2,trklen SLL r2,2 space for 4 buffers STORAGE OBTAIN,LENGTH=(r2) ST r1,buf1 AL r1,trklen ST r1,buf2 AL r1,trklen ST r1,buf3 AL r1,trklen ST r1,buf4 */* ------------------------------------------------------------------- * create a persistent c environment * ------------------------------------------------------------------ */ LA r2,handle LA r3,=A(32*1024) LA r4,=A(1) STM r2,r4,pl OI pl+8,X'80' LA r1,pl L rf,=V(EDCXHOTL) create persistent c environ BALR re,rf ******* #MSG 'persistent c environment created, handle=0x%x',handle */* ------------------------------------------------------------------- * setup the output channel programs * ------------------------------------------------------------------ */ LA r2,ccws point to 1st ccws USING CCW0,r2 LA r3,lrparm1 point to 1st LR parameters USING LRparm,r3 LA r4,idaw1 point to 1st idaw list LA rf,2 build 2 sets of ccws bldcp XC CCW0(8),CCW0 clear the ccw MVI CCW0CMD,DX set define extent command LA r1,dxarea address of dx area STCM r1,7,CCW0ADDR set address MVI CCW0FLAG,CCW0CC command chaining MVC CCW0CNT,=Y(L'dxarea) set length LA r2,CCW0END to next ccw XC CCW0(8),CCW0 clear the ccw MVI CCW0CMD,TIC set transfer-in-control command LA r1,CCW0END address of next ccw STCM r1,7,CCW0ADDR set next ccw address LA r2,CCW0END to next ccw XC CCW0(8),CCW0 clear the ccw MVI CCW0CMD,LR set locate record command STCM r3,7,CCW0ADDR set address in locate record ccw OI CCW0FLAG,CCW0CC command chaining MVC CCW0CNT,=Y(LRparml) set length MVI LRop,LRocount+LRfwrite set operation byte LA r0,255 build 255 write ccws bldcp2 LA r2,CCW0END point to next ccw XC CCW0(8),CCW0 clear the ccw MVI CCW0CMD,WCKD set read track command STCM r4,7,CCW0ADDR set address for idaw LA r4,4(,r4) point to next idaw BCT r0,bldcp2 loop back LA r2,ccws point to 2nd LA r2,ccwl(,r2) channel program LA r3,lrparm2 point to 2nd LR parameters LA r4,idaw2 point to 2nd idaw list BCT rf,bldcp build 2nd channel program DROP r2,r3 */* ------------------------------------------------------------------- * setup the output define extent area * ------------------------------------------------------------------ */ MVI dxarea,X'c0' permit all write operations MVI dxarea+1,X'c0' eckd L r1,cyls low extent is cyl 0 head 0 BCTR r1,0 set high extent stcm r1,3,dxarea+12 ICM r1,3,RDCheads BCTR r1,0 STCM r1,3,dxarea+14 */* ------------------------------------------------------------------- * Read/write each track image * ------------------------------------------------------------------ */ SLR r2,r2 init buffer switch SLR r3,r3 init l1tab index MVC trkstat,trk10pct init status rwloop DS 0H */* Read the next l2tab */ LR r4,r3 SLL r4,2 AL r4,l1tab #LC r5,0(r4) LTR r4,r5 BZ l2null #READ OFFSET=(r4),LENGTH=CCKD_L2TAB_SIZE,ADDR=l2tab B l2ok l2null LA r0,l2tab LA r1,CCKD_L2TAB_SIZE SLR rf,rf MVCL re,r0 l2ok DS 0H */* Loop for each entry in the l2tab, exit if all tracks processed */ SLR r4,r4 rwloop2 LR rf,r3 SLL rf,8 AR rf,r4 CL rf,tracks BNL rwexit ST rf,track */* Get offset/length of the track image from the l2tab entry */ LR r5,r4 SLL r5,3 LA r5,l2tab(r5) USING CCKD_L2ENT,r5 #LC r6,l2ent_pos #LHC r7,l2ent_len DROP r5 L r5,bufs(r2) */* Read the track image unless its a null track */ LTR r6,r6 BZ trknull #READ OFFSET=(r6),LENGTH=(r7),ADDR=(r5) B trkok trknull XC 0(CCKD_NULLTRK_SIZE,r5),0(r5) */* Build a null trk: 0cchh cchh0008 00000000 cchh1000 ffffffff */ SLR re,re L rf,track D re,heads STCM rf,3,1(r5) STCM re,3,3(r5) MVC 5(4,r5),1(r5) MVI 8(r5),8 MVC 21(4,r5),1(r5) MVI 25(r5),1 MVC 29(8,r5),eightFF trkok DS 0H CLI 0(r5),CCKD_COMPRESS_MAX BNH compok #MSG 'Trk %d unknown compression: %d:1',track,0(r5) MVC result,=A(8) B trknull compok DS 0H */* Uncompress the track image */ SLR rf,rf IC rf,0(,r5) SLL rf,2 B *+4(rf) B compnone 0 - not compressed B compzlib 1 - zlib compression B compbz2 2 - bz2 compression */* Not compressed */ compnone LR r6,r5 B compdone */* zlib compression */ compzlib LR r6,r5 AL r6,trklen MVC 0(CKDDASD_TRKHDR_SIZE,r6),0(r5) LA re,handle LA rf,=V(UNCOMPRE) LA r0,CKDDASD_TRKHDR_SIZE(,r6) L r1,trklen SH r1,=Y(CKDDASD_TRKHDR_SIZE) ST r1,complen LA r1,complen STM re,r1,pl LA re,CKDDASD_TRKHDR_SIZE(,r5) LR rf,r7 SH rf,=Y(CKDDASD_TRKHDR_SIZE) STM re,rf,pl+16 LA r1,pl L rf,=V(EDCXHOTU) BALR re,rf LTR rf,rf BZ compdone ST rf,retcd #MSG 'trk %d zlib uncompress error: %d',track,retcd MVC result,=A(8) B trknull */* bzip2 compression */ compbz2 LR r6,r5 AL r6,trklen MVC 0(CKDDASD_TRKHDR_SIZE,r6),0(r5) LA re,handle LA rf,=V(bzbuffd) LA r0,CKDDASD_TRKHDR_SIZE(,r6) L r1,trklen SH r1,=Y(CKDDASD_TRKHDR_SIZE) ST r1,complen LA r1,complen STM re,r1,pl LA re,CKDDASD_TRKHDR_SIZE(,r5) LR rf,r7 SH rf,=Y(CKDDASD_TRKHDR_SIZE) SLR r0,r0 SLR r1,r1 STM re,r1,pl+16 LA r1,pl L rf,=V(EDCXHOTU) BALR re,rf LTR rf,rf BZ compdone ST rf,retcd #MSG 'trk %d bzip2 decompress error: %d',track,retcd MVC result,=A(8) B trknull compdone DS 0H */* Schedule the track image to be written */ #WRITE ADDR=(r6) */* Write status message if it's time */ CLC track,trkstat BL rwnext2 #MSG '%d tracks written',track L r1,trkstat AL r1,trk10pct ST r1,trkstat rwnext2 X r2,=A(8) flip/flop buffers LA r4,1(,r4) CH r4,=Y(256) BL rwloop2 rwnext LA r3,1(,r3) B rwloop rwexit DS 0H TIME DEC STM r0,r1,ctime LA r1,ctime LA r0,dtime BAL re,datetime #MSG '%d tracks written at %s:20, max code: %d', x tracks,dtime,result */* ------------------------------------------------------------------- * cleanup and terminate * ------------------------------------------------------------------ */ terminate DS 0H */* Make sure all write i/o has completed */ #WRITE ADDR=0 */* Terminate the persistant c environment */ CLC =A(0),handle BE term1 LA r1,handle ST r1,pl OI pl,X'80' LA r1,pl L rf,=V(EDCXHOTT) BALR re,rf term1 DS 0H */* Close the cckd file */ TM ut1.DCBOFLGS,DCBOFOPN BNO term2 MVC openl,m_openl CLOSE (sysut1),MODE=31,MF=(E,openl) term2 DS 0H */* Free the i/o areas */ L r1,buf1 LTR r1,r1 BZ term3 L r2,trklen SLL r2,2 STORAGE RELEASE,ADDR=(1),LENGTH=(r2) term3 DS 0H */* Free the l1tab */ L r1,l1tab LTR r1,r1 BZ term4 L r2,numl1tab SLL r2,2 STORAGE RELEASE,ADDR=(1),LENGTH=(r2) term4 DS 0H */* Call debchk to delete the deb */ TM flags,debadded BNO term5 MODESET MODE=SUP,KEY=ZERO DEBCHK unitdcb,TYPE=DELETE,AM=EXCP delete the deb MODESET MODE=PROB,KEY=NZERO term5 DS 0H L r2,debaddr LTR r2,r2 BZ term6 */* Remove the deb from the deb chain */ USING DEBAVT,r2 LA r3,DEBBASIC DROP r2 L r4,PSATOLD-PSA USING TCB,r4 LA r5,TCBDEB-(DEBDEBAD-DEBBASIC) USING DEBBASIC,r4 MODESET MODE=SUP,KEY=ZERO SETLOCK OBTAIN,TYPE=LOCAL,REGS=STDSAVE,MODE=UNCOND SPKA X'80' termdeb LR r4,r5 SLR r5,r5 ICM r5,7,DEBDEBB BZ termdebx CLR r3,r5 BNE termdeb SPKA 0 MVC DEBDEBB,DEBDEBB-DEBBASIC(r5) DROP r4 termdebx SPKA 0 SETLOCK RELEASE,TYPE=LOCAL,REGS=STDSAVE MODESET MODE=PROB,KEY=NZERO */* Free deb storage */ MODESET MODE=SUP,KEY=ZERO FREEMAIN RU,A=(r2),LV=DEBLENGTH,SP=230 MODESET MODE=PROB,KEY=NZERO term6 DS 0H */* Turn the ucb `not ready' bit back on if we turned it off */ TM flags,notready BNO term7 L r2,ucbaddr USING UCBOB,r2 MODESET MODE=SUP,KEY=ZERO OI UCBFLA,UCBNRY MODESET MODE=PROB,KEY=NZERO DROP r2 term7 DS 0H */* Uncapture the ucb */ TM flags,captucb BNO term8 MVC pl(l_cupl),m_cupl MODESET MODE=SUP IOSCAPU UCAPTUCB,CAPTPTR=cucbaddr,MF=(E,pl) MODESET MODE=PROB term8 DS 0H */* Unpin the ucb */ TM flags,ucbpin BNO term9 MVC pl(l_uupl),m_uupl MODESET MODE=SUP UCBPIN UNPIN,PTOKEN=ptoken,MF=(E,pl) MODESET MODE=PROB term9 DS 0H */* Close the sysprint file */ pdcb USING IHADCB,prtdcb TM pdcb.DCBOFLGS,DCBOFOPN BNO term10 MVC openl,m_openl CLOSE (prtdcb),MODE=31,MF=(E,openl) term10 DS 0H */* Free the work areas */ STORAGE RELEASE,ADDR=(rb),LENGTH=work24l LR r1,rd L r2,result L rd,4(,rd) STORAGE RELEASE,ADDR=(1),LENGTH=workl */* Return */ LR rf,r2 RETURN (14,12),RC=(15) */* ------------------------------------------------------------------- * format date & time * ------------------------------------------------------------------ */ datetime STM re,r2,12(rd) save some regs LR r2,r0 copy output area address MVI 0(r2),C' ' blank the output area MVC 1(19,r2),0(r2) MVC 11(9,r2),=X'4021207a20207a2020' edit pattern for time ED 11(9,r2),0(r1) edited time XC dw,dw clear double word work area SLR rf,rf ICM rf,3,4(r1) decimal year SLL rf,4 shift over a nibble ST rf,dw+4 store in the double word OI dw+7,X'0f' set bottom nibble AP dw,=P'1900' calculate the year OI dw+7,X'0f' fix bottom nibble for unpk UNPK 7(4,r2),dw set the year CVB rf,dw get binary year N rf,=A(3) test for leap year BZ *+8 jumps if leap year LA rf,2 else set non-leapyr offset ZAP dw,6(2,r1) get julian day in double word CVB r0,dw get julian day binary LA re,dtjtab point to julian table dtfind CH r0,8(rf,re) found table entry ? BNH dtfound yes, exit loop LA re,8(,re) point to next entry B dtfind and loop back dtfound MVC 3(3,r2),4(re) set month from the table SH r0,0(rf,re) calculate day of month CVD r0,dw get day of month packed L r0,dw+4 load packed day SLL r0,20 shift out hi bits SRL r0,28 shift down STC r0,0(,r2) set 1st digit of the month OI 0(r2),C'0' convert to ebcdic character L r0,dw+4 load packed day SLL r0,24 shift out hi bits SRL r0,28 shift down STC r0,1(,r2) set 2nd digit of the month OI 1(r2),C'0' convert to ebcdic character LM re,r2,12(rd) restore regs BR re and thankfully return dtjtab DC Y(0,0),C'Jan ' Julian date table DC Y(31,31),C'Feb ' DC Y(60,59),C'Mar ' DC Y(91,90),C'Apr ' DC Y(121,120),C'May ' DC Y(152,151),C'Jun ' DC Y(182,181),C'Jul ' DC Y(213,212),C'Aug ' DC Y(244,243),C'Sep ' DC Y(274,273),C'Oct ' DC Y(305,304),C'Nov ' DC Y(335,334),C'Dec ' DC Y(999,999),C'??? ' */* ------------------------------------------------------------------- * error routines * ------------------------------------------------------------------ */ Enoparm #MSG '** Unit address not specified' B Eexit Ebadparm MVC dw,=CL8' ' CH r4,=Y(8) BNH *+8 LA r4,8 SH r4,=Y(1) BM *+4+4+6 EX r4,*+4 MVC dw(0),0(r3) #MSG '** Invalid unit address: %s:8',dw B Eexit Edevid #MSG '** SYSUT1 is not a cckd file; devid validation failed' B Eexit Esynad1 #MSG '** SYSUT1 fatal error, Synad EP loaded' CZV70 B Eexit CZV70 Edevterr STM rf,r0,retcd CLC retcd(8),=A(4,4) missing ddname ? BE Enoddn yes, noddn error #MSG '** SYSUT1 DEVTYPE error: rc=%d, reason=%d', X retcd,rsncd B Eexit Enoddn #MSG '** SYSUT1 ddname not found' B Eexit Enotdasd1 #MSG '** SYSUT1 not a dasd file' B Eexit Eopenerr #MSG '** SYSUT1 did not open' B Eexit Ebadblksz #MSG '** SYSUT1 blksz is not 16384' CZV70 B Eexit Etrkcalc ST rf,retcd #MSG '** TRKCAP failed for SYSUT1: rc=%d',retcd B Eexit Ebaddevt #MSG '** cckd dasd devtype not supported: 0x%x2:1',devtype+1 B Eexit Eempty #MSG '** cckd file contains all null tracks' B Eexit Epoint ST rf,retcd #MSG '** SYSUT1 point error: rc=%d ttr=%x6:3',retcd,ttr B Eexit Ebaducbl CH RF,=Y(4) BE Enoucb #MSG '** UCBLOOK error for unit %x4:2: rc 0x%x rsn 0x%x', X unit,retcd,rsncd B Eexit Enoucb #MSG '** UCB not found for unit %x4:2',unit B Eexit Ebaducbt L r2,ucbaddr USING UCBOB,r2 #MSG '** UCB for unit %x4:2 is not dasd, type is %x:1', X unit,UCBTBYT3 B Eexit DROP r2 Ebaducbs #MSG '** Device %x4:2 is not offline',unit B Eexit Ebaducbc #MSG '** IOSCAPU CAPTUCB failed for %x4:2; rc=0x%x rsn=0x%x',X unit,retcd,rsncd B Eexit Ebaddeba #MSG '** DEBCHK ADD for %x4:2 failed; rc=0x%x', X unit,retcd B Eexit Esnserr #MSG '** Sense failed for %x4:2: command %x2:1, CC 0x%x2:1, SX tat 0x%x4:2',unit,ccws,ecb1,i1.IOBSTBYT B Eexit Ebadcap ST rf,retcd #MSG '** TRKBAL for %x4:2 unexpected return code; rc=0x%x', X unit,retcd B Eexit Emisdevt #MSG '** devtype mismatch %x4:2=%x4:2, cckd=%x4:2', X unit,RDCdevt,devtype B Eexit Emisheads #MSG '** number heads mismatch %x4:2=%d:2, cckd=%d', X unit,RDCheads,heads B Eexit Emislen #MSG '** trklen mismatch %x4:2=%d, cckd=%d', X unit,utrklen,trklen B Eexit Eioerr SLR r2,r2 ICM r2,7,waitecb+1 LA r0,ecb1 LA r3,iob1 CLR r0,r2 BE *+8 LA r3,iob2 USING ECB,r2 USING IOBSTDRD,r3 #MSG '** I/O error %x4:2 CCHH %x8: CC %x2:1, Stat %x4:2', X unit,prevcchh,ECBCC,IOBSTBYT DROP r2,r3 B Eexit Eexit MVC result,=A(12) B terminate */* ------------------------------------------------------------------- * literals and constants * ------------------------------------------------------------------ */ LTORG , parmmvc MVC dw(0),0(r3) *** executed *** parmhexc TRT dw(0),hexchars *** executed *** parmhex TR dw(0),hextab *** executed *** parmpack PACK dw2,dw(0) *** executed *** m_unitdcb DCB DDNAME=0,DSORG=PS,MACRF=E l_unitdcb EQU *-m_unitdcb m_sysut1 DCB DDNAME=SYSUT1,DSORG=PS,MACRF=RP,DCBE=m_sysut1e,RECFM=F l_sysut1 EQU *-m_sysut1 m_sysut1e DCBE RMODE31=BUFF,SYNAD=Esynad1,BLOCKTOKENSIZE=LARGE CZV70 l_sysut1e EQU *-m_sysut1e m_prtdcb DCB DDNAME=SYSPRINT,DSORG=PS,MACRF=PL,DCBE=m_prtdcbe l_prtdcb EQU *-m_prtdcb m_prtdcbe DCBE RMODE31=BUFF l_prtdcbe EQU *-m_prtdcbe m_openl OPEN (0),MODE=31,MF=L l_openl EQU *-m_openl UCBLOOK MF=(L,m_ulpl) l_ulpl EQU *-m_ulpl UCBPIN MF=(L,m_uupl) l_uupl EQU *-m_uupl IOSCAPU MF=(L,m_cupl) l_cupl EQU *-m_cupl m_tcpl TRKCALC MF=L l_tcpl EQU *-m_tcpl eightFF DC X'ffffffffffffffff' devtype_table DC 256X'00' ORG devtype_table+x'80' DC X'33' ORG devtype_table+x'90' DC X'33' ORG devtype_table+x'45' DC X'93' ORG devtype_table+256 hextab DC 256X'00' ORG hextab+C'0' DC AL1(0,1,2,3,4,5,6,7,8,9) ORG hextab+C'a' DC AL1(10,11,12,13,14,15) ORG hextab+C'A' DC AL1(10,11,12,13,14,15) ORG hextab+256 hexchars DC 256x'ff' ORG hexchars+C'a' DC 6x'0' ORG hexchars+C'A' DC 6x'0' ORG hexchars+C'0' DC 10x'0' ORG hexchars+256 upcase DC C' ',255AL1(*-upcase) ORG upcase+c'a' DC C'ABCDEFGHI' ORG upcase+c'j' DC C'JKLMNOPQR' ORG upcase+c's' DC C'STUVWXYZ' ORG upcase+256 A2E DS 0D * 0 1 2 3 4 5 6 7 8 9 a b c d e f DC X'00010203372D2E2F1605250B0C0D0E0F' 0 DC X'101112133C3D322618193F27221D351F' 1 DC X'405A7F7B5B6C507D4D5D5C4E6B604B61' 2 DC X'F0F1F2F3F4F5F6F7F8F97A5E4C7E6E6F' 3 DC X'7CC1C2C3C4C5C6C7C8C9D1D2D3D4D5D6' 4 DC X'D7D8D9E2E3E4E5E6E7E8E9ADE0BD5F6D' 5 DC X'79818283848586878889919293949596' 6 DC X'979899A2A3A4A5A6A7A8A9C04FD0A107' 7 DC X'00010203372D2E2F1605250B0C0D0E0F' 8 DC X'101112133C3D322618193F27221D351F' 9 DC X'405A7F7B5B6C507D4D5D5C4E6B604B61' a DC X'F0F1F2F3F4F5F6F7F8F97A5E4C7E6E6F' b DC X'7CC1C2C3C4C5C6C7C8C9D1D2D3D4D5D6' c DC X'D7D8D9E2E3E4E5E6E7E8E9ADE0BD5F6D' d DC X'79818283848586878889919293949596' e DC X'979899A2A3A4A5A6A7A8A9C04FD0A107' f hex2char EQU *-240 DC C'0123456789ABCDEF' DROP , mainend DS 0D */* ------------------------------------------------------------------- * Subroutine to read the cckd file * ------------------------------------------------------------------ */ USING readr,r9 USING work,rd USING work24,rb USING main,rc USING (main+4095,mainend),ra readr STM r0,rf,save1 LR r9,rf LM r2,r4,0(r1) load offset, length, address */* Read the first block into the tempbuf */ LR r7,r2 copy the offset SRL r7,14 get the block number CZV70 LTR r2,r2 test offset BZ r_getblk1 always read 1st block for offset 0 CL r7,lastblk already have the 1st block ? BE r_gotblk1 yes, continue ST r7,lastblk remember this block SLR r6,r6 D r6,bpt calculate ttr STCM r7,7,ttr CZV70 LA r6,1(,r6) STC r6,ttr+3 CZV70 POINT sysut1,ttr position to the block LTR rf,rf BNZ Epoint r_getblk1 READ ut1decb,SF,sysut1,tempbuf,'S',MF=E CHECK ut1decb read the block r_gotblk1 DS 0H */* Copy data from the first block to the caller's buffer */ LR r5,r2 calculate data offset N r5,=A(X'00003fff') in the first block CZV70 LH r6,=Y(16384) calculate data length CZV70 SR r6,r5 in the first block AR r2,r6 new offset LR re,r4 target address LR rf,r6 data length in the first block CR rf,r3 if requested length is less BL *+6 then use that instead LR rf,r3 LA r0,tempbuf(r5) source address LR r1,rf length to copy AR r4,rf adjust target address SR r3,rf adjust target length MVCL re,r0 copy data from the 1st block */* Read the intermediate blocks directly into the caller's buffer */ r_getint LTR r3,r3 test length left to read BZ r_return return if everything read CH r3,=Y(16384) able to read a full block ? CZV70 BL r_getlast no, special processing for last READ ut1decb,SF,sysut1,(r4),'S',MF=E CHECK ut1decb read an intermediate block AH r2,=Y(16384) adjust the offset CZV70 SH r3,=Y(16384) adjust the length left CZV70 AH r4,=Y(16384) adjust buffer position CZV70 B r_getint read some more */* Read the last block into the tempbuf */ r_getlast SRL r2,14 change offset to block number CZV70 ST r2,lastblk and save it READ ut1decb,SF,sysut1,tempbuf,'S',MF=E CHECK ut1decb LR re,r4 target address LR rf,r3 target length LA r0,tempbuf source address LR r1,rf source length MVCL re,r0 copy data from the last block r_return LM r0,rf,save1 BR re LTORG , DROP , */* ------------------------------------------------------------------- * Subroutine to write track images to the offline dasd unit * ------------------------------------------------------------------ */ USING writer,r9 USING work,rd USING work24,rb USING main,rc USING (main+4095,mainend),ra writer STM r0,rf,save1 LR r9,rf */* If buffer address is zero then we simply wait on the last I/O */ LTR r1,r1 BZ w_finish */* Get the IOB we will use */ L r2,iobswtch 0 = iob1, 1 = iob2 LA r3,iob1 presume iob1 LTR r2,r2 BZ *+8 LA r3,iob2 use iob2 if switch is non-zero USING IOBSTDRD,r3 X r2,=A(1) flip/flop the switch ST r2,iobswtch */* Complete the channel program */ MVC prevcchh,curcchh copy last cchh scheculed MVC curcchh,1(r1) current cchh (from HA) MVC IOBCC(4),curcchh set extent in the iob SLR r2,r2 ICM r2,7,IOBECBPB USING ECB,r2 XC ECB,ECB clear the ecb */* If record 1 is end-of-track then make it eof then eot */ CLC eightFF,5+8+8(r1) check for end-of-track BNE w_wnoteot continue if not MVC 5+8+8(8,r1),5(r1) else copy r0 t0 r1 MVI 5+8+8+4(r1),1 and set r to 1 MVI 5+8+8+7(r1),0 and data len to 0 MVC 5+8+8+8(8,r1),eightFF now set the eot w_wnoteot DS 0h LA r1,5+8+8(,r1) point to record 1 SLR rf,rf clear record count SLR r4,r4 ICM r4,7,IOBSTRTB address of the channel program USING CCW0,r4 LA r4,CCW0END point past dx ccw LA r4,CCW0END point past tic ccw SLR r5,r5 ICM r5,7,CCW0ADDR locate record parm addr USING LRparm,r5 MVC LRseek,IOBCC MVC LRsearch,IOBCC w_wckd LA r4,CCW0END point to next ccw LA rf,1(,rf) increment record count SLR r6,r6 ICM r6,7,CCW0ADDR load IDAW address ST r1,0(,r6) set record addr in the IDAW SLR r0,r0 IC r0,5(,r1) key length SLR re,re ICM re,3,6(r1) data length AR re,r0 LA re,8(,re) cound-key-data-length STCM re,3,CCW0CNT OI CCW0FLAG,CCW0CC+CCW0IDA set chain & idaw bits AR r1,re point to the next record CLC eightFF,0(r1) at end of the track ? BNE w_wckd no, keep building NI CCW0FLAG,255-CCW0CC turn off chain bit for last ccw STC rf,LRcount set count of WCKD ccws */* Schedule this channel program and wait for the previous one */ LR rf,r2 copy ecb address L r2,waitecb load ecb address to wait on ST rf,waitecb set new ecb address to wait on EXCP IOBSTDRD schedule the i/o LTR r2,r2 any ecb to wait on ? BZ w_return no, just return WAIT 1,ECB=ECB wait for previous i/o CLI ECBCC,ECBNORM successful completion ? BNE Eioerr no, i/o error B w_return */* Wait for the last i/o to finish */ w_finish L r2,waitecb ecb for last i/o LTR r2,r2 is it set ? BZ w_return no, just return XC waitecb,waitecb WAIT 1,ECB=ECB wait for the last i/o CLI ECBCC,ECBNORM normal completion ? BNE Eioerr no, i/o error w_return LM r0,rf,save1 BR re LTORG , DROP , */* ------------------------------------------------------------------- * Subroutine to issue messages * ------------------------------------------------------------------ */ USING msgr,r9 USING work,rd USING work24,rb USING main,rc USING (main+4095,mainend),ra msgr STM r0,rf,save2 LR r9,rf prt USING IHADCB,prtdcb TM prt.DCBOFLGS,DCBOFOPN BO mr_opened continue if message file is opened LR r2,r1 save reg 1 TM flags,noprint test if no print file BO mr_ret return if not MVC prtdcb,m_prtdcb copy the model print dcb MVC prtdcbe,m_prtdcbe copy model print dcbe LA r1,prtdcbe set dcbe address ST r1,prt.DCBDCBE in the dcb OI flags,noprint presume no print DEVTYPE prt.DCBDDNAM,dw issue devtype for the ddname LTR rf,rf test devtype return code BNZ mr_ret return if some error L r1,=A(mr_oxit) get address of the open exit LA rf,mr_oxitl get open exit length BCTR rf,0 decrement EX rf,*+4 copy the open exit MVC openxit(0),0(r1) *** executed *** LA r1,openxit get open exit addr ST r1,exlst set in exit list MVI exlst,x'85' set exit type LA r1,exlst point to exit list STCM r1,7,prt.DCBEXLSA set exlst addr in the dcb MVC openl,m_openl copy model open list OPEN (prtdcb,OUTPUT),MODE=31,MF=(E,openl) TM prt.DCBOFLGS,DCBOFOPN did the file open ? BNO mr_ret no, return NI flags,255-noprint else turn off `noprt' bit LR r1,r2 restore reg 1 mr_opened LM r4,r5,0(r1) pattern addr, length BCTR r5,0 LA r3,8(,r1) first parameter LA r6,msg MVI msg,C' ' init msg to blanks MVC msg+1(L'msg-1),msg mr_loop LTR r5,r5 BM mr_exit LA r1,1(r4,r5) SLR r2,r2 EX r5,mr_trt1 SR r1,r4 length scanned BNP mr_skip1 LR rf,r1 BCTR rf,0 EX rf,mr_mvc1 copy literal text AR r6,r1 mr_skip1 AR r4,r1 SR r5,r1 BM mr_exit BP mr_skip2 MVC 0(1,r6),0(r4) string ends in special char LA r6,1(,r6) B mr_exit mr_skip2 B *(r2) br on special char type B mr_pct '%' B mr_bs '\' mr_pct CLI 1(r4),C's' BE mr_pct_s CLI 1(r4),C'x' BE mr_pct_x CLI 1(r4),C'd' BE mr_pct_d MVC 0(1,r6),0(r4) treat '%' as any other char LA r6,1(,r6) LA r4,1(,r4) BCTR r5,0 B mr_loop mr_pct_s L r7,0(,r3) load string ptr LA r3,4(,r3) LA r4,2(,r4) point past '%s' SH r5,=Y(2) BAL re,mr_op r1 - target len, r2 - source len LTR r2,r2 BNZ mr_pct_s3 LR r2,r7 source len = 0, find end of string mr_pct_s1 CLI 0(r2),C' ' BNH mr_pct_s2 LA r2,1(,r2) B mr_pct_s1 mr_pct_s2 SR r2,r7 BNP mr_loop mr_pct_s3 LR rf,r2 copy source string to the msg BCTR rf,0 EX rf,mr_mvc2 LTR r1,r1 BNZ mr_pct_s5 AR r6,r2 truncate trailing spaces if mr_pct_s4 BCTR r6,0 target len is 0 CLI 0(r6),C' ' BNH mr_pct_s4 LA r6,1(,r6) B mr_loop mr_pct_s5 CR r1,r2 BH mr_pct_s6 AR r6,r1 truncate the string B mr_loop mr_pct_s6 AR r6,r2 pad string with trailing blanks SR r1,r2 mr_pct_s7 MVI 0(r6),C' ' LA r6,1(,r6) BCT r1,mr_pct_s7 B mr_loop mr_pct_x L r7,0(,r3) load hex ptr LA r3,4(,r3) LA r4,2(,r4) point past '%x' SH r5,=Y(2) BAL re,mr_op r1 - target len, r2 - source len LTR r2,r2 BNZ *+8 LA r2,4 default source len is 4 EX r2,mr_pct_x_unpk TR dw,mr_hextab LTR r1,r1 BNZ mr_pct_x1 LA r1,8 determine default target len CLC =C'00',dw BNE mr_pct_x1 LA r1,6 CLC =C'0000',dw BNE mr_pct_x1 LA r1,4 CLC =C'000000',dw BNE mr_pct_x1 LA r1,2 mr_pct_x1 LA r7,dw+8 copy the hex string to the msg SR r7,r1 BCTR r1,0 EX r1,mr_mvc2 LA r6,1(r1,r6) B mr_loop mr_pct_d L r7,0(,r3) load decimal ptr LA r3,4(,r3) LA r4,2(,r4) point past '%d' SH r5,=Y(2) BAL re,mr_op r1 - target len, r2 - source len LTR r2,r2 BNZ *+8 LA r2,4 default source len is 4 LA rf,4 SR rf,r2 LA re,15 SRL re,0(rf) EX re,mr_pct_d_icm CVD rf,dw MVC dw2(16),=X'40202020202020202020202020202120' ED dw2(16),dw LTR r1,r1 BNZ mr_pct_d2 LA rf,dw2+16 default length - mr_pct_d1 BCTR rf,0 truncate leading spaces CLI 0(rf),C' ' BH mr_pct_d1 LA r1,dw2+15 SR r1,rf mr_pct_d2 LA r7,dw2+16 SR r7,r1 BCTR r1,0 EX r1,mr_mvc2 LA r6,1(r1,r6) B mr_loop mr_bs MVC 0(1,r6),1(r4) copy char following '\' LA r6,1(,r6) LA r4,2(,r4) SH r5,=Y(2) B mr_loop mr_exit LA r1,msg SR r6,r1 calculate msg length BNP mr_ret TM prt.DCBRECFM,DCBRECCA+DCBRECCM BZ *+8 LA r6,1(,r6) increment for carriage control TM prt.DCBRECFM,DCBRECU BO mr_u TM prt.DCBRECFM,DCBRECF BO mr_f TM prt.DCBRECFM,DCBRECV BO mr_v mr_u CH r6,prt.DCBBLKSI BNH *+8 LH r6,prt.DCBBLKSI STH r6,prt.DCBLRECL PUT prtdcb TM prt.DCBRECFM,DCBRECCA+DCBRECCM BZ mr_u1 MVI 0(r1),C' ' LA r1,1(,r1) BCTR r6,0 TM prt.DCBRECFM,DCBRECCA BO mr_u1 BCTR r1,0 MVI 0(r1),X'09' LA r1,1(,r1) mr_u1 BCTR r6,0 EX r6,mr_mvc3 B mr_ret mr_f CH r6,prt.DCBLRECL BNH *+8 LH r6,prt.DCBLRECL PUT prtdcb TM prt.DCBRECFM,DCBRECCA+DCBRECCM BZ mr_f1 MVI 0(r1),C' ' LA r1,1(,r1) BCTR r6,0 TM prt.DCBRECFM,DCBRECCA BO mr_f1 BCTR r1,0 MVI 0(r1),X'09' LA r1,1(,r1) mr_f1 BCTR r6,0 EX r6,mr_mvc3 B mr_ret mr_v LA r6,4(,r6) LH r1,prt.DCBBLKSI SH r1,=Y(4) CR r6,r1 BNH *+6 LR r6,r1 STH r6,prt.DCBLRECL PUT prtdcb STH r6,0(,r1) XC 2(2,r1),2(r1) LA r1,4(,r1) SH r6,=Y(4) TM prt.DCBRECFM,DCBRECCA+DCBRECCM BZ mr_v1 MVI 0(r1),C' ' LA r1,1(,r1) BCTR r6,0 TM prt.DCBRECFM,DCBRECCA BO mr_v1 BCTR r1,0 MVI 0(r1),X'09' LA r1,1(,r1) mr_v1 BCTR r6,0 EX r6,mr_mvc3 B mr_ret mr_ret LM r0,rf,save2 BR re */* ------------------------------------------------------------------- * message subroutine to get operand lengths * ------------------------------------------------------------------ */ mr_op SLR r1,r1 SLR r2,r2 mr_op1 LTR r5,r5 first number is target length BMR re CLI 0(r4),C'0' BL mr_op2 IC rf,0(,r4) N rf,=A(X'0000000f') MH r1,=Y(10) AR r1,rf LA r4,1(,r4) BCTR r5,0 B mr_op1 mr_op2 CLI 0(r4),C':' second number follows a ':' BNER re mr_op3 LA r4,1(,r4) second number is source length SH r5,=Y(1) BMR re CLI 0(r4),C'0' BLR re IC rf,0(,r4) N rf,=A(X'0000000f') MH r2,=Y(10) AR r2,rf B mr_op3 */* ---------------------------------------------------------------- */ mr_mvc1 MVC 0(0,r6),0(r4) mr_trt1 TRT 0(0,r4),mr_tab1 mr_mvc2 MVC 0(0,r6),0(r7) mr_mvc3 MVC 0(0,r1),msg mr_pct_x_unpk UNPK dw(9),0(0,r7) mr_pct_d_icm ICM rf,0,0(r7) mr_tab1 DC XL256'0' ORG mr_tab1+C'%' DC AL1(4) ORG mr_tab1+C'\' DC AL1(8) ORG mr_tab1+256 mr_hextab EQU *-240 DC C'0123456789abcdef' LTORG , #MSG TYPE=GEN messages DROP , */* ------------------------------------------------------------------- * message open exit - relocated to 24 bit storage * ------------------------------------------------------------------ */ USING mr_oxit,rf USING IHADCB,R1 mr_oxit CLI DCBRECFM,0 any record format ? BNE *+8 jumps if yes MVI DCBRECFM,DCBRECV+DCBRECBR else set to `vb' SLR r0,r0 get a zero CH r0,DCBLRECL any lrecl BNE *+10 jumps if yes MVC DCBLRECL,=Y(125) copy default lrecl CH r0,DCBBLKSI any blksize BNE *+10 jumps if yes MVC DCBBLKSI,=Y(16384) copy default blksize CZV70 TM DCBRECFM,DCBRECU test record type BO mr_oxitu undefined TM DCBRECFM,DCBRECV test record type BO mr_oxitv variable TM DCBRECFM,DCBRECF test record type BO mr_oxitf fixed B mr_oxit0 unknown, return mr_oxitu MVC DCBLRECL,DCBBLKSI undefined, set lrecl from blksize B mr_oxit0 return mr_oxitv LH r3,DCBBLKSI variable, load blksize LA r0,4 calculate maximum SR r3,r0 lrecl CH r3,DCBLRECL check against lrecl BNL mr_oxit0 return if not too high STH r3,DCBLRECL else reset to max B mr_oxit0 return mr_oxitf LH r3,DCBBLKSI fixed, load blksize SLR r2,r2 clear for divide LH r0,DCBLRECL load lrecl DR r2,r0 divide lrecl into blksize LTR r2,r2 test if any remainder BZ mr_oxit0 return if not MH r3,DCBLRECL calculate new blksize STH r3,DCBBLKSI set new blksize mr_oxit0 BR re LTORG , mr_oxitl EQU *-mr_oxit DROP , */* ------------------------------------------------------------------- * workareas * ------------------------------------------------------------------ */ work DSECT , workid DS 0CL4 identifier save DS 18F standard save area save1 DS 16F save area for read/write save2 DS 16F save area for subroutines result DS F result (return) value flags DS X flag bits ucbpin EQU X'80' offline dasd ucb pinned captucb EQU X'40' offline dasd ucb captured debadded EQU X'20' offline dasd ucb deb added notready EQU X'10' offline ucb `not ready' bit noprint EQU X'01' print ddname not present unit DS H offline unit address bpt DS F cckd file blocks per track heads DS F cckd heads per cylinder trklen DS F cckd track length utrklen DS F unit track length complen DS F compression length devtype DS H cckd device type numl1tab DS F number l1tab entries lasttrk DS F last track lastcyl DS F last cylinder cyls DS F cylinders to write tracks DS F tracks to write track DS F tracks being written trk10pct DS F tracks per status message trkstat DS F write status msg at this trk handle DS F persistent c handle prevcchh DS F previous cchh written curcchh DS F current cchh being written waitecb DS A address of ecb to wait on iobswtch DS F iob flip/flop indicator retcd DS F return code rsncd DS F reason code ucbaddr DS A ucb address cucbaddr DS A captured ucb address debaddr DS A deb address bufs DS 0A i/o area address buf1 DS A buf2 DS A buf3 DS A buf4 DS A ptoken DS D ucb pin token devta DS D devtype area ctime DS D current date/time dtime DS CL20 date/time display area lastblk DS F last cckd 16384 block read CZV70 ttr DS F ttr for cckd block dw DS D double word work areas dw2 DS D dw3 DS D dw4 DS D sysut1e DS XL(l_sysut1e) cckd file dcbe prtdcbe DS XL(l_prtdcbe) print dcbe pl DS 32F general parameter list openl DS XL(l_openl) open parameter list devhdr DS 0XL(CKDDASD_DEVHDR_SIZE) device header cdevhdr DS XL(CCKDDASD_DEVHDR_SIZE) compressed device header l1tab DS A l1tab address l2tab DS XL(CCKD_L2TAB_SIZE) l2tab msg DS CL256 message tempbuf DS XL16384 temp buffer for cckd read CZV70 workl EQU *-work work24 DSECT , 24-bit work area work24id DS CL4 identifier zeros DS XL16 24-bit zeroes unitdcb DS XL(l_unitdcb) offline dasd dcb sysut1 DS XL(l_sysut1) sysut1 dcb READ ut1decb,SF,MF=L sysut1 decb prtdcb DS XL(l_prtdcb) sysprint dcb exlst DS F dcb exit list snsidarea DS XL20 device snsid info snsarea DS XL32 device sense rdcarea DS XL64 device characteristics snssarea DS XL40 device snss info ecb1 DS F output ecb 1 ecb2 DS F output ecb 2 iob1 DS XL40 output iob 1 iob2 DS XL40 output iob 2 lrparm1 DS XL16 locate record parameter area 1 lrparm2 DS XL16 locate record parameter area 2 dxarea DS XL16 define extent area openxit DS XL256 relocated message open exit idaw1 DS 255A idaws 1 idaw2 DS 255A idaws 2 ccws DS 258D channel program 1 ccwl EQU *-ccws channel program length ccw2 DS 258D channel program 2 work24l EQU *-work24 RDCinfo DSECT , read device characteristics info RDCsdt DS XL2 storage director type RDCsdmi DS X storage director model information RDCdevt DS XL2 device type RDCdevm DS X device model RDCdasdf DS XL4 device & storage director facilities RDCclass DS X device class code RDCtype DS X device type code RDCprime DS XL2 number of primary cylinders RDCheads DS XL2 tracks per cylinde RDCsctrs DS X number of sectors RDCtrkln DS XL3 total track length (usable) RDChar0 DS XL2 length of ha and r0 RDCtccf DS X track capacity calculation formula RDCfctrs DS XL5 track capacity calculation factors RDCacyl DS XL2 address of first alternate cylinder RDCacyln DS XL2 number of alternate tracks RDCdcyl DS XL2 address of first diagnostic cylinder RDCdcyln DS XL2 number of diagnostic tracks RDCscyl DS XL2 address of first device support cyl RDCscyln DS XL2 number of device support tracks RDCmdrid DS X mdr record id RDCobrid DS X obr record id RDCsdtc DS X storage director type code RDCrtspl DS X read trackset parameter length RDCmaxr0 DS XL2 maximum record zero data length DS X (reserved) RDCtss DS X track set size RDCatccf DS X additional track capacity calc. factr RDCrps DS XL2 rps sector calculation factors DS XL3 (reserved) RDCgdff DS X generic device/cu functions/features DS X (reserved -- zeroes) RDCrduc DS X real control unit code RDCrdc DS X real device code DS XL6 (reserved) RDCinfol EQU *-RDCinfo LRparm DSECT , locate record paramete LRop DS X operation byte LRocount EQU B'00000000' orient count LRohome EQU B'01000000' orient home LRodata EQU B'10000000' orient data LRoindex EQU B'11000000' orient index LRorient EQU X'00' orient LRwrite EQU X'01' write data LRfwrite EQU X'03' format write LRread EQU X'06' read data LRwt EQU X'0b' write track LRrt EQU X'0c' read tracks LRrd EQU X'16' read LRaux DS X auxiliary byte LRusetlf EQU B'10000000' transfer length factor specified LRrcccw EQU B'00000001' a read count ccw is suffixed DS X LRcount DS X count parameter LRseek DS 0XL4 seek addr LRseekcc DS XL2 LRseekhh DS XL2 LRsearch DS 0XL5 search arg LRsrchcc DS XL2 LRsrchhh DS XL2 LRsrchr DS X LRsector DS X LRtlf DS XL2 transfer length factor LRparml EQU *-LRparm CKDDASD_DEVHDR DSECT , devhdr_devid DS CL8 devhdr_heads DS F devhdr_trksize DS F devhdr_devtype DS X devhdr_fileseq DS X devhdr_highcyl DS H DS XL492 CKDDASD_DEVHDR_SIZE EQU *-CKDDASD_DEVHDR CKDDASD_TRKHDR DSECT , trkhdr_bin DS X trkhdr_cyl DS XL2 trkhdr_head DS XL2 CKDDASD_TRKHDR_SIZE EQU *-CKDDASD_TRKHDR CCKDDASD_DEVHDR DSECT , cdevhdr_vrm DS XL3 cdevhdr_options DS X cdevhdr_numl1tab DS F cdevhdr_numl2tab DS F cdevhdr_size DS F cdevhdr_used DS F cdevhdr_free DS F cdevhdr_free_total DS F cdevhdr_free_largest DS F cdevhdr_free_number DS F cdevhdr_free_imbed DS F cdevhdr_cyls DS F DS X cdevhdr_compress DS X cdevhdr_compress_parm DS H DS XL464 CCKDDASD_DEVHDR_SIZE EQU *-CCKDDASD_DEVHDR CCKD_VERSION EQU 0 CCKD_RELEASE EQU 2 CCKD_MODLVL EQU 1 CCKD_NOFUDGE EQU 1 CCKD_BIGENDIAN EQU 2 CCKD_OPENED EQU 128 CCKD_COMPRESS_NONE EQU 0 CCKD_COMPRESS_ZLIB EQU 1 CCKD_COMPRESS_BZIP2 EQU 2 CCKD_COMPRESS_MAX EQU CCKD_COMPRESS_BZIP2 CCKD_L1TAB_POS EQU CKDDASD_DEVHDR_SIZE+CCKDDASD_DEVHDR_SIZE CCKD_L1ENT_SIZE EQU 4 CCKD_NULLTRK_SIZE EQU 37 CCKD_L2ENT DSECT , l2ent_pos DS F l2ent_len DS H l2ent_size DS H CCKD_L2ENT_SIZE EQU *-CCKD_L2ENT CCKD_L2TAB_SIZE EQU 256*CCKD_L2ENT_SIZE */* ------------------------------------------------------------------- * dsects * ------------------------------------------------------------------ */ PRINT NOGEN DCBD DSORG=PS IHADCBE , UCBDSECT DSECT , IEFUCBOB , IEZDEB , DEBLENGTH EQU (DEBBASND-DEBAVT)+(DEBDASDE-DEBDASD)+DEBXLEN IEZIOB , IHAECB , IOSDCCW , CVT DSECT=YES IHAPSA , IKJTCB , STAR TRKCALC MF=D */* ------------------------------------------------------------------- * equates * ------------------------------------------------------------------ */ SK EQU X'07' SNSID EQU X'e4' SNS EQU X'04' RDC EQU X'64' SNSS EQU X'54' RT EQU X'de' DX EQU X'63' LR EQU X'47' WR0 EQU X'15' WCKD EQU X'1d' TIC EQU X'08' r0 EQU 0 r1 EQU 1 r2 EQU 2 r3 EQU 3 r4 EQU 4 r5 EQU 5 r6 EQU 6 r7 EQU 7 r8 EQU 8 r9 EQU 9 ra EQU 10 rb EQU 11 rc EQU 12 rd EQU 13 re EQU 14 rf EQU 15 END , hercules-3.12/util/dasdlist0000775000175000017500000000253012564723224012715 00000000000000#!/bin/sh # # This command prints a track from a CKD DASD image file. # It uses the Unix Octal Dump (od) command to obtain # the device geometry from the CKD header, then xxd to # print the track in hexadecimal format. # filename=$1 cyl=$2 head=$3 if [ -z "$filename" ]; then echo "Usage: dasdlist filename [cyl head]" exit 1 fi if [ ! -f $filename ]; then echo "File $filename does not exist" exit 1 fi # # Check the first 8 bytes of the header for valid CKD DASD image file # ckdid=`head -n 1 $filename | cut -c1-8` if [ $ckdid != "CKD_P370" ]; then echo "File $filename is not a CKD DASD image file" exit 2 fi # # The next 8 bytes contain the tracks/cyl and track length constants # heads=`od -An -tu4 -j 8 -N 4 $filename` trklen=`od -An -tu4 -j 12 -N 4 $filename` heads=`expr $heads` trklen=`expr $trklen` echo "$filename $heads trks/cyl, $trklen bytes/trk" # # If cylinder number is not given then exit # if [ -z "$cyl" ] || [ -z "$head" ]; then echo "To dump a track specify dasdlist $filename cyl head" exit 0 fi # # Calculate the offset to the requested cylinder and track # offset=`expr 512 + '(' $cyl '*' $heads + $head ')' '*' $trklen` num=`expr $trklen` # # Dump the requested track # echo "$filename Cyl $cyl Head $head" echo "xxd -E -g4 -u -s $offset -l $num $filename" xxd -E -g4 -u -s $offset -l $num $filename hercules-3.12/util/dasdlist.bat0000775000175000017500000000003512564723224013460 00000000000000bash dasdlist %1 %2 %3 %4 %5 hercules-3.12/util/bldlvlck0000775000175000017500000001400112564723224012677 00000000000000#!/usr/bin/perl -w # $Id: #**************************************************************************** # # BLDLVLCK # # This perl script checks the user's system for the required levels of # software needed to properly build Hercules from the source repository. # #**************************************************************************** # # ---- CHANGE LOG ---- # # DD/MM/YY Description... # 26/02/03 Created by Jim Morrison. # 21/09/03 Removed libintl & libtool. Although "gettextize" is no longer # run, pkg "gettext" is still needed to run the msgfmt/msgmerge # utilities. libintl is now self-contained. libtool is now self- # contained. (ISW) # 24/10/05 Added history section in preparation for possible changes. (Fish) # 24/10/05 According to jj, automake 1.6 is insufficient. He says 1.9 works # though, but doesn't know about 1.7 or 1.8 yet. (Fish) # 30/11/07 Changed URL to point to hercules-390.org. (JRM) # 30/11/10 Remove obsolete CVS test, add special gsed test for Apple/Darwin # (Enrico Sorichetti by Fish) # 06/12/10 M4 fix (Enrico Sorichetti by Fish) #**************************************************************************** use strict; # Facility, required level, special flag, download URL my @req = qw( autoconf 2.5 0 http://www.gnu.org/directory/autoconf.html automake 1.9 0 http://www.gnu.org/directory/automake.html gawk 3.0 0 http://www.gnu.org/directory/gawk.html gcc 3 0 http://www.gnu.org/directory/gcc.html grep 1 0 http://www.gnu.org/directory/grep.html libiconv 1.8 1 http://www.gnu.org/directory/libiconv.html m4 1.4.6 0 http://www.gnu.org/directory/GNU/gnum4.html make 3.79 0 http://www.gnu.org/directory/make.html perl 5.6 1 http://www.gnu.org/directory/perl/html sed 3.02 0 http://www.gnu.org/directory/sed.html ); my $msg; my $instversion; sayintro(); for (my $i = 0; $i < @req; $i += 4) { my $facility = $req[$i]; if ($facility eq 'sed') { if ($^O eq 'darwin') { print "Apple/Darwin ==> sed changed to gsed!\n" ; $facility = 'gsed'; } } my $level = $req[$i+1]; my $special = $req[$i+2]; if ($facility eq 'm4') { if ($^O eq 'darwin') { print "Apple/Darwin ==> custom version parsing!\n" ; $special = 1; } } my $url = $req[$i+3]; if ($special) { weird($facility, $level, $url); } else { if (present($facility, $url)) { my @resp = `$facility --version`; chomp $resp[0]; $instversion = getvers($resp[0]); $msg = ckvers($level, $instversion); print "$msg\t$facility requires $level, found $instversion\n"; print "\tURL: $url\n" if $msg eq 'UPGRADE'; } } print "\n"; } exit 0; sub weird { my ($facility, $level, $url) = @_; if ($facility eq 'libiconv') { if (present('iconv', $url)) { my @resp = `iconv --version`; chomp $resp[0]; my $instversion = getvers($resp[0]); my $msg = ckvers($level, $instversion); print "$msg\t$facility requires $level, found $instversion\n"; } print "\tURL: $url\n" if $msg eq 'UPGRADE'; return; } if ($facility eq 'perl') { if (present($facility, $url)) { my $instversion = getvers($^V); my $msg = ckvers($level, $instversion); print "$msg\t$facility requires $level, found $instversion\n"; print "\tURL: $url\n" if $msg eq 'UPGRADE'; } return; } if ($facility eq 'libtool') { if (present($facility, $url)) { my @resp = `libtoolize --version`; print "\t$resp[0]\n"; chomp $resp[0]; my $instversion = getvers($resp[0]); my $msg = ckvers($level, $instversion); print "$msg\t$facility requires $level, found $instversion\n"; print "\tURL: $url\n" if $msg eq 'UPGRADE'; } return; } if ($facility eq 'm4') { # m4 --version: GNU m4 1.4o if (present($facility, $url)) { my $resp = `m4 --version`; chomp $resp; my $msg = 'HUH? '; my $instversion = "DUNNO"; if ($resp =~ /GNU [mM]4 (\d+.\d+.\d+)/) { $instversion = ''; $instversion = $1 if defined $1; $instversion = "$1.$2" if defined $1 && defined $2; $instversion = "$1.$2.$3" if defined $1 && defined $2 && defined $3; $msg = ckvers($level, $instversion); } print "$msg\t$facility requires $level, found $instversion\n"; print "\tURL: $url\n" if $msg eq 'UPGRADE'; } return; } print "ERROR $facility flagged as special, not found\n"; } sub getvers { my $resp = $_[0]; my $vers; if ($resp =~ /(\d+).(\d+).(\d+)/) { $vers = "$1.$2.$3"; return $vers; } if ($resp =~ /(\d+).(\d+)/) { $vers = "$1.$2"; return $vers; } print "HUH?\n"; } sub ckvers { my ($reqvers, $instvers) = @_; my @rv = split /\./, $reqvers; my @iv = split /\./, $instvers; for (my $i = 0; $i < @rv; $i++) { if ( (exists $rv[$i]) && (exists $iv[$i]) && ($iv[$i] > $rv[$i]) ) { return 'OK'; } if ( (exists $rv[$i]) && (exists $iv[$i]) && ($iv[$i] < $rv[$i]) ) { return 'UPGRADE'; } } return 'OK'; } sub sayintro { print "This utility will check the level of various utilities needed to build\n"; print "hercules. Checking is done against versions that are KNOWN to work.\n"; print "This doesn't mean a build will NOT succeed with older versions\n"; print "of the utilities, but will give a hint as to what package may need\n"; print "an upgrade if the build ever fails with some odd reason.\n\n\n"; } sub present { my ($facility, $url) = @_; my @present = `which $facility 2>/dev/null`; if (! @present) { print "INSTALL\t$facility not found\n"; print "\tURL: $url\n"; } return scalar @present; } hercules-3.12/html/0000775000175000017500000000000012625667404011234 500000000000000hercules-3.12/html/images/0000775000175000017500000000000012625667404012501 500000000000000hercules-3.12/html/images/loadoffu.gif0000664000175000017500000000135512564723224014706 00000000000000GIF87a%Ʀ‚‚¦—9­­­¦x”‹z¥¥¥¡¡¡ŸŸŸººŸžž¦Pɶ[•z]”z\™™™4&,è­4‘‡§¨€v™š’ˆ|jr}r¨‰†¨}[¦ƒ„œœ\F$©s””“œŠ1¤†¨u˜‡e|l¥’k¨~n¬|^«z]©z[š~‹˜z^–z\ƒ\F”qP¡{`žŸŸ§z\“{f}|nª}l˜pMŸˆW«{Yª««|fŒvDŒjDšš—¢žwžd^Dƒœœœœ‘wYtF,¥{\•’§‚›z\¸º–Á¶«€[ÒÓ¬¬z\«z[D.$žŠ:›’beaX¨¨©z\žœ”z[ƸW§~qª}j¥…¤…|gÿÿÿ¯¨k£…fÀ=¤†I§€w•wX©©ˆƒv«{]© h†|j©§uª{_¦ƒ†œžŠ‚t‹ŒŒ¿¿¿ÉÅv¤†”¨}c«z\,%þ€‚ƒ„…†‡ˆ‰Š‹Œ‰Žp‚^p^“^‘^ ‘ƒ”‚p•—˜•¤Ÿ„¤p›——­¤¨£•°«š ¬^®½° Ÿ›¦Ÿ˜¢’ËÌ̓ÎÓÑÓÐÎÖÕÔØÖÝO32M49/-ÞéÓMMMMc&MêÝ$ZrMrýr\]²ÄpðäÞ~MT`© „Iœ4Ápœ3`0`à@™)¨ØK÷Ã><ªlä(äÁ2¤cwd!B 8 4.V˜)bC Vp"À‰3 $if6ÙÒĈ‚žL—šqPãIGn”hãëR)Cüø*bAS>–úäðAŒ I²9BÀŸ‚¼qã`â=Zš¬AM‚=¢ÄŒÙÁ `–d€7Ù"‡×…˜£¡ x(†îöÃAƒ+;Ö®žM»¶íÕ;hercules-3.12/html/images/restartu.gif0000664000175000017500000000252012564723224014753 00000000000000GIF87a!çÿK¥ÿºÛÿ‹Æÿ°Öÿ7›ÿÁÿ¦ÑÿËåÿH£ÿm·ÿŒÿÜíÿ> ÿ>žÿˆÄÿ4™ÿ£ÑÿO¨ÿ ÿj³ÿ;žÿ…ÂÿªÔÿV«ÿV©ÿÅãÿ€ÿ~ýq¸ÿÿ]®ÿ …ÿ?Ÿÿ®×ÿÓéÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿµÚÿ<ÿ«Õÿ †ÿ|¾ÿ|¼ÿ¡Ðÿ(“ÿ—Íÿ—ËÿÆÿ²Úÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿ”Éÿe²ÿ‰ÿÔêÿ€¿ÿG£ÿ¶Ùÿ)”ÿ˜ÊÿâðÿŽÇÿŠÿ„Âÿ„Àÿ0—ÿŸÏÿ€ÿ•Êÿÿÿf³ÿf±ÿ°×ÿ7œÿ¦Ôÿ¾ÿR«ÿR©ÿw»ÿÁáÿm¶ÿÿˆÃÿ£ÎÿO§ÿãñÿ;ÿªÕÿÏçÿq¹ÿ–ËÿŽÿŒÆÿÖêÿ]¯ÿ]­ÿ§Óÿ§ÑÿÌåÿx¾ÿx¼ÿÎÿ$‘ÿ“Ëÿ“Éÿ¸ÛÿŒÿ? ÿ®Úÿ®Øÿ‰ÿ-+„Z­ÿZ«ÿ‚ÿuºÿ¿Þÿäòÿ|ùÚíÿ«ÔÿW«ÿW©ÿC¡ÿ²×ÿžÏÿJ¤ÿ”Êÿe³ÿˆÿ€Àÿ¥Òÿ,•ÿv»ÿ›Ïÿv¹ÿ›ÍÿG¢ÿl¶ÿ‘Èÿ¶Üÿb±ÿb¯ÿ]`¿†ÿ}¾ÿ}¼ÿN©ÿN§ÿi´ÿi²ÿ‹ÿ„Áÿ,!þØTAJ¦|4d£hÈ!ªD`i† Œò"„ ÜÄ%ÔLjú°Ò!b$R´ˆ"ãÆ:ü8é°©§K&3áè£pBÃCwZˆ°£¢P$iÄÉc€ž›"yàRÑA>²€ i ™N¡JÕÓÑÖ7%~†òŠ#¡X“.mJ3ê(=U±zêñgk…“C2t(B)SHE.F±s«#Oo —¤Û',¼/Å,¥Å;S±^¸ƒ‡æ®š³ýàìÄ´gºŒÂê…”#™ {Ev,㈷KC±ƒ %B`À™ô³ ÐÎ Aë½MóÖ þ\pÔ  Z 1“èÒ£?2ÈRBÓiÑÒrR`£Â¹òbפAH$P1 Â# ŒæVFÐÑŸÿ5PÇ%aøPÀA€AF¡¸!wXPá h`x\ep!ŠAui€Å'Џä€caÕ„$4ÐãsBtB˜p(uW^+2•Cyä0,É•W 8¹˜YaeÅC±xÏ]æÚV&ÅFKŠ”ÕXX¹`•”¼èŸ#­ÅµåuE‘õXåádžPƒ‘þ% G\ ÜøÕJ %V7à1FdR²è•IÇÕB%„ÅXea… "†²A¥ 7z¦9˜fs]WHvC`5¬ºàj™ŒÊ(ÝktñQÈl=í¡ì²Ì6ëì³Ëní´Ô2 @µØB+P@;hercules-3.12/html/images/back.gif0000664000175000017500000000127512564723224014010 00000000000000GIF89aD³„ÿ„ÿÿÿÿ))ÿ11ÿ99ÿqqÿ¯¯ÿÎÎÿÖÖÿÞÞÿïïÿÿÿ!ù,Dû0ÈIé«8ëÍ;Âåd¹¡©®š²p¸¯l“tøì|ïÿÀ ¨É ŽÈ¤rÉl:›¢ŠñI­Z™ÑÉôÊíB¥N…xœ8,b³’h8‰2¡@ âÄWû|ûývI ozInj ‡ {3To˜Œ I’Gn ’  GŒv‘N"[IojoIpn¸ Ÿ £ª¡ r®”U–˜¦…G Џ spap¦ŠT;W‰o­Gµ›oɪÙ»_°±cnÖGƒ…¦éMŒÇƒ¿XÜ‘…ĘNðLÛ$ §2©ŽÉ1¥àI‘¤ÃŽ{®¿8JÊW«‘2>NšaâhfZgŒìºÄ±P¾†Çþ%ɲŒIGH´Þü l›q7ES³§’1PHB `i*³ÐIÀŽ;4 tiêÔ‹Ù³5À ]Û…l@¦CâÊûãÃÎxq q›·/J¾~ý‚¸/áÂ"!þïThis GIF file was assembled with GIF Construction Set from: Alchemy Mindworks Inc. P.O. Box 500 Beeton, Ontario L0G 1A0 CANADA. This comment block will not appear in files created with a registered version of GIF Construction Set;hercules-3.12/html/images/loadonu.gif0000664000175000017500000000077212564723224014552 00000000000000GIF87a%¥¦‚‚ŸŸŸ´¶”z\4&,üæD§¨€vK65ˆ|jr}r¦ƒ„\F$©sœz\¨u|lüþÔüþ¬ƒ\F¡{`“{füþ„}|nª}l˜pM«|fŒvDŒjDüâ4d^Düþ¤tF,§‚üþ|¬z\üþTD.$üÖTüö,¨|üÂTŒŽü¾Tª}jüÚ,¥…ü¶,ÿÿÿ<+/†|j©rùÿÿ¦ƒ†¿¿¿šz\¤†”üþ”üª$,%þÀ‚@,GaÉd*›Ð¨t P(¨Dލád€@vËÈF-·í¼[õ8½àÂÝî\í.ªíq`gdr2iƒvgcalf8WX‘’“”TJ—˜™š›œžŸ—3  ˜'%   %%%%*5%ž.:%:ÀÀ¾'›'¿¿&&)¾% ›°¾+;Í;+´º™' ¾1$!ÙÚ;$)ì™°#/;Ø6;!!9î %äÍ 1o‰h¸+#àÀ‚Qذ%®á»Ç1;#”àñp# Œ»Q‚Å ø"¶ “ Z,b¤˜gà ;vŽÑôí'"<‰óFSÚ4R ~zIªªÕ«¤‚;hercules-3.12/html/images/startd.gif0000664000175000017500000000151712564723224014410 00000000000000GIF87a!ƪ·ª¦µ¦ÜäÛN|L×àÖÔÞÓÂÐÁ¿Î¾¾Ì½»Êº·È¶°Â¯^‡[«¾ª[…XXƒU©¶¨WƒTUR¦´¥TQ¡¸ ¡¶ £²¢O}LŸ°ž²œ™¬˜•ª”’¨‘Œ¤‹ˆ¢‡ž€œ~~œ}¬¿ªœ­š›­™˜¯–äê䎥ŒÙâÙ‹§‰‹£‰‡¡……Ÿƒ„Ÿ‚~›|{™yz™xx—vw—ut•rq“on‘lm‘kjhged‹bc‹agzoa‰_Z…XPNÚãÙž°žÏÙÎÃÑÂ=NE¹É¸¸Ç·¶ÇµµÅ´fŒc³Å²`ˆ]­¿¬\†YY„VV‚SS€P¤³£¡± ž¯¯œ›­šš­™—«–”©““©’‘«§Ž¥¥ŒŠ£‰‡¡†ƒŸ‚}›|z™yÞåÞªŽÝåݤ‹‰¢‡ƒž‚ž€œ}}š{|šzv–ts”qr”pljkiiŽgeŒc_ˆ]\†Z,!þ€‚ƒ„…†‡ˆ‰Š‹>j0l1n24o6q78r:t;u=?M w@PQRA‚>.bklcn3”–˜rsœž  O¥§©¬-®0"²´•—89›€é÷/àÏZ3±Ò`åÊáË+3óó§Md¼e%YQ!mZ®×—bܹýM+ T†X©Œx§Cl·½¾Åj pÒ&,ÏåéQ2Þ8XQp>»´åÄxLæ Vp'm¸x—†=ÕÀù8«é×[Ár³fÜEBF-‚aà&¨à‚ ;hercules-3.12/html/images/bkued.gif0000664000175000017500000000250012564723224014172 00000000000000GIF87a!çK¥ÿºÛÿ‹Æÿ7›ÿ¦ÑÿH£ÿm·ÿŒÿ> ÿˆÄÿ4™ÿ£ÑÿO¨ÿ ÿj³ÿ;žÿ…ÂÿV«ÿV©ÿ€ÿ~ýq¸ÿÿ]®ÿ …ÿ?Ÿÿ¤Îÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿ<ÿ«Õÿ †ÿ|¾ÿ|¼ÿ(“ÿ—Íÿr·ÿ—Ëÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿe²ÿ‰ÿ€¿ÿG£ÿ¶Ùÿ\_¾)”ÿ˜Ìÿ˜ÊÿŠÿ„Âÿ0—ÿŸÏÿÿÿf³ÿf±ÿ7œÿ¦Ôÿ¾ÿR«ÿR©ÿm¶ÿÿc¯ÿˆÃÿ£ÎÿO§ÿ{új²ÿ;ÿªÕÿªÓÿ Îÿq¹ÿŽÿŒÆÿ8›ÿ]¯ÿ§Óÿx¾ÿx¼ÿ$‘ÿ“Ëÿ“ÉÿŒÿ? ÿ®Úÿ®Øÿ‡ÿ-+„Z­ÿZ«ÿ‚ÿuºÿW«ÿW©ÿC¡ÿ²×ÿJ¤ÿ”Êÿ”Èÿe³ÿˆÿ€Àÿ,—ÿ,•ÿQ©ÿv»ÿ›Ïÿv¹ÿ›ÍÿG¢ÿl¶ÿb±ÿb¯ÿ†ÿ}¾ÿ}¼ÿN§ÿi´ÿ‹ÿ³Öÿ„Áÿ,!þH° Áƒ*\xC>,ʤ9Ò¤M5` XЃ .ª|Ù1£„‹3*8xɃ |Z˜™@Ñ"F(W8zy!É 8&QV`iÁ%%-ÊH à"˜;âàâà‚@OR`ÉÁ‡ËЬh#TSAü9¦D†3,a QáRHf–jzsˆÎU¿ šáÇË?0ðXØóÎÝ™Lõ`Ôˆ–g’~XÒ0±MQ°I'Ô dóiÔ€\ŽÃ2‚œ‰?Ëèƒe¦‘&|3úíøQ­O– xÔ¹h㘶÷^Ô0"'o. z²´üµ\㓦¹Ý¦¬(§?þ~¸ÀRÄ®iñÌøaı64ÿK•åóèåüéL‰ ÙˆÅd@°ÛS±´Â!œÇƒÄyæ’ a€w”½àKwäà†Ôa hô^Û5€dO9GKSܱ`Ôñ@ 1(¶ÇŽÉ4QENõK ø‡^€¸„°áAÅ`a¡Ô¤-…_,eÁ„‘9tÑ`u€ÀÐOØ%%|É7KR±2&Y£œÙ±Øqx-…Ûr°$FlÙA ÷9¨ßŠ}•X5¥Éb@Ä–y¬ g~Ä0fcHA¶ç,Ù@H$dQd‡—²ÙzŸÁTÛD'ʱ$€¨‘Nêƒ:t"z4œ )vw•¡FM‘aì±È&«ì²Ç ;hercules-3.12/html/images/loadu.gif0000664000175000017500000000250112564723224014205 00000000000000GIF87a!çÿK¥ÿºÛÿ‹Æÿ7›ÿ¦ÑÿH£ÿm·ÿŒÿÜíÿ> ÿ>žÿˆÄÿ4™ÿ£ÑÿÈãÿO¨ÿ ÿj³ÿ;žÿ…ÂÿV«ÿV©ÿ€ÿL¦ÿ~ýq¸ÿÿ]®ÿ …ÿ?Ÿÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿ<ÿ†Áÿ«Õÿ †ÿ|¾ÿ|¼ÿ(“ÿ—Íÿ—Ëÿ²Úÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿe²ÿ‰ÿ€¿ÿG£ÿ¶Ùÿ)”ÿ˜ÊÿŽÇÿŠÿ„Âÿ0—ÿŸÏÿ€ÿÿÿf³ÿf±ÿ°×ÿ7œÿ¦Ôÿ¾ÿËäÿR«ÿR©ÿm¶ÿ·ÜÿÿˆÃÿ£ÎÿO§ÿãñÿ;ÿªÕÿÏçÿq¹ÿ–ËÿŽÿŒÆÿ]¯ÿ§Óÿ§Ñÿx¾ÿx¼ÿÎÿ$‘ÿ“Ëÿ“ÉÿŒÿ? ÿ®Úÿ‰Äÿ®Øÿ‰ÿ-+„Z­ÿZ«ÿ‚ÿuºÿ|ùÿÿÿW«ÿW©ÿC¡ÿ²×ÿJ¤ÿ”Êÿe³ÿŠÅÿˆÿ€Àÿ,•ÿv»ÿ›Ïÿv¹ÿ›ÍÿG¢ÿl¶ÿ‘Èÿ¶Üÿb±ÿb¯ÿ]`¿†ÿ}¾ÿ}¼ÿÇâÿN©ÿN§ÿi´ÿi²ÿ‹ÿØìÿ„Áÿ,!þ@4Áˆ!m.8¡rGG’8Ò§Å D¡Âà â DôäÑ C]ÜÐiÂPPV$R´8"ãF3Þ Ñ€¨ç†A& Åp£0BÃ:gNp@£â˜DüØ“Èc€žˆülx2!ÏÁ6œ8pé ™N¡J]Óñ V0 ~>ò#¡X“.mJ3j¤5U±.²gë„“C2tøA)Ó><.1s+ŸE` —¤ë&,¼/­,¥yÄ3S±VX¢†æ®‡³ÍàìÄ´[¢DÂ*eŸ™ {Ev,㈷K1ƒ•K 9V„ô³ ÐÎ Aë½M“VþTà£(Œf^Ózò`¬“C+™ίA]’I&2@€Ä Ž`F ÛÍ4V=”Ÿú GzL…r ÀH ÆC¢q‡• šÀ„—Á•ÅT×M4r‡K È×VBüáB&>—ƒ"„ ‡QwåbX=ãŽ=ê·B\yÕ‘‹™%VJL‘cx€÷Üe®meRlD±tGY%U J(H‰ùñÑZ\Q^WY b¥F h) <æ÷cq!ÐâW+9rÔXÁ€Æ_h MþWG•Pc•…U!vìé…’!Àù¥„br6Gv:`5À(¡¦0ê–¢(Ýktµ1Çl=±áë¯À+ì°¿"Bì±È @²Ì+P@;hercules-3.12/html/images/startu.gif0000664000175000017500000000152212564723224014425 00000000000000GIF87a!ƪ·ª¦µ¦ÜäÛN|L×àÖÔÞÓÂÐÁ¿Î¾¾Ì½»Êº·È¶°Â¯^‡[«¾ª[…XXƒU©¶¨WƒTUR¦´¥TQ¡¸ ¡¶ £²¢O}LŸ°ž²œ™¬˜•ª”’¨‘Œ¤‹ˆ¢‡ž€œ~~œ}7F>¬¿ªœ­š›­™˜¯–äê䎥ŒÙâÙ‹§‰‹£‰‡¡……Ÿƒ„Ÿ‚~›|{™yz™xx—vw—ut•rq“on‘lm‘kjhged‹bc‹aa‰_Z…XPNÚãÙž°žÏÙÎÃѹɸ¸Ç·¶ÇµµÅ´fŒc³Å²`ˆ]­¿¬\†YY„V^oeV‚SS€P¤³£¡± ž¯¯œ›­šš­™—«–”©““©’‘«§Ž¥¥ŒŠ£‰‡¡†ƒŸ‚}›|z™yÞåÞªŽÝåݤ‹‰¢‡ƒž‚ž€œ}}š{|šzv–ts”qr”pljkiiŽgeŒc_ˆ]\†Z,!þ€Pj1l2n35o7q89r;t?L w@OQRAƒP/bklcn4‹rs“•— Nœž Pº.¥1"©«ŒŽ9:’”=?v´›ŸºPi¼…‡ª¬pűÈÊšQRÏ-ia¥!#ˆÁ­Æ²Ü¶Ï- .0b1èÕ®íȘœl’ðì šqÒ ³ÑX;K7=뢂ž½…F´á·.R,KÊj=óÐÅ ½h½Pq¦%´ži!YaÊTŠ]c÷qÖ³[hžtÑ$‰(Œ¬BRÂÂ-{Úy–¨Ðq¨9Sä)˜Yáo’dÏ8T J‘Þ"¸Êœ¹`ÀÍ€\„ìôøò™ ,Ug¶ƒr¢œë¢RzVńڂ¿|cŸ>œ¬X{¦ÁÊÀIJ®woÚFuÃ<>£ÒùóÚ«(Åœ;ÛŽg¨ ±â80̓Ñ,SCíêÙ”ÜO ÿ>žÿˆÄÿ4™ÿ£ÑÿO¨ÿ ÿj³ÿ;žÿ…ÂÿV«ÿV©ÿ€ÿ~ýq¸ÿÿ]®ÿ …ÿ?Ÿÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿ<ÿ«Õÿ †ÿ|¾ÿ|¼ÿ(“ÿ—Íÿ—Ëÿ²Úÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿe²ÿ‰ÿ€¿ÿG£ÿ¶Ùÿ)”ÿ˜ÊÿŠÿ„Âÿ0—ÿŸÏÿ€ÿÿÿf³ÿf±ÿ7œÿ¦Ôÿ¾ÿR«ÿR©ÿm¶ÿÿˆÃÿ£ÎÿO§ÿ;ÿªÕÿq¹ÿŽÿŒÆÿ]¯ÿ§Óÿ§Ñÿx¾ÿx¼ÿ$‘ÿ“Ëÿ“ÉÿŒÿ? ÿ®Úÿ®Øÿ‰ÿ-+„Z­ÿZ«ÿ‚ÿuºÿ|ùW«ÿW©ÿC¡ÿ²×ÿJ¤ÿ”Êÿe³ÿˆÿ€Àÿ,•ÿv»ÿ›Ïÿv¹ÿ›ÍÿG¢ÿl¶ÿ¶Üÿb±ÿb¯ÿ]`¿†ÿ}¾ÿ}¼ÿN©ÿN§ÿi´ÿi²ÿ‹ÿ„Áÿ,!þÀ!ˆ`*a’ÆÆ†4àá&Å¢abƒ È ÄƒÄÏ ;R˜1ÂpÎM$R´"ãF/Äø¸€§':&í´£ðAÃ3[Hh£â?è`“Çc€žxÞ`@aÍA0Žôp) ™N¡JõÒQ Ö*~úñÚ"¡X“.mJ3* /U±î‘1fk„“C2tÈA)S78.Ñrk›=U —¤&,¼/›,¥-S±N(‚"†æ®w³½àìÄ´P’ª$P›™ {Ev,㈷KÿЂ5 ƒ5NX‰ó³ ÐÎ Aë½M3ÖþLh£ÇÊkº`ï–ÝNúJ¬XD8ßA>õ’3î¸ z7¯ã™W`•Cò)Aß`ç]·ÒgŒ‰ÆV 8B^×HüaP]ÁG.)ðŸXõ‡ YLø\ z&Jü‡”ƒ<`倉(ªHß .rå•ü-f–DX±„‰9¨Þs—¹¶•I±ÅRe56V%q£Î×Fkqùx]Qd=ÔV]”`À‘¬â|,Z~µRGq€ \8AÅ‘r¸©#‹Áq%„P 1VYXÕFšSÜèA—L"ø$gedgVÜðh ‘"ùf…Ò%XW³õôŪ¬¶êê«°²ŠG¬´ÖÚ*¶æ«@;hercules-3.12/html/images/manoffu.gif0000664000175000017500000000134612564723224014542 00000000000000GIF87a%Ʀ‚‚¦—9­­­¦x”‹z¥¥¥¡¡¡ŸŸŸººŸžž¦Pɶ[•z]”z\™™™4&,è­4‘‡§¨€v™š’ˆ|jr}r¨‰†¨}[¦ƒ„œœ\F$©s””“œŠ1¤†¨u˜‡e|l¥’k¨~n¬|^«z]©z[š~‹˜z^–z\ƒ\F”qP¡{`žŸŸ§z\“{f}|nª}l˜pMŸˆW«{Yª««|fŒvDŒjDšš—¢žwžd^Dƒœœœœ‘wYtF,¥{\•’§‚›z\¸º–Á¶«€[ÒÓ¬¬z\«z[D.$žŠ:›’beaX¨¨©z\žœ”z[ƸW§~qª}j¥…¤…|gÿÿÿ¯¨k£…fÀ=¤†I§€w•wX©©ˆƒv«{]© h†|j©§uª{_¦ƒ†œžŠ‚t‹ŒŒ¿¿¿ÉÅv¤†”¨}c«z\,%þ€‚ƒ„…†‡ˆ‰Š‹ŒŽ^^p‘“‘^‡‘pŸ”p–‘’†p^•pœ‘—£ªž ©¥’©œ§…©‚©^£½²ÆÇȆÉÎÌÎËÉÑÐÏÓÑØO32M49/-ÙäÎMMMMc&MåØ$ZrMrør\]Y1OòžÜk¢K%Lâ0 ठyçäœ)ã€ÊŒHA%¹'ìÙàQÅâE!¾qà€Ü¹#€r`À!µÐ¸XAÂ¥ˆ M$X™‰`æÌ$t¤qÙdK# p-jÆA ¹Q¢M-©E¥ qð#«ˆapø(Z‹Ã1L0üÈæSj!òƇò hi²J5 ôˆÂ’e‡€P€Y’a]c:ˆ6bކ",Öax¸Û ®ì([ºµë×°K;hercules-3.12/html/images/stopd.gif0000664000175000017500000000263012564723224014235 00000000000000GIF87a!çÿzzÿ)+ÿYYÿ‹‡ÿ‡‡ÿ ÿ:8ÿ88ÿÿõÿRRÿPRÿ€€ÿ˜—ÿ31ÿ11ÿa_ÿ__òÿÿÿ<>ÿ†ƒÿššÿIKÿyyÿ**ÿXXÿ ÿ ÿ|ÿ—“ÿceÿ““ÿy|ÿ×ØŽ ÿ^[ÿBDÿrrÿX[ÿ##ÿ!#ÿQQÿ›–ÿÿ20ÿ00ýÿˆŒÿWTÿ==ÿ;=ÿkkÿ™™ÿ‚ÿÿLJÿJJÿxxÿ+)ÿ))ÿÿddÿ–’ÿ’’ÿx{ÿª©ÿÀÀùÿÿCCÿqqÿ$"ÿ""ÿRPÿPPÿÿ]]ÿ‹ÿ‹‹ÿ‡‹ÿ<<ÿTSÿjjÿÿKIÿIIñÿ„„ÿjmÿÿ55ÿecÿccÿîÿDBîÿžžÿ!!ÿ!ÿ}}ÿ..ÿ\\ÿ ÿ=;ÿ;;ÿƒ€ÿgiÿÿFHÿÒÒÿ''ÿUUÿƒƒÿÿ•šÿÿ44ÿ|yÿ`bÿùÿ¾¾ÿÿÿ §ÿ[XÿUXÿÿƒ†ÿËËÿ ÿ ÿNNÿ||øöÿ--öÿ[[ÿ‰‰ÿ ÿ8:ÿhhÿ––ÿ’–ÿÿÿGGÿuuÿ&&ÿTTÿ‚‚ÿÿÆÇÿ{xÿaaÿ_aÿÿ@@ÿ¢œÿnnÿTWÿœœÿÿMM»++ÿˆˆÿ ÿ99ÿ79ÿigÿggÿ••ÿÿHFÿFFÿttêÿmjÿQSÿÿ22ÿ02ÿb`ýÿ``ÿŽŽÿÿ??ÿ››ÿÉÉÿ ÿ,!þH° Áƒ*\¨ŠƒT<0% vA8Ì1S슂0ÀÖòBÆGÄØ¨ªÃ¦‡;â$UãÀÅF>4-é˜ °Hð”ìãH –j˜Â• ‹ÄQZåÑ•†ƒ&3gtÈúó“U—½ú,ÐÂRBR-Rí˜5ÓF+/2jZÊã ktyÒ‹%—IA.È Q¦a›ª^­«€ëVBY–º+((óŒŠ$/»ä.i|éO…ÔvX*)ee’^’þ?äQ¸bžç,AäÑgj–™¶ß¨|YÐ&'‰ÈÏ4WÀÄØõK$ÄWÊ-“|q™ 4< [üâ€"UŒPGzKr…,€TÀ’"Dd’ÂÞ¢FžH‘H§Œ% ƒžU9K¹(BB-#Þ‹{¨!Œ  QFœà`È[  *:\ÂR!€ð‰ˆ$‚ f 4e[’ä—UtYÂR[äB"hÙ ˜ÒåZ3Q[9™ KRLQH.h\9â ¯älaÇ£Paј:±Ä‡«lá†"`9_l'n”œAõ¨\, ÁG`ãŽòÁ†‰q6‘J´Ô& À%•ˆ"$T*¢‡¦®nÙÁ ]fQžTq±” ½J1ßVHg1•ÅS6|¦ K„dpG“úé!ng…«{@ÑmŒ ˆ±)â 1i¥¹€Pàv\¼œh%Bkgl¸" 7ìðÃGܰ@;hercules-3.12/html/images/dial1.gif0000664000175000017500000000255212564723224014101 00000000000000GIF87a;6„www___UUUMMMêêê333)))ÌÌÌÀÀÀ²²²–––†††€€€fffÿÿÿãããÝÝÝ×××"""ççÖ  ¤ ,;6þ &Žd‰U”a€µTÆ –Å@0u™À PT©‹âà@H€ àp„bÑ(¨†`¡¤ HD ‡âÀP"B ©V ÀÀîWD ij… l U JJuv }} Žf h… ‰5 uZ’9—B… ž  U[UÅž’]°%YŸ Š Ä"fŸÄÒÃu Í" lÒ›W žŽ"vùlãŸ5Ð »ô+‹¡M…Æ!l³   0@`‡X PŽ"à0Ì6¼Þmz§ÄB€:þP  B,êD[@‘€›ÜÀPpP W5ià”l ÁA Zz«b¬ F ø )*­h„ " (j3¤€ x†BjÎ >‚„= ÄZ“aA‡(P埭Ãt}:àc žà‚¶©ESÍŽYÓ»B kŠ„´×`êðAH¢÷S“´#v" ÉÐ'è>Pwâ?]‡Œhhg„00à©î+®‹þ ýCáÇ…&в¦mȈ•i’)Àb›0åEjSŠÐR"V9–ä`qY'¤ÍØ  dCQ<éAA7=HPQL É\9\uÀjNib§Œù€ÖÙñÈD”€a Ô&ªäbELŠ‹SJ~(äpâ ä“”–•_ ‰Cjÿ䩪„(l!g@sÓ#Ÿ’”¡?ŒrVi ¥jÁµþ@Ë«iBù4´ä Ô¬ŠD¦ZHµØ*A-µ`nzÞ›¶;L³èzÐ’Ä‚( ºµØÛ«rBaç¸Í:[gªg¨šj¾®Òâ–Ü&*6˜ÂвėJRö€M —B¯ÆÃÕœÁö{16KTk­½JLš,yŸ(Pdž 8Â!¯mMs¨ÑïµJÖñis¦É< >Tž*ÜBi@“Qtn*.¹’Y–2g”@`ó/s48ô¯ú2œ” ×Ñ6í5‰ªîÁ‹;/nüQÂV&;Hn':÷£1¬ÉÌ)ÁKÈëßÔ›èä¼`“¤¸ÌáF€‰"¬=Z´ópœÛtÜ¡óREÝé–¦ 1nWÉýö•¿êV¯²Ø¤a„Uƒx~=yÜÔBÃSƦYÀ' ‘„w–’ƒx=4¸ÔÝð'áM °„%£Ý^£!|öéXŒÀRÁ-W-Awé•ca÷¯ƒÏZ@'v-ùªÜ¤>ô"D TRGþ‘/ÅA € ‰ÆAÄw•À `œSG.¦™¹(<Yˆød-$5$Mf–ªš‰åQEñ˜þP8LDpòó˜C‚5®P‚†—¸Àp¹BÈ$eèÂÓžD?°ä7šGmðÔ…`èM!;hercules-3.12/html/images/manonu.gif0000664000175000017500000000076012564723224014403 00000000000000GIF87a%¥¦‚‚ŸŸŸ´¶”z\4&,üæD§¨€vK65ˆ|jr}r¦ƒ„\F$©sœz\¨u|lüþÔüþ¬ƒ\F¡{`“{füþ„}|nª}l˜pM«|fŒvDŒjDüâ4d^Düþ¤tF,§‚üþ|¬z\üþTD.$üÖTüö,¨|üÂTŒŽü¾Tª}jüÚ,¥…ü¶,ÿÿÿ<+/†|j©rùÿÿ¦ƒ†¿¿¿šz\¤†”üþ”üª$,%þ@€pH,ȤrÉl:›™ âӨ@!;Fq_*Εvœ¬ŠãF¯cµ,H—¥i¦ec}rO†‡ˆF‹ŒŽ‘’“”•–”3 —'% – %%%%*5%”.:%:··µ'‘'¶¶&&)µ% ‘§µ+;Ä;+«±' µ1$!ÐÑ;$)ã§#/;Ï6;!!9å %éê!êê$%4Ê•€O¿}(lXpÀˆÎÞ¹›cˆ†Jð0(EE½®Ý(Áb†w[H&ÉÅ*1R¨3ðbÜ8¾VÖBf“@”²U[™LÙ%6=\ÜÄ´©ÓIA;hercules-3.12/html/images/stopu.gif0000664000175000017500000000263212564723224014260 00000000000000GIF87a!çÿzzÿ)+ÿYYÿ‹‡ÿ‡‡ÿ ÿ:8ÿ88ÿÿõÿRRÿPRÿ€€ÿ˜—ÿ31ÿ11ÿa_ÿ__òÿÿÿ<>ÿ†ƒÿššÿIKÿyyÿ**ÿXXÿ ÿ ÿ|ÿ—“ÿceÿ““ÿy|ÿ×ØŽ ÿ^[ÿBDÿrrÿX[ÿ##ÿ!#ÿQQÿ›–ÿÿ20ÿ00ýÿˆŒÿWTÿ==ÿ;=ÿkkÿ™™ÿ‚ÿÿLJÿJJÿxxÿ+)ÿ))ÿÿddÿ–’ÿ’’ÿx{ÿª©ÿÀÀùÿÿCCÿqqÿ$"ÿ""ÿRPÿPPÿÿ]]ÿ‹ÿ‹‹ÿ‡‹ÿ<<ÿTSÿjjÿÿKIÿIIñÿ„„ÿjmÿÿ55ÿecÿccÿîÿDBîÿžžÿ!!ÿ!ÿ}}ÿ..ÿ\\ÿ ÿ=;ÿ;;ÿƒ€ÿgiÿÿFHÿÒÒÿ''ÿUUÿƒƒÿÿ•šÿÿ44ÿ|yÿ`bÿùÿ¾¾ÿÿÿ §ÿ[XÿUXÿÿƒ†ÿËËÿ ÿ ÿNNÿ||øöÿ--öÿ[[ÿ‰‰ÿ ÿ8:ÿhhÿ––ÿ’–ÿÿÿGGÿuuÿ&&ÿTTÿ‚‚ÿÿÆÇÿ{xÿaaÿ_aÿÿ@@ÿ¢œÿnnÿTWÿœœÿÿMM»++ÿˆˆÿ ÿ99ÿ79ÿigÿggÿ••ÿÿHFÿFFÿttêÿmjÿQSÿÿ22ÿ02ÿb`ýÿ``ÿŽŽÿÿ??ÿ››ÿÉÉÿ ÿ,!þPEƒA*˜’»€ „Fæ˜)vEA`k y!ãˆ# bl TÕa“Áq’ŒªqÀa#š–PL€X¤x8öq¤…ŒªŸj˜Â• KÂQZåÑ•†ƒ&3gtÈúc“U—½ú,ÐòS•„ 4Z¤Ú1K¥V^"@Ô´UÅ?Öxè„u£®`&5y°ì¨6Ò6Ä‹6?ÐíØu_AéˆåA Å_^ ¤ù¡‰ ¢Ã×|èò¤WW.“‚@ ù`Ê¿-#4}êVÕ5¬rv-uVPPðå‘2I^v­]bøÒŸ ¢ítURÊÊ$¼ 7ÈÃ/Ã<1 þÎY‚¨bMÑ]3Q¿á² MNuWù]­€9,ˆ½µÙ•„úR·Lòd*Ðð@,ù_o9‚ETGÙ€™.]’Á!0z§hhH§îE­!4F06ÖU ¤l+£Žæ‚Ôqñ†ji†•H«–±áÊO&lðÁ'¬°Áª,ìðÃñÄ ;hercules-3.12/html/images/dial2.gif0000664000175000017500000000361212564723224014100 00000000000000GIF87a:6¥™™™www___UUUMMMøøø999êêê333)))ÌÌÌÀÀÀ²²²–––†††€€€fffÿÿÿBBBñññãããÝÝÝ×××"""ççÖËËË  ¤ ,:6þ@ G¨!rŽEŒÃÁ ‚@çÁ1®“NCb‘X‘g"s8²ÍçãDðh0B  OefLnDEKJ      ¢ –KlH¼–¡ È ¤  v ¯´mMC—B  ÁÑ ž  ©ÇÌZÖ Ö^Žxë–FI$™t  ™ Ú½»pD„@ @t`ÐáP ŽíúuH´—$5iÆ€˜P¡»wÍ8àx @¦ 8 ðäŽAþŽ/7ººð`‚%iš ]¢* êz¾ä ‚ªt¸öŠPwZ8€ÀÑnŠ”Y`QB¡dêUw ă@¶DÁ« ZÚuˆv!Ö ¸c‚)Š/“E¶ÓAÀ `H`kB(¬P÷`ƒ jä\àkÁ 0¸‘ìK©É\ àÂ' à$€ÃÎ@îæy§ ¦ÒRña÷ËݤFf` ƒž®'üÁ»÷Ž…\+Â6½;3%Žª®Ã†B]-â$ž"Ð5³ŸDî\p| ]lHcG\üm¤NE~þÕƒ@pÁ‰QKˆáeò_ÙAÁS†*£ÀµÝ4 vB †ø!ˆ!xÞVÔÁ ;y 6 ,Ç_\¾dp˜ib€;~ö‚ŠóÑW™ö[ØQTAÝW@Pac¶ˆ÷!âDZ¼³ÑX Tð$®éWÁìÇ$4àAL+y¦ÈŽ#Â)»uÐ :yHpODÔ! A¼2¤dÔ4 ÁVxp`£·8Z ¤›nTZútPÀç©IaÝ&ÕZ‚€幉à‡Vb‚5uJÄ` àáÀÍlGæ \§ ‰ÓoÂé˜(A'º¶ÃQþ½=å_OrêŽL$ $°­pÃGø®ÓpdM€ÙÉ%•†M>Ð +1b ˆ§NÀV  x!™ï˜¦f!ǴˤÁh±[?hR‚qÂæ×äÂô1G•f§d2:ðo ê ‡%¾ÀÁÖLjÀðm²ZûìÊØ€\ö»ù3 ÁqÆn0ÓÌw©s†Ë^ŒÌ͈ÒQ3Hó@{5‹×Ò“vÙV avDJzlðLi+p LdÀÕ+¨Ý^¹èéÀO~…²ÁÝf·[èFt|ñÅêiǬºN eþåñ^¨pYŽÌ` ¼A(ÈÊ.þDÌ0™Q#A¿›ûyëƒG¦Àð ñ'7B¬|éÐ1Ù·o`Œ»ÃßÑnO—Y0—ñ¸±‹Ç*ÈS³d»Tyêíß®+²›y¡¹M6p@ü*éNÇ e¾·à÷Ñè7HÍ´V—v0ë\¥øo4„!;ܧ&¯kÝíÔ÷’ ¤Í}[š5ÐõŽq±EòÃLôüòŠ*’óÛeÌ4¾w]&k[‘˜)ø†' …P ¨À'^'ÁyìuÐkaÆ\™Fs“Ë1^GT˜Ð4baå®w;s!cw|bËÜÒ$¹„ÂMD1¼çe.‚ÏóúìP p€æ`FßþÄAŠ„":Ôaõ~·· P0uC ¦X#êü釒+ñ4–O”"5•—škyã?Æ9â ï:´c1áC*ö§4“€LÁ†G°¥_ɘ\vÈÆG:²‰N+åChޤOxÍ”‰ôhÁSËúäA)Ê?ùã|€”— B¢¶¤ EP…j‚̱M,†ž ¢¾—ݦSƒ9ÀÈ!L®á lQ°3Ú³‰ pâSxC3ÿ-)Ï C¤Sd„É—ø»;‚³&oQÝ÷6߈UKSRH>2¾NJ[»§ŽÄR0…µª†!Üâ`(bé;ðoYÕ8!]æi©Èã˜pÃ$ÌЋƒ¤å¹Có—ʪB¹sHÔÓLàå@K%(q„£¶1šx@žñ¿­¸ÅŠÉØÍêãš`²ášáêW/s /`¼é²ÌÊT%6¤ÙªI3 ‚pu>M8ƒköЉ:ã2…ðä>fAHé´iØE$ˈ“Èutrµ4¸y«IXK¸Ê ;hercules-3.12/html/images/note.gif0000664000175000017500000000036412564723224014053 00000000000000GIF89a ò€€€€€€€ÀÀÀÿÿÿÿÿÿÿ!ù, ¹HºÜºIƒÊmþ[×Ƨ‰Œ” FÛ ! …ª\ º}Ø›¬G¤3‘¯Xƒ•`0ÙrIrjN#¦¯ ƒ ³Sâå™)Å(3mçzu+éðÖ¤’7õ4±îzzv…€r‚†‡)‰Œ’Ž)‚‘~”y–=™<›¡1œ¡”q¦‚£§¢g;«r­´Lžª§w±h –ŸÀa|x2Â34Ÿ:ÁÅÒÇA" ;hercules-3.12/html/images/stored.gif0000664000175000017500000000256012564723224014406 00000000000000GIF87a!çÿÄâÿK¥ÿp·ÿºÛÿ‹Æÿ°Øÿ7›ÿÁÿ¦ÑÿH£ÿm·ÿŒÿ> ÿ>žÿˆÄÿ4™ÿ£ÑÿO¨ÿ ÿj³ÿ;žÿ…ÂÿªÔÿV«ÿV©ÿ€ÿ~ýq¸ÿ–Êÿÿ]®ÿ …ÿÌæÿÂáÿI¤ÿ?ŸÿÓéÿÀÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿ<ÿ†Áÿ«Õÿ †ÿ|¾ÿ|¼ÿ¡Ðÿ(“ÿ—Íÿ—Ëÿ²Úÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿ”Éÿe²ÿŠÄÿ‰ÿÔêÿ€¿ÿ¥ÑÿÀàÿG£ÿ‘Çÿ¶Ùÿ\_¾Ñèÿ)”ÿ˜Ìÿ˜ÊÿŠÿ„Âÿ©Ôÿ0—ÿŸÏÿ€ÿ•Êÿÿÿf³ÿf±ÿ‹Åÿ7œÿ¦Ôÿ¾ÿR«ÿR©ÿm¶ÿÿˆÃÿ~¾ÿ£ÎÿO§ÿj´ÿÙìÿ;ÿ`¯ÿªÕÿÏçÿ ÐÿÅâÿq¹ÿŽÿB ÿŒÆÿ]¯ÿ§Óÿ§Ñÿx¾ÿx¼ÿÎÿ$‘ÿ“Ëÿ“ÉÿŒÿ? ÿ®Úÿ®Øÿ‰ÿ-+„Z­ÿZ«ÿ‚ÿu¼ÿuºÿ|ùÚíÿÿÿÿÐèÿW«ÿW©ÿC¡ÿ²×ÿƒÀÿÍæÿžÏÿÃáÿJ¤ÿ”Êÿ”Èÿe³ÿ¯×ÿˆÿ€Àÿ,•ÿv»ÿ›Ïÿv¹ÿ›ÍÿÀßÿG¢ÿl¶ÿ‘Èÿ¶Üÿb±ÿb¯ÿ‡ÃÿÑéÿ†ÿ}¾ÿ}¼ÿN©ÿN§ÿD¢ÿi´ÿi²ÿ‹ÿØìÿ„Áÿ,!þH° Áƒ*\¸¤BR;icf’F%,p‰0E“<>4€5DFB8¸$Œ« ¤æ bô¥"¨FÒlìøq…H’2xªÂe‡P/Ié4q‚ÅF}^ ˆÐÃcžW@Á„êd–›:„©` ¢  `X XõÅN«Xµ2Iˆ¥G]•Õ!1퀋Q§Ví™ ®,Uý0$¶Ì¥+^,!•ª¦& ±ðÊ2“*;Œ]î„ÖÌ_œi¦vļŸ­,/x¡á#4Y‘’)DÆ”O[HP:ó.1°XŽ‘•ièÆ"bì0‘Á +Iˆè‰*Îê«Wøþ°”!J‘w:U0"‘AäÔ`ƒÇ­8ÂýÀÒ…d’ʆ`@GNÔ ÅYrXA…(È!„j—åÁKz´@^úÀDaˆ’È'• òˆаÄ'TÆS,=±‡†cp¨Ê%ˆtD"N¡ Fœ"À¢@RBjúÙÀ’ 2º GžÝõF¯<Ä—_¬2ÉM¸¨ KTprÃN–WD*‹5V–L©’S°$A˜c–Éá iŽULQôTT±ÔEa>A‰åyV›X/•YM“°E,ÅÐÅœž4¹a&´á¥§R}N°Fi°ôG ªdnxæWx1P¥Y4±òT ,åàÇuê «vžùÜXZ(%Ñj±ÅÒ(ŽœJÇœ)hš¨b¡éê"ýÅRJ4ó…¶ %z¶í%È"5 P ì¶ëî»ðÆÛ®@;hercules-3.12/html/images/dial3.gif0000664000175000017500000000361212564723224014101 00000000000000GIF87a:6¥™™™www___UUUMMMøøø999êêê333)))ÌÌÌÀÀÀ²²²–––†††€€€fffÿÿÿBBBñññãããÝÝÝ×××"""ççÖËËË  ¤ ,:6þ@ G¨!rŽEŒÃÁ ‚@çÁ1®“NCb‘X‘g"s8²ÍçãDðh0B  OefLnDEKJ      ¢ –KlH¼–¡ È ¤  v ¯´mMC—B  ÁÑ ž  ©ÇÌZÖ Ö^Žxë–FI$™t  ™ Ú½»pD„@ @t`ÐáP ŽíúuH´—$5iÆ€˜P¡»wÍ8àx @¦ 8 ðäŽAþŽ/7ººð`‚%iš ]¢* êz¾ä ‚ªt¸öŠPwZ8€ÀÑnŠ”Y`QB¡dêUw ă@¶DÁ« ZÚuˆv!Ö ¸c‚)Š/“E¶ÓAÀ `H`kB(¬P÷`ƒ jä\àkÁ 0¸‘ìK©É\ àÂ' à$€ÃÎ@îæy§ ¦ÒRña÷ËݤFf` ƒž®'üÁ»÷Ž…\+Â6½;3%Žª®Ã†B]-â$ž"Ð5³ŸDî\p| ]lHcG\üm¤NE~þÕƒ@pÁ‰QKˆáeò_ÙAÁS†*£ÀµÝ4 vB †ø!ˆ!xÞVÔÁ ;y 6 ,Ç_\¾dp˜ib€;~ö‚ŠóÑW™ö[ØQTAÝW@Pac¶ˆ÷!âDZ¼³ÑX Tð$®éWÁìÇ$4àAL+y¦ÈŽ#Â)»uÐ :yHpODÔ! A¼2¤dÔ4 ÁVxp`£·8Z ¤›nTZútPÀç©IaÝ&ÕZ‚€幉à‡Vb‚5uJÄ` àáÀÍlGæ \§ ‰ÓoÂé˜(A'º¶ÃQþ½=å_OrêŽL$ $°­pÃGø®ÓpdM€ÙÉ%•†M>Ð +1b ˆ§NÀV  x!™ï˜¦f!ǴˤÁh±[?hR‚qÂæ×äÂô1G•f§d2:ðo ê ‡%¾ÀÁÖLjÀðm²ZûìÊØ€\ö»ù3 ÁqÆn0ÓÌw©s†Ë^ŒÌ͈ÒQ3Hó@{5‹×Ò“vÙV avDJzlðLi+p LdÀÕ+¨Ý^¹èéÀO~…²ÁÝf·[èFt|ñÅêiǬºN eþåñ^¨pYŽÌ` ¼A(ÈÊ.þDÌ0™Q#A¿›ûyëƒG¦Àð ñ'7B¬|éÐ1Ù·o`Œ»ÃßÑnO—Y0—ñ¸±‹Ç*ÈS³d»Tyêíß®+²›y¡¹M6p@ü*éNÇ e¾·à÷Ñè7HÍ´V—v0ë\¥øo4„!;ܧ&¯kÝíÔ÷’ ¤Í}[š5ÐõŽq±EòÃLôüòŠ*’óÛeÌ4¾w]&k[‘˜)ø†' …P ¨À'^'ÁyìuÐkaÆ\™Fs“Ë1^GT˜Ð4baå®w;s!cw|bËÜÒ$¹„ÂMD1¼çe.‚ÏóúìP p€æ`FßþÄAŠ„":Ôaõ~·· P0uC ¦X#êü釒+ñ4–O”"5•—škyã?Æ9â ï:´c1áC*ö§4“€LÁ†G°¥_ɘ\vÈÆG:²‰N+åChޤOxÍ”‰ôhÁSËúäA)Ê?ùã|€”— B¢¶¤ EP…j‚̱M,†ž ¢¾—ݦSƒ9ÀÈ!L®á lQ°3Ú³‰ pâSxC3ÿ-)Ï C¤Sd„É—ø»;‚³&oQÝ÷6߈UKSRH>2¾NJ[»§ŽÄR0…µª†!Üâ`(bé;ðoYÕ8!]æi©Èã˜pÃ$ÌЋƒ¤å¹Có—ʪB¹sHÔÓLàå@K%(q„£¶1šx@žñ¿­¸ÅŠÉØÍêãš`²ášáêW/s /`¼é²ÌÊT%6¤ÙªI3 ‚pu>M8ƒköЉ:ã2…ðä>fAHé´iØE$ˈ“Èutrµ4¸y«IXK¸Ê ;hercules-3.12/html/images/osi-certified-60x50.jpg0000664000175000017500000001661612564723224016436 00000000000000ÿØÿàJFIFHHÿíPhotoshop 3.08BIMíHH8BIM x8BIMó8BIM 8BIM' 8BIMõH/fflff/ff¡™š2Z5-8BIMøpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè8BIM@@8BIM8BIM p<2´#(TÿØÿàJFIFHHÿþ&File written by Adobe Photoshop¨ 5.2ÿîAdobed€ÿÛ„            ÿÀ2<"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?õT’CȾ¬l{2.;j¥Ž±çÁ­œ’u©Ó(õóm0èÑËœvºÛï{¿ª¹û~¿ã‡~ƒëûÏsÌÜõËfçäu<·gåÒYüÛ;W_æRÏýûö n’CCžZ%Û]ù{¶ª³æ$M@9Ù9Ù™ˆh:×/}Ó~¸ôœë[E›ðïy†2ð\u—0º­Ëuy'²Æv{> …Ú}KëåSgMÊy²ìPMŽÕΤûFóùÏ¥ÞÏûm?~3Ã!E›–æýÃÁ1Ré]^$’S¶ßÿÐõUõ»wüÛÏÛϧ¬~îæïÿ ¶ò(«'Ì{†ê®c˜ñâ× ®@‹"BÁÅ>UÝw¿S~Éûìñêkö˜ú^´þ—ÕþWþ‹\FvGLËvP;ÙüÕ¬¯ó-gþýËGõ'¥²Ü<ì»A ÌœfÆ“[eþÕ{?ëj¯. r‘ÑÎäÄ¡šP1Öµð§®ý“öæoضúÛ;>©´}£oöþŸü&õsênÿùÀͼ}žÝÿ ÕGý5‹e' ÖâÝ v#ÝSÏØ`;þ¸ßzë>©â×ÓfwQ¢ì¶P{H  81¾£¿2Ë®µ®Ùÿ†0e˜Êª‰´aŒ§Ì™× &^\’Ó‘Sn¡Áõºv¸p`íDW7ÿÑïºÇÖ|“Ü[jÈÉÈ5‡Õ‹QµÌ¥§k².Û*Ü«ßõÓ¤1ÃìõäçV)¯&Ûq)u­ª«}_æïc\ýkì@ë}/®³­?«tЍÊûVØ-ªû [{î¯!®k-õúo}k/ê_X£—ecâUWV§&Ü[«±‚eõT×3.†8”õ?¢ý`³/¦ÝQ¸à:¿T½¥…®¶¶äTúlöØ×zOVðÓ°°±ñ±l`ÇdWIÞãá¾Icœ±*ú»Ô‡üáXÇ;ª²†Ñd‘¹Õã3×\ÖÑú·1ßGóó~¯åæ[]£¬j^Ë)~-6±›KÍ_­>ÏcZýµmýéý•~“ý¡º(]Ö½Ý;úoÕÖõ†çdúG>òS,x2ö4ûª¡Çg­±ŸOj/í<œ–c[-yc ¥ÌimBß}uÞ\ÿ¥ìݶ¯UP¯êë©·7›2)Ï¿&×ÜêîvK+wªæ¹Þ¥,ɪݟðJ“>©g6†µ¾•y˜ŒuÍ&G¡Žük]1þ”³bT Þ¦»1TÔêÛSIÒC§èéíݹö®/ì¯ÚÞï²ú?iãݳo«ô?{jçq~­fRÚ-v%o58 q-µ®®À*v;/h¯º˜úœÿÏ­öÙWò֯윯ù¥ûÙöŸ°ý—“³§èý(ÝéîI/ÿÒõT—Ê©$§ê¤—Ê©$§ê¤—Ê©$§ê¤—Ê©$§ÿÙ8BIMÿâ XICC_PROFILE HLinomntrRGB XYZ Î 1acspMSFTIEC sRGBöÖÓ-HP cprtP3desc„lwtptðbkptrXYZgXYZ,bXYZ@dmndTpdmddĈvuedL†viewÔ$lumiømeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ óQÌXYZ XYZ o¢8õXYZ b™·…ÚXYZ $ „¶ÏdescIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view¤þ_.ÏíÌ \žXYZ L VPWçmeassig CRT curv #(-27;@EJOTY^chmrw|†‹•šŸ¤©®²·¼ÁÆËÐÕÛàåëðöû %+28>ELRY`gnu|ƒ‹’š¡©±¹ÁÉÑÙáéòú &/8AKT]gqz„Ž˜¢¬¶ÁËÕàëõ !-8COZfr~Š–¢®ºÇÓàìù -;HUcq~Œš¨¶ÄÓáðþ +:IXgw†–¦µÅÕåö'7HYj{Œ¯ÀÑãõ+=Oat†™¬¿Òåø 2FZn‚–ª¾Òçû  % : O d y ¤ º Ï å û  ' = T j ˜ ® Å Ü ó " 9 Q i € ˜ ° È á ù  * C \ u Ž § À Ù ó & @ Z t Ž © Ã Þ ø.Id›¶Òî %A^z–³Ïì &Ca~›¹×õ1OmŒªÉè&Ed„£Ãã#Ccƒ¤Åå'Ij‹­Îð4Vx›½à&Il²ÖúAe‰®Ò÷@eНÕú Ek‘·Ý*QwžÅì;cвÚ*R{£ÌõGp™Ãì@j”¾é>i”¿ê  A l ˜ Ä ð!!H!u!¡!Î!û"'"U"‚"¯"Ý# #8#f#”#Â#ð$$M$|$«$Ú% %8%h%—%Ç%÷&'&W&‡&·&è''I'z'«'Ü( (?(q(¢(Ô))8)k))Ð**5*h*›*Ï++6+i++Ñ,,9,n,¢,×- -A-v-«-á..L.‚.·.î/$/Z/‘/Ç/þ050l0¤0Û11J1‚1º1ò2*2c2›2Ô3 3F33¸3ñ4+4e4ž4Ø55M5‡5Â5ý676r6®6é7$7`7œ7×88P8Œ8È99B99¼9ù:6:t:²:ï;-;k;ª;è<' >`> >à?!?a?¢?â@#@d@¦@çA)AjA¬AîB0BrBµB÷C:C}CÀDDGDŠDÎEEUEšEÞF"FgF«FðG5G{GÀHHKH‘H×IIcI©IðJ7J}JÄK KSKšKâL*LrLºMMJM“MÜN%NnN·OOIO“OÝP'PqP»QQPQ›QæR1R|RÇSS_SªSöTBTTÛU(UuUÂVV\V©V÷WDW’WàX/X}XËYYiY¸ZZVZ¦Zõ[E[•[å\5\†\Ö]']x]É^^l^½__a_³``W`ª`üaOa¢aõbIbœbðcCc—cëd@d”dée=e’eçf=f’fèg=g“géh?h–hìiCišiñjHjŸj÷kOk§kÿlWl¯mm`m¹nnknÄooxoÑp+p†pàq:q•qðrKr¦ss]s¸ttptÌu(u…uáv>v›vøwVw³xxnxÌy*y‰yçzFz¥{{c{Â|!||á}A}¡~~b~Â#„å€G€¨ kÍ‚0‚’‚ôƒWƒº„„€„ã…G…«††r†×‡;‡ŸˆˆiˆÎ‰3‰™‰þŠdŠÊ‹0‹–‹üŒcŒÊ1˜ÿŽfŽÎ6žnÖ‘?‘¨’’z’ã“M“¶” ”Š”ô•_•É–4–Ÿ— —u—à˜L˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿÿþ&File written by Adobe Photoshop¨ 5.2ÿîAdobed@ÿÛ„       ÿÀ2<ÿÝÿÄ¢  s!1AQa"q2‘¡±B#ÁRÑá3bð$r‚ñ%C4S’¢²csÂ5D'“£³6TdtÃÒâ&ƒ „”EF¤´VÓU(òãóÄÔäôeu…•¥µÅÕåõfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù*:JZjzŠšªºÊÚêúm!1AQa"q‘2¡±ðÁÑá#BRbrñ3$4C‚’S%¢c²ÂsÒ5âDƒT“ &6E'dtU7ò£³Ã()Óã󄔤´ÄÔäôeu…•¥µÅÕåõFVfv†–¦¶ÆÖæöGWgw‡—§·Ç×ç÷8HXhxˆ˜¨¸ÈØèø9IYiy‰™©¹ÉÙéù*:JZjzŠšªºÊÚêúÿÚ ?÷ö*ìU óo|±äm4jžgÔ#±¶sÂ5y§’•á H »{*œ¯&HÀ\¬¹aŒqHÐxýçüå6’³¥ùSRºµi®&µ´b nî¤þX Bì~ယ‚@_ yÌú·žuéüÛ¯1úíÕE•©5K+2k¼c  ¡‘†ï%Iíœ.³U,ó'§GÎuÚÉj2ÐrJ„ÊÏ$q$³¼ u·†Yý%;ƒ'¤­À­LƆÌ\A..<&.1$4E­õµ ‹I—Ù‘”å{Ä÷½â{ˆ}9ÿ8éùƒ®X^ù']¸{­OCŽ9ôëɘ´³é²Š$c»<,8?i2~.YÙvn¨æ…aîû+Xsã©}Q{žmÓ±WÿÑ÷ö*ó¯ÏŸ[þU›= òú˜õ8õô½Tõ?á9W1µWáJ»œMeø2®çÇg©¥=¼3ÏŸ2}mÿ8òtùY£Óúà~œ O[ôŸ3ëúÔß•~Ï/÷_?ï´|>xySéZ<©ó‡æiÐOæ_š–}/ÑX‹™·§¡õïE~·Â›}¿·O÷o©œÇjpøÞžíÞC¶8<Ovì“þqï×ÿ•¯oèW‡è›ÿ¬Ó§§êÛq¯û>9‘Ø×âKÜåv ø²÷>¾Î­ìÝŠ¿ÿÒ÷ö*ƒÕ´Ë=oK½Ñµý[ B mn£þh§BŽ>》‚_ ù“Êú·‘uéü¥®«}nÚ¦ÂìŠ%õ˜4ŽxÏBiA*ÒJÿ“œ.³K,=Ý:×èå§ÈGðžOkÿœpòT†æ¿1jËmæ"Ú$< Bö–ŠñË "›´’:ê=<è{+?Äôýƒ‡Ÿâûžu§¿•å¾Ðµ2°Í Ï.Ÿtƈ•¶n*ãÚEâãÇ–sZœ&L|ÞOU‚XóJmôäV‹mäh.üÙç%—LÕ5ëhÚÆ;ˆVÛJŽe ­J$“K*³#n©érýªuŸ§ð!êæ^¿³4ß—Çrú¤÷ý3T°ÖlbÔ´ÉÖæÆ~^”é^-ÁŠVÁͰ îØ ‹¼)ÿÓõÇæçO•¿/5ht ë[ZÖÞÊM^æÃA±}Bk]2ôÚîà)P‘rF嘩â§Ju?ùÈÏ!ÚʃF²Ö¼Ñfºužµ¨_ùM—P·±Óõ5i-¥¹*U—š#?W*’Ê1Tâêçòçó~ëÌ^JÔìZþ_*Ëf/žâ7·h%Ômò-ædFôyÁ”ü-•äÇаՓr ‹ÊöÞSò¿–ô@»·M¶Zk}a%õdÕD…©#5K~Ñjä¡äBƒÕ<ŸùIŸàó^·õ'óž«$péö÷—*ÂK«Xš ³·0Hþß_ÔÊüqñÖí_—ÆgÇ^¤Àù»Ëúæ±o¢É¡]ÞÞ=½«ß´¶ð4V+¨,Q\³Ëö§É–/W·U­¤Þ@,žÎëBµ±/§Ík0Ä7#ö|q” KÆúøþVfÿþŒý5_LúÿTô}îë^\gÇ _ÿÔôoæO’?3mÿ1î¿0.tý/[ý7åð•ý†©{&œm;™®!»GHf õØIÀßâØ«Í5ßùÇ_Ì /HÐ4O)èúlÞaÒ¼½§èºæ&Ÿ®ê>^Ôì¯mP«Ëséw1å dsâ87\UéV”~qOù\Kw{m-ÇžíôÈt«Òì†il´Xl'{…EýØ–hÚ¡yü þÇ@yò«]ó%í¥òùJËGÒ§¶¼Ó®ô6þÖØÄ×R[®´¿Q‘UÊBT´ ë§xɹªžÚ~RK¦SIÓnõ½;Íz®·¨M O¬Oe©Ë¨Gúï1’»Š^jÅÁX7ÅX½¯ä?™ Ò⊩YëMoåÛiµ(¤oQN“¤Ie; ñ••“ù€¯ÃŠªè“¾`Ó¡Òµ |»gq-„ñ¥ÿ—ïµe³»Xô÷³Žé ¢G‰¤ ÿ>žÿˆÄÿ4™ÿ£ÑÿO¨ÿ ÿj³ÿ;žÿ…ÂÿªÔÿV«ÿV©ÿ€ÿ~ýq¸ÿ–Êÿÿ]®ÿ …ÿÌæÿÂáÿI¤ÿ?ŸÿÓéÿÀÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿ<ÿ†Áÿ«Õÿ †ÿ|¾ÿ|¼ÿ¡Ðÿ(“ÿ—Íÿ—Ëÿ²Úÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿ”Éÿe²ÿŠÄÿ‰ÿÔêÿ€¿ÿ¥ÑÿÀàÿG£ÿ‘Çÿ¶ÙÿÑèÿ)”ÿ˜Ìÿ˜ÊÿŠÿ„Âÿ©Ôÿ0—ÿŸÏÿ€ÿ•Êÿÿÿf³ÿf±ÿ‹Åÿ7œÿ¦Ôÿ¾ÿR«ÿR©ÿm¶ÿÿˆÃÿ~¾ÿ£ÎÿO§ÿj´ÿÙìÿ;ÿ`¯ÿªÕÿÏçÿ ÐÿÅâÿq¹ÿŽÿB ÿŒÆÿ]¯ÿ§Óÿ§Ñÿx¾ÿx¼ÿÎÿ$‘ÿ“Ëÿ“ÉÿŒÿ? ÿ®Úÿ®Øÿ‰ÿ-+„Z­ÿZ«ÿ‚ÿu¼ÿuºÿ|ùÚíÿÿÿÿÐèÿW«ÿW©ÿC¡ÿ²×ÿƒÀÿÍæÿžÏÿÃáÿJ¤ÿ”Êÿ”Èÿe³ÿ¯×ÿˆÿ€Àÿ,•ÿv»ÿ›Ïÿv¹ÿ›ÍÿÀßÿG¢ÿl¶ÿ‘Èÿ¶Üÿb±ÿb¯ÿ‡Ãÿ]`¿Ñéÿ†ÿ}¾ÿ}¼ÿN©ÿN§ÿD¢ÿi´ÿi²ÿ‹ÿØìÿ„Áÿ,!þ0U˨4|)# £¶D’É À"#Ä   4ÆUQr-òÂð#h$R´¸"ãF<Qá`ªgP&Gé¤pBCF|^ ˆÐ£"žV<¹„Êc€ž¦4uS¡ÒÁ@¾°°é ™N¡JýÓqÖ:(~ºòª#¡Ø“.mJ3*¬?U±ªúQhk…“C2tXB)ÓLL.^Ùs+&Uu —¤+(l¼/Ñ,¥yÅ›=S±^èBÇæ® %1BhL©4´˜dæAÚ7a`a# ӌ̆EÄØa"CV‘Í  ÒO­ìÁ”"3ìþpú©`D"‚Ä©±æŽ«3ZMLû« .`Je§†94QC`ÅQÅ¡0‡£A† XåÑBwPìçÃl€ "žP"ˆ#$²GœàØLx`儊Q¡*–Òˆ4q„0qŠ„òH ¢ÍgV*¬èB.^—`¼bP]x±Š$.9pb&XM±É zé]©f˜W))4V^AJ•Zrée…3ˆÉ•W µÐQII„dhéÄ$÷yw™k[™DJb,IRVc[`lvb$…˜´לBÙ9Y¡•1(Ч 8tI!˜vÄÅ€“_­ÄÊQY%`•CjÐÑg'¥¾ &r\e!TB^ŒUV¢4êl¦0© ƒi6W¦Š,„V(al Èúij’á½FW а4@O€”kî¹è¦«®¹¦¬ëî»çï¼ë ;hercules-3.12/html/images/dial4.gif0000664000175000017500000000361212564723224014102 00000000000000GIF87a:6¥™™™www___UUUMMMøøø999êêê333)))ÌÌÌÀÀÀ²²²–––†††€€€fffÿÿÿBBBñññãããÝÝÝ×××"""ççÖËËË  ¤ ,:6þ@ G¨!rŽEŒÃÁ ‚@çÁ1®“NCb‘X‘g"s8²ÍçãDðh0B  OefLnDEKJ      ¢ –KlH¼–¡ È ¤  v ¯´mMC—B  ÁÑ ž  ©ÇÌZÖ Ö^Žxë–FI$™t  ™ Ú½»pD„@ @t`ÐáP ŽíúuH´—$5iÆ€˜P¡»wÍ8àx @¦ 8 ðäŽAþŽ/7ººð`‚%iš ]¢* êz¾ä ‚ªt¸öŠPwZ8€ÀÑnŠ”Y`QB¡dêUw ă@¶DÁ« ZÚuˆv!Ö ¸c‚)Š/“E¶ÓAÀ `H`kB(¬P÷`ƒ jä\àkÁ 0¸‘ìK©É\ àÂ' à$€ÃÎ@îæy§ ¦ÒRña÷ËݤFf` ƒž®'üÁ»÷Ž…\+Â6½;3%Žª®Ã†B]-â$ž"Ð5³ŸDî\p| ]lHcG\üm¤NE~þÕƒ@pÁ‰QKˆáeò_ÙAÁS†*£ÀµÝ4 vB †ø!ˆ!xÞVÔÁ ;y 6 ,Ç_\¾dp˜ib€;~ö‚ŠóÑW™ö[ØQTAÝW@Pac¶ˆ÷!âDZ¼³ÑX Tð$®éWÁìÇ$4àAL+y¦ÈŽ#Â)»uÐ :yHpODÔ! A¼2¤dÔ4 ÁVxp`£·8Z ¤›nTZútPÀç©IaÝ&ÕZ‚€幉à‡Vb‚5uJÄ` àáÀÍlGæ \§ ‰ÓoÂé˜(A'º¶ÃQþ½=å_OrêŽL$ $°­pÃGø®ÓpdM€ÙÉ%•†M>Ð +1b ˆ§NÀV  x!™ï˜¦f!ǴˤÁh±[?hR‚qÂæ×äÂô1G•f§d2:ðo ê ‡%¾ÀÁÖLjÀðm²ZûìÊØ€\ö»ù3 ÁqÆn0ÓÌw©s†Ë^ŒÌ͈ÒQ3Hó@{5‹×Ò“vÙV avDJzlðLi+p LdÀÕ+¨Ý^¹èéÀO~…²ÁÝf·[èFt|ñÅêiǬºN eþåñ^¨pYŽÌ` ¼A(ÈÊ.þDÌ0™Q#A¿›ûyëƒG¦Àð ñ'7B¬|éÐ1Ù·o`Œ»ÃßÑnO—Y0—ñ¸±‹Ç*ÈS³d»Tyêíß®+²›y¡¹M6p@ü*éNÇ e¾·à÷Ñè7HÍ´V—v0ë\¥øo4„!;ܧ&¯kÝíÔ÷’ ¤Í}[š5ÐõŽq±EòÃLôüòŠ*’óÛeÌ4¾w]&k[‘˜)ø†' …P ¨À'^'ÁyìuÐkaÆ\™Fs“Ë1^GT˜Ð4baå®w;s!cw|bËÜÒ$¹„ÂMD1¼çe.‚ÏóúìP p€æ`FßþÄAŠ„":Ôaõ~·· P0uC ¦X#êü釒+ñ4–O”"5•—škyã?Æ9â ï:´c1áC*ö§4“€LÁ†G°¥_ɘ\vÈÆG:²‰N+åChޤOxÍ”‰ôhÁSËúäA)Ê?ùã|€”— B¢¶¤ EP…j‚̱M,†ž ¢¾—ݦSƒ9ÀÈ!L®á lQ°3Ú³‰ pâSxC3ÿ-)Ï C¤Sd„É—ø»;‚³&oQÝ÷6߈UKSRH>2¾NJ[»§ŽÄR0…µª†!Üâ`(bé;ðoYÕ8!]æi©Èã˜pÃ$ÌЋƒ¤å¹Có—ʪB¹sHÔÓLàå@K%(q„£¶1šx@žñ¿­¸ÅŠÉØÍêãš`²ášáêW/s /`¼é²ÌÊT%6¤ÙªI3 ‚pu>M8ƒköЉ:ã2…ðä>fAHé´iØE$ˈ“Èutrµ4¸y«IXK¸Ê ;hercules-3.12/html/images/poweroffd.gif0000664000175000017500000000265412564723224015105 00000000000000GIF87a!çÿzzÿ¾¿ÿ)+ÿYYÿ‹‡ÿ‡‡ÿããÿ ÿ:8ÿ88ÿ68ÿÿõÿ‰Šÿ¡¡ÿRRÿPRÿ€€ÿ31ÿ11ÿa_ÿ__ÿòÿÿÿ<>ÿ†ƒÿššÿIKÿyyÿ‘ÿ**ÿXXÿ ÿââÿ ÿ|ÿ—“ÿceÿy|ÿÁÁŽ ÿ^[ÿDDÿBDÿrrÿX[ÿˆ‰ÿÎÎÿ##ÿSQÿQQÿ›–ÿ•–ÿÿ20ÿ00ýÿFGÿ¢£ÿˆŒÿèèÿWTÿ==ÿ;=ÿkkÿ‚ÿÿLJÿJJÿxxÿ+)ÿ))ÿWWÿÿddÿ–’ÿ’’ÿx{ÿª©ùÿÿCCÿ[ZÿqqÿÍÍÿ$"ÿ""ÿRPÿPPÿ¬¬ÿÿ]]ÿ‹ÿ‹‹ÿ‰‹ÿ‡‹ÿççÿ<<ÿjjÿÿKIÿIIÿ¥¥ñÿ„„ÿjmÿÿ55ÿecÿccÿ¿¿ÿîÿDBîÿ´µÿÌÌÿ!!ÿ!ÿ}}ÿ««ÿ..ÿ\\ÿ¸¸ÿææÿ ÿ=;ÿ;;ÿƒ€ÿgiÿÅÅÿÿFHÿÒÒÿ''ÿUUÿÿ•šÿÿ44ÿ|yÿbbÿ`bÿùÿ¾¾ÿÿÿ §ÿ[XÿUXÿÿƒ†ÿµ´ÿ ÿ ÿNNÿ||øöÿ--öÿ[[ÿ‰‰ÿ··ÿååÿ ÿ8:ÿhhÿ––ÿ’–ÿÄÄÿÿÿGGÿuuÿ££ÿÑÑÿÿÿÿ&&ÿTTÿRTÿ°°ÿÿ{xÿaaÿ_aÿÿ½½ÿ@@ÿ¢œÿnnÿTWÿÊÊÿÿMM»++ÿˆˆÿääÿ ÿ99ÿ79ÿigÿggÿÿHFÿFFÿttÿ¢¢êÿÐÐÿmjÿQSÿÿ—˜ÿ22ÿb`ýÿ``ÿÿA?ÿ??ÿƒ„ÿ››ÿÉÉÿ ÿ,!þH° Áƒ*\ˆ,H„cHdU ÇAÁ# ¤D(ÊcîLƒ9ß!h’ƒÇ”RèTˆl®‡GU &$ÁERJneéÈ€Ê7U&•¤Tj–~Ãv Ä`˜=ÚÖGÄ­S³œžHåË™ÔÂ(¨Ha‹Úóˆ2¿ô`ÈVØõK*ð7Ì5¬ÀqY AÔÊf3WFŠdáÉÐ\¢K¡D1 Ž×‹#CM¬0N8•àðÈrqäØ%,eŠ ÓÀxÍ3)H’T"XCFU"Æ[  “1FÄÂ'œÀË‹1Æá‹Àèâƒ5h ‚…a«<—UtÁÂ’lqBbhY 5J VaeàÖGNyÃRcp’ÍcÂH„3N89ÛCmÖLÍ©K“„‘ „„™þÅF#.L}ÀT“ÊÅ“€Q@F"Ùß3qÌXãǤ!ÍLeÄ©)°ÔŠ+¿„q ˜¡@‚*¯gŽ ‰ i•œ¤°äÁ ̆ñƒ£bZH\“g1•ÆSC|¶ K›xÐ ¡6:Á.‚g¯’|1mÕΈ±„‰0ò>ê¨ÙœP!xm h"lg‚4# wìñÇ ‡Ü±@;hercules-3.12/html/images/sysoffu.gif0000664000175000017500000000130712564723224014602 00000000000000GIF87a%Ʀ‚‚¦—9­­­¦x”‹z¥¥¥¡¡¡ŸŸŸººŸžž¦Pɶ[•z]”z\™™™4&,è­4‘‡§¨€v™š’K65ˆ|jr}r¨‰†¨}[¦ƒ„œœ\F$©s””“œŠ1¤†¨u˜‡e|l¥’küþÔ¨~n¬|^«z]©z[š~‹˜z^–z\ƒ\F”qP¡{`žŸŸ§z\“{f}|nª}l˜pMŸˆW«{Yª««|fŒvDŒjDšš—¢žwžd^Dƒœœœœ‘wYtF,¥{\•’§‚›z\¸º–Á¶«€[ÒÓ¬¬z\«z[D.$žŠ:›’beaX¨¨©z\ž¿¿œ”z[ƸW§~qª}j¥…¤…|g¯¨k£…fÀ=¤†I<+/§€w•wX©©ˆƒv«{]© h†|j©§uùÿÿª{_¦ƒ†œžŠ‚t‹ŒŒÉÅv¤†”¨}c«z\,%þ€‚ƒ„…†‡ˆ‰Š‹ŒˆV‹Vl%”%”“•Š%%š—Š“ll•Ÿ¦§‰ªV“‚ªœ¦—°¨´Ž¹º»¼½¾¿ÀŽc¼O32M49/-MMMMd&M‹#[sMsàs]^Z1 OˆOßM*YJLr NMˆÐsh0̈HAE›¡'¼ÙàQÅß?!¾”iÐÀ´#€b@€!¤q±b„ÅšD¸²ñÀÆIê Qc± —&F€|éòLƒ68rƒÄ›;]JÒà‡Ð Âàðá2äb\@wÐ͉¦„<$œömiÒ „5-ôˆB‘"‡t P€Y‚ZÝ:ˆ,º‚N†",¨]¸çèGXv8 F¹2¡@;hercules-3.12/html/images/favicon.ico0000664000175000017500000007644612564723224014556 0000000000000000 ¨%F hî%@@ (BV*  ¨~l(0`   ˆÌêððððððððððððððððððððððððððððððððððððìÏ%5ÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåBÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿé#ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‘Ïÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÓîÿÿÿÿÿÿÿÿÿ ÿÿ""ÿ&&ÿ%%ÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ##ÿ''ÿ%%ÿÿ ÿ ÿÿÿÿÿÿÿÿÿÿíñÿÿÿÿÿÿÿÿ ÿ&&ÿ-<<ÿ9MMÿ?UUÿ=RRÿ3EEÿ%11ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿ))ÿ/??ÿ;OOÿ@VVÿ=RRÿ3DDÿ#//ÿÿ ÿÿÿÿÿÿÿÿÿñðÿÿÿÿÿÿÿ ÿ##ÿ3DDÿ;sLÿ¤ÿ°ÿ°ÿ¦ÿ/w8ÿ(66ÿÿÿÿÿÿÿÿÿÿÿ ÿ))ÿ7JJÿ9|Gÿ§ÿ±ÿ±ÿ¥ÿ0k<ÿ#//ÿ ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ'44ÿF^^ÿ¦ÿ´ÿ´ÿ´ÿ´ÿ±ÿ3b@ÿ''ÿ ÿÿÿÿÿÿÿÿÿÿ.>>ÿDnXÿ® ÿ´ÿ´ÿ´ÿ´ÿ¥ÿ2CCÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-<<ÿLffÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ3z=ÿ$00ÿ ÿÿÿÿÿÿÿÿÿ ÿ6IIÿ?~Oÿ´ÿ´ÿ´ÿ´ÿ´ÿ¯ÿ:NNÿ""ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-<<ÿLffÿ! ÿ´ÿ´ÿ´ÿ´ÿ¯ÿMÿ­ ÿ´ÿ´ÿ³ÿ06ÿ?UUÿ))ÿ ÿÿÿÿÿÿÿÿÿÿ1BBÿMhhÿ4Š=ÿ²ÿ´ÿ´ÿ¯ÿ9„Eÿ6IIÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-<<ÿLffÿªÿ´ÿ´ÿ´ÿ´ÿ´ÿ6qCÿ"--ÿ ÿÿÿÿÿÿÿÿÿÿ5GGÿCwWÿ²ÿ´ÿ´ÿ´ÿ´ÿªÿ9LLÿ!!ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ.>>ÿMggÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ4z?ÿ%11ÿ ÿÿÿÿÿÿÿÿÿ!!ÿ8KKÿ@}Qÿ´ÿ´ÿ´ÿ´ÿ´ÿ®ÿ;OOÿ##ÿ ÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-<<ÿLffÿ%œ$ÿ´ÿ´ÿ´ÿ´ÿ« ÿ>hRÿ$00ÿ ÿÿÿÿÿÿÿÿÿÿ6HHÿMofÿ¦ÿ´ÿ´ÿ´ÿ´ÿ$"ÿ9LLÿ!!ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ*88ÿJccÿLoeÿ ¡ÿ´ÿ´ÿ­ ÿExXÿCZZÿ!,,ÿ ÿÿÿÿÿÿÿÿÿÿ1BBÿMhhÿHt]ÿªÿ´ÿ´ÿ£ÿJocÿ6HHÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ*88ÿJccÿ6ˆ@ÿ°ÿ´ÿ´ÿ´ÿ(˜*ÿC]Yÿ!,,ÿ ÿÿÿÿÿÿÿÿÿÿ0AAÿMhhÿ+”/ÿ³ÿ´ÿ´ÿ±ÿ6‡@ÿ6HHÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-<<ÿLffÿ­ ÿ´ÿ´ÿ´ÿ´ÿ´ÿ7xDÿ(66ÿÿ ÿÿÿÿÿÿÿ ÿ$$ÿ8KKÿAzSÿ³ÿ´ÿ´ÿ´ÿ´ÿ¬ ÿ9LLÿ!!ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-==ÿMggÿ® ÿ´ÿ´ÿ´ÿ´ÿ´ÿ:Hÿ6IIÿ"--ÿ ÿÿÿÿÿÿÿ&&ÿ,;;ÿE]]ÿA|Rÿ³ÿ´ÿ´ÿ´ÿ´ÿ® ÿ:NNÿ""ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ*99ÿKddÿ-’2ÿ´ÿ´ÿ´ÿ´ÿ! ÿNmhÿKddÿ>SSÿ6IIÿ6HHÿ6HHÿ6HHÿ6HHÿ6HHÿ6HHÿ:NNÿE\\ÿOjjÿPkkÿ(˜)ÿ´ÿ´ÿ´ÿ´ÿ,“0ÿ7JJÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ'55ÿHaaÿNmhÿ"Ÿÿ´ÿ´ÿ´ÿ%œ$ÿ-“1ÿ+•.ÿ+•.ÿ*”-ÿ*”-ÿ*”-ÿ*”-ÿ*”-ÿ*”-ÿ*”-ÿ+•.ÿ+•.ÿ+•.ÿ,“0ÿ(˜*ÿ³ÿ´ÿ´ÿ ¡ÿLleÿ4FFÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ)77ÿJccÿ+”/ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ*”-ÿ5GGÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-<<ÿLffÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ® ÿ9LLÿ!!ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-==ÿMggÿ­ ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ­ ÿ:NNÿ""ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ*99ÿKddÿ3‹<ÿ³ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ³ÿ/5ÿ7JJÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ'55ÿHaaÿNmhÿ!Ÿÿ´ÿ´ÿ´ÿ,“0ÿ<‚Iÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ9…Eÿ;‚Iÿ06ÿ´ÿ´ÿ´ÿ£ÿKmcÿ4FFÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ)77ÿJccÿ*–,ÿ´ÿ´ÿ´ÿ´ÿ¥ÿKqbÿNiiÿHaaÿE\\ÿD[[ÿD[[ÿD[[ÿD[[ÿD[[ÿD[[ÿF^^ÿLffÿPkkÿNmhÿ ¡ÿ´ÿ´ÿ´ÿ´ÿ'˜(ÿ6HHÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-<<ÿLffÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ:‚Gÿ?UUÿ-<<ÿ$00ÿ"..ÿ"..ÿ"..ÿ"..ÿ"..ÿ#//ÿ'55ÿ6HHÿKddÿ@}Qÿ´ÿ´ÿ´ÿ´ÿ´ÿ®ÿ9MMÿ!!ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-==ÿMggÿ« ÿ´ÿ´ÿ´ÿ´ÿ´ÿSSÿDxXÿ²ÿ´ÿ´ÿ´ÿ´ÿ©ÿ:NNÿ""ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ+::ÿKeeÿ<‚Jÿ­ ÿ´ÿ´ÿ²ÿ/4ÿD^\ÿ$00ÿ ÿÿÿÿÿÿÿÿ ÿÿ4FFÿNiiÿ5Š>ÿ±ÿ´ÿ´ÿ¯ÿ9ƒFÿ7JJÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ)77ÿJccÿKqbÿ ¡ÿ´ÿ´ÿ­ ÿA|SÿCZZÿ!,,ÿ ÿÿÿÿÿÿÿÿÿÿ0AAÿMhhÿEwYÿªÿ´ÿ´ÿ¤ÿHp`ÿ5GGÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ*99ÿKeeÿ"Ÿÿ´ÿ´ÿ´ÿ´ÿ®ÿ=gOÿ"..ÿ ÿÿÿÿÿÿÿÿÿÿ3EEÿJpbÿªÿ´ÿ´ÿ´ÿ´ÿ"Ÿÿ7JJÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-==ÿMggÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ4z?ÿ%11ÿ ÿÿÿÿÿÿÿÿÿ!!ÿ8KKÿ?~Pÿ´ÿ´ÿ´ÿ´ÿ´ÿ¯ÿ:NNÿ""ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ-==ÿMggÿ§ÿ´ÿ´ÿ´ÿ´ÿ³ÿ9qHÿ$00ÿ ÿÿÿÿÿÿÿÿÿ!!ÿ7JJÿEwYÿ±ÿ´ÿ´ÿ´ÿ´ÿ¦ÿ:NNÿ""ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ+::ÿKeeÿA{Sÿªÿ´ÿ´ÿ±ÿ5‰?ÿBXXÿ ++ÿ ÿÿÿÿÿÿÿÿÿÿ3EEÿNiiÿ:„Fÿ¯ÿ´ÿ´ÿ« ÿA{Rÿ7JJÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ*88ÿJccÿHt^ÿ¥ÿ´ÿ´ÿ¯ÿ>Nÿ?UUÿ((ÿ ÿÿÿÿÿÿÿÿÿÿ2CCÿMhhÿ?~Pÿ« ÿ´ÿ´ÿ¦ÿFr\ÿ6HHÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ,;;ÿLffÿ¤ÿ´ÿ´ÿ´ÿ´ÿ¯ÿ:hKÿ!,,ÿ ÿÿÿÿÿÿÿÿÿÿ5GGÿFt[ÿ¯ÿ´ÿ´ÿ´ÿ´ÿ£ÿ8KKÿ ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ.>>ÿMggÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ3z>ÿ$00ÿ ÿÿÿÿÿÿÿÿÿ""ÿ9LLÿ?~Nÿ´ÿ´ÿ´ÿ´ÿ´ÿ¯ÿ:NNÿ""ÿ ÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿ+::ÿKddÿ¢ÿ´ÿ´ÿ´ÿ´ÿ±ÿ9kIÿ"..ÿ ÿÿÿÿÿÿÿÿÿÿ5GGÿGs]ÿ¯ÿ´ÿ´ÿ´ÿ´ÿ£ÿ7JJÿ ÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿ ÿ"--ÿ?TTÿFt[ÿ#"ÿ¯ÿ±ÿ« ÿ6„@ÿ5GGÿ""ÿ ÿÿÿÿÿÿÿÿÿÿ)77ÿF^^ÿ;‚Iÿ©ÿ±ÿ±ÿ£ÿ=qOÿ,;;ÿÿÿÿÿÿÿÿÿÿðñÿÿÿÿÿÿÿ ÿÿ)77ÿ?TTÿKddÿNiiÿMhhÿHaaÿ8KKÿ!,,ÿÿÿÿÿÿÿÿÿÿÿ ÿ""ÿ/??ÿD[[ÿMggÿNiiÿMhhÿE]]ÿ2CCÿ%%ÿ ÿÿÿÿÿÿÿÿÿñíÿÿÿÿÿÿÿÿ ÿÿ!,,ÿ+::ÿ1BBÿ0AAÿ)77ÿ&&ÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ%11ÿ.>>ÿ3DDÿ/??ÿ'44ÿ""ÿ ÿÿÿÿÿÿÿÿÿÿíÊÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÐxÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰Òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿß)ÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ5xÅéððððððððððððððððððððððððððððððððððððëÊ€àÀ€€€Àð(    ZÜððððððððððððÞ]äÿ ÿ ÿ ÿÿÿÿÿÿ ÿÿ ÿÿÿåóÿ!!ÿœÿ¯ÿJÿÿÿÿ ÿT#ÿ¯ÿ™ ÿ ÿÿóð ÿ'55ÿ¢ÿ´ÿO!ÿÿÿÿÿ/e;ÿ´ÿÿÿÿðð ÿ+::ÿ©ÿ´ÿ\ ÿÿÿÿÿ1r;ÿ´ÿ¦ ÿÿÿðð ÿ+::ÿ£ÿ´ÿ Q%ÿÿÿÿÿ4jBÿ´ÿÿÿÿðð ÿ+::ÿ¨ÿ´ÿ&m+ÿ""ÿ!ÿ$ÿ%22ÿ4|?ÿ´ÿ¤ÿÿÿðð ÿ+::ÿ¤ÿ´ÿ­ ÿ« ÿª ÿ« ÿ« ÿ­ ÿ´ÿŸÿÿÿðð ÿ+::ÿ¤ÿ´ÿ¨ÿ¦ÿ¦ÿ¦ÿ¦ÿ§ÿ´ÿŸÿÿÿðð ÿ+::ÿ¨ÿ´ÿ0z9ÿ/??ÿ+<9ÿ->;ÿ9LLÿ9€Eÿ´ÿ¤ ÿÿÿðð ÿ+::ÿ¢ÿ´ÿ$V+ÿÿ ÿ ÿ&&ÿ7lGÿ³ÿœÿÿÿðð ÿ+::ÿ©ÿ´ÿ[ ÿÿÿÿÿ1r;ÿ´ÿ¤ ÿÿÿðð ÿ+::ÿ¤ÿ´ÿR$ÿÿÿÿÿ4lAÿ´ÿžÿÿÿðó ÿ#//ÿ ÿ±ÿRÿÿÿÿÿ*e2ÿ±ÿ›ÿ ÿÿóâÿÿ#//ÿ!,,ÿÿÿÿÿ ÿ##ÿ%11ÿ""ÿ ÿÿäVÛð ñððððððð ñððÝZ€€(@€   P ÔìððððððððððððððððððððððððððððððððððððððððððððððððíÙ§[®ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½'ËÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜ%©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÁBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿZ™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ«×ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïñÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ%%ÿ''ÿ''ÿ""ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ ÿ&&ÿ((ÿ''ÿ!!ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ ÿÿ&33ÿ4FFÿ=RRÿAWWÿ@VVÿ:NNÿ0@@ÿ!,,ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ%%ÿ*99ÿ8KKÿ?UUÿBXXÿ@VVÿ9LLÿ-<<ÿ''ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿ ÿÿ+::ÿ@\Vÿ,1ÿªÿ°ÿ°ÿ¬ ÿ#š"ÿ3fAÿ%22ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ%%ÿ3EEÿ@mSÿ$œ#ÿ­ ÿ°ÿ°ÿ¬ ÿ'’)ÿ3PCÿ((ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿ ÿ"..ÿ@VVÿ*–,ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ« ÿ5ZEÿ''ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ-<<ÿGe^ÿ¥ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ%–$ÿ-==ÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ,;;ÿKeeÿ­ ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ0‚8ÿ'44ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ##ÿ9LLÿSSÿ''ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ/??ÿMggÿ=€Lÿªÿ´ÿ´ÿ´ÿ´ÿ%œ$ÿDnZÿ-<<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ'55ÿHaaÿ#ž ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ±ÿ9lHÿ"..ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ4FFÿFr\ÿ­ ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ" ÿ3DDÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ.>>ÿMggÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ.‡4ÿ)77ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ%%ÿNÿ²ÿ´ÿ´ÿ´ÿ²ÿ(˜)ÿ+•.ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*–,ÿ*•-ÿ*–,ÿ¯ÿ´ÿ´ÿ´ÿ´ÿ;ƒHÿJccÿ,;;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿ ÿ!,,ÿBXXÿGu\ÿ ¡ÿ´ÿ´ÿ´ÿ´ÿ´ÿ3‹<ÿPkkÿPkkÿMggÿKddÿJccÿJccÿJccÿJccÿJccÿJccÿJccÿJccÿJccÿJccÿKddÿLffÿNiiÿPkkÿPkkÿ8†Dÿ³ÿ´ÿ´ÿ´ÿ´ÿ¥ÿ@sQÿ-<<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ'44ÿH``ÿ"Ÿÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ³ÿ@}PÿD[[ÿ3EEÿ,;;ÿ*88ÿ*88ÿ*88ÿ*88ÿ*88ÿ*88ÿ*88ÿ*88ÿ*88ÿ*88ÿ*99ÿ/??ÿ;OOÿLffÿHt]ÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ ÿ3EEÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ-==ÿMggÿ¯ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ0Œ7ÿ5GGÿ((ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ)77ÿE\\ÿ9…Eÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ¯ÿ;OOÿ##ÿ ÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ0@@ÿMhhÿ® ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ1‡9ÿ-<<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ**ÿ?TTÿ<‚Iÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ­ ÿSSÿ''ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ.>>ÿMggÿKqbÿ%›%ÿ´ÿ´ÿ´ÿ´ÿ4‹<ÿLffÿ/??ÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿ ÿ'44ÿH``ÿ-“1ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ« ÿSSÿ8†Cÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ¯ÿMÿIbbÿ*99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿ ÿ"..ÿBYYÿ?~Nÿ¬ ÿ´ÿ´ÿ´ÿ´ÿ´ÿ*“.ÿ7JJÿ""ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ*99ÿIbbÿ+•.ÿ³ÿ´ÿ´ÿ´ÿ´ÿ­ ÿ;yIÿ-<<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ)77ÿIbbÿ¦ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ4o@ÿ!,,ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ3EEÿAySÿ³ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ¤ÿ4FFÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿÿ/??ÿMggÿ°ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ-‰2ÿ)77ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ&&ÿ>ÿMggÿ« ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ3ƒ<ÿ*99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ''ÿ>SSÿ=€Lÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ« ÿeQÿ$00ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ6HHÿLmeÿ§ÿ´ÿ´ÿ´ÿ´ÿ´ÿ´ÿ+‘0ÿ4FFÿÿÿÿÿÿÿÿÿÿÿÿÿÿððÿÿÿÿÿÿÿÿÿÿ ÿ""ÿ3DDÿJccÿ8†Dÿ¤ÿ¯ÿ°ÿ°ÿ ¡ÿ?wPÿ3EEÿ!!ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ'44ÿD[[ÿEwYÿ#ž!ÿ¯ÿ°ÿ°ÿªÿ07ÿA[Wÿ%22ÿÿÿÿÿÿÿÿÿÿÿÿÿÿðñÿÿÿÿÿÿÿÿÿÿÿ ÿ&&ÿ0AAÿCZZÿLffÿOjjÿOjjÿMhhÿF^^ÿ4FFÿ**ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ+::ÿ@VVÿKeeÿNiiÿPkkÿNiiÿKddÿ>SSÿ*88ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿðíÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ$00ÿ-==ÿ3DDÿ3EEÿ/??ÿ'44ÿ##ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ!,,ÿ,;;ÿ2CCÿ4FFÿ1BBÿ*99ÿ ++ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿîÒÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¤7ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿN—ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°¸ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊ–ûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¦:ŽÎëððððððððððððððððððððððððððððððððððððððððððððððððìÔ–DøàÀ€€€€Ààø( @   >´çððððððððððððððððððððððððé¸F:òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷D¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½ìÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿìñÿÿÿÿÿ ÿÿ""ÿ ÿÿ ÿÿÿÿÿÿÿÿÿ ÿÿ""ÿÿÿÿÿÿÿÿÿñðÿÿÿÿ ÿ!!ÿxÿ­ÿ¯ÿÿ'ÿ ÿÿÿÿÿÿÿ ÿ/&ÿÿ¯ÿ®ÿsÿ ÿÿÿÿÿÿððÿÿÿÿ ÿ%11ÿ­ÿ´ÿ´ÿ´ÿYÿ ÿÿÿÿÿÿÿÿ$`*ÿ´ÿ´ÿ´ÿ«ÿÿÿÿÿÿÿððÿÿÿÿÿ*99ÿ#™!ÿ´ÿ´ÿ© ÿE&ÿ ÿÿÿÿÿÿÿÿ0T>ÿ©ÿ´ÿ´ÿ‘ÿ ÿÿÿÿÿÿððÿÿÿÿÿ,;;ÿ7Cÿ´ÿ´ÿ!– ÿ$00ÿ ÿÿÿÿÿÿÿ!!ÿ6IIÿ(—*ÿ´ÿ´ÿ)t/ÿ!!ÿÿÿÿÿÿððÿÿÿÿÿ-<<ÿ¬ ÿ´ÿ´ÿ´ÿ[ ÿ ÿÿÿÿÿÿÿ!!ÿ,g6ÿ´ÿ´ÿ´ÿ©ÿ!!ÿÿÿÿÿÿððÿÿÿÿÿ-<<ÿ§ÿ´ÿ´ÿ³ÿT$ÿ ÿÿÿÿÿÿ ÿ!!ÿ/`:ÿ°ÿ´ÿ´ÿ¢ ÿ!!ÿÿÿÿÿÿððÿÿÿÿÿ-<<ÿ9~Fÿ³ÿ´ÿ$’$ÿ$00ÿ ÿÿÿÿÿÿ ÿ!!ÿ7JJÿ+”/ÿ´ÿ´ÿ+m4ÿ!!ÿÿÿÿÿÿððÿÿÿÿÿ-<<ÿ£ÿ´ÿ´ÿ°ÿ!Q'ÿÿÿÿÿÿÿ ÿ$$ÿ1`=ÿ¯ÿ´ÿ´ÿÿ!!ÿÿÿÿÿÿððÿÿÿÿÿ-<<ÿ­ ÿ´ÿ´ÿ´ÿ&e,ÿ##ÿÿÿÿÿÿÿ%22ÿ4p@ÿ´ÿ´ÿ´ÿªÿ!!ÿÿÿÿÿÿððÿÿÿÿÿ,;;ÿ5„?ÿ³ÿ´ÿ©ÿ4s@ÿ)^3ÿ#X*ÿ#X*ÿ#X*ÿ#X*ÿ#X*ÿ&\.ÿ/g;ÿ4ÿ˜ÿ±ÿ®ÿtÿÿÿÿÿÿÿñêÿÿÿÿ ÿÿ"--ÿ+::ÿ*88ÿ((ÿÿÿÿÿÿÿÿÿ ÿ ÿ&33ÿ,;;ÿ'44ÿ!!ÿ ÿÿÿÿÿÿë±ÿÿÿÿÿ ÿ ÿÿÿ ÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿ ÿÿÿÿÿÿÿ¸3ìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿò<5­æððððððððððððððððððððððððè²<À€€Àhercules-3.12/html/images/poweroffu.gif0000664000175000017500000000265612564723224015130 00000000000000GIF87a!çÿzzÿ¾¿ÿ)+ÿYYÿ‹‡ÿ‡‡ÿããÿ ÿ:8ÿ88ÿ68ÿÿõÿ‰Šÿ¡¡ÿRRÿPRÿ€€ÿ31ÿ11ÿa_ÿ__ÿòÿÿÿ<>ÿ†ƒÿššÿIKÿyyÿ‘ÿ**ÿXXÿ ÿââÿ ÿ|ÿ—“ÿceÿy|ÿÁÁŽ ÿ^[ÿDDÿBDÿrrÿX[ÿˆ‰ÿÎÎÿ##ÿSQÿQQÿ›–ÿ•–ÿÿ20ÿ00ýÿFGÿ¢£ÿˆŒÿèèÿWTÿ==ÿ;=ÿkkÿ‚ÿÿLJÿJJÿxxÿ+)ÿ))ÿWWÿÿddÿ–’ÿ’’ÿx{ÿª©ùÿÿCCÿ[ZÿqqÿÍÍÿ$"ÿ""ÿRPÿPPÿ¬¬ÿÿ]]ÿ‹ÿ‹‹ÿ‰‹ÿ‡‹ÿççÿ<<ÿjjÿÿKIÿIIÿ¥¥ñÿ„„ÿjmÿÿ55ÿecÿccÿ¿¿ÿîÿDBîÿ´µÿÌÌÿ!!ÿ!ÿ}}ÿ««ÿ..ÿ\\ÿ¸¸ÿææÿ ÿ=;ÿ;;ÿƒ€ÿgiÿÅÅÿÿFHÿÒÒÿ''ÿUUÿÿ•šÿÿ44ÿ|yÿbbÿ`bÿùÿ¾¾ÿÿÿ §ÿ[XÿUXÿÿƒ†ÿµ´ÿ ÿ ÿNNÿ||øöÿ--öÿ[[ÿ‰‰ÿ··ÿååÿ ÿ8:ÿhhÿ––ÿ’–ÿÄÄÿÿÿGGÿuuÿ££ÿÑÑÿÿÿÿ&&ÿTTÿRTÿ°°ÿÿ{xÿaaÿ_aÿÿ½½ÿ@@ÿ¢œÿnnÿTWÿÊÊÿÿMM»++ÿˆˆÿääÿ ÿ99ÿ79ÿigÿggÿÿHFÿFFÿttÿ¢¢êÿÐÐÿmjÿQSÿÿ—˜ÿ22ÿb`ýÿ``ÿÿA?ÿ??ÿƒ„ÿ››ÿÉÉÿ ÿ,!þ@$Â1$²ª„ã àR"å1w¦Áœo4ÉÁcJ© tª D6—Á#ˆª’À!)%·²Pd@å›*Ž8R*µÆ²Ÿ~Ãv MÂ`˜=ÚÖGÄ­n¨¦M"A;hercules-3.12/html/images/greend.gif0000664000175000017500000000144112564723224014347 00000000000000GIF87a!Æ[~YX|VUzSTzRQxONvLHrF™¥™FpDŸPwM˜¤—•¢”’ ‘ŽžŒœ‹‹œŠˆš‡…˜„‚––€~”}{’zxwtŽsqŒpnŠmmŠl~“|wutrq‹op‹nj‡hg…egzocƒa`^][Z}XY}WV{TSyQOwMMuKLuJGqE‘ ‘=NELtIKtHIrF–£•“¡’‘ŸŸŠ›‰‰›ˆ‡™†ƒ—‚€•}“|y‘xvusro‹n|’zywxvuŽsrŒpnŠllˆjkˆii†gh†fe„cb‚`_€],!þ€‚ƒ„…†‡ˆ‰Š‹$@F!IJL#M%N&O')*+ -23/ ‚$ B”–˜šœž ¢¤-.¨/¬?E¯GB“•—™›Ÿ*£,§4¬?Ž!HI"KL·ÍºÐ£¥§¬CÃG’ßK˸ΠѤԬ>ØÚ°Ç’Ùb– Žs-Xõ°ÐÁŸ;cB¼)™7®à.i¬(,l˜ÍQ€”(´j+6úÛÉ8zä šc5åÂ~ö“(²^¹¬vÔÔÈoå»nòÄ “•¡6:ÌD2y0s}báiÍ”E;¾›2«3®]¡‚]'ÖX<‡}²z!‡×¨8µ=’5éeŬpе«ö¦ÑXW•UduCÝ: KÍöêcb&J5±²qC0„´_7²Ó 1Y¸[¬pvph~숰 A î2V5TÃp\÷îÚ•ßžfÅ · ‚#€Æëp,­‰#X!(®ùc߆ÛÂ{¾DPŒïàËO¼ @;hercules-3.12/html/images/poweronoffd.gif0000664000175000017500000000267312564723224015443 00000000000000GIF87a!犌‹†‹‹…‰‰ƒ--,]\[\\Z¬ª¥«ª¤€}²²®±°­°°¬DDB¯®«®®ª­®©­¬©¬¬¨«ª§ªª¦©¨¥¨¨¤§¨£•”Ž::8987“’Œ’‹‘ŠŒŒ…‹Š„ŠŠƒeeb––’“’’’Ž\[Y‡†ƒPOM±±¬±¯¬°¯«®­©­­¨¬«§««¦«©¦ª©¥©©¤¨©£”“Œ¡¡œ²±°±±¯¯¯­­­«¬­ª••[ZW‹‹†®¬¨¬¬¦¬ª¦ªª¤«¨¥ª¨¤©¨£´²±³²°±°®°°­¯®¬®®«­®ª¬¬©¦¨£‘‹ŠŒ‡ŒŒ†ŠŠ„/....-“’QQO€€}³³¯³±¯²±®±±­EEC°¯¬¯¯«®¯ª¯­«®­ª­­©¬­¨¬«¨««§ª©¦©©¥¨©¤:98’‘‹±±°‰Œ‹…‰‰‚.-,——“[ZXZZWQPN±°¬°°«°®«¯®ª­¬¨¬¬§«ª¦ªª¥ª¨¥©¨¤¨¨£°°®¬®ªgec•”””ŒŒ‡ŠŠ…®­¨¬«¦««¥«©¥©©£•“Œ´³±³±°±±®EED¯¯¬­­ª••998¡¡ž,!þH° Áƒ*\(‡$IK$EˆÆA—‹Z22è‚$‰$HqD’d<JœÌ—‹]ÈÜø¥fƒ!!yã$J#Œ@ÔÁ—*º@â³;7AnÙ¢Z´Õ(›0!uyú´ÁÅ¥\¸€l °ÑD[[D€ ÌfÉ®p il—´j»°P#‘žÃ[ÇLœ´C¤_ì C÷aM;o ì€ Ñ‹ÃD…¶ ƒ…E|üø‰á‡… dØ ÜE › :ï0¦Å†:6N¤P0(ÅæX©‰Džš‚kð°¨ú¢ \Ç(XC(΢88þøƒ…N‰í–ôD}Q uë‹DWyàA zÄ!OÇDYQ†O©à|ñµ€ˆ‰$A\ˆT0CüqA¸ ,ØaàtC,B„u|T FN@`À ´G~Ñ 0Ax°Ç‡áãˆ|ü1ƒ'B@ÅUD €¡È¯µGK@Eˆˆj}\€Azx‘‹ 1X`†ˆA0‘@PT(§j3ü‘Æ ÂçcŒðñ èñÚ›Ä9'k2X ( ôˆBƒ€ z#,!€Ì©Z ˜QA/˜‘脤a }üI¢dDçœhð!ꚸšqF¨zƯk¾ºÄ’ô„ ƒ76ûZ³Lí³Œ¡ÄCUPˆM4í·àNk¯Âjî59D%®¹¯f:WHT–EÉ 7DB E`.¦’4À—DöÊ».7<"’ äƒSLpÀ!‚!¼‚ ƒðƇ €RbH,âƒ@;hercules-3.12/html/images/translucentoffd.gif0000664000175000017500000000177112564723224016312 00000000000000GIF87a!ÆŠŒ‹†‹‹…‰‰ƒ¬ª¥«ª¤²²®±°­°°¬¯®«®®ª­®©­¬©¬¬¨«ª§ªª¦©¨¥¨¨¤§¨£•”Ž“’Œ’‹‘ŠŒŒ…‹Š„ŠŠƒ––’±±¬±¯¬°¯«®­©­­¨¬«§««¦«©¦ª©¥©©¤¨©£”“Œ²±°±±¯¯¯­­­«¬­ª••‹‹†®¬¨¬¬¦¬ª¦ªª¤«¨¥ª¨¤©¨£´²±³²°±°®°°­¯®¬®®«­®ª¬¬©¦¨£‘‹ŠŒ‡ŒŒ†ŠŠ„³³¯³±¯²±®±±­°¯¬¯¯«®¯ª¯­«®­ª­­©¬­¨¬«¨««§ª©¦©©¥¨©¤’‘‹±±°‰Œ‹…‰‰‚——“±°¬°°«°®«¯®ª­¬¨¬¬§«ª¦ªª¥ª¨¥©¨¤¨¨£°°®¬®ª””ŒŒ‡ŠŠ…®­¨¬«¦««¥«©¥©©£•“Œ´³±³±°±±®¯¯¬­­ª••,!þ€‚ƒ„…†‡ˆ‰Š‹Y)ss;s I G—D™G89srrq6p¤¤U‚-’“ IH—G²›Hµ¡q7¤(§u“ L Ä HGrF°ZZ· EEº))‚LÜÄ ¶°rGÏÏ—ËFF ‚o/jÛ ªI[ æä sãGéꎰpb—ƒÛ˜L¢ÃÂÌH´SBïQ--—n ªP`MˆƒÄ„}p  „6`Ĉ!ŒƒMh xD:~QÀD›—/1ÚmCfŒÊ(O`v©%°& CÛÄàÆäàš¨4hŒÙº¦—2/ ‚U¤—†fm³uk”þ `8YòŒÃبm|Pãe½=Õ<(fk¸ ¼ðð ÅîÓmh ó`Ê<¹}c´F"`8pÀÅCDz®å\‚eb  CF›//?ti•@P€5"“Q&‚„ ?ƒ%Cf„'O*˜$H[®bJŒ‘R¢/VÜ€ ——ÔXo»R ðE@CfJ}2& ”??ºÉ‚‚XQv+=ðÄ„ðÄ{„A "„AžM4IuìEÆÐuø:P$BGáHÌ!ÈbDÅOŒ&ãK26Ð@4:À„ôÀ+ôЃD9I…NP`Xá’LÔ’@9Ì‘KRøß$Ü,À@0 X(  Èe@²À’þÍ?’ly%”) ‡(6Ô)ˆ . 1`…dpBŠÁ¤A€ADІ ‚;hercules-3.12/html/images/greenu.gif0000664000175000017500000000144412564723224014373 00000000000000GIF87a!Æ[~YX|VUzSTzRQxONvLHrF™¥™FpDŸPwM˜¤—•¢”’ ‘ŽžŒœ‹‹œŠˆš‡…˜„‚––€7F>~”}{’zxwtŽsqŒpnŠmmŠl~“|wutrq‹op‹nj‡hg…ecƒa`^][Z}XY}WV{TSyQOwMMuKLuJGqE‘ ‘^oeLtIKtHIrF–£•“¡’‘ŸŸŠ›‰‰›ˆ‡™†ƒ—‚€•}“|y‘xvusro‹n|’zywxvuŽsrŒpnŠllˆjkˆii†gh†fe„cb‚`_€],!þ€1@F "IJL$M%N&O')*+ -23/ ƒ1 !B‹‘“•—™›-.Ÿ/1¹?E¦ GBŠŒŽ’”–*š,ž4¹1?…‡"HI#KL®Å±ÈšœžÏC»†G‰ØKïƗɛÌÏ>ÑÓ§¿Á­Ä°(ðàZ<ëqÁýs¾„\SÂŽ›?YÊžQ hPZ¡ ú5ì÷“¦g<*P¼G ѵlíºýûölBH‚övQûµp£;ožíp9±ItÖÖmã`å3 ;_<¨!È`ëR²ô,R—"}ZD§J£TcU­&ÍJn«/u#øÝ|öBŽ«ŠJcN3”JJ‡'žáhûv,ÌŸ¨  søì†‚¶tø]*ÍFÁL†FzfãÆ^b±R,77a0m®ž5¨|8B_ÍõÊ))bUÚaÏjŒ†qØ-\²$ó¡ýŒlöFÈ÷ ×U Iã '/ Pp‘´åOia  xÐogÄ€Xü@FH¡°A ïU÷À ‹ðÁÈ î¶È1üH 0ñ |,¡ºá†Ž Q¤qA`E+Ð1 Düá‚ ?H *ìaàCi¢Ä@ŠH!ƈ A4Òk+ìQnlÀD”(ÈiT`Á|taBŽ$ˆ /PPF„9 ‚p\hçi1‚F ÂäøÑB ðÁšB´Qç©Á@Á£.Pð‡ iP*ˆ j¨Žc< lt ȧ½0ALÐBŽVHܸðÇ Œ1B€- gøê›À–aÆ©jƱoÖª„”t0È€TpÆ eèh-kÖFA¶ØJ F1Ç;àÀÚ¦«®B¶’Q«­ðŠÑH ±N:Á;F­ž*dÕèô€dJIB ;èp!= ïÀ Ü•PÀýÖk ‘dTÄÆN„ˆP¡T€<Çrx ²Dу"P@GOÔüD‰œpH"4Û@1+ÒC(«ìËs€LòÈ ç ÀÇ!\²'§¼rË/Ç<³Í7; @@;hercules-3.12/html/images/translucentoffu.gif0000664000175000017500000000206112564723224016324 00000000000000GIF87a!ÆŒ‹†‰‰ƒ¬ª¥«ª¤²²®±°­°°¬¯®«®®ª­®©­¬©¬¬¨«ª§ªª¦©¨¥¨¨¤§¨£“’Œ‘ŠŽ‰ŽˆŒŒ…‹Š„––’>Š K½GFtE¨\\¯—DD²''+,SKÖ½®¨tFÈÈŽÄEE—>g.mÕ ¢H]àÞuÝFãäFSXÜ€Xm‰";*ÒÔAq„˯$ï µââèÕ™ T¸ù0°×® @ˆqG 2!Ȉa°€É.üŒHÀR…a,¡& 8@á˜)sŠ“–_Zõ3BË„ p`X[2Ð Ô3ÊhEÙL‚—ŽªPx õ#˜‚b…£U+þ ^4Q‚LÃdƒ&èÐŒ{w¶i0bŒÖp=€ÙÁ‹]+VdÀ™TL)zè´ÖA Qc@€xÁ€_ìÞźÖó˜{LP’Œ™o°ìð¥Ô+(Р1ÙÌÉ1 Dèù3¨3!8qB"¼XÚn%3¢L”~¯ÎˆĠ À°TD¡Jö¶(Ɉp@„ƒ1f¤ä7CÂzõ¥1‘€XPQÁPÛ¡Ô€ 4ðóæ@€0Æy 0Á"½Gb08݈N<± è=¡âtêpDœ1@‚¥åÈRŽ ,À㎠,‘ƒ!`1 )ð˜ÀCL6©ˆ†Md¨á”K´r8L€‹.S2‘ညX“€º$ ‘2t”P +¨Æ! ti¦÷$B&˜XžP™Ô৬!€B°!„ƒnq4ªÅA´À@dÀ˜þÀ¨±Æ¥™¥l´Ä¢Zðèƒjè œ (¡†"*€¢Œ: ©¤”Z𩦱;hercules-3.12/html/images/hercpic-rblk-256.gif0000664000175000017500000001242612564723224015767 00000000000000GIF89aÄ4.YYB¢¢¢""ððð;;,AA1aaI±VhBÄÄÄRR>Lz=++!I‚;bmI~~~jjO11%§MM: ®HH5777ž"66(´ÿÿÿ!ù,ÿà'ŽdiŠE1HöW,Ïtmßx®ï|ïÿÀ F dFáÄl:‰æâ©Z¯Ø¬vËíz¿à°xL.›É„„òÉnêyN¯Ûïø¼"Yºÿ$* z„…†‡ˆ‰k€lQrŠ“”•–“ Pƒ—žŸ ¡b›' ¢ª«¬ ~¦­´µ¶…𛳷¾¿Àbº ÁÈÉÊUĽËÑÒ´ÃnÐÓØÙŸ°M Úàá•Ý&©âéê„Mëñòg¥'×óùú^åö ¨Å‰& Pâ‡û8C±â< °àYܘNWICj› B‚È“Ú ÿ¤ €²å´]ÊT&âÌ›¿àÃÉ“ÒJ´(Ä¢H‰¦£ !hÒ§IõAª4tÉŠ1ºNë¤Ó È:”†Ø³hÑÒ¨ ŽèŒ´pÕÊàª,F0·1Ð^ÝË—¯Ü l •¡·¯á«gç]f÷WÙ¼ö>˜ü€‚åË(?@,6F`e/ˆ•<³iÊ{;{Z$-¼£ ”æÀá€írß>ÀÁòdª³^ö8öìÚ·s#ØM;ófà0„Dָ쫕‘#ÈÀÝ‚÷ï¸gXÞû·êÅd@–ý@{wðà¹ë.xõt`Õ_«yríí4Ð@À `ÿxËe}ȇ¸eà€¨a ŽÇ›y0 ÷K~¬”5Zeh N´èâ‹6Þ‡õ á~ýQÀ€øâ-"¨ ‡F'â-$ªbbµY˜a°TVie8Àp°YgGÚ2˜h²Qˆ€Š D ¥•lR¹,°åŒEBèK’¢ŒÉäô¨&*è „v° ÈØå—«96ØhfZ` Zè¥bçÔiã®å‰£lM8A¥˜¦*(s. \£·èIꙓZª*¦8Àif`Þg ž <…}&àÀ·&»Á dÐé !úª™íÑšÿÉÞª .Çè§¿†ì¨Õ­Ù¦ª€Ízù*¸­ÈJl ›î­`«Ñ‚¯zbUFköÞ«êú"Àk¿Ö<«¤Ø¬êºÍÀèpáþK-Å ñ­$š» OÛŸôüñ¥ïË+¬µëɨJzîÊêêê,¯bo^E éàœ*»üÂÛŠÌ–[né ¸ü®´JlÀÓK](ÂÎ^Œõ*LWò(©Åªìµ  0»h¯&£MoÔkÚr§=­JÙ”œýŸL @Ý„¶Ý®ØqÿAàtÞAÈV‰¤¸3;¬xàƒ;¾j##®ñɋ߬yÿ $ªð žM^¢å€ >z ùvžwâ€G¹æ¥7pºä¯âwë·k;ÉJ‹JmíÁžûî©÷žõñ‹»þ:ºïóó `ûë¥GÞ|Ì”_òûâ $_7Åo—ì;ë¡=:úâ­þÒá7mùŽô¢K8ä _ÝðÆ?ÚëÀf±Ù9Ïx¢˜8ºØÉ¯xÜØ8ÂmàpßÏÈT³8`t“Ýü|´nOxÕóœW·±´i® {Ǥb¹Ï‚ñ㙑ô& ¾õMk Ôžùp¶.Îwÿc­>¨1›¬h¥"ÀÒ`h‘wˆÈûÕ3ú[g>Ç©C˜EQŠÙÓ‰q¶kªRŸÕåº6;îž”Üâ°0 oÞÿ‹FüD+—RvtmÛY0UÇB%Ò ™ŽkÙî0:.Òk¡RÛ– µT6Tìe#™%Âr’4¡BýXÛ\-£zBžˆ(¦¤˜(¼â2‚EÀd@½F½¢®’lܧ?ç6Àªõ‰?åšG?FÀgÆ3¬‰H$ùnè¸åy nŸC›îéµ»ô«E(P£·V¥"m¥i­ÝV½Æ?žŽôP5Äø0÷º Ï­ædŸ¹g:Dz4Ž—“^9‡XÁ^n–uíìk‰Èb²¢­ªWY+Vèm„õß3kÛØ:Žz¥]è’ÚH³zv·5­!½ +1åϩ}T.5? <°ÿdL«"‰û±ÆêV£Oã«ÔÚzÕÀ’0š’¯ÑˆÙ¢gÜèöåùôHKrKfé(5îwYÙrBÈÕ@0ÏVÛë úuÕ½®´!q;X»^œý³}¨B÷º×híñÊ:®ì³0Âzï.Q¸C»þðÅÁ0ùNª9òö½mw»ÃˆåÁéôKÑ‚æqp"Ê·ÈÔWøƒlÓt{m]­òæãÂúÖ»þõq)“‘[nL-õ¬óÎòß¹i³°g[Ÿ3¢Ïa†OüâøÙAY,]7™ï{ílïº×ÑÍøÓ‡YQ¼és4Ãýî{ÿûà¿eã$Ê‚ì®ú'"/ùÒO¹¯kVƒ–³›úÛÿþøÏ¿þw“ ™ÊEjbséÒPÿû”{º×R¼KšôE@#2â8XhÞ! $]&€ªÒkbÖh†U”Ia×PHHB’ ,Ø‚.ø‚0ƒ,è#)x~ÍUeîô|Âtg”g~is¨VƒB8„DX„FXƒÕWM¶4n+·~Ò7}ei±vì'Vx…X˜…Z¸…\Ø…^ø…Ø–O~Æ„Ð}ZFJ-¢b•µ†l8^â¤jMYO8lšPmx‡xÈVÀ‡{qsˆ&2X°–„yXˆ†È2Evøf[8Ìwˆ‰†2NêÇr4§H(‰šXˆ2åd—\A§†›8ŠyxX•èwRaXGЬ˜tÿ:8z@^­8‹lØ`?ç„ÚE> G‹¼(1¦vŸØo¡å{½XŒÊ„sO·ˆe7ŒÆØŒF³<2T†~øS%HŒÎhŒvµZÁ‹ÀsÞ¸NN×S°hufgßH‹ÝÇÒhì7_W>ç©’vµŽ…ÐŽô `µ'¬èx}xØ~€Ç)(ó¥ˆÙE€CU)À…—‹×ñˆ ÐdcÆuŸ“€àÙŠ!ôŠãhIÌ6)æø‘wmÁµÂ¨H±¶‹(‰7FNqˆŠÚeLs’1S‡ö<(M±Fˆ;yˆí”ƒ§(‡<Kq¦Tmò”P•R9•TY•U¢TÿK†”·xi9q£4j?x„ÂFP–fy–h™–j¹–lÙ–nù–Psb¨•g“k-²€z˜‚+(ƒ~ù—€™ 4˜‚™˜-G‚èf:ön3¶Šö#[ò€8™”Y™x!$¥&_žôi5 y]Y¯Ôl#¶h22ô·ª¹š¬iý')>øƒ§§%¢7’¡ö0³ƒ¢a–0¼ááœÂ9œÜ§#)’™²yl”¸•–(‘×"<úT1ªw|ÔYÖ™Û—D)_ùkŸl¡I4K«HD@F {깞êY&¸ñGºY(™”Ó¶{o¿uy²yüY'2{4†CÿdÈ’·)‹‚…‡x JwxW‚bi0|÷„€f[0i0†3nÒ± :Qhƒ/¤uE§Œ ÈŒÓ#wßYmš ÊŽ?©Z°¥“—âsuÙm¶UžÏè¢]@544*ŸTÇœ®´¢Aº›…€hØes½–j†$¬•U»ä«z}š¬wJ­Rø§§–•Ë-a ˆãifiHG¸„žú©Œ¸¬-R˜¿Ggš¢µõh?Ò‘1§®¥Êª›*ej„Y‰¬±"Uf­b‡ƒÐJ“ãzc*£½z¡„ò˜ž¹°PŠ›.nš| «­X5Qï'5U–~«Z©íF¨ú1t¨ìÊ[ –Ûù1Jöp¹J®Q–FIKqRi3› ;o¯T6±³j©@»2Ú¶±”Ê¥§©¤CT*Œ®Ê´©²PG‚ÿ#¥–õpôZm5{³øä¤pª´kŠr"šŒ,kp7…pÙZ¥-©‹q÷\[ …2Ʀ˜pqËŽ»Z¡š…¥(¥¥7ª¢½E·Ùâ]išQ‡t²õ´z_gêa;hL:uJwt:JDTº²Žj¢I§¸>zZXK:—«s‡Ë·†*«” ±é’ކ¹m»\‡¦›i(fzkS§±‹=oÇ´™¬f[pÚxZK±t»º{IœêŠûU„е¹¼¸›·z›£¨›,~»³;Q^{/ó9²å&½[zÞŠ3æÄ›¥'¸ªâ¦šZµ$È”£ªoÐ ¸v²DäDëê¾:æªgwz$fºÿÂkñ©’œ«”—XOök07¦ŽçëŽu¨› <©I[¯ è"°½ƒ¢hˆ‰½^‰¼R¦¾€%ú­‰i¸ÛZ‚(iÏzMkëhŠW°øv” ;¿Ñ»”†V¹lcMWv»[’>X´…ÒgtÉÁ ¾á g™„¡ñG† Œ¾özL»6—3ì½fxÀÕêlˤ±œDü®Í*1‡²d;ÁK« œ.½–0LŽO£kFóc·ÚTw‹·ÓÚƒý›S$ÖÂÓê±ñÙP"ËÃÓ¨¬³¿ GÄ\R`9§ EÂs ”Î9¾IödžŒ¾ÒÉlU€“|Æ ãÙ{¸#¿T,»/|DŽӽ€ìÈí:AÿyêpY¸¤§ŠÕËIÃû¸8:·o‹q™ì³ Âc·M\›ìÊ=×ÛÈlr´ËXe+ŽlËR·¹4|n+ËÚºú›¹Ý(¹ù[¢ÈsËÚHÆ¢ü£ˆû[³Üª¡ó¹ÙèÊ\ r¤Ka“{¸8¬TÖL¢ØüÌuUÌ¿¬»g4‘C·mù<ÁÜeJÍ“~v—É,5ì{ʺz“«ŒR…üÏÇa–¼wåÜÌâe@¬TÎÍth[ €ÁÙbʹ ÌF¬ËÐ㺎2T Zø¼ë_æK˵Œ› ¡c\Ç y¤ó%IÌŒÑ$ :ü<›èÊ€«DSÕDEÍÐ Msó’ÐÕ>mÌÿ}å—Î Pßµ àN@ë»~½¾  èÁŽpëPpì'q Qàή ™ &ìÕ®¢ŽíæÛ.ŒÀéÞžíMîñ`Ý^î­Îðéè~ãì¾ì+ ûÙŸüÞïþþïðo!ÐÐÞ;hercules-3.12/html/images/poweronond.gif0000664000175000017500000000273412564723224015303 00000000000000GIF87a!çÑÒÍÐÒÌddbºº³VVT°°©¯®¨®®§¬¬¥~{×ÕÏFFDßßÚ©ª¥ÞÝÙÝÝØrqoÝÛØqqnÜÛ×ÛÛÖÚÛÕÛÙÖÚÙÕ987ÙÙÔØÙÓØ×Ó××ÒÖÕÑÕÕÐÔÓÏÓÓÎÒÓÍÑÓÌÏÑÊÎÑÉÝÝÛÛÛÙº¹²ÇǶµ®µ³­´³¬°¯¨¯¯§®­¦­­¥½½¸¼»·¹¹´ÜÜÖÜÚÖÛÚÕÙØÓØØÒØÖÒ×ÖÑÖÖÐÖÔÐÕÔÏÔÔÎÓÔÍÔÒÎÓÒÍßÞÜÞÞÛÝÜÚÜÜÙ¹¸°ÙÚÖÉÈÃØÚÕ·¶®·´®¶´­®®¨ÚÙÓÙÙÒÙ×ÒØ×ÑÕÕÎÖÓÏÕÓÎáßÝàßÜÞÝÚÝÝÙÜÛØÛÛ×ÙÙÕÑÓÍccabc``a^°¯©UUS­­¦¹¹µÚØÒØØÐHGFØÖÐGGEÔÒÌààÛÎÐÆàÞÛßÞÚÞÞÙÞÜÙrroÝÜØÜÜ×ÛÚÖÚÚÕ997ÙÚÔÙØÔØØÓ×ÖÒÖÖÑÕÔÐÔÔÏÓÔΞšÒÒÍ›™ÑÒÌÞÞÜÜÜÚÖØÔµ´­±°©°°¨¯®§¬¬¤¼¼·{ÞÝØrqnqqmÜÛÖÚÙÔØ×Ò××ÑÖÕÐÕÕÏÕÓÏÔÓÎÓÓÍÒÓÌÑÑËÞÝÛÛÛØÙÙÖ¸·¯ØÙÕØ×Õ·µ®ÕÙÒ»»µ¹¹³¹·³­­§ÚÚÓÙØÒØÖÑ×ÖÐÖÖÏÖÔÏÔÔÍÔÒÍáàÝàÞÜÞÞÚÝÜÙÜÜØÛÚ׺¸°ÚÚÖnpl998ÙÚÕÚØÖ897ØØÔרÓ,!þ¹H° Áƒ*\(ãħOº¶àÁcÁrÜht¡ˆ‘-X°Ð²2«dICM}Ú"qâ .Êq@“£–›¶l‰¤u¥ä”\LÄ“áŽQ;æ@‚P+Žœ‹¶êÔÉžžˆLA‰R†¯FïT¨`+ F,¤JµuKœ·!m Ì…æ‰WJxî°Üb¡†²j'Øù”ÂÛ8X²ÈårdM8¼f˜ØE”’-(´Ô¹Uá‚^–4C]Š«V)áàEJ)D¾îØ ºŠÒ(JHpU¸U±YK‚’)ÓM€~´©€N%ŠuiÇŽJ8ÆB`+ÔðL=2þù`óE/ªYð $j ̨T :»/Þ£Œš3¼ìÀ lä‰*ÐIìÐH~ÄýqIðÒG ðr‰‘ Â ‚ôÑ+½LRÇ„\0A,UÀbã%â…&¼Q\°\R&<ðF0|Ø0É 06QÅ“5^¢É À.a’IyÀ"DS¼bI{PrÃKvÄ‚,mÐ(Ä!ˆ@Â/ƒh <D èÐÇc”Ü1‘@‰ '\qÇ%7Æ’‚gtÓUwÝj{ ÊE¡ß…çœò&›2B œ¤ôu°ºÔ—Çò÷†ìÐǦ?` ð€‰uªn¡ßYˆá†ÈöáǬìàÐn¨ª.Zl!Ð ™„ðG*và­·{|»Ç|xÀG¸äò‘.,Ý"Ð) ̸ôÖ;Ñpà¾ünÁM·a„@BÝË/«ê2ÑWxè1[|¢UX 1„@޲…Âýâñ‰-v°ÔðD |´ŒdÅÊ9ád4¢@#Ä Œ¼°ÈÎ/0‚@* p€ b ÈÑb8!P@;hercules-3.12/html/images/translucentond.gif0000664000175000017500000000266612564723224016160 00000000000000GIF87a!çÑÒÍÐÒÌÏÒ˺º³°°©¯®¨®®§¬¬¥×ÕÏßßÚÞÝÙÝÝØÝÛØÜÛ×ÛÛÖÚÛÕÛÙÖÚÙÕÙÙÔØÙÓØ×Ó××ÒÖÕÑÕÕÐÔÓÏÓÓÎÒÓÍÑÓÌÏÑÊÎÑÉÎÏÉÝÝÛÛÛÙº¹²¶µ®µ³­´³¬°¯¨¯¯§®­¦­­¥½½¸ÜÜÖÜÚÖÛÚÕÙØÓØØÒØÖÒ×ÖÑÖÖÐÖÔÐÕÔÏÔÔÎÓÔÍÔÒÎÓÒÍßÞÜÞÞÛÝÜÚÜÜÙ¹¸°ÙÚÖØÚÕ·¶®·´®¶´­®®¨ÚÙÓÙÙÒÙ×ÒØ×ÑÕÕÎÖÓÏÕÓÎáßÝàßÜÞÝÚÝÝÙÜÛØÛÛ×ÙÙÕÑÓͰ¯©­­¦ÚØÒØØÐØÖÐÔÒÌààÛÎÐÆàÞÛßÞÚÞÞÙÞÜÙÝÜØÜÜ×ÛÚÖÚÚÕÙÚÔÙØÔØØÓ×ÖÒÖÖÑÕÔÐÔÔÏÓÔÎÒÒÍÑÒÌÞÞÜÜÜÚÖØÔµ´­±°©°°¨¯®§¬¬¤¼¼·ÞÝØÜÛÖÚÙÔØ×Ò××ÑÖÕÐÕÕÏÕÓÏÔÓÎÓÓÍÒÓÌÑÑËÞÝÛÛÛØÙÙÖ¸·¯ØÙÕØ×Õ·µ®ÕÙÒ»»µ¹¹³­­§ÚÚÓÙØÒØÖÑ×ÖÐÖÖÏÖÔÏÔÔÍÔÒÍáàÝàÞÜÞÞÚÝÜÙÜÜØÛÚ׺¸°ÚÚÖÙÚÕÚØÖØØÔרÓ,!þ¡H° Áƒ*\˜âàAœžˆãŒ]²hL @ÇŽ'L˜XRR©dÉ6 z"qb .vI@“£“›˜0‰´´¤$”PL!ŒQ0 ¼ØQp‰K—‹˜¾|ÉrËž‚r O„¯FÃ4h€© F& ¤JÅt‘ —·!1 ÜTeˆW2úþ̸@>Æ>ÔhP¨Æ…ë-òäæËÅîߋ˰`Æ‚fŒG¤qA |XGÁHµ~Ä¡±GfThá ûíáGqgœQ!ŽtrÇB’$!ÉŠ{X †t EqfH²Gq|ă ”±Â,”DDª¨! ¨€„·ÇŠ7ØpD$z¸@,¼†@#P‚EŠ7àˆA¨±Fqh¤˜„ 2\ð‚áÆDÁ1œpÅ—ÜrÍ=ÝtÕÁWtBaçwáWÞyé­×Þ{ØÉGbp" Qâ©þ( "¨ DTçwRha…gðW tè¡“râĉÐhÈ@+ÀKF°dQFƒR`lhÂR&-BÈ'Ÿkíµ‘:A¤v+A7e²Ã •m·ePÊÉD_‰1ÆPb<1ˆT1ÕáÆëz+Æ ˜€Á’»­;î8X2’ $„TPAÇtÐ 'Ìa‚›0‡ŒP@%LA@(O!„@;hercules-3.12/html/images/hercpic-rblk-80.gif0000664000175000017500000000271412564723224015701 00000000000000GIF89aPPÄDD3Z[D::,ceJóóóššš$$VvC&™&Gi8¥ ¬D„8û9À À{;lh ¼‰5ÊIÈxƒAiŽxÿUp@²ƒF :ùhD™Å‘$/œ”Y„"„•-_Bˆ‰P¡€34 ±fE8.àXÔßÑHn(æN!¹HR  …fOW58Hz/˜M{†  !CT—@C™Ä,yi5„Å'Á¸<ÿÎÕP/ß zQ$&âwˆ2€8”à€k\Å_ܽ·Ù¾ ­l˜QD¦“…ø´È6ß¾¡±…T–=·v>“SþdI’ÌÜAv±`t>Áã©$ÞúxUW}ã[úÙòSç÷Œã¾^saÖŒ DDþ#Ó×Á/œö˜z"Z€uG—öÌÞsðÝ#A‘ñEŸ8±žÿaˆ‘²˜šá³d{õçr@\€1ÐÙz~•™T¦WV}å]¥à@ ¼f S_EèPÖhT9Ú•@%‰Øáã}ô´$Q6Z%RKòµÒÇ’L2É @ÔmV#jF!Õ’@CI'\vÉe/ €€S¨Z@ÅAV-´éæ›m2C—`$e0ßL(ž•ÖŠ jÙ0*è ƒà'c2JX …¶wßœ|.àÀ¤”Vj饕¨…’‘§'~|¶$ê¨ùl‘Tžy©¬¶zªfb‡c«´’:$£y*fÀMµöJ’P°âyc9úJ뭞꺚±Ì¶u§ú÷èˆÍöÊ@ÿ‰/B›«eúÉ' „+î¸ä–;nm.š¬e i@~ (¡ôjè¡|J@Á©¸V‰•Vj®çÀqþâ§@%¬¶Ã‹%4^Fü¥/b‚×Áe käw¤()ÈàG/æ•1ÃF6×pŸøèò ì«u‘Ø´ê@¨[5_!\ôÏ”Mö®$:ÐRÙþõI›˜ª¬#¹Ý@ý:sÞÃvÌr³ÅŒöãCÔ¼ÐÍæL9Ï9ndxÿ¬5M«7bS>—åx­}xé%ÊÙaCa»JãSš^Ñ‘þ)]ÔâCAØUËJWî¤æºïÊ–œ ze‘Ý9€wæzßηßE/9P޹nÙ·7WÇÐîÝp&®qÛ*“œííUĺ€ã'W¾´GUÀ=> ¨ê²C¸å½¯tyI` ÆßâØ†r<` HÇ0À^¦@Ç6Öa úý ZþQF/˜Q®" ‡5XØÂ5•ÐBÚŸ£ !‰6q1ÔE 6áÃV\â£H†<üð‡&¦ ˆJäCxÄwòXÄ0l‘ 6XƒÕ€I7ŒñŒ[ˆ€Æ6Jáø€ÝHÇ"D€¨£… €+˜¡{ܣ⨃$1g䀛 7TÀ3ˆ¤$'ƒD€#;hercules-3.12/html/images/powerononu.gif0000664000175000017500000000303312564723224015315 00000000000000GIF87a!çÑÒÍÐÒÌddbºº³VVT°°©¯®¨®®§¬¬¥~{×ÕÏFFDßßÚ©ª¥ÞÝÙÝÝØrqoÝÛØqqnÜÛ×ÛÛÖÚÛÕÛÙÖÚÙÕ987ÙÙÔØÙÓØ×Ó××ÒÖÕÑÕÕÐÔÓÏÓÓÎÒÓÍÑÓÌÏÑÊÎÑÉÝÝÛÛÛÙº¹²ÇǶµ®µ³­´³¬°¯¨¯¯§®­¦­­¥½½¸¼»·¹¹´ÜÜÖÜÚÖÛÚÕÙØÓØØÒØÖÒ×ÖÑÖÖÐÖÔÐÕÔÏÔÔÎÓÔÍÔÒÎÓÒÍßÞÜÞÞÛÝÜÚÜÜÙ¹¸°ÙÚÖÉÈÃØÚÕ·¶®·´®¶´­¬¬£®®¨ÚÙÓÙÙÒÙ×ÒØ×ÑÕÕÎÖÓÏÕÓÎáßÝàßÜÞÝÚÝÝÙÜÛØÛÛ×ÙÙÕÑÓÍccabc``a^°¯©UUS­­¦¹¹µÚØÒØØÐHGFØÖÐGGEÔÒÌààÛÎÐÆàÞÛßÞÚÞÞÙÞÜÙrroÝÜØÜÜ×ÛÚÖÚÚÕ997ÙÚÔÙØÔØØÓ×ÖÒÖÖÑÕÔÐÔÔÏÓÔΞšÒÒÍ›™ÑÒÌÞÞÜÜÜÚÖØÔµ´­±°©°°¨¯®§¼¼·{ÞÝØrqnqqmÜÛÖÚÙÔØ×Ò××ÑÖÕÐÕÕÏÕÓÏÔÓÎÓÓÍÒÓÌÑÑËÞÝÛÛÛØÙÙÖ¸·¯ØÙÕØ×Õ·µ®ÕÙÒ@E9»»µ¹¹³¹·³­­§ÚÚÓÙØÒØÖÑ×ÖÐÖÖÏÖÔÏÔÔÍÔÒÍáàÝàÞÜÞÞÚÝÜÙÜÜØÛÚ׺¸°ÚÚÖnpl998ÙÚÕÚØÖ897ØØÔרÓ,!þ“q“']\ðà±`9n":€PÄ—,Yh]™Å‘£!`Lyâ’Pá ÊqÀrâ–—¶le¤……ãC2Pˆ'ßv*Ìy¡V9mÕ©#84;1u*ŤI²þ¼S¡‚--³@XºÔ–Ã,qÒb´E`E.4P°NÂs‡$ 5ì|%;Áާ±ÒÆÉ¢ÅVŠDGÖHÁk…]B)á‚bK[.Ô%YÁrR[¹Z€bàªãI8øD™B ‘¯;6z®š$j\nÕ öH¢%A‚Á„éG&@?ÒTH§ Ų´c%]!˜•h”pL=0þù`óE/ªYð A$j Ì D :—°ðœ8ø2jœÁ˼°ÁF—¨B °‘Äp€ÁRŒÒ˜üaIðÒG ðb‰ Â ‚ôÑ+½HRG…L0Q,VÀ¢£%â…&¼A\°XBÜ%<ð†0|Ø É ZhÅ”9Z’É À.a‚IyÀ"DT¼RI{LrÃIv01 ²´£G†  ¿ ¢&0e=€ C‹Mr‡B&"\Å÷Ã_DRHŸÐIGu©í¡ K(ú]x>€ * \¢I #²  `J_þà¡K" ´0&£à}Àá;ôê—€<\R¬ „˜§ÃiÈá‡ÐöᇮìàØ~«.[pÑB.+`Â=¸ØÁ¹çîî{ðáê¶ËG¸tK")œòI0Á°ëï¿ m°lð¼t‹F¬ Oó«. e…‡<áÁ…'[4•ÅCœbJ#‡pAñÁxxb‹$]¬Å Ÿ0-]a322øþ̸@>Æ…=~ÔhPó§Æë-ðàæ‹Ã#¼'Þ‚ À`Æx4ìqAİGuLÁR „~| ¡Çfd¨á 2X GÄqF†8Ò‰_DIH¢„$0êaRÐÄ™!‰ÄíC V„RÆ v°¡„J$ùâ‡4\ xž0Þ`‘äáw°p@2%X¸xCd°k‡†‹JØ Ã/˜±Øa(4!ÂíWÜqÉ-×ÜsÑMWÝue¡Ð?ðù]xã•w^zëµ÷ÞuòQ œÀA VúÙßxA&¸ šJ€bÞŽg!†fx†ÀPˆ#š¡)'O@AÂ&"ð2øJÁ²Ë’Á,d”QA¢D[Fš” !,2( @+î¸ I Á˜«®¼”É;ˆ Oë–±)' e%Æ<‰… O4Õ8,¢n@ïºb‚ $í«¾ð~€ƒ%-¡ñ) AB „( pÂ&È¡² sÀÈPÂÄaóC$BÇSØS”󌀲Êr°|BÉ#‹üqΟx ²È$›|ôÊ-¿óÌ5ß õ';hercules-3.12/html/images/interruptd.gif0000664000175000017500000000264412564723224015311 00000000000000GIF87a!çÿ¦¨ÿ)+ÿYYÿ‹‡ÿ‡‡ÿ ÿ:8ÿ88ÿÿõÿ¡¡ÿÏÏÿRRÿPRÿ€€ÿ®®ÿ31ÿ11ÿa_ÿ__ÿÿ¥¤òÿÿééÿÿ<>ÿ†ƒÿššÿÈÈÿIKÿyyÿ**ÿXXÿ ÿ ÿ|ÿeeÿ—“ÿceÿ““ÿy|Ž ÿ^[ÿBDÿrrÿЉÿ##ÿ!#ÿSQÿQQÿ›–ÿ•–ÿÿ20ÿ00ýÿŒŒÿˆŒÿWTÿ==ÿ;=ÿmkÿkkÿ™™ÿ‚ÿÿLJÿJJÿxxÿ+)ÿ))ÿ……ÿÿddÿ–’ÿbdÿ’’ÿx{ùÿÿCCÿqqÿ$"ÿ""ÿRPÿPPÿ–•ÿÿ]]ÿ‹ÿ‹‹ÿ‡‹ÿ¹¹ÿ<<ÿjjÿÿKIÿIIñÿ„„ÿjmÿÿ55ÿecÿccÿîÿDBîÿžžÿÌÌÿ!!ÿ!ÿ}}ÿ..ÿ\\ÿŠŠÿ ÿ=;ÿ;;ÿƒ€ÿiiÿgiÿ——ÿÿFHÿ¤¤ÿÒÒÿ''ÿUUÿÿ•šÿÿ44ÿ|yÿ`bÿùÿÿÿ §ÿ[XÿUXÿÿƒ†ÿËËÿ ÿ ÿNNÿ||øöÿ--öÿ[[ÿ‰‰ÿ ÿ8:ÿhhÿ––ÿ¬­ÿ’–ÿÿÿGGÿuuÿ££ÿÑÑÿ&&ÿTTÿÿ{xÿaaÿ_aÿÿ@@ÿ¢œÿnnÿTWÿœœÿÿMMÿ©©»++ÿˆˆÿ ÿ99ÿ79ÿigÿggÿ••ÿÿHFÿFFÿttêÿmjÿQSÿÿ22ÿ02ÿb`ýÿ``ÿêêÿÿ??ÿ››ÿ ÿßàÿ,!þH° Áƒ*\¨«‡\FNM‰Æ" ›D ’SMŒ6ÐðXrCGNÚ¨k«‡EM‘åãÀÅMHVUé˜@ ´O%•dĩ̖vÔB†kŒDYz!RVGÄ*9sˆkô“šÍ-(Ã’BÒ4p6óG¯42®ŠqËc£ xH´›IË5’¾„ÈV–žp«²2íÏÇŸ%öšdj³¤„Ò!æÂ0‚4ê$YeÅ’cxJ ÑÒŒå™PL.È Q¦a›ª^­«€+^BYÒ ŒÉ«-‘ ¨4ËäVilªQ†Ô…XR¡&T f’þ?4R¸"¢U±äÑgj–¨¶©|+,—ÈÏ4WÀ ÓØõK+ÄGË1¡¨qÇ\0OØ" .¢dqD(±X° •ˆ!Œ#°„ ¨¼p`(£<£µ¨L¹ðG 6¨ðÁ–qä˜#,%ƒÉ ŘxL£PSÀ‚øÁ@H#%©¨ Á Nèt ¦°4 &¸Râ‰kÀ‚ÙMÙ¦(ˆÄe]¥°T€C˜p„ZÖµ¹ÖL`àVGNrÜÂR^L’ ^šÄ/L(‚ÙCcâ†,`X¤¦N,-ÒÅ.fìI_Λ.1gPY*KO,‹ø¤|À¬ñ ©µ\ Äð‰&›À’(¤ÄÒ…'[b’H¨µŠ9B$d’QžTq±äA ÅvÁƒ¡]H\ ŽÐSd<õÃgʰ$‰†  i¡ÐAâvaÔªÈ#БÑü€KÌÂnšršŒ nwF±Ý‰Ö%¼v–‡/±`ñÅg¬ñÆ ;hercules-3.12/html/images/redd.gif0000664000175000017500000000260512564723224014024 00000000000000GIF87a!çÿJLÿzzÿ)+ÿYYÿ‡‡ÿ™žÿ ÿ:8ÿ88ÿÿÿ_\ÿY\ÿ"$ÿRRÿPRÿ€€ÿÿ31ÿ11ÿa_ÿ__òÿÿÿXUÿ<>ÿššÿKKÿIKÿyyïÿ**ÿ(*ÿXXÿ ÿ ÿ77ÿ|ÿeeÿceÿ““ÿy|ÿ“Ž ÿ^[îÿBDÿrrÿ##ÿ!#ÿSQÿQQÿÿÿ20ýÿ00ýÿruÿ ÿWTÿ==ÿ;=ÿkkÿÿLJÿJJÿxxúÿ))ÿÿÿfdÿddÿ–’ÿ’’ÿx{÷ÿÿCCÿqqÿ$"ÿ""ÿRPÿPPÿ]]ÿ‹ÿ‹‹ÿ‡‹ÿ><ÿ<<ÿjjÿÿKIÿIIÿ*(ÿ„„ÿjmÿ–›ÿÿ55ÿecÿccÿÿDBÿ\YÿBBÿ@Bÿ#!ÿ!!ÿ}}ÿ..ÿ\\ëÿ ÿ=;ÿ;;ÿƒ€ÿgiÿ“—ÿÿFHÿ\_ÿ''ÿUUÿƒƒÿÿÿ44ÿ|yÿ`bÿùùÿÿÿ §ÿƒ†ÿ ÿ ÿNNÿ||ÿ--ÿ‰‰ÿ ÿ ÿ8:ÿhhÿ––ÿ|ÿGGõÿuuÿ[^ÿ&&ÿTTÿÿÿ13ÿ“ÿ_aÿ‹ÿÿB@ÿ@@ÿ¢œÿnnÿTWÿœœÿÿMM»++ÿtqÿŒˆÿˆˆÿ ÿ99ÿ79ÿigÿggþÿÿHFÿFFÿttÿmjÿÿb`ÿ``ÿÿ??ÿ ,!þH° Áƒ*\ØÊO VDöD1µ’ Âp¢ÒÈËD¿$‘ðtc‡¡'@ÌØŠ@ª¬†H4eqDpš±JÈ‚DèÄ*c#‡‘L^°¼âòa‡™\,b<ÂiÊ*=  `˜t “(YúÚDÀÇGDrÁ icˆŒô(H“aR‰$6lzÂ/9üÀ”¥Ô†fÜV æÊ/»xwbIË/Ÿ>~ÉØá‹ÞRaœC$Ÿ¾² Rɯœh@Ìņ&b¡9Éh„Uë¤X$°DÅZ‰/e«°ƒk¢ uRYå(ŸXò Þú/ì‡Dšþ›ª#Ò‘>nxg%e—¥&WÄñ ¨ð:örñvd™™çí Þs=ÆÒšÄÀÝ„00‚C÷±Ñ²¢$ôñc $ò K'¬P *»à‘}.YÁŠ3åšhWÍÅ/—8¡‹cÔ‚!|ЉrD`E­¸QO·°ô/px(wgXX*²y ³\ÔŸ…W±É"'+²TXÒdOœdð¶ŽNš10pà Uêeƒ’AßV4nòŒ²­C2!È!‚š,JÈÁÁ‰„+7ܼ©ÄN’52pqrDÏ¥JÑ8°a¤$8L¼éyUé"€x±@LŽQJ{v1ÆA‚#Ý !€JOBâÀq 1Ý'm¢D`“ )0az(è E&ÞEv°£ˆ=DÔÙ`¤Å» ?Kâ jUËžM»v¶@;hercules-3.12/html/images/interruptu.gif0000664000175000017500000000264712564723224015335 00000000000000GIF87a!çÿ¦¨ÿ)+ÿYYÿ‹‡ÿ‡‡ÿ ÿ:8ÿ88ÿÿõÿ¡¡ÿÏÏÿRRÿPRÿ€€ÿ®®ÿ31ÿ11ÿa_ÿ__ÿÿ¥¤òÿÿééÿÿ<>ÿ†ƒÿššÿÈÈÿIKÿyyÿ**ÿXXÿ ÿ ÿ|ÿeeÿ—“ÿceÿ““ÿy|Ž ÿ^[ÿBDÿrrÿЉÿ##ÿ!#ÿSQÿQQÿ›–ÿ•–ÿÿ20ÿ00ýÿŒŒÿˆŒÿWTÿ==ÿ;=ÿmkÿkkÿ™™ÿ‚ÿÿLJÿJJÿxxÿ+)ÿ))ÿ……ÿÿddÿ–’ÿbdÿ’’ÿx{ùÿÿCCÿqqÿ$"ÿ""ÿRPÿPPÿ–•ÿÿ]]ÿ‹ÿ‹‹ÿ‡‹ÿ¹¹ÿ<<ÿjjÿÿKIÿIIñÿ„„ÿjmÿÿ55ÿecÿccÿîÿDBîÿžžÿÌÌÿ!!ÿ!ÿ}}ÿ..ÿ\\ÿŠŠÿ ÿ=;ÿ;;ÿƒ€ÿiiÿgiÿ——ÿÿFHÿ¤¤ÿÒÒÿ''ÿUUÿÿ•šÿÿ44ÿ|yÿ`bÿùÿÿÿ §ÿ[XÿUXÿÿƒ†ÿËËÿ ÿ ÿNNÿ||øöÿ--öÿ[[ÿ‰‰ÿ ÿ8:ÿhhÿ––ÿ¬­ÿ’–ÿÿÿGGÿuuÿ££ÿÑÑÿ&&ÿTTÿÿ{xÿaaÿ_aÿÿ@@ÿ¢œÿnnÿTWÿœœÿÿMMÿ©©»++ÿˆˆÿ ÿ99ÿ79ÿigÿggÿ••ÿÿHFÿFFÿttêÿmjÿQSÿÿ22ÿ02ÿb`ýÿ``ÿêêÿÿ??ÿ››ÿ ÿßàÿ,!þÐÕÃ.#§¦D】„M"É©&Fhx ,¹¡# ' mŒ Ô5‚•Á"€¦ÈòqÀá&$«ªPL Ú§‡82âT殟vÔB†kLBYz!RVGÄ*9sˆkd“šÍ-(óS… =hà*2Lå^i&@\ãVÅFðh…5“¦®k*5y°¬,=Ò6deÚ‹6KÐíØ5ÔgA ‰5BÌÅ_i$ÔI²ÊŠ¥Ãñ”@£¥Y×3¡˜@ ù`Ê¿-'4}êVU<¼rv¥“W[ð5’2Pi–­­bØT£ ¢ u¥B+L¨Ì: 7hÄ/CD9 þªb©bMÑ]QQâ2$VX.uWù]­€A2¦½µÙu…zZÇ„¢ÆOpÁ ÿ†ƒÿššÿIKÿyyÿ**ÿXXÿ ÿ ÿ|ÿ—“ÿceÿy|Ž ÿ^[ÿBDÿrrÿX[ÿ##ÿ!#ÿSQÿQQÿ›–ÿÿ20ÿ00ýÿˆŒÿWTÿ==ÿ;=ÿkkÿ‚ÿÿLJÿJJÿxxÿ+)ÿ))ÿÿddÿ–’ÿ’’ÿx{ùÿÿCCÿqqÿ$"ÿ""ÿRPÿPPÿÿ]]ÿ‹ÿ‹‹ÿ‡‹ÿ<<ÿjjÿÿKIÿIIñÿ„„ÿjmÿÿ55ÿecÿccÿîÿDBîÿ!!ÿ!ÿ}}ÿ..ÿ\\ÿ ÿ=;ÿ;;ÿƒ€ÿgiÿÿFHÿ''ÿUUÿÿ•šÿÿ44ÿ|yÿ`bÿùÿÿÿ §ÿ[XÿUXÿÿƒ†ÿ ÿ ÿNNÿ||øöÿ--öÿ[[ÿ‰‰ÿ ÿ8:ÿhhÿ––ÿ’–ÿÿÿGGÿuuÿ&&ÿTTÿÿ{xÿaaÿ_aÿÿ@@ÿ¢œÿnnÿTWÿÿMM»++ÿˆˆÿ ÿ99ÿ79ÿigÿggÿÿHFÿFFÿttêÿmjÿQSÿÿ22ÿ02ÿb`ýÿ``ÿÿ??ÿ ÿ,!þØc&Œ†Àªpàƒ@Ôx‘%–Wc ð`ñ"ˆ [L Ü´á‘Ái†T’aÀa ŽŠPD äU¡n8Î4¥Ë¦Ÿb`B¥)JÂJ<½QFƒ#/_lˆ¢c³“­æ(˜òs„ 1Thº1Jå OW@tt"SE:Æp€„õ ®Y"5y°l¥2Ò6Uc$‹6;ÐíØõPWA׈ÅAŠÄßW„ÙáÈŸÃÇt°’¤U×*‡z@ ù`Ê¿-4}ê6Õ1rv½D#TIJðÅ‘–CWV­-bx ¢Ùt%réÉ!¬ 7ˆÃ/Ã7. þª)§bMÑ]Q§áòGHútWù]m5(b½µÙ5„úK§‚d&Ä‚|¤¨XZâ±¢Ô1AW~ÑH ^'‰`¢‚ •axkMtX]¥âG¥`xJ( ÄÙ}Há×Y™@L™Ø°HWz4àA$f˜Å$‘1PÔk"¾¡–Sm)ÒTÔàAÿøØ*I–JNÄL^dÒMè‘ DbH(=ÈÈšAQ¤ÁE%N4ôdL]ÉÁ'T˜áGE²§‡…AeHé¹VW?ȱĨÈâz¡d±a‡Gh"E‚xŽØ‚Ž]!’%L¤pš)’mࡤô)¥VW¬p*0¨9ä½ÅQR5fªt•Çm|àgš €a!uOd‡´†°ÌXWvX¬~šŠþQWŪqVŒ’ñÉO"Ôkï½øæ«¯½›ìëï¿÷ðÀû ;hercules-3.12/html/images/waitonu.gif0000664000175000017500000000076312564723224014577 00000000000000GIF87a%¥¦‚‚ŸŸŸ´¶”z\4&,üæD§¨€vK65ˆ|jr}r¦ƒ„\F$©sœz\¨u|lüþÔüþ¬ƒ\F¡{`“{füþ„}|nª}l˜pM«|fŒvDŒjDüâ4d^Düþ¤tF,§‚üþ|¬z\üþTD.$üÖTüö,¨|üÂTŒŽü¾Tª}jüÚ,¥…ü¶,ÿÿÿ<+/†|j©rùÿÿ¦ƒ†¿¿¿šz\¤†”üþ”üª$,%þ@€pH,ȤrÉl:™8B&•2ÅU†“y­CA”+pqÂìMœâºÑ)6­-½Ó,o®³‰]T‚o^kO‰Š‹FŽ‘’“”•–—˜™—3 š'% ™ %%%%*5%—.:%:ºº¸'”'¹¹&&)¸% ”ª¸+;Ç;+®´’' ¸1$!ÓÔ;$)æ’ª#/;Ò6;!!9è %ìí!íí$J@ ®Œ}ýþùCA`ÃmF”ˆ&/žÅæ@@ŒP‚GŠ(02¦íF 0È[Ø‚³J.\±ˆ‘¢æÌ9æ×²œ:ˆ¸Ä ›KfÍ4ÈéA£§§P£Z ;hercules-3.12/html/images/loadd.gif0000664000175000017500000000247712564723224014200 00000000000000GIF87a!çÿK¥ÿºÛÿ‹Æÿ7›ÿ¦ÑÿH£ÿm·ÿŒÿÜíÿ> ÿ>žÿˆÄÿ4™ÿ£ÑÿÈãÿO¨ÿ ÿj³ÿ;žÿ…ÂÿV«ÿV©ÿ€ÿL¦ÿ~ýq¸ÿÿ]®ÿ …ÿ?Ÿÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿ<ÿ†Áÿ«Õÿ †ÿ|¾ÿ|¼ÿ(“ÿ—Íÿ—Ëÿ²Úÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿe²ÿ‰ÿ€¿ÿG£ÿ¶Ùÿ\_¾)”ÿ˜ÊÿŽÇÿŠÿ„Âÿ0—ÿŸÏÿ€ÿÿÿf³ÿf±ÿ°×ÿ7œÿ¦Ôÿ¾ÿËäÿR«ÿR©ÿm¶ÿ·ÜÿÿˆÃÿ£ÎÿO§ÿãñÿ;ÿªÕÿÏçÿq¹ÿ–ËÿŽÿŒÆÿ]¯ÿ§Óÿ§Ñÿx¾ÿx¼ÿÎÿ$‘ÿ“Ëÿ“ÉÿŒÿ? ÿ®Úÿ‰Äÿ®Øÿ‰ÿ-+„Z­ÿZ«ÿ‚ÿuºÿ|ùÿÿÿW«ÿW©ÿC¡ÿ²×ÿJ¤ÿ”Êÿe³ÿŠÅÿˆÿ€Àÿ,•ÿv»ÿ›Ïÿv¹ÿ›ÍÿG¢ÿl¶ÿ‘Èÿ¶Üÿb±ÿb¯ÿ†ÿ}¾ÿ}¼ÿÇâÿN©ÿN§ÿi´ÿi²ÿ‹ÿØìÿ„Áÿ,!þH° Áƒ*\Èc‘C2Ü\xR;((q ÄO 28$ˆ„C…84ÈÈÊ£‡¼¼©ã¤â ; ®lìøq„H’*fÀ!¢åB/Åx31‚E;hNp@Ã#™Eá“èd–6@™ ¢ O 8õÄN«Xµ²1 ‡eG•!1­€‹Q§Ví™5›®,Ùˆ#vÌ¥+^ü •ªŸ œʲϢ0Œ]î}ƒ¶Ê_œW¦vÄ<‚Ë™­,+0aQ#4YDkžfà–#\.R"±œ2©Ï ÐËFD«v²F߬‹œaÙ¥A+Ä:êP)iЧþûîÉ¥  *ôQ$&´²j Ay vÌ •W“!Á²L‰êA¬WÃv’¼Ô„ $ñ‚#Yˆ!ˆx<‘Á’fü7E€ŠÅaÅD±Å(0â„CˆQjã±$…&tq¡gwi$ñuàqÓùùÁÒ€¸`F‹Öå ÈbÉÅÄ”_€¡(K)$‘®€äXeu°¤dmmÄÒTéCçYçYmb½„S5áÁeJ°”ÂQ Â"€}І–Þ5µÖ‰,­‘‚aŠðÂ)^ÐhMŽ<õK0¤a r(•F"7JIä„Zl±dÈ‚~ewš™aš&£Ñž, °ª)¨*&¢/fgÛ^nС›@mkì±È&«¬±;hercules-3.12/html/images/restartd.gif0000664000175000017500000000251612564723224014737 00000000000000GIF87a!çÿK¥ÿºÛÿ‹Æÿ°Öÿ7›ÿÁÿ¦ÑÿËåÿH£ÿm·ÿŒÿÜíÿ> ÿ>žÿˆÄÿ4™ÿ£ÑÿO¨ÿ ÿj³ÿ;žÿ…ÂÿªÔÿV«ÿV©ÿÅãÿ€ÿ~ýq¸ÿÿ]®ÿ …ÿ?Ÿÿ®×ÿÓéÿu»ÿšÏÿšÍÿ!ÿ!ŽÿÈÿÆÿµÚÿ<ÿ«Õÿ †ÿ|¾ÿ|¼ÿ¡Ðÿ(“ÿ—Íÿ—ËÿÆÿ²Úÿ^¯ÿ^­ÿ „ÿ/˜ÿy¾ÿy¼ÿ”Éÿe²ÿ‰ÿÔêÿ€¿ÿG£ÿ¶Ùÿ\_¾)”ÿ˜ÊÿâðÿŽÇÿŠÿ„Âÿ„Àÿ0—ÿŸÏÿ€ÿ•Êÿÿÿf³ÿf±ÿ°×ÿ7œÿ¦Ôÿ¾ÿR«ÿR©ÿw»ÿÁáÿm¶ÿÿˆÃÿ£ÎÿO§ÿãñÿ;ÿªÕÿÏçÿq¹ÿ–ËÿŽÿŒÆÿÖêÿ]¯ÿ]­ÿ§Óÿ§ÑÿÌåÿx¾ÿx¼ÿÎÿ$‘ÿ“Ëÿ“Éÿ¸ÛÿŒÿ? ÿ®Úÿ®Øÿ‰ÿ-+„Z­ÿZ«ÿ‚ÿuºÿ¿Þÿäòÿ|ùÚíÿ«ÔÿW«ÿW©ÿC¡ÿ²×ÿžÏÿJ¤ÿ”Êÿe³ÿˆÿ€Àÿ¥Òÿ,•ÿv»ÿ›Ïÿv¹ÿ›ÍÿG¢ÿl¶ÿ‘Èÿ¶Üÿb±ÿb¯ÿ†ÿ}¾ÿ}¼ÿN©ÿN§ÿi´ÿi²ÿ‹ÿ„Áÿ,!þH° Áƒ*\X¤ÂM9úhÐfÑD",X‰Ð$ÒŒ9>0äEˆ?: X¤K¨šÖø9”¥¢%DÆlìø…H’/tüyÒ¥‡K/5áð3q‚EDxZˆ°ÃãQ(qÄéd–’ÀÅAÀÄa”!G(o¤6K'p¸Bzv—]ˆò_dñÉ"79PYG,91 uÜh,–\LLù˜ŒM°$’L:i RŽUUJÖÖF,]†’G0ržužÕ&ÖK¸1UÓ"lQfK.\±e%6ømx‰é]Ska4Kz¸€Àš'ÔÐdPÆ×>šE(O‰ÀÒ yáÆš•Hê%”ÈE…Re¡[5,e’H£mliB p*š^ÞÞ, @Ĭ.ÔÊæ¤9fgÛ^}¢›@|D+í´ÔVk­´;hercules-3.12/html/include/0000775000175000017500000000000012625667404012657 500000000000000hercules-3.12/html/include/header.htmlpart0000664000175000017500000000006512564723224015600 00000000000000 Hercules hercules-3.12/html/include/footer.htmlpart0000664000175000017500000000002012564723224015635 00000000000000 hercules-3.12/html/Makefile.in0000664000175000017500000004436312625667166013240 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = html DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/mkinstalldirs \ $(dist_images_pkgdata_DATA) $(dist_include_pkgdata_DATA) \ $(dist_pkgdata_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(images_pkgdatadir)" \ "$(DESTDIR)$(include_pkgdatadir)" "$(DESTDIR)$(pkgdatadir)" DATA = $(dist_images_pkgdata_DATA) $(dist_include_pkgdata_DATA) \ $(dist_pkgdata_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ dist_pkgdata_DATA = cckddasd.html fishgui.html hercconf.html hercfaq.html \ hercinst.html herclic.html hercload.html hercmsca.html hercmscf.html \ hercmscp.html hercmsct.html hercmscu.html hercmsda.html hercmsdc.html \ hercmsdg.html hercmsdi.html hercmsdl.html hercmsds.html hercmsdt.html \ hercmsdu.html hercmsg.html hercmshd.html hercmshe.html hercmshg.html \ hercmshm.html hercmsht.html hercmshu.html hercmsif.html hercmsin.html \ hercmslc.html hercmslg.html hercmspn.html hercmspr.html hercmspu.html \ hercmsrd.html hercmssd.html hercmsta.html hercmstc.html hercmste.html \ hercmstm.html hercmsts.html hercmstt.html hercmstu.html hercmsvm.html \ hercnew.html hercrdr.html hercrnot.html hercsupp.html herctcp.html \ hercules.html index.html shared.html tasks.html hercules.css include_sources = include/header.htmlpart include/footer.htmlpart include_pkgdatadir = $(pkgdatadir)/include dist_include_pkgdata_DATA = $(include_sources) images_sources = images/loadoffu.gif images/restartu.gif \ images/back.gif images/loadonu.gif images/startd.gif \ images/bkued.gif images/loadu.gif images/startu.gif \ images/blueu.gif images/manoffu.gif images/stopd.gif \ images/dial1.gif images/manonu.gif images/stopu.gif \ images/dial2.gif images/note.gif images/stored.gif \ images/dial3.gif images/osi-certified-60x50.jpg images/storeu.gif \ images/dial4.gif images/poweroffd.gif images/sysoffu.gif \ images/favicon.ico images/poweroffu.gif images/sysonu.gif \ images/greend.gif images/poweronoffd.gif images/translucentoffd.gif \ images/greenu.gif images/poweronoffu.gif images/translucentoffu.gif \ images/hercpic-rblk-256.gif images/poweronond.gif images/translucentond.gif \ images/hercpic-rblk-80.gif images/powerononu.gif images/translucentonu.gif \ images/interruptd.gif images/redd.gif images/waitoffu.gif \ images/interruptu.gif images/redu.gif images/waitonu.gif \ images/loadd.gif images/restartd.gif images_pkgdatadir = $(pkgdatadir)/images dist_images_pkgdata_DATA = $(images_sources) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu html/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu html/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_images_pkgdataDATA: $(dist_images_pkgdata_DATA) @$(NORMAL_INSTALL) @list='$(dist_images_pkgdata_DATA)'; test -n "$(images_pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(images_pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(images_pkgdatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(images_pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(images_pkgdatadir)" || exit $$?; \ done uninstall-dist_images_pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_images_pkgdata_DATA)'; test -n "$(images_pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(images_pkgdatadir)'; $(am__uninstall_files_from_dir) install-dist_include_pkgdataDATA: $(dist_include_pkgdata_DATA) @$(NORMAL_INSTALL) @list='$(dist_include_pkgdata_DATA)'; test -n "$(include_pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(include_pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(include_pkgdatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(include_pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(include_pkgdatadir)" || exit $$?; \ done uninstall-dist_include_pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_include_pkgdata_DATA)'; test -n "$(include_pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(include_pkgdatadir)'; $(am__uninstall_files_from_dir) install-dist_pkgdataDATA: $(dist_pkgdata_DATA) @$(NORMAL_INSTALL) @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done uninstall-dist_pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(images_pkgdatadir)" "$(DESTDIR)$(include_pkgdatadir)" "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_images_pkgdataDATA \ install-dist_include_pkgdataDATA install-dist_pkgdataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_images_pkgdataDATA \ uninstall-dist_include_pkgdataDATA uninstall-dist_pkgdataDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_images_pkgdataDATA \ install-dist_include_pkgdataDATA install-dist_pkgdataDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am \ uninstall-dist_images_pkgdataDATA \ uninstall-dist_include_pkgdataDATA uninstall-dist_pkgdataDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/html/Makefile.am0000664000175000017500000000425612564723224013212 00000000000000dist_pkgdata_DATA = cckddasd.html fishgui.html hercconf.html hercfaq.html \ hercinst.html herclic.html hercload.html hercmsca.html hercmscf.html \ hercmscp.html hercmsct.html hercmscu.html hercmsda.html hercmsdc.html \ hercmsdg.html hercmsdi.html hercmsdl.html hercmsds.html hercmsdt.html \ hercmsdu.html hercmsg.html hercmshd.html hercmshe.html hercmshg.html \ hercmshm.html hercmsht.html hercmshu.html hercmsif.html hercmsin.html \ hercmslc.html hercmslg.html hercmspn.html hercmspr.html hercmspu.html \ hercmsrd.html hercmssd.html hercmsta.html hercmstc.html hercmste.html \ hercmstm.html hercmsts.html hercmstt.html hercmstu.html hercmsvm.html \ hercnew.html hercrdr.html hercrnot.html hercsupp.html herctcp.html \ hercules.html index.html shared.html tasks.html hercules.css include_sources = include/header.htmlpart include/footer.htmlpart include_pkgdatadir = $(pkgdatadir)/include dist_include_pkgdata_DATA = $(include_sources) images_sources = images/loadoffu.gif images/restartu.gif \ images/back.gif images/loadonu.gif images/startd.gif \ images/bkued.gif images/loadu.gif images/startu.gif \ images/blueu.gif images/manoffu.gif images/stopd.gif \ images/dial1.gif images/manonu.gif images/stopu.gif \ images/dial2.gif images/note.gif images/stored.gif \ images/dial3.gif images/osi-certified-60x50.jpg images/storeu.gif \ images/dial4.gif images/poweroffd.gif images/sysoffu.gif \ images/favicon.ico images/poweroffu.gif images/sysonu.gif \ images/greend.gif images/poweronoffd.gif images/translucentoffd.gif \ images/greenu.gif images/poweronoffu.gif images/translucentoffu.gif \ images/hercpic-rblk-256.gif images/poweronond.gif images/translucentond.gif \ images/hercpic-rblk-80.gif images/powerononu.gif images/translucentonu.gif \ images/interruptd.gif images/redd.gif images/waitoffu.gif \ images/interruptu.gif images/redu.gif images/waitonu.gif \ images/loadd.gif images/restartd.gif images_pkgdatadir = $(pkgdatadir)/images dist_images_pkgdata_DATA = $(images_sources) hercules-3.12/html/cckddasd.html0000664000175000017500000010641112564723224013600 00000000000000 Hercules: Compressed Dasd Emulation

Compressed Dasd Emulation


Contents


Introduction

Using compressed DASD files you can significantly reduce the file space required for emulated DASD files and possibly gain a performance boost because less physical I/O occurs. Both CKD (Count-Key-Data) and FBA (Fixed-Block-Architecture) emulation files can be compressed.

In regular (or uncompressed) files, each CKD track or FBA block occupies a specific spot in the emulation file. The offset of the track or block in the file can be directly calculated knowing the track or block number and the maximum size of the track or block. In compressed files, each track image or group of blocks may be compressed by zlib or bzip2, and only occupies the space neccessary for the compressed image. The offset of a compressed track or block is obtained by performing a two-table lookup. The lookup tables themselves reside in the emulation file.

Because FBA blocks are 512 bytes in length, and that being a rather small number, FBA blocks are grouped into block groups. Each block group contains 120 FBA blocks (60K).

Whenever a track or block group is written to a compressed file, it is written either to an existing free space within the file, or at the end of the file, then the lookup tables are updated, and then the space the track or block group previously occupied is freed. The location of a track or block group in the file can change many times.

In the event of a failure (for example, Hercules crash, operating system crash or power failure), the compressed emulation file on the host's physical disk may be out of sync if the host operating system defers physical writes to the file system containing the emulation file. Several methods have evolved to reduce the amount of data lost in these kind of events.

A compressed file may occupy only 20% of the disk space required by an uncompressed file. In other words, you may be able to have 5 times more emulated volumes using compressed DASD files. However, compressed files are more sensitive to failures and corruption may occur.


Shadow Files

An compressed CKD or FBA dasd can have more than one physical file. The additional files are called shadow files. The function is implemented as a kind of snapshot, where a new shadow file can be created on demand. An emulated dasd is represented by a base file and 0 or more shadow files. All files are opened read-only except for the current file, which is opened read-write.

Shadow files are specified by the sf=shadow-file-name parameter on the device statement for the compressed DASD device.

Please note that the specified shadow filename does not have to actually exist. The shadow-file-name operand of the sf= parameter is simply a filename template that will be used to name the shadow file whenever a shadow file is to be created, but shadow files do not actually get created until you specifically create them via the sf+xxxx (or sf+*) command. Please refer to the discussion of the sf command several paragraphs below for more information.

The shadow file name should have spot where the shadow file number will be set. This is either the character preceding the last period after the last slash or the last character if there is no period. For example:

0100 3390 disks/linux1.dsk sf=shadows/linux1_*.dsk

There can be up to 8 shadow files in use at any time for an emulated dasd device. The base file is designated file[0] and the shadow files are file[1] to file[8]. The highest numbered file in use at a given time is the current file, where all writes will occur. Track reads start with the current file and proceed down until a file is found that actually contains the track image.

A shadow file contains all the changes made to the emulated dasd since it was created, until the next shadow file is created. The moment of the shadow file's creation can be thought of as a snapshot of the current emulated dasd at that time, because if the shadow file is later removed, then the emulated dasd reverts back to the state it was at when the snapshot was taken.

Using shadow files, you can keep the base file on a read-only device such as cdrom, or change the base file attributes to read-only, ensuring that this file can never be corrupted.

Hercules console commands are provided to add a new shadow file, remove the current shadow file (with or without backward merge), compress the curent shadow file, and display the shadow file status and statistics:

sf+ unit Create a new shadow file
sf- unit merge
nomerge
force
Remove a shadow file. If merge is specified or defaulted, then the contents of the current file is merged into the previous file, the current file is removed, and the previous file becomes the current file. The previous file must be able to be opened read-write. If nomerge is specified then the contents of the current file is discarded and the previous file becomes the current file. However, if the previous file is read-only, then a new shadow file is created (re-added) and that becomes the current file. The force option is required when doing a merge to the base file and the base file is read-only because the ro option was specified on the device config statement.
sfc unit Compress the current file
sfk unit level Perform the chkdsk function on the current file. Level is a number -1 ... 4, the default is 2. The levels are:
-1     devhdr, cdevhdr, l1 table
  0     devhdr, cdevhdr, l1 table, l2 tables
  1     devhdr, cdevhdr, l1 table, l2 tables, free spaces
  2     devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkhdrs
  3     devhdr, cdevhdr, l1 table, l2 tables, free spaces, trkimgs
  4     devhdr, cdevhdr. Build everything else from recovery
sfd unit Display shadow file status and statistics

Note. You can use * in place of unit address to apply the command to all compressed dasd (e.g. 'sf+*', or 'sf-* nomerge').


Compressed DASD File Structure

A compressed DASD file has 6 types of spaces, a device header, a compressed device header, a primary lookup table, secondary lookup tables, track or block group images, and free spaces. The first 3 types only occur once, at the beginning of the file in order. The rest of the file is occupied by the other 3 space types.

The first 512 bytes of a compressed DASD file contains a device header. The device header contains an eye-catcher that identifies the file type (CKD or FBA and base or shadow). The device type and file size is also specified in this header. The header is identical to the header used for uncompressed CKD files, except for the eye-catcher:

devid heads trksize
devt seq hicyl  


reserved


The next 512 bytes contains the compressed device header. This contains file usage information such as the amount of free space in the file:

vrm opts numl1 numl2 size
used ->free free largest
number   cyls   comp parm


reserved


After the compressed device header is the primary lookup table, also called the level 1 table or l1tab. Each 4 byte unsigned entry in the l1tab contains the file offset of a secondary lookup table or level 2 table or l2tab. The track or block group number being accessed divided by 256 gives the index into the l1tab. That is, each l1tab entry represents 256 tracks or block groups. The number of entries in the l1tab is dependent on the size of the emulated device:

l20 l21 l22 l23
l24 l25 l26 l27


.     .     .


l2n-4 l2n-3 l2n-2 l2n-1

Following the l1tab, in no particular order, are l2tabs, track or block group images, and free spaces.

Each secondary lookup table (or l2tab), contains 256 8-byte entries. The entry is indexed by the remainder of the track or block group number divided by 256. Each entry contains an unsigned 4 byte offset, an unsigned 2 byte length and an unsigned 2 byte size. The length is the space required for the track or block group image and the size is the amount of space actually used. The size may be greater than the length to prevent short free spaces from accumulating in the file.

0  ->image         length size
1  ->image         length size

.     .    .

255  ->image         length size

A track or block group image contains two fields, a 5-byte header and a variable amount of data that may or may not be compressed. The length in the l2tab entry includes the length of the header and the data.

hdr track or block group data

The 5 byte header contains a 1 byte compression indicator and 4 bytes that identify the track or block group. The format of the identifier depends on whether the emulated device is CKD or FBA:

CKD hdr
comp CC   HH  

The 2 byte CC is the cylinder number for the track image and the HH is the head number. These numbers are stored in big-endian byte order. When the compression indicator byte is zeroed, the 5 byte header is identical to the Home Address (or HA) for the track image. The data, which may or may not be compressed, begins with the R0 count and ends with the end-of-track (or eot) marker, which is a count field containing FFFFFFFFFFFFFFFF. The HA plus the uncompressed track data comprise the track image.

FBA hdr
comp nnnn        

The 4 byte nnnn field is the FBA block group number in big-endian byte order. The data contains 120 FBA blocks, which may or may not be compressed. Uncompressed, the FBA block group is 60K. The header for FBA, unlike CKD, is not used as part of the uncompressed image.

The compression indicator byte contains the value 0, 1 or 2. Any other value is invalid.
0
    Data is uncompressed
1
    Data is compressed using zlib
2
    Data is compressed using bzip2
3 .. 255    Not valid

Free space contains a 4-byte offset to the next free space, a 4-byte length of the free space, and zero or more bytes of residual data:

->next length    residual   

The minimum length of a free space is 8 bytes. The free space chain is ordered by file offset and no two free spaces are adjacent. The compressed device header contains the offset to the first free space. The chain is terminated when a free space has zero offset to the next free space. The free space chain is read when the file is opened for read-write and written when the file is closed; while the file is opened, the free space chain is maintained in storage.


How It Works

Reading

A track or block group image is read while executing a channel program or by the readahead thread. An image has to be read before it is updated or written to. An image may be cached. If an image is cached, then the channel program may complete synchronously. This means that if all the data a channel program accesses is cached and Hercules does not have to perform physical I/O, then the channel program runs synchronously within the SSCH or SIO instruction in the CPU thread. All DASD channel programs are started synchronously. If a CCW in the channel program requires physical I/O then the channel program is interrupted and restarted at that CCW asynchronously in a device I/O thread.

All compressed devices share a common cache; the devices can be a mixture of FBA and/or CKD device types. Each cache entry contains a pointer to a 64K buffer containing an uncompressed track or block group image. If the track or block group image being read is not found in the cache, then the oldest (or least recently used or LRU) entry that is not busy is stolen. A cache entry is busy if it is being read, or last accessed by an active channel program, or updated but not yet written, or being written. If no cache entries are available then the read must enter a cache wait. When images are detected to be accessed sequentially then the readahead thread(s) may be signalled to read following sequential images.

Writing

When a cache entry is updated or written to, a bit is turned on indicating the cache entry has been updated. When a cache wait occurs, or (more likely) during space recovery, a cache flush is performed. When the cache is flushed, if any entries have the updated bit on, then the writer thread(s) are signalled. The writer thread selects the oldest cache entry with the updated bit on, compresses the image, and writes it to the file. The new image is written to a new space in the file and then the space previously occupied by the image is freed. In certain circumstances, the image may be written under stress. A stress write occurs when a reading thread is in a cache wait or when a high percentage of cache entries are pending write. In this circumstance, the compression parameters are relaxed to reduce the CPU requirements. An image written under stress is likely to take up more space than the same image written not under stress. The writer thread(s) run 1 nicer than the CPU thread(s); compression is a CPU intensive activity.

Space Recovery

Space recovery is also called, somewhat inaccurately, garbage collection. The primary function of the space recovery thread, or garbage collector, is to keep the emulated compressed DASD files as small as possible. After all, that is the reason for using compressed DASD files in the first place.

When a track or block group image is written, it is written to a new location in the file. It is either written to an existing free space within the file or to the end of the file, increasing the size of the file. The space previously occupied by the image is freed, but it is not immediately available for space allocation requests. Instead, it is pending free space. It is assigned a pending value (typically 2) that is decremented each space recovery cycle (typically every 10 seconds). When the pending value reaches 0 then the space is available for allocation. This increases the chance that a track or block group image can be recovered in the event of a failure.

The space recovery routine relocates track or block group images towards the beginning of the file, causing free space to move towards the end of the file. When a free space reaches the end of the file, it `falls off', that is, the file size is reduced.

Simply, the space recovery routine selects a space after a sufficiently large non-pending free space. It then reads and writes consecutive spaces using the normal cckd read and write routines. The space read will become pending free space and will hopefully be written to a non-pending free space occurring earlier in the file. Sometimes it is necessary to write the space later in the file to increase free space size earlier in the file. Left to itself, the space recovery routine will eventually remove all free space from the file. However, it is not intended to be a replacement for the cckdcomp utility; rather, the intent is to provide sufficient free space to prevent excessive file growth.

Another function performed by space recovery is to relocate L2 (secondary lookup) tables towards the beginning of the file. This enables the chkdsk function to complete more quickly during initialization and simplifies chkdsk recovery.


The cckd command and initialization statement

The cckd command and initialization statement can be used to affect cckd processing. The CCKD initialization statement is specified as a Hercules configuration file statement and supports the same options as the cckd command explained below.

Syntax:
cckdhelpDisplay cckd help
cckdstats Display current cckd statistics
cckdoptsDisplay current cckd options
cckdopt=valueSet a cckd option
  Multiple options may be specified, separated by a comma with no intervening blanks.
 comp=nCompression to be used
 compparm=nCompression parameter to be used
 ra=nNumber readahead threads
 raq=nReadahead queue size
 rat=nNumber of tracks to readahead
 wr=nNumber writer threads
 gcint=nGarbage collection interval
 gcparm=nGarbage collection parameter
 nostress=nTurn stress writes on or off
 freepend=nSet the free pending value
 fsync=nTurn fsync on or off
 trace=nNumber of trace table entries
 linuxnull=nCheck for null linux tracks
 gcstart=nStart garbage collector

Options:
comp=n Compression type:
-1 Default
  0 None
  1 zlib
  2 bzip2

Override the compression used for all cckd files. -1 (default) means don't override the compression.

compparm=n Compression parameter. A value between -1 and 9. -1 means use the default parameter. A higher value generally means more compression at the expense of cpu and/or storage.

ra=n Number of readahead threads. When sequential track or block group access is detected, some number (rat=) of tracks or block groups are queued (raq=) to be read by one of the readahead threads.

The default is 2.

You can specify a number between 1 and 9.

raq=n Size of the readahead queue. When sequential track or block group access is detected, some number (rat= ) of tracks or block groups are queued in the readahead queue.

The default is 4.

You can specify a number between 0 and 16 (a value of zero disables readahead).

rat=n Number of tracks or block groups to read ahead when sequential access has been detected.

The default is 2.

You can specify a number between 0 and 16 (a value of zero disables readahead).

wr=n Number of writer threads. When the cache is flushed updated cache entries are marked write pending and a writer thread is signalled. The writer thread compresses the track or block group and writes the compressed image to the emulation file. A writer thread is cpu-intensive while compressing the track or block group and i/o-intensive while writing the compressed image. The writer thread runs one nicer than the CPU thread(s).

The default is 2.

You can specify a number between 1 and 9.

gcint=n Number of seconds the garbage collector thread waits durinng an interval. At the end of an interval, the garbage collector performs space recovery, flushes the cache, and optionally fsyncs the emulation file. (However, the file will not be fsynced unless at least 5 seconds have elapsed since the last fsync).

The default is 10 seconds.

You can specify a number between 1 and 60.

gcparm=n A value affecting the amount of data moved during the garbage collector's space recovery routine. The garbage collector determines an amount of space to move based on the ratio of free space to used space in an emulation file, and on the number of free spaces in the file. (The garbage collector wants to reduce the free space to used space ratio and the number of free spaces). The value is logarithmic; a value of 8 means moving 28 the selected value while a negative value similarly decreases the amount to be moved. Normally, 256K will be moved for a file in an interval. Specifying a value of 8 can increase the amount to 64M. At least 64K will be moved. Interestingly, specifying a large value (such as 8) may not increase the garbage collection efficiency correspondingly.

The default is 0.

You can specify a number between -8 and 8.

nostress= Indicates whether stress writes will occur or not. A track or block group may be written under stress when a high percentage of the cache is pending write or when a device i/o thread is waiting for a cache entry. When a stressed write occurs, the compression algorithm and/or compression parm may be relaxed, resulting in faster compression but usually a larger compressed image. If nostress is set to one, then a stressed situation is ignored. You would typically set this value to one when you want create the smallest emulation file possible in exchange for a possible performance degradation.

The default is 0.

You can specify 0 (enable stressed writes) or 1 (disable stressed writes).

freepend= Specifies the free pending value for freed space. When a track or block group image is written the space it previously occupied is freed. This space will not be available for future allocations until n garbage collection intervals have completed. In the event of a catastrophic failure, previously written track or block group images should be recoverable if the current image has not yet been written to the physical disk. By default the value is set to -1. This means that if fsync is specified then the value is 1 otherwise it is 2. If 0 is specified then freed space is immediately available for new allocations.

The default is -1.

You can specify a number between -1 and 4.

fsync= Enables or disables fsync. When fsync is enabled, then the disk emulation file is synchronized with the physical hard disk at the end of a garbage collection interval (however, no more often than 5 seconds). This means that if freepend is non-zero then if a catastrophic error occurs then the emulated disks should be recovered coherently. However, fsync may cause performance degradation depending on the host operating system and/or the host operating system level.

The default is 0 (fsync disabled).

You can specify 0 (disable fsync) or 1 (enable fsync).

trace= Number of cckd trace entries. You would normally specify a non-zero value when debugging or capturing a problem in cckd code. When the problem occurs, you should enter the k Hercules console command which will print the trace table entries.

The default is 0.

You can specify a number between 0 and 200000. Each entry represents 128 bytes. Normally, for debugging, I use 100000.

linuxnull= If set to 1 then tracks written to 3390 cckd volumes that were initialized with the -linux option will be checked if they are null (that is, if all 12 4096 byte user records contain zeroes). This is used by the dasdcopy utility.

The default is 0.

gcstart= If set to 1 then space recovery will become active on any emulated disks that have free space. Normally space recovery will ignore emulated disks until they have been updated.

The default is 0.


Utilities

ckd2cckd  
cckd2ckd  
fba2cfba  
cfba2fba  
These utilities are deprecated. Use the dasdcopy utility instead

cckdcdsk   [-v] [-f] [-ro] [-level] filename1 [filename2 ...]
  Check the integrity of one or more compressed files. Recover damaged files.
 
-v   Display version and exit.
-f   Perform check even if the OPENED bit is on.
-ro   Open the file(s) read-only. The file will not be updated.
-level   A number 1 .. 4 indicating the level of checking.
1 Minimal checking (default)
2 Medium checking. All track headers will be read.
3 Maximal checking. All track images will be read and uncompressed.
4 Recover everything

cckdcomp   [-v] [-f] [-level] filename1 [filename2 ...]
  Remove all free space from a compressed file or files.
 
-v   Display version and exit.
-f   Perform compress even if the OPENED bit is on.
-level   A number 1 .. 3 indicating the chkdsk level.

cckdswap   [-v] [-f] [-level] filename1 [filename2 ...]
  Change the endianess or byte-order of a compressed file or files
 
-v   Display version and exit.
-f   Perform swap even if the OPENED bit is on.
-level   A number 1 .. 3 indicating the chkdsk level.


Greg Smith gsmith@nc.rr.com


back

Last updated $Date$ $Revision$

hercules-3.12/html/fishgui.html0000664000175000017500000000725012564723224013477 00000000000000
Dial 1 Dial 2 Dial 3 Dial 4
Sys Man Wait Load
hercules-3.12/html/hercconf.html0000664000175000017500000046345012564723224013640 00000000000000 Hercules Version 3: Configuration File

Hercules Version 3: Configuration File

This page describes the configuration file for the Hercules S/370, ESA/390, and z/Architecture emulator.

The configuration file hercules.cnf contains the processor and device layout. It is roughly equivalent to the IOCDS on a real System/390. The configuration file is an ASCII text file.

Example configuration file

Please note that the below example configuration file should not be considered a good example of what an actual configuration file looks like. It is only meant to illustrate what some of the supported configuration file statements look like and how they are used.




    ####################################################################
    #                HERCULES EMULATOR CONTROL FILE                    #
    #             (Note: not all parameters are shown)                 #
    ####################################################################


    #
    #     System parameters
    #


    ARCHMODE   ESA/390
    OSTAILOR   OS/390
    LOADPARM   0120....

    CPUSERIAL  000611
    CPUMODEL   3090
    CPUVERID   FD
    LPARNAME   HERCULES
    LPARNUM    21
    MODEL      EMULATOR
    PLANT      ZZ
    MANUFACTURER HRC
    MAINSIZE   64
    XPNDSIZE   0
    NUMCPU     1
    NUMVEC     1
    MAXCPU     8
    ENGINES    CP
    SYSEPOCH   1900
    YROFFSET   -28
    TZOFFSET   -0500

    HTTPROOT   /usr/local/share/hercules/
    HTTPPORT   8081 NOAUTH

    CCKD       RA=2,RAQ=4,RAT=2,WR=2,GCINT=10,GCPARM=0,NOSTRESS=0,TRACE=0,FREEPEND=-1
    SHRDPORT   3990

    PANTITLE   "My own private MAINFRAME!"
    PANRATE    FAST
    LOGOPT     TIMESTAMP
    CODEPAGE   default
    CNSLPORT   3270
    CONKPALV   (3,1,10)
    LEGACYSENSEID   OFF

    HERCPRIO   0
    TODPRIO    -20
    DEVPRIO    8
    CPUPRIO    15

    TIMERINT   DEFAULT
    TODDRAG    1.0
    DEVTMAX    8

    DIAG8CMD   disable
    SHCMDOPT   disable

    DEFSYM     TAPEDIR   "$(HOME)/tapes"
    AUTOMOUNT  $(TAPEDIR)
    AUTOMOUNT  +/tapes
    AUTOMOUNT  -/tapes/vault

    MODPATH    /usr/local/hercules
    LDMOD      dyncrypt

    PGMPRDOS   restricted
    ECPSVM     no
    ASN_AND_LX_REUSE  disable

    AUTO_SCSI_MOUNT      no
    MOUNTED_TAPE_REINIT  allow

    INCLUDE    mydevs.cfg
    IGNORE     INCLUDE_ERRORS
    INCLUDE    optdevs.cfg


    #
    #     Device statements
    #


    0009      3215-C  /

    000A      1442    adrdmprs.rdr
    000C      3505    jcl.txt     ascii  trunc
    000D      3525    pch00d.txt  ascii
    000E      1403    prt00e.txt  noclear
    001E      1403    192.168.200.1:1403 sockdev

    001F      3270    * 192.168.0.1
    0200.4    3270    * 192.168.0.0  255.255.255.0
    0220.8    3270    GROUP1  192.168.100.0  255.255.255.0
    0228.8    3270    GROUP2
    0230.16   3270

    0000      SYSG    SYSGCONS

    0120      3380    ${DASD_PATH=dasd/}mvsv5r.120
    0121      3380    ${DASD_PATH=dasd/}mvsv5d.121
    0122      3380    ${DASD_PATH=dasd/}mvswk1.122
    0123      3380    192.168.1.100

    0140      3370    dosres.140
    0141      3370    syswk1.141
    0300      3370    sysres.300

    0400      CTCT    30880  192.168.100.2  30880  2048      
    0401      CTCT    30881  192.168.100.2  30881  2048
    0420.2    CTCI    192.168.200.1  192.168.200.2
    0440.2    LCS     -n   /dev/net/tun   192.168.200.2
    0E40      CTCE    31880  192.168.1.202  32880
    0E41      CTCE    31882  192.168.1.202  32882

    0580      3420    /dev/nst0   # SCSI  (Linux or Windows)
    0581      3420    \\.\Tape0   # SCSI  (Windows only)
    0582      3420    ickdsf.aws  noautomount
    0583      3420    /cdrom/tapes/uaa196.tdf
    0584-0587 3420    $(TAPEDIR)/volumes.$(CUU) maxsizeM=170 eotmargin=131072

    0590      3480    /dev/nst0 --no-erg --blkid-32   # Quantum DLT SCSI

    0023      2703    lport=3780 rhost=localhost rport=3781 dial=no
    00C3      2703     lport=32003 dial=IN tty=1


Comment lines

Blank lines, and lines beginning with a # sign or an asterisk, are treated as comments.


System parameters

System parameters may appear in any order but they must precede all device statements. Each system parameter must be on a separate line. The following system parameters may be specified:

ARCHMODE   S/370 | ESA/390 | z/Arch | ESAME

specifies the initial architecture mode:

  • use S/370 for OS/360, VM/370, and MVS 3.8.
  • use ESA/390 for MVS/XA, MVS/ESA, OS/390, VM/ESA, VSE/ESA, Linux/390, and ZZSA.
  • use z/Arch or ESAME for z/OS and zLinux.

ESAME is a synonym for z/Arch. When z/Arch or ESAME is specified, the machine will always IPL in ESA/390 mode, but is capable of being switched into z/Architecture mode after IPL. This is handled automatically by all z/Architecture operating systems.

ASN_AND_LX_REUSE   DISABLE | ENABLE

specifies that the ASN-and-LX-Reuse Facility (ALRF) is to be disabled or enabled. The default is disabled. This is a z/Architecture-only feature (it is always disabled for S/390 or ESA/390). Set this to ENABLE  if the operating system supports this z/Architecture feature and the use of this feature is desired. Set it to DISABLE  or do not specify anything if the operating system doesn't support this feature, and it inadvertently sets CR0 bit 44 to 1, usually leading to unexpected program interrupt when instructions such as LASP are issued.

ASN_AND_LX_REUSE may be abbreviated as ALRF

AUTOMOUNT   [±]directory

specifies the host system directory where the guest is allowed or not allowed to automatically load virtual tape volumes from. Prefix allowable directories with a '+' plus sign and unallowable directories with a '-' minus sign. The default prefix if neither is specified is the '+' plus sign (i.e. an allowable directory).

Caution:  Enabling this feature may have security consequences depending on which allowable host system directories you specify as well as how your guest operating system enforces authorized use of the Set Diagnose (X'4B') channel command code.

All host system virtual tape volumes to be "automounted" by the guest must reside within one of the specified allowable host system directories or any of its subdirectories while not also being within any of the specified unallowable directories or any of their subdirectories, in order for the guest-invoked automount to be accepted.

Note: specifying a disallowed automount directory does not preclude the Hercules operator from manually mounting any desired file via the devinit panel command -- even one in a currently defined "disallowed" automount directory. The AUTOMOUNT statement only controls guest-invoked automatic tape mounts and not manual tape mounts performed by the Hercules operator.

All directories must be specified on separate statements, but as many statements as needed may be specified in order to describe the desired allowable/unallowable directories layout. For convenience, an automount panel command is also provided to dynamically add/remove new/existing allowable/unallowable automount directories at any time.

The automount feature is activated whenever you specify at least one allowable or unallowable directory. If only unallowable directories are specified, then the current directory becomes the only defined allowable automount directory by default.

All specified directories are always resolved to fully-qualified absolute directory paths before being saved.

Refer to the description of the virtual tape device 'noautomount' option for more information.

AUTO_SCSI_MOUNT   NO | YES | nn

specifies whether automatic detection of SCSI tape mounts are to be enabled or not.

Specifying NO or 0 seconds (the default) indicates the option is disabled, forcing all SCSI tape mounts to be done manually via an appropriate devinit command.

A value from 1 to 99 seconds inclusive enables the option and causes periodic queries of the SCSI tape drive to automatically detect when a new tape is mounted. Specifying YES  is the same as specifying 5 seconds, the current default interval.

The scsimount panel command may also be used to display and/or modify this value on demand once Hercules has been started. Note too that the scsimount panel command also lists any mounts and/or dismounts that may still be pending on the drive, as long as you've defined your tape drive as a model that has an LCD "display" (such as a model 3480, 3490 or 3590).

Note:  enabling this option may cause Hercules to take longer to shutdown depending on the value specified for this option as well as how the host operating system (Windows, Linux, etc) and associated hardware (SCSI adapter) behaves to drive status queries for drives which do not have any media currently mounted on them.

CCKD   cckd-parameters

The CCKD command and initialization statement can be used to affect cckd processing. The CCKD initialization statement is specified as a Hercules configuration file statement and supports the same options as the cckd panel command. Refer to the Compressed Dasd Emulation web page for more information.

CODEPAGE   mapping

specifies the codepage conversion mapping table used for ASCII/EBCDIC translation.

default specifies traditional Hercules codepage mapping.

Other supported codepage mappings are:

Mapping Description
ASCII EBCDIC
437/037 437 PC United States 037 United States/Canada
437/500 437 PC United States 500 International
437/1047 437 PC United States 1047 Open Systems Latin 1
819/037 819 ISO-8859-1 037 United States/Canada
819/037v2 819 ISO-8859-1 037 United States/Canada version 2
819/273 819 ISO-8859-1 273 Austria/Germany
819/277 819 ISO-8859-1 277 Denmark/Norway
819/278 819 ISO-8859-1 278 Finland/Sweden
819/280 819 ISO-8859-1 280 Italy
819/284 819 ISO-8859-1 284 Spain
819/285 819 ISO-8859-1 285 United Kingdom
819/297 819 ISO-8859-1 297 France
819/500 819 ISO-8859-1 500 International
819/1047 819 ISO-8859-1 1047 Open Systems Latin 1
850/273 850 PC Latin 1 273 Austria/Germany
850/1047 850 PC Latin 1 1047 Open Systems Latin 1
1252/037 1252 Windows Latin 1 037 United States/Canada
1252/037v2 1252 Windows Latin 1 037 United States/Canada version 2
1252/1047 1252 Windows Latin 1 1047 Open Systems Latin 1
1252/1140 1252 Windows Latin 1 1140 United States/Canada with Euro

Iconv single byte codepages may also be used (e.g. UTF8/EBCDIC-CP-NL) if the host environment supports iconv.

If no codepage is specified then the environment variable HERCULES_CP will be inspected. The default codepage mapping is default.

CNSLPORT   nnnn

specifies the port number (in decimal) to which tn3270 and telnet clients will connect.

The CNSLPORT statement may also have the form of host:port, where the telnet console server will bind to the specified address.

CONKPALV   (idle,intv,count)

specifies the tn3270 console and telnet clients keep-alive option values that control automatic detection of disconnected tn3270/telnet client sessions.

idle   specifies the number of seconds of inactivity until the first keep-alive probe is sent (idle time until first probe, or probe frequency).
intv   specifies the interval in seconds between when successive keep-alive packets are sent if no acknowledgement is received from the previous one (i.e. the timeout value of the probes themselves).
count   specifies the number of unacknowledged keep-alive packets sent before the connection is considered to have failed.

The default values are 3, 1, and 10. That is, send the initial probe 3 seconds after the line goes idle and then wait no more than one second for it to be responded to. Do this 10 times before considering the client as having died.

Note: This is a built-in feature of TCP/IP and allows detection of unresponsive TCP/IP connections and not idle clients. That is to say, your connection will not be terminated after 3 seconds of idle time. Your 3270 session can remain idle for many minutes without any data being transmitted. If the TCP/IP stack at the other end of the connection -- not your 3270 client itself -- fails to respond to the internal keep-alive probe packets, then it means that the TCP/IP stack is down or there has been a break in the connection. Thus, even if your 3270 client is completely idle, your system's TCP/IP stack itself should still respond to the keep-alive probes sent by the TCP/IP stack at the Hercules end of the link. If it doesn't, then TCP/IP will terminate the tn3270/telnet session which will cause Hercules to disconnect the terminal.

The three values can also be modified on-demand via the conkpalv panel command, which has the exact same syntax. Note that the syntax is very unforgiving: no spaces are allowed anywhere within the parentheses and each value must be separated from the other with a single comma.

Note: On Windows platforms the count value is ignored and cannot be changed from its default value of 10. Also, some older platforms may ignore all of the values specified and use platform default values instead.

CPUMODEL   xxxx

specifies the 4 hexadecimal digit CPU machine type number stored by the STIDP instruction Note: Prior to ESA/390 this was known as the CPU model number

CPUPRIO   nn

specifies the priority of the CPU thread. Default is a nice value of 15, which means a low priority such that I/O can be scheduled and completed in favour of CPU cycles being burned. On Multi-CPU systems, a real CPU can be "dedicated" to Hercules, by giving the CPU thread a very high dispatching priority (-20). See "Thread Priorities" below for more information.

Caution:   CPUPRIO should not have a higher dispatching priority than the TOD Clock and timer thread.

CPUSERIAL   xxxxxx

specifies the 6 hexadecimal digit CPU serial number stored by the STIDP instruction

CPUVERID   xx

specifies the 2 hexadecimal digit CPU version code stored by the STIDP instruction. The default version code is FD when ARCHMODE S/370 or ARCHMODE ESA/390 is specified. For the z/Architecture mode, the version code is always stored as 00 and the value specified here is ignored.

DEFSYM   symbol value

Defines symbol symbol as to contain value value. The symbol can then be the object of a substitution later in the configuration file or for panel commands. If value contains blanks or spaces, then it should be enclosed in double quotation marks ("). See substitutions for a more in-depth discussion on this feature.

Substitution is available even in configuration statements, meaning it is possible to perform substitution in the DEFSYM statement itself. However, symbols are always defined as the last step in the process, so attempting to self define a symbol will result in an empty string:

    DEFSYM FOO $(FOO)
Will set symbol FOO to ""

DEVPRIO   nn

specifies the priority of the device threads. The default value is 8. See "Thread Priorities" below for more information.

Caution:   DEVPRIO should not have a higher dispatching priority than the TOD Clock and timer thread.

DEVTMAX   -1 | 0 | nnn

specifies the maximum number of device threads allowed.

Specify -1 to cause 'one time only' temporary threads to be created to service each I/O request to a device. Once the I/O request is complete, the thread exits. Subsequent I/O to the same device will cause another worker thread to be created again.

Specify 0 to cause an unlimited number of 'semi-permanent' threads to be created on an 'as-needed' basis. With this option, a thread is created to service an I/O request for a device if one doesn't already exist, but once the I/O is complete, the thread enters an idle state waiting for new work. If a new I/O request for the device arrives before the timeout period expires, the existing thread will be reused. The timeout value is currently hard coded at 5 minutes. Note that this option can cause one thread (or possibly more) to be created for each device defined in your configuration. Specifying 0 means there is no limit to the number of threads that can be created.

Specify a value from 1 to nnn  to set an upper limit to the number of threads that can be created to service any I/O request to any device. Like the 0 option, each thread, once done servicing an I/O request, enters an idle state. If a new request arrives before the timeout period expires, the thread is reused. If all threads are busy when a new I/O request arrives however, a new thread is created only if the specified maximum has not yet been reached. If the specified maximum number of threads has already been reached, then the I/O request is placed in a queue and will be serviced by the first available thread (i.e. by whichever thread becomes idle first). This option was created to address a threading issue (possibly related to the cygwin Pthreads implementation) on Windows systems.

The default for Windows is 8. The default for all other systems is 0.

DIAG8CMD   DISABLE | ENABLE [ECHO | NOECHO]

When ENABLE is specified, commands issued through the Diagnose 8 interface will be executed by Hercules as Hercules commands. When set to DISABLE, commands issued through the Diagnose 8 interface will generate a Specification Exception program interrupt on the issuing CPU.

An optional second argument can be given to request whether the commands issued using the Diagnose 8 interface will be traced at the console. This may be useful for programs that routinely issue panel commands using the Diagnose 8 interface. When ECHO is specified, a message is issued as the panel is about to issue the command, the command is redisplayed as if it was entered through the panel input line, and a final message is issued to indicate the command completed. When NOECHO is specified, no such messages are displayed and the command completes silently.

The value of ECHO or NOECHO has no effect on command output being placed into a response buffer if the Diagnose 8 interface requested one.

The default is DISABLE NOECHO

Caution:   Enabling this feature may have security consequences.

When this feature is enabled it is possible for guest operating systems running under Hercules to issue commands directly to the host operating system by means of the Hercules sh (shell) command. This ability may be disabled via the SHCMDOPT statement.

ECPSVM   YES | NO | LEVEL nn

specifies whether ECPS:VM (Extended Control Program Support : Virtual Machine) support is to be enabled. If YES is specified, then the support level reported to the operating system is 20. The purpose of ECPS:VM is to provide to the VM/370 Operating system a set of shortcut facilities to perform hypervisor functions (CP Assists) and virtual machine simulation (VM Assists). Although this feature does not affect VM Operating system products operating in XA, ESA or z/Architecture mode, it will affect VM/370 and VM/SP products running under VM/XA, VM/ESA or z/VM. Running VM/370 and VM/SP products under VM/XA, VM/ESA or z/VM should be done with ECPS:VM disabled. ECPS:VM should not be enabled in an AP or MP environment. ECPS:VM has no effect on non-VM operating systems. It is however recommended to disable ECPS:VM when running native non-VM operating systems. If a specific LEVEL is specified, this value will be reported to the operating system when it issues a Store ECPS:VM level, but it doesn't otherwise alter the ECPS:VM facility operations. This is a partial implementation.

ENGINES   [nn*]CP|IL|AP|IP[,...]

specifies the type of engine for each installed processor. The default engine type is CP.

nn* is an optional repeat count. Spaces are not permitted.

Examples:

ENGINES CP,CP,AP,IP
specifies that processor engines 0 and 1 are of type CP, engine 2 is type AP, and engine 3 is type IP.

ENGINES 4*CP,2*AP,2*IP
specifies that the first four processor engines (engines 0-3) are of type CP, the next two (engines 4-5) are of type AP, and the next two (engines 6-7) are of type IP.

The number of installed processor engines is determined by the MAXCPU statement. If the ENGINES statement specifies more than MAXCPU engines, the excess engines are ignored. If fewer than MAXCPU engines are specified, the remaining engines are set to type CP.

HERCPRIO   nn

specifies the process priority for Hercules. The default is 0. See "Process Priorities" below for more information.

HTTPPORT   nnnn [AUTH | NOAUTH] [ userid password ]

specifies the port number (in decimal) on which the HTTP server will listen. The port number must either be 80 or within the range 1024 - 65535 inclusive. If no HTTPPORT statement is present or an invalid port number is specified, then the HTTP server thread will not be activated.
AUTH indictates that a userid and password are required to access the HTTP server, whereas NOAUTH indicates that a userid and password are not required. The userid and password may be any valid string.

HTTPROOT   directory

specifies the root directory where the HTTP server's files reside. If not specified, the default value for Win32 builds of Hercules is the directory where the Hercules executable itself is executing out of, and for non-Win32 builds it is the directory specified as the default package installation directory when the Hercules executable was built (which can vary depending on how the Hercules package was built, but is usually /usr/local/share/hercules/).

IGNORE   INCLUDE_ERRORS

Indicates that errors caused by subsequent INCLUDE statements for files which do not exist should instead be ignored rather than causing startup to be aborted (as would otherwise normally occur).

INCLUDE   filepath

An INCLUDE statement tells Hercules configuration file processing to treat the contents of the file specified by filepath as if its contents had appeared in the configuration file at the point where the INCLUDE statement appears.

Note that the included file may itself contain yet another INCLUDE statement as long as the maximum nesting depth (current 8) is not exceeded.

IODELAY   usec [NOWARN]

specifies the amount of time (in microseconds) to wait after an I/O interrupt is ready to be set pending. This value can also be set using the Hercules console. The purpose of this parameter is to bypass a bug in the Linux/390 and zLinux dasd.c device driver. The problem is more apt to happen under Hercules than on a real machine because we may present an I/O interrupt sooner than a real machine.

If the IODELAY value is non-zero a warning message (HHCCF037W) will be issued unless NOWARN is specified.

NOTE : OSTAILOR LINUX no longer sets IODELAY to 800 since the problem described above is no longer present in recent versions of the Linux kernel.

LDMOD   module list

specifies additional modules that are to be loaded by the Hercules dynamic loader. The default search order is with the hercules directory in the default DLL search path. Most systems also support absolute filenames (ie names starting with '/' or '.') in which case the default search path is not taken.

Multiple LDMOD statements may be used.

LEGACYSENSEID   OFF | DISABLE | ON | ENABLE

specifies whether the SENSE ID CCW (X'E4') will be honored for the devices that originally didn't support that feature. This includes (but may not be limited to) 3410 and 3420 tape drives, 2311 and 2314 direct access storage devices, and 2703 communication controllers.

Specify ON or ENABLE if your guest operating system needs the Sense ID support to dynamically detect those devices. Note that most current operating systems will not detect those devices even though Sense ID is enabled because those devices never supported the Sense ID in the first place. So this mainly applies to custom built or modified versions of guest operating systems that are aware of this specific Hercules capability.

Because those legacy devices didn't originally support this command, and for compatibility reasons, the default is OFF or DISABLE.

LOADPARM   xxxxxxxx

specifies the eight-character IPL parameter which is used by some operating systems to select system parameters.

LOGOPT   TIMESTAMP | NOTIMESTAMP

sets Hercules log options. TIMESTAMP causes messages to the log to be time stamped. NOTIMESTAMP prevents time stamping of log messages. TIMESTAMP and NOTIMESTAMP may be abbreviated as TIME and NOTIME respectively. The current resolution of the stamp is one second.

The default is TIMESTAMP.

LPARNAME   name

specifies the LPAR name returned by DIAG X'204'. The default is HERCULES.

LPARNUM   xx

specifies the one- or two-digit hexadecimal LPAR identification number stored by the STIDP instruction. If a one-digit number is specified then STIDP stores a format-0 CPU ID. If a two-digit number is specified then STIDP stores a format-1 CPU ID. If LPARNUM is not specified, then STIDP stores a basic-mode CPU ID.

MAINSIZE   nnnn

specifies the main storage size in megabytes, where nnnn  is a decimal number. The lower limit is 2. The actual upper limit is determined by your host system's architecture and operating system, and (on some systems) the amount of physical memory and paging space you have available.

MANUFACTURER   name

specifies the MANUFACTURER name returned the STSI instruction. The default is HRC.

MAXCPU   nn

specifies the number of installed processor engines. The NUMCPU statement specifies the number of engines which will be configured online at startup time. All processors are CP engines unless otherwise specified by the ENGINES statement.

The value of MAXCPU cannot exceed the value of MAX_CPU_ENGINES. If MAXCPU is not specified then the default value is the value of MAX_CPU_ENGINES.

MAX_CPU_ENGINES is a compile-time variable which sets an upper limit on the value of MAXCPU. The value of MAX_CPU_ENGINES is displayed in the Build information message on the Hercules control panel at startup time. To change the value of MAX_CPU_ENGINES you must rebuild Hercules. For Unix builds, specify ./configure --enable-multi-cpu=nn before performing make. For Windows builds, specify SET MAX_CPU_ENGINES=nn before performing nmake.

MAX_CPU_ENGINES may be up to 128 on 64-bit Linux platforms. On Windows, and on all 32-bit platforms, the maximum value is 64. For performance reasons, values above 32 are not recommended for 32-bit platforms. If MAX_CPU_ENGINES is set to 1 then multiprocessing is disabled. See also NUMCPU for a discussion of the performance implications of MAX_CPU_ENGINES.

MODEL   hardware_model [ capacity_model ] [ perm_capacity_model ] [ temp_capacity_model ]

specifies the MODEL names returned by the STSI instruction.

If two operands are supplied, the first is the hardware model name (CPC ND model) and the second is the capacity model name (CPC SI model). If only one operand is supplied, it is used as both the hardware model name and the capacity model name. The optional third and fourth operands specify the permanent capacity model name and the temporary capacity model name respectively.

The default is EMULATOR.

MODPATH   path

specifies the path where dynamic modules are loaded from. When a modpath statement is specified, the path on the modpath statement is searched before the default path is searched. When a relative path is specified is interpreted as a relative path within the default search path, if an absolute path is specified is interpreted as such.

The default MODPATH is hercules, which means modules are loaded from the directory hercules within the default LD_LIBRARY_PATH.

MOUNTED_TAPE_REINIT   DISALLOW | ALLOW

specifies whether reinitialization of tape drive devices (via the devinit command, in order to mount a new tape) should be allowed if there is already a tape mounted on the drive.

Specifying ALLOW (the default) indicates new tapes may be mounted (via 'devinit nnnn new-tape-filename') irrespective of whether or not there is already a tape mounted on the drive.

Specifying DISALLOW prevents new tapes from being mounted if one is already mounted. When DISALLOW is specified and a tape is already mounted on the drive, it must first be unmounted (via the command 'devinit nnnn *') before the new tape can be mounted. Otherwise the devinit attempt to mount the new tape is rejected.

This option is meant as a safety mechanism to protect against accidentally dismounting a tape from the wrong drive as a result of a simple typo (thereby cancelling a potentially important tape job) and was added by user request.

Also note that for SCSI tape drives the 'devinit nnnn *' command has no effect as the tape must be unmounted manually (since it is a real physical device and not one emulated via a disk file like .AWS tapes).

NUMCPU   nn

specifies the number of emulated processor engines which will be configured online at startup time. NUMCPU cannot exceed the value of MAXCPU. If NUMCPU is less than MAXCPU then the remaining engines can be configured online later.

Multiprocessor emulation works best if your host system actually has more than one physical CPU, but you can still emulate multiple CPUs nervertheless even on a uniprocessor system (and you might even achieve a small performance benefit when you do). There is little point, however, in specifying NUMCPU greater than 1 unless your guest operating system (running under Hercules) is actually able to support multiple CPUs (and if you do not actually need multiprocessor emulation, then setting MAX_CPU_ENGINES to 1 at compile time might even produce a slight performance advantage too).

NUMVEC   nn

specifies the number of emulated vector facilities. Default is one per CPU. Only available by default in ESA/390 mode.

OSTAILOR   OS/390 | z/OS | VM | VSE | LINUX | QUIET | NULL

specifies the intended operating system. The effect of this parameter is to reduce control panel message traffic by selectively suppressing trace messages for program checks which are considered normal in the specified environment. QUIET discards all exception messages. NULL allows all exception messages to be logged.

Optionally prefix any value except QUIET or NULL with '+' to cause the suppressions for that environment to be combined (added) to those already specified, or with '-' to remove such suppressions (i.e. to allow them).

If the OSTAILOR statement is omitted, exception messages for program checks 10, 11, 16, and 1C are suppressed.

Use the ostailor or pgmtrace panel commands to display or alter the current settings.

PANRATE   SLOW | FAST | nn

specifies the panel refresh rate, in milliseconds between refreshes. SLOW is the same as 500, and FAST is the same as 50. A value less than the Linux system clock tick interval (10 on Intel, 1 on Alpha), or more than 5000, will be rejected. SLOW is the default.

PANTITLE   "title-string"

specifies an optional console window title-bar string to be used in place of the default supplied by the windowing system. If the value contains any blanks it must be enclosed within double-quotes.

This option allows one to distinguish between different Hercules sessions when running more than one instance of Hercules on the same machine.

This option takes effect only when the Hercules console is displayed on an xterm terminal (commonly used on Unix systems), or in a Windows command prompt window. Note that this option has no effect when Hercules is run under control of the Hercules GUI since Hercules's console window is hidden in favor of using the GUI's window instead.

PGMPRDOS   RESTRICTED | LICENSED

specifies whether or not Hercules will run licensed program product ESA or z/Architecture operating systems. If RESTRICTED is specified, Hercules will stop all CPUs when a licensed program product operating system is detected. Specify LICENSED to allow these operating systems to run normally. This parameter has no effect on Linux/390, Linux for z/Series, or any 370-mode OS.

NOTE:  It is YOUR responsibility to comply with the terms of the license for the operating system you intend to run on Hercules. If you specify LICENSED and run a licensed operating system in violation of that license, then don't come after the Hercules developers when the vendor sends his lawyers after you.

RESTRICTED is the default. Specifying LICENSED will produce a message when a licensed operating system is detected to remind you of your responsibility to comply with software license terms.

PLANT   name

specifies the PLANT name returned by the STSI instruction. The default is ZZ.

SHCMDOPT   DISABLE | NODIAG8

When set to DISABLE, sh (shell) commands are globally disabled, and will result in an error if entered either directly via the Hercules hardware console or programmatically via the DIAG8CMD interface.

When set to NODIAG8 only the programmatic execution of shell commands via the the Diagnose 8 interface is disabled, but sh (shell) commands entered directly via the Hercules hardware console will still work.

NOTE:  "entered directly via the Hercules hardware console" also pertains to both commands entered via the HTTP server facility as well as commands entered via .rc "run command" scripts.

SHRDPORT   nnnn

specifies the port number (in decimal) on which the Shared Device server will listen. Specifying SHRDPORT will allow other Hercules instances to access devices on this instance. (Currently only DASD devices may be shared). By default, the other Hercules instances (clients) will use port 3990. If you specify a different port number, then you will have to specify this port number on the device statement for the other Hercules clients. If no SHRDPORT statement is present then the Shared Device server thread will not be activated.

SYSEPOCH   yyyyyears]

specifies the base date for the TOD clock. Use the default value (1900) for all systems except OS/360. Use 1960 for OS/360. Values other than these were formerly used to offset the TOD clock by a number of years to move the date before the year 2000 for non-Y2K-compliant operating systems. This use is deprecated, and support will be removed in a future release; at that time, only values of 1900 or 1960 will be accepted. Other values will produce a warning message with the equivalent values to specify in the SYSEPOCH statement.
An optional year offset may be specified, and will be treated as though it had been specified on a YROFFSET statement.

TIMERINT   DEFAULT | nnnn

specifies the internal timers update interval, in microseconds. This parameter specifies how frequently Hercules's internal timers-update thread updates the TOD Clock, CPU Timer, and other architectural related clock/timer values. The default interval is 50 microseconds, which strikes a reasonable balance between clock accuracy and overall host performance. The minimum allowed value is 1 microsecond and the maximum is 1000000 microseconds (i.e. one second).

Caution:   While a lower TIMERINT value may help increase the accuracy of your guest's TOD Clock and CPU Timer values, it could also have a severe negative impact on the overall performance of your host operating system. This is especially true when a low TIMERINT value is coupled with a high HERCPRIO and TODPRIO priority setting. Exercise extreme caution when choosing your desired TIMERINT in relationship to your chosen HERCPRIO and TODPRIO priority settings.

TODDRAG   nn

specifies the TOD clock drag factor. This parameter can be used to slow down or speed up the TOD clock by a factor of nn. A significant slowdown can improve the performance of some operating systems which consume significant amounts of CPU time processing timer interrupts. A drag factor of 2.0 slows down the clock by 50%. A drag factor of 0.5 doubles the speed of the clock. A drag factor of 1.01 slows down the clock by 1%, and 0.99 speeds up the clock by 1%.

TODPRIO   nn

specifies the priority of the TOD Clock and timer thread. The default value is -20. See "Thread Priorities" below for more information.

Caution:   TODPRIO should be given a dispatching priority equal to or higher than any other thread within Hercules.

TRACEOPT   TRADITIONAL | REGSFIRST | NOREGS

sets the Hercules instruction tracing display option. TRADITIONAL (the default), displays the registers following the instruction about to be executed such that pressing enter (to execute the displayed instruction) then shows the next instruction to be executed followed by the updated registers display.

REGSFIRST displays the current register contents followed by the instruction about to be executed such that pressing enter (to execute the displayed instruction) then shows the updated registers followed by the next instruction to be executed.

NOREGS suppresses the registers display altogether and shows just the instruction to be executed.

In addition to the TRACEOPT configuration file statement there is also a corresponding traceopt panel command to dynamically display and/or update the current setting at any time.

TZOFFSET   ±hhmm

specifies the hours and minutes by which the TOD clock will be offset from the current system time. For GMT, use the default value (+0000). For timezones west of Greenwich, specify a negative value (example: -0500 for US Eastern Standard Time, -0800 for US Pacific Standard Time). For timezones east of Greenwich, specify a positive value (example: +0100 for Central European Time, +0930 for South Australian Time).

XPNDSIZE   nnnn

specifies the expanded storage size in megabytes, where nnnn is a decimal number. The lower limit is 0. The actual upper limit is determined by your host system's architecture and operating system, and (on some systems) the amount of physical memory and paging space you have available.

YROFFSET   ±years

specifies a number of years to offset the TOD clock from the actual date. Positive numbers will move the clock forward in time, while negative numbers will move it backward. A common value for non-Y2K-compliant operating systems is YROFFSET -28, which has the advantage that the day of the week and the presence or absence of February 29 is the same as the current year. This value may not be specified as greater than ±142 years, the total range of the TOD clock. Specifying a value that causes the computed TOD clock year to be earlier than the value of SYSEPOCH or more than 142 years later than that value will produce unexpected results.

A comment preceded by a # sign may be appended to any system parameter statement.


Symbol substitutions

In configuration and device statements, as well as in panel commands and OAT files, symbols may be substituted for text.

Syntax

To substitute symbol symbol with its contents, the symbol should be enclosed within parenthesis and preceded by a $ sign. For example, if symbol FOO contains the text string "BAR" then $(FOO) will be substituted with the string "BAR";. Symbol names are case sensitive.

Example
        DEFSYM  TAPEDIR  "/home/hercules/tapes"

        ...

        0380  3420  $(TAPEDIR)/scratch.aws

        ...

In this example, device 0380 will be a 3420 loaded with the AWS tape file in /home/hercules/tapes/scratch.aws

Special symbols

Device group symbols

When multiple devices are defined with a single device definition statement, then the symbols

  •   CUU  
  •   (3 digits device number, upper case hexadecimal digits)
  •   CCUU  
  •   (4 digits device number, upper case hexadecimal digits)
  •   cuu  
  •   (3 digits device number, lower case hexadecimal digits)
  •   ccuu  
  •   (4 digits device number, lower case hexadecimal digits)

    are defined to contain for each device the relevant device address. For example:

        0200,0201  3340  /home/hercules/dasds/myvols.$(CUU)
    

    will define two 3340 packs, with device 0200 being loaded with the file myvols.200 and device 0201 defined with myvols.201.

    Environment variables

    If a symbol is not explicitly defined by a DEFSYM statement and an environment variable by the same name exists, the string contents of that environment variable will be used for substitution.

    Undefined symbols

    If a symbol is not defined by an explicit DEFSYM, is not an automatically generated symbol and is not an environment variable, an empty string will be substituted.

    Escaping substitution, recursion

    To be able to specify the '$(' string without incurring substitution, an additional '$' sign should be used. For example, $$(FOO) will not be substituted. If substitution is required but the preceding text is to contain a '$' sign as the very last character, then $$$(FOO) should be specified. Thus, if symbol FOO contains "BAR", then $$(FOO) will remain "$$(FOO)" while $$$(FOO) will become "$BAR".

    Substitution is not recursive (only one substitution pass is made).


    Enhanced symbol substitutions

    Enhanced symbol substitution differs from the above normal symbol substitution in several very important ways:

    First, the syntax is different. Enhanced substitution symbol names are specified using ${var} (dollar + brace) rather than $(var) (dollar + parenthesis).

    Second, the enhanced syntax supports specifying a default value that is to be used instead whenever the name symbol is otherwise not defined. The default value is placed within the opening and closing braces just as the symbol name is, but separated from it by either a single equal sign '=' or a colon-equal-sign ':='.

    For example, specifying "${DASD_PATH=dasd/}" in your configuration file requests that the value of the "DASD_PATH" symbol or environment variable be substituted, or, if the variable is undefined, to use the value "dasd/" instead. If no default value is specified then an empty string is used instead.

    Finally, enhanced symbol substitution occurs only from host defined environment variables and not from any identically named DEFSYM symbol should one exist. For example, if environment variable 'FOO' is defined with the value "bar", then the configuration file statement "DEFSYM FOO myfoo" followed immediately by the statement "${FOO}" causes the value "bar" to be substituted and not 'myfoo' as might otherwise be believed, whereas the statement "$(FOO)", since it is a normal symbol substitution sequence does get replaced with "myfoo" (since that was the value defined to it via the preceding DEFSYM statement).

    In other words each symbol substitution technique is supported completely separately from one another. DEFSYM allows one to define/undefine/use private (internally defined) symbols separate from the host operating system's environment variable pool, whereas the enhanced symbol substitution does not and instead only allows read-only access to the host's environment variable pool with no support for modifying an already defined symbol (environment variable) but a nonethless convenient means of defining a default value to be used should the specified host environment variable be currently undefined.

    Further note that symbol names, being the names of environment variables, are subject to whatever case sensitivity or case insensitivity that the host operating system happens to enforce/allow. On Windows, environment variables are not case sensitive, whereas on other operating systems they may be. Thus "${FOO}", "${foo}", "${Foo}", etc, all cause the same value to be substituted on Windows, whereas the DEFSYM symbols $(FOO) and $(foo), being two completely different and unique symbols, could be substituted with two completely different values (since DEFSYM is case sensitive across all supported platforms, including Windows).

    Syntax

    To substitute symbol symbol with the current environment variable value, the symbol should be enclosed within braces and preceded by a $ sign. For example, if an environment variable named FOO holds the value "BAR", then ${FOO} will be substituted with the string "BAR". If the environment variable "FOO" is not defined then a null (empty) string is substituted instead.

    If the string "${FOO:=myfoo}" is used instead, then the value "BAR" will still be substituted if the value "BAR" was indeed previously assigned to FOO, but will be substituted with the value "myfoo" instead if the environment variable FOO is currently undefined.

    Note too that the default value is a literal string and no substitution is applied to it. Thus attempting to use the syntax "${foo=${bar}}" will not yield the expected results. It will not be substituted with the currently defined value of the "bar" environment variable, but rather will always be substituted with the literal string "${bar" followed immediately by the literal character '}'.

    Symbol names (environment variable names) are not case sensitive on Windows whereas they might be on other host operating systems.


    Process and Thread Priorities


    Process Priorities

    Note: Under Linux, a process is a thread and thread priority information applies instead.

    For Windows, the following conversions are used for translating Unix process priorities to Windows process priority classes:


    Unix
    Priority

    Windows Process
    Priority Class

    Meaning
           
    -20 to -16   Real-time Process that has the highest possible priority. The threads of the process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
           
    -15 to -9   High Process that performs time-critical tasks that must be executed immediately. The threads of the process preempt the threads of normal or idle priority class processes. An example is the Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class application can use nearly all available CPU time.
           
    -8 to -1   Above Normal Process that has priority above the Normal class but below the High class.
           
    0 to 7   Normal Process with no special scheduling needs.
           
    8 to 14   Below Normal Process that has priority above the Idle class but below the Normal class.
           
    15 to 20   Idle Process whose threads run only when the system is idle. The threads of the process are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle-priority class is inherited by child processes.


    Caution:   On Windows, the value you choose for your Process Priority has a direct impact on how your Thread Priorities are interpreted! You should never modify one without understanding what impact your doing so might have on the other!


    Thread Priorities

    On a Linux/Unix host, Hercules needs to be a setuid root program to allow it to reset its dispatching priority to a high (negative) value (i.e., chown root.root hercules; chmod +s hercules).

    For Windows, the following conversions are used for translating Linux/Unix thread priorities to Windows thread priorities:


    Unix
    Priority

    Windows
    Thread Priority

    Meaning
           
    -20 to -16   Time Critical Base priority of 15 for Idle, Below Normal, Normal, Above Normal, or High class processes, and a base priority of 31 for Realtime class processes.
           
    -15 to -9   Highest Priority 2 points above the priority class.
           
    -8 to -1   Above Normal Priority 1 point above the priority class.
           
    0 to 7   Normal Normal priority for the priority class.
           
    8 to 14   Below Normal Priority 1 point below the priority class.
           
    15 to 19   Lowest Priority 2 points below the priority class.
           
    20   Idle Base priority of 1 for Idle, Below Normal, Normal, Above Normal, or High class processes, and a base priority of 16 for Realtime class processes.


    Caution:   On Windows, your Thread Priority is interpreted differently based on your chosen Process Priority setting! You should never modify your Thread Priority settings without first reviewing your chosen Process Priority setting!


    Device statements

    The remaining statements in the configuration file are device statements. There must be one device statement for each I/O device or group of identical I/O devices. The format of the device statement is:

    devnum(s)   devtype   [ arguments ]   [ # comments... ]

    where the generic syntax for device numbers is   [n:]CCUU[,CCUU][-CCUU][.nn][...]   as explained below:

    devnum(s)

    is either a single devnum, a range of devnums (separated by a '-' (dash)), a count of devnums (separated by a '.' (dot/period/stop)), or a comma separated list of devnums. Examples would be 200-210 or 0300.10 or 0400,0403 or 0100,0110-011F.

    All devices defined when devnums specifies more than one device have identical characteristics (except for the device number itself). All devices defined as a group must be defined on a single channel. A channel is defined as a contiguous group of 256 (or hexadecimal 100) devices. 0010 and 0020 are on the same channels. 0100 and 0210 are not.

    See devnum immediately below for an explanation of how each device number is specified.

    The 4 special subtitution symbols CUU, CCUU, cuu and ccuu are also defined for each device in a device group. See substitutions for details.

    devnum

    is either a 1 to 4 digit hexadecimal number in the range 0000 to FFFF for ESA/390, or 0000 to 0FFF for S/370. The device number uniquely identifies each device to the operating system.

    Channel Set / Logical Channel Subsystem

    An optional Channel Set or Logical Channel Subsystem Identification can be specified for a device number or group of devices. The Identification number is specified at the beginning of the definition, followed by a ':' character. For example :

    1:0400-040F 3270

    defines 3270 devices 400 to 40F to be on S/370 Channel Set 1 or on S/390 or z/Architecture Logical Channel Subsystem # 1.

    Since each Logical Channel Subsystem defines its own device numbering space, care should be taken in S/370 mode as to define a coherent set of device numbers.

    Not all S/390 or z/Architecture operating systems support Multiple Logical Channel Subsystems (this feature was introduced with the z9-109).

    If no Channel Set or Logical Channel Subsystem Identification is specified, then it is assumed to be 0.

    devtype

    is the device type. Valid device types are shown in the table just below.

    arguments

    is a list of parameters whose meaning depends on the device type. The arguments required for each class of device are shown further below.

    # comments...

    A comment preceded by a # sign may be appended to any device definition statement.


     

    Supported Device Types

    Device type Description Emulated by
    3270, 3287 Local non-SNA 3270 display or printer TN3270 client connection
    SYSG Integrated 3270 console TN3270 client connection
    1052, 3215 Console printer-keyboards Telnet client connection
    1052-C, 3215-C Integrated console printer-keyboards Integrated on Hercules console
    1442, 2501, 3505 Card readers Disk file(s) (ASCII or EBCDIC)
    3525 Card punch Disk file (ASCII or EBCDIC)
    1403, 3211 Line printers Disk file (ASCII)
    3410, 3420, 3422, 3430, 3480, 3490, 3590, 9347, 8809 Tape drives Disk file, CDROM, or SCSI tape
    3088 Channel-to-Channel Adapter device "CTCT" driver or "CTCE" driver
    (( CTCI )) Channel-to-Channel link to host TCP/IP stack "CTCI" TUN/TAP Driver
    (( LCS )) IBM 2216 router, IBM 3172 running ICP, IBM 8232 LCS device, LCS3172 driver of a P/390, IBM Open Systems Adapter (OSA) "LCS" (LAN Channel Station)
    TUN/TAP Driver
    3310, 3370, 9332, 9335, 9336, 0671 FBA direct access storage devices Disk file
    2305, 2311, 2314, 3330, 3340, 3350, 3375, 3380, 3390, 9345 CKD direct access storage devices Disk file
    2703 Communication Line TCP Socket
    2703 Remote Teletype TCP Socket


    Arguments required for each device type

    Local non-SNA 3270 devices

    There are no required arguments for this particular device type, but there are however several optional arguments which are discussed below.

    To use this device, a tn3270 client must connect to the host machine via the port number specified on the CNSLPORT statement. A valid tn3270 device type, such as IBM-3278, must be used.

    If your tn3270 client software allows you to specify a device type suffix (e.g. IBM-3278@001F ), then you can use the suffix to connect to that specific device number, if eligible. If no suffix is specified, then your client will be connected to the first available 3270 device for which it is eligible, if any.

    If you specify a specific terminal device address (via the device type suffix of your tn3270 client software), then you must be eligible to connect at that device address or your connection is immediately rejected; an alternative terminal device for which you might be eligible is not automatically selected instead.

    Optional arguments:

    groupname

    If a terminal group name is given on the device statement, a device type suffix with this group name can be used to indicate that a device in this group is to be used. If a group name is specified as a terminal type suffix (e.g. IBM-3278@GROUPNAME ) and there are no devices defined for that group (or there are no more available devices remaining in that group), then the connection is rejected. If no group name is specified as a terminal type suffix, then the connection will only be eligible for any terminal devices which do not have a group name specified on their device statements. The terminal group name, if specified, should be 1 to 8 alphanumeric characters, the first character being alphabetic, and it should not be a hexadecimal number. Upper and lower case letters in the group name are considered to be equivalent.

    ipaddr [ mask ]

    The optional IP address and optional subnet mask specify the ip address(es) of which client(s) are allowed to connect at the device address identified by the device statement on which they appear. This provides an alternative and/or additional means of specifying to which device(s) a client tn3270 session may, or should, connect.

    If the IP address of the tn3270 client trying to connect, when 'and'ed with the optional subnet mask (which defaults to 255.255.255.255 if not specified), matches the IP address entered on the device statement, then the client is eligible to connect at that device address. Otherwise the client is ineligible to connect at that address and then next available device, if any, for which the client is eligible to connect (if any) is selected instead.

    If no permissible terminal devices remain (i.e. terminal devices for which the client is eligible to connect), or there are no more available terminal devices remaining, then the client connection is rejected.

    The optional IP address and subnet mask may also be specified in conjunction with the previously mentioned terminal group argument, but the terminal group argument, if specified, must be specified ahead of (i.e. before) the optional ip address and subnet mask arguments. To specify an IP address and subnet mask without also specifying a terminal group, simply use '*' as the group name instead.

    If an IP address / subnet mask are not specified, then any client tn3270 session is allowed to connect to the device (provided they are also a member of the specified terminal group, if any).

    The terminal group name argument, if specified, always takes precedence over any optional ip address and subnet mask which may also be specified.

    To summarize, the device number suffix always takes precedence over any group name which may also be specified, and any group name, if specified, always takes precedence over any ip address / subnet mask value which may also be specified.


    Integrated 3270 console device

    The integrated 3270 (SYSG) console is similar to a local non-SNA 3270 device, except that it is not addressed by subchannel number and it is supported only by certain system control programs. The SYSG console is defined like a 3270 device except that the device type is SYSG and the device number is ignored. Only one SYSG console can be defined in a configuration.

    Use tn3270 client software to connect to the SYSG console device via the port number specified on the CNSLPORT statement, just as you would connect to a regular local non-SNA 3270 device.

    The SYSG console configuration statement recognizes optional arguments which specify group name and IP address in the same way as previously described for a local non-SNA 3270 device. These optional arguments provide a means to ensure that a given tn3270 client can connect directly to the SYSG console. If the group name and IP address arguments are not specified, then the SYSG console is considered to be a member of the general pool of devices eligible for connection to any incoming tn3270 client.


    Integrated Console printer-keyboard devices

    There is one optional argument which is the command prefix for sending input to the device. The default command prefix is '/'.

    Note: There is no restriction on the character you can select. If you select a command character that is the first character of a panel command, you will not be able to use that command.

    To send a logon command to a 1052-C or 3215-C enter /logon on the Hercules console.

    All integrated devices must use a different command prefix.


    Console printer-keyboard devices

    There are no required arguments for this particular device type, but there are however several optional arguments discussed below.

    To use this device, a telnet client must connect to the host machine via the port number specified on the CNSLPORT statement.

    If your telnet client software allows you to specify a device type suffix (for example: ansi@0009 ), then you can use that suffix to specify the specific 1052 or 3215 device to which you wish to connect. If you do not specify a suffix in your telnet client software (or your software does not allow it), then your client will be connected to the first available 1052 or 3215 device for which it is eligible.

    An optional noprompt argument may be specified on the device statement to cause suppression of the "Enter input for console device nnnn" prompt message which is otherwise normally issued to the device whenever the system is awaiting input on that device.

    Additionally, a terminal group name, ip address and subnet mask may all also be optionally specified in the exact same manner as discussed in the previous Local non-SNA 3270 devices section with the exception that the "noprompt" option, if specified, must precede the other arguments.


    Card reader devices

    The argument specifies a list of file names containing card images. Additional arguments may be specified after the file names:

    sockdev

    indicates the card reader is a socket device wherein the filename is actually a socket specification instead of a device filename. When used, there must only be one filename specified in the form: port or host:port or sockpath/sockname. The device then accepts remote connections on the given TCP/IP port or Unix Domain Socket, and reads data from the socket instead of from a device file. This allows automatic remote submission of card reader data. See the Hercules Socket Reader page for more details.

    eof

    specifies that unit exception status is presented after reading the last card in the file. This option is persistent, and will remain in effect until the reader is reinitialized with the intrq option.

    intrq

    specifies that unit check status with intervention required sense bytes is presented after reading the last card in the file. This option is persistent, and will remain in effect until the reader is reinitialized with the eof option.

    multifile

    specifies, when multiple input files are entered, to automatically open the next input file and continue reading whenever EOF is encountered on a given file. If not specified, then reading stops once EOF is reached on a given file and an attention interrupt is then required to open and begin reading the next file.

    ebcdic

    specifies that the file contains fixed length 80-byte EBCDIC records with no line-end delimiters.

    ascii

    specifies that the file contains variable length lines of ASCII characters delimited by LF (line feed) sequences or CRLF (carraige return line feed) sequences at the end of each line.

    If neither EBCDIC nor ASCII is specified, then the device handler attempts to detect the format of the card image file when the device is first accessed. Auto-detection is not supported for socket devices, and the default is ASCII if sockdev is specified.

    trunc

    specifies, for ASCII files, that lines longer than 80 characters are truncated instead of producing a unit check error.

    autopad

    specifies, for EBCDIC files, that the file is automatically padded to a multiple of 80 bytes if necessary.


    Card punch devices

    The argument specifies the name of a file to which the punched output will be written. Additional arguments may be specified after the file name:

    ascii

    specifies that the file will be written as variable length lines of ASCII characters delimited by line feeds or carriage return line feed sequences at the end of each line. Trailing blanks are removed from each line. If the ascii argument is not specified, the file is written as fixed length 80-byte EBCDIC records with no line-end delimiters.

    crlf

    specifies, for ASCII files, that carriage return line feed sequences are written at the end of each line. If the crlf argument is not specified, then line-feeds only are written at the end of each line.

    noclear

    specifies that the output file will not be cleared to zero bytes when it is opened. If the noclear argument is not specified, then any previous content of the file is destroyed when the file is opened for output.


    Line printer devices

    The argument specifies the name of a file to which the printer output will be written. The output is written in the form of variable length lines of ASCII characters delimited by line feeds or by carriage return line feed sequences. Trailing blanks are removed from each line. Carriage control characters are translated to blank lines or ASCII form feed characters. If the file exists it will be overwritten.

    Additional arguments may be specified after the file name:

    sockdev

    indicates the line printer is a socket device wherein the filename is actually a socket specification instead of a device filename. When used, there must only be one filename specified in the form: port or host:port. The device then accepts remote connections on the given TCP/IP port, and writes data to the socket instead of to a device file. This allows automatic remote spooling of line printer data. The sockdev option is mutually exclusive with all other printer options (e.g. crlf, etc) and must be specified alone.

    crlf

    specifies, for ASCII files, that carriage return line feed sequences are written at the end of each line. If the crlf argument is not specified, then line-feeds only are written at the end of each line.

    noclear

    specifies that the output file will not be cleared to zero bytes when it is opened. If the noclear argument is not specified, then any previous content of the file is destroyed when the file is opened for output.

    fcbcheck

    specifies that an attempt to skip to a FCB channel for which no line number has been set will cause the command to be rejected with a unit check. This is the default.

    nofcbcheck

    specifies that an attempt to skip to a FCB channel for which no line number has been set will cause the next line of output to be printed on the next line on the printer output. The opposite, fcbcheck, is the default.

    rawcc

    specifies that printer output CCWs are not to be interpreted, but simply dumped in hex to the printer output file. This is useful for debugging. Default is to interpret printer CCWs normally.

    fcb=argument

    specifies an initial FCB image to use for this printer. The argument may either consist of 12 numbers separated by commas (these are the line numbers for channels 1 to 12), or of pairs of numbers in the format nn:chan where chan is the channel number and nn is the line number that the channel corresponds to. Use 00 to leave the line number unset for a channel (see fcbcheck above). The default is fcb=1,7,13,19,25,31,37,43,63,49,55,61 which is equivalent to fcb=1:1,7:2,13:3,19:4,25:5,31:6,37:7,43:8,63:9,49:10,55:11,61:12

    browse | print

    specifies whether the output should be optimized and cleaned up for browsing, or optimized for printing. The default is browse.

    index=nn

    specifies 3211 indexing. Valid values are 0 to 31. The default is 0.

    lpi=6|8

    specifies vertical spacing of 6 or 8 lines per inch.

    lpp=nn

    specifies the number of lines per page. The default is 66.

    If the filename begins with the vertical bar '|' pipe character, then it is removed and the remainder of the filename is interpreted as a command line (the name of a program or batch file followed by any necessary arguments) to which to "pipe" the printer output to. This is known as the "print-to-pipe" feature. All printer output is then sent to the piped program's stdin input, and all of the piped program's stdout and stderr output is piped back to Hercules for displaying on the hardware console.

    If the "print-to-pipe" command line contains arguments, then quotes must be placed around the entire filename string including the vertical bar, for example:

        000E 1403 "|/usr/bin/lpr -Phplj" crlf          (for Unix)
        000E 1403 "|c:\utils\pr -s -PLPT1:" crlf       (for Windows)
        
    The above example uses the pr program downloaded from http://www.atnetsend.net/computing/

    If the "print-to-pipe" command line itself contains quotes, then the command line must be enclosed in apostrophes instead of quotes, for example:

        000E 1403 '|"c:\Program Files\My Utils\pr" -s -PLPT1:' crlf
        

    Tim Pinkawa has an example which shows how the print-to-pipe feature can be used to create output in PDF format: http://www.timpinkawa.net/hercules/prtspool.html


    Emulated tape devices

    Five types of tape emulation are supported (see further below).

    The only required parameter is the device filename. All other parameters are optional and must follow the filename. Use '*' (asterisk) for the filename to specify an empty (unmounted) tape drive. The specified file, if other than '*', must exist.

    Additionally, if the file name starts with the '@' character (at sign), the file really describes a list of tape emulation files to be loaded in succession.

    The syntax of each line is identical to the information that can be specified after the device type when the options are specified directly after the device type in the configuration file.

    If the emulation file filename in the file list is the '*' (asterisk) character, then this specifies a set of options to be applied to all additional emulation files specified in the file list.

    Parameters are appended in succession. In all cases, if the same parameter is specified more than once, the last instance takes precedence.

    Therefore, it is possible to specify a set of parameters in the base configuration file, another set on a '*' line, and another set for each individual line. Parameters are then appended in that order: options specified on the base device statement itself first, followed by those options specified on the '*' statement, and finally those specified on each individual file list statement last. A SCSI tape device should not be given in a file list.

    Refer to the distributed source-code's "README.TAPE" document for additional information regarding system and application programming for tape devices and instructions regarding use of the emulated ACF (Automatic Cartridge Feeder) and AUTOMOUNT features for virtual (non-SCSI) tape devices.

    SCSI tape drives

    These are real tape drives attached to the host machine via a SCSI interface. Hercules emulation always makes the drive appear as a channel attached device such as 3420 or 3480, although the underlying physical drive may be any type of SCSI attached tape drive, including 4mm or 8mm DAT, DLT, SCSI attached 3480/3490 cartridge drives, and SCSI attached 3420 open reel tape drives.

    Host-attached SCSI tapes are read and written using variable length EBCDIC blocks and filemarks exactly like a mainframe tape volume, and as a result can be freely used/exchanged on either (i.e. SCSI tapes created on a real mainframe can subsequently be read by Hercules just fine, and a SCSI tape created by Hercules can be subsequently read on a mainframe just fine, thus providing a convenient means of exchanging data between the two).

    If you plan on using SCSI tapes with Hercules you might also be interested in the AUTO_SCSI_MOUNT configuration option.

    The only required device statement parameter for SCSI attached tape drives is the name of the device as it is known by the host operating system, usually  "/dev/nst0(for Linux or Windows) or  "\\.\Tape0"   (for Windows only), where '0' means tape drive number 0 (your first or only host-attached SCSI tape drive), '1' means your second host-attached SCSI tape drive, etc.

    Depending on what actual model of SCSI tape drive you actually have and how it behaves, you may need to specify one or more additional optional parameters for Hercules to provide proper emulation of the desired device type. For example: a Quantum 'DLT' (Digital Linear Tape) SCSI tape drive does not return nor use a block-id format compatible with 3480/3490 drives (it instead uses a full 32-bit block-id just like the model 3590 does). It also does not support the Erase Gap CCW at all.

    Thus, in order to use, for example, a Quantum DLT drive with Hercules, you MUST specify some special additional options to prevent the Erase Gap command from being issued to the drive as well as to inform Hercules that the drive uses 32-bit block-ids.

    Please note that the below options define how the actual SCSI hardware device behaves, which is completely different from the way the emulated device will appear to behave to your guest. That is to say, if you define your tape drive to Hercules as a 3480 device, then Hercules will perform 3480 device type emulation such that the device appears to your guest o/s as if it were a 3480 device. If the actual SCSI device behaves as a 3590 device however (perhaps using/returning 32-bit block-ids instead of the expected 22-bit format block-ids that 3480's use), then you MUST specify the --blkid-32 special option on your Hercules device statement so that Hercules's emulation logic can know that it needs to translate 22-bit block-ids to 32-bit ones before sending them to the actual SCSI hardware (and vice versa: to translate 32-bit block-ids from the actual SCSI drive into 22-bit format block-ids that your guest expects from a 3480 device).

    Special options for SCSI tapes

    As explained just above, certain model SCSI tape drives such as the Quantum DLT series may require special handling in order to provide the desired proper device type emulation. These special options are:

    --no-erg

    This option is intended to prevent issuance of the Erase Gap command to those SCSI tape drives which do not support it (such as the Quantum DLT series). It causes Hercules's device emulation logic to ignore any Erase Gap commands issued to the drive and to return immediate 'success' instead.

    This option should only be used (specified) for drives such as the Quantum, which support switching from read mode to write mode in the middle of a data stream without the need of an intervening Erase Gap command. Specifying it for any other model SCSI drive may cause incorrect functioning as a result of the Erase Gap command not being issued to the actual SCSI hardware.

    Check the manufacturer information for your particular model of SCSI-attached tape drive (and/or use Fish's "ftape" Windows utility) to determine whether or not this option is needed for your particular drive.

    --blkid-32

    This option indicates that your SCSI-attached tape drive only supports 32-bit block-ids (as used by 3590 drives) and not the 22-bit format used by 3480/3490 drives. You should only specify this option if you intend to define the drive as a model 3480 or 3490 device, and then only if your actual SCSI drive uses 32-bit block-ids of course. If you define your Hercules tape drive as a model 3590 device however, then this option is of course not needed since model 3590 drives are already presumed to use 32-bit block-ids.

    Specifying this option on a 3480/3490 device statement will cause Hercules device emulation logic to automatically translate the actual SCSI tape drive's 32-bit block-id into 22-bit format before returning it back to the guest operating system (since that is the format it expects it to be in for a model 3480/3490 drive), and to translate the guest's 22-bit format block-id into 32-bit format before sending it to the actual SCSI hardware (since that is the format that the actual hardware requires it to be in).

    --blkid-22

    The complete opposite of the above --blkid-32 option.


    Optical Media Attach (OMA) virtual files

    These are read-only files which usually reside on CDROM. OMA virtual tapes consist of one CDROM file corresponding to each physical file of the emulated tape. An ASCII text file called the tape descriptor file (TDF) specifies the names of the files which make up the virtual tape. The argument specifies the name of the tape descriptor file (for example /cdrom/tapes/uaa196.tdf)

    Each file on the virtual tape can be in one of three formats:

    TEXT

    TEXT files consist of variable length ASCII records delimited by carriage return line feed sequences at the end of each record. Each record is translated to EBCDIC and presented to the program as one physical tape block.

    FIXED nnnnn

    FIXED files consist of fixed length EBCDIC blocks of the specified length (nnnnn)

    HEADERS

    HEADERS files consist of variable length EBCDIC blocks. Each block is preceded by a 12-byte header.

    If you have any IBM manuals in Bookmanager format on CDROM, you can see some examples of TDF files in the \TAPES directory on the CDROM.


    AWSTAPE virtual files

    These contain a complete tape in one file. AWSTAPE files consist of variable length EBCDIC blocks. Each block is preceded by a 6-byte header. Filemarks are represented by a 6-byte header with no data. This is the same format as is used by the P/390. The argument specifies the location of the AWSTAPE file (for example ickdsf.aws)


    FakeTape virtual files

    These contain a complete tape in one file. FakeTape files consist of variable length EBCDIC blocks. Each block is preceded by a 12-ASCII-hex-character header. Filemarks are represented by a 12-character header with no data. The FakeTape format is used by the Flex-ES system from Fundamental Software Inc (FSI). The argument specifies the location of the FakeTape file (for example ickdsf.fkt). Note: "FLEX-ES" and "FakeTape" are trademarks of Fundamental Software, Inc.


    HET virtual files    (Hercules Emulated Tape)

    These contain a complete tape in one file and have the same structure as the AWSTAPE format with the added ability to have compressed data. The first argument specifies the location of the HET file. The filename must end with ".het" to be recognized by Hercules as an HET file. (for example 023178.het)

    Additional arguments that allow you to control various HET settings are:

    AWSTAPE

    The AWSTAPE argument causes HET files to be written in AWSTAPE format. This basically, disables the additional features provided by the HET format.

    COMPRESS=n
    IDRC=n

    COMPRESS and IDRC control whether compression should be used when writing to HET files. The value n  can be 1 to turn on compression (the default) or 0 to turn it off. IDRC is currently a synonym for COMPRESS, but may be used in the future to control other emulated tape drive features.

    METHOD=n

    The METHOD option allows you to specify which compression method to use. You may specify 1 for ZLIB compression or 2 for BZIP2 compression. The default is 1.

    LEVEL=n

    The LEVEL option controls the level of compression. It ranges from 1 for fastest compression to 9  for best compression. The default is 4.

    CHUNKSIZE=nnnnn

    The CHUNKSIZE option allows you to create HET files that contain different chunk sizes. The AWSTAPE (and therefore the HET) format allows each tape block to be logically broken up into smaller chunks. For instance, if your S/3x0 application creates tapes with a block size of 27998, those blocks would be broken down into nnnnn  sized chunks. The range is from 4096 to 65535, the latter being the default. Decreasing the value from its default may reduce compression performance. For compatability with AWSTAPE files created by the P/390, specify AWSTAPE with CHUNKSIZE=4096.


    The following parameters apply to AWS, HET and FakeTape emulation files:

    MAXSIZE=n  |  MAXSIZEK=n  |  MAXSIZEM=n

    Specifies the maximum size (in bytes, Kilobytes or Megabytes) that the emulated file is allowed to grow to. Specifying zero for this parameter means "unlimited" (i.e. there is no limit).

    EOTMARGIN=n

    Specifies the number of bytes remaining before reaching maxsize at which point the tape device will signal the presence of the "End of Tape" marker (reflector), thus allowing the program to switch to the next tape.

    READONLY=n

    Specifies whether the tape is mounted read-only (without a write ring or with the cartridge protect switch set to "write protect"). A parameter of 1 means read-only; a parameter of 0 means read-write. If READONLY=1, RO or NORING is not specified, the default is READONLY=0. Note that READONLY=0 does not override the host system file permission settings for the underlying AWS or HET file. If the AWS or HET file is marked read-only, the tape will be mounted read-only despite specification of READONLY=0.

    RO
    NORING

    Specifies that the tape is mounted read-only (without a write ring or with the cartridge protect switch set to "write protect"). RO and NORING are equivalent to READONLY=1.

    RW
    RING

    Specifies that the tape should be mounted read-write, if possible. RW and RING are equivalent to READONLY=0. This is the default if RO, NORING or READONLY=1 is not specified. Note that RW and RING do not override the host system file permission settings for the underlying AWS or HET file. If the AWS or HET file is marked read-only, the tape will be mounted read-only despite specification of RW or RING.

    DEONIRQ=n

    Specifies whether a device end is presented if intervention is required during tape motion. A parameter of 1 selects this option; a parameter of 0 turns it off.

    NOAUTOMOUNT

    Indicates support for guest-initiated automatic tape volume mounting is to always be disabled for this tape device.

    Automatic guest tape-mount support is automatically globally enabled for all virtual (non-SCSI) tape devices by default whenever an allowable automount directory is defined via the AUTOMOUNT configuration file statement or the automount panel command. The NOAUTOMOUNT option allows you to specifically disable such support for a given device.

    The automount feature enables software running in guest operating systems to automatically mount, unmount and/or query for themselves the host "virtual tape volume" filename mounted on a tape drive, via the use of special CCW opcodes (0x4B Set Diagnose and 0xE4 Sense Id) without any intervention on the part of the Hercules operator. An example of such a program for DOS/VSE called TMOUNT is provided in the util subdirectory of the distributed source code.

    This is a sticky option. When specified, automount support for the device remains disabled until the option is specifically removed via a devinit command without the option specified. This means if NOAUTOMOUNT is enabled for a device while global automount functionality is currently disabled (because no AUTOMOUNT statement was specified at Hercules startup), then automount functionality remains disabled for the device even should global automount functionality be later manually enabled via an automount panel command.

    When the 0x4B Set Diagnose CCW is used to auto-mount a virtual tape volume onto a given tape drive, an absolute (fully-qualified) pathname should normally always be specified, but need not be if a path relative to the currently defined "default allowable" automount directory is used instead.

    The default allowable automount directory is always the first "allowable" directory that was defined, or else the current directory if no allowable directories were specifically defined. (There is always a default allowable directory whenever any allowable or unallowable automount directories are defined.)

    Fully-resolved, absolute-full-path filenames are defined as being those which, for Windows, have a ':' (colon) in the second position or, for other host operating systems (e.g. Linux), have a '/' (slash) in the first position. Paths which start with a '.' (period) are considered relative paths and will always be appended to the currently defined default allowable automount directory, before being resolved into fully-qualified paths by the host system. (I.e. only fully-resolved absolute pathnames are used in the performance of the actual automatic tape volume mount.)

    For example, if more than one allowable automount directory is defined and the volume wishing to be mounted happens to reside in the second one, then a fully-qualified absolute pathname should of course be specified (or else one that is relative to the default directory which happens to resolve to the desired file).

    All attempts to automount host files in a "disallowed" directory or any of its subdirectories will be rejected. Similarly any attempt to automount a file which is not within any "allowable" directory or subdirectory will be rejected. An error message is always issued in such cases. A message is also issued whenever a successful mount or unmount is performed.

    A sample guest automount program called TMOUNT for the DOS/VSE operating system is provided in the util subdirectory of the distributed source code.


    Channel-to-channel adapters

    The first argument defines the emulation type, and the remaining arguments depend on the chosen emulation type. If the first argument is not a recognized emulation type, then the driver will operate as in Hercules Version 1, using Willem Konynenberg's vmnet package, as described in Axel Schwarzer's CTCA 3088 document.

    The following are the emulation types currently supported:

    CTCI     (Channel to Channel link to TCP/IP stack)

    A point-to-point IP connection with the TCP/IP stack of the driving system on which Hercules is running. See the Hercules TCP/IP page for details.

    (Note: The CTCI protocol is only for the Linux version of Hercules. For Windows, use the below CTCI protocol instead).


    CTCI     (Channel to Channel link to Win32 TCP/IP stack)

    A modified Win32 version of the CTCI protocol for the Windows crowd. Note that the protocol name (CTCI) is the same, even though the actual implementation is very different. See Fish's CTCI-W32 page for further details and information.

    Required for both Linux and Windows:

    guestip

    specifies the IP address of the guest operating system running under Hercules.

    hostip

    specifies the IP address of the host (Linux or Windows) side of the point-to-point link. This may or may not be the same as your system's regular IP address. For Windows, if the host system is configured with DHCP, this should instead be the MAC address of the Ethernet adapter you wish to use to have Hercules communicate with the outside world.

    Optional for Windows:

    If these arguments are specified, they must precede the required arguments.

    -k  kernel-capture-buffer-size
    -i  tuntap32-i/o-buffer-size

    See Fish's CTCI-W32 page for further details and information.

    Optional for both Linux and Windows:

    If these arguments are specified, they must precede the required arguments:

    -n name    or   --dev name

    specifies the name of the tunnel device to use.

    The default for Linux is /dev/net/tun (which is correct for version 2.4 and above of the Linux kernel).

    For Windows, specify the IP address or MAC address of the real Windows adapter to emulate the virtual guest's adapter on. The default is the first adapter found according to Windows' adapter binding order, which may not be the one you want if you have multiple adapters.

    See question #22 of the CTCI-W32 F.A.Q. (Frequently Asked Questions) document for more information about adapter binding order, and the CTCI-W32 Configuration web page for general information regarding CTCI-W32 configuration.

    -m MAC address    or   --mac MAC address

    where 'MAC address' is the optional hardware address for the virtual interface in the format: hh:hh:hh:hh:hh:hh. The default value is '00:00:5E:nn:nn:nn' where the :nn:nn:nn portion is constructed from the last 3 octets of the specified guestip.

    -s netmask

    where netmask is the netmask to use for the automatically added point-to-point route in standard dotted internet noitation (e.g. 255.255.255.0)

    -d    or   --debug

    specifies that debugging output is to be produced on the Hercules control panel. This should normally be left unspecified.


    CTCT     (Channel to Channel Emulation via TCP connection)

    An emulated CTCA to another Hercules system. This emulation mode appears to the operating system running in the Hercules machine as an IBM 3088 Channel to Channel Adapter. It provides communication via a TCP connection with another instance of the CTCT driver, and is designed to carry TCP/IP communications between two guest TCP/IP stacks. CTCT may also be used for communication between the client and server components of the MVS Dynamic Debug Tool.

    Four arguments are required:

    lport

    specifies the local TCP port. This is the TCP port that Hercules will listen on for this CTCA.

    rhost

    specifies the remote host. This is the name or IP address of the remote system that Hercules is running on, not the name or IP address of the OS running on that copy of Hercules.

    rport

    specifies the remote TCP port. The rport parameter on this system must match the lport parameter on the remote system, and vice versa.

    bufsize

    specifies the buffer size for the link. If this link is used for IP traffic, this parameter should be more than the MTU of the interface definition in the OS.

    Note: CTCT only supports IP traffic. Use CTCE to transport general purpose payloads such as NJE, SNA, PVM, etc.


    CTCE     (Enhanced Channel to Channel Emulation via TCP connection)

    The CTCE device type will emulate a real 3088 Channel to Channnel Adapter also for non-IP traffic, enhancing the CTCT capabilities. CTCE connections are also based on TCP/IP between two (or more) Hercules instances, and requires an even-odd pair of port numbers per device side. Only the even port numbers are to be configured; the odd numbers are just derived by adding 1 to the (configured) even port numbers. The socket connection pairs cross-connect, the arrows showing the send->receive direction :

               x-lport-even -> y-rport-odd
               x-lport-odd  <- y-rport-even
            

    Three arguments are required:

    lport
    is the even TCP/IP port on the local system.
    raddress
    is the IP address of the remote system.
    rport
    is the even TCP/IP port on the remote system.

    The remaining arguments are optional:

    mtu
    optional mtu buffer size, defaults to 32778
    sml
    optional small minimum for mtu, defaults to 8

    A sample CTCE device configuration is shown below:

    Hercules PC Host A with IP address 192.168.1.100 :

                  0E40  CTCE  30880  192.168.1.200  30880
                  0E41  CTCE  30882  192.168.1.200  30882 

    Hercules PC Host B with IP address 192.168.1.200 :

                  0E40  CTCE  30880  192.168.1.100  30880
                  0E41  CTCE  30882  192.168.1.100  30882 

    CTCE connected Hercules instances can be hosted on either Unix or Windows platforms, both sides do not need to be the same.


    LCS     (LAN Channel Station Emulation)

    An emulated Lan Channel Station Adapter. This emulation mode appears to the operating system running in the Hercules machine as an IBM 8232 LCS device, an IBM 2216 router, a 3172 running ICP (Interconnect Communications Program), the LCS3172 driver of a P/390, or an IBM Open Systems Adapter.

    Rather than a point-to-point link, this emulation creates a virtual ethernet adapter through which the guest operating system running in the Hercules machine can communicate. As such, this mode is not limited to TCP/IP traffic, but in fact will handle any ethernet frame.

    The configuration statement for LCS is as follows:

    NOTE: There are no required parameters for the LCS emulation, however there are several options that can be specified on the config statement:

    NOTE: On the MAC OS X Platform, the long option format (--xxx) is not supported. Only the short option format (-x : one dash, one letter) should be used.

    -n devname    or   --dev devname

    where devname is:

    (Linux/Unix)

    the name of the TUN/TAP special character device, normally /dev/net/tun.

    (Windows)

    is either the IP or MAC address of the driving systems network card. TunTap32 will automatically select the first network card it finds if this option is omitted, this may not be desirable for some users.

    -o filename    or   --oat filename

    where filename specifies the filename of the Address Translation file. If this option is specified, the optional --mac and guestip entries are ignored in preference to statements in the OAT. (See further below for the syntax of the OAT file)

    -m MAC Address    or   --mac MAC address

    where MAC Address is the optional hardware address of the interface in the format: hh:hh:hh:hh:hh:hh. If you use the --oat option, do not specify an address here.

    guestip

    is an optional IP address of the Hercules (guest OS) side. Note: This is only used to establish a point-to-point routing table entry on driving system. If you use the --oat option, do not specify an address here.

    OAT file syntax

    The syntax for the Address Translation file is as follows:

    
    *********************************************************
    * Dev   Mode  Port  Entry specific information...       *
    *********************************************************
    
      0400  IP    00    PRI  172.021.003.032
      0402  IP    00    SEC  172.021.003.033
      0404  IP    00    NO   172.021.003.038
      0406  IP    01    NO   172.021.002.016
      040E  SNA   00
    
    HWADD  00  02:00:FE:DF:00:42
    HWADD  01  02:00:FE:DF:00:43
    
    ROUTE  00  172.021.003.032  255.255.255.224
    

    where:

    Dev
    is the base device address

    Mode
    is the operation mode: IP or SNA.

    Note:  the SNA operation mode is NOT currently implemented.

    Port
    is the virtual (relative) adapter number.

    For IP modes, the entry specific information is as follows:

    PRI | SEC | NO

    specifies where a packet with an unknown IP address is forwarded to. PRI is the primary default entry, SEC specifies the entry to use when the primary is not available, and NO specifies that this is not a default entry.

    nnn.nnn.nnn.nnn

    specifies the home IP address

    When the operation mode is IP, specify only the even (read) device number dev. The odd (write) address will be create automatically.

    Note:  the SNA operation mode is NOT currently implemented.

    Additionally, two other statements may be included in the address translation file. The HWADD and ROUTE statements:

    HWADD  pp  hh:hh:hh:hh:hh:hh

    Use the HWADD to specify a hardware (MAC) address for a virtual adapter. The first parameter after HWADD specifies with relative adapter for which the address is applied.

    ROUTE  pp  nnn.nnn.nnn.nnn  ...

    The ROUTE statement is included for convenience. This allows the hercifc program to create a network route for this specified virtual adapter. Please note that it is not necessary to include point-to-point routes for each IP address in the table. This is done automatically by the emulation module.

    The read/write devices can be swapped by coding the odd address of the even-odd pair in the OAT

    Up to 4 virtual (relative) adapters 00-03 are currently supported.

    If no Address Translation file is specified, the emulation module will create the following:

    • An ethernet adapter (port 0) for TCP/IP traffic only.
    • Two device addresses will be defined (devnum and devnum + 1).


    CKD DASD devices

    The argument specifies the name of a file containing the disk CKD DASD image or the INET address of a Hercules shared device server.

    The file consists of a 512-byte device header record followed by fixed length track images. The length of each track image depends on the emulated device type, and is always rounded up to the next multiple of 512 bytes.

    Volumes larger than 2GB (for example, the 3390 model 3) can be supported by spreading the data across more than one file. Each file contains a whole number of cylinders. The first file (which contains cylinders 0-2518 in the case of a 3390) usually has _1 as the last two characters of its name. The ckddasd driver allocates the remaining files by replacing the last character of the file name by the characters 2, 3, etc.

    Note:  When CKD DASD images are spread across multiple files, you must specify only the first file name (the file with suffix _1) in the configuration statement.

    If your operating system supports large file sizes (or 64-bit offsets) then volumes larger than 2G can be kept in a single file.

    Alternatively, the argument may specify the name of a file containing a compressed CKD DASD image. The CKD driver will automatically detect whether the file contains a regular CKD image or a compressed CKD image.

    Refer to "Creating an empty DASD volume" in the "Creating, formatting, and loading DASD volumes" section of the Creating DASD web page for information on using the 'dasdinit' command/utility to create compressed dasd files. Refer to the Compressed Dasd Emulation page for details on the actual CCKD emulation itself and additional information on the CCKD initialization/tuning control file statement.

    If you specify an INET address, the format is:

    ip-name-or-addr:port:devnum

    ip-name-or-addr specifies the internet name or address where the Hercules shared device server is running.

    port specifies the port number the shared device server is listening on. If omitted, the default is 3990.

    devnum specifies the device number on the shared device server. If omitted, the default is the current device number.

    In addition to the above, some additional optional arguments are also supported.

    sf=shadow-file-name

    A shadow file contains all the changes made to the emulated dasd since it was created, until the next shadow file is created. The moment of the shadow file's creation can be thought of as a snapshot of the current emulated dasd at that time, because if the shadow file is later removed, then the emulated dasd reverts back to the state it was at when the snapshot was taken.

    Using shadow files, you can keep the base file on a read-only device such as cdrom, or change the base file attributes to read-only, ensuring that this file can never be corrupted.

    Hercules console commands are provided to add a new shadow file, remove the current shadow file (with or without backward merge), compress the current shadow file, and display the shadow file status and statistics

    For detailed information regarding shadow files and their use, please see the "Shadow Files" section of the Compressed Dasd Emulation web page.

    [no]syncio

    syncio enables possible 'synchronous' i/o. This is a dasd i/o feature wherein guest i/o requests are completed "synchronously" during the actual emulated execution of the SIO/SSCH (start-i/o / start subchannel) instruction rather than being deferred and executed asynchronously in a separate device i/o thread.

    Only i/o which are known to be able to be completed without actually needing to perform any actual host i/o are completed synchronously (e.g. whenever the data being requested is found to already be in cache). If the requested data is not found in the cache, then an actual host i/o will need to be done and the request is passed to a device i/o thread to be completed asyncronously instead.

    syncio is the default for ckd. syncio statistics may be displayed via the Hercules syncio panel command.

    syncio may be abbreviated as syio

    readonly

    readonly returns "write inhibited" sense when a write is attempted. Note that not all of the sense bits may be getting set absolutely correctly however. (Some people have reported getting different error messages under Hercules than a real machine, but it really hasn't been an issue for a while now.)

    readonly may be abbreviated as rdonly or ro

    fakewrite

    fakewrite is a kludge for the readonly sense problem mentioned above. Here the disk is not intended to be updated (MVS updates the DSCB last referenced field for a readonly file) and any writes appear to be successful even though nothing actually gets written.

    fakewrite may be abbreviated as fakewrt or fw

    [no]lazywrite
    [no]fulltrackio

    These options have been deprecated. They are still accepted, but they do absolutely nothing.

    fulltrackio may be abbreviated as fulltrkio or ftio

    cu=type

    Specifies the type of control unit to which this device is attached. The use of this parameter does not necessarily imply that all functions of the specified control unit are emulated, its only purpose is to force a particular control unit type to be indicated in the data returned by SENSE ID and similar CCW's.

    The default value depends on the device type:

    Device typeDefault CU type
    23112841
    23142314
    3330 3340
    3350 3375
    3380
    3880
    33903990
    93459343

    Other values which may be specified are: 3990-3 and 3990-6.

    Normally the default value is appropriate and this parameter need not be specified.


    FBA DASD devices

    The argument specifies the name of a file which contains the FBA DASD image or the INET address of a Hercules shared device server.

    The file consists of fixed length 512-byte records, each of which represents one physical block of the emulated disk.

    To allow access to a minidisk within a full-pack FBA DASD image file, two additional arguments may be specified after the file name:

    origin

    specifies the relative block number within the DASD image file at which the minidisk begins. The number must be less than the number of blocks in the file. The default origin is zero.

    numblks

    specifies the number of 512-byte blocks in the minidisk. This number must not exceed the number of blocks in the file minus the origin. If omitted, or if specified as an asterisk, then the minidisk continues to the end of the DASD image file.

    If you specify an INET address the format is:

    ip-name-or-addr:port:devnum

    ip-name-or-addr specifies the internet name or address where the Hercules shared device server is running.

    port specifies the port number the shared device server is listening on. If omitted, the default is 3990.

    devnum specifies the device number on the shared device server. If omitted, the default is the current device number.

    In addition to the above, some additional optional arguments are also supported.

    sf=shadow-file-name

    The handling of shadow files for FBA devices is identical as that for CKD devices. Please refer to the preceding CKD section for information regarding use of the sf= shadow file option.

    [no]syncio

    syncio enables possible 'synchronous' i/o and is explained in detail in the preceding CKD dasd section. Note however that syncio is currently disabled by default for FBA dasd due to an as yet unresolved problem and must therefore be specifically enabled if you wish to use it for FBA dasd.

    syncio may be abbreviated as syio


    Communication Line - BSC

    ( Preliminary 2703 BSC Support )

    Describes a BSC emulation line entry to either link 2 Hercules engines or a custom made program emulating a 2780, 3780 or 3x74, or a custom made program interfacing to a real BSC line.

    The communication is emulated over a TCP connection. All bytes are transfered as-is (except for doubling DLE in transparent mode) just like it would over a real BSC link. Emulated EIA (DCD, DTR, CTS, etc..) or X.21/V.11 leads (C, T, etc..) are treated differently depending on the DIAL option selected.

    The line emulates a point-to-point BSC link. There is no point-to-multipoint handling.

    The following options define the line emulation behaviour:

    DIAL=IN | OUT | INOUT | NO

    Specifies call direction (if any). If DIAL=NO is specified, the TCP outgoing connection is attempted as soon as an 'ENABLE' CCW is executed. Also, in this mode, an incoming connection will always be accepted. If DIAL=IN|INOUT is specified, a TCP incoming call is accepted ONLY if an 'ENABLE' CCW is currently executing on the device. If DIAL=OUT, the 'ENABLE' CCW is rejected. When DIAL=IN|INOUT is specified, a DIAL CCW allows the application to establish a TCP connection to a specific host. For other DIAL values, the DIAL CCW is rejected.

    lhost=hostname | ip address | *

    Specifies which IP address to listen on. This also conditions the network interface from which incoming calls will be accepted. Specifying '*' means all incoming TCP calls are accepted, regardless of the destination IP address or call origin. This is the default value. Specifying a specific IP address when DIAL=OUT is specified has no effect.

    lport=service name | port number

    Specifies the TCP port for which to listen to incoming TCP calls. This value is mandatory for DIAL=IN|INOUT|NO. It is ignored for DIAL=OUT.

    rhost=hostname | ip address
    rport=service name | port number

    Specifies the remote host and port to which to direct a TCP connection on a DIAL=NO line when an 'ENABLE' CCW is executed. This option is mandatory when DIAL=NO is specified. It is ignored for other DIAL values.

    The following options are tuning options. In most cases, using the default values give the best results

    rto=0 | -1 | nnn | 3000

    Specifies the number of milliseconds before terminating a read on a timeout, when no read termination control character is received. Specifying 0 means the READ ends immediately. -1 specifies there is no timeout.

    pto=0 | -1 | nnn | 3000

    Specifies the number of milliseconds before terminating a POLL on a timeout, when no ACK or NACK sequence is received. Specifying 0 means the POLL ends immediately. -1 specifies there is no timeout.

    eto=0 | -1 | nnn | 10000

    Specifies the number of milliseconds before terminating an ENABLE operation on a timeout. the timeout applies when DIAL=NO|IN|INOUT is specified, the outgoing TCP call fails (DIAL=NO) and there is no previously or currently established TCP connection for this line. When DIAL=NO is specified, the timeout defaults to 10 seconds. For DIAL=IN|INOUT, the timeout defaults to -1.

    Communication Line - TTY

    ( Preliminary 2703 TELE2 TTY Support )

    Describes a 2703 Telegraph Terminal Control Type II (TTY 33/35) stop/start line, providing access to the Host OS via a standard TELNET client.

    To the host OS the line emulates an asynchronous TELE2 connection. The communication is emulated over a TELNET connection.

    The following options define the line emulation behaviour:

    lport=port number

    Specifies the TCPIP port to listen on for incoming TCP calls.

    dial=IN

    Specifies that this line is for in-bound calls. Required.

    tty=1

    Specifies that this definition is for a TTY port. Required


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercfaq.html0000664000175000017500000011703212622153562013447 00000000000000 Hercules Version 3: Frequently-Asked Questions

    Hercules Version 3: Frequently-Asked Questions


    1.01What is Hercules?
    1.02So what exactly does that mean?
    1.03Is it functional enough to run production work?
    1.04What are the licensing restrictions for Hercules?
     
    2.01Can it run z/OS, z/VM, z/VSE?
    2.02What operating systems can I run legally?
    2.03What other programs will run under Hercules?
    2.04Where can I obtain OS/360 ?
    2.05Where can I obtain MVS ?
    2.06Where can I obtain VM/370 ?
    2.07Where can I obtain DOS/VS ?
    2.08Where can I obtain Linux/390 ?
    2.09Where can I find documentation?
     
    3.01What PC hardware do I need to run Hercules?
    3.02What sort of MIPS rate can I expect?
    3.03What PC software do I need to run Hercules?
    3.04What software do I need to build Hercules on Linux and Unix?
    3.05What software do I need to build Hercules on Windows?
    3.06Can Hercules be ported to run on other platforms?
     
    4.01How can I create a virtual DASD volume?
    4.02Can I read a tape which was created on a mainframe?
    4.03Can I attach a PC tape drive to Hercules?
    4.04Can I process mainframe tapes with Hercules?
    4.05Can I create Assembler programs without a mainframe?
     
    5.01What architectural features are implemented?
     
    6.01Who are the Herculeans?
     
    7.01Where can I obtain technical support?


    1.01 What is Hercules?

    Hercules is a software implementation of the System/370, ESA/390 and z/Architecture mainframe architectures. Hercules runs under Windows and Linux, as well as under various other Unix or Unix-like systems on Intel Pentium and other hardware platforms including Alpha, Sparc, and Mac.

    1.02 So what exactly does that mean?

    It means that your PC can execute programs designed to run on an IBM mainframe.

    Hercules executes S/370, ESA/390, and z/Architecture instructions and channel programs. It emulates mainframe I/O devices by using PC devices. For example, 3390 DASD devices are emulated by large files on your hard disk, and local 3270 screens are emulated by tn3270 sessions.

    Hercules implements only the raw S/370, ESA/390, and z/Architecture instruction set; it does not provide any operating system facilities. This means that you need to provide an operating system or standalone program which Hercules can load from an emulated disk or tape device. You will have to write the operating system or standalone program yourself, unless you can manage to obtain a license from IBM to run one of their operating systems on your PC, or use IBM programs and operating systems which are effectively in the public domain.

    1.03 Is it functional enough to run production work?

    Hercules has never claimed to be a production-capable system. It was always meant to be a system programmer's toy. Having said that, it's now become good enough to run a wide range of software without problems, and there are reports that it has been used to run production work in some parts of the world.

    1.04 What are the licensing restrictions for Hercules?

    Hercules is a copyright work which has been made generally available, subject to the terms of the Q Public License. In essence this allows free use and distribution of the program for personal and commercial use. You may not distribute modified copies of the program, but you may distribute your own patches along with the program, provided that you also grant the maintainer permission to include those patches in future versions of the program. You may not copy any portion of the source code for use in any other program.


    2.01 Can it run z/OS, z/VM, z/VSE?

    Yes. Hercules is a software implementation of z/Architecture, and so it is capable of running z/OS, z/VM, and z/VSE. Hercules also implements ESA/390 (including SIE) and so it can run OS/390, VM/ESA, and VSE/ESA, as well as older versions of these operating systems such as MVS/ESA, MVS/XA, MVS/SP, MVS/SE, VM/SP, VSE/SP, and DOS/VSE.

    But (and this is a big but), these operating systems are all IBM Licensed Program Products, whose conditions of use generally restrict their usage to specific IBM machine serial numbers. So you cannot just copy these systems from work and run them on your PC, as this would almost certainly be a violation of your company's licensing agreement with IBM.

    2.02 What operating systems can I run legally?

    Operating systems which may legally be run on Hercules include:

    • Older IBM operating systems including OS/360, DOS/360, DOS/VS, MVS 3.8, VM/370, and TSS/370 which are widely believed to be either public domain or "copyrighted software provided without charge."
    • The open source operating system "Linux on System z". Several distributors provide 64-bit z/Architecture versions of Linux, and some also provide ESA/390-compatible versions. Mainframe Linux distributions include SUSE Linux Enterprise Server, Red Hat Enterprise Linux, Fedora, and Debian. Many developers use Hercules to help port their software to the mainframe with Linux on System z.
    • The open source operating system "OpenSolaris for System z". Sine Nomine Associates brought OpenSolaris to System z, relying on features provided by z/VM. Emulation of those specific z/VM features for OpenSolaris is included in Hercules starting with version 3.07.
    • The Michigan Terminal System (MTS) version D6.0A, which is a pre-built version of MTS for use with Hercules (see http://archive.michigan-terminal-system.org).
    • The MUSIC/SP operating system may be available for educational and demonstration purposes upon request to its copyright holder, McGill University. Some of MUSIC/SP's features, notably networking, require z/VM (and thus an IBM license).

    2.03 What other programs will run under Hercules?

    Any program which uses the S/370, ESA/390, or z/Architecture instruction set, as implemented in Hercules. Some special utilities in the form of standalone programs are known to run well. A good example is Jan Jaeger's excellent standalone editor (ZZSA) which is included in the Hercules distribution, or it can be downloaded from http://www.cbttape.org/~jjaeger; ZZSA allows you to examine and edit MVS datasets without the need to load an operating system. Note: ZZSA runs in ESA/390 mode. See Jan Jaeger's website for more information and special logon procedures.

    2.04 Where can I obtain OS/360 ?

    Rick Fochtman's OS/360 archive CD is obtainable by download from http://www.jaymoseley.com/hercules/install.htm

    Jay Maynard's "IBM Public Domain Software Collection" at http://www.ibiblio.org/jmaynard/ contains copies of the OS/360 Release 21.8 distribution tapes.

    2.05 Where can I obtain MVS 3.8 ?

    The MVS 3.8J Turnkey System built by Volker Bandke can be obtained from http://www.bsp-gmbh.com/

    For news about updates to the MVS 3.8J Turnkey System, subscribe to the H390-MVS forum at http://tech.groups.yahoo.com/group/H390-MVS/

    Phil Roberts has made available an updated MVS Turnkey System which can be downloaded from http://www.4shared.com/file/RfClJ57w/tk3upd.html

    Paul Edwards created a distribution consisting of a modified version of Hercules together with operating system modifications which allow applications to break the 24-bit addressing barrier inherent in S/370. The distribution is called MVS/380 and it can be downloaded from http://mvs380.sourceforge.net/

    2.05 Where can I obtain VM/370 ?

    The VM/370 page at http://www.cbttape.org/vm6.htm contains download links for the Andy Norrie VM 4-pack system and the Bob Abeles VM/370 R6 distribution.

    Dave Wade's VM/370 Downloads page at http://www.smrcc.org.uk/members/g4ugm/VM370.htm contains links to the most recent VM/370 distributions.

    You may also wish to subscribe to the H390-VM forum at http://tech.groups.yahoo.com/group/H390-VM/

    2.07 Where can I obtain DOS/VS ?

    George Shedlock's DOS/VS 5-pack system can be obtained from https://docs.google.com/open?id=0B7scZ2voEa--Zm50U09xYy15ejg

    Other useful files may be downloaded from the H390-DOSVS forum at http://tech.groups.yahoo.com/group/H390-DOSVS/files/

    2.08 Where can I obtain Linux/390 ?

    The best starting point for information about Linux for S/390 and Linux for zSeries is http://www.linuxvm.org/

    2.09 Where can I find documentation?

    There are several sites containing introductory documentation for MVS 3.8 with Hercules, including:

    Much of the original IBM documentation for the 360 and 370 series is preserved at the bitsavers.org website. A good starting point is:

    Jay Maynard produced a document describing how to build an OS/360 system on Hercules, called "OS/360 on Hercules". It can be found at

    This will build an MVT system without TCAM/TSO, but with two 3270 consoles. You will need Malcolm Beattie's "Guide to Using 3270 Consoles and Terminals for Hercules" with this MVT version.


    3.01 What PC hardware do I need to run Hercules?

    Classic IBM operating systems (OS/360, MVS 3.8, VM/370) are very light by today's standards and will run satisfactorily on a 300Mhz Pentium with as little as 32MB RAM.

    Anything more up-to-date, such as Linux/390 or OS/390, requires much more processing power. Hercules is CPU intensive, so you will want to use the fastest processor you can get. A 2GHz Pentium, preferably with hyperthreading, will probably provide acceptable performance for a light workload. Recent 64-bit multiprocessor systems will provide better performance. Hercules makes extensive use of multi-threading to overlap I/O with CPU activity, and to dispatch multiple emulated CPU's in parallel.

    For the latest 64-bit operating systems such as zLinux and z/OS, be aware that there is a performance penalty when Hercules emulates z/Architecture on a 32-bit processor such as the Pentium. If you are serious about running 64-bit then you will probably want to build Hercules for a 64-bit processor such as Alpha (DEC/Compaq/HP), AMD64 (AMD Opteron, Athlon-64, Turion 64), IA64 (Intel Itanium 2), together with a 64-bit version of Linux, or PPC (Power Mac G5) with OS X.

    Hercules does not depend on the x86 architecture. It has been built and run successfully on 500 MHz Alpha 21164, SPARC, and S/390 Linux. One guy has even run OS/360 under Hercules under Linux/390 under Hercules under Linux/390 under VM/ESA! The prize for the world's smallest mainframe probably goes to Ivan Warren, who claims to have run VM/370 under Hercules on an iPAQ 5450 handheld PDA.

    You should provide enough RAM to accommodate your S/390 real storage (main storage plus expanded storage) in addition to the normal requirements of your PC's operating system. For maximum throughput, you should set your main and expanded storage sizes high enough to eliminate S/390 paging. S/390 storage is allocated out of your PC's virtual storage.

    You also need enough hard disk space to accommodate the emulated DASD. A virtual "3330 model 1" disk drive will need about 100 megabytes of space for emulation (a 3330-11 will need about 200 megabytes). A 3380 "single density" model will need about 650MB, a 3390 model 2 needs about 2GB, and a 3390 model 3 needs about 3GB. If you use the compressed CKD DASD feature, these sizes will shrink dramatically, usually to about 20 to 30 percent of the original size.

    3.02 What sort of MIPS rate can I expect?

    Thanks to the cumulative work of many individuals, including Valery Pogonchenko, Juergen Dobrinski, Albert Louw, Gabor Hoffer, Jan Jaeger, Paul Leisy, Clem Clarke, and Greg Smith, the performance of Hercules today is vastly better than it was 5 years ago.

    Even on a Celeron 300 you should see an execution speed of 1 to 2 MIPS, which is enough to run OS/360 (MFT or MVT) or MVS 3.8 with a response time better than that of a 3033 from the 1970's. It's also fast enough to run VSE/ESA with an acceptable response time. On a more recent system with a 2GHz Pentium processor, you may see the system peak at around 30 MIPS which is enough to run Linux/390 or z/OS with a light workload.

    Performance on server class machines is now fairly respectable. For example, on a dual-core Intel Xeon with hyperthreading (4 CPUs) running at 3.46GHz, you might expect to see a sustained MIPS rate of 40 to 60 MIPS. A dual-processor quad-core Mac Pro (8 cores, 3 GHz) will sustain over 150 MIPS. For anyone who is prepared to spend a considerable amount of money on their Hercules system, there are reports that a sustained 300+ MIPS has been achieved on an Intel Core i7 processor running at 3.75GHz using all four cores plus hyperthreading (8 CPUs).

    Typical I/O rates of around 50 EXCP/second are reported on average hardware, with rates over 500/second achievable with hardware RAID.

    3.03 What PC software do I need to run Hercules?

    The following software platforms are supported:

  • Linux (kernel 2.4 or later)
  • Windows XP, Windows Vista, or Windows 7
  • Mac OS X 10.3 or later
  • Solaris 2.9 or later (Sparc or Intel)
  • FreeBSD

    You will also need tn3270 client software for the virtual 3270 console. The tn3270 client can run on the same machine as Hercules, or on any Unix or Windows box with a TCP/IP connection to the Hercules machine.

    The supported and recommended tn3270 clients for Hercules are:

    x3270 for Unix
    x3270 is included with most Linux distributions, or you can download it from http://x3270.bgp.nu/
    Vista tn3270 for Windows
    Vista tn3270 can be obtained from www.tombrennansoftware.com. The very modest license fee charged for this excellent 3270 emulator helps to support an independent software developer.
    Brown University tn3270 for Macintosh
    Brown University tn3270 is freely available. You can download it from http://www.brown.edu/cis/tn3270/. There is one setting that must be changed to use this program with some operating systems, especially MVS 3.8: Open a connection to Hercules, but before IPLing the system, go to the Session->Features menu and set "Change embedded nulls to blanks" to "No". Click on "OK". Now, click on File->Save default settings... to make the setting permanent.

    Other tn3270 clients, such as QWS3270, IBM Personal Communications, Attachmate Extra, or Dynacomm Elite should also work in most cases, but be aware that some tn3270 clients have bugs which make them unusable as OS/360 or MVS consoles.

    3.04 What software do I need to build Hercules on Linux and Unix?

    To build Hercules for Linux and other Unix-like environments you need to use the gcc compiler, version 3.x or above. You will also need a full set of GNU development tools, including recent versions of autoconf, automake, libiconv, make, perl, sed, and m4. Refer to the util/bldlvlck file in the Hercules distribution for details.

    3.05 What software do I need to build Hercules on Windows?

    To build Hercules for the Windows environment you need to use the Microsoft C/C++ compiler (MSVC) version 14.x or later. The 32-bit compiler and SDK are packaged as Microsoft Visual C++ 2010 Express (Version 16.x) available for download from Microsoft.

    Although no longer available for download, Microsoft Visual C++ 2005 Express (Version 14.x) or Microsoft Visual C++ 2008 Express (Version 15.x) may also be used. Alternatively, Microsoft Visual Studio 8.0, 9.0, or 10.0 may be used. For further information, see the README.WIN32 file.

    To build Hercules for 64-bit Windows platforms you will need either Microsoft Visual C++ 2010 Express and the Microsoft Windows SDK 7.1, or Microsoft Visual Studio 9.0 or 10.0 Professional. For further information, see the README.WIN64 file.

    3.06 Can Hercules be ported to run on other platforms?

    With the introduction of autotools, we do make efforts to ensure Hercules builds and run on several different operating system platforms (mostly Linux, Windows, MAC, Solaris, and FreeBSD right now), but we of course simply cannot guarantee that it will run on every operating system platform out there.

    The Hercules code is not intended to be specific to Intel hardware, so if you find any issues or faults related to running on other hardware (SPARC, Alpha, PPC, ...) under Linux, feel free to report it to the Hercules forum (see the Hercules Technical Support page).


    4.01 How can I create a virtual DASD volume?

    The Creating Hercules DASD document describes various methods of creating and loading virtual DASD volumes.

    4.02 Can I read a tape which was created on a mainframe?

    Yes, indirectly. The mainframe tape must be converted to AWSTAPE format and then downloaded to your PC. The tapeconv.jcl file in the Hercules directory contains a sample program which you can run under OS/390 on your mainframe system. It reads a file from tape and converts it to AWSTAPE format. Download the AWSTAPE file to your PC (making sure to choose binary format for the download), and then add the downloaded filename to the Hercules configuration file as a virtual tape device. You will then be able to read the tape file from the virtual tape drive located on your PC.

    Note: the "tapeconv" program will not correctly process input tapes whose block size exceeds 32760! One symptom of this may be the message " ADRY011E I/O ERROR - DEVICE NOT ATTACHED.0000,NA,00...00,0000" when attempting to restore from tape originally created using the default DF/DSS block size. The solution is to recreate the dump tape with DCB=BLKSIZE=32760.

    4.03 Can I attach a PC tape drive to Hercules?

    Yes. Hercules can read and write tapes on SCSI drives. I have tested this with 4mm DAT, QIC-1000, and 9-track drives.

    4.04 Can I process mainframe tapes with Hercules?

    Yes. It is possible to obtain 9-track open reel drives and 3480-type cartridge drives which attach to the SCSI bus. Hercules makes these appear to the operating system as channel-attached 3420 or 3480 devices, making it possible to read and write real mainframe tapes.

    4.05 Can I create Assembler programs without a mainframe?

    Yes. If you want to write Assembler (BAL) programs to run on Hercules, but you don't have access to a mainframe, then there are two interesting products which you can run on your PC to assemble programs:

    The "Tachyon 390 Cross Assembler" ( http://www.tachyonsoft.com/tachyon )
    With this assembler you can produce S/390-compatible object decks using your Linux or Windows PC. A high degree of HLASM compatibility, coupled with the ability to perform complex assemblies at lightning speed, make this a product which is well worth looking at. I have tried this assembler and it is truly amazing.
    The "Dignus Systems/C Compiler" ( http://www.dignus.com )
    This is a C compiler which runs under Windows or Linux and generates mainframe assembler code which you can then assemble using the Tachyon assembler.

    Sam Golob wrote a fascinating review of these two products in the September 1999 issue of NaSPA Technical Support magazine.


    5.01 What architectural features are implemented?

    The following standard features of ESA/390 have been implemented:

    • Address-Limit Checking
    • Commercial Instruction Set
    • Decimal Instructions
    • Hexadecimal Floating-Point Instructions
    • 24-bit and 31-bit addressing
    • Key-Controlled Protection
    • Page Protection
    • Low-Address Protection
    • Dynamic Address Translation
    • 370-XA Channel Subsystem
    • Channel Indirect Data Addressing
    • Program Controlled Interruption (PCI)
    • Channel Program Suspend/Resume
    • Dual Address Space
    • Access Register Mode
    • Home Space Mode
    • Branch and Save
    • Conditional Swapping
    • TOD Clock, Clock Comparator, and CPU Timer
    • MVCS/MVCP/MVCK/MVCSK/MVCDK instructions
    • TB/TPROT instructions
    • LURA/STURA instructions
    • BAKR/PC/PR/PT instructions
    • Linkage Stack
    • Compare and Form Codeword and Update Tree instructions

    The following optional features of ESA/390 have been implemented:

    • Access-List-Controlled Protection
    • Binary Floating-Point instructions
    • Branch and Set Authority
    • Broadcasted Purging
    • Checksum instruction
    • Compare and Move Extended instructions
    • Dynamic Reconfiguration
    • Expanded Storage
    • Fast Synchronous Data Mover Facility
    • Floating-Point-Support Extensions
    • Halfword-Immediate instructions
    • Branch-Relative instructions
    • Incorrect-Length-Indication Suppression
    • Interpretive Execution (SIE)
    • Move Inverse
    • Move Page (Facility 2)
    • MVS assists
    • Operational Extensions: Console Integration
    • Private Space
    • Set Address Space Control Fast
    • Service-call-logical-processor (SCLP) facility
    • Square Root
    • Storage-Protection Override
    • Storage Key assist
    • String instructions
    • Subspace Group
    • Compare Until Substring Equal
    • Concurrent Sense
    • Suppression on Protection with Virtual-Address enhancement
    • Extended TOD clock
    • Compression
    • Perform Locked Operation
    • Vector Facility
    • Multiple Controlled Data Space (VM dataspaces)
    • Extended Translation
    • Extended Translation Facility 2
    • Store System Information
    • Cancel I/O Facility
    • Program Event Recording
    • Guest PER enhancement

    The following optional features of z/Architecture have been implemented:

    • HFP Multiply-and-Add/Subtract Facility
    • Message Security Assist
    • Long-Displacement Facility
    • DAT-Enhancement Facility
    • Extended-Translation Facility 3
    • ASN-and-LX-Reuse Facility
    • List-Directed Initial Program Load
    • Modified CCW Indirect Data Addressing (MIDAW) Facility
    • Extended-Immediate Facility
    • Message-Security-Assist Extension 1
    • Message-Security-Assist Extension 2
    • DAT-Enhancement Facility 2
    • Store-Clock-Fast Facility
    • Store-Facility-List-Extended Facility
    • ETF2-Enhancement Facility
    • ETF3-Enhancement Facility
    • PER-3 Facility
    • TOD-Clock-Steering Facility
    • Conditional-Emergency-Signal and Sense-Running-Status Facility
    • Multiple Logical Channel Subsystems Facility
    • Floating-Point-Support Enhancement Facilities (FPR-GR-Loading, FPS-Sign-Handling, and DFP-Rounding)
    • Decimal Floating Point Facility
    • IEEE-Exception-Simulation Facility
    • Extract-CPU-Time Facility
    • Conditional-SSKE Facility
    • Compare-and-Swap-and-Store Facility
    • Execute-Extensions Facility
    • General-Instructions-Extension Facility
    • Move-with-Optional-Specifications Facility
    • Parsing-Enhancement Facility
    • Compare-and-Swap-and-Store Facility 2
    • Integrated 3270 (SYSG) Console
    • Configuration-Topology Facility
    • HFP-Unnormalized-Extensions Facility
    • CMPSC-Enhancement Facility
    • High-Word Facility
    • Interlocked-Access Facility
    • Load/Store-on-Condition Facility
    • Distinct-Operands Facility
    • Population-Count Facility
    • Message-Security-Assist Extension 3
    • Message-Security-Assist Extension 4
    • Fast-BCR-Serialization Facility
    • Enhanced-Monitor Facility
    • Reset-Reference-Bits-Multiple Facility
    • Access-Exception-Fetch/Store-Indication Facility
    • Load-Program-Parameter Facility
    • IPTE-Range Facility
    • Enhanced-DAT Facility
    • Decimal Floating Point Zoned-Conversion Facility
    • Execution-Hint Facility
    • Load-and-Trap Facility
    • Miscellaneous-Instruction-Extensions Facility
    • Floating-Point-Extension Facility

    The following optional features of z/Architecture have not yet been implemented:

    • PFPO Facility
    • Restore-Subchannel Facility
    • Integrated ASCII (SYSA) Console
    • CPU-Measurement Counter Facility
    • CPU-Measurement Sampling Facility
    • Nonquiescing Key-Setting Facility
    • Enhanced-DAT Facility 2
    • Interlocked-Access Facility 2
    • Local-TLB-Clearing Facility
    • PER Zero-Address-Detection Facility
    • Processor-Assist Facility
    • Transactional-Execution Facility
    • Warning-Track-Interruption Facility

    The following standard feature has not yet been implemented:

    • Clear I/O (full functionality for S/370)

    The following optional features have been partially implemented:

    • Channel-Subsystem Call
    • VM/370 assists

    The following features are not yet implemented, either due to lack of documentation, limited host system capability, or lack of supporting hardware:

    • Asynchronous Data Mover Facility
    • Asynchronous Pageout Facility
    • Coupling Links
    • ESCON
    • FICON
    • MIF (Multiple Image Facility)
    • Extended Sorting
    • External Time Reference (Sysplex Timer)
    • ICRF (Cryptography)
    • Operational Extensions: Automatic Reconfiguration, Storage Reconfiguration, SCP-initiated Reset, Processor Availability
    • PR/SM
    • Program-Controlled re-IPL

    Hercules is compliant with IBM's ALS-1, ALS-2 and ALS-3 architectural level sets to the degree necessary to run all OS/390 versions through 2.10 and known versions of z/OS in both ARCHLVL 1 and ARCHLVL 2 mode, and Linux and z/VM in both ESA/390 and z/Architecture mode.


    6.01 Who are the Herculeans?

    The following people are among those who have contributed to this project, either as coders or as testers or both:

  • Roger Bowler (original author)
  • Jay Maynard
  • Jan Jaeger
  • Butch Anton
  • Volker Bandke
  • David Barth
  • Malcolm Beattie
  • Mario Bezzi
  • Florian Bilek
  • Gordon Bonorchis
  • Gert Caers
  • Mike Cairns
  • Bill Carlborg
  • Chris Cheney
  • Marcin Cieslak
  • Clem Clarke
  • Peter Coghlan
  • Vic Cross
  • Jacob Dekel
  • Guy Desbiens
  • Jacques Dilbert
  • Juergen Dobrinski
  • Fritz Elfert
  • Neale Ferguson
  • Tomas Fott
  • Mike Frysinger
  • Martin Gasparovic
  • Mark Gaubatz
  • Steve Gay
  • Paolo Giacobbis
  • Peter Glanzmann
  • Roland Goetschi
  • Graham Goodwin
  • Paul Gorlinsky
  • Harold Grovesteen
  • John P. Hartmann
  • Glen Herrmannsfeldt
  • Brandon Hill
  • Laddie Hanus
  • Robert Hodge
  • Gabor Hoffer
  • Dan Horak
  • Peter J. Jansen
  • Soren Jorvang
  • Willem Konynenberg
  • John Kozak
  • Nobumichi Kozawa
  • Peter Kuschnerus
  • Paul Leisy
  • Kevin Leonard
  • Albert Louw
  • Peter Macdonald
  • Lutz Mader
  • Tomas Masek
  • Rick McKelvy
  • John McKown
  • Dave Morton
  • Christophe Nillon
  • Mike Noel
  • Andy Norrie
  • Dutch Owen
  • Max H. Parke
  • Gerd Petermann
  • Reed H. Petty
  • Jim Pierson
  • Richard Pinion
  • Tim Pinkawa
  • Pasi Pirhonen
  • Valery Pogonchenko
  • Andy Polyakov
  • Frans Pop
  • Wolfhard Reimer
  • Emerson Santos
  • Jeff Savit
  • Axel Schwarzer
  • Paul Scott
  • Daniel Seagraves
  • Victor Shkamerda
  • Ian Shorter
  • Greg Smith
  • Enrico Sorichetti
  • John Summerfield
  • Peter Sylvester
  • Mark Szlaga
  • Adam Thornton
  • Adrian Trenkwalder
  • "Fish" (David B. Trout)
  • Ronen Tzur
  • Bernard van der Helm
  • Ard van der Leeuw
  • Kris Van Hees
  • Adam Vandenberg
  • Christophe Varlet
  • Kees Verruijt
  • Giuseppe Vitillaro
  • Dave Wade
  • Ivan Warren
  • Juergen Winkelmann
  • Ian Worthington
  • Rod Zazubek
  • Bjoern A. Zeeb
  • Matt Zimmerman

    And thanks for support and encouragement from:

  • Tim Alpaerts
  • Bertus Bekker
  • Giorgio de Nunzio
  • Rick Fochtman
  • Alex Friis
  • Sam Golob
  • Achim Haag
  • Cory Hamasaki
  • Tony Harminc
  • Richard Higson
  • Jim Keohane
  • Sam Knutson
  • Mike Ross
  • Daniel Rudin
  • Rich Smrcina
  • Henk Stegeman
  • Mark S. Waterbury

    If anyone feels they have been unfairly omitted from either of these lists, please let the maintainer (maintainer @ hercules-390.eu) know.


    7.01 Where can I obtain technical support?

    Please see the Hercules Technical Support page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercinst.html0000664000175000017500000007557412625667132013701 00000000000000 Hercules Version 3: Installation and Operation

    Hercules Version 3: Installation and Operation


    Contents

    Installation Procedure

    Configuration Procedure

    Creating DASD volumes

    Operating Procedure

    Technical Support


    Installation Procedure

    Building from source - Windows

    1. Download the distribution file hercules-3.12.zip
    2. (optional) If you want your executable to support compressed DASD or the Hercules Automatic Operator (HAO), also download these packages:
    3. Hercules for Windows is built using the Microsoft Visual C (MSVC) compiler. Refer to file README.WIN32 or README.WIN64 for details.

    Building from source - Mac OS X

    1. Install Xcode from the App Store.
    2. Install Homebrew using the procedure described at http://brew.sh/
    3. Use these commands to install pre-requisite software:
      brew install autoconf
      brew install automake
      brew install gnu-sed
      automake --add-missing
    4. Proceed with Building from source - Linux and Mac OS X below.

    Building from source - Linux and Mac OS X

    1. Download the distribution file hercules-3.12.tar.gz
      Note: By downloading this file you agree to the terms of the Q Public Licence.

    2. Use these commands to unzip the distribution file:
      tar xvzf ../hercules-3.12.tar.gz
      cd hercules-3.12
    3. Verify you have all of the correct versions of all of the required packages installed:

      ./util/bldlvlck

    4. Configure Hercules for your system:

      ./configure

      By default, the configure script will attempt to guess appropriate compiler optimization flags for your system. If its guesses turn out to be wrong, you can disable all optimization by passing the --disable-optimization option to configure, or specify your own optimization flags with --enable-optimization=FLAGS

      For additional configuration options, run: ./configure --help

    5. Build the executables:

      make

    6. Install the programs: as root:

      make install

    Important: You must use at least version 3.00 of the gcc compiler and the glibc2 library. Refer to the Hercules Frequently-Asked Questions page for required compiler and other software levels.

    Installing pre-built binaries for Mac OS X:

    Homebrew may be used to install Hercules on a Mac with an Intel processor and OS X 10.5 or above.

    1. Homebrew requires Xcode which can be installed from the App Store.
    2. Install Homebrew using the procedure described at http://brew.sh/
    3. Enter these commands at a terminal prompt:
      brew help
      brew doctor
      brew install hercules

    Installing pre-built binaries for Windows:

    1. Download one of the following packages
    2. You may also want to install Fish's Hercules GUI for Windows. You can get it from http://www.softdevlabs.com/Hercules/hercgui-index.html.


    Configuration Procedure

    You will need to amend the configuration file hercules.cnf to reflect your device layout and intended mode of operation (S/370, ESA/390, or z/Architecture). See the Hercules Configuration File page for a complete description.


    Creating DASD volumes

    The Creating Hercules DASD page describes various methods of creating and loading virtual DASD volumes. The compressed CKD DASD support is described in this page.


    Operating Procedure

    Note: If you intend to run any licensed software on your PC using Hercules, it is your responsibility to ensure that you do not violate the software vendor's licensing terms.

    Starting Hercules

    To start Hercules enter this command at the Unix or Windows command prompt:

        hercules  [ -f filename ]
                  [ -d ]
                  [ -p dyndir ]  [[-l dynmod ] ... ]
                  [ > logfile ]
    

    where:

    filename

    is the name of the configuration file. The default, if none is specified, is hercules.cnf. The default may be overridden via the HERCULES_CNF environment variable.

    -d

    specifies that Hercules is to be run in 'daemon' mode, wherein it runs invisibly with no attached console.

    dyndir

    is the directory from which dynamic modules are to be loaded. The default depends on the host platform on which Hercules is being run. This option overrides the default.

    dynmod

    is the name of an additional dynamic module to be loaded at startup. More than one additional module may be specified, although each must be preceded with the -l option specifier.

    logfile

    is an optional log file which will receive a copy of all messages displayed on the control panel

    Next connect a tn3270 client to the console port (normally port 3270). The client will be connected to the first 3270 device address specified in the configuration file (this should be the master console address). If your master console is a 1052 or 3215, connect a telnet client instead of a tn3270 client.

    Now you can enter an ipl command from the control panel.



    Using the keyboard

    The main Hercules screen contains a scrollable list of messages with a command input area and system status line at the bottom of the screen.

    To scroll through the messages, use either the Page Up or Page Down keys, the Ctrl + Up Arrow or Ctrl + Down Arrow keys, or the Home or End and/or the Ctrl + Home or Ctrl + End keys.

    Important messages are highlighted in a different color (usually red) and are prevented from being scrolled off the screen for two minutes. If Extended Cursor handling is available then important messages currently at the top of the screen can be removed early by moving the cursor to the line containing the message and then pressing enter.

    Use the Insert key to switch between insert and overlay mode when typing in the command input area. Use the Home and End keys to move to the first or last character of the command you are typing, or the use the left/right arrow keys to move to a specific character. Use the Escape key to erase the input area.

    Pressing Escape when the command input area is already empty causes the screen to switch to the semi-graphical "New Panel" display mode, which shows the overall status of the system and devices.

    When in the semi-graphical "New Panel" display mode there is no command input area. Instead, single character "hot keys" are used to issue some of the more common functions such as starting or stopping the CPU. The hot-keys are those which are highlighted. Pressing the '?' key displays brief help information on how to use the semi-graphical panel.

    Normal cursor handling
    Key Action
    Esc Erases the contents of the command input area. If the command input area is already empty, switches to semi-graphical New Panel.
    Del Deletes the character at the cursor position.
    Backspace Erases the previous character.
    Insert Toggles between insert mode and overlay mode.
    Tab Attempts to complete the partial file name at the cursor position in the command input area. If more than one possible file exists, a list of matching file names is displayed.
    Home Moves the cursor to the start of the input in the command input area. If the command input area is empty, scrolls the message area to the top.
    End Moves the cursor to the end of the input in the command input area. If the command input area is empty, scrolls the message area to the bottom.
    Page Up Scrolls the message area up one screen.
    Page Down Scrolls the message area down one screen.
    Up arrow Recalls previous command into the input area.
    Down arrow Recalls next command into the input area.
    Right arrow Moves cursor to next character of input area.
    Left arrow Moves cursor to previous character of input area.
    Ctrl + Up arrow Scrolls the message area up one line.
    Ctrl + Down arrow Scrolls the message area down one line.
    Ctrl + Home Scrolls the message area to the top.
    Ctrl + End Scrolls the message area to the bottom.

    The following additional keyboard functions are effective when the Hercules Extended Cursor Handling feature (OPTION_EXTCURS) is activated at compile time. At present, this feature is activated on the Windows platform only.

    Extended cursor handling
    Key Action
    Alt + Up arrow Moves cursor up one row.
    Alt + Down arrow Moves cursor down one row.
    Alt + Right arrow Moves cursor right one column.
    Alt + Left arrow Moves cursor left one column.
    Tab If cursor is outside the command input area, moves cursor to the start of the input in the command input area. Otherwise behaves as described in previous table.
    Home If cursor is outside the command input area, moves cursor to the start of the input in the command input area. Otherwise behaves as described in previous table.
    End If cursor is outside the command input area, moves cursor to the end of the input in the command input area. Otherwise behaves as described in previous table.


    Panel commands

    The following is what is displayed on the Hercules harware console (HMC) in response to the '?' command being entered. Please note that it may not be completely accurate or up-to-date. Please enter the '?' command for yourself for a more complete, accurate and up-to-date list of supported panel commands.

    
      Command      Description...
      -------      -----------------------------------------------
      ?            list all commands
      help         command specific help
    
      *            (log comment to syslog)
    
      message      display message on console a la VM
      msg          same as message
      msgnoh       same as message - no header
    
      hst          history of commands
      hao          Hercules Automatic Operator
      log          direct log output
      logopt       change log options
      version      display version information
    
      quit         terminate the emulator
      exit         (synonym for 'quit')
    
      cpu          define target cpu for panel display and commands
    
      start        start CPU (or printer device if argument given)
      stop         stop CPU (or printer device if argument given)
    
      startall     start all CPU's
      stopall      stop all CPU's
    
      cf           configure current CPU online or offline
      cfall        configure all CPU's online or offline
    
      .reply       scp command
      !message     scp priority messsage
      ssd          Signal Shutdown
    
      ptt          display pthread trace
    
      i            generate I/O attention interrupt for device
      ext          generate external interrupt
      restart      generate restart interrupt
      archmode     set architecture mode
      loadparm     set IPL parameter
    
      ipl          IPL Normal from device xxxx
      iplc         IPL Clear from device xxxx
      sysreset     Issue SYSTEM Reset manual operation
      sysclear     Issue SYSTEM Clear Reset manual operation
      store        store CPU status at absolute zero
    
      psw          display or alter program status word
      gpr          display or alter general purpose registers
      fpr          display floating point registers
      fpc          display floating point control register
      cr           display or alter control registers
      ar           display access registers
      pr           display prefix register
      timerint     display or set timers update interval
      clocks       display tod clkc and cpu timer
      ipending     display pending interrupts
      ds           display subchannel
      r            display or alter real storage
      v            display or alter virtual storage
      u            disassemble storage
      devtmax      display or set max device threads
      k            display cckd internal trace
    
      attach       configure device
      detach       remove device
      define       rename device
      devinit      reinitialize device
      devlist      list device or all devices
    
      qd           query dasd
    
      automount    show/update allowable tape automount directories
    
      scsimount    automatic SCSI tape mounts
    
      cd           change directory
      pwd          print working directory
      sh           shell command
    
      cache        cache command
      cckd         cckd command
      shrd         shrd command
      conkpalv     display/alter console TCP keep-alive settings
      quiet        toggle automatic refresh of panel display data
    
      t            instruction trace
      t+           instruction trace on
      t-           instruction trace off
      t?           instruction trace query
      s            instruction stepping
      s+           instruction stepping on
      s-           instruction stepping off
      s?           instruction stepping query
      b            set breakpoint
      b+           set breakpoint
      b-           delete breakpoint
      g            turn off instruction stepping and start CPU
    
      ostailor     trace program interrupts
      pgmtrace     trace program interrupts
      savecore     save a core image to file
      loadcore     load a core image file
      loadtext     load a text deck file
    
      ldmod        load a module
      rmmod        delete a module
      lsmod        list dynamic modules
      lsdep        list module dependencies
    
      iodelay      display or set I/O delay value
      ctc          enable/disable CTC debugging
      toddrag      display or set TOD clock drag factor
      panrate      display or set rate at which console refreshes
      msghld       display or set the timeout of held messages
      syncio       display syncio devices statistics
      maxrates     display maximum observed MIPS/SIOS rate for the
                   defined interval or define a new reporting interval
    
      defsym       Define symbol
      script       Run a sequence of panel commands contained in a file
      cscript      Cancels a running script thread
    
      evm          ECPS:VM Commands (Deprecated)
      ecpsvm       ECPS:VM Commands
    
      aea          Display AEA tables
      aia          Display AIA fields
      tlb          Display TLB tables
    
      sizeof       Display size of structures
    
      suspend      Suspend hercules
      resume       Resume hercules
    
      herclogo     Read a new hercules logo file
    
      traceopt     Instruction trace display options
    
      cmdtgt       Specify the command target
    
      herc         Hercules command
    
      scp          Send scp command
    
      pscp         Send prio message scp command
    
      sf+dev       add shadow file
      sf-dev       delete shadow file
      sfc          compress shadow files
      sfk          check shadow files
      sfd          display shadow file stats
    
      t{+/-}dev    turn CCW tracing on/off
      s{+/-}dev    turn CCW stepping on/off
      t{+/-}CKD    turn CKD_KEY tracing on/off
      f{+/-}adr    mark frames unusable/usable
    
    

    The ipl command may also be used to perform a load from cdrom or server. For example if a standard SuSE S/390 Linux distribution CD is loaded and mounted on /cdrom for example, this cdrom may then be ipl-ed by: ipl /cdrom/suse.ins

    The attach and detach commands are used to dynamically add or remove devices from the configuration, and the define command can be used to alter the device number of an existing device.

    The devinit command can be used to reopen an existing device. The args (if specified) override the arguments specified in the configuration file for this device. The device type cannot be changed and must not be specified. This command can be used to rewind a tape, to mount a new tape or disk image file on an existing device, to load a new card deck into a reader, or to close and reopen a printer or punch device.

    In single-step mode, pressing the enter key will advance to the next instruction.

    There is also an alternate semi-graphical control panel. Press Esc to switch between the command line format and the semi-graphical format. Press ? to obtain help in either control panel.

    Some commands also offer additional help information regarding their syntax, etc. Enter  "help <command name>"   to display this additional help information. (Note: not every command supports help)

    When a command is prefixed with '-', the the command will not be redisplayed at the console. This can be used in scripts and is also used internally when commands are to be invoked without being redisplayed at the panel.


    The  hercules.rc  (run-commands)  file

    Hercules also supports the ability to automatically execute panel commands upon startup via the 'run-commands' file. If the run-commands file is found to exist when Hercules starts, each line contained within it is read and interpreted as a panel command exactly as if the command were entered from the HMC system console.

    The default filename for the run-commands file is "hercules.rc", but may be overridden by setting the "HERCULES_RC" environment variable to the desired filename.

    Except for the 'pause' command (see paragraph further below), each command read from the run-commands file is logged to the console preceded by a '> ' (greater-than sign) character so you can easily distinguish between panel commands entered from the keyboard from those entered via the .rc file.

    Lines starting with '#' are treated as "silent comments" and are thus not logged to the console. Line starting with '*' however are treated as "loud comments" and will be logged.

    In addition to being able to execute any valid panel command (including the 'sh' shell command) via the run-commands file, an additional 'pause nnn' command is supported in order to introduce a brief delay before reading and processing the next line in the file. The value nnn can be any number from 1 to 999 and specifies the number of seconds to delay before reading the next line. Creative use of the run-commands file can completely automate Hercules startup.


    The "Hercules Automatic Operator" (HAO) Facility

    The Hercules Automatic Operator (HAO) feature is a facility which can automatically issue panel commands in response to specific messages appearing on the Hercules console.

    To use the Hercules Automatic Operator facility, you first define a "rule" consisting of a "target" and an associated "command". The "target" is a regular expression pattern used to match against the text of the various messages that Hercules issues as it runs. Whenever a match is found, the rule "fires" and its associated command is automatically issued.

    The Hercules Automatic Operator facility only operates on messages issued to the Hercules console. These messages may originate from Hercules itself, or from the guest operating system via the SCP SYSCONS interface or via the integrated console printer-keyboard (3215-C or 1052-C). HAO cannot intercept messages issued by the guest operating system to its own terminals.

    Defining a Rule

    To define a HAO rule, enter the command:

       hao tgt target
    

    to define the rule's "target" match pattern followed by the command:

       hao cmd command
    

    to define the rule's associated panel-command.

    The target is a regular expression as defined by your host platform. When running on Linux, Hercules uses POSIX Extended Regular Expression syntax. On a Windows platform, regular expression support is provided by Perl Compatible Regular Expression (PCRE). The HAO facility can only be used if regular expression support was included in Hercules at build time.

    The associated command is whatever valid Hercules panel command you wish to issue in response to a message being issued that matches the given target pattern.

    Substituting substrings in the command

    The command may contain special variables $1, $2, etc, which will be replaced by the values of "capturing groups" in the match pattern. A capturing group is a part of the regular expression enclosed in parentheses which is matched with text in the target message. In this way, commands may be constructed which contain substrings extracted from the message which triggered the command.

    The following special variables are recognized:

    • $1 to $9 - the text which matched the 1st to 9th capturing group in the target regular expression
    • $` - the text preceding the regular expression match
    • $' - the text following the regular expression match
    • $$ - replaced by a single dollar sign

    Note that substitution of a $n variable does not occur if there are fewer than n capturing groups in the regular expression.

    As an example, the rule below issues the command 'i 001F' in response to the message HHCTE014I 3270 device 001F client 127.0.0.1 connection reset:

       hao tgt HHCTE014I 3270 device ([0-9A-F]{3,4})
       hao cmd i $1
    

    Another example, shown below, illustrates how the dot matrix display of a 3480 tape unit might be used to implement an automatic tape library:

       hao tgt HHCTA010I ([0-9A-F]{4}): Now Displays: (?:".{8}" / )?"M([A-Z0-9]{1,6})\s*S"
       hao cmd devinit $1 /u/tapes/$2.awstape
    
    Other commands and limitations

    To delete a fully or partially defined HAO rule, first use the 'hao list' command to list all of the defined (or partially defined) rules, and then use the 'hao del nnn' command to delete the specific rule identified by nnn (all rules are assigned numbers as they are defined and are thus identified by their numeric value). Optionally, you can delete all defined or partially defined rules by issuing the command 'hao clear'.

    The current implementation limits the total number of defined rules to 64. This limit may be raised by increasing the value of the HAO_MAXRULE constant in hao.c and rebuilding Hercules.

    All defined rules are checked for a match each time Hercules issues a message. There is no way to specify "stop processing subsequent rules". If a message is issued that matches two or more rules, each associated command is then issued in sequence.


    Technical Support

    For technical support, please see the Hercules Technical Support page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/herclic.html0000664000175000017500000001167112564723224013454 00000000000000 Hercules: Q Public License

    THE Q PUBLIC LICENSE version 1.0


    Copyright (C) 1999 Trolltech AS, Norway.
    Everyone is permitted to copy and
    distribute this license document.

    The intent of this license is to establish freedom to share and change the software regulated by this license under the open source model.

    This license applies to any software containing a notice placed by the copyright holder saying that it may be distributed under the terms of the Q Public License version 1.0. Such software is herein referred to as the Software. This license covers modification and distribution of the Software, use of third-party application programs based on the Software, and development of free software which uses the Software.

    Granted Rights

    1. You are granted the non-exclusive rights set forth in this license provided you agree to and comply with any and all conditions in this license. Whole or partial distribution of the Software, or software items that link with the Software, in any form signifies acceptance of this license.

    2. You may copy and distribute the Software in unmodified form provided that the entire package, including - but not restricted to - copyright, trademark notices and disclaimers, as released by the initial developer of the Software, is distributed.

    3. You may make modifications to the Software and distribute your modifications, in a form that is separate from the Software, such as patches. The following restrictions apply to modifications:

    a. Modifications must not alter or remove any copyright notices in the Software.

    b. When modifications to the Software are released under this license, a non-exclusive royalty-free right is granted to the initial developer of the Software to distribute your modification in future versions of the Software provided such versions remain available under these terms in addition to any other license(s) of the initial developer.

    4. You may distribute machine-executable forms of the Software or machine-executable forms of modified versions of the Software, provided that you meet these restrictions:

    a. You must include this license document in the distribution.

    b. You must ensure that all recipients of the machine-executable forms are also able to receive the complete machine-readable source code to the distributed Software, including all modifications, without any charge beyond the costs of data transfer, and place prominent notices in the distribution explaining this.

    c. You must ensure that all modifications included in the machine-executable forms are available under the terms of this license.

    5. You may use the original or modified versions of the Software to compile, link and run application programs legally developed by you or by others.

    6. You may develop application programs, reusable components and other software items that link with the original or modified versions of the Software. These items, when distributed, are subject to the following requirements:

    a. You must ensure that all recipients of machine-executable forms of these items are also able to receive and use the complete machine-readable source code to the items without any charge beyond the costs of data transfer.

    b. You must explicitly license all recipients of your items to use and re-distribute original and modified versions of the items in both machine-executable and source code forms. The recipients must be able to do so without any charges whatsoever, and they must be able to re-distribute to anyone they choose.

    c. If the items are not available to the general public, and the initial developer of the Software requests a copy of the items, then you must supply one.

    Limitations of Liability

    In no event shall the initial developers or copyright holders be liable for any damages whatsoever, including - but not restricted to - lost revenue or profits or other direct, indirect, special, incidental or consequential damages, even if they have been advised of the possibility of such damages, except to the extent invariable law, if any, provides otherwise.

    No Warranty

    The Software and this license document are provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

    Choice of Law

    This license is governed by the Laws of England.


    back

    Last updated 3 December 2000 hercules-3.12/html/hercload.html0000664000175000017500000006155612622153562013630 00000000000000 Hercules Version 3: Creating DASD

    Hercules Version 3: Creating DASD

    This page describes various ways of creating and loading DASD volumes for use with Hercules.


    Contents

    Using pre-built DASD images

    Creating, formatting, and loading DASD volumes

    Building a DASD volume from unloaded PDS or sequential files

    Other DASD utilities


    Using pre-built DASD images

    IBM distributes pre-built OS/390 and z/OS systems on two different CD-ROM packages:

    The OS/390 and z/OS Application Development CD (ADCD)
    available only to members of IBM PartnerWorld for Developers, and
    The OS/390 and z/OS DemoPkg
    available only to IBM employees and qualified IBM Business Partners.

    Both of these packages contain pre-built DASD image files which simply need to be unzipped onto your hard drive. The unzipped images can be directly read by Hercules.

    Be aware, however, that you cannot use the ADCD images because the PartnerWorld scheme requires you to purchase or lease an IBM approved machine in order to obtain the ADCD, and the software on the ADCD is licensed for use only on the machine that it was shipped with. See http://www.ibm.com/servers/enable/site/zinfo/adcd.html. If you want Hercules to be an approved machine so that you can use the ADCD, then I suggest you lobby IBM Developer Relations at the address given on their web page.

    Different rules apply to the OS/390 and z/OS DemoPkg CD which is available only to IBM employees and business partners. If you fall into this category then you probably know what the rules are -- I don't :-(


    Creating, formatting, and loading DASD volumes

    Creating an empty DASD volume

    The dasdinit program must first be run from the Unix shell prompt to create a file containing an empty DASD volume.

    The format of the dasdinit command is:


    Hercules DASD image file creation program
    Version 3.06
    (c)Copyright 1999-2009 by Roger Bowler, Jan Jaeger, and others
    Builds an empty dasd image file:
    
      dasdinit [-options] filename devtype[-model] [volser] [size]
    
    where:
    
      -v         display version info and help
      -z         build compressed dasd image file using zlib
      -bz2       build compressed dasd image file using bzip2
      -0         build compressed dasd image file with no compression
      -lfs       build a large (uncompressed) dasd file (if supported)
      -a         build dasd image file that includes alternate cylinders
                 (option ignored if size is manually specified)
      -r         build 'raw' dasd image file  (no VOL1 or IPL track)
      -linux     null track images will look like linux dasdfmt'ed images
                 (3390 device type only)
    
      filename   name of dasd image file to be created
    
      devtype    CKD: 2305, 2311, 2314, 3330, 3340, 3350, 3375, 3380, 3390, 9345
                 FBA: 0671, 3310, 3370, 9313, 9332, 9335, 9336
    
      model      device model (implies size) (opt)
    
      volser     volume serial number (1-6 characters)
                 (specified only if '-r' option not used)
    
      size       number of CKD cylinders or 512-byte FBA sectors
                 (required if model not specified else optional)
    


    The current list of device types and models supported is:


                  CKD DEVICES
    
                                 alt
            devtype-model  cyls  cyls
    
            2311           [*]
            2311-1         200    2
    
            2314           [*]
            2314-1         200    3
    
            3330           [*]
            3330-1         404    7
            3330-2         808    7
            3330-11        808    7
    
            3340           [*]
            3340-1         348    1
            3340-35        348    1
            3340-2         696    2
            3340-70        696    2
    
            3350           [*]
            3350-1         555    5
    
            3375           [*]
            3375-1         959    1
    
            3380           [*]
            3380-1         885    1
            3380-A         885    1
            3380-B         885    1
            3380-D         885    1
            3380-J         885    1
            3380-2        1770    2
            3380-E        1770    2
            3380-3        2655    3
            3380-K        2655    3
            EMC3380K+     3339    3
            EMC3380K++    3993    3
    
            3390           [*]
            3390-1        1113    1
            3390-2        2226    1
            3390-3        3339    1
            3390-9       10017    3
            3390-27      32760    3
            3390-54      65520    3
    
            9345           [*]
            9345-1        1440    0
            9345-2        2156    0
    
    
                 FBA DEVICES
    
            devtype-model  blocks
    
            3310              [*]
            3310-1         125664
    
            3370              [*]
            3370-Al        558000
            3370-B1        558000
            3370-A2        712752
            3370-B2        712752
    
            9313              [*]
            9313-1         246240
    
            9332              [*]
            9332-200       360036
            9332-400       360036
            9332-600       554800
    
            9335              [*]
            9335-1         804714
    
            9336              [*]
            9336-10        920115
            9336-20       1672881
            9336-25       1672881
    
            0671-08        513072
            0671           574560
            0671-04        624456
    

    [*] size may be specified else size defaults to the first listed model.

    Volumes exceeding 2GB

    For CKD volumes which exceed 2GB, such as the 3390-3, and the -lfs parameter is not specified, the DASDINIT program will create multiple files by appending the characters _1, _2, _3 etc. to the file name specified on the command line. These characters are inserted before the first dot (.) after the last slash (/). If there is no dot, then the characters are appended to the end of the name. Each file contains a whole number of cylinders. Hercules CKD support recognizes the files as belonging to a single logical volume. Specify the full name of just the first file in the Hercules configuration file (e.g. "filename_1").

    The DASDINIT program cannot create FBA volumes exceeding 2GB unless the -lfs parameter is specified and large file size is supported on your platform..

    Examples

    To create a 3330 model 1 CKD volume consisting of 404 cylinders (plus 7 alternate cylinders too) with volume serial number WORK01 in a file called work01.151:

        dasdinit -a work01.151 3330-1 work01
    

    To create a compressed 3350 CKD volume consisting of 560 cylinders (555 cylinders plus the 5 alternate cylinders) with volume serial number SYSRES in a file called dosvs34.24f:

        dasdinit -a -bz2 dosvs34.24f 3350-1 sysres
    

    To create a 3370 FBA volume with only 100000 sectors (instead of the usual 558000 sectors) with volume serial number WORK02 in a file called mini.work02.140:

        dasdinit mini.work02.140 3370 work02 100000
    

    To create a 3390 model 3 (triple density) CKD volume of 3339 cylinders with volume serial number WORK03:

        dasdinit triple.a88 3390-3 work03
    

    Because this volume exceeds 2GB, DASDINIT will create two files with triple_1.a88 containing cylinders 0-2518 and triple_2.a88 containing cylinders 2519-3339. If you specify

        dasdinit -lfs triple.a88 3390-3 work03
    

    then DASDINIT will create a single file triple.a88 containing all the cylinders. Your platform must support large file size to specify the -lfs option.

    Formatting the empty DASD volume

    After creating a DASD volume you can format it with a program such as standalone IBCDASDI or ICKDSF.

    Here is an example of the IBCDASDI control statements required to initialize a 3330 volume:

    
    WORK01 JOB  'INITIALIZE 3330 WORK VOLUME'
           MSG   TODEV=1052,TOADDR=009
           DADEF TODEV=3330,TOADDR=151,IPL=NO,VOLID=WORK01,BYPASS=YES
           VLD   NEWVOLID=WORK01,OWNERID=HERCULES
           VTOCD STRTADR=1,EXTENT=5
           END
    

    To run IBCDASDI, place the above statements in a file called init3330.txt and start Hercules in S/370 mode with a configuration file containing these statements:

    
    CPUSERIAL 001234
    CPUMODEL 3145
    MAINSIZE 2
    CNSLPORT 1052
    ARCHMODE S/370
    0009   1052
    000A   1442    ibcdasdi.rdr
    000C   1442    init3330.txt
    0151   3330    work01.151
    

    After IPLing from card reader device 00A, connect a telnet client to port 1052, and press enter. At the IBCDASDI prompt, enter:

    input=1442 00c

    Loading the new DASD volume

    Next you need to create a full volume dump file on your mainframe and convert it to AWSTAPE format using the tapeconv.jcl job in the Hercules source directory. The AWSTAPE file can then be downloaded in binary format to your PC where it can be defined as a virtual tape drive in the Hercules configuration file.

    A standalone program can now be IPLed into Hercules to restore the volume image from the virtual tape onto the formatted virtual DASD volume.


    Building a DASD volume from unloaded PDS or sequential files

    The dasdload program can be run from the Unix shell prompt to create a new DASD image file and load it with data from unloaded PDS or sequential files.

    The format of the dasdload command is:

    dasdload [options] ctlfile outfile msglevel

    where

    [options]
    -z
    build compressed dasd image file using zlib
    -bz2
    build compressed dasd image file using bzip2
    -0
    build compressed dasd image file with no compression
    -lfs
    build a large dasd image file (can exceed 2G)
    -a
    build dasd image file that includes alternate cylinders
    ctlname
    is the name of the control file which specifies the datasets that are to be loaded onto the newly-created volume
    outfile
    is the name of the DASD image file to be created
    msglevel
    is a number from 0 to 5 which controls the level of detail of the messages issued during the load.

    Control file

    The control file required by the dasdload program is an ASCII text file consisting of a volume statement followed by one dataset statement for each dataset to be created.

    The format of the volume statement is:

    volser devtype[-model] [cyls [ipltext] ]

    where:

    volser
    is the volume serial number for the newly-created volume
    devtype
    is the emulated device type (2311, 2314, 3330, 3340, 3350, 3375, 3380, or 3390) for the new volume. FBA device types are not supported by the dasdload program. Model may be specified like dasdinit above.
    cyls
    is the size of the new volume in cylinders. If cyls is coded as * or as 0 or is omitted, then the default size for the device type and model is used. Cylinders is ignored for compressed devices.
    ipltext
    is an optional parameter specifying the name of a file containing the IPL text which will be written to the volume. The file must be in the form of an object deck containing fixed length 80-byte EBCDIC records in the same format as expected by IBCDASDI or ICKDSF.

    The format of a dataset statement is:

    dsname method units pri sec dir dsorg recfm lrecl blksize keylen

    where:

    dsname
    is the dataset name
    method
    is the dataset loading method which can be one of the following:
    XMIT filename
    the dataset is loaded from an unloaded PDS created by the TSO XMIT command. The input is a binary file containing fixed length 80 byte records with no record delimiters.
    VS filename
    the dataset is loaded from an unloaded PDS created by IEBCOPY. The input is a binary file containing variable length spanned records with the record descriptor words omitted and with no record delimiters.
    SEQ filename
    the sequential dataset is loaded from a binary file. ascii/ebcdic translation is not currently supported. Also, the dsorg must either be PS or DA and recfm must either be F or FB.
    XMSEQ filename
    the dataset is loaded from a dump of a sequential dataset created by the TSO XMIT command. The input is a binary file containing fixed length 80 byte records with no record delimiters.
    TEXT filename
    a sequential dataset is loaded from an ASCII text file and translated to EBCDIC using the default codepage. Each line of text is treated as a logical record; LF and CRLF are recognized as end of line delimiters.
    EMPTY
    the dataset is initialized with an end of file record (if DSORG is PS) or an empty PDS directory (if DSORG is PO)
    DIP
    the dataset is initialized with a LOGREC header record
    CVOL
    the dataset is initialized as an OS SYSCTLG containing the minimum entries needed to IPL an OS/360 system
    VTOC
    specifies the size and location of the VTOC. A dataset name must be coded on this statement, although it is not used. If no VTOC statement is present, the VTOC will be placed after the last dataset on the volume and the size of the VTOC will be the minimum number of tracks necessary.
    units
    is the space allocation units: TRK or CYL.
    pri
    is the space allocation primary quantity
    sec
    is the space allocation secondary quantity
    dir
    is the number of directory blocks
    dsorg
    is the dataset organization: PS, PO, DA, or IS,
    recfm
    is the record format: F, FA, FM, FB, FBA, FBM, FBS, V, VA, VM, VB, VBA, VBM, VBS, or U.
    lrecl
    is the logical record length
    blksize
    is the block size
    keylen
    is the key length

    All parameters except dsname and method are optional. Defaults of zero are supplied for DCB parameters. For datasets loaded with the XMIT or XMSEQ methods, the DCB parameters are taken from the unloaded file, and the minimum space allocation required to load the dataset is used unless a larger quantity is specified. If space allocation is omitted, the default is TRK 1 0 0. If CYL is specified without any primary quantity then the default space allocation is 1 cylinder or the minimum number of cylinders required to load the dataset, whichever is larger.

    Examples

    [1] To create a 2314 volume in a file called sysres.230 using the control file sysres.plf with message level 2:

    dasdload sysres.plf sysres.230 2

    An example control file is shown below:

    #
    # Pack layout file for MFT system residence volume
    #
    sysres 2314 * ieaipl00.rdr
    sys1.parmlib    xmit    /cdrom/os360/reslibs/parmlib.xmi
    sys1.imagelib   xmit    /cdrom/os360/reslibs/imagelib.xmi
    sysctlg         cvol    trk 1 0 0       ps f 256 256 8
    sysvtoc         vtoc    trk 5
    sys1.logrec     dip     trk 1 0 0
    sys1.nucleus    xmit    /cdrom/os360/reslibs/nucleus.xmi cyl
    sys1.svclib     xmit    /cdrom/os360/reslibs/svclib.xmi cyl
    sys1.sysjobqe   empty   cyl 2 0 0       da f 176 176 0
    sys1.dump       empty   cyl 10 0 0      ps u 0 3625 0
    

    [2] To create a compressed 3390-3 volume in a file called linux.500 containing a bootable linux system for linux/390 installation using the control file linux.prm:

    dasdload -z linux.prm linux.500

    An example control file is shown below:

    #
    # Build a bootable linux disk
    #   [Note: the dataset names (sys1.linux. ...) are hard-coded in
    #          linuxipl.obj and cannot be changed without rebuilding it]
    #
    linux  3390-3 * linuxipl.obj
    sys1.linux.parmfile    SEQ images/redhat.prm trk   1 0 0 ps fb 1024 1024
    sys1.linux.tapeipl.ikr SEQ images/kernel.img trk 200 0 0 ps fb 1024 1024
    sys1.linux.initrd      SEQ images/initrd.img trk 200 0 0 ps fb 1024 1024
    

    Fixing the XCTL tables in SVCLIB

    On an OS/360 system, the Open/Close/EOV modules in SYS1.SVCLIB have XCTL tables embedded within them. These tables contain TTRs pointing to other modules, and these TTRs need to be adjusted after loading SVCLIB to DASD. OS/360 provides a program called IEHIOSUP to perform this function, but the catch is that you can't run IEHIOSUP until you have the system up and running, and you can't IPL until you have fixed the XCTL tables. To solve this problem, Hercules provides a program called dasdisup which can be run from the Unix command line after running dasdload.

    The format of the dasdisup command is:

    dasdisup outfile [sf=shadow-file-name]

    where

    outfile
    is the name of the DASD image file to be updated
    shadow-file-name
    (optional) is the name of the associated shadow file as specified in the Hercules config file

    Note: do not use this procedure except on OS/360 IPL volumes; other operating systems do not have XCTL tables.


    Other DASD utilities

    These programs can be used to extract data from CKD DASD images by means of commands issued at the Unix shell prompt.

    DASDLS - List datasets on volume

    DASDLS, written by Malcolm Beattie with subsequent enhancements by Chris Cheney, is a command to let you list the names and attributes of the datasets contained in a disk image.

    The command format is:
    dasdls [options] ckdfile [sf=shadow-file-name]
    where ckdfile is the name of a Unix file containing a CKD volume and shadow-file-name (optional) is the name of the associated shadow file.

    The options are:

    -info
    Show Format 1 DSCB information; this option is implied if any of the other options are set.
    -caldt
    Display dates as YYYYMMMDD; if this option is not supplied dates are displayed as YYDDD.
    -refdt
    Display the last-referenced date (not applicable to MVT); otherwise it is omitted.
    -expdt
    Display the expiry date; otherwise it is omitted.
    -hdr
    Display column headers; otherwise they are omitted.
    -dsnl[=n]
    Reserve space on the output line for dataset names up to 'n' characters; if '=n' is not supplied, space for 26 characters is reserved; if the -dsnl option is omitted, space for 44 characters is reserved.
    -yroffs[=n]
    Add the year offset 'n' (which may be negative) to dates before displaying them; if '=n' is omitted, 28 is used. No checking is done that the value of 'n' is sensible.
    Examples

    List all the datasets currently on the volume /mnt/sdb1/dasd/mvtres.cckd:

    dasdls /mnt/sdb1/dasd/mvtres.cckd
    

    List all the datasets currently on the volume /mnt/sdb1/dasd/mvtres.cckd, showing information from the Format 1 DSCB, with column headers and reserving only 20 characters for the dsname:

    dasdls -dsnl=20 -hdr /mnt/sdb1/dasd/mvtres.cckd
    

    List all the datasets currently on the volume /mnt/sdb1/dasd/mvtres.cckd, showing information from the Format 1 DSCB, with calendar date format and reserving only 20 characters for the dsname:

    dasdls -dsnl=20 -caldt /mnt/sdb1/dasd/mvtres.cckd
    

    DASDCAT - Display PDS members

    DASDCAT, written by Malcolm Beattie, is a command to let you read datasets from disk images.

    The command format is:
    dasdcat -i ckdfile [sf=shadow-file-name] dsname1 dsname2 ... -i ckdfile2 dsname10 ...
    where ckdfile is the name of a Unix file containing a CKD volume, shadow-file-name (optional) is the name of the associated shadow file, and dsname can be a plain (non-partitioned) dataset name (which is currently not handled) or of the form pdsname/memname where memname can be:

    • PDS member name (automatically uppercased), optionally followed by ":" and flags "a" or "c".
      • "c" means (c)ard images and turns a PDS members with a block size that's a multiple of 80 into multiple newline separated lines of 72 characters with EBCDIC converted to ASCII and with sequence numbers chopped off.
      • "a" means (a)sciify the member (but don't chop off sequence numbers or do the card image thing).
    • ? (don't forget to quote it to avoid the shell globbing it) to list the names of all PDS members instead of outputting their contents.
    • * (again, quote it or backwhack it to avoid it being a glob) to output all members of the PDS instead of just a named one. This can optionally be followed with colon-then-flags, as above. Each member is preceded with a line "> Member: memname" and, if the "c" for card-images flags is used, each line of the members' contents is preceded with "| " to guarantee it can be distinguished from contents.
    Examples
    
    % dasdcat -i mvtres.350 sf= mvtres_1.350 'sys1.parmlib/?'
    ieabld00
    ieaige00
    ieaigg00
    ieaigg01
    iearsv00
    ikjprm00
    lnklst00
    presres
    smfdeflt
    % dasdcat -i mvtres.350 sys1.parmlib/smfdeflt:c
     OPT=2, SYSTEM,JOB AND STEP DATA COLLECTION
     EXT=YES, USER EXITS ARE TO BE TAKEN
     JWT=15, MAXIMUM CONTINUOUS WAIT TIME IS 15 MINS.PER STEP
     BUF=400, A MINIMUM 400 BYTE BUFFER IS DEFINED
     SID=6A, SYSTEM ID IS 6A
     MDL=65, MODEL IS MOD 65
     OPI=YES, PERMIT OPERATOR INTERVENTION
     MAN=ALL, RECORD USER AND SYSTEM RECORDS
     PRM=(,282,NL) SYS1.MAN ALLOCATED TO NON-LABELED TAPE
    % dasdcat -i mvtres.350 sys1.help/\*:c
    > Member ACCOUNT
    | )S SUBCOMMANDS -
    | ADD/A,CHANGE/C,DELETE/D,LIST/L,LISTIDS/LISTI,HELP/H,END
    | )F FUNCTION -
    | THE ACCOUNT COMMAND PROCESSOR INVOKES THE CONVERSATIONAL PROGRAMS
    ...
    > Member ALLOC
    | )F FUNCTION -
    | THE ALLOCATE COMMAND DYNAMICALLY DEFINES AND ALLOCATES A DATA SET
    | WITH OR WITHOUT AN ATTRIBUTE LIST OF DCB PARAMETERS
    | )X SYNTAX -
    | ALLOCATE DATASET('DSNAME'/*) FILE('DDNAME')
    ...
    

    DASDPDSU - Unload PDS members

    DASDPDSU is a command which unloads PDS members from a disk image and copies each member to a file memname.mac in the current working directory.

    The command format is:
    dasdpdsu ckdfile [sf=shadow-file-name] pdsname [ascii]
    where ckdfile is the name of a Unix file containing a CKD volume, shadow-file-name (optional) is the name of the associated shadow file, and pdsname is the name of a PDS on that volume. If the optional ascii keyword is specified, the members will be unloaded as ASCII variable length text files. Otherwise the members are unloaded as fixed length EBCDIC binary files.


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsca.html0000664000175000017500000003331512564723224013627 00000000000000 Hercules Version 3: System Messages: CA - Communication Adapter

    Hercules Version 3: System Messages: CA - Communication Adapter

    This page describes the Communication Adapter emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCCA001I CCUU:Connect out to ipaddr:port failed during initial status : System Cause Text
    Explanation
    HERCULES attempted to make an outgoing TCP connection to ipaddr:port, but the system indicated that there was an error while processing the request.
    System Action
    The DIAL or ENABLE CCW that caused the connection attempt ends with Unit Check and Intervention Required. The reason for the failure is indicated in the System Cause Text field
    Operator Action
    None
    Programmer Action
    Correct the RHOST/RPORT configuration statements in the configuration file. If this message occured during a program initiated DIAL, correct the dial data.
    Module
    commadpt.c
    Function
    commadpt_connout

    HHCCA002I CCUU:Line Communication thread thread id started
    Explanation
    The thread responsible for asynchronous operations for the BSC emulated line CCUU has been started.
    System Action
    The system continues
    Operator Action
    None. This is an informational message
    Programmer Action
    None. This is an informational message
    Module
    commadpt.c
    Function
    commadpt_thread

    HHCCA003E CCUU:Cannot obtain socket for incoming calls : System Cause Text
    Explanation
    A system error occured while attempting to create a socket to listen for incoming calls.
    System Action
    The device creation is aborted.
    Operator Action
    None.
    Programmer Action
    Check the System Cause Text for any information relating to the host system. Notify support.
    Module
    commadpt.c
    Function
    commadpt_thread

    HHCCA004W CCUU:Waiting 5 seconds for port port to become available
    Explanation
    While attempting to reserve port port to listen to it, the system indicated the port was already being used.
    System Action
    The system waits 5 seconds and then retries the operation
    Operator Action
    Terminate the device if the port is in error
    Programmer Action
    Determine the program holding the specified port. If the port cannot be made available, use a different port.

    HHCCA005I CCUU:Listening on port port for incoming TCP connections
    Explanation
    The system is now listening on port port for incoming a tcp connection.
    System Action
    The system continues
    Operator Action
    None. This is an informational message
    Programmer Action
    None. This is an informational message

    HHCCA006T CCUU:Select failed : System Cause Text
    Explanation
    An error occured during a 'select' system call.
    System Action
    The BSC thread is terminated
    Operator Action
    None.
    Programmer Action
    Check the System Cause Text for any indication of where the error might come from. Notify Support.

    HHCCA007W CCUU:Outgoing call failed during ENABLE|DIAL command : System Cause Text
    Explanation
    The system reported that a previously initiated TCP connection could not be completed
    System Action
    The I/O operation responsible for the TCP outgoing connection is ended with Unit Check and Intervention Required.
    Operator Action
    If the error indicates that the error is temporary, retry the operation.
    Programmer Action
    Check that the destination for this line is correctly configured. If the operation was a DIAL attempt, check in the application configuration or operation data.

    HHCCA008I CCUU:cthread - Incoming Call
    Explanation
    The BSC thread has received an incoming call.
    System Action
    Depending on configuration and operational status, the call is either accepted or rejected. Eventually, an ongoign I/O operation may complete.
    Operator Action
    None. This is an informational message
    Programmer Action
    None. This is an informational message

    HHCCA009I CCUU:BSC utility thread terminated
    Explanation
    The BSC thread has ended
    System Action
    the system continue.
    Operator Action
    Refer to any previous error message if this message was not unexpected
    Programmer Action
    Refer to any previous error message if this message was not unexpected

    HHCCA010I CCUU:initialisation not performed
    Explanation
    The Device initialisation process has failed.
    System Action
    the system terminates or continues, depending on the reason for which the device was initialisation was initiated.
    Operator Action
    Refer to any previous error message
    Programmer Action
    Refer to any previous error message

    HHCCA011E CCUU:Error parsing Keyword
    Explanation
    The device keyword parser found an error while parsing a known keyword.
    System Action
    The system continues. The device initialisation routine turns on a NOGO flag.
    Operator Action
    for a runtime initialisation, correct the device initialisation parameters, otherwise notify the programmer.
    Programmer Action
    For an engine initialisation, correct the device configuration parameters in the configuration file.

    HHCCA012E CCUU:Unrecognized parameter Keyword
    Explanation
    The device keyword parser found an unknown keyword in the device parameter list.
    System Action
    The system continues. The device initialisation routine turns on a NOGO flag.
    Operator Action
    for a runtime initialisation, correct the device initialisation parameters, otherwise notify the programmer.
    Programmer Action
    For an engine initialisation, correct the device configuration parameters in the configuration file.

    HHCCA013E CCUU:Incorrect local port|remote port|local host|remote host specification value
    Explanation
    The device initialisation routine could not correctly parse a parameter value.
    System Action
    The system continues. The device initialisation routine turns on a NOGO flag.
    Operator Action
    for a runtime initialisation, correct the device initialisation parameters, otherwise notify the programmer.
    Programmer Action
    For an engine initialisation, correct the device configuration parameters in the configuration file.

    HHCCA014E CCUU:Incorrect switched/dial specification value; defaulting to DIAL=OUT
    Explanation
    The device initialisation routine found an incorrect DIAL value.
    System Action
    The system continues. The device initialisation routine turns on a NOGO flag.
    Operator Action
    for a runtime initialisation, correct the device initialisation parameters, otherwise notify the programmer.
    Programmer Action
    For an engine initialisation, correct the device configuration parameters in the configuration file.

    HHCCA015E CCUU:Missing parameter : DIAL=NO|IN|OUT|INOUT and LPORT|RPORT|LHOST|RHOST not specified
    Explanation
    The device initialisation routine found that a mandatory parameter was not provided for a specific DIAL Value.
    System Action
    The system continues. The device initialisation routine turns on a NOGO flag.
    Operator Action
    for a runtime initialisation, correct the device initialisation parameters, otherwise notify the programmer.
    Programmer Action
    For an engine initialisation, correct the device configuration parameters in the configuration file.
    Note
    For DIAL=NO , LPORT, RPORT and RHOST are needed
    For DIAL=IN , LPORT is required
    For DIAL=OUT None of LPORT,LHOST,RPORT,RHOST are required
    For DIAL=INOUT, LPORT is required

    HHCCA016W CCUU:Conflicting parameter : DIAL=NO|IN|OUT|INOUT and LPORT|RPORT|LHOST|RHOST=value specified
    Explanation
    The device initialisation routine found that a parameter was provided for a parameter that is not relevant for a specific DIAL Value.
    System Action
    The parameter is ignored. The system continues
    Operator Action
    for a runtime initialisation, correct the device initialisation parameters, otherwise notify the programmer.
    Programmer Action
    For an engine initialisation, correct the device configuration parameters in the configuration file.
    Note
    For DIAL=IN , RPORT and RHOST are ignored
    For DIAL=OUT , LPORT, LHOST, RPORT and RHOST are ignored
    For DIAL=INOUT, RPORT and RHOST are ignored

    HHCCA017I CCUU:LPORT|RPORT|LHOST|RHOST parameter ignored
    Explanation
    The system indicates that the parameter specified is ignored. This message is preceeded by message HHCCA016W
    System Action
    The system continues
    Operator Action
    None
    Programmer Action
    None

    HHCCA018E CCUU:Bind failed : System Cause Text
    Explanation
    While attempting to bind a socket to a specific host/port, the host system returned an uncorrectable error.
    System Action
    BSC Thread terminates
    Operator Action
    None
    Programmer Action
    Check that the LHOST parameter for this device is indeed a local IP address. Otherwise, notify support.

    HHCCA019E CCUU:BSC comm thread did not initialise
    Explanation
    The BSC communication thread reported that it terminated while the device was initialising.
    System Action
    The device is not initialised.
    Operator Action
    Check for any previously issued error message.
    Programmer Action
    Check for any previously issued error message.

    HHCCA020E CCUU:Memory allocation failure for main control block
    Explanation
    A memory allocation failure occured while attempting to reserve memory for the Communication Adapter control block
    System Action
    The device is not initialised.
    Operator Action
    None
    Programmer Action
    Contact support

    HHCCA021I CCUU:Initialisation failed due to previous errors
    Explanation
    The initialisation process for device CCUU did not complete succesfully
    System Action
    The device is not initialised
    Operator Action
    None
    Programmer Action
    Refer to any previous error message

    HHCCA300D Debug Message
    Explanation
    This is a debug message. CCW Tracing has been turned on for this device and the Line Handler issues debug messages to help diagnose interface, conformance and protocol issues.
    System Action
    The system continues
    Operator Action
    If the debug messages are no longer necessary, turn off CCW tracing (panel command : 't-CCUU').
    Programmer Action
    None


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmscf.html0000664000175000017500000012010012564723224013621 00000000000000 Hercules Version 3: System Messages: CF - Configuration Processing

    Hercules Version 3: System Messages: CF: Configuration Processing

    This page describes the terminal emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCCF001S Error reading file filename line lineno: error
    Meaning
    An error was encountered reading the configuration file named filename at line number lineno. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function read_config
    HHCCF002S File filename line lineno is too long
    Meaning
    The line at line number lineno in the configuration file filename is too long and cannot be processed.
    Action
    Correct the line and restart Hercules.
    Issued by
    bldcfg.c, function read_config
    HHCCF003S Cannot open file filename: error
    Meaning
    The configuration file named filename could not be opened. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF004S No device records in file filename
    Meaning
    The configuration file named filename does not contain any device definition records. Without them, Hercules cannot do any meaningful work.
    Action
    Specify one or more device definitions in the configuration file and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF005S Unrecognized argument argument
    Meaning
    An invalid argument, argument, was specified on the HTTPPORT configuration statement in the file named filename at line number lineno. Only the arguments auth and noauth are valid.
    Action
    Correct the invalid argument and restart Hercules.
    Issued by
    hsccmd.c, function httpport_cmd
    HHCCF008S Error in filename line lineno: Unrecognized keyword keyword
    Meaning
    An invalid configuration statement was specified in the file named filename at line number lineno. The invalid keyword was keyword.
    Action
    Correct the invalid statement and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF009S Error in filename line lineno: Incorrect number of operands
    Meaning
    The configuration statement at line lineno of the file named filename had an invalid number of operands. For all but the HTTPPORT statement, exactly one operand is required.
    Action
    Correct the invalid statement and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF010S Error in filename line lineno: Unknown or unsupported ARCHMODE specification mode
    Meaning
    The ARCHMODE configuration statement at line lineno of the file named filename specified an invalid architecture. Only S/370, ESA/390, or ESAME are valid. If one of these was specified, then support for that architecture was excluded when the copy of Hercules in use was compiled.
    Action
    Correct the specified value and restart Hercules. If the message was issued because support for the desired architecture was excluded, then recompile Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF011S Error in filename line lineno: serialno is not a valid serial number
    Meaning
    The serial number serialno specified on the CPUSERIAL configuration statement at line number lineno of the file named filename must be exactly six digits long, and must be a valid hexadecimal number.
    Action
    Correct the serial number and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF012S Error in filename line lineno: modelno is not a valid CPU model
    Meaning
    The model number modelno specified on the CPUMODEL configuration statement at line number lineno of the file named filename must be exactly four digits long, and must be a valid hexadecimal number.
    Action
    Correct the model number and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF013S Error in filename line lineno: Invalid main storage size size
    Meaning
    The main storage size size specified on the MAINSIZE configuration statement at line number lineno of the file named filename must be a valid decimal number whose value is at least 2. For 32-bit platforms the value must not exceed 4095.
    Action
    Correct the main storage size and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF014S Error in filename line lineno: Invalid expanded storage size size
    Meaning
    The expanded storage size size specified on the XPNDSIZE configuration statement at line number lineno of the file named filename must be a valid decimal number between 0 and 16777215. For 32-bit platforms the value must not exceed 4095.
    Action
    Correct the expanded storage size and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF015S Error in filename line lineno: Invalid console port number port
    Meaning
    The console port number port specified on the CNSLPORT configuration statement at line number lineno of the file named filename must be a valid nonzero decimal number.
    Action
    Correct the console port number and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF016S Error in filename line lineno: Invalid threadname thread priority priority
    Meaning
    The thread priority priority specified on the xxxPRIO configuration statement at line number lineno of the file named filename must be a valid decimal number.
    Action
    Correct the priority on the statement and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF017W Hercules is not running as setuid root, cannot raise threadname priority
    Meaning
    A negative value for the threadname thread priority parameter xxxPRIO was specified, but Hercules is not running as the root user (either directly or via the setuid mechanism). This parameter value would cause the priority of the CPU execution thread to be raised above the normal level if Hercules were running as root. Since it is not, however, the parameter will have no effect.
    Action
    Either specify a positive value to lower the CPU thread priority, zero to not alter the priority, or omit the statement entirely to use the Hercules default CPU thread priority of 15.
    Issued by
    bldcfg.c, function build_config
    HHCCF018S Error in filename line lineno: Invalid number of CPUs number
    Meaning
    The number of emulated CPUs number specified on the NUMCPU configuration statement at line number lineno of the file named filename must be a valid decimal number between 1 and the maximum number (MAX_CPU_ENGINES) defined when Hercules was built.
    Action
    Correct the number of emulated CPUs and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF019S Error in filename line lineno: Invalid number of VFs number
    Meaning
    The number of emulated Vector Facility engines number specified on the NUMVEC configuration statement at line number lineno of the file named filename must be a valid decimal number between 1 and the maximum number defined when Hercules was built (usually 2).
    Action
    Correct the number of emulated Vector Facility engines and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF020W Vector Facility support not configured
    Meaning
    A request for Vector Facility support was made by the NUMVEC configuration statement, but Hercules was built without the Vector Facility code. The request has been ignored.
    Action
    If Vector Facility support is desired, recompile Hercules. If not, remove the NUMVEC configuration statement.
    Issued by
    bldcfg.c, function build_config
    HHCCF021S Error in filename line lineno: Invalid maximum number of CPUs number
    Meaning
    The maximum number of emulated CPUs number specified on the MAXCPU configuration statement at line number lineno of the file named filename must be a valid decimal number. It must not exceed the maximum number (MAX_CPU_ENGINES) defined when Hercules was built.
    Action
    Correct the MAXCPU parameter and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF022S Error in filename line lineno: epoch is not a valid system epoch
    Patch config.c to expand the table.
    Meaning
    The system epoch epoch specified on the SYSEPOCH configuration statement at line number lineno of the file named filename must be one of the following: 1900, 1928, 1960, 1988, or 1970.
    Action
    Correct the system epoch and restart Hercules. If a different epoch is desired, a change must be made to the Hercules source file config.c and Hercules rebuilt.
    Issued by
    bldcfg.c, function build_config
    HHCCF023S Error in filename line lineno: offset is not a valid timezone offset
    Meaning
    The system timezone offset offset specified on the TZOFFSET configuration statement at line number lineno of the file named filename must be five characters long, and a valid decimal number of the form (+|-)number, where number must be between zero and 2359 (representing 23 hours, 59 minutes).
    Action
    Correct the time zone offset and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF024S Error in filename line lineno: Invalid TOD clock drag factor drag
    Meaning
    The TOD clock drag factor drag specified on the TODDRAG configuration statement at line number lineno of the file named filename must be a valid decimal number between 1 and 10000.
    Action
    Correct the TOD clock drag factor and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF025S Error in filename line lineno: Invalid panel refresh rate rate
    Meaning
    The control panel refresh rate rate specified on the PANRATE configuration statement at line number lineno of the file named filename must be either F, S, or a valid decimal number between 1 and 5000.
    Action
    Correct the control panel refresh rate and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF026S Error in filename line lineno: Unknown OS tailor specification tailor
    Meaning
    The OS tailoring value tailor specified on the OSTAILOR configuration statement at line number lineno of the file named filename must be either OS/390, z/OS, VSE, VM, LINUX, NULL, or QUIET.
    Action
    Correct the OS tailoring value and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF027S Error in filename line lineno: Invalid maximum device threads threads
    Meaning
    The maximum device threads threads specified on the DEVTMAX configuration statement at line number lineno of the file named filename must be a valid decimal number greater than -1.
    Action
    Correct the maximum device threads and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF028S Invalid program product OS license setting permission
    Meaning
    The program product OS permission permission specified on the PGMPRDOS configuration statement must be either LICENSED or RESTRICTED. The alternative spelling LICENCED is also accepted.
    Action
    Correct the program product OS permission and restart Hercules.
    Issued by
    hsccmd.c, function pgmprdos_cmd
    HHCCF029S Invalid HTTP port number port
    Meaning
    The HTTP server port number port specified on the HTTPPORT configuration statement must be either 80, or a valid decimal number greater than 1024.
    Action
    Correct the HTTP server port number and restart Hercules.
    Issued by
    hsccmd.c, function httpport_cmd
    HHCCF030S Error in filename line lineno: Invalid I/O delay value delay
    Meaning
    The I/O delay value delay specified on the IODELAY configuration statement at line number lineno of the file named filename must be a valid decimal number.
    Action
    Correct the I/O delay value and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF031S Cannot obtain sizeMB main storage: error
    Meaning
    An attempt to obtain the amount of main storage specified by MAINSTOR failed for the reason described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF032S Cannot obtain storage key array: error
    Meaning
    An attempt to obtain storage for the array of storage keys failed for the reason described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF033S Cannot obtain sizeMB expanded storage: error
    Meaning
    An attempt to obtain the amount of expanded storage specified by XPNDSTOR failed for the reason described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF034W Expanded storage support not installed
    Meaning
    A request was made for expanded storage by the XPNDSTOR configuration parameter, but Hercules was built without expanded storage support. The request was ignored.
    Action
    Either remove the XPNDSTOR configuration parameter, or recompile Hercules with expanded storage support included.
    Issued by
    bldcfg.c, function build_config
    HHCCF035S Error in filename line lineno: Missing device number or device type
    Meaning
    The I/O device definition statement at line number lineno of the file named filename did not contain a device number or a device type.
    Action
    Supply the missing value and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF036S Error in filename line lineno: number is not a valid device number(s) specification
    Meaning
    The I/O device definition statement at line number lineno of the file named filename specified an invalid device number number. The device number must be one to four hexadecimal digits.
    Action
    Correct the device number and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF037S Message pipe creation failed: error
    Meaning
    An attempt to create a pipe for communication with the control panel failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF038S Message pipe open failed: error
    Meaning
    An attempt to open the pipe for communication with the control panel failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF039W PGMPRDOS LICENSED specified.
              A licensed program product operating system is running.
              You are responsible for meeting all conditions of your
              software licenses.
    Meaning
    The configuration parameter PGMPRDOS LICENSED was specified and Hercules has detected that the operating system is a licensed program product. This message is issued to remind you that compliance with the terms of the license for your system's software is your responsibility.
    Action
    Be sure you know what you're doing.
    Issued by
    losc.c, function losc_check
    HHCCF040E Cannot create CPU number thread: error
    Meaning
    An attempt to create a new thread for execution of CPU number failed. The error is described by error. The CPU has not been added to the configuration.
    Action
    Correct the error and retry the operation.
    Issued by
    config.c, function configure_cpu
    HHCCF041E Device address already exists
    Meaning
    An attempt was made to define a device at address address. There is already a device at that address.
    Action
    Either choose another device address, or use the detach command to remove the existing device.
    Issued by
    config.c, function attach_device
    HHCCF042E Device type type not recognized
    Meaning
    An attempt was made to define a device of type type. This device type is not supported by Hercules. It may also indicate that the system was unable to load the device handler for the specified device type.
    Action
    Specify a supported device type. If the device type is supported, make sure the the system can load the load modules necessary for device operations. Either use the LD_LIBRARY_PATH environment variable or use ldconfig(8) to customize the library search path.
    Issued by
    config.c, function attach_device
    HHCCF043E Cannot obtain device block for device address: error
    Meaning
    An attempt to allocate memory for the control block describing the device with address address failed. The error is described by error. The device has not been defined.
    Action
    Correct the error and retry the operation.
    Issued by
    config.c, function attach_device
    HHCCF044E Initialization failed for device address
    Meaning
    The device at address address could not be initialized. The device initialization routine has issued a message describing the problem in further detail; refer to that message for more information.
    Issued by
    config.c, function attach_device
    HHCCF045E Cannot obtain buffer for device address: error
    Meaning
    An attempt to allocate memory for the data buffer for the device with address address failed. The error is described by error. The device has not been defined.
    Action
    Correct the error and retry the operation.
    Issued by
    config.c, function attach_device
    HHCCF046E Device address does not exist
    Meaning
    An attempt was made to remove a device at address address. There is no device at that address.
    Action
    Choose another device address to remove, if desired.
    Issued by
    config.c, function detach_device
    HHCCF047I Device address detached
    Meaning
    The device at address address has been successfully removed from the system.
    Issued by
    config.c, function detach_device
    HHCCF048E Device address does not exist
    Meaning
    An attempt was made to rename a device at address address. There is no device at that address.
    Action
    Choose another device address to rename, if desired.
    Issued by
    config.c, function define_device
    HHCCF049E Device address already exists
    Meaning
    An attempt was made to rename a device to address address. There is already a device at that address.
    Action
    Either choose another device address, or use the detach command to remove the existing device.
    Issued by
    config.c, function define_device
    HHCCF050I Device oldaddr defined as newaddr
    Meaning
    The device which was previously defined with the address oldaddr has been changed to the address newaddr.
    Issued by
    config.c, function define_device
    HHCCF051S Error in filename line lineno: verid is not a valid CPU version code
    Meaning
    The version code verid specified on the CPUVERID configuration statement at line number lineno of the file named filename must be exactly two digits long, and must be a valid hexadecimal number.
    Action
    Correct the model number and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF052S DIAG8CMD invalid option: option
    Meaning
    The argument option on the DIAG8CMD is invalid. Valid options are enable, disable, echo, and noecho,
    Action
    Correct the statement and restart Hercules.
    Issued by
    hsccmd.c, function diag8_cmd
    HHCCF053E Incorrect second device number in device range near character c
    Meaning
    The 2nd argument of a device range contains an incorrect device number
    Action
    Correct the statement and restart Hercules.
    Issued by
    config.c, function parse_devnums
    HHCCF054E Incorrect Device count near character c
    Meaning
    The count field in a device count specification is invalid
    Action
    Correct the statement and restart Hercules.
    Issued by
    config.c, function parse_devnums
    HHCCF055E Incorrect device address specification near character c
    Meaning
    The first or only CUU in a device specification statement is invalid
    Action
    Correct the statement and restart Hercules.
    Issued by
    config.c, function parse_devnums
    HHCCF056E Incorrect device address range. CUU1>CUU2
    Meaning
    The first device number of a range is greater than the last device number
    Action
    Correct the statement and restart Hercules.
    Issued by
    config.c, function parse_devnums
    HHCCF057E CUU is on wrong channel (1st device defined on channel CC)
    Meaning
    At least one of the devices in a device number specification is on a different channel than a previously defined device number within the same specification. All device numbers on a single configuration line must be on a single channel (Group of 256 devices)
    Action
    Correct the statement and restart Hercules.
    Issued by
    config.c, function parse_devnums
    HHCCF058E Some or all devices in CUU-CUU duplicate devices already defined
    Meaning
    At least one of the device numbers on a device specification statement defines a device number that is already specified on that same statement.
    Action
    Correct the statement and restart Hercules.
    Issued by
    config.c, function parse_devnums
    HHCCF061W ECPS:VM Statement deprecated. Use ECPSVM instead
    Meaning
    The "ECPS:VM" statement was encountered. This statement is deprecated in favor of the "ECPSVM" statement.
    Action
    The configuration statement is still carried out, but the statement syntax should be changed as soon as possible.
    Issued by
    config.c
    HHCCF062W Missing ECPSVM level value. 20 Assumed
    Meaning
    The "ECPSVM" statement keyword "LEVEL" was encountered, but no numeric level followed it
    Action
    The default level of 20 is used, and the ECPS:VM feature is made available. The statement should be corrected as soon as possible.
    Issued by
    config.c
    HHCCF063W Specifying ECPSVM level directly is deprecated. Use the 'LEVEL' keyword instead
    Meaning
    The deprecated "ECPSVM" level syntax form (without the LEVEL keyword) was found.
    Action
    The ECPS:VM Level is set to the specified value. The configuration statement should be updated to include the "LEVEL" keyword.
    Issued by
    config.c
    HHCCF064W Hercules set priority priority failed: error
    Meaning
    An attempt to change the priority of the Hercules process to priority failed. The error is described by error. The process priority has not been changed. Hercules overall performance may be impaired as a result.
    Action
    If performance problems are noted, correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF065I Hercules: tid=threadid, pid=processid, pgid=processgroupid, priority=priority
    Meaning
    Hercules thread id is threadid, its process id is processid, its process group id is processgroupid and its execution priority is priority.
    Issued by
    bldcfg.c, function build_config
    HHCCF066E Invalid HTTPROOT: error
    Meaning
    The pathname specified on your HTTPROOT statement is invalid. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCCF067S Incorrect keyword keyword for the ASN_AND_LX_REUSE statement
    Meaning
    The keyword specified for the ASN_AND_LX_REUSE statement is not ENABLE or DISABLE
    Action
    Correct the error and restart Hercules.
    Issued by
    hsccmd.c, function alrf_cmd
    HHCCF068E Invalid value: value; Enter "help scsimount" for help.
    Meaning
    The automatic SCSI tape mount value is not "NO" nor a value between 1 and 99 seconds inclusive.
    Action
    Reissue the SCSIMOUNT command.
    Issued by
    hsccmd.c, function scsimount_cmd
    HHCCF069I Run-options enabled for this run:
              NUMCPU:           n
              ASN-and-LX-reuse: Enabled/Disabled
              DIAG8CMD:         Enabled/Disabled
    Meaning
    This message confirms the setting of various run-time options specified in the configuration file at startup time.
    Action
    None.
    Issued by
    bldcfg.c, function build_config
    HHCCF074E Unspecified error occured while parsing Logical Channel Subsystem Identification
    Meaning
    A logic error occured while parsing the Logical Channel Subsystem Identification component of a device number or device number group.
    Action
    Notify hercules support. This is an error in the hercules parsing routines.
    Issued by
    config.c, function parse_lcss
    HHCCF075E No more than 1 Logical Channel Subsystem Identification may be specified
    Meaning
    While specifying a device number or device number group, more than 1 ':' character was encountered while parsing the Logical Channel Subsystem Identification component. There can be only one Logical Channel Subsystem Identification for a device or group of devices.
    Action
    Correct the device number or device number group specification and either reissue the command or restart the hercules engine (depending on whether the error occured while issuing a command or while starting the engine).
    Issued by
    config.c, function parse_lcss
    HHCCF076E Non numeric Logical Channel Subsystem Identification XX
    Meaning
    While specifying a device number or device number group, a non decimal value was encountered while parsing the Logical Channel Subsystem Identification component. The Logical Channel Subsystem Identification for a device or group of devices must be specified as a numeric value.
    Action
    Correct the device number or device number group specification and either reissue the command or restart the hercules engine (depending on whether the error occured while issuing a command or while starting the engine).
    Issued by
    config.c, function parse_lcss
    HHCCF077E Logical Channel Subsystem Identification NN exceeds maximum of 3
    Meaning
    While specifying a device number or device number group, a Logical Channel Identification was encountered that exceeded the architecture maximum value of MM. The Logical Channel Subsystem Identification for a device or group of devices must be within 0 and 3 (inclusive).
    Action
    Correct the device number or device number group specification and either reissue the command or restart the hercules engine (depending on whether the error occured while issuing a command or while starting the engine).
    Issued by
    config.c, function parse_lcss
    HHCCF079A A licensed program product operating system has been detected. All processors have been stopped.
    Meaning
    Hercules has detected that the operating system is a licensed program product, but the PGMPRDOS LICENSED parameter was not specified in the Hercules configuration file.
    Action
    Hercules enters the stopped state. To run this operating system you must obtain a license from the operating system supplier and specify the PGMPRDOS LICENSED parameter in the configuration file. If you are unable to obtain a valid license allowing you to run this operating system on your machine, you must use another operating system (such as MVS3.8J or Linux for System z) which does not require a license.
    Issued by
    losc.c, function losc_check
    HHCCF081I fname Will ignore include errors .
    Meaning
    An ignore include_errors statement was encountered in file fname requesting that any include statements subsequently found within file fname which happen to reference include files which do not exist should simply cause a HHCCF084W warning instead of a HHCCF085S fatal error.
    Action
    Processing continues. This is an informational-only message.
    Issued by
    bldcfg.c, function build_config
    HHCCF082S Error in fname line nnn: Maximum nesting level (nn) reached
    Meaning
    The maximum number of nested include statements has been exceeded. The include statement which caused the maximum nesting level of nn to be exceeded is identified as statement number nnn of file fname.
    Action
    This is a fatal error. Configuration file processing is immediately terminated and Hercules startup is aborted. Correct the error and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF083I fname1 Including fname2 at nnn.
    Meaning
    An include statement for file fname2 was encountered on line nnn of file fname1.
    Action
    Configuration file processing switches immediately to processing the statements contained in file fname2. Once all of the ststements in file fname2 have been completely processed, configuration file processing will then return to statement nnn+1 of file fname1. This is an informational-only message.
    Issued by
    bldcfg.c, function build_config
    HHCCF084W fname1 Open error ignored file fname2: error
    Meaning
    File fname1 contained an include statement for file fname2 which could not be opened because of error.
    Action
    Processing continues. This is a informational warning only. Check to make sure the filename specified by fname2 was spelled correctly and restart Hercules if desired.
    Issued by
    bldcfg.c, function build_config
    HHCCF085S fname1 Open error file fname2: error
    Meaning
    File fname1 contained an include statement for file fname2 which could not be opened because of error.
    Action
    This is a fatal error. Configuration file processing is immediately terminated and Hercules startup is aborted. Correct the possible misspelling of filename fname2 and restart Hercules.
    Issued by
    bldcfg.c, function build_config
    HHCCF086S Error in filename: NUMCPU nn must not exceed MAXCPU mm
    Meaning
    The number of online CPUs nn specified in the NUMCPU configuration statement in the file named filename cannot exceed the maximum number of CPUs mm specified in the MAXCPU configuration statement.
    Action
    Either decrease the NUMCPU parameter, or increase the MAXCPU parameter, and restart Hercules.
    Issued by
    bldcfg.c, function build_config


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmscp.html0000664000175000017500000002020612564723224013641 00000000000000 Hercules Version 3: System Messages: CP - CPU Emulation

    Hercules Version 3: System Messages: CP - CPU Emulation

    This page describes the CPU emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCCP001W CPU thread set priority priority failed: error
    Meaning
    An attempt to change the priority of the CPU thread to priority failed. The error is described by error. The thread priority has not been changed. Hercules overall performance may be impaired as a result.
    Action
    If performance problems are noted, correct the error and restart Hercules.
    Issued by
    cpu.c, function cpu_thread
    HHCCP002I CPUnumber thread started: tid=threadid, pid=processid, priority=priority
    Meaning
    The execution thread for CPU number number has been started. Its thread id is threadid, its process id is processid, and its execution priority is priority.
    Issued by
    cpu.c, function cpu_thread
    HHCCP003I CPUnumber architecture mode mode
    Meaning
    CPU number has been set to the mode architecture mode.
    Action
    If a different architecture mode is desired, it may be changed with the ARCHMODE configuration statement or the archmode control panel command.
    Issued by
    cpu.c, function cpu_thread
    HHCCP004I CPUnumber Vector Facility online
    Meaning
    The Vector Facility for CPU number is online and available for use.
    Issued by
    cpu.c, function cpu_thread
    HHCCP005E CPUnumber thread already started
    Meaning
    An attempt was made to add CPU number number to the configuration. This CPU already exists.
    Action
    If another CPU is desired in the configuration, select a different number.
    Issued by
    cpu.c, function cpu_thread
    HHCCP006S Cannot create timer thread: error
    Meaning
    An attempt to create the thread used for timing functions has failed. The error is described by error. The CPU thread terminates and successful continuation of Hercules is not possible.
    Action
    Correct the error and restart Hercules.
    Issued by
    cpu.c, function cpu_thread
    HHCCP007I CPUnumber architecture mode set to mode
    Meaning
    CPU number number has been changed to the architecture mode mode.
    Issued by
    cpu.c, function cpu_thread
    HHCCP008I CPUnumber thread ended: tid=threadid, pid=processid
    Meaning
    The execution thread for CPU number number has ended. Its thread id was threadid, and its process id was processid.
    Issued by
    cpu.c, function cpu_thread
    HHCCP009E CPU MASK MISMATCH: prevmask - currmask. Last instruction: instruction.
    Meaning
    The CPU interrupt mask has changed unexpectedly. The previous mask was prevmask, and the current mask is currmask. The last instruction executed was instruction. This is an internal error.
    Action
    Report this message and the circumstances to the Hercules developers.
    Issued by
    cpu.c, function process_interrupt
    HHCCP010I CPUnumber store status completed.
    Meaning
    CPU number number has completed a store status operation.
    Issued by
    cpu.c, function process_interrupt
    HHCCP011I CPUnumber: Disabled wait state
    Meaning
    CPU number number has entered a disabled wait state. It will not execute any further instructions unless it is reset or restarted. This is usually done to report a severe error in execution of an operating system.
    Action
    Correct the error denoted by the wait state code, if applicable.
    Issued by
    cpu.c, function process_interrupt
    HHCCP023I External interrupt: Interrupt key
    Meaning
    The CPU has taken an external interrupt because the operator pressed the interrupt key or issued the panel command ext.
    Action
    None.
    Issued by
    external.c, function perform_external_interrupt
    HHCCP024I External interrupt: Clock comparator
    Meaning
    The CPU has taken a clock comparator interrupt. This message is issued only when the CPU is in single-stepping or instruction-tracing mode.
    Action
    None. External interrupts are part of normal system operation.
    Issued by
    external.c, function perform_external_interrupt
    HHCCP025I External interrupt: CPU timer=xx...xx
    Meaning
    The CPU has taken a CPU timer interrupt. xx...xx is the hexadecimal value of the CPU timer. This message is issued only when the CPU is in single-stepping or instruction-tracing mode.
    Action
    None. External interrupts are part of normal system operation.
    Issued by
    external.c, function perform_external_interrupt
    HHCCP026I External interrupt: Interval timer
    Meaning
    The CPU has taken an external interrupt caused by the interval timer. This message is issued only when the CPU is in single-stepping or instruction-tracing mode.
    Action
    None. External interrupts are part of normal system operation.
    Issued by
    external.c, function perform_external_interrupt
    HHCCP027I External interrupt: Service signal intparm
    Meaning
    The CPU has taken a service signal external interrupt. intparm is the interrupt parameter. This message is issued only when the CPU is in single-stepping or instruction-tracing mode.
    Action
    None. External interrupts are part of normal system operation.
    Issued by
    external.c, function perform_external_interrupt
    HHCCP090W The configuration has been placed into a system check-stop state because of an incompatible service call
    Meaning
    A READ SCP INFO (code X'00020001') Service call has been issued from a CPU which is not a CP engine. All the CPUs in the configuration are put into a Check-Stop state.
    Action
    Ensure the CPU that issues the service call is a CP engine and restart the program.
    Issued by
    service.c, function service_call


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsct.html0000664000175000017500000000207712564723224013653 00000000000000 Hercules Version 3: System Messages: CT - Channel-to-Channel Adapter Emulation

    Hercules Version 3: System Messages: CT - Channel-to-Channel Adapter Emulation

    This page describes the channel-to-channel adapter emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCCT001I
    Meaning
    Issued by
    ctcadpt.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmscu.html0000664000175000017500000004516312564723224013657 00000000000000 Hercules Version 3: System Messages: CU - CCKD Utilities

    Hercules Version 3: System Messages: CU - CCKD Utilities

    Messages issued by the cckd utility commands (cckdcdsk, cckdcomp and cckdswap) and cckd utility functions (cckd_chkdsk, cckd_comp and cckd_swap) are described here. The utility functions are called by both the utility commands and Hercules.

    Messages

    Messages are in the format
    HHCCUnnnt file message text
    where nnn is the message number, t is either I, W or E, depending on the severity of the message. file will either be the part of the file name following the last slash (/ or \) when called by a utility command, or will be xxxx: file[n] where xxxx is the device number and n is the shadow file number when called by Hercules.

    The file portion of the message is omitted below for brevity.


    HHCCU101I converting to endian-format
    Meaning
    The file is in the wrong endian (byte order) format for the host architecture. The file is being converted to the host endian format endian-format.
    Issued by
    cckdutil.c functions cckd_comp and cckd_chkdsk
    HHCCU102I compress successful, n bytes released
    Meaning
    The compress function successfully completed and free n bytes from the file. If n is 0, then the level 2 tables were repositioned to the beginning of the file in order.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU103I file already compressed
    Meaning
    The compress function determined that the file is already compressed. The file is not updated.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU104I free space rebuilt
    Meaning
    Free space errors were detected and free space has been successfully rebuilt
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU300I number space images recovered
    Meaning
    Recovery phase 1 completed, recovering number spaces (trks or blkgrps)
    Issued by
    cckdutil.c function cckd_comp
    HHCCU301I space[id] recovered offset offset len length
    Meaning
    The space space (trk or blkgrp) was recovered at offset offset and length length. id is the trk or blkgrp number.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU500W recovery not completed, file opened read-only
    Meaning
    Phase 3 recovery did not complete because the file is not opened for write
    Action
    Omit the -ro option for cckdcdsk, or change the file permissions to enable the file to be opened for read-write for Hercules
    Issued by
    cckdutil.c function cckd_comp
    HHCCU501W recovery not completed, missing compression
    Meaning
    Phase 3 recovery did not complete because one or more trk or blkgrp images were compressed using a compression (zlib or bzip2) that was not built into Hercules
    Action
    Processing terminates. The file has not been updated. Build Hercules with the missing compression libraries.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU502W free space not rebuilt, file opened read-only
    Meaning
    Free space errors were detected but the free space was not rebuilt because the file is not opened for write
    Action
    Omit the -ro option for cckdcdsk, or change the file permissions to enable the file to be opened for read-write for Hercules
    Issued by
    cckdutil.c function cckd_comp
    HHCCU600W forcing check level level[; reason]
    Meaning
    Errors have been detected in the compressed file that warrant the escalation of the check level to level. An additional explanation reason may be supplied.
    Action
    At a minimum, free space will be rebuilt
    Issued by
    cckdutil.c function cckd_comp
    HHCCU601W cdevhdr inconsistencies found code=code
    Meaning
    The space statistics in the cckddasd device header (cdevhdr) contain inconsistencies described by code. code is a 16-bit bit field and more than one bit may be on. See cckdutil.c for the different bit settings.
    Action
    At a minimum, free space will be rebuilt
    Issued by
    cckdutil.c function cckd_comp
    %s offset 0x%" I32_FMT "x len %d is out of bounds
    HHCCU602W space offset offset len length is out of bounds
    Meaning
    The space space (trk, blkgrp or l2) either precedes the end of the L1 table (at the beginning of the file) or exceeds the end of the file
    Action
    The space will be recovered. If the space is an L2 table, then all tracks or block groups associated with the table will also be recovered.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU603W space1 offset offset1 len length overlaps space2 offset offset2
    Meaning
    The space space1 overlaps space space2.
    Action
    The spaces will be recovered. If either space is an L2 table, then all tracks or block groups associated with that table will also be recovered.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU604W space l2 inconsistency: len length, size size
    Meaning
    The space space (trk or blkgrp) has an inconsistent l2 entry. Either the length length is too small or is too large or exceeds the size size
    Action
    The space will be recovered.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU610W free space errors detected
    Meaning
    Free space is not consistent
    Action
    Free space will be rebuilt
    Issued by
    cckdutil.c function cckd_comp
    HHCCU620W space[id] hdr error offset offset: xxxxxxxxxx
    Meaning
    A header error was found for space (trk or blkgrp) during validation. id is the trk or blkgrp number. The header is located at file offset offset. The contents of the 5 byte header is xxxxxxxxxx in hex.

    The first byte of the header should be either 00 (compress none), 01 (compress zlib) or 02 (compress bzip2).
    For ckd, the next two bytes is the cylinder (in big-endian byte order) and the two bytes after that is the head (also in big-endian byte order).
    For fba, the next four bytes is the block group number (in big-endian byte order).

    The header contains an invalid value. Either the offset is incorrect or the header has been overlaid.

    Action
    The space will be recovered
    Issued by
    cckdutil.c function cckd_comp
    HHCCU621W space[id] compressed using compression, not supported
    Meaning
    During validation, the header for space (trk or blkgrp) indicates that the space was compressed using compression (zlib or bzip2) but support for that compression method was not built into Hercules. id is the trk or blkgrp number.
    Action
    Processing continues. However, no recovery will take place.
    Build Hercules with the specified compression library.
    Issued by
    cckdutil.c function cckd_comp
    HHCCU622W space[id] offset offset len length validation error
    Meaning
    The space (trk or blkgrp) at offset offset and length length failed validation. id is the trk or blkgrp number. Either the space did not uncompress successfully or the uncompressed space contains some kind of error. This error is detected during check level 3 validation.
    Action
    The space will be recovered
    Issued by
    cckdutil.c function cckd_comp
    HHCCU700E open error: error text
    Meaning
    Open failed for the file. The text associated with the error number is displayed.
    Action
    Processing for the file terminates.
    Issued by
    cckdccdsk.c, cckdcomp.c
    HHCCU701E fstat error: error text
    Meaning
    The file status system call failed. The text associated with the error number is displayed.
    Action
    Function processing terminates. Probable Hercules logic error. Contact the hercules mailing list for assistance.
    Issued by
    cckdutil.c functions cckd_swapend, cckd_comp and cckd_chkdsk
    HHCCU702E lseek error offset offset: error text
    Meaning
    File reposition to offset offset failed. The text associated with the error number is displayed.
    Action
    Function processing terminates. Probable Hercules logic error. Contact the hercules mailing list for assistance.
    Issued by
    cckdutil.c functions cckd_swapend, cckd_comp and cckd_chkdsk
    HHCCU703E read error rc=retcode offset offset len length: error text
    Meaning
    A read failed at offset offset for length length. If retcode is not negative then the read was incomplete and the value indicates how many bytes were read. Otherwise the text associated with the error number is displayed.
    Action
    Function processing terminates. Possible Hercules logic error. Possible hardware error. Contact the hercules mailing list for assistance.
    Issued by
    cckdutil.c functions cckd_swapend, cckd_comp and cckd_chkdsk
    HHCCU704E write error rc=retcode offset offset len length: error text
    Meaning
    A write failed at offset offset for length length. If retcode is not negative then the write was incomplete and the value indicates how many bytes were written. Otherwise the text associated with the error number is displayed.
    Action
    Function processing terminates. Possible Hercules logic error. Possible hardware error. Contact the hercules mailing list for assistance.
    Issued by
    cckdutil.c functions cckd_swapend, cckd_comp and cckd_chkdsk
    HHCCU705E malloc error, size size: error text
    Meaning
    Malloc (allocate memory) failed for size size.
    Action
    Function processing terminates. Try reducing Hercules storage requirements (eg mainsize).
    Issued by
    cckdutil.c functions cckd_swapend, cckd_comp and cckd_chkdsk
    HHCCU706E calloc error, size size: error text
    Meaning
    Calloc (allocate cleared memory) failed for size size.
    Action
    Function processing terminates. Try reducing Hercules storage requirements (eg mainsize).
    Issued by
    cckdutil.c functions cckd_swapend, cckd_comp and cckd_chkdsk
    HHCCU707E OPENED bit is on, use -f
    Meaning
    The file OPENED bit is on in the cckd header but -f was not specified
    Action
    File processing terminates. Make sure the file is not in use. If it is not, try the command again specifying the -f option.
    Issued by
    cckdcdsk.c, cckdcomp.c
    HHCCU708E chkdsk errors
    Meaning
    The utility called cckd_chkdsk for the file and it returned in error
    Action
    File processing terminates. Perform the actions suggested by the preceding cckd_chkdsk errors
    Issued by
    cckdcomp.c
    HHCCU900E dasd lookup error type=type cyls=cyls
    Meaning
    The device type type from the device header along with the number of cylinders cyls did not match a table entry in dasdtab.c. Note that type is the last two bytes of the device type (eg 90 for a 3390 device type).
    Action
    Function processing terminates. Specify the correct file name or manually correct the device header.
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU901E bad trksize: size1, expecting size2
    Meaning
    The track size size1 from the device header does match the track size size2 from the table entry in dasdtab.c
    Action
    Function processing terminates. Specify the correct file name or manually correct the device header.
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU902E bad number of heads: heads1, expecting heads2
    Meaning
    The number of heads heads1 from the device header does match the number of heads heads2 from the table entry in dasdtab.c
    Action
    Function processing terminates. Specify the correct file name or manually correct the device header.
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU903E bad `numl1tab': nbr1, expecting nbr2
    Meaning
    The number of L1 table entries nbr1 in the cckd device header does not match the number calculated nbr2. The number calculated is the number of cylinders times the number of heads (ie the number of tracks) divided by 256, rounded up by 1 if there is a remainder.
    Action
    Function processing terminates. Specify the correct file name or manually correct the device headers.
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU904E file too small to contain L1 table: %size1, need size2
    Meaning
    The size of the file size1 is not large enough to contain all L1 table entries; the size required is size2. The minimum size of a cckd file is
    512 + 512 + ( 4 * number of L1 entries)
    Action
    Function processing terminates. Specify the correct file name.
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU905E not enough file space for recovery
    Meaning
    During phase 2 recovery, there is not enough space in the maximum file size to contain the rebuilt L2 tables. This is an unusual situation and probably indicates some kind of programming error.
    Action
    Function processing terminates. The file has not been updated. Contact the hercules mailing list for assistance.
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU910E error during swap
    Meaning
    Error occurred during cckd_swap(). See the preceding error messages.
    Issued by
    cckdutil.c function cckd_chkdsk
    HHCCU999E not a compressed file
    Meaning
    The first 8 bytes of the file did not match an expected identifier. For a cckd file, the identifier must be either CKD_C370 or CKD_S370. For a cfba file, the identifier must be either FBA_C370 or FBA_S370.
    Action
    Function processing terminates. Specify the correct file name.
    Issued by
    cckdutil.c functions cckd_swapend, cckd_comp and cckd_chkdsk


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsda.html0000664000175000017500000000177512564723224013635 00000000000000 Hercules Version 3: System Messages: DA - DASD Emulation

    Hercules Version 3: System Messages: DA - DASD Emulation

    This page describes the DASD emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCDA001I
    Meaning
    Issued by
    ckddasd.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsdc.html0000664000175000017500000001260112564723224013625 00000000000000 Hercules Version 3: System Messages: DC - dasdcopy

    Hercules Version 3: System Messages: DC - dasdcopy

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator disk image copy utility.

    Note that this utility can be called by several names: dasdcopy, ckd2cckd, cckd2ckd, fba2cfba, and cfba2fba. The same program is used for all of these functions. The name used to invoke the program is reported in each of these messages as progname.

    Messages

    HHCDC001E progname: filename open error: error
    Meaning
    An error was encountered when trying to open the input file named filename to determine its type. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC002E progname: filename read error: error
    Meaning
    An error was encountered when trying to read the input file named filename to determine its type. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC003E progname: filename open failed
    Meaning
    An error was encountered when trying to open the input file named filename for copying. A previous message described the error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC004E progname: ckd lookup failed for size cyls
    Meaning
    There was no disk drive table entry that matched the number of cylinders in the CKD source file, size. The program cannot determine how much data to copy.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC005E progname: fba lookup failed, blks size
    Meaning
    There was no disk drive table entry that matched the number of blocks in the FBA source file, size. The program cannot determine how much data to copy.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC006E progname: filename create failed
    Meaning
    An error was encountered when trying to create the output file named filename. A previous message described the error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC007E progname: filename open failed
    Meaning
    An error was encountered when trying to open the newly created output file named filename. A previous message described the error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC008E progname: filename read error (track|block) number stat=status
    Meaning
    An error was encountered when trying to read a block or track from the input file named filename. The block or track is number number. The status returned is shown as status.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC009E progname: filename write error (track|block) number stat=status
    Meaning
    An error was encountered when trying to read a block or track from the input file named filename. The block or track is number number. The status returned is shown as status.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdcopy.c, function main
    HHCDC010I progname successfully completed
    Meaning
    The copy operation has completed successfully.
    Issued by
    dasdcopy.c, function main


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsdg.html0000664000175000017500000001051212564723224013630 00000000000000 Hercules Version 3: System Messages: DG - DYNGUI.DLL

    Hercules Version 3: System Messages: DG - DYNGUI.DLL

    This page describes the DYNGUI.DLL messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCDG001I dyngui.dll - name - version vers initiated
    Meaning
    The dyngui loadable module was successfully loaded and initiated.
    Action
    None. This message is informational only.
    Issued by
    dyngui.c
    HHCDG002I dyngui.dll terminated
    Meaning
    The dyngui loadable module was successfully terminated.
    Action
    None. This message is informational only.
    Issued by
    dyngui.c
    HHCDG003S select failed on input stream: errmsg
    Meaning
    The socket select function call failed on the input stream. errmsg  describes the exact error.
    Action
    None; this is a fatal error; the system is immediately terminated.
    Issued by
    dyngui.c
    HHCDG004S read failed on input stream: errmsg
    Meaning
    An unrecoverable i/o error occurred while reading from the input stream. errmsg  describes the exact error.
    Action
    None; this is a fatal error; the system is immediately terminated.
    Issued by
    dyngui.c
    HHCDG005E Device query buffer overflow! (device=xxxx)
    Meaning
    The device query buffer is not large enough to hold all of the information returned by the device handler. xxxx  is the device whose information was being queried at the time the error occurred.
    Action
    The system attempts to continue functioning, but unpredictable results may occur (i.e. the system could crash). You should report this error to the Hercules developers immediately so that they can build you a new dyngui.dll with a larger device query buffer. Since the dyngui.dll is an unloadable module however, you will need to restart Hercules in order to begin using the newly fixed version of dyngui.dll.
    Issued by
    dyngui.c
    HHCDG006S malloc pszInputBuff failed: errmsg
    Meaning
    There was not enough virtual memory on the host system to satisfy the malloc request for the input stream buffer. errmsg  describes the exact error.
    Action
    None; this is a fatal error; the system is immediately terminated. You should increase the size of your host system's virtual memory allocation so that there is enough for Hercules to run, or else decrease the amount of memory that Hercules needs in order to run (e.g. decrease your MAINSIZE value).
    Issued by
    dyngui.c
    HHCDG007S malloc pszCommandBuff failed: errmsg
    Meaning
    There was not enough virtual memory on the host system to satisfy the malloc request for the command processing buffer. errmsg  describes the exact error.
    Action
    None; this is a fatal error; the system is immediately terminated. You should increase the size of your host system's virtual memory allocation so that there is enough for Hercules to run, or else decrease the amount of memory that Hercules needs in order to run (e.g. decrease your MAINSIZE value).
    Issued by
    dyngui.c


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsdi.html0000664000175000017500000000270112564723224013633 00000000000000 Hercules Version 3: System Messages: DI - dasdinit

    Hercules Version 3: System Messages: DI - dasdinit

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program dasdinit.

    Messages

    HHCDI001I DASD initialization successfully completed.
    Meaning
    The requested DASD volume has been successfully initialized and is ready for use.
    Issued by
    dasdinit.c, function main
    HHCDI002I DASD initialization unsuccessful
    Meaning
    Initialization of the requested DASD volume was not successful.
    Action
    Refer to preceding error messages to determine the cause.
    Issued by
    dasdinit.c, function main


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsdl.html0000664000175000017500000017132212564723224013644 00000000000000 Hercules Version 3: System Messages: DL - dasdload

    Hercules Version 3: System Messages: DL - dasdload

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program dasdload.

    Information messages (I suffix) from dasdload have an associated message level. They are only issued if the third argument to dasdload, the verbosity level, is no lower than the message level. The default verbosity level is 1, which causes level 0 and 1 information messages to be issued.

    Messages

    HHCDL001E Cannot open filename: error
    Meaning
    The control file named filename cannot be opened. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function main
    HHCDL002E Volume serial statement missing from filename
    Meaning
    The control file named filename does not contain a volume serial statement. One is required.
    Action
    Supply a volume serial statement and rerun dasdload.
    Issued by
    dasdload.c, function main
    HHCDL003E Volume serial serial in filename line lineno is not valid
    Meaning
    The volume serial serial supplied in line lineno of the control file named filename is not valid. It must be from one to six characters long.
    Action
    Supply a valid volume serial and rerun dasdload.
    Issued by
    dasdload.c, function main
    HHCDL004E Device type type in filename line lineno is not recognized
    Meaning
    The device type type specified in line lineno of the control file named filename is not a supported CKD device.
    Action
    Specify a supported CKD device type and rerun dasdload.
    Issued by
    dasdload.c, function main
    HHCDL005E count in filename line lineno is not a valid cylinder count
    Meaning
    The requested number, count, of cylinders for the volume in line lineno of the control file named filename is invalid. It must be a decimal number.
    Action
    Supply a valid cylinder count and rerun dasdload.
    Issued by
    dasdload.c, function main
    HHCDL006I Creating type volume serial: tracks trks/cyl, length bytes/track
    Meaning
    The volume named serial, of type type, is being created, with tracks tracks per cylinder and length bytes per track.
    Message level
    0
    Issued by
    dasdload.c, function main
    HHCDL007E Cannot create filename
    Meaning
    The DASD image file named filename cannot be created. A previous message described the problem.
    Action
    Correct the reported error and rerun dasdload.
    Issued by
    dasdload.c, function main
    HHCDL008E Cannot open filename
    Meaning
    The DASD image file named filename could not be opened. A previous message described the problem.
    Action
    Correct the reported error and rerun dasdload.
    Issued by
    dasdload.c, function main
    HHCDL009I Loading type volume serial
    Meaning
    The newly created volume with serial serial, of type type, is being loaded.
    Message level
    0
    Issued by
    dasdload.c, function main
    HHCDL010E Cannot obtain storage for DSCB pointer array: error
    Meaning
    An attempt to obtain storage for the array of DSCB pointers, which will populate the VTOC, failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_control_file
    HHCDL011E Invalid statement in filename line lineno
    Meaning
    An invalid control statement was found at line lineno of the control file named filename.
    Action
    Correct the invalid statement and rerun dasdload.
    Issued by
    dasdload.c, function process_control_file
    HHCDL012I Creating dataset dsn at cyl cylinder head head
    Meaning
    The dataset named dsn is being created. It begins at cylinder cylinder, head head.
    Message level
    1
    Issued by
    dasdload.c, function process_control_file
    HHCDL013I Dataset dsn contains size tracks
    Meaning
    The dataset named dsn is size tracks long.
    Message level
    2
    Issued by
    dasdload.c, function process_control_file
    HHCDL014I Free space starts at cyl cylinder head head
    Meaning
    Free space on the volume begins at cylinder cylinder, head head, and extends to the end of the volume.
    Message level
    1
    Issued by
    dasdload.c, function process_control_file
    HHCDL015W Volume exceeds cylinders
    Meaning
    The amount of space used on the volume exceeds the number of cylinders, cylinders, requested in the control file. The number of cylinders was explicitly requested instead of being allowed to default to the size of a full volume for the device type. The volume has been extended to accomodate the data written.
    Action
    Specify more cylinders in the control file, or allow the number to default.
    Issued by
    dasdload.c, function process_control_file
    HHCDL016I Total of count cylinders written to filename
    Meaning
    A total of count cylinders have been written to the DASD image file named filename.
    Message level
    0
    Issued by
    dasdload.c, function process_control_file
    HHCDL017I Updating VTOC pointer pointer
    Meaning
    The pointer to the VTOC in the volume label is being updated to point to the VTOC, at location pointer.
    Message level
    5
    Issued by
    dasdload.c, function process_control_file
    HHCDL018E Cannot read VOL1 record
    Meaning
    An attempt to read the volume label failed. A previous message described the error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_control_file
    HHCDL019E Cannot read filename line lineno: error
    Meaning
    An error was encountered while trying to read the statement at line number lineno of the control file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_ctrl_stmt
    HHCDL020E Line too long in filename line lineno
    Meaning
    The line at line number lineno of the control file named filename is too long to be processed. This error can be caused by failing to terminate the last line with an end-of-line marker.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_ctrl_stmt
    HHCDL021E DSNAME or initialization method missing
    Meaning
    Either the dataset name, or the method to be used to initialize it, is missing from the control file. Both are required.
    Action
    Supply the missing value and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL022E Invalid initialization method: method
    Meaning
    The method specified to initialize the dataset, method, is invalid. It must be one of xmit, vs, empty, dip, cvol, vtoc, or seq.
    Action
    Correct the initialization method and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL023E Initialization file name missing
    Meaning
    A dataset was specified as being initialized by either the xmit, vs, or seq initialization methods, but no source file was specified to provide the data to be loaded.
    Action
    Specify a source file name, or specify the empty dataset initialization method if the dataset is not to be loaded.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL024E Invalid allocation units: units
    Meaning
    The allocation unit specified, units, is invalid. It must be either cyl or trk.
    Action
    Specify a valid allocation unit and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL025E Invalid primary space: space
    Meaning
    The primary space requested, space, is not a valid decimal number greater than 0.
    Action
    Specify a valid space request and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL026E Invalid secondary space: space
    Meaning
    The secondary space requested, space, is not a valid decimal number greater than 0.
    Action
    Specify a valid space request and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL027E Invalid directory space: space
    Meaning
    The PDS directory space requested, space, is not a valid decimal number greater than 0.
    Action
    Specify a valid space request and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL028E Invalid dataset organization: dsorg
    Meaning
    The requested dataset organization, dsorg, is invalid. It must be one of is, ps, da, or po.
    Action
    Specify a valid dataset organization and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL029E Invalid record format: recfm
    Meaning
    The requested record format, recfm, is invalid. It must be one of f, fb, fbs, v, vb, vbs, or u.
    Action
    Specify a valid record format and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL030E Invalid logical record length: lrecl
    Meaning
    The requested logical record length, lrecl, is invalid. It must be a decimal number between 0 and 32767.
    Action
    Specify a valid logical record length and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL031E Invalid block size: blksize
    Meaning
    The requested block size, blksize, is invalid. It must be a decimal number between 0 and 32767.
    Action
    Specify a valid block size and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL032E Invalid key length: keylen
    Meaning
    The requested key length, keylen, is invalid. It must be a decimal number between 0 and 255.
    Action
    Specify a valid key length and rerun dasdload.
    Issued by
    dasdload.c, function parse_ctrl_stmt
    HHCDL033E CCHH=cchh not found in extent table
    Meaning
    The absolute track address, cchh, was not found in the table listing the locations occupied by the dataset being loaded. There is likely a problem with the input file.
    Action
    Correct the input file and rerun dasdload.
    Issued by
    dasdload.c, function calculate_ttr
    HHCDL034E Cannot open filename: error
    Meaning
    The file named filename, which was specified as the source of IPL text to be written to the volume, could not be opened. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_ipl_text
    HHCDL035E Cannot read filename: error
    Meaning
    An error was encountered while reading the IPL text file named filename. The error is described by error. If no error is reported, the file did not contain an integral number of 80-byte card images.
    Action
    Correct the reported error, or supply a valid IPL text file consisting of 80-byte card images, and rerun dasdload.
    Issued by
    dasdload.c, function read_ipl_text
    HHCDL036E filename is not a valid object file
    Meaning
    The IPL text file named filename is not a valid object file. A record read from the file did not contain the required flag in the first byte.
    Action
    Supply a valid object file and rerun dasdload.
    Issued by
    dasdload.c, function read_ipl_text
    HHCDL037I IPL text address=addr length=length
    Meaning
    The object code from the current record of the IPL text file will be loaded into memory at address address, and is length bytes long.
    Message level
    5
    Issued by
    dasdload.c, function read_ipl_text
    HHCDL038E TXT record in filename has invalid count length
    Meaning
    A text record in the IPL text file named filename has an invalid length, length. The length cannot exceed 56.
    Action
    Supply a valid IPL text file and rerun dasdload.
    Issued by
    dasdload.c, function read_ipl_text
    HHCDL039E IPL text in filename exceeds buflen bytes
    Meaning
    The IPL text file named filename is too long to fit in the available space on the volume. The IPL text cannot exceed buflen bytes in length.
    Action
    Supply a shorter IPL text file, or specify a volume with a larger track size, and rerun dasdload.
    Issued by
    dasdload.c, function read_ipl_text
    HHCDL040E Input record CCHHR=cchhr exceeds output device track size
    Meaning
    The block to be written at absolute address cchhr is too large to fit on a track on the disk being loaded.
    Action
    Specify a device with a larger track size and rerun dasdload.
    Issued by
    dasdload.c, function write_block
    HHCDL041E Dataset exceeds extent size: reltrk=track, maxtrk=maxtrk
    Meaning
    The data to be written to the dataset is too large for the space requested for it. If the space request was allowed to default, the input file is corrupt.
    Action
    If the space request was made explicitly, request more space. If the request was defaulted, supply a valid input file. Rerun dasdload.
    Issued by
    dasdload.c, function write_block
    HHCDL042E Input record CCHHR=cchhr exceeds virtual device track size
    Meaning
    The block to be written at absolute address cchhr is too large to fit on a track on the disk being loaded. In addition, this message being issued instead of message HHCDL040E indicates an internal inconsistency in the way Hercules computes the space available on a track.
    Action
    Specify a device with a larger track size and rerun dasdload. Report the inconsistenct to the Hercules development team.
    Issued by
    dasdload.c, function write_block
    HHCDL043E filename cyl cylinder head head read error
    Meaning
    The data at cylinder cylinder, head head of the disk image file named filename could not be read in order to be updated. A previous message described the error.
    Action
    Correct the previously reported error and rerun dasdload.
    Issued by
    dasdload.c, function update_block
    HHCDL044E filename cyl cylinder head head invalid track header header
    Meaning
    The track header header at cylinder cylinder, head head in the disk image file named filename contained an address that did not match the actual address.
    Action
    Rerun dasdload. If the error persists, report it to the Hercules development team.
    Issued by
    dasdload.c, function update_block
    HHCDL045E filename cyl cylinder head head record record record not found
    Meaning
    The record requested for update at cylinder cylinder, head head, record record of the DASD image file named filename was not found.
    Action
    Rerun dasdload. If the error persists, report it to the Hercules development team.
    Issued by
    dasdload.c, function update_block
    HHCDL046E Cannot update cyl cylinder head head rec record: Unmatched KL/DL
    Meaning
    The record to be written at cylinder cylinder, head head, recordhead does not have the same key or data length as the record that already exists at that location. This is not allowed for a record update operation.
    Action
    Rerun dasdload. If the error persists, report it to the Hercules development team.
    Issued by
    dasdload.c, function update_block
    HHCDL047E filename cyl cylinder head head read error
    Meaning
    A read error was encountered when reading the track at cylinder cylinder, head head, in the disk image file named filename. A previous message described the error.
    Action
    Correct the error reported by the previous message and rereun dasdload.
    Issued by
    dasdload.c, function update_block
    HHCDL048I Updating cyl cylinder head head rec record kl keylen dl datalen
    Meaning
    The record at cylinder cylinder, head head, record record is being updated. It has a key length of keylen and data length datalen.
    Message level
    4
    Issued by
    dasdload.c, function update_block
    HHCDL049E Cannot obtain storage for DSCB: error
    Meaning
    An attempt to obtain storage to build a DSCB to describe a dataset on the volume being loaded failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function build_format1_dscb
    HHCDL050E DSCB count exceeds maximum, increase MAXDSCB
    Meaning
    There are too many datasets on the volume being loaded, and an internal structure in dasdload is full.
    Action
    Increase the value of the symbol MAXDSCB in the source program and recompile dasdload, then rerun the program.
    Issued by
    dasdload.c, function build_format1_dscb
    HHCDL051E Cannot obtain storage for DSCB: error
    Meaning
    An attempt to obtain storage to build a DSCB to describe the VTOC on the volume being loaded failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function build_format4_dscb
    HHCDL052E DSCB count exceeds maximum, increase MAXDSCB
    Meaning
    There are too many datasets on the volume being loaded, and an internal structure in dasdload is full.
    Action
    Increase the value of the symbol MAXDSCB in the source program and recompile dasdload, then rerun the program.
    Issued by
    dasdload.c, function build_format4_dscb
    HHCDL053E Cannot obtain storage for DSCB: error
    Meaning
    An attempt to obtain storage to build a DSCB to describe the free space on the volume being loaded failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function build_format5_dscb
    HHCDL054E DSCB count exceeds maximum, increase MAXDSCB
    Meaning
    There are too many datasets on the volume being loaded, and an internal structure in dasdload is full.
    Action
    Increase the value of the symbol MAXDSCB in the source program and recompile dasdload, then rerun the program.
    Issued by
    dasdload.c, function build_format5_dscb
    HHCDL055E VTOC too small, tracks tracks required
    Meaning
    The VTOC allocation of tracks is too small to hold the VTOC.
    Action
    Specify at least tracks tracks for the VTOC and rerun dasdload.
    Issued by
    dasdload.c, function write_vtoc
    HHCDL056E Error reading VTOC cyl cylinder head head
    Meaning
    The first track of the VTOC could not be read so it could be updated. A previous message described the error.
    Action
    Correct the error reported by the previous message and rerun dasdload.
    Issued by
    dasdload.c, function write_vtoc
    HHCDL057I VTOC starts at cyl cylinder head head and is tracks tracks
    Meaning
    The VTOC on the volume being loaded starts at cylinder cylinder, head head and is tracks tracks long.
    Message level
    1
    Issued by
    dasdload.c, function write_vtoc
    HHCDL058I Format format DSCB CCHHR=cchhr (TTR=ttr) dsname
    Meaning
    The format format DSCB is located at absolute address cchhr, and relative address within the VTOC ttr. If format is 1, the dataset described by the DSCB is named dsname.
    Message level
    4
    Issued by
    dasdload.c, function write_vtoc
    HHCDL059I Format 0 DSCB CCHHR cchhr (TTR=ttr)
    Meaning
    A format 0 (empty) DSCB is located at absolute address cchhr, and relative address within the VTOC ttr.
    Message level
    4
    Issued by
    dasdload.c, function write_vtoc
    HHCDL060E Error reading track cyl cylinder head head
    Meaning
    An error was encountered reading the track at cylinder cyl, head head. A previous message described the error.
    Action
    Correct the error reported by the previous message and rerun dasdload.
    Issued by
    dasdload.c, function write_vtoc
    HHCDL061E Incomplete text unit
    Meaning
    An text unit read from the input file was too short to contain a valid header. The input data is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function next_tu
    HHCDL062I position tuname key fields
    Meaning
    The text unit at position of the input buffer has the name tuname and the numeric key value key. There are fields fields in the text unit.
    Message level
    4
    Issued by
    dasdload.c, function next_tu
    HHCDL063E Too many fields in text unit
    Meaning
    A text unit was read from the input file that had too many fields in the header for that type of text unit. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function next_tu
    HHCDL064E Incomplete text unit
    Meaning
    An text unit read from the input file was too short to contain a valid field length. The input data is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function next_tu
    HHCDL065E Incomplete text unit
    Meaning
    An text unit read from the input file was shorter than the length in the field header. The input data is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function next_tu
    HHCDL066E filename read error: error
    Meaning
    An error was encountered when reading the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_xmit_rec
    HHCDL067E filename invalid segment header: header
    Meaning
    A segment read from the file named filename has an invalid header, header. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function read_xmit_rec
    HHCDL068E filename first segment indicator expected
    Meaning
    A segment read from the file named filename should have the first segment indicator set, but does not. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function read_xmit_rec
    HHCDL069E filename first segment indicator not expected
    Meaning
    A segment read from the file named filename should not have the first segment indicator set, but does. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function read_xmit_rec
    HHCDL070E filename control record indicator mismatch
    Meaning
    There was a mismatch between the first segment and the control record. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function read_xmit_rec
    HHCDL071E filename read error: error
    Meaning
    An error was encountered when reading a segment from the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_xmit_rec
    HHCDL072E filename read error: error
    Meaning
    An error was encountered when reading a COPYR1 record from the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_vs_rec
    HHCDL073E filename read error: error
    Meaning
    An error was encountered when reading a COPYR2 record from the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_vs_rec
    HHCDL074E filename read error: error
    Meaning
    An error was encountered when reading a data block header from the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_vs_rec
    HHCDL075E filename read error: error
    Meaning
    An error was encountered when reading a data block from the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function read_vs_rec
    HHCDL076I File number: number
    Meaning
    The file being processed is number number.
    Message level
    4
    Issued by
    dasdload.c, function process_inmr02
    HHCDL077E Invalid text unit at offset offset
    Meaning
    An invalid text unit was read from position offset. A previous message described the error. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_inmr02
    HHCDL078I File filenum: DSNAME=dsname
    Meaning
    The dataset name of file number filenum is dsname.
    Message level
    2
    Issued by
    dasdload.c, function process_inmr02
    HHCDL079I DSORG=dsorg RECFM=recfm LRECL=lrecl BLKSIZE=blksize KEYLEN=keylen DIRBLKS=dirblks
    Meaning
    For the dataset listed in the preceding HHCDL078I message, the dataset organization is dsorg, the record format is recfm, the logical record length is lrecl, the block size is blksize, the key length is keylen, and the directory block count is dirblks.
    Message level
    2
    Issued by
    dasdload.c, function process_inmr02
    HHCDL080E Invalid text unit at offset offset
    Meaning
    An invalid text unit was read from position offset. A previous message described the error. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_inmrxx
    HHCDL081E COPYR1 record length is invalid
    Meaning
    The length of the COPYR1 record is invalid. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_copyr1
    HHCDL082E COPYR1 header identifier not correct
    Meaning
    The header identifier of the COPYR1 record is invalid. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_copyr1
    HHCDL083E COPYR1 unload format is unsupported
    Meaning
    The COPYR1 record indicates that the file was unloaded in a formatthat is not supported by dasdload. The file may be corrupt, or it may simply be in a newer format than is supported by this version of dasdload.
    Action
    Supply a supported input file and rerun dasdload.
    Issued by
    dasdload.c, function process_copyr1
    HHCDL084I Original dataset: DSORG=dsorg RECFM=recfm LRECL=lrecl BLKSIZE=blksize KEYLEN=keylen
    Meaning
    For the original dataset, the dataset organization is dsorg, the record format is recfm, the logical record length is lrecl, the block size is blksize, the key length is keylen, and the directory block count is dirblks.
    Message level
    2
    Issued by
    dasdload.c, function process_copyr1
    HHCDL085I Dataset was unloaded from device type ucbtype (device)
    Meaning
    The dataset was unloaded from a device device, with UCB device type ucbtype.
    Message level
    2
    Issued by
    dasdload.c, function process_copyr1
    HHCDL086I Original device has cylinders cyls and heads heads
    Meaning
    The device listed in the preceding HHCDL085I message has cylinders cylinders and heads heads.
    Message level
    2
    Issued by
    dasdload.c, function process_copyr1
    HHCDL087E COPYR2 record length is invalid
    Meaning
    The length of the COPYR2 record just read is not valid. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_copyr2
    HHCDL088E Invalid number of extents extents
    Meaning
    The number of extents reported in the COPYR2 record is invalid, either less than 1 or more than 16. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_copyr2
    HHCDL089I Extent extent: Begin CCHH=begcchh End CCHH=endcchh Tracks=tracks
    Meaning
    For extent number extent, the extent starts at cylinder and head begcchh, and ends at endcchh, for a total of tracks tracks.
    Message level
    4
    Issued by
    dasdload.c, function process_copyr2
    HHCDL090I End of directory
    Meaning
    The end of the PDS directory has been reached.
    Message level
    3
    Issued by
    dasdload.c, function process_dirblk
    HHCDL091E Directory block record length is invalid
    Meaning
    The directory block read from the input file has the wrong length. It must be 276 bytes long. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_dirblk
    HHCDL092E Cannot obtain storage for directory block: error
    Meaning
    An attempt to obtain storage for the directory block being processed failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_dirblk
    HHCDL093E Number of directory blocks exceeds maxdblk, increase MAXDBLK
    Meaning
    The number of directory blocks in the dataset being processed exceeds the size of an internal control structure. The maximum number is maxdblk.
    Action
    Increase the value of the constant MAXDBLK in the program source and recompile dasdload.
    Issued by
    dasdload.c, function process_dirblk
    HHCDL094E Directory block byte count is invalid
    Meaning
    The length of the current directory block is invalid. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function process_dirblk
    HHCDL095I (Alias|Member) memname TTR=ttr
    Userdata=userdata
    Meaning
    The alias or member named memname is located at relative address ttr. If user data is present, it is printed as userdata.
    Message level
    3
    Issued by
    dasdload.c, function process_dirblk
    HHCDL096I Member name TTR=oldttr replaced by newttr
    Meaning
    In the directory entry for member name, the old pointer to the mamber oldttr was replaced by the member's actual relative address newttr.
    Message level
    4
    Issued by
    dasdload.c, function replace_ttr
    HHCDL097E Member name TTR=ttrnot found in dataset
    Meaning
    A request was made to update the directory entry for the member named name, but there was no directory entry to update.
    Action
    This is likely an internal logic error. Report the error to the Hercules development team.
    Issued by
    dasdload.c, function replace_ttr
    HHCDL098I Updating note list for member name at TTR=ttr CCHHR=cchhr
    Meaning
    The note list for the member named name, at relative address ttr, absolute address cchhr, is being updated.
    Message level
    4
    Issued by
    dasdload.c, function update_note_list
    HHCDL099E filename cyl cylinder head head read error
    Meaning
    An attempt to read the track in the DASD image file named filename at cylinder cylinder, head head, failed. A previous error described the failure.
    Action
    Correct the error reported by the previous message and rerun dasdload.
    Issued by
    dasdload.c, function update_note_list
    HHCDL100E filename cyl cylinder head head invalid track header header
    Meaning
    The header, header, of the track in the DASD image file named filename at cylinder cylinder, head head did not agree with the actual address of the track. This is probably an internal logic error.
    Action
    Report the error to the Hercules development team.
    Issued by
    dasdload.c, function update_note_list
    HHCDL101E filename cyl cylinder head head rec record note list record not found
    Meaning
    A request was made to update a note list record at cylinder cylinder, head head, record record, but the record was not found. The input dataset may be corrupt.
    Action
    Supply a valid input dataset and rerun dasdload.
    Issued by
    dasdload.c, function update_note_list
    HHCDL102E Member member note list at cyl cylinder head head rec record dlen datalen is too short for numttrs TTRs
    Meaning
    The data length datalen of the note list record for member member at cylinder cylinder, head head, record record, is too short to contain the requested number, numttrs, of record pointers. The input dataset is probably corrupt.
    Action
    Supply a valid input dataset and rerun dasdload.
    Issued by
    dasdload.c, function update_note_list
    HHCDL103E filename track read error cyl cylinder head head
    Meaning
    An attempt to read the track in the DASD image file named filename at cylinder cylinder, head head, failed. A previous error described the failure.
    Action
    Correct the error reported by the previous message and rerun dasdload.
    Issued by
    dasdload.c, function update_note_list
    HHCDL104I Updating cyl cylinder head head rec record kl keylen dl datalen
    Meaning
    The record at cylinder cylinder, head head, record record, with key length keynel and data length datalen isbeing updated.
    Message level
    4
    Issued by
    dasdload.c, function update_note_list
    HHCDL105E Directory block byte count is invalid
    Meaning
    The length of the current directory block is invalid. The input file is probably corrupt.
    Action
    Supply a valid input file and rerun dasdload.
    Issued by
    dasdload.c, function update_dirblk
    HHCDL106E Cannot open file filename: error
    Meaning
    An attempt to open the IEBCOPY input file named filename failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL107E Cannot obtain input buffer: error
    Meaning
    An attempt to obtain a 64K byte input buffer for reading the IEBCOPY input file failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL108E Cannot obtain storage for directory block array:error
    Meaning
    An attempt to obtain storage for the internal array used to store directory blocks failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL109E Cannot obtain storage for TTR table: error
    Meaning
    An attempt to obtain storage for the internal array used to store track pinters for later conversion failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL110I Processing file filename
    Meaning
    The input file named filename is being processed.
    Message level
    1
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL111I Control record: recname length length
    Meaning
    A control record named recname of length length has been read.
    Message level
    4
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL112I File number: filenum ((not) selected)
    Meaning
    The data file, number filenum, was (or was not) selected for processing.
    Message level
    4
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL113I Data record: length length
    Meaning
    A data record of length length has been read.
    Message level
    4
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL114E write error: input record CCHHR=cchhr (TTR=ttr) KL=keylen DL=datalen
    Meaning
    An error was encountered writing the data record at absolute address cchhr, relative address ttr, with key length keylen and data length datalen. A previous message described the error.
    Action
    Correct the error described by the previous message and rerun dasdload.
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL115I CCHHR=incchhr (TTR=inttr) KL=keylen DL=datalen -> CCHHR=outcchhr (TTR=outttr)
    Meaning
    The record at absolute address incchhr, relative address inttr, with key length keylen and data length datalen, is being written to the output DASD image at absolute address outcchhr, relative address outttr.
    Message level
    4
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL116E TTR count exceeds maxttr, increase MAXTTR
    Meaning
    The list of relative address pointers exceeds the size of the internal array used to contain them, maxttr.
    Action
    Increase the constant MAXTTR in the program source and recompile dasdload.
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL0117I Catalog block at cyl cylinder head head rec record
    Meaning
    A catalog record has been written to disk at cylinder cylinder, head head, and record record.
    Message level
    4
    Issued by
    dasdload.c, function cvol_initialize
    HHCDL0118I Catalog block at cyl cylinder head head rec record
    Meaning
    A catalog index record has been written to disk at cylinder cylinder, head head, and record record.
    Message level
    4
    Issued by
    dasdload.c, function cvol_initialize
    HHCDL0119I Catalog block at cyl cylinder head head rec record
    Meaning
    An empty catalog record has been written to disk at cylinder cylinder, head head, and record record.
    Message level
    4
    Issued by
    dasdload.c, function cvol_initialize
    HHCDL120I DIP complete at cyl cylinder head head record record
    Meaning
    The LOGREC dataset has been initialized. The last block written was at cylinder cylinder, head head, record record.
    Message level
    3
    Issued by
    dasdload.c, function dip_initialize
    HHCDL121E SEQ dsorg must be PS or DA: dsorg=dsorg
    Meaning
    The dataset organization specified for the input dataset was dsorg. It must be either PS or DA, but is not.
    Action
    Specify a valid dataset organization for sequential file processing, or specify the correct processing option for the file being loaded, and rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL122E SEQ recfm must be F or FB: recfm=recfm
    Meaning
    The record format specified for the input dataset was recfm. It must be either F or FB, but is not.
    Action
    Specify a valid record format for sequential file processing and rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL123E SEQ invalid lrecl or blksz: lrecl=lrecl blksz=blksz
    Meaning
    The logical record length specified for the input dataset was lrecl, and the block size was blksz. Either the block size was not a multiple of the logical record length and the record format was specified as FB, or the block size was different from the logical record length and the record format was specified as F.
    Action
    Specify a valid logical record length and block size for sequential file processing and rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL124E SEQ keyln must be 0 for blocked files
    Meaning
    The key length was specified as nonzero and the record format was specified as FB. This combination is invalid.
    Action
    If a key is required, specify a record format of F. If no key is required, specify a key length of 0. Rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL125E Cannot open filename: error
    Meaning
    An error was encountered when attempting to open the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL126E Cannot stat filename: error
    Meaning
    An error was encountered when attempting to obtain the size of the file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL127E filename cyl cylinder head head read error
    Meaning
    An attempt to read the track in the DASD image file named filename at cylinder cylinder, head head, failed. A previous error described the failure.
    Action
    Correct the error reported by the previous message and rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL128E filename read error: error
    Meaning
    An error was encountered reading the input file named filename. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function seq_initialize
    HHCDL130W WARNING -- XMIT file utility is not IEBCOPY; file filename not loaded
    Meaning
    The file filename cannot be loaded as an XMIT file because it is not an unloaded PDS.
    Action
    If filename is an unloaded sequential file, rerun dasdload specifying XMSEQ instead of XMIT.
    Issued by
    dasdload.c, function process_iebcopy_file
    HHCDL131I Control record: recname length length
    Meaning
    A control record named recname of length length has been read.
    Message level
    4
    Issued by
    dasdload.c, function process_inmcopy_file
    HHCDL132I File number: filenum ((not) selected)
    Meaning
    The data file, number filenum, was (or was not) selected for processing.
    Message level
    Issued by
    dasdload.c, function process_inmcopy_file
    HHCDL133I Data record: length length
    Meaning
    A data record of length length has been read.
    Message level
    4
    Issued by
    dasdload.c, function process_inmcopy_file
    HHCDL135I CCHHR=outcchhr (TTR=outttr) KL=keylen DL=datalen
    Meaning
    A record with key length keylen and data length datalen, is being written to the output DASD image at absolute address outcchhr, relative address outttr.
    Message level
    4
    Issued by
    dasdload.c, function process_inmcopy_file
    HHCDL136E Cannot open file filename: error
    Meaning
    An attempt to open the sequential XMIT input file named filename failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_inmcopy_file
    HHCDL137E Cannot obtain input buffer: error
    Meaning
    An attempt to obtain a 64K byte input buffer for reading the sequential XMIT input file failed. The error is described by error.
    Action
    Correct the error and rerun dasdload.
    Issued by
    dasdload.c, function process_inmcopy_file
    HHCDL138W WARNING -- XMIT file utility is not INMCOPY; file filename not loaded
    Meaning
    The file filename cannot be loaded as an XMSEQ file because it does not appear to contain an unloaded sequential file.
    Issued by
    dasdload.c, function process_inmcopy_file
    HHCDL139I Processing file filename
    Meaning
    The input file named filename is being processed as a sequential XMIT file.
    Message level
    1
    Issued by
    dasdload.c, function process_inmcopy_file


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsds.html0000664000175000017500000002377212564723224013660 00000000000000 Hercules Version 3: System Messages: DS - dasdisup

    Hercules Version 3: System Messages: DS - dasdisup

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program dasdisup.

    Messages

    HHCDS001E Cannot obtain storage for member array: error
    Meaning
    An attempt to obtain storage for the array of SYS1.SVCLIB members failed. The error is described by error.
    Action
    Correct the error and rerun dasdisup.
    Issued by
    dasdisup.c, function main
    HHCDS002I End of directory: count members selected
    Meaning
    The end of the SYS1.SVCLIB directory has been reached. count members have been selected for processing.
    Issued by
    dasdisup.c, function main
    HHCDS003E Directory block byte count is invalid
    Meaning
    The length of the directory block read is invalid. The SYS1.SVCLIB directory is probably corrupt.
    Action
    Rebuild SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function process_dirblk
    HHCDS004E Number of members exceeds MAX_MEMBERS
    Meaning
    SYS1.SVCLIB has too many members to fit in the array used to store their information.
    Action
    Increase the value of MAX_MEMBERS in dasdisup.c and recompile the program, then run it again.
    Issued by
    dasdisup.c, function process_dirblk
    HHCDS005E Member member TTR count is zero
    Meaning
    The member named member has no data associated with it. Since aliases have been skipped already, this means that the SYS1.SVCLIB directory is corrupt.
    Action
    Rebuild SYS1.SVCLIB and run dasdisup again.
    Issued by
    dasdisup.c, function process_dirblk
    HHCDS006W Member member is not single text record
    Meaning
    The member named member is not contained in a single text record. This is an invalid condition. The member will be skipped later, and message HHCDS011E will be issued.
    Action
    If this member must be processed, rebuild SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function process_dirblk
    HHCDS007W Member member size size exceeds X'7F8' bytes
    Meaning
    The member named member is too long. The maximum length of an OS/360 SVC load module is X'7F8' (2040 decimal) bytes. The member will be processed, but OS/360 will have problems with it.
    Action
    Correct the member in SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function process_dirblk
    HHCDS008W Member member size size is not a multiple of 8
    Meaning
    The member named member is not a multiple of 8 bytes long. Its actual size is size. This is not valid for an OS/360 load module. OS/360 will issue an ABEND when an attempt is made to load the module.
    Action
    Correct the member in SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function process_dirblk
    HHCDS009I Alias alias skipped
    Meaning
    The alias named alias has been skipped, since no processing is necessary for it.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS010I Member member skipped
    Meaning
    The member named member has been skipped, since it does not have an XCTL table.
    Action
    If the member should have an XCTL table, rebuild it in SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS011E Member member has multiple text records
    Meaning
    The member named member has multiple text records. This is not a valid condition for an OS/360 SVC module. The member will not be processed. Message HHCDS006W was issued for this member earlier.
    Action
    If this member must be processed, rebuild it in SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS012E Member member has invalid TTR ttr
    Meaning
    The pointer to the text record for the member named member is invalid. The pointer found is ttr. The member cannot be located to be processed. The SYS1.SVCLIB directory is probably corrupt.
    Action
    Rebuild SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS013I Processing member member text record TTR=ttr CCHHR=cchhr
    Meaning
    The member named member is being processed. Its relative location is ttr, and its absolute location is cchhr.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS014E Member member error reading TTR ttr
    Meaning
    An attempt to read the member named member, at the relative location ttr, failed. The member cannot be processed.
    Action
    Rebuild SYS1.SVCLIB and rerun dasdisup. If this is unsuccessful, rebuild the entire DASD volume.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS015E Member member TTR ttr text record length length is not valid
    Meaning
    The length length of the text record at location ttr of the member named member is less than 8, greater than 1024, or not a multiple of 8. All of these conditions must be met for the length to be valid. The member is probably corrupt.
    Action
    Rebuild the member in SYS1.SVCLIB and rerun dasdisup.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS016E Member member TTR ttr text record length textlength does not match length dirlength in directory
    Meaning
    The length textlength of the text record at location ttr is not the same as the length dirlength in the directory entry for member member. Either the member, or the directory, is probably corrupt.
    Action
    Rebuild the member in SYS1.SVCLIB and rerun dasdisup. If this does not correct the problem, rebuild SYS1.SVCLIB in its entirety.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS017E Member member TTR ttr XCTL table improperly terminated
    Meaning
    The XCTL table in member member at location ttr runs past the end of the text record. The member is probably corrupt.
    Action
    Rebuild the member and rerun dasdisup.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS018I member (Alias|Member) skipped
    Meaning
    The member or alias named member is not an Open, Close, or EOV module, and so does not have an XCTL table that needs to be updated. It has been skipped.
    Issued by
    dasdisup.c, function resolve_xctltab
    HHCDS019I In member member: reference TTRL=ttrl status
    Meaning
    A reference to the member named reference in the member named member was found, The referenced member is at the location ttrl in the table. status is optional; it may be one of:
    ** Member reference not found
    The referenced member was not found in SYS1.SVCLIB. The reference cannot be updated.
    replaced by TTRL=newttrl flag
    The reference was updated to point to the referenced member's actual location at newttrl. If flag is ****, the actual length of the referenced member is different from the length of the member in the reference pointer.
    Issued by
    dasdisup.c, function resolve_xctltab


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsdt.html0000664000175000017500000000566112564723224013656 00000000000000 Hercules Version 3: System Messages: DT - dasdcat

    Hercules Version 3: System Messages: DT - dasdcat

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program dasdcat.

    Messages

    HHCDT001E failed to open image filename
    Meaning
    An error was ancountered trying to open the DASD image file named filename. A previous message described the error.
    Action
    Correct the error and rerun dasdcat.
    Issued by
    dasdcat.c, function main
    HHCDT002E Can't make 80 column card images from block length length
    Meaning
    A block read from the member specified is not a multiple of 80 characters long, and so cannot be split evenly into 80-character card images. The actual length read is length.
    Action
    Select a different member, or omit the c flag from the member specification.
    Issued by
    dasdcat.c, function do_cat_cards
    HHCDT003E Directory block byte count is invalid
    Meaning
    The length of a PDS directory block in the specified dataset is invalid. The PDS directory is corrupt, or the dataset is not a PDS.
    Action
    Make sure the dataset specified is a PDS (partitioned dataset). If it is, then the dataset is corrupt.
    Issued by
    dasdcat.c, function process_dirblk
    HHCDT004E non-PDS-members not yet supported
    Meaning
    This version of dasdcat does not support reading sequential datasets.
    Action
    Specify a PDS as input to dasdcat.
    Issued by
    dasdcat.c, function do_cat_nonpds
    HHCDT005E unknown dataset name option: 'option'
    Meaning
    An invalid option was specified on the dataset name specification. Only the options a and c are valid.
    Action
    Remove the invalid option from the dataset name specification and rerun dasdcat.
    Issued by
    dasdcat.c, function do_cat


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsdu.html0000664000175000017500000007415112564723224013657 00000000000000 Hercules Version 3: System Messages: DU - DASD Utilities Common Functions

    Hercules Version 3: System Messages: DU - DASD Utilities Common Functions

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator DASD utility programs that are common to more than one utility.

    Messages

    HHCDU001I Updating cyl cylinder head head
    Meaning
    The track at cylinder number cylinder and head number head is being rewritten after being modified. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function read_track
    HHCDU002E filename write track error: stat=status
    Meaning
    An attempt to rewrite a track from the DASD image named filename failed. The status returned was status.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function read_track
    HHCDU003I Reading cyl cylinder head head
    Meaning
    The track at cylinder number cylinder and head number head is being read. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function read_track
    HHCDU004E filename read track error: stat=status
    Meaning
    An attempt to read a track from the DASD image named filename failed. The status returned was status.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function read_track
    HHCDU005I Searching extent 0 begin (begcyl,beghead) end (endcyl,endhead)
    Meaning
    The first extent of the dataset is being searched for a key. The extent starts at the track at cylinder begcyl, head beghead, and ends at the track at cylinder endcyl, head endhead. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function search_key_equal
    HHCDU006I Searching extent extent begin (begcyl,beghead) end (endcyl,endhead)
    Meaning
    An extent, extent, of the dataset is being searched for a key. The extent starts at the track at cylinder begcyl, head beghead, and ends at the track at cylinder endcyl, head endhead. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function search_key_equal
    HHCDU007E Track track not found in extent table
    Meaning
    An attempt was made to convert a track number to an absolute address, but the track specified, track, is beyond the end of the dataset.
    Action
    Correct the error and retry the operation. The dataset, the VTOC, or the DASD image may be corrupt.
    Issued by
    dasdutil.c, function convert_tt
    HHCDU008E Cannot obtain storage for device descriptor buffer: error
    Meaning
    An attempt to obtain storage for the buffer used to hold a CKD DASD image's description failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function open_ckd_image
    HHCDU009E Cannot open filename: error
    Meaning
    The CKD image file named filename could not be opened. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function open_ckd_image
    HHCDU010E filename read error: error
    Meaning
    An error was encountered while reading the CKD header record from the file named filename. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function open_ckd_image
    HHCDU011E filename CKD header invalid
    Meaning
    The file filename is not a valid CKD DASD image file. Either the first record is not the length of a CKD header record, or the marker in the header record is not correct.
    Action
    Supply the name of a valid CKD DASD image file and retry the operation.
    Issued by
    dasdutil.c, function open_ckd_image
    HHCDU012E DASD table entry not found for devtype type
    Meaning
    The device type in the CKD header record does not correspond to any known DASD device. The CKD DASD image file may be corrupt, or else the device is not supported by Hercules.
    Action
    Supply the name of a supported CKD DASD image file and retry the operation.
    Issued by
    dasdutil.c, function open_ckd_image
    HHCDU013E CKD initialization failed for filename
    Meaning
    The device-specific initialization routine for the file named filename failed. Another message describes the specific failure.
    Action
    See the specific message for the action needed.
    Issued by
    dasdutil.c, function open_ckd_image
    HHCDU014I filename heads=heads trklen=trklen
    Meaning
    The device represented by the CKD DASD image file named filename has heads heads and tracks of trklen bytes length. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function open_ckd_image
    HHCDU015I Updating cyl cylinder head head
    Meaning
    During processing of a request to close the CKD image file, the track at cylinder number cylinder and head number head is being rewritten, since it has been modified. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function close_ckd_image
    HHCDU016E filename write track error: stat=status
    Meaning
    During processing of a request to close the CKD image file, an attempt to rewrite a track from the DASD image named filename failed. The status returned was status.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function close_ckd_image
    HHCDU017E Cannot obtain storage for device descriptor buffer: error
    Meaning
    An attempt to obtain storage for the buffer used to hold a FBA DASD image's description failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function open_fba_image
    HHCDU018E DASD table entry not found for devtype type
    Meaning
    The default FBA device type does not correspond to any known DASD device. This is likely an internal programming error.
    Action
    Report the bug to the Hercules development team.
    Issued by
    dasdutil.c, function open_fba_image
    HHCDU019E FBA initialization failed for filename
    Meaning
    The device-specific initialization routine for the file named filename failed. Another message describes the specific failure.
    Action
    See the specific message for the action needed.
    Issued by
    dasdutil.c, function open_fba_image
    HHCDU020I filename sectors=sectors size=size
    Meaning
    The device represented by the FBA DASD image file named filename has sectors sectors of size bytes length. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function open_fba_image
    HHCDU021E VOL1 record not found
    Meaning
    The volume being processed does not have a volume label. It is probably blank and unformatted.
    Action
    Format the volume, or specify a formatted volume and retry the operation.
    Issued by
    dasdutil.c, function build_extent_array
    HHCDU022I VOLSER=serial VTOC=cchhr
    Meaning
    The volume being processed has the volume serial serial, and its VTOC format 4 DSCB is at absolute location cchhr. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function build_extent_array
    HHCDU023I VTOC start begcchh end endcchh
    Meaning
    The VTOC of the volume being processed begins at cylinder and head begcchh and ends at cylinder and head endcchh. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function build_extent_array
    HHCDU024E Dataset dsn not found in VTOC
    Meaning
    The requested dataset, dsn, was not found in the VTOC and does not exist on this volume.
    Action
    Specify the correct dataset name, or select the volume on which it appears.
    Issued by
    dasdutil.c, function build_extent_array
    HHCDU025I DSNAME=dsn F1DSCB CCHHR=cchhr
    Meaning
    The format 1 DSCB for the requested dataset, dsn, is at absolute location cchhr. This message is only issued if verbose message reporting has been selected.
    Issued by
    dasdutil.c, function build_extent_array
    HHCDU026E F1DSCB record not found
    Meaning
    The requested dataset is listed in the VTOC, but its format 1 DSCB record was not found when an attempt was made to read it. The VTOC may be corrupt.
    Action
    Recreate the dataset and retry the operation.
    Issued by
    dasdutil.c, function build_extent_array
    HHCDU027E F3DSCB record not found
    Meaning
    The requested dataset is reported to contain more than three extents in the format 1 DSCB, but its format 3 DSCB record was not found when an attempt was made to read it. The VTOC may be corrupt.
    Action
    Recreate the dataset and retry the operation.
    Issued by
    dasdutil.c, function build_extent_array
    HHCDU028E filename open error: error
    Meaning
    An attempt to create the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU029E filename device header write error: error
    Meaning
    An attempt to write the device header to the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU030E filename compressed device header write error: error
    Meaning
    An attempt to write the compressed device header to the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU031E Cannot obtain l1tab buffer: error
    Meaning
    An attempt to obtain storage for the primary lookup table buffer failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU032E filename primary lookup table write error: error
    Meaning
    An attempt to write the primary lookup table to the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU033E filename secondary lookup table write error: error
    Meaning
    An attempt to write the secondary lookup table to the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU034E filename dasdcopy ftruncate error: error
    Meaning
    An attempt to truncate the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU035E filename cylinder cyl head head write error: error
    Meaning
    An attempt to write the track at cylinder cyl, head head to the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU036E filename compressed device header lseek error: error
    Meaning
    An attempt to reposition to the beginning of the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU037E filename compressed device header write error: error
    Meaning
    An attempt to rewrite the compressed device header record of the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU038E filename secondary lookup table lseek error: error
    Meaning
    An attempt to reposition to the secondary lookup table of the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU039E filename secondary lookup table write error: error
    Meaning
    An attempt to rewrite the secondary lookup table of the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU040E filename close error: error
    Meaning
    An attempt to close the CKD DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU041I count cylinders successfully written to file filename
    Meaning
    The CKD DASD image file named filename has been successfully created. It contains count cylinders.
    Issued by
    dasdutil.c, function create_ckd_file
    HHCDU042E Cylinder count count is outside range min-max
    Meaning
    The requested number of cylinders, count, is outside the valid range from min to max.
    Action
    Specify a valid number of cylinders and retry the operation.
    Issued by
    dasdutil.c, function create_ckd
    HHCDU043E Cannot obtain track buffer: error
    Meaning
    An attempt to obtain storage for the track buffer failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_ckd
    HHCDU044I Creating type volume serial: cylinders cyls, tracks trks/cyl, length bytes/track
    Meaning
    A new volume is being created of device type type and volume serial number serial. It has cylinders cylinders, tracks tracks per cylinder, and length bytes per track.
    Issued by
    dasdutil.c, function create_ckd
    HHCDU045E Sector count count is outside range min-max
    Meaning
    The requested number of sectors, count, is outside the valid range from min to max.
    Action
    Specify a valid number of cylinders and retry the operation.
    Issued by
    dasdutil.c, function create_fba
    HHCDU046E Cannot obtain sector buffer: error
    Meaning
    An attempt to obtain storage for the sector buffer failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_fba
    HHCDU047I Creating type volume serial: sectors sectors, length bytes/sector
    Meaning
    A new volume is being created of device type type and volume serial number serial. It has sectors sectors and length bytes per sector.
    Issued by
    dasdutil.c, function create_fba
    HHCDU048E filename open error: error
    Meaning
    An attempt to create the FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_fba
    HHCDU049E filename dasdcopy ftruncate error: error
    Meaning
    An attempt to truncate the FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_fba
    HHCDU050E filename sector sector write error: error
    Meaning
    An attempt to write sector number sector to the FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_fba
    HHCDU051E filename close error: error
    Meaning
    An attempt to close the FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_fba
    HHCDU052I count sectors successfully written to file filename
    Meaning
    The FBA DASD image file named filename has been successfully created. It contains count sectors.
    Issued by
    dasdutil.c, function create_fba
    HHCDU053E File size too large: size [l1tab]
    Meaning
    The requested file size, size, would result in a primary lookup table that is too large. The DASD image cannot be created as a compressed image.
    Action
    Either specify fewer sectors, or create the DASD image uncompressed.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU054E filename open error: error
    Meaning
    An attempt to create the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU055I Creating type compressed volume serial: sectors sectors, length bytes/sector
    Meaning
    A new compressed FBA volume is being created of device type type and volume serial number serial. It has sectors sectors and length bytes per sector.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU056E filename devhdr write error: error
    Meaning
    An attempt to write the device header to the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU057E filename cdevhdr write error: error
    Meaning
    An attempt to write the compressed device header to the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU058E filename l1tab write error: error
    Meaning
    An attempt to write the primary lookup table to the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU059E filename l2tab write error: error
    Meaning
    An attempt to write the secondary lookup table to the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU060E filename block header write error: error
    Meaning
    An attempt to write a compressed block header to the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU061E filename block write error: error
    Meaning
    An attempt to write a compressed block to the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU062E filename block write error: error
    Meaning
    An attempt to write an uncompressed block to the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU063E filename cdevhdr lseek error: error
    Meaning
    An attempt to reposition to the beginning of the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU064E filename cdevhdr rewrite error: error
    Meaning
    An attempt to rewrite the compressed device header record of the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU065E filename l2tab lseek error: error
    Meaning
    An attempt to reposition to the secondary lookup table of the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU066E filename l2tab rewrite error: error
    Meaning
    An attempt to rewrite the secondary lookup table of the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU067E filename close error: error
    Meaning
    An attempt to close the compressed FBA DASD image file named filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    dasdutil.c, function create_compressed_fba
    HHCDU068I count sectors successfully written to file filename
    Meaning
    The compressed FBA DASD image file named filename has been successfully created. It contains count sectors.
    Issued by
    dasdutil.c, function create_compressed_fba


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsg.html0000664000175000017500000001140512564723224013466 00000000000000 Hercules Version 3: System Message Overview

    Hercules Version 3: System Message Overview

    This page describes the system messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Message format

    All Hercules-issued messages are of the form: HHCmmnnns text where:

    HHC
    is the message prefix for Hercules. All Hercules messages will have this prefix.
    mm
    specifies the function that issued the message, from the following list:
    CA
    Communication Adapter emulation
    CF
    Configuration file processing
    CP
    CPU emulation
    CT
    Channel-to-channel adapter emulation
    CU
    CCKD utility
    DA
    DASD emulation (both CKD and FBA)
    DC
    dasdcopy
    DG
    dyngui.dll
    DI
    dasdinit
    DL
    dasdload
    DS
    dasdisup
    DT
    dasdcat
    DU
    DASD utilities common functions
    HD
    Hercules Dynamic Loader
    HE
    hetinit
    HG
    hetget
    HM
    hetmap
    HT
    HTTP server
    HU
    hetupd
    IF
    hercifc (Network interface configuration handler)
    IN
    Hercules initialization
    LC
    LCS emulation
    LG
    System Log functions
    PN
    Hercules control panel command messages
    PR
    Printer emulation
    PU
    Card punch emulation
    RD
    Card reader emulation
    SD
    Socket devices common functions
    TA
    Tape device emulation
    TC
    tapecopy
    TE
    1052 and 3270 terminal emulation
    TM
    tapemap
    TS
    tapesplt
    TT
    TOD Clock and Timer Services
    TU
    TUN/TAP driver support
    VM
    VM/CP emulation facility
    nnn
    Specific message number, assigned more or less sequentially.
    s
    Message severity:
    S
    Severe error. Causes immediate termination of Hercules.
    E
    Error. The function being requested did not execute correctly, but Hercules should continue running.
    W
    Warning. Not necessarily an error, but something to take note of and possibly correct.
    I
    Information. General messages that do not require any further action.
    A
    Action. You need to do something.
    text
    Message text.

    You may look up any message by following the link from the function identifier in the above list.


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmshd.html0000664000175000017500000001745612564723224013647 00000000000000 Hercules Version 3: System Messages: HD - Hercules Dynamic Loader

    Hercules Version 3: System Messages: HD - Hercules Dynamic Loader

    This page describes the Dynamic Loader messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCHD001E registration alloc failed for entry
    Meaning
    Storage could not be obtained to register entrypoint entry
    Issued by
    hdl.c, function hdl_fent
    HHCHD002E cannot allocate memory for DLL descriptor: error
    Meaning
    Initialisation of the dynamic loader environment failed due to the error described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    hdl.c, function hdl_main
    HHCHD003E unable to open hercules as DLL: error
    Meaning
    The main hercules load module could not be opened by the dynamic loader. The dynamic loader error is described by error
    Action
    Correct the error and restart Hercules.
    Issued by
    hdl.c, function hdl_main
    HHCHD004I No initializer in module: error
    Meaning
    The initializer in DLL named module could not be found. The error is described by error
    Action
    Correct the error and restart Hercules.
    Issued by
    hdl.c, function hdl_main
    HHCHD005E module already loaded.
    Meaning
    An attempt was made to load an already loaded module.
    Action
    Unload to module first.
    Issued by
    hdl.c, function hdl_load
    HHCHD006S cannot allocate memory for DLL descriptor: error
    Meaning
    Initialisation of the dynamic loader environment failed due to the error described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    hdl.c, function hdl_load
    HHCHD007E unable to open DLL module: error
    Meaning
    The DLL named module could not be opened. The error is described by error.
    Action
    Ensure that the correct module is specified and is accessible.
    Issued by
    hdl.c, function hdl_load
    HHCHD008I No initializer in module: error
    Meaning
    The initializer in DLL named module could not be found. The error is described by error
    Action
    Correct the error and restart Hercules.
    Issued by
    hdl.c, function hdl_load
    HHCHD009E module not found
    Meaning
    An attempt was made to unload a module that was not loaded.
    Action
    No action required.
    Issued by
    hdl.c, function hdl_dele
    HHCHD010I Dependency check failed for module, version(vers_actual) expected(vers_exp)
    Meaning
    The version of the module's required dependency does not match the version of the dependency in the module that contains the dependency.
    Action
    No action required.
    Issued by
    hdl.c, function hdl_dchk
    HHCHD011I Dependency check failed for module, size(size_actual) expected(size_exp)
    Meaning
    The size of the module's required dependency does not match the size of the dependency in the module that contains the dependency.
    Action
    No action required.
    Issued by
    hdl.c, function hdl_dchk
    HHCHD012E No depency section in module: error
    Meaning
    The module being loaded does not contain the required dependency section. The error is described by error.
    Action
    Rebuild the module with the required HDL_DEPENDENCY_SECTION defined.
    Issued by
    hdl.c, function hdl_main
    HHCHD013E No depency section in module: error
    Meaning
    The module being loaded does not contain the required dependency section. The error is described by error.
    Action
    Rebuild the module with the required HDL_DEPENDENCY_SECTION defined.
    Issued by
    hdl.c, function hdl_load
    HHCHD014E Dependency check failed for module module
    Meaning
    One or more required dependencies were not satisfied. The preceding HHCHD010I and/or HHCHD011I message(s) identifies which of the dependencies failed and the reason why.
    Action
    If the module was not loaded, rebuild the module using the same version of the required dependency as the module that contains the dependency and try again.
    Issued by
    hdl.c, function hdl_load
    HHCHD015E Unloading of module not allowed
    Meaning
    An attempt was made to unload a module that was not allowed to be unloaded.
    Action
    No action required.
    Issued by
    hdl.c, function hdl_dele
    HHCHD018I Loadable module directory is dir
    Meaning
    The default loadable module directory was manually changed to dir via either a supplied MODPATH configuration file statement or via the -d command-line option.
    Action
    None required. This is an informational-only message.
    Issued by
    hdl.c, function hdl_setpath
    HHCHD100I Loading module ...
    Meaning
    Module module  is being loaded.
    Action
    No action required
    Issued by
    hsccmd.c, function ldmod_cmd
    HHCHD101I Module module loaded
    Meaning
    Module module  has been loaded.
    Action
    No action required
    Issued by
    hsccmd.c, function ldmod_cmd
    HHCHD102I Unloading module ...
    Meaning
    Module module  is being unloaded.
    Action
    No action required
    Issued by
    hsccmd.c, function rmmod_cmd
    HHCHD103I Module module unloaded
    Meaning
    Module module  has been unloaded.
    Action
    No action required
    Issued by
    hsccmd.c, function rmmod_cmd


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmshe.html0000664000175000017500000000200512564723224013630 00000000000000 Hercules Version 3: System Messages: HE - hetinit

    Hercules Version 3: System Messages: HE - hetinit

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program hetinit.

    Messages

    HHCHE001I
    Meaning
    Issued by
    hetinit.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmshg.html0000664000175000017500000000200112564723224013626 00000000000000 Hercules Version 3: System Messages: HG - hetget

    Hercules Version 3: System Messages: HG - hetget

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program hetget.

    Messages

    HHCHG001I
    Meaning
    Issued by
    hetget.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmshm.html0000664000175000017500000000200112564723224013634 00000000000000 Hercules Version 3: System Messages: HM - hetmap

    Hercules Version 3: System Messages: HM - hetmap

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program hetmap.

    Messages

    HHCHM001I
    Meaning
    Issued by
    hetmap.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsht.html0000664000175000017500000001215312564723224013654 00000000000000 Hercules Version 3: System Messages: HT - HTTP Server

    Hercules Version 3: System Messages: HT - HTTP Server

    This page describes the HTTP server messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCHT001I HTTP listener thread started: tid=threadid, pid=processid
    Meaning
    The HTTP server thread to accept and process incoming requests has been started. The thread id is threadid, and the process id is processid.
    Issued by
    httpserv.c, function http_server
    HHCHT002E socket: error
    Meaning
    An attempt to obtain a TCP socket to receive HTTP requests failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCHT003W Waiting for port port to become free
    Meaning
    The thread that handles HTTP connection requests is waiting for the TCP port denoted by port to become available for use.
    Action
    If this message persists, some other program has control of the TCP port listed. Find out which one it is and terminate it.
    Issued by
    httpserv.c, function http_server
    HHCHT004E bind: error
    Meaning
    An attempt to bind the socket to the TCP port to receive HTTP requests failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCHT005E listen: error
    Meaning
    An attempt to put the socket into listening state for HTTP requests failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCHT006I Waiting for HTTP requests on port port pid=num
    Meaning
    Hercules is ready to accept HTTP requests on port port.
    Issued by
    httpserv.c, function http_server
    HHCHT007E select: error
    Meaning
    An attempt to wait for data from HTTP requests failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCHT008E accept: error
    Meaning
    An attempt to accept a TCP connection for HTTP requests failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCHT009E fdopen: error
    Meaning
    An attempt to open the socket for reading HTTP requests failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCHT010E http_request create_thread: error
    Meaning
    An attempt to create a thread for processing HTTP requests failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    httpserv.c, function http_server
    HHCHT011E html_include: Cannot open filename: error
    Meaning
    The file named filename, which was included from another file, could not be opened. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    httpserv.c, function html_include
    HHCHT014I HTTPROOT = pathname
    Meaning
    The root directory path for the HTTP server is pathname.
    Action
    None.
    Issued by
    httpserv.c, function http_server


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmshu.html0000664000175000017500000000200512564723224013650 00000000000000 Hercules Version 3: System Messages: HU - hetutil

    Hercules Version 3: System Messages: HU - hetinit

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program hetutil.

    Messages

    HHCHU001I
    Meaning
    Issued by
    hetutil.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsif.html0000664000175000017500000000636212564723224013644 00000000000000 Hercules Version 3: System Messages: IF - hercifc

    Hercules Version 3: System Messages: IF - hercifc

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program hercifc.

    Messages

    HHCIF001E programname: Must be called from within Hercules.
    Meaning
    This program can only be called from Hercules itself, and may not be executed from the command line. The program was executed using the name programname.
    Action
    Don't do that.
    Issued by
    hercifc.c, function main
    HHCIF002E programname: Cannot obtain socket: error
    Meaning
    An attempt to obtain a socket for controlling the destination interface failed. The error is described by error. The program was executed using the name programname.
    Action
    Correct the error and retry the operation.
    Issued by
    hercifc.c, function main
    HHCIF003E programname: I/O error on read: error
    Meaning
    An attempt to read a request from Hercules failed. The error is described by error. The program was executed using the name programname.
    Action
    Correct the error and retry the operation.
    Issued by
    hercifc.c, function main
    HHCIF004W programname: Unknown request: request.
    Meaning
    The request from Hercules was invalid. The request code was request. The request has been ignored. The program was executed using the name programname.
    Action
    Make sure that the hercifc program is the same version as the running copy of Hercules. If so, this is an internal error. Report it.
    Issued by
    hercifc.c, function main
    HHCIF005E programname: ioctl error doing operation on interface: error
    Meaning
    An attempt to perform an ioctl operation, operation, on interface interface failed. The error is described by error. The program was executed using the name programname.
    Action
    Correct the error and retry the operation.
    Issued by
    hercifc.c, function main


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsin.html0000664000175000017500000001144712564723224013654 00000000000000 Hercules Version 3: System Messages: IN - Hercules Initialization

    Hercules Version 3: System Messages: IN - Hercules Initialization

    This page describes the system initialization messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCIN001S Cannot register SIGINT handler: error
    Meaning
    An attempt to register a handler for the SIGINT signal failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    impl.c, function main
    HHCIN002E Cannot suppress SIGPIPE signal: error
    Meaning
    An attempt to ignore the SIGPIPE signal failed. The error is described by error. This will cause Hercules to terminate abnormally if a printer device is defined to a pipe, and that pipe is closed while data is being written to it.
    Action
    Correct the error and restart Hercules. Do not print to a pipe until you have corrected the error.
    Issued by
    impl.c, function main
    HHCIN003S Cannot register SIGILL/FPE/SEGV/BUS/USR handler: error
    Meaning
    An attempt to register a handler for one of the listed signals failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    impl.c, function main
    HHCIN004S Cannot create watchdog thread: error
    Meaning
    An attempt to create the watchdog thread to monitor Hercules execution failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    impl.c, function main
    HHCIN005S Cannot create http_server thread: error
    Meaning
    An attempt to create the HTTP server thread failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    impl.c, function main
    HHCIN006S Cannot create panel thread: error
    Meaning
    An attempt to create the operator control panel thread failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    impl.c, function main
    HHCIN007S Cannot create devnum connection thread: error
    Meaning
    The shared device server was unable to create the thread meant to manage remote device devnum. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    impl.c, function main
    HHCIN008S DYNGUI.DLL load failed; Hercules terminated.
    Meaning
    The external GUI interface module 'dyngui.dll' could not loaded. The preceding HHCHD007E message should provide the reason for the failure.
    Action
    Correct the error and restart Hercules. If the error is Win32 error 126 ("The specified module could not be found"), check your Windows PATH setting and/or your MODPATH control statement to ensure one or both of them includes the directory where Hercules is executing from.
    Issued by
    impl.c, function main
    HHCIN009S Cannot register SIGTERM handler: error
    Meaning
    An attempt to register a handler for the SIGTERM signal failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    impl.c, function main
    HHCIN099I Hercules terminated
    Meaning
    Hercules has ended.
    Action
    None.
    Issued by
    hsccmd.c, function quit_cmd


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmslc.html0000664000175000017500000002740412564723224013644 00000000000000 Hercules Version 3: System Messages: LC - LAN Channel Station Emulation

    Hercules Version 3: System Messages: LC - LAN Channel Station Emulation

    This page describes the LAN Channel Station emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCLC001E nnnn unable to allocate LCSBLK
    Meaning
    There is insufficient storage to allocate the control block for LCS device number nnnn.
    Action
    Correct the error and restart Hercules.
    Issued by
    ctc_lcs.c, function LCS_Init
    HHCLC017E nnnn invalid device name devname
    Meaning
    The value of the -n or -dev parameter in the configuration statement for LCS device number nnnn is missing or too long.
    Action
    Correct the parameter and reinitialize the device.
    Issued by
    ctc_lcs.c, function ParseArgs
    HHCLC018E nnnn invalid MAC address macaddr
    Meaning
    The value of the -m or -mac parameter in the configuration statement for LCS device number nnnn is not a valid MAC address.
    Action
    Correct the parameter and reinitialize the device.
    Issued by
    ctc_lcs.c, function ParseArgs
    HHCLC019E nnnn too many arguments in statement.
    Meaning
    The configuration statement for LCS device number nnnn contains too many positional parameters.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function ParseArgs
    HHCLC020E nnnn invalid IP address ipaddr
    Meaning
    The first positional parameter in the configuration statement for LCS device number nnnn is not a valid IP address.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function ParseArgs
    HHCLC021E Invalid HWADD statement in filename: stmt
    Meaning
    The port number parameter of the HWADD statement stmt in OAT file filename is not numeric.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC022E Invalid MAC in HWADD statement in filename: stmt (macaddr)
    Meaning
    The second positional parameter of the HWADD statement stmt in OAT file filename is not a valid MAC address.
    Action
    Correct the parameter and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC023E Invalid ROUTE statement in filename: stmt
    Meaning
    The port number parameter of the ROUTE statement stmt in OAT file filename is not numeric.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC024E Invalid net address in ROUTE filename: stmt (netaddr)
    Meaning
    The second positional parameter of the ROUTE statement stmt in OAT file filename is not a valid IP network address.
    Action
    Correct the parameter and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC025E Invalid net mask in ROUTE filename: stmt (netaddr)
    Meaning
    The third positional parameter of the ROUTE statement stmt in OAT file filename is not a valid IP network mask.
    Action
    Correct the parameter and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC026E Error in filename: Missing device number or mode
    Meaning
    The OAT file filename contains a statement which cannot be identified.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC027E Error in filename: devnum: Invalid device number
    Meaning
    The device number devnum specified in the OAT file filename is not a valid hexadecimal number.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC028E Error in filename: stmt: Missing PORT number
    Meaning
    Statement stmt in OAT file filename for the IP port of an LCS device does not contain a port number.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC029E Error in filename: port: Invalid PORT number
    Meaning
    The port number port specified in the OAT file filename for the IP port of an LCS device is not a valid decimal number.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC031E Error in filename: stmt: Invalid entry starting at text
    Meaning
    The parameter text specified in statement stmt in the OAT file filename should be PRI, SEC, or NO.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC032E Error in filename: stmt: Invalid IP address (ipaddr)
    Meaning
    The parameter ipaddr specified in statement stmt in the OAT file filename is not a valid IP address.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC033E Error in filename: stmt: Missing PORT number
    Meaning
    Statement stmt in OAT file filename for the SNA port of an LCS device does not contain a port number.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC034E Error in filename: port: Invalid PORT number
    Meaning
    The port number port specified in the OAT file filename for the SNA port of an LCS device is not a valid decimal number.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC035E Error in filename: stmt: SNA does not accept any arguments
    Meaning
    Statement stmt in OAT file filename for the SNA port of an LCS device contains positional parameters which are not used for SNA ports.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC036E Error in filename: mode: Invalid MODE
    Meaning
    Mode mode specified in a device statement in the OAT file filename should be IP or SNA.
    Action
    Correct the statement and reinitialize the device.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC037E Error reading file filename line nnnn: description
    Meaning
    An error occurred reading the OAT file for an LCS device. description is the operating system's description of the error. The error occurred at line nnnn of file filename.
    Action
    Check that the correct OAT file name is specified in the configuration file.
    Issued by
    ctc_lcs.c, function ReadOAT
    HHCLC038E File filename line nnnn is too long
    Meaning
    An error occurred reading the OAT file for an LCS device. The error occurred at line nnnn of file filename. Either the line exceeds 255 characters, or there is no linefeed at the end of the file.
    Action
    Correct the OAT file.
    Issued by
    ctc_lcs.c, function ReadOAT
    HHCLC039E Cannot open file filename: description
    Meaning
    An error occurred opening the OAT file filename for an LCS device. description is the operating system's description of the error.
    Action
    Check that the correct OAT file name is specified in the configuration file.
    Issued by
    ctc_lcs.c, function BuildOAT
    HHCLC040E nnnn LCSDEV mmmm not in configuration
    Meaning
    The device number mmmm specified in the OAT file does not match the LCS device number nnnn in the configuration file.
    Action
    Correct the OAT file and reinitialize the device.
    Issued by
    ctc_lcs.c, function LCS_Init
    HHCLC055I tapn using MAC hh:hh:hh:hh:hh:hh
    Meaning
    The MAC address assigned the TUN/TAP device tapn is hh:hh:hh:hh:hh:hh.
    Action
    None.
    Issued by
    ctc_lcs.c, function LCS_LanStats
    HHCLC056W tapn NOT using MAC hh:hh:hh:hh:hh:hh
    Meaning
    MAC address hh:hh:hh:hh:hh:hh was requested in the configuration statement or in the OAT file for an LCS device but the operating system did not accept the request to change the MAC address for TUN/TAP device tapn.
    Action
    The device will use the MAC address shown in the preceding HHCLC055I message.
    Issued by
    ctc_lcs.c, function LCS_LanStats
    HHCLC073I nnnn: TAP device tapn opened
    Meaning
    LCS device number nnnn is now associated with the kernel TUN/TAP device named tapn.
    Action
    None.
    Issued by
    ctc_lcs.c, function LCS_Init


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmslg.html0000664000175000017500000001346312564723224013650 00000000000000 Hercules Version 3: System Messages: LG - Log functions

    Hercules Version 3: System Messages: LG - Log functions

    This page describes messages related to the log funtions of the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCLG001E Error redirecting stdout: error
    Meaning
    The stdout stream could not be redirected to the system logger, the error is described by error.
    Issued by
    logger.c, function logger_thread
    HHHCLG002E Error reading syslog pipe: error
    Meaning
    An error occurred while reading the syslog pipe. The error is described by error.
    Issued by
    logger.c, function logger_thread
    HHCLG003E Error writing hardcopy log: error
    Meaning
    The error as indicated by error occurred while writeing the hardcopy log.
    Issued by
    logger.c, function logger_thread
    HHCLG004E Error duplicating stderr: error
    Meaning
    Stdout could not be redirected to stderr. The error is described by error.
    Issued by
    logger.c, function logger_init
    HHCLG005E Error duplicating stdout: error
    Meaning
    Stderr could not be redirected to stdout. The error is described by error.
    Issued by
    logger.c, function logger_init
    HHCLG006E Duplicate error redirecting hardcopy log: error
    Meaning
    The error described by error occurred whilst redirecting the hardcopy log.
    Issued by
    logger.c, function logger_init
    HHCLG007S Hardcopy log fdopen failed: error
    Meaning
    An attempt to open a stream for the hardcopy log failed. The error is described by error.
    Issued by
    logger.c, function logger_init
    HHCLG008S logbuffer malloc failed: error
    Meaning
    An instorage buffer for the system log could not be obtained. The error is described by error.
    Issued by
    logger.c, function logger_init
    HHCLG009S Syslog message pipe creation failed: error
    Meaning
    An attempt to create the pipe for the system logger failed. The error is described by error.
    Action
    Check that your firewall is not preventing Hercules from opening a listening pipe.
    Issued by
    logger.c, function logger_init
    HHCLG012E Cannot create logger thread: error
    Meaning
    An attempt to create the logger thread failed. error is the description of the error code returned by the pthread_create call.
    Action
    If the error is "No error" ensure that Hercules has been correctly linked with the pthread library.
    Issued by
    logger.c, function logger_init
    HHCLG014E log not active
    Meaning
    A log off command was issued but there was no active log file.
    Action
    None.
    Issued by
    logger.c, function log_sethrdcpy
    HHCLG015I log closed
    Meaning
    The active log file has been closed as a result of a log off command.
    Action
    None.
    Issued by
    logger.c, function log_sethrdcpy
    HHCLG016E Error opening logfile filename: error
    Meaning
    The new log file requested by a log command could not be opened. error is the description of the error code returned by the open call.
    Action
    Reissue the log command with the correct filename.
    Issued by
    logger.c, function log_sethrdcpy
    HHCLG017S log file fdopen failed for filename: error
    Meaning
    The logger was unable to obtain the file descriptor for the new log file requested by a log command. error is the description of the error code returned by the fdopen call.
    Action
    Reissue the log command with the correct filename.
    Issued by
    logger.c, function log_sethrdcpy
    HHCLG018I log switched to filename
    Meaning
    As a result of a log command the logger is now writing to the requested log file.
    Action
    None.
    Issued by
    logger.c, function log_sethrdcpy


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmspn.html0000664000175000017500000001712612564723224013663 00000000000000 Hercules Version 3: System Messages: PN - Control Panel

    Hercules Version 3: System Messages: PN - Control Panel

    This page describes the control panel messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCPN001I Control panel thread started: tid=threadid, pid=processid
    Meaning
    The control panel thread has been started. Its thread id is threadid, and its process id is processid.
    Issued by
    panel.c, function panel_display
    HHCPN002S Cannot obtain keyboard buffer: error
    Meaning
    An attempt to obtain memory for the keyboard buffer, used to hold operator input, failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    panel.c, function panel_display
    HHCPN003S Cannot obtain message buffer: error
    Meaning
    An attempt to obtain memory for the message buffer, used to hold operator output, failed. The error is described by error.
    Action
    Correct the error and restart Hercules.
    Issued by
    panel.c, function panel_display
    HHCPN004E select: error
    Meaning
    An error was encountered while waiting for input from the console. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    panel.c, function panel_display
    HHCPN005E keyboard read: error
    Meaning
    An error was encountered while attempting to read keyboard input. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    panel.c, function panel_display
    HHCPN006E message pipe read: error
    Meaning
    An error was encountered while attempting to read from the pipe used to communicate to the control panel thread from the rest of Hercules. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    panel.c, function panel_display
    HHCPN007E RC file filename open failed: error
    Meaning
    The RC file containing commands to be executed at Hercules startup, named filename, could not be opened. The error is described by error.
    Action
    Correct the error and restart Hercules, if necessary. The commands contained in the file may be issued manually.
    Issued by
    panel.c, function process_rc_file
    HHCPN008I RC file processing thread started using file filename
    Meaning
    Processing of the commands contained in the file named filename has begun.
    Issued by
    panel.c, function process_rc_file
    HHCPN009E RC file buffer malloc failed: error
    Meaning
    An attempt to obtain storage for the buffer for commands being read from the startup command file failed. The error is described by error.
    Action
    Correct the error and restart Hercules, if needed. The comands contained in the file may be issued manually.
    Issued by
    panel.c, function process_rc_file
    HHCPN010W Ignoring invalid RC file pause statement: argument
    Meaning
    The argument, argument, on the pause statement in the startup command file is invalid. It must be a decimal number between 0 and 999. Processing will continue without any pause.
    Action
    Correct the invalid argument and restart Hercules, if desired.
    Issued by
    panel.c, function process_rc_file
    HHCPN011I Pausing RC file processing for delay seconds...
    Meaning
    Processing of the startup command file is being delayed for delay seconds because of a pause statement in the file.
    Issued by
    panel.c, function process_rc_file
    HHCPN012I Resuming RC file processing...
    Meaning
    Processing of the startup command file has resumed at the expiration of the delay interval.
    Issued by
    panel.c, function process_rc_file
    HHCPN013I EOF reached on RC file. Processing complete.
    Meaning
    The end of the startup command file has been reached, and processing of the file is complete.
    Issued by
    panel.c, function process_rc_file
    HHCPN014E I/O error reading RC file: error
    Meaning
    An error was encountered while reading a command from the startup command file. The error is described by error. Any remaining commands in the file will not be processed.
    Action
    Correct the error and restart Hercules, if desired. Any unprocessed commands may be issued manually.
    Issued by
    panel.c, function process_rc_file
    HHCPN052E Target CPU nnnn type cputype does not allow ipl
    Meaning
    An ipl command was issued but the target CPU nnnn is a processor engine of type cputype which does not support the initial program load procedure.
    Action
    Use the cpu command to set the target CPU to a processor of type CP, IFL, or ICF, then re-issue the ipl command.
    Issued by
    hsccmd.c, function ipl_cmd2
    HHCPN180E 'sh' commands are disabled
    Meaning
    The 'sh' (shell) command has been purposely disabled via a SHCMDOPT configuration file statement. Shell commands entered via the Hercules hardware console will not be processed.
    Action
    Remove or modify the SHCMDOPT configuration file statement and restart Hercules.
    Issued by
    hsccmd.c, function sh_cmd
    HHCPN181E Device number s:CCUU not found
    Meaning
    The device number CCUU on Logical Channel Subsystem s was not found in the configuration.
    Action
    Reissue the command with an existing device number.
    Issued by
    hsccmd.c, Multiple functions


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmspr.html0000664000175000017500000001405412564723224013664 00000000000000 Hercules Version 3: System Messages: PR - Printer Emulation

    Hercules Version 3: System Messages: PR - Printer Emulation

    This page describes the printer emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCPR001E File name missing or invalid for printer address
    Meaning
    There was no file name specified for the printer at address address, or else there was one specified, but it was too long.
    Action
    Correct the error in the Hercules configuration file. The device may be made available by specifying a filename with the devinit command.
    Issued by
    printer.c, function printer_init_handler
    HHCPR002E Invalid argument for printer address: argument
    Meaning
    An invalid argument was specified on the definition of the printer at address address.
    Action
    Correct or remove the invalid argument.
    Issued by
    printer.c, function printer_init_handler
    HHCPR003E address Error writing to filename: error
    Meaning
    An error was encountered when writing output for the printer at address address to the file named filename. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function write_buffer
    HHCPR004E Error opening file filename: error
    Meaning
    An error was encountered when opening the file named filename. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function open_printer
    HHCPR005E address device initialization error: pipe: error
    Meaning
    An error was encountered when opening a pipe for the printer at address address. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function open_printer
    HHCPR006E address device initialization error: fork: error
    Meaning
    An error was encountered when starting the program to process the output from the printer at address address. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function open_printer
    HHCPR007I pipe receiver (pid=processid) starting for address
    Meaning
    The program to process the output from the printer at address address is starting. Its process id is processid.
    Issued by
    printer.c, function open_printer
    HHCPR008E address dup2 error: error
    Meaning
    The file descriptor for stdin could not be duplicated for the program to process the output from the printer at address address. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function open_printer
    HHCPR009E address dup2 error: error
    Meaning
    The file descriptor for stdout could not be duplicated for the program to process the output from the printer at address address. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function open_printer
    HHCPR010E address dup2 error: error
    Meaning
    The file descriptor for stderr could not be duplicated for the program to process the output from the printer at address address. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function open_printer
    HHCPR011I pipe receiver (pid=processid) terminating for address
    Meaning
    The program to process the output from the printer at address address has ended sucessfully. Its process id was processid.
    Issued by
    printer.c, function open_printer
    HHCPR012E address Unable to execute program: error
    Meaning
    The program named program to process the output from the printer at address address could not be started. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    printer.c, function open_printer


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmspu.html0000664000175000017500000000467412564723224013676 00000000000000 Hercules Version 3: System Messages: PU - Card Punch Emulation

    Hercules Version 3: System Messages: PU - Card Punch Emulation

    This page describes the card punch emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCPU001E File name missing or invalid
    Meaning
    The file name specified for punched output is invalid, or no file name is given.
    Action
    Correct the error and retry the operation.
    Issued by
    cardpch.c, function cardpch_init_handler
    HHCPU002E Invalid argument: argument
    Meaning
    An invalid argument, argument, was specified for the card punch. Valid arguments are ascii, ebcdic, and crlf.
    Action
    Correct the invalid argument and retry the operation.
    Issued by
    cardpch.c, function cardpch_init_handler
    HHCPU003E Error opening file filename: error
    Meaning
    The file named filename could not be opened for output of card punch data. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardpch.c, function cardpch_execute_ccw
    HHCPU004E Error writing to filename: error
    Meaning
    The file named filename encountered an error while writing card punch data. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardpch.c, function write_buffer


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsrd.html0000664000175000017500000002202512564723224013645 00000000000000 Hercules Version 3: System Messages: RD - Card Reader Emulation

    Hercules Version 3: System Messages: RD - Card Reader Emulation

    This page describes the card reader emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCRD001E Out of memory
    Meaning
    A request to allocate memory for the list of files to be read failed.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD002E File name too long (max=max): "filename"
    Meaning
    The file name specified by filename is too long. The maximum length is max.
    Action
    Specify a shorter name.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD003E Unable to access file "filename": error
    Meaning
    The file specified by filename could not be accessed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD004E Out of memory
    Meaning
    A request to allocate memory for the list of files to be read failed.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD005E Specify 'ascii' or 'ebcdic' (or neither) but not both
    Meaning
    Both of the character set translation options ascii and ebcdic were specified. At most one is allowed.
    Action
    Select only one character set translation option.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD006E Only one filename (sock_spec) allowed for socket devices
    Meaning
    More than one filename argument was given for a socket card reader device. Only one is allowed. This error can also result if an option name is misspelled.
    Action
    Remove the extraneous filenames, or correct the misspelled options.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD007I Defaulting to 'ascii' for socket device address
    Meaning
    The socket card reader device at address address has been set to ASCII mode, since neither translation option was specified. The socket card reader device cannot automatically select the translation option.
    Action
    If you wish to read cards without translation from ASCII to EBCDIC, you must specify the ebcdic option on the reader definition.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD008W 'multifile' option ignored: only one file specified
    Meaning
    Only one file was specified for input to the card reader, and the multifile option was specified. This option is meaningless with only one input file. The option has been ignored.
    Action
    If you wish to read more than one input file without signalling end-of-file or intervention required between them, they must all be specified on the same reader definition. If you only wish to process one file, omit the multifile option.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD009E File name too long (max=max): "filename"
    Meaning
    The file name specified by filename is too long. The maximum length is max.
    Action
    Specify a shorter name.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD010E Unable to access file "filename": error
    Meaning
    The file specified by filename could not be accessed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function cardrdr_init_handler
    HHCRD011E Close error on file "filename": error
    Meaning
    An attempt to close the file specified by filename failed. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function cardrdr_close_device
    HHCRD012I ipaddr (hostname) disconnected from device address (socketspec)
    Meaning
    The client on the host named hostname, with the IP address ipaddr, has disconnected from the socket card reader device at address address, specified by socketspec.
    Issued by
    cardrdr.c, function cardrdr_close_device
    HHCRD013E Error opening file filename: error
    Meaning
    The file named filename could not be opened for reading. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function open_cardrdr
    HHCRD014E Error reading file filename: error
    Meaning
    An error was encountered while attempting to read the first 160 bytes of the file named filename in order to determine its character set. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function open_cardrdr
    HHCRD015E Seek error in file filename: error
    Meaning
    An error was encountered while attempting to return to the beginnning of file named filename after determining its character set. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function open_cardrdr
    HHCRD016E Error reading file filename: error
    Meaning
    An error was encountered while attempting to read an EBCDIC card image from the file named filename. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function read_ebcdic
    HHCRD017E Unexpected end of file on filename
    Meaning
    Too few characters were read from the file named filename. The autopad option was not specified.
    Action
    Either ensure that all records in the file are 80 bytes long, or specify the autopad option on the reader definition.
    Issued by
    cardrdr.c, function read_ebcdic
    HHCRD018E Error reading file filename: error
    Meaning
    An error was encountered while attempting to read an ASCII card image from the file named filename. The error is described by error.
    Action
    Correct the error and retry the operation.
    Issued by
    cardrdr.c, function read_ascii
    HHCRD019E Card image exceeds size bytes in file filename
    Meaning
    A line in the file named filename is too long to fit on one card. The trunc option was not specified. The maximum length is size bytes.
    Action
    Either ensure that all lines in the file are less than size bytes long, or specify the trunc option on the reader definition.
    Issued by
    cardrdr.c, function read_ascii


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmssd.html0000664000175000017500000000202612564723224013645 00000000000000 Hercules Version 3: System Messages: SD - Socket Devices

    Hercules Version 3: System Messages: SD - Socket Devices

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator common routines to support socket devices.

    Messages

    HHCSD001I
    Meaning
    Issued by
    panel.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsta.html0000664000175000017500000000202212564723224013637 00000000000000 Hercules Version 3: System Messages: TA - Tape Device Emulation

    Hercules Version 3: System Messages: TA - Tape Device Emulation

    This page describes the tape device emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCTA001I
    Meaning
    Issued by
    tapedev.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmstc.html0000664000175000017500000000201112564723224013637 00000000000000 Hercules Version 3: System Messages: TC - tapecopy

    Hercules Version 3: System Messages: TC - tapecopy

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program tapecopy.

    Messages

    HHCTC001I
    Meaning
    Issued by
    tapecopy.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmste.html0000664000175000017500000001437712564723224013663 00000000000000 Hercules Version 3: System Messages: TE - 1052/3270 Terminal Emulation

    Hercules Version 3: System Messages: TE - 1052/3270 Terminal Emulation

    This page describes the terminal emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCTE001I Console connection thread started: tid=threadid, pid=processid
    Meaning
    The thread that handles connection requests from console devices has been started.
    Issued by
    console.c, function console_connection_handler
    HHCTE002W Waiting for port port to become free
    Meaning
    The thread that handles connection requests from console devices is waiting for the TCP port denoted by port to become available for use.
    Action
    If this message persists, some other program has control of the TCP port listed. Find out which one it is and terminate it.
    Issued by
    console.c, function console_connection_handler
    HHCTE003I Waiting for console connection on port port pid=num
    Meaning
    Hercules is ready to accept console connections on port port.
    Issued by
    console.c, function console_connection_handler
    HHCTE004I Console connection thread terminated
    Meaning
    The thread that handles connection requests from console devices has been terminated.
    Issued by
    console.c, function console_connection_handler
    HHCTE005E Cannot create console thread: reason
    Meaning
    The thread that handles connection requests from console devices could not be started. The reason is shown as reason.
    Action
    Correct the reason listed and restart Hercules.
    Issued by
    console.c, function console_initialise
    HHCTE006A Enter input for console device address
    Meaning
    The 1052 console device at address is waiting for input.
    Action
    Type the desired input for the console and press the ENTER key. If you do not wish to get this message when input is requested, define the console with the option noprompt.
    Issued by
    console.c, function constty_execute_ccw
    HHCTE007I Device address closed by client ipaddr
    Meaning
    The client at IP address ipaddr that was connected to the 3270 console at address address has closed the connection. The device is no longer available for use.
    Issued by
    console.c, function recv_3270_data
    HHCTE008I Device address closed by client ipaddr
    Meaning
    The client at IP address ipaddr that was connected to the 1052 console at address address has closed the connection. The device is no longer available for use.
    Issued by
    console.c, function recv_1052_data
    HHCTE009I Client ipaddr connected to type device address
    Meaning
    The client at IP address ipaddr has connected to Hercules as a type device and is now available at address address.
    Issued by
    console.c, function connect_client
    HHCTE010E CNSLPORT statement invalid: statement
    Meaning
    The CNSLPORT statement in the hercules configuration file is invalid.
    Issued by
    console.c, function console_connection_handler
    HHCTE011E Device devn: Invalid IP address: ipaddr
    Meaning
    The IP address ipaddr is invalid.
    Issued by
    console.c, function loc3270_init_handler or constty_init_handler.
    HHCTE012E Device devn: Invalid mask value: ipmask
    Meaning
    The mask value ipmask is invalid.
    Issued by
    console.c, function loc3270_init_handler or constty_init_handler.
    HHCTE013E Device devn: Extraneous argument(s): xxx...
    Meaning
    The argument xxx and any which follow it (if any) was not recognized nor understood and are thus invalid.
    Issued by
    console.c, function loc3270_init_handler or constty_init_handler.
    HHCTE014I type device devn disconnected.
    Meaning
    The client connected to device devn has abruptly terminated the connection (ECONNRESET).
    Issued by
    console.c, function recv_3270_data
    HHCTE017E Device devn: Duplicate SYSG console definition
    Meaning
    Device number devn has been defined as an integrated 3270 (SYSG) console, but a SYSG console already exists. Only one SYSG console can be defined per system.
    Issued by
    console.c, function loc3270_init_handler


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmstm.html0000664000175000017500000000200512564723224013654 00000000000000 Hercules Version 3: System Messages: TM - tapemap

    Hercules Version 3: System Messages: TM - tapemap

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program tapemap.

    Messages

    HHCTM001I
    Meaning
    Issued by
    tapemap.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsts.html0000664000175000017500000000201112564723224013657 00000000000000 Hercules Version 3: System Messages: TS - tapesplt

    Hercules Version 3: System Messages: TS - tapesplt

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator utility program tapesplt.

    Messages

    HHCTS001I
    Meaning
    Issued by
    tapesplt.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmstt.html0000664000175000017500000000437312564723224013675 00000000000000 Hercules Version 3: System Messages: TT - TOD Clock and Timer Services

    Hercules Version 3: System Messages: TT - TOD Clock and Timer Services

    This page describes the TOD Clock and Timer Services messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCTT001W Timer thread set priority priority failed: error
    Meaning
    An attempt to change the priority of the timer thread to priority failed. The error is described by error. The thread priority has not been changed. Hercules overall performance may be impaired as a result.
    Action
    If performance problems are noted, correct the error and restart Hercules.
    Issued by
    timer.c, function timer_update_thread
    HHCTT002I Timer thread started: tid=threadid, pid=processid, priority=priority
    Meaning
    The thread for timing functions has been started. Its thread id is threadid, its process id is processid and the thread priority is priority.
    Issued by
    timer.c, function timer_update_thread
    HHCTT003I Timer thread ended
    Meaning
    The thread for timing functions has ended.
    Issued by
    timer.c, function timer_update_thread


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmstu.html0000664000175000017500000000202612564723224013667 00000000000000 Hercules Version 3: System Messages: TU - TUN/TAP device support

    Hercules Version 3: System Messages: TU - TUN/TAP device support

    This page describes the messages for the Hercules S/370, ESA/390, and z/Architecture emulator TUN/TAP support routines.

    Messages

    HHCTU001I
    Meaning
    Issued by
    tuntap.c, function


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercmsvm.html0000664000175000017500000000725612564723224013673 00000000000000 Hercules Version 3: System Messages: VM - VM/CP Emulation

    Hercules Version 3: System Messages: VM - VM/CP Emulation

    This page describes the VM/CP emulation messages for the Hercules S/370, ESA/390, and z/Architecture emulator.

    Messages

    HHCVM001I *panel_command* panel command issued by guest
    Explanation
    The guest operating system has issued a DIAGNOSE 8 instruction to perform the panel_command panel command to be carried out by the hercules panel command processor
    System Action
    The hercules panel command processor carries out the command, if possible.
    Operator Action
    None
    Programmer Action
    No action is requested if this behaviour is expected. If this behaviour poses a security concern, the DIAG8CMD configuration statement should either be ommited or specified with the disabled argument.
    Module
    vm.c

    HHCVM002I *panel_command command complete
    Explanation
    The panel_command panel command has been carried out by the panel command processor. Note that this message only appears if the guest issued diagnose 8 instruction specified that it didn't request the command response to be placed in a supplied buffer.
    System Action
    The system continues
    Operator Action
    None. This is an informational message
    Programmer Action
    None. This is an informational message
    Module
    vm.c

    HHCVM003I Host command processing disabled by configuration statement
    Explanation
    The guest operating system attempted using the DIAGNOSE 8 Instruction to carry out a panel command, but the system configuration disabled this feature (with the DIAG8CMD configuration statement)
    System Action
    The panel command is ignored.
    Operator Action
    None.
    Programmer Action
    If it is deemed necessary for the guest operating system to issue DIAGNOSE 8 commands to issue panel commands, the DIAG8CMD with the enable argument should be specified in the configuration file.
    Module
    vm.c

    HHCVM004E Host command processing not included in engine build
    Explanation
    The hercules engine has been built WITHOUT Diagnose 8 panel command facility support
    System Action
    The panel command is not issued. The system continues.
    Operator Action
    None
    Programmer Action
    If it is desired that DIAGNOSE 8 Instruction be carried out as panel commands, the facility should be included in the build process. Additionally, the DIAG8CMD configuration statement should be specified with the enable parameter.
    Module
    vm.c


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercnew.html0000664000175000017500000015362712625667132013511 00000000000000 Hercules: What's new

    What's new in Hercules


    What's planned for release 4.00

    Release date: Not yet determined

    • I/O subsystem restructure (Mark Gaubatz)
    • Enhanced timer resolution (Mark Gaubatz)
    • REXX support (Jan Jaeger)
    • Object REXX support (Enrico Sorichetti)
    • Selective enablement of architecural features (Jan Jaeger)
    • Message restructure (Bernard van der Helm, Paul Gorlinsky)
    • Windows native threads support (Paul Gorlinsky)
    • Driver for MPCPTP and/or MPCPTP6 devices (Ian Shorter)
    • QDIO support for Linux (Jan Jaeger, Harold Grovesteen)
    • Using pre-configured tunnel device with CTCI (John P. Hartmann)

    Download hercules-4.00.tar.gz

    What's new in release 3.12

    Release date: 30 November 2015

    • dasdload corrections and support for loading ASCII TEXT files (Roger Bowler)
    • comm3705_RU-size+unack_attn_delay patch (Juergen Winkelmann)
    • CCKDDUMP/CCKDLOAD support for DSNTYPE=LARGE (Christophe Varlet)
    • CMPSC corrections (Bernard van der Helm)
    • Miscellaneous bug fixes (Peter Coghlan, Gert Caers, Giuseppe Vitillaro, Bill Carlborg, David "Fish" Trout)

    Download hercules-3.12.tar.gz

    What's new in release 3.11

    Release date: 15 September 2014

    • Floating-Point-Extension Facility (Roger Bowler)
    • Enhanced Channel-to-Channel Adapter via TCP/IP (Peter J. Jansen)
    • Load/Store-on-Condition Facility corrections (Neale Ferguson)
    • LCS corrections (Paul Gorlinsky, David "Fish" Trout, Ivan Warren)
    • Floating-Point-Extension Facility corrections (Neale Ferguson)
    • CMPSC corrections (Bernard van der Helm)
    • Load sequential datasets from XMIT files (Roger Bowler)
    • Eliminate compiler warnings for Linux and Mac (Roger Bowler)

    Download hercules-3.11.tar.gz

    What's new in release 3.10

    Release date: 1 February 2014

    • Fix incorrect PSW IA in SIE mode with PER (Ian Worthington)
    • Corrections to build procedures (Mike Frysinger, Dan Horak)
    • Fixes for Mac OS X (Butch Anton, Adam Vandenberg, Enrico Sorichetti)
    • Configuration topology facility fixes (Paolo Giacobbis)
    • Convert BFP instructions to use SoftFloat package (Roger Bowler)
    • Preliminary support for 2GB page frames (Roger Bowler)
    • PFMF fixes (John P. Hartmann)
    • CMPSC corrections (Bernard van der Helm)
    • dasdls enhancements (Chris Cheney)

    Download hercules-3.10.tar.gz

    What's new in release 3.09

    Release date: 15 July 2013

    • Allow regex replacement variables in HAO commands (Roger Bowler)
    • Prevent duplicate EQID (Gordon Bonorchis)
    • Permit concurrent read access to printer and punch files (Roger Bowler)
    • DFP zoned-conversion facility (Roger Bowler)
    • Execution-hint facility (Roger Bowler)
    • Miscellaneous-instruction-extensions facility (Roger Bowler)
    • Load-and-trap facility (Roger Bowler)
    • Fix for VSAM Extended Format (David "Fish" Trout)
    • APL\360 2741 patch (Max H. Parke)
    • Fix interval timer repeating interrupt (Ivan Warren, Kevin Leonard)
    • Corrections to build procedures (Mike Frysinger, Dan Horak)
    • Miscellaneous bug fixes (Roger Bowler)

    Download hercules-3.09.tar.gz

    What's new in release 3.08

    Release date: 8 December 2012

    • 1403 and 3211 FCB support (Enrico Sorichetti)
    • Shutdown on SIGTERM (Frans Pop)
    • Disable close-window button (Paul Gorlinsky)
    • Allow larger IPL text (Laddie Hanus)
    • Drop support for Cygwin, Win98, WinNT, Win2000 (Roger Bowler)
    • Windows shutdown handlers (Paul Gorlinsky)
    • Dynamically loadable instructions (Jan Jaeger)
    • Additional codepages (Kevin Leonard)
    • Load/Store-on-Condition Facility (Roger Bowler)
    • Distinct-Operands Facility (Roger Bowler)
    • Population-Count Facility (Roger Bowler)
    • High-Word Facility (Roger Bowler)
    • Message Security Assist Extensions 3 and 4 (Bernard van der Helm)
    • Interlocked-Access Facility (Roger Bowler)
    • CMPSC-Enhancement Facility (Bernard van der Helm)
    • Fast-BCR-Serialization Facility (Roger Bowler)
    • Reset-Reference-Bits-Multiple Facility (Jan Jaeger)
    • Access-Exception-Fetch/Store-Indication Facility (Roger Bowler)
    • Enhanced-Monitor Facility (Jan Jaeger)
    • Load-Program-Parameter Facility (Paul Gorlinsky)
    • IPTE-Range Facility (Jan Jaeger)
    • Enhanced-DAT Facility (Jan Jaeger)
    • Increase CKD_MAXFILES from 4 to 27 for 3390-27 and -54 (Paul Gorlinsky)
    • CKD read attention message command (Florian Bilek)
    • Support 128 CPUs on 64-bit Linux (Jan Jaeger)
    • Issue Hercules commands via HTTP (Robert Hodge)
    • Compression performance enhancements (Bernard van der Helm)
    • Compression bug fixes (Bernard van der Helm, John P. Hartmann)
    • Crypto bug fixes (Bernard van der Helm)
    • Hexadecimal floating-point bug fixes (Andy Polyakov)
    • SCSI tape enhancements and bug fixes (David "Fish" Trout)
    • 3420 sense code corrections for MTS (Harold Grovesteen)
    • Prevent multiple instances opening same output file under Windows (David "Fish" Trout)
    • 2703 and 3705 fixes and 3791 support (Max H. Parke, Juergen Winkelmann)
    • Enable GUI support as default for all platforms (Jacob Dekel)
    • Miscellaneous bug fixes (Paul Gorlinsky, Ivan Warren, David "Fish" Trout, Jan Jaeger, Bernard van der Helm, Roger Bowler, Kevin Leonard, Ian Shorter, John P. Hartmann)

    Download hercules-3.08.tar.gz

    What's new in release 3.07

    Release date: 10 March 2010

    • Fast Synchronous Data Mover Facility (Guy Desbiens)
    • Diagnose 210, 250, 260 (Harold Grovesteen)
    • Extended Diagnose 204 feature (Jan Jaeger)
    • Complete Diagnose 24 (Harold Grovesteen)
    • Configuration-Topology Facility (Fish)
    • HFP-Unnormalized-Extensions Facility (Harold Grovesteen)
    • CMPSC performance improvements (Bernard van der Helm)
    • uptime command (Fish)
    • Raise XPNDSIZE limit to 1048576MB (Roger Bowler)
    • MAXCPU and LPARNUM configuration statements (Roger Bowler)
    • Add capacity model identifiers to MODEL config statement (Roger Bowler)
    • SCLPROOT configuration statement (Jan Jaeger)
    • Add "noclear" option to printer and card punch devices (Jay Maynard)
    • Socket printer support (Fish)
    • 3705 SNA device support (Max H. Parke)
    • TTY and 2741 support for 2703 (Max H. Parke)
    • Tracing enhancements (Jan Jaeger)
    • Allow configure --enable-external-gui for Unix builds
    • Enable tun/tap emulation for 64-bit Windows builds (Ivan Warren)
    • 64-bit Windows support (Roger Bowler)
    • Raise MAX_CPU_ENGINES limit to 64 (Roger Bowler, Ivan Warren)
    • Numerous bug fixes (Ivan Warren, Fish, Jan Jaeger, Bernard van der Helm, Roger Bowler, Jay Maynard)

    Download hercules-3.07.tar.gz

    What's new in release 3.06

    Release date: 11 January 2009

    • Integrated 3270 (SYSG) console support (Roger Bowler, Jan Jaeger)
    • HMC DVD-RAM read/write support (Jan Jaeger)
    • 64-bit native version now supported on Mac OS X (Jay Maynard)
    • Ability to specify IFL, zIIP, and zAAP engine types (Roger Bowler, Jan Jaeger, Ivan Warren)
    • Console-like message handling (David "Fish" Trout, Bernard van der Helm)
    • Tape automount CCW support (David "Fish" Trout)
    • CKD Locate Record Extended CCW (Greg Smith)
    • Support for FLEX-ES FakeTape tape images (David "Fish" Trout; FLEX-ES and FakeTape are trademarks of Fundamental Software, Inc.)
    • More complete 3490 and 3590 tape support (David "Fish" Trout)
    • Solaris build support (Jeff Savit)
    • FreeBSD build support (Bjoern A. Zeeb)
    • Panel enhancements:
      • Display virtual storage in primary, secondary, and home space (Paul Leisy)
      • Display and modify PSW fields by panel command (Roger Bowler)
      • Modify control registers by panel command (Roger Bowler)
      • Specify IPL parameter by PARM operand (Ivan Warren)
      • New panel commands: automount, cmdtgt, ctc, herc, msghld, pscp, scp, sfk (David "Fish" Trout, Bernard van der Helm)
    • LEGACYSENSEID configuration statement (Ivan Warren)
    • New instruction feature support (introduced with System z10):
      • Parsing-Enhancement Facility (Bernard van der Helm)
      • Message-Security-Assist Extension 2 (Bernard van der Helm)
      • General-Instructions-Extension Facility (Roger Bowler, Jan Jaeger)
      • Execute-Extensions Facility (Bernard van der Helm)
      • Move-with-Optional-Specifications Facility (Roger Bowler)
      • Compare-and-Swap-and-Store Facility 2 (Ivan Warren)
    • Many emulation fixes (Roger Bowler, Jan Jaeger, Ivan Warren, David "Fish" Trout, Greg Smith, Paul Leisy, Jay Maynard, Bernard van der Helm, Kevin Leonard, Tony Harminc)

    Download hercules-3.06.tar.gz

    What's new in release 3.05

    Release date: 23 June 2007

    • Prebuilt Cygwin binary no longer supplied; building Cygwin version from source still supported (Jay Maynard)
    • New system features: Compare-and-Swap-and-Store, Conditional SSKE, Decimal Floating Point, Floating Point Support Enhancement (Roger Bowler)
    • Extract CPU Time Facility (Jan Jaeger)
    • Multiple Logical Channel Subsystems Facility (Jan Jaeger, Ivan Warren)
    • 3590 tape support (David "Fish" Trout)
    • 3990-6 control unit and ECKD support (Greg Smith)
    • Many performance improvements (Greg Smith, Ivan Warren, Jan Jaeger)
    • Many emulation fixes (Greg Smith, Roger Bowler, Ivan Warren, David "Fish" Trout, Kevin Leonard, Peter Coghlan)
    • Major SCSI tape fixes (David "Fish" Trout)
    • Added floating point instructions CGER, CGDR and CGXR (Bernard van der Helm)
    • Address range options for instruction trace and step (Greg Smith)
    • Update gpr registers via panel command (David "Fish" Trout)
    • Console connection keep-alive (David "Fish" Trout)
    • Customizable 3270 connection screen (Ivan Warren)
    • dasdconv quiet and stdin options (Roger Bowler)
    • Hercules Automatic Operator (Bernard van der Helm, David "Fish" Trout)
    • Enhanced symbol substitution (Leland Lucius, Enrico Sorichetti, David "Fish" Trout)
    • Miscellaneous new panel commands: qd (Greg Smith), fpc, traceopt (Roger Bowler), logopt (Kevin Leonard), cd, pwd, timerint, defsym (David "Fish" Trout)

    Download hercules-3.05.tar.gz

    What's new in release 3.04.1

    Release date: 25 March 2006

    • Fix to allow building for Intel-based Mac OS X (Jay Maynard)
      Note: This version only applies to the Mac OS X 10.4 (Tiger) platform. Version 3.04 is current for all other platforms.

    Download hercules-3.04.1.tar.gz

    What's new in release 3.04

    Release date: 24 February 2006

    • CCKD garbage collection fix (Greg Smith)
    • Reworked timing functions (Jan Jaeger)
    • Codepage 1047 conversion tables (Kevin Leonard)
    • Fixed off-by-one-day bug with SYSEPOCH other than 1900; added new config parameter, YROFFSET, and added warning if SYSEPOCH is not 1900 or 1960 (Jay Maynard, Jan Jaeger)
    • New 2305 CKD disk emulation (Jay Maynard)
    • Added floating point instructions CEGR, CDGR and CXGR (Bernard van der Helm)
    • Added support for cgi-bin dynamic modules (David "Fish" Trout)
    • Instruction fixes: PLO, CVB, CXFBR, CXGBR (Bernard van der Helm, David "Fish" Trout, Greg Smith, Pasi Pirhonen)
    • Fix for Windows ..\relative path dasd files (David "Fish" Trout)

    Download hercules-3.04.tar.gz

    What's new in release 3.03.1

    Release date: 30 December 2005

    • Fix translation exception bug that was causing some Linux kernels to panic (Fabrizio Calabretta, Greg Smith, Ivan Warren)
    • TOD Clock-Steering Facility (Jan Jaeger, Bernard van der Helm)
    • Fix bug in shadow file filename processing on native Windows (David "Fish" Trout)
    • Performance improvements in TM instruction family (Bernard van der Helm)
    • Support for Linux zipl LOADPARM of PROMPT (Jan Jaeger)

    Download hercules-3.03.1.tar.gz

    What's new in release 3.03

    Release date: 20 December 2005

    • Native Windows version no longer requires Cygwin (David "Fish" Trout, Roger Bowler, Ivan Warren)
    • SMP host integrity fixes (Greg Smith, David "Fish" Trout, Bob Deblier)
    • ALS5, z9 and other architectural enhancements (Roger Bowler, Bernard van der Helm, Jan Jaeger, David "Fish" Trout)
    • Restructured cryptographic support no longer depends on libgcrypt (Bernard van der Helm, Roger Bowler, Ivan Warren)
    • Support emulation of up to 32 CPUs; maximum without special build options now 8 (Ivan Warren)
    • Enhanced semigraphical control panel now uses all of larger console windows (Greg Smith, David "Fish" Trout)
    • Many emulation fixes (Roger Bowler, Jan Jaeger, Bernard van der Helm, David "Fish" Trout, Greg Smith, Ivan Warren, Andy Styles, John Decker)
    • CMPSC fixes now produce identical results with real systems (Jacques Dilbert, Bernard van der Helm)
    • Integrated 1052-C / 3215-C console support (Jan Jaeger)
    • tapecopy support for writing as well as reading tapes (Jay Maynard)

    Download hercules-3.03.tar.gz

    What's new in release 3.02

    Release date: 11 December 2004

    • Significant performance improvements (Jan Jaeger, Greg Smith, Gabor Hoffer)
    • SIE performance almost the same as native (Jan Jaeger, Gabor Hoffer)
    • SCSI tape support in Windows (David "Fish" Trout)
    • Mac OS X CTC networking support (Jay Maynard)
    • Suspend/resume facility (Greg Smith)
    • ASN-and-LX-Reuse Facility (Roger Bowler)
    • Enable or disable ASN-and-LX-reuse in config (Jan Jaeger, Ivan Warren)
    • Extended Translation Facility 3 (Bernard van der Helm)
    • DAT-enhancement facility (Roger Bowler)
    • Immediate CCWs now correctly handled when Suppress Incorrect Length Indication is specified (Ivan Warren)
    • 3270 option provided to control connection to group of devices (Ivan Warren)
    • 3270 connections can be limited by IP address (David "Fish" Trout)
    • Remaining 26 binary floating point instructions (Roger Bowler)
    • IPL CLear, System Reset, and System Reset Clear operator commands (Ivan Warren)
    • Pentium 4 optimizations enabled in gcc (Ivan Warren)

    Download hercules-3.02.tar.gz

    What's new in release 3.01

    Release date: 30 November 2003

    • Bypass gcc 2.96 optimizer bug that caused incorrect instruction execution (Ivan Warren)
    • Added command-line control panel command history (Martin Gasparovic, Volker Bandke)
    • Message Security Assist (Bernard van der Helm, Jan Jaeger)
    • Fixed device interrupt pending on IPL that caused OS/360 to have to be IPLed twice (David "Fish" Trout, Greg Smith)
    • Added pthreads trace function for debugging (Greg Smith)
    • Fish threads code rewritten, closer to POSIX thread functionality while still performing better (David "Fish" Trout)
    • Fixed incompatibility with Windows NT telnet client (Greg Price, David "Fish" Trout)
    • Performance and integrity enhancements for RS instructions (Greg Smith)

    Download hercules-3.01.tar.gz

    What's new in release 3.00

    Release date: 2 October 2003

    • Dynamically loaded module support for devices, instructions, and operator console panels (Jan Jaeger, David "Fish" Trout, Ivan Warren)
    • Shared and remote DASD support (Greg Smith)
    • z990 (ALS4) instruction support (Roger Bowler, Jan Jaeger, Bernard van der Helm)
    • HFP Multiply-Add/Subtract Facility (Roger Bowler)
    • Long Displacement Facility (Roger Bowler)
    • Simplified network adapter specifications (David "Fish" Trout, Jim Pierson)
    • New device emulations: 2703, 3410, 3490, 9347 (Ivan Warren)
    • ECPS:VM support (Ivan Warren)
    • Reworked process priority handling (Mark Gaubatz)
    • Greatly improved interval timer resolution (Mark Gaubatz)
    • Internal consistency checking improvvements (Greg Smith)
    • Corrected 3270 session disconnect processing (Ivan Warren)
    • Instruction disassembler in control panel (Jan Jaeger)
    • Tape read backward fixes (Jay Jaeger)
    • Fix for double memory consumption bug on Windows (Mark D., David "Fish" Trout)
    • OMA tape processing fixes (Ivan Warren)
    • Message logging restructuring (Jan Jaeger, David "Fish" Trout)
    • S/370 I/O race condition fixes (Victor Shkamerda, Greg Smith)
    • Manual pages for some commands (Jim Morrison)

    Download hercules-3.00.tar.gz

    What's new in release 2.17.1

    Release date: 12 February 2003

    • Corrected RPM installed files permissions (John Summerfield)
    • Corrected dasdload verbosity level (Jay Maynard)
    • Corrected card reader eof/intrq option handling, added * to designate no file loaded (Jay Maynard)
    • Correct SLB instruction condition code (Jan Jaeger)
    • Fix dasdutil.c track conversion function (Jim Morrison)

    Download hercules-2.17.1.tar.gz

    What's new in release 2.17

    Release date: 1 February 2003

    • Restructured DASD subsystem: better use of memory, compressed FBA support, framework for shared DASD (Greg Smith)
    • New dasdcopy utility replaces ckd2cckd and cckd2ckd, and adds compressed FBA support (Greg Smith)
    • Native support for Mac OS X 10.2 and above (Paul Scott)
    • Reworked CTC and LCS emulation (Jim Pierson)
    • SMP host integrity fixes (Greg Smith and Jan Jaeger)
    • Fixes for compile errors with gcc 3.x (Greg Smith and David "Fish" Trout)
    • S/370 dual address space and MVS assist fixes (Jan Jaeger)
    • Renumbered all messages to consistent format, removed duplicate numbers, and began message documentation (Jay Maynard)
    • Added options for 1052/3215 consoles and card readers (Jay Maynard)
    • Numerous instruction and I/O emulation fixes (Greg Smith, Jan Jaeger, Juergen Dobrinski, Bernard van der Helm, Andy Norrie, and David "Fish" Trout)

    Download hercules-2.17.tar.gz

    What's new in release 2.16.5

    Release date: 8 July 2002

    • Correct serious CCKD image file corruption error (Greg Smith)
    • Allow tape files to be opened for input if on CD-ROM (Volker Bandke)

    Download hercules-2.16.5.tar.gz

    What's new in release 2.16.4

    Release date: 3 July 2002

    • Read backward support for emulated tape (Volker Bandke)
    • Added 9313, 9332, and 9335 to list of supported devices (Tomas Masek)

    Download hercules-2.16.4.tar.gz

    What's new in release 2.16.3

    Release date: 2 July 2002

    • CTC fix for TurboLinux bug (Jim Pierson)
    • 3287 printer support via TN3270 (Tomas Masek)
    • S/370 extended memory fixes (Tomas Masek)
    • ctcadpt.c compilation fix for FreeBSD (Mark Szlaga)
    • Fixed 3270 ERASE ALL UNPROTECTED command to not count data read (Tomas Fott)
    • Fixes to ckdtab in dasdtab.c (Greg Smith)
    • Retrofitted cckd chkdsk fixes/enhancements (Greg Smith)
    • FBA fixes contributed by Tomas Masek (Greg Smith)
    • Compatibility fixes for cckd and 2.17 (Greg Smith)

    Download hercules-2.16.3.tar.gz

    What's new in release 2.16.2

    Release date: 20 May 2002

    • Fixed 3350 dasdtab entry (Greg Smith)
    • Fixed 370 interval timer error (Valery Pogonchenko)
    • Control panel attach command bug fix (David "Fish" Trout)

    Download hercules-2.16.2.tar.gz

    What's new in release 2.16.1

    Release date: 4 May 2002

    • fthreads locking fixes (David "Fish" Trout)
    • dasdload bug fix (Greg Smith)
    • FBA dasd devices allow any size disk (Jay Maynard)
    • Control panel attach command bug fix (Kris Van Hees)
    • Windows versions (finally) accessible from main page (Jay Maynard)

    Download hercules-2.16.1.tar.gz

    What's new in release 2.16

    Release date: 20 April 2002

    • PER support (Jan Jaeger, Paul Leisy)
    • S/370 multiprocessor support (Jan Jaeger)
    • Licensed software restriction (Jan Jaeger, Jay Maynard)
    • Performance mods (Gabor Hoffer, Juergen Dobrinski, Greg Smith, and Paul Leisy)
    • Interrupt subclass priorities (Greg Smith)
    • dasdcat program (Malcolm Beattie, Roger Bowler)
    • Updated TCP/IP documentation (Roger Bowler)
    • CTCI support for Windows (David "Fish" Trout)
    • Print to unix pipe (Roger Bowler)
    • Preliminary Lan Channel Station (LCS) support
    • HTTP server (Jan Jaeger)
    • Various fixes (as recorded in CHANGES) (Paul Leisy, Matt Zimmerman, Greg Smith, Volker Bandke, Bernard van der Helm, David "Fish" Trout)

    Download hercules-2.16.tar.gz

    What's new in release 2.15

    Release date: 04 December 2001

    • Autoconf added to ease portability (Matt Zimmerman, Fritz Elfert, Willem Konynenberg)
    • Numerous instruction fixes (Paul Leisy)
    • TUN/TAP support for Linux kernels beyond 2.4.6 (Matt Zimmerman)
    • Timer fixes (Greg Smith)
    • Synchronous I/O (Greg Smith)
    • Support for IPL from CD-ROMs as with HMC (Jan Jaeger)
    • CTC hang at shutdown fixed (Jan Jaeger)
    • CTC TCP/IP now works with VM/ESA (Kris Van Hees)
    • Compressed CKD endianness and RAS fixes (Greg Smith)
    • Hot reader support (David "Fish" Trout)
    • Machine checks now reported for host exceptions, loops, and wait states (Jan Jaeger)

    Download hercules-2.15.tar.gz

    (There was no release 2.14)

    What's new in release 2.13

    Release date: 05 July 2001

    • Restrict TODEPOCH to 1900, 1928, 1960, 1970, or 1988, and correct offset calculation (Michael Koehne)
    • HET unmount option (Michael Koehne)
    • quiet command (Michael Koehne)
    • Panel instruction disassembly (Jan Jaeger)
    • CMPSC corrections (Bernard van der Helm)
    • CTCT CTC over TCP/IP (Vic Cross)
    • Sundry instruction and channel fixes (Jan Jaeger)
    • Numerous instruction fixes (Paul Leisy)
    • CKD trace command (Valery Pogonchenko)
    • Performance enhancements (Juergen Dobrinski)
    • CGEBR/CGDBR instructions (Jan Jaeger)
    • CEGBR/CDGBR instructions (Kris Van Hees)
    • CKD 9345 support (Greg Smith)
    • Storage Key Assist (Jan Jaeger)
    • Move Page Facility 2 (Jan Jaeger)

    Download hercules-2.13.tar.gz

    What's new in release 2.12

    Release date: 04 May 2001

    • Numerous instruction fixes (Paul Leisy, Jan Jaeger, Peter Stammbach, Roger Bowler)
    • FBA and CKD read-only support (Greg Smith)
    • Enable ISKE/RRBE/SSKE in S/370 mode (Valery Pogonchenko)
    • CCKD corrections (Greg Smith)
    • CMPSC fixes for expansion (Greg Smith)
    • Correct prefix alignment for ESA/390 guest in 64 bit mode SIE (Jan Jaeger)
    • Card reader multiple files and EBCDIC autopad support
    • Support for built-in TUN driver of Linux kernel 2.4.x
    • Device I/O thread throttling (Greg Smith, Fish)
    • Small optimization of vstore/vfetch and TPI (Jan Jaeger)
    • Sense/Set Path Group ID for DASD (Jan Jaeger)
    • Dynamic device threads (Jan Jaeger)
    • Fast interrupt processing for MCK and PER (Jan Jaeger)
    • Allow HET files to reside on read-only media (Leland Lucius)
    • Utilities display versioning and copyright info (Greg Smith)
    • Present device end on terminating console session (Jan Jaeger)
    • sh panel command (Bernard van der Helm)
    • 9221 power-off diagnose (Jan Jaeger)
    • Debug format enhancements (Peter Stammbach)
    • Fix for device threads (Juergen Dobrinski)
    • Sundry new ESAME instructions and corrections (Roger Bowler, Jan Jaeger)
    • Improved interrupt processing (Valery Pogonchenko)
    • Incorrect-Length-Indication-Suppression facility (Jan Jaeger)
    • S/370 interval timer fixes (Mark Gaubatz)
    • 64-bit Interpretive Execution (Jan Jaeger)
    • IEEE floating point (Willem Konynenberg)
    • 64-bit panel updates (Roger Bowler)
    • LPM fixes and display subchannel command (Nobumichi Kozawa)
    • Fix amode64 in load_psw (Ulrich Weigand)
    • Multiply Logical instructions (Vic Cross)
    • Environment variables to override filenames of hercules.rc hercules.cnf and hercifc (Jan Jaeger)
    • Floating point enhancements (Roger Bowler, Jan Jaeger)
    • Country codepage tables (Roger Bowler)

    Download hercules-2.12.tar.gz

    What's new in release 2.11

    Release date: 09 February 2001

    • Sundry new ESAME instructions and corrections (Jan Jaeger)
    • Panel display instruction operands (Roger Bowler)
    • TRAP and RP instructions (Jan Jaeger)
    • TP instruction (Roger Bowler)
    • Tape data chaining patch (Brandon Hill)
    • Bypass Cygwin stack problem (Greg Smith)
    • Fixes for Windows port (Volker Bandke)
    • SSK/ISK/RRB fix for 2K storage keys (Valery Pogonchenko, Jan Jaeger)
    • Extended Translation Facility 2 (Roger Bowler)
    • Divide Logical instructions (Vic Cross)

    Download hercules-2.11.tar.gz

    What's new in release 2.10

    Release date: 02 February 2001

    • z/Architecture support (Jan Jaeger)
    • TUN/TAP support for CTC (Roger Bowler)
    • OSTAILOR VSE option (Roger Bowler)
    • 2K/4K storage key support (Jan Jaeger)
    • Fully functional CMPSC instruction (Bernard van der Helm)
    • Fix read-only AWSTAPE (Roger Bowler)
    • Sundry new ESAME instructions (Jan Jaeger, Roger Bowler)
    • Format-2 2K/4K IDAW (Roger Bowler)
    • ESAME 5-level DAT (Roger Bowler)
    • ESAME ASN authorization and ALET translation (Roger Bowler)
    • ESAME linkage-stack instructions (Roger Bowler)
    • ESAME subspace replacement (Roger Bowler)
    • ESAME DUCT format changes (Roger Bowler)
    • Unloaded tape drive support (Brandon Hill)
    • Extended floating point (Peter Kuschnerus)
    • Divide Single instructions (Jan Jaeger)
    • EPSW instruction (Roger Bowler)
    • Compressed CKD updates (Greg Smith)
    • Timer update correction (Valery Pogonchenko)
    • Fix MVCLE instruction (Jan Jaeger)
    • Interval Timer fix (Bob Abeles)

    Download hercules-2.10.tar.gz

    What's new in release 1.71

    Release date: 18 January 2001

    • Compressed CKD DASD support release 2, with improved performance, shadow file support, and better reliability (Greg Smith)
    • Hercules Emulated Tape format support (Leland Lucius)
    • Make HET bzip2 compression optional, analogous to CCKD bzip2 (Jay Maynard)
    • Fix for track overflow record zeroing (Roger Bowler)
    • Clarified licensing discussion in FAQ (Roger Bowler)
    • Treat printer X'37' CCW as NOP (Jay Maynard, suggested by Brandon Hill)
    • Treat X'E503' MVS/XA assist instruction as no-op (Jay Maynard, suggested by Brandon Hill)
    • Read commands from hercules.rc at startup (Willem Konynenberg)
    • New tapelist program prints contents of 80-byte record tapes (Jim Morrison)
    • Increased MAXDBLK from 3000 to 40000 and MAXTTR from 10000 to 40000 in dasdload (Volker Bandke)

    Download hercules-1.71.tar.gz

    What's new in release 1.70

    Release date: 3 December 2000

    • New file hercwin32.zip contains build scripts for Win32 version (Volker Bandke)
    • More performance enhancements (Juergen Dobrinski)
    • ALS-1 and ALS-2 support completion (Roger Bowler and Jan Jaeger)
    • Extended Translation Facility (Roger Bowler)
    • Pick up correct float.c module (Jay Maynard for Peter Kuschnerus)
    • Distribute Windows binaries as well as Linux (Jay Maynard)
    • Fix orienting bug in CKD DASD search CCW processing (Bob Abeles)
    • Obtain TOD clock lock when accessing or updating 370 interval timer (Bob Abeles)
    • Change license to the QPL Open Source Definition-compliant license (Roger Bowler, Jay Maynard, and Jan Jaeger)

    Download hercules-1.70.tar.gz

    What's new in release 1.69

    Release date: 29 October 2000

    • Correct AXR and SXR instruction results when significance exception raised (Peter Kuschnerus, with help from Mario Bezzi)
    • Correct CD and CDR instruction condition code logic (Peter Kuschnerus)
    • Do not generate support for square root instructions in 370 mode (Peter Kuschnerus)
    • Floating point arithmetic tuning (Peter Kuschnerus)
    • Performance optimization fixes (Juergen Dobrinski)
    • Spelling corrections (Adam Thornton)
    • Fixed version number (Jay Maynard)

    Download hercules-1.69.tar.gz

    What's new in release 1.68

    Release date: 8 October 2000

    • Rewritten and updated FAQ (Dave Morton)
    • Compressed CKD DASD support (Greg Smith)
    • Many performance improvements (Juergen Dobrinski, with help from Albert Louw and Valery Pogonchenko)
    • DASD I/O optimizations (Greg Smith and Malcolm Beattie)
    • Simplified building on non-Intel architectures (Jay Maynard)
    • Fix for random bug in MP instruction (Mario Bezzi)
    • Treat all 3505 card reader read CCWs the same (Jay Maynard)

    Download hercules-1.68.tar.gz

    What's new in release 1.67

    Release date: 4 September 2000

    • Win32 portability changes (John Kozak)
    • Fix for 64K segment length checking in 370 DAT (Jay Maynard, found by Mario Bezzi)
    • Fix for TPI storing interrupt code when no interrupt pending (Jay Maynard, found by Greg Smith)
    • Skip to channel 9 and 12 support (Roger Bowler)
    • Panel refresh rate speedup and command (Reed Petty)
    • Fix storage protection override on fetch (Jan Jaeger)
    • SIE support, with S/370 and ESA/390 modes and vector support (Jan Jaeger)
    • Bugfix for MXR instruction (by Peter Kuschnerus)
    • CONCS, DISCS and RCHP instructions (Jan Jaeger)
    • Fix flags on intermediate subchannel status (Jan Jaeger)
    • Break SYSCONS output lines when too long (Jan Jaeger)
    • Floating point instructions SQDR and SQER (by Peter Kuschnerus)
    • Lock Page instruction (Jan Jaeger)

    Download hercules-1.67.tar.gz

    What's new in release 1.66

    Release date: 3 August 2000

    • Simplify logmsg and DEVTRACE macro definitions (Jay Maynard)
    • Prevent incorrect length indication on CONTROL NOP CCW (Jay Maynard)
    • Complete 370 HIO processing (Jay Maynard)
    • Correct nullification of TPI and TSCH (Jan Jaeger)
    • Add device locking to MSCH (Jan Jaeger)
    • Correct TPROT instruction (Jan Jaeger)
    • Correct address wrapping on assist instructions (Jan Jaeger)
    • Change interrupt logic to use longjmp on all interrupts (Jan Jaeger)
    • Clear remainder of ASTE when loading ASTE with ASF=0 in translate_asn (Jan Jaeger)
    • Add (incomplete) PLO instruction (Jan Jaeger)
    • Fix CLCL interruption problem (Jan Jaeger)
    • Fix addresswrap in MVO (Jan Jaeger)
    • Make ED and EDMK perform a trial run (Jan Jaeger)
    • Fix address wraparound in MVO (Jan Jaeger)
    • Fix CR15 corruption in form_stack_entry, fix nullification in form_stack_entry and unstack_registers (Jan Jaeger)
    • Fix loss of interrupts in PR (Jan Jaeger)

    Download hercules-1.66.tar.gz

    What's new in release 1.65

    Release date: 22 July 2000

    • Track overflow processing fixes (by Jay Maynard, suggested by Valery Pogonchenko)
    • Added TOD clock update to STCK, STCKE, DIAG 204, and TRACE processing (by Jay Maynard)
    • Fixed READ DEVICE CHARACTERISTICS alternate track values for 3380 and 3390 (by Peter Macdonald)
    • Skeletal CMPSC instruction (by Bernard van der Helm)
    • Added support for 3340 and 3375 DASD (by Jay Maynard, with help from Rick Fochtman and David Cole)
    • Corrected interval timer update increment (by Jay Maynard)
    • float.c optimization for new instruction decode and execution (by Peter Kuschnerus)
    • Fix program check on TIC ccw (by Jan Jaeger)
    • Fix program check on NOP ccw (by Jan Jaeger)
    • Instruction decode & execution restructure (by Jan Jaeger)
    • Added -fomit-frame-pointer to compiles for improved performance (by Jan Jaeger)
    • Fix STCKE instruction (by Bernard van der Helm)

    Download hercules-1.65.tar.gz

    What's new in release 1.64

    Release date: 4 July 2000

    • Added track overflow processing for CKD DASD (by Jay Maynard)
    • Makefile change to allow RPM building with RPM_BUILD_ROOT (by David Barth)
    • Added NetBSD build definitions to makefile (by Soren Jorvang)
    • Moved version definition to version.h and removed makefile dependency for source modules (by Jay Maynard)
    • Package change: tarball now explodes into hercules-<version> subdirectory (by Jay Maynard, suggested by Soren Jorvang)
    • Fix backward going TOD clock (by Jan Jaeger)
    • Suppress superflous HHC701/HHC702 messages (by Jan Jaeger)
    • Rework cpu.c to decode instructions by macro (by Jan Jaeger)
    • Bypass bug in IBM telnet client (by Jan Jaeger)

    Download hercules-1.64.tar.gz

    What's new in release 1.63

    Release date: 18 June 2000

    • 3270 CCW processing improvements (by Jan Jaeger)
    • OSTAILOR generalization, and new pgmtrace panel command (by Jan Jaeger)
    • VM IUCV instruction correction and DIAGNOSE improvements (by Jan Jaeger)
    • CPU timer and clock comparator improvements (by Jan Jaeger, after a suggestion by Willem Konynenberg)
    • 3480 READ BLOCK ID and LOCATE CCW support (by Brandon Hill)
    • Networking support via virtual CTCA (by Willem Konynenberg)
    • Restructured CPU execution, by function call instead of switch statement (by Mike Noel)
    • Support for IEBCOPY sequential output datasets in dasdload (by Ronen Tzur)
    • New dasdls command lists the VTOC of a CKD DASD volume (by Malcolm Beattie)
    • New AWSTAPE handling commands: tapesplt, tapemap (by Jay Maynard)
    • make install target to install in /usr/bin (by Jay Maynard)

    Download hercules-1.63.tar.gz

    What's new in release 1.62

    Release date: 3 June 2000

    • Still more multiprocessor improvements (by Jan Jaeger)
    • Dynamic CPU reconfiguration (by Jan Jaeger)
    • Basic vector facility (by Jan Jaeger)
    • Floating point version 6 (by Peter Kuschnerus)
    • READ AND RESET BUFFERED LOG CCW (X'A4') support (by Jay Maynard)
    • WRITE SPECIAL CKD CCW (X'01') support (by Jay Maynard)
    • FBA DASD model reporting fixes (by Jay Maynard)

    Download hercules-1.62.tar.gz

    What's new in release 1.61

    Release date: 21 May 2000

    • More multiprocessor improvements (by Jan Jaeger)
    • New startall/stopall panel commands (by Jan Jaeger)
    • STIDP stores processor address in first digit of CPU id (by Roger Bowler)
    • Correction to IPTE instruction for S/370 (by Jay Maynard)
    • Dummy HIO instruction for S/370 (by Jay Maynard)
    • Support for emulated 0671 FBA DASD (by Jay Maynard)
    • FBA device reserve/release CCW support (by Jay Maynard)
    • New OSTAILOR configuration option allows selective suppression of program check messages (by Jay Maynard)

    Download hercules-1.61.tar.gz

    What's new in release 1.60

    Release date: 14 May 2000

    • Multiprocessor locking improvements (by Jan Jaeger)
    • Machine check and channel report word (by Jan Jaeger)
    • Store Channel Report Word (STCRW) instruction (by Jan Jaeger)
    • New attach/detach/define commands to allow dynamic addition and deletion of devices from the configuration (by Jan Jaeger)
    • Compare and Swap and Purge (CSP) instruction (by Jan Jaeger)
    • Broadcasted purging (by Jan Jaeger)
    • Fix LASP instruction SASN authorization using wrong AX if bits 29-31 are 010 and SASN \= PASN (by Mario Bezzi)
    • Fix SAC instruction special operation exception setting secondary space mode when ASF=0 (by Mario Bezzi)
    • Remove intdrag option and replace drag command by toddrag command
    • New extpending flag to improve performance (originally contributed by Valery Pogonchenko and enhanced by Jan Jaeger)
    • Allow longer host name in console connected message (by Jay Maynard)
    • Floating point version 5 including fixes by Mario Bezzi (contributed by Peter Kuschnerus)

    Download hercules-1.60.tar.gz

    What's new in release 1.59

    Release date: 30 Apr 2000

    • Missing interrupt after CSCH instruction
    • S/370 DAT support (contributed by Jay Maynard)
    • Tape device sense byte improvements (by Jan Jaeger)
    • Read Buffered Log (CCW X'24') for tape devices (by Jan Jaeger)
    • Reject Sense ID CCW for 3420 tape devices (by Jan Jaeger)
    • Suppress unprintable character in HMC messages (by Jan Jaeger)
    • Suppress attention interrupt if subchannel not enabled (by Roger Bowler)
    • New interrupt drag factor to improve performance (by Roger Bowler)
    • New toddrag and intdrag config options and drag control panel command allow drag factors to be set (by Roger Bowler)
    • Light optimization on CPU critical path (by Valery Pogonchenko)
    • Eliminate fetch protection override in S/370 mode (by Valery Pogonchenko)

    What's new in release 1.58

    Release date: 22 Apr 2000

    • Support for CKD DASD volumes exceeding 2GB such as 3390-3 (by Roger Bowler)
    • 3274-1D SELECT RB/RMP/RBP/WRT commands (by Roger Bowler)
    • Support for 3270 14-bit SBA addressing and inbound SFE order (by Roger Bowler)
    • Command reject if Write Structured Field CCW issued to a 3270 without extended attributes (by Roger Bowler)
    • Fix missing CSW_IL indication when CCW count exhausted (by Roger Bowler)
    • Do not set unit exception if CCW count is zero (by Jan Jaeger)
    • Suppress space switch event program check messages (by Jan Jaeger)
    • Branch tracing and cross memory tracing for BALR, BASR, BASSM, BAKR, BSA, BSG, SSAR, PC, PT, PR instructions (by Jan Jaeger)
    • New diagnose instruction to stop CPU (by Jan Jaeger)
    • Drag factor option slows down TOD clock, to decrease overhead on very slow machines (by Jan Jaeger)
    • Correction to PR instruction (by Jan Jaeger)
    • Correction to LASP instruction (by Jan Jaeger)
    • Make CLCLE/MVCLE/CKSM instructions conditional features (by Jan Jaeger)
    • Enable channel measurement mode (by Jan Jaeger)
    • Modify program_check() to handle shadow registers correctly (by Jan Jaeger)
    • Change DAT to favour PSTD in TEA, to give reduction in page fault path length (by Jan Jaeger)
    • Avoid clearing registers at CPU reset (by Jan Jaeger)
    • Leave GPR, AR and FPR intact during CPU reset for SADUMP (by Jan Jaeger)
    • Zeroize field for called space identification in PC stack entry (by Jan Jaeger)
    • New CCW X'8D' (Write Update Key and Data) required by STOW (by Jan Jaeger)
    • Fix for 0B7 abend in D M=CHP command (by Jan Jaeger)
    • Floating point version 4 including fixes by Valery Pogonchenko (contributed by Peter Kuschnerus)
    • Fix incorrect second operand address in MVCIN instruction (by Roger Bowler)
    • Correct sign of zero result in SRP instruction (by Roger Bowler)
    • Erase Gap (CCW X'17') for tape devices (by Roger Bowler)
    • Activate MIPS counter on control panel (by Dutch Owen)
    • Suppress tracing of ISK, SCK, and DP instructions

    What's new in release 1.57

    Release date: 30 Mar 2000

    • Fix program check 0032 due to wrong stack entry being updated
    • Fix wrong SSTD loaded by LASP instruction (found by Jan Jaeger)
    • Bypass main storage lock in single CP configuration (by Jan Jaeger)
    • Fix incorrect condition code in PGIN instruction (by Jan Jaeger)
    • Corrections to expanded storage instructions (by Jan Jaeger)
    • New STCPS and SCHM instructions (by Jan Jaeger)
    • Set more appropriate sense bytes for tape errors

    What's new in release 1.56

    Release date: 28 Mar 2000

    • Fix incorrect unit exception on SCSI tape FSB/BSB CCW (reported by Daniel Rudin)
    • Fix unit check on AWSTAPE write (reported by Axel Schwarzer)
    • Close SCSI tape after tape is ejected
    • Detect tapemark during SCSI tape FSB/BSB CCW
    • Suppress HMC response prompt (by Jan Jaeger)
    • Expanded storage support (by Jan Jaeger)
    • Move Page Facility 2
    • Correct signed length error in MVCK/MVCS/MVCP (by Jan Jaeger)
    • Undetected CC=3 in SRP instruction
    • Wrong remainder in DP instruction when dividend is less than divisor
    • Specification exception in DP instruction should have higher priority than data exception

    What's new in release 1.55

    Release date: 22 Mar 2000

    • FBA minidisk support
    • Additional diagnose functions
    • Allow real storage frames to be marked unusable (by Jan Jaeger)

    What's new in release 1.54

    Release date: 18 Mar 2000

    • Address wraparound improvement (contributed by Jan Jaeger)
    • Floating point version 3 (contributed by Peter Kuschnerus)
    • Correction to SLDA/SRA instructions (contributed by Jan Jaeger)
    • Recognize tabs and end-of-file character in ASCII cardrdr files
    • Hercules-specific diagnose instructions (contributed by Jay Maynard)
    • Correct missing timer interrupt when interval timer goes from zero to negative (thanks to Valery Pogonchenko)
    • Enable HMC system console in S/370 mode
    • Correct sign propagation in multiply instruction
    • Reduce CPU thread priority (thanks to Steve Gay and Reed H.Petty)

    What's new in release 1.53

    Release date: 01 Mar 2000

    • Add BSF/FSF/BSB/FSB CCW support for tape devices
    • Allow final short block in OMA fixed block files
    • Allow processing of read-only AWSTAPE files and SCSI tapes
    • Skeleton ctcadpt module for future 3088 support
    • Correctly nullify IC/NI/OI/XI/CLM/STCM/ICM/TRT instructions on page translation exception (thanks to Jan Jaeger)
    • Improved floating point support (contributed by Peter Kuschnerus)
    • Correct shift result when shift count exceeds 31 (thanks to Glen Herrmannsfeldt and Jay Maynard)
    • Fix incorrect MVCL cc=3 when destination length is 1

    What's new in release 1.52

    Release date: 19 Feb 2000

    • Prevent incorrect length indication on 3270 Select CCW
    • 2K storage protection for S/370
    • Prevent wait for console port (thanks to Malcolm Beattie)
    • Allow keyword parameters in configuration file
    • New sysepoch and tzoffset parameters (thanks to Jay Maynard)
    • Adjust TRACE and DIAG204 for extended TOD (thanks to Jan Jaeger)
    • Set TOD clock in SCK instruction (thanks to Jan Jaeger)

    What's new in release 1.51

    Release date: 15 Feb 2000

    • 3270 read buffer fix for OS/360 NIP
    • Floating point instructions (contributed by Peter Kuschnerus)
    • Remove 32-bit pointer dependency from dasdload for Alpha
    • HMC system console support (contributed by Jan Jaeger)
    • Correct condition code after decimal overflow (thanks to Jan Jaeger)
    • Set reference and change bits for PSA access (thanks to Jan Jaeger)
    • New CRLF option for printer and card punch (default is now LF)

    What's new in release 1.50

    Release date: 10 Feb 2000

    • Remove interval timer debugging message
    • Fix hung console resulting from attention interrupt fix in 1.49
    • Seek and Set Sector (CCW=27) for Itel 7330 DASD controller
    • Correct SIGP handling of non-existent CPUs (thanks to Jan Jaeger)
    • Extended TOD clock bit in processor features (thanks to Jan Jaeger)
    • Alternate control panel help text (contributed by Dutch Owen)
    • Card reader end of file option (thanks to Dutch Owen)
    • Card reader ASCII/EBCDIC auto-detection
    • Fix SIGP RESTART to target correct CPU (thanks to Jan Jaeger)
    • Allow VTOC size and location to be specified for dasdload.

    What's new in release 1.49

    Release date: 05 Feb 2000

    • Alternate control panel (contributed by Dutch Owen)
    • Present attention interrupt when console connects
    • Fix dasdload CVOL logic (thanks to Jay Maynard)
    • Fix dasdload initialization of empty PDS
    • Allow device size to be specified for dasdload Note: the volser record in the pack layout file must be changed to specify the device type and cylinder count; the device type is no longer specified on the command line.
    • Add dummy Set Clock instruction (does nothing except set cc 0)

    What's new in release 1.48

    Release date: 31 Jan 2000

    • Fix dasdload to handle note lists (prevent 32D abend)
    • I/O interrupt performance enhancement
    • Correctly detect overflow in signed Add/Subtract instructions
    • Fix track overflow problem
    • 3270 Read Modified CCW

    What's new in release 1.47

    Release date: 23 Jan 2000

    • Allow tn3270 or telnet client to connect to specific device number
    • Align control panel instruction counter (thanks to Mario Bezzi)
    • Ensure panel display does not corrupt TEA (by Jan Jaeger)
    • STIDP incorrectly propagates high order bit of CPU model (fixed by Jan Jaeger)
    • Fix byte-ordering problem with CKD DASD header on non-Intel machines (reported by Adam Thornton)
    • STIDC instruction
    • Extended TOD clock (STCKE and SCKPF instructions)
    • 3211 Load FCB and Diagnostic Read CCW
    • 3270 Read Buffer CCW
    • Fix console.c to inhibit input while console has status pending

    What's new in release 1.46

    Release date: 11 Jan 2000

    • HSCH instruction
    • SIGP instruction
    • Suppress tracing of page faults
    • Display control registers and access registers after program check
    • Add regs parameter to program_check function calls
    • New panel command to perform store status function
    • Suppress tracing of CCW file protect and end of cylinder errors

    What's new in release 1.45

    Release date: 08 Jan 2000

    • Make MVCL/CLCL interruptible (contributed by Jan Jaeger)
    • Diagnose 204 (contributed by Jan Jaeger)
    • Read Channel Subsystem Info (contributed by Jan Jaeger)
    • Fix incorrect register count in TRACE instruction
    • Correct nullification of STM/LM/LAM/STAM/STCTL/LCTL/STCM and SS instructions whose operands cross a page boundary
    • Suppression on Protection with Virtual-Address enhancement
    • Select correct address space for MVCS/MVCP (fixed by Jan Jaeger)
    • Correct registers after CLCL/CLCLE with non-zero condition code
    • Defer clock comparator interrupt while instruction stepping
    • Remove 32K limit on data chained write CCWs for non-CKD devices
    • Correct overrun error on data chained write for FBA DASD

    What's new in release 1.44

    Release date: 01 Jan 2000

    • Support for 9336 FBA DASD
    • Read Replicated Data command for FBA DASD
    • Prevent recursive program check after instruction fetch error
    • Operand tracing for MVCL/CLCL and RRE instructions

    What's new in release 1.43

    Release date: 27 Dec 1999

    • New control panel command: devlist
    • Write Update Data (X'85') CCW for CKD devices
    • Makefile changed to use $(CC) instead of cc
    • Fix dat.c to prevent ASN translation specification exception (program check X'0017') if subspace group facility is installed and ASF is one
    • Fix cpu.c to clear ILC before fetching instruction to prevent PSW being backed up if access error occurs during instruction fetch
    • Correct program check ILC when instruction is nullified
    • Obtain CPU model number for STIDP from configuration file (contributed by Jay Maynard) Note: if upgrading from an earlier release, you must change your hercules.cnf file to add a valid CPU model number after the CPU serial number
    • Prevent wait after devinit (thanks to Jay Maynard)
    • Open printer with O_SYNC to ensure buffers flushed (suggested by Daniel Seagraves)
    • Fix xmem.c to prevent loop in program_call when loading 4-word ETE (thanks to Jan Jaeger)
    • Improved TLB lookup (contributed by Jan Jaeger)

    What's new in release 1.42

    Release date: 16 Dec 1999

    • New makefile builds both S/370 and ESA/390 executables: hercules-370 and hercules-390 (contributed by Jay Maynard)
    • 3480 Set Path Group Id and Unassign CCWs (contributed by Jan Jaeger)
    • CFC and UPT instructions (contributed by Peter Kuschnerus)
    • Card punch support
    • Erase (X'11') CCW for CKD devices
    • Correct setting of translation exception address
    • Correct file mode when opening printer file
    • Correct condition code for shift arithmetic instructions

    What's new in release 1.41

    Release date: 07 Dec 1999

    • Set reference and change bits correctly for main storage accesses by channel, dat, xmem, stack, block, and service modules (thanks to Jan Jaeger)
    • New devinit command (contributed by Jay Maynard)
    • Reject control panel virtual storage display command if CR1=0
    • Fix dasdload to correctly write EOF record for empty file and to correctly fill block overhead fields in format4 DSCB.
    • Diagnose functions MSSFCALL and SCPEND (contributed by Jan Jaeger)
    • Corrections to service.c and assist.c (contributed by Jan Jaeger)
    • Alpha platform portability definitions (contributed by Jay Maynard)
    • 3480 Assign CCW (thanks to Rick McKelvy)

    What's new in release 1.40

    Release date: 30 Nov 1999

    • New DASDISUP program performs OS/360 IEHIOSUP function
    • Correct SCSW handling for suspend/resume
    • Forward space file CCW for tape devices
    • 3480 load display CCW (contributed by Jan Jaeger) and sense path group id CCW (thanks to Rick McKelvy)
    • Correct handling of OMA tape headers to correctly recognize tape mark and to align headers to 16-byte boundary
    • EBCDIC character translation of CCW data displays
    • Fix command reject for CKD read commands outside the domain of a locate record

    What's new in release 1.39

    Release date: 24 Nov 1999

    • Concurrent sense
    • I/O initial status interruption
    • Channel program suspend/resume function and RSCH instruction
    • Read Device Characteristics CCW for 3480
    • Fix incorrect command reject on Sense Subsystem Status CCW
    • Increase 3270 write buffer size to prevent console I/O error when using Zap function of ZZSA
    • Fix very nasty error in dat.c causing wrong bytes to be fetched or stored when operand crosses page boundary
    • Remove temporary fix to ckddasd.c introduced in 1.37

    What's new in release 1.38

    Release date: 22 Nov 1999

    • New panel commands to allow storage alteration
    • Fix incorrect I/O parameter on attention interrupt (thanks to Jan Jaeger for reporting this bug)
    • Clear PMCW correctly during I/O reset
    • Change 3270 control unit type to 3274-1D
    • Fix restart command broken by 1.37

    What's new in release 1.37

    Release date: 19 Nov 1999

    • Storage range display
    • EBCDIC character translation of storage displays
    • New breakpoint command (contributed by Dan Horak)
    • Messages go to log file as well as screen if stdout is redirected
    • Fix missing interrupt caused by channel.c failing to obtain device lock before setting interrupt pending
    • Fix incorrect cond code 1 in attention SCSW built by console.c
    • New Read Channel Path Information service call
    • Temporary fix to ckddasd.c multitrack search
    • Addition of Read Device Characteristics and Sense Subsystem Status commands for CKD devices
    • New DASDPDSU program to unload PDS members from a CKD volume

    What's new in release 1.36

    Release date: 12 Nov 1999

    • Clear subchannel instruction
    • Correct fault causing control panel display corruption

    What's new in release 1.35

    Release date: 09 Nov 1999

    • Improved control panel user interface
    • New control panel commands: start, stop, restart, ipl, loadparm
    • New loadcore command to load disk image files
    • S/370 interval timer
    • Allow 31-bit mode linkage in lock instructions
    • Support for PCI in ESA/390 mode as well as S/370 mode
    • Correct problem causing false channel protection checks

    What's new in release 1.34

    Release date: 29 Oct 1999

    • New DASDLOAD program to create a CKD volume from unloaded PDS files
    • Correct CKD module to prevent record not found error on multitrack Read Count CCW

    What's new in release 1.33

    Release date: 26 Oct 1999

    • Write support for SCSI tapes and AWSTAPE files
    • Correct handling of REWIND command for AWSTAPE files
    • Correct nasty bug in Subtract Logical instruction (thanks to Roland Goetschi for finding this bug)
    • Ensure unique TOD clock values for Store Clock
    • Correction to unstacking process for PR instruction
    • Implementation of Read Multiple CKD command

    What's new in release 1.32

    Release date: 18 Oct 1999

    • Support for virtual tapes in OMA (Optical Media Attach) format
    • SCSI tape support (read-only)
    • Minor corrections to CKD DASD support


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercrdr.html0000664000175000017500000001622512564723224013474 00000000000000 Hercules Version 3: Submitting jobs via the socket reader

    Hercules version 3: Submitting jobs via the socket reader

    The "sockdev" option allows you to submit cards directly to a Hercules card reader from outside of Hercules. What you do is define your reader with the "sockdev" keyword and either a TCP/IP port number or the name of a Unix Domain Socket. Then whenever you want to submit a card deck to that particular card reader, you use an external program to connect to the socket and transmit the cards to the reader.

    Socket readers were implemented by Fish, based upon code originally contributed by Malcolm Beattie.

    Socket readers are defined in the Hercules configuration file like this:

    devnum devtype sockspec sockdev [option ...]

    The socket specification sockspec can take any of the following formats:

    ipaddr:port

    The reader listens on the specified IP address and port number. ipaddr must be the IP address of an interface on the local system. For example, 127.0.0.1:1234 to accept only jobs submitted locally via the loopback interface.

    hostname:port

    Similar to the previous example, where hostname must resolve to an IP address belonging to the local system. Example: localhost:1234.

    port

    The reader listens on the specified port number and accepts jobs submitted to any IP address defined on the local system. Example: 1234.

    sockpath/sockname

    The reader listens on the specified Unix Domain Socket. Example: /tmp/hercrdr.00C.

    Examples

    
        000A   2501   127.0.0.1:2501    sockdev  ascii  trunc  eof
        000C   3505   localhost:1234    sockdev  ascii  trunc  eof
        0012   3505   3505              sockdev  ascii  trunc  eof
        0014   2501   /tmp/hercrdr.014  sockdev  ascii  trunc  eof
    

    Submitting jobs from Windows

    The "HercRdr" program, distributed as part of Fish's GUI Package, allows you to send jobs to a socket reader via TCP/IP. Simply enter "HercRdr" from the command line (i.e. from either a "MSDos Prompt" window if you're using Win9x or from a "Command Prompt" window if you're using NT/2K/XP) to submit your file(s). Here's the "help information" that's displayed whenever you enter "HercRdr" without any parameters:

    
        C:\WINDOWS>hercrdr
        Submits card file(s) to a Hercules card reader bound to a given socket:port.
    
        Format:
    
         HERCRDR [-nnn] [host:port] file [file...]
    
        Where:
    
         -nnn timeout value in seconds (1-999; default is 3)
         host:port sock_spec of target reader (if not specified,
         value of HERCRDR environ var is used, if set)
         file file(s) to be submitted
    
        Examples:
    
         HERCRDR localhost:1234 fileone.txt filetwo.txt
         set HERCRDR=localhost:1234
         HERCRDR file3.txt file4.txt
         HERCRDR override:5678 filefive.txt
         HERCRDR 192.168.0.1:5678 666.txt 777.txt 888.txt 999.txt
    
        Returns:
    
         -1 unclassified error
         0 file(s) successfully submitted
         1 no route to host (bad sock_spec or connection refused)
         2 timeout value exceeded while trying to connect
         3 transmission error (e.g. connection prematurely closed)
         4 file not found (or other file error)
    
    

    How to submit jobs directly from SPF/PC

    If you are lucky enough to have a copy of SPF/PC Version 4 or SPF/Pro (produced by CTC but unfortunately no longer available), then you can capture the authentic mainframe experience by submitting jobs directly from your edit session. The SUB command can be implemented by means of a REXX macro, such as this one provided by Volker Bandke:

    
        /* +----------------------------- REXX -----------------------------+ */
        /*                                                                    */
        /*      Name: D:\APPS\SPFPRO\REXX\USER\SUB.SPF                        */
        /*                                                                    */
        /*      Type: SPF edit macro                                          */
        /*                                                                    */
        /*      Desc: submit JCL to MVS 3.8                                   */
        /*                                                                    */
        /*      Creation date: 24 Aug 1999, creation time: 18:49:40           */
        /*                                                                    */
        /*      Author: (c) Volker Bandke                                     */
        /*                                                                    */
        /* +----------------------------------------------------------------+ */
        'isredit macro (p1 p2 p3 p4 p5 p6 p7 p8 p9)'
        "ISREDIT (member) = MEMBER"
        "ISPEXEC CONTROL ERRORS CANCEL"
        parse upper var member file '.' ext
        do
        'ISREDIT REPLACE' $$$$$$$$.SPF '.ZF .ZL'
        ADDRESS "CMD" "HERCRDR 192.168.1.102:3505 $$$$$$$$.SPF"
        zedsmsg = 'File submitted'
        zedlmsg = 'The member '||member||' has been submitted to MVS'
        'ispexec setmsg msg(isrz000)'
        ADDRESS "CMD" "DELETE $$$$$$$$.SPF"
        end
        EXIT 0
    

    Submitting jobs from Unix

    Using a Perl script

    Malcolm Beattie has provided a simple Perl script which can submit jobs using either TCP/IP or Unix Domain Sockets.

    The script is invoked using one of the following command formats:

        hercsub  192.168.1.102:3505  dummy.jcl
        hercsub  /tmp/hercrdr.00C  dummy jcl
    Here is the sample script:
    
        #!/usr/bin/perl
        use Socket;
        use IO::Socket::UNIX;
        use IO::Socket::INET;
    
        if (@ARGV < 1) {
          print STDERR "Usage: hercsub socket_spec [job]\n";
          exit 2;
        }
    
        my $spec = shift @ARGV;
        my $sock;
    
        if ($spec =~ m{^/}) {
          $sock = IO::Socket::UNIX->new(Peer => $spec);
        } else {
          $sock = IO::Socket::INET->new(PeerAddr => $spec);
        }
    
        die "Failed to connect to socket $spec: $!\n" unless defined($sock);
    
        while (<>) {
          print $sock $_;
        }
    
    

    Using the netcat program

    The netcat (nc) program can also be used to submit files to a Hercules reader via TCP/IP.

    Install netcat (which is useful for innumerable other things as well) and use:

    nc -w1 localhost 1234 < dummy.jcl

    For more information, type  man nc.


    Last updated 21 Apr 2006 hercules-3.12/html/hercrnot.html0000664000175000017500000002153712564723224013671 00000000000000 Hercules Version 3: Release Notes and Known Issues

    Hercules Version 3: Release Notes and Known Issues


    Release notes for release 3.03

    Release date: 20 December 2005

    New device types 1052-C and 3215-C

    The new integrated console printer-keyboard is emulated on the hercules console. Commands are sent to the console by means of a command character. (default '/', thus a logon command is sent by /logon)

    Message Security Assist

    Starting from release 3.03 the glibcrypt library is no longer needed.

    Release notes for release 3.02

    Release date: 11 December 2004

    ASN-and-LX-reuse facility

    This is a new feature of z/Architecture which can cause problems with certain versions of operating systems running in ARCHLVL=2 mode without the so-called "Driver 55" fixes. To avoid such problems, specify ASN_AND_LX_REUSE DISABLE in the configuration file.

    Release notes for release 3.01

    Release date: 30 November 2003

    Library modules and HTTP documents default directories

    An error in the 3.00 configuration script caused many users to have to override the default modules and HTTP documents directory in the Hercules configuration file, or by setting an environment variable. This error has been corrected. Hercules also now reports the actual directory that it uses by default for these files at startup time. If you specified the MODPATH or HTTPROOT configuration file statements because you encountered problems, you should examine the messages printed at startup to see if the default directories are now correct, and remove the statements if so.

    In general, MODPATH and HTTPROOT should not have to be specified except in unusual circumstances.

    Windows default directories

    In conjunction with the fix above, the default directories of the Windows distributed binaries have been changed. The new directories are under C:\cygwin\usr\local (which is the same as /usr/local under the Cygwin environment). No action is needed unless you have specified the MODPATH or HTTPROOT configuration file entries; if so, see the previous note.

    Message Security Assist

    Support for z990 crypto instructions is conditional on the presence of the glibcrypt library. When Hercules is BUILT, the development files for glibcrypt should be available. When hercules is RUN, the runtime files for glibcrypt should be installed.

    Depending on the level of glibcrypt used to *build* hercules, the associated level of glibcrypt should also be present on the target machine. On systems supporting shared library versioning, multiple levels of the glibcrypt runtime libraries can be installed simultaneously, ensuring availability of the z990 crypto instructions, regardless of the level of glibcrypt with which hercules was initially built.

    CTC and LCS device numbers

    CTC and LCS devices now MUST specify ALL addresses on the configuration statement. Previously (i.e. with version 3.00), only the first (even numbered) device needed to be defined and Hercules would automatically define the odd numbered device for you. Starting with Hercules version 3.01 however, you now need to define BOTH devices, just like you did with versions prior to 3.00. Once again, starting with version 3.01, you **MUST** define BOTH DEVICES.

    Release notes for release 3.00

    Release date: 3 October 2003

    CTCI device changes
    • The CTCI-W32 protocol is deprecated. You should use the CTCI protocol instead.
    • The VMNET protocol is also deprecated. Not even its author uses it any more. Every system on which Hercules is now prebuilt has the TUN/TAP driver functionality available in one form or another, and it's much more robust.
    Both of these will go away in a future release.

    In addition, you must not define both even/odd CTCI device pairs in your configuration file. You should only define the first even numbered device. Hercules will automatically define the odd numbered device for you. If you define the odd numbered device by mistake, an open error will occur on that device. This is by design. See the README.NETWORKING document for further details.

    Hercules Dynamic Loader support

    Starting with version 3.00, Hercules now contains support for the dynamic loading of certain modules upon startup on Linux, Windows, and Mac OS X. This support should also work on any platform supported by GNU libtool. As a result of this new feature, Hercules itself now no longer consists of just the 'hercules.exe' module by itself, but rather consists of both the 'hercules.exe' program as well as whatever dynamic modules (DLLs) that accompany it.

    As a result of this change, whenever you install a new version of Hercules, you must ensure that you ALSO install the accompanying new versions of the new dynamic modules as well. Attempting to use a version of Hercules with a dynamic module that was not specifically built for that version will cause loading of that dynamic module to fail.

    You cannot mix versions of Hercules with differing versions of dynamically loaded modules.

    Ensure that your library path (set by the environment variable LD_LIBRARY_PATH) set correctly such that it includes the directory of your Hercules dynamic load libraries. If you see message HHCCF042E, which indicates that the system is unable to locate necessary loadable modules, this is likely your problem. This should not be necessary if you have a binary download, but if you're building from source, especially if you've previously installed a binary package, this should be the first thing you do.

    ECPS:VM

    Do not use ECPS:VM (See README.ECPSVM) in an AP or MP environment in VM/370. If AP=YES or MP=YES is coded in DMKSYS and the AP/MP control file is used to build the CP nucleus and NUMCPU is set to more than 1 in the hercules.cnf file, any of LOK001, LOK003 or other abends will occur. This occurs because the Hercules ECPS:VM CP Assist implementation is not MP safe, and particularly, attempts VM dispatching without holding necessary AP or MP locks.

    Memory allocation on Windows

    Due to the change in the "mainstor" memory allocation technique used by Hercules to address a "double memory consumption" bug in Cygwin's malloc implementation, some Windows Hercules users may experience an "out of memory" error whenever Hercules is started with a large MAINSIZE configuration file value:

    HHCCF031S Cannot obtain nnnMB main storage

    This error will most likely occur (if it does at all) for those users who have manually adjusted their Cygwin heap_chunk_in_mb Windows registry setting value (in order to allow them to specify a large MAINSIZE value when running Hercules). If this problem does occur (i.e. if you do happen to experience the above mentioned error with this new release of Hercules), then either reduce your heap_chunk_in_mb value (yes, that's correct: reduce it, as in change it to a smaller value) or else remove it altogether (so as to let it default).

    A complete discussion of this issue is in the RELEASE.NOTES file in the source distribution.

    Thread priority and other problems

    There is a known problem with thread priority handling under Mac OS X. The OS X threading model is different from the one classically used in Linux. This causes failures to set the timer thread priority, and slow performance as all of Hercules is set to a low execution priority. This will be fixed in a future release. A workaround, for now, for slow performance is to add the statement

    CPUPRIO 0

    to your Hercules configuration file.

    A possibly related problem is that Hercules fails in random ways when using the NPTL (new POSIX threads library) library under Linux. This library is used by default in Red Hat 9, and possibly other systems. If problems are encountered on a very recent version of Linux, try issuing the command

    export LD_ASSUME_KERNEL=2.4.1

    before starting Hercules.


    If you have a question about Hercules, see the Hercules Frequently-Asked Questions page.


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercsupp.html0000664000175000017500000002312212564723224013666 00000000000000 Hercules Version 3: Technical Support

    Hercules Version 3: Technical Support


    Paid Support

    Hercules technical support may be available for a fee. Enquiries should be addressed to Open Source Mainframes, Inc. at opensourcemainframes.org


    Free Support

    If your question and/or concern regarding Hercules is not already addressed in the FAQ, then you might consider posting your question to either the main Hercules-390 forum or one of the more "focused" forums discussed next:


    
        HERCULES-390:   Discussion group for users of the Hercules ESA/390 mainframe emulator
    
            Community email addresses:
    
                Post message:  hercules-390@yahoogroups.com
                Subscribe:     hercules-390-subscribe@yahoogroups.com
                Unsubscribe:   hercules-390-unsubscribe@yahoogroups.com
                List owner:    hercules-390-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/hercules-390
    
    


    The Hercules-390 forum is your primary source for free Hercules support, and you are strongly encouraged to subscribe. There is a vibrant, active community of over 5000+ members, many of whom are very knowledgeable in many different areas of mainframe technology, both from a hardware point of view as well as from an operating system and software point of view.

    In addition to the main Hercules-390 forum, other more specialized Hercules forums also exist to provide more focused support for a variety of popular IBM mainframe operating systems, such as DOS, VM, and MVS:


    
        H390-DOSVS:   DOS/VS and DOS/VSE under Hercules
    
            Community email addresses:
    
                Post message:  h390-dosvs@yahoogroups.com
                Subscribe:     h390-dosvs-subscribe@yahoogroups.com
                Unsubscribe:   h390-dosvs-unsubscribe@yahoogroups.com
                List owner:    h390-dosvs-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/h390-dosvs
    
    
    
        H390-MVS:   Hercules-390 users whom are trying to run MVS
    
            Community email addresses:
    
                Post message:  h390-mvs@yahoogroups.com
                Subscribe:     h390-mvs-subscribe@yahoogroups.com
                Unsubscribe:   h390-mvs-unsubscribe@yahoogroups.com
                List owner:    h390-mvs-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/h390-mvs
    
    
    
        TURNKEY-MVS:   Support for Volker Bandke's "MVS Tur(n)key System", a freely available
                       pre-built MVS 3.8J Operating System running under the Hercules emulator!
    
            Community email addresses:
    
                Post message:  turnkey-mvs@yahoogroups.com
                Subscribe:     turnkey-mvs-subscribe@yahoogroups.com
                Unsubscribe:   turnkey-mvs-unsubscribe@yahoogroups.com
                List owner:    turnkey-mvs-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/turnkey-mvs
    
    
    
        H390-VM:   Hercules-390 users that are trying to run VM/370, VM/SP, & VM/ESA
    
            Community email addresses:
    
                Post message:  h390-vm@yahoogroups.com
                Subscribe:     h390-vm-subscribe@yahoogroups.com
                Unsubscribe:   h390-vm-unsubscribe@yahoogroups.com
                List owner:    h390-vm-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/h390-vm
    
    
    
        HERC-4PACK:   Support for Andy Norrie's 4 pack Hercules VM system.
    
            Community email addresses:
    
                Post message:  herc-4pack@yahoogroups.com
                Subscribe:     herc-4pack-subscribe@yahoogroups.com
                Unsubscribe:   herc-4pack-unsubscribe@yahoogroups.com
                List owner:    herc-4pack-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/herc-4pack
    
    
    
        HERCULES-390-ANNOUNCE:   General announcements regarding the Hercules-390 emulator
    
            Community email addresses:
    
                Post message:  hercules-390-announce@yahoogroups.com
                Subscribe:     hercules-390-announce-subscribe@yahoogroups.com
                Unsubscribe:   hercules-390-announce-unsubscribe@yahoogroups.com
                List owner:    hercules-390-announce-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/hercules-390-announce
    
    
    
        HERCULES-ADVOCACY:   Advocacy of issues relating to the Hercules emulator for IBM mainframe systems.
    
            Community email addresses:
    
                Post message:  hercules-advocacy@yahoogroups.com
                Subscribe:     hercules-advocacy-subscribe@yahoogroups.com
                Unsubscribe:   hercules-advocacy-unsubscribe@yahoogroups.com
                List owner:    hercules-advocacy-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/hercules-advocacy
    
    
    
        HERCULES-S370ASM:   Forum discussing use of S/370 assembler with the Hercules emulator
    
            Community email addresses:
    
                Post message:  hercules-s370asm@yahoogroups.com
                Subscribe:     hercules-s370asm-subscribe@yahoogroups.com
                Unsubscribe:   hercules-s370asm-unsubscribe@yahoogroups.com
                List owner:    hercules-s370asm-owner@yahoogroups.com
    
            Files and archives at:
    
                http://groups.yahoo.com/group/hercules-s370asm
    
    



    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/herctcp.html0000664000175000017500000003721112564723224013471 00000000000000 Hercules Version 3: TCP/IP networking with Hercules

    Hercules version 3: TCP/IP networking with Hercules

    This page describes how to set up TCP/IP connectivity between a Hercules machine and the outside world.

    Since Hercules runs as a user process under the control of a driving system (usually Linux/x86 or Windows), it does not have direct access to the driving system's network adapter. This presents a problem in establishing connectivity between the network and the TCP/IP stack of an operating system running under Hercules.

    But thanks to a technique originally demonstrated by Willem Konynenberg, it is possible to establish a virtual point-to-point link between the TCP/IP stack running under Hercules and the TCP/IP stack of the driving system. The driving system is then used as a router to pass IP frames between the Hercules TCP/IP stack and the rest of the network, as shown in the following diagram:

            +--------------------------------+
            |     Linux/x86 Driving System   |
            |                                |
            +-------------+                  |
            |  Hercules   |                  +--------+
            |-------------|                  |  eth0  |
            |   OS/390    |      TCP/IP ------------------> Network
            |   TCP/IP    |                  |10.1.2.1|
            |-------------|         |        +--------+
            |    CTCA     |         |        |
            |192.168.200.1|         |        |
            +------|------+   192.168.200.2  |
            |  /dev/tun           tun0       |
            |      |                |        |
            |      +----------------+        |
            |       Virtual CTC link         |
            |                                |
            +--------------------------------+
    

    The virtual CTC link is provided by the Universal TUN/TAP driver developed by Maxim Krasnyansky. This driver creates a tunnel which appears to Hercules as a character device (/dev/tun0 or /dev/net/tun) and appears to the driving system as a virtual network interface (tun0). The Hercules 3088 driver makes the tun device appear as a CTCA (Channel to Channel Adapter) to the S/390 operating system running under Hercules. Each end of the link has its own IP address which is distinct from the IP address of the driving system's real network adapter.

    The Universal TUN/TAP driver is currently only available for Linux, Solaris, and FreeBSD.   However, similar functionality may be obtained on Windows 98/Me/2000/XP systems (but not Windows NT) via the CTCI-W32 protocol.

    Installing the TUN/TAP Driver (Linux 2.2)

    The Linux 2.2 kernel does not include the TUN/TAP driver, so you need to install it using the following procedure:

    1. Download the file tun-1.0-1.i386.rpm from http://vtun.sourceforge.net/tun
    2. Install the driver using the following commands:
      su
      (enter the root password when prompted)
      rpm -ivh tun-1.0-1.i386.rpm
      chgrp xxxxx /dev/tun*
      (where xxxxx is the group under which you run Hercules)
      chmod g+w /dev/tun*
      chmod o-r /dev/tun*
    3. Edit the file /etc/modules.conf (it is called /etc/conf.modules in some distributions) and add the following line:
      alias char-major-90 tun
      This causes the TUN/TAP driver to be loaded automatically when a /dev/tun* device is opened by Hercules.

    Installing the TUN/TAP Driver (Linux 2.4)

    The TUN/TAP driver is delivered as part of the Linux 2.4 kernel, and if you are using one of the popular Linux distributions you will find that the TUN/TAP driver is already installed. If not, then you must rebuild the kernel with the configuration option CONFIG_TUN=m specified.

    Note that the version of TUN/TAP in Linux 2.4 differs from the earlier version in that it allows access to all TUN interfaces (tun0, tun1, etc) through a single character device /dev/net/tun, instead of defining multiple devices /dev/tun0, /dev/tun1, etc.

    The procedure for completing the TUN/TAP setup for Linux 2.4 is shown below.

    1. Use these commands to create the TUN device:
      su
      (enter the root password when prompted)
      mkdir /dev/net
      mknod /dev/net/tun c 10 200
      chgrp xxxxx /dev/net/tun
      (where xxxxx is the group under which you run Hercules)
      chmod g+rw /dev/net/tun
      chmod o-rw /dev/net/tun
    2. Edit the file /etc/modules.conf (it is called /etc/conf.modules in some distributions) and add the following line:
      alias char-major-10-200 tun
      This causes the TUN/TAP driver to be loaded automatically when the /dev/net/tun device is opened by Hercules.

    Installing the TUN/TAP Driver (Linux 2.6)

    For distributions based on the Linux 2.6 kernel you will probably find that the TUN/TAP driver is already installed and the /dev/net/tun device is already defined. If not, then follow the procedure for Linux 2.4 as descibed above.

    You will certainly need to alter the permissions on the /dev/net/tun device to allow Hercules to open it.

    • Use the following commands to set the necessary permissions:
      su
      (enter the root password when prompted)
      chown root:xxxxx /dev/net/tun
      (where xxxxx is the group under which you run Hercules)
      chmod 0660 /dev/net/tun
    • Additional notes from Greg Smith:
      1. I find on my Fedora Core 6 system that I have to add the above 2 commands to /etc/rc.local and update /etc/udev/rules.d/50-udev.rules replacing
        KERNEL=="tun", NAME="net/%k"
        by
        KERNEL=="tun", NAME="net/%k", GROUP="xxxxx", MODE="0660"
      2. In the hercules log you should see /dev/net/tun0 opened. I get a couple of error messages about SIOCDIFADDR and SIOCSIFHWADDR ioctl's failing but these can be ignored (maybe I'll fix that soon).

    In Linux 2.6 the file /etc/modules.conf no longer exists, instead there is a file called /etc/modprobe.conf. TUN/TAP will usually work, however, without any change to the modprobe configuration.

    Configuring the TUN interface

    The tun0 network interface in the driving system must be configured as a point-to-point link. The design of the TUN/TAP driver does not allow the interface to be statically configured like a regular network interface — the tun0 interface does not exist until Hercules opens the TUN device. For this reason, Hercules provides a special program called hercifc to configure the tun0 network interface. This program is launched automatically by Hercules 3088 CTC device initialization.

    To allow the hercifc program to issue the necessary configuration commands, you must ensure that hercifc is installed with setuid root file permissions. When Hercules is built with the configuration option --enable-setuid-hercifc, make install will install hercifc in /usr/local/bin with setuid root permissions. Note: Unrestricted access to the hercifc program could present a potential security exposure, so you will want to ensure that hercifc can be executed only by the group which is authorized to run Hercules. The following commands alter the file permissions to ensure that only users in a trusted group can execute hercifc:
    su
    (enter the root password when prompted)
    chgrp xxxxx /usr/local/bin/hercifc
    (where xxxxx is the group under which you run Hercules)
    chmod 4750 /usr/local/bin/hercifc
    exit

    Enabling IP forwarding

    You must ensure that your kernel is enabled for IP forwarding. Popular Linux distributions usually have a configuration option to enable IP forwarding or routing:

    • For RedHat, specify net.ipv4.ip_forward=1 in the /etc/sysctl.conf file.
    • For SuSE, specify IP_FORWARD="yes" in the /etc/rc.config file.
    • If you cannot find this option in your distribution, the following command should work on any Linux 2.x kernel:
      echo "1" > /proc/sys/net/ipv4/ip_forward

    Defining a route to Hercules TCP/IP

    Client systems which connect to TCP/IP applications running in the Hercules machine need to have a routing entry which defines the driving system as the gateway into the Hercules system. An example route definition for a Unix client system is shown below:

    route add 192.168.200.1 gw 10.1.2.1
    

    For a Windows client, go to Settings -> Control Panel -> Network -> Configuration -> TCP/IP -> Properties -> Gateway and add the driving system's IP address to the list of gateways. Alternatively, enter a route command such as:

    route add 192.168.200.0 mask 255.255.255.0 10.1.2.1 metric 1
    

    If you want to avoid having to update client systems, another way is to add an appropriate routing entry to your default gateway router.

    Defining the link in Hercules

    You must define a CTC device pair in the Hercules configuration file. The second device must bear the same definition as the 1st instance and be at device number + 1. The 1st device number must be even. Devices should preferably be grouped (furthermore, it makes the configuration file easier to read).


    0E20.2 CTCI 192.168.200.1 192.168.200.2
    or
    0E20,0E21 CTCI 192.168.200.1 192.168.200.2
    or
    0E20-0E21 CTCI 192.168.200.1 192.168.200.2

    Check Device Definition Statement syntax for an explanation of device grouping.

    Two IP addresses must be assigned, one for the driving system's end of the link, and one for the Hercules end of the link. For this example I have chosen 192.168.200.1 for the Hercules IP address, and 192.168.200.2 for the driving system's IP address. Since this is a point-to-point link, any addresses may be chosen, provided that the network part of the address (192.168.200 in this example) does not conflict with any existing network addresses used in your IP network.

    Configuring the Hercules TCP/IP stack

    TCP/IP for VSE

    This is an example of the configuration statements which you need to include in the IPINIT00.L member of PRD1.BASE:

    SET IPADDR   = 192.168.200.001
    SET MASK     = 255.255.255.000
    DEFINE LINK,ID=CTCE20,TYPE=CTCA,DEV=(E20,E21),MTU=1500
    DEFINE ROUTE,ID=LINUX,LINKID=CTCE20,IPADDR=0.0.0.0
    

    The CTC devices should be defined to VSE using the following statements in the $IPLxxx.PROC procedure in IJSYSRS.SYSLIB:

    ADD E20:E21,CTCA,EML
    

    TCP/IP for OS/390 or VM/ESA

    This is an example of the configuration statements which you need to include in the TCPIP.PROFILE.TCPIP dataset (OS/390), or in the PROFILE TCPIP file on TCPMAINT 198 (VM):

    DEVICE CTCDEV1 CTC E20
    LINK CTCLINK1 CTC 0 CTCDEV1
    HOME 192.168.200.1 CTCLINK1
    GATEWAY
    ; Network      First Hop     Link Name Size   Subnet Mask  Subnet Value
    192.168.200.2  =             CTCLINK1  1500   HOST
    DEFAULTNET     192.168.200.2 CTCLINK1  1500   0
    START CTCDEV1
    

    For OS/390, the CTC devices need to be defined as device type 3088 in the IODF. Use the D U,CTC command to find out which 3088 addresses are defined in your IODF.

    For VM, the CTC devices must be attached to the TCPIP virtual machine.

    Because TCP/IP uses long running channel programs, the missing interrupt handler should be disabled for the CTC devices. For OS/390, add this statement in PARMLIB member IECIOS00:

    MIH TIME=00:00,DEV=(E20-E21)
    

    For VM, add this command to the PROFILE EXEC file of OPERATOR 191:

    'CP SET MITIME 0E20-0E21 OFF'
    

    Linux for S/390

    This is an example of the network definitions which you need in a Linux/390 system running under Hercules:

    ifconfig ctc0 192.168.200.1 pointopoint 192.168.200.2 mtu 1500
    route add defaultroute gw 192.168.200.2
    

    Linux/390 will autodetect the CTC devices E20 and E21 at startup and will assign the interface name ctc0.

    What to do if TUN/TAP doesn't work

    Check the following (thanks to Richard Higson for this checklist):

    1. Enter the command ls -l /dev/tun0 /dev/net/tun.
      For Linux 2.4, the response should be:
      ls: /dev/tun0: No such file or directory
      crw-rw---- 1 root xxxxx 10, 200 Sep 13 07:06 /dev/net/tun

      For Linux 2.2, the response should be:
      crw-rw---- 1 root xxxxx 90, 0 Feb 3 2001 /dev/tun0
      ls: /dev/net/tun: No such file or directory

      (xxxxx should be the group under which you run Hercules).
    2. ls -l /usr/local/bin/hercifc should show
      -rwsr-x--- 1 root xxxxx 17333 Dec 31 20:55 /usr/local/bin/hercifc

      (xxxxx should be the group under which you run Hercules).
    3. When hercules comes up, and before IPLing your favorite OS, verify that you have your underlying network stuff up and ready to roar:
      [root]# ifconfig
      eth0      Link encap:Ethernet  HWaddr 00:12:34:56:78:9A
                inet addr:10.1.2.1  Bcast:10.255.255.255  Mask:255.0.0.0
                UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
      tun0      Link encap:Point-to-Point Protocol
                inet addr:192.168.200.2  P-t-P:192.168.200.1  Mask:255.255.255.0
                UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
      [root]# netstat -in
      Kernel Interface table
      Iface   MTU Met   RX-OK RX-ERR RX-DRP RX-OVR   TX-OK TX-ERR TX-DRP TX-OVR Flg
      eth0   1500   0     201      0      0      0     196      0      0      0 BMRU
      tun0   1500   0       0      0      0      0       0      0      0      0 MOPRU
      [root]# netstat -rn
      Kernel IP routing table
      Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
      10.0.0.0        0.0.0.0         255.0.0.0       U        40 0          0 eth0
      192.168.200.0   0.0.0.0         255.255.255.0   U        40 0          0 tun0
      127.0.0.0       0.0.0.0         255.0.0.0       U        40 0          0 lo
      0.0.0.0         10.1.0.1        0.0.0.0         UG       40 0          0 eth0
    4. `cat /proc/sys/net/ipv4/ip_forward` should show "1". If it doesn't, your L386 won't forward (==route) packets at all.
    5. Is the TUN/TAP driver loaded?
      1. TUN/TAP compiled into the kernel (`make menuconfig`) look for "CONFIG_TUN=m" in /usr/src/linux
      2. `lsmod` after starting hercules should show tun 3456 2 (autoclean)
    6. Look for
      Dec 14 16:47:19 wie kernel: Universal TUN/TAP device driver 1.3 (C)1999-2000
      Maxim Krasnyansky

      in syslog after starting hercules


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/hercules.html0000664000175000017500000000125712564723224013654 00000000000000 Hercules <body> <p>Hercules uses frames. Your browser does not support frames.</p> </body> hercules-3.12/html/index.html0000664000175000017500000003506512625667132013160 00000000000000 The Hercules System/370, ESA/390, and z/Architecture Emulator
    Hercules logo
    Hercules is OSI Certified Open Source Software

    The Hercules System/370, ESA/390, and z/Architecture Emulator


    Hercules is an open source software implementation of the mainframe System/370 and ESA/390 architectures, in addition to the latest 64-bit z/Architecture. Hercules runs under Linux, Windows, Solaris, FreeBSD, and Mac OS X.

    Hercules is OSI Certified Open Source Software licensed under the terms of the Q Public Licence.

    Hercules was created by Roger Bowler. Jay Maynard (“the Tron Guy”) was the maintainer from 2000 to 2012. Jan Jaeger designed and implemented many of the advanced features of Hercules, including dynamic reconfiguration, integrated console, interpretive execution and z/Architecture support. A dedicated crew of programmers is constantly at work implementing new features and fixing bugs.


    To find out more about Hercules, follow these links:

    Web documentation:

    PDF manuals:


    To download the current release version, use the following links:

    • Source code:

    • Windows binaries:

      • hercules-3.12-w32.msi: Windows 32-bit Installer package
      • hercules-3.12-w32.zip: 32-bit binaries only archive
      • hercules-3.12-w64.msi: Windows 64-bit Installer package
      • hercules-3.12-w64.zip: 64-bit binaries only archive

        Note: Installing the .msi Windows Installer package ensures the required Microsoft Runtime components are installed and also provides convenience shortcuts in the programs menu. If the required components are already present and the shortcuts are not needed on the target system, the self-extracting or .zip archive may be used instead.



    What people are saying about Hercules


    “ Never in my wildest dreams did I expect to see MVS running on a machine that I personally own. Hercules is a marvelous tool. My thanks to you all for a job very well done. ”
    — Reed H. Petty

    “ I do miss my mainframe a lot, and playing with Herc sure brings back memories. Just seeing the IBM message prefixes, and responding to console messages again was a wonderful bit of nostalgia! ”
    — Bob Brown

    “ I have installed your absolutely fantastic /390 emulator. You won't believe what I felt when I saw the prompt. Congratulations, this is a terrific software. I really have not had such a fascinating and interesting time on my PC lately. ”
    — IBM Large Systems Specialist

    “ Such simulators have been available for a long time. One of the most complete (up to modern 64-bit z/Architecture) is hercules. ”
    — Michel Hack, IBM Thomas J. Watson Research Center

    “ An apparently excellent emulator that allows those open source developers with an "itch to scratch", to come to the S/390 table and contribute. ”
    — Mike MacIsaac, IBM

    “ BTW grab a copy of Hercules and you can test it at home. It's a very good S/390 and zSeries (S/390 64bit) emulator.. ”
    — Alan Cox

    “ It works even better than I imagined. Hercules is a fine piece of software! ”
    — Dave Sienkiewicz

    “ Hercules is a systems programmer's dream come true. ”
    — René Vincent Jansen

    “ Aside from the electric trains my parents got me in 1953, this is the best toy I've ever been given, bar none.”
    — Jeffrey Broido

    “ Congratulations to you and your team on a fine piece of work! ”
    — Rich Smrcina

    “ Congratulations on a magnificent achievement! ”
    — Mike Ross

    “ For anyone thinking running Hercules is too much trouble or too hard or whatever, I came home from work one day and my 13 year old 8th grade son had MVS running under VM under Hercules on Linux. He had gotten all the information about how to do this from the Internet. When he complained about MVS console configuration and figuring out how to get it to work with VM, I knew he had felt all the pain he ever needed to feel about mainframes. ”
    — Scott Ledbetter, StorageTek

    “ I am running a fully graphical Centos z/Linux environment on my desktop. The Hercules emulator is an amazing feat of engineering. I just wanted to send my compliments to the team for an excellent job! Thanks much for making this product part of the open-source community! ”
    — Roby Gamboa

    “ I have DOS and DOS/VS running on Hercules with some demo applications, both batch and on-line. It does bring back some good memories. My compliments go to the Hercules team. Thank you. ”
    — Bill Carlborg

    “ This is stunning piece of work. To say that I am blown away is an understatement. I have a mainframe on my notebook!!!!!! P.S. Now if I can just remember my JCL ”
    — Roger Tunnicliffe



    Read Hesh Wiener's Technology News article about Hercules at http://www.tech-news.com/another/ap200601b.html

    Read Moshe Bar's BYTE.com article about Hercules at http://web.archive.org/web/20010712143133/http://www.byte.com/documents/s=429/BYT20000801S0002/

    For eighteen months, the IBM Redbook SG24-4987 Linux for S/390 at http://www.redbooks.ibm.com/abstracts/sg244987.html contained a chapter written by Richard Higson describing how to run Linux/390 under Hercules. Then suddenly, all mention of Hercules was mysteriously removed from the online edition of the book! Read the story of the disappearing Redbook chapter at http://www2.marist.edu/htbin/wlvtype?LINUX-VM.25658

    View the foils from Jay Maynard's presentation given at SHARE Session 2880 in San Francisco on 20 August 2002 as a PDF file (815K) from http://linuxvm.org/Present/SHARE99/S2880JMa.pdf




    The source code repository

    The complete source code and development history for Hercules is also available via anonymous access from these git repositories:

    https://github.com/rbowler/spinhawk

    The spinhawk repository is used to build the 3.xx series of “gold” releases. The intent of the 3.xx release stream is to provide regular production-quality releases fully compatible with version 3.07, containing additional architectural features and bug fixes, as well as selected enhancements from the developer sandbox.

    https://github.com/hercules-390/hyperion

    The hyperion repository is used by a group of developers as a cutting-edge developer sandbox. It is currently designated as version 4.00. This repository evolved from Hercules version 3.07 enriched by a series of user interface changes and usability enhancements produced during the TurboHercules period. It also contains experimental support for the QDIO and MPCPTP6 networking interfaces and a redesigned I/O subsystem.

    Please note that the development repositories may contain faults which may be fixed at an unspecified later date, as well as experimental code which might not appear in any future production release.

    Build instructions are contained in the source files INSTALL (for Unix) or README.WIN32 or README.WIN64 (for Windows).



    Other Hercules-related sites



    If you have any questions or comments  please consider joining the hercules-390 discussion group at http://groups.yahoo.com/group/hercules-390.

    Bug reports for the current release (together with your diagnosis of the fault, please) may be posted at the hercules-390 discussion group. Problems with the developer sandbox version should be entered into the Hyperion issue tracker at https://github.com/hercules-390/hyperion/issues.



    IBM, System/370, ESA/390, and z/Architecture are trademarks or registered trademarks of IBM Corporation. Other product names mentioned here are trademarks of other companies.

    Last updated $Date$ $Revision$

    hercules-3.12/html/shared.html0000664000175000017500000003746312564723224013320 00000000000000 Hercules: Shared Device Server

    Hercules Shared Device Server


    Contents


    Overview

    (C) Copyright Greg Smith, 2002-2007

    Shared device support allows multiple Hercules instances to share devices. The device will be 'local' to one instance and 'remote' to all other instances. The local instance is the 'server' for that device and the remote instance is the 'client'. You do not have to IPL an operating system on the device server. Any number of Hercules instances can act as a server in a "Hercplex".

    To use a device on a remote system, instead of specifying a file name on the device config statement, you specify

    ip_address_or_name:port:devnum

    For example:

        0100  3350  localhost:3990:0100
    

    which says there is a device server on the local host listening on port 3990 and we want to use its 0100 device as 0100. The default port is 3990 and the default remote device number is the local device number. So we could say:

        0100  3350  localhost
    

    instead, providing we don't actually have a file 'localhost'. Interestingly, the instance on the local host listening on 3990 could have a statement:

        0100  3350  192.168.200.1::0200
    

    which means that instance in turn will use device 0200 on the server at 192.168.200.1 listening on port 3990. The original instance will have to 'hop' thru the second instance to get to the real device.

    Device sharing can be 'split' between multiple instances. For example, suppose instance A has:

        SHRDPORT 3990
        0100  3350  localhost:3991
        0101  3350  mvscat
    

    and instance B has:

        SHRDPORT 3991
        0100  3350  mvsres
        0101  3350  localhost
    

    Then each instance acts as both a client and as a server.

    When 'SHRDPORT' is specified, thread 'shared_server' is started at the end of Hercules initialization. In the example above, neither Hercules instance can initialize their devices until the server is started on each system. In this case, the device trying to access a server gets the 'connecting' bit set on in the DEVBLK and the device still needs to initialize. After the shared server is started, a thread is attached for each device that is connecting to complete the connection (which is the device init handler).


    Technical BS

    There are (at least) two approaches to sharing devices. One is to execute the channel program on the server system. The server will need to request from the client system information such as the ccw and the data to be written, and will need to send to the client data that has been read and status information. The second is to execute the channel program on the client system. Here the client system makes requests to the server system to read and write data.

    The second approach is currently implemented. The first approach arguably emulates 'more correctly'. However, an advantage of the implemented approach is that it is easier because only the client sends requests and only the server sends responses.

    Both client and server have a DEVBLK structure for the device. Absurdly, perhaps, in originally designing an implementation for shared devices it was not clear what type of process should be the server. It was a quantum leap forward to realize that it could just be another hercules instance.

    Protocol

    (If this section is as boring for you to read as it was for me to write then please skip to the next section ;-)

    The client sends an 8 byte request header and maybe some data:

        +-----+-----+-----+-----+-----+-----+-----+-----+
        | cmd |flag |  devnum   |    id     |   length  |
        +-----+-----+-----+-----+-----+-----+-----+-----+
    
                    <-------- length --------->
                    +----- .  .  .  .  . -----+
                    |          data           |
                    +----- .  .  .  .  . -----+
    

    'cmd' identifies the client request. The requests are:

    0xe0   CONNECT

    Connect to the server. This requires the server to allocate resources to support the connection. Typically issued during device initialization or after being disconnected after a network error or timeout.

    0xe1   DISCONNECT

    Disconnect from the server. The server can now release the allocated resources for the connection. Typically issued during device close or detach.

    0xe2   START

    Start a channel program on the device. If the device is busy or reserved by another system then wait until the device is available unless the NOWAIT flag bit is set, then return a BUSY code. Once START succeeds then the device is unavailable until the END request.

    0xe3   END

    Channel program has ended. Any waiters for the device can now retry.

    0xe4   RESUME

    Similar to START except a suspended channel program has resumed.

    0xe5   SUSPEND

    Similar to END except a channel program has suspended itself. If the channel program is not resumed then the END request is not issued.

    0xe6   RESERVE

    Makes the device unavailable to any other system until a RELEASE request is issued. Must be issued within the scope of START/END.

    0xe7   RELEASE

    Makes the device available to other systems after the next END request. Must be issued within the scope of START/END.

    0xe8   READ

    Read from a device. A 4-byte 'record' identifier is specified in the request data to identify what data to read in the device context. Must be issued within the scope of START/END.

    0xe9   WRITE

    Write to a device. A 2-byte 'offset' and a 4-byte 'record' is specified in the request data, followed by the data to be written. 'record' identifies what data is to be written in the device context and 'offset' and 'length' identify what to update in 'record'. Must be issued within the scope of START/END.

    0xea   SENSE

    Retrieves the sense information after an i/o error has occurred on the server side. This is typically issued within the scope of the channel program having the error. Client side sense or concurrent sense will then pick up the sense data relevant to the i/o error. Must be issued within the scope of START/END.

    0xeb   QUERY

    Obtain device information, typically during device initialization.

    0xec   COMPRESS

    Negotiate compression parameters. Notifies the server what compression algorithms are supported by the client and whether or not data sent back and forth from the client or server should be compressed or not. Typically issued after CONNECT.

    NOTE: This action should actually be SETOPT or some such; it was just easier to code a COMPRESS specific SETOPT (less code).


    'flag' qualifies the client request and varies by the request.

    0x80   NOWAIT

    For START, if the device is unavailable then return BUSY instead of waiting for the device.

    0x40   QUERY

    Identifies the QUERY request:

    0x41   DEVCHAR

    Device characteristics data

    0x42   DEVID

    Device identifier data

    0x43   DEVUSED

    Hi used track/block (for dasdcopy)

    0x48   CKDCYLS

    Number cylinders for CKD device

    0x4c   FBAORIGIN

    Origin block for FBA

    0x4d   FBANUMBLK

    Number of FBA blocks

    0x4e   FBABLKSIZ

    Size of an FBA block

    0x3x   COMP

    For WRITE, data is compressed at offset 'x':

    0x2x   BZIP2

    using bzip2

    0x1x   LIBZ

    using zlib

    0xxy

    For COMPRESS, identifies the compression algorithms supported by the client (0x2y for bzip2, 0x1y for zlib, 0x3y for both) and the zlib compression parameter 'y' for sending otherwise uncompressed data back and forth. If 'y' is zero (default) then no uncompressed data is compressed between client & server.


    'devnum' identifies the device by number on the server instance. The device number may be different than the device number on the client instance.

    'id' identifies the client to the server. Each client has a unique positive (non-zero) identifier. For the initial CONNECT request 'id' is zero. After a successful CONNECT, the server returns in the response header the identifier to be used for all other requests (including subsequent CONNECT requests). This is saved in dev->rmtid.

    'length' specifies the length of the data following the request header. Currently length is non-zero for READ/WRITE requests.


    The server sends an 8 byte response header and maybe some data:

        +-----+-----+-----+-----+-----+-----+-----+-----+
        |code |stat |  devnum   |    id     |  length   |
        +-----+-----+-----+-----+-----+-----+-----+-----+
    
                    <-------- length --------->
                    +----- .  .  .  .  . -----+
                    |          data           |
                    +----- .  .  .  .  . -----+
    

    'code' indicates the response to the request. OK (0x00) indicates success however other codes also indicate success but qualified in some manner:

    0x80   ERROR

    An error occurred. The server provides an error message in the data section.

    0x40   IOERR

    An i/o error occurred during a READ/WRITE request. The status byte has the 'unitstat' data. This should signal the client to issue the SENSE request to obtain the current sense data.

    0x20   BUSY

    Device was not available for a START request and the NOWAIT flag bit was turned on.

    0x10   COMP

    Data returned is compressed. The status byte indicates how the data is compressed (zlib or bzip2) and at what offset the compressed data starts (0 .. 15). This bit is only turned on when both the 'code' and 'status' bytes would otherwise be zero.

    0x08   PURGE

    START request was issued by the client. A list of 'records' to be purged from local cache is returned. These are 'records' that have been updated since the last START/END request from the client by other systems. Each record identifier is a 4-byte field in the data segment. The number of records then is 'length'/4. If the number of records exceeds a threshold (16) then 'length' will be zero indicating that the client should purge all locally cached records for the device.

    'stat' contains status information as a result of the request. For READ/WRITE requests this contains the 'unitstat' information if an IOERR occurred.

    'devnum' specifies the server device number

    'id' specifies the system identifier for the request.

    'length' is the size of the data returned.


    Caching

    Cached records (eg CKD tracks or FBA blocks) are kept independently on both the client and server sides. Whenever the client issues a START request to initiate a channel program the server will return a list of records to purge from the client's cache that have been updated by other clients since the last START request. If the list is too large the server will indicate that the client should purge all records for the device.


    Compression

    Data that would normally be transferred uncompressed between client and host can optionally be compressed by specifying the 'comp=' keyword on the device configuration statement or attach command. For example:

        0100  3350  192.168.2.12  comp=3
    

    The value of the 'comp=' keyword is the zlib compression parameter which should be a number between 1 .. 9. A value closer to 1 means less compression but less processor time to perform the compression. A value closer to 9 means the data is compressed more but more processor time is required.

    If the server is on 'localhost' then you should not specify 'comp='. Otherwise you are just stealing processor time to do compression/ uncompression from hercules. If the server is on a local network then I would recommend specifying a low value such as 1, 2 or 3. We are on a curve here, trying to trade cpu cycles for network traffic to derive an optimal throughput.

    If the devices on the server are compressed devices (eg CCKD or CFBA) then the 'records' (eg. track images or block groups) may be transferred compressed regardless of the 'comp=' setting. This depends on whether the client supports the compression type (zlib or bzip2) of the record on the server and whether the record is actually compressed in the server cache.

    For example:

    Suppose on the client that you execute one or more channel programs to read a record on a ckd track, update a record on the same track, and then read another (or the same) record on the track.

    For the first read the server will read the track image and pass it to the client as it was originally compressed in the file. To update a portion of the track image the server must uncompress the track image so data in it can be updated. When the client next reads from the track image, the track image is uncompressed.

    Specifying 'comp=' means that uncompressed data sent to the client will be compressed. If the data to be sent to the client is already compressed then the data is sent as is, unless the client has indicated that it does not support that compression algorithm.


    To Do

    1. More doc (sorry, I got winded)
    2. Delays observed during short transfers (redrive select ?)
    3. Better server side behaviour due to disconnect
    4. etc.

    Greg Smith gsmith@nc.rr.com


    back

    Last updated $Date$ $Revision$

    hercules-3.12/html/tasks.html0000664000175000017500000000250112564723224013160 00000000000000 Tasks
    The Hercules System/370, ESA/390, and z/Architecture Emulator, (c) Copyright by Roger Bowler, Jan Jaeger, and others

    Tasks

    System Log
    IPL

    Debugging

    Registers
    Storage
    Miscellaneous
    Devices
    Version Info

    Configuration

    CPU

    Registers

    GPRs
    CRs
    PSW

    Information

    Documentation
    hercules-3.12/html/hercules.css0000664000175000017500000000560012564723224013474 00000000000000 hercules-3.12/man/0000775000175000017500000000000012625667404011043 500000000000000hercules-3.12/man/Makefile.in0000664000175000017500000004050712625667166013043 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = man DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man4dir)" man4dir = $(mandir)/man4 NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ man_MANS = cckddiag.1 cckd.4 dasdseq.1 hercules.1 EXTRA_DIST = $(man_MANS) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu man/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu man/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man4: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man4dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man4dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man4dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.4[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^4][0-9a-z]*$$,4,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man4dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man4dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man4dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man4dir)" || exit $$?; }; \ done; } uninstall-man4: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man4dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.4[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^4][0-9a-z]*$$,4,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man4dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man4dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-man4 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man1 uninstall-man4 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man1 install-man4 install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-man uninstall-man1 uninstall-man4 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/man/Makefile.am0000664000175000017500000000011612564723224013010 00000000000000man_MANS = cckddiag.1 cckd.4 dasdseq.1 hercules.1 EXTRA_DIST = $(man_MANS) hercules-3.12/man/cckddiag.10000664000175000017500000000531612564723224012576 00000000000000.TH cckddiag 1 "2003-02-03" .SH NAME \fBcckddiag\fP - Hercules CCKD DASD diagnostic tool .SH SYNOPSIS \fBcckddiag\fP [options...] \fBfilename\fP .SH DESCRIPTION Hercules support tool used to assist in the diagnosis of CCKD DASD problems. Operates on Hercules CCKD DASD volumes in read-only mode, and displays various information contained in CCKD DASD files. Effective usage requires internal knowledge of Hercules CCKD DASD files. .SH OPTIONS The following options are used to specify which portions of the CCKD DASD file are to be displayed. Options may not be combined; for example, -cd1 is not a valid option. Surround each option by blank(s). Argument numbers may be specified either in decimal or hexadecimal. If the number begins with the characters 0x the number is presumed to be hexadecimal; else the number is presumed to be decimal. No numeric overflow checking is done, the user is assumed (!) to know what they're doing. Options are divided into three categories: \fBglobal options\fP, \fBtrack-related options\fP, and \fBthe offset option\fP. .SH Global options .SS filename specifies the Hercules CCKD DASD filename (sometimes referred to as the DASD image file) .SS -v display version and exit .SS -d display DEVHDR .SS -c display CDEVHDR .SS -1 display L1TAB (note this option is a numeric one) .SS -g enable debug output .SH Track-related options To direct cckddiag to a specific track, two options are provided: -a and -r. The remaining track-related options describe the kind of output desired. The TRKHDR for the track is displayed for all track-related options. .SS -a cc hh display \fBabsolute\fP CCHH data - where \fBcc\fP and \fBhh\fP are respectively the cylinder number (relative zero), and the head number (relative zero). .SS -r tt display \fBrelative\fP track data - where \fBtt\fP is the track number (relative zero). .SS -2 display L2TAB - requires a corresponding -a or -r specification to direct cckddiag to a specific track. .SS -t display track data - displays the COUNT, KEY, and DATA record summaries for the data residing on the indicated track. .SS -x hex display track key/data - displays the KEY and DATA records' contents in hexadecimal display format for the indicated track. Some repetitive data may be omitted from the hex display output. .SH Offset option This option provides the ability to examine any portion of the CCKD file, as an alternative to track specification. .SS -o oo ll hex display data at offset \fBoo\fP of length \fBll\fP. .SH "SEE ALSO" .TP cckd(4) .TP http://www.hercules-390.org/ the Hercules emulator homepage. .TP http://www.hercules-390.org/cckddasd.html which describes the Hercules CCKD DASD facility. .SH HISTORY 2003-02-07 originally written by James M. Morrison hercules-3.12/man/cckd.40000664000175000017500000001211612564723224011750 00000000000000.TH cckd 4 "2003-02-03" .SH NAME \fBcckd\fP - Hercules Compressed CKD DASD image file .SH DESCRIPTION Hercules DASD image file that emulates IBM mainframe DASD devices on a (usually) non-mainframe platform. Specified in the Hercules configuration file (default name hercules.cnf) to describe the DASD devices Hercules is to emulate. Also specified as input and/or output file to several Hercules utilities. Hercules compressed DASD devices are frequently referred to as CCKD. Hercules uncompressed DASD devices are frequently referred to as CKD. Hercules CKD DASD image files are largely compatible with P/390 AWS DASD files. .SH TECHNICAL OVERVIEW The following provides a technical overview of CCKD internal structures. Except as indicated below, data in the following structures is stored in the byte order indicated by the CDEVHDR.options CCKD_BIGENDIAN bit (the 0x02 bit). This bit is 1 when data is big-endian byte order, 0 when data is little-endian byte order. .SS DEVHDR occupies the first 512 bytes of a CKD or CCKD DASD file. The DEVHDR contains the device type and the number of heads per cylinder. Its contents are the same whether the DASD image is compressed (CCKD) or not (CKD). Described by the CKDDASD_DEVHDR struct; 512 bytes in size. .SS CDEVHDR immediately follows the DEVHDR, and contains fields describing the number of L1ENTs in the L1TAB, the number of L2ENTs in each L2TAB, and anchors the free space chain. Described by the CCKDDASD_DEVHDR struct; 512 bytes in size. .SS L1TAB immediately follows the CDEVHDR, and consists of L1ENT entries, each of which points to an L2TAB. Each L1ENT is an U32 (4 bytes) offset into the CCKD DASD file. The CDEVHDR numl1tab field describes how many L1ENTs are in the L1TAB. L1ENTs are described by the CCKD_L1ENT typedef; the L1TAB is of variable size. Conceptually each L1ENT describes cdevhdr.numl2tab tracks. .SS L2TAB is pointed to by an L1ENT, and is composed of L2ENT entries, the number of which is described by the CDEVHDR numl2tab field; currently 256 L2ENTs in each L2TAB. L2ENTs contain the offset to the TRKHDR, and the combined length of the TRKHDR and (optionally) compressed track data. The CDEVHDR numl2tab field describes how many L2ENTs are in each L2TAB. Currently, there are 256 L2ENTs in each L2TAB. Described by the CCKD_L2ENT struct; (256 * 8) bytes in size. Conceptually each L2ENT describes one track. .SS FREEBLK describes free space in the CCKD DASD image, anchored by the CDEVHDR free field. Consists of a 4 byte offset to the next free space (or zero for end of free space chain), and a 4 byte length of the free space (which length includes the 8 bytes occupied by the FREEBLK itself), followed by zero or more bytes of residual data. Described by the first 8 bytes of the CCKD_FREEBLK struct; 8 bytes in size. .SS TRKHDR Occurs once at the beginning of each track. contains flag (one byte), CC (two bytes), and HH (two bytes) of the track. When the flag byte = 0x00, TRKHDR is the same as the Home Address on real DASD. Flag bits are described in hercules.h, and are of the format nlllllcc where n=1 for new track header format, lllll is used for track recovery purposes, and cc describes the track compression algorithm. The compression algorithms are: B'00' = uncompressed, B'01' = zlib, B'10' = bzip2, B'11' is currently invalid. Data in TRKHDR is stored in big-endian byte order. Described by the CKDDASD_TRKHDR struct; 5 bytes in size. .SS COUNT field 8 bytes, containing CC (two bytes), HH (two bytes), R (one byte), KL (one byte), and DL (two bytes). CC is the (relative zero) cylinder number. HH is the (relative zero) head number. R is the (relative zero) record number on the track. KL is the key length; if zero no key is present. DL is the length of the data record. Data in the COUNT field is stored in big-endian byte order. Described by the CKDDASD_RECHDR struct; 8 bytes in size. .SS KEY field if present, KL bytes of record key; immediately follows the COUNT field. Byte order is not a factor for the KEY field; to the extent it is examined by Hercules code it is simply a byte stream. Size varies. .SS DATA field. if present, DL bytes of record data; immediately follows the KEY field for keyed record, else immediately follows the COUNT field for unkeyed records. Byte order is not a factor for the DATA field; to the extent it is examined by Hercules code it is simply a byte stream. Size varies. .SH GLOSSARY .SS CKD Count, Key, Data - contents of an track. Also refers to the Hercules uncompressed DASD image file. .SS CCKD Compressed Count, Key, Data - compressed contents of a track. Also refers to the Hercules compressed DASD image file. .SS DASD Direct Access Storage Device - term the IBM mainframe world uses to refer to hard drives. .SS EOT End Of Track - indicated by 8X'FF' in the COUNT field. .SH "SEE ALSO" .TP \fBhttp://www.hercules-390.org/\fP the Hercules emulator homepage. .TP \fBhttp://www.hercules-390.org/cckddasd.html\fP which describes the Hercules CCKD DASD facility. .TP \fBhttp://www.hercules-390.org/hercconf.html\fP which describes the Hercules configuration file. .SH HISTORY 2003-02-07 originally written by James M. Morrison hercules-3.12/man/dasdseq.10000664000175000017500000001041012564723224012460 00000000000000.TH dasdseq 1 "2003-03-10" .SH NAME \fBdasdseq\fP - Hercules DSORG=PS retrieval command .SH SYNOPSIS \fBdasdseq\fP [options...] \fBimage \fP[sf=shadow] \fBfilespec\fP .br \fBdasdseq \fP[-debug] [-expert] [-ascii] \fBimage \fP[sf=shadow] [attr] \fBfilespec \fP[debugopts] [ascii] .SH DESCRIPTION Hercules command to retrieve a DSORG=PS (sequential) dataset from CKD/CCKD DASD. The dataset is presumed to be encoded in EBCDIC. The second form of the command is for 'expert mode' users, and allows more advanced access to data on the DASD image. .SH OPTIONS The following options are used to specify dasdseq behavior. Surround each option by blank(s). Options are divided into three categories: \fBrequired, optional, and expert mode operands.\fP .SH Required operands .SS image specifies the Hercules CKD/CCKD DASD filename (sometimes referred to as the DASD image file) .SS filespec dataset name of the file to retrieve. Case insensitive, converted to upper case for searching VTOC on image DASD volume. .SH Optional operands .SS sf=shadow For CCKD images which also use shadow files, specifies the [path/]filename of the shadow file. Note the sf=, which must be present for this option. .SS -ascii convert the output file to ASCII (from EBCDIC). Additionally, trailing blanks are trimmed. The 'ascii' option (no leading dash) is deprecated, and may be removed in a future release. .SH Expert mode operands All expert mode operands are considered to be experimental. \fB dasdseq [-debug] [-expert] [-ascii] image [sf=shadow] [attr] filespec [debugopts]\fP .SS -debug Additional debug options are displayed. Specifying -debug will (eventually) display dataset extent information. .SS attr dataset attributes (only useful with -abs) \fB[-recfm fb] [-lrecl aa]\fP -recfm designates RECFM, reserved for future support fb - fixed, blocked (only RECFM currently supported) -lrecl designates dataset LRECL aa - decimal logical record length (default 80) Blocksize need not be specified; dasdseq handles whatever block size comes off the volume. .SS filespec composed of the following sub-operands, in the following order: \fBheads, abs, filename.\fP .SS -heads xx defines # tracks per cylinder on device; xx = decimal number of heads per cylinder on device .SS -abs cc hh tt [...] [-abs cc hh tt] -abs indicates the beginning of each extent's location in terms of absolute dasd image location. cc - decimal cylinder number (relative zero) hh - decimal head number (relative zero) tt - decimal number of tracks in extent When -abs is specified, each -abs group specifies one dataset extent. For multi-extent datasets, -abs groups may be repeated as needed, in the order in which the dataset's extents occur. A maximum of 123 extents are supported. With -abs, no VTOC structure is implied; a F1 DSCB will not be sought. Dasdseq will frequently report 'track not found in extent table' (along with a message from fbcopy about rc -1 from convert_tt) due to potentially missing EOF markers in the extent, and the fact that the F1 DSCB DS1LSTAR field is not valid. Check your output file before you panic. Fbcopy -abs ignores EOF, in case you are attempting to recovery PDS member(s) from a damaged dasd volume, preferring to wait until all tracks in the extent have been processed. Tracks containing PDS members may have more than one EOF per track. Expect a lot of associated manual effort with -abs. When -abs is -not- specified, filename specifies the MVS DSORG=PS dataset on the volume. The dasd image volume containing the dataset must have a valid VTOC structure, and a F1 DSCB describing the dataset. .SS filename will be the filename of the output file in the current directory; output filename in the same case as the command line filename. .SS debugopts Produces debugging output, refer to the source code. \fBverbose [x [y [z]]]\fP verbose debug output level (default = 0 when not specified). Higher numbers produce more output. x main program (default = 1 when verbose specified) y copyfile + showf1 z dasdutil .SH "SEE ALSO" .TP dasdpdsu for DSORG=PO datasets .TP cckd(4) for CCKD DASD .TP http://www.hercules-390.org/cckddasd.html which describes the Hercules CCKD DASD facility. .TP http://www.hercules-390.org/ the Hercules emulator homepage. .SH HISTORY 2003-03-10 originally written by James M. Morrison hercules-3.12/man/hercules.10000664000175000017500000000660712564723224012663 00000000000000.TH HERCULES 1 "May 2013" "Hercules Version 3.08.2" "User Commands" .SH NAME \fBHercules\fR \- IBM System/370, ESA/390, and z/Architecture Emulator .SH SYNOPSIS .B hercules [\fB\-f\fR \fIconfig\-filename\fR] [\fB\-d\fR] [\fB\-b\fR \fIlogo\-filename\fR] [\fB\-p\fR \fIdyn\-load\-dir\fR] [[\fB\-l\fR \fIdynmod\-to\-load\fR]...] [> \fIlogfile\fR] .SH DESCRIPTION \fBHercules\fR is a software implementation of the System/370, ESA/390 and z/Architecture mainframe architectures. It means that your PC can emulate an IBM mainframe processor. The mainframe can range from a System/360 to a z10 - running in "S/370" mode, "ESA/390" mode, or "z/Architecture" mode. \fBHercules\fR executes S/370, ESA/390, and z/Architecture instructions and channel programs. It emulates mainframe I/O devices by using PC devices. For example, 3390 DASD devices are emulated by large files on your hard disk, and local 3270 screens are emulated by tn3270 sessions. (Note: Not all 370 and 390 features have been implemented in \fBHercules\fR. Also, certain non-standard models, 360/20s, and the 360/67 virtual memory mode are not emulated.) \fBHercules\fR implements only the raw S/370, ESA/390, and z/Architecture instruction set; it does not provide any operating system facilities. This means that you need to provide an operating system or standalone program which \fBHercules\fR can load from an emulated disk or tape device. You will have to write the operating system or standalone program yourself, unless you can manage to obtain a license from IBM to run one of their operating systems on your PC, or use IBM programs and operating systems which have been placed in the public domain. .SH OPTIONS .TP \fB\-f\fR \fIconfig\-filename\fR Sets the name of the configuration file. The default, if none is specified, is \fBhercules.cnf\fR. The default may be overridden via the \fBHERCULES_CNF\fR environment variable. .TP \fB\-d\fR Specifies that Hercules is to be run in 'daemon' mode, wherein it runs invisibly with no attached console. .TP \fB\-b\fR \fIlogo\-filename\fR Sets the name of the file containg the screen logo that's presented when a 3270 terminal connects. When not specified the default \fBherclogo.txt\fR file is looked for and when not found the built-in logo is used. .TP \fB\-p\fR \fIdyn\-load\-dir\fR Sets the directory from which dynamic modules are to be loaded. The default depends on the host platform on which Hercules is being run. This option overrides the default. .TP \fB\-l\fR \fIdynmod\-to\-load\fR Sets the name of an additional dynamic module to be loaded at startup. More than one additional module may be specified, although each must be preceded with the \fB-l\fR option specifier. .TP \fIlogfile\fR Sets an optional log file which will receive a copy of all messages displayed on the control panel .SH FILES .B hercules.cnf .SH ENVIRONMENT .B HERCULES_CNF .SH AUTHORS \fBHercules\fR was created by Roger Bowler. Jay Maynard (“the Tron Guyâ€) was the maintainer from 2000 to 2012. Jan Jaeger designed and implemented many of the advanced features of \fBHercules\fR, including dynamic reconfiguration, integrated console, interpretive execution and z/Architecture support. A dedicated crew of programmers is constantly at work implementing new features and fixing bugs. This manual page was written by Dan Horák using text snippets from the \fBHercules\fR web site. .SH SEE ALSO \fBHercules\fR Homepage: \fBhttp://www.hercules-s390.eu\fR hercules-3.12/crypto/0000775000175000017500000000000012625667405011611 500000000000000hercules-3.12/crypto/Makefile.in0000664000175000017500000005327212625667166013613 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Makefile for Hercules S/370, ESA/390 and z/Architecture emulator # # $Id$ # # $Log$ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = crypto DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/autoconf/mkinstalldirs \ $(top_srcdir)/autoconf/depcomp $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/autoconf/hercules.m4 \ $(top_srcdir)/autoconf/libtool.m4 \ $(top_srcdir)/autoconf/ltdl.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/autoconf/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(modexecdir)" LTLIBRARIES = $(modexec_LTLIBRARIES) am__DEPENDENCIES_1 = ../libhercs.la ../libherc.la ../libhercu.la @OPTION_DYNAMIC_LOAD_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) dyncrypt_la_DEPENDENCIES = $(am__DEPENDENCIES_2) am_dyncrypt_la_OBJECTS = dyncrypt.lo sha1.lo sha256.lo des.lo aes.lo dyncrypt_la_OBJECTS = $(am_dyncrypt_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = dyncrypt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(dyncrypt_la_LDFLAGS) $(LDFLAGS) -o $@ @OPTION_DYNAMIC_LOAD_TRUE@am_dyncrypt_la_rpath = -rpath $(modexecdir) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/autoconf/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(dyncrypt_la_SOURCES) DIST_SOURCES = $(dyncrypt_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ GREP = @GREP@ HERCIFC_GROUPNAME = @HERCIFC_GROUPNAME@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modexecdir = @modexecdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lns = @LN_S@ LDADD = @LIBS@ ../libhercs.la ../libherc.la ../libhercu.la AM_CPPFLAGS = -I$(top_srcdir) dyndev_SRC = dyncrypt.c sha1.c sha256.c des.c aes.c @BUILD_SHARED_FALSE@XSTATIC = -static @BUILD_SHARED_TRUE@XSTATIC = @OPTION_DYNAMIC_LOAD_FALSE@DYNSRC = $(dyndev_SRC) @OPTION_DYNAMIC_LOAD_TRUE@DYNSRC = @OPTION_DYNAMIC_LOAD_FALSE@LTDL = @OPTION_DYNAMIC_LOAD_TRUE@LTDL = ../ltdl.c @OPTION_DYNAMIC_LOAD_FALSE@DYNMOD_LD_FLAGS = @OPTION_DYNAMIC_LOAD_TRUE@DYNMOD_LD_FLAGS = -module \ @OPTION_DYNAMIC_LOAD_TRUE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_TRUE@ $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_TRUE@ -export-dynamic \ @OPTION_DYNAMIC_LOAD_TRUE@ -avoid-version @OPTION_DYNAMIC_LOAD_FALSE@DYNMOD_LD_ADD = @OPTION_DYNAMIC_LOAD_TRUE@DYNMOD_LD_ADD = $(LDADD) @OPTION_DYNAMIC_LOAD_FALSE@LIB_LD_FLAGS = $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_FALSE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_FALSE@ -avoid-version @OPTION_DYNAMIC_LOAD_TRUE@LIB_LD_FLAGS = -export-dynamic \ @OPTION_DYNAMIC_LOAD_TRUE@ $(XSTATIC) \ @OPTION_DYNAMIC_LOAD_TRUE@ -no-undefined \ @OPTION_DYNAMIC_LOAD_TRUE@ -avoid-version HERCMODS = dyncrypt.la @OPTION_DYNAMIC_LOAD_TRUE@modexec_LTLIBRARIES = $(HERCMODS) dyncrypt_la_SOURCES = dyncrypt.c sha1.c sha256.c des.c aes.c dyncrypt_la_LDFLAGS = $(DYNMOD_LD_FLAGS) dyncrypt_la_LIBADD = $(DYNMOD_LD_ADD) noinst_HEADERS = sha1.h sha256.h des.h aes.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu crypto/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu crypto/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-modexecLTLIBRARIES: $(modexec_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(modexec_LTLIBRARIES)'; test -n "$(modexecdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(modexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(modexecdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(modexecdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(modexecdir)"; \ } uninstall-modexecLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(modexec_LTLIBRARIES)'; test -n "$(modexecdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(modexecdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(modexecdir)/$$f"; \ done clean-modexecLTLIBRARIES: -test -z "$(modexec_LTLIBRARIES)" || rm -f $(modexec_LTLIBRARIES) @list='$(modexec_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } dyncrypt.la: $(dyncrypt_la_OBJECTS) $(dyncrypt_la_DEPENDENCIES) $(EXTRA_dyncrypt_la_DEPENDENCIES) $(AM_V_CCLD)$(dyncrypt_la_LINK) $(am_dyncrypt_la_rpath) $(dyncrypt_la_OBJECTS) $(dyncrypt_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/des.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dyncrypt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(modexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-modexecLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-modexecLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-modexecLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-modexecLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-modexecLTLIBRARIES \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-modexecLTLIBRARIES %.s: %.c $(COMPILE) -S $< # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: hercules-3.12/crypto/Makefile.am0000664000175000017500000000245412564723224013564 00000000000000## Process this file with automake to produce Makefile.in # # Makefile for Hercules S/370, ESA/390 and z/Architecture emulator # # $Id$ # # $Log$ lns=@LN_S@ LDADD = @LIBS@ ../libhercs.la ../libherc.la ../libhercu.la AM_CPPFLAGS = -I$(top_srcdir) dyndev_SRC = dyncrypt.c sha1.c sha256.c des.c aes.c if BUILD_SHARED XSTATIC = else XSTATIC = -static endif if OPTION_DYNAMIC_LOAD DYNSRC = LTDL = ../ltdl.c DYNMOD_LD_FLAGS = -module \ -no-undefined \ $(XSTATIC) \ -export-dynamic \ -avoid-version DYNMOD_LD_ADD = $(LDADD) LIB_LD_FLAGS = -export-dynamic \ $(XSTATIC) \ -no-undefined \ -avoid-version else DYNSRC = $(dyndev_SRC) LTDL = DYNMOD_LD_FLAGS = DYNMOD_LD_ADD = LIB_LD_FLAGS = $(XSTATIC) \ -no-undefined \ -avoid-version endif HERCMODS = dyncrypt.la if OPTION_DYNAMIC_LOAD modexec_LTLIBRARIES = $(HERCMODS) endif dyncrypt_la_SOURCES = dyncrypt.c sha1.c sha256.c des.c aes.c dyncrypt_la_LDFLAGS = $(DYNMOD_LD_FLAGS) dyncrypt_la_LIBADD = $(DYNMOD_LD_ADD) noinst_HEADERS = sha1.h sha256.h des.h aes.h %.s: %.c $(COMPILE) -S $< hercules-3.12/crypto/sha1.h0000664000175000017500000000146712564723224012540 00000000000000/* $OpenBSD: sha1.h,v 1.4 2004/04/28 20:39:35 hshoexer Exp $ */ /* modified for use with dyncrypt */ /* * SHA-1 in C * By Steve Reid * 100% Public Domain */ #ifndef _SHA1_H_ #define _SHA1_H_ #define SHA1_BLOCK_LENGTH 64 #define SHA1_DIGEST_LENGTH 20 typedef struct { u_int32_t state[5]; u_int64_t count; unsigned char buffer[SHA1_BLOCK_LENGTH]; } SHA1_CTX; void SHA1Init(SHA1_CTX * context); void SHA1Transform(u_int32_t state[5], unsigned char buffer[SHA1_BLOCK_LENGTH]); void SHA1Update(SHA1_CTX *context, unsigned char *data, unsigned int len); void SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context); /* Context structure definition for dyncrypt */ typedef SHA1_CTX sha1_context; #endif /* _SHA1_H_ */ hercules-3.12/crypto/sha256.h0000664000175000017500000000745212564723224012714 00000000000000/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */ /* modified for use with dyncrypt */ /* * FILE: sha2.h * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ */ #ifndef _SHA2_H #define _SHA2_H /*** SHA-256/384/512 Various Length Definitions ***********************/ #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #define SHA384_BLOCK_LENGTH 128 #define SHA384_DIGEST_LENGTH 48 #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) /*** SHA-256/384/512 Context Structures *******************************/ typedef struct _SHA256_CTX { u_int32_t state[8]; u_int64_t bitcount; u_int8_t buffer[SHA256_BLOCK_LENGTH]; } SHA256_CTX; typedef struct _SHA512_CTX { u_int64_t state[8]; u_int64_t bitcount[2]; u_int8_t buffer[SHA512_BLOCK_LENGTH]; } SHA512_CTX; typedef SHA512_CTX SHA384_CTX; void SHA256_Init(SHA256_CTX *); void SHA256_Update(SHA256_CTX *, const u_int8_t *, size_t) /* __attribute__((__bounded__(__string__,2,3))) */; void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX *) /* __attribute__((__bounded__(__minbytes__,1,SHA256_DIGEST_LENGTH))) */; void SHA384_Init(SHA384_CTX *); void SHA384_Update(SHA384_CTX *, const u_int8_t *, size_t) /* __attribute__((__bounded__(__string__,2,3))) */; void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX *) /* __attribute__((__bounded__(__minbytes__,1,SHA384_DIGEST_LENGTH))) */; void SHA512_Init(SHA512_CTX *); void SHA512_Update(SHA512_CTX *, const u_int8_t *, size_t) /* __attribute__((__bounded__(__string__,2,3))) */; void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX *) /* __attribute__((__bounded__(__minbytes__,1,SHA512_DIGEST_LENGTH))) */; /* Context structure definitions for dyncrypt */ typedef SHA256_CTX sha256_context; typedef SHA384_CTX sha384_context; typedef SHA512_CTX sha512_context; #endif /* _SHA2_H */ hercules-3.12/crypto/des.h0000664000175000017500000000137112564723224012451 00000000000000// $Id$ // // $Log$ #ifndef _DES_H #define _DES_H typedef u_int32_t word32; typedef struct { word32 k0246[16], k1357[16]; word32 iv0, iv1; } DESContext; typedef struct { DESContext sched[1]; } des_context; typedef struct { DESContext sched[3]; } des3_context; typedef BYTE CHAR8[8]; void des_set_key(des_context *ctx, CHAR8 key); void des_encrypt(des_context *ctx, CHAR8 input, CHAR8 output); void des_decrypt(des_context *ctx, CHAR8 input, CHAR8 output); void des3_set_2keys(des3_context *ctx, CHAR8 k1, CHAR8 k2); void des3_set_3keys(des3_context *ctx, CHAR8 k1, CHAR8 k2, CHAR8 k3); void des3_encrypt(des3_context *ctx, CHAR8 input, CHAR8 output); void des3_decrypt(des3_context *ctx, CHAR8 input, CHAR8 output); #endif /*_DES_H*/ hercules-3.12/crypto/aes.h0000664000175000017500000000501112564723224012441 00000000000000/* $OpenBSD: rijndael.h,v 1.11 2005/05/25 05:47:53 markus Exp $ */ /* modified for use by dyncrypt */ // $Id$ /** * rijndael-alg-fst.h * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // $Log$ #ifndef __RIJNDAEL_H #define __RIJNDAEL_H #define MAXKC (256/32) #define MAXKB (256/8) #define MAXNR 14 typedef u_int8_t u8; typedef u_int16_t u16; typedef u_int32_t u32; /* The structure for key information */ typedef struct { int enc_only; /* context contains only encrypt schedule */ int Nr; /* key-length-dependent number of rounds */ u32 ek[4*(MAXNR + 1)]; /* encrypt key schedule */ u32 dk[4*(MAXNR + 1)]; /* decrypt key schedule */ } rijndael_ctx; int rijndael_set_key(rijndael_ctx *, u_char *, int); int rijndael_set_key_enc_only(rijndael_ctx *, u_char *, int); void rijndael_decrypt(rijndael_ctx *, u_char *, u_char *); void rijndael_encrypt(rijndael_ctx *, u_char *, u_char *); int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int); int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int); void rijndaelEncrypt(const unsigned int [], int, const unsigned char [], unsigned char []); /* Additional definitions for dyncrypt */ typedef rijndael_ctx aes_context; #define aes_set_key rijndael_set_key #define aes_encrypt rijndael_encrypt #define aes_decrypt rijndael_decrypt #endif /* __RIJNDAEL_H */ hercules-3.12/crypto/dyncrypt.c0000664000175000017500000045431512564723224013557 00000000000000/* DYNCRYPT.C (c) Bernard van der Helm, 2003-2011 */ /* z/Architecture crypto instructions */ /*----------------------------------------------------------------------------*/ /* Implementation of the z/Architecture crypto instructions described in */ /* SA22-7832-04: z/Architecture Principles of Operation within the Hercules */ /* z/Architecture emulator. */ /* */ /* (c) Copyright Bernard van der Helm, 2003-2011 */ /* Noordwijkerhout, The Netherlands. */ /*----------------------------------------------------------------------------*/ // $Id$ #include "hstdinc.h" #ifndef _DYNCRYPT_C_ #define _DYNCRYPT_C_ #endif /* #ifndef _DYNCRYPT_C_ */ #ifndef _DYNCRYPT_DLL_ #define _DYNCRYPT_DLL_ #endif /* #ifndef _DYNCRYPT_DLL_ */ #include "hercules.h" #include "opcode.h" #include "inline.h" #include "aes.h" #include "des.h" #include "sha1.h" #include "sha256.h" /*----------------------------------------------------------------------------*/ /* Sanity compile check */ /*----------------------------------------------------------------------------*/ #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1) && !defined(FEATURE_MESSAGE_SECURITY_ASSIST) #error You cannot have "Message Security Assist extension 1" without having "Message Security Assist" #endif /* #if ... */ #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2) && !defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1) #error You cannot have "Message Security Assist extension 2" without having "Message Security Assist extension 1" #endif /* #if ... */ #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) && !defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2) #error You cannot have "Message Security Assist extension 3" without having "Message Security Assist extension 2" #endif /* #if ... */ #if defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4) && !defined(FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3) #error You cannot have "Message Security Assist extension 4" without having "Message Security Assist extension 3" #endif /* #if ... */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST /*----------------------------------------------------------------------------*/ /* Debugging options */ /*----------------------------------------------------------------------------*/ #if 0 #define OPTION_KIMD_DEBUG #define OPTION_KLMD_DEBUG #define OPTION_KM_DEBUG #define OPTION_KMAC_DEBUG #define OPTION_KMC_DEBUG #define OPTION_KMCTR_DEBUG #define OPTION_KMF_DEBUG #define OPTION_KMO_DEBUG #define OPTION_PCC_DEBUG #define OPTION_PCKMO_DEBUG #endif /* #if 0|1 */ /*----------------------------------------------------------------------------*/ /* General Purpose Register 0 macro's (GR0) */ /*----------------------------------------------------------------------------*/ /* fc : Function code */ /* m : Modifier bit */ /* lcfb : Length of cipher feedback */ /* wrap : Indication if key is wrapped */ /* tfc : Function code without wrap indication */ /*----------------------------------------------------------------------------*/ #define GR0_fc(regs) ((regs)->GR_L(0) & 0x0000007F) #define GR0_m(regs) (((regs)->GR_L(0) & 0x00000080) ? TRUE : FALSE) #define GR0_lcfb(regs) ((regs)->GR_L(0) >> 24) #define GR0_wrap(egs) (((regs)->GR_L(0) & 0x08) ? TRUE : FALSE) #define GR0_tfc(regs) (GR0_fc(regs) & 0x77) /*----------------------------------------------------------------------------*/ /* Bit strings for query functions */ /*----------------------------------------------------------------------------*/ #undef KIMD_BITS #undef KLMD_BITS #undef KM_BITS #undef KMAC_BITS #undef KMC_BITS #undef KMCTR_BITS #undef KMF_BITS #undef KMO_BITS #undef PCC_BITS #undef PCKMO_BITS #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 #define KIMD_BITS { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #define KIMD_BITS { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 #define KIMD_BITS { 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #define KIMD_BITS { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #endif #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #define KLMD_BITS { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 #define KLMD_BITS { 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #define KLMD_BITS { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 #define KM_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 #define KM_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #define KM_BITS { 0xf0, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 #define KM_BITS { 0xf0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #define KM_BITS { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #endif #endif #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 #define KMAC_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 #define KMAC_BITS { 0xf0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #define KMAC_BITS { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 #define KMC_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 #define KMC_BITS { 0xf0, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 #define KMC_BITS { 0xf0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #else #define KMC_BITS { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #endif #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 #define PCKMO_BITS { 0xf0, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 #define KMCTR_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define KMF_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define KMO_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define PCC_BITS { 0xf0, 0x70, 0x38, 0x38, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif /*----------------------------------------------------------------------------*/ /* Write bytes on one line */ /*----------------------------------------------------------------------------*/ #define LOGBYTE(s, v, x) \ { \ int i; \ \ logmsg(" " s " "); \ for(i = 0; i < (x); i++) \ logmsg("%02X", (v)[i]); \ logmsg(" | "); \ for(i = 0; i < (x); i++) \ { \ if(isprint(guest_to_host((v)[i]))) \ logmsg("%c", guest_to_host((v)[i])); \ else \ logmsg("."); \ } \ logmsg(" |\n"); \ } /*----------------------------------------------------------------------------*/ /* Write bytes on multiple lines */ /*----------------------------------------------------------------------------*/ #define LOGBYTE2(s, v, x, y) \ { \ int i; \ int j; \ \ logmsg(" " s "\n"); \ for(i = 0; i < (y); i++) \ { \ logmsg(" "); \ for(j = 0; j < (x); j++) \ logmsg("%02X", (v)[i * (x) + j]); \ logmsg(" | "); \ for(j = 0; j < (x); j++) \ { \ if(isprint(guest_to_host((v)[i * (x) + j]))) \ logmsg("%c", guest_to_host((v)[i * (x) + j])); \ else \ logmsg("."); \ } \ logmsg(" |\n"); \ } \ } /*----------------------------------------------------------------------------*/ /* CPU determined amount of data (processed in one go) */ /*----------------------------------------------------------------------------*/ #define PROCESS_MAX 16384 /*----------------------------------------------------------------------------*/ /* Used for printing debugging info */ /*----------------------------------------------------------------------------*/ #define TRUEFALSE(boolean) ((boolean) ? "True" : "False") #ifndef __STATIC_FUNCTIONS__ #define __STATIC_FUNCTIONS__ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* GCM multiplication over GF(2^128) */ /*----------------------------------------------------------------------------*/ /* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. * * Tom St Denis, tomstdenis@..., http://libtomcrypt.org */ /* Remarks Bernard van der Helm: Strongly adjusted for * Hercules-390. We need the internal function gcm_gf_mult. * The rest of of the code is deleted. * * Thanks Tom! */ /* Hercules adjustments */ #define zeromem(dst, len) memset((dst), 0, (len)) #define XMEMCPY memcpy /* Original code from gcm_gf_mult.c */ /* right shift */ static void gcm_rightshift(unsigned char *a) { int x; for(x = 15; x > 0; x--) a[x] = (a[x] >> 1) | ((a[x-1] << 7) & 0x80); a[0] >>= 1; } /* c = b*a */ static const unsigned char mask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; static const unsigned char poly[] = { 0x00, 0xE1 }; void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c) { unsigned char Z[16], V[16]; unsigned x, y, z; zeromem(Z, 16); XMEMCPY(V, a, 16); for (x = 0; x < 128; x++) { if(b[x>>3] & mask[x&7]) { for(y = 0; y < 16; y++) Z[y] ^= V[y]; } z = V[15] & 0x01; gcm_rightshift(V); V[0] ^= poly[z]; } XMEMCPY(c, Z, 16); } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ /*----------------------------------------------------------------------------*/ /* Get the chaining vector for output processing */ /*----------------------------------------------------------------------------*/ static void sha1_getcv(sha1_context *ctx, BYTE icv[20]) { int i, j; for(i = 0, j = 0; i < 5; i++) { icv[j++] = (ctx->state[i] & 0xff000000) >> 24; icv[j++] = (ctx->state[i] & 0x00ff0000) >> 16; icv[j++] = (ctx->state[i] & 0x0000ff00) >> 8; icv[j++] = (ctx->state[i] & 0x000000ff); } } /*----------------------------------------------------------------------------*/ /* Set the initial chaining value */ /*----------------------------------------------------------------------------*/ static void sha1_seticv(sha1_context *ctx, BYTE icv[20]) { int i, j; for(i = 0, j = 0; i < 5; i++) { ctx->state[i] = icv[j++] << 24; ctx->state[i] |= icv[j++] << 16; ctx->state[i] |= icv[j++] << 8; ctx->state[i] |= icv[j++]; } } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 /*----------------------------------------------------------------------------*/ /* Get the chaining vector for output processing */ /*----------------------------------------------------------------------------*/ static void sha256_getcv(sha256_context *ctx, BYTE icv[32]) { int i, j; for(i = 0, j = 0; i < 8; i++) { icv[j++] = (ctx->state[i] & 0xff000000) >> 24; icv[j++] = (ctx->state[i] & 0x00ff0000) >> 16; icv[j++] = (ctx->state[i] & 0x0000ff00) >> 8; icv[j++] = (ctx->state[i] & 0x000000ff); } } /*----------------------------------------------------------------------------*/ /* Set the initial chaining value */ /*----------------------------------------------------------------------------*/ static void sha256_seticv(sha256_context *ctx, BYTE icv[32]) { int i, j; for(i = 0, j = 0; i < 8; i++) { ctx->state[i] = icv[j++] << 24; ctx->state[i] |= icv[j++] << 16; ctx->state[i] |= icv[j++] << 8; ctx->state[i] |= icv[j++]; } } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 /*----------------------------------------------------------------------------*/ /* Get the chaining vector for output processing */ /*----------------------------------------------------------------------------*/ static void sha512_getcv(sha512_context *ctx, BYTE icv[64]) { int i, j; for(i = 0, j = 0; i < 8; i++) { icv[j++] = (ctx->state[i] & 0xff00000000000000LL) >> 56; icv[j++] = (ctx->state[i] & 0x00ff000000000000LL) >> 48; icv[j++] = (ctx->state[i] & 0x0000ff0000000000LL) >> 40; icv[j++] = (ctx->state[i] & 0x000000ff00000000LL) >> 32; icv[j++] = (ctx->state[i] & 0x00000000ff000000LL) >> 24; icv[j++] = (ctx->state[i] & 0x0000000000ff0000LL) >> 16; icv[j++] = (ctx->state[i] & 0x000000000000ff00LL) >> 8; icv[j++] = (ctx->state[i] & 0x00000000000000ffLL); } } /*----------------------------------------------------------------------------*/ /* Set the initial chaining value */ /*----------------------------------------------------------------------------*/ static void sha512_seticv(sha512_context *ctx, BYTE icv[64]) { int i, j; for(i = 0, j = 0; i < 8; i++) { ctx->state[i] = (U64) icv[j++] << 56; ctx->state[i] |= (U64) icv[j++] << 48; ctx->state[i] |= (U64) icv[j++] << 40; ctx->state[i] |= (U64) icv[j++] << 32; ctx->state[i] |= (U64) icv[j++] << 24; ctx->state[i] |= (U64) icv[j++] << 16; ctx->state[i] |= (U64) icv[j++] << 8; ctx->state[i] |= (U64) icv[j++]; } } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* Shif left */ /*----------------------------------------------------------------------------*/ void shift_left(BYTE *dst, BYTE* src, int len) { int carry; int i; carry = 0; for(i = 0; i < len; i++) { if(carry) { carry = src[len - 1 - i] & 0x80; dst[len - 1 - i] = src[len - 1 - i] << 1; dst[len - 1 - i] |= 0x01; } else { carry = src[len - 1 - i] & 0x80; dst[len - 1 - i] = src[len - 1 - i] << 1; } } } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /*----------------------------------------------------------------------------*/ /* Unwrap key using aes */ /*----------------------------------------------------------------------------*/ static int unwrap_aes(BYTE *key, int keylen) { BYTE buf[16]; aes_context context; BYTE cv[16]; int i; obtain_lock(&sysblk.wklock); /* Verify verification pattern */ if(unlikely(memcmp(&key[keylen], sysblk.wkvpaes_reg, 32))) { release_lock(&sysblk.wklock); return(1); } aes_set_key(&context, sysblk.wkaes_reg, 256); release_lock(&sysblk.wklock); switch(keylen) { case 16: { aes_decrypt(&context, key, key); break; } case 24: { aes_decrypt(&context, &key[8], buf); memcpy(&key[8], &buf[8], 8); memcpy(cv, key, 8); aes_decrypt(&context, key, key); for(i = 0; i < 8; i++) key[i + 16] = buf[i] ^ cv[i]; break; } case 32: { memcpy(cv, key, 16); aes_decrypt(&context, key, key); aes_decrypt(&context, &key[16], &key[16]); for(i = 0; i < 16; i++) key[i + 16] ^= cv[i]; break; } } return(0); } /*----------------------------------------------------------------------------*/ /* Unwrap key using dea */ /*----------------------------------------------------------------------------*/ static int unwrap_dea(BYTE *key, int keylen) { BYTE cv[16]; des3_context context; int i; int j; obtain_lock(&sysblk.wklock); /* Verify verification pattern */ if(unlikely(memcmp(&key[keylen], sysblk.wkvpdea_reg, 24))) { release_lock(&sysblk.wklock); return(1); } des3_set_3keys(&context, sysblk.wkdea_reg, &sysblk.wkdea_reg[8], &sysblk.wkdea_reg[16]); release_lock(&sysblk.wklock); for(i = 0; i < keylen; i += 8) { /* Save cv */ memcpy(cv, &cv[8], 8); memcpy(&cv[8], &key[i], 8); des3_decrypt(&context, &key[i], &key[i]); des3_encrypt(&context, &key[i], &key[i]); des3_decrypt(&context, &key[i], &key[i]); if(i) { /* XOR */ for(j = 0; j < 8; j++) key[i + j] ^= cv[j]; } } return(0); } /*----------------------------------------------------------------------------*/ /* Wrap key using aes */ /*----------------------------------------------------------------------------*/ static void wrap_aes(BYTE *key, int keylen) { BYTE buf[16]; aes_context context; BYTE cv[16]; int i; obtain_lock(&sysblk.wklock); memcpy(&key[keylen], sysblk.wkvpaes_reg, 32); aes_set_key(&context, sysblk.wkaes_reg, 256); release_lock(&sysblk.wklock); switch(keylen) { case 16: { aes_encrypt(&context, key, key); break; } case 24: { aes_encrypt(&context, key, cv); memcpy(buf, &key[16], 8); memset(&buf[8], 0, 8); for(i = 0; i < 16; i++) buf[i] ^= cv[i]; aes_encrypt(&context, buf, buf); memcpy(key, cv, 8); memcpy(&key[8], buf, 16); break; } case 32: { aes_encrypt(&context, key, key); for(i = 0; i < 16; i++) key[i + 16] ^= key[i]; aes_encrypt(&context, &key[16], &key[16]); break; } } } /*----------------------------------------------------------------------------*/ /* Wrap key using dea */ /*----------------------------------------------------------------------------*/ static void wrap_dea(BYTE *key, int keylen) { des3_context context; int i; int j; obtain_lock(&sysblk.wklock); memcpy(&key[keylen], sysblk.wkvpdea_reg, 24); des3_set_3keys(&context, sysblk.wkdea_reg, &sysblk.wkdea_reg[8], &sysblk.wkdea_reg[16]); release_lock(&sysblk.wklock); for(i = 0; i < keylen; i += 8) { if(i) { /* XOR */ for(j = 0; j < 8; j++) key[i + j] ^= key[i + j - 8]; } des3_encrypt(&context, &key[i], &key[i]); des3_decrypt(&context, &key[i], &key[i]); des3_encrypt(&context, &key[i], &key[i]); } } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* 2^m table with GF multiplication entries 127, 126, 125, ... */ /* 2 2^b1 */ /* 2*2 2^b10 */ /* 2*2*2*2 2^b100 */ /* 2*2*2*2*2*2*2*2 2^b1000 */ /* ... */ /*----------------------------------------------------------------------------*/ #if 0 #include #include /*----------------------------------------------------------------------------*/ /* GCM multiplication over GF(2^128) */ /*----------------------------------------------------------------------------*/ /* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * guarantee it works. * * Tom St Denis, tomstdenis@..., http://libtomcrypt.org */ /* Remarks Bernard van der Helm: Strongly adjusted for * Hercules-390. We need the internal function gcm_gf_mult. * The rest of of the code is deleted. * * Thanks Tom! */ /* Hercules adjustments */ #define zeromem(dst, len) memset((dst), 0, (len)) #define XMEMCPY memcpy /* Original code from gcm_gf_mult.c */ /* right shift */ static void gcm_rightshift(unsigned char *a) { int x; for(x = 15; x > 0; x--) a[x] = (a[x] >> 1) | ((a[x-1] << 7) & 0x80); a[0] >>= 1; } /* c = b*a */ static const unsigned char mask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; static const unsigned char poly[] = { 0x00, 0xE1 }; void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c) { unsigned char Z[16], V[16]; unsigned x, y, z; zeromem(Z, 16); XMEMCPY(V, a, 16); for (x = 0; x < 128; x++) { if(b[x>>3] & mask[x&7]) { for(y = 0; y < 16; y++) Z[y] ^= V[y]; } z = V[15] & 0x01; gcm_rightshift(V); V[0] ^= poly[z]; } XMEMCPY(c, Z, 16); } void power(unsigned char *a, unsigned char b) { unsigned char two[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2 }; memset(a, 0, 15); a[15] = 2; for(b--; b; b--) gcm_gf_mult(a, two, a); } #define P(a) { int _i; printf(" { "); for(_i = 0; _i < 16; _i++) { printf("0x%02x", a[_i]); printf((_i < 15 ? ", " : " ")); } printf("},\n"); } /*----------------------------------------------------------------------------*/ /* Program to generate exp_table */ /* Many thanks to Evert Combe */ /*----------------------------------------------------------------------------*/ int main(void) { unsigned char exp_table[128][16]; unsigned char a[16]; int i; memset(a, 0, 15); a[15] = 2; for(i = 1; i < 128 ; i++) { memcpy(exp_table[128 - i], a, 16); gcm_gf_mult(a, a, a); } for(i = 0; i < 128; i++) P(exp_table[i]); printf("Checking last 8 enties\n"); for(i = 1; i < 0x100; i <<= 1) { power(a, i); P(a); } return(0); } #endif /* #if 0 */ static BYTE exp_table[128][16] = { { 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x0e, 0xab, 0x4c, 0x00, 0x00, 0x00, 0x00 }, { 0x7f, 0x6d, 0xb6, 0xda, 0xdb, 0x6d, 0xb6, 0xdb, 0x6d, 0xb6, 0xdb, 0x6c, 0x92, 0x49, 0x24, 0x92 }, { 0x5c, 0x8b, 0x14, 0x51, 0x45, 0x15, 0x9e, 0x79, 0xe7, 0x9f, 0x3c, 0xf3, 0xcf, 0x3d, 0xf7, 0xdf }, { 0x14, 0xe7, 0x9f, 0x8a, 0x29, 0xe7, 0x9f, 0xff, 0xfe, 0xba, 0xea, 0x28, 0xa3, 0x0c, 0x31, 0xc7 }, { 0x66, 0x4d, 0xa2, 0x9b, 0x79, 0xf6, 0xca, 0x30, 0xd1, 0x5b, 0x75, 0xc7, 0x04, 0x00, 0x10, 0x51 }, { 0xcf, 0x6a, 0x7e, 0x04, 0x24, 0xb0, 0x80, 0x67, 0xd1, 0x21, 0xe2, 0xdf, 0x3a, 0xae, 0xff, 0xba }, { 0xf2, 0x9e, 0xa7, 0xe7, 0xf3, 0x64, 0x7c, 0x0f, 0xad, 0x4b, 0x4d, 0xbc, 0x5a, 0xd5, 0xfd, 0x5f }, { 0xa9, 0xff, 0xac, 0xe1, 0x19, 0x06, 0x87, 0x1c, 0xb0, 0x3c, 0x50, 0xfc, 0xac, 0x30, 0xd5, 0x55 }, { 0x03, 0xd6, 0x8f, 0x61, 0xc3, 0x06, 0xd4, 0x12, 0xc7, 0xd3, 0x34, 0xa2, 0x06, 0x0f, 0xdf, 0x1c }, { 0x4a, 0x23, 0x3f, 0xdc, 0xd3, 0xcd, 0x27, 0x2c, 0xc6, 0xe5, 0x34, 0x69, 0x8c, 0xff, 0xd8, 0xeb }, { 0x90, 0x84, 0xe3, 0xce, 0x7e, 0xca, 0x90, 0x78, 0xfe, 0xab, 0xae, 0xef, 0x43, 0x08, 0x2a, 0x9a }, { 0xa6, 0x15, 0x2d, 0x3b, 0xc8, 0xab, 0xd2, 0x7d, 0x90, 0x8b, 0x9b, 0x29, 0xda, 0x67, 0x7f, 0xfb }, { 0x5c, 0x96, 0xc3, 0x29, 0x8a, 0x77, 0xba, 0x83, 0x23, 0x5e, 0x48, 0xd5, 0xfe, 0x81, 0xf5, 0x57 }, { 0xd3, 0x8c, 0x67, 0x4e, 0x2d, 0x21, 0xcf, 0x3e, 0x94, 0x13, 0x63, 0x25, 0xab, 0xf1, 0xda, 0xaa }, { 0x0b, 0xc6, 0xfe, 0x9f, 0xdd, 0x96, 0x36, 0xd2, 0x7d, 0x19, 0x13, 0xcf, 0x97, 0x7c, 0x8c, 0x49 }, { 0x53, 0xa4, 0x5a, 0x64, 0x48, 0xb9, 0x05, 0xf5, 0x74, 0x6a, 0xa2, 0x29, 0xcc, 0xc3, 0x1d, 0x9a }, { 0xf2, 0x8c, 0xf2, 0x28, 0xca, 0x61, 0x25, 0x6d, 0x10, 0xd0, 0x97, 0xc7, 0x09, 0x25, 0x08, 0x7b }, { 0x2f, 0x0d, 0x0e, 0xbf, 0xd8, 0xd6, 0x50, 0x2d, 0x02, 0x92, 0xd3, 0x51, 0x60, 0x75, 0xa7, 0xf3 }, { 0x9c, 0x0d, 0xcc, 0x04, 0xc4, 0x81, 0x20, 0xfa, 0x58, 0x23, 0xb9, 0xfc, 0x96, 0x1e, 0x47, 0xc5 }, { 0xbb, 0x23, 0x09, 0xf2, 0x24, 0x26, 0xcd, 0x3a, 0xb5, 0x02, 0xfe, 0xd6, 0x01, 0x70, 0x6b, 0xc3 }, { 0x43, 0x3d, 0x70, 0xe1, 0x5a, 0x1c, 0xa2, 0x6e, 0x37, 0xe0, 0x26, 0x7b, 0x12, 0xb9, 0x3b, 0xe5 }, { 0x6c, 0xf6, 0x5a, 0xd9, 0xca, 0xb0, 0x19, 0x68, 0x87, 0x2c, 0x4f, 0xf4, 0xe4, 0xba, 0x05, 0xe7 }, { 0x88, 0x30, 0xba, 0x86, 0xb8, 0x19, 0x92, 0x99, 0xb9, 0xf3, 0xfb, 0x3f, 0xcb, 0xc6, 0x69, 0x18 }, { 0x5c, 0x97, 0x53, 0x46, 0x91, 0x5e, 0xc1, 0xa4, 0xdf, 0xb4, 0xde, 0x97, 0xa8, 0xce, 0x50, 0x84 }, { 0x2c, 0x04, 0x4b, 0x4f, 0x4f, 0x50, 0x53, 0xbd, 0x4e, 0x19, 0x70, 0x82, 0xa2, 0xb1, 0x2f, 0x26 }, { 0xeb, 0x4a, 0x7b, 0xda, 0xd8, 0x24, 0x6d, 0xed, 0x26, 0x51, 0x8d, 0x78, 0xb3, 0xb6, 0xde, 0xef }, { 0x41, 0x06, 0xa7, 0xfa, 0x6c, 0x80, 0x75, 0x30, 0xe4, 0x56, 0x02, 0xe7, 0xd7, 0xc4, 0xcf, 0x0a }, { 0x3c, 0x4f, 0x85, 0x6f, 0x49, 0x12, 0x60, 0x45, 0x59, 0x1f, 0x49, 0xcd, 0x0f, 0xf5, 0x50, 0xa4 }, { 0xc9, 0x7e, 0x51, 0x94, 0x8a, 0x53, 0xae, 0x62, 0xbc, 0xae, 0x5f, 0x67, 0x31, 0xae, 0xe3, 0xb4 }, { 0xee, 0x16, 0x60, 0x78, 0x01, 0x7a, 0x57, 0x19, 0x39, 0xeb, 0x61, 0x09, 0x4b, 0x8a, 0x10, 0x86 }, { 0x26, 0x20, 0xcc, 0xe3, 0xa3, 0x83, 0x4d, 0xbc, 0x06, 0x44, 0x8d, 0x5e, 0x88, 0x81, 0xa4, 0xd9 }, { 0x5d, 0x21, 0xc3, 0x06, 0x28, 0x86, 0x1f, 0x9b, 0x92, 0xf7, 0xec, 0x30, 0x2f, 0xc6, 0xda, 0x61 }, { 0x7f, 0xe4, 0xdc, 0xca, 0x4f, 0xd4, 0x5a, 0x63, 0x81, 0xa6, 0xd9, 0x5e, 0x9c, 0x20, 0x3d, 0x65 }, { 0xe9, 0x90, 0xab, 0xe2, 0xf8, 0xb0, 0x92, 0xf0, 0xe6, 0x2d, 0x1d, 0x65, 0xa6, 0x1d, 0xdb, 0x18 }, { 0x11, 0x86, 0x31, 0x4c, 0x39, 0x06, 0x3b, 0xaf, 0x32, 0x52, 0x96, 0x9f, 0x4a, 0x3c, 0xb1, 0xe9 }, { 0xc2, 0x8c, 0xcf, 0xd0, 0x5a, 0xa9, 0x33, 0x02, 0x59, 0x74, 0xcb, 0x35, 0xf2, 0x23, 0xf9, 0x77 }, { 0xfc, 0x45, 0x3f, 0x91, 0x81, 0xc6, 0xb9, 0x41, 0x90, 0xa9, 0xfe, 0x80, 0xc6, 0x5c, 0x48, 0xc7 }, { 0x6f, 0x52, 0x47, 0x41, 0x54, 0xa3, 0x1a, 0xfd, 0xf5, 0xcc, 0x8b, 0x3e, 0x93, 0x92, 0xf0, 0x98 }, { 0x0d, 0xea, 0x57, 0x81, 0x32, 0xa9, 0x32, 0x17, 0x1f, 0x53, 0x93, 0x2a, 0xaf, 0xeb, 0x32, 0x96 }, { 0xf1, 0x59, 0x84, 0xe3, 0xa0, 0x57, 0xde, 0x87, 0xe4, 0x7e, 0x93, 0x23, 0x1e, 0x80, 0x3e, 0x94 }, { 0xe4, 0x6c, 0x7e, 0x56, 0x4f, 0xe2, 0x0e, 0xfd, 0x73, 0x41, 0x2a, 0xb5, 0x0f, 0xa5, 0xdb, 0x06 }, { 0x9b, 0x94, 0x70, 0xb7, 0x47, 0x15, 0xa5, 0xa9, 0xbd, 0x46, 0x76, 0xf1, 0xe5, 0xb1, 0x11, 0xef }, { 0xb4, 0xff, 0x39, 0x54, 0x74, 0x60, 0x3d, 0xc0, 0x30, 0xdc, 0x31, 0x13, 0x19, 0xd7, 0x5e, 0x8a }, { 0x1c, 0x73, 0xa4, 0x25, 0x99, 0x5d, 0x56, 0xd6, 0xd5, 0xe2, 0xbf, 0x89, 0x62, 0x17, 0xaa, 0xb6 }, { 0x8a, 0x9d, 0x6b, 0x27, 0xc0, 0x0d, 0xe3, 0x23, 0xba, 0x6e, 0x8e, 0x2b, 0x89, 0x5a, 0xdc, 0x94 }, { 0x3f, 0x01, 0x5b, 0xa2, 0xf9, 0x5b, 0xb3, 0x2d, 0xb1, 0xa7, 0x6e, 0x5a, 0x0b, 0x48, 0x1f, 0x06 }, { 0x8f, 0x26, 0x29, 0x79, 0xd4, 0x23, 0x24, 0xa9, 0x7e, 0x12, 0x8c, 0xca, 0x11, 0x9f, 0xe4, 0xef }, { 0x65, 0x77, 0xb2, 0x14, 0x2c, 0x26, 0xcf, 0x2d, 0xef, 0xe1, 0xda, 0x6c, 0x69, 0x09, 0x78, 0xbc }, { 0x44, 0x0e, 0x8b, 0x99, 0x6b, 0x63, 0x15, 0xb0, 0x71, 0x6b, 0x4b, 0xca, 0xe5, 0x66, 0x5a, 0x94 }, { 0x13, 0xa6, 0xb9, 0x4a, 0x3d, 0x2d, 0xe6, 0xe6, 0x6f, 0xe8, 0x88, 0x7b, 0xac, 0x1b, 0xc2, 0x94 }, { 0xe9, 0x98, 0x49, 0x53, 0x5e, 0xad, 0x09, 0x9d, 0xef, 0xad, 0xca, 0xf4, 0x3f, 0xf3, 0x4c, 0x06 }, { 0x53, 0x5d, 0xbc, 0xee, 0x0a, 0x6f, 0x5a, 0xa2, 0xe9, 0xa8, 0xfc, 0x87, 0x58, 0x9d, 0xc5, 0x02 }, { 0x08, 0xba, 0x8e, 0x3d, 0x2e, 0x6b, 0x43, 0xc1, 0xc7, 0x99, 0x2e, 0x00, 0x80, 0xfc, 0x4e, 0x7f }, { 0x97, 0x5f, 0xfb, 0xd4, 0x6b, 0xf0, 0x86, 0xd3, 0x04, 0xb1, 0x08, 0x88, 0xa1, 0x00, 0x0f, 0x47 }, { 0x5b, 0x5d, 0x01, 0x13, 0xe6, 0xf1, 0xb6, 0xc8, 0xc7, 0x39, 0xa9, 0x0c, 0xb3, 0x6d, 0xa4, 0xae }, { 0x17, 0xab, 0xe0, 0x8c, 0xbc, 0x21, 0xc2, 0xfa, 0x71, 0x33, 0xd7, 0x9b, 0xcc, 0x82, 0x18, 0x26 }, { 0xa0, 0x7f, 0x08, 0x4f, 0xef, 0xdc, 0x29, 0x4b, 0xa5, 0x26, 0xb7, 0x60, 0xcc, 0x7a, 0xff, 0xb4 }, { 0x30, 0x41, 0xdf, 0xc2, 0x5d, 0x99, 0xf7, 0x62, 0xd5, 0xbc, 0x39, 0x3e, 0xef, 0x89, 0x9f, 0x14 }, { 0xa0, 0x2f, 0x6d, 0x2e, 0x7d, 0x79, 0xd6, 0xf5, 0xf7, 0x1b, 0x85, 0x52, 0xa2, 0x14, 0x37, 0x86 }, { 0x44, 0xff, 0xf7, 0xa3, 0x22, 0x11, 0xd5, 0xac, 0xb5, 0x10, 0xe1, 0xd5, 0x5e, 0xe0, 0x06, 0xa6 }, { 0x2a, 0x2a, 0x3a, 0xcd, 0xeb, 0x6c, 0xb1, 0x9e, 0xd5, 0x5a, 0x4c, 0x7d, 0xcd, 0x38, 0xf6, 0xfd }, { 0x48, 0xae, 0x38, 0x63, 0x13, 0xc2, 0x56, 0x57, 0xb6, 0x98, 0x8b, 0x30, 0xe0, 0xb8, 0xa0, 0xf1 }, { 0xc8, 0xb2, 0x0f, 0x43, 0x5c, 0x72, 0xc8, 0x1d, 0x26, 0x9a, 0x1b, 0x9c, 0xfb, 0x7b, 0xfb, 0x61 }, { 0xb1, 0xcb, 0x75, 0x7d, 0x06, 0xff, 0xe6, 0xe3, 0xfb, 0x53, 0x9f, 0x6a, 0x69, 0x79, 0xe1, 0xe5 }, { 0x4f, 0xd4, 0xfb, 0x3c, 0xe0, 0x4c, 0xc1, 0x6e, 0x88, 0xe3, 0x47, 0x41, 0xe1, 0x52, 0xc5, 0x3c }, { 0xc6, 0x85, 0x7a, 0x49, 0x7a, 0x87, 0x67, 0xae, 0xab, 0xa2, 0xd0, 0x8b, 0x65, 0x1a, 0xc4, 0x30 }, { 0x48, 0x13, 0x7b, 0x71, 0x3d, 0x3c, 0xde, 0xd9, 0x03, 0xbe, 0x03, 0xcb, 0x7f, 0x25, 0x16, 0x69 }, { 0x3c, 0xbe, 0xf8, 0xeb, 0xb7, 0x0c, 0x80, 0x41, 0xfa, 0x8c, 0xeb, 0x9e, 0xcf, 0xe5, 0x58, 0x65 }, { 0xf0, 0xe3, 0x91, 0xe1, 0xf9, 0x53, 0x45, 0x2b, 0x06, 0x08, 0x7d, 0xbe, 0x02, 0xcf, 0x51, 0xf5 }, { 0xc9, 0x2d, 0xf0, 0x46, 0x92, 0xf1, 0xcf, 0xa8, 0xd3, 0x3e, 0x1e, 0x7e, 0xff, 0x14, 0x98, 0xc7 }, { 0x9a, 0x79, 0xfb, 0x25, 0x52, 0xd2, 0xd8, 0xcb, 0x58, 0xd0, 0x45, 0x12, 0x86, 0xb9, 0xcf, 0xbc }, { 0xae, 0x5b, 0xc9, 0x11, 0x4e, 0x2a, 0xc2, 0x4d, 0x28, 0xca, 0x9f, 0x2c, 0x44, 0x32, 0x68, 0xa2 }, { 0x31, 0xbc, 0xda, 0xf0, 0xbd, 0x2e, 0xee, 0xdb, 0xf3, 0xe8, 0xb6, 0x43, 0x64, 0xef, 0x4d, 0x24 }, { 0xbc, 0xda, 0x7f, 0x1c, 0x13, 0x30, 0x1b, 0xd1, 0xeb, 0xbb, 0x10, 0xba, 0x89, 0x41, 0x98, 0xa6 }, { 0x05, 0xec, 0xbf, 0x29, 0x8e, 0xd2, 0x01, 0x75, 0x60, 0xeb, 0x32, 0x1e, 0x5e, 0x96, 0xc1, 0x6f }, { 0xec, 0xb7, 0x32, 0x7b, 0xf5, 0xe0, 0xd1, 0x48, 0x50, 0x7e, 0xf2, 0x55, 0x2c, 0xdd, 0x4f, 0x75 }, { 0x7b, 0xeb, 0x5a, 0xf9, 0xd4, 0x02, 0x8e, 0xcb, 0xdc, 0xd7, 0x1b, 0xad, 0x62, 0x9c, 0xb8, 0xaa }, { 0xa1, 0x59, 0x6c, 0x37, 0x20, 0xfc, 0x5f, 0x34, 0xac, 0x45, 0x49, 0x08, 0xf1, 0x7c, 0x06, 0x92 }, { 0x52, 0x8c, 0xf0, 0x71, 0x6f, 0x8f, 0xd5, 0x44, 0xa8, 0xb1, 0x2b, 0x86, 0xf5, 0x36, 0x1d, 0x96 }, { 0xef, 0x15, 0x39, 0xce, 0x30, 0x61, 0x5b, 0xb7, 0x02, 0x9e, 0x7c, 0x74, 0x97, 0xef, 0x14, 0xeb }, { 0xfc, 0x13, 0x25, 0x22, 0x73, 0xec, 0xd0, 0x35, 0x78, 0x50, 0x41, 0xea, 0x4f, 0x0f, 0x8a, 0x2c }, { 0x66, 0x05, 0xfd, 0x5b, 0xb0, 0xc2, 0x71, 0x6e, 0xfa, 0x7f, 0x3d, 0x6a, 0x9f, 0x76, 0x7c, 0x90 }, { 0x3e, 0xa9, 0x72, 0x89, 0x93, 0x2a, 0x4b, 0x35, 0x03, 0x8c, 0xd2, 0x8b, 0xb8, 0x76, 0xab, 0x96 }, { 0x1b, 0x80, 0x3a, 0x46, 0xd9, 0x41, 0x5b, 0x3c, 0xda, 0x93, 0x36, 0x5c, 0x82, 0x93, 0x2b, 0x79 }, { 0x4e, 0xc9, 0x01, 0x28, 0xd3, 0xda, 0x9e, 0x0a, 0x5b, 0x2f, 0x3e, 0x14, 0x4c, 0xf0, 0x05, 0xa8 }, { 0x25, 0x70, 0xe6, 0x5e, 0x2e, 0x98, 0xca, 0xf8, 0x65, 0xa4, 0x56, 0xb6, 0x11, 0x4f, 0x44, 0xa4 }, { 0xdc, 0xed, 0x91, 0x03, 0x0f, 0xf5, 0x7a, 0x54, 0x3b, 0xd4, 0xb2, 0xd6, 0x7d, 0x4f, 0xae, 0x6f }, { 0x61, 0x40, 0xae, 0x15, 0xb0, 0xbc, 0x41, 0x15, 0x2e, 0x81, 0x1c, 0x46, 0x8f, 0xb9, 0xc3, 0x43 }, { 0xb2, 0xc2, 0x7d, 0xa9, 0xf9, 0xc2, 0xf9, 0x30, 0x3f, 0xdc, 0xdd, 0x31, 0x01, 0x42, 0x7a, 0xc1 }, { 0xc6, 0x99, 0x24, 0xf9, 0x84, 0xe3, 0x7a, 0xaf, 0x2d, 0x5a, 0x89, 0xe9, 0x54, 0x7a, 0x52, 0x9a }, { 0xf1, 0x1f, 0x01, 0xcb, 0x45, 0x62, 0x8c, 0xc6, 0x05, 0x9e, 0xf7, 0x27, 0xc4, 0x88, 0xf2, 0x96 }, { 0x2a, 0x71, 0x25, 0x91, 0x23, 0x4c, 0xd1, 0x07, 0x15, 0xac, 0x3f, 0xd0, 0x30, 0xee, 0x6d, 0x6b }, { 0x3e, 0x62, 0x9c, 0xf5, 0x4d, 0x5e, 0xf7, 0x9d, 0xd7, 0xcc, 0x8b, 0xa7, 0x82, 0x3b, 0x2f, 0x53 }, { 0x63, 0xfe, 0x06, 0xf3, 0xb9, 0xc9, 0x90, 0x3b, 0xbf, 0x9c, 0x39, 0xce, 0x3d, 0xa7, 0xfa, 0x73 }, { 0x29, 0x21, 0x90, 0x36, 0x09, 0x7e, 0x99, 0x49, 0x8f, 0xd7, 0xac, 0xde, 0xa2, 0x19, 0x58, 0xd7 }, { 0x80, 0xed, 0x34, 0xb5, 0xf0, 0x63, 0xd5, 0xfb, 0xc8, 0x4f, 0xe2, 0x1a, 0x71, 0x0f, 0xfa, 0x9c }, { 0x81, 0x7e, 0xa4, 0xa8, 0x1a, 0xb8, 0x81, 0x92, 0x0a, 0x23, 0xbe, 0x3a, 0xd1, 0xb2, 0x83, 0xb0 }, { 0x6a, 0x4e, 0x55, 0xf9, 0x34, 0x1c, 0x4b, 0x5a, 0xc6, 0xff, 0xb2, 0x5f, 0xfe, 0xb2, 0x84, 0x84 }, { 0x58, 0xf2, 0x1c, 0x23, 0x7b, 0xb7, 0x7b, 0x66, 0x42, 0xa8, 0x6b, 0xe0, 0xb8, 0x47, 0x04, 0xb4 }, { 0xef, 0xa4, 0x62, 0xbb, 0x1e, 0xb1, 0x35, 0x3f, 0xbb, 0x01, 0xea, 0x8b, 0xff, 0x76, 0x98, 0x22 }, { 0x09, 0x35, 0xbb, 0x6e, 0x31, 0x97, 0x66, 0xa5, 0xa6, 0x4c, 0xfa, 0x31, 0x7e, 0x48, 0xe2, 0x00 }, { 0x04, 0x54, 0x56, 0xde, 0x31, 0x28, 0xff, 0xbd, 0xa3, 0x3d, 0xea, 0xfc, 0xbd, 0x68, 0xf6, 0x49 }, { 0x3e, 0x48, 0x5d, 0x0c, 0x12, 0x2d, 0xc6, 0x5e, 0x2b, 0x9d, 0xed, 0x5c, 0x87, 0x62, 0x3f, 0x08 }, { 0x64, 0xba, 0x79, 0x1b, 0x65, 0x71, 0xd8, 0x84, 0xbf, 0x10, 0x4a, 0xf0, 0x15, 0x1d, 0x89, 0x5b }, { 0x65, 0xc9, 0x63, 0x70, 0xb6, 0x37, 0x2b, 0x04, 0xdf, 0x33, 0xc5, 0x6f, 0x84, 0x0d, 0xce, 0xc5 }, { 0x31, 0xf2, 0x51, 0x68, 0x29, 0x7e, 0x00, 0x81, 0x1a, 0xc4, 0xf8, 0x10, 0xe8, 0xae, 0xfc, 0x2e }, { 0x4f, 0x7d, 0x19, 0xd2, 0x80, 0x50, 0x37, 0x64, 0x3b, 0xad, 0xab, 0x6c, 0xd0, 0xdf, 0x6f, 0x02 }, { 0x89, 0xe2, 0xe6, 0xc1, 0xbc, 0x38, 0xef, 0x87, 0x71, 0x72, 0x44, 0xe6, 0x83, 0x74, 0x47, 0x5b }, { 0x05, 0xe2, 0x60, 0xd6, 0x8e, 0x83, 0x5c, 0xef, 0x1b, 0xd3, 0x04, 0x35, 0x72, 0xf4, 0x8f, 0x57 }, { 0x52, 0xf7, 0x55, 0xa0, 0x28, 0x80, 0xe2, 0x4e, 0x52, 0xd4, 0xb7, 0x0a, 0x1e, 0xf8, 0xd4, 0xaa }, { 0x63, 0x97, 0x05, 0xb0, 0xcb, 0xfe, 0xd8, 0xd4, 0xb8, 0xed, 0xb6, 0x42, 0x9d, 0xc9, 0x44, 0x6d }, { 0x63, 0xfc, 0x77, 0x16, 0x57, 0x31, 0xe6, 0xe4, 0x5c, 0xa0, 0x8f, 0x2b, 0x2e, 0xbf, 0x88, 0xbc }, { 0x68, 0x14, 0x3e, 0xe4, 0xac, 0x9b, 0x4d, 0x70, 0x54, 0x79, 0xcc, 0x2f, 0x00, 0x37, 0xdc, 0x94 }, { 0xc1, 0x9f, 0xb7, 0xd9, 0x3a, 0x48, 0x6c, 0x9b, 0xf9, 0x42, 0x68, 0xa9, 0xd7, 0x4a, 0x4e, 0x22 }, { 0x8e, 0xfd, 0x7f, 0x37, 0x41, 0xb4, 0xde, 0x6e, 0xea, 0x3a, 0x09, 0x97, 0x3f, 0x6c, 0x76, 0x6d }, { 0xc1, 0x5c, 0x7f, 0x54, 0x47, 0x36, 0x55, 0xb4, 0xf1, 0xce, 0x5d, 0x42, 0xdf, 0xea, 0x3d, 0x43 }, { 0x75, 0x55, 0x50, 0x24, 0x68, 0xda, 0x44, 0x40, 0x39, 0xc6, 0x79, 0xcf, 0x3d, 0x52, 0xad, 0xc1 }, { 0x53, 0xdc, 0xbb, 0xe0, 0x11, 0xc9, 0xf1, 0xc9, 0x55, 0x6f, 0x60, 0xbf, 0xaf, 0x3c, 0xe0, 0x3e }, { 0x7e, 0x5c, 0x70, 0xb0, 0x48, 0xfd, 0x05, 0x74, 0xab, 0x3f, 0xac, 0x53, 0x8a, 0xdc, 0xa2, 0xdd }, { 0xba, 0x27, 0x91, 0x4c, 0xe8, 0xb0, 0x04, 0x08, 0x2b, 0xb2, 0xd5, 0x8f, 0xea, 0x61, 0x2b, 0x63 }, { 0xda, 0x4c, 0xea, 0xef, 0xd6, 0x7f, 0x23, 0x0f, 0x91, 0x74, 0x04, 0xb6, 0xcd, 0x58, 0x9a, 0x53 }, { 0xb4, 0x2b, 0x1e, 0xfc, 0x97, 0x53, 0x84, 0x0d, 0xd0, 0x98, 0xf1, 0x35, 0xe2, 0x6b, 0xc4, 0xd7 }, { 0xa2, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xda, 0x2b, 0x1e, 0xfc, 0x4d, 0x78, 0x9a, 0xf1 }, { 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xda, 0x2b, 0xc4, 0xd7 }, { 0xa2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf1 }, { 0x6e, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7 }, { 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } }; #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ #endif /* #ifdef __STATIC_FUNCTIONS__ */ /*----------------------------------------------------------------------------*/ /* Needed functions from sha1.c and sha256.c. */ /* We do our own counting and padding, we only need the hashing. */ /*----------------------------------------------------------------------------*/ void sha1_process(sha1_context *ctx, BYTE data[64]); void sha256_process(sha256_context *ctx, BYTE data[64]); void sha512_process(sha512_context *ctx, BYTE data[128]); /*----------------------------------------------------------------------------*/ /* Compute intermediate message digest (KIMD) FC 1-3 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kimd_sha)(int r1, int r2, REGS *regs, int klmd) { sha1_context sha1_ctx; #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 sha256_context sha256_ctx; #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 sha512_context sha512_ctx; #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ int crypted; int fc; BYTE message_block[128]; int message_blocklen = 0; BYTE parameter_block[64]; int parameter_blocklen = 0; UNREFERENCED(r1); /* Initialize values */ fc = GR0_fc(regs); switch(fc) { case 1: /* sha-1 */ { message_blocklen = 64; parameter_blocklen = 20; break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { message_blocklen = 64; parameter_blocklen = 32; break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { message_blocklen = 128; parameter_blocklen = 64; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ } /* Check special conditions */ if(unlikely(!klmd && (GR_A(r2 + 1, regs) % message_blocklen))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, parameter_blocklen - 1, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KIMD_DEBUG if(parameter_blocklen > 32) { LOGBYTE2("icv :", parameter_block, 16, parameter_blocklen / 16); } else { LOGBYTE("icv :", parameter_block, parameter_blocklen); } #endif /* #ifdef OPTION_KIMD_DEBUG */ /* Set initial chaining value */ switch(fc) { case 1: /* sha-1 */ { sha1_seticv(&sha1_ctx, parameter_block); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { sha256_seticv(&sha256_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { sha512_seticv(&sha512_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ } /* Try to process the CPU-determined amount of data */ for(crypted = 0; crypted < PROCESS_MAX; crypted += message_blocklen) { /* Fetch and process a block of data */ ARCH_DEP(vfetchc)(message_block, message_blocklen - 1, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KIMD_DEBUG LOGBYTE2("input :", message_block, 16, message_blocklen / 16); #endif /* #ifdef OPTION_KIMD_DEBUG */ switch(fc) { case 1: /* sha-1 */ { sha1_process(&sha1_ctx, message_block); sha1_getcv(&sha1_ctx, parameter_block); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { sha256_process(&sha256_ctx, message_block); sha256_getcv(&sha256_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { sha512_process(&sha512_ctx, message_block); sha512_getcv(&sha512_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ } /* Store the output chaining value */ ARCH_DEP(vstorec)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KIMD_DEBUG if(parameter_blocklen > 32) { LOGBYTE2("ocv :", parameter_block, 16, parameter_blocklen / 16); } else { LOGBYTE("ocv :", parameter_block, parameter_blocklen); } #endif /* #ifdef OPTION_KIMD_DEBUG */ /* Update the registers */ SET_GR_A(r2, regs, GR_A(r2, regs) + message_blocklen); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - message_blocklen); #ifdef OPTION_KIMD_DEBUG logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KIMD_DEBUG */ /* check for end of data */ if(unlikely(GR_A(r2 + 1, regs) < 64)) { if(unlikely(klmd)) return; regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* Compute intermediate message digest (KIMD) FC 65 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kimd_ghash)(int r1, int r2, REGS *regs) { int crypted; int i; BYTE message_block[16]; BYTE parameter_block[32]; UNREFERENCED(r1); /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 16)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 15, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, 31, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KIMD_DEBUG LOGBYTE("icv :", parameter_block, 16); LOGBYTE("h :", ¶meter_block[16], 16); #endif /* #ifdef OPTION_KIMD_DEBUG */ /* Try to process the CPU-determined amount of data */ for(crypted = 0; crypted < PROCESS_MAX; crypted += 16) { /* Fetch and process a block of data */ ARCH_DEP(vfetchc)(message_block, 15, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KIMD_DEBUG LOGBYTE("input :", message_block, 16); #endif /* #ifdef OPTION_KIMD_DEBUG */ /* XOR and multiply */ for(i = 0; i < 16; i++) parameter_block[i] ^= message_block[i]; gcm_gf_mult(parameter_block, ¶meter_block[16], parameter_block); /* Store the output chaining value */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KIMD_DEBUG LOGBYTE("ocv :", parameter_block, 16); #endif /* #ifdef OPTION_KIMD_DEBUG */ /* Update the registers */ SET_GR_A(r2, regs, GR_A(r2, regs) + 16); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 16); #ifdef OPTION_KIMD_DEBUG logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KIMD_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ /*----------------------------------------------------------------------------*/ /* Compute last message digest (KLMD) FC 1-3 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(klmd_sha)(int r1, int r2, REGS *regs) { sha1_context sha1_ctx; #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 sha256_context sha256_ctx; #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 sha512_context sha512_ctx; #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ int fc; int i; int mbllen = 0; BYTE message_block[128]; int message_blocklen = 0; BYTE parameter_block[80]; int parameter_blocklen = 0; UNREFERENCED(r1); /* Initialize values */ fc = GR0_fc(regs); switch(fc) { case 1: /* sha-1 */ { mbllen = 8; message_blocklen = 64; parameter_blocklen = 20; break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { mbllen = 8; message_blocklen = 64; parameter_blocklen = 32; break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { mbllen = 16; message_blocklen = 128; parameter_blocklen = 64; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ } /* Process intermediate message blocks */ if(unlikely(GR_A(r2 + 1, regs) >= (unsigned) message_blocklen)) { ARCH_DEP(kimd_sha)(r1, r2, regs, 1); if(regs->psw.cc == 3) return; } /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, parameter_blocklen - 1, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen + mbllen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KLMD_DEBUG if(parameter_blocklen > 32) { LOGBYTE2("icv :", parameter_block, 16, parameter_blocklen / 16); } else { LOGBYTE("icv :", parameter_block, parameter_blocklen); } LOGBYTE("mbl :", ¶meter_block[parameter_blocklen], mbllen); #endif /* #ifdef OPTION_KLMD_DEBUG */ /* Set initial chaining value */ switch(fc) { case 1: /* sha-1 */ { sha1_seticv(&sha1_ctx, parameter_block); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { sha256_seticv(&sha256_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { sha512_seticv(&sha512_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ } /* Fetch and process possible last block of data */ if(likely(GR_A(r2 + 1, regs))) { ARCH_DEP(vfetchc)(message_block, GR_A(r2 + 1, regs) - 1, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KLMD_DEBUG if(GR_A(r2 + 1, regs) > 32) { LOGBYTE("input :", message_block, 32); LOGBYTE(" ", &message_block[32], (int) GR_A(r2 + 1, regs) - 32); } else LOGBYTE("input :", message_block, (int) GR_A(r2 + 1, regs)); #endif /* #ifdef OPTION_KLMD_DEBUG */ } /* Do the padding */ i = GR_A(r2 + 1, regs); if(unlikely(i >= (message_blocklen - mbllen))) { message_block[i++] = 0x80; while(i < message_blocklen) message_block[i++] = 0x00; switch(fc) { case 1: /* sha-1 */ { sha1_process(&sha1_ctx, message_block); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { sha256_process(&sha256_ctx, message_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { sha512_process(&sha512_ctx, message_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ } for(i = 0; i < message_blocklen - mbllen; i++) message_block[i] = 0x00; } else { message_block[i++] = 0x80; while(i < message_blocklen - mbllen) message_block[i++] = 0x00; } /* Set the message bit length */ memcpy(&message_block[message_blocklen - mbllen], ¶meter_block[parameter_blocklen], mbllen); /* Calculate and store the message digest */ switch(fc) { case 1: /* sha-1 */ { sha1_process(&sha1_ctx, message_block); sha1_getcv(&sha1_ctx, parameter_block); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { sha256_process(&sha256_ctx, message_block); sha256_getcv(&sha256_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { sha512_process(&sha512_ctx, message_block); sha512_getcv(&sha512_ctx, parameter_block); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ } ARCH_DEP(vstorec)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KLMD_DEBUG if(parameter_blocklen > 32) { LOGBYTE2("md :", parameter_block, 16, parameter_blocklen / 16); } else { LOGBYTE("md :", parameter_block, parameter_blocklen); } #endif /* #ifdef OPTION_KLMD_DEBUG */ /* Update registers */ SET_GR_A(r2, regs, GR_A(r2, regs) + GR_A(r2 + 1, regs)); SET_GR_A(r2 + 1, regs, 0); #ifdef OPTION_KLMD_DEBUG logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KLMD_DEBUG */ /* Set condition code */ regs->psw.cc = 0; } /*----------------------------------------------------------------------------*/ /* Cipher message (KM) FC 1-3 and 9-11 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(km_dea)(int r1, int r2, REGS *regs) { int crypted; des_context des_ctx; des3_context des3_ctx; int keylen; BYTE message_block[8]; int modifier_bit; BYTE parameter_block[48]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 8)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = tfc * 8; parameter_blocklen = keylen; if(wrap) parameter_blocklen += 24; /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KM_DEBUG switch(tfc) { case 1: /* dea */ { LOGBYTE("k :", parameter_block, 8); break; } case 2: /* tdea-128 */ { LOGBYTE("k1 :", parameter_block, 8); LOGBYTE("k2 :", ¶meter_block[8], 8); break; } case 3: /* tdea-192 */ { LOGBYTE("k1 :", parameter_block, 8); LOGBYTE("k2 :", ¶meter_block[8], 8); LOGBYTE("k3 :", ¶meter_block[16], 8); break; } } if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen], 24); #endif /* #ifdef OPTION_KM_DEBUG */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /* Verify and unwrap */ if(wrap && unwrap_dea(parameter_block, keylen)) { #ifdef OPTION_KM_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KM_DEBUG */ regs->psw.cc = 1; return; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ /* Set the cryptographic key */ switch(tfc) { case 1: /* dea */ { des_set_key(&des_ctx, parameter_block); break; } case 2: /* tdea-128 */ { des3_set_2keys(&des3_ctx, parameter_block, ¶meter_block[8]); break; } case 3: /* tdea-192 */ { des3_set_3keys(&des3_ctx, parameter_block, ¶meter_block[8], ¶meter_block[16]); break; } } /* Try to process the CPU-determined amount of data */ modifier_bit = GR0_m(regs); r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 8) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 7, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("input :", message_block, 8); #endif /* #ifdef OPTION_KM_DEBUG */ /* Do the job */ switch(tfc) { case 1: /* dea */ { if(modifier_bit) des_decrypt(&des_ctx, message_block, message_block); else des_encrypt(&des_ctx, message_block, message_block); break; } case 2: /* tdea-128 */ case 3: /* tdea-192 */ { if(modifier_bit) des3_decrypt(&des3_ctx, message_block, message_block); else des3_encrypt(&des3_ctx, message_block, message_block); break; } } /* Store the output */ ARCH_DEP(vstorec)(message_block, 7, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("output:", message_block, 8); #endif /* #ifdef OPTION_KM_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 8); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 8); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 8); #ifdef OPTION_KM_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KM_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 /*----------------------------------------------------------------------------*/ /* Cipher message (KM) FC 18-20 and 26-28 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(km_aes)(int r1, int r2, REGS *regs) { aes_context context; int crypted; int keylen; BYTE message_block[16]; int modifier_bit; BYTE parameter_block[64]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 16)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 17) * 8 + 8; parameter_blocklen = keylen; if(wrap) parameter_blocklen += 32; /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("k :", parameter_block, keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen], 32); #endif /* #ifdef OPTION_KM_DEBUG */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /* Verify and unwrap */ if(wrap && unwrap_aes(parameter_block, keylen)) { #ifdef OPTION_KM_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KM_DEBUG */ regs->psw.cc = 1; return; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ /* Set the cryptographic keys */ aes_set_key(&context, parameter_block, keylen * 8); /* Try to process the CPU-determined amount of data */ modifier_bit = GR0_m(regs); r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 16) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 15, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("input :", message_block, 16); #endif /* #ifdef OPTION_KM_DEBUG */ /* Do the job */ if(modifier_bit) aes_decrypt(&context, message_block, message_block); else aes_encrypt(&context, message_block, message_block); /* Store the output */ ARCH_DEP(vstorec)(message_block, 15, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("output:", message_block, 16); #endif /* #ifdef OPTION_KM_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 16); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 16); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 16); #ifdef OPTION_KM_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KM_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* Cipher message (KM) FC 50, 52, 58 and 60 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(km_xts_aes)(int r1, int r2, REGS *regs) { aes_context context; int crypted; int i; int keylen; BYTE message_block[16]; int modifier_bit; BYTE parameter_block[80]; int parameter_blocklen; int r1_is_not_r2; int tfc; BYTE two[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }; int wrap; BYTE *xts; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 16)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 49) * 8 + 8; parameter_blocklen = keylen + 16; if(wrap) parameter_blocklen += 32; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)((GR_A(1, regs) + parameter_blocklen - 16) & ADDRESS_MAXWRAP(regs), 1, 15, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); xts = ¶meter_block[parameter_blocklen - 16]; #ifdef OPTION_KM_DEBUG LOGBYTE("k :", parameter_block, keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen], 32); LOGBYTE("xts :", xts, 16); #endif /* #ifdef OPTION_KM_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_aes(parameter_block, keylen)) { #ifdef OPTION_KM_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KM_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic keys */ aes_set_key(&context, parameter_block, keylen * 8); /* Try to process the CPU-determined amount of data */ modifier_bit = GR0_m(regs); r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 16) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 15, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("input :", message_block, 16); #endif /* #ifdef OPTION_KM_DEBUG */ /* XOR, decrypt/encrypt and XOR again*/ for(i = 0; i < 16; i++) message_block[i] ^= parameter_block[parameter_blocklen - 16 + i]; if(modifier_bit) aes_decrypt(&context, message_block, message_block); else aes_encrypt(&context, message_block, message_block); for(i = 0; i < 16; i++) message_block[i] ^= parameter_block[parameter_blocklen - 16 + i]; /* Calculate output XTS */ gcm_gf_mult(xts, two, xts); /* Store the output and XTS */ ARCH_DEP(vstorec)(message_block, 15, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); ARCH_DEP(vstorec)(xts, 15, (GR_A(1, regs) + parameter_blocklen - 16) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("output:", message_block, 16); LOGBYTE("xts :", xts, 16); #endif /* #ifdef OPTION_KM_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 16); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 16); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 16); #ifdef OPTION_KM_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KM_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ /*----------------------------------------------------------------------------*/ /* Compute message authentication code (KMAC) FC 1-3 and 9-11 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmac_dea)(int r1, int r2, REGS *regs) { des_context context1; des_context context2; des_context context3; int crypted; int i; int keylen; BYTE message_block[8]; BYTE parameter_block[56]; int parameter_blocklen; int tfc; int wrap; UNREFERENCED(r1); /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 8)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = tfc * 8; parameter_blocklen = keylen + 8; if(wrap) parameter_blocklen += 24; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 7, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMAC_DEBUG LOGBYTE("icv :", parameter_block, 8); switch(tfc) { case 1: /* dea */ { LOGBYTE("k1 :", ¶meter_block[8], 8); break; } case 2: /* tdea-128 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); break; } case 3: /* tdea-192 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); LOGBYTE("k3 :", ¶meter_block[24], 8); break; } } if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 8], 24); #endif /* #ifdef OPTION_KMAC_DEBUG */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /* Verify and unwrap */ if(wrap && unwrap_dea(¶meter_block[8], keylen)) { #ifdef OPTION_KM_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KM_DEBUG */ regs->psw.cc = 1; return; } #endif /* #ifdef #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ /* Set the cryptographic key */ switch(tfc) { case 1: /* dea */ { des_set_key(&context1, ¶meter_block[8]); break; } case 2: /* tdea-128 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); break; } case 3: /* tdea-192 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); des_set_key(&context3, ¶meter_block[24]); break; } } /* Try to process the CPU-determined amount of data */ for(crypted = 0; crypted < PROCESS_MAX; crypted += 8) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 7, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMAC_DEBUG LOGBYTE("input :", message_block, 8); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* XOR the message with chaining value */ for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; /* Calculate the output chaining value */ switch(tfc) { case 1: /* dea */ { des_encrypt(&context1, message_block, parameter_block); break; } case 2: /* tdea-128 */ { des_encrypt(&context1, message_block, parameter_block); des_decrypt(&context2, parameter_block, parameter_block); des_encrypt(&context1, parameter_block, parameter_block); break; } case 3: /* tdea-192 */ { des_encrypt(&context1, message_block, parameter_block); des_decrypt(&context2, parameter_block, parameter_block); des_encrypt(&context3, parameter_block, parameter_block); break; } } /* Store the output chaining value */ ARCH_DEP(vstorec)(parameter_block, 7, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMAC_DEBUG LOGBYTE("ocv :", parameter_block, 8); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* Update the registers */ SET_GR_A(r2, regs, GR_A(r2, regs) + 8); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 8); #ifdef OPTION_KMAC_DEBUG logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* Compute message authentication code (KMAC) FC 18-20 and 26-28 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmac_aes)(int r1, int r2, REGS *regs) { aes_context context; int crypted; int i; int keylen; BYTE message_block[16]; BYTE parameter_block[80]; int parameter_blocklen; int tfc; int wrap; UNREFERENCED(r1); /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 16)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 17) * 8 + 8; parameter_blocklen = keylen + 16; if(wrap) parameter_blocklen += 32; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 15, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMAC_DEBUG LOGBYTE("icv :", parameter_block, 16); LOGBYTE("k :", ¶meter_block[16], keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 16], 32); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_aes(¶meter_block[16], keylen)) { #ifdef OPTION_KMAC_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMAC_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ aes_set_key(&context, ¶meter_block[16], keylen * 8); /* Try to process the CPU-determined amount of data */ for(crypted = 0; crypted < PROCESS_MAX; crypted += 16) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 15, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMAC_DEBUG LOGBYTE("input :", message_block, 16); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* XOR the message with chaining value */ for(i = 0; i < 16; i++) message_block[i] ^= parameter_block[i]; /* Calculate the output chaining value */ aes_encrypt(&context, message_block, parameter_block); /* Store the output chaining value */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMAC_DEBUG LOGBYTE("ocv :", parameter_block, 16); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* Update the registers */ SET_GR_A(r2, regs, GR_A(r2, regs) + 16); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 16); #ifdef OPTION_KMAC_DEBUG logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ /*----------------------------------------------------------------------------*/ /* Cipher message with chaining (KMC) FC 1-3 and 9-11 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmc_dea)(int r1, int r2, REGS *regs) { des_context context1; des_context context2; des_context context3; int crypted; int i; int keylen; BYTE message_block[8]; int modifier_bit; BYTE ocv[8]; BYTE parameter_block[56]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 8)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = tfc * 8; parameter_blocklen = keylen + 8; if(wrap) parameter_blocklen += 24; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 7, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("icv :", parameter_block, 8); switch(tfc) { case 1: /* dea */ { LOGBYTE("k :", ¶meter_block[8], 8); break; } case 2: /* tdea-128 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); break; } case 3: /* tdea-192 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); LOGBYTE("k3 :", ¶meter_block[24], 8); break; } } if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 8], 24); #endif /* #ifdef OPTION_KMC_DEBUG */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /* Verify and unwrap */ if(wrap && unwrap_dea(¶meter_block[8], keylen)) { #ifdef OPTION_KMC_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMC_DEBUG */ regs->psw.cc = 1; return; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ /* Set the cryptographic key */ switch(tfc) { case 1: /* dea */ { des_set_key(&context1, ¶meter_block[8]); break; } case 2: /* tdea-128 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); break; } case 3: /* tdea-192 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); des_set_key(&context3, ¶meter_block[24]); break; } } /* Try to process the CPU-determined amount of data */ modifier_bit = GR0_m(regs); r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 8) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 7, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("input :", message_block, 8); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Do the job */ switch(tfc) { case 1: /* dea */ { if(modifier_bit) { /* Save, decrypt and XOR */ memcpy(ocv, message_block, 8); des_decrypt(&context1, message_block, message_block); for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; } else { /* XOR, encrypt and save */ for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; des_encrypt(&context1, message_block, message_block); memcpy(ocv, message_block, 8); } break; } case 2: /* tdea-128 */ { if(modifier_bit) { /* Save, decrypt and XOR */ memcpy(ocv, message_block, 8); des_decrypt(&context1, message_block, message_block); des_encrypt(&context2, message_block, message_block); des_decrypt(&context1, message_block, message_block); for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; } else { /* XOR, encrypt and save */ for(i = 0 ; i < 8; i++) message_block[i] ^= parameter_block[i]; des_encrypt(&context1, message_block, message_block); des_decrypt(&context2, message_block, message_block); des_encrypt(&context1, message_block, message_block); memcpy(ocv, message_block, 8); } break; } case 3: /* tdea-192 */ { if(modifier_bit) { /* Save, decrypt and XOR */ memcpy(ocv, message_block, 8); des_decrypt(&context3, message_block, message_block); des_encrypt(&context2, message_block, message_block); des_decrypt(&context1, message_block, message_block); for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; } else { /* XOR, encrypt and save */ for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; des_encrypt(&context1, message_block, message_block); des_decrypt(&context2, message_block, message_block); des_encrypt(&context3, message_block, message_block); memcpy(ocv, message_block, 8); } break; } } /* Store the output */ ARCH_DEP(vstorec)(message_block, 7, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("output:", message_block, 8); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Store the output chaining value */ ARCH_DEP(vstorec)(ocv, 7, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("ocv :", ocv, 8); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 8); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 8); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 8); #ifdef OPTION_KMC_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMC_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Set cv for next 8 bytes */ memcpy(parameter_block, ocv, 8); } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 /*----------------------------------------------------------------------------*/ /* Cipher message with chaining (KMC) FC 18-20 and 26-28 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmc_aes)(int r1, int r2, REGS *regs) { aes_context context; int crypted; int i; int keylen; BYTE message_block[16]; int modifier_bit; BYTE ocv[16]; BYTE parameter_block[80]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 16)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 17) * 8 + 8; parameter_blocklen = keylen + 16; if(wrap) parameter_blocklen += 32; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 15, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("icv :", parameter_block, 16); LOGBYTE("k :", ¶meter_block[16], keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 16], 32); #endif /* #ifdef OPTION_KMC_DEBUG */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /* Verify and unwrap */ if(wrap && unwrap_aes(¶meter_block[16], keylen)) { #ifdef OPTION_KM_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMC_DEBUG */ regs->psw.cc = 1; return; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ /* Set the cryptographic key */ aes_set_key(&context, ¶meter_block[16], keylen * 8); /* Try to process the CPU-determined amount of data */ modifier_bit = GR0_m(regs); r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 16) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 15, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("input :", message_block, 16); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Do the job */ if(modifier_bit) { /* Save, decrypt and XOR */ memcpy(ocv, message_block, 16); aes_decrypt(&context, message_block, message_block); for(i = 0; i < 16; i++) message_block[i] ^= parameter_block[i]; } else { /* XOR, encrypt and save */ for(i = 0; i < 16; i++) message_block[i] ^= parameter_block[i]; aes_encrypt(&context, message_block, message_block); memcpy(ocv, message_block, 16); } /* Store the output */ ARCH_DEP(vstorec)(message_block, 15, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("output:", message_block, 16); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Store the output chaining value */ ARCH_DEP(vstorec)(ocv, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("ocv :", ocv, 16); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 16); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 16); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 16); #ifdef OPTION_KMC_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMC_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Set cv for next 16 bytes */ memcpy(parameter_block, ocv, 16); } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 /*----------------------------------------------------------------------------*/ /* Cipher message with chaining (KMC) FC 67 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmc_prng)(int r1, int r2, REGS *regs) { des_context context1; des_context context2; des_context context3; int i; int crypted; BYTE message_block[8]; BYTE parameter_block[32]; BYTE ocv[8]; BYTE tcv[8]; int r1_is_not_r2; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 8)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 7, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, 31, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("icv :", parameter_block, 8); LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); LOGBYTE("k3 :", ¶meter_block[24], 8); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Set the cryptographic keys */ des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); des_set_key(&context3, ¶meter_block[24]); /* Try to process the CPU-determined amount of data */ r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 8) { /* Fetch a block of data */ ARCH_DEP(vfetchc)(message_block, 7, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("input :", message_block, 8); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Do the job */ des_encrypt(&context1, message_block, message_block); des_decrypt(&context2, message_block, message_block); des_encrypt(&context3, message_block, message_block); /* Save the temporary cv */ memcpy(tcv, message_block, 8); /* XOR */ for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; des_encrypt(&context1, message_block, message_block); des_decrypt(&context2, message_block, message_block); des_encrypt(&context3, message_block, message_block); /* Store the output */ ARCH_DEP(vstorec)(message_block, 7, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("output:", message_block, 8); #endif /* #ifdef OPTION_KMC_DEBUG */ /* XOR */ for(i = 0; i < 8; i++) message_block[i] ^= tcv[i]; des_encrypt(&context1, message_block, message_block); des_decrypt(&context2, message_block, message_block); des_encrypt(&context3, message_block, message_block); /* Save the ocv */ memcpy(ocv, message_block, 8); /* Store the output chaining value */ ARCH_DEP(vstorec)(ocv, 7, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("ocv :", ocv, 8); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 8); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 8); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 8); #ifdef OPTION_KMC_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMC_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Set cv for next 8 bytes */ memcpy(parameter_block, ocv, 8); } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* Cipher message with counter (KMCTR) FC 1-3 and 9-11 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmctr_dea)(int r1, int r2, int r3, REGS *regs) { des_context context1; des_context context2; des_context context3; BYTE countervalue_block[8]; int crypted; int i; int keylen; BYTE message_block[8]; BYTE parameter_block[48]; int parameter_blocklen; int r1_is_not_r2; int r1_is_not_r3; int r2_is_not_r3; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 8)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = tfc * 8; parameter_blocklen = keylen; if(wrap) parameter_blocklen += 24; /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMCTR_DEBUG switch(tfc) { case 1: /* dea */ { LOGBYTE("k :", parameter_block, 8); break; } case 2: /* tdea-128 */ { LOGBYTE("k1 :", parameter_block, 8); LOGBYTE("k2 :", ¶meter_block[8], 8); break; } case 3: /* tdea-192 */ { LOGBYTE("k1 :", parameter_block, 8); LOGBYTE("k2 :", ¶meter_block[8], 8); LOGBYTE("k3 :", ¶meter_block[16], 8); break; } } if(wrap) LOGBYTE("wkvp :", ¶meter_block[parameter_blocklen - 24], 24); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_dea(parameter_block, keylen)) { #ifdef OPTION_KMCTR_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMCTR_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ switch(tfc) { case 1: /* dea */ { des_set_key(&context1, parameter_block); break; } case 2: /* tdea-128 */ { des_set_key(&context1, parameter_block); des_set_key(&context2, ¶meter_block[8]); break; } case 3: /* tdea-192 */ { des_set_key(&context1, parameter_block); des_set_key(&context2, ¶meter_block[8]); des_set_key(&context3, ¶meter_block[16]); break; } } /* Try to process the CPU-determined amount of data */ r1_is_not_r2 = r1 != r2; r1_is_not_r3 = r1 != r3; r2_is_not_r3 = r2 != r3; for(crypted = 0; crypted < PROCESS_MAX; crypted += 8) { /* Fetch a block of data and counter-value */ ARCH_DEP(vfetchc)(message_block, 7, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); ARCH_DEP(vfetchc)(countervalue_block, 7, GR_A(r3, regs) & ADDRESS_MAXWRAP(regs), r3, regs); #ifdef OPTION_KMCTR_DEBUG LOGBYTE("input :", message_block, 8); LOGBYTE("cv :", countervalue_block, 8); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* Do the job */ switch(tfc) { /* Encrypt */ case 1: /* dea */ { des_encrypt(&context1, countervalue_block, countervalue_block); break; } case 2: /* tdea-128 */ { des_encrypt(&context1, countervalue_block, countervalue_block); des_decrypt(&context2, countervalue_block, countervalue_block); des_encrypt(&context1, countervalue_block, countervalue_block); break; } case 3: /* tdea-192 */ { des_encrypt(&context1, countervalue_block, countervalue_block); des_decrypt(&context2, countervalue_block, countervalue_block); des_encrypt(&context3, countervalue_block, countervalue_block); break; } } /* XOR */ for(i = 0; i < 8; i++) countervalue_block[i] ^= message_block[i]; /* Store the output */ ARCH_DEP(vstorec)(countervalue_block, 7, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMCTR_DEBUG LOGBYTE("output:", countervalue_block, 8); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 8); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 8); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 8); if(likely(r1_is_not_r3 && r2_is_not_r3)) SET_GR_A(r3, regs, GR_A(r3, regs) + 8); #ifdef OPTION_KMCTR_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); logmsg(" GR%02d : " F_GREG "\n", r3, (regs)->GR(r3)); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } /*----------------------------------------------------------------------------*/ /* Cipher message with counter (KMCTR) FC 18-20 and 26-28 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmctr_aes)(int r1, int r2, int r3, REGS *regs) { aes_context context; BYTE countervalue_block[16]; int crypted; int i; int keylen; BYTE message_block[16]; BYTE parameter_block[48]; int parameter_blocklen; int r1_is_not_r2; int r1_is_not_r3; int r2_is_not_r3; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 16)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 17) * 8 + 8; parameter_blocklen = keylen; if(wrap) parameter_blocklen += 32; /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMCTR_DEBUG LOGBYTE("k :", parameter_block, keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[parameter_blocklen - 32], 32); #endif /* #ifdef OPTION_KMCTR_DEBUG */ if(wrap && unwrap_aes(parameter_block, keylen)) { #ifdef OPTION_KMCTR_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMCTR_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ aes_set_key(&context, parameter_block, keylen * 8); /* Try to process the CPU-determined amount of data */ r1_is_not_r2 = r1 != r2; r1_is_not_r3 = r1 != r3; r2_is_not_r3 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 16) { /* Fetch a block of data and counter-value */ ARCH_DEP(vfetchc)(message_block, 15, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); ARCH_DEP(vfetchc)(countervalue_block, 15, GR_A(r3, regs) & ADDRESS_MAXWRAP(regs), r3, regs); #ifdef OPTION_KMCTR_DEBUG LOGBYTE("input :", message_block, 16); LOGBYTE("cv :", countervalue_block, 16); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* Do the job */ /* Encrypt and XOR */ aes_encrypt(&context, countervalue_block, countervalue_block); for(i = 0; i < 16; i++) countervalue_block[i] ^= message_block[i]; /* Store the output */ ARCH_DEP(vstorec)(countervalue_block, 15, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMCTR_DEBUG LOGBYTE("output:", countervalue_block, 16); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 16); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 16); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 16); if(likely(r1_is_not_r3 && r2_is_not_r3)) SET_GR_A(r3, regs, GR_A(r3, regs) + 16); #ifdef OPTION_KMCTR_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); logmsg(" GR%02d : " F_GREG "\n", r3, (regs)->GR(r3)); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } /*----------------------------------------------------------------------------*/ /* Cipher message with cipher feedback (KMF) FC 1-3 and 9-11 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmf_dea)(int r1, int r2, REGS *regs) { des_context context1; des_context context2; des_context context3; int crypted; int i; int keylen; int lcfb; BYTE message_block[8]; int modifier_bit; BYTE output_block[8]; BYTE parameter_block[56]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Initialize values */ lcfb = GR0_lcfb(regs); /* Check special conditions */ if(unlikely(!lcfb || lcfb > 8 || GR_A(r2 + 1, regs) % lcfb)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = tfc * 8; parameter_blocklen = keylen + 8; if(wrap) parameter_blocklen += 24; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 7, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("cv :", parameter_block, 8); switch(tfc) { case 1: /* dea */ { LOGBYTE("k :", ¶meter_block[8], 8); break; } case 2: /* tdea-128 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); break; } case 3: /* tdea-192 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); LOGBYTE("k3 :", ¶meter_block[24], 8); break; } } if(wrap) LOGBYTE("wkvp :", ¶meter_block[parameter_blocklen - 24], 24); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_dea(¶meter_block[8], keylen)) { #ifdef OPTION_KMF_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMF_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ switch(tfc) { case 1: /* dea */ { des_set_key(&context1, ¶meter_block[8]); break; } case 2: /* tdea-128 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); break; } case 3: /* tdea-192 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); des_set_key(&context3, ¶meter_block[24]); break; } } /* Try to process the CPU-determined amount of data */ modifier_bit = GR0_m(regs); r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += lcfb) { /* Do the job */ switch(tfc) { case 1: /* dea */ { des_encrypt(&context1, parameter_block, output_block); break; } case 2: /* tdea-128 */ { des_encrypt(&context1, parameter_block, output_block); des_decrypt(&context2, output_block, output_block); des_encrypt(&context1, output_block, output_block); break; } case 3: /* tdea-192 */ { des_encrypt(&context1, parameter_block, output_block); des_decrypt(&context2, output_block, output_block); des_encrypt(&context3, output_block, output_block); break; } } ARCH_DEP(vfetchc)(message_block, lcfb - 1, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("input :", message_block, lcfb); #endif /* #ifdef OPTION_KMF_DEBUG */ for(i = 0; i < lcfb; i++) output_block[i] ^= message_block[i]; for(i = 0; i < 8 - lcfb; i++) parameter_block[i] = parameter_block[i + lcfb]; if(modifier_bit) { /* Decipher */ for(i = 0; i < lcfb; i++) parameter_block[i + 8 - lcfb] = message_block[i]; } else { /* Encipher */ for(i = 0; i < lcfb; i++) parameter_block[i + 8 - lcfb] = output_block[i]; } /* Store the output */ ARCH_DEP(vstorec)(output_block, lcfb - 1, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("output:", output_block, lcfb); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Store the chaining value */ ARCH_DEP(vstorec)(parameter_block, 7, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("cv :", parameter_block, 8); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + lcfb); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + lcfb); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - lcfb); #ifdef OPTION_KMF_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMF_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } /*----------------------------------------------------------------------------*/ /* Cipher message with cipher feedback (KMF) FC 18-20 and 26-28 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmf_aes)(int r1, int r2, REGS *regs) { aes_context context; int crypted; int i; int keylen; int lcfb; BYTE message_block[16]; int modifier_bit; BYTE output_block[16]; BYTE parameter_block[80]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Initialize values */ lcfb = GR0_lcfb(regs); /* Check special conditions */ if(unlikely(!lcfb || lcfb > 16 || GR_A(r2 + 1, regs) % lcfb)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 17) * 8 + 8; parameter_blocklen = keylen + 16; if(wrap) parameter_blocklen += 32; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 15, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("cv :", parameter_block, 16); LOGBYTE("k :", ¶meter_block[16], keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[parameter_blocklen - 32], 32); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_aes(¶meter_block[16], keylen)) { #ifdef OPTION_KMF_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMF_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ aes_set_key(&context, ¶meter_block[16], keylen * 8); /* Try to process the CPU-determined amount of data */ modifier_bit = GR0_m(regs); r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += lcfb) { aes_encrypt(&context, parameter_block, output_block); ARCH_DEP(vfetchc)(message_block, lcfb - 1, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("input :", message_block, lcfb); #endif /* #ifdef OPTION_KMF_DEBUG */ for(i = 0; i < lcfb; i++) output_block[i] ^= message_block[i]; for(i = 0; i < 16 - lcfb; i++) parameter_block[i] = parameter_block[i + lcfb]; if(modifier_bit) { /* Decipher */ for(i = 0; i < lcfb; i++) parameter_block[i + 16 - lcfb] = message_block[i]; } else { /* Encipher */ for(i = 0; i < lcfb; i++) parameter_block[i + 16 - lcfb] = output_block[i]; } /* Store the output */ ARCH_DEP(vstorec)(output_block, lcfb - 1, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("output:", output_block, lcfb); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Store the chaining value */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("cv :", parameter_block, 16); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + lcfb); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + lcfb); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - lcfb); #ifdef OPTION_KMF_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMF_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } /*----------------------------------------------------------------------------*/ /* Cipher message with output feedback (KMO) FC 1-3 and 9-11 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmo_dea)(int r1, int r2, REGS *regs) { des_context context1; des_context context2; des_context context3; int crypted; int i; int keylen; BYTE message_block[8]; BYTE parameter_block[56]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 8)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = tfc * 8; parameter_blocklen = keylen + 8; if(wrap) parameter_blocklen += 24; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 7, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("cv :", parameter_block, 8); switch(tfc) { case 1: /* dea */ { LOGBYTE("k :", ¶meter_block[8], 8); break; } case 2: /* tdea-128 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); break; } case 3: /* tdea-192 */ { LOGBYTE("k1 :", ¶meter_block[8], 8); LOGBYTE("k2 :", ¶meter_block[16], 8); LOGBYTE("k3 :", ¶meter_block[24], 8); break; } } if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 8], 24); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_dea(¶meter_block[8], keylen)) { #ifdef OPTION_KMO_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMO_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ switch(tfc) { case 1: /* dea */ { des_set_key(&context1, ¶meter_block[8]); break; } case 2: /* tdea-128 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); break; } case 3: /* tdea-192 */ { des_set_key(&context1, ¶meter_block[8]); des_set_key(&context2, ¶meter_block[16]); des_set_key(&context3, ¶meter_block[24]); break; } } /* Try to process the CPU-determined amount of data */ r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 8) { /* Do the job */ switch(tfc) { case 1: /* dea */ { des_encrypt(&context1, parameter_block, parameter_block); break; } case 2: /* tdea-128 */ { des_encrypt(&context1, parameter_block, parameter_block); des_decrypt(&context2, parameter_block, parameter_block); des_encrypt(&context1, parameter_block, parameter_block); break; } case 3: /* tdea-192 */ { des_encrypt(&context1, parameter_block, parameter_block); des_decrypt(&context2, parameter_block, parameter_block); des_encrypt(&context3, parameter_block, parameter_block); break; } } ARCH_DEP(vfetchc)(message_block, 7, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("input :", message_block, 8); #endif /* #ifdef OPTION_KMO_DEBUG */ for(i = 0; i < 8; i++) message_block[i] ^= parameter_block[i]; /* Store the output */ ARCH_DEP(vstorec)(message_block, 7, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("output:", message_block, 8); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Store the chaining value */ ARCH_DEP(vstorec)(parameter_block, 7, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("cv :", parameter_block, 8); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 8); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 8); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 8); #ifdef OPTION_KMO_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMO_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } /*----------------------------------------------------------------------------*/ /* Cipher message with output feedback (KMO) FC 18-20 and 26-28 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(kmo_aes)(int r1, int r2, REGS *regs) { aes_context context; int crypted; int i; int keylen; BYTE message_block[16]; BYTE parameter_block[80]; int parameter_blocklen; int r1_is_not_r2; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR_A(r2 + 1, regs) % 16)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Return with cc 0 on zero length */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 17) * 8 + 8; parameter_blocklen = keylen + 16; if(wrap) parameter_blocklen += 32; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, 15, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("cv :", parameter_block, 16); LOGBYTE("k :", ¶meter_block[16], keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 16], 32); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_aes(¶meter_block[16], keylen)) { #ifdef OPTION_KMO_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_KMO_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ aes_set_key(&context, ¶meter_block[16], keylen * 8); /* Try to process the CPU-determined amount of data */ r1_is_not_r2 = r1 != r2; for(crypted = 0; crypted < PROCESS_MAX; crypted += 16) { aes_encrypt(&context, parameter_block, parameter_block); ARCH_DEP(vfetchc)(message_block, 15, GR_A(r2, regs) & ADDRESS_MAXWRAP(regs), r2, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("input :", message_block, 16); #endif /* #ifdef OPTION_KMO_DEBUG */ for(i = 0; i < 16; i++) message_block[i] ^= parameter_block[i]; /* Store the output */ ARCH_DEP(vstorec)(message_block, 15, GR_A(r1, regs) & ADDRESS_MAXWRAP(regs), r1, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("output:", message_block, 16); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Store the chaining value */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("cv :", parameter_block, 16); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Update the registers */ SET_GR_A(r1, regs, GR_A(r1, regs) + 16); if(likely(r1_is_not_r2)) SET_GR_A(r2, regs, GR_A(r2, regs) + 16); SET_GR_A(r2 + 1, regs, GR_A(r2 + 1, regs) - 16); #ifdef OPTION_KMO_DEBUG logmsg(" GR%02d : " F_GREG "\n", r1, (regs)->GR(r1)); logmsg(" GR%02d : " F_GREG "\n", r2, (regs)->GR(r2)); logmsg(" GR%02d : " F_GREG "\n", r2 + 1, (regs)->GR(r2 + 1)); #endif /* #ifdef OPTION_KMO_DEBUG */ /* check for end of data */ if(unlikely(!GR_A(r2 + 1, regs))) { regs->psw.cc = 0; return; } } /* CPU-determined amount of data processed */ regs->psw.cc = 3; } /*----------------------------------------------------------------------------*/ /* Perform cryptographic computation (PCC) FC 1-3 and 9-11 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(pcc_cmac_dea)(REGS *regs) { des_context context1; des_context context2; des_context context3; int i; BYTE k[8]; int keylen; BYTE mask[8] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; BYTE parameter_block[72]; int parameter_blocklen; BYTE r64[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b }; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = tfc * 8; parameter_blocklen = keylen + 24; if(wrap) parameter_blocklen += 24; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)((GR_A(1, regs) + 16) & ADDRESS_MAXWRAP(regs), 1, 7, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCC_DEBUG LOGBYTE("ml :", parameter_block, 1); LOGBYTE("msg :", ¶meter_block[8], 8); LOGBYTE("icv :", ¶meter_block[16], 8); switch(tfc) { case 1: /* dea */ { LOGBYTE("k :", ¶meter_block[24], 8); break; } case 2: /* tdea-128 */ { LOGBYTE("k1 :", ¶meter_block[24], 8); LOGBYTE("k2 :", ¶meter_block[32], 8); break; } case 3: /* tdea-192 */ { LOGBYTE("k1 :", ¶meter_block[24], 8); LOGBYTE("k2 :", ¶meter_block[32], 8); LOGBYTE("k3 :", ¶meter_block[40], 8); break; } } if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 24], 24); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_dea(¶meter_block[24], keylen)) { #ifdef OPTION_PCC_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_PCC_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ switch(tfc) { case 1: /* dea */ { des_set_key(&context1, ¶meter_block[24]); break; } case 2: /* tdea-128 */ { des_set_key(&context1, ¶meter_block[24]); des_set_key(&context2, ¶meter_block[32]); break; } case 3: /* tdea-192 */ { des_set_key(&context1, ¶meter_block[24]); des_set_key(&context2, ¶meter_block[32]); des_set_key(&context3, ¶meter_block[40]); break; } } /* Check validity ML value */ if(parameter_block[0] > 64) { regs->psw.cc = 2; return; } /* Place the one bit */ if(parameter_block[0] != 64) parameter_block[(parameter_block[0] / 8) + 8] |= (0x80 >> (parameter_block[0] % 8)); /* Pad with zeroes */ if(parameter_block[0] < 63) { parameter_block[(parameter_block[0] / 8) + 8] &= mask[parameter_block[0] % 8]; for(i = (parameter_block[0] / 8) + 1; i < 8; i++) parameter_block[i + 8] = 0x00; } #ifdef OPTION_PCC_DEBUG LOGBYTE("msg :", ¶meter_block[8], 8); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Calculate subkey */ memset(k, 0, 8); switch(tfc) { case 1: /* dea */ { des_encrypt(&context1, k, k); break; } case 2: /* tdea-128 */ { des_encrypt(&context1, k, k); des_decrypt(&context2, k, k); des_encrypt(&context1, k, k); break; } case 3: /* tdea-192 */ { des_encrypt(&context1, k, k); des_decrypt(&context2, k, k); des_encrypt(&context3, k, k); break; } } /* Calculate subkeys Kx and Ky */ if(k[0] & 0x80) shift_left(k, k, 8); else { shift_left(k, k, 8); for(i = 0; i < 8; i++) k[i] ^= r64[i]; } if(parameter_block[0] != 64) { if(k[0] & 0x80) shift_left(k, k, 8); else { shift_left(k, k, 8); for(i = 0; i < 8; i++) k[i] ^= r64[i]; } } /* XOR with kx or ky and encrypt */ for(i = 0; i < 8; i++) { parameter_block[i + 8] ^= k[i]; parameter_block[i + 8] ^= parameter_block[i + 16]; } switch(tfc) { case 1: /* dea */ { des_encrypt(&context1, ¶meter_block[8], ¶meter_block[8]); break; } case 2: /* tdea-128 */ { des_encrypt(&context1, ¶meter_block[8], ¶meter_block[8]); des_decrypt(&context2, ¶meter_block[8], ¶meter_block[8]); des_encrypt(&context1, ¶meter_block[8], ¶meter_block[8]); break; } case 3: /* tdea-192 */ { des_encrypt(&context1, ¶meter_block[8], ¶meter_block[8]); des_decrypt(&context2, ¶meter_block[8], ¶meter_block[8]); des_encrypt(&context3, ¶meter_block[8], ¶meter_block[8]); break; } } #ifdef OPTION_PCC_DEBUG LOGBYTE("cmac :", ¶meter_block[8], 8); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Store the CMAC */ ARCH_DEP(vstorec)(¶meter_block[8], 7, (GR_A(1, regs) + 16) & ADDRESS_MAXWRAP(regs), 1, regs); /* Normal completion */ regs->psw.cc = 0; } /*----------------------------------------------------------------------------*/ /* Perform cryptographic computation (PCC) FC 18-20 and 26-28 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(pcc_cmac_aes)(REGS *regs) { aes_context context; int i; BYTE k[16]; int keylen; BYTE mask[8] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; BYTE parameter_block[104]; int parameter_blocklen; BYTE r128[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }; int tfc; int wrap; /* Check special conditions */ if(unlikely(GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 17) * 8 + 8; parameter_blocklen = keylen + 24; if(wrap) parameter_blocklen += 32; /* Test writeability output chaining value */ ARCH_DEP(validate_operand)((GR_A(1, regs) + 24) & ADDRESS_MAXWRAP(regs), 1, 15, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCC_DEBUG LOGBYTE("ml :", parameter_block, 1); LOGBYTE("msg :", ¶meter_block[8], 16); LOGBYTE("icv :", ¶meter_block[24], 16); LOGBYTE("k :", ¶meter_block[40], keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen + 40], 32); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_aes(¶meter_block[40], keylen)) { #ifdef OPTION_PCC_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_PCC_DEBUG */ regs->psw.cc = 1; return; } /* Set the cryptographic key */ aes_set_key(&context, ¶meter_block[40], keylen * 8); /* Check validity ML value */ if(parameter_block[0] > 128) { regs->psw.cc = 2; return; } /* Place the one bit */ if(parameter_block[0] != 128) parameter_block[(parameter_block[0] / 8) + 8] |= (0x80 >> (parameter_block[0] % 8)); /* Pad with zeroes */ if(parameter_block[0] < 127) { parameter_block[(parameter_block[0] / 8) + 8] &= mask[parameter_block[0] % 8]; for(i = (parameter_block[0] / 8) + 1; i < 16; i++) parameter_block[i + 8] = 0x00; } #ifdef OPTION_PCC_DEBUG LOGBYTE("msg :", ¶meter_block[8], 16); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Calculate subkeys */ memset(k, 0, 16); aes_encrypt(&context, k, k); /* Calculate subkeys Kx and Ky */ if(k[0] & 0x80) shift_left(k, k, 16); else { shift_left(k, k, 16); for(i = 0; i < 16; i++) k[i] ^= r128[i]; } if(parameter_block[0] != 128) { if(k[0] & 0x80) shift_left(k, k, 16); else { shift_left(k, k, 16); for(i = 0; i < 16; i++) k[i] ^= r128[i]; } } /* XOR with kx or ky and encrypt */ for(i = 0; i < 16; i++) { parameter_block[i + 8] ^= k[i]; parameter_block[i + 8] ^= parameter_block[i + 24]; } aes_encrypt(&context, ¶meter_block[8], ¶meter_block[8]); #ifdef OPTION_PCC_DEBUG LOGBYTE("cmac :", ¶meter_block[8], 16); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Store the CMAC */ ARCH_DEP(vstorec)(¶meter_block[8], 15, (GR_A(1, regs) + 24) & ADDRESS_MAXWRAP(regs), 1, regs); /* Normal completion */ regs->psw.cc = 0; } /*----------------------------------------------------------------------------*/ /* Perform cryptographic computation (PCC) FC 50, 52, 58 and 60 */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(pcc_xts_aes)(REGS *regs) { BYTE *bsn; aes_context context; BYTE *ibi; int keylen; BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; BYTE parameter_block[104]; int parameter_blocklen; int tfc; BYTE *tweak; int wrap; BYTE *xts; BYTE zero[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* Check special conditions */ if(unlikely(GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Initialize values */ tfc = GR0_tfc(regs); wrap = GR0_wrap(regs); keylen = (tfc - 49) * 8 + 8; parameter_blocklen = keylen + 64; if(wrap) parameter_blocklen += 32; /* Test writeability XTS parameter */ ARCH_DEP(validate_operand)((GR_A(1, regs) + parameter_blocklen - 16) & ADDRESS_MAXWRAP(regs), 1, 31, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); tweak = ¶meter_block[parameter_blocklen - 64]; bsn = ¶meter_block[parameter_blocklen - 48]; ibi = ¶meter_block[parameter_blocklen - 32]; xts = ¶meter_block[parameter_blocklen - 16]; #ifdef OPTION_PCC_DEBUG LOGBYTE("k :", parameter_block, keylen); if(wrap) LOGBYTE("wkvp :", ¶meter_block[keylen], 32); LOGBYTE("tweak :", tweak, 16); LOGBYTE("bsn :", bsn, 16); LOGBYTE("ibi :", ibi, 16); LOGBYTE("xts :", xts, 16); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Verify and unwrap */ if(wrap && unwrap_aes(parameter_block, keylen)) { #ifdef OPTION_PCC_DEBUG logmsg("Wrapping Verification Pattern does not match, return with cc1\n"); #endif /* #ifdef OPTION_PCC_DEBUG */ regs->psw.cc = 1; return; } /* Check block sequential number (j) == 0 */ if(!memcmp(bsn, zero, 16)) { memset(ibi, 0, 15); ibi[15] = 128; memset(xts, 0, 15); xts[15] = 1; } else { /* Check intermediate block index (t) > 127 */ if(memcmp(ibi, zero, 15) || ibi[15] > 127) { /* Invalid imtermediate block index, return with cc2 */ regs->psw.cc = 2; return; } /* Intitial execution? */ if(!ibi[15]) { memset(xts, 0, 15); xts[15] = 1; } /* Calculate xts parameter */ do { if(bsn[ibi[15] / 8] & mask[ibi[15] % 8]) gcm_gf_mult(xts, exp_table[ibi[15]], xts); ibi[15]++; } while(ibi[15] != 128); } /* Encrypt tweak and multiply */ aes_set_key(&context, parameter_block, keylen * 8); aes_encrypt(&context, tweak, tweak); gcm_gf_mult(xts, tweak, xts); #ifdef OPTION_PCC_DEBUG LOGBYTE("ibi :", ibi, 16); LOGBYTE("xts :", xts, 16); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Store Intermediate Bit Index and XTS */ ARCH_DEP(vstorec)(ibi, 31, (GR_A(1, regs) + parameter_blocklen - 32) & ADDRESS_MAXWRAP(regs), 1, regs); /* Normal completion */ regs->psw.cc = 0; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /*----------------------------------------------------------------------------*/ /* Perform cryptographic key management operation (PCKMO) FC 1-3 [RRE] */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(pckmo_dea)(REGS *regs) { int fc; int keylen; BYTE parameter_block[64]; int parameter_blocklen; /* Initialize values */ fc = GR0_fc(regs); keylen = fc * 8; parameter_blocklen = keylen + 24; /* Test writeability */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, parameter_blocklen - 1, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCKMO_DEBUG LOGBYTE("key in : ", parameter_block, keylen); LOGBYTE("wkvp : ", ¶meter_block[keylen], parameter_blocklen - keylen); #endif /* #ifdef OPTION_PCKMO_DEBUG */ /* Encrypt the key and fill the wrapping key verification pattern */ wrap_dea(parameter_block, keylen); /* Store the parameterblock */ ARCH_DEP(vstorec)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCKMO_DEBUG LOGBYTE("key out: ", parameter_block, keylen); LOGBYTE("wkvp : ", ¶meter_block[keylen], parameter_blocklen - keylen); #endif /* #ifdef OPTION_PCKMO_DEBUG */ } /*----------------------------------------------------------------------------*/ /* Perform cryptographic key management operation (PCKMO) FC 18-20 [RRE] */ /*----------------------------------------------------------------------------*/ static void ARCH_DEP(pckmo_aes)(REGS *regs) { int fc; int keylen; BYTE parameter_block[64]; int parameter_blocklen; /* Initialize values */ fc = GR0_fc(regs); keylen = (fc - 16) * 8; parameter_blocklen = keylen + 32; /* Test writeability */ ARCH_DEP(validate_operand)(GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, parameter_blocklen - 1, ACCTYPE_WRITE, regs); /* Fetch the parameter block */ ARCH_DEP(vfetchc)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCKMO_DEBUG LOGBYTE("key in : ", parameter_block, keylen); LOGBYTE("wkvp : ", ¶meter_block[keylen], parameter_blocklen - keylen); #endif /* #ifdef OPTION_PCKMO_DEBUG */ /* Encrypt the key and fill the wrapping key verification pattern */ wrap_aes(parameter_block, keylen); /* Store the parameterblock */ ARCH_DEP(vstorec)(parameter_block, parameter_blocklen - 1, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCKMO_DEBUG LOGBYTE("key out: ", parameter_block, keylen); LOGBYTE("wkvp : ", ¶meter_block[keylen], parameter_blocklen - keylen); #endif /* #ifdef OPTION_PCKMO_DEBUG */ } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ /*----------------------------------------------------------------------------*/ /* B93E KIMD - Compute intermediate message digest [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(compute_intermediate_message_digest_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_KIMD_DEBUG logmsg("KIMD: compute intermediate message digest\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" bit 56 : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KIMD_DEBUG */ /* Check special conditions */ if(unlikely(!r2 || r2 & 0x01 || GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KIMD_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KIMD_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KIMD_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* sha-1 */ { ARCH_DEP(kimd_sha)(r1, r2, regs, 0); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { ARCH_DEP(kimd_sha)(r1, r2, regs, 0); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { ARCH_DEP(kimd_sha)(r1, r2, regs, 0); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 case 65: /* ghash */ { ARCH_DEP(kimd_ghash)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } /*----------------------------------------------------------------------------*/ /* B93F KLMD - Compute last message digest [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(compute_last_message_digest_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_KLMD_DEBUG logmsg("KLMD: compute last message digest\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" bit 56 : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KLMD_DEBUG */ /* Check special conditions */ if(unlikely(!r2 || r2 & 0x01 || GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KLMD_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KLMD_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KLMD_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* sha-1 */ { ARCH_DEP(klmd_sha)(r1, r2, regs); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 2: /* sha-256 */ { ARCH_DEP(klmd_sha)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 3: /* sha-512 */ { ARCH_DEP(klmd_sha)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } /*----------------------------------------------------------------------------*/ /* B92E KM - Cipher message [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_KM_DEBUG logmsg("KM: cipher message\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" m : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KM_DEBUG */ /* Check special conditions */ if(unlikely(!r1 || r1 & 0x01 || !r2 || r2 & 0x01)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KM_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KM_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KM_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* dea */ case 2: /* tdea-128 */ case 3: /* tdea-192 */ { ARCH_DEP(km_dea)(r1, r2, regs); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 case 9: /* encrypted dea */ case 10: /* encrypted tdea-128 */ case 11: /* encrypted tdea-192 */ { ARCH_DEP(km_dea)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 18: /* aes-128 */ { ARCH_DEP(km_aes)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 19: /* aes-192 */ case 20: /* aes-256 */ { ARCH_DEP(km_aes)(r1, r2, regs); break; } #endif /* #ifdef #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 case 26: /* encrypted aes-128 */ case 27: /* encrypted aes-192 */ case 28: /* encrypted aes-256 */ { ARCH_DEP(km_aes)(r1, r2, regs); break; } #endif /* #ifdef #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 case 50: /* xts aes-128 */ case 52: /* xts aes-256 */ case 58: /* encrypted xts aes-128 */ case 60: /* encrypted xts aes-256 */ { ARCH_DEP(km_xts_aes)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } /*----------------------------------------------------------------------------*/ /* B91E KMAC - Compute message authentication code [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(compute_message_authentication_code_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_KMAC_DEBUG logmsg("KMAC: compute message authentication code\n"); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" bit 56 : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* Check special conditions */ if(unlikely(!r2 || r2 & 0x01 || GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KMAC_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMAC_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KMAC_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* dea */ case 2: /* tdea-128 */ case 3: /* tdea-192 */ { ARCH_DEP(kmac_dea)(r1, r2, regs); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 case 9: /* encrypted dea */ case 10: /* encrypted tdea-128 */ case 11: /* encrypted tdea-192 */ { ARCH_DEP(kmac_dea)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 case 18: /* aes */ case 19: /* aes-192 */ case 20: /* aes-256 */ case 26: /* encrypted aes */ case 27: /* encrypted aes-192 */ case 28: /* encrypted aes-256 */ { ARCH_DEP(kmac_aes)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } /*----------------------------------------------------------------------------*/ /* B92F KMC - Cipher message with chaining [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_chaining_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_KMC_DEBUG logmsg("KMC: cipher message with chaining\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" m : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Check special conditions */ if(unlikely(!r1 || r1 & 0x01 || !r2 || r2 & 0x01)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KMC_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMC_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KMC_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* dea */ case 2: /* tdea-128 */ case 3: /* tdea-192 */ { ARCH_DEP(kmc_dea)(r1, r2, regs); break; } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 case 9: /* encrypted dea */ case 10: /* encrypted tdea-128 */ case 11: /* encrypted tdea-192 */ { ARCH_DEP(kmc_dea)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 18: /* aes-128 */ { ARCH_DEP(kmc_aes)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 case 19: /* aes-192 */ case 20: /* aes-256 */ { ARCH_DEP(kmc_aes)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 case 26: /* encrypted aes-128 */ case 27: /* encrypted aes-192 */ case 28: /* encrypted aes-256 */ { ARCH_DEP(kmc_aes)(r1, r2, regs); break; } #endif /* FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 case 67: /* prng */ { ARCH_DEP(kmc_prng)(r1, r2, regs); break; } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 */ default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 /*----------------------------------------------------------------------------*/ /* B92D KMCTR - Cipher message with counter [RRF] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_counter_d) { int r1; int r2; int r3; RRF_M(inst, regs, r1, r2, r3); #ifdef OPTION_KMCTR_DEBUG logmsg("KMCTR: cipher message with counter\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" r3 : GR%02d\n", r3); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* Check special conditions */ if(unlikely(!r1 || r1 & 0x01 || !r2 || r2 & 0x01 || !r3 || r3 & 0x01)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KMO_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMCTR_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KMCTR_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* dea */ case 2: /* tdea-128 */ case 3: /* tdea-192 */ case 9: /* encrypted dea */ case 10: /* encrypted tdea-128 */ case 11: /* encrypted tdea-192 */ { ARCH_DEP(kmctr_dea)(r1, r2, r3, regs); break; } case 18: /* aes-128 */ case 19: /* aes-192 */ case 20: /* aes-256 */ case 26: /* encrypted aes-128 */ case 27: /* encrypted aes-192 */ case 28: /* encrypted aes-256 */ { ARCH_DEP(kmctr_aes)(r1, r2, r3, regs); break; } default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } /*----------------------------------------------------------------------------*/ /* B92A KMF - Cipher message with cipher feedback [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_cipher_feedback_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_KMF_DEBUG logmsg("KMF: cipher message with cipher feedback\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" lcfb : %d\n", GR0_lcfb(regs)); logmsg(" m : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Check special conditions */ if(unlikely(!r1 || r1 & 0x01 || !r2 || r2 & 0x01)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KMF_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMF_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KMF_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* dea */ case 2: /* tdea-128 */ case 3: /* tdea-192 */ case 9: /* encrypted dea */ case 10: /* encrypted tdea-128 */ case 11: /* encrypted tdea-192 */ { ARCH_DEP(kmf_dea)(r1, r2, regs); break; } case 18: /* aes-128 */ case 19: /* aes-192 */ case 20: /* aes-256 */ case 26: /* encrypted aes-128 */ case 27: /* encrypted aes-192 */ case 28: /* encrypted aes-256 */ { ARCH_DEP(kmf_aes)(r1, r2, regs); break; } default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } /*----------------------------------------------------------------------------*/ /* B92B KMO - Cipher message with output feedback [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(cipher_message_with_output_feedback_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_KMO_DEBUG logmsg("KMO: cipher message with output feedback\n"); logmsg(" r1 : GR%02d\n", r1); logmsg(" address : " F_VADR "\n", regs->GR(r1)); logmsg(" r2 : GR%02d\n", r2); logmsg(" address : " F_VADR "\n", regs->GR(r2)); logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1)); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Check special conditions */ if(unlikely(!r1 || r1 & 0x01 || !r2 || r2 & 0x01)) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = KMO_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_KMO_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_KMO_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* dea */ case 2: /* tdea-128 */ case 3: /* tdea-192 */ case 9: /* encrypted dea */ case 10: /* encrypted tdea-128 */ case 11: /* encrypted tdea-192 */ { ARCH_DEP(kmo_dea)(r1, r2, regs); break; } case 18: /* aes-128 */ case 19: /* aes-192 */ case 20: /* aes-256 */ case 26: /* encrypted aes-128 */ case 27: /* encrypted aes-192 */ case 28: /* encrypted aes-256 */ { ARCH_DEP(kmo_aes)(r1, r2, regs); break; } default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } /*----------------------------------------------------------------------------*/ /* B92C PCC - Perform cryptographic computation [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(perform_cryptographic_computation_d) { int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_PCC_DEBUG logmsg("PCC: perform cryptographic computation\n"); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" bit 56 : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Check special conditions */ if(unlikely(GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); switch(GR0_fc(regs)) { case 0: /* Query */ { BYTE parameter_block[16] = PCC_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCC_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_PCC_DEBUG */ /* Set condition code 0 */ regs->psw.cc = 0; return; } case 1: /* dea */ case 2: /* tdea-128 */ case 3: /* tdea-192 */ case 9: /* encrypted dea */ case 10: /* encrypted tdea-128 */ case 11: /* encrypted tdea-192 */ { ARCH_DEP(pcc_cmac_dea)(regs); break; } case 18: /* aes-128 */ case 19: /* aes-192 */ case 20: /* aes-256 */ case 26: /* encrypted aes-128 */ case 27: /* encrypted aes-192 */ case 28: /* encrypted aes-256 */ { ARCH_DEP(pcc_cmac_aes)(regs); break; } case 50: /* aes-128 */ case 52: /* aes-256 */ case 58: /* encrypted aes-128 */ case 60: /* encrypted aes-256 */ { ARCH_DEP(pcc_xts_aes)(regs); break; } default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 */ #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 /*----------------------------------------------------------------------------*/ /* B928 PCKMO - Perform cryptographic key management operation [RRE] */ /*----------------------------------------------------------------------------*/ DEF_INST(perform_cryptographic_key_management_operation_d) { int fc; int r1; int r2; RRE(inst, regs, r1, r2); #ifdef OPTION_PCKMO_DEBUG logmsg("PCKMO: perform cryptographic key management operation\n"); logmsg(" GR00 : " F_GREG "\n", regs->GR(0)); logmsg(" bit 56 : %s\n", TRUEFALSE(GR0_m(regs))); logmsg(" fc : %d\n", GR0_fc(regs)); logmsg(" GR01 : " F_GREG "\n", regs->GR(1)); #endif /* #ifdef OPTION_PCKMO_DEBUG */ /* Privileged operation */ PRIV_CHECK(regs); /* Check special conditions */ if(unlikely(GR0_m(regs))) ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); /* Initialize values */ fc = GR0_fc(regs); switch(fc) { case 0: /* Query */ { BYTE parameter_block[16] = PCKMO_BITS; /* Store the parameter block */ ARCH_DEP(vstorec)(parameter_block, 15, GR_A(1, regs) & ADDRESS_MAXWRAP(regs), 1, regs); #ifdef OPTION_PCKMO_DEBUG LOGBYTE("output:", parameter_block, 16); #endif /* #ifdef OPTION_PCKMO_DEBUG */ return; } case 1: /* encrypt-dea */ case 2: /* encrypt-tdea-128 */ case 3: /* encrypt-tdea-192 */ { ARCH_DEP(pckmo_dea)(regs); break; } case 18: /* encrypt-aes-128 */ case 19: /* encrypt-aes-192 */ case 20: /* encrypt-aes-256 */ { ARCH_DEP(pckmo_aes)(regs); break; } default: { ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION); break; } } } #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 */ #endif /* #ifdef FEATURE_MESSAGE_SECURITY_ASSIST */ #ifndef _GEN_ARCH #ifdef _ARCHMODE2 #define _GEN_ARCH _ARCHMODE2 #include "dyncrypt.c" #endif /* #ifdef _ARCHMODE2 */ #ifdef _ARCHMODE3 #undef _GEN_ARCH #define _GEN_ARCH _ARCHMODE3 #include "dyncrypt.c" #endif /* #ifdef _ARCHMODE3 */ HDL_DEPENDENCY_SECTION; { HDL_DEPENDENCY(HERCULES); HDL_DEPENDENCY(REGS); // HDL_DEPENDENCY(DEVBLK); HDL_DEPENDENCY(SYSBLK); // HDL_DEPENDENCY(WEBBLK); } END_DEPENDENCY_SECTION; HDL_REGISTER_SECTION; { #if defined(_390_FEATURE_MESSAGE_SECURITY_ASSIST) HDL_REGISTER(s390_cipher_message, s390_cipher_message_d); HDL_REGISTER(s390_cipher_message_with_chaining, s390_cipher_message_with_chaining_d); HDL_REGISTER(s390_cipher_message_with_cipher_feedback, s390_cipher_message_with_cipher_feedback_d); HDL_REGISTER(s390_cipher_message_with_counter, s390_cipher_message_with_counter_d); HDL_REGISTER(s390_cipher_message_with_output_feedback, s390_cipher_message_with_output_feedback_d); HDL_REGISTER(s390_compute_intermediate_message_digest, s390_compute_intermediate_message_digest_d); HDL_REGISTER(s390_compute_last_message_digest, s390_compute_last_message_digest_d); HDL_REGISTER(s390_compute_message_authentication_code, s390_compute_message_authentication_code_d); HDL_REGISTER(s390_perform_cryptographic_computation, s390_perform_cryptographic_computation_d); HDL_REGISTER(s390_perform_cryptographic_key_management_operation, s390_perform_cryptographic_key_management_operation_d); #endif /*defined(_390_FEATURE_MESSAGE_SECURITY_ASSIST)*/ #if defined(_900_FEATURE_MESSAGE_SECURITY_ASSIST) HDL_REGISTER(z900_cipher_message, z900_cipher_message_d); HDL_REGISTER(z900_cipher_message_with_chaining, z900_cipher_message_with_chaining_d); HDL_REGISTER(z900_cipher_message_with_cipher_feedback, z900_cipher_message_with_cipher_feedback_d); HDL_REGISTER(z900_cipher_message_with_counter, z900_cipher_message_with_counter_d); HDL_REGISTER(z900_cipher_message_with_output_feedback, z900_cipher_message_with_output_feedback_d); HDL_REGISTER(z900_compute_intermediate_message_digest, z900_compute_intermediate_message_digest_d); HDL_REGISTER(z900_compute_last_message_digest, z900_compute_last_message_digest_d); HDL_REGISTER(z900_compute_message_authentication_code, z900_compute_message_authentication_code_d); HDL_REGISTER(z900_perform_cryptographic_computation, z900_perform_cryptographic_computation_d); HDL_REGISTER(z900_perform_cryptographic_key_management_operation, z900_perform_cryptographic_key_management_operation_d); #endif /*defined(_900_FEATURE_MESSAGE_SECURITY_ASSIST)*/ logmsg("Crypto module loaded (c) Copyright Bernard van der Helm, 2003-2010\n"); logmsg(" Active: Message Security Assist\n"); #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_1 logmsg(" Message Security Assist Extension 1\n"); #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_2 logmsg(" Message Security Assist Extension 2\n"); #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_3 logmsg(" Message Security Assist Extension 3\n"); #endif #ifdef FEATURE_MESSAGE_SECURITY_ASSIST_EXTENSION_4 logmsg(" Message Security Assist Extension 4\n"); #endif } END_REGISTER_SECTION; #endif /* #ifndef _GEN_ARCH */ hercules-3.12/crypto/sha1.c0000664000175000017500000001415412564723224012530 00000000000000/* $OpenBSD: sha1.c,v 1.5 2004/04/28 20:39:35 hshoexer Exp $ */ /* modified for use with dyncrypt */ /* * SHA-1 in C * By Steve Reid * 100% Public Domain * * Test Vectors (from FIPS PUB 180-1) * "abc" * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 * A million repetitions of "a" * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* #define SHA1HANDSOFF */ /* Copies data before messing with it. */ #include "hstdinc.h" #include "sha1.h" #define bcopy(_src,_dest,_len) memcpy(_dest,_src,_len) #define bzero(_dest,_len) memset(_dest,'\0',_len) #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ #ifndef WORDS_BIGENDIAN #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ |(rol(block->l[i],8)&0x00FF00FF)) #else #define blk0(i) block->l[i] #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); /* Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1Transform(u_int32_t state[5], unsigned char buffer[SHA1_BLOCK_LENGTH]) { u_int32_t a, b, c, d, e; typedef union { unsigned char c[64]; u_int32_t l[16]; } CHAR64LONG16; CHAR64LONG16* block; #ifdef SHA1HANDSOFF static unsigned char workspace[SHA1_BLOCK_LENGTH]; block = (CHAR64LONG16 *)workspace; bcopy(buffer, block, SHA1_BLOCK_LENGTH); #else block = (CHAR64LONG16 *)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void SHA1Init(SHA1_CTX *context) { /* SHA1 initialization constants */ context->count = 0; context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; } /* Run your data through this. */ void SHA1Update(SHA1_CTX *context, unsigned char *data, unsigned int len) { unsigned int i; unsigned int j; j = (u_int32_t)((context->count >> 3) & 63); context->count += (len << 3); if ((j + len) > 63) { bcopy(data, &context->buffer[j], (i = 64 - j)); SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { SHA1Transform(context->state, &data[i]); } j = 0; } else i = 0; bcopy(&data[i], &context->buffer[j], len - i); } /* Add padding and return the message digest. */ void SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context) { unsigned int i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count >> ((7 - (i & 7)) * 8)) & 255); /* Endian independent */ } SHA1Update(context, (unsigned char *)"\200", 1); while ((context->count & 504) != 448) { SHA1Update(context, (unsigned char *)"\0", 1); } SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ if (digest) for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } #if 0 /* We want to use this for "keyfill" */ /* Wipe variables */ i = 0; bzero(context->buffer, 64); bzero(context->state, 20); bzero(context->count, 8); bzero(&finalcount, 8); #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ SHA1Transform(context->state, context->buffer); #endif #endif } /* Hashing-only function called by dyncrypt */ void sha1_process(sha1_context *ctx, unsigned char data[64]) { SHA1Transform(ctx->state, data); } hercules-3.12/crypto/sha256.c0000664000175000017500000006012312564723224012701 00000000000000/* $OpenBSD: sha2.c,v 1.6 2004/05/03 02:57:36 millert Exp $ */ /* modified for use with dyncrypt */ /* * FILE: sha2.c * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ */ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #include "hercules.h" #include "opcode.h" /* For CSWAP macros */ #include "sha256.h" #define bcopy(_src,_dest,_len) memcpy(_dest,_src,_len) #define bzero(_dest,_len) memset(_dest,'\0',_len) /* * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ #define SHA2_UNROLL_TRANSFORM /*** SHA-256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) { \ (w)[0] += (u_int64_t)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** INTERNAL FUNCTION PROTOTYPES *************************************/ /* NOTE: These should not be accessed directly from outside this * library -- they are intended for private internal visibility/use * only. */ void SHA512_Last(SHA512_CTX *); void SHA256_Transform(SHA256_CTX *, const u_int8_t *); void SHA512_Transform(SHA512_CTX *, const u_int8_t *); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ static const u_int32_t K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ static const u_int32_t sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; /* Hash constant words K for SHA-384 and SHA-512: */ static const u_int64_t K512[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; /* Initial hash value H for SHA-384 */ static const u_int64_t sha384_initial_hash_value[8] = { 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL }; /* Initial hash value H for SHA-512 */ static const u_int64_t sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL }; /*** SHA-256: *********************************************************/ void SHA256_Init(SHA256_CTX *context) { if (context == NULL) return; bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH); bzero(context->buffer, SHA256_BLOCK_LENGTH); context->bitcount = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) do { \ W256[j] = (u_int32_t)data[3] | ((u_int32_t)data[2] << 8) | \ ((u_int32_t)data[1] << 16) | ((u_int32_t)data[0] << 24); \ data += 4; \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND256(a,b,c,d,e,f,g,h) do { \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA256_Transform(SHA256_CTX *context, const u_int8_t *data) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, *W256; int j; W256 = (u_int32_t *)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds to 64: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA256_Transform(SHA256_CTX *context, const u_int8_t *data) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, T2, *W256; int j; W256 = (u_int32_t *)context->buffer; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { W256[j] = (u_int32_t)data[3] | ((u_int32_t)data[2] << 8) | ((u_int32_t)data[1] << 16) | ((u_int32_t)data[0] << 24); data += 4; /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA256_Update(SHA256_CTX *context, const u_int8_t *data, size_t len) { size_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ bcopy(data, &context->buffer[usedspace], freespace); context->bitcount += freespace << 3; len -= freespace; data += freespace; SHA256_Transform(context, context->buffer); } else { /* The buffer is not yet full */ bcopy(data, &context->buffer[usedspace], len); context->bitcount += len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA256_Transform(context, data); context->bitcount += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ bcopy(data, context->buffer, len); context->bitcount += len << 3; } /* Clean up: */ usedspace = freespace = 0; } void SHA256_Final(u_int8_t digest[], SHA256_CTX *context) { u_int32_t *d = (u_int32_t *)digest; unsigned int usedspace; /* If no digest buffer is passed, we don't bother doing this: */ if (digest != NULL) { usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; /* Convert FROM host byte order */ context->bitcount = CSWAP64(context->bitcount); if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA256_BLOCK_LENGTH) { bzero(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA256_Transform(context, context->buffer); /* And set-up for the last transform: */ bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Set the bit count: */ *(u_int64_t *)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; /* Final transform: */ SHA256_Transform(context, context->buffer); { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { *d++ = CSWAP32(context->state[j]); } } } /* Clean up state data: */ bzero(context, sizeof(*context)); usedspace = 0; } /* Hashing-only functions called by dyncrypt */ void sha256_process(sha256_context *ctx, u_int8_t data[64]) { SHA256_Transform(ctx, data); } void sha512_process(sha512_context *ctx, u_int8_t data[64]) { SHA512_Transform(ctx, data); } /*** SHA-512: *********************************************************/ void SHA512_Init(SHA512_CTX *context) { if (context == NULL) return; bcopy(sha512_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); bzero(context->buffer, SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) do { \ W512[j] = (u_int64_t)data[7] | ((u_int64_t)data[6] << 8) | \ ((u_int64_t)data[5] << 16) | ((u_int64_t)data[4] << 24) | \ ((u_int64_t)data[3] << 32) | ((u_int64_t)data[2] << 40) | \ ((u_int64_t)data[1] << 48) | ((u_int64_t)data[0] << 56); \ data += 8; \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + W512[j]; \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND512(a,b,c,d,e,f,g,h) do { \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA512_Transform(SHA512_CTX *context, const u_int8_t *data) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, *W512 = (u_int64_t *)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA512_Transform(SHA512_CTX *context, const u_int8_t *data) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, T2, *W512 = (u_int64_t *)context->buffer; int j; /* Initialize registers with the prev. intermediate value */ a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7]; j = 0; do { W512[j] = (u_int64_t)data[7] | ((u_int64_t)data[6] << 8) | ((u_int64_t)data[5] << 16) | ((u_int64_t)data[4] << 24) | ((u_int64_t)data[3] << 32) | ((u_int64_t)data[2] << 40) | ((u_int64_t)data[1] << 48) | ((u_int64_t)data[0] << 56); data += 8; /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA512_Update(SHA512_CTX *context, const u_int8_t *data, size_t len) { size_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ bcopy(data, &context->buffer[usedspace], freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; SHA512_Transform(context, context->buffer); } else { /* The buffer is not yet full */ bcopy(data, &context->buffer[usedspace], len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA512_Transform(context, data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ bcopy(data, context->buffer, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } void SHA512_Last(SHA512_CTX *context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; /* Convert FROM host byte order */ context->bitcount[0] = CSWAP64(context->bitcount[0]); context->bitcount[1] = CSWAP64(context->bitcount[1]); if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA512_BLOCK_LENGTH) { bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA512_Transform(context, context->buffer); /* And set-up for the last transform: */ bzero(context->buffer, SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits): */ *(u_int64_t *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; *(u_int64_t *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; /* Final transform: */ SHA512_Transform(context, context->buffer); } void SHA512_Final(u_int8_t digest[], SHA512_CTX *context) { u_int64_t *d = (u_int64_t *)digest; /* If no digest buffer is passed, we don't bother doing this: */ if (digest != NULL) { SHA512_Last(context); /* Save the hash data for output: */ { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { *d++ = CSWAP64(context->state[j]); } } } /* Zero out state data */ bzero(context, sizeof(*context)); } /*** SHA-384: *********************************************************/ void SHA384_Init(SHA384_CTX *context) { if (context == NULL) return; bcopy(sha384_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); bzero(context->buffer, SHA384_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } void SHA384_Update(SHA384_CTX *context, const u_int8_t *data, size_t len) { SHA512_Update((SHA512_CTX *)context, data, len); } void SHA384_Final(u_int8_t digest[], SHA384_CTX *context) { u_int64_t *d = (u_int64_t *)digest; /* If no digest buffer is passed, we don't bother doing this: */ if (digest != NULL) { SHA512_Last((SHA512_CTX *)context); /* Save the hash data for output: */ { /* Convert TO host byte order */ int j; for (j = 0; j < 6; j++) { *d++ = CSWAP64(context->state[j]); } } } /* Zero out state data */ bzero(context, sizeof(*context)); } hercules-3.12/crypto/des.c0000664000175000017500000007060712564723224012454 00000000000000/* des.c - implementation of DES * http://www.tartarus.org/~simon-anonsvn/viewcvs.cgi/putty/ * modified for use with dyncrypt */ // $Id$ /* * PuTTY is copyright 1997-2005 Simon Tatham. * * Portions copyright Robert de Bath, Joris van Rantwijk, Delian * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus * Kuhn, and CORE SDI S.A. * * 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 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. */ // $Log$ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #include "hercules.h" #include "opcode.h" /* For fetch_fw */ #include "des.h" /* * Description of DES * ------------------ * * Unlike the description in FIPS 46, I'm going to use _sensible_ indices: * bits in an n-bit word are numbered from 0 at the LSB to n-1 at the MSB. * And S-boxes are indexed by six consecutive bits, not by the outer two * followed by the middle four. * * The DES encryption routine requires a 64-bit input, and a key schedule K * containing 16 48-bit elements. * * First the input is permuted by the initial permutation IP. * Then the input is split into 32-bit words L and R. (L is the MSW.) * Next, 16 rounds. In each round: * (L, R) <- (R, L xor f(R, K[i])) * Then the pre-output words L and R are swapped. * Then L and R are glued back together into a 64-bit word. (L is the MSW, * again, but since we just swapped them, the MSW is the R that came out * of the last round.) * The 64-bit output block is permuted by the inverse of IP and returned. * * Decryption is identical except that the elements of K are used in the * opposite order. (This wouldn't work if that word swap didn't happen.) * * The function f, used in each round, accepts a 32-bit word R and a * 48-bit key block K. It produces a 32-bit output. * * First R is expanded to 48 bits using the bit-selection function E. * The resulting 48-bit block is XORed with the key block K to produce * a 48-bit block X. * This block X is split into eight groups of 6 bits. Each group of 6 * bits is then looked up in one of the eight S-boxes to convert * it to 4 bits. These eight groups of 4 bits are glued back * together to produce a 32-bit preoutput block. * The preoutput block is permuted using the permutation P and returned. * * Key setup maps a 64-bit key word into a 16x48-bit key schedule. Although * the approved input format for the key is a 64-bit word, eight of the * bits are discarded, so the actual quantity of key used is 56 bits. * * First the input key is converted to two 28-bit words C and D using * the bit-selection function PC1. * Then 16 rounds of key setup occur. In each round, C and D are each * rotated left by either 1 or 2 bits (depending on which round), and * then converted into a key schedule element using the bit-selection * function PC2. * * That's the actual algorithm. Now for the tedious details: all those * painful permutations and lookup tables. * * IP is a 64-to-64 bit permutation. Its output contains the following * bits of its input (listed in order MSB to LSB of output). * * 6 14 22 30 38 46 54 62 4 12 20 28 36 44 52 60 * 2 10 18 26 34 42 50 58 0 8 16 24 32 40 48 56 * 7 15 23 31 39 47 55 63 5 13 21 29 37 45 53 61 * 3 11 19 27 35 43 51 59 1 9 17 25 33 41 49 57 * * E is a 32-to-48 bit selection function. Its output contains the following * bits of its input (listed in order MSB to LSB of output). * * 0 31 30 29 28 27 28 27 26 25 24 23 24 23 22 21 20 19 20 19 18 17 16 15 * 16 15 14 13 12 11 12 11 10 9 8 7 8 7 6 5 4 3 4 3 2 1 0 31 * * The S-boxes are arbitrary table-lookups each mapping a 6-bit input to a * 4-bit output. In other words, each S-box is an array[64] of 4-bit numbers. * The S-boxes are listed below. The first S-box listed is applied to the * most significant six bits of the block X; the last one is applied to the * least significant. * * 14 0 4 15 13 7 1 4 2 14 15 2 11 13 8 1 * 3 10 10 6 6 12 12 11 5 9 9 5 0 3 7 8 * 4 15 1 12 14 8 8 2 13 4 6 9 2 1 11 7 * 15 5 12 11 9 3 7 14 3 10 10 0 5 6 0 13 * * 15 3 1 13 8 4 14 7 6 15 11 2 3 8 4 14 * 9 12 7 0 2 1 13 10 12 6 0 9 5 11 10 5 * 0 13 14 8 7 10 11 1 10 3 4 15 13 4 1 2 * 5 11 8 6 12 7 6 12 9 0 3 5 2 14 15 9 * * 10 13 0 7 9 0 14 9 6 3 3 4 15 6 5 10 * 1 2 13 8 12 5 7 14 11 12 4 11 2 15 8 1 * 13 1 6 10 4 13 9 0 8 6 15 9 3 8 0 7 * 11 4 1 15 2 14 12 3 5 11 10 5 14 2 7 12 * * 7 13 13 8 14 11 3 5 0 6 6 15 9 0 10 3 * 1 4 2 7 8 2 5 12 11 1 12 10 4 14 15 9 * 10 3 6 15 9 0 0 6 12 10 11 1 7 13 13 8 * 15 9 1 4 3 5 14 11 5 12 2 7 8 2 4 14 * * 2 14 12 11 4 2 1 12 7 4 10 7 11 13 6 1 * 8 5 5 0 3 15 15 10 13 3 0 9 14 8 9 6 * 4 11 2 8 1 12 11 7 10 1 13 14 7 2 8 13 * 15 6 9 15 12 0 5 9 6 10 3 4 0 5 14 3 * * 12 10 1 15 10 4 15 2 9 7 2 12 6 9 8 5 * 0 6 13 1 3 13 4 14 14 0 7 11 5 3 11 8 * 9 4 14 3 15 2 5 12 2 9 8 5 12 15 3 10 * 7 11 0 14 4 1 10 7 1 6 13 0 11 8 6 13 * * 4 13 11 0 2 11 14 7 15 4 0 9 8 1 13 10 * 3 14 12 3 9 5 7 12 5 2 10 15 6 8 1 6 * 1 6 4 11 11 13 13 8 12 1 3 4 7 10 14 7 * 10 9 15 5 6 0 8 15 0 14 5 2 9 3 2 12 * * 13 1 2 15 8 13 4 8 6 10 15 3 11 7 1 4 * 10 12 9 5 3 6 14 11 5 0 0 14 12 9 7 2 * 7 2 11 1 4 14 1 7 9 4 12 10 14 8 2 13 * 0 15 6 12 10 9 13 0 15 3 3 5 5 6 8 11 * * P is a 32-to-32 bit permutation. Its output contains the following * bits of its input (listed in order MSB to LSB of output). * * 16 25 12 11 3 20 4 15 31 17 9 6 27 14 1 22 * 30 24 8 18 0 5 29 23 13 19 2 26 10 21 28 7 * * PC1 is a 64-to-56 bit selection function. Its output is in two words, * C and D. The word C contains the following bits of its input (listed * in order MSB to LSB of output). * * 7 15 23 31 39 47 55 63 6 14 22 30 38 46 * 54 62 5 13 21 29 37 45 53 61 4 12 20 28 * * And the word D contains these bits. * * 1 9 17 25 33 41 49 57 2 10 18 26 34 42 * 50 58 3 11 19 27 35 43 51 59 36 44 52 60 * * PC2 is a 56-to-48 bit selection function. Its input is in two words, * C and D. These are treated as one 56-bit word (with C more significant, * so that bits 55 to 28 of the word are bits 27 to 0 of C, and bits 27 to * 0 of the word are bits 27 to 0 of D). The output contains the following * bits of this 56-bit input word (listed in order MSB to LSB of output). * * 42 39 45 32 55 51 53 28 41 50 35 46 33 37 44 52 30 48 40 49 29 36 43 54 * 15 4 25 19 9 1 26 16 5 11 23 8 12 7 17 0 22 3 10 14 6 20 27 24 */ /* * Implementation details * ---------------------- * * If you look at the code in this module, you'll find it looks * nothing _like_ the above algorithm. Here I explain the * differences... * * Key setup has not been heavily optimised here. We are not * concerned with key agility: we aren't codebreakers. We don't * mind a little delay (and it really is a little one; it may be a * factor of five or so slower than it could be but it's still not * an appreciable length of time) while setting up. The only tweaks * in the key setup are ones which change the format of the key * schedule to speed up the actual encryption. I'll describe those * below. * * The first and most obvious optimisation is the S-boxes. Since * each S-box always targets the same four bits in the final 32-bit * word, so the output from (for example) S-box 0 must always be * shifted left 28 bits, we can store the already-shifted outputs * in the lookup tables. This reduces lookup-and-shift to lookup, * so the S-box step is now just a question of ORing together eight * table lookups. * * The permutation P is just a bit order change; it's invariant * with respect to OR, in that P(x)|P(y) = P(x|y). Therefore, we * can apply P to every entry of the S-box tables and then we don't * have to do it in the code of f(). This yields a set of tables * which might be called SP-boxes. * * The bit-selection function E is our next target. Note that E is * immediately followed by the operation of splitting into 6-bit * chunks. Examining the 6-bit chunks coming out of E we notice * they're all contiguous within the word (speaking cyclically - * the end two wrap round); so we can extract those bit strings * individually rather than explicitly running E. This would yield * code such as * * y |= SPboxes[0][ (rotl(R, 5) ^ top6bitsofK) & 0x3F ]; * t |= SPboxes[1][ (rotl(R,11) ^ next6bitsofK) & 0x3F ]; * * and so on; and the key schedule preparation would have to * provide each 6-bit chunk separately. * * Really we'd like to XOR in the key schedule element before * looking up bit strings in R. This we can't do, naively, because * the 6-bit strings we want overlap. But look at the strings: * * 3322222222221111111111 * bit 10987654321098765432109876543210 * * box0 XXXXX X * box1 XXXXXX * box2 XXXXXX * box3 XXXXXX * box4 XXXXXX * box5 XXXXXX * box6 XXXXXX * box7 X XXXXX * * The bit strings we need to XOR in for boxes 0, 2, 4 and 6 don't * overlap with each other. Neither do the ones for boxes 1, 3, 5 * and 7. So we could provide the key schedule in the form of two * words that we can separately XOR into R, and then every S-box * index is available as a (cyclically) contiguous 6-bit substring * of one or the other of the results. * * The comments in Eric Young's libdes implementation point out * that two of these bit strings require a rotation (rather than a * simple shift) to extract. It's unavoidable that at least _one_ * must do; but we can actually run the whole inner algorithm (all * 16 rounds) rotated one bit to the left, so that what the `real' * DES description sees as L=0x80000001 we see as L=0x00000003. * This requires rotating all our SP-box entries one bit to the * left, and rotating each word of the key schedule elements one to * the left, and rotating L and R one bit left just after IP and * one bit right again just before FP. And in each round we convert * a rotate into a shift, so we've saved a few per cent. * * That's about it for the inner loop; the SP-box tables as listed * below are what I've described here (the original S value, * shifted to its final place in the input to P, run through P, and * then rotated one bit left). All that remains is to optimise the * initial permutation IP. * * IP is not an arbitrary permutation. It has the nice property * that if you take any bit number, write it in binary (6 bits), * permute those 6 bits and invert some of them, you get the final * position of that bit. Specifically, the bit whose initial * position is given (in binary) as fedcba ends up in position * AcbFED (where a capital letter denotes the inverse of a bit). * * We have the 64-bit data in two 32-bit words L and R, where bits * in L are those with f=1 and bits in R are those with f=0. We * note that we can do a simple transformation: suppose we exchange * the bits with f=1,c=0 and the bits with f=0,c=1. This will cause * the bit fedcba to be in position cedfba - we've `swapped' bits c * and f in the position of each bit! * * Better still, this transformation is easy. In the example above, * bits in L with c=0 are bits 0x0F0F0F0F, and those in R with c=1 * are 0xF0F0F0F0. So we can do * * difference = ((R >> 4) ^ L) & 0x0F0F0F0F * R ^= (difference << 4) * L ^= difference * * to perform the swap. Let's denote this by bitswap(4,0x0F0F0F0F). * Also, we can invert the bit at the top just by exchanging L and * R. So in a few swaps and a few of these bit operations we can * do: * * Initially the position of bit fedcba is fedcba * Swap L with R to make it Fedcba * Perform bitswap( 4,0x0F0F0F0F) to make it cedFba * Perform bitswap(16,0x0000FFFF) to make it ecdFba * Swap L with R to make it EcdFba * Perform bitswap( 2,0x33333333) to make it bcdFEa * Perform bitswap( 8,0x00FF00FF) to make it dcbFEa * Swap L with R to make it DcbFEa * Perform bitswap( 1,0x55555555) to make it acbFED * Swap L with R to make it AcbFED * * (In the actual code the four swaps are implicit: R and L are * simply used the other way round in the first, second and last * bitswap operations.) * * The final permutation is just the inverse of IP, so it can be * performed by a similar set of operations. */ #define rotl(x, c) ( (x << c) | (x >> (32-c)) ) #define rotl28(x, c) ( ( (x << c) | (x >> (28-c)) ) & 0x0FFFFFFF) #define GET_32BIT_MSB_FIRST(_storage) fetch_fw((BYTE*)(_storage)) #define PUT_32BIT_MSB_FIRST(_storage, _value) store_fw(_storage, _value) static word32 bitsel(word32 * input, const int *bitnums, int size) { word32 ret = 0; while (size--) { int bitpos = *bitnums++; ret <<= 1; if (bitpos >= 0) ret |= 1 & (input[bitpos / 32] >> (bitpos % 32)); } return ret; } static void des_key_setup(word32 key_msw, word32 key_lsw, DESContext * sched) { static const int PC1_Cbits[] = { 7, 15, 23, 31, 39, 47, 55, 63, 6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61, 4, 12, 20, 28 }; static const int PC1_Dbits[] = { 1, 9, 17, 25, 33, 41, 49, 57, 2, 10, 18, 26, 34, 42, 50, 58, 3, 11, 19, 27, 35, 43, 51, 59, 36, 44, 52, 60 }; /* * The bit numbers in the two lists below don't correspond to * the ones in the above description of PC2, because in the * above description C and D are concatenated so `bit 28' means * bit 0 of C. In this implementation we're using the standard * `bitsel' function above and C is in the second word, so bit * 0 of C is addressed by writing `32' here. */ static const int PC2_0246[] = { 49, 36, 59, 55, -1, -1, 37, 41, 48, 56, 34, 52, -1, -1, 15, 4, 25, 19, 9, 1, -1, -1, 12, 7, 17, 0, 22, 3, -1, -1, 46, 43 }; static const int PC2_1357[] = { -1, -1, 57, 32, 45, 54, 39, 50, -1, -1, 44, 53, 33, 40, 47, 58, -1, -1, 26, 16, 5, 11, 23, 8, -1, -1, 10, 14, 6, 20, 27, 24 }; static const int leftshifts[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; word32 C, D; word32 buf[2]; int i; buf[0] = key_lsw; buf[1] = key_msw; C = bitsel(buf, PC1_Cbits, 28); D = bitsel(buf, PC1_Dbits, 28); for (i = 0; i < 16; i++) { C = rotl28(C, leftshifts[i]); D = rotl28(D, leftshifts[i]); buf[0] = D; buf[1] = C; sched->k0246[i] = bitsel(buf, PC2_0246, 32); sched->k1357[i] = bitsel(buf, PC2_1357, 32); } sched->iv0 = sched->iv1 = 0; } static const word32 SPboxes[8][64] = { {0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004L}, {0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000L}, {0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200L}, {0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080L}, {0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100L}, {0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010L}, {0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002L}, {0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000L} }; #define f(R, K0246, K1357) (\ s0246 = R ^ K0246, \ s1357 = R ^ K1357, \ s0246 = rotl(s0246, 28), \ SPboxes[0] [(s0246 >> 24) & 0x3F] | \ SPboxes[1] [(s1357 >> 24) & 0x3F] | \ SPboxes[2] [(s0246 >> 16) & 0x3F] | \ SPboxes[3] [(s1357 >> 16) & 0x3F] | \ SPboxes[4] [(s0246 >> 8) & 0x3F] | \ SPboxes[5] [(s1357 >> 8) & 0x3F] | \ SPboxes[6] [(s0246 ) & 0x3F] | \ SPboxes[7] [(s1357 ) & 0x3F]) #define bitswap(L, R, n, mask) (\ swap = mask & ( (R >> n) ^ L ), \ R ^= swap << n, \ L ^= swap) /* Initial permutation */ #define IP(L, R) (\ bitswap(R, L, 4, 0x0F0F0F0F), \ bitswap(R, L, 16, 0x0000FFFF), \ bitswap(L, R, 2, 0x33333333), \ bitswap(L, R, 8, 0x00FF00FF), \ bitswap(R, L, 1, 0x55555555)) /* Final permutation */ #define FP(L, R) (\ bitswap(R, L, 1, 0x55555555), \ bitswap(L, R, 8, 0x00FF00FF), \ bitswap(L, R, 2, 0x33333333), \ bitswap(R, L, 16, 0x0000FFFF), \ bitswap(R, L, 4, 0x0F0F0F0F)) static void des_encipher(word32 * output, word32 L, word32 R, DESContext * sched) { word32 swap, s0246, s1357; IP(L, R); L = rotl(L, 1); R = rotl(R, 1); L ^= f(R, sched->k0246[0], sched->k1357[0]); R ^= f(L, sched->k0246[1], sched->k1357[1]); L ^= f(R, sched->k0246[2], sched->k1357[2]); R ^= f(L, sched->k0246[3], sched->k1357[3]); L ^= f(R, sched->k0246[4], sched->k1357[4]); R ^= f(L, sched->k0246[5], sched->k1357[5]); L ^= f(R, sched->k0246[6], sched->k1357[6]); R ^= f(L, sched->k0246[7], sched->k1357[7]); L ^= f(R, sched->k0246[8], sched->k1357[8]); R ^= f(L, sched->k0246[9], sched->k1357[9]); L ^= f(R, sched->k0246[10], sched->k1357[10]); R ^= f(L, sched->k0246[11], sched->k1357[11]); L ^= f(R, sched->k0246[12], sched->k1357[12]); R ^= f(L, sched->k0246[13], sched->k1357[13]); L ^= f(R, sched->k0246[14], sched->k1357[14]); R ^= f(L, sched->k0246[15], sched->k1357[15]); L = rotl(L, 31); R = rotl(R, 31); swap = L; L = R; R = swap; FP(L, R); output[0] = L; output[1] = R; } static void des_decipher(word32 * output, word32 L, word32 R, DESContext * sched) { word32 swap, s0246, s1357; IP(L, R); L = rotl(L, 1); R = rotl(R, 1); L ^= f(R, sched->k0246[15], sched->k1357[15]); R ^= f(L, sched->k0246[14], sched->k1357[14]); L ^= f(R, sched->k0246[13], sched->k1357[13]); R ^= f(L, sched->k0246[12], sched->k1357[12]); L ^= f(R, sched->k0246[11], sched->k1357[11]); R ^= f(L, sched->k0246[10], sched->k1357[10]); L ^= f(R, sched->k0246[9], sched->k1357[9]); R ^= f(L, sched->k0246[8], sched->k1357[8]); L ^= f(R, sched->k0246[7], sched->k1357[7]); R ^= f(L, sched->k0246[6], sched->k1357[6]); L ^= f(R, sched->k0246[5], sched->k1357[5]); R ^= f(L, sched->k0246[4], sched->k1357[4]); L ^= f(R, sched->k0246[3], sched->k1357[3]); R ^= f(L, sched->k0246[2], sched->k1357[2]); L ^= f(R, sched->k0246[1], sched->k1357[1]); R ^= f(L, sched->k0246[0], sched->k1357[0]); L = rotl(L, 31); R = rotl(R, 31); swap = L; L = R; R = swap; FP(L, R); output[0] = L; output[1] = R; } /* Functions called by dyncrypt */ void des_set_key(des_context *ctx, CHAR8 key) { DESContext *sched = ctx->sched; word32 kL, kR; kL = GET_32BIT_MSB_FIRST(key); kR = GET_32BIT_MSB_FIRST(key+4); des_key_setup(kL, kR, &sched[0]); } void des_encrypt(des_context *ctx, CHAR8 input, CHAR8 output) { DESContext *sched = ctx->sched; word32 out[2], xL, xR; xL = GET_32BIT_MSB_FIRST(input); xR = GET_32BIT_MSB_FIRST(input+4); des_encipher(out, xL, xR, sched); PUT_32BIT_MSB_FIRST(output, out[0]); PUT_32BIT_MSB_FIRST(output+4, out[1]); } void des_decrypt(des_context *ctx, CHAR8 input, CHAR8 output) { DESContext *sched = ctx->sched; word32 out[2], xL, xR; xL = GET_32BIT_MSB_FIRST(input); xR = GET_32BIT_MSB_FIRST(input+4); des_decipher(out, xL, xR, sched); PUT_32BIT_MSB_FIRST(output, out[0]); PUT_32BIT_MSB_FIRST(output+4, out[1]); } void des3_set_2keys(des3_context *ctx, CHAR8 k1, CHAR8 k2) { DESContext *sched = ctx->sched; word32 kL, kR; kL = GET_32BIT_MSB_FIRST(k1); kR = GET_32BIT_MSB_FIRST(k1+4); des_key_setup(kL, kR, &sched[0]); des_key_setup(kL, kR, &sched[2]); kL = GET_32BIT_MSB_FIRST(k2); kR = GET_32BIT_MSB_FIRST(k2+4); des_key_setup(kL, kR, &sched[1]); } void des3_set_3keys(des3_context *ctx, CHAR8 k1, CHAR8 k2, CHAR8 k3) { DESContext *sched = ctx->sched; word32 kL, kR; kL = GET_32BIT_MSB_FIRST(k1); kR = GET_32BIT_MSB_FIRST(k1+4); des_key_setup(kL, kR, &sched[0]); kL = GET_32BIT_MSB_FIRST(k2); kR = GET_32BIT_MSB_FIRST(k2+4); des_key_setup(kL, kR, &sched[1]); kL = GET_32BIT_MSB_FIRST(k3); kR = GET_32BIT_MSB_FIRST(k3+4); des_key_setup(kL, kR, &sched[2]); } void des3_encrypt(des3_context *ctx, CHAR8 input, CHAR8 output) { DESContext *sched = ctx->sched; word32 out[2], xL, xR; xL = GET_32BIT_MSB_FIRST(input); xR = GET_32BIT_MSB_FIRST(input+4); des_encipher(out, xL, xR, sched); xL = out[0]; xR = out[1]; des_decipher(out, xL, xR, sched+1); xL = out[0]; xR = out[1]; des_encipher(out, xL, xR, sched+2); PUT_32BIT_MSB_FIRST(output, out[0]); PUT_32BIT_MSB_FIRST(output+4, out[1]); } void des3_decrypt(des3_context *ctx, CHAR8 input, CHAR8 output) { DESContext *sched = ctx->sched; word32 out[2], xL, xR; xL = GET_32BIT_MSB_FIRST(input); xR = GET_32BIT_MSB_FIRST(input+4); des_decipher(out, xL, xR, sched+2); xL = out[0]; xR = out[1]; des_encipher(out, xL, xR, sched+1); xL = out[0]; xR = out[1]; des_decipher(out, xL, xR, sched); PUT_32BIT_MSB_FIRST(output, out[0]); PUT_32BIT_MSB_FIRST(output+4, out[1]); } hercules-3.12/crypto/aes.c0000664000175000017500000016330112564723224012443 00000000000000/* $OpenBSD: rijndael.c,v 1.18 2005/05/25 05:47:53 markus Exp $ */ /* modified for use by dyncrypt */ // $Id$ /** * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // $Log$ #include "hstdinc.h" #if !defined(_HENGINE_DLL_) #define _HENGINE_DLL_ #endif #include "hercules.h" #include "opcode.h" /* For fetch_fw */ #include "aes.h" #define FULL_UNROLL /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02]; Te4[x] = S [x].[01, 01, 01, 01]; Td0[x] = Si[x].[0e, 09, 0d, 0b]; Td1[x] = Si[x].[0b, 0e, 09, 0d]; Td2[x] = Si[x].[0d, 0b, 0e, 09]; Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01, 01, 01, 01]; */ static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; static const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; static const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; static const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; static const u32 Te4[256] = { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, }; static const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; static const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; static const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; static const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; static const u32 Td4[256] = { 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, }; static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #define GETU32(_storage) fetch_fw((BYTE*)(_storage)) #define PUTU32(_storage, _value) { store_fw(_storage, _value); } /** * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int i = 0; u32 temp; rk[0] = GETU32(cipherKey ); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); if (keyBits == 128) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { return 10; } rk += 4; } } rk[4] = GETU32(cipherKey + 16); rk[5] = GETU32(cipherKey + 20); if (keyBits == 192) { for (;;) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { return 12; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); if (keyBits == 256) { for (;;) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { return 14; } temp = rk[11]; rk[12] = rk[ 4] ^ (Te4[(temp >> 24) ] & 0xff000000) ^ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(temp ) & 0xff] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } return 0; } /** * Expand the cipher key into the decryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int Nr, i, j; u32 temp; /* expand the cipher key: */ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); /* invert the order of the round keys: */ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the first and the last: */ for (i = 1; i < Nr; i++) { rk += 4; rk[0] = Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[0] ) & 0xff] & 0xff]; rk[1] = Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[1] ) & 0xff] & 0xff]; rk[2] = Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[2] ) & 0xff] & 0xff]; rk[3] = Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[3] ) & 0xff] & 0xff]; } return Nr; } void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt ) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; /* round 3: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; /* round 4: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; /* round 5: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; /* round 6: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; /* round 7: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; /* round 8: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; /* round 9: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; /* round 11: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; /* round 13: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[(t0 >> 24) ] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3 ) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24) ] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0 ) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24) ] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1 ) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24) ] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Te4[(t0 >> 24) ] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t3 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(ct , s0); s1 = (Te4[(t1 >> 24) ] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t0 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te4[(t2 >> 24) ] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t1 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te4[(t3 >> 24) ] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t2 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(ct + 12, s3); } static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(ct ) ^ rk[0]; s1 = GETU32(ct + 4) ^ rk[1]; s2 = GETU32(ct + 8) ^ rk[2]; s3 = GETU32(ct + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; /* round 3: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; /* round 4: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; /* round 5: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; /* round 6: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; /* round 7: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; /* round 8: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; /* round 9: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; /* round 11: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; /* round 13: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1 ) & 0xff] ^ rk[4]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2 ) & 0xff] ^ rk[5]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3 ) & 0xff] ^ rk[6]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Td0[(t0 >> 24) ] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[(t1 ) & 0xff] ^ rk[0]; s1 = Td0[(t1 >> 24) ] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[(t2 ) & 0xff] ^ rk[1]; s2 = Td0[(t2 >> 24) ] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[(t3 ) & 0xff] ^ rk[2]; s3 = Td0[(t3 >> 24) ] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[(t0 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Td4[(t0 >> 24) ] & 0xff000000) ^ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t1 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(pt , s0); s1 = (Td4[(t1 >> 24) ] & 0xff000000) ^ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t2 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(pt + 4, s1); s2 = (Td4[(t2 >> 24) ] & 0xff000000) ^ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t3 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(pt + 8, s2); s3 = (Td4[(t3 >> 24) ] & 0xff000000) ^ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t0 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(pt + 12, s3); } /* setup key context for encryption only */ int rijndael_set_key_enc_only(rijndael_ctx *ctx, u_char *key, int bits) { int rounds; rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); if (rounds == 0) return -1; ctx->Nr = rounds; ctx->enc_only = 1; return 0; } /* setup key context for both encryption and decryption */ int rijndael_set_key(rijndael_ctx *ctx, u_char *key, int bits) { int rounds; rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); if (rounds == 0) return -1; if (rijndaelKeySetupDec(ctx->dk, key, bits) != rounds) return -1; ctx->Nr = rounds; ctx->enc_only = 0; return 0; } void rijndael_decrypt(rijndael_ctx *ctx, u_char *src, u_char *dst) { rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); } void rijndael_encrypt(rijndael_ctx *ctx, u_char *src, u_char *dst) { rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); }